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, ¶meter);
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