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