1 /* This file tests that the host correctly receives the keys the device sends to it. */
2 
3 #include "usbx_test_common_hid.h"
4 
5 #include "ux_host_class_hid_keyboard.h"
6 
7 #define HOST_WAIT_TIME  1
8 #define SLAVE_WAIT_TIME (3*HOST_WAIT_TIME)
9 
10 static UCHAR ux_host_class_hid_keyboard_regular_array[] =
11 {
12    0,0,0,0,
13    'a','b','c','d','e','f','g','h','i','j', 'k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
14    '1','2','3','4','5','6','7','8','9','0',
15    0x0d,0x1b,0x08,0x07,0x20,'-','=','[',']',
16    '\\','#',';',0x27,'`',',','.','/',0xf0,
17    0xbb,0xbc,0xbd,0xbe,0xbf,0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,
18    0x00,0xf1,0x00,0xd2,0xc7,0xc9,0xd3,0xcf,0xd1,0xcd,0xcd,0xd0,0xc8,0xf2,
19    '/','*','-','+',
20    0x0d,'1','2','3','4','5','6','7','8','9','0','.','\\',0x00,0x00,'=',
21    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
22 };
23 
24 static UCHAR ux_host_class_hid_keyboard_shift_array[] =
25 {
26    0,0,0,0,
27    'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
28    '!','@','#','$','%','^','&','*','(',')',
29    0x0d,0x1b,0x08,0x07,0x20,'_','+','{','}',
30    '|','~',':','"','~','<','>','?',0xf0,
31    0xbb,0xbc,0xbd,0xbe,0xbf,0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,
32    0x00,0xf1,0x00,0xd2,0xc7,0xc9,0xd3,0xcf,0xd1,0xcd,0xcd,0xd0,0xc8,0xf2,
33    '/','*','-','+',
34    0x0d,'1','2','3','4','5','6','7','8','9','0','.','\\',0x00,0x00,'=',
35    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
36 };
37 
38 static UCHAR ux_host_class_hid_keyboard_numlock_on_array[] =
39 {
40    '/','*','-','+',
41    0x0d,'1','2','3','4','5','6','7','8','9','0','.','\\',0x00,0x00,'=',
42 };
43 
44 static UCHAR ux_host_class_hid_keyboard_numlock_off_array[] =
45 {
46    '/','*','-','+',
47    0x0d,0xcf,0xd0,0xd1,0xcb,'5',0xcd,0xc7,0xc8,0xc9,0xd2,0xd3,'\\',0x00,0x00,'=',
48 };
49 
50 static UX_HOST_CLASS_HID_KEYBOARD_LAYOUT test_layout_swap_regular_shift =
51 {
52     .ux_host_class_hid_keyboard_layout_regular_array = ux_host_class_hid_keyboard_shift_array,
53     .ux_host_class_hid_keyboard_layout_shift_array = ux_host_class_hid_keyboard_regular_array,
54     .ux_host_class_hid_keyboard_layout_numlock_on_array = ux_host_class_hid_keyboard_numlock_on_array,
55     .ux_host_class_hid_keyboard_layout_numlock_off_array = ux_host_class_hid_keyboard_numlock_off_array,
56     .ux_host_class_hid_keyboard_layout_keys_upper_range = UX_HID_KEYBOARD_KEYS_UPPER_RANGE,
57     .ux_host_class_hid_keyboard_layout_letters_lower_range = UX_HID_KEYBOARD_KEY_LETTER_A,
58     .ux_host_class_hid_keyboard_layout_letters_upper_range = UX_HID_KEYBOARD_KEY_LETTER_Z,
59     .ux_host_class_hid_keyboard_layout_keypad_lower_range = UX_HID_KEYBOARD_KEYS_KEYPAD_LOWER_RANGE,
60     .ux_host_class_hid_keyboard_layout_keypad_upper_range = UX_HID_KEYBOARD_KEYS_KEYPAD_UPPER_RANGE,
61 };
62 
63 
64 #define DUMMY_USBX_MEMORY_SIZE (64*1024)
65 static UCHAR dummy_usbx_memory[DUMMY_USBX_MEMORY_SIZE];
66 
67 static UCHAR hid_report_descriptor[] = {
68 
69     0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
70     0x09, 0x06,                    // USAGE (Keyboard)
71     0xa1, 0x01,                    // COLLECTION (Application)
72     0x05, 0x07,                    //   USAGE_PAGE (Keyboard)
73     0x19, 0xe0,                    //   USAGE_MINIMUM (Keyboard LeftControl)
74     0x29, 0xe7,                    //   USAGE_MAXIMUM (Keyboard Right GUI)
75     0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
76     0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
77     0x75, 0x01,                    //   REPORT_SIZE (1)
78     0x95, 0x08,                    //   REPORT_COUNT (8)
79     0x81, 0x02,                    //   INPUT (Data,Var,Abs)
80     0x95, 0x01,                    //   REPORT_COUNT (1)
81     0x75, 0x08,                    //   REPORT_SIZE (8)
82     0x81, 0x03,                    //   INPUT (Cnst,Var,Abs)
83     0x95, 0x05,                    //   REPORT_COUNT (5)
84     0x75, 0x01,                    //   REPORT_SIZE (1)
85     0x05, 0x08,                    //   USAGE_PAGE (LEDs)
86     0x19, 0x01,                    //   USAGE_MINIMUM (Num Lock)
87     0x29, 0x05,                    //   USAGE_MAXIMUM (Kana)
88     0x91, 0x02,                    //   OUTPUT (Data,Var,Abs)
89     0x95, 0x01,                    //   REPORT_COUNT (1)
90     0x75, 0x03,                    //   REPORT_SIZE (3)
91     0x91, 0x03,                    //   OUTPUT (Cnst,Var,Abs)
92     0x95, 0x06,                    //   REPORT_COUNT (6)
93     0x75, 0x08,                    //   REPORT_SIZE (8)
94     0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
95     0x25, ARRAY_COUNT(ux_host_class_hid_keyboard_regular_array) + 1,  //   LOGICAL_MAXIMUM ()
96     0x05, 0x07,                    //   USAGE_PAGE (Keyboard)
97     0x19, 0x00,                    //   USAGE_MINIMUM (Reserved (no event indicated))
98     0x29, ARRAY_COUNT(ux_host_class_hid_keyboard_regular_array) + 1,  //   USAGE_MAXIMUM ()
99     0x81, 0x00,                    //   INPUT (Data,Ary,Abs)
100     0xc0                           // END_COLLECTION
101 };
102 #define HID_REPORT_LENGTH sizeof(hid_report_descriptor)/sizeof(hid_report_descriptor[0])
103 
104 
105 #define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 52
106 static UCHAR device_framework_full_speed[DEVICE_FRAMEWORK_LENGTH_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     /* Configuration descriptor */
114         0x09, 0x02, 0x22, 0x00, 0x01, 0x01, 0x00, 0xc0,
115         0x32,
116 
117     /* Interface descriptor */
118         0x09, 0x04, 0x02, 0x00, 0x01, 0x03, 0x00, 0x00,
119         0x00,
120 
121     /* HID descriptor */
122         0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_REPORT_LENGTH),
123         MSB(HID_REPORT_LENGTH),
124 
125     /* Endpoint descriptor (Interrupt) */
126         0x07, 0x05, 0x82, 0x03, 0x08, 0x00, 0x08
127 
128     };
129 
130 
131 #define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 62
132 static UCHAR device_framework_high_speed[DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED] = {
133 
134     /* Device descriptor */
135         0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40,
136         0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02,
137         0x03, 0x01,
138 
139     /* Device qualifier descriptor */
140         0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40,
141         0x01, 0x00,
142 
143     /* Configuration descriptor */
144         0x09, 0x02, 0x22, 0x00, 0x01, 0x01, 0x00, 0xc0,
145         0x32,
146 
147     /* Interface descriptor */
148         0x09, 0x04, 0x02, 0x00, 0x01, 0x03, 0x00, 0x00,
149         0x00,
150 
151     /* HID descriptor */
152         0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_REPORT_LENGTH),
153         MSB(HID_REPORT_LENGTH),
154 
155     /* Endpoint descriptor (Interrupt) */
156         0x07, 0x05, 0x82, 0x03, 0x08, 0x00, 0x08
157 
158     };
159 
160 
161     /* String Device Framework :
162      Byte 0 and 1 : Word containing the language ID : 0x0904 for US
163      Byte 2       : Byte containing the index of the descriptor
164      Byte 3       : Byte containing the length of the descriptor string
165     */
166 
167 #define STRING_FRAMEWORK_LENGTH 40
168 static UCHAR string_framework[] = {
169 
170     /* Manufacturer string descriptor : Index 1 */
171         0x09, 0x04, 0x01, 0x0c,
172         0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c,
173         0x6f, 0x67, 0x69, 0x63,
174 
175     /* Product string descriptor : Index 2 */
176         0x09, 0x04, 0x02, 0x0c,
177         0x55, 0x53, 0x42, 0x20, 0x4b, 0x65, 0x79, 0x62,
178         0x6f, 0x61, 0x72, 0x64,
179 
180     /* Serial Number string descriptor : Index 3 */
181         0x09, 0x04, 0x03, 0x04,
182         0x30, 0x30, 0x30, 0x31
183     };
184 
185 
186     /* Multiple languages are supported on the device, to add
187        a language besides english, the unicode language code must
188        be appended to the language_id_framework array and the length
189        adjusted accordingly. */
190 #define LANGUAGE_ID_FRAMEWORK_LENGTH 2
191 static UCHAR language_id_framework[] = {
192 
193     /* English. */
194         0x09, 0x04
195     };
196 
197 
198 UINT  _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter);
199 
200 
ux_system_host_change_function(ULONG a,UX_HOST_CLASS * b,VOID * c)201 static UINT ux_system_host_change_function(ULONG a, UX_HOST_CLASS *b, VOID *c)
202 {
203     return 0;
204 }
205 
error_callback(UINT system_level,UINT system_context,UINT error_code)206 static VOID error_callback(UINT system_level, UINT system_context, UINT error_code)
207 {
208 
209     /* @BUG_FIX_PENDING: ux_dcd_sim_slave_function.c doesn't support transfer aborts, which happen during device unregistration of a class. */
210     if (error_code != UX_FUNCTION_NOT_SUPPORTED)
211     {
212 
213         /* Failed test.  */
214         printf("Error on line %d, system_level: %d, system_context: %d, error code: 0x%x\n", __LINE__, system_level, system_context, error_code);
215         test_control_return(1);
216     }
217 }
218 
219 /* Define what the initial system looks like.  */
220 
221 #ifdef CTEST
test_application_define(void * first_unused_memory)222 void test_application_define(void *first_unused_memory)
223 #else
224 void    usbx_ux_host_class_hid_keyboard_ioctl_test_application_define(void *first_unused_memory)
225 #endif
226 {
227 
228 UINT status;
229 CHAR *                          stack_pointer;
230 CHAR *                          memory_pointer;
231 
232 
233     /* Inform user.  */
234     printf("Running ux_host_class_hid_keyboard_ioctl Test....................... ");
235 
236     /* Initialize the free memory pointer */
237     stack_pointer = (CHAR *) usbx_memory;
238     memory_pointer = stack_pointer + (UX_DEMO_STACK_SIZE * 2);
239 
240     /* Initialize USBX. Memory */
241     status = ux_system_initialize(memory_pointer, UX_DEMO_MEMORY_SIZE, UX_NULL,0);
242 
243     /* Check for error.  */
244     if (status != UX_SUCCESS)
245     {
246 
247         printf("Error on line %d, error code: 0x%x\n", __LINE__, status);
248         test_control_return(1);
249     }
250 
251     /* Register the error callback. */
252     _ux_utility_error_callback_register(error_callback);
253 
254     /* The code below is required for installing the host portion of USBX */
255     status =  ux_host_stack_initialize(ux_system_host_change_function);
256     if (status != UX_SUCCESS)
257     {
258 
259         printf("Error on line %d, error code: 0x%x\n", __LINE__, status);
260         test_control_return(1);
261     }
262 
263     status =  ux_host_stack_class_register(_ux_system_host_class_hid_name, ux_host_class_hid_entry);
264     if (status != UX_SUCCESS)
265     {
266 
267         printf("Error on line %d, error code: 0x%x\n", __LINE__, status);
268         test_control_return(1);
269     }
270 
271     /* Register the HID client(s).  */
272     status =  ux_host_class_hid_client_register(_ux_system_host_class_hid_client_keyboard_name, ux_host_class_hid_keyboard_entry);
273     if (status != UX_SUCCESS)
274     {
275 
276         printf("Error on line %d, error code: 0x%x\n", __LINE__, status);
277         test_control_return(1);
278     }
279 
280     /* The code below is required for installing the device portion of USBX. No call back for
281        device status change in this example. */
282     status =  ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED,
283                                        device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED,
284                                        string_framework, STRING_FRAMEWORK_LENGTH,
285                                        language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH,UX_NULL);
286     if(status!=UX_SUCCESS)
287     {
288 
289         printf("Error on line %d, error code: 0x%x\n", __LINE__, status);
290         test_control_return(1);
291     }
292 
293     /* Initialize the hid class parameters.  */
294     hid_parameter.ux_device_class_hid_parameter_report_address = hid_report_descriptor;
295     hid_parameter.ux_device_class_hid_parameter_report_length  = HID_REPORT_LENGTH;
296     hid_parameter.ux_device_class_hid_parameter_callback       = demo_thread_hid_callback;
297 
298     /* Initialize the device hid class. The class is connected with interface 2 */
299     status =  ux_device_stack_class_register(_ux_system_slave_class_hid_name, ux_device_class_hid_entry,
300                                                 1,2, (VOID *)&hid_parameter);
301     if(status!=UX_SUCCESS)
302     {
303 
304         printf("Error on line %d, error code: 0x%x\n", __LINE__, status);
305         test_control_return(1);
306     }
307 
308     /* Initialize the simulated device controller.  */
309     status =  _ux_dcd_sim_slave_initialize();
310 
311     /* Check for error.  */
312     if (status != UX_SUCCESS)
313     {
314 
315         printf("Error on line %d, error code: 0x%x\n", __LINE__, status);
316         test_control_return(1);
317     }
318 
319     /* Register all the USB host controllers available in this system */
320     status =  ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, ux_hcd_sim_host_initialize,0,0);
321 
322     /* Check for error.  */
323     if (status != UX_SUCCESS)
324     {
325 
326         printf("Error on line %d, error code: 0x%x\n", __LINE__, status);
327         test_control_return(1);
328     }
329 
330     /* Create the main host simulation thread.  */
331     status =  tx_thread_create(&tx_demo_thread_host_simulation, "tx demo host simulation", tx_demo_thread_host_simulation_entry, 0,
332             stack_pointer, UX_DEMO_STACK_SIZE,
333             20, 20, 1, TX_AUTO_START);
334 
335     /* Check for error.  */
336     if (status != TX_SUCCESS)
337     {
338 
339         printf("Error on line %d, error code: 0x%x\n", __LINE__, status);
340         test_control_return(1);
341     }
342 
343     /* Create the main demo thread.  */
344     status =  tx_thread_create(&tx_demo_thread_slave_simulation, "tx demo slave simulation", tx_demo_thread_slave_simulation_entry, 0,
345             stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE,
346             20, 20, 1, TX_AUTO_START);
347 
348     /* Check for error.  */
349     if (status != TX_SUCCESS)
350     {
351 
352         printf("Running HID Keyboard Basic Functionality Test....................... ERROR #10\n");
353         test_control_return(1);
354     }
355 
356 }
357 
_wait_key(UX_HOST_CLASS_HID_KEYBOARD * keyboard,ULONG * keyboard_key,ULONG * keyboard_state)358 static UINT  _wait_key(UX_HOST_CLASS_HID_KEYBOARD *keyboard, ULONG *keyboard_key, ULONG *keyboard_state)
359 {
360 
361 UINT        status;
362 UINT        i;
363 
364 
365     for(i = 0; i < 200; i ++)
366     {
367         status = ux_host_class_hid_keyboard_key_get(keyboard, keyboard_key, keyboard_state);
368         if (status == UX_SUCCESS)
369         {
370 
371 #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)
372             if (*keyboard_state & UX_HID_KEYBOARD_STATE_FUNCTION)
373                 continue;
374 #endif
375 
376 #if !defined(UX_HOST_CLASS_HID_KEYBOARD_EVENTS_KEY_CHANGES_MODE_REPORT_KEY_DOWN_ONLY)
377             if (*keyboard_state & UX_HID_KEYBOARD_STATE_KEY_UP)
378                 continue;
379 #endif
380             return UX_SUCCESS;
381         }
382         _ux_utility_delay_ms(2);
383     }
384     return UX_ERROR;
385 }
386 
tx_demo_thread_host_simulation_entry(ULONG arg)387 static void  tx_demo_thread_host_simulation_entry(ULONG arg)
388 {
389 
390 UINT                            status;
391 UX_HOST_CLASS_HID_KEYBOARD      *keyboard;
392 ULONG                           keyboard_key;
393 ULONG                           keyboard_state;
394 
395     /* Find the HID class */
396     status = demo_class_hid_get();
397     if (status != UX_SUCCESS)
398     {
399 
400         printf("Error on line %d, error code: 0x%x\n", __LINE__, status);
401         test_control_return(1);
402     }
403 
404     /* Get the HID client */
405     hid_client = hid -> ux_host_class_hid_client;
406 
407     /* Check if the instance of the keyboard is live */
408     while (hid_client -> ux_host_class_hid_client_local_instance == UX_NULL)
409         tx_thread_sleep(10);
410 
411     /* Get the keyboard instance */
412     keyboard =  (UX_HOST_CLASS_HID_KEYBOARD *)hid_client -> ux_host_class_hid_client_local_instance;
413 
414     /**************************************************************************/
415     /* Case: normal layout */
416 
417     /* Wait a regular key. */
418     status = _wait_key(keyboard, &keyboard_key, &keyboard_state);
419     if (status != UX_SUCCESS)
420     {
421         printf("ERROR #%d: code 0x%x\n", __LINE__, status);
422         test_control_return(1);
423     }
424     if (keyboard_key != 'a')
425     {
426         printf("ERROR #%d: key 0x%x (%c)\n", __LINE__, status, (UCHAR)keyboard_key);
427         test_control_return(1);
428     }
429 
430     /**************************************************************************/
431     /* Case: swap layout */
432 
433     status = ux_host_class_hid_keyboard_ioctl(keyboard, UX_HID_KEYBOARD_IOCTL_SET_LAYOUT, (VOID *)&test_layout_swap_regular_shift);
434     if (status != UX_SUCCESS)
435     {
436         printf("ERROR #%d: code 0x%x\n", __LINE__, status);
437         test_control_return(1);
438     }
439 
440     /* Resume slave to send a key. */
441     _ux_utility_thread_resume(&tx_demo_thread_slave_simulation);
442 
443     /* Wait a regular key. */
444     status = _wait_key(keyboard, &keyboard_key, &keyboard_state);
445     if (status != UX_SUCCESS)
446     {
447         printf("ERROR #%d: code 0x%x\n", __LINE__, status);
448         test_control_return(1);
449     }
450     if (keyboard_key != 'A')
451     {
452         printf("ERROR #%d: key 0x%x (%c)\n", __LINE__, status, (UCHAR)keyboard_key);
453         test_control_return(1);
454     }
455 
456     /**************************************************************************/
457     /* Case: normal layout */
458 
459     status = ux_host_class_hid_keyboard_ioctl(keyboard, UX_HID_KEYBOARD_IOCTL_SET_LAYOUT, UX_NULL);
460     if (status != UX_SUCCESS)
461     {
462         printf("ERROR #%d: code 0x%x\n", __LINE__, status);
463         test_control_return(1);
464     }
465 
466     /* Resume slave to send a key. */
467     _ux_utility_thread_resume(&tx_demo_thread_slave_simulation);
468 
469     /* Wait a regular key. */
470     status = _wait_key(keyboard, &keyboard_key, &keyboard_state);
471     if (status != UX_SUCCESS)
472     {
473         printf("ERROR #%d: code 0x%x\n", __LINE__, status);
474         test_control_return(1);
475     }
476     if (keyboard_key != 'a')
477     {
478         printf("ERROR #%d: key 0x%x (%c)\n", __LINE__, status, (UCHAR)keyboard_key);
479         test_control_return(1);
480     }
481 
482     /**************************************************************************/
483     /* Case: invalid IOCTL */
484 
485     status = ux_host_class_hid_keyboard_ioctl(keyboard, ~0, UX_NULL);
486     if (status == UX_SUCCESS)
487     {
488         printf("ERROR #%d: code 0x%x\n", __LINE__, status);
489         test_control_return(1);
490     }
491 
492     /* Now disconnect the device.  */
493     _ux_device_stack_disconnect();
494 
495     /* And deinitialize the class.  */
496     status =  ux_device_stack_class_unregister(_ux_system_slave_class_hid_name, ux_device_class_hid_entry);
497 
498     /* Deinitialize the device side of usbx.  */
499     _ux_device_stack_uninitialize();
500 
501     /* And finally the usbx system resources.  */
502     _ux_system_uninitialize();
503 
504     /* Successful test.  */
505     printf("SUCCESS!\n");
506     test_control_return(0);
507 }
508 
demo_thread_hid_callback(UX_SLAVE_CLASS_HID * class,UX_SLAVE_CLASS_HID_EVENT * event)509 static UINT    demo_thread_hid_callback(UX_SLAVE_CLASS_HID *class, UX_SLAVE_CLASS_HID_EVENT *event)
510 {
511     return(UX_SUCCESS);
512 }
513 
tx_demo_thread_slave_simulation_entry(ULONG arg)514 static void  tx_demo_thread_slave_simulation_entry(ULONG arg)
515 {
516 
517 UINT                            status;
518 UX_SLAVE_DEVICE                 *device;
519 UX_SLAVE_INTERFACE              *interface;
520 UX_SLAVE_CLASS_HID              *hid;
521 UX_SLAVE_CLASS_HID_EVENT        hid_event;
522 UCHAR                           state_modifier[2] = {0, (0x01 << 1)};
523 
524     /* Get the pointer to the device.  */
525     device =  &_ux_system_slave -> ux_system_slave_device;
526 
527     /* reset the HID event structure.  */
528     ux_utility_memory_set(&hid_event, 0, sizeof(UX_SLAVE_CLASS_HID_EVENT));
529 
530     /* Is the device configured ? */
531     while (device->ux_slave_device_state != UX_DEVICE_CONFIGURED)
532 
533         /* Then wait.  */
534         tx_thread_sleep(10);
535 
536     /* Get the interface.  We use the first interface, this is a simple device.  */
537     interface = device->ux_slave_device_first_interface;
538 
539     /* Form that interface, derive the HID owner.  */
540     hid = interface->ux_slave_interface_class_instance;
541 
542     /* Wait resume to continue. */
543     while(1) {
544 
545         /* Send a key!  */
546         hid_event.ux_device_class_hid_event_length = 8;
547         hid_event.ux_device_class_hid_event_buffer[0] = 0;
548         hid_event.ux_device_class_hid_event_buffer[1] = 0;
549         hid_event.ux_device_class_hid_event_buffer[2] = UX_HID_KEYBOARD_KEY_LETTER_A;
550         status = ux_device_class_hid_event_set(hid, &hid_event);
551         if (status != UX_SUCCESS)
552         {
553 
554             printf("Error on line %d, error code: 0x%x\n", __LINE__, status);
555             test_control_return(1);
556         }
557 
558         /* Release it.  */
559         hid_event.ux_device_class_hid_event_buffer[2] = 0;
560         status = ux_device_class_hid_event_set(hid, &hid_event);
561         if (status != UX_SUCCESS)
562         {
563 
564             printf("Error on line %d, error code: 0x%x\n", __LINE__, status);
565             test_control_return(1);
566         }
567 
568         ux_utility_thread_suspend(&tx_demo_thread_slave_simulation);
569     }
570 }
571