-
Notifications
You must be signed in to change notification settings - Fork 0
/
usbConstructs.c
372 lines (334 loc) · 15.8 KB
/
usbConstructs.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
#include "USB_API/USB_Common/device.h"
#include "USB_API/USB_Common/types.h" //Basic Type declarations
#include "USB_config/descriptors.h"
#include "USB_API/USB_Common/usb.h" //USB-specific functions
#ifdef _CDC_
#include "USB_API/USB_CDC_API/UsbCdc.h"
#endif
#ifdef _HID_
#include "USB_API/USB_HID_API/UsbHid.h"
#endif
#ifdef _PHDC_
#include "USB_API/USB_PHDC_API/UsbPHDC.h"
#endif
#include <intrinsics.h>
#include "usbConstructs.h"
/**************************************************************************************************
* These are example, user-editable construct functions for calling the API.
*
* In cases where fast development is the priority, it's usually best to use these sending
* construct functions, rather than calling USBCDC_sendData() or USBHID_sendData()
* directly. This is because they put boundaries on the "background execution" of sends,
* simplfying the application.
*
* xxxsendDataWaitTilDone() essentially eliminates background processing altogether, always
* polling after the call to send and not allowing execution to resume until it's done. This
* allows simpler coding at the expense of wasted MCU cycles, and MCU execution being "locked"
* to the host (also called "synchronous" operation).
*
* xxxsendDataInBackground() takes advantage of background processing ("asynchronous" operation)
* by allowing sending to happen during application execution; while at the same time ensuring
* that the sending always definitely occurs. It provides most of the simplicity of
* xxxsendDataWaitTilDone() while minimizing wasted cycles. It's probably the best choice
* for most applications.
*
* A true, asynchronous implementation would be the most cycle-efficient, but is the most
* difficult to code; and can't be "contained" in an example function as these other approaches
* are. Such an implementation might be advantageous in RTOS-based implementations or those
* requiring the highest levels of efficiency.
*
* These functions take into account all the pertinent return codes, toward ensuring fully
* robust operation. The send functions implement a timeout feature, using a loose "number of
* retries" approach. This was done in order to avoid using additional hardware resources. A
* more sophisticated approach, which the developer might want to implement, would be to use a
* hardware timer.
*
* Please see the MSP430 CDC/HID/MSC USB API Programmer's Guide for a full description of these
* functions, how they work, and how to use them.
**************************************************************************************************/
#ifdef _HID_
/* This construct implements post-call polling to ensure the sending completes before the function
* returns. It provides the simplest coding, at the expense of wasted cycles and potentially
* allowing MCU execution to become "locked" to the host, a disadvantage if the host (or bus) is
* slow. The function also checks all valid return codes, and returns non-zero if an error occurred.
* It assumes no previous send operation is underway; also assumes size is non-zero. */
BYTE hidSendDataWaitTilDone (BYTE* dataBuf,
WORD size,
BYTE intfNum,
ULONG ulTimeout)
{
ULONG sendCounter = 0;
WORD bytesSent, bytesReceived;
switch (USBHID_sendData(dataBuf,size,intfNum)){
case kUSBHID_sendStarted:
break;
case kUSBHID_busNotAvailable:
return ( 2) ;
case kUSBHID_intfBusyError:
return ( 3) ;
case kUSBHID_generalError:
return ( 4) ;
default:;
}
/* If execution reaches this point, then the operation successfully started. Now wait til it's finished. */
while (1){
BYTE ret = USBHID_intfStatus(intfNum,&bytesSent,&bytesReceived);
if (ret & kUSBHID_busNotAvailable){ /* This may happen at any time */
return ( 2) ;
}
if (ret & kUSBHID_waitingForSend){
if (ulTimeout && (sendCounter++ >= ulTimeout)){ /* Incr counter & try again */
return ( 1) ; /* Timed out */
}
} else {
return ( 0) ; /* If neither busNotAvailable nor waitingForSend, it succeeded */
}
}
}
/* This construct implements pre-call polling to ensure the sending completes before the function
* returns. It provides simple coding while also taking advantage of the efficiencies of background
* processing. If a previous send operation is underway, this function does waste cycles polling,
* like xxxsendDataWaitTilDone(); however it's less likely to do so since much of the sending
* presumably took place in the background since the last call to xxxsendDataInBackground().
* The function also checks all valid return codes, and returns non-zero if an error occurred.
* It assumes no previous send operation is underway; also assumes size is non-zero.
* This call assumes a previous send operation might be underway; also assumes size is non-zero.
* Returns zero if send completed; non-zero if it failed, with 1 = timeout and 2 = bus is gone. */
BYTE hidSendDataInBackground (BYTE* dataBuf,
WORD size,
BYTE intfNum,
ULONG ulTimeout)
{
ULONG sendCounter = 0;
WORD bytesSent, bytesReceived;
while (USBHID_intfStatus(intfNum,&bytesSent,
&bytesReceived) & kUSBHID_waitingForSend){
if (ulTimeout && ((sendCounter++) > ulTimeout)){ /* A send operation is underway; incr counter & try again */
return ( 1) ; /* Timed out */
}
}
/* The interface is now clear. Call sendData(). */
switch (USBHID_sendData(dataBuf,size,intfNum)){
case kUSBHID_sendStarted:
return ( 0) ;
case kUSBHID_busNotAvailable:
return ( 2) ;
default:
return ( 4) ;
}
}
/* This call only retrieves data that is already waiting in the USB buffer -- that is, data that has
* already been received by the MCU. It assumes a previous, open receive operation (began by a direct
* call to USBxxx_receiveData()) is NOT underway on this interface; and no receive operation remains
* open after this call returns. It doesn't check for kUSBxxx_busNotAvailable, because it doesn't
* matter if it's not. size is the maximum that is allowed to be received before exiting; i.e., it
* is the size allotted to dataBuf. Returns the number of bytes received. */
WORD hidReceiveDataInBuffer (BYTE* dataBuf, WORD size, BYTE intfNum)
{
WORD bytesInBuf,rxCount;
BYTE* currentPos = dataBuf;
while (bytesInBuf = USBHID_bytesInUSBBuffer(intfNum))
{
if ((WORD)(currentPos - dataBuf + bytesInBuf) <= size){
rxCount = bytesInBuf;
} else {
rxCount = size;
}
USBHID_receiveData(currentPos,rxCount,intfNum);
currentPos += bytesInBuf;
}
return (rxCount);
}
#endif
/*********************************************************************************************
* Please see the MSP430 USB CDC API Programmer's Guide Sec. 9 for a full description of these
* functions, how they work, and how to use them.
**********************************************************************************************/
#ifdef _CDC_
/* This construct implements post-call polling to ensure the sending completes before the function
* returns. It provides the simplest coding, at the expense of wasted cycles and potentially
* allowing MCU execution to become "locked" to the host, a disadvantage if the host (or bus) is
* slow. The function also checks all valid return codes, and returns non-zero if an error occurred.
* It assumes no previous send operation is underway; also assumes size is non-zero. */
BYTE cdcSendDataWaitTilDone (BYTE* dataBuf,
WORD size,
BYTE intfNum,
ULONG ulTimeout)
{
ULONG sendCounter = 0;
WORD bytesSent, bytesReceived;
switch (USBCDC_sendData(dataBuf,size,intfNum))
{
case kUSBCDC_sendStarted:
break;
case kUSBCDC_busNotAvailable:
return ( 2) ;
case kUSBCDC_intfBusyError:
return ( 3) ;
case kUSBCDC_generalError:
return ( 4) ;
default:;
}
/* If execution reaches this point, then the operation successfully started. Now wait til it's finished. */
while (1){
BYTE ret = USBCDC_intfStatus(intfNum,&bytesSent,&bytesReceived);
if (ret & kUSBCDC_busNotAvailable){ /* This may happen at any time */
return ( 2) ;
}
if (ret & kUSBCDC_waitingForSend){
if (ulTimeout && (sendCounter++ >= ulTimeout)){ /* Incr counter & try again */
return ( 1) ; /* Timed out */
}
} else {
return ( 0) ; /* If neither busNotAvailable nor waitingForSend, it succeeded */
}
}
}
/* This construct implements pre-call polling to ensure the sending completes before the function
* returns. It provides simple coding while also taking advantage of the efficiencies of background
* processing. If a previous send operation is underway, this function does waste cycles polling,
* like xxxsendDataWaitTilDone(); however it's less likely to do so since much of the sending
* presumably took place in the background since the last call to xxxsendDataInBackground().
* The function also checks all valid return codes, and returns non-zero if an error occurred.
* It assumes no previous send operation is underway; also assumes size is non-zero.
* This call assumes a previous send operation might be underway; also assumes size is non-zero.
* Returns zero if send completed; non-zero if it failed, with 1 = timeout and 2 = bus is gone. */
BYTE cdcSendDataInBackground (BYTE* dataBuf,
WORD size,
BYTE intfNum,
ULONG ulTimeout)
{
ULONG sendCounter = 0;
WORD bytesSent, bytesReceived;
while (USBCDC_intfStatus(intfNum,&bytesSent,
&bytesReceived) & kUSBCDC_waitingForSend){
if (ulTimeout && ((sendCounter++) > ulTimeout)){ /* A send operation is underway; incr counter & try again */
return ( 1) ; /* Timed out */
}
}
/* The interface is now clear. Call sendData(). */
switch (USBCDC_sendData(dataBuf,size,intfNum)){
case kUSBCDC_sendStarted:
return ( 0) ;
case kUSBCDC_busNotAvailable:
return ( 2) ;
default:
return ( 4) ;
}
}
/* This call only retrieves data that is already waiting in the USB buffer -- that is, data that has
* already been received by the MCU. It assumes a previous, open receive operation (began by a direct
* call to USBxxx_receiveData()) is NOT underway on this interface; and no receive operation remains
* open after this call returns. It doesn't check for kUSBxxx_busNotAvailable, because it doesn't
* matter if it's not. size is the maximum that is allowed to be received before exiting; i.e., it
* is the size allotted to dataBuf. Returns the number of bytes received. */
WORD cdcReceiveDataInBuffer (BYTE* dataBuf, WORD size, BYTE intfNum)
{
WORD bytesInBuf,rxCount;
BYTE* currentPos = dataBuf;
while (bytesInBuf = USBCDC_bytesInUSBBuffer(intfNum)){
if ((WORD)(currentPos - dataBuf + bytesInBuf) <= size){
rxCount = bytesInBuf;
} else {
rxCount = size;
}
USBCDC_receiveData(currentPos,rxCount,intfNum);
currentPos += bytesInBuf;
}
return (rxCount);
}
#endif
#ifdef _PHDC_
/* This construct implements post-call polling to ensure the sending completes before the function
* returns. It provides the simplest coding, at the expense of wasted cycles and potentially
* allowing MCU execution to become "locked" to the host, a disadvantage if the host (or bus) is
* slow. The function also checks all valid return codes, and returns non-zero if an error occurred.
* It assumes no previous send operation is underway; also assumes size is non-zero. */
BYTE phdcSendDataWaitTilDone (BYTE* dataBuf,
WORD size,
BYTE intfNum,
ULONG ulTimeout)
{
ULONG sendCounter = 0;
WORD bytesSent, bytesReceived;
switch (USBPHDC_sendData(dataBuf,size,intfNum))
{
case kUSBPHDC_sendStarted:
break;
case kUSBPHDC_busNotAvailable:
return ( 2) ;
case kUSBPHDC_intfBusyError:
return ( 3) ;
case kUSBPHDC_generalError:
return ( 4) ;
default:;
}
/* If execution reaches this point, then the operation successfully started. Now wait til it's finished. */
while (1){
BYTE ret = USBPHDC_intfStatus(intfNum,&bytesSent,&bytesReceived);
if (ret & kUSBPHDC_busNotAvailable){ /* This may happen at any time */
return ( 2) ;
}
if (ret & kUSBPHDC_waitingForSend){
if (ulTimeout && (sendCounter++ >= ulTimeout)){ /* Incr counter & try again */
return ( 1) ; /* Timed out */
}
} else {
return ( 0) ; /* If neither busNotAvailable nor waitingForSend, it succeeded */
}
}
}
/* This construct implements pre-call polling to ensure the sending completes before the function
* returns. It provides simple coding while also taking advantage of the efficiencies of background
* processing. If a previous send operation is underway, this function does waste cycles polling,
* like xxxsendDataWaitTilDone(); however it's less likely to do so since much of the sending
* presumably took place in the background since the last call to xxxsendDataInBackground().
* The function also checks all valid return codes, and returns non-zero if an error occurred.
* It assumes no previous send operation is underway; also assumes size is non-zero.
* This call assumes a previous send operation might be underway; also assumes size is non-zero.
* Returns zero if send completed; non-zero if it failed, with 1 = timeout and 2 = bus is gone. */
BYTE phdcSendDataInBackground (BYTE* dataBuf,
WORD size,
BYTE intfNum,
ULONG ulTimeout)
{
ULONG sendCounter = 0;
WORD bytesSent, bytesReceived;
while (USBPHDC_intfStatus(intfNum,&bytesSent,
&bytesReceived) & kUSBPHDC_waitingForSend){
if (ulTimeout && ((sendCounter++) > ulTimeout)){ /* A send operation is underway; incr counter & try again */
return ( 1) ; /* Timed out */
}
}
/* The interface is now clear. Call sendData(). */
switch (USBPHDC_sendData(dataBuf,size,intfNum)){
case kUSBPHDC_sendStarted:
return ( 0) ;
case kUSBPHDC_busNotAvailable:
return ( 2) ;
default:
return ( 4) ;
}
}
/* This call only retrieves data that is already waiting in the USB buffer -- that is, data that has
* already been received by the MCU. It assumes a previous, open receive operation (began by a direct
* call to USBxxx_receiveData()) is NOT underway on this interface; and no receive operation remains
* open after this call returns. It doesn't check for kUSBxxx_busNotAvailable, because it doesn't
* matter if it's not. size is the maximum that is allowed to be received before exiting; i.e., it
* is the size allotted to dataBuf. Returns the number of bytes received. */
WORD phdcReceiveDataInBuffer (BYTE* dataBuf, WORD size, BYTE intfNum)
{
WORD bytesInBuf,rxCount;
BYTE* currentPos = dataBuf;
while (bytesInBuf = USBPHDC_bytesInUSBBuffer(intfNum)){
if ((WORD)(currentPos - dataBuf + bytesInBuf) <= size){
rxCount = bytesInBuf;
} else {
rxCount = size;
}
USBPHDC_receiveData(currentPos,rxCount,intfNum);
currentPos += bytesInBuf;
}
return (currentPos - dataBuf);
}
#endif