Accessibility Flare Check-in #4

Here’s the video chat info for this Thursday. See you then!

Bristlemouth Accessibility Flare Check-in #4
Thursday, August 8 · 10:30 – 11:00am
Time zone: America/Los_Angeles
Google Meet joining info
Video call link: https://meet.google.com/izm-cseo-eni
Or dial: ‪(US) +1 216-839-0869‬ PIN: ‪235 983 901‬#
More phone numbers: https://tel.meet/izm-cseo-eni?pin=6083794049607

Meeting starting in 20 minutes — all are welcome! Just come listen in!

Here’s a summary of what I learned this week on two fronts from a rust perspective: driving the ADIN on the mote and trying to create a Bristlemouth packet builder and parser.

Rust mote proof-of-concept

  • The embassy ADIN driver does not support Open Alliance SPI.
  • The Bristlemouth mote requires Open Alliance SPI to enable the full bandwidth.
  • Open Alliance SPI adds some protocol structure to the bytes transferred on a SPI bus. It adds a 4-byte header and explicitly separates commands that read and write configuration registers on the MAC-PHY chip from actual MAC-PHY data transfer.
  • I was able to manually construct the right control transaction to make my rust proof-of-concept talk to the ADIN2111 on the mote.
  • Maybe at some point as a side project, I’ll do the work to add Open Alliance SPI support to the embassy driver.
  • Additionally I learned that the PHYID register of the ADIN2111 encodes a model number which is different between the ADIN1110 and ADIN2111. I also had to manually change that to get the mote to work.

Rust network packet code

  • I explored the APIs of some crates for embedded networking. Most notable is smoltcp, used by embassy-net and others.
  • It handles asynchronous data transfer with a Device trait with transmit and receive methods that immediately return single-use tokens that can be passed around/returned from a more internal function, and then consumed with a callback.
  • I also explored some of the packet building and manipulation libraries like pnet and etherparse. On embedded targets the stdlib is not available which makes some of this code incompatible/tricky.
  • In rust, in places where in C I would typedef a callback function to use as a function argument, it’s usually more idiomatic to define a Trait with a required method, and then pass a struct that implements the Trait. This often results in at least one additional named layer of indirection.

An example (though this is just the struct, not a separate trait) is the RtcTimeProvider struct that has a now() method:

So instead of passing a callback for getting current time, you pass an RtcTimeProvider. Then code can call now() on that object later repeatedly. You get the time provider object by first configuring the Rtc, then calling rtc.time_provider(). So you don’t get the current time from the Rtc object directly. You first get a narrowly-scoped time provider object, and use that to repeatedly call now().

If we looked at a variety of C drivers, I doubt the “time provider” layer would exist in any of them. You’d configure the RTC, then use it to get the current time. This is part and parcel to the safety that rust provides in an embedded context. Instead of giving all the code full access to all the resources (enabling us to change behavior in one part of the code that unexpectedly breaks a totally separate part of the code), it’s best practice to split up the resources into the narrowest piece that’s actually required for the targeted functionality.

We’ve started turning our attention toward the end-of-phase deliverable of some rough draft API docs.

1 Like

I’ve been continuing to trot down my “separate FreeRTOS from BCMP” path. Although along the way I have been looking at other examples. I have been looking more at zenoh-pico and how they separate their platform code from the core libraries, and how they provide access to the network packets to the users.

In doing so I have begun to recognize the patterns and see how it can be applied to our code. It has also helped me to draw out the potential different layers of the BCMP library and what each layer provides/needs from the other layers. I have begun to write/draw this out in my notebook and am beginning a doc where I write all of the funcitons that are being used by BCMP that could fall into the different layers of what I am calling right now the:
Platform - Core - Public layers.

The plaftorm layer would be any functions that are platform specific, things that we currently use from FreeRTOS.

The core layer is the layer that uses functions from the platform layer to provide the core BCMP functionality - processing of messages, automatic heartbeats, stuff that makes a node able to respond to its neighbor and participate in the bristlemouth network.

The public layer is then how we allow users of the core library to access the data that is coming through BCMP. For example, a function to get the latest neighbor table. Or providing a callback for BCMP to run when it gets a repsonse to the PING message I just requested it send.

I am going to continue writing out the different functions that are used, what layer I think they are a part of, and what dependencies/connections to the other layers they have. One thing I am keeping in mind while doing this is that the current code will need to change a lot - and this may involve removing/changing some of the dependencies.

Another area I dove a bit into this week was how the actual packet gets through LWIP to BCMP. This is a more specifc connection between the core layer and IP layer (I think the IP layer in some cases can be considered part of the platform layer) and this connection will also need to become abstracted and generic such that we could use another IP layer, like Zephyr’s IP stack and say, “Here you go zephyr, call this whenever you get a raw packet that uses the BCMP header!”.

1 Like