diff options
-rw-r--r-- | libmaple/usb/descriptors.h | 25 | ||||
-rw-r--r-- | libmaple/usb/usb.c | 77 | ||||
-rw-r--r-- | libmaple/usb/usb.h | 7 | ||||
-rw-r--r-- | libmaple/usb/usb_callbacks.c | 155 | ||||
-rw-r--r-- | libmaple/usb/usb_callbacks.h | 11 | ||||
-rw-r--r-- | libmaple/usb/usb_config.h | 1 | ||||
-rw-r--r-- | wirish/usb_serial.cpp | 14 |
7 files changed, 146 insertions, 144 deletions
diff --git a/libmaple/usb/descriptors.h b/libmaple/usb/descriptors.h index 6652942..6f7d08b 100644 --- a/libmaple/usb/descriptors.h +++ b/libmaple/usb/descriptors.h @@ -1,4 +1,27 @@ -/* insert license */ +/* ***************************************************************************** + * The MIT License + * + * Copyright (c) 2010 LeafLabs LLC. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * ****************************************************************************/ + #ifndef __DESCRIPTORS_H #define __DESCRIPTORS_H diff --git a/libmaple/usb/usb.c b/libmaple/usb/usb.c index 923e54b..4e86ed0 100644 --- a/libmaple/usb/usb.c +++ b/libmaple/usb/usb.c @@ -332,82 +332,67 @@ void usbWaitReset(void) { * This function will quickly copy up to 64 bytes of data (out of an * arbitrarily large buffer) into the USB peripheral TX buffer and return the * number placed in that buffer. It is up to usercode to divide larger packets - * into 64-byte chunks to guarantee delivery. Use usbGetCountTx() to determine - * whether the bytes were ACTUALLY recieved by the host or just transfered to - * the buffer. + * into 64-byte chunks to guarantee delivery. * - * The function will return -1 if it doesn't think that the USB host is - * "connected", but it can't detect this state robustly. "Connected" in this - * context means that an actual program on the Host operating system is - * connected to the virtual COM/ttyACM device and is recieving the bytes; the - * Host operating system is almost always configured and keeping this endpoint - * alive, but the bytes never get read out of the endpoint buffer. - * - * The behavior of this function is subtle and frustrating; it has gone through - * many simpler and cleaner implementation that frustratingly don't work cross - * platform. - * - * */ -uint16 usbSendBytes(uint8* sendBuf, uint16 len) { - - uint16 loaded = 0; - - if (bDeviceState != CONFIGURED || (!usbGetDTR() && !usbGetRTS())) { - // Indicates to caller to stop trying, were not configured/connected - // The DTR and RTS lines are handled differently on major platforms, so - // the above logic is unreliable - return 0; - } + * + */ +void usbBlockingSendByte(char ch) { + while (countTx); + UserToPMABufferCopy(&ch,VCOM_TX_ADDR,1); + _SetEPTxCount(VCOM_TX_ENDP,1); + _SetEPTxValid(VCOM_TX_ENDP); + countTx = 1; + while (countTx); +} +uint32 usbSendBytes(uint8* sendBuf, uint32 len) { + /* any checks on connection (via dtr/rts) done upstream in wirish or by user */ - // Due to a variety of shit this is how we roll; all buffering etc is pushed - // upstream + /* last xmit hasnt finished, abort */ if (countTx) { return 0; } // We can only put VCOM_TX_EPSIZE bytes in the buffer - if(len > VCOM_TX_EPSIZE) { - loaded = VCOM_TX_EPSIZE; - } else { - loaded = len; + if(len > VCOM_TX_EPSIZE/2) { + len = VCOM_TX_EPSIZE/2; } // Try to load some bytes if we can - if (loaded) { - UserToPMABufferCopy(sendBuf,VCOM_TX_ADDR + countTx, loaded); - _SetEPTxCount(VCOM_TX_ENDP, countTx+loaded); + if (len) { + UserToPMABufferCopy(sendBuf,VCOM_TX_ADDR, len); + _SetEPTxCount(VCOM_TX_ENDP, len); _SetEPTxValid(VCOM_TX_ENDP); - countTx += loaded; + countTx += len; } - return loaded; + return len; } /* returns the number of available bytes are in the recv FIFO */ -uint8 usbBytesAvailable(void) { - return VCOM_RX_EPSIZE - maxNewBytes; +uint32 usbBytesAvailable(void) { + return newBytes; } /* copies len bytes from the local recieve FIFO (not usb packet buffer) into recvBuf and deq's the fifo. will only copy the minimum of len or the available bytes. returns the number of bytes copied */ -uint8 usbReceiveBytes(uint8* recvBuf, uint8 len) { - if (len > VCOM_RX_EPSIZE - maxNewBytes) { - len = VCOM_RX_EPSIZE - maxNewBytes; +uint32 usbReceiveBytes(uint8* recvBuf, uint32 len) { + if (len > newBytes) { + len = newBytes; } int i; for (i=0;i<len;i++) { - recvBuf[i] = (uint8)(vcomBufferRx[recvBufOut]); - recvBufOut = (recvBufOut + 1) % VCOM_RX_EPSIZE; + recvBuf[i] = (uint8)(vcomBufferRx[i]); } - maxNewBytes += len; + newBytes -= len; /* re-enable the rx endpoint which we had set to receive 0 bytes */ - if (maxNewBytes - len == 0) { - SetEPRxCount(VCOM_RX_ENDP,maxNewBytes); + if (newBytes == 0) { + SetEPRxCount(VCOM_RX_ENDP,VCOM_RX_EPSIZE); + SetEPRxStatus(VCOM_RX_ENDP,EP_RX_VALID); } return len; diff --git a/libmaple/usb/usb.h b/libmaple/usb/usb.h index ffba9ff..0ed02e5 100644 --- a/libmaple/usb/usb.h +++ b/libmaple/usb/usb.h @@ -73,9 +73,10 @@ void usb_lpIRQHandler(void); void usbWaitReset(void); /* blocking functions for send/receive */ -uint16 usbSendBytes(uint8* sendBuf,uint16 len); -uint8 usbBytesAvailable(void); -uint8 usbReceiveBytes(uint8* recvBuf, uint8 len); +void usbBlockingSendByte(char ch); +uint32 usbSendBytes(uint8* sendBuf,uint32 len); +uint32 usbBytesAvailable(void); +uint32 usbReceiveBytes(uint8* recvBuf, uint32 len); uint8 usbGetDTR(void); uint8 usbGetRTS(void); uint8 usbIsConnected(void); diff --git a/libmaple/usb/usb_callbacks.c b/libmaple/usb/usb_callbacks.c index 250acea..ccb0fdd 100644 --- a/libmaple/usb/usb_callbacks.c +++ b/libmaple/usb/usb_callbacks.c @@ -32,12 +32,12 @@ USB_Line_Coding line_coding = { datatype: 0x08 }; -uint8 vcomBufferRx[VCOM_RX_EPSIZE]; -volatile uint8 countTx = 0; -volatile uint8 recvBufIn = 0; -volatile uint8 recvBufOut = 0; -volatile uint8 maxNewBytes = VCOM_RX_EPSIZE; - +uint8 vcomBufferRx[VCOM_RX_BUFLEN]; +volatile uint32 countTx = 0; +volatile uint32 recvBufIn = 0; +volatile uint32 recvBufOut = 0; +volatile uint32 maxNewBytes = VCOM_RX_BUFLEN; +volatile uint32 newBytes = 0; RESET_STATE reset_state = DTR_UNSET; uint8 line_dtr_rts = 0; @@ -46,7 +46,7 @@ void vcomDataTxCb(void) { /* allows usbSendBytes to stop blocking */ - + /* assumes tx transactions are atomic 64 bytes (nearly certain they are) */ countTx = 0; } @@ -56,84 +56,65 @@ void vcomDataTxCb(void) { in the fifo. this number will be reincremented after calls to usbReceiveBytes */ void vcomDataRxCb(void) { - /* do whatever after data has been received from host */ - - /* setEPRxCount on the previous cycle should garuntee - we havnt received more bytes than we can fit */ - uint8 newBytes = GetEPRxCount(VCOM_RX_ENDP); - /* assert (newBytes <= maxNewBytes); */ - - /* todo, not checking very carefully for edge cases. USUALLY, - if we emit the reset pulse and send 4 bytes, then newBytes - should be 4. But its POSSIBLE that this would be violated - in some cases */ - - /* magic number, {0x31, 0x45, 0x41, 0x46} is "1EAF" */ - char chkBuf[4]; - char cmpBuf[4] = {0x31, 0x45, 0x41, 0x46}; - if (reset_state == DTR_NEGEDGE) { - reset_state = DTR_LOW; - - if (newBytes >= 4) { - unsigned int target = (unsigned int)usbWaitReset | 0x1; - - PMAToUserBufferCopy(chkBuf,VCOM_RX_ADDR,4); - - int i; - USB_Bool cmpMatch = TRUE; - for (i=0; i<4; i++) { - if (chkBuf[i] != cmpBuf[i]) { - cmpMatch = FALSE; - } - } - - if (cmpMatch) { - asm volatile("mov r0, %[stack_top] \n\t" // Reset the stack - "mov sp, r0 \n\t" - "mov r0, #1 \n\t" - "mov r1, %[target_addr] \n\t" - "mov r2, %[cpsr] \n\t" - "push {r2} \n\t" // Fake xPSR - "push {r1} \n\t" // Target address for PC - "push {r0} \n\t" // Fake LR - "push {r0} \n\t" // Fake R12 - "push {r0} \n\t" // Fake R3 - "push {r0} \n\t" // Fake R2 - "push {r0} \n\t" // Fake R1 - "push {r0} \n\t" // Fake R0 - "mov lr, %[exc_return] \n\t" - "bx lr" - : - : [stack_top] "r" (STACK_TOP), - [target_addr] "r" (target), - [exc_return] "r" (EXC_RETURN), - [cpsr] "r" (DEFAULT_CPSR) - : "r0", "r1", "r2"); - /* should never get here */ - } - } + /* do whatever after data has been received from host */ + + /* setEPRxCount on the previous cycle should garuntee + we havnt received more bytes than we can fit */ + newBytes = GetEPRxCount(VCOM_RX_ENDP); + SetEPRxStatus(VCOM_RX_ENDP,EP_RX_NAK); + + /* todo, not checking very carefully for edge cases. USUALLY, + if we emit the reset pulse and send 4 bytes, then newBytes + should be 4. But its POSSIBLE that this would be violated + in some cases */ + + /* magic number, {0x31, 0x45, 0x41, 0x46} is "1EAF" */ + char chkBuf[4]; + char cmpBuf[4] = {0x31, 0x45, 0x41, 0x46}; + if (reset_state == DTR_NEGEDGE) { + reset_state = DTR_LOW; + + if (newBytes >= 4) { + unsigned int target = (unsigned int)usbWaitReset | 0x1; + + PMAToUserBufferCopy(chkBuf,VCOM_RX_ADDR,4); + + int i; + USB_Bool cmpMatch = TRUE; + for (i=0; i<4; i++) { + if (chkBuf[i] != cmpBuf[i]) { + cmpMatch = FALSE; + } + } + + if (cmpMatch) { + asm volatile("mov r0, %[stack_top] \n\t" // Reset the stack + "mov sp, r0 \n\t" + "mov r0, #1 \n\t" + "mov r1, %[target_addr] \n\t" + "mov r2, %[cpsr] \n\t" + "push {r2} \n\t" // Fake xPSR + "push {r1} \n\t" // Target address for PC + "push {r0} \n\t" // Fake LR + "push {r0} \n\t" // Fake R12 + "push {r0} \n\t" // Fake R3 + "push {r0} \n\t" // Fake R2 + "push {r0} \n\t" // Fake R1 + "push {r0} \n\t" // Fake R0 + "mov lr, %[exc_return] \n\t" + "bx lr" + : + : [stack_top] "r" (STACK_TOP), + [target_addr] "r" (target), + [exc_return] "r" (EXC_RETURN), + [cpsr] "r" (DEFAULT_CPSR) + : "r0", "r1", "r2"); + /* should never get here */ + } } + } - - - if (recvBufIn + newBytes < VCOM_RX_EPSIZE) { - PMAToUserBufferCopy(&vcomBufferRx[recvBufIn],VCOM_RX_ADDR,newBytes); - recvBufIn += newBytes; - } else { - /* we have to copy the data in two chunks because we roll over - the edge of the circular buffer */ - uint8 tailBytes = VCOM_RX_EPSIZE - recvBufIn; - uint8 remaining = newBytes - tailBytes; - - PMAToUserBufferCopy(&vcomBufferRx[recvBufIn],VCOM_RX_ADDR,tailBytes); - PMAToUserBufferCopy(&vcomBufferRx[0], VCOM_RX_ADDR,remaining); - - recvBufIn = (recvBufIn + newBytes ) % VCOM_RX_EPSIZE; - } - - maxNewBytes -= newBytes; - SetEPRxCount(VCOM_RX_ENDP,maxNewBytes); - SetEPRxValid(VCOM_RX_ENDP); + PMAToUserBufferCopy(&vcomBufferRx[0],VCOM_RX_ADDR,newBytes); } void vcomManagementCb(void) { @@ -177,7 +158,7 @@ void usbReset(void) { _SetEPRxAddr(ENDP0,VCOM_CTRL_RX_ADDR); _SetEPTxAddr(ENDP0,VCOM_CTRL_TX_ADDR); Clear_Status_Out(ENDP0); - + SetEPRxCount(ENDP0, pProperty->MaxPacketSize); SetEPRxValid(ENDP0); @@ -232,11 +213,11 @@ RESULT usbDataSetup(uint8 request) { if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) { switch (request) { - case (GET_LINE_CODING): + case (GET_LINE_CODING): CopyRoutine = vcomGetSetLineCoding; last_request = GET_LINE_CODING; break; - case (SET_LINE_CODING): + case (SET_LINE_CODING): CopyRoutine = vcomGetSetLineCoding; last_request = SET_LINE_CODING; break; @@ -284,7 +265,7 @@ RESULT usbNoDataSetup(u8 request) { reset_state = DTR_NEGEDGE; } else { reset_state = DTR_HIGH; - } + } break; case DTR_NEGEDGE: diff --git a/libmaple/usb/usb_callbacks.h b/libmaple/usb/usb_callbacks.h index a94de11..20d2c13 100644 --- a/libmaple/usb/usb_callbacks.h +++ b/libmaple/usb/usb_callbacks.h @@ -34,11 +34,12 @@ typedef enum { extern RESET_STATE reset_state; /* tracks DTR/RTS */ extern uint8 line_dtr_rts; -extern volatile uint8 countTx; -extern uint8 vcomBufferRx[VCOM_RX_EPSIZE]; /* no reason this has to be VCOM_RX_EPSIZE, could be bigger */ -extern volatile uint8 recvBufIn; /* the FIFO in index to the recvbuffer */ -extern volatile uint8 recvBufOut; /* the FIFO out index to the recvbuffer */ -extern volatile uint8 maxNewBytes; +extern volatile uint32 countTx; +extern uint8 vcomBufferRx[VCOM_RX_BUFLEN]; /* no reason this has to be VCOM_RX_EPSIZE, could be bigger */ +extern volatile uint32 recvBufIn; /* the FIFO in index to the recvbuffer */ +extern volatile uint32 recvBufOut; /* the FIFO out index to the recvbuffer */ +extern volatile uint32 maxNewBytes; +extern volatile uint32 newBytes; void vcomDataTxCb(void); void vcomDataRxCb(void); diff --git a/libmaple/usb/usb_config.h b/libmaple/usb/usb_config.h index ba05d42..e5f3979 100644 --- a/libmaple/usb/usb_config.h +++ b/libmaple/usb/usb_config.h @@ -26,6 +26,7 @@ #define VCOM_RX_EPNUM 0x03 #define VCOM_RX_ADDR 0x110 #define VCOM_RX_EPSIZE 0x40 +#define VCOM_RX_BUFLEN (VCOM_RX_EPSIZE*3) #define bMaxPacketSize 0x40 /* 64B, maximum for USB FS Devices */ diff --git a/wirish/usb_serial.cpp b/wirish/usb_serial.cpp index 5c8a65f..e2cdee3 100644 --- a/wirish/usb_serial.cpp +++ b/wirish/usb_serial.cpp @@ -101,17 +101,27 @@ uint32 USBSerial::available(void) { return usbBytesAvailable(); } +/* blocks forever until len_bytes is received */ uint32 USBSerial::read(void *buf, uint32 len) { if (!buf) { return 0; } - return usbReceiveBytes((uint8*)buf, len); + uint32 bytes_in = 0; + while (len > 0) { + uint32 new_bytes = usbReceiveBytes((uint8*)((uint8*)buf+bytes_in), len); + len -= new_bytes; + bytes_in += new_bytes; + } + + return len; } +/* blocks forever until 1 byte is received */ uint8 USBSerial::read(void) { uint8 ch; - usbReceiveBytes(&ch, 1); + + while (usbReceiveBytes(&ch, 1) == 0); return ch; } |