1 /* This test concentrates on the ux_host_class_hid_report_get API. */
2 
3 #include "usbx_test_common_hid.h"
4 #include "ux_host_class_hid_keyboard.h"
5 
6 
7 static UCHAR hid_report_descriptor[] = {
8 
9     0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
10     0x09, 0x06,                    // USAGE (Keyboard)
11     0xa1, 0x01,                    // COLLECTION (Application)
12     0x05, 0x07,                    //   USAGE_PAGE (Keyboard)
13     0x19, 0xe0,                    //   USAGE_MINIMUM (Keyboard LeftControl)
14     0x29, 0xe7,                    //   USAGE_MAXIMUM (Keyboard Right GUI)
15     0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
16     0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
17     0x75, 0x01,                    //   REPORT_SIZE (1)
18     0x95, 0x08,                    //   REPORT_COUNT (8)
19     0x81, 0x02,                    //   INPUT (Data,Var,Abs)
20     0x95, 0x01,                    //   REPORT_COUNT (1)
21     0x75, 0x08,                    //   REPORT_SIZE (8)
22     0x81, 0x03,                    //   INPUT (Cnst,Var,Abs)
23     0x95, 0x05,                    //   REPORT_COUNT (5)
24     0x75, 0x01,                    //   REPORT_SIZE (1)
25     0x05, 0x08,                    //   USAGE_PAGE (LEDs)
26     0x19, 0x01,                    //   USAGE_MINIMUM (Num Lock)
27     0x29, 0x05,                    //   USAGE_MAXIMUM (Kana)
28     0x91, 0x02,                    //   OUTPUT (Data,Var,Abs)
29     0x95, 0x01,                    //   REPORT_COUNT (1)
30     0x75, 0x03,                    //   REPORT_SIZE (3)
31     0x91, 0x03,                    //   OUTPUT (Cnst,Var,Abs)
32     0x95, 0x06,                    //   REPORT_COUNT (6)
33     0x75, 0x08,                    //   REPORT_SIZE (8)
34     0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
35     0x25, 0x65,                    //   LOGICAL_MAXIMUM (101)
36     0x05, 0x07,                    //   USAGE_PAGE (Keyboard)
37     0x19, 0x00,                    //   USAGE_MINIMUM (Reserved (no event indicated))
38     0x29, 0x65,                    //   USAGE_MAXIMUM (Keyboard Application)
39     0x81, 0x00,                    //   INPUT (Data,Ary,Abs)
40     0xc0                           // END_COLLECTION
41 };
42 #define HID_REPORT_LENGTH sizeof(hid_report_descriptor)/sizeof(hid_report_descriptor[0])
43 
44 
45 #define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 52
46 static UCHAR device_framework_full_speed[DEVICE_FRAMEWORK_LENGTH_FULL_SPEED] = {
47 
48     /* Device descriptor */
49         0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08,
50         0x81, 0x0A, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
51         0x00, 0x01,
52 
53     /* Configuration descriptor */
54         0x09, 0x02, 0x22, 0x00, 0x01, 0x01, 0x00, 0xc0,
55         0x32,
56 
57     /* Interface descriptor */
58         0x09, 0x04, 0x02, 0x00, 0x01, 0x03, 0x00, 0x00,
59         0x00,
60 
61     /* HID descriptor */
62         0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_REPORT_LENGTH),
63         MSB(HID_REPORT_LENGTH),
64 
65     /* Endpoint descriptor (Interrupt) */
66         0x07, 0x05, 0x82, 0x03, 0x08, 0x00, 0x08
67 
68     };
69 
70 
71 #define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 62
72 static UCHAR device_framework_high_speed[DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED] = {
73 
74     /* Device descriptor */
75         0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40,
76         0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02,
77         0x03, 0x01,
78 
79     /* Device qualifier descriptor */
80         0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40,
81         0x01, 0x00,
82 
83     /* Configuration descriptor */
84         0x09, 0x02, 0x22, 0x00, 0x01, 0x01, 0x00, 0xc0,
85         0x32,
86 
87     /* Interface descriptor */
88         0x09, 0x04, 0x02, 0x00, 0x01, 0x03, 0x00, 0x00,
89         0x00,
90 
91     /* HID descriptor */
92         0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_REPORT_LENGTH),
93         MSB(HID_REPORT_LENGTH),
94 
95     /* Endpoint descriptor (Interrupt) */
96         0x07, 0x05, 0x82, 0x03, 0x08, 0x00, 0x08
97 
98     };
99 
100 
101     /* String Device Framework :
102      Byte 0 and 1 : Word containing the language ID : 0x0904 for US
103      Byte 2       : Byte containing the index of the descriptor
104      Byte 3       : Byte containing the length of the descriptor string
105     */
106 
107 #define STRING_FRAMEWORK_LENGTH 40
108 static UCHAR string_framework[] = {
109 
110     /* Manufacturer string descriptor : Index 1 */
111         0x09, 0x04, 0x01, 0x0c,
112         0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c,
113         0x6f, 0x67, 0x69, 0x63,
114 
115     /* Product string descriptor : Index 2 */
116         0x09, 0x04, 0x02, 0x0c,
117         0x55, 0x53, 0x42, 0x20, 0x4b, 0x65, 0x79, 0x62,
118         0x6f, 0x61, 0x72, 0x64,
119 
120     /* Serial Number string descriptor : Index 3 */
121         0x09, 0x04, 0x03, 0x04,
122         0x30, 0x30, 0x30, 0x31
123     };
124 
125 
126     /* Multiple languages are supported on the device, to add
127        a language besides english, the unicode language code must
128        be appended to the language_id_framework array and the length
129        adjusted accordingly. */
130 #define LANGUAGE_ID_FRAMEWORK_LENGTH 2
131 static UCHAR language_id_framework[] = {
132 
133     /* English. */
134         0x09, 0x04
135     };
136 
137 
138 /* Define the ISR dispatch.  */
139 
140 extern VOID    (*test_isr_dispatch)(void);
141 
142 
143 /* Prototype for test control return.  */
144 
145 void  test_control_return(UINT status);
146 
147 
148 /* Define the ISR dispatch routine.  */
149 
test_isr(void)150 static void    test_isr(void)
151 {
152 
153     /* For further expansion of interrupt-level testing.  */
154 }
155 
156 UINT  _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter);
157 
error_callback(UINT system_level,UINT system_context,UINT error_code)158 static VOID error_callback(UINT system_level, UINT system_context, UINT error_code)
159 {
160 }
161 
162 /* Define what the initial system looks like.  */
163 
164 #ifdef CTEST
test_application_define(void * first_unused_memory)165 void test_application_define(void *first_unused_memory)
166 #else
167 void    usbx_ux_host_class_hid_report_get_test_application_define(void *first_unused_memory)
168 #endif
169 {
170 
171 UINT status;
172 CHAR *                          stack_pointer;
173 CHAR *                          memory_pointer;
174 
175 
176     /* Inform user.  */
177     printf("Running ux_host_class_hid_report_get Test........................... ");
178 
179     /* Initialize the free memory pointer */
180     stack_pointer = (CHAR *) usbx_memory;
181     memory_pointer = stack_pointer + (UX_DEMO_STACK_SIZE * 2);
182 
183     /* Initialize USBX. Memory */
184     status = ux_system_initialize(memory_pointer, UX_DEMO_MEMORY_SIZE, UX_NULL,0);
185 
186     /* Check for error.  */
187     if (status != UX_SUCCESS)
188     {
189 
190         printf("Error on line %d\n", __LINE__);
191         test_control_return(1);
192     }
193 
194     /* Register the error callback. */
195     _ux_utility_error_callback_register(error_callback);
196 
197     /* The code below is required for installing the host portion of USBX */
198     status =  ux_host_stack_initialize(UX_NULL);
199     if (status != UX_SUCCESS)
200     {
201 
202         printf("Error on line %d\n", __LINE__);
203         test_control_return(1);
204     }
205 
206     status =  ux_host_stack_class_register(_ux_system_host_class_hid_name, ux_host_class_hid_entry);
207     if (status != UX_SUCCESS)
208     {
209 
210         printf("Error on line %d\n", __LINE__);
211         test_control_return(1);
212     }
213 
214     /* Register the HID client(s).  */
215     status =  ux_host_class_hid_client_register(_ux_system_host_class_hid_client_keyboard_name, ux_host_class_hid_keyboard_entry);
216     if (status != UX_SUCCESS)
217     {
218 
219         printf("Error on line %d\n", __LINE__);
220         test_control_return(1);
221     }
222 
223     /* The code below is required for installing the device portion of USBX. No call back for
224        device status change in this example. */
225     status =  ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED,
226                                        device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED,
227                                        string_framework, STRING_FRAMEWORK_LENGTH,
228                                        language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH,UX_NULL);
229     if(status!=UX_SUCCESS)
230     {
231 
232         printf("Error on line %d\n", __LINE__);
233         test_control_return(1);
234     }
235 
236     /* Initialize the hid class parameters for a keyboard.  */
237     hid_parameter.ux_device_class_hid_parameter_report_address = hid_report_descriptor;
238     hid_parameter.ux_device_class_hid_parameter_report_length  = HID_REPORT_LENGTH;
239     hid_parameter.ux_device_class_hid_parameter_callback       = demo_thread_hid_callback;
240 
241     /* Initilize the device hid class. The class is connected with interface 2 */
242     status =  ux_device_stack_class_register(_ux_system_slave_class_hid_name, ux_device_class_hid_entry,
243                                                 1,2, (VOID *)&hid_parameter);
244     if(status!=UX_SUCCESS)
245     {
246 
247         printf("Error on line %d\n", __LINE__);
248         test_control_return(1);
249     }
250 
251 
252     /* Initialize the simulated device controller.  */
253     status =  _ux_dcd_sim_slave_initialize();
254 
255     /* Check for error.  */
256     if (status != UX_SUCCESS)
257     {
258 
259         printf("Error on line %d\n", __LINE__);
260         test_control_return(1);
261     }
262 
263     /* Register all the USB host controllers available in this system */
264     status =  ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, ux_hcd_sim_host_initialize,0,0);
265 
266     /* Check for error.  */
267     if (status != UX_SUCCESS)
268     {
269 
270         printf("Error on line %d\n", __LINE__);
271         test_control_return(1);
272     }
273 
274     /* Create the main host simulation thread.  */
275     status =  tx_thread_create(&tx_demo_thread_host_simulation, "tx demo host simulation", tx_demo_thread_host_simulation_entry, 0,
276             stack_pointer, UX_DEMO_STACK_SIZE,
277             20, 20, 1, TX_AUTO_START);
278 
279     /* Check for error.  */
280     if (status != TX_SUCCESS)
281     {
282 
283         printf("Error on line %d\n", __LINE__);
284         test_control_return(1);
285     }
286 
287     /* Create the main demo thread.  */
288     status =  tx_thread_create(&tx_demo_thread_slave_simulation, "tx demo slave simulation", tx_demo_thread_slave_simulation_entry, 0,
289             stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE,
290             20, 20, 1, TX_AUTO_START);
291 
292     /* Check for error.  */
293     if (status != TX_SUCCESS)
294     {
295 
296         printf("Error on line %d\n", __LINE__);
297         test_control_return(1);
298     }
299 
300 }
301 
ux_hcd_sim_host_entry_filter(UX_HCD * hcd,UINT function,VOID * parameter)302 static UINT ux_hcd_sim_host_entry_filter(UX_HCD *hcd, UINT function, VOID *parameter)
303 {
304 
305 UINT status;
306 
307     switch(function)
308     {
309     case UX_HCD_TRANSFER_REQUEST:
310 
311         status = UX_ERROR;
312 
313         break;
314 
315 
316     default:
317 
318         status = _ux_hcd_sim_host_entry(hcd, function, parameter);
319         break;
320     }
321 
322     return status;
323 }
324 
tx_demo_thread_host_simulation_entry(ULONG arg)325 static void  tx_demo_thread_host_simulation_entry(ULONG arg)
326 {
327 
328 UINT                                status;
329 UX_HOST_CLASS_HID_REPORT_GET_ID     report_id;
330 UX_HOST_CLASS_HID_CLIENT_REPORT     input_report_request;
331 UX_HOST_CLASS_HID_REPORT            *input_report_descriptor;
332 UX_HOST_CLASS_HID_KEYBOARD          *keyboard;
333 UCHAR                               input_report_buffer_char[1024];
334 ULONG                               *input_report_buffer_long = (ULONG *)input_report_buffer_char;
335 
336 
337     /* Find the HID class */
338     status = demo_class_hid_get();
339     if (status != UX_SUCCESS)
340     {
341 
342         printf("Error on line %d\n", __LINE__);
343         test_control_return(1);
344     }
345 
346     /* Get the HID client */
347     hid_client = hid -> ux_host_class_hid_client;
348 
349     /* Check if the instance of the keyboard is live */
350     while (hid_client -> ux_host_class_hid_client_local_instance == UX_NULL)
351         tx_thread_sleep(10);
352 
353     /* Get the keyboard instance */
354     keyboard = (UX_HOST_CLASS_HID_KEYBOARD *)hid_client->ux_host_class_hid_client_local_instance;
355 
356     /**************************************************/
357     /** Test case: functionality test. **/
358     /**************************************************/
359 
360     /* Disable the default method of retrieving events (periodic interrupt endpoint) since we'll be using control transfers. */
361     status = ux_host_class_hid_periodic_report_stop(hid);
362     if (status != UX_SUCCESS)
363     {
364 
365         printf("Error on line %d\n", __LINE__);
366         test_control_return(1);
367     }
368 
369     /* Get the report ID for the keyboard. */
370     report_id.ux_host_class_hid_report_get_report = UX_NULL;
371     report_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT;
372     status = _ux_host_class_hid_report_id_get(hid, &report_id);
373     if (status != UX_SUCCESS)
374     {
375 
376         printf("Error on line %d\n", __LINE__);
377         test_control_return(1);
378     }
379 
380     input_report_descriptor = report_id.ux_host_class_hid_report_get_report;
381 
382     /* Fill out input report request. */
383     input_report_request.ux_host_class_hid_client_report = input_report_descriptor;
384     input_report_request.ux_host_class_hid_client_report_buffer = input_report_buffer_long;
385     input_report_request.ux_host_class_hid_client_report_length = input_report_descriptor -> ux_host_class_hid_report_byte_length;
386 
387     /* For the first part of this test, we request the raw report. */
388 
389     input_report_request.ux_host_class_hid_client_report_flags = UX_HOST_CLASS_HID_REPORT_RAW;
390 
391     /* Poll until we've received an input report with actual data. */
392     while (1)
393     {
394 
395         /* Reset the actual length. */
396         input_report_request.ux_host_class_hid_client_report_actual_length = 0;
397 
398         /* Get a raw input report from the device. */
399         status = ux_host_class_hid_report_get(hid, &input_report_request);
400         if (status != UX_SUCCESS)
401         {
402 
403             printf("Error on line %d\n", __LINE__);
404             test_control_return(1);
405         }
406 
407         /* Was there actual data? The modifier should be set if there is. */
408         if (input_report_buffer_char[0] != 0)
409             break;
410 
411         tx_thread_sleep(10);
412     }
413 
414     /* Check the data. */
415 
416     /* Is this not the modifier we're expecting? */
417     if (input_report_buffer_char[0] != 0x45)
418     {
419 
420         printf("Error on line %d\n", __LINE__);
421         test_control_return(1);
422     }
423 
424     /* Are these not the keys we're expecting? */
425     if (input_report_buffer_char[2] != 0x04 ||
426         input_report_buffer_char[3] != 0x05 ||
427         input_report_buffer_char[4] != 0x06 ||
428         input_report_buffer_char[5] != 0x07 ||
429         input_report_buffer_char[6] != 0x08 ||
430         input_report_buffer_char[7] != 0x09)
431     {
432 
433         printf("Error on line %d\n", __LINE__);
434         test_control_return(1);
435     }
436 
437     /* We just tested getting the report raw; this second part is getting it decompressed.
438        Note that the decompressed version is interleaved as 'Usage Value Usage Value...' */
439 
440     input_report_request.ux_host_class_hid_client_report_flags = UX_HOST_CLASS_HID_REPORT_DECOMPRESSED;
441 
442     /* Poll until we've received an input report with actual data. */
443     while (1)
444     {
445 
446         /* Reset the actual length. */
447         input_report_request.ux_host_class_hid_client_report_actual_length = 0;
448 
449         /* Get a raw input report from the device. */
450         status = ux_host_class_hid_report_get(hid, &input_report_request);
451         if (status != UX_SUCCESS)
452         {
453 
454             printf("Error on line %d\n", __LINE__);
455             test_control_return(1);
456         }
457 
458         /* Was there actual data? This value should be non-zero if it is. */
459         if (input_report_buffer_long[2*0 + 1] != 0)
460             break;
461 
462         tx_thread_sleep(10);
463     }
464 
465     /* Check the data. */
466 
467     /* Are these not the modifiers we're expecting? */
468     if (input_report_buffer_long[2*0 + 0] != 0x000700e0 ||
469         input_report_buffer_long[2*0 + 1] != 1 ||
470         input_report_buffer_long[2*1 + 0] != 0x000700e1 ||
471         input_report_buffer_long[2*1 + 1] != 0 ||
472         input_report_buffer_long[2*2 + 0] != 0x000700e2 ||
473         input_report_buffer_long[2*2 + 1] != 1 ||
474         input_report_buffer_long[2*3 + 0] != 0x000700e3 ||
475         input_report_buffer_long[2*3 + 1] != 0 ||
476         input_report_buffer_long[2*4 + 0] != 0x000700e4 ||
477         input_report_buffer_long[2*4 + 1] != 0 ||
478         input_report_buffer_long[2*5 + 0] != 0x000700e5 ||
479         input_report_buffer_long[2*5 + 1] != 0 ||
480         input_report_buffer_long[2*6 + 0] != 0x000700e6 ||
481         input_report_buffer_long[2*6 + 1] != 1 ||
482         input_report_buffer_long[2*7 + 0] != 0x000700e7 ||
483         input_report_buffer_long[2*7 + 1] != 0)
484     {
485 
486         printf("Error on line %d\n", __LINE__);
487         test_control_return(1);
488     }
489 
490     /* Are these not the usages and keys we're expecting? */
491     if (input_report_buffer_long[2*9  + 0] != 0x00070004 ||
492         input_report_buffer_long[2*9  + 1] != 0x00000004 ||
493         input_report_buffer_long[2*10 + 0] != 0x00070005 ||
494         input_report_buffer_long[2*10 + 1] != 0x00000005 ||
495         input_report_buffer_long[2*11 + 0] != 0x00070006 ||
496         input_report_buffer_long[2*11 + 1] != 0x00000006 ||
497         input_report_buffer_long[2*12 + 0] != 0x00070007 ||
498         input_report_buffer_long[2*12 + 1] != 0x00000007 ||
499         input_report_buffer_long[2*13 + 0] != 0x00070008 ||
500         input_report_buffer_long[2*13 + 1] != 0x00000008 ||
501         input_report_buffer_long[2*14 + 0] != 0x00070009 ||
502         input_report_buffer_long[2*14 + 1] != 0x00000009)
503     {
504 
505         printf("Error on line %d\n", __LINE__);
506         test_control_return(1);
507     }
508 
509     /* Now disconnect the device.  */
510     _ux_device_stack_disconnect();
511 
512     /* And deinitialize the class.  */
513     status =  ux_device_stack_class_unregister(_ux_system_slave_class_hid_name, ux_device_class_hid_entry);
514 
515     /* Deinitialize the device side of usbx.  */
516     _ux_device_stack_uninitialize();
517 
518     /* And finally the usbx system resources.  */
519     _ux_system_uninitialize();
520 
521     /* Successful test.  */
522     printf("SUCCESS!\n");
523     test_control_return(0);
524 }
525 
demo_thread_hid_callback(UX_SLAVE_CLASS_HID * class,UX_SLAVE_CLASS_HID_EVENT * event)526 static UINT    demo_thread_hid_callback(UX_SLAVE_CLASS_HID *class, UX_SLAVE_CLASS_HID_EVENT *event)
527 {
528     return(UX_SUCCESS);
529 }
530 
tx_demo_thread_slave_simulation_entry(ULONG arg)531 static void  tx_demo_thread_slave_simulation_entry(ULONG arg)
532 {
533 
534 UX_SLAVE_DEVICE                 *device;
535 UX_SLAVE_INTERFACE              *interface;
536 UX_SLAVE_CLASS_HID              *hid;
537 UX_SLAVE_CLASS_HID_EVENT        hid_event;
538 
539     /* Get the pointer to the device.  */
540     device =  &_ux_system_slave -> ux_system_slave_device;
541 
542     /* reset the HID event structure.  */
543     ux_utility_memory_set(&hid_event, 0, sizeof(UX_SLAVE_CLASS_HID_EVENT));
544 
545     while(1)
546     {
547 
548         /* Is the device configured ? */
549         while (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED)
550 
551             /* Then wait.  */
552             tx_thread_sleep(10);
553 
554         /* Until the device stays configured.  */
555         while (device -> ux_slave_device_state == UX_DEVICE_CONFIGURED)
556         {
557 
558             /* Get the interface.  We use the first interface, this is a simple device.  */
559             interface =  device -> ux_slave_device_first_interface;
560 
561             /* Form that interface, derive the HID owner.  */
562             hid = interface -> ux_slave_interface_class_instance;
563 
564             /* Wait for 2 seconds. */
565             ux_utility_thread_sleep(20);
566 
567             /* Then insert a key into the keyboard event.  Length is fixed to 8.  */
568             hid_event.ux_device_class_hid_event_length = 8;
569 
570             /* First byte is a modifier byte. Set some bits: 10100010.  */
571             hid_event.ux_device_class_hid_event_buffer[0] = 0x45;
572 
573             /* Second byte is reserved. */
574             hid_event.ux_device_class_hid_event_buffer[1] = 0;
575 
576             /* The 6 next bytes are keys.  */
577             hid_event.ux_device_class_hid_event_buffer[2] = 0x04;
578             hid_event.ux_device_class_hid_event_buffer[3] = 0x05;
579             hid_event.ux_device_class_hid_event_buffer[4] = 0x06;
580             hid_event.ux_device_class_hid_event_buffer[5] = 0x07;
581             hid_event.ux_device_class_hid_event_buffer[6] = 0x08;
582             hid_event.ux_device_class_hid_event_buffer[7] = 0x09;
583 
584             /* Set the keyboard event.  */
585             ux_device_class_hid_event_set(hid, &hid_event);
586         }
587     }
588 }
589 
590