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