diff --git a/USBHost_t36.h b/USBHost_t36.h index cfbe277..0909e34 100644 --- a/USBHost_t36.h +++ b/USBHost_t36.h @@ -744,6 +744,50 @@ private: }; +class USBSerial: public USBDriver, public Stream { +public: + enum { BUFFER_SIZE = 4200 }; // must hold at least 6 max size packets, plus 2 extra bytes + USBSerial(USBHost &host) { init(); } + void begin(uint32_t baud, uint32_t format=0); + void end(void); + virtual int available(void); + virtual int peek(void); + virtual int read(void); + virtual size_t write(uint8_t c); +protected: + virtual bool claim(Device_t *device, int type, const uint8_t *descriptors, uint32_t len); + virtual void disconnect(); +private: + static void rx_callback(const Transfer_t *transfer); + static void tx_callback(const Transfer_t *transfer); + void rx_data(const Transfer_t *transfer); + void tx_data(const Transfer_t *transfer); + void init(); + static bool check_rxtx_ep(uint32_t &rxep, uint32_t &txep); + bool init_buffers(uint32_t rsize, uint32_t tsize); +private: + Pipe_t mypipes[3] __attribute__ ((aligned(32))); + Transfer_t mytransfers[7] __attribute__ ((aligned(32))); + uint32_t bigbuffer[(BUFFER_SIZE+3)/4]; + Pipe_t *rxpipe; + Pipe_t *txpipe; + uint8_t *rx1; // location for first incoming packet + uint8_t *rx2; // location for second incoming packet + uint8_t *rxbuf; // receive circular buffer + uint16_t rxhead;// receive head + uint16_t rxtail;// receive tail + uint8_t *tx1; // location for first outgoing packet + uint8_t *tx2; // location for second outgoing packet + uint8_t *txbuf; + uint16_t txhead; + uint16_t txtail; + uint16_t rxsize;// size of receive circular buffer + uint16_t txsize;// size of transmit circular buffer + uint8_t rxstate;// bitmask: which receive packets are queued + bool ignore_first_two_bytes; +}; + + class MouseController : public USBHIDInput { public: MouseController(USBHost &host) { USBHIDParser::driver_ready_for_hid_collection(this); } diff --git a/serial.cpp b/serial.cpp new file mode 100644 index 0000000..648e9fc --- /dev/null +++ b/serial.cpp @@ -0,0 +1,272 @@ +/* USB EHCI Host for Teensy 3.6 + * Copyright 2017 Paul Stoffregen (paul@pjrc.com) + * + * 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. + */ + +#include +#include "USBHost_t36.h" // Read this header first for key info + +// quick hack - ultimately USBHost print & println need to be renamed +#define print USBHost::print +#define println USBHost::println + +void USBSerial::init() +{ + contribute_Pipes(mypipes, sizeof(mypipes)/sizeof(Pipe_t)); + contribute_Transfers(mytransfers, sizeof(mytransfers)/sizeof(Transfer_t)); + driver_ready_for_device(this); +} + +bool USBSerial::claim(Device_t *dev, int type, const uint8_t *descriptors, uint32_t len) +{ + // only claim at interface level + println("USBSerial claim this=", (uint32_t)this, HEX); + print("vid=", dev->idVendor, HEX); + println(", pid=", dev->idProduct, HEX); + if (type == 0) { + if (dev->idVendor == 0x0403 && dev->idProduct == 0x6001) { + // FTDI FT232 + println("len = ", len); + if (len < 23) return false; + if (descriptors[0] != 9) return false; // length 9 + if (descriptors[9] != 7) return false; // length 7 + if (descriptors[10] != 5) return false; // ep desc + uint32_t rxep = descriptors[11]; + if (descriptors[12] != 2) return false; // bulk type + if (descriptors[13] != 64) return false; // size 64 + if (descriptors[14] != 0) return false; + if (descriptors[16] != 7) return false; // length 7 + if (descriptors[17] != 5) return false; // ep desc + uint32_t txep = descriptors[18]; + if (descriptors[19] != 2) return false; // bulk type + if (descriptors[20] != 64) return false; // size 64 + if (descriptors[21] != 0) return false; + if (!check_rxtx_ep(rxep, txep)) return false; + print("FTDI, rxep=", rxep & 15); + println(", txep=", txep); + if (!init_buffers(64, 64)) return false; + rxpipe = new_Pipe(dev, 2, rxep & 15, 1, 64); + if (!rxpipe) return false; + txpipe = new_Pipe(dev, 2, txep, 0, 64); + if (!txpipe) { + // TODO: free rxpipe + return false; + } + ignore_first_two_bytes = true; + rxpipe->callback_function = rx_callback; + queue_Data_Transfer(rxpipe, rx1, 64, this); + rxstate = 1; + if (rxsize > 128) { + queue_Data_Transfer(rxpipe, rx2, 64, this); + rxstate = 3; + } + txpipe->callback_function = tx_callback; + return true; + } + } + return false; +} + +// check if two legal endpoints, 1 receive & 1 transmit +bool USBSerial::check_rxtx_ep(uint32_t &rxep, uint32_t &txep) +{ + if ((rxep & 0x0F) == 0) return false; + if ((txep & 0x0F) == 0) return false; + uint32_t rxdir = rxep & 0xF0; + uint32_t txdir = txep & 0xF0; + if (rxdir == 0x80 && txdir == 0x00) { + return true; + } + if (rxdir == 0x00 && txdir == 0x80) { + std::swap(rxep, txep); + return true; + } + return false; +} + +// initialize buffer sizes and pointers +bool USBSerial::init_buffers(uint32_t rsize, uint32_t tsize) +{ + // buffer must be able to hold 2 of each packet, plus have room to + if (sizeof(bigbuffer) < (rsize + tsize) * 3 + 2) return false; + rx1 = (uint8_t *)bigbuffer; + rx2 = rx1 + rsize; + tx1 = rx2 + rsize; + tx2 = tx1 + tsize; + rxbuf = tx2 + tsize; + // FIXME: this assume 50-50 split - not true when rsize != tsize + rxsize = (sizeof(bigbuffer) - (rsize + tsize) * 2) / 2; + txsize = rxsize; + txbuf = rxbuf + rxsize; + rxhead = 0; + rxtail = 0; + txhead = 0; + txtail = 0; + rxstate = 0; + return true; +} + + + + + + + +void USBSerial::rx_callback(const Transfer_t *transfer) +{ + if (!transfer->driver) return; + ((USBSerial *)(transfer->driver))->rx_data(transfer); +} + +void USBSerial::tx_callback(const Transfer_t *transfer) +{ + if (!transfer->driver) return; + ((USBSerial *)(transfer->driver))->tx_data(transfer); +} + +void USBSerial::rx_data(const Transfer_t *transfer) +{ + uint32_t len = transfer->length - ((transfer->qtd.token >> 16) & 0x7FFF); + print("rx: "); + print_hexbytes(transfer->buffer, len); + + // first update rxstate bitmask + if (transfer->buffer == rx1) { + rxstate &= 0xFE; + } else if (transfer->buffer == rx2) { + rxstate &= 0xFD; + } + // get start of data and actual length + const uint8_t *p = (const uint8_t *)transfer->buffer; + if (ignore_first_two_bytes) { + if (len >= 2) { + p += 2; + len -= 2; + } else { + len = 0; + } + } + // copy data from packet buffer to circular buffer + if (len > 0) { + // TODO: copy to buffer + } + // re-queue packet buffer(s) if possible + uint32_t avail; + uint32_t head = rxhead; + uint32_t tail = rxtail; + if (head >= tail) { + avail = rxsize - 1 + (tail - head); + } else { + avail = (tail - head) - 1; + } + uint32_t packetsize = rx2 - rx1; + if (avail >= packetsize) { + if ((rxstate & 0x01) == 0) { + queue_Data_Transfer(rxpipe, rx1, packetsize, this); + rxstate |= 0x01; + } else if ((rxstate & 0x02) == 0) { + queue_Data_Transfer(rxpipe, rx2, packetsize, this); + rxstate |= 0x02; + } + if ((rxstate & 0x03) != 0x03 && avail >= packetsize * 2) { + if ((rxstate & 0x01) == 0) { + queue_Data_Transfer(rxpipe, rx1, packetsize, this); + rxstate |= 0x01; + } else if ((rxstate & 0x02) == 0) { + queue_Data_Transfer(rxpipe, rx2, packetsize, this); + rxstate |= 0x02; + } + } + } +} + +void USBSerial::tx_data(const Transfer_t *transfer) +{ + println("tx: "); +} + + + + + + + +void USBSerial::begin(uint32_t baud, uint32_t format) +{ +} + +void USBSerial::end(void) +{ +} + +int USBSerial::available(void) +{ + return 0; +} + +int USBSerial::peek(void) +{ + return -1; +} + +int USBSerial::read(void) +{ + return -1; +} + +size_t USBSerial::write(uint8_t c) +{ + return 1; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +void USBSerial::disconnect() +{ +} + +