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