1 /* This is a small demo of the USBX   */
2 
3 #include "ux_api.h"
4 #include "ux_system.h"
5 #include "ux_utility.h"
6 #include "ux_host_class_dpump.h"
7 #include "ux_device_class_dpump.h"
8 
9 
10 /* Define USBX demo constants.  */
11 
12 #define UX_DEMO_STACK_SIZE      4096
13 #define UX_DEMO_MEMORY_SIZE     (28*1024)
14 
15 
16 /* Define the counters used in the demo application...  */
17 
18 ULONG                           thread_0_counter;
19 ULONG                           thread_1_counter;
20 ULONG                           error_counter;
21 
22 
23 /* Define USBX demo global variables.  */
24 
25 ULONG                           ux_demo_memory_buffer[(UX_DEMO_MEMORY_SIZE + UX_DEMO_STACK_SIZE * 2) / sizeof(ULONG)];
26 
27 unsigned char                   host_out_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE];
28 unsigned char                   host_in_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE];
29 unsigned char                   device_buffer[UX_HOST_CLASS_DPUMP_PACKET_SIZE];
30 
31 UX_HOST_CLASS                   *class_driver;
32 UX_HOST_CLASS_DPUMP             *dpump;
33 UX_SLAVE_CLASS_DPUMP            *dpump_device;
34 
35 
36 #define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 50
37 UCHAR device_framework_full_speed[] = {
38 
39     /* Device descriptor */
40         0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08,
41         0xec, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
42         0x00, 0x01,
43 
44     /* Configuration descriptor */
45         0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0,
46         0x32,
47 
48     /* Interface descriptor */
49         0x09, 0x04, 0x00, 0x00, 0x02, 0x99, 0x99, 0x99,
50         0x00,
51 
52     /* Endpoint descriptor (Bulk Out) */
53         0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00,
54 
55     /* Endpoint descriptor (Bulk In) */
56         0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00
57     };
58 
59 
60 #define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 60
61 UCHAR device_framework_high_speed[] = {
62 
63     /* Device descriptor */
64         0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40,
65         0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02,
66         0x03, 0x01,
67 
68     /* Device qualifier descriptor */
69         0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40,
70         0x01, 0x00,
71 
72     /* Configuration descriptor */
73         0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xc0,
74         0x32,
75 
76     /* Interface descriptor */
77         0x09, 0x04, 0x00, 0x00, 0x02, 0x99, 0x99, 0x99,
78         0x00,
79 
80     /* Endpoint descriptor (Bulk Out) */
81         0x07, 0x05, 0x01, 0x02, 0x00, 0x02, 0x00,
82 
83     /* Endpoint descriptor (Bulk In) */
84         0x07, 0x05, 0x82, 0x02, 0x00, 0x02, 0x00
85     };
86 
87     /* String Device Framework :
88      Byte 0 and 1 : Word containing the language ID : 0x0904 for US
89      Byte 2       : Byte containing the index of the descriptor
90      Byte 3       : Byte containing the length of the descriptor string
91     */
92 
93 #define STRING_FRAMEWORK_LENGTH 38
94 UCHAR string_framework[] = {
95 
96     /* Manufacturer string descriptor : Index 1 */
97         0x09, 0x04, 0x01, 0x0c,
98         0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c,
99         0x6f, 0x67, 0x69, 0x63,
100 
101     /* Product string descriptor : Index 2 */
102         0x09, 0x04, 0x02, 0x0c,
103         0x44, 0x61, 0x74, 0x61, 0x50, 0x75, 0x6d, 0x70,
104         0x44, 0x65, 0x6d, 0x6f,
105 
106     /* Serial Number string descriptor : Index 3 */
107         0x09, 0x04, 0x03, 0x04,
108         0x30, 0x30, 0x30, 0x31
109     };
110 
111 
112     /* Multiple languages are supported on the device, to add
113        a language besides English, the unicode language code must
114        be appended to the language_id_framework array and the length
115        adjusted accordingly. */
116 #define LANGUAGE_ID_FRAMEWORK_LENGTH 2
117 UCHAR language_id_framework[] = {
118 
119     /* English. */
120         0x09, 0x04
121     };
122 
123 
124 /* Define prototypes for external Host Controller's (HCDs), classes and clients.  */
125 
126 VOID                tx_demo_instance_activate(VOID  *dpump_instance);
127 VOID                tx_demo_instance_deactivate(VOID *dpump_instance);
128 
129 UINT                _ux_host_class_dpump_entry(UX_HOST_CLASS_COMMAND *command);
130 UINT                ux_hcd_sim_initialize(UX_HCD *hcd);
131 UINT                _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer,
132                                     ULONG requested_length, ULONG *actual_length);
133 UINT                _ux_host_class_dpump_read (UX_HOST_CLASS_DPUMP *dpump, UCHAR *data_pointer,
134                                     ULONG requested_length, ULONG *actual_length);
135 
136 TX_THREAD           tx_demo_thread_host_simulation;
137 TX_THREAD           tx_demo_thread_device_simulation;
138 void                tx_demo_thread_host_simulation_entry(ULONG);
139 void                tx_demo_thread_device_simulation_entry(ULONG);
140 VOID                error_handler(void);
141 
142 
143 /* Define the entry point.  */
144 
main()145 int  main()
146 {
147 
148     /* Enter the ThreadX kernel.  */
149     tx_kernel_enter();
150 
151     return(0);
152 }
153 
154 
155 /* Define what the initial system looks like.  */
156 
tx_application_define(void * first_unused_memory)157 void  tx_application_define(void *first_unused_memory)
158 {
159 
160 CHAR                            *stack_pointer;
161 CHAR                            *memory_pointer;
162 UINT                            status;
163 UX_SLAVE_CLASS_DPUMP_PARAMETER  parameter;
164 
165 
166     UX_PARAMETER_NOT_USED(first_unused_memory);
167 
168     /* Initialize the free memory pointer.  */
169     stack_pointer = (CHAR *) ux_demo_memory_buffer;
170     memory_pointer = stack_pointer + (UX_DEMO_STACK_SIZE * 2);
171 
172     /* Initialize USBX Memory.  */
173     status =  ux_system_initialize(memory_pointer, UX_DEMO_MEMORY_SIZE, UX_NULL, 0);
174 
175     /* Check for error.  */
176     if (status != UX_SUCCESS)
177         error_handler();
178 
179     /* The code below is required for installing the host portion of USBX.  */
180     status =  ux_host_stack_initialize(UX_NULL);
181 
182     /* Check for error.  */
183     if (status != UX_SUCCESS)
184         error_handler();
185 
186     /* Register all the host class drivers for this USBX implementation.  */
187     status =  ux_host_stack_class_register(_ux_system_host_class_dpump_name, ux_host_class_dpump_entry);
188 
189     /* Check for error.  */
190     if (status != UX_SUCCESS)
191         error_handler();
192 
193     /* Register all the USB host controllers available in this system */
194     status =  ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, ux_hcd_sim_host_initialize,0,0);
195 
196     /* Check for error.  */
197     if (status != UX_SUCCESS)
198         error_handler();
199 
200     /* The code below is required for installing the device portion of USBX */
201     status =  _ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED,
202                                        device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED,
203                                        string_framework, STRING_FRAMEWORK_LENGTH,
204                                        language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL);
205 
206     /* Check for error.  */
207     if (status != UX_SUCCESS)
208         error_handler();
209 
210     /* Set the parameters for callback when insertion/extraction of a Data Pump device.  */
211     parameter.ux_slave_class_dpump_instance_activate   =  tx_demo_instance_activate;
212     parameter.ux_slave_class_dpump_instance_deactivate =  tx_demo_instance_deactivate;
213 
214     /* Initialize the device dpump class. The class is connected with interface 0 */
215      status =  _ux_device_stack_class_register(_ux_system_slave_class_dpump_name, _ux_device_class_dpump_entry,
216                                                1, 0, &parameter);
217 
218     /* Check for error.  */
219     if (status != UX_SUCCESS)
220         error_handler();
221 
222     /* Initialize the simulated device controller.  */
223     status =  _ux_dcd_sim_slave_initialize();
224 
225     /* Check for error.  */
226     if (status != UX_SUCCESS)
227         error_handler();
228 
229     /* Create the main host simulation thread.  */
230     status =  tx_thread_create(&tx_demo_thread_host_simulation, "tx demo host simulation", tx_demo_thread_host_simulation_entry, 0,
231             stack_pointer, UX_DEMO_STACK_SIZE,
232             20, 20, 1, TX_AUTO_START);
233 
234     /* Check for error.  */
235     if (status != TX_SUCCESS)
236         error_handler();
237 
238     /* Create the main demo thread.  */
239     status =  tx_thread_create(&tx_demo_thread_device_simulation, "tx demo slave simulation", tx_demo_thread_device_simulation_entry, 0,
240             stack_pointer + UX_DEMO_STACK_SIZE, UX_DEMO_STACK_SIZE,
241             20, 20, 1, TX_AUTO_START);
242 
243     /* Check for error.  */
244     if (status != TX_SUCCESS)
245         error_handler();
246 }
247 
248 
tx_demo_thread_host_simulation_entry(ULONG arg)249 void  tx_demo_thread_host_simulation_entry(ULONG arg)
250 {
251 
252 UINT            status;
253 ULONG           actual_length;
254 UCHAR           current_char;
255 UX_HOST_CLASS   *class;
256 
257 
258     UX_PARAMETER_NOT_USED(arg);
259 
260     /* Find the main data pump container.  */
261     status =  ux_host_stack_class_get(_ux_system_host_class_dpump_name, &class);
262 
263     /* Check for error.  */
264     if (status != UX_SUCCESS)
265         error_handler();
266 
267     /* We get the first instance of the data pump device.  */
268     do
269     {
270 
271         status =  ux_host_stack_class_instance_get(class, 0, (VOID **) &dpump);
272         tx_thread_relinquish();
273     } while (status != UX_SUCCESS);
274 
275     /* We still need to wait for the data pump status to be live.  */
276     while (dpump -> ux_host_class_dpump_state != UX_HOST_CLASS_INSTANCE_LIVE)
277     {
278 
279         tx_thread_relinquish();
280     }
281 
282     /* At this point, the data pump class has been found.  Now use the
283        data pump to send and receive data between the host and device.  */
284 
285     /* We start with a 'A' in buffer.  */
286     current_char = 'A';
287 
288     while(1)
289     {
290 
291         /* Increment thread counter.  */
292         thread_0_counter++;
293 
294         /* Initialize the write buffer. */
295         _ux_utility_memory_set(host_out_buffer, current_char, UX_HOST_CLASS_DPUMP_PACKET_SIZE); /* Use case of memset is verified. */
296 
297         /* Increment the character in buffer.  */
298         current_char++;
299 
300         /* Check for upper alphabet limit.  */
301         if (current_char > 'Z')
302             current_char =  'A';
303 
304         /* Write to the host Data Pump Bulk out endpoint.  */
305         status =  _ux_host_class_dpump_write (dpump, host_out_buffer, UX_HOST_CLASS_DPUMP_PACKET_SIZE, &actual_length);
306 
307         /* Check for error.  */
308         if (status != UX_SUCCESS)
309             error_handler();
310 
311         /* Verify that the status and the amount of data is correct.  */
312         if ((status != UX_SUCCESS) || actual_length != UX_HOST_CLASS_DPUMP_PACKET_SIZE)
313             return;
314 
315         /* Read to the Data Pump Bulk out endpoint.  */
316         status =  _ux_host_class_dpump_read (dpump, host_in_buffer, UX_HOST_CLASS_DPUMP_PACKET_SIZE, &actual_length);
317 
318         /* Verify that the status and the amount of data is correct.  */
319         if ((status != UX_SUCCESS) || actual_length != UX_HOST_CLASS_DPUMP_PACKET_SIZE)
320             error_handler();
321 
322         /* Relinquish to other thread.  */
323         tx_thread_relinquish();
324     }
325 }
326 
327 
tx_demo_thread_device_simulation_entry(ULONG arg)328 void  tx_demo_thread_device_simulation_entry(ULONG arg)
329 {
330 
331 UINT    status;
332 ULONG   actual_length;
333 
334 
335     UX_PARAMETER_NOT_USED(arg);
336 
337     while(1)
338     {
339 
340         /* Ensure the dpump class on the device is still alive.  */
341         while (dpump_device != UX_NULL)
342         {
343 
344             /* Increment thread counter.  */
345             thread_1_counter++;
346 
347             /* Read from the device data pump.  */
348             status =  _ux_device_class_dpump_read(dpump_device, device_buffer, UX_HOST_CLASS_DPUMP_PACKET_SIZE, &actual_length);
349 
350             /* Verify that the status and the amount of data is correct.  */
351             if ((status != UX_SUCCESS) || actual_length != UX_HOST_CLASS_DPUMP_PACKET_SIZE)
352                 error_handler();
353 
354             /* Now write to the device data pump.  */
355             status =  _ux_device_class_dpump_write(dpump_device, device_buffer, UX_HOST_CLASS_DPUMP_PACKET_SIZE, &actual_length);
356 
357             /* Verify that the status and the amount of data is correct.  */
358             if ((status != UX_SUCCESS) || actual_length != UX_HOST_CLASS_DPUMP_PACKET_SIZE)
359                 error_handler();
360         }
361 
362         /* Relinquish to other thread.  */
363         tx_thread_relinquish();
364     }
365 }
366 
tx_demo_instance_activate(VOID * dpump_instance)367 VOID  tx_demo_instance_activate(VOID *dpump_instance)
368 {
369 
370     /* Save the DPUMP instance.  */
371     dpump_device = (UX_SLAVE_CLASS_DPUMP *) dpump_instance;
372 }
373 
tx_demo_instance_deactivate(VOID * dpump_instance)374 VOID  tx_demo_instance_deactivate(VOID *dpump_instance)
375 {
376 
377     UX_PARAMETER_NOT_USED(dpump_instance);
378 
379     /* Reset the DPUMP instance.  */
380     dpump_device = UX_NULL;
381 }
382 
383 
error_handler(void)384 VOID  error_handler(void)
385 {
386 
387     /* Increment error counter.  */
388     error_counter++;
389 
390     while(1)
391     {
392 
393         /* Error - just spin here!  Look at call tree in debugger
394            to see where the error occurred.  */
395     }
396 }
397 
398