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 
14 #include "ux_host_class_cdc_acm.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 #include "ux_host_stack.h"
21 
22 /* Define constants.  */
23 #define                             UX_DEMO_DEBUG_SIZE  (4096*8)
24 #define                             UX_DEMO_STACK_SIZE  1024
25 #define                             UX_DEMO_BUFFER_SIZE (UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1)
26 #define                             UX_DEMO_XMIT_BUFFER_SIZE 512
27 #define                             UX_DEMO_RECEPTION_BUFFER_SIZE 512
28 #define                             UX_DEMO_FILE_BUFFER_SIZE 512
29 #define                             UX_DEMO_RECEPTION_BLOCK_SIZE 64
30 #define                             UX_DEMO_MEMORY_SIZE     (96*1024)
31 #define                             UX_DEMO_FILE_SIZE       (128 * 1024)
32 #define                             UX_RAM_DISK_MEMORY      (256 * 1024)
33 
34 #define     LSB(x) ( (x) & 0x00ff)
35 #define     MSB(x) (((x) & 0xff00) >> 8)
36 
37 /* Configuration descriptor 9 bytes */
38 #define CFG_DESC(wTotalLength, bNumInterfaces, bmAttributes, bConfigurationValue)\
39     /* Configuration 1 descriptor 9 bytes */\
40     0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\
41     (bNumInterfaces), (bConfigurationValue), 0x00,\
42     (bmAttributes), 0x00,
43 #define CFG_DESC_LEN 9
44 
45 #define IAD_DESC(bIfc) \
46     /* Interface association descriptor. 8 bytes.  */\
47     0x08, 0x0b, (bIfc), 0x02, 0x02, 0x02, 0x00, 0x00,
48 #define IAD_DESC_LEN 8
49 
50 #define CDC_IFC_DESC_ALL(bIfc, bIntIn, bBulkIn, bBulkOut)\
51     /* Communication Class Interface Descriptor Requirement. 9 bytes.   */\
52     0x09, 0x04, (bIfc), 0x00, 0x01, 0x02, 0x02, 0x01, 0x00,\
53     /* Header Functional Descriptor 5 bytes */\
54     0x05, 0x24, 0x00, 0x10, 0x01,\
55     /* ACM Functional Descriptor 4 bytes */\
56     0x04, 0x24, 0x02, 0x0f,\
57     /* Union Functional Descriptor 5 bytes */\
58     0x05, 0x24, 0x06, (bIfc), (bIfc + 1),\
59     /* Call Management Functional Descriptor 5 bytes */\
60     0x05, 0x24, 0x01, 0x03, (bIfc + 1),\
61     /* Endpoint interrupt in descriptor 7 bytes */\
62     0x07, 0x05, (bIntIn), 0x03, 0x40, 0x00, 0x10,\
63     /* Data Class Interface Descriptor Requirement 9 bytes */\
64     0x09, 0x04, (bIfc + 1), 0x00, 0x02, 0x0A, 0x00, 0x00, 0x00,\
65     /* Endpoint bulk in descriptor 7 bytes */\
66     0x07, 0x05, (bBulkIn), 0x02, 0x40, 0x00, 0x01,\
67     /* Endpoint bulk out descriptor 7 bytes */\
68     0x07, 0x05, (bBulkOut), 0x02, 0x40, 0x00, 0x01,
69 #define CDC_IFC_DESC_ALL1(bIfc, bIntIn, bBulkIn, bBulkOut)\
70     /* Communication Class Interface Descriptor Requirement. 9 bytes.   */\
71     0x09, 0x04, (bIfc), 0x00, 0x01, 0x02, 0x02, 0x01, 0x00,\
72     /* Header Functional Descriptor 5 bytes */\
73     0x05, 0x24, 0x00, 0x10, 0x01,\
74     /* ACM Functional Descriptor 4 bytes */\
75     0x04, 0x24, 0x02, 0x0f,\
76     /* Union Functional Descriptor 5 bytes */\
77     0x05, 0x24, 0x06, (bIfc), (bIfc + 1),\
78     /* Call Management Functional Descriptor 5 bytes */\
79     0x05, 0x24, 0x01, 0x03, (bIfc + 1),\
80     /* Endpoint interrupt in descriptor 7 bytes */\
81     0x07, 0x05, (bIntIn), 0x03, 0x40, 0x00, 0x10,\
82     /* Data Class Interface Descriptor Requirement 9 bytes */\
83     0x09, 0x04, (bIfc + 1), 0x00, 0x02, 0x0A, 0x00, 0x00, 0x00,\
84     /* Endpoint bulk out descriptor 7 bytes */\
85     0x07, 0x05, (bBulkOut), 0x02, 0x40, 0x00, 0x01,\
86     /* Endpoint bulk in descriptor 7 bytes */\
87     0x07, 0x05, (bBulkIn), 0x02, 0x40, 0x00, 0x01,
88 #define CDC_IFC_DESC_ALL_LEN (9+5+4+5+5+7+ 9+7+7)
89 
90 /* Define local/extern function prototypes.  */
91 static VOID                                test_thread_entry(ULONG);
92 static TX_THREAD                           tx_test_thread_host_simulation;
93 static TX_THREAD                           tx_test_thread_slave_simulation;
94 static VOID                                tx_test_thread_host_simulation_entry(ULONG);
95 static VOID                                tx_test_thread_slave_simulation_entry(ULONG);
96 
97 static VOID                                test_cdc_instance_activate(VOID  *cdc_instance);
98 static VOID                                test_cdc_instance_deactivate(VOID *cdc_instance);
99 static VOID                                test_cdc_instance_parameter_change(VOID *cdc_instance);
100 
101 /* Define global data structures.  */
102 static UCHAR                               usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)];
103 
104 static UX_HOST_CLASS_CDC_ACM               *cdc_acm_host_control = UX_NULL;
105 static UX_HOST_CLASS_CDC_ACM               *cdc_acm_host_data = UX_NULL;
106 
107 static UX_HOST_CLASS_CDC_ACM               *cdc_acm_host_control1 = UX_NULL;
108 static UX_HOST_CLASS_CDC_ACM               *cdc_acm_host_data1 = UX_NULL;
109 
110 static UX_SLAVE_CLASS_CDC_ACM              *cdc_acm_slave = UX_NULL;
111 
112 static UX_SLAVE_CLASS_CDC_ACM              *cdc_acm_slave1 = UX_NULL;
113 
114 static UCHAR                               cdc_acm_slave_change;
115 static UX_SLAVE_CLASS_CDC_ACM_PARAMETER    parameter;
116 
117 static ULONG                               error_counter;
118 
119 static ULONG                               error_callback_counter;
120 static UCHAR                               error_callback_ignore;
121 
122 static ULONG                               call_counter;
123 
124 static UCHAR                               buffer[UX_DEMO_BUFFER_SIZE];
125 
126 static UCHAR                               test_slave_code = 0;
127 static UCHAR                               test_slave_state = 0;
128 
129 /* Define device framework.  */
130 
131 static unsigned char device_framework_full_speed[] = {
132 
133     /* Device descriptor     18 bytes
134        0x02 bDeviceClass:    CDC class code
135        0x00 bDeviceSubclass: CDC class sub code
136        0x00 bDeviceProtocol: CDC Device protocol
137 
138        idVendor & idProduct - http://www.linux-usb.org/usb.ids
139     */
140     0x12, 0x01, 0x10, 0x01,
141     0xEF, 0x02, 0x01,
142     0x08,
143     0x84, 0x84, 0x00, 0x00,
144     0x00, 0x01,
145     0x01, 0x02, 03,
146     0x01, /* bNumConfigurations */
147 
148     /* Configuration 1 descriptor 9 bytes, total 75 bytes */
149     CFG_DESC(CFG_DESC_LEN + (IAD_DESC_LEN + CDC_IFC_DESC_ALL_LEN) * 2, 4, 0x40, 1)
150     /* IAD 8 bytes */
151     IAD_DESC(0)
152     /* CDC_ACM interfaces */
153     CDC_IFC_DESC_ALL(0, 0x83, 0x81, 0x02)
154     /* IAD 8 bytes */
155     IAD_DESC(2)
156     /* CDC_ACM interfaces */
157     CDC_IFC_DESC_ALL1(2, 0x86, 0x85, 0x04)
158 };
159 #define             DEVICE_FRAMEWORK_LENGTH_FULL_SPEED      sizeof(device_framework_full_speed)
160 
161 static unsigned char device_framework_high_speed[] = {
162 
163     /* Device descriptor     18 bytes
164        0x02 bDeviceClass:    CDC class code
165        0x00 bDeviceSubclass: CDC class sub code
166        0x00 bDeviceProtocol: CDC Device protocol
167 
168        idVendor & idProduct - http://www.linux-usb.org/usb.ids
169     */
170     0x12, 0x01, 0x00, 0x02,
171     0xEF, 0x02, 0x01,
172     0x40,
173     0x84, 0x84, 0x00, 0x00,
174     0x00, 0x01,
175     0x01, 0x02, 03,
176     0x01, /* bNumConfigurations */
177 
178     /* Device qualifier descriptor 10 bytes */
179     0x0a, 0x06, 0x00, 0x02,
180     0x02, 0x00, 0x00,
181     0x40,
182     0x01,
183     0x00,
184 
185     /* Configuration 1 descriptor 9 bytes, total 75 bytes */
186     CFG_DESC(CFG_DESC_LEN + IAD_DESC_LEN + CDC_IFC_DESC_ALL_LEN, 2, 0x60, 1)
187     /* IAD 8 bytes */
188     IAD_DESC(0)
189     /* CDC_ACM interfaces */
190     CDC_IFC_DESC_ALL1(0, 0x83, 0x81, 0x02)
191     /* IAD 8 bytes */
192     IAD_DESC(2)
193     /* CDC_ACM interfaces */
194     CDC_IFC_DESC_ALL(2, 0x86, 0x85, 0x04)
195 };
196 #define             DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED      sizeof(device_framework_high_speed)
197 
198 static unsigned char string_framework[] = {
199 
200     /* Manufacturer string descriptor : Index 1 - "Express Logic" */
201     0x09, 0x04, 0x01, 0x0c,
202     0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c,
203     0x6f, 0x67, 0x69, 0x63,
204 
205     /* Product string descriptor : Index 2 - "EL Composite device" */
206     0x09, 0x04, 0x02, 0x13,
207     0x45, 0x4c, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x6f,
208     0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76,
209     0x69, 0x63, 0x65,
210 
211     /* Serial Number string descriptor : Index 3 - "0001" */
212     0x09, 0x04, 0x03, 0x04,
213     0x30, 0x30, 0x30, 0x31
214 };
215 #define             STRING_FRAMEWORK_LENGTH                 sizeof(string_framework)
216 
217 /* Multiple languages are supported on the device, to add
218     a language besides english, the unicode language code must
219     be appended to the language_id_framework array and the length
220     adjusted accordingly. */
221 static unsigned char language_id_framework[] = {
222 
223     /* English. */
224     0x09, 0x04
225 };
226 #define             LANGUAGE_ID_FRAMEWORK_LENGTH            sizeof(language_id_framework)
227 
228 /* Define the ISR dispatch.  */
229 
230 extern VOID    (*test_isr_dispatch)(void);
231 
232 
233 /* Prototype for test control return.  */
234 
235 void  test_control_return(UINT status);
236 
237 
238 /* Define the ISR dispatch routine.  */
239 
test_isr(void)240 static void    test_isr(void)
241 {
242 
243     /* For further expansion of interrupt-level testing.  */
244 }
245 
break_on_cdc_acm_all_ready(VOID)246 static UINT break_on_cdc_acm_all_ready(VOID)
247 {
248 
249     if (cdc_acm_host_control == UX_NULL || cdc_acm_host_data == UX_NULL)
250         /* Do not break. */
251         return 0;
252 
253     if (cdc_acm_host_control1 == UX_NULL || cdc_acm_host_data1 == UX_NULL)
254         /* Do not break. */
255         return 0;
256 
257     if (cdc_acm_host_control->ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE)
258         /* Do not break. */
259         return 0;
260 
261     if (cdc_acm_host_data->ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE)
262         /* Do not break. */
263         return 0;
264 
265     if (cdc_acm_host_control1->ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE)
266         /* Do not break. */
267         return 0;
268 
269     if (cdc_acm_host_data1->ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE)
270         /* Do not break. */
271         return 0;
272 
273     if (cdc_acm_slave == UX_NULL || cdc_acm_slave1 == UX_NULL)
274         /* Do not break. */
275         return 0;
276 
277     /* All found, break. */
278     return 1;
279 }
280 
break_on_removal(VOID)281 static UINT break_on_removal(VOID)
282 {
283 
284     if (cdc_acm_host_control != UX_NULL || cdc_acm_host_data != UX_NULL)
285         /* Do not break. */
286         return 0;
287 
288     if (cdc_acm_host_control1 != UX_NULL || cdc_acm_host_data1 != UX_NULL)
289         /* Do not break. */
290         return 0;
291 
292     if (cdc_acm_slave != UX_NULL || cdc_acm_slave1 != UX_NULL)
293         /* Do not break. */
294         return 0;
295 
296     return 1;
297 }
298 
test_host_change_function(ULONG event,UX_HOST_CLASS * cls,VOID * inst)299 static UINT test_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst)
300 {
301 
302 UX_HOST_CLASS_CDC_ACM *cdc_acm = (UX_HOST_CLASS_CDC_ACM *) inst;
303 
304     switch(event)
305     {
306 
307         case UX_DEVICE_INSERTION:
308 
309             if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS)
310             {
311                 if (cdc_acm_host_control == UX_NULL)
312                     cdc_acm_host_control = cdc_acm;
313                 else
314                     if (cdc_acm_host_control1 == UX_NULL)
315                         cdc_acm_host_control1 = cdc_acm;
316             }
317             else
318             {
319                 if (cdc_acm_host_data == UX_NULL)
320                     cdc_acm_host_data = cdc_acm;
321                 else
322                     if (cdc_acm_host_data1 == UX_NULL)
323                         cdc_acm_host_data1 = cdc_acm;
324             }
325             break;
326 
327         case UX_DEVICE_REMOVAL:
328 
329             if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS)
330             {
331                 if (cdc_acm_host_control == cdc_acm)
332                     cdc_acm_host_control = UX_NULL;
333                 if (cdc_acm_host_control1 == cdc_acm)
334                     cdc_acm_host_control1 = UX_NULL;
335             }
336             else
337             {
338                 if (cdc_acm_host_data == cdc_acm)
339                     cdc_acm_host_data = UX_NULL;
340                 if (cdc_acm_host_data1 == cdc_acm)
341                     cdc_acm_host_data1 = UX_NULL;
342             }
343             break;
344 
345         default:
346             break;
347     }
348     return 0;
349 }
350 
test_cdc_instance_activate(VOID * cdc_instance)351 static VOID    test_cdc_instance_activate(VOID *cdc_instance)
352 {
353 
354     /* Save the CDC instance.  */
355     if (cdc_acm_slave == UX_NULL)
356         cdc_acm_slave = (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance;
357     else
358     if (cdc_acm_slave1 == UX_NULL)
359         cdc_acm_slave1 =  (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance;
360 }
test_cdc_instance_deactivate(VOID * cdc_instance)361 static VOID    test_cdc_instance_deactivate(VOID *cdc_instance)
362 {
363 
364     /* Reset the CDC instance.  */
365     if ((VOID *)cdc_acm_slave == cdc_instance)
366         cdc_acm_slave = UX_NULL;
367     if ((VOID *)cdc_acm_slave1 == cdc_instance)
368         cdc_acm_slave1 = UX_NULL;
369 }
370 
test_cdc_instance_parameter_change(VOID * cdc_instance)371 static VOID test_cdc_instance_parameter_change(VOID *cdc_instance)
372 {
373 
374     /* Set CDC parameter change flag. */
375     cdc_acm_slave_change = UX_TRUE;
376 }
377 
test_ux_error_callback(UINT system_level,UINT system_context,UINT error_code)378 static VOID test_ux_error_callback(UINT system_level, UINT system_context, UINT error_code)
379 {
380     error_callback_counter ++;
381 
382     if (!error_callback_ignore)
383     {
384         /* Ignore UX_DEVICE_HANDLE_UNKNOWN.  */
385         if (UX_DEVICE_HANDLE_UNKNOWN == error_code)
386             return;
387         {
388             /* Failed test.  */
389             printf("#%d, system_level: %d, system_context: %d, error_code: 0x%x\n", __LINE__, system_level, system_context, error_code);
390             // test_control_return(1);
391         }
392     }
393 }
394 
395 /* Define what the initial system looks like.  */
396 
397 #ifdef CTEST
test_application_define(void * first_unused_memory)398 void test_application_define(void *first_unused_memory)
399 #else
400 void usbx_ux_device_class_cdc_acm_timeout_test_application_define(void *first_unused_memory)
401 #endif
402 {
403 
404 UINT                    status;
405 CHAR *                  stack_pointer;
406 CHAR *                  memory_pointer;
407 
408 #if UX_MAX_SLAVE_CLASS_DRIVER == 1
409     printf("Running ux_device_class_cdc_acm_timeout Test....................SKIP SUCCESS!\n");
410     test_control_return(0);
411     return;
412 #else
413     printf("Running ux_device_class_cdc_acm_timeout Test........................ ");
414 #endif
415 
416     /* Initialize the free memory pointer */
417     stack_pointer = (CHAR *) usbx_memory;
418     memory_pointer = stack_pointer + (UX_DEMO_STACK_SIZE * 2);
419 
420     /* Initialize USBX Memory */
421     status = ux_system_initialize(memory_pointer, UX_DEMO_MEMORY_SIZE, UX_NULL, 0);
422     /* Check for error.  */
423     if (status != UX_SUCCESS)
424     {
425 
426         printf("ERROR #%d\n", __LINE__);
427         test_control_return(1);
428     }
429 
430     /* Register the error callback. */
431     _ux_utility_error_callback_register(test_ux_error_callback);
432 
433     /* The code below is required for installing the host portion of USBX */
434     status =  ux_host_stack_initialize(test_host_change_function);
435     if (status != UX_SUCCESS)
436     {
437 
438         printf("ERROR #%d\n", __LINE__);
439         test_control_return(1);
440     }
441 
442     /* Register CDC ACM class */
443     status =  ux_host_stack_class_register(_ux_system_host_class_cdc_acm_name, ux_host_class_cdc_acm_entry);
444     if (status != UX_SUCCESS)
445     {
446 
447         printf("ERROR #%d\n", __LINE__);
448         test_control_return(1);
449     }
450 
451     /* The code below is required for installing the device portion of USBX. No call back for
452        device status change in this example. */
453     status =  ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED,
454                                        device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED,
455                                        string_framework, STRING_FRAMEWORK_LENGTH,
456                                        language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH,UX_NULL);
457     if(status!=UX_SUCCESS)
458     {
459 
460         printf("ERROR #%d\n", __LINE__);
461         test_control_return(1);
462     }
463 
464     /* Set the parameters for callback when insertion/extraction of a CDC device.  */
465     parameter.ux_slave_class_cdc_acm_instance_activate   =  test_cdc_instance_activate;
466     parameter.ux_slave_class_cdc_acm_instance_deactivate =  test_cdc_instance_deactivate;
467     parameter.ux_slave_class_cdc_acm_parameter_change    =  test_cdc_instance_parameter_change;
468 
469     /* Initialize the device cdc class. This class owns both interfaces starting with 0. */
470     status  =  ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry,
471                                              1,0,  &parameter);
472     status |=  ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry,
473                                              1,2,  &parameter);
474     status |=  ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry,
475                                              1,4,  &parameter);
476 #if UX_MAX_SLAVE_CLASS_DRIVER > 1
477     if(status!=UX_SUCCESS)
478     {
479 
480         printf("ERROR #%d\n", __LINE__);
481         test_control_return(1);
482     }
483 #endif
484     /* Initialize the simulated device controller.  */
485     status =  _ux_test_dcd_sim_slave_initialize();
486 
487     /* Check for error.  */
488     if (status != TX_SUCCESS)
489     {
490 
491         printf("ERROR #%d\n", __LINE__);
492         test_control_return(1);
493     }
494 
495 #if UX_MAX_SLAVE_CLASS_DRIVER > 1
496     error_callback_ignore = UX_TRUE; /* One of interface fail.  */
497 #endif
498 
499     /* Register HCD for test */
500     status =  ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, _ux_test_hcd_sim_host_initialize,0,0);
501     if (status != UX_SUCCESS)
502     {
503 
504         printf("ERROR #%d\n", __LINE__);
505         test_control_return(1);
506     }
507 
508     /* Create the main host simulation thread.  */
509     status =  tx_thread_create(&tx_test_thread_host_simulation, "tx test host simulation", tx_test_thread_host_simulation_entry, 0,
510             stack_pointer, UX_DEMO_STACK_SIZE,
511             20, 20, 1, TX_AUTO_START);
512 
513     /* Check for error.  */
514     if (status != TX_SUCCESS)
515     {
516 
517         printf("ERROR #%d\n", __LINE__);
518         test_control_return(1);
519     }
520 
521     /* Create the main slave simulation  thread.  */
522     status =  tx_thread_create(&tx_test_thread_slave_simulation, "tx test slave simulation", tx_test_thread_slave_simulation_entry, 0,
523             stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE,
524             20, 20, 1, TX_DONT_START);
525 
526     /* Check for error.  */
527     if (status != TX_SUCCESS)
528     {
529 
530         printf("ERROR #%d\n", __LINE__);
531         test_control_return(1);
532     }
533 }
534 
tx_test_thread_host_simulation_entry(ULONG arg)535 void  tx_test_thread_host_simulation_entry(ULONG arg)
536 {
537 
538 UINT                                                status;
539 UINT                                                i;
540 UX_SLAVE_ENDPOINT                                   *slave_endpoint;
541 ULONG                                               actual_length;
542 
543 
544     stepinfo("\n");
545 
546     /* Test connect. */
547     stepinfo(">>>>>>>>>>>>>>>> Test connect (FS)\n");
548     ux_test_hcd_sim_host_connect(UX_FULL_SPEED_DEVICE);
549     ux_test_breakable_sleep(500, break_on_cdc_acm_all_ready);
550     if (!(cdc_acm_host_control
551             && cdc_acm_host_data
552             && cdc_acm_slave
553 #if UX_MAX_SLAVE_CLASS_DRIVER > 1
554             && cdc_acm_host_control1
555             && cdc_acm_host_data1
556             && cdc_acm_slave1
557 #endif
558             ))
559     {
560 
561         printf("ERROR #%d: connect fail\n", __LINE__);
562         test_control_return(1);
563     }
564 
565     stepinfo(">>>>>>>>>>>>>>>> Test slave read without timeout\n");
566     test_slave_code = 1;
567     _ux_utility_thread_resume(&tx_test_thread_slave_simulation);
568     _ux_utility_delay_ms(10);
569     if (test_slave_state > 1)
570     {
571         printf("ERROR #%d: read not pending\n", __LINE__);
572         test_control_return(1);
573     }
574     if (test_slave_state < 1)
575     {
576         printf("ERROR #%d: read not started\n", __LINE__);
577         test_control_return(1);
578     }
579 
580     stepinfo(">>>>>>>>>>>>>>>> Test slave set read timeout (fail)\n");
581     status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_READ_TIMEOUT, (VOID *)10);
582     if (status != UX_ERROR)
583     {
584         printf("ERROR #%d: code 0x%x\n", __LINE__, status);
585         test_control_return(1);
586     }
587 
588     stepinfo(">>>>>>>>>>>>>>>> Test slave set read timeout (fail)\n");
589     slave_endpoint = cdc_acm_slave->ux_slave_class_cdc_acm_interface->ux_slave_interface_first_endpoint;
590     cdc_acm_slave->ux_slave_class_cdc_acm_interface->ux_slave_interface_first_endpoint = slave_endpoint->ux_slave_endpoint_next_endpoint;
591     cdc_acm_slave->ux_slave_class_cdc_acm_interface->ux_slave_interface_first_endpoint->ux_slave_endpoint_next_endpoint = slave_endpoint;
592     slave_endpoint->ux_slave_endpoint_next_endpoint = UX_NULL;
593     status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_READ_TIMEOUT, (VOID *)10);
594     if (status != UX_ERROR)
595     {
596         printf("ERROR #%d: code 0x%x\n", __LINE__, status);
597         test_control_return(1);
598     }
599     slave_endpoint = cdc_acm_slave->ux_slave_class_cdc_acm_interface->ux_slave_interface_first_endpoint;
600     cdc_acm_slave->ux_slave_class_cdc_acm_interface->ux_slave_interface_first_endpoint = slave_endpoint->ux_slave_endpoint_next_endpoint;
601     cdc_acm_slave->ux_slave_class_cdc_acm_interface->ux_slave_interface_first_endpoint->ux_slave_endpoint_next_endpoint = slave_endpoint;
602     slave_endpoint->ux_slave_endpoint_next_endpoint = UX_NULL;
603 
604     stepinfo(">>>>>>>>>>>>>>>> Test slave read abort\n");
605     status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_ABORT_PIPE, (VOID *)UX_SLAVE_CLASS_CDC_ACM_ENDPOINT_RCV);
606     if (status != UX_SUCCESS)
607     {
608         printf("ERROR #%d: code 0x%x\n", __LINE__, status);
609         test_control_return(1);
610     }
611     _ux_utility_delay_ms(10);
612     if (test_slave_state < 2)
613     {
614         printf("ERROR #%d: read not aborted\n", __LINE__);
615         test_control_return(1);
616     }
617 
618     stepinfo(">>>>>>>>>>>>>>>> Test slave write without timeout\n");
619     test_slave_code = 2;
620     _ux_utility_thread_resume(&tx_test_thread_slave_simulation);
621     _ux_utility_delay_ms(10);
622     if (test_slave_state > 1)
623     {
624         printf("ERROR #%d: write not pending\n", __LINE__);
625         test_control_return(1);
626     }
627     if (test_slave_state < 1)
628     {
629         printf("ERROR #%d: write not started\n", __LINE__);
630         test_control_return(1);
631     }
632 
633     stepinfo(">>>>>>>>>>>>>>>> Test slave set write timeout (fail)\n");
634     status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_WRITE_TIMEOUT, (VOID *)10);
635     if (status != UX_ERROR)
636     {
637         printf("ERROR #%d: code 0x%x\n", __LINE__, status);
638         test_control_return(1);
639     }
640 
641     stepinfo(">>>>>>>>>>>>>>>> Test slave set write timeout (fail)\n");
642     slave_endpoint = cdc_acm_slave->ux_slave_class_cdc_acm_interface->ux_slave_interface_first_endpoint;
643     cdc_acm_slave->ux_slave_class_cdc_acm_interface->ux_slave_interface_first_endpoint = slave_endpoint->ux_slave_endpoint_next_endpoint;
644     cdc_acm_slave->ux_slave_class_cdc_acm_interface->ux_slave_interface_first_endpoint->ux_slave_endpoint_next_endpoint = slave_endpoint;
645     slave_endpoint->ux_slave_endpoint_next_endpoint = UX_NULL;
646     status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_WRITE_TIMEOUT, (VOID *)10);
647     if (status != UX_ERROR)
648     {
649         printf("ERROR #%d: code 0x%x\n", __LINE__, status);
650         test_control_return(1);
651     }
652     slave_endpoint = cdc_acm_slave->ux_slave_class_cdc_acm_interface->ux_slave_interface_first_endpoint;
653     cdc_acm_slave->ux_slave_class_cdc_acm_interface->ux_slave_interface_first_endpoint = slave_endpoint->ux_slave_endpoint_next_endpoint;
654     cdc_acm_slave->ux_slave_class_cdc_acm_interface->ux_slave_interface_first_endpoint->ux_slave_endpoint_next_endpoint = slave_endpoint;
655     slave_endpoint->ux_slave_endpoint_next_endpoint = UX_NULL;
656 
657     stepinfo(">>>>>>>>>>>>>>>> Test slave write abort\n");
658     status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_ABORT_PIPE, (VOID *)UX_SLAVE_CLASS_CDC_ACM_ENDPOINT_XMIT);
659     if (status != UX_SUCCESS)
660     {
661         printf("ERROR #%d: fail, code 0x%x\n", __LINE__, status);
662         test_control_return(1);
663     }
664     _ux_utility_delay_ms(10);
665     if (test_slave_state < 2)
666     {
667         printf("ERROR #%d: write not aborted\n", __LINE__);
668         test_control_return(1);
669     }
670 
671     stepinfo(">>>>>>>>>>>>>>>> Test slave read/write with timeout\n");
672     test_slave_code = 3;
673     _ux_utility_thread_resume(&tx_test_thread_slave_simulation);
674     for (i = 0; i < 100; i ++)
675     {
676         _ux_utility_delay_ms(10);
677         if (test_slave_state >= 1)
678             break;
679     }
680     stepinfo(" Step after %d x 10 ms\n", i);
681     for (i = 0; i < 100; i ++)
682     {
683         _ux_utility_delay_ms(10);
684         if (test_slave_state >= 2)
685             break;
686     }
687     stepinfo(" Step after %d x 10 ms\n", i);
688     for (i = 0; i < 100; i ++)
689     {
690         _ux_utility_delay_ms(10);
691         if (test_slave_state >= 3)
692             break;
693     }
694     stepinfo(" Step after %d x 10 ms\n", i);
695     if (test_slave_state < 3)
696     {
697         printf("ERROR #%d: slave operation not end\n", __LINE__);
698         error_counter ++;
699     }
700 
701     stepinfo(">>>>>>>>>>>>>>>> Test slave read with timeout success\n");
702     test_slave_code = 4;
703     _ux_utility_thread_resume(&tx_test_thread_slave_simulation);
704     status = ux_host_class_cdc_acm_write(cdc_acm_host_data, buffer, 1, &actual_length);
705     test_slave_code = 4;
706     _ux_utility_thread_resume(&tx_test_thread_slave_simulation);
707     status = ux_host_class_cdc_acm_write(cdc_acm_host_data, buffer, 256, &actual_length);
708     test_slave_code = 4;
709     _ux_utility_thread_resume(&tx_test_thread_slave_simulation);
710     status = ux_host_class_cdc_acm_write(cdc_acm_host_data, buffer, 250, &actual_length);
711 
712     stepinfo(">>>>>>>>>>>>>>>> Test slave write with timeout success\n");
713     test_slave_code = 5;
714     _ux_utility_thread_resume(&tx_test_thread_slave_simulation);
715     status = ux_host_class_cdc_acm_read(cdc_acm_host_data, buffer, 1, &actual_length);
716     test_slave_code = 5;
717     _ux_utility_thread_resume(&tx_test_thread_slave_simulation);
718     status = ux_host_class_cdc_acm_read(cdc_acm_host_data, buffer, 1023, &actual_length);
719     test_slave_code = 5;
720     _ux_utility_thread_resume(&tx_test_thread_slave_simulation);
721 #if !defined(UX_DEVICE_CLASS_CDC_ACM_WRITE_AUTO_ZLP)
722     status = ux_host_class_cdc_acm_read(cdc_acm_host_data, buffer, 1024, &actual_length);
723 #else
724     /* Read as much as we can, device pending ZLP to terminate.  */
725     status = ux_host_class_cdc_acm_read(cdc_acm_host_data, buffer, sizeof(buffer), &actual_length);
726 #endif
727 
728     stepinfo(">>>>>>>>>>>>>>>> Test disconnect\n");
729     ux_test_dcd_sim_slave_disconnect();
730     ux_test_hcd_sim_host_disconnect();
731 
732     ux_test_breakable_sleep(100, break_on_removal);
733 
734     if (cdc_acm_host_control || cdc_acm_host_data || cdc_acm_slave)
735     {
736 
737         printf("ERROR #%d: disconnect fail\n", __LINE__);
738         test_control_return(1);
739     }
740 
741     stepinfo(">>>>>>>>>>>>>>>> Deinitialize\n");
742 
743     /* Deinitialize the class.  */
744     ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry);
745     ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry);
746     ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry);
747 
748     /* Deinitialize the device side of usbx.  */
749     _ux_device_stack_uninitialize();
750 
751     /* And finally the usbx system resources.  */
752     _ux_system_uninitialize();
753 
754     stepinfo(">>>>>>>>>>>>>>>> Dump results\n");
755 
756     if (error_counter > 0)
757     {
758 
759         /* Test error.  */
760         printf("ERROR #%d: total %ld errors\n", __LINE__, error_counter);
761         test_control_return(1);
762     }
763 
764     /* Successful test.  */
765     printf("SUCCESS!\n");
766     test_control_return(0);
767 }
768 
tx_test_thread_slave_simulation_entry(ULONG arg)769 void  tx_test_thread_slave_simulation_entry(ULONG arg)
770 {
771 UINT  status;
772 ULONG actual_length;
773 
774     while(1)
775     {
776         switch (test_slave_code)
777         {
778         case 1:
779         case 4:
780             stepinfo(">>>>>>>>>>>>>>>> Slave read START%s\n", test_slave_code == 1 ? "(no timeout)" : "");
781             test_slave_state ++;
782             status = ux_device_class_cdc_acm_read(cdc_acm_slave, buffer, 256, &actual_length);
783             test_slave_state ++;
784             stepinfo(">>>>>>>>>>>>>>>> Slave read END: 0x%x, %ld\n", status, actual_length);
785             if (status != (test_slave_code == 1 ? UX_ABORTED : UX_SUCCESS))
786             {
787                 printf("ERROR #%d: read code 0x%x\n", __LINE__, status);
788                 error_counter ++;
789             }
790             break;
791 
792         case 2:
793         case 5:
794             stepinfo(">>>>>>>>>>>>>>>> Slave write START%s\n", test_slave_code == 2 ? "(no timeout)" : "");
795             test_slave_state ++;
796             status = ux_device_class_cdc_acm_write(cdc_acm_slave, buffer, 1024, &actual_length);
797             test_slave_state ++;
798             stepinfo(">>>>>>>>>>>>>>>> Slave write END: 0x%x, %ld\n", status, actual_length);
799             if (status != (test_slave_code == 2 ? UX_ABORTED : UX_SUCCESS))
800             {
801                 printf("ERROR #%d: test %x, write code 0x%x\n", __LINE__, test_slave_code, status);
802                 error_counter ++;
803             }
804             break;
805 
806         case 3:
807             stepinfo(">>>>>>>>>>>>>>>> Slave set read/write timeout\n");
808             status  = ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_READ_TIMEOUT, (VOID *)10);
809             status |= ux_device_class_cdc_acm_ioctl(cdc_acm_slave, UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_WRITE_TIMEOUT, (VOID *)10);
810             test_slave_state ++;
811             if (status != UX_SUCCESS)
812             {
813                 printf("ERROR #%d: code 0x%x\n", __LINE__, status);
814                 error_counter ++;
815             }
816 
817             stepinfo(">>>>>>>>>>>>>>>> Slave write START\n");
818             status = ux_device_class_cdc_acm_write(cdc_acm_slave, buffer, 1024, &actual_length);
819             test_slave_state ++;
820             stepinfo(">>>>>>>>>>>>>>>> Slave write END\n");
821             if (status == UX_SUCCESS)
822             {
823                 printf("ERROR #%d: code 0x%x\n", __LINE__, status);
824                 error_counter ++;
825             }
826             stepinfo(">>>>>>>>>>>>>>>> Slave read START\n");
827             status = ux_device_class_cdc_acm_read(cdc_acm_slave, buffer, 1024, &actual_length);
828             test_slave_state ++;
829             stepinfo(">>>>>>>>>>>>>>>> Slave read END\n");
830             if (status == UX_SUCCESS)
831             {
832                 printf("ERROR #%d: code 0x%x\n", __LINE__, status);
833                 error_counter ++;
834             }
835             break;
836 
837         default:
838             break;
839         }
840         tx_thread_suspend(&tx_test_thread_slave_simulation);
841         test_slave_state = 0;
842     }
843 }
844