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_host_class_dpump.h"
9 #include "ux_device_class_dpump.h"
10
11
12 /* Define USBX demo constants. */
13
14 #define UX_DEMO_STACK_SIZE 4096
15 #define UX_DEMO_BUFFER_SIZE 2048
16 #define UX_DEMO_RUN 1
17 #define UX_DEMO_MEMORY_SIZE (64*1024)
18
19
20 /* Define the counters used in the demo application... */
21
22 static ULONG thread_0_counter;
23 static ULONG thread_1_counter;
24 static ULONG error_counter;
25
26
27 /* Define USBX demo global variables. */
28
29 static unsigned char host_out_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE];
30 static unsigned char host_in_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE];
31 static unsigned char slave_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE];
32
33 static UX_HOST_CLASS *class_driver;
34 static UX_HOST_CLASS_DPUMP *dpump;
35 static UX_SLAVE_CLASS_DPUMP *dpump_slave;
36
37 static UINT expected_error;
38
39 #define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50
40 static UCHAR device_framework_full_speed[] = {
41
42 /* Device descriptor */
43 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08,
44 0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
45 0x00, 0x01,
46
47 /* Configuration descriptor */
48 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0,
49 0x32,
50
51 /* Interface descriptor */
52 0x09, 0x04, 0x00, 0x00, 0x02, 0x99, 0x99, 0x99,
53 0x00,
54
55 /* Endpoint descriptor (Bulk Out) */
56 0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00,
57
58 #ifdef UX_DEVICE_BIDIRECTIONAL_ENDPOINT_SUPPORT
59 /* Endpoint descriptor (Bulk In) */
60 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00
61 #else
62 /* Endpoint descriptor (Bulk In) */
63 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00
64 #endif
65 };
66
67
68 #define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60
69 static UCHAR device_framework_high_speed[] = {
70
71 /* Device descriptor */
72 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40,
73 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02,
74 0x03, 0x01,
75
76 /* Device qualifier descriptor */
77 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40,
78 0x01, 0x00,
79
80 /* Configuration descriptor */
81 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0,
82 0x32,
83
84 /* Interface descriptor */
85 0x09, 0x04, 0x00, 0x00, 0x02, 0x99, 0x99, 0x99,
86 0x00,
87
88 /* Endpoint descriptor (Bulk Out) */
89 0x07, 0x05, 0x01, 0x02, 0x00, 0x02, 0x00,
90
91 #ifdef UX_DEVICE_BIDIRECTIONAL_ENDPOINT_SUPPORT
92 /* Endpoint descriptor (Bulk In) */
93 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00
94 #else
95 /* Endpoint descriptor (Bulk In) */
96 0x07, 0x05, 0x82, 0x02, 0x00, 0x02, 0x00
97 #endif
98 };
99
100 /* String Device Framework :
101 Byte 0 and 1 : Word containing the language ID : 0x0904 for US
102 Byte 2 : Byte containing the index of the descriptor
103 Byte 3 : Byte containing the length of the descriptor string
104 */
105
106 #define STRING_FRAMEWORK_LENGTH 38
107 static UCHAR string_framework[] = {
108
109 /* Manufacturer string descriptor : Index 1 */
110 0x09, 0x04, 0x01, 0x0c,
111 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c,
112 0x6f, 0x67, 0x69, 0x63,
113
114 /* Product string descriptor : Index 2 */
115 0x09, 0x04, 0x02, 0x0c,
116 0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70,
117 0x44, 0x65, 0x6d, 0x6f,
118
119 /* Serial Number string descriptor : Index 3 */
120 0x09, 0x04, 0x03, 0x04,
121 0x30, 0x30, 0x30, 0x31
122 };
123
124
125 /* Multiple languages are supported on the device, to add
126 a language besides English, the unicode language code must
127 be appended to the language_id_framework array and the length
128 adjusted accordingly. */
129 #define LANGUAGE_ID_FRAMEWORK_LENGTH 2
130 static UCHAR language_id_framework[] = {
131
132 /* English. */
133 0x09, 0x04
134 };
135
136
137 /* Define prototypes for external Host Controller's (HCDs), classes and clients. */
138
139 static VOID tx_demo_instance_activate(VOID *dpump_instance);
140 static VOID tx_demo_instance_deactivate(VOID *dpump_instance);
141
142 #if defined(UX_HOST_STANDALONE)
143 static UINT tx_demo_host_change_function(ULONG e, UX_HOST_CLASS *c, VOID *p);
144 #else
145 #define tx_demo_host_change_function UX_NULL
146 #endif
147
148 UINT _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command);
149 UINT ux_hcd_sim_initialize(UX_HCD *hcd);
150 UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer,
151 ULONG requested_length, ULONG *actual_length);
152 UINT _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer,
153 ULONG requested_length, ULONG *actual_length);
154
155 static TX_THREAD tx_demo_thread_host_simulation;
156 static TX_THREAD tx_demo_thread_slave_simulation;
157 static void tx_demo_thread_host_simulation_entry(ULONG);
158 static void tx_demo_thread_slave_simulation_entry(ULONG);
159
160
161 /* Define the ISR dispatch. */
162
163 extern VOID (*test_isr_dispatch)(void);
164
165
166 /* Prototype for test control return. */
167
168 void test_control_return(UINT status);
169
170
171 /* Define the ISR dispatch routine. */
172
test_isr(void)173 static void test_isr(void)
174 {
175
176 /* For further expansion of interrupt-level testing. */
177 }
178
179
error_callback(UINT system_level,UINT system_context,UINT error_code)180 static VOID error_callback(UINT system_level, UINT system_context, UINT error_code)
181 {
182 if (expected_error == 0 || error_code != expected_error)
183 {
184 /* Failed test. */
185 printf("Error on line %d, system_level: %d, system_context: %d, error code: %x\n", __LINE__, system_level, system_context, error_code);
186 // test_control_return(1);
187 }
188 }
189
190 /* Define what the initial system looks like. */
191
192 #ifdef CTEST
test_application_define(void * first_unused_memory)193 void test_application_define(void *first_unused_memory)
194 #else
195 void usbx_dpump_basic_test_application_define(void *first_unused_memory)
196 #endif
197 {
198
199 UINT status;
200 CHAR *stack_pointer;
201 CHAR *memory_pointer;
202 UX_SLAVE_CLASS_DPUMP_PARAMETER parameter;
203
204
205 /* Initialize the free memory pointer. */
206 stack_pointer = (CHAR *) first_unused_memory;
207 memory_pointer = stack_pointer + (UX_DEMO_STACK_SIZE * 2);
208
209 /* Initialize USBX Memory. */
210 status = ux_system_initialize(memory_pointer, UX_DEMO_MEMORY_SIZE, UX_NULL, 0);
211
212 /* Check for error. */
213 if (status != UX_SUCCESS)
214 {
215
216 printf("Running DPUMP Basic Functionality Test.............................. ERROR #1\n");
217 test_control_return(1);
218 }
219
220 /* Register the error callback. */
221 _ux_utility_error_callback_register(error_callback);
222
223 /* The code below is required for installing the host portion of USBX. */
224 status = ux_host_stack_initialize(tx_demo_host_change_function);
225
226 /* Check for error. */
227 if (status != UX_SUCCESS)
228 {
229
230 printf("Running DPUMP Basic Functionality Test.............................. ERROR #2\n");
231 test_control_return(1);
232 }
233
234 /* Register all the host class drivers for this USBX implementation. */
235 status = ux_host_stack_class_register(_ux_system_host_class_dpump_name, ux_host_class_dpump_entry);
236
237 /* Check for error. */
238 if (status != UX_SUCCESS)
239 {
240
241 printf("Running DPUMP Basic Functionality Test.............................. ERROR #3\n");
242 test_control_return(1);
243 }
244
245 /* The code below is required for installing the device portion of USBX */
246 status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED,
247 device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED,
248 string_framework, STRING_FRAMEWORK_LENGTH,
249 language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL);
250
251 /* Check for error. */
252 if (status != UX_SUCCESS)
253 {
254
255 printf("Running DPUMP Basic Functionality Test.............................. ERROR #5\n");
256 test_control_return(1);
257 }
258
259 /* Set the parameters for callback when insertion/extraction of a Data Pump device. */
260 parameter.ux_slave_class_dpump_instance_activate = tx_demo_instance_activate;
261 parameter.ux_slave_class_dpump_instance_deactivate = tx_demo_instance_deactivate;
262
263 /* Initialize the device dpump class. The class is connected with interface 0 */
264 status = ux_device_stack_class_register(_ux_system_slave_class_dpump_name, _ux_device_class_dpump_entry,
265 1, 0, ¶meter);
266
267 /* Check for error. */
268 if (status != UX_SUCCESS)
269 {
270
271 printf("Running DPUMP Basic Functionality Test.............................. ERROR #6\n");
272 test_control_return(1);
273 }
274
275 /* Initialize the simulated device controller. */
276 status = _ux_dcd_sim_slave_initialize();
277
278 /* Check for error. */
279 if (status != UX_SUCCESS)
280 {
281
282 printf("Running DPUMP Basic Functionality Test.............................. ERROR #7\n");
283 test_control_return(1);
284 }
285
286 /* Register all the USB host controllers available in this system */
287 status = ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, ux_hcd_sim_host_initialize,0,0);
288
289 /* Check for error. */
290 if (status != UX_SUCCESS)
291 {
292
293 printf("Running DPUMP Basic Functionality Test.............................. ERROR #4\n");
294 test_control_return(1);
295 }
296
297 /* Create the main host simulation thread. */
298 status = tx_thread_create(&tx_demo_thread_host_simulation, "tx demo host simulation", tx_demo_thread_host_simulation_entry, 0,
299 stack_pointer, UX_DEMO_STACK_SIZE,
300 20, 20, 1, TX_AUTO_START);
301
302 /* Check for error. */
303 if (status != TX_SUCCESS)
304 {
305
306 printf("Running DPUMP Basic Functionality Test.............................. ERROR #8\n");
307 test_control_return(1);
308 }
309
310 /* Create the main demo thread. */
311 status = tx_thread_create(&tx_demo_thread_slave_simulation, "tx demo slave simulation", tx_demo_thread_slave_simulation_entry, 0,
312 stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE,
313 20, 20, 1, TX_AUTO_START);
314
315 /* Check for error. */
316 if (status != TX_SUCCESS)
317 {
318
319 printf("Running DPUMP Basic Functionality Test.............................. ERROR #9\n");
320 test_control_return(1);
321 }
322 }
323
324
tx_demo_thread_host_simulation_entry(ULONG arg)325 static void tx_demo_thread_host_simulation_entry(ULONG arg)
326 {
327
328 UINT status;
329 ULONG actual_length;
330 UCHAR current_char;
331 UX_HOST_CLASS *class;
332 UINT i;
333 #if 0
334 UX_ENDPOINT *endpoint;
335 #endif
336
337
338 /* Inform user. */
339 printf("Running DPUMP Basic Functionality Test.............................. ");
340
341 /* Find the class container with unregistered name. */
342 status = ux_host_stack_class_get(_ux_system_host_class_hid_name, &class);
343
344 /* Should return error. */
345 if (status != UX_HOST_CLASS_UNKNOWN)
346 {
347
348 /* DPUMP basic test error. */
349 printf("ERROR #10\n");
350 test_control_return(1);
351 }
352
353 /* Find the main data pump container. */
354 status = ux_host_stack_class_get(_ux_system_host_class_dpump_name, &class);
355
356 /* Check for error. */
357 if (status != UX_SUCCESS)
358 {
359
360 /* DPUMP basic test error. */
361 printf("ERROR #10\n");
362 test_control_return(1);
363 }
364
365 /* We get the first instance of the data pump device. */
366 do
367 {
368
369 status = ux_host_stack_class_instance_get(class, 0, (VOID **) &dpump);
370
371 #if defined(UX_HOST_STANDALONE)
372 ux_system_tasks_run();
373 #endif
374 tx_thread_relinquish();
375
376 } while (status != UX_SUCCESS);
377
378 /* We still need to wait for the data pump status to be live. */
379 while (dpump -> ux_host_class_dpump_state != UX_HOST_CLASS_INSTANCE_LIVE)
380 {
381
382 #if defined(UX_HOST_STANDALONE)
383 ux_system_tasks_run();
384 #endif
385 tx_thread_relinquish();
386
387 }
388
389 /* At this point, the data pump class has been found. Now use the
390 data pump to send and receive data between the host and device. */
391
392 /* We start with a 'A' in buffer. */
393 current_char = 'A';
394
395 /* Perform this test sequence 100 times. */
396 for (i = 0; i < 100; i++)
397 {
398
399 /* Increment thread counter. */
400 thread_0_counter++;
401
402 /* Initialize the write buffer. */
403 _ux_utility_memory_set(host_out_buffer, current_char, UX_HOST_CLASS_DPUMP_PACKET_SIZE);
404
405 /* Increment the character in buffer. */
406 current_char++;
407
408 /* Check for upper alphabet limit. */
409 if (current_char > 'Z')
410 current_char = 'A';
411
412 /* Write to the host Data Pump Bulk out endpoint. */
413 status = _ux_host_class_dpump_write (dpump, host_out_buffer, UX_HOST_CLASS_DPUMP_PACKET_SIZE, &actual_length);
414
415 /* Check for error. */
416 if (status != UX_SUCCESS)
417 {
418
419 /* DPUMP basic test error. */
420 printf("ERROR #%d: 0x%x\n", __LINE__, status);
421 test_control_return(1);
422 }
423
424 /* Verify that the status and the amount of data is correct. */
425 if ((status != UX_SUCCESS) || actual_length != UX_HOST_CLASS_DPUMP_PACKET_SIZE)
426 {
427
428 /* DPUMP basic test error. */
429 printf("ERROR #12\n");
430 test_control_return(1);
431 }
432
433 #if defined(UX_HOST_STANDALONE)
434 /* Relinquish to other thread. */
435 tx_thread_relinquish();
436 #endif
437
438 /* Read to the Data Pump Bulk out endpoint. */
439 status = _ux_host_class_dpump_read (dpump, host_in_buffer, UX_HOST_CLASS_DPUMP_PACKET_SIZE, &actual_length);
440
441 /* Verify that the status and the amount of data is correct. */
442 if ((status != UX_SUCCESS) || actual_length != UX_HOST_CLASS_DPUMP_PACKET_SIZE)
443 {
444
445 /* DPUMP basic test error. */
446 printf("ERROR #13\n");
447 test_control_return(1);
448 }
449
450 /* Relinquish to other thread. */
451 tx_thread_relinquish();
452 }
453
454 #if 0
455 /* Test ux_host_stack_endpoint_reset with invalid endpoint number. */
456 endpoint = dpump -> ux_host_class_dpump_interface -> ux_interface_first_endpoint;
457 endpoint -> ux_endpoint_descriptor.bEndpointAddress = 0xf;
458 expected_error = UX_TRANSFER_STALLED;
459 status = _ux_host_stack_endpoint_reset(endpoint);
460
461 /* Check for error. */
462 if (status == UX_SUCCESS)
463 {
464
465 /* DPUMP basic test error. */
466 printf("ERROR #14\n");
467 test_control_return(1);
468 }
469 #endif
470
471 expected_error = 0;
472
473 /* Sleep for a tick to make sure everything is complete. */
474 tx_thread_sleep(1);
475
476 /* Check for errors from other threads. */
477 if (error_counter)
478 {
479
480 /* DPUMP error. */
481 printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter);
482 test_control_return(1);
483 }
484 else
485 {
486
487 /* Successful test. */
488 printf("SUCCESS!\n");
489 test_control_return(0);
490 }
491 }
492
493
tx_demo_thread_slave_simulation_entry(ULONG arg)494 static void tx_demo_thread_slave_simulation_entry(ULONG arg)
495 {
496
497 UINT status;
498 ULONG actual_length;
499 #if defined(UX_DEVICE_STANDALONE)
500 #define DPUMP_DEVICE_STATE_READ UX_STATE_STEP
501 #define DPUMP_DEVICE_STATE_WRITE UX_STATE_STEP + 1
502 UINT dpump_device_state = UX_STATE_RESET;
503 #endif
504
505
506 while(1)
507 {
508 #if defined(UX_DEVICE_STANDALONE)
509
510 /* Run device tasks. */
511 ux_system_tasks_run();
512
513 /* DPUMP echo state machine. */
514 switch(dpump_device_state)
515 {
516 case UX_STATE_RESET:
517 if (dpump_slave != UX_NULL)
518
519 /* Start reading. */
520 dpump_device_state = DPUMP_DEVICE_STATE_READ;
521 break;
522
523 case DPUMP_DEVICE_STATE_READ:
524
525 /* Read from the device data pump. */
526 if (dpump_slave == UX_NULL)
527 {
528 dpump_device_state = UX_STATE_RESET;
529 break;
530 }
531 status = ux_device_class_dpump_read_run(dpump_slave, slave_buffer, UX_HOST_CLASS_DPUMP_PACKET_SIZE, &actual_length);
532
533 if (status < UX_STATE_NEXT)
534 {
535 printf("ERROR #%d: read status 0x%x\n", __LINE__, status);
536 error_counter ++;
537 return;
538 }
539
540 if (status == UX_STATE_NEXT)
541 {
542 if (actual_length != UX_HOST_CLASS_DPUMP_PACKET_SIZE)
543 {
544 printf("ERROR #%d: read length %ld\n", __LINE__, actual_length);
545 error_counter ++;
546 return;
547 }
548
549 dpump_device_state = DPUMP_DEVICE_STATE_WRITE;
550 }
551 break;
552
553 case DPUMP_DEVICE_STATE_WRITE:
554
555 /* Now write to the device data pump. */
556 if (dpump_slave == UX_NULL)
557 {
558 dpump_device_state = UX_STATE_RESET;
559 break;
560 }
561 status = ux_device_class_dpump_write_run(dpump_slave, slave_buffer, UX_HOST_CLASS_DPUMP_PACKET_SIZE, &actual_length);
562
563 if (status < UX_STATE_NEXT)
564 {
565 printf("ERROR #%d: write status 0x%x\n", __LINE__, status);
566 error_counter ++;
567 return;
568 }
569
570 if (status == UX_STATE_NEXT)
571 dpump_device_state = DPUMP_DEVICE_STATE_READ;
572 break;
573
574 default:
575 dpump_device_state = UX_STATE_RESET;
576 }
577
578 /* Increment thread counter. */
579 thread_1_counter++;
580
581 /* Relinquish to other thread. */
582 tx_thread_relinquish();
583
584 #else
585 /* Ensure the dpump class on the device is still alive. */
586 while (dpump_slave != UX_NULL)
587 {
588
589 /* Increment thread counter. */
590 thread_1_counter++;
591
592 /* Read from the device data pump. */
593 status = _ux_device_class_dpump_read(dpump_slave, slave_buffer, UX_HOST_CLASS_DPUMP_PACKET_SIZE, &actual_length);
594
595 /* Verify that the status and the amount of data is correct. */
596 if ((status != UX_SUCCESS) || actual_length != UX_HOST_CLASS_DPUMP_PACKET_SIZE)
597 {
598 printf("ERROR #%d.%ld: read status 0x%x, length %ld\n", __LINE__, thread_1_counter, status, actual_length);
599
600 /* Increment error counter. */
601 error_counter++;
602
603 /* Return from thread. */
604 return;
605 }
606
607 /* Now write to the device data pump. */
608 status = _ux_device_class_dpump_write(dpump_slave, slave_buffer, UX_HOST_CLASS_DPUMP_PACKET_SIZE, &actual_length);
609
610 /* Verify that the status and the amount of data is correct. */
611 if ((status != UX_SUCCESS) || actual_length != UX_HOST_CLASS_DPUMP_PACKET_SIZE)
612 {
613 printf("ERROR #%d.%ld: write status 0x%x, length %ld\n", __LINE__, thread_1_counter, status, actual_length);
614
615 /* Increment error counter. */
616 error_counter++;
617
618 /* Return from thread. */
619 return;
620 }
621 }
622
623 /* Relinquish to other thread. */
624 tx_thread_relinquish();
625 #endif
626 }
627 }
628
tx_demo_instance_activate(VOID * dpump_instance)629 static VOID tx_demo_instance_activate(VOID *dpump_instance)
630 {
631
632 /* Save the DPUMP instance. */
633 dpump_slave = (UX_SLAVE_CLASS_DPUMP *) dpump_instance;
634 }
635
tx_demo_instance_deactivate(VOID * dpump_instance)636 static VOID tx_demo_instance_deactivate(VOID *dpump_instance)
637 {
638
639 /* Reset the DPUMP instance. */
640 dpump_slave = UX_NULL;
641 }
642
643 #if defined(UX_HOST_STANDALONE)
tx_demo_host_change_function(ULONG e,UX_HOST_CLASS * c,VOID * p)644 static UINT tx_demo_host_change_function(ULONG e, UX_HOST_CLASS *c, VOID *p)
645 {
646 if (e == UX_STANDALONE_WAIT_BACKGROUND_TASK)
647 {
648 tx_thread_relinquish();
649 }
650 }
651 #endif
652