Happy almost-new-year! It’s been another busy month, with some solid firmware progress on the ADSBee 1090. This update contains some usual month-in-review information about newly released features, but also includes a bit of blab at the end about how OTA firmware updates work for ADSBee, as a treat!
- Firmware Version 0.7.0
- OTA firmware upgrade capability (experimental)
- Network diagnostic and configuration features
- ADSBee PyPi package
- Ethernet support (very experimental)
- Deep Dive: How do OTA firmware updates work for ADSBee?
Firmware Version 0.7.0
This month’s biggest milestone was the release of firmware version 0.7.0, which includes some much-awaited features that should be very welcome for network users of the ADSBee 1090!
OTA Firmware Upgrade Capability
Since the initial inception of the ADSBee 1090, my intention has always been to make it easy to cram into small or generally difficult to access spaces (e.g. attics, boxes on roofs / trees, etc) that might have better ADSB reception than more accessible alternatives. There are a number of creative solutions available for getting power to these spaces in order to run an ADSBee, but until now it’s been generally inadvisable to put an ADSBee in said difficult-to-access spaces due to the need to physically access the device in order to upgrade firmware over USB.
With the release of firmware 0.7.0, users can now send firmware upgrades to their ADSBee 1090 remotely. Each firmware release after 0.7.0 will now include both the usual .uf2 file, for upgrading firmware over USB in DFU mode, and a new .ota file, which uses a custom file format to allow firmware binaries to be flashed over the network using a web browser or a Python script (more on the Python stuff later). This feature is still considered “experimental”, in that there are still a few bugs that can make a firmware upgrade fail under some circumstances, but the firmware and bootloader architecture of the ADSBee make it very resistant to “bricking” itself by attempting to boot an invalid firwmare image, since each firmware needs to pass a multi-step CRC check before it’s used. In all the cases that I have tested, a failed firmware upgrade (resulting from network disconnection, software bugs, or other issues) can be circumvented by attempting the upgrade again.
Network Diagnostic and Configuration Features
It’s now easier than ever to debug network connectivity issues on an ADSBee 1090 via the command line interface by using the new AT+NETWORK_INFO?
AT command. ADSBees queried with this command will reply with the connection status of each of their network interfaces, as well as the IP and MAC address of all clients connected to their WiFi Access Point, if enabled.
ADSBee 1090’s can also have a custom hostname configured via the AT+HOSTNAME
command. This is handy if you’d like to differentiate multiple ADSBee devices on your network, for instance one ADSBee 1090 can be named “adsbee-attic” while another might be labelled “adsbee-portable”. mDNS hasn’t been activated yet in ADSBee firmware, so hostnames can’t be used to ping ADSBee devices or navigate to their local webpages, but that’s coming soon!
ADSBee PyPi Package
If you enjoy Python scripting and have a fun project you’d like to integrate with an ADSBee, you’ll be pleased to learn that the ADSBee python library I originally wrote for programming and testing ADSBee 1090’s in production is now available as a PyPi package! Getting started is as simple as pip install adsbee
. The library includes a number of utility functions for sending and receiving AT commands over serial or network connections, and also includes a function that can execute fully automated firmware updates over aforementioned serial or network connections.
The Python library is still in its infancy, and is pretty much an internal tool that I’ve just blasted into the public world with very little in the way of documentation. I’ll be improving features and documentation in future releases, but if you’d like to get started with it in the meantime, the functions are well commented and I’ll be happy to provide examples and guidance on Discord. The source code for the library can be found here: as always, PRs are welcomed!
Experimental Ethernet Support
ADSBee 1090’s can now be connected to Ethernet! Although Ethernet connectivity isn’t yet reliable in all circumstances, devices connected to a W5500 Lite module as shown below can join a network, get assigned an IP address, and feed endpoints over the internet! Just be sure to enable the Ethernet interface with AT+ETHERNET=1
.
Right now the Ethernet connectivity feature is a bit of an experiment, and isn’t considered “stable”. Future updates will focus on improving robustness and adding additional hardware and firmware features for Ethernet connectivity. Stay tuned!
How do OTA Firmware Updates work for ADSBee?
Updating firmware on an embedded device can be a bit tricky, since allowing firmware to update itself inevitably leads to the possibility that a device may update itself with the wrong firmware, or put the right firmware in the wrong place, leading to an unbootable or unusable configuration known colloqually as a “bricked” device.
In order to avoid this scenario, embedded devices like ADSBee that are being updated Over The Air (OTA) typically follow a few rules (well, probably a lot of rules, but here’s two that I know are important):
- Don’t update the code that is currently being executed.
- Don’t execute code unless it’s been verified to be correct.
Don’t update the code that is currently being executed.
Rule #1 seems obvious, since rewriting the very code that you are executing can lead to some problematic behavior. Typically rule #1 is accomplished by having either a factory-flashed bootloader that is in charge of updating applications and is never updated itself after leaving the factory, or with a system of multiple firmware partitions that can update each other.
The factory-flashed bootloader method is what’s currently used when ADSBee devices are updated over USB using the USB DFU (Device Firmware Upgrade) method. A bootloader has been permanently programmed into the ROM of the RP2040 during manufacturing on the Raspberry Pi Foundation’s production line, and this bootloader is capable of receiving .uf2-formatted firmware binaries over USB and programming them into the flash memory attached to the RP2040.
The downside of the factory-flashed bootloader method is that once this bootloader is installed, there’s no going back. Whatever protocol was programmed into the bootloader for updating device firmware will be the protocol that is used until the end of time for updating the product with new firmware. In the case of things like network firmware updates, which can be more complex and may be expanded with additional features over time, having a bootloader that’s frozen in time can become a problem as the software on the rest of the system evolves. Since ADSBee 1090 is intended to be delivered to beta customers half-baked and iterated on to fix bugs and fulfill newly discovered feature requests, I chose to implement the multi-partition firmware update method instead.
According to my google search results, unlike snails, whales are widely understood to sleep more than three. To my knowledge, many other mammals, like humans, are not very good at sleeping underwater (or perhaps more accurately, waking up after going to sleep underwater). How does a whale sleep without drowning?
Apparently, whales have a nifty trick up their sleeve. Whales can sleep one hemisphere of their brain at a time, allowing the other hemisphere to stay aware of the whale’s surroundings and move to the surface to breathe. Whale sleep behaviors vary between species, but whales can generally sleep while swimming slowly, or while bobbing around near the surface nearly motionless, like the sperm whales that are doing a great log impression in the image above (credit to Scientific American for the pic).
Much like a sleepy whale, the ADSBee’s firmware storage is divided into two application sectors, called FLASH_APP0 and FLASH_APP1. Each sector is identical in size and can store just under 8MB of code. When firmware in FLASH_APP0 is executed, it has access to the APP1 sector and can happily erase, write, and read firmware in that sector to its hearts content. Conversely, when firmware in FLASH_APP1 is executed, it has access to the FLASH_APP0 sector and can erase / read / write firmware in that section of storage without risk of overwriting itself.
When a firmware update is initiated, the application that is currently running on the ADSBee 1090 receives a firmware image that it writes into the complementary flash sector. Once this newly written firmware is verified to be correct, the microcontroller can “jump” into the new sector to begin executing that code.
There’s one piece of the puzzle remaining: when the ADSBee first boots up, how do we know which section to jump into first? This is where the FLASH_BL region comes in. FLASH_BL contains a very small bootloader whose only job is to check which partition was flashed most recently, and whether said partition is valid. If a partition is freshly flashed and is properly verified, the bootloader picks that partition to jump into. If a partition is freshly flashed but fails checksum verification, the bootloader falls back to the older firmware in the complementary partition.
Don’t execute code unless it’s verified to be correct.
Like billions of devices around the world, ADSBee 1090 relies on Cyclic Redundancy Checks to verify that chunks of firmware images being sent over the air, and complete firmware images, are correct (i.e. no bit flips introduced in transit, or other errors). Each chunk of data transferred over the air includes a CRC32 calculated over its bytes that is used to verify the integrity of the received data packet and corresponding chunk of firmware programmed in flash. Likewise, each firmware partition is pre-pended in flash with a binary header that indicates the status of the firmware partition and includes a CRC32 value for verifying its contents. Using these CRC values, the ADSBee is able to confirm that bits haven’t been flipped during transit, and that they have been programmed to flash successfully, before executing a newly flashed firmware image.
What are the steps to an OTA update?
OTA updates are a bit of a song and dance, with a few commands for putting the ADSBee into a firmware update mode, and then a bidirectional transmit and reply process used for sending the firmware binary in chunks over the serial connection normally used for AT commands.
Before any data chunks can start flying, it all starts with a .ota file. The .ota file is a new file format I invented, probably out of a lack of understanding of existing solutions, for flashing the ADSBee. Each .ota file contains two verisons of the firmware. One version is compiled for FLASH_APP0, and one is compiled for FLASH_APP1. This is a bit of a kludge, but was necessary since ARM M0+ cores don’t support Position Independent Code (code that can be run without a knowledge of where it is in flash).
Once an ADSBee-flashing program has read in the .ota file, the next step is to tell the ADSBee to enter a firmware update mode and then send over the relevant chunks of data. This is done over the AT command interface using the procedure below.
And that’s about it! Right now there are two programs written for updating ADSBee 1090’s over the air. One is written into the adsbee python library, and one is baked into the ADSBee 1090’s own webpage as a javascript application, allowing firmware images to be uploaded directly from any web browser. Updating firmware over the air currently takes just under 2 minutes (most of this time is spent erasing and writing flash, which seems to be quite slow). I’m sure there’s some additional optimizations that can be made to speed things up further; if you have any cool ideas about updating firmware (or see something that I goofed in my OTA process), I’d love to hear from you!
Acknowledgements
Many thanks to Brian Starkey for his excellent writeup of a similar Pi Pico bootloader project, which was a useful reference when implementing my own bootloader.
Hunter Adams also has a fantastic bootloader for the Pico that served as additional inspiration for my implementation.
Both of the aforementioned sources focused on bootloaders with a single application partition, but nevertheless contained many of valuable tidbits that came in handy when developing my multi-partition bootloader!
🎊Here’s to 2025! 🎊
It’s been a fantastic year on the ADSBee project! In just around 6 months this project has gone from a janky little prototype sitting on my workbench, to a janky little product sitting in homes around the USA, and around the world (as far away as Ireland and Australia)! Thanks for following along and making this project worth working on. Stay tuned, there’s lots more to come!