1 /* This test is designed to test the simple dpump host/device class operation.  */
2 
3 #include <stdio.h>
4 #include "tx_api.h"
5 #include "ux_api.h"
6 #include "ux_system.h"
7 #include "ux_utility.h"
8 #include "ux_hcd_sim_host.h"
9 
10 #include "fx_api.h"
11 
12 #include "ux_device_class_dfu.h"
13 #include "ux_device_stack.h"
14 #include "ux_host_stack.h"
15 
16 #include "ux_test_dcd_sim_slave.h"
17 #include "ux_test_hcd_sim_host.h"
18 #include "ux_test_utility_sim.h"
19 
20 
21 #define UX_DEMO_REQUEST_MAX_LENGTH                                                 \
22     ((UX_HCD_SIM_HOST_MAX_PAYLOAD) > (UX_SLAVE_REQUEST_DATA_MAX_LENGTH) ?         \
23      (UX_HCD_SIM_HOST_MAX_PAYLOAD) : (UX_SLAVE_REQUEST_DATA_MAX_LENGTH))
24 
25 
26 /* Define constants.  */
27 
28 #define  UX_DEMO_MEMORY_SIZE             (128*1024)
29 #define  UX_DEMO_STACK_SIZE              (1024)
30 
31 
32 /* Define local/extern function prototypes.  */
33 
34 static void        test_thread_entry(ULONG);
35 static TX_THREAD   tx_test_thread_host_simulation;
36 static TX_THREAD   tx_test_thread_slave_simulation;
37 static void        tx_test_thread_host_simulation_entry(ULONG);
38 static void        tx_test_thread_slave_simulation_entry(ULONG);
39 
40 static VOID        demo_thread_dfu_activate(VOID *dfu);
41 static VOID        demo_thread_dfu_deactivate(VOID *dfu);
42 static UINT        demo_thread_dfu_read(VOID *dfu, ULONG block_number, UCHAR * data_pointer, ULONG length, ULONG *actual_length);
43 static UINT        demo_thread_dfu_write(VOID *dfu, ULONG block_number, UCHAR * data_pointer, ULONG length, ULONG *media_status);
44 static UINT        demo_thread_dfu_get_status(VOID *dfu, ULONG *media_status);
45 static UINT        demo_thread_dfu_notify(VOID *dfu, ULONG notification);
46 static UINT        demo_thread_dfu_custom_request(VOID *dfu, UX_SLAVE_TRANSFER *transfer);
47 
48 /* Define global data structures.  */
49 
50 static UCHAR                               usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)];
51 
52 static ULONG                               error_counter;
53 
54 static ULONG                               set_cfg_counter;
55 
56 static ULONG                               rsc_mem_free_on_set_cfg;
57 static ULONG                               rsc_sem_on_set_cfg;
58 static ULONG                               rsc_sem_get_on_set_cfg;
59 static ULONG                               rsc_mutex_on_set_cfg;
60 
61 static ULONG                               rsc_enum_sem_usage;
62 static ULONG                               rsc_enum_sem_get_count;
63 static ULONG                               rsc_enum_mutex_usage;
64 static ULONG                               rsc_enum_mem_usage;
65 
66 static ULONG                               interaction_count;
67 
68 static UCHAR                               error_callback_ignore = UX_TRUE;
69 static ULONG                               error_callback_counter;
70 
71 static UX_SLAVE_CLASS_DFU_PARAMETER        dfu_parameter;
72 
73 static UX_DEVICE                           *device;
74 static ULONG                               dfu_block;
75 static ULONG                               dfu_transfer_length;
76 static ULONG                               dfu_actual_length;
77 static UCHAR                               dfu_host_buffer[UX_DEMO_REQUEST_MAX_LENGTH];
78 static UCHAR                               dfu_device_buffer[UX_DEMO_REQUEST_MAX_LENGTH];
79 
80 
81 /* Define device framework.  */
82 
83 /* DFU descriptor must be same for all frameworks!!!  */
84 #define DFU_FUNCTION_DESCRIPTOR                                                 \
85     /* Functional descriptor for DFU.  */                                       \
86     0x09, 0x21,                                                                 \
87     0x0f,       /* bmAttributes: B3 bitWillDetach                   */          \
88                 /*               B2 bitManifestationTolerant        */          \
89                 /*               B1 bitCanUpload, B0 bitCanDnload   */          \
90     0xE8, 0x03, /* wDetachTimeOut: 0x03E8 (1000) */                             \
91     UX_W0(UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH),                                 \
92     UX_W1(UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH), /* wTransferSize:   */          \
93     0x00, 0x01, /* bcdDFUVersion:  0x0100  */
94 
95 /* Interface descriptor for APP/DFU mode.  */
96 #define DFU_INTERFACE_DESCRIPTOR(bInterfaceNumber, bInterfaceProtocol)          \
97     /* Interface descriptor for DFU.  */                                        \
98     0x09, 0x04,                                                                 \
99     (bInterfaceNumber), 0x00, 0x00,                                             \
100     0xFE, 0x01, (bInterfaceProtocol),                                           \
101     0x00,                                                                       \
102 
103 #define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed)
104 static UCHAR device_framework_full_speed[] = {
105 
106     /* Device descriptor */
107     0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x40,
108     0x99, 0x99, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02,
109     0x03, 0x01,
110 
111     /* Configuration descriptor */
112     0x09, 0x02, 0x1b, 0x00, 0x01, 0x01, 0x00, 0xc0,
113     0x32,
114 
115     /* Interface descriptor for DFU (bInterfaceProtocol = 1).  */
116     DFU_INTERFACE_DESCRIPTOR(0x00, 0x01)
117     DFU_FUNCTION_DESCRIPTOR
118 };
119 
120 #define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed)
121 static UCHAR device_framework_high_speed[] = {
122 
123     /* Device descriptor */
124     0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40,
125     0x99, 0x99, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02,
126     0x03, 0x01,
127 
128     /* Device qualifier descriptor */
129     0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40,
130     0x01, 0x00,
131 
132     /* Configuration descriptor */
133     0x09, 0x02, 0x1b, 0x00, 0x01, 0x01, 0x00, 0xc0,
134     0x32,
135 
136     /* Interface descriptor for DFU (bInterfaceProtocol = 1).  */
137     DFU_INTERFACE_DESCRIPTOR(0x00, 0x01)
138     DFU_FUNCTION_DESCRIPTOR
139 };
140 
141 /* String Device Framework :
142     Byte 0 and 1 : Word containing the language ID : 0x0904 for US
143     Byte 2       : Byte containing the index of the descriptor
144     Byte 3       : Byte containing the length of the descriptor string
145 */
146 #define STRING_FRAMEWORK_LENGTH sizeof(string_framework)
147 static UCHAR string_framework[] = {
148 
149     /* Manufacturer string descriptor : Index 1 - "Microsoft AzureRTOS" */
150     0x09, 0x04, 0x01, 19,
151     'M', 'i', 'c', 'r', 'o', 's', 'o', 'f',
152     't', ' ', 'A', 'z', 'u', 'r', 'e', 'R',
153     'T', 'O', 'S',
154 
155     /* Product string descriptor : Index 2 - "DFU Demo Device" */
156     0x09, 0x04, 0x02, 15,
157     'D', 'F', 'U', ' ', 'D', 'e', 'm', 'o',
158     ' ', 'D', 'e', 'v', 'i', 'c', 'e',
159 
160     /* Serial Number string descriptor : Index 3 - "0000" */
161     0x09, 0x04, 0x03, 0x04,
162     '0', '0', '0', '0'
163 };
164 
165 /* Multiple languages are supported on the device, to add
166     a language besides english, the unicode language code must
167     be appended to the language_id_framework array and the length
168     adjusted accordingly. */
169 #define LANGUAGE_ID_FRAMEWORK_LENGTH sizeof(language_id_framework)
170 static UCHAR language_id_framework[] = {
171 
172     /* English. */
173     0x09, 0x04
174 };
175 
176 
177 #define DEVICE_FRAMEWORK_LENGTH_DFU sizeof(device_framework_dfu)
178 static UCHAR device_framework_dfu[] = {
179 
180     /* Device descriptor */
181     0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x40,
182     0x99, 0x99, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02,
183     0x03, 0x01,
184 
185     /* Configuration descriptor */
186     0x09, 0x02, 0x1B, 0x00, 0x01, 0x01, 0x00, 0xc0,
187     0x32,
188 
189     /* Interface descriptor for DFU (bInterfaceProtocol = 2).  */
190     DFU_INTERFACE_DESCRIPTOR(0x00, 0x02)
191     DFU_FUNCTION_DESCRIPTOR
192 };
193 
194 
195 /* Define the ISR dispatch.  */
196 
197 extern VOID    (*test_isr_dispatch)(void);
198 
199 
200 /* Prototype for test control return.  */
201 
202 void  test_control_return(UINT status);
203 
error_callback(UINT system_level,UINT system_context,UINT error_code)204 static VOID error_callback(UINT system_level, UINT system_context, UINT error_code)
205 {
206 
207     error_callback_counter ++;
208 
209     if (!error_callback_ignore)
210     {
211         {
212             /* Failed test.  */
213             printf("Error #%d, system_level: %d, system_context: %d, error_code: 0x%x\n", __LINE__, system_level, system_context, error_code);
214             test_control_return(1);
215         }
216     }
217 }
218 
219 
220 /* Define the ISR dispatch routine.  */
221 
test_isr(void)222 static void    test_isr(void)
223 {
224 
225     /* For further expansion of interrupt-level testing.  */
226 }
227 
228 
demo_system_host_change_function(ULONG event,UX_HOST_CLASS * cls,VOID * inst)229 static UINT demo_system_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst)
230 {
231     if (event == UX_DEVICE_CONNECTION)
232     {
233         device = (UX_DEVICE *)inst;
234     }
235     if (event == UX_DEVICE_DISCONNECTION)
236     {
237         if ((VOID *)device == inst)
238             device = UX_NULL;
239     }
240 }
241 
242 
243 /* Define what the initial system looks like.  */
244 
245 #ifdef CTEST
test_application_define(void * first_unused_memory)246 void test_application_define(void *first_unused_memory)
247 #else
248 void    usbx_device_dfu_basic_test_application_define(void *first_unused_memory)
249 #endif
250 {
251 
252 UINT                    status;
253 CHAR *                  stack_pointer;
254 CHAR *                  memory_pointer;
255 ULONG                   test_n;
256 
257     /* Inform user.  */
258     printf("Running Device DFU Basic Functionality Test......................... ");
259 
260     /* Reset testing counts. */
261     ux_test_utility_sim_mutex_create_count_reset();
262     ux_test_utility_sim_sem_create_count_reset();
263     ux_test_utility_sim_sem_get_count_reset();
264     /* Reset error generations */
265     ux_test_utility_sim_sem_error_generation_stop();
266     ux_test_utility_sim_mutex_error_generation_stop();
267     ux_test_utility_sim_sem_get_error_generation_stop();
268 
269     /* Initialize the free memory pointer */
270     stack_pointer = (CHAR *) usbx_memory;
271     memory_pointer = stack_pointer + (UX_DEMO_STACK_SIZE * 2);
272 
273     /* Initialize USBX Memory */
274     status = ux_system_initialize(memory_pointer, UX_DEMO_MEMORY_SIZE, UX_NULL,0);
275 
276     /* Check for error.  */
277     if (status != UX_SUCCESS)
278     {
279 
280         printf("ERROR #%d\n", __LINE__);
281         test_control_return(1);
282     }
283 
284     /* Register the error callback. */
285     _ux_utility_error_callback_register(error_callback);
286 
287     /* The code below is required for installing the host portion of USBX */
288     status =  ux_host_stack_initialize(demo_system_host_change_function);
289     if (status != UX_SUCCESS)
290     {
291 
292         printf("ERROR #%d\n", __LINE__);
293         test_control_return(1);
294     }
295 
296     /* There is no host class for DFU now.  */
297 
298     /* The code below is required for installing the device portion of USBX. No call back for
299        device status change in this example. */
300     status =  ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED,
301                                        device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED,
302                                        string_framework, STRING_FRAMEWORK_LENGTH,
303                                        language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH,UX_NULL);
304     if(status!=UX_SUCCESS)
305     {
306 
307         printf("ERROR #%d\n", __LINE__);
308         test_control_return(1);
309     }
310 
311     /* Store the DFU parameters.   */
312     dfu_parameter.ux_slave_class_dfu_parameter_instance_activate               =  demo_thread_dfu_activate;
313     dfu_parameter.ux_slave_class_dfu_parameter_instance_deactivate             =  demo_thread_dfu_deactivate;
314     dfu_parameter.ux_slave_class_dfu_parameter_read                            =  demo_thread_dfu_read;
315     dfu_parameter.ux_slave_class_dfu_parameter_write                           =  demo_thread_dfu_write;
316     dfu_parameter.ux_slave_class_dfu_parameter_get_status                      =  demo_thread_dfu_get_status;
317     dfu_parameter.ux_slave_class_dfu_parameter_notify                          =  demo_thread_dfu_notify;
318 #ifdef UX_DEVICE_CLASS_DFU_CUSTOM_REQUEST_ENABLE
319     dfu_parameter.ux_device_class_dfu_parameter_custom_request                 =  demo_thread_dfu_custom_request;
320 #endif
321     dfu_parameter.ux_slave_class_dfu_parameter_framework                       =  device_framework_dfu;
322     dfu_parameter.ux_slave_class_dfu_parameter_framework_length                =  DEVICE_FRAMEWORK_LENGTH_DFU;
323 
324     /* Initilize the device dfu class. The class is connected with interface 1 on configuration 1. */
325     status =  ux_device_stack_class_register(_ux_system_slave_class_dfu_name, ux_device_class_dfu_entry,
326                                              1, 0, (VOID *)&dfu_parameter);
327     if(status!=UX_SUCCESS)
328     {
329 
330         printf("ERROR #%d\n", __LINE__);
331         test_control_return(1);
332     }
333 
334     /* Initialize the simulated device controller.  */
335     status =  _ux_dcd_sim_slave_initialize();
336 
337     /* Check for error.  */
338     if (status != TX_SUCCESS)
339     {
340 
341         printf("ERROR #%d\n", __LINE__);
342         test_control_return(1);
343     }
344 
345     /* Register all the USB host controllers available in this system */
346     status =  ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, _ux_hcd_sim_host_initialize,0,0);
347     if (status != UX_SUCCESS)
348     {
349 
350         printf("ERROR #%d\n", __LINE__);
351         test_control_return(1);
352     }
353 
354     /* Create the main host simulation thread.  */
355     status =  tx_thread_create(&tx_test_thread_host_simulation, "tx demo host simulation", tx_test_thread_host_simulation_entry, 0,
356             stack_pointer, UX_DEMO_STACK_SIZE,
357             20, 20, 1, TX_AUTO_START);
358 
359     /* Check for error.  */
360     if (status != TX_SUCCESS)
361     {
362 
363         printf("ERROR #%d\n", __LINE__);
364         test_control_return(1);
365     }
366 
367     /* Create the main slave simulation  thread.  */
368     status =  tx_thread_create(&tx_test_thread_slave_simulation, "tx demo slave simulation", tx_test_thread_slave_simulation_entry, 0,
369             stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE,
370             20, 20, 1, TX_AUTO_START);
371 
372     /* Check for error.  */
373     if (status != TX_SUCCESS)
374     {
375 
376         printf("ERROR #%d\n", __LINE__);
377         test_control_return(1);
378     }
379 }
380 
_req_DFU_LOCK(UX_TRANSFER * control_transfer)381 static UINT _req_DFU_LOCK(UX_TRANSFER *control_transfer)
382 {
383 UINT        status;
384 #if defined(UX_HOST_STANDALONE)
385     while(1)
386     {
387         ux_system_tasks_run();
388         tx_thread_relinquish();
389 
390         UX_ENDPOINT *endpoint = control_transfer -> ux_transfer_request_endpoint;
391         if (endpoint == UX_NULL || endpoint -> ux_endpoint_state != UX_ENDPOINT_RUNNING)
392         {
393             status = UX_ENDPOINT_HANDLE_UNKNOWN;
394             break;
395         }
396         UX_DEVICE *device = endpoint -> ux_endpoint_device;
397         if (device == UX_NULL || device -> ux_device_handle != (ULONG)(ALIGN_TYPE)(device))
398         {
399             status = UX_DEVICE_HANDLE_UNKNOWN;
400             break;
401         }
402         if ((device -> ux_device_flags & UX_DEVICE_FLAG_LOCK) == 0)
403         {
404             device -> ux_device_flags |= UX_DEVICE_FLAG_LOCK;
405             control_transfer -> ux_transfer_request_flags |= UX_TRANSFER_FLAG_AUTO_DEVICE_UNLOCK;
406             control_transfer -> ux_transfer_request_timeout_value = UX_WAIT_FOREVER;
407             status = UX_SUCCESS;
408             break;
409         }
410     }
411 #else
412     status = _ux_utility_semaphore_get(&control_transfer->ux_transfer_request_endpoint->ux_endpoint_device->ux_device_protection_semaphore, UX_WAIT_FOREVER);
413 #endif
414     if (status != UX_SUCCESS)
415     {
416         printf("ERROR #%d: %x\n", __LINE__, status);
417         test_control_return(1);
418     }
419 }
_req_DFU_GETSTATE(UX_TRANSFER * control_transfer)420 static UINT _req_DFU_GETSTATE(UX_TRANSFER *control_transfer)
421 {
422     _req_DFU_LOCK(control_transfer);
423     control_transfer->ux_transfer_request_type              = 0xA1;
424     control_transfer->ux_transfer_request_function          = UX_SLAVE_CLASS_DFU_COMMAND_GET_STATE;
425     control_transfer->ux_transfer_request_index             = 0;
426     control_transfer->ux_transfer_request_requested_length  = 1;
427     control_transfer->ux_transfer_request_data_pointer      = dfu_host_buffer;
428     control_transfer->ux_transfer_request_value             = 0;
429     return ux_host_stack_transfer_request(control_transfer);
430 }
_req_DFU_GETSTATUS(UX_TRANSFER * control_transfer)431 static UINT _req_DFU_GETSTATUS(UX_TRANSFER *control_transfer)
432 {
433     _req_DFU_LOCK(control_transfer);
434     control_transfer->ux_transfer_request_type              = 0xA1;
435     control_transfer->ux_transfer_request_function          = UX_SLAVE_CLASS_DFU_COMMAND_GET_STATUS;
436     control_transfer->ux_transfer_request_index             = 0;
437     control_transfer->ux_transfer_request_requested_length  = 6;
438     control_transfer->ux_transfer_request_data_pointer      = dfu_host_buffer;
439     control_transfer->ux_transfer_request_value             = 0;
440     return ux_host_stack_transfer_request(control_transfer);
441 }
_req_DFU_DETACH(UX_TRANSFER * control_transfer)442 static UINT _req_DFU_DETACH(UX_TRANSFER *control_transfer)
443 {
444     _req_DFU_LOCK(control_transfer);
445     control_transfer->ux_transfer_request_type              = 0x21;
446     control_transfer->ux_transfer_request_function          = UX_SLAVE_CLASS_DFU_COMMAND_DETACH;
447     control_transfer->ux_transfer_request_index             = 0;
448     control_transfer->ux_transfer_request_value             = 1000;
449     control_transfer->ux_transfer_request_requested_length  = 0;
450     return ux_host_stack_transfer_request(control_transfer);
451 }
_req_DFU_DNLOAD_IN(UX_TRANSFER * control_transfer,ULONG block,ULONG len)452 static UINT _req_DFU_DNLOAD_IN(UX_TRANSFER *control_transfer, ULONG block, ULONG len)
453 {
454     _req_DFU_LOCK(control_transfer);
455     control_transfer->ux_transfer_request_type              = 0xA1;
456     control_transfer->ux_transfer_request_function          = UX_SLAVE_CLASS_DFU_COMMAND_DOWNLOAD;
457     control_transfer->ux_transfer_request_index             = 0;
458     control_transfer->ux_transfer_request_data_pointer      = dfu_host_buffer;
459     control_transfer->ux_transfer_request_requested_length  = len;
460     control_transfer->ux_transfer_request_value             = block;
461     return ux_host_stack_transfer_request(control_transfer);
462 }
_req_DFU_DNLOAD(UX_TRANSFER * control_transfer,ULONG block,ULONG len)463 static UINT _req_DFU_DNLOAD(UX_TRANSFER *control_transfer, ULONG block, ULONG len)
464 {
465     _req_DFU_LOCK(control_transfer);
466     control_transfer->ux_transfer_request_type              = 0x21;
467     control_transfer->ux_transfer_request_function          = UX_SLAVE_CLASS_DFU_COMMAND_DOWNLOAD;
468     control_transfer->ux_transfer_request_index             = 0;
469     control_transfer->ux_transfer_request_data_pointer      = dfu_host_buffer;
470     control_transfer->ux_transfer_request_requested_length  = len;
471     control_transfer->ux_transfer_request_value             = block;
472     return ux_host_stack_transfer_request(control_transfer);
473 }
_req_DFU_UPLOAD(UX_TRANSFER * control_transfer,ULONG block,ULONG len)474 static UINT _req_DFU_UPLOAD(UX_TRANSFER *control_transfer, ULONG block, ULONG len)
475 {
476     _req_DFU_LOCK(control_transfer);
477     control_transfer->ux_transfer_request_type              = 0xA1;
478     control_transfer->ux_transfer_request_function          = UX_SLAVE_CLASS_DFU_COMMAND_UPLOAD;
479     control_transfer->ux_transfer_request_index             = 0;
480     control_transfer->ux_transfer_request_data_pointer      = dfu_host_buffer;
481     control_transfer->ux_transfer_request_requested_length  = len;
482     control_transfer->ux_transfer_request_value             = block;
483     return ux_host_stack_transfer_request(control_transfer);
484 }
_req_DFU_CLRSTATUS(UX_TRANSFER * control_transfer)485 static UINT _req_DFU_CLRSTATUS(UX_TRANSFER *control_transfer)
486 {
487     _req_DFU_LOCK(control_transfer);
488     control_transfer->ux_transfer_request_type              = 0x21;
489     control_transfer->ux_transfer_request_function          = UX_SLAVE_CLASS_DFU_COMMAND_CLEAR_STATUS;
490     control_transfer->ux_transfer_request_index             = 0;
491     control_transfer->ux_transfer_request_data_pointer      = UX_NULL;
492     control_transfer->ux_transfer_request_requested_length  = 0;
493     control_transfer->ux_transfer_request_value             = 0;
494     return ux_host_stack_transfer_request(control_transfer);
495 }
496 
497 
tx_test_thread_host_simulation_entry(ULONG arg)498 static void  tx_test_thread_host_simulation_entry(ULONG arg)
499 {
500 UX_ENDPOINT             *control_endpoint;
501 UX_TRANSFER             *control_transfer;
502 ULONG                   len, trans_len, block;
503 INT                     i;
504 UINT                    status;
505 
506     stepinfo("\n");
507 
508     stepinfo(">>>>>>>>>>>> Test DFU connect\n");
509     status = ux_test_wait_for_non_null((VOID **)&device);
510     UX_TEST_ASSERT(status == UX_SUCCESS);
511     if (device -> ux_device_state == UX_DEVICE_CONFIGURED)
512     {
513         printf("ERROR #%d, device state 0x%lx\n", __LINE__, device->ux_device_state);
514         test_control_return(1);
515     }
516 
517     stepinfo(">>>>>>>>>>>> Test DFU set configure\n");
518     status = ux_host_stack_device_configuration_select(device->ux_device_first_configuration);
519     UX_TEST_ASSERT(status == UX_SUCCESS);
520 
521     /* Get endpoint and transfer request.  */
522     control_endpoint = &device->ux_device_control_endpoint;
523     control_transfer = &control_endpoint->ux_endpoint_transfer_request;
524 
525     stepinfo(">>>>>>>>>>>> Test DFU_GETSTATE\n");
526     status = _req_DFU_GETSTATE(control_transfer);
527     if (status != UX_SUCCESS)
528     {
529         printf("ERROR #%d: transfer status 0x%x\n", __LINE__, status);
530         test_control_return(1);
531     }
532     UX_TEST_ASSERT(dfu_host_buffer[0] == UX_SYSTEM_DFU_STATE_APP_IDLE);
533 
534     stepinfo(">>>>>>>>>>>> Test DFU DETACH\n");
535 
536     /* Uses DFU framework after USB reset (re-connect).  */
537     ux_test_dcd_sim_slave_connect_framework(device_framework_dfu, DEVICE_FRAMEWORK_LENGTH_DFU);
538     status = _req_DFU_DETACH(control_transfer);
539     if (status != UX_SUCCESS)
540     {
541         printf("ERROR #%d: transfer status 0x%x\n", __LINE__, status);
542         test_control_return(1);
543     }
544     status = ux_test_wait_for_null((VOID **)&device);
545     UX_TEST_ASSERT(status == UX_SUCCESS);
546     status = ux_test_wait_for_non_null((VOID **)&device);
547     UX_TEST_ASSERT(status == UX_SUCCESS);
548     status = ux_host_stack_device_configuration_select(device->ux_device_first_configuration);
549     UX_TEST_ASSERT(status == UX_SUCCESS);
550 
551     status = _req_DFU_GETSTATE(control_transfer);
552     if (status != UX_SUCCESS)
553     {
554         printf("ERROR #%d: transfer status 0x%x\n", __LINE__, status);
555         test_control_return(1);
556     }
557     UX_TEST_ASSERT(dfu_host_buffer[0] == UX_SYSTEM_DFU_STATE_DFU_IDLE);
558 
559 #if defined(UX_DEVICE_CLASS_DFU_CUSTOM_REQUEST_ENABLE)
560     status = _req_DFU_DNLOAD(control_transfer, 0, 0);
561     if (status != UX_SUCCESS)
562     {
563         printf("ERROR #%d: transfer status 0x%x\n", __LINE__, status);
564         test_control_return(1);
565     }
566     UX_TEST_ASSERT(dfu_host_buffer[0] == UX_SYSTEM_DFU_STATE_DFU_IDLE);
567 #else
568 #endif
569 
570 
571 #if !defined(UX_DEVICE_CLASS_DFU_UPLOAD_DISABLE)
572 
573     stepinfo(">>>>>>>>>>>> Test DFU UPLOAD FAIL\n");
574     status = _req_DFU_UPLOAD(control_transfer, 0, UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH + 1);
575     if (status != UX_TRANSFER_STALLED)
576     {
577         printf("ERROR #%d: UPLOAD should STALL\n", __LINE__);
578         test_control_return(1);
579     }
580     status = _req_DFU_CLRSTATUS(control_transfer);
581     if (status != UX_SUCCESS)
582     {
583         printf("ERROR #%d: CLRSTATUS error 0x%x\n", __LINE__, status);
584         test_control_return(1);
585     }
586 
587     stepinfo(">>>>>>>>>>>> Test DFU UPLOAD\n");
588     trans_len = UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH;
589     for (block = 0; block < 99; block ++)
590     {
591         for (i = 0; i < trans_len; i ++)
592         {
593             dfu_device_buffer[i] = (UCHAR)(block + i);
594             dfu_host_buffer[i] = 0xFF;
595         }
596         dfu_actual_length = trans_len;
597         status = _req_DFU_UPLOAD(control_transfer, block, trans_len);
598         if (status != UX_SUCCESS)
599         {
600             printf("ERROR #%d(%ld, %ld): UPLOAD status 0x%x\n", __LINE__, block, trans_len, status);
601             test_control_return(1);
602         }
603         UX_TEST_ASSERT(dfu_transfer_length == trans_len);
604         UX_TEST_ASSERT(dfu_block == block);
605         if (ux_utility_memory_compare(dfu_host_buffer, dfu_device_buffer, trans_len) != UX_SUCCESS)
606         {
607             printf("ERROR #%d(%ld, %ld): data error\n", __LINE__, block, trans_len);
608             printf(" device buffer %p: %2x %2x ...\n", dfu_device_buffer, dfu_device_buffer[0], dfu_device_buffer[1]);
609             printf(" host   buffer %p: %2x %2x ...\n", dfu_host_buffer, dfu_host_buffer[0], dfu_host_buffer[1]);
610             test_control_return(1);
611         }
612     }
613     /* Finish upload.  */
614     dfu_actual_length = trans_len >> 1;
615     status = _req_DFU_UPLOAD(control_transfer, block, trans_len);
616     if (status != UX_SUCCESS)
617     {
618         printf("ERROR #%d: UPLOAD(0) 0x%x\n", __LINE__, status);
619         test_control_return(1);
620     }
621     /* Check state.  */
622     status = _req_DFU_GETSTATE(control_transfer);
623     if (status != UX_SUCCESS)
624     {
625         printf("ERROR #%d: transfer status 0x%x\n", __LINE__, status);
626         test_control_return(1);
627     }
628     UX_TEST_ASSERT(dfu_host_buffer[0] == UX_SYSTEM_DFU_STATE_DFU_IDLE);
629 #endif
630 
631     stepinfo(">>>>>>>>>>>> Test DFU DNLOAD error\n");
632     status = _req_DFU_DNLOAD_IN(control_transfer, 0, 16);
633     UX_TEST_CHECK_CODE(UX_TRANSFER_STALLED, status);
634 #if defined(UX_DEVICE_CLASS_DFU_ERROR_GET_ENABLE)
635     status = _req_DFU_GETSTATUS(control_transfer);
636     UX_TEST_CHECK_SUCCESS(status);
637 #endif
638     status = _req_DFU_CLRSTATUS(control_transfer);
639     UX_TEST_CHECK_SUCCESS(status);
640 
641     stepinfo(">>>>>>>>>>>> Test DFU DNLOAD\n");
642     for (len = 1, block = 0; len < UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH * 2; len <<= 1)
643     {
644         for (i = 0; i < len; i ++)
645         {
646             dfu_host_buffer[i] = (UCHAR)(block + i);
647             dfu_device_buffer[i] = 0xFF;
648         }
649         trans_len = UX_MIN(len, UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH);
650 
651         status = _req_DFU_DNLOAD(control_transfer, block, trans_len);
652         if (status != UX_SUCCESS)
653         {
654             printf("ERROR #%d(%ld, %ld): DNLOAD status 0x%x\n", __LINE__, block, trans_len, status);
655             test_control_return(1);
656         }
657         UX_TEST_ASSERT(dfu_transfer_length == trans_len);
658         UX_TEST_ASSERT(dfu_block == block);
659         if (ux_utility_memory_compare(dfu_host_buffer, dfu_device_buffer, trans_len) != UX_SUCCESS)
660         {
661             printf("ERROR #%d(%ld, %ld): data error\n", __LINE__, block, trans_len);
662             test_control_return(1);
663         }
664 
665         status = _req_DFU_GETSTATUS(control_transfer);
666         if (status != UX_SUCCESS)
667         {
668             printf("ERROR #%d(%ld, %ld): GETSTATUS status 0x%x\n", __LINE__, block, trans_len, status);
669             test_control_return(1);
670         }
671 
672         block ++;
673     }
674     /* Finish download.  */
675     status = _req_DFU_DNLOAD(control_transfer, block, 0);
676     if (status != UX_SUCCESS)
677     {
678         printf("ERROR #%d: DNLOAD(0) 0x%x\n", __LINE__, status);
679         test_control_return(1);
680     }
681     /* Manifestation.  */
682     status = _req_DFU_GETSTATE(control_transfer);
683     if (status != UX_SUCCESS)
684     {
685         printf("ERROR #%d: GETSTATE status 0x%x\n", __LINE__, status);
686         test_control_return(1);
687     }
688     UX_TEST_ASSERT(dfu_host_buffer[0] == UX_SLAVE_CLASS_DFU_STATUS_STATE_DFU_MANIFEST_SYNC);
689 
690     /* Uses DFU framework after USB reset (re-connect).  */
691     ux_test_dcd_sim_slave_connect_framework(UX_NULL, 0);
692     status = _req_DFU_GETSTATUS(control_transfer);
693     if (status != UX_SUCCESS)
694     {
695         printf("ERROR #%d: GETSTATUS status 0x%x\n", __LINE__, status);
696         test_control_return(1);
697     }
698     UX_TEST_ASSERT(dfu_host_buffer[4] == UX_SLAVE_CLASS_DFU_STATUS_STATE_DFU_MANIFEST_WAIT_RESET);
699 
700     /* Reset  */
701     status = ux_test_wait_for_null((VOID **)&device);
702     UX_TEST_ASSERT(status == UX_SUCCESS);
703     status = ux_test_wait_for_non_null((VOID **)&device);
704     UX_TEST_ASSERT(status == UX_SUCCESS);
705     status = ux_host_stack_device_configuration_select(device->ux_device_first_configuration);
706     UX_TEST_ASSERT(status == UX_SUCCESS);
707 
708     status = _req_DFU_GETSTATE(control_transfer);
709     if (status != UX_SUCCESS)
710     {
711         printf("ERROR #%d: transfer status 0x%x\n", __LINE__, status);
712         test_control_return(1);
713     }
714     UX_TEST_ASSERT(dfu_host_buffer[0] == UX_SYSTEM_DFU_STATE_APP_IDLE);
715 
716     stepinfo(">>>>>>>>>>>> All Done\n");
717 
718     /* Finally disconnect the device. */
719     ux_device_stack_disconnect();
720 
721     /* Deinitialize the device side of usbx.  */
722     _ux_device_stack_uninitialize();
723 
724     /* And finally the usbx system resources.  */
725     _ux_system_uninitialize();
726 
727     /* Successful test.  */
728     printf("SUCCESS!\n");
729     test_control_return(0);
730 }
731 
tx_test_thread_slave_simulation_entry(ULONG arg)732 static void  tx_test_thread_slave_simulation_entry(ULONG arg)
733 {
734     while(1)
735     {
736 
737 #if defined(UX_DEVICE_STANDALONE)
738         ux_system_tasks_run();
739         tx_thread_relinquish();
740 #else
741 
742         /* Sleep so ThreadX on Win32 will delete this thread. */
743         tx_thread_sleep(10);
744 #endif
745     }
746 }
747 
demo_device_state_change(ULONG event)748 static UINT    demo_device_state_change(ULONG event)
749 {
750     return(UX_SUCCESS);
751 }
752 
demo_thread_dfu_activate(VOID * dfu)753 static VOID    demo_thread_dfu_activate(VOID *dfu)
754 {
755 }
756 
demo_thread_dfu_deactivate(VOID * dfu)757 static VOID    demo_thread_dfu_deactivate(VOID *dfu)
758 {
759 }
760 
demo_thread_dfu_read(VOID * dfu,ULONG block_number,UCHAR * data_pointer,ULONG length,ULONG * actual_length)761 static UINT    demo_thread_dfu_read(VOID *dfu, ULONG block_number, UCHAR * data_pointer, ULONG length, ULONG *actual_length)
762 {
763 ULONG       return_length;
764 
765     stepinfo("dfuRead %ld,%ld: %2x %2x %2x %2x ... -> %p\n", block_number, length,
766         dfu_device_buffer[0], dfu_device_buffer[1], dfu_device_buffer[2], dfu_device_buffer[3],
767         data_pointer);
768     dfu_block = block_number;
769     dfu_transfer_length = length;
770 
771     return_length = UX_MIN(length, sizeof(dfu_device_buffer));
772     return_length = UX_MIN(return_length, dfu_actual_length);
773 
774     ux_utility_memory_copy(data_pointer, dfu_device_buffer, return_length);
775 
776     /* Here is where the data block is read from the firmware.  */
777     /* Some code needs to be inserted specifically for a target platform.  */
778     *actual_length =  return_length;
779     return(UX_SUCCESS);
780 }
781 
demo_thread_dfu_write(VOID * dfu,ULONG block_number,UCHAR * data_pointer,ULONG length,ULONG * media_status)782 static UINT    demo_thread_dfu_write(VOID *dfu, ULONG block_number, UCHAR * data_pointer, ULONG length, ULONG *media_status)
783 {
784     stepinfo("dfuWrite %ld,%ld\n", block_number, length);
785     dfu_block = block_number;
786     dfu_transfer_length = length;
787     ux_utility_memory_copy(dfu_device_buffer, data_pointer, UX_MIN(length, sizeof(dfu_device_buffer)));
788 
789     /* Here is where the data block is coming to be written to the firmware.  */
790     /* Some code needs to be inserted specifically for a target platform.  */
791     /* Return media status ok.  */
792     *media_status =  UX_SLAVE_CLASS_DFU_MEDIA_STATUS_OK    ;
793     return(UX_SUCCESS);
794 }
795 
demo_thread_dfu_get_status(VOID * dfu,ULONG * media_status)796 static UINT    demo_thread_dfu_get_status(VOID *dfu, ULONG *media_status)
797 {
798 
799     /* Return media status ok.  */
800     *media_status =  UX_SLAVE_CLASS_DFU_MEDIA_STATUS_OK    ;
801 
802     return(UX_SUCCESS);
803 }
804 
demo_thread_dfu_notify(VOID * dfu,ULONG notification)805 static UINT    demo_thread_dfu_notify(VOID *dfu, ULONG notification)
806 {
807     stepinfo("dfuNotify 0x%lx\n", notification);
808     switch (notification)
809     {
810 
811 
812         case    UX_SLAVE_CLASS_DFU_NOTIFICATION_BEGIN_DOWNLOAD        :
813 
814             /* Begin of Download. */
815             break;
816 
817         case    UX_SLAVE_CLASS_DFU_NOTIFICATION_END_DOWNLOAD        :
818 
819             /* Completion of Download. */
820             break;
821 
822         case    UX_SLAVE_CLASS_DFU_NOTIFICATION_ABORT_DOWNLOAD        :
823 
824             /* Download was aborted. */
825             break;
826 
827         case    UX_SLAVE_CLASS_DFU_NOTIFICATION_BEGIN_UPLOAD        :
828 
829             /* Begin of UPLOAD. */
830             break;
831 
832         case    UX_SLAVE_CLASS_DFU_NOTIFICATION_END_UPLOAD        :
833 
834             /* Completion of UPLOAD. */
835             break;
836 
837         case    UX_SLAVE_CLASS_DFU_NOTIFICATION_ABORT_UPLOAD        :
838 
839             /* Download was aborted. */
840             break;
841 
842         default :
843 
844             /* Bad notification signal. Should never get here.  */
845             break;
846 
847     }
848 
849     return(UX_SUCCESS);
850 }
851 
demo_thread_dfu_custom_request(VOID * dfu,UX_SLAVE_TRANSFER * transfer)852 static UINT demo_thread_dfu_custom_request(VOID *dfu, UX_SLAVE_TRANSFER *transfer)
853 {
854 UCHAR      *setup;
855 UCHAR      *buffer;
856 
857     /* Check state and request to insert custom operation, before the standard
858        handling process.
859        If no standard handling process is needed, return UX_SUCCESS.
860     */
861 
862    /* E.g., accept DNLOAD command with wLength 0 in dfuIDLE.  */
863    if (ux_device_class_dfu_state_get((UX_SLAVE_CLASS_DFU *)dfu) == UX_SLAVE_CLASS_DFU_STATUS_STATE_DFU_IDLE)
864    {
865        setup = transfer -> ux_slave_transfer_request_setup;
866        buffer = transfer -> ux_slave_transfer_request_data_pointer;
867 
868         if (setup[UX_SETUP_REQUEST] == UX_SLAVE_CLASS_DFU_COMMAND_DOWNLOAD &&
869             setup[UX_SETUP_LENGTH] == 0 &&
870             setup[UX_SETUP_LENGTH + 1] == 0)
871         {
872 
873             /* Accept the case (by default it's stalled).  */
874             stepinfo("dfuIDLE - accept dfuDNLOAD & wLength 0\n");
875 
876             /* Fill the status data payload.  First with status.  */
877             *buffer = UX_SLAVE_CLASS_DFU_STATUS_OK;
878 
879             /* Poll time out value is set to 500ms.  */
880             *(buffer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT) = UX_DW0(500);
881             *(buffer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT + 1) = UX_DW1(500);
882             *(buffer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT + 2) = UX_DW2(500);
883 
884             /* Next state: still dfuIDLE.  */
885             *(buffer + UX_SLAVE_CLASS_DFU_GET_STATUS_STATE) = (UCHAR) UX_SYSTEM_DFU_STATE_DFU_IDLE;
886 
887             /* String index set to 0.  */
888             *(buffer + UX_SLAVE_CLASS_DFU_GET_STATUS_STRING) = 0;
889 
890             /* We have a request to obtain the status of the DFU instance. */
891             _ux_device_stack_transfer_request(transfer, UX_SLAVE_CLASS_DFU_GET_STATUS_LENGTH, UX_SLAVE_CLASS_DFU_GET_STATUS_LENGTH);
892 
893             /* Inform stack it's taken.  */
894             return(UX_SUCCESS);
895         }
896     }
897 
898     /* No custom request.  */
899     return(UX_ERROR);
900 }
901