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, &parameter);
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