1 /***************************************************************************
2 * Copyright (c) 2024 Microsoft Corporation
3 *
4 * This program and the accompanying materials are made available under the
5 * terms of the MIT License which is available at
6 * https://opensource.org/licenses/MIT.
7 *
8 * SPDX-License-Identifier: MIT
9 **************************************************************************/
10
11 /**************************************************************************/
12 /**************************************************************************/
13 /** */
14 /** USBX Component */
15 /** */
16 /** Device DFU Class */
17 /** */
18 /**************************************************************************/
19 /**************************************************************************/
20
21 #define UX_SOURCE_CODE
22
23
24 /* Include necessary system files. */
25
26 #include "ux_api.h"
27 #include "ux_device_class_dfu.h"
28 #include "ux_device_stack.h"
29
30
31 #if UX_DEVICE_CLASS_DFU_STATUS_MODE == 1
32 static inline VOID _ux_device_class_dfu_status_get(UX_SLAVE_CLASS_DFU *,
33 UX_SLAVE_TRANSFER *, UCHAR, UCHAR, UCHAR, UCHAR);
34 #endif
35
36
37 /**************************************************************************/
38 /* */
39 /* FUNCTION RELEASE */
40 /* */
41 /* _ux_device_class_dfu_control_request PORTABLE C */
42 /* 6.1.12 */
43 /* AUTHOR */
44 /* */
45 /* Chaoqiong Xiao, Microsoft Corporation */
46 /* */
47 /* DESCRIPTION */
48 /* */
49 /* This function manages the based sent by the host on the control */
50 /* endpoints with a CLASS or VENDOR SPECIFIC type. */
51 /* */
52 /* INPUT */
53 /* */
54 /* dfu Pointer to dfu class */
55 /* */
56 /* OUTPUT */
57 /* */
58 /* None */
59 /* */
60 /* CALLS */
61 /* */
62 /* _ux_device_stack_endpoint_stall Endpoint stall */
63 /* _ux_device_stack_transfer_request Transfer request */
64 /* */
65 /* CALLED BY */
66 /* */
67 /* DFU Class */
68 /* */
69 /* RELEASE HISTORY */
70 /* */
71 /* DATE NAME DESCRIPTION */
72 /* */
73 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
74 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
75 /* used UX prefix to refer to */
76 /* TX symbols instead of using */
77 /* them directly, */
78 /* resulting in version 6.1 */
79 /* 04-02-2021 Chaoqiong Xiao Modified comment(s), */
80 /* added DFU_UPLOAD support, */
81 /* removed block count (it's */
82 /* from host request wValue), */
83 /* resulting in version 6.1.6 */
84 /* 10-15-2021 Chaoqiong Xiao Modified comment(s), */
85 /* fixed compile warning, */
86 /* resulting in version 6.1.9 */
87 /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */
88 /* added UPLOAD length check, */
89 /* added standalone support, */
90 /* resulting in version 6.1.10 */
91 /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */
92 /* checked r/w callback status,*/
93 /* resulting in version 6.1.11 */
94 /* 07-29-2022 Chaoqiong Xiao Modified comment(s), */
95 /* fixed parameter/variable */
96 /* names conflict C++ keyword, */
97 /* added UPLOAD length check */
98 /* in _UPLOAD_IDLE state, */
99 /* added DNLOAD REQ */
100 /* validation, */
101 /* resulting in version 6.1.12 */
102 /* */
103 /**************************************************************************/
_ux_device_class_dfu_control_request(UX_SLAVE_CLASS_COMMAND * command)104 UINT _ux_device_class_dfu_control_request(UX_SLAVE_CLASS_COMMAND *command)
105 {
106
107 UX_SLAVE_TRANSFER *transfer_request;
108 UX_SLAVE_DEVICE *device;
109 UX_SLAVE_CLASS *class_ptr;
110 UX_SLAVE_CLASS_DFU *dfu;
111
112 ULONG request;
113 ULONG request_type;
114 ULONG request_value;
115 ULONG request_length;
116 ULONG actual_length;
117 UINT status;
118 #if defined(UX_DEVICE_CLASS_DFU_CUSTOM_REQUEST_ENABLE) || (UX_DEVICE_CLASS_DFU_STATUS_MODE != 1)
119 ULONG media_status;
120 #endif
121
122
123 /* Get the pointer to the device. */
124 device = &_ux_system_slave -> ux_system_slave_device;
125
126 /* Get the class container. */
127 class_ptr = command -> ux_slave_class_command_class_ptr;
128
129 /* Get the storage instance from this class container. */
130 dfu = (UX_SLAVE_CLASS_DFU *) class_ptr -> ux_slave_class_instance;
131
132 /* Get the pointer to the transfer request associated with the control endpoint. */
133 transfer_request = &device -> ux_slave_device_control_endpoint.ux_slave_endpoint_transfer_request;
134
135 #ifdef UX_DEVICE_CLASS_DFU_CUSTOM_REQUEST_ENABLE
136 if (dfu -> ux_device_class_dfu_custom_request)
137 {
138
139 /* The status simply tells us if the registered callback handled the
140 request - if there was an issue processing the request, it would've
141 stalled the control endpoint, notifying the host (and not us). */
142 media_status = dfu -> ux_device_class_dfu_custom_request(dfu, transfer_request);
143
144 /* Custom request handled. */
145 if (media_status == UX_SUCCESS)
146 return(media_status);
147
148 /* Try to handle with standard handler. */
149 }
150 #endif
151
152 /* Extract all necessary fields of the request. */
153 request = *(transfer_request -> ux_slave_transfer_request_setup + UX_SETUP_REQUEST);
154 request_type = *(transfer_request -> ux_slave_transfer_request_setup + UX_SETUP_REQUEST_TYPE);
155
156 /* Pickup the request wValue. */
157 request_value = _ux_utility_short_get(transfer_request -> ux_slave_transfer_request_setup + UX_SETUP_VALUE);
158
159 /* Pickup the request wLength. */
160 request_length = _ux_utility_short_get(transfer_request -> ux_slave_transfer_request_setup + UX_SETUP_LENGTH);
161
162 /* What state are we in ? */
163 switch (_ux_system_slave -> ux_system_slave_device_dfu_state_machine)
164 {
165
166 case UX_SYSTEM_DFU_STATE_APP_IDLE :
167
168
169 /* Here we process only the request we can accept in the APP IDLE state. */
170 switch (request)
171 {
172
173 case UX_SLAVE_CLASS_DFU_COMMAND_DETACH :
174
175 /* The host is asking for a Detach and switch to the DFU mode. Either we force the reset here or
176 we wait for a specified timer. If there is no reset while this timer is running we abandon
177 the DFU Detach.*/
178 if (_ux_system_slave -> ux_system_slave_device_dfu_capabilities & UX_SLAVE_CLASS_DFU_CAPABILITY_WILL_DETACH)
179 {
180
181 /* Wake up the DFU thread and send a detach request.. */
182 _ux_device_class_dfu_event_flags_set(dfu, UX_DEVICE_CLASS_DFU_THREAD_EVENT_DISCONNECT);
183 }
184 else
185 {
186
187 /* We expect the host to issue a reset. Arm a timer in the DFU thread. */
188 _ux_device_class_dfu_event_flags_set(dfu, UX_DEVICE_CLASS_DFU_THREAD_EVENT_WAIT_RESET);
189 }
190
191 /* We can switch dfu state machine. */
192 _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SYSTEM_DFU_STATE_APP_DETACH;
193
194 break;
195
196 case UX_SLAVE_CLASS_DFU_COMMAND_GET_STATUS :
197
198 #if UX_DEVICE_CLASS_DFU_STATUS_MODE == 1
199 _ux_device_class_dfu_status_get(dfu, transfer_request, UX_FALSE, 0, 0, 0);
200 #else
201 /* Fill the status data payload. First with status. */
202 *transfer_request -> ux_slave_transfer_request_data_pointer = (UCHAR) dfu -> ux_slave_class_dfu_status;
203
204 /* Poll time out value is set to 1ms. */
205 *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT) = UX_DW0(UX_DEVICE_CLASS_DFU_STATUS_POLLTIMEOUT);
206 *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT + 1) = UX_DW1(UX_DEVICE_CLASS_DFU_STATUS_POLLTIMEOUT);
207 *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT + 2) = UX_DW2(UX_DEVICE_CLASS_DFU_STATUS_POLLTIMEOUT);
208
209 /* Next state. */
210 *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_STATE) = (UCHAR) _ux_system_slave -> ux_system_slave_device_dfu_state_machine;
211
212 /* String index set to 0. */
213 *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_STRING) = 0;
214 #endif
215
216 /* We have a request to obtain the status of the DFU instance. */
217 _ux_device_stack_transfer_request(transfer_request, UX_SLAVE_CLASS_DFU_GET_STATUS_LENGTH, UX_SLAVE_CLASS_DFU_GET_STATUS_LENGTH);
218
219 break;
220
221 case UX_SLAVE_CLASS_DFU_COMMAND_GET_STATE :
222
223 /* Fill the status data payload. First with state. */
224 *transfer_request -> ux_slave_transfer_request_data_pointer = (UCHAR) _ux_system_slave -> ux_system_slave_device_dfu_state_machine;
225
226 /* We have a request to obtain the status of the DFU instance. */
227 _ux_device_stack_transfer_request(transfer_request, UX_SLAVE_CLASS_DFU_GET_STATE_LENGTH, UX_SLAVE_CLASS_DFU_GET_STATE_LENGTH);
228
229 break;
230
231 default:
232
233 /* Unknown function. Stall the endpoint. */
234 _ux_device_stack_endpoint_stall(&device -> ux_slave_device_control_endpoint);
235 break;
236 }
237
238 break;
239
240 case UX_SYSTEM_DFU_STATE_APP_DETACH :
241
242 /* Here we process only the request we can accept in the APP DETACH state. */
243 switch (request)
244 {
245
246 case UX_SLAVE_CLASS_DFU_COMMAND_GET_STATUS :
247
248 #if UX_DEVICE_CLASS_DFU_STATUS_MODE == 1
249 _ux_device_class_dfu_status_get(dfu, transfer_request, UX_FALSE, 0, 0, 0);
250 #else
251
252 /* Fill the status data payload. First with status. */
253 *transfer_request -> ux_slave_transfer_request_data_pointer = (UCHAR) dfu -> ux_slave_class_dfu_status;
254
255 /* Poll time out value is set to 1ms. */
256 *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT) = UX_DW0(UX_DEVICE_CLASS_DFU_STATUS_POLLTIMEOUT);
257 *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT + 1) = UX_DW1(UX_DEVICE_CLASS_DFU_STATUS_POLLTIMEOUT);
258 *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT + 2) = UX_DW2(UX_DEVICE_CLASS_DFU_STATUS_POLLTIMEOUT);
259
260 /* Next state. */
261 *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_STATE) = (UCHAR) _ux_system_slave -> ux_system_slave_device_dfu_state_machine;
262
263 /* String index set to 0. */
264 *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_STRING) = 0;
265 #endif
266
267 /* We have a request to obtain the status of the DFU instance. */
268 _ux_device_stack_transfer_request(transfer_request, UX_SLAVE_CLASS_DFU_GET_STATUS_LENGTH, UX_SLAVE_CLASS_DFU_GET_STATUS_LENGTH);
269
270 break;
271
272 case UX_SLAVE_CLASS_DFU_COMMAND_GET_STATE :
273
274 /* Fill the status data payload. First with state. */
275 *transfer_request -> ux_slave_transfer_request_data_pointer = (UCHAR) _ux_system_slave -> ux_system_slave_device_dfu_state_machine;
276
277 /* We have a request to obtain the status of the DFU instance. */
278 _ux_device_stack_transfer_request(transfer_request, UX_SLAVE_CLASS_DFU_GET_STATE_LENGTH, UX_SLAVE_CLASS_DFU_GET_STATE_LENGTH);
279
280 break;
281
282 default:
283
284 /* Unknown function. Stall the endpoint. */
285 _ux_device_stack_endpoint_stall(&device -> ux_slave_device_control_endpoint);
286 break;
287 }
288
289 break;
290
291 case UX_SYSTEM_DFU_STATE_DFU_IDLE :
292
293 /* Here we process only the request we can accept in the DFU mode IDLE state. */
294 switch (request)
295 {
296
297 case UX_SLAVE_CLASS_DFU_COMMAND_DOWNLOAD :
298
299 /* Command verify: check bmRequestType and data length. */
300 if ((request_type != UX_DEVICE_CLASS_DFU_REQTYPE_INTERFACE_SET) ||
301 (request_length != transfer_request -> ux_slave_transfer_request_actual_length))
302 {
303
304 /* Zero length download is not accepted. Stall the endpoint. */
305 _ux_device_stack_endpoint_stall(&device -> ux_slave_device_control_endpoint);
306
307 /* In the system, state the DFU state machine to dfu ERROR. */
308 _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SYSTEM_DFU_STATE_DFU_ERROR;
309 }
310
311 /* We received a DOWNLOAD command. Check the length field of the request. It cannot be 0. */
312 else if (request_length == 0)
313 {
314
315 /* Zero length download is not accepted. Stall the endpoint. */
316 _ux_device_stack_endpoint_stall(&device -> ux_slave_device_control_endpoint);
317
318 /* In the system, state the DFU state machine to dfu ERROR. */
319 _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SYSTEM_DFU_STATE_DFU_ERROR;
320
321 }
322 else
323 {
324
325 /* Have we declared a DOWNLOAD possible in our device framework ? */
326 if (_ux_system_slave -> ux_system_slave_device_dfu_capabilities & UX_SLAVE_CLASS_DFU_CAPABILITY_CAN_DOWNLOAD)
327 {
328
329 /* Send a notification to the application. Begin of transfer. */
330 dfu -> ux_slave_class_dfu_notify(dfu, UX_SLAVE_CLASS_DFU_NOTIFICATION_BEGIN_DOWNLOAD);
331
332 /* Write the first block to the firmware. */
333 status = dfu -> ux_slave_class_dfu_write(dfu, request_value,
334 transfer_request -> ux_slave_transfer_request_data_pointer,
335 request_length,
336 &actual_length);
337
338 /* Application can actively reject and set error state. */
339 if (status != UX_SUCCESS)
340 {
341 _ux_device_stack_endpoint_stall(&device -> ux_slave_device_control_endpoint);
342 _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SYSTEM_DFU_STATE_DFU_ERROR;
343 break;
344 }
345
346 /* In the system, state the DFU state machine to dfu DOWNLOAD SYNC. */
347 _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SYSTEM_DFU_STATE_DFU_DNLOAD_SYNC;
348
349 }
350 else
351 {
352
353 /* Download is not accepted. Stall the endpoint. */
354 _ux_device_stack_endpoint_stall(&device -> ux_slave_device_control_endpoint);
355
356 /* In the system, state the DFU state machine to dfu ERROR. */
357 _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SYSTEM_DFU_STATE_DFU_ERROR;
358
359 }
360
361 }
362 break;
363
364 case UX_SLAVE_CLASS_DFU_COMMAND_ABORT :
365
366 /* Send a notification to the application. */
367 dfu -> ux_slave_class_dfu_notify(dfu, UX_SLAVE_CLASS_DFU_NOTIFICATION_ABORT_DOWNLOAD);
368
369 /* In the system, state the DFU state machine to dfu IDLE. */
370 _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SYSTEM_DFU_STATE_DFU_IDLE;
371
372 break;
373
374 case UX_SLAVE_CLASS_DFU_COMMAND_GET_STATUS :
375
376 #if UX_DEVICE_CLASS_DFU_STATUS_MODE == 1
377 _ux_device_class_dfu_status_get(dfu, transfer_request, UX_FALSE, 0, 0, 0);
378 #else
379
380 /* Fill the status data payload. First with status. */
381 *transfer_request -> ux_slave_transfer_request_data_pointer = (UCHAR) dfu -> ux_slave_class_dfu_status;
382
383 /* Poll time out value is set to 1ms. */
384 *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT) = UX_DW0(UX_DEVICE_CLASS_DFU_STATUS_POLLTIMEOUT);
385 *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT + 1) = UX_DW1(UX_DEVICE_CLASS_DFU_STATUS_POLLTIMEOUT);
386 *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT + 2) = UX_DW2(UX_DEVICE_CLASS_DFU_STATUS_POLLTIMEOUT);
387
388 /* Next state. */
389 *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_STATE) = (UCHAR) UX_SYSTEM_DFU_STATE_DFU_IDLE;
390
391 /* String index set to 0. */
392 *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_STRING) = 0;
393 #endif
394
395 /* We have a request to obtain the status of the DFU instance. */
396 _ux_device_stack_transfer_request(transfer_request, UX_SLAVE_CLASS_DFU_GET_STATUS_LENGTH, UX_SLAVE_CLASS_DFU_GET_STATUS_LENGTH);
397
398 break;
399
400 case UX_SLAVE_CLASS_DFU_COMMAND_GET_STATE :
401
402 /* Fill the status data payload. First with state. */
403 *transfer_request -> ux_slave_transfer_request_data_pointer = (UCHAR) _ux_system_slave -> ux_system_slave_device_dfu_state_machine;
404
405 /* We have a request to obtain the status of the DFU instance. */
406 _ux_device_stack_transfer_request(transfer_request, UX_SLAVE_CLASS_DFU_GET_STATE_LENGTH, UX_SLAVE_CLASS_DFU_GET_STATE_LENGTH);
407
408 break;
409
410 #ifndef UX_DEVICE_CLASS_DFU_UPLOAD_DISABLE
411 case UX_SLAVE_CLASS_DFU_COMMAND_UPLOAD:
412
413 /* bitCanUpload != 1, or length = 0, or length > wTransferSize (we can support max of control buffer size). */
414 if (!(_ux_system_slave -> ux_system_slave_device_dfu_capabilities & UX_SLAVE_CLASS_DFU_CAPABILITY_CAN_UPLOAD) ||
415 (request_length == 0) ||
416 (request_length > UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH))
417 {
418 _ux_device_stack_endpoint_stall(&device -> ux_slave_device_control_endpoint);
419
420 /* In the system, state the DFU state machine to dfu ERROR. */
421 _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SYSTEM_DFU_STATE_DFU_ERROR;
422
423 break;
424 }
425
426 /* bitCanUpload = 1. */
427
428 /* Send a notification to the application. Begin of transfer. */
429 dfu -> ux_slave_class_dfu_notify(dfu, UX_SLAVE_CLASS_DFU_NOTIFICATION_BEGIN_UPLOAD);
430
431 /* Read the first block to the firmware. */
432 status = dfu -> ux_slave_class_dfu_read(dfu, request_value,
433 transfer_request -> ux_slave_transfer_request_data_pointer,
434 request_length,
435 &actual_length);
436
437 /* Application can actively reject and set error state. */
438 if (status != UX_SUCCESS)
439 {
440 _ux_device_stack_endpoint_stall(&device -> ux_slave_device_control_endpoint);
441 _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SYSTEM_DFU_STATE_DFU_ERROR;
442 break;
443 }
444
445 /* In the system, state the DFU state machine to dfu UPLOAD IDLE. */
446 _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SYSTEM_DFU_STATE_DFU_UPLOAD_IDLE;
447
448 /* We have a request to upload DFU firmware block. */
449 _ux_device_stack_transfer_request(transfer_request, actual_length, request_length);
450
451 break;
452 #endif
453
454 default:
455
456 /* Unknown function. Stall the endpoint. */
457 _ux_device_stack_endpoint_stall(&device -> ux_slave_device_control_endpoint);
458
459 /* In the system, state the DFU state machine to dfu ERROR. */
460 _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SYSTEM_DFU_STATE_DFU_ERROR;
461
462 break;
463 }
464
465 break;
466
467
468 case UX_SYSTEM_DFU_STATE_DFU_DNLOAD_SYNC :
469
470 /* Here we process only the request we can accept in the DFU mode DOWNLOAD state. */
471 switch (request)
472 {
473
474 case UX_SLAVE_CLASS_DFU_COMMAND_GET_STATUS :
475
476 #if UX_DEVICE_CLASS_DFU_STATUS_MODE == 1
477 _ux_device_class_dfu_status_get(dfu, transfer_request, UX_TRUE,
478 UX_SLAVE_CLASS_DFU_STATUS_STATE_DFU_DNLOAD_IDLE,
479 UX_SLAVE_CLASS_DFU_STATUS_STATE_DFU_DNBUSY,
480 UX_SLAVE_CLASS_DFU_STATUS_STATE_DFU_ERROR);
481 #else
482
483 /* Check if the device is still buys performing the write. Write could be delayed. */
484 dfu -> ux_slave_class_dfu_get_status(dfu, &media_status);
485
486 /* Check status of device. */
487 switch (media_status)
488 {
489
490 case UX_SLAVE_CLASS_DFU_MEDIA_STATUS_OK :
491
492 /* Set the next state for idle and no error status. */
493 dfu -> ux_slave_class_dfu_status = UX_SLAVE_CLASS_DFU_STATUS_OK ;
494 _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SLAVE_CLASS_DFU_STATUS_STATE_DFU_DNLOAD_IDLE;
495 break;
496
497 case UX_SLAVE_CLASS_DFU_MEDIA_STATUS_BUSY :
498
499 /* Set the next state for busy but no error status. */
500 dfu -> ux_slave_class_dfu_status = UX_SLAVE_CLASS_DFU_STATUS_OK ;
501 _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SLAVE_CLASS_DFU_STATUS_STATE_DFU_DNBUSY;
502 break;
503
504 case UX_SLAVE_CLASS_DFU_MEDIA_STATUS_ERROR :
505
506 /* Set the next state for busy and error status. */
507 dfu -> ux_slave_class_dfu_status = UX_SLAVE_CLASS_DFU_STATUS_ERROR_WRITE ;
508 _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SLAVE_CLASS_DFU_STATUS_STATE_DFU_ERROR;
509 break;
510
511 }
512
513 /* Fill the status data payload. First with status. */
514 *transfer_request -> ux_slave_transfer_request_data_pointer = (UCHAR) dfu -> ux_slave_class_dfu_status;
515
516 /* Poll time out value is set to 1ms. */
517 *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT) = UX_DW0(UX_DEVICE_CLASS_DFU_STATUS_POLLTIMEOUT);
518 *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT + 1) = UX_DW1(UX_DEVICE_CLASS_DFU_STATUS_POLLTIMEOUT);
519 *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT + 2) = UX_DW2(UX_DEVICE_CLASS_DFU_STATUS_POLLTIMEOUT);
520
521 /* Next state. */
522 *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_STATE) = (UCHAR) _ux_system_slave -> ux_system_slave_device_dfu_state_machine;
523
524 /* String index set to 0. */
525 *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_STRING) = 0;
526 #endif
527
528 /* We have a request to obtain the status of the DFU instance. */
529 _ux_device_stack_transfer_request(transfer_request, UX_SLAVE_CLASS_DFU_GET_STATUS_LENGTH, UX_SLAVE_CLASS_DFU_GET_STATUS_LENGTH);
530
531 break;
532
533 case UX_SLAVE_CLASS_DFU_COMMAND_GET_STATE :
534
535 /* Fill the status data payload. First with state. */
536 *transfer_request -> ux_slave_transfer_request_data_pointer = (UCHAR) _ux_system_slave -> ux_system_slave_device_dfu_state_machine;
537
538 /* We have a request to obtain the status of the DFU instance. */
539 _ux_device_stack_transfer_request(transfer_request, UX_SLAVE_CLASS_DFU_GET_STATE_LENGTH, UX_SLAVE_CLASS_DFU_GET_STATE_LENGTH);
540
541 break;
542
543 default:
544
545 /* Unknown function. Stall the endpoint. */
546 _ux_device_stack_endpoint_stall(&device -> ux_slave_device_control_endpoint);
547
548 /* In the system, state the DFU state machine to dfu ERROR. */
549 _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SYSTEM_DFU_STATE_DFU_ERROR;
550
551 break;
552 }
553
554 break;
555
556 case UX_SLAVE_CLASS_DFU_STATUS_STATE_DFU_DNLOAD_IDLE :
557
558 /* Here we process only the request we can accept in the DFU mode DNLOAD state. */
559 switch (request)
560 {
561
562 case UX_SLAVE_CLASS_DFU_COMMAND_DOWNLOAD :
563
564 /* Command verify: check bmRequestType and data length. */
565 if ((request_type != UX_DEVICE_CLASS_DFU_REQTYPE_INTERFACE_SET) ||
566 (request_length != transfer_request -> ux_slave_transfer_request_actual_length))
567 {
568
569 /* Zero length download is not accepted. Stall the endpoint. */
570 _ux_device_stack_endpoint_stall(&device -> ux_slave_device_control_endpoint);
571
572 /* In the system, state the DFU state machine to dfu ERROR. */
573 _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SYSTEM_DFU_STATE_DFU_ERROR;
574 }
575
576 /* We received a DOWNLOAD command. Check the length field of the request. If it is 0,
577 we are done with the transfer. */
578 else if (request_length == 0)
579 {
580
581 /* Send the notification of end of download to application. */
582 dfu -> ux_slave_class_dfu_notify(dfu, UX_SLAVE_CLASS_DFU_NOTIFICATION_END_DOWNLOAD);
583
584 /* In the system, state the DFU state machine to DFU MANIFEST SYNCH. */
585 _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SLAVE_CLASS_DFU_STATUS_STATE_DFU_MANIFEST_SYNC;
586
587 }
588
589 else
590 {
591
592 /* Write the next block to the firmware. */
593 status = dfu -> ux_slave_class_dfu_write(dfu, request_value,
594 transfer_request -> ux_slave_transfer_request_data_pointer,
595 request_length,
596 &actual_length);
597
598 /* Application can actively reject and set error state. */
599 if (status != UX_SUCCESS)
600 {
601 _ux_device_stack_endpoint_stall(&device -> ux_slave_device_control_endpoint);
602 _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SYSTEM_DFU_STATE_DFU_ERROR;
603 break;
604 }
605
606 /* In the system, state the DFU state machine to dfu DOWNLOAD SYNC. */
607 _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SYSTEM_DFU_STATE_DFU_DNLOAD_SYNC;
608 }
609
610 break;
611
612 case UX_SLAVE_CLASS_DFU_COMMAND_ABORT :
613
614 /* Send a notification to the application. */
615 dfu -> ux_slave_class_dfu_notify(dfu, UX_SLAVE_CLASS_DFU_NOTIFICATION_ABORT_DOWNLOAD);
616
617 /* In the system, state the DFU state machine to dfu IDLE. */
618 _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SYSTEM_DFU_STATE_DFU_IDLE;
619
620 break;
621
622 case UX_SLAVE_CLASS_DFU_COMMAND_GET_STATUS :
623
624 #if UX_DEVICE_CLASS_DFU_STATUS_MODE == 1
625 _ux_device_class_dfu_status_get(dfu, transfer_request, UX_FALSE, 0, 0, 0);
626 #else
627
628 /* Fill the status data payload. First with status. */
629 *transfer_request -> ux_slave_transfer_request_data_pointer = (UCHAR) dfu -> ux_slave_class_dfu_status;
630
631 /* Poll time out value is set to 1ms. */
632 *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT) = UX_DW0(UX_DEVICE_CLASS_DFU_STATUS_POLLTIMEOUT);
633 *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT + 1) = UX_DW1(UX_DEVICE_CLASS_DFU_STATUS_POLLTIMEOUT);
634 *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT + 2) = UX_DW2(UX_DEVICE_CLASS_DFU_STATUS_POLLTIMEOUT);
635
636 /* Next state. */
637 *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_STATE) = (UCHAR) _ux_system_slave -> ux_system_slave_device_dfu_state_machine;
638
639 /* String index set to 0. */
640 *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_STRING) = 0;
641 #endif
642
643 /* We have a request to obtain the status of the DFU instance. */
644 _ux_device_stack_transfer_request(transfer_request, UX_SLAVE_CLASS_DFU_GET_STATUS_LENGTH, UX_SLAVE_CLASS_DFU_GET_STATUS_LENGTH);
645
646 break;
647
648 case UX_SLAVE_CLASS_DFU_COMMAND_GET_STATE :
649
650 /* Fill the status data payload. First with state. */
651 *transfer_request -> ux_slave_transfer_request_data_pointer = (UCHAR) _ux_system_slave -> ux_system_slave_device_dfu_state_machine;
652
653 /* We have a request to obtain the status of the DFU instance. */
654 _ux_device_stack_transfer_request(transfer_request, UX_SLAVE_CLASS_DFU_GET_STATE_LENGTH, UX_SLAVE_CLASS_DFU_GET_STATE_LENGTH);
655
656 break;
657
658 default:
659
660 /* Unknown function. Stall the endpoint. */
661 _ux_device_stack_endpoint_stall(&device -> ux_slave_device_control_endpoint);
662
663 /* In the system, state the DFU state machine to dfu ERROR. */
664 _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SYSTEM_DFU_STATE_DFU_ERROR;
665
666 break;
667 }
668
669 break;
670
671 case UX_SLAVE_CLASS_DFU_STATUS_STATE_DFU_MANIFEST_SYNC :
672
673 /* Here we process only the request we can accept in the MANIFEST SYNCH state. */
674 switch (request)
675 {
676
677 case UX_SLAVE_CLASS_DFU_COMMAND_GET_STATUS :
678
679 #if UX_DEVICE_CLASS_DFU_STATUS_MODE == 1
680 _ux_device_class_dfu_status_get(dfu, transfer_request, UX_TRUE,
681 UX_SLAVE_CLASS_DFU_STATUS_STATE_DFU_MANIFEST_WAIT_RESET,
682 UX_SLAVE_CLASS_DFU_STATUS_STATE_DFU_MANIFEST,
683 UX_SLAVE_CLASS_DFU_STATUS_STATE_DFU_ERROR);
684 if ((_ux_system_slave -> ux_system_slave_device_dfu_state_machine ==
685 UX_SLAVE_CLASS_DFU_STATUS_STATE_DFU_MANIFEST_WAIT_RESET) &&
686 (_ux_system_slave -> ux_system_slave_device_dfu_capabilities &
687 UX_SLAVE_CLASS_DFU_CAPABILITY_WILL_DETACH))
688 {
689
690 /* Wake up the DFU thread and send a detach request.. */
691 _ux_device_class_dfu_event_flags_set(dfu, UX_DEVICE_CLASS_DFU_THREAD_EVENT_DISCONNECT);
692 }
693 #else
694
695 /* Check if the device is still buys performing the write. Write could be delayed. */
696 dfu -> ux_slave_class_dfu_get_status(dfu, &media_status);
697
698 /* Check status of device. */
699 switch (media_status)
700 {
701
702 case UX_SLAVE_CLASS_DFU_MEDIA_STATUS_OK :
703
704 /* Set the next state for wait reset and no error status. */
705 dfu -> ux_slave_class_dfu_status = UX_SLAVE_CLASS_DFU_STATUS_OK ;
706 _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SLAVE_CLASS_DFU_STATUS_STATE_DFU_MANIFEST_WAIT_RESET;
707
708 /* Check who is responsible for the RESET. */
709 if (_ux_system_slave -> ux_system_slave_device_dfu_capabilities & UX_SLAVE_CLASS_DFU_CAPABILITY_WILL_DETACH)
710 {
711
712 /* Wake up the DFU thread and send a detach request.. */
713 _ux_device_class_dfu_event_flags_set(dfu, UX_DEVICE_CLASS_DFU_THREAD_EVENT_DISCONNECT);
714
715 }
716
717 break;
718
719 case UX_SLAVE_CLASS_DFU_MEDIA_STATUS_BUSY :
720
721 /* Set the next state for busy but no error status. */
722 dfu -> ux_slave_class_dfu_status = UX_SLAVE_CLASS_DFU_STATUS_OK ;
723 _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SLAVE_CLASS_DFU_STATUS_STATE_DFU_MANIFEST;
724 break;
725
726 case UX_SLAVE_CLASS_DFU_MEDIA_STATUS_ERROR :
727
728 /* Set the next state for busy and error status. */
729 dfu -> ux_slave_class_dfu_status = UX_SLAVE_CLASS_DFU_STATUS_ERROR_WRITE ;
730 _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SLAVE_CLASS_DFU_STATUS_STATE_DFU_ERROR;
731 break;
732 }
733
734 /* Fill the status data payload. First with status. */
735 *transfer_request -> ux_slave_transfer_request_data_pointer = (UCHAR) dfu -> ux_slave_class_dfu_status;
736
737 /* Poll time out value is set to 1ms. */
738 *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT) = UX_DW0(UX_DEVICE_CLASS_DFU_STATUS_POLLTIMEOUT);
739 *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT + 1) = UX_DW1(UX_DEVICE_CLASS_DFU_STATUS_POLLTIMEOUT);
740 *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT + 2) = UX_DW2(UX_DEVICE_CLASS_DFU_STATUS_POLLTIMEOUT);
741
742 /* Next state. */
743 *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_STATE) = (UCHAR) _ux_system_slave -> ux_system_slave_device_dfu_state_machine;
744
745 /* String index set to 0. */
746 *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_STRING) = 0;
747 #endif
748
749 /* We have a request to obtain the status of the DFU instance. */
750 _ux_device_stack_transfer_request(transfer_request, UX_SLAVE_CLASS_DFU_GET_STATUS_LENGTH, UX_SLAVE_CLASS_DFU_GET_STATUS_LENGTH);
751
752 break;
753
754 case UX_SLAVE_CLASS_DFU_COMMAND_GET_STATE :
755
756 /* Fill the status data payload. First with state. */
757 *transfer_request -> ux_slave_transfer_request_data_pointer = (UCHAR) _ux_system_slave -> ux_system_slave_device_dfu_state_machine;
758
759 /* We have a request to obtain the status of the DFU instance. */
760 _ux_device_stack_transfer_request(transfer_request, UX_SLAVE_CLASS_DFU_GET_STATE_LENGTH, UX_SLAVE_CLASS_DFU_GET_STATE_LENGTH);
761
762 break;
763
764 default:
765
766 /* Unknown function. Stall the endpoint. */
767 _ux_device_stack_endpoint_stall(&device -> ux_slave_device_control_endpoint);
768 break;
769 }
770
771 break;
772
773 case UX_SLAVE_CLASS_DFU_STATUS_STATE_DFU_ERROR :
774
775 /* Here we process only the request we can accept in the ERROR state. */
776 switch (request)
777 {
778
779 #ifdef UX_DEVICE_CLASS_DFU_ERROR_GET_ENABLE
780 case UX_SLAVE_CLASS_DFU_COMMAND_GET_STATUS :
781
782 /* Fill the status data payload. First with status. */
783 *transfer_request -> ux_slave_transfer_request_data_pointer = (UCHAR) dfu -> ux_slave_class_dfu_status;
784
785 /* Poll time out value is set to 1ms. */
786 *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT) = 1;
787 *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT + 1) = 0;
788 *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT + 2) = 0;
789
790 /* Next state. */
791 *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_STATE) = (UCHAR) _ux_system_slave -> ux_system_slave_device_dfu_state_machine;
792
793 /* String index set to 0. */
794 *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_STRING) = 0;
795
796 /* We have a request to obtain the status of the DFU instance. */
797 _ux_device_stack_transfer_request(transfer_request, UX_SLAVE_CLASS_DFU_GET_STATUS_LENGTH, UX_SLAVE_CLASS_DFU_GET_STATUS_LENGTH);
798
799 break;
800
801 case UX_SLAVE_CLASS_DFU_COMMAND_GET_STATE :
802
803 /* Fill the status data payload. First with state. */
804 *transfer_request -> ux_slave_transfer_request_data_pointer = (UCHAR) _ux_system_slave -> ux_system_slave_device_dfu_state_machine;
805
806 /* We have a request to obtain the status of the DFU instance. */
807 _ux_device_stack_transfer_request(transfer_request, UX_SLAVE_CLASS_DFU_GET_STATE_LENGTH, UX_SLAVE_CLASS_DFU_GET_STATE_LENGTH);
808
809 break;
810 #endif
811
812 case UX_SLAVE_CLASS_DFU_COMMAND_CLEAR_STATUS :
813
814 /* In the system, state the DFU state machine to dfu IDLE. */
815 dfu -> ux_slave_class_dfu_status = UX_SLAVE_CLASS_DFU_MEDIA_STATUS_OK;
816 _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SYSTEM_DFU_STATE_DFU_IDLE;
817
818 break;
819
820 default:
821
822 /* Unknown function. Stall the endpoint. */
823 _ux_device_stack_endpoint_stall(&device -> ux_slave_device_control_endpoint);
824 break;
825
826 }
827
828 break;
829
830 #ifndef UX_DEVICE_CLASS_DFU_UPLOAD_DISABLE
831 case UX_SLAVE_CLASS_DFU_STATUS_STATE_DFU_UPLOAD_IDLE: /* bitCanUpload == 1. */
832
833 /* Here we process only the request we can accept in the DFU mode UPLOAD IDLE state. */
834 switch (request)
835 {
836
837 case UX_SLAVE_CLASS_DFU_COMMAND_UPLOAD:
838
839 /* Check if length > wTransferSize (we can support max of control buffer size). */
840 if (request_length > UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH)
841 {
842 _ux_device_stack_endpoint_stall(&device -> ux_slave_device_control_endpoint);
843 _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SYSTEM_DFU_STATE_DFU_ERROR;
844 break;
845 }
846
847 /* Length 0 case undefined, just keep state. */
848 if (request_length == 0)
849 break;
850
851 /* We received a UPLOAD command with length > 0. */
852
853 /* Read the next block from the firmware. */
854 status = dfu -> ux_slave_class_dfu_read(dfu, request_value,
855 transfer_request -> ux_slave_transfer_request_data_pointer,
856 request_length,
857 &actual_length);
858
859 /* Application can actively reject and set error state. */
860 if (status != UX_SUCCESS)
861 {
862 _ux_device_stack_endpoint_stall(&device -> ux_slave_device_control_endpoint);
863 _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SYSTEM_DFU_STATE_DFU_ERROR;
864 break;
865 }
866
867 /* If it's short frame, switch to dfu IDLE. */
868 if (actual_length < request_length)
869 {
870
871 /* Send a notification to the application. */
872 dfu -> ux_slave_class_dfu_notify(dfu, UX_SLAVE_CLASS_DFU_NOTIFICATION_END_UPLOAD);
873
874 /* In the system, state the DFU state machine to dfu IDLE. */
875 _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SYSTEM_DFU_STATE_DFU_IDLE;
876 }
877
878 /* We have a request to upload DFU firmware block. */
879 _ux_device_stack_transfer_request(transfer_request, actual_length, request_length);
880
881 break;
882
883 case UX_SLAVE_CLASS_DFU_COMMAND_ABORT :
884
885 /* Send a notification to the application. */
886 dfu -> ux_slave_class_dfu_notify(dfu, UX_SLAVE_CLASS_DFU_NOTIFICATION_ABORT_UPLOAD);
887
888 /* In the system, state the DFU state machine to dfu IDLE. */
889 _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SYSTEM_DFU_STATE_DFU_IDLE;
890
891 break;
892
893 case UX_SLAVE_CLASS_DFU_COMMAND_GET_STATUS :
894
895 #if UX_DEVICE_CLASS_DFU_STATUS_MODE == 1
896 _ux_device_class_dfu_status_get(dfu, transfer_request, UX_FALSE, 0, 0, 0);
897 #else
898
899 /* Fill the status data payload. First with status. */
900 *transfer_request -> ux_slave_transfer_request_data_pointer = (UCHAR) dfu -> ux_slave_class_dfu_status;
901
902 /* Poll time out value is set to 1ms. */
903 *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT) = UX_DW0(UX_DEVICE_CLASS_DFU_STATUS_POLLTIMEOUT);
904 *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT + 1) = UX_DW1(UX_DEVICE_CLASS_DFU_STATUS_POLLTIMEOUT);
905 *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT + 2) = UX_DW2(UX_DEVICE_CLASS_DFU_STATUS_POLLTIMEOUT);
906
907 /* Next state. */
908 *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_STATE) = (UCHAR) _ux_system_slave -> ux_system_slave_device_dfu_state_machine;
909
910 /* String index set to 0. */
911 *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_STRING) = 0;
912 #endif
913
914 /* We have a request to obtain the status of the DFU instance. */
915 _ux_device_stack_transfer_request(transfer_request, UX_SLAVE_CLASS_DFU_GET_STATUS_LENGTH, UX_SLAVE_CLASS_DFU_GET_STATUS_LENGTH);
916
917 break;
918
919 case UX_SLAVE_CLASS_DFU_COMMAND_GET_STATE :
920
921 /* Fill the status data payload. First with state. */
922 *transfer_request -> ux_slave_transfer_request_data_pointer = (UCHAR) _ux_system_slave -> ux_system_slave_device_dfu_state_machine;
923
924 /* We have a request to obtain the status of the DFU instance. */
925 _ux_device_stack_transfer_request(transfer_request, UX_SLAVE_CLASS_DFU_GET_STATE_LENGTH, UX_SLAVE_CLASS_DFU_GET_STATE_LENGTH);
926
927 break;
928
929 default:
930
931 /* Unknown function. Stall the endpoint. */
932 _ux_device_stack_endpoint_stall(&device -> ux_slave_device_control_endpoint);
933
934 /* In the system, state the DFU state machine to dfu ERROR. */
935 _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SYSTEM_DFU_STATE_DFU_ERROR;
936
937 break;
938 }
939
940 break;
941 #endif
942
943 default:
944
945 /* Unknown state. Should not happen. */
946 return(UX_ERROR);
947 }
948
949 return(UX_SUCCESS);
950 }
951
952 #if UX_DEVICE_CLASS_DFU_STATUS_MODE == 1
_ux_device_class_dfu_status_get(UX_SLAVE_CLASS_DFU * dfu,UX_SLAVE_TRANSFER * transfer,UCHAR move_state,UCHAR state_ok,UCHAR state_busy,UCHAR state_error)953 static inline VOID _ux_device_class_dfu_status_get(UX_SLAVE_CLASS_DFU *dfu,
954 UX_SLAVE_TRANSFER *transfer,
955 UCHAR move_state,
956 UCHAR state_ok, UCHAR state_busy, UCHAR state_error)
957 {
958 ULONG media_status = ((UX_SLAVE_CLASS_DFU_MEDIA_STATUS_OK) |
959 (UX_SLAVE_CLASS_DFU_STATUS_OK << 4) |
960 (UX_DEVICE_CLASS_DFU_STATUS_POLLTIMEOUT << 8));
961 UCHAR *buffer = transfer -> ux_slave_transfer_request_data_pointer;
962 ULONG dfu_status, dfu_polltimeout;
963
964 /* Get status from application. */
965 dfu -> ux_slave_class_dfu_get_status(dfu, &media_status);
966
967 /* Extract bStatus and bwPollTimeout. */
968 dfu_status = (media_status >> 4) & 0xFu;
969 dfu_polltimeout = (media_status >> 8) & 0xFFFFFFu;
970 dfu -> ux_slave_class_dfu_status = dfu_status;
971
972 /* Move state based on returned status. */
973 if (move_state)
974 {
975
976 /* OK/BUSY/ERROR ? */
977 switch((media_status & 0xF))
978 {
979 case UX_SLAVE_CLASS_DFU_MEDIA_STATUS_OK:
980 _ux_system_slave -> ux_system_slave_device_dfu_state_machine = state_ok;
981 break;
982 case UX_SLAVE_CLASS_DFU_MEDIA_STATUS_BUSY:
983 _ux_system_slave -> ux_system_slave_device_dfu_state_machine = state_busy;
984 break;
985 case UX_SLAVE_CLASS_DFU_MEDIA_STATUS_ERROR:
986 default:
987 _ux_system_slave -> ux_system_slave_device_dfu_state_machine = state_error;
988 break;
989 }
990 }
991
992 /* Fill the status data payload. First with status. */
993 *buffer = (UCHAR) dfu_status;
994
995 /* Poll time out value is set to 1ms. */
996 *(buffer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT) = UX_DW0(dfu_polltimeout);
997 *(buffer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT + 1) = UX_DW1(dfu_polltimeout);
998 *(buffer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT + 2) = UX_DW2(dfu_polltimeout);
999
1000 /* Next state. */
1001 *(buffer + UX_SLAVE_CLASS_DFU_GET_STATUS_STATE) = (UCHAR) _ux_system_slave -> ux_system_slave_device_dfu_state_machine;
1002
1003 /* String index set to 0. */
1004 *(buffer + UX_SLAVE_CLASS_DFU_GET_STATUS_STRING) = 0;
1005 }
1006 #endif
1007