-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft for new implementation of dot15d4 #38
base: main
Are you sure you want to change the base?
Conversation
Add a new module 'mac' that will contain logic for mac layer functionalities such as CSMA and TSCH. Move existing CSMA module to this new module.
'Driver' trait naming choice felt confusing and did not really represents its intents. - Rename Driver trait to 'UpperLayer' - Move trait outside of "phy" module - Renamed methods : 'transmit' -> 'frame_to_transmit', 'received' -> 'received_frame' - Remove 'driver' source file. - Updated tests for Upperlayer
Ideally, upper layer should only be reported error coming from MAC sublayer
- Move CSMA constants to MAC - Add constant module to PHY - Remove 'user_configurable_constants' module. Now included in MAC constants - Update 'build.rs' script
Use MAC requests and MAC indications instead of FrameBuffer
Thanks for sharing your preliminary result in the open - this is very helpful! As this is still a Draft and I'm not even sure whether you're interested in external reviews, I won't review right away. But if and when you're interested in a review let me know. |
@fg-cfh We are definitely open for external reviews, so go ahead! 😀 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi! I did a quick high-level review of the MAC/driver interface which is crucial to get right initially IMO. I didn't review anything else yet for lack of time, sorry for that. Just a first high-level comment that needs to be discussed of course - would be nice to hear your opinion about those ideas. Maybe I'm overlooking something?
); | ||
|
||
match select::select(mac_service.run(), phy_service.run()).await { | ||
Either::First(_) => panic!("Tasks should never terminate, MAC MCPS just did"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Something seems to be wrong with the names.
- MCPS: MAC data service
- MLME: MAC management service
None of those map to an entity called PhyService in my understanding and MacService seems to encompass both. I think it would be important to get the naming and definitions right on those central architecture pieces.
TIMER: DelayNs + Clone, | ||
{ | ||
pub async fn run(&mut self) -> ! { | ||
let (mut tx, mut rx) = (Channel::new(), Channel::new()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A "full duplex" pair of packet channels might be a good abstraction for high-level socket-like communicaton (OSI 3+) but IMO won't cut it in the case of IEEE 802.15.4 for the MAC <-> PHY/Driver interface.
The standard leaves the details of the MAC <-> PHY/Driver interface up to implementors, so that's where we're free to bring in our own ideas:
- In my experience, the PHY/driver needs to know exactly the current and the next task. Precisely that, not more not less. A queue or buffer is neither needed nor wanted.
- Tasks are not just RX/TX but also CCA, acknowledgements, header mangling, encryption/decryption/signing, CRC-checking, etc.
- The granularity of tasks is defined by three factors:
- They need to be large enough (time extension) to be programmable by a CPU - ideally with lots of low-energy sleep time in between.
- They need to specify generic "pieces of work" that can be applied to all hardware out there, no matter its vendor-specific capabilities.
- The task repertoire needed for a minimal working driver should be as small as possible to keep the entry hurdle for new drivers low.
Typical examples of generic (implementation-independent) task primtives are:
- "Send a packet such that it's RMARKER will pass the antenna at the precise radio clock tick T. Encrypt and sign the packet on-the-fly."
- "Ensure that the receiver is on just-in-time so that you'll be able to recognize a packet whose RMARKER is expected to pass the antenna at the precise radio clock tick T +/- X ticks. Keep the receiver on for precisely Y ticks or until an incoming packet is fully received - whatever comes later - and then got to low-energy idle."
- "Use an Enh-Ack to acknowledge the next incoming packet precisely after AIFS - measured as X radio clock ticks. Ensure that it contains a timing header whose timestamp you'll mangle based on the RX timestamp of the preceding packet."
- "Do a CCA of precisely aCcaTime, then immediately send a packet after aTurnaroundTime - if the channel is idle - otherwise place the radio in low-energy mode. Calculate everything such that the RMARKER of the TX packet will pass the antenna at the precise radio clock tick T."
Some SoCs will execute full tasks of the above kind in hardware. Others will require such tasks to be partially controlled by CPU, again others need them to be implemented in software alone - sometimes with reduced standard compliance (which is good enough for many applications and needs to be supported in practice).
The scheduler may only program the next task while the current task is already running. Re-scheduling decisions often need to be taken at very short notice, up to a minimal guard time a few µs before task switching actually occurs. The scheduler needs to be able to cancel any already programmed task and program another one instead.
To make it worse, real-world hardware often requires the driver not only to implement each task on its own but also optimize the transition between them (TX-to-RX, CCA-to-TX, RX-to-ACK, etc.). Often the previous task will trigger the next task in specific ways for every pair of tasks. Hence the requirement for the driver to always know exactly two tasks.
Take for example "shorts" or PPI in nRF SoCs. Similar mechanisms exist for TI SoCs. Those SoCs are most common in real-world applications (2.4G and SubG) and can therefore not be ignored on the architecture level. UWB SoCs have sophisticated timing support in hardware (hence the RMARKER reference above). Again other SoCs implement ACKs, address filtering, etc. in hardware and the MAC should be able to make use of such capabilities while still being written as generically as possible for best re-use across hardware.
It will be very hard to fix this later, because, unfortunately, it's this API that driver and framework maintainers need to co-ordinate upon. Any change to this API will have to go through a lengthy and ugly deprecation procedure.
I propose the following metaphor: "The PHY/Driver is an execution engine. It is pre-programmed with a single task just-in-time by the MAC.". This means
- procedure-call oriented rather than event driven (i.e. the MAC knows a lot about driver primitives, the driver almost nothing about the MAC - the inverse of channel logic)
- tasks rather than packets
- proactive pre-programming of a single task with precise timing rather than reactive "best effort" execution of a stream of tasks
These are not "future requirements" IMO. They will be initially required for TSCH and CSMA/CA to work reliably and efficiently (low-power) in practice. At the same time this capability will unlock other IEEE 802.15.4 sub-protocols you may want to implement in the future.
If you like I can try to make a proposal for this interface (PR) - exemplifying it as an alternative nRF52840 driver. I propose that I show this to you once the most important ideas are visible. And that we then think together whether this approach is attractive to you and if so - how to integrate it. What do you think?
...edited for clarity and readability
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm unsure whether such a rigorous API is required. But I'm also not saying it isn't.
I think the trick to solving this is by proposing an actual API. Then there's something concrete to discuss.
For example, there might a really elegant way of doing radio transitions you're thinking of.
Or maybe there's a simpler system we can think of.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the trick to solving this is by proposing an actual API.
Agreed.
Or maybe there's a simpler system we can think of.
I'm sure, there is. That's why I'd hope for your review.
This is a draft for the new implementation of the crate "dot15d4" that aims to better comply with the standard. This draft also contains new features related to TSCH.