I faced the same problem: couldn't afford stalling of a thread writing to the virtual USB serial port. I considered several approaches to fixing the issue and ended up patching ChibiOS, which seemed just the simpler solution.
Basically it adds a couple of fields to the SerialUSBConfig structure which are the timeouts to use when wiriting/reading to/from the associated queue. If you use TIME_INFINITE in both cases you'll get exactly the same default ChibiOS behaviour.
Note that using TIME_IMMEDIATE or some other finite timeout in the writes might have a weird effect on the stream you receive on the PC side. If the cable is disconnected the queue will accept chars until it's full, then discard everything. When you first connect the cable what you'll get first is what you sent first possibly ages ago, not what you attempted to send recently.
Code: Select all
diff -rupN a/os/hal/include/serial_usb.h b/os/hal/include/serial_usb.h
--- a/os/hal/include/serial_usb.h 2013-05-11 08:13:40.000000000 +0200
+++ b/os/hal/include/serial_usb.h 2015-08-18 20:45:10.213602883 +0200
@@ -161,6 +161,14 @@ typedef struct {
* @brief Interrupt IN endpoint used for notifications.
*/
usbep_t int_in;
+ /**
+ * @brief Default timeout to use for output operations (write/put).
+ */
+ systime_t out_tout;
+ /**
+ * @brief Default timeout to use for input operations (read/get).
+ */
+ systime_t in_tout;
} SerialUSBConfig;
/**
diff -rupN a/os/hal/src/serial_usb.c b/os/hal/src/serial_usb.c
--- a/os/hal/src/serial_usb.c 2013-05-11 08:13:46.000000000 +0200
+++ b/os/hal/src/serial_usb.c 2015-08-18 20:45:46.060759983 +0200
@@ -69,23 +69,25 @@ static cdc_linecoding_t linecoding = {
static size_t write(void *ip, const uint8_t *bp, size_t n) {
return chOQWriteTimeout(&((SerialUSBDriver *)ip)->oqueue, bp,
- n, TIME_INFINITE);
+ n, ((SerialUSBDriver *)ip)->config->out_tout);
}
static size_t read(void *ip, uint8_t *bp, size_t n) {
return chIQReadTimeout(&((SerialUSBDriver *)ip)->iqueue, bp,
- n, TIME_INFINITE);
+ n, ((SerialUSBDriver *)ip)->config->in_tout);
}
static msg_t put(void *ip, uint8_t b) {
- return chOQPutTimeout(&((SerialUSBDriver *)ip)->oqueue, b, TIME_INFINITE);
+ return chOQPutTimeout(&((SerialUSBDriver *)ip)->oqueue,
+ b, ((SerialUSBDriver *)ip)->config->out_tout);
}
static msg_t get(void *ip) {
- return chIQGetTimeout(&((SerialUSBDriver *)ip)->iqueue, TIME_INFINITE);
+ return chIQGetTimeout(&((SerialUSBDriver *)ip)->iqueue,
+ ((SerialUSBDriver *)ip)->config->in_tout);
}
static msg_t putt(void *ip, uint8_t b, systime_t timeout) {