aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarti Bolivar <mbolivar@leaflabs.com>2013-01-18 18:08:01 -0500
committerMarti Bolivar <mbolivar@leaflabs.com>2013-01-18 18:12:21 -0500
commit369f98af8dfdf0cf7610e735883b12a151c78260 (patch)
treec983e00039363add7f9a7dce857527f66b8de2c1
parente7eac89b679f4dda632ff45da135207dbc1c8edb (diff)
parentafb4199070e464c317b86741e107692120e05097 (diff)
downloadlibrambutan-369f98af8dfdf0cf7610e735883b12a151c78260.tar.gz
librambutan-369f98af8dfdf0cf7610e735883b12a151c78260.zip
Merge branch 'bug/usb-full-ep'
This resolves issues related to sending full (64B) packets via USB 2.0. In this case, some hosts continue to expect more data. Add infrastructure for sending 0-byte packets to signal end of transmission, and use it in SerialUSB. Signed-off-by: Marti Bolivar <mbolivar@leaflabs.com>
-rw-r--r--libmaple/include/libmaple/usb_cdcacm.h22
-rw-r--r--libmaple/usb/stm32f1/usb_cdcacm.c47
-rw-r--r--wirish/usb_serial.cpp13
3 files changed, 50 insertions, 32 deletions
diff --git a/libmaple/include/libmaple/usb_cdcacm.h b/libmaple/include/libmaple/usb_cdcacm.h
index 8b3c1fe..5fe832c 100644
--- a/libmaple/include/libmaple/usb_cdcacm.h
+++ b/libmaple/include/libmaple/usb_cdcacm.h
@@ -72,6 +72,27 @@ extern "C" {
#define USB_INTERFACE_SUBCLASS_CDC_ACM 0x02
#define USB_INTERFACE_CLASS_DIC 0x0A
+/*
+ * Endpoint configuration
+ */
+
+#define USB_CDCACM_CTRL_ENDP 0
+#define USB_CDCACM_CTRL_RX_ADDR 0x40
+#define USB_CDCACM_CTRL_TX_ADDR 0x80
+#define USB_CDCACM_CTRL_EPSIZE 0x40
+
+#define USB_CDCACM_TX_ENDP 1
+#define USB_CDCACM_TX_ADDR 0xC0
+#define USB_CDCACM_TX_EPSIZE 0x40
+
+#define USB_CDCACM_MANAGEMENT_ENDP 2
+#define USB_CDCACM_MANAGEMENT_ADDR 0x100
+#define USB_CDCACM_MANAGEMENT_EPSIZE 0x40
+
+#define USB_CDCACM_RX_ENDP 3
+#define USB_CDCACM_RX_ADDR 0x110
+#define USB_CDCACM_RX_EPSIZE 0x40
+
#ifndef __cplusplus
#define USB_CDCACM_DECLARE_DEV_DESC(vid, pid) \
{ \
@@ -106,6 +127,7 @@ uint32 usb_cdcacm_peek(uint8* buf, uint32 len);
uint32 usb_cdcacm_data_available(void); /* in RX buffer */
uint16 usb_cdcacm_get_pending(void);
+uint8 usb_cdcacm_is_transmitting(void);
uint8 usb_cdcacm_get_dtr(void);
uint8 usb_cdcacm_get_rts(void);
diff --git a/libmaple/usb/stm32f1/usb_cdcacm.c b/libmaple/usb/stm32f1/usb_cdcacm.c
index addab3c..ecb9397 100644
--- a/libmaple/usb/stm32f1/usb_cdcacm.c
+++ b/libmaple/usb/stm32f1/usb_cdcacm.c
@@ -82,27 +82,6 @@ static void usbSetConfiguration(void);
static void usbSetDeviceAddress(void);
/*
- * Endpoint configuration
- */
-
-#define USB_CDCACM_CTRL_ENDP 0
-#define USB_CDCACM_CTRL_RX_ADDR 0x40
-#define USB_CDCACM_CTRL_TX_ADDR 0x80
-#define USB_CDCACM_CTRL_EPSIZE 0x40
-
-#define USB_CDCACM_TX_ENDP 1
-#define USB_CDCACM_TX_ADDR 0xC0
-#define USB_CDCACM_TX_EPSIZE 0x40
-
-#define USB_CDCACM_MANAGEMENT_ENDP 2
-#define USB_CDCACM_MANAGEMENT_ADDR 0x100
-#define USB_CDCACM_MANAGEMENT_EPSIZE 0x40
-
-#define USB_CDCACM_RX_ENDP 3
-#define USB_CDCACM_RX_ADDR 0x110
-#define USB_CDCACM_RX_EPSIZE 0x40
-
-/*
* Descriptors
*/
@@ -288,6 +267,8 @@ static volatile uint8 vcomBufferRx[USB_CDCACM_RX_EPSIZE];
static volatile uint32 rx_offset = 0;
/* Number of bytes left to transmit */
static volatile uint32 n_unsent_bytes = 0;
+/* Are we currently sending an IN packet? */
+static volatile uint8 transmitting = 0;
/* Number of unread bytes */
static volatile uint32 n_unread_bytes = 0;
@@ -413,7 +394,7 @@ void usb_cdcacm_putc(char ch) {
* buffer, and returns the number of bytes copied. */
uint32 usb_cdcacm_tx(const uint8* buf, uint32 len) {
/* Last transmission hasn't finished, so abort. */
- if (n_unsent_bytes) {
+ if (usb_cdcacm_is_transmitting()) {
return 0;
}
@@ -425,10 +406,14 @@ uint32 usb_cdcacm_tx(const uint8* buf, uint32 len) {
/* Queue bytes for sending. */
if (len) {
usb_copy_to_pma(buf, len, USB_CDCACM_TX_ADDR);
- usb_set_ep_tx_count(USB_CDCACM_TX_ENDP, len);
- n_unsent_bytes = len;
- usb_set_ep_tx_stat(USB_CDCACM_TX_ENDP, USB_EP_STAT_TX_VALID);
}
+ // We still need to wait for the interrupt, even if we're sending
+ // zero bytes. (Sending zero-size packets is useful for flushing
+ // host-side buffers.)
+ usb_set_ep_tx_count(USB_CDCACM_TX_ENDP, len);
+ n_unsent_bytes = len;
+ transmitting = 1;
+ usb_set_ep_tx_stat(USB_CDCACM_TX_ENDP, USB_EP_STAT_TX_VALID);
return len;
}
@@ -437,7 +422,11 @@ uint32 usb_cdcacm_data_available(void) {
return n_unread_bytes;
}
-uint16 usb_cdcacm_get_pending() {
+uint8 usb_cdcacm_is_transmitting(void) {
+ return transmitting;
+}
+
+uint16 usb_cdcacm_get_pending(void) {
return n_unsent_bytes;
}
@@ -518,12 +507,8 @@ int usb_cdcacm_get_n_data_bits(void) {
*/
static void vcomDataTxCb(void) {
- /* The following assumes that all of the bytes we copied during
- * the last call to usb_cdcacm_tx were sent during the IN
- * transaction (this seems to be the case). */
- /* TODO find out why this is broken:
- * n_unsent_bytes = usb_get_ep_tx_count(USB_CDCACM_TX_ENDP); */
n_unsent_bytes = 0;
+ transmitting = 0;
}
static void vcomDataRxCb(void) {
diff --git a/wirish/usb_serial.cpp b/wirish/usb_serial.cpp
index 380f197..d21766f 100644
--- a/wirish/usb_serial.cpp
+++ b/wirish/usb_serial.cpp
@@ -92,13 +92,24 @@ void USBSerial::write(const void *buf, uint32 len) {
uint32 old_txed = 0;
uint32 start = millis();
+ uint32 sent = 0;
+
while (txed < len && (millis() - start < USB_TIMEOUT)) {
- txed += usb_cdcacm_tx((const uint8*)buf + txed, len - txed);
+ sent = usb_cdcacm_tx((const uint8*)buf + txed, len - txed);
+ txed += sent;
if (old_txed != txed) {
start = millis();
}
old_txed = txed;
}
+
+
+ if (sent == USB_CDCACM_TX_EPSIZE) {
+ while (usb_cdcacm_is_transmitting() != 0) {
+ }
+ /* flush out to avoid having the pc wait for more data */
+ usb_cdcacm_tx(NULL, 0);
+ }
}
uint32 USBSerial::available(void) {