Overview
For the Bootloader, the following operations will be carried through datagrams. For some operations like querying, update ID/name, and flash application code, the data will first be serialized through protobufs. To generate protobuf files, run make bootloader_protos
.
Datagram Format
Please check over the format for a datagram (https://uwmidsun.atlassian.net/wiki/spaces/ELEC/pages/2030895112/Bootloader%2BFlash%2Bover%2BCAN#Transport-layer-(Datagrams)). Below, the id and type of data will be specified. Status return functions will share the same datagram ID of 0. The number of node IDs addressed through the client is arbitrary, and the special value 0 means every controller board is addressed. Every response datagram will have a value of 0 for the list of node IDs parameter, as 0 is the ID of the client.
Querying
In the querying function, the client sends out a datagram containing the pattern-matching information: controller board IDs, name, current project name, project info, and/or git version information. The client message can target one, several, or zero projects from the information. An example of this would be id=5, project=bms_carrier, name=curiosity
to match controller board 5 running BMS carrier named curiosity
.
The client → boards datagram should have the following format:
uint8 id = 1 // Use 1 here as the datagram ID to avoid conflicts uint8 ids_addressed = 0 // The special value 0 means every controller board is addressed uint16 data_size // Size of the protobuf (in n bytes) uint8[n] data // The protobuf (located in the protos folder in the bootloader project: querying.proto)
The response datagram will have the following format:
uint8 id = 2 // Use 2 here as the datagram ID to avoid conflicts uint16 data_size // Size of the protobuf (in n bytes) uint8[n] data // The protobuf (located in the protos folder in the bootloader project: querying_response.proto)
Ping
The ping function sends out a list of node IDs or none to ping all boards. Each board will send back a message with its ID if it is in the bootloader and ready to receive commands.
The client → boards datagram should have the following format:
uint8 id = 3 // Use 3 here as the datagram ID to avoid conflicts uint8 ids_addressed // The number(m) of nodes on the network that should receive the datagram. The special value 0 means every controller board is addressed uint8[m] node_id // The different node IDs. Keep this blank if ids_addressed = 0
Note: This function has no data
The response datagram will have the following format:
uint8 id = 4 // Use 4 here as the datagram ID to avoid conflicts uint16 data_size = 1 // This is the size of the ID of the controller board in n bytes uint8 data // The id of the controller board
Jump to application
Direct the matched boards to jump to the application code. The client sends out a list of IDs it wants to jump; each matched controller board computes the CRC of the application code, checks it, responds with a status code, and jumps to the application. (Actually doing this is super tricky: info here https://interrupt.memfault.com/blog/how-to-write-a-bootloader-from-scratch .)
Depending on how the design works out, we might be able to skip the CRC.
The client → boards datagram should have the following format:
uint8 id = 5 // Use 5 here as the datagram ID to avoid conflicts uint8 ids_addressed // The number(m) of nodes on the network that should receive the datagram. The special value 0 means every controller board is addressed uint8[m] node_id // The different node IDs. Keep this blank if ids_addressed = 0
Note: This function has no data
The response datagram will have the following format:
uint8 id = 0 // Use 0 here as the datagram ID to avoid conflicts uint16 data_size = 1 // This is the size of the status code in n bytes uint8 data // The status code
Update ID / Update name
This function will be split into two different commands, update ID and update name. These functions update the name or ID of a single controller board. The client sends out an ID to update and the new ID or name. The controller board overwrites the config (being careful to write one page, check it, and then write the other), and responds back with a status code. The protobuf used will change based on which function is used (name vs ID).
The client → boards datagram should have the following format:
uint8 id = 6 // Use 6 here as the datagram ID to avoid conflicts uint16 data_size // Size of the protobuf (in n bytes) uint8[n] data // The protobuf (located in the protos folder in the bootloader project: update_id.proto or update_name.proto)
The response datagram will have the following format:
uint8 id = 0 // Use 0 here as the datagram ID to avoid conflicts uint16 data_size = 1 // This is the size of the status code in n bytes uint8 data // The status code
Flash application code
The client sends out IDs of the boards to flash to, metadata like project name, git version (+branch?) info, and application CRC and size, then the application code itself. The controller boards write the application code to flash (making sure not to keep it all in memory at once to avoid overflows) and compute their own CRC of the application code. If it matches, they overwrite the project name/git version info/application CRC/application size in the config and clear the project info (being careful to write one page, check it, and then write the other), then respond back with an “OK” status code message. If it doesn’t match, they mark their config as “no project” (again being careful) and respond back with an appropriate status code.
The client → boards datagram should have the following format:
uint8 id = 7 // Use 7 here as the datagram ID to avoid conflicts uint16 data_size // Size of the protobuf (in n bytes) uint8[n] data // The protobuf (located in the protos folder in the bootloader project: flash_application_code.proto)
The response datagram will have the following format:
uint8 id = 0 // Use 0 here as the datagram ID to avoid conflicts uint16 data_size = 1 // This is the size of the status code in n bytes uint8 data // The status code
Note: The application code is to be transmitted in 2048-byte chunks in separate datagrams as raw data