Anachro Bus Routing plan
I want some kind of "message board table" based on received/sent message types
For routing, you always echo messages from one bus to the other.
Everyone just sends to "everyone" (for now?) If you are a dom, you periodically transmit frames on your turn If you're a sub, schedule in downstream incoming frames either: send out a dedupe message every 15-30s
When joining a network:
- Send dedupe code (maybe also make this the announce message?)
- This triggers other device to start sending message?
- Wait for N seconds to see if an echo occurs
Dedupe message is just 4 bytes of unique id, 4 bytes random number. If you hear the message come back, disregard that channel for 30-60 seconds, set some warning code (yellow light)?
Device discovery?
Avoiding fixed device ids?
Maybe:
In the future: maybe have some kind of crypto here? Probably not wanted/needed here yet.
Overall summary
- Have a "broadcast" window, something like 1ms
- Dom sends out random u32 and largest available ID range
- Anyone not on the bus must jitter between 100us-900us
- Then send their IDu8, plus (ID as u32 muladd random)
- "READY" state achieved!
- If not ready, wait for next round
- Send ACK for any success number
- For each READY number, next
- Send new random number challenge
- Respond (jittered) with response
- If multiple good responses for one number, NAK number
- "SET" state achieved!
- For each SET number, next
- Send new random number challenge
- respond EXACTLY 10us (or something)
- "ACTIVE" state achieved
- Send "active ack"
Dom
- Spend 999ms doing normal stuff
- Top of every second:
Sub
Mostly the opposite as above, but also:
- If in the READY/STEADY/ACTIVE/CONNECTED state, don't respond to all call
- If >= 3 seconds from last ACK without moving forward (except in connected), reset to IDLE
- MAYBE don't bid on every all-call? 1/2? 1/4? 1/8?
Broadcast/response - broadcast_initial
Dom sends
# broadcast initial
[ random_number: u32 ][ min_wait_us: u32 ][ max_wait_us: u32 ][ min_id: u32 ][ max_id: u32 ]
After rng.gen_range(min_wait_us..=max_wait_us)
us, Sub sends back:
# broadcast ack
[ own_id: u32 ][ own_id_checksum: u32 ]
where:
own_id
:rng.gen_range(min_id..=max_id)
own_id_checksum
:own_id.wrapping_mul(random_number).wrapping_add(random_number)
If successful, Dom sends:
# broadcast ackack
[ own_id: u32 ][ SUCCESS_MAGIC_WORD: u32 ]
Then twice: - broadcast_ping
Dom sends
# broadcast confirm
[ random_number: u32 ][ min_wait_us: u32 ][ max_wait_us: u32 ][ id: u32 ]
where id
should == own_id
and random_number
is a TOTALLY NEW random number
TODO: Maybe just make this a dest
field, with the initial broadcast being 0
or something
After rng.gen_range(min_wait_us..=max_wait_us)
us, Sub sends back:
# broadcast ack
[ own_id: u32 ][ own_id_checksum: u32 ]
where:
own_id
:rng.gen_range(min_id..=max_id)
own_id_checksum
:own_id.wrapping_mul(random_number).wrapping_add(random_number)
If successful, Dom sends:
# broadcast ackack
[ own_id: u32 ][ SUCCESS_MAGIC_WORD: u32 ]
Routing thoughts
Okay, so above I described "everyone broadcasts everwhere", but I think I need to decide what kind of stuff I need.
I think I have two main choices:
- Keep the bus everywhere idea
- All devices would basically just look for specific message IDs on the bus
- All devices would have to listen and decode (or at least filter packed ID) continuously
- This probably wouldn't work great with Anachro, which is more point-to-point
- This wouldn't require any kind of "coordinator" role
- Do real routing, focus on (sender, receiver) pairs
- Easiest way: Expect a DAG, with the arbitrator "rooted" at the terminal node
- Have "send up" and "send down" primatives
- They push an addr on each level
- moving up push on sub -> dom
- moving down push on dom -> sub
- What about sub/sub devices?
- When we hit the terminal node, the message stops propigating
- They push an addr on each level
- Have "send up" and "send down" primatives
- Easiest way: Expect a DAG, with the arbitrator "rooted" at the terminal node
Prop routing
- dom only (head)
- sub only (bus OR tail)
- dom/sub (head + bus)
- sub/sub (tail + bus)
- dom/dom (head + head, not possible yet)
Example network 1
- Device A - dom only
- Device B (id: 1) - sub only (bus)
- Device C (id: 2) - sub only (bus)
- Device D (id: 3) - dom/sub (bus)
- Device F (id: 1) - sub only (bus)
- Device G (id: 2) - sub only (bus)
- Device H (id: 3) - sub (tail)
- Device E (id: 4) - sub only (tail)
Examples:
Device A would be prompted (how?) to send a "Send down" message:
- to B: [1]
- Terminates here
- to C: [2]
- Terminates here
- to D: [3]
- To F: [3, 1]
- Terminates here
- To G: [3, 2]
- Terminates here
- To H: [3, 3]
- Terminates here
- To F: [3, 1]
- to E: [4]
- Terminates here
Foreach terminator, respond with the end message. Responses:
- [1, $anachro_id]
- [2, $anachro_id]
- [3, 1, $anachro_id]
- [3, 2, $anachro_id]
- [3, 3, $anachro_id]
- [4, $anachro_id]
I guess what I really want is to be able to include a unique ID in the response, like the anachro uuid. I guess it's my bus, why not?
OH, but I guess I don't need a GLOBAL routing table, just:
- Which way is the anachro arbitrator
- Which anachro devices are on which sub nodes
Can I use this to handle the sub/sub tail case?
- Rooted node starts
- Subs log onto the bus
- If a Sub is also a dom:
- Start domming
The process for "joining" the anachro message bus is:
- If we're a power-dom (anachro arbitrator), just start domming immediately
- Otherwise, wait for one of the ports to become active
Profiles
- power-dom: anachro router + 1x dom port
- switch: anachro device + 1x dom port + 1x sub port
Pains in the ass
- What if a tail is also a sub on a bus?
- This is annoying, because they are a dom on neither interface
- This requires subs to ALSO have a routing table, I guess