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 #if defined(UX_HOST_STANDALONE)
369         ux_system_tasks_run();
370 #else
371         tx_thread_sleep(10);
372 #endif
373     } while (status != UX_SUCCESS);
374 
375     /* We still need to wait for the cdc_acm status to be live */
376     while (cdc_acm_host -> ux_host_class_cdc_acm_state != UX_HOST_CLASS_INSTANCE_LIVE)
377     {
378 #if defined(UX_HOST_STANDALONE)
379         ux_system_tasks_run();
380 #else
381         tx_thread_sleep(10);
382 #endif
383     }
384 
385     /* Isolate both the control and data interfaces.  */
386     if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_DATA_CLASS)
387     {
388         /* This is the data interface.  */
389         cdc_acm_host_data = cdc_acm_host;
390 
391         /* In that case, the second one should be the control interface.  */
392         status =  ux_host_stack_class_instance_get(class, 1, (void **) &cdc_acm_host);
393 
394         /* Check error.  */
395         if (status != UX_SUCCESS)
396             return(status);
397 
398         /* Check for the control interfaces.  */
399         if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS)
400         {
401 
402             /* This is the control interface.  */
403             cdc_acm_host_control = cdc_acm_host;
404 
405             return(UX_SUCCESS);
406 
407         }
408     }
409     else
410     {
411         /* Check for the control interfaces.  */
412         if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS)
413         {
414 
415             /* This is the control interface.  */
416             cdc_acm_host_control = cdc_acm_host;
417 
418             /* In that case, the second one should be the data interface.  */
419             status =  ux_host_stack_class_instance_get(class, 1, (void **) &cdc_acm_host);
420 
421             /* Check error.  */
422             if (status != UX_SUCCESS)
423                 return(status);
424 
425             /* Check for the data interface.  */
426             if (cdc_acm_host -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_DATA_CLASS)
427             {
428 
429                 /* This is the data interface.  */
430                 cdc_acm_host_data = cdc_acm_host;
431 
432                 return(UX_SUCCESS);
433 
434             }
435         }
436     }
437 
438     /* Return ERROR.  */
439     return(UX_ERROR);
440 }
441 
demo_system_host_change_function(ULONG event,UX_HOST_CLASS * cls,VOID * inst)442 static UINT demo_system_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst)
443 {
444 
445 UX_HOST_CLASS_CDC_ACM *cdc_acm = (UX_HOST_CLASS_CDC_ACM *) inst;
446 
447     switch(event)
448     {
449 
450         case UX_DEVICE_INSERTION:
451 
452             if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS)
453                 cdc_acm_host_control = cdc_acm;
454             else
455                 cdc_acm_host_data = cdc_acm;
456             break;
457 
458         case UX_DEVICE_REMOVAL:
459 
460             if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS)
461                 cdc_acm_host_control = UX_NULL;
462             else
463                 cdc_acm_host_data = UX_NULL;
464             break;
465 
466 #if defined(UX_HOST_STANDALONE)
467         case UX_STANDALONE_WAIT_BACKGROUND_TASK:
468             tx_thread_relinquish();
469             break;
470 #endif
471 
472         default:
473             break;
474     }
475     return 0;
476 }
477 
test_cdc_instance_activate(VOID * cdc_instance)478 static VOID    test_cdc_instance_activate(VOID *cdc_instance)
479 {
480 
481     /* Save the CDC instance.  */
482     cdc_acm_slave = (UX_SLAVE_CLASS_CDC_ACM *) cdc_instance;
483 }
test_cdc_instance_deactivate(VOID * cdc_instance)484 static VOID test_cdc_instance_deactivate(VOID *cdc_instance)
485 {
486 
487     /* Reset the CDC instance.  */
488     cdc_acm_slave = UX_NULL;
489 }
490 
test_cdc_instance_parameter_change(VOID * cdc_instance)491 static VOID test_cdc_instance_parameter_change(VOID *cdc_instance)
492 {
493 
494     /* Set CDC parameter change flag. */
495     cdc_acm_slave_change = UX_TRUE;
496 
497     /* Get new paramster.  */
498     ux_device_class_cdc_acm_ioctl(cdc_acm_slave,
499                                 UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_CODING,
500                                 (VOID*)&cdc_acm_slave_line_coding);
501     ux_device_class_cdc_acm_ioctl(cdc_acm_slave,
502                                 UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_CODING,
503                                 (VOID*)&cdc_acm_slave_line_state);
504 }
505 
test_swap_framework_bulk_ep_descriptors(VOID)506 static VOID test_swap_framework_bulk_ep_descriptors(VOID)
507 {
508 UCHAR tmp;
509 
510     tmp = device_framework_full_speed[DEVICE_FRAMEWORK_EPA_POS_1_FS];
511     device_framework_full_speed[DEVICE_FRAMEWORK_EPA_POS_1_FS] = device_framework_full_speed[DEVICE_FRAMEWORK_EPA_POS_2_FS];
512     device_framework_full_speed[DEVICE_FRAMEWORK_EPA_POS_2_FS] = tmp;
513 
514     tmp = device_framework_high_speed[DEVICE_FRAMEWORK_EPA_POS_1_HS];
515     device_framework_high_speed[DEVICE_FRAMEWORK_EPA_POS_1_HS] = device_framework_high_speed[DEVICE_FRAMEWORK_EPA_POS_2_HS];
516     device_framework_high_speed[DEVICE_FRAMEWORK_EPA_POS_2_HS] = tmp;
517 }
518 
ux_test_hcd_entry_set_cfg(UX_TEST_ACTION * action,VOID * _params)519 static VOID ux_test_hcd_entry_set_cfg(UX_TEST_ACTION *action, VOID *_params)
520 {
521 
522     set_cfg_counter ++;
523 
524     rsc_mem_alloc_cnt_on_set_cfg = ux_test_utility_sim_mem_alloc_count();
525 
526     rsc_sem_on_set_cfg = ux_test_utility_sim_sem_create_count();
527     rsc_sem_get_on_set_cfg = ux_test_utility_sim_sem_get_count();
528     rsc_mutex_on_set_cfg = ux_test_utility_sim_mutex_create_count();
529 }
530 
531 /* Define what the initial system looks like.  */
532 
533 #ifdef CTEST
test_application_define(void * first_unused_memory)534 void test_application_define(void *first_unused_memory)
535 #else
536 void    usbx_standalone_cdc_acm_basic_test_application_define(void *first_unused_memory)
537 #endif
538 {
539 
540 UINT                    status;
541 CHAR *                  stack_pointer;
542 CHAR *                  memory_pointer;
543 
544     /* Inform user.  */
545     printf("Running STANDALONE CDC ACM Basic Test............................... ");
546 
547     /* Reset testing counts. */
548     ux_test_utility_sim_mem_alloc_log_enable(UX_TRUE);
549     ux_test_utility_sim_mem_alloc_count_reset();
550     ux_test_utility_sim_mutex_create_count_reset();
551     ux_test_utility_sim_sem_create_count_reset();
552     ux_test_utility_sim_sem_get_count_reset();
553     /* Reset error generations */
554     ux_test_utility_sim_sem_error_generation_stop();
555     ux_test_utility_sim_mutex_error_generation_stop();
556     ux_test_utility_sim_sem_get_error_generation_stop();
557 
558     /* Initialize the free memory pointer */
559     stack_pointer = (CHAR *) usbx_memory;
560     memory_pointer = stack_pointer + (UX_DEMO_STACK_SIZE * 2);
561 
562     /* Initialize USBX Memory */
563     status = ux_system_initialize(memory_pointer, UX_DEMO_MEMORY_SIZE, UX_NULL,0);
564 
565     /* Check for error.  */
566     if (status != UX_SUCCESS)
567     {
568 
569         printf("ERROR #1\n");
570         test_control_return(1);
571     }
572 
573     /* Register the error callback. */
574     _ux_utility_error_callback_register(error_callback);
575 
576     /* The code below is required for installing the host portion of USBX */
577     status =  ux_host_stack_initialize(demo_system_host_change_function);
578     if (status != UX_SUCCESS)
579     {
580 
581         printf("ERROR #2\n");
582         test_control_return(1);
583     }
584 
585     /* Register CDC-ACM class.  */
586     status =  ux_host_stack_class_register(_ux_system_host_class_cdc_acm_name, ux_host_class_cdc_acm_entry);
587     if (status != UX_SUCCESS)
588     {
589 
590         printf("ERROR #3\n");
591         test_control_return(1);
592     }
593 
594     /* The code below is required for installing the device portion of USBX. No call back for
595        device status change in this example. */
596     status =  ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED,
597                                        device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED,
598                                        string_framework, STRING_FRAMEWORK_LENGTH,
599                                        language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH,UX_NULL);
600     if(status!=UX_SUCCESS)
601     {
602 
603         printf("ERROR #5\n");
604         test_control_return(1);
605     }
606 
607     /* Set the parameters for callback when insertion/extraction of a CDC device.  */
608     parameter.ux_slave_class_cdc_acm_instance_activate   =  test_cdc_instance_activate;
609     parameter.ux_slave_class_cdc_acm_instance_deactivate =  test_cdc_instance_deactivate;
610     parameter.ux_slave_class_cdc_acm_parameter_change    =  test_cdc_instance_parameter_change;
611 
612     /* Initialize the device cdc class. This class owns both interfaces starting with 0. */
613     status =  ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry,
614                                              1,0,  &parameter);
615 
616     if(status!=UX_SUCCESS)
617     {
618 
619         printf("ERROR #6\n");
620         test_control_return(1);
621     }
622 
623     /* Initialize the simulated device controller.  */
624     status =  _ux_dcd_sim_slave_initialize();
625 
626     /* Check for error.  */
627     if (status != TX_SUCCESS)
628     {
629 
630         printf("ERROR #7\n");
631         test_control_return(1);
632     }
633 
634     /* Register all the USB host controllers available in this system */
635     status =  ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, _ux_test_hcd_sim_host_initialize,0,0);
636     if (status != UX_SUCCESS)
637     {
638 
639         printf("ERROR #4\n");
640         test_control_return(1);
641     }
642 
643     /* Create the main host simulation thread.  */
644     status =  tx_thread_create(&ux_test_thread_host_simulation, "tx demo host simulation", ux_test_thread_host_simulation_entry, 0,
645             stack_pointer, UX_DEMO_STACK_SIZE,
646             20, 20, 1, TX_AUTO_START);
647 
648     /* Check for error.  */
649     if (status != TX_SUCCESS)
650     {
651 
652         printf("ERROR #8\n");
653         test_control_return(1);
654     }
655 
656     /* Create the main slave simulation  thread.  */
657     status =  tx_thread_create(&ux_test_thread_slave_simulation, "tx demo slave simulation", ux_test_thread_slave_simulation_entry, 0,
658             stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE,
659             20, 20, 1, TX_AUTO_START);
660 
661     /* Check for error.  */
662     if (status != TX_SUCCESS)
663     {
664 
665         printf("ERROR #9\n");
666         test_control_return(1);
667     }
668 }
669 
670 #if defined(UX_HOST_STANDALONE)
test_host_delay(ULONG ticks)671 static void test_host_delay(ULONG ticks)
672 {
673 ULONG t_start = tx_time_get();
674 ULONG t_now, t_elapsed;
675     while(1)
676     {
677         ux_system_tasks_run();
678         tx_thread_relinquish();
679         if (ticks != TX_WAIT_FOREVER)
680         {
681             if (ticks == 0)
682                 break;
683             t_now = tx_time_get();
684             t_elapsed = _ux_utility_time_elapsed(t_start, t_now);
685             if (t_elapsed > ticks)
686                 break;
687         }
688     }
689 }
690 #else
691 #define test_host_delay         tx_thread_sleep
692 #endif
693 
test_cdc_acm_device_ioctl_parameters(void)694 static void test_cdc_acm_device_ioctl_parameters(void)
695 {
696 UINT                status;
697     if (cdc_acm_slave == UX_NULL)
698     {
699         printf("ERROR #%d, device instance not ready\n", __LINE__);
700         test_control_return(1);
701     }
702 
703     /* Get and check default line coding.  */
704     ux_utility_memory_set(&cdc_acm_slave_line_coding, 0, sizeof(cdc_acm_slave_line_coding));
705     status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave,
706                                 UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_CODING,
707                                 (VOID*)&cdc_acm_slave_line_coding);
708     UX_TEST_ASSERT(status == UX_SUCCESS);
709     UX_TEST_ASSERT(cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_baudrate ==
710                     UX_HOST_CLASS_CDC_ACM_LINE_CODING_DEFAULT_RATE);
711     UX_TEST_ASSERT(cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_stop_bit ==
712                     UX_HOST_CLASS_CDC_ACM_LINE_CODING_DEFAULT_STOP_BIT);
713     UX_TEST_ASSERT(cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_parity ==
714                     UX_HOST_CLASS_CDC_ACM_LINE_CODING_DEFAULT_PARITY);
715     UX_TEST_ASSERT(cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_data_bit ==
716                     UX_HOST_CLASS_CDC_ACM_LINE_CODING_DEFAULT_DATA_BIT);
717 
718     /* Set new line coding, read back to test.  */
719     cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_baudrate ++;
720     cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_stop_bit ++;
721     cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_parity ++;
722     cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_data_bit ++;
723     status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave,
724                                 UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_LINE_CODING,
725                                 (VOID*)&cdc_acm_slave_line_coding);
726     UX_TEST_ASSERT(status == UX_SUCCESS);
727 
728     ux_utility_memory_set(&cdc_acm_slave_line_coding, 0, sizeof(cdc_acm_slave_line_coding));
729     status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave,
730                                 UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_CODING,
731                                 (VOID*)&cdc_acm_slave_line_coding);
732     UX_TEST_ASSERT(status == UX_SUCCESS);
733     UX_TEST_ASSERT(cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_baudrate ==
734                     UX_HOST_CLASS_CDC_ACM_LINE_CODING_DEFAULT_RATE + 1);
735     UX_TEST_ASSERT(cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_stop_bit ==
736                     UX_HOST_CLASS_CDC_ACM_LINE_CODING_DEFAULT_STOP_BIT + 1);
737     UX_TEST_ASSERT(cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_parity ==
738                     UX_HOST_CLASS_CDC_ACM_LINE_CODING_DEFAULT_PARITY + 1);
739     UX_TEST_ASSERT(cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_data_bit ==
740                     UX_HOST_CLASS_CDC_ACM_LINE_CODING_DEFAULT_DATA_BIT + 1);
741 
742     /* Set line coding back.  */
743     cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_baudrate --;
744     cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_stop_bit --;
745     cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_parity --;
746     cdc_acm_slave_line_coding.ux_slave_class_cdc_acm_parameter_data_bit --;
747     status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave,
748                                 UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_LINE_CODING,
749                                 (VOID*)&cdc_acm_slave_line_coding);
750     UX_TEST_ASSERT(status == UX_SUCCESS);
751 
752     /* Get and check line state.  */
753     ux_utility_memory_set(&cdc_acm_slave_line_state, 0, sizeof(cdc_acm_slave_line_state));
754     status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave,
755                                 UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_STATE,
756                                 (VOID*)&cdc_acm_slave_line_state);
757     UX_TEST_ASSERT(status == UX_SUCCESS);
758     UX_TEST_ASSERT(cdc_acm_slave_line_state.ux_slave_class_cdc_acm_parameter_dtr == 1);
759     UX_TEST_ASSERT(cdc_acm_slave_line_state.ux_slave_class_cdc_acm_parameter_rts == 1);
760 
761     /* Set new line state, read back to test.  */
762     cdc_acm_slave_line_state.ux_slave_class_cdc_acm_parameter_dtr ++;
763     cdc_acm_slave_line_state.ux_slave_class_cdc_acm_parameter_rts ++;
764     status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave,
765                                 UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_LINE_STATE,
766                                 (VOID*)&cdc_acm_slave_line_state);
767     UX_TEST_ASSERT(status == UX_SUCCESS);
768 
769     ux_utility_memory_set(&cdc_acm_slave_line_state, 0, sizeof(cdc_acm_slave_line_state));
770     status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave,
771                                 UX_SLAVE_CLASS_CDC_ACM_IOCTL_GET_LINE_STATE,
772                                 (VOID*)&cdc_acm_slave_line_state);
773     UX_TEST_ASSERT(status == UX_SUCCESS);
774     UX_TEST_ASSERT(cdc_acm_slave_line_state.ux_slave_class_cdc_acm_parameter_dtr == 2);
775     UX_TEST_ASSERT(cdc_acm_slave_line_state.ux_slave_class_cdc_acm_parameter_rts == 2);
776 
777     /* Set line state back.  */
778     cdc_acm_slave_line_state.ux_slave_class_cdc_acm_parameter_dtr --;
779     cdc_acm_slave_line_state.ux_slave_class_cdc_acm_parameter_rts --;
780     status = ux_device_class_cdc_acm_ioctl(cdc_acm_slave,
781                                 UX_SLAVE_CLASS_CDC_ACM_IOCTL_SET_LINE_STATE,
782                                 (VOID*)&cdc_acm_slave_line_state);
783     UX_TEST_ASSERT(status == UX_SUCCESS);
784 }
785 
786 
test_thread_host_reception_callback(UX_HOST_CLASS_CDC_ACM * cdc_acm,UINT status,UCHAR * reception_buffer,ULONG reception_size)787 static void test_thread_host_reception_callback(UX_HOST_CLASS_CDC_ACM *cdc_acm, UINT status, UCHAR *reception_buffer, ULONG reception_size)
788 {
789 ULONG       i;
790 
791     /* And move to the next reception buffer.  Check if we are at the end of the application buffer.  */
792     if (cdc_acm_host_reception.ux_host_class_cdc_acm_reception_data_tail +
793             cdc_acm_host_reception.ux_host_class_cdc_acm_reception_block_size >=
794         cdc_acm_host_reception.ux_host_class_cdc_acm_reception_data_buffer +
795             cdc_acm_host_reception.ux_host_class_cdc_acm_reception_data_buffer_size)
796 
797         /* We are at the end of the buffer. Move back to the beginning.  */
798         cdc_acm_host_reception.ux_host_class_cdc_acm_reception_data_tail =
799             cdc_acm_host_reception.ux_host_class_cdc_acm_reception_data_buffer;
800 
801     else
802 
803         /* Program the tail to be after the current buffer.  */
804         cdc_acm_host_reception.ux_host_class_cdc_acm_reception_data_tail +=
805             cdc_acm_host_reception.ux_host_class_cdc_acm_reception_block_size;
806 
807     cdc_acm_host_reception_status = status;
808     cdc_acm_host_reception_count ++;
809 
810     /* Save buffer.  */
811     for (i = 0;
812         (i < reception_size) &&
813         (cdc_acm_host_read_buffer_length < sizeof(cdc_acm_host_read_buffer));
814         i ++, cdc_acm_host_read_buffer_length ++)
815     {
816         cdc_acm_host_read_buffer[cdc_acm_host_read_buffer_length] = reception_buffer[i];
817     }
818 
819     return;
820 }
821 
822 
test_cdc_acm_device_read_length_set(ULONG new_length)823 static void test_cdc_acm_device_read_length_set(ULONG new_length)
824 {
825     if (device_read_length == new_length)
826         return;
827     tx_thread_sleep(1);
828     if (new_length < 64)
829         device_read_length = 64;
830     else
831     {
832         /* Align with 64.  */
833         device_read_length = (new_length & 63u) ? ((new_length & ~63u) + 64) : new_length;
834     }
835 #if !defined(UX_DEVICE_STANDALONE)
836     /* Cancel the pending read to apply new length.  */
837     ux_device_class_cdc_acm_ioctl(cdc_acm_slave,
838             UX_SLAVE_CLASS_CDC_ACM_IOCTL_ABORT_PIPE,
839             (VOID*)UX_SLAVE_CLASS_CDC_ACM_ENDPOINT_RCV);
840 #else
841     /* Wait a while to let device background task do action.  */
842     tx_thread_sleep(2);
843 #endif
844 }
845 
846 
test_cdc_acm_device_read_write_blocking(void)847 static void test_cdc_acm_device_read_write_blocking(void)
848 {
849 UINT        status;
850 ULONG       actual_length;
851 UCHAR       test_chr;
852 ULONG       test_length;
853 ULONG       i, test;
854 #undef N_TEST
855 #define N_TEST 5
856 struct {
857     UCHAR chr;
858     ULONG len;
859 } tests[N_TEST] = {
860     {'$', 1},
861     {'A', 64},
862     {'N', 65},
863     {'3', UX_SLAVE_REQUEST_DATA_MAX_LENGTH - 64},
864     {'G', UX_SLAVE_REQUEST_DATA_MAX_LENGTH},
865 };
866 
867     for (test = 0; test < N_TEST; test ++)
868     {
869         test_chr    = tests[test].chr;
870         test_length = tests[test].len;
871         test_cdc_acm_device_read_length_set(test_length);
872 
873         for (i = 0; i < test_length; i ++)
874         {
875             host_buffer[i] = test_chr;
876         }
877 
878         /* Blocking write.  */
879         status = ux_host_class_cdc_acm_write(cdc_acm_host_data, host_buffer,
880                                              test_length, &actual_length);
881         UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "test_length %ld\n", test_length);
882         if (((test_length & 63) == 0) && actual_length != device_read_length)
883         {
884             status = ux_host_class_cdc_acm_write(cdc_acm_host_data, host_buffer,
885                                                  0, &actual_length);
886             UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "test_length %ld\n", test_length);
887         }
888 
889         /* Blocking read.  */
890         _ux_utility_memory_set(host_buffer, ~test_chr, test_length);
891         status = ux_host_class_cdc_acm_read(cdc_acm_host_data, host_buffer,
892                                             test_length, &actual_length);
893         UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "test_length %ld\n", test_length);
894         if (actual_length != test_length)
895         {
896             printf("ERROR #%d, length not match %ld <> %ld\n", __LINE__, test_length, actual_length);
897             test_control_return(1);
898         }
899         for (i = 0; i < test_length; i ++)
900         {
901             UX_TEST_ASSERT_MESSAGE(host_buffer[i] == test_chr, "test_length %ld\n", test_length);
902         }
903     }
904 }
905 
906 
907 #if defined(UX_HOST_STANDALONE)
908 
909 static ULONG test_cdc_acm_host_write_callback_count = 0;
910 static UINT  test_cdc_acm_host_write_callback_status;
911 static ULONG test_cdc_acm_host_write_callback_actual_length;
test_cdc_acm_host_write_callback(UX_HOST_CLASS_CDC_ACM * cdc_acm,UINT status,ULONG actual_length)912 static VOID test_cdc_acm_host_write_callback(UX_HOST_CLASS_CDC_ACM *cdc_acm,
913                                              UINT status, ULONG actual_length)
914 {
915     test_cdc_acm_host_write_callback_count ++;
916     test_cdc_acm_host_write_callback_status = status;
917     test_cdc_acm_host_write_callback_actual_length = actual_length;
918 }
919 
920 /* Uses _write_with_callback.  */
921 
test_cdc_acm_host_write(UX_HOST_CLASS_CDC_ACM * cdc_acm,UCHAR * data_pointer,ULONG requested_length,ULONG * actual_length)922 static UINT test_cdc_acm_host_write(UX_HOST_CLASS_CDC_ACM *cdc_acm,
923                                     UCHAR *data_pointer,
924                                     ULONG requested_length,
925                                     ULONG *actual_length)
926 {
927 UINT  status;
928 ULONG i;
929 
930     status = ux_host_class_cdc_acm_ioctl(cdc_acm,
931                                 UX_HOST_CLASS_CDC_ACM_IOCTL_WRITE_CALLBACK,
932                                 (VOID*)test_cdc_acm_host_write_callback);
933     if (status != UX_SUCCESS)
934         return(status);
935 
936     test_cdc_acm_host_write_callback_count = 0;
937     status = ux_host_class_cdc_acm_write_with_callback(cdc_acm, data_pointer, requested_length);
938     if (status != UX_SUCCESS)
939     {
940         printf("ERROR #%d : write exec error 0x%x\n", __LINE__, status);
941         return(status);
942     }
943     test_host_delay(requested_length/64 + 1);
944     if (test_cdc_acm_host_write_callback_count == 0)
945     {
946         printf("ERROR #%d : write timeout\n", __LINE__);
947         return(UX_TRANSFER_TIMEOUT);
948     }
949     status = ux_host_class_cdc_acm_ioctl(cdc_acm,
950                                 UX_HOST_CLASS_CDC_ACM_IOCTL_GET_WRITE_STATUS,
951                                 (VOID*)actual_length);
952     if (status != test_cdc_acm_host_write_callback_status ||
953         *actual_length != test_cdc_acm_host_write_callback_actual_length)
954     {
955         printf("ERROR #%d : write status conflict\n", __LINE__);
956         return(UX_ERROR);
957     }
958     return(UX_SUCCESS);
959 }
960 #else
961 #define test_cdc_acm_host_write                 ux_host_class_cdc_acm_write
962 #endif
963 
964 
test_cdc_acm_device_read_write(void)965 static void test_cdc_acm_device_read_write(void)
966 {
967 UINT        status;
968 ULONG       actual_length;
969 UCHAR       test_chr;
970 ULONG       test_length;
971 ULONG       i, test;
972 #undef N_TEST
973 #define N_TEST 6
974 struct {
975     UCHAR chr;
976     ULONG len;
977 } tests[N_TEST] = {
978     {'$', 1},
979     {'A', 64},
980     {'N', 65},
981     {'3', UX_SLAVE_REQUEST_DATA_MAX_LENGTH - 64},
982     {'G', UX_SLAVE_REQUEST_DATA_MAX_LENGTH},
983     {'H', UX_SLAVE_REQUEST_DATA_MAX_LENGTH + 1},
984 };
985 
986     /* Read packet by packet on device side.  */
987     test_cdc_acm_device_read_length_set(64);
988 
989     /* Reception parameter */
990     cdc_acm_host_reception.ux_host_class_cdc_acm_reception_block_size = UX_DEMO_RECEPTION_BLOCK_SIZE;
991     cdc_acm_host_reception.ux_host_class_cdc_acm_reception_data_buffer = cdc_acm_host_reception_buffer;
992     cdc_acm_host_reception.ux_host_class_cdc_acm_reception_data_buffer_size = UX_DEMO_RECEPTION_BUFFER_SIZE;
993     cdc_acm_host_reception.ux_host_class_cdc_acm_reception_callback = test_thread_host_reception_callback;
994 
995     /* Start reception.  */
996     status = ux_host_class_cdc_acm_reception_start(cdc_acm_host_data, &cdc_acm_host_reception);
997     if (status != UX_SUCCESS)
998     {
999         printf("ERROR #%d: reception start fail %x\n", __LINE__, status);
1000         test_control_return(1);
1001     }
1002 
1003     for (test = 0; test < N_TEST; test ++)
1004     {
1005         test_chr    = tests[test].chr;
1006         test_length = tests[test].len;
1007 
1008         for (i = 0; i < test_length; i ++)
1009         {
1010             host_buffer[i] = test_chr;
1011             cdc_acm_host_read_buffer[i] = ~test_chr;
1012         }
1013         cdc_acm_host_read_buffer_length = 0;
1014 
1015         status = test_cdc_acm_host_write(cdc_acm_host_data, host_buffer,
1016                                                 test_length, &actual_length);
1017         UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "test_length %ld\n", test_length);
1018         if (((test_length & 63) == 0) && actual_length != device_read_length)
1019         {
1020             status = test_cdc_acm_host_write(cdc_acm_host_data, host_buffer,
1021                                                 0, &actual_length);
1022             UX_TEST_ASSERT_MESSAGE(status == UX_SUCCESS, "test_length %ld\n", test_length);
1023         }
1024 
1025         /* Wait a while for background reception.  */
1026         test_host_delay(test_length/64 + 1);
1027 
1028         UX_TEST_ASSERT_MESSAGE(cdc_acm_host_reception_status == UX_SUCCESS, "test_length %ld\n", test_length);
1029         if (cdc_acm_host_read_buffer_length != test_length)
1030         {
1031             printf("ERROR #%d, length not match %ld <> %ld\n", __LINE__,
1032                 test_length, cdc_acm_host_read_buffer_length);
1033             test_control_return(1);
1034         }
1035         for (i = 0; i < test_length; i ++)
1036         {
1037             UX_TEST_ASSERT_MESSAGE(cdc_acm_host_read_buffer[i] == test_chr, "test_length %ld\n", test_length);
1038         }
1039     }
1040 
1041     /* Stop reception.  */
1042     ux_host_class_cdc_acm_reception_stop(cdc_acm_host_data, &cdc_acm_host_reception);
1043 }
1044 
ux_test_thread_host_simulation_entry(ULONG arg)1045 void  ux_test_thread_host_simulation_entry(ULONG arg)
1046 {
1047 
1048 UINT                                                status;
1049 
1050     stepinfo("\n");
1051 
1052     /* Find the cdc_acm class and wait for the link to be up.  */
1053     status =  demo_class_cdc_acm_get();
1054     if (status != UX_SUCCESS)
1055     {
1056 
1057         /* CDC ACM basic test error.  */
1058         printf("ERROR #10\n");
1059         test_control_return(1);
1060     }
1061 
1062     test_cdc_acm_device_ioctl_parameters();
1063     test_cdc_acm_device_read_write_blocking();
1064     test_cdc_acm_device_read_write();
1065 
1066     /* Finally disconnect the device. */
1067     ux_device_stack_disconnect();
1068 
1069     /* And deinitialize the class.  */
1070     status =  ux_device_stack_class_unregister(_ux_system_slave_class_cdc_acm_name, ux_device_class_cdc_acm_entry);
1071 
1072     /* Deinitialize the device side of usbx.  */
1073     _ux_device_stack_uninitialize();
1074 
1075     /* And finally the usbx system resources.  */
1076     _ux_system_uninitialize();
1077 
1078     /* Successful test.  */
1079     printf("SUCCESS!\n");
1080     test_control_return(0);
1081 
1082 }
1083 
ux_test_thread_slave_simulation_entry(ULONG arg)1084 void  ux_test_thread_slave_simulation_entry(ULONG arg)
1085 {
1086 
1087 UINT    status;
1088 ULONG   actual_length;
1089 ULONG   read_length = device_read_length;
1090 ULONG   write_length, write_zlp = UX_FALSE;
1091 #define CDC_ACM_DEVICE_STATE_READ     UX_STATE_STEP
1092 #define CDC_ACM_DEVICE_STATE_WRITE    UX_STATE_STEP + 1
1093 #define CDC_ACM_DEVICE_STATE_ZLP      UX_STATE_STEP + 2
1094 UINT    cdc_acm_device_state = UX_STATE_RESET;
1095 
1096     while(1)
1097     {
1098 
1099 #if defined(UX_DEVICE_STANDALONE)
1100 
1101         /* Keep running device stack tasks.  */
1102         ux_system_tasks_run();
1103 
1104         /* Reset state if read length changed.  */
1105         if (read_length != device_read_length)
1106         {
1107             cdc_acm_device_state = UX_STATE_RESET;
1108             read_length = device_read_length;
1109         }
1110 
1111         /* CDC ACM echo state machine.  */
1112         switch(cdc_acm_device_state)
1113         {
1114         case UX_STATE_RESET:
1115             if (cdc_acm_slave == UX_NULL)
1116                 break;
1117 
1118             {
1119                 ux_device_class_cdc_acm_ioctl(cdc_acm_slave,
1120                         UX_SLAVE_CLASS_CDC_ACM_IOCTL_ABORT_PIPE,
1121                         (VOID*)UX_SLAVE_CLASS_CDC_ACM_ENDPOINT_XMIT);
1122                 ux_device_class_cdc_acm_ioctl(cdc_acm_slave,
1123                         UX_SLAVE_CLASS_CDC_ACM_IOCTL_ABORT_PIPE,
1124                         (VOID*)UX_SLAVE_CLASS_CDC_ACM_ENDPOINT_RCV);
1125                 cdc_acm_device_state = CDC_ACM_DEVICE_STATE_READ;
1126             }
1127             /* Fall through.  */
1128         case CDC_ACM_DEVICE_STATE_READ:
1129             if (cdc_acm_slave == UX_NULL)
1130             {
1131                 cdc_acm_device_state = UX_STATE_RESET;
1132                 break;
1133             }
1134             status = ux_device_class_cdc_acm_read_run(cdc_acm_slave,
1135                             device_buffer, device_read_length, &actual_length);
1136             if (status < UX_STATE_NEXT)
1137             {
1138                 printf("ERROR #%d: read status 0x%x\n", __LINE__, status);
1139                 return;
1140             }
1141             if (status == UX_STATE_NEXT)
1142             {
1143                 write_length = actual_length;
1144                 if ((actual_length < device_read_length) &&
1145                     ((actual_length & 63) == 0))
1146                 {
1147                     write_zlp = UX_TRUE;
1148                 }
1149                 cdc_acm_device_state = CDC_ACM_DEVICE_STATE_WRITE;
1150             }
1151             break;
1152         case CDC_ACM_DEVICE_STATE_WRITE:
1153             if (cdc_acm_slave == UX_NULL)
1154             {
1155                 cdc_acm_device_state = UX_STATE_RESET;
1156                 break;
1157             }
1158             status = ux_device_class_cdc_acm_write_run(cdc_acm_slave,
1159                             device_buffer, write_length, &actual_length);
1160             if (status < UX_STATE_NEXT)
1161             {
1162                 printf("ERROR #%d: write status 0x%x\n", __LINE__, status);
1163                 return;
1164             }
1165             if (status == UX_STATE_NEXT)
1166             {
1167                 if (write_zlp && ((write_length % 64) == 0))
1168                 {
1169                     cdc_acm_device_state = CDC_ACM_DEVICE_STATE_ZLP;
1170                     break;
1171                 }
1172                 cdc_acm_device_state = CDC_ACM_DEVICE_STATE_READ;
1173                 break;
1174             }
1175             break;
1176         case CDC_ACM_DEVICE_STATE_ZLP:
1177             if (cdc_acm_slave == UX_NULL)
1178             {
1179                 cdc_acm_device_state = UX_STATE_RESET;
1180                 break;
1181             }
1182             status = ux_device_class_cdc_acm_write_run(cdc_acm_slave,
1183                             device_buffer, 0, &actual_length);
1184             if (status < UX_STATE_NEXT)
1185             {
1186                 printf("ERROR #%d: ZLP status 0x%x\n", __LINE__, status);
1187                 return;
1188             }
1189             if (status == UX_STATE_NEXT)
1190                 cdc_acm_device_state = CDC_ACM_DEVICE_STATE_READ;
1191             break;
1192         default:
1193             cdc_acm_device_state = UX_STATE_RESET;
1194         }
1195 
1196         /* Let other threads run.  */
1197         tx_thread_relinquish();
1198 #else
1199 
1200     if (cdc_acm_slave == UX_NULL)
1201     {
1202         tx_thread_sleep(1);
1203         continue;
1204     }
1205     /* Force reading packet by packet.  */
1206     status = ux_device_class_cdc_acm_read(cdc_acm_slave, device_buffer,
1207                                         device_read_length, &actual_length);
1208     if (status == UX_SUCCESS)
1209     {
1210         write_length = actual_length;
1211         status = ux_device_class_cdc_acm_write(cdc_acm_slave, device_buffer,
1212                                             write_length, &actual_length);
1213     }
1214 #endif
1215     }
1216 }
1217