1 /* This test ensures that the parser correctly handles multiple report IDs for input reports. */
2 
3 #include "usbx_test_common_hid.h"
4 #include "ux_host_class_hid_keyboard.h"
5 
6 #define TEST_LOG_N                  8
7 
8 static TX_SEMAPHORE                 test_semaphore_host_wakes_device;
9 
10 static ULONG                        test_log_count = 0;
11 static ULONG                        test_log_index = 0;
12 static INT                          test_log_report_id[TEST_LOG_N] = {-1};
13 static UCHAR                        test_log_report_data[TEST_LOG_N][32];
14 static ULONG                        test_log_report_data_len[TEST_LOG_N];
15 
16 static UCHAR                        test_device_report_id = 0;
17 static UCHAR                        test_device_report_count = 1;
18 static UCHAR                        test_device_report_fill = 0x5A;
19 static UCHAR                        test_device_report_len = 1; /* Without ID */
20 
21 static UCHAR hid_report_descriptor[] = {
22 
23     0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
24     0x09, 0x06,                    // USAGE (Keyboard)
25     0xa1, 0x01,                    // COLLECTION (Application)
26 
27     /* 0: 4 x 1-bit values  */
28     0x19, 0x01,                    //   USAGE_MINIMUM (1)
29     0x29, 0x04,                    //   USAGE_MAXIMUM (4)
30     0x75, 0x04,                    //   REPORT_SIZE (4)
31     0x95, 0x04,                    //   REPORT_COUNT (4)
32     0x81, 0x02,                    //   INPUT (Data,Var,Abs)
33 
34     /* 2: 3 x bytes  */
35     0x85, 0x02,                    //   REPORT_ID (2)
36     0x19, 0x05,                    //   USAGE_MINIMUM (5)
37     0x29, 0x07,                    //   USAGE_MAXIMUM (7)
38     0x75, 0x08,                    //   REPORT_SIZE (8)
39     0x95, 0x03,                    //   REPORT_COUNT (3)
40     0x81, 0x02,                    //   INPUT (Data,Var,Abs)
41 
42     /* 4: 1 x 16-bit value  */
43     0x85, 0x04,                    //   REPORT_ID (4)
44     0x09, 0x08,                    //   USAGE (8)
45     0x75, 0x10,                    //   REPORT_SIZE (16)
46     0x95, 0x01,                    //   REPORT_COUNT (1)
47     0x81, 0x02,                    //   INPUT (Data,Var,Abs)
48 
49     /* USBX expects keyboards to have at least one output report, otherwise it's an error. */
50     0x95, 0x05,                    //   REPORT_COUNT (5)
51     0x75, 0x01,                    //   REPORT_SIZE (1)
52     0x05, 0x08,                    //   USAGE_PAGE (LEDs)
53     0x19, 0x01,                    //   USAGE_MINIMUM (Num Lock)
54     0x29, 0x05,                    //   USAGE_MAXIMUM (Kana)
55     0x91, 0x02,                    //   OUTPUT (Data,Var,Abs)
56 
57     0xc0,                          // END_COLLECTION
58 };
59 #define HID_REPORT_LENGTH sizeof(hid_report_descriptor)/sizeof(hid_report_descriptor[0])
60 
61 
62 #define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 52
63 static UCHAR device_framework_full_speed[DEVICE_FRAMEWORK_LENGTH_FULL_SPEED] = {
64 
65     /* Device descriptor */
66         0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08,
67         0x81, 0x0A, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
68         0x00, 0x01,
69 
70     /* Configuration descriptor */
71         0x09, 0x02, 0x22, 0x00, 0x01, 0x01, 0x00, 0xc0,
72         0x32,
73 
74     /* Interface descriptor */
75         0x09, 0x04, 0x02, 0x00, 0x01, 0x03, 0x00, 0x00,
76         0x00,
77 
78     /* HID descriptor */
79         0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_REPORT_LENGTH),
80         MSB(HID_REPORT_LENGTH),
81 
82     /* Endpoint descriptor (Interrupt) */
83         0x07, 0x05, 0x82, 0x03, 0x08, 0x00, 0x08
84 
85     };
86 
87 
88 #define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 62
89 static UCHAR device_framework_high_speed[DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED] = {
90 
91     /* Device descriptor */
92         0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40,
93         0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02,
94         0x03, 0x01,
95 
96     /* Device qualifier descriptor */
97         0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40,
98         0x01, 0x00,
99 
100     /* Configuration descriptor */
101         0x09, 0x02, 0x22, 0x00, 0x01, 0x01, 0x00, 0xc0,
102         0x32,
103 
104     /* Interface descriptor */
105         0x09, 0x04, 0x02, 0x00, 0x01, 0x03, 0x00, 0x00,
106         0x00,
107 
108     /* HID descriptor */
109         0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_REPORT_LENGTH),
110         MSB(HID_REPORT_LENGTH),
111 
112     /* Endpoint descriptor (Interrupt) */
113         0x07, 0x05, 0x82, 0x03, 0x08, 0x00, 0x08
114 
115     };
116 
117 
118     /* String Device Framework :
119      Byte 0 and 1 : Word containing the language ID : 0x0904 for US
120      Byte 2       : Byte containing the index of the descriptor
121      Byte 3       : Byte containing the length of the descriptor string
122     */
123 
124 #define STRING_FRAMEWORK_LENGTH 40
125 static UCHAR string_framework[] = {
126 
127     /* Manufacturer string descriptor : Index 1 */
128         0x09, 0x04, 0x01, 0x0c,
129         0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c,
130         0x6f, 0x67, 0x69, 0x63,
131 
132     /* Product string descriptor : Index 2 */
133         0x09, 0x04, 0x02, 0x0c,
134         0x55, 0x53, 0x42, 0x20, 0x4b, 0x65, 0x79, 0x62,
135         0x6f, 0x61, 0x72, 0x64,
136 
137     /* Serial Number string descriptor : Index 3 */
138         0x09, 0x04, 0x03, 0x04,
139         0x30, 0x30, 0x30, 0x31
140     };
141 
142 
143     /* Multiple languages are supported on the device, to add
144        a language besides english, the unicode language code must
145        be appended to the language_id_framework array and the length
146        adjusted accordingly. */
147 #define LANGUAGE_ID_FRAMEWORK_LENGTH 2
148 static UCHAR language_id_framework[] = {
149 
150     /* English. */
151         0x09, 0x04
152     };
153 
154 
155 
error_callback(UINT system_level,UINT system_context,UINT error_code)156 static VOID error_callback(UINT system_level, UINT system_context, UINT error_code)
157 {
158     /* Fine, HID client not registered.  */
159     if (error_code == UX_HOST_CLASS_HID_UNKNOWN)
160         return;
161 
162     /* Failed test.  */
163     printf("Error on line %d, system_level: %x, system_context: %x, error code: %x\n", __LINE__, system_level, system_context, error_code);
164     test_control_return(1);
165 }
166 
167 /* Define what the initial system looks like.  */
168 
169 #ifdef CTEST
test_application_define(void * first_unused_memory)170 void test_application_define(void *first_unused_memory)
171 #else
172 void    usbx_hid_report_multiple_reports_ids_test_application_define(void *first_unused_memory)
173 #endif
174 {
175 
176 UINT status;
177 CHAR *                          stack_pointer;
178 CHAR *                          memory_pointer;
179 UINT                            descriptor_size = HID_REPORT_LENGTH;
180 
181 
182     /* Inform user.  */
183     printf("Running HID Report Multiple Reports IDs Test........................ ");
184 
185     /* Initialize the free memory pointer */
186     stack_pointer = (CHAR *) usbx_memory;
187     memory_pointer = stack_pointer + (UX_DEMO_STACK_SIZE * 2);
188 
189     /* Initialize USBX. Memory */
190     status = ux_system_initialize(memory_pointer, UX_DEMO_MEMORY_SIZE, UX_NULL,0);
191 
192     /* Check for error.  */
193     if (status != UX_SUCCESS)
194     {
195 
196         printf("Error on line %d\n", __LINE__);
197         test_control_return(1);
198     }
199 
200     /* Register the error callback. */
201     _ux_utility_error_callback_register(error_callback);
202 
203     /* The code below is required for installing the host portion of USBX */
204     status =  ux_host_stack_initialize(UX_NULL);
205     if (status != UX_SUCCESS)
206     {
207 
208         printf("Error on line %d\n", __LINE__);
209         test_control_return(1);
210     }
211 
212     status =  ux_host_stack_class_register(_ux_system_host_class_hid_name, ux_host_class_hid_entry);
213     if (status != UX_SUCCESS)
214     {
215 
216         printf("Error on line %d\n", __LINE__);
217         test_control_return(1);
218     }
219 
220     /* The code below is required for installing the device portion of USBX. No call back for
221        device status change in this example. */
222     status =  ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED,
223                                        device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED,
224                                        string_framework, STRING_FRAMEWORK_LENGTH,
225                                        language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH,UX_NULL);
226     if(status!=UX_SUCCESS)
227     {
228 
229         printf("Error on line %d\n", __LINE__);
230         test_control_return(1);
231     }
232 
233     /* Initialize the hid class parameters.  */
234     hid_parameter.ux_device_class_hid_parameter_report_address = hid_report_descriptor;
235     hid_parameter.ux_device_class_hid_parameter_report_length  = HID_REPORT_LENGTH;
236     hid_parameter.ux_device_class_hid_parameter_callback       = demo_thread_hid_callback;
237     /* Report ID not inserted from event field, we manage buffer by ourselvs.  */
238     hid_parameter.ux_device_class_hid_parameter_report_id      = UX_FALSE;
239 
240     /* Initilize the device hid class. The class is connected with interface 2 */
241     status =  ux_device_stack_class_register(_ux_system_slave_class_hid_name, ux_device_class_hid_entry,
242                                                 1,2, (VOID *)&hid_parameter);
243     if(status!=UX_SUCCESS)
244     {
245 
246         printf("Error on line %d\n", __LINE__);
247         test_control_return(1);
248     }
249 
250 
251     /* Initialize the simulated device controller.  */
252     status =  _ux_dcd_sim_slave_initialize();
253 
254     /* Check for error.  */
255     if (status != UX_SUCCESS)
256     {
257 
258         printf("Error on line %d\n", __LINE__);
259         test_control_return(1);
260     }
261 
262     /* Register all the USB host controllers available in this system */
263     status =  ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, ux_hcd_sim_host_initialize,0,0);
264 
265     /* Check for error.  */
266     if (status != UX_SUCCESS)
267     {
268 
269         printf("Error on line %d\n", __LINE__);
270         test_control_return(1);
271     }
272 
273     UX_TEST_CHECK_SUCCESS(ux_utility_semaphore_create(&test_semaphore_host_wakes_device, "test_semaphore_host_wakes_device", 0));
274 
275     /* Create the main host simulation thread.  */
276     status =  tx_thread_create(&tx_demo_thread_host_simulation, "tx demo host simulation", tx_demo_thread_host_simulation_entry, 0,
277             stack_pointer, UX_DEMO_STACK_SIZE,
278             20, 20, 1, TX_AUTO_START);
279 
280     /* Check for error.  */
281     if (status != TX_SUCCESS)
282     {
283 
284         printf("Error on line %d\n", __LINE__);
285         test_control_return(1);
286     }
287 
288     /* Create the main device thread.  */
289     status =  tx_thread_create(&tx_demo_thread_slave_simulation, "tx demo slave simulation", tx_demo_thread_slave_simulation_entry, 0,
290             stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE,
291             20, 20, 1, TX_AUTO_START);
292 
293     /* Check for error.  */
294     if (status != TX_SUCCESS)
295     {
296 
297         printf("Error on line %d\n", __LINE__);
298         test_control_return(1);
299     }
300 }
301 
302 
test_log_reset(UCHAR data_fill)303 static inline void test_log_reset(UCHAR data_fill)
304 {
305 ULONG i;
306     test_log_count = 0;
307     test_log_index = 0;
308     for (i = 0; i < TEST_LOG_N; i ++)
309         test_log_report_id[i] = -1;
310     ux_utility_memory_set(test_log_report_data_len, 0, sizeof(test_log_report_data_len));
311     ux_utility_memory_set(test_log_report_data, 0, sizeof(test_log_report_data));
312 }
test_log_add(UCHAR report_id,UCHAR * data_buf,ULONG data_size)313 static inline void test_log_add(UCHAR report_id, UCHAR *data_buf, ULONG data_size)
314 {
315     test_log_count ++;
316     if (test_log_index < TEST_LOG_N)
317     {
318         test_log_report_id[test_log_index] = report_id;
319         test_log_report_data_len[test_log_index] = data_size;
320         if (data_size)
321             ux_utility_memory_copy(test_log_report_data[test_log_index], data_buf, data_size);
322         test_log_index ++;
323     }
324 }
325 
demo_host_class_hid_report0_callback(UX_HOST_CLASS_HID_REPORT_CALLBACK * callback)326 static VOID demo_host_class_hid_report0_callback(UX_HOST_CLASS_HID_REPORT_CALLBACK *callback)
327 {
328     test_log_add(0, callback->ux_host_class_hid_report_callback_buffer,callback->ux_host_class_hid_report_callback_actual_length);
329 }
demo_host_class_hid_report2_callback(UX_HOST_CLASS_HID_REPORT_CALLBACK * callback)330 static VOID demo_host_class_hid_report2_callback(UX_HOST_CLASS_HID_REPORT_CALLBACK *callback)
331 {
332     test_log_add(2, callback->ux_host_class_hid_report_callback_buffer,callback->ux_host_class_hid_report_callback_actual_length);
333 }
demo_host_class_hid_report4_callback(UX_HOST_CLASS_HID_REPORT_CALLBACK * callback)334 static VOID demo_host_class_hid_report4_callback(UX_HOST_CLASS_HID_REPORT_CALLBACK *callback)
335 {
336     test_log_add(4, callback->ux_host_class_hid_report_callback_buffer,callback->ux_host_class_hid_report_callback_actual_length);
337 }
338 
tx_demo_thread_host_simulation_entry(ULONG arg)339 static void  tx_demo_thread_host_simulation_entry(ULONG arg)
340 {
341 
342 UINT                                status;
343 UX_HOST_CLASS_HID_REPORT_GET_ID     report_id;
344 UX_HOST_CLASS_HID_CLIENT_REPORT     input_report_request;
345 UX_HOST_CLASS_HID_REPORT            *input_report_descriptor;
346 UX_HOST_CLASS_HID_REPORT_CALLBACK   call_back;
347 ULONG                               c, i;
348 
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\n", __LINE__);
356         test_control_return(1);
357     }
358 
359     /* Start periodic report transfer.  */
360     _ux_host_class_hid_periodic_report_start(hid);
361 
362     /* Reset logs.  */
363     test_log_reset(0);
364 
365     /* Trigger device events.  */
366     test_device_report_id = 1;
367     test_device_report_count = 2;
368     test_device_report_fill = 0xef; /* 0xef, 0xf0  */
369     test_device_report_len = 3; /* ...  */
370     UX_TEST_CHECK_SUCCESS(ux_utility_semaphore_put(&test_semaphore_host_wakes_device));
371 
372     /* Check received callbacks.  */
373     tx_thread_sleep(50);
374     UX_TEST_ASSERT(test_log_count == 0);
375 
376     /* Get the first input report descriptor. */
377     report_id.ux_host_class_hid_report_get_report = UX_NULL;
378     report_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT;
379     status = ux_host_class_hid_report_id_get(hid, &report_id);
380     if (status != UX_SUCCESS)
381     {
382 
383         printf("Error on line %d\n", __LINE__);
384         test_control_return(1);
385     }
386 
387     input_report_descriptor = report_id.ux_host_class_hid_report_get_report;
388     if (input_report_descriptor -> ux_host_class_hid_report_id != 0)
389     {
390 
391         printf("Error on line %d\n", __LINE__);
392         test_control_return(1);
393     }
394 
395     /* Register callback for the report descriptor.  */
396     call_back.ux_host_class_hid_report_callback_id =         input_report_descriptor -> ux_host_class_hid_report_id;
397     call_back.ux_host_class_hid_report_callback_function =   demo_host_class_hid_report0_callback;
398     call_back.ux_host_class_hid_report_callback_flags =      UX_HOST_CLASS_HID_REPORT_RAW;
399     call_back.ux_host_class_hid_report_callback_buffer =     UX_NULL;
400     call_back.ux_host_class_hid_report_callback_length =     0;
401     status =  _ux_host_class_hid_report_callback_register(hid, &call_back);
402 
403     /* Reset logs.  */
404     test_log_reset(0);
405 
406     /* Trigger device events.  */
407     test_device_report_id = 0;
408     test_device_report_count = 3;
409     test_device_report_fill = 0x30; /* 0x30, 0x31, 0x32  */
410     test_device_report_len = 1; /* 4 x 1-bit value.  */
411     UX_TEST_CHECK_SUCCESS(ux_utility_semaphore_put(&test_semaphore_host_wakes_device));
412 
413     /* Check received callbacks.  */
414     tx_thread_sleep(50);
415     UX_TEST_ASSERT(test_log_count == 3);
416     for (c = 0; c < 3; c ++)
417     {
418         UX_TEST_ASSERT(test_log_report_id[c] == 0);
419         UX_TEST_ASSERT(test_log_report_data_len[c] == 2);
420         UX_TEST_ASSERT(test_log_report_data[c][0] == 0);
421         UX_TEST_ASSERT(test_log_report_data[c][1] == (0x30 + c));
422     }
423 
424     /* Get the second input report descriptor. */
425     report_id.ux_host_class_hid_report_get_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT;
426     status = ux_host_class_hid_report_id_get(hid, &report_id);
427     if (status != UX_SUCCESS)
428     {
429 
430         printf("Error on line %d\n", __LINE__);
431         test_control_return(1);
432     }
433 
434     input_report_descriptor = report_id.ux_host_class_hid_report_get_report;
435     if (input_report_descriptor->ux_host_class_hid_report_id != 2)
436     {
437 
438         printf("Error on line %d\n", __LINE__);
439         test_control_return(1);
440     }
441 
442     /* Register callback for the report descriptor.  */
443     call_back.ux_host_class_hid_report_callback_id =         input_report_descriptor -> ux_host_class_hid_report_id;
444     call_back.ux_host_class_hid_report_callback_function =   demo_host_class_hid_report2_callback;
445     call_back.ux_host_class_hid_report_callback_flags =      UX_HOST_CLASS_HID_REPORT_RAW;
446     call_back.ux_host_class_hid_report_callback_buffer =     UX_NULL;
447     call_back.ux_host_class_hid_report_callback_length =     0;
448     status =  _ux_host_class_hid_report_callback_register(hid, &call_back);
449 
450     /* Reset logs.  */
451     test_log_reset(0);
452 
453     /* Trigger device events.  */
454     test_device_report_id = 2;
455     test_device_report_count = 5;
456     test_device_report_fill = 0x52; /* 0x52 .. 0x56  */
457     test_device_report_len = 3; /* 3 x bytes.  */
458     UX_TEST_CHECK_SUCCESS(ux_utility_semaphore_put(&test_semaphore_host_wakes_device));
459 
460     /* Check received callbacks.  */
461     tx_thread_sleep(50);
462     UX_TEST_ASSERT(test_log_count == test_device_report_count);
463     for (c = 0; c < test_device_report_count; c ++)
464     {
465         UX_TEST_ASSERT(test_log_report_id[c] == test_device_report_id);
466         UX_TEST_ASSERT(test_log_report_data_len[c] == test_device_report_len+1);
467         UX_TEST_ASSERT(test_log_report_data[c][0] == test_device_report_id);
468         for (i = 0; i < test_device_report_len; i ++)
469             UX_TEST_ASSERT(test_log_report_data[c][1 + i] ==
470                             (test_device_report_fill + c));
471     }
472 
473 
474     /* Get the third input report descriptor. */
475     status = ux_host_class_hid_report_id_get(hid, &report_id);
476     if (status != UX_SUCCESS)
477     {
478 
479         printf("Error on line %d\n", __LINE__);
480         test_control_return(1);
481     }
482 
483     input_report_descriptor = report_id.ux_host_class_hid_report_get_report;
484     if (input_report_descriptor->ux_host_class_hid_report_id != 4)
485     {
486 
487         printf("Error on line %d\n", __LINE__);
488         test_control_return(1);
489     }
490 
491     /* Register callback for the report descriptor.  */
492     call_back.ux_host_class_hid_report_callback_id =         input_report_descriptor -> ux_host_class_hid_report_id;
493     call_back.ux_host_class_hid_report_callback_function =   demo_host_class_hid_report4_callback;
494     call_back.ux_host_class_hid_report_callback_flags =      UX_HOST_CLASS_HID_REPORT_RAW;
495     call_back.ux_host_class_hid_report_callback_buffer =     UX_NULL;
496     call_back.ux_host_class_hid_report_callback_length =     0;
497     status =  _ux_host_class_hid_report_callback_register(hid, &call_back);
498 
499     /* Reset logs.  */
500     test_log_reset(0);
501 
502     /* Trigger device events.  */
503     test_device_report_id = 4;
504     test_device_report_count = 7;
505     test_device_report_fill = 0x77; /* 0x77 .. 0x7D  */
506     test_device_report_len = 2; /* 1 x 16-bit value.  */
507     UX_TEST_CHECK_SUCCESS(ux_utility_semaphore_put(&test_semaphore_host_wakes_device));
508 
509     /* Check received callbacks.  */
510     tx_thread_sleep(50);
511     UX_TEST_ASSERT(test_log_count == test_device_report_count);
512     for (c = 0; c < test_device_report_count; c ++)
513     {
514         UX_TEST_ASSERT(test_log_report_id[c] == test_device_report_id);
515         UX_TEST_ASSERT(test_log_report_data_len[c] == test_device_report_len+1);
516         UX_TEST_ASSERT(test_log_report_data[c][0] == test_device_report_id);
517         for (i = 0; i < test_device_report_len; i ++)
518             UX_TEST_ASSERT(test_log_report_data[c][1 + i] ==
519                             (test_device_report_fill + c));
520     }
521 
522 
523     /* Now disconnect the device.  */
524     _ux_device_stack_disconnect();
525 
526     /* And deinitialize the class.  */
527     status =  ux_device_stack_class_unregister(_ux_system_slave_class_hid_name, ux_device_class_hid_entry);
528 
529     /* Deinitialize the device side of usbx.  */
530     _ux_device_stack_uninitialize();
531 
532     /* And finally the usbx system resources.  */
533     _ux_system_uninitialize();
534 
535     /* Successful test.  */
536     printf("SUCCESS!\n");
537     test_control_return(0);
538 }
539 
demo_thread_hid_callback(UX_SLAVE_CLASS_HID * class,UX_SLAVE_CLASS_HID_EVENT * event)540 static UINT    demo_thread_hid_callback(UX_SLAVE_CLASS_HID *class, UX_SLAVE_CLASS_HID_EVENT *event)
541 {
542     return(UX_SUCCESS);
543 }
544 
tx_demo_thread_slave_simulation_entry(ULONG arg)545 static void  tx_demo_thread_slave_simulation_entry(ULONG arg)
546 {
547 
548 UX_SLAVE_DEVICE                 *device;
549 UX_SLAVE_INTERFACE              *interface;
550 UX_SLAVE_CLASS_HID              *hid;
551 UX_SLAVE_CLASS_HID_EVENT        hid_event;
552 ULONG                           i;
553 
554     /* Get the pointer to the device.  */
555     device =  &_ux_system_slave -> ux_system_slave_device;
556 
557     /* reset the HID event structure.  */
558     ux_utility_memory_set(&hid_event, 0, sizeof(UX_SLAVE_CLASS_HID_EVENT));
559 
560     while (1)
561     {
562 
563         /* Is the device configured ? */
564         while (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED)
565 
566             /* Then wait.  */
567             tx_thread_sleep(10);
568 
569         /* Until the device stays configured.  */
570         while (device -> ux_slave_device_state == UX_DEVICE_CONFIGURED)
571         {
572 
573             /* Get the interface.  We use the first interface, this is a simple device.  */
574             interface =  device -> ux_slave_device_first_interface;
575 
576             /* From that interface, derive the HID owner.  */
577             hid = interface -> ux_slave_interface_class_instance;
578 
579              /* Wait for host to trigger. */
580             UX_TEST_CHECK_SUCCESS(ux_utility_semaphore_get(&test_semaphore_host_wakes_device, UX_WAIT_FOREVER));
581 
582             for (i = 0; i < test_device_report_count; i ++)
583             {
584 
585                 /* Build the event to test.  */
586 
587                 /* Set length of event.  */
588                 hid_event.ux_device_class_hid_event_length = test_device_report_len + 1;
589 
590                 /* Set ID.  */
591                 hid_event.ux_device_class_hid_event_buffer[0] = test_device_report_id;
592 
593                 /* Set fills.  */
594                 ux_utility_memory_set(&hid_event.ux_device_class_hid_event_buffer[1],
595                                     test_device_report_fill + i,
596                                     test_device_report_len);
597 
598                 /* Set the mouse event.  */
599                 ux_device_class_hid_event_set(hid, &hid_event);
600             }
601             }
602     }
603 }