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