|
| 1 | +# Firmware Update Sequence diagram |
| 2 | + |
| 3 | +Firmware update scenario consists of two main stages: |
| 4 | +- Initiating the firmware update |
| 5 | +- Downloading the firmware file |
| 6 | + |
| 7 | +These two stages are almost independent, thought some parameters are passed between them. |
| 8 | + |
| 9 | +## Switching Cyphal nodes to "update" mode |
| 10 | + |
| 11 | +To update the firmware, the nodes must be switched to "update" mode. |
| 12 | +This is done by sending the `COMMAND_BEGIN_SOFTWARE_UPDATE` command to each node using the `435.ExecuteCommand` RPC service. |
| 13 | +The command triggers a target node to switch to "update" mode and prepare for the firmware update. |
| 14 | +As part of the preparation process, the node remembers the path to the firmware file and the source node ID of the daemon that will provide the firmware file. |
| 15 | +After that, the firmware updating process runs without any further interaction with the original user, who initiated the update. |
| 16 | + |
| 17 | +```mermaid |
| 18 | +sequenceDiagram |
| 19 | + autonumber |
| 20 | + actor User |
| 21 | + participant NodeCommandClient as NodeCommandClient<br/>and its internal `ExecCmdClient` |
| 22 | + participant ExecCmdService |
| 23 | + participant CyExecCmdClient as Cyphal<br/>`435.ExecuteCommand.1.3`<br/>RPC client per node |
| 24 | + actor NodeX as NodeX<br/><<cyphal node>> |
| 25 | + |
| 26 | + Note over NodeCommandClient, CyExecCmdClient: Initiating a firmware update. |
| 27 | + User ->>+ NodeCommandClient: beginSoftwareUpdate(node_ids, path) |
| 28 | + NodeCommandClient --) ExecCmdService: * Route{ChMsg{}}<br/>ExecCmd.Request_0_2{<br/>node_ids, cmd{path}, timeout} |
| 29 | + NodeCommandClient --) ExecCmdService: Route{ChEnd{alive=true}} |
| 30 | + deactivate NodeCommandClient |
| 31 | + Note over ExecCmdService, NodeX: Switching nodes to "update" mode. |
| 32 | + par in parallel for each node id |
| 33 | + ExecCmdService ->>+ CyExecCmdClient: rpcClientX = create(node_id) |
| 34 | + ExecCmdService ->> CyExecCmdClient: request({BEGIN_SOFTWARE_UPDATE, path}, timeout}) |
| 35 | + CyExecCmdClient --)+ NodeX: uavcan::node::<br/>435.ExecuteCommand.<br/>Request_1_3{cmd, path} |
| 36 | + deactivate CyExecCmdClient |
| 37 | + NodeX --)+ CyExecCmdClient: uavcan::node::<br/>435.ExecuteCommand.<br/>Response_1_3{status} |
| 38 | + Note right of NodeX: The node<br/>has been switched<br/>to "update" mode.<br/><br/>Remember `path` and<br/>src_node_id (of the daemon). |
| 39 | + CyExecCmdClient ->>- ExecCmdService: response({status}) |
| 40 | + ExecCmdService --) NodeCommandClient: Route{ChMsg{}}<br/>ExecCmd.Response_0_2{node_id, status} |
| 41 | + end |
| 42 | + ExecCmdService --)+ NodeCommandClient: Route{ChEnd{alive=false}} |
| 43 | + NodeCommandClient -)- User: result{map<status_or_failure>} |
| 44 | + deactivate NodeX |
| 45 | +
|
| 46 | + box SDK Client |
| 47 | + actor User |
| 48 | + participant NodeCommandClient |
| 49 | + end |
| 50 | + box Daemon process<br/>《cyphal node》 |
| 51 | + participant ExecCmdService |
| 52 | + participant CyExecCmdClient |
| 53 | + end |
| 54 | + box Cyphal Network Nodes |
| 55 | + actor NodeX |
| 56 | + end |
| 57 | +``` |
| 58 | +Here are descriptions for arrows in the diagram: |
| 59 | +1. `User` sends a command to the `NodeCommandClient` to begin the firmware update on the specified nodes, with the specified path to the firmware file. |
| 60 | +2. `NodeCommandClient` sends corresponding IPC request(s) to the `ExecCmdService` to build full scope of the update process. |
| 61 | +3. `NodeCommandClient` triggers the update process on the remote `ExecCmdService` by marking the end of the channel (with keeping it alive). |
| 62 | +4. For each target node id a new Cyphal RPC client is created for standard `435.ExecuteCommand` RPC service. |
| 63 | +5. These RPC clients are used to request the command (from step #2) execution on remote target nodes. |
| 64 | +6. The command is delivered to the `435.ExecuteCommand` RPC server on target node. |
| 65 | +7. The target node confirms the command execution and switches to "update" mode. |
| 66 | +The node also remembers the path to the firmware file and the source node id from where the command had arrived - |
| 67 | +this information will be used during the next "downloading" stage. |
| 68 | +8. The confirmation response is passed back to the `ExecCmdService`. This step will fail with "timeout" if the node is not responding in time. |
| 69 | +9. The `ExecCmdService` sends the response back to the `NodeCommandClient`, which collects the results for all nodes. |
| 70 | +10. Once we've got responses from all nodes, the `ExecCmdService` sends the channel completion. |
| 71 | +11. The `User` receives the overall result of the command execution, which is a map of node ids to their statuses or failures. |
| 72 | +Note that even for not responding nodes there will be `Timedout` failure in the map (see step #8). |
| 73 | + |
| 74 | +## Downloading the firmware file |
| 75 | + |
| 76 | +```mermaid |
| 77 | +sequenceDiagram |
| 78 | + autonumber |
| 79 | + participant FileProvider |
| 80 | + participant FileSystem as Root directories<br/>on the OS file system |
| 81 | + participant CyFileReadServer as Cyphal<br/>`408.Read.1.1`<br/>RPC server |
| 82 | + actor NodeX as NodeX<br/><<cyphal node>> |
| 83 | + |
| 84 | + activate NodeX |
| 85 | + par in parallel on each node |
| 86 | + loop repeat until EOF |
| 87 | + NodeX --)+ CyFileReadServer: uavcan::file::408.Read.<br/>Request_1_1{path, offset} |
| 88 | + deactivate NodeX |
| 89 | + Note right of NodeX: The node<br/>is reading the file chunk<br/>from the daemon node. |
| 90 | + CyFileReadServer ->>+ FileProvider: read(path, offset) |
| 91 | + FileProvider ->> FileProvider: findFirstValidFile(path) |
| 92 | + FileProvider ->> FileSystem: read(file, offset, size) |
| 93 | + FileProvider ->>- CyFileReadServer: file data chunk |
| 94 | + CyFileReadServer --)- NodeX: uavcan::file::408.Read.<br/>Response_1_1{data} |
| 95 | + activate NodeX |
| 96 | + Note left of NodeX: The node stores (in flash) the file chunk,<br/>moves the offset and repeats. |
| 97 | + end |
| 98 | + Note right of NodeX: Download has completed.<br/>Verify and apply the firmware update.<br/>Restart the node. |
| 99 | + end |
| 100 | + deactivate NodeX |
| 101 | +
|
| 102 | + box Daemon process<br/>《cyphal node》 |
| 103 | + participant FileProvider |
| 104 | + participant FileSystem |
| 105 | + participant CyFileReadServer |
| 106 | + end |
| 107 | + box Cyphal Network Nodes |
| 108 | + actor NodeX |
| 109 | + end |
| 110 | +``` |
| 111 | +Here are descriptions for arrows in the diagram: |
| 112 | +1. A node in "update" mode sends a request to the `408.Read` RPC server on the daemon node to read a chunk of the firmware file. |
| 113 | +2. The `408.Read` RPC server forwards the request to the `FileProvider`, which is responsible for reading files from the file system. |
| 114 | +3. The `FileProvider` tries to find the requested file in one of the "root" directories. |
| 115 | +4. Once the file is found, the `FileProvider` opens and reads the requested chunk of data from the file system. |
| 116 | +5. The `FileProvider` sends the data chunk back to the `408.Read` RPC server as a response. |
| 117 | +6. The RPC server posts the data chunk back to the node, which stores it in flash memory, |
| 118 | +advances the offset, and repeats the process until the end of the file (EOF) is detected. |
| 119 | + |
| 120 | +Once downloading is successfully completed, the node verifies the firmware file and applies the update. |
| 121 | +After that, the node restarts and runs the new firmware. |
0 commit comments