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 
9 #include "fx_api.h"
10 
11 #include "ux_device_class_cdc_acm.h"
12 #include "ux_device_stack.h"
13 #include "ux_host_class_cdc_acm.h"
14 
15 #include "ux_test_dcd_sim_slave.h"
16 #include "ux_test_hcd_sim_host.h"
17 #include "ux_test_utility_sim.h"
18 
19 /* Define constants.  */
20 #define                             UX_DEMO_DEBUG_SIZE  (4096*8)
21 #define                             UX_DEMO_STACK_SIZE  1024
22 #define                             UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1)
23 #define                             UX_DEMO_XMIT_BUFFER_SIZE 512
24 #define                             UX_DEMO_RECEPTION_BUFFER_SIZE 512
25 #define                             UX_DEMO_FILE_BUFFER_SIZE 512
26 #define                             UX_DEMO_RECEPTION_BLOCK_SIZE 64
27 #define                             UX_DEMO_MEMORY_SIZE     (64*1024)
28 #define                             UX_DEMO_FILE_SIZE       (128 * 1024)
29 #define                             UX_RAM_DISK_MEMORY      (256 * 1024)
30 
31 /* Define local/extern function prototypes.  */
32 static TX_THREAD   ux_test_thread_host_simulation;
33 static TX_THREAD   ux_test_thread_slave_simulation;
34 static void        ux_test_thread_host_simulation_entry(ULONG);
35 static void        ux_test_thread_slave_simulation_entry(ULONG);
36 
37 static VOID        test_cdc_instance_activate(VOID  *cdc_instance);
38 static VOID        test_cdc_instance_deactivate(VOID *cdc_instance);
39 static VOID        test_cdc_instance_parameter_change(VOID *cdc_instance);
40 
41 static VOID        ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *params);
42 
43 /* Define global data structures.  */
44 static UCHAR                               usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)];
45 static UX_HOST_CLASS                       *class_driver;
46 static UX_HOST_CLASS_CDC_ACM               *cdc_acm_host_control;
47 static UX_HOST_CLASS_CDC_ACM               *cdc_acm_host_data;
48 static UX_HOST_CLASS_CDC_ACM_RECEPTION     cdc_acm_host_reception;
49 static UCHAR                               cdc_acm_host_reception_buffer[UX_DEMO_RECEPTION_BUFFER_SIZE];
50 static UINT                                cdc_acm_host_reception_status = 0;
51 static ULONG                               cdc_acm_host_reception_count = 0;
52 static UCHAR                               cdc_acm_host_read_buffer[UX_SLAVE_REQUEST_DATA_MAX_LENGTH * 2];
53 static ULONG                               cdc_acm_host_read_buffer_length;
54 
55 static UX_SLAVE_CLASS_CDC_ACM              *cdc_acm_slave;
56 static UX_SLAVE_CLASS_CDC_ACM_PARAMETER    parameter;
57 static UCHAR                               cdc_acm_slave_change;
58 static UX_SLAVE_CLASS_CDC_ACM_LINE_CODING_PARAMETER cdc_acm_slave_line_coding;
59 static UX_SLAVE_CLASS_CDC_ACM_LINE_STATE_PARAMETER  cdc_acm_slave_line_state;
60 static ULONG                               device_read_length = UX_SLAVE_REQUEST_DATA_MAX_LENGTH;
61 static UCHAR                               device_buffer[UX_SLAVE_REQUEST_DATA_MAX_LENGTH * 2];
62 
63 static UCHAR                               host_buffer[UX_SLAVE_REQUEST_DATA_MAX_LENGTH * 2];
64 
65 static ULONG                               set_cfg_counter;
66 
67 static ULONG                               rsc_mem_alloc_cnt_on_set_cfg;
68 static ULONG                               rsc_sem_on_set_cfg;
69 static ULONG                               rsc_sem_get_on_set_cfg;
70 static ULONG                               rsc_mutex_on_set_cfg;
71 
72 static ULONG                               rsc_enum_sem_usage;
73 static ULONG                               rsc_enum_sem_get_count;
74 static ULONG                               rsc_enum_mutex_usage;
75 static ULONG                               rsc_enum_mem_alloc_count;
76 
77 static ULONG                               rsc_cdc_sem_usage;
78 static ULONG                               rsc_cdc_sem_get_count;
79 static ULONG                               rsc_cdc_mutex_usage;
80 static ULONG                               rsc_cdc_mem_alloc_count;
81 
82 static ULONG                               interaction_count;
83 
84 static UCHAR                               error_callback_ignore = UX_TRUE;
85 static ULONG                               error_callback_counter;
86 
87 /* Define device framework.  */
88 
89 #define             DEVICE_FRAMEWORK_LENGTH_FULL_SPEED      93
90 #define             DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED      103
91 #define             STRING_FRAMEWORK_LENGTH                 47
92 #define             LANGUAGE_ID_FRAMEWORK_LENGTH            2
93 
94 static unsigned char device_framework_full_speed[] = {
95 
96     /* Device descriptor     18 bytes
97        0x02 bDeviceClass:    CDC class code
98        0x00 bDeviceSubclass: CDC class sub code
99        0x00 bDeviceProtocol: CDC Device protocol
100 
101        idVendor & idProduct - http://www.linux-usb.org/usb.ids
102     */
103     0x12, 0x01, 0x10, 0x01,
104     0xEF, 0x02, 0x01,
105     0x08,
106     0x84, 0x84, 0x00, 0x00,
107     0x00, 0x01,
108     0x01, 0x02, 03,
109     0x01,
110 
111     /* Configuration 1 descriptor 9 bytes */
112     0x09, 0x02, 0x4b, 0x00,
113     0x02, 0x01, 0x00,
114     0x40, 0x00,
115 
116     /* Interface association descriptor. 8 bytes.  */
117     0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00,
118 
119     /* Communication Class Interface Descriptor Requirement. 9 bytes.   */
120     0x09, 0x04, 0x00,
121     0x00,
122     0x01,
123     0x02, 0x02, 0x01,
124     0x00,
125 
126     /* Header Functional Descriptor 5 bytes */
127     0x05, 0x24, 0x00,
128     0x10, 0x01,
129 
130     /* ACM Functional Descriptor 4 bytes */
131     0x04, 0x24, 0x02,
132     0x0f,
133 
134     /* Union Functional Descriptor 5 bytes */
135     0x05, 0x24, 0x06,
136     0x00,                          /* Master interface */
137     0x01,                          /* Slave interface  */
138 
139     /* Call Management Functional Descriptor 5 bytes */
140     0x05, 0x24, 0x01,
141     0x03,
142     0x01,                          /* Data interface   */
143 
144     /* Endpoint 0x83 descriptor 7 bytes */
145     0x07, 0x05, 0x83,
146     0x03,
147     0x08, 0x00,
148     0xFF,
149 
150     /* Data Class Interface Descriptor Requirement 9 bytes */
151     0x09, 0x04, 0x01,
152     0x00,
153     0x02,
154     0x0A, 0x00, 0x00,
155     0x00,
156 
157     /* Endpoint 0x02 descriptor 7 bytes */
158     0x07, 0x05, 0x02, /* @ 93 - 14 + 2 = 81 */
159     0x02,
160     0x40, 0x00,
161     0x00,
162 
163     /* Endpoint 0x81 descriptor 7 bytes */
164     0x07, 0x05, 0x81, /* @ 93 - 7 + 2 = 88 */
165     0x02,
166     0x40, 0x00,
167     0x00,
168 
169 };
170 
171 #define DEVICE_FRAMEWORK_EPA_POS_1_FS (DEVICE_FRAMEWORK_LENGTH_FULL_SPEED - 14 + 2)
172 #define DEVICE_FRAMEWORK_EPA_POS_2_FS (DEVICE_FRAMEWORK_LENGTH_FULL_SPEED - 7 + 2)
173 
174 static unsigned char device_framework_high_speed[] = {
175 
176     /* Device descriptor
177        0x02 bDeviceClass:    CDC class code
178        0x00 bDeviceSubclass: CDC class sub code
179        0x00 bDeviceProtocol: CDC Device protocol
180 
181        idVendor & idProduct - http://www.linux-usb.org/usb.ids
182     */
183     0x12, 0x01, 0x00, 0x02,
184     0xEF, 0x02, 0x01,
185     0x40,
186     0x84, 0x84, 0x00, 0x00,
187     0x00, 0x01,
188     0x01, 0x02, 03,
189     0x01,
190 
191     /* Device qualifier descriptor */
192     0x0a, 0x06, 0x00, 0x02,
193     0x02, 0x00, 0x00,
194     0x40,
195     0x01,
196     0x00,
197 
198     /* Configuration 1 descriptor */
199     0x09, 0x02, 0x4b, 0x00,
200     0x02, 0x01, 0x00,
201     0x40, 0x00,
202 
203     /* Interface association descriptor. */
204     0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00,
205 
206     /* Communication Class Interface Descriptor Requirement */
207     0x09, 0x04, 0x00,
208     0x00,
209     0x01,
210     0x02, 0x02, 0x01,
211     0x00,
212 
213     /* Header Functional Descriptor */
214     0x05, 0x24, 0x00,
215     0x10, 0x01,
216 
217     /* ACM Functional Descriptor */
218     0x04, 0x24, 0x02,
219     0x0f,
220 
221     /* Union Functional Descriptor */
222     0x05, 0x24, 0x06,
223     0x00,
224     0x01,
225 
226     /* Call Management Functional Descriptor */
227     0x05, 0x24, 0x01,
228     0x00,
229     0x01,
230 
231     /* Endpoint 0x83 descriptor */
232     0x07, 0x05, 0x83,
233     0x03,
234     0x08, 0x00,
235     0xFF,
236 
237     /* Data Class Interface Descriptor Requirement */
238     0x09, 0x04, 0x01,
239     0x00,
240     0x02,
241     0x0A, 0x00, 0x00,
242     0x00,
243 
244     /* Endpoint 0x02 descriptor */
245     0x07, 0x05, 0x02, /* @ 103 - 14 + 2 = 91 */
246     0x02,
247     0x40, 0x00,
248     0x00,
249 
250     /* Endpoint 0x81 descriptor */
251     0x07, 0x05, 0x81, /* @ 103 - 7 + 2 = 98 */
252     0x02,
253     0x40, 0x00,
254     0x00,
255 
256 };
257 
258 #define DEVICE_FRAMEWORK_EPA_POS_1_HS (DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED - 14 + 2)
259 #define DEVICE_FRAMEWORK_EPA_POS_2_HS (DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED - 7 + 2)
260 
261 static unsigned char string_framework[] = {
262 
263     /* Manufacturer string descriptor : Index 1 - "Express Logic" */
264         0x09, 0x04, 0x01, 0x0c,
265         0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c,
266         0x6f, 0x67, 0x69, 0x63,
267 
268     /* Product string descriptor : Index 2 - "EL Composite device" */
269         0x09, 0x04, 0x02, 0x13,
270         0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f,
271         0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76,
272         0x69, 0x63, 0x65,
273 
274     /* Serial Number string descriptor : Index 3 - "0001" */
275         0x09, 0x04, 0x03, 0x04,
276         0x30, 0x30, 0x30, 0x31
277     };
278 
279 
280     /* Multiple languages are supported on the device, to add
281        a language besides english, the unicode language code must
282        be appended to the language_id_framework array and the length
283        adjusted accordingly. */
284 static unsigned char language_id_framework[] = {
285 
286     /* English. */
287         0x09, 0x04
288     };
289 
290 /* Setup requests */
291 
292 static UX_TEST_SETUP _SetConfigure = UX_TEST_SETUP_SetConfigure;
293 
294 static UX_TEST_HCD_SIM_ACTION log_on_SetCfg[] = {
295 /* function, request to match,
296    port action, port status,
297    request action, request EP, request data, request actual length, request status,
298    status, additional callback,
299    no_return */
300 {   UX_HCD_TRANSFER_REQUEST, &_SetConfigure,
301         UX_FALSE, UX_TEST_PORT_STATUS_DISC,
302         UX_TEST_SETUP_MATCH_REQ, 0, UX_NULL, 0, 0,
303         UX_SUCCESS, ux_test_hcd_entry_set_cfg,
304         UX_TRUE}, /* Invoke callback & continue */
305 {   0   }
306 };
307 
308 /* Define the ISR dispatch.  */
309 
310 extern VOID    (*test_isr_dispatch)(void);
311 
312 
313 /* Prototype for test control return.  */
314 
315 void  test_control_return(UINT status);
316 
317 
318 /* Define the ISR dispatch routine.  */
319 
test_isr(void)320 static void    test_isr(void)
321 {
322 
323     /* For further expansion of interrupt-level testing.  */
324 }
325 
error_callback(UINT system_level,UINT system_context,UINT error_code)326 static VOID error_callback(UINT system_level, UINT system_context, UINT error_code)
327 {
328 
329     error_callback_counter ++;
330 
331     if (!error_callback_ignore)
332     {
333         {
334             /* Failed test.  */
335             printf("Error #%d, system_level: %d, system_context: %d, error_code: 0x%x\n", __LINE__, system_level, system_context, error_code);
336             test_control_return(1);
337         }
338     }
339 }
340 
sleep_break_on_error(VOID)341 static UINT  sleep_break_on_error(VOID)
342 {
343 
344     if (error_callback_counter >= 3)
345         return error_callback_counter;
346 
347     return UX_SUCCESS;
348 }
349 
demo_class_cdc_acm_get(void)350 static UINT  demo_class_cdc_acm_get(void)
351 {
352 
353 UINT                                status;
354 UX_HOST_CLASS                       *class;
355 UX_HOST_CLASS_CDC_ACM               *cdc_acm_host;
356 
357 
358     /* Find the main cdc_acm container */
359     status =  ux_host_stack_class_get(_ux_system_host_class_cdc_acm_name, &class);
360     if (status != UX_SUCCESS)
361         return(status);
362 
363     /* We get the first instance of the cdc_acm device */
364     do
365     {
366 
367         status =  ux_host_stack_class_instance_get(class, 0, (void **) &cdc_acm_host);
368         tx_thread_sleep(10);
369     } while (status != UX_SUCCESS);
370 
371     /* We still need to wait for the cdc_acm status to be live */
372     while (cdc_acm_host -> ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE)
373         tx_thread_sleep(10);
374 
375     /* Isolate both the control and data interfaces.  */
376     if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_DATA_CLASS)
377     {
378         /* This is the data interface.  */
379         cdc_acm_host_data = cdc_acm_host;
380 
381         /* In that case, the second one should be the control interface.  */
382         status =  ux_host_stack_class_instance_get(class, 1, (void **) &cdc_acm_host);
383 
384         /* Check error.  */
385         if (status != UX_SUCCESS)
386             return(status);
387 
388         /* Check for the control interfaces.  */
389         if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS)
390         {
391 
392             /* This is the control interface.  */
393             cdc_acm_host_control = cdc_acm_host;
394 
395             return(UX_SUCCESS);
396 
397         }
398     }
399     else
400     {
401         /* Check for the control interfaces.  */
402         if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS)
403         {
404 
405             /* This is the control interface.  */
406             cdc_acm_host_control = cdc_acm_host;
407 
408             /* In that case, the second one should be the data interface.  */
409             status =  ux_host_stack_class_instance_get(class, 1, (void **) &cdc_acm_host);
410 
411             /* Check error.  */
412             if (status != UX_SUCCESS)
413                 return(status);
414 
415             /* Check for the data interface.  */
416             if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_DATA_CLASS)
417             {
418 
419                 /* This is the data interface.  */
420                 cdc_acm_host_data = cdc_acm_host;
421 
422                 return(UX_SUCCESS);
423 
424             }
425         }
426     }
427 
428     /* Return ERROR.  */
429     return(UX_ERROR);
430 }
431 
demo_system_host_change_function(ULONG event,UX_HOST_CLASS * cls,VOID * inst)432 static UINT demo_system_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst)
433 {
434 
435 UX_HOST_CLASS_CDC_ACM *cdc_acm = (UX_HOST_CLASS_CDC_ACM *) inst;
436 
437     switch(event)
438     {
439 
440         case UX_DEVICE_INSERTION:
441 
442             if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS)
443                 cdc_acm_host_control = cdc_acm;
444             else
445                 cdc_acm_host_data = cdc_acm;
446             break;
447 
448         case UX_DEVICE_REMOVAL:
449 
450             if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS)
451                 cdc_acm_host_control = UX_NULL;
452             else
453                 cdc_acm_host_data = UX_NULL;
454             break;
455 
456         default:
457             break;
458     }
459     return 0;
460 }
461 
test_cdc_instance_activate(VOID * cdc_instance)462 static VOID    test_cdc_instance_activate(VOID *cdc_instance)
463 {
464 
465     /* Save the CDC instance.  */
466     cdc_acm_slave = (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance;
467 }
test_cdc_instance_deactivate(VOID * cdc_instance)468 static VOID test_cdc_instance_deactivate(VOID *cdc_instance)
469 {
470 
471     /* Reset the CDC instance.  */
472     cdc_acm_slave = UX_NULL;
473 }
474 
test_cdc_instance_parameter_change(VOID * cdc_instance)475 static VOID test_cdc_instance_parameter_change(VOID *cdc_instance)
476 {
477 
478     /* Set CDC parameter change flag. */
479     cdc_acm_slave_change = UX_TRUE;
480 
481     /* Get new paramster.  */
482     ux_device_class_cdc_acm_ioctl(cdc_acm_slave,
483                                 UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_CODING,
484                                 (VOID*)&cdc_acm_slave_line_coding);
485     ux_device_class_cdc_acm_ioctl(cdc_acm_slave,
486                                 UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_CODING,
487                                 (VOID*)&cdc_acm_slave_line_state);
488 }
489 
test_swap_framework_bulk_ep_descriptors(VOID)490 static VOID test_swap_framework_bulk_ep_descriptors(VOID)
491 {
492 UCHAR tmp;
493 
494     tmp = device_framework_full_speed[DEVICE_FRAMEWORK_EPA_POS_1_FS];
495     device_framework_full_speed[DEVICE_FRAMEWORK_EPA_POS_1_FS] = device_framework_full_speed[DEVICE_FRAMEWORK_EPA_POS_2_FS];
496     device_framework_full_speed[DEVICE_FRAMEWORK_EPA_POS_2_FS] = tmp;
497 
498     tmp = device_framework_high_speed[DEVICE_FRAMEWORK_EPA_POS_1_HS];
499     device_framework_high_speed[DEVICE_FRAMEWORK_EPA_POS_1_HS] = device_framework_high_speed[DEVICE_FRAMEWORK_EPA_POS_2_HS];
500     device_framework_high_speed[DEVICE_FRAMEWORK_EPA_POS_2_HS] = tmp;
501 }
502 
ux_test_hcd_entry_set_cfg(UX_TEST_ACTION * action,VOID * _params)503 static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *_params)
504 {
505 
506     set_cfg_counter ++;
507 
508     rsc_mem_alloc_cnt_on_set_cfg = ux_test_utility_sim_mem_alloc_count();
509 
510     rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count();
511     rsc_sem_get_on_set_cfg = ux_test_utility_sim_sem_get_count();
512     rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count();
513 }
514 
515 /* Define what the initial system looks like.  */
516 
517 #ifdef CTEST
test_application_define(void * first_unused_memory)518 void test_application_define(void *first_unused_memory)
519 #else
520 void    usbx_standalone_device_cdc_acm_basic_test_application_define(void *first_unused_memory)
521 #endif
522 {
523 
524 UINT                    status;
525 CHAR *                  stack_pointer;
526 CHAR *                  memory_pointer;
527 
528     /* Inform user.  */
529     printf("Running STANDALONE CDC ACM Basic Test............................... ");
530 
531     /* Reset testing counts. */
532     ux_test_utility_sim_mem_alloc_log_enable(UX_TRUE);
533     ux_test_utility_sim_mem_alloc_count_reset();
534     ux_test_utility_sim_mutex_create_count_reset();
535     ux_test_utility_sim_sem_create_count_reset();
536     ux_test_utility_sim_sem_get_count_reset();
537     /* Reset error generations */
538     ux_test_utility_sim_sem_error_generation_stop();
539     ux_test_utility_sim_mutex_error_generation_stop();
540     ux_test_utility_sim_sem_get_error_generation_stop();
541 
542     /* Initialize the free memory pointer */
543     stack_pointer = (CHAR *) usbx_memory;
544     memory_pointer = stack_pointer + (UX_DEMO_STACK_SIZE * 2);
545 
546     /* Initialize USBX Memory */
547     status = ux_system_initialize(memory_pointer, UX_DEMO_MEMORY_SIZE, UX_NULL,0);
548 
549     /* Check for error.  */
550     if (status != UX_SUCCESS)
551     {
552 
553         printf("ERROR #1\n");
554         test_control_return(1);
555     }
556 
557     /* Register the error callback. */
558     _ux_utility_error_callback_register(error_callback);
559 
560     /* The code below is required for installing the host portion of USBX */
561     status =  ux_host_stack_initialize(demo_system_host_change_function);
562     if (status != UX_SUCCESS)
563     {
564 
565         printf("ERROR #2\n");
566         test_control_return(1);
567     }
568 
569     /* Register CDC-ACM class.  */
570     status =  ux_host_stack_class_register(_ux_system_host_class_cdc_acm_name, ux_host_class_cdc_acm_entry);
571     if (status != UX_SUCCESS)
572     {
573 
574         printf("ERROR #3\n");
575         test_control_return(1);
576     }
577 
578     /* The code below is required for installing the device portion of USBX. No call back for
579        device status change in this example. */
580     status =  ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED,
581                                        device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED,
582                                        string_framework, STRING_FRAMEWORK_LENGTH,
583                                        language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH,UX_NULL);
584     if(status!=UX_SUCCESS)
585     {
586 
587         printf("ERROR #5\n");
588         test_control_return(1);
589     }
590 
591     /* Set the parameters for callback when insertion/extraction of a CDC device.  */
592     parameter.ux_slave_class_cdc_acm_instance_activate   =  test_cdc_instance_activate;
593     parameter.ux_slave_class_cdc_acm_instance_deactivate =  test_cdc_instance_deactivate;
594     parameter.ux_slave_class_cdc_acm_parameter_change    =  test_cdc_instance_parameter_change;
595 
596     /* Initialize the device cdc class. This class owns both interfaces starting with 0. */
597     status =  ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry,
598                                              1,0,  &parameter);
599 
600     if(status!=UX_SUCCESS)
601     {
602 
603         printf("ERROR #6\n");
604         test_control_return(1);
605     }
606 
607     /* Initialize the simulated device controller.  */
608     status =  _ux_dcd_sim_slave_initialize();
609 
610     /* Check for error.  */
611     if (status != TX_SUCCESS)
612     {
613 
614         printf("ERROR #7\n");
615         test_control_return(1);
616     }
617 
618     /* Register all the USB host controllers available in this system */
619     status =  ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, _ux_test_hcd_sim_host_initialize,0,0);
620     if (status != UX_SUCCESS)
621     {
622 
623         printf("ERROR #4\n");
624         test_control_return(1);
625     }
626 
627     /* Create the main host simulation thread.  */
628     status =  tx_thread_create(&ux_test_thread_host_simulation, "tx demo host simulation", ux_test_thread_host_simulation_entry, 0,
629             stack_pointer, UX_DEMO_STACK_SIZE,
630             20, 20, 1, TX_AUTO_START);
631 
632     /* Check for error.  */
633     if (status != TX_SUCCESS)
634     {
635 
636         printf("ERROR #8\n");
637         test_control_return(1);
638     }
639 
640     /* Create the main slave simulation  thread.  */
641     status =  tx_thread_create(&ux_test_thread_slave_simulation, "tx demo slave simulation", ux_test_thread_slave_simulation_entry, 0,
642             stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE,
643             20, 20, 1, TX_AUTO_START);
644 
645     /* Check for error.  */
646     if (status != TX_SUCCESS)
647     {
648 
649         printf("ERROR #9\n");
650         test_control_return(1);
651     }
652 }
653 
test_cdc_acm_device_ioctl_parameters(void)654 static void test_cdc_acm_device_ioctl_parameters(void)
655 {
656 UINT                status;
657     if (cdc_acm_slave == UX_NULL)
658     {
659         printf("ERROR #%d, device instance not ready\n", __LINE__);
660         test_control_return(1);
661     }
662 
663     /* Get and check default line coding.  */
664     ux_utility_memory_set(&cdc_acm_slave_line_coding, 0, sizeof(cdc_acm_slave_line_coding));
665     status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave,
666                                 UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_CODING,
667                                 (VOID*)&cdc_acm_slave_line_coding);
668     UX_TEST_ASSERT(status == UX_SUCCESS);
669     UX_TEST_ASSERT(cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_baudrate ==
670                     UX_HOST_CLASS_CDC_ACM_LINE_CODING_DEFAULT_RATE);
671     UX_TEST_ASSERT(cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_stop_bit ==
672                     UX_HOST_CLASS_CDC_ACM_LINE_CODING_DEFAULT_STOP_BIT);
673     UX_TEST_ASSERT(cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_parity ==
674                     UX_HOST_CLASS_CDC_ACM_LINE_CODING_DEFAULT_PARITY);
675     UX_TEST_ASSERT(cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_data_bit ==
676                     UX_HOST_CLASS_CDC_ACM_LINE_CODING_DEFAULT_DATA_BIT);
677 
678     /* Set new line coding, read back to test.  */
679     cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_baudrate ++;
680     cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_stop_bit ++;
681     cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_parity ++;
682     cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_data_bit ++;
683     status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave,
684                                 UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_LINE_CODING,
685                                 (VOID*)&cdc_acm_slave_line_coding);
686     UX_TEST_ASSERT(status == UX_SUCCESS);
687 
688     ux_utility_memory_set(&cdc_acm_slave_line_coding, 0, sizeof(cdc_acm_slave_line_coding));
689     status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave,
690                                 UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_CODING,
691                                 (VOID*)&cdc_acm_slave_line_coding);
692     UX_TEST_ASSERT(status == UX_SUCCESS);
693     UX_TEST_ASSERT(cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_baudrate ==
694                     UX_HOST_CLASS_CDC_ACM_LINE_CODING_DEFAULT_RATE + 1);
695     UX_TEST_ASSERT(cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_stop_bit ==
696                     UX_HOST_CLASS_CDC_ACM_LINE_CODING_DEFAULT_STOP_BIT + 1);
697     UX_TEST_ASSERT(cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_parity ==
698                     UX_HOST_CLASS_CDC_ACM_LINE_CODING_DEFAULT_PARITY + 1);
699     UX_TEST_ASSERT(cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_data_bit ==
700                     UX_HOST_CLASS_CDC_ACM_LINE_CODING_DEFAULT_DATA_BIT + 1);
701 
702     /* Set line coding back.  */
703     cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_baudrate --;
704     cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_stop_bit --;
705     cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_parity --;
706     cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_data_bit --;
707     status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave,
708                                 UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_LINE_CODING,
709                                 (VOID*)&cdc_acm_slave_line_coding);
710     UX_TEST_ASSERT(status == UX_SUCCESS);
711 
712     /* Get and check line state.  */
713     ux_utility_memory_set(&cdc_acm_slave_line_state, 0, sizeof(cdc_acm_slave_line_state));
714     status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave,
715                                 UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_STATE,
716                                 (VOID*)&cdc_acm_slave_line_state);
717     UX_TEST_ASSERT(status == UX_SUCCESS);
718     UX_TEST_ASSERT(cdc_acm_slave_line_state.ux_slave_class_cdc_acm_parameter_dtr == 1);
719     UX_TEST_ASSERT(cdc_acm_slave_line_state.ux_slave_class_cdc_acm_parameter_rts == 1);
720 
721     /* Set new line state, read back to test.  */
722     cdc_acm_slave_line_state.ux_slave_class_cdc_acm_parameter_dtr ++;
723     cdc_acm_slave_line_state.ux_slave_class_cdc_acm_parameter_rts ++;
724     status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave,
725                                 UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_LINE_STATE,
726                                 (VOID*)&cdc_acm_slave_line_state);
727     UX_TEST_ASSERT(status == UX_SUCCESS);
728 
729     ux_utility_memory_set(&cdc_acm_slave_line_state, 0, sizeof(cdc_acm_slave_line_state));
730     status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave,
731                                 UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_STATE,
732                                 (VOID*)&cdc_acm_slave_line_state);
733     UX_TEST_ASSERT(status == UX_SUCCESS);
734     UX_TEST_ASSERT(cdc_acm_slave_line_state.ux_slave_class_cdc_acm_parameter_dtr == 2);
735     UX_TEST_ASSERT(cdc_acm_slave_line_state.ux_slave_class_cdc_acm_parameter_rts == 2);
736 
737     /* Set line state back.  */
738     cdc_acm_slave_line_state.ux_slave_class_cdc_acm_parameter_dtr --;
739     cdc_acm_slave_line_state.ux_slave_class_cdc_acm_parameter_rts --;
740     status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave,
741                                 UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_LINE_STATE,
742                                 (VOID*)&cdc_acm_slave_line_state);
743     UX_TEST_ASSERT(status == UX_SUCCESS);
744 }
745 
746 
test_thread_host_reception_callback(UX_HOST_CLASS_CDC_ACM * cdc_acm,UINT status,UCHAR * reception_buffer,ULONG reception_size)747 static void test_thread_host_reception_callback(UX_HOST_CLASS_CDC_ACM *cdc_acm, UINT status, UCHAR *reception_buffer, ULONG reception_size)
748 {
749 ULONG       i;
750 
751     /* And move to the next reception buffer.  Check if we are at the end of the application buffer.  */
752     if (cdc_acm_host_reception.ux_host_class_cdc_acm_reception_data_tail +
753             cdc_acm_host_reception.ux_host_class_cdc_acm_reception_block_size >=
754         cdc_acm_host_reception.ux_host_class_cdc_acm_reception_data_buffer +
755             cdc_acm_host_reception.ux_host_class_cdc_acm_reception_data_buffer_size)
756 
757         /* We are at the end of the buffer. Move back to the beginning.  */
758         cdc_acm_host_reception.ux_host_class_cdc_acm_reception_data_tail =
759             cdc_acm_host_reception.ux_host_class_cdc_acm_reception_data_buffer;
760 
761     else
762 
763         /* Program the tail to be after the current buffer.  */
764         cdc_acm_host_reception.ux_host_class_cdc_acm_reception_data_tail +=
765             cdc_acm_host_reception.ux_host_class_cdc_acm_reception_block_size;
766 
767     cdc_acm_host_reception_status = status;
768     cdc_acm_host_reception_count ++;
769 
770     /* Save buffer.  */
771     for (i = 0;
772         (i < reception_size) &&
773         (cdc_acm_host_read_buffer_length < sizeof(cdc_acm_host_read_buffer));
774         i ++, cdc_acm_host_read_buffer_length ++)
775     {
776         cdc_acm_host_read_buffer[cdc_acm_host_read_buffer_length] = reception_buffer[i];
777     }
778 
779     return;
780 }
781 
test_cdc_acm_device_read_write(void)782 static void test_cdc_acm_device_read_write(void)
783 {
784 UINT        status;
785 ULONG       actual_length;
786 UCHAR       test_chr;
787 ULONG       test_length;
788 ULONG       i, test;
789 #define N_TEST 6
790 struct {
791     UCHAR chr;
792     ULONG len;
793 } tests[N_TEST] = {
794     {'$', 1}, {'A', 64}, {'N', 65},
795     {'3', UX_SLAVE_REQUEST_DATA_MAX_LENGTH - 64},
796     {'G', UX_SLAVE_REQUEST_DATA_MAX_LENGTH},
797     {'H', UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1},
798 };
799 
800     /* Reception parameter */
801     cdc_acm_host_reception.ux_host_class_cdc_acm_reception_block_size = UX_DEMO_RECEPTION_BLOCK_SIZE;
802     cdc_acm_host_reception.ux_host_class_cdc_acm_reception_data_buffer = cdc_acm_host_reception_buffer;
803     cdc_acm_host_reception.ux_host_class_cdc_acm_reception_data_buffer_size = UX_DEMO_RECEPTION_BUFFER_SIZE;
804     cdc_acm_host_reception.ux_host_class_cdc_acm_reception_callback = test_thread_host_reception_callback;
805 
806     /* Start reception.  */
807     status = ux_host_class_cdc_acm_reception_start(cdc_acm_host_data, &cdc_acm_host_reception);
808     if (status != UX_SUCCESS)
809     {
810         printf("ERROR #%d: reception start fail %x\n", __LINE__, status);
811         test_control_return(1);
812     }
813 
814     for (test = 0; test < N_TEST; test ++)
815     {
816         test_chr    = tests[test].chr;
817         test_length = tests[test].len;
818 
819         for (i = 0; i < test_length; i ++)
820         {
821             host_buffer[i] = test_chr;
822             cdc_acm_host_read_buffer[i] = ~test_chr;
823         }
824         cdc_acm_host_read_buffer_length = 0;
825 
826         status = ux_host_class_cdc_acm_write(cdc_acm_host_data, host_buffer,
827                                                 test_length, &actual_length);
828         UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "test_length %ld\n", test_length);
829         if ((test_length & 63) == 0)
830         {
831             status = ux_host_class_cdc_acm_write(cdc_acm_host_data, host_buffer,
832                                                     0, &actual_length);
833             UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "test_length %ld\n", test_length);
834         }
835         /* Wait a while for background reception.  */
836         tx_thread_sleep(test_length/64 + 1);
837 
838         UX_TEST_ASSERT_MESSAGE(cdc_acm_host_reception_status == UX_SUCCESS, "test_length %ld\n", test_length);
839         if (cdc_acm_host_read_buffer_length != test_length)
840         {
841             printf("ERROR #%d, length not match %ld <> %ld\n", __LINE__,
842                 test_length, cdc_acm_host_read_buffer_length);
843             test_control_return(1);
844         }
845         for (i = 0; i < test_length; i ++)
846         {
847             UX_TEST_ASSERT_MESSAGE(cdc_acm_host_read_buffer[i] == test_chr, "test_length %ld\n", test_length);
848         }
849     }
850 
851     /* Stop reception.  */
852     ux_host_class_cdc_acm_reception_stop(cdc_acm_host_data, &cdc_acm_host_reception);
853 }
854 
ux_test_thread_host_simulation_entry(ULONG arg)855 void  ux_test_thread_host_simulation_entry(ULONG arg)
856 {
857 
858 UINT                                                status;
859 
860     stepinfo("\n");
861 
862     /* Find the cdc_acm class and wait for the link to be up.  */
863     status =  demo_class_cdc_acm_get();
864     if (status != UX_SUCCESS)
865     {
866 
867         /* CDC ACM basic test error.  */
868         printf("ERROR #10\n");
869         test_control_return(1);
870     }
871 
872     test_cdc_acm_device_ioctl_parameters();
873     test_cdc_acm_device_read_write();
874 
875     /* Finally disconnect the device. */
876     ux_device_stack_disconnect();
877 
878     /* And deinitialize the class.  */
879     status =  ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry);
880 
881     /* Deinitialize the device side of usbx.  */
882     _ux_device_stack_uninitialize();
883 
884     /* And finally the usbx system resources.  */
885     _ux_system_uninitialize();
886 
887     /* Successful test.  */
888     printf("SUCCESS!\n");
889     test_control_return(0);
890 
891 }
892 
ux_test_thread_slave_simulation_entry(ULONG arg)893 void  ux_test_thread_slave_simulation_entry(ULONG arg)
894 {
895 
896 UINT    status;
897 ULONG   actual_length;
898 ULONG   read_length = device_read_length;
899 ULONG   write_length, write_zlp = UX_FALSE;
900 #define CDC_ACM_DEVICE_STATE_READ     UX_STATE_STEP
901 #define CDC_ACM_DEVICE_STATE_WRITE    UX_STATE_STEP + 1
902 #define CDC_ACM_DEVICE_STATE_ZLP      UX_STATE_STEP + 2
903 UINT    cdc_acm_device_state = UX_STATE_RESET;
904 
905     while(1)
906     {
907 
908         /* Keep running device stack tasks.  */
909         ux_system_tasks_run();
910 
911         /* Reset state if read length changed.  */
912         if (read_length != device_read_length)
913         {
914             cdc_acm_device_state = UX_STATE_RESET;
915             read_length = device_read_length;
916         }
917 
918         /* CDC ACM echo state machine.  */
919         switch(cdc_acm_device_state)
920         {
921         case UX_STATE_RESET:
922             if (cdc_acm_slave != UX_NULL)
923             {
924                 ux_device_class_cdc_acm_ioctl(cdc_acm_slave,
925                         UX_SLAVE_CLASS_CDC_ACM_IOCTL_ABORT_PIPE,
926                         (VOID*)UX_SLAVE_CLASS_CDC_ACM_ENDPOINT_XMIT);
927                 ux_device_class_cdc_acm_ioctl(cdc_acm_slave,
928                         UX_SLAVE_CLASS_CDC_ACM_IOCTL_ABORT_PIPE,
929                         (VOID*)UX_SLAVE_CLASS_CDC_ACM_ENDPOINT_RCV);
930                 cdc_acm_device_state = CDC_ACM_DEVICE_STATE_READ;
931             }
932             break;
933         case CDC_ACM_DEVICE_STATE_READ:
934             if (cdc_acm_slave == UX_NULL)
935             {
936                 cdc_acm_device_state = UX_STATE_RESET;
937                 break;
938             }
939             status = ux_device_class_cdc_acm_read_run(cdc_acm_slave,
940                             device_buffer, device_read_length, &actual_length);
941             if (status < UX_STATE_NEXT)
942             {
943                 printf("ERROR #%d: read status 0x%x\n", __LINE__, status);
944                 return;
945             }
946             if (status == UX_STATE_NEXT)
947             {
948                 write_length = actual_length;
949                 if ((actual_length < device_read_length) &&
950                     ((actual_length & 63) == 0))
951                 {
952                     write_zlp = UX_TRUE;
953                 }
954                 cdc_acm_device_state = CDC_ACM_DEVICE_STATE_WRITE;
955             }
956             break;
957         case CDC_ACM_DEVICE_STATE_WRITE:
958             if (cdc_acm_slave == UX_NULL)
959             {
960                 cdc_acm_device_state = UX_STATE_RESET;
961                 break;
962             }
963             status = ux_device_class_cdc_acm_write_run(cdc_acm_slave,
964                             device_buffer, write_length, &actual_length);
965             if (status < UX_STATE_NEXT)
966             {
967                 printf("ERROR #%d: write status 0x%x\n", __LINE__, status);
968                 return;
969             }
970             if (status == UX_STATE_NEXT)
971             {
972                 if (write_zlp && ((write_length % 64) == 0))
973                 {
974                     cdc_acm_device_state = CDC_ACM_DEVICE_STATE_ZLP;
975                     break;
976                 }
977                 cdc_acm_device_state = CDC_ACM_DEVICE_STATE_READ;
978                 break;
979             }
980         case CDC_ACM_DEVICE_STATE_ZLP:
981             if (cdc_acm_slave == UX_NULL)
982             {
983                 cdc_acm_device_state = UX_STATE_RESET;
984                 break;
985             }
986             status = ux_device_class_cdc_acm_write_run(cdc_acm_slave,
987                             device_buffer, 0, &actual_length);
988             if (status < UX_STATE_NEXT)
989             {
990                 printf("ERROR #%d: ZLP status 0x%x\n", __LINE__, status);
991                 return;
992             }
993             if (status == UX_STATE_NEXT)
994                 cdc_acm_device_state = CDC_ACM_DEVICE_STATE_READ;
995             break;
996         default:
997             cdc_acm_device_state = UX_STATE_RESET;
998         }
999 
1000         /* Let other threads run.  */
1001         tx_thread_relinquish();
1002     }
1003 }
1004