source: azure_iot_hub_riscv/trunk/asp_baseplatform/gdic/ble_shield2.1/utility/dfu.c@ 453

Last change on this file since 453 was 453, checked in by coas-nagasima, 4 years ago

ファイルを追加

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 11.1 KB
Line 
1#include <lib_aci.h>
2#include <ble_assert.h>
3#include <dfu.h>
4
5static uint8_t state = ST_ANY;
6static uint32_t firmware_len;
7static uint16_t notify_every;
8static uint32_t bytes_received;
9static uint16_t packets_received;
10
11static void dfu_notify (aci_state_t *aci_state);
12static bool dfu_send (aci_state_t *aci_state, uint8_t *buffer, uint8_t buffer_len);
13
14static uint8_t dfu_data_pkt_handle (aci_state_t *aci_state, aci_evt_t *aci_evt);
15static uint8_t dfu_init_pkt_handle (aci_state_t *aci_state, aci_evt_t *aci_evt);
16static uint8_t dfu_image_activate (aci_state_t *aci_state, aci_evt_t *aci_evt);
17static uint8_t dfu_image_size_set (aci_state_t *aci_state, aci_evt_t *aci_evt);
18static uint8_t dfu_image_validate (aci_state_t *aci_state, aci_evt_t *aci_evt);
19
20#define DEBUG
21
22enum
23{
24 OP_CODE_START_DFU = 1, /**< Value of the Op code field for 'Start DFU' command.*/
25 OP_CODE_RECEIVE_INIT = 2, /**< Value of the Op code field for 'Initialize DFU parameters' command.*/
26 OP_CODE_RECEIVE_FW = 3, /**< Value of the Op code field for 'Receive firmware image' command.*/
27 OP_CODE_VALIDATE = 4, /**< Value of the Op code field for 'Validate firmware' command.*/
28 OP_CODE_ACTIVATE_N_RESET = 5, /**< Value of the Op code field for 'Activate & Reset' command.*/
29 OP_CODE_SYS_RESET = 6, /**< Value of the Op code field for 'Reset System' command.*/
30 OP_CODE_IMAGE_SIZE_REQ = 7, /**< Value of the Op code field for 'Report received image size' command.*/
31 OP_CODE_PKT_RCPT_NOTIF_REQ = 8, /**< Value of the Op code field for 'Request packet receipt notification.*/
32 OP_CODE_RESPONSE = 16, /**< Value of the Op code field for 'Response.*/
33 OP_CODE_PKT_RCPT_NOTIF = 17 /**< Value of the Op code field for 'Packets Receipt Notification'.*/
34};
35
36/* State transitions */
37
38static uint8_t dfu_begin_init (aci_state_t *aci_state, aci_evt_t *aci_evt)
39{
40 ble_assert (aci_state != NULL);
41 ble_assert (aci_evt != NULL);
42 ble_assert (state == ST_RDY);
43
44 return ST_RX_INIT_PKT;
45}
46
47static uint8_t dfu_begin_transfer (aci_state_t *aci_state, aci_evt_t *aci_evt)
48{
49 ble_assert (aci_state != NULL);
50 ble_assert (aci_evt != NULL);
51 ble_assert ((state == ST_RDY) | (state == ST_RX_INIT_PKT));
52
53 return ST_RX_DATA_PKT;
54}
55
56static uint8_t dfu_data_pkt_handle (aci_state_t *aci_state, aci_evt_t *aci_evt)
57{
58 static uint8_t response[3] = {OP_CODE_RESPONSE, BLE_DFU_RECEIVE_APP_PROCEDURE, BLE_DFU_RESP_VAL_SUCCESS};
59
60 ble_assert (aci_state != NULL);
61 ble_assert (aci_evt != NULL);
62 ble_assert (state == ST_RX_DATA_PKT);
63
64 bytes_received += aci_evt->len-2;
65 packets_received++;
66
67 /* Send notification for every N packets */
68 if (0 == (packets_received % notify_every))
69 {
70 #ifdef DEBUG
71 Serial.println(F(" Writing notification"));
72 #endif DEBUG
73
74 dfu_notify (aci_state);
75 }
76
77 if (firmware_len == bytes_received)
78 {
79 #ifdef DEBUG
80 Serial.print(F(" All bytes received ("));
81 Serial.print(bytes_received, DEC);
82 Serial.println(F(")"));
83 #endif
84
85 dfu_send (aci_state, response, 3);
86 }
87
88 return ST_RX_DATA_PKT;
89}
90
91static uint8_t dfu_image_size_set(aci_state_t *aci_state, aci_evt_t *aci_evt)
92{
93 static uint8_t response[3] = {OP_CODE_RESPONSE, BLE_DFU_START_PROCEDURE, BLE_DFU_RESP_VAL_SUCCESS};
94
95 ble_assert (aci_state != NULL);
96 ble_assert (aci_evt != NULL);
97 ble_assert (state == ST_IDLE);
98
99 firmware_len = (uint32_t)aci_evt->params.data_received.rx_data.aci_data[3] << 24 |
100 (uint32_t)aci_evt->params.data_received.rx_data.aci_data[2] << 16 |
101 (uint32_t)aci_evt->params.data_received.rx_data.aci_data[1] << 8 |
102 (uint32_t)aci_evt->params.data_received.rx_data.aci_data[0];
103
104 #ifdef DEBUG
105 Serial.print(F("Received length: "));
106 Serial.println(firmware_len, DEC);
107 #endif
108
109 /* Write response */
110 dfu_send (aci_state, response, 3);
111
112 return ST_RDY;
113}
114
115static uint8_t dfu_image_activate(aci_state_t *aci_state, aci_evt_t *aci_evt)
116{
117 ble_assert (aci_state != NULL);
118 ble_assert (aci_evt != NULL);
119 ble_assert (state == ST_FW_VALID);
120
121 lib_aci_disconnect(aci_state, ACI_REASON_TERMINATE);
122
123 return ST_FW_VALID;
124}
125
126static uint8_t dfu_init_pkt_handle (aci_state_t *aci_state, aci_evt_t *aci_evt)
127{
128 ble_assert (aci_state != NULL);
129 ble_assert (aci_evt != NULL);
130 ble_assert (state == ST_RX_INIT_PKT);
131
132 return ST_RX_INIT_PKT;
133}
134
135static uint8_t dfu_image_validate (aci_state_t *aci_state, aci_evt_t *aci_evt)
136{
137 uint8_t new_state;
138 uint8_t response[3] = {OP_CODE_RESPONSE, BLE_DFU_VALIDATE_PROCEDURE};
139
140 ble_assert (aci_state != NULL);
141 ble_assert (aci_evt != NULL);
142 ble_assert (state == ST_RX_DATA_PKT);
143
144 /* TODO: Implement CRC validation */
145 if (bytes_received == firmware_len)
146 {
147 #ifdef DEBUG
148 Serial.println(F(" Validation successful"));
149 #endif
150 /* Completed successfully */
151 response[3] = BLE_DFU_RESP_VAL_SUCCESS;
152 dfu_send(aci_state, response, 3);
153
154 state = ST_FW_VALID;
155 }
156 else
157 {
158 #ifdef DEBUG
159 Serial.println(F(" Validation failed"));
160 #endif
161
162 /* CRC error */
163 response[3] = BLE_DFU_RESP_VAL_CRC_ERROR;
164 dfu_send(aci_state, response, 3);
165
166 state = ST_FW_VALID;
167 }
168
169 return state;
170}
171
172static uint8_t dfu_notification_set (aci_state_t *aci_state, aci_evt_t *aci_evt)
173{
174 ble_assert (aci_state != NULL);
175 ble_assert (aci_evt != NULL);
176
177 notify_every = (uint16_t)aci_evt->params.data_received.rx_data.aci_data[2] << 8 |
178 (uint16_t)aci_evt->params.data_received.rx_data.aci_data[1];
179
180
181
182 #ifdef DEBUG
183 Serial.print(F(" Remote device requested notification every "));
184 Serial.print(notify_every, DEC);
185 Serial.println(F(" packets"));
186 #endif
187
188 return state;
189}
190
191dfu_transition_t trans[] = {
192 { ST_IDLE, BLE_DFU_PACKET_WRITE, &dfu_image_size_set },
193 { ST_RDY, BLE_DFU_RECEIVE_INIT_DATA, &dfu_begin_init },
194 { ST_RX_INIT_PKT, BLE_DFU_PACKET_WRITE, &dfu_init_pkt_handle },
195 { ST_RDY, BLE_DFU_RECEIVE_APP_DATA, &dfu_begin_transfer },
196 { ST_RX_INIT_PKT, BLE_DFU_RECEIVE_APP_DATA, &dfu_begin_transfer },
197 { ST_RX_DATA_PKT, BLE_DFU_PACKET_WRITE, &dfu_data_pkt_handle },
198 { ST_RX_DATA_PKT, BLE_DFU_VALIDATE, &dfu_image_validate },
199 { ST_FW_VALID, BLE_DFU_SYS_RESET, &dfu_image_activate },
200 { ST_FW_VALID, BLE_DFU_ACTIVATE_N_RESET, &dfu_image_activate },
201 { ST_ANY, BLE_DFU_PKT_RCPT_NOTIF_ENABLED, &dfu_notification_set },
202 { ST_ANY, BLE_DFU_PKT_RCPT_NOTIF_DISABLED, &dfu_notification_set }
203};
204
205#define TRANS_COUNT (sizeof(trans)/sizeof(*trans))
206
207/* Write receive notification */
208static void dfu_notify (aci_state_t *aci_state)
209{
210 uint8_t response[6] = {OP_CODE_PKT_RCPT_NOTIF,
211 0,
212 (uint8_t) bytes_received,
213 (uint8_t) (bytes_received >> 8),
214 (uint8_t) (bytes_received >> 16),
215 (uint8_t) (bytes_received >> 24)
216 };
217
218 ble_assert (aci_state != NULL);
219
220 dfu_send (aci_state, response, 6);
221}
222
223static bool dfu_send (aci_state_t *aci_state, uint8_t *buffer, uint8_t buffer_len)
224{
225 bool status = false;
226
227 ble_assert (aci_state != NULL);
228 ble_assert (buffer != NULL);
229
230 if (lib_aci_is_pipe_available(aci_state,
231 PIPE_DEVICE_FIRMWARE_UPDATE_BLE_SERVICE_DFU_CONTROL_POINT_TX) &&
232 (aci_state->data_credit_available >= 1))
233 {
234 status = lib_aci_send_data(PIPE_DEVICE_FIRMWARE_UPDATE_BLE_SERVICE_DFU_CONTROL_POINT_TX,
235 buffer,
236 buffer_len);
237 if (status)
238 {
239 aci_state->data_credit_available--;
240 }
241 }
242
243 return status;
244}
245
246static uint8_t dfu_get_event (aci_state_t *aci_state, aci_evt_t *aci_evt)
247{
248 uint8_t event;
249
250 ble_assert (aci_state != NULL);
251 ble_assert (aci_evt != NULL);
252
253 switch (aci_evt->params.data_received.rx_data.pipe_number)
254 {
255 case PIPE_DEVICE_FIRMWARE_UPDATE_BLE_SERVICE_DFU_PACKET_RX:
256 event = BLE_DFU_PACKET_WRITE;
257 break;
258
259 case PIPE_DEVICE_FIRMWARE_UPDATE_BLE_SERVICE_DFU_CONTROL_POINT_RX_ACK_AUTO:
260 #ifdef DEBUG
261 Serial.print(F("PIPE_DEVICE_FIRMWARE_UPDATE_BLE_SERVICE_DFU_CONTROL_POINT_RX_ACK_AUTO. Opcode: "));
262 Serial.println(aci_evt->params.data_received.rx_data.aci_data[0], DEC);
263 #endif
264
265 switch (aci_evt->params.data_received.rx_data.aci_data[0])
266 {
267 /* Start DFU */
268 case OP_CODE_START_DFU:
269 event = BLE_DFU_START;
270 break;
271
272 /* Initialize DFU parameters */
273 case OP_CODE_RECEIVE_INIT:
274 event = BLE_DFU_RECEIVE_INIT_DATA;
275 break;
276
277 /* Receive firmware image */
278 case OP_CODE_RECEIVE_FW:
279 event = BLE_DFU_RECEIVE_APP_DATA;
280 break;
281
282 /* Validate firmware image */
283 case OP_CODE_VALIDATE:
284 event = BLE_DFU_VALIDATE;
285 break;
286
287 /* Activate image and reset */
288 case OP_CODE_ACTIVATE_N_RESET:
289 event = BLE_DFU_ACTIVATE_N_RESET;
290 break;
291
292 /* Reset system */
293 case OP_CODE_SYS_RESET:
294 event = BLE_DFU_SYS_RESET;
295 break;
296
297 /* Report received image size */
298 case OP_CODE_IMAGE_SIZE_REQ:
299 event = BLE_DFU_BYTES_RECEIVED_SEND;
300 break;
301
302 /* Packet receipt notification request */
303 case OP_CODE_PKT_RCPT_NOTIF_REQ:
304 if (aci_evt->params.data_received.rx_data.aci_data[1] == 0)
305 {
306 event = BLE_DFU_PKT_RCPT_NOTIF_DISABLED;
307 }
308 else
309 {
310 event = BLE_DFU_PKT_RCPT_NOTIF_ENABLED;
311 }
312 break;
313
314 default:
315 event = EV_ANY;
316 break;
317 }
318 break;
319
320 default:
321 event = EV_ANY;
322 }
323 return event;
324}
325
326void dfu_initialize (void)
327{
328 #ifdef DEBUG
329 Serial.println(F(" Initializing DFU state machine"));
330 #endif
331
332 if (true)
333 {
334 state = ST_IDLE;
335 }
336 else
337 {
338 state = ST_INIT_ERROR;
339 }
340}
341
342void dfu_update (aci_state_t *aci_state, aci_evt_t *aci_evt)
343{
344 hal_aci_evt_t aci_data;
345 uint8_t event;
346 uint8_t i;
347
348 ble_assert (aci_state != NULL);
349 ble_assert (aci_evt != NULL);
350
351 event = dfu_get_event(aci_state, aci_evt);
352
353 for (i = 0; i < TRANS_COUNT; i++)
354 {
355 if ((state == trans[i].st) || (ST_ANY == trans[i].st))
356 {
357 if ((event == trans[i].ev) || (EV_ANY == trans[i].ev))
358 {
359 #ifdef DEBUG
360 Serial.print(F("Transition (state = "));
361 Serial.print(trans[i].st);
362 Serial.print(F(", event = "));
363 Serial.print(trans[i].ev);
364 Serial.println(F(")"));
365 #endif
366
367 state = (trans[i].fn)(aci_state, aci_evt);
368 return;
369 }
370 }
371 }
372
373 /* Unhandled event */
374 ble_assert(false);
375}
Note: See TracBrowser for help on using the repository browser.