1 /* This file tests the
2  * _ux_device_class_hid_control_request
3  * _ux_device_class_hid_interrupt_thread
4  */
5 
6 #include "usbx_test_common_hid.h"
7 
8 #include "ux_test_dcd_sim_slave.h"
9 #include "ux_test_hcd_sim_host.h"
10 #include "ux_test_utility_sim.h"
11 
12 #include "ux_host_class_hid_mouse.h"
13 #include "ux_host_class_hid_keyboard.h"
14 
15 #define DUMMY_USBX_MEMORY_SIZE          (64*1024)
16 
17 static UCHAR                            dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE];
18 
19 static UX_SLAVE_CLASS_HID               *slave_hid = UX_NULL;
20 static UX_SLAVE_CLASS_HID_EVENT         slave_hid_event;
21 
22 #define DEMO_PACKET_SIZE                8
23 #define DEVICE_BUFFER_LENGTH            32 /* 4*8  */ + 1
24 
25 static TX_SEMAPHORE                     device_semaphore;
26 static UCHAR                            device_buffer[DEVICE_BUFFER_LENGTH];
27 static UINT                             device_read_status;
28 static ULONG                            device_read_request_length;
29 static ULONG                            device_read_actual_length;
30 static ULONG                            device_read_count;
31 
32 #define HOST_BUFFER_LENGTH              32 /* 4*8  */
33 
34 static UCHAR                            host_buffer[HOST_BUFFER_LENGTH];
35 static ULONG                            host_buffer_length;
36 
37 static UCHAR hid_report_descriptor[] = {
38 
39     0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
40     0x09, 0x06,                    // USAGE (Keyboard)
41     0xa1, 0x01,                    // COLLECTION (Application)
42     0x05, 0x07,                    //   USAGE_PAGE (Keyboard)
43     0x19, 0xe0,                    //   USAGE_MINIMUM (Keyboard LeftControl)
44     0x29, 0xe7,                    //   USAGE_MAXIMUM (Keyboard Right GUI)
45     0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
46     0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
47     0x75, 0x01,                    //   REPORT_SIZE (1)
48     0x95, 0x08,                    //   REPORT_COUNT (8)
49     0x81, 0x02,                    //   INPUT (Data,Var,Abs)
50     0x95, 0x01,                    //   REPORT_COUNT (1)
51     0x75, 0x08,                    //   REPORT_SIZE (8)
52     0x81, 0x03,                    //   INPUT (Cnst,Var,Abs)
53     0x95, 0x05,                    //   REPORT_COUNT (5)
54     0x75, 0x01,                    //   REPORT_SIZE (1)
55     0x05, 0x08,                    //   USAGE_PAGE (LEDs)
56     0x19, 0x01,                    //   USAGE_MINIMUM (Num Lock)
57     0x29, 0x05,                    //   USAGE_MAXIMUM (Kana)
58     0x91, 0x02,                    //   OUTPUT (Data,Var,Abs)
59     0x95, 0x01,                    //   REPORT_COUNT (1)
60     0x75, 0x03,                    //   REPORT_SIZE (3)
61     0x91, 0x03,                    //   OUTPUT (Cnst,Var,Abs)
62     0x95, 0x06,                    //   REPORT_COUNT (6)
63     0x75, 0x08,                    //   REPORT_SIZE (8)
64     0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
65     0x25, 0x65,                    //   LOGICAL_MAXIMUM (101)
66     0x05, 0x07,                    //   USAGE_PAGE (Keyboard)
67     0x19, 0x00,                    //   USAGE_MINIMUM (Reserved (no event indicated))
68     0x29, 0x65,                    //   USAGE_MAXIMUM (Keyboard Application)
69     0x81, 0x00,                    //   INPUT (Data,Ary,Abs)
70     0xc0                           // END_COLLECTION
71 };
72 #define HID_REPORT_LENGTH sizeof(hid_report_descriptor)/sizeof(hid_report_descriptor[0])
73 
74 /* Configuration descriptor 9 bytes */
75 #define CFG_DESC(wTotalLength, bNumInterfaces, bConfigurationValue)\
76     /* Configuration 1 descriptor 9 bytes */\
77     0x09, 0x02, LSB(wTotalLength), MSB(wTotalLength),\
78     (bNumInterfaces), (bConfigurationValue), 0x00,\
79     0x40, 0x00,
80 #define CFG_DESC_LEN 9
81 
82 /* HID Mouse interface descriptors 9+9+7=25 bytes */
83 #define HID_MOUSE_IFC_DESC_ALL(ifc, interrupt_epa)     \
84     /* Interface descriptor */\
85     0x09, 0x04, (ifc), 0x00, 0x01, 0x03, 0x00, 0x00, 0x00,\
86     /* HID descriptor */\
87     0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_REPORT_LENGTH),\
88     MSB(HID_REPORT_LENGTH),\
89     /* Endpoint descriptor (Interrupt) */\
90     0x07, 0x05, (interrupt_epa), 0x03, 0x08, 0x00, 0x08,
91 #define HID_MOUSE_IFC_DESC_ALL_LEN 25
92 
93 /* HID Test interface descriptors 9+9+7+7=32 bytes */
94 #define HID_TEST_IFC_DESC_ALL(ifc, epa0, epa0_type, epa1, epa1_type)     \
95     /* Interface descriptor */\
96     0x09, 0x04, (ifc), 0x00, 0x02, 0x03, 0x00, 0x00, 0x00,\
97     /* HID descriptor */\
98     0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_REPORT_LENGTH),\
99     MSB(HID_REPORT_LENGTH),\
100     /* Endpoint descriptor */\
101     0x07, 0x05, (epa0), (epa0_type), 0x08, 0x00, 0x08,\
102     /* Endpoint descriptor */\
103     0x07, 0x05, (epa1), (epa1_type), 0x08, 0x00, 0x08,
104 #define HID_TEST_IFC_DESC_ALL_LEN 32
105 
106 static UCHAR device_framework_full_speed[] = {
107 
108     /* Device descriptor */
109     0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08,
110     0x81, 0x0A, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
111     0x00, 0x01,
112 
113     CFG_DESC(CFG_DESC_LEN+HID_TEST_IFC_DESC_ALL_LEN, 1, 1)
114     /* Interrupt IN @ 1st */
115     HID_TEST_IFC_DESC_ALL(0, 0x81, 3, 0x02, 3)
116 };
117 #define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED sizeof(device_framework_full_speed)
118 
119 
120 static UCHAR device_framework_high_speed[] = {
121 
122     /* Device descriptor */
123     0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40,
124     0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02,
125     0x03, 0x01,
126 
127     /* Device qualifier descriptor */
128     0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40,
129     0x01, 0x00,
130 
131     CFG_DESC(CFG_DESC_LEN+HID_MOUSE_IFC_DESC_ALL_LEN, 1, 1)
132     /* Interrupt IN @ 1st */
133     HID_TEST_IFC_DESC_ALL(0, 0x81, 3, 0x02, 3)
134 };
135 #define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED sizeof(device_framework_high_speed)
136 
137 
138     /* String Device Framework :
139      Byte 0 and 1 : Word containing the language ID : 0x0904 for US
140      Byte 2       : Byte containing the index of the descriptor
141      Byte 3       : Byte containing the length of the descriptor string
142     */
143 
144 #define STRING_FRAMEWORK_LENGTH 40
145 static UCHAR string_framework[] = {
146 
147     /* Manufacturer string descriptor : Index 1 */
148     0x09, 0x04, 0x01, 0x0c,
149     0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c,
150     0x6f, 0x67, 0x69, 0x63,
151 
152     /* Product string descriptor : Index 2 */
153     0x09, 0x04, 0x02, 0x0c,
154     0x55, 0x53, 0x42, 0x20, 0x4b, 0x65, 0x79, 0x62,
155     0x6f, 0x61, 0x72, 0x64,
156 
157     /* Serial Number string descriptor : Index 3 */
158     0x09, 0x04, 0x03, 0x04,
159     0x30, 0x30, 0x30, 0x31
160 };
161 
162 
163 /* Multiple languages are supported on the device, to add
164     a language besides english, the unicode language code must
165     be appended to the language_id_framework array and the length
166     adjusted accordingly. */
167 #define LANGUAGE_ID_FRAMEWORK_LENGTH 2
168 static UCHAR language_id_framework[] = {
169 
170     /* English. */
171     0x09, 0x04
172 };
173 
174 
175 UINT  _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter);
176 
177 
ux_system_host_change_function(ULONG a,UX_HOST_CLASS * b,VOID * c)178 static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c)
179 {
180     return 0;
181 }
182 
instance_activate_callback(VOID * parameter)183 static VOID instance_activate_callback(VOID *parameter)
184 {
185 
186     slave_hid = (UX_SLAVE_CLASS_HID *)parameter;
187 }
188 
error_callback(UINT system_level,UINT system_context,UINT error_code)189 static VOID error_callback(UINT system_level, UINT system_context, UINT error_code)
190 {
191 
192     // printf("Error on line %d: 0x%x, 0x%x, 0x%x\n", __LINE__, system_level, system_context, error_code);
193 }
194 
195 /* Define what the initial system looks like.  */
196 
197 #ifdef CTEST
test_application_define(void * first_unused_memory)198 void test_application_define(void *first_unused_memory)
199 #else
200 void    usbx_ux_device_class_hid_read_test_application_define(void *first_unused_memory)
201 #endif
202 {
203 
204 UINT                            status;
205 CHAR                            *stack_pointer;
206 CHAR                            *memory_pointer;
207 
208 
209     /* Inform user.  */
210     printf("Running ux_device_class_hid_ read/interrupt OUT tests .............. ");
211     stepinfo("\n");
212 
213     /* Initialize the free memory pointer */
214     stack_pointer = (CHAR *) usbx_memory;
215     memory_pointer = stack_pointer + (UX_DEMO_STACK_SIZE * 2);
216 
217     /* Initialize USBX. Memory */
218     status = ux_system_initialize(memory_pointer, UX_DEMO_MEMORY_SIZE, UX_NULL,0);
219 
220     /* Check for error.  */
221     if (status != UX_SUCCESS)
222     {
223 
224         printf("Error on line %d, error code: 0x%x\n", __LINE__, status);
225         test_control_return(1);
226     }
227 
228     /* Register the error callback. */
229     _ux_utility_error_callback_register(error_callback);
230 
231     /* The code below is required for installing the host portion of USBX */
232     status =  ux_host_stack_initialize(ux_system_host_change_function);
233     if (status != UX_SUCCESS)
234     {
235 
236         printf("Error on line %d, error code: 0x%x\n", __LINE__, status);
237         test_control_return(1);
238     }
239 
240     status =  ux_host_stack_class_register(_ux_system_host_class_hid_name, ux_host_class_hid_entry);
241     if (status != UX_SUCCESS)
242     {
243 
244         printf("Error on line %d, error code: 0x%x\n", __LINE__, status);
245         test_control_return(1);
246     }
247 
248     /* The code below is required for installing the device portion of USBX. No call back for
249        device status change in this example. */
250     status =  ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED,
251                                        device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED,
252                                        string_framework, STRING_FRAMEWORK_LENGTH,
253                                        language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH,UX_NULL);
254     if(status!=UX_SUCCESS)
255     {
256 
257         printf("Error on line %d, error code: 0x%x\n", __LINE__, status);
258         test_control_return(1);
259     }
260 
261     /* Initialize the hid class parameters.  */
262     hid_parameter.ux_device_class_hid_parameter_report_address = hid_report_descriptor;
263     hid_parameter.ux_device_class_hid_parameter_report_length  = HID_REPORT_LENGTH;
264     hid_parameter.ux_device_class_hid_parameter_callback       = demo_thread_hid_callback;
265     hid_parameter.ux_slave_class_hid_instance_activate         = instance_activate_callback;
266 
267     /* Initialize the device hid class. The class is connected with interface 2 */
268     status  = ux_device_stack_class_register(_ux_system_slave_class_hid_name, ux_device_class_hid_entry,
269                                              1,0, (VOID *)&hid_parameter);
270     if(status!=UX_SUCCESS)
271     {
272 
273         printf("Error on line %d, error code: 0x%x\n", __LINE__, status);
274         test_control_return(1);
275     }
276 
277     /* Initialize the simulated device controller.  */
278     status =  _ux_dcd_sim_slave_initialize();
279 
280     /* Check for error.  */
281     if (status != UX_SUCCESS)
282     {
283 
284         printf("Error on line %d, error code: 0x%x\n", __LINE__, status);
285         test_control_return(1);
286     }
287 
288     /* Register all the USB host controllers available in this system */
289     status =  ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, ux_hcd_sim_host_initialize,0,0);
290 
291     /* Check for error.  */
292     if (status != UX_SUCCESS)
293     {
294 
295         printf("Error on line %d, error code: 0x%x\n", __LINE__, status);
296         test_control_return(1);
297     }
298 
299     /* Create the main host simulation thread.  */
300     status =  tx_thread_create(&tx_demo_thread_host_simulation, "tx demo host simulation", tx_demo_thread_host_simulation_entry, 0,
301             stack_pointer, UX_DEMO_STACK_SIZE,
302             20, 20, 1, TX_AUTO_START);
303 
304     /* Check for error.  */
305     if (status != TX_SUCCESS)
306     {
307 
308         printf("Error on line %d, error code: 0x%x\n", __LINE__, status);
309         test_control_return(1);
310     }
311 
312     /* Create the main device simulation thread.  */
313     stack_pointer += UX_DEMO_STACK_SIZE;
314     status =  tx_thread_create(&tx_demo_thread_device_simulation, "tx demo device simulation", tx_demo_thread_device_simulation_entry, 0,
315             stack_pointer, UX_DEMO_STACK_SIZE,
316             20, 20, 1, TX_AUTO_START);
317 
318     /* Check for error.  */
319     if (status != TX_SUCCESS)
320     {
321 
322         printf("ERROR $%d, error code: 0x%x\n", __LINE__, status);
323         test_control_return(1);
324     }
325 }
326 
327 
tx_demo_thread_host_simulation_entry(ULONG arg)328 static void  tx_demo_thread_host_simulation_entry(ULONG arg)
329 {
330 
331 UINT                                status;
332 UX_DEVICE                           *device;
333 UX_ENDPOINT                         *endpoint;
334 
335     stepinfo(">>>>>>>>>> Thread start\n");
336 
337     _ux_utility_delay_ms(500);
338 
339     /* Get device instance. */
340     status = ux_host_stack_device_get(0, &device);
341 
342     if (status != UX_SUCCESS)
343     {
344         printf("ERROR #%d: get_device fail, 0x%x\n", __LINE__, status);
345         test_control_return(1);
346     }
347 
348     stepinfo(">>>>>>>>>> Get HID class instance\n");
349 
350     /* Find the HID class */
351     status = demo_class_hid_get();
352     if (status != UX_SUCCESS)
353     {
354 
355         printf("Error on line %d, error code: %d\n", __LINE__, status);
356         test_control_return(1);
357     }
358     if (slave_hid == UX_NULL)
359     {
360         printf("Error on line %d, HID slave instance error\n", __LINE__);
361         test_control_return(1);
362     }
363 
364 #if defined(UX_DEVICE_CLASS_HID_INTERRUPT_OUT_SUPPORT)
365     endpoint = hid -> ux_host_class_hid_interface -> ux_interface_first_endpoint;
366     if (endpoint -> ux_endpoint_descriptor.bEndpointAddress & 0x80)
367         endpoint = endpoint -> ux_endpoint_next_endpoint;
368     if (endpoint == UX_NULL)
369     {
370         printf("ERROR #%d: endpoint OUT not found\n", __LINE__);
371         test_control_return(1);
372     }
373     endpoint->ux_endpoint_transfer_request.ux_transfer_request_timeout_value = 100;
374     /* Device read 8, host send 0.  */
375     device_read_request_length = 8;
376     device_read_count = 0;
377     tx_semaphore_put(&device_semaphore);
378     status = ux_test_host_endpoint_write(endpoint, host_buffer, 0, UX_NULL);
379     UX_TEST_ASSERT(status == UX_SUCCESS);
380     UX_TEST_ASSERT(device_read_count == 1);
381     UX_TEST_ASSERT(device_read_status == UX_SUCCESS);
382     UX_TEST_ASSERT(device_read_actual_length == 0);
383     /* Device read 8, host send 1.  */
384     tx_semaphore_put(&device_semaphore);
385     ux_utility_memory_set(host_buffer, 0x5A, sizeof(host_buffer));
386     ux_utility_memory_set(device_buffer, 0x37, sizeof(device_buffer));
387     status = ux_test_host_endpoint_write(endpoint, host_buffer, 1, UX_NULL);
388     UX_TEST_ASSERT(status == UX_SUCCESS);
389     UX_TEST_ASSERT(device_read_count == 2);
390     UX_TEST_ASSERT(device_read_status == UX_SUCCESS);
391     UX_TEST_ASSERT(device_read_actual_length == 1);
392     UX_TEST_ASSERT(device_buffer[0] == host_buffer[0]);
393     UX_TEST_ASSERT(device_buffer[1] == 0X37);
394     /* Device read 8, host send 8.  */
395     tx_semaphore_put(&device_semaphore);
396     ux_utility_memory_set(host_buffer, 0x5A, sizeof(host_buffer));
397     ux_utility_memory_set(device_buffer, 0x37, sizeof(device_buffer));
398     status = ux_test_host_endpoint_write(endpoint, host_buffer, 8, UX_NULL);
399     UX_TEST_ASSERT(status == UX_SUCCESS);
400     UX_TEST_ASSERT(device_read_count == 3);
401     UX_TEST_ASSERT(device_read_status == UX_SUCCESS);
402     UX_TEST_ASSERT(device_read_actual_length == 8);
403     UX_TEST_ASSERT(device_buffer[0] == host_buffer[0]);
404     UX_TEST_ASSERT(device_buffer[7] == host_buffer[7]);
405     UX_TEST_ASSERT(device_buffer[8] == 0X37);
406     /* Device read 32, host send 8, then 3.  */
407     device_read_request_length = 32;
408     tx_semaphore_put(&device_semaphore);
409     ux_utility_memory_set(host_buffer, 0x5A, sizeof(host_buffer));
410     ux_utility_memory_set(device_buffer, 0x37, sizeof(device_buffer));
411     status = ux_test_host_endpoint_write(endpoint, host_buffer, 8, UX_NULL);
412     UX_TEST_ASSERT(status == UX_SUCCESS);
413     UX_TEST_ASSERT(device_read_count == 3);
414     status = ux_test_host_endpoint_write(endpoint, host_buffer, 3, UX_NULL);
415     UX_TEST_ASSERT(status == UX_SUCCESS);
416     UX_TEST_ASSERT(device_read_count == 4);
417     UX_TEST_ASSERT(device_read_status == UX_SUCCESS);
418     UX_TEST_ASSERT(device_read_actual_length == 11);
419     UX_TEST_ASSERT(device_buffer[0] == host_buffer[0]);
420     UX_TEST_ASSERT(device_buffer[10] == host_buffer[10]);
421     UX_TEST_ASSERT(device_buffer[11] == 0X37);
422 #endif
423 
424     _ux_utility_delay_ms(500);
425 
426     stepinfo(">>>>>>>>>> Test done\n");
427 
428     /* Now disconnect the device.  */
429     _ux_device_stack_disconnect();
430 
431     /* And deinitialize the class.  */
432     status =  ux_device_stack_class_unregister(_ux_system_slave_class_hid_name, ux_device_class_hid_entry);
433 
434     /* Deinitialize the device side of usbx.  */
435     _ux_device_stack_uninitialize();
436 
437     /* And finally the usbx system resources.  */
438     _ux_system_uninitialize();
439 
440     /* Successful test.  */
441     printf("SUCCESS!\n");
442     test_control_return(0);
443 }
444 
445 
tx_demo_thread_device_simulation_entry(ULONG arg)446 static void  tx_demo_thread_device_simulation_entry(ULONG arg)
447 {
448 
449 UINT                    status;
450 
451     status = tx_semaphore_create(&device_semaphore, "device semaphore", 0);
452     if (status != TX_SUCCESS)
453     {
454         printf("ERROR #%d device semaphore creation error 0x%x\n", __LINE__, status);
455         test_control_return(1);
456         return;
457     }
458 
459     while(1)
460     {
461         if (slave_hid == UX_NULL)
462         {
463             tx_thread_sleep(10);
464             continue;
465         }
466         /* Wait semaphore to start read.  */
467         status = tx_semaphore_get(&device_semaphore, TX_WAIT_FOREVER);
468         if (status != TX_SUCCESS)
469         {
470             printf("ERROR #%d device semaphore get error 0x%x\n", __LINE__, status);
471             test_control_return(1);
472             return;
473         }
474         /* Read and save status.  */
475 #if defined(UX_DEVICE_STANDALONE)
476         do
477         {
478             ux_system_tasks_run();
479             status = ux_device_class_hid_read_run(slave_hid, device_buffer, device_read_request_length, &device_read_actual_length);
480         } while(status == UX_STATE_WAIT);
481         status = (status == UX_STATE_NEXT) ? UX_SUCCESS : UX_ERROR;
482 #else
483         status = ux_device_class_hid_read(slave_hid, device_buffer, device_read_request_length, &device_read_actual_length);
484 #endif
485         device_read_status = status;
486         device_read_count ++;
487     }
488 }
489 
490 
demo_thread_hid_callback(UX_SLAVE_CLASS_HID * class,UX_SLAVE_CLASS_HID_EVENT * event)491 static UINT    demo_thread_hid_callback(UX_SLAVE_CLASS_HID *class, UX_SLAVE_CLASS_HID_EVENT *event)
492 {
493     return(UX_SUCCESS);
494 }
495