Skip to content

Commit 4f36857

Browse files
committed
Get Windows to use WinUSB driver for device
Combines usb_stm32.c and usb_stm32_serial.c and ties together previous changes by providing enough functionality to get Windows to automatically select the WinUSB driver.
1 parent fb45d7b commit 4f36857

File tree

2 files changed

+228
-267
lines changed

2 files changed

+228
-267
lines changed

lib/pbio/drv/usb/usb_stm32.c

Lines changed: 228 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@
1010
#include <stdbool.h>
1111

1212
#include <contiki.h>
13+
#include <contiki-lib.h>
1314
#include <stm32f4xx_hal.h>
1415
#include <stm32f4xx_hal_pcd_ex.h>
16+
#include <usbd_cdc.h>
1517
#include <usbd_core.h>
1618

1719
#include <pbdrv/usb.h>
@@ -22,8 +24,30 @@
2224

2325
PROCESS(pbdrv_usb_process, "USB");
2426

27+
static uint8_t usb_in_buf[CDC_DATA_FS_MAX_PACKET_SIZE];
28+
static uint8_t usb_out_buf[CDC_DATA_FS_MAX_PACKET_SIZE - 1];
29+
static volatile bool usb_in_busy;
30+
static volatile bool usb_out_busy;
31+
32+
static volatile bool usb_connected;
33+
34+
// size must be power of 2 for ringbuf! also can't be > 255!
35+
static uint8_t stdout_data[128];
36+
static uint8_t stdin_data[128];
37+
static struct ringbuf stdout_buf;
38+
static struct ringbuf stdin_buf;
39+
40+
static USBD_CDC_LineCodingTypeDef LineCoding = {
41+
.bitrate = 115200,
42+
.format = CDC_STOP_BITS_1,
43+
.paritytype = CDC_PARITY_NONE,
44+
.datatype = 8,
45+
};
46+
2547
static USBD_HandleTypeDef husbd;
2648
static PCD_HandleTypeDef hpcd;
49+
extern USBD_DescriptorsTypeDef VCP_Desc;
50+
2751
static volatile bool vbus_active;
2852
static pbdrv_usb_bcd_t pbdrv_usb_bcd;
2953

@@ -121,14 +145,146 @@ void pbdrv_usb_stm32_handle_vbus_irq(bool active) {
121145
process_poll(&pbdrv_usb_process);
122146
}
123147

148+
/**
149+
* @brief CDC_Itf_Init
150+
* Initializes the CDC media low layer
151+
* @param None
152+
* @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL
153+
*/
154+
static int8_t CDC_Itf_Init(void) {
155+
ringbuf_init(&stdin_buf, stdin_data, (uint8_t)PBIO_ARRAY_SIZE(stdin_data));
156+
ringbuf_init(&stdout_buf, stdout_data, (uint8_t)PBIO_ARRAY_SIZE(stdout_data));
157+
USBD_CDC_SetTxBuffer(&husbd, usb_out_buf, 0);
158+
USBD_CDC_SetRxBuffer(&husbd, usb_in_buf);
159+
usb_in_busy = false;
160+
usb_out_busy = false;
161+
usb_connected = false;
162+
163+
return USBD_OK;
164+
}
165+
166+
/**
167+
* @brief CDC_Itf_DeInit
168+
* DeInitializes the CDC media low layer
169+
* @param None
170+
* @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL
171+
*/
172+
static int8_t CDC_Itf_DeInit(void) {
173+
usb_connected = false;
174+
return USBD_OK;
175+
}
176+
177+
/**
178+
* @brief CDC_Itf_Control
179+
* Manage the CDC class requests
180+
* @param Cmd: Command code
181+
* @param Buf: Buffer containing command data (request parameters)
182+
* @param Len: Number of data to be sent (in bytes)
183+
* @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL
184+
*/
185+
static int8_t CDC_Itf_Control(uint8_t cmd, uint8_t *pbuf, uint16_t length) {
186+
switch (cmd) {
187+
case CDC_SEND_ENCAPSULATED_COMMAND:
188+
break;
189+
190+
case CDC_GET_ENCAPSULATED_RESPONSE:
191+
break;
192+
193+
case CDC_SET_COMM_FEATURE:
194+
break;
195+
196+
case CDC_GET_COMM_FEATURE:
197+
break;
198+
199+
case CDC_CLEAR_COMM_FEATURE:
200+
break;
201+
202+
case CDC_SET_LINE_CODING:
203+
LineCoding.bitrate = pbuf[0] | (pbuf[1] << 8) | (pbuf[2] << 16) | (pbuf[3] << 24);
204+
LineCoding.format = pbuf[4];
205+
LineCoding.paritytype = pbuf[5];
206+
LineCoding.datatype = pbuf[6];
207+
break;
208+
209+
case CDC_GET_LINE_CODING:
210+
pbuf[0] = (uint8_t)(LineCoding.bitrate);
211+
pbuf[1] = (uint8_t)(LineCoding.bitrate >> 8);
212+
pbuf[2] = (uint8_t)(LineCoding.bitrate >> 16);
213+
pbuf[3] = (uint8_t)(LineCoding.bitrate >> 24);
214+
pbuf[4] = LineCoding.format;
215+
pbuf[5] = LineCoding.paritytype;
216+
pbuf[6] = LineCoding.datatype;
217+
break;
218+
219+
case CDC_SET_CONTROL_LINE_STATE: {
220+
USBD_SetupReqTypedef *req = (void *)pbuf;
221+
// REVISIT: MicroPython defers the connection state here to allow
222+
// some time to disable local echo on the remote terminal
223+
usb_connected = !!(req->wValue & CDC_CONTROL_LINE_DTR);
224+
break;
225+
}
226+
case CDC_SEND_BREAK:
227+
break;
228+
}
229+
230+
return USBD_OK;
231+
}
232+
233+
/**
234+
* @brief CDC_Itf_DataRx
235+
* Data received over USB OUT endpoint are sent over CDC interface
236+
* through this function.
237+
* @param Buf: Buffer of data to be transmitted
238+
* @param Len: Number of data received (in bytes)
239+
* @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL
240+
*/
241+
static int8_t CDC_Itf_Receive(uint8_t *Buf, uint32_t *Len) {
242+
for (uint32_t i = 0; i < *Len; i++) {
243+
ringbuf_put(&stdin_buf, Buf[i]);
244+
}
245+
usb_in_busy = false;
246+
// process_poll(&pbdrv_usb_process);
247+
return USBD_OK;
248+
}
249+
250+
/**
251+
* @brief CDC_Itf_TransmitCplt
252+
* Data transmitted callback
253+
*
254+
* @note
255+
* This function is IN transfer complete callback used to inform user that
256+
* the submitted Data is successfully sent over USB.
257+
*
258+
* @param Buf: Buffer of data to be received
259+
* @param Len: Number of data received (in bytes)
260+
* @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL
261+
*/
262+
static int8_t CDC_Itf_TransmitCplt(uint8_t *Buf, uint32_t *Len, uint8_t epnum) {
263+
usb_out_busy = false;
264+
// process_poll(&pbdrv_usb_process);
265+
return USBD_OK;
266+
}
267+
268+
static USBD_CDC_ItfTypeDef USBD_CDC_fops = {
269+
.Init = CDC_Itf_Init,
270+
.DeInit = CDC_Itf_DeInit,
271+
.Control = CDC_Itf_Control,
272+
.Receive = CDC_Itf_Receive,
273+
.TransmitCplt = CDC_Itf_TransmitCplt,
274+
};
275+
124276
// Common USB driver implementation.
125277

126278
void pbdrv_usb_init(void) {
127279
// Link the driver data structures
128280
husbd.pData = &hpcd;
129281
hpcd.pData = &husbd;
130282

131-
USBD_Init(&husbd, NULL, 0);
283+
USBD_Init(&husbd, &VCP_Desc, 0);
284+
USBD_RegisterClass(&husbd, USBD_CDC_CLASS);
285+
USBD_CDC_RegisterInterface(&husbd, &USBD_CDC_fops);
286+
USBD_Start(&husbd);
287+
132288
process_start(&pbdrv_usb_process);
133289

134290
// VBUS may already be active
@@ -139,13 +295,75 @@ pbdrv_usb_bcd_t pbdrv_usb_get_bcd(void) {
139295
return pbdrv_usb_bcd;
140296
}
141297

298+
static void pbdrv_usb_serial_transmit(void) {
299+
static uint32_t tx_size = 0;
300+
301+
if (usb_out_busy) {
302+
return;
303+
}
304+
305+
// If tx_size > 0 it means we have a pending retry, otherwise we get as
306+
// much as we can from the stdout buffer.
307+
if (tx_size == 0) {
308+
tx_size = ringbuf_elements(&stdout_buf);
309+
if (tx_size > PBIO_ARRAY_SIZE(usb_out_buf)) {
310+
tx_size = PBIO_ARRAY_SIZE(usb_out_buf);
311+
}
312+
if (tx_size > 0) {
313+
for (uint32_t i = 0; i < tx_size; i++) {
314+
usb_out_buf[i] = ringbuf_get(&stdout_buf);
315+
}
316+
}
317+
}
318+
319+
if (tx_size > 0) {
320+
USBD_CDC_SetTxBuffer(&husbd, usb_out_buf, tx_size);
321+
if (USBD_CDC_TransmitPacket(&husbd) == USBD_OK) {
322+
usb_out_busy = true;
323+
tx_size = 0;
324+
}
325+
}
326+
}
327+
328+
static void pbdrv_usb_serial_receive(void) {
329+
if (usb_in_busy) {
330+
return;
331+
}
332+
333+
if (USBD_CDC_ReceivePacket(&husbd) == USBD_OK) {
334+
usb_in_busy = true;
335+
}
336+
}
337+
338+
// TODO: need to multiplex stdin/stdout with Bluetooth or remove USB serial
339+
340+
pbio_error_t pbsys_usb_put_char(uint8_t c) {
341+
if (!usb_connected) {
342+
// don't lock up print() when USB not connected - data is discarded
343+
return PBIO_SUCCESS;
344+
}
345+
if (ringbuf_put(&stdout_buf, c) == 0) {
346+
return PBIO_SUCCESS;
347+
}
348+
return PBIO_SUCCESS;
349+
}
350+
351+
pbio_error_t pbsys_usb_get_char(uint8_t *c) {
352+
if (ringbuf_elements(&stdin_buf) == 0) {
353+
return PBIO_ERROR_AGAIN;
354+
}
355+
*c = ringbuf_get(&stdin_buf);
356+
return PBIO_SUCCESS;
357+
}
358+
142359
// Event loop
143360

144361
PROCESS_THREAD(pbdrv_usb_process, ev, data) {
145362
static struct pt bcd_pt;
146363
static PBIO_ONESHOT(no_vbus_oneshot);
147364
static PBIO_ONESHOT(bcd_oneshot);
148365
static bool bcd_busy;
366+
static struct etimer timer;
149367

150368
PROCESS_POLLHANDLER({
151369
if (!bcd_busy && pbio_oneshot(!vbus_active, &no_vbus_oneshot)) {
@@ -164,12 +382,20 @@ PROCESS_THREAD(pbdrv_usb_process, ev, data) {
164382

165383
PROCESS_BEGIN();
166384

385+
etimer_set(&timer, 5);
386+
167387
for (;;) {
168-
PROCESS_WAIT_EVENT();
388+
PROCESS_WAIT_EVENT_UNTIL(ev == PROCESS_EVENT_POLL || (ev == PROCESS_EVENT_TIMER && etimer_expired(&timer)));
169389

170390
if (bcd_busy) {
171391
bcd_busy = PT_SCHEDULE(pbdrv_usb_stm32_bcd_detect(&bcd_pt));
172392
}
393+
394+
if (etimer_expired(&timer)) {
395+
etimer_reset(&timer);
396+
pbdrv_usb_serial_transmit();
397+
pbdrv_usb_serial_receive();
398+
}
173399
}
174400

175401
PROCESS_END();

0 commit comments

Comments
 (0)