the home site for me: also iteration 3 or 4 of my site
4
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: add rp2350 bit and correct capitalization

+10 -5
+10 -5
content/blog/2026-04-25_frc-systemcore-image.md
··· 1 1 +++ 2 - title = "Reverse engineering the FRC systemcore image" 2 + title = "Reverse engineering the FRC SystemCore image" 3 3 date = 2026-04-25 4 4 slug = "frc-systemcore-image" 5 5 description = "looks quite interesting 👀" ··· 8 8 tags = ["frc", "reverse engineering"] 9 9 +++ 10 10 11 - FIRST announced the systemcore several months ago now and the beta software started rolling out recently and becoming way more polished so with the release of the [new driver station](https://github.com/wpilibsuite/FirstDriverStation-Public) I decided it was time to dig into the firmware image and see what I could find! 11 + FIRST announced the SystemCore several months ago now and the beta software started rolling out recently and becoming way more polished so with the release of the [new driver station](https://github.com/wpilibsuite/FirstDriverStation-Public) I decided it was time to dig into the firmware image and see what I could find! 12 12 13 13 <!-- more --> 14 14 15 - ![the systemcore in all its glory](https://l4.dunkirk.sh/i/mGIuJH5L1I-o.webp){caption="they really did a great job of making it look nice and polished"} 15 + ![the SystemCore in all its glory](https://l4.dunkirk.sh/i/mGIuJH5L1I-o.webp){caption="they really did a great job of making it look nice and polished"} 16 16 17 - The systemcore is based on an Raspberry Pi Compute Module 5 and as a result the image is just a zipped .img file that extracts to 10 GB in size (the size of the emmc) but considering that the original zip file is only 1.8 GB there is likely quite a bit of empty / wasted space. It is interesting that they didn't choose to go the auto expanding route but I'm guessing they did this for ease of use. 17 + The SystemCore is based on a Raspberry Pi Compute Module 5 with a 16 GB eMMC (which formats to about 14.5 GB). The firmware image extracts to 10 GB but this only covers the partition layout, not the full eMMC -- the remaining space is unpartitioned. Considering that the original zip file is only 1.8 GB there is likely quite a bit of empty / wasted space within the partitions. It is interesting that they didn't choose to go the auto expanding route but I'm guessing they did this for ease of use. 18 18 19 19 | Partition | Type | Start LBA | Sectors | Size | Description | 20 20 | --------- | ------------ | ---------- | ---------- | ----- | ----------------------------- | ··· 130 130 - `GET/POST /api/wifi` - configure SSID, password, WPA (rewrites `hostapd.conf`, restarts the AP) 131 131 - `GET/POST /api/network` - configure eth0 networking (rewrites `dhcpcd.conf`) 132 132 - `GET /api/health` - health check 133 - - `GET /api/oshash` - OS version hash (curious whether this will get used to validate the systemcore image on the FMS?) 133 + - `GET /api/oshash` - OS version hash (curious whether this will get used to validate the SystemCore image on the FMS?) 134 134 135 135 The update manager handles the A/B partition scheme. It receives a partition image, DD-extracts it to the inactive rootfs partition, then mounts the boot partition read-write and updates `autoboot.txt`. The reboot uses the Pi's `tryboot` mechanism - `sudo reboot "0 tryboot"` - which boots into the new partition once, and only commits it as the default after validation. If it fails, you just power cycle and it falls back. Classic A/B update pattern, well executed. 136 136 ··· 163 163 164 164 The `robot.service` runs as the `systemcore` user (UID 105) with real-time priority 50. It waits up to 15 seconds for all five CAN interfaces to come up before starting user code. The `robotCommand` script itself isn't in the image - it's created at runtime by the package manager when user code is deployed. The `ConditionPathExists=/home/systemcore/robotCommand` directive means the service won't even attempt to start until code has been deployed, which is a nice touch. 165 165 166 + ### Smart IO 167 + 168 + The SystemCore integrates an RP2350 microcontroller for Smart IO - the successor to the Raspberry Pi Pico's PIO (Programmable IO). Unlike a standalone Pico, this RP2350 has no flash attached; instead, the CM5 loads its firmware into RAM over a serial interface at boot time. The corresponding Linux kernel modules handle this loading sequence, pushing the UF2-style firmware blob from the `picoflasherprocess` (which carries an embedded `fw.uf2` at 127 KB) into the RP2350's RAM before the IO daemon starts. The `iodaemon` then communicates with the RP2350 over USB (via libusb) to drive the status LEDs, relay CAN bus info, and handle GPIO. 169 + 166 170 ### Odds and Ends 167 171 168 172 The image ships with a VS Code server on port 4900 and a `ttyd` web terminal on port 4901. On the discovery side, the SystemCore advertises itself via mDNS as both `_SystemCore._tcp` and the legacy NI services (`_ni._tcp`, `_ni-rt._tcp`). It currently uses the roboRIO hostname pattern `roboRIO-{team}-FRC` alongside `SystemCore-{team}-FIRST`. This was done as a backwards compatibilty move during the beta period but will be removed in the full release in 2027. ··· 177 181 178 182 - 2026-04-25 16:50 - Added clarification from Thad House on radio daemon not being written yet 179 183 - 2026-04-25 16:55 - Added clarification that dual hostnames will be removed for production release 184 + - 2026-04-25 21:25 - Fixed eMMC size (16 GB physical, ~14.5 GB formatted; 10 GB is image partitions only), added RP2350 Smart IO section, corrected SystemCore capitalization