From e2eba5c00da1be972f7b179974f4002af872a4b6 Mon Sep 17 00:00:00 2001 From: Kurt Eckhardt Date: Wed, 1 Nov 2017 16:41:54 -0700 Subject: [PATCH] This commit has a few different parts. It is still a WIP This commit adds support for at least some of the Serial boards with the CH341 chipset, tested using a board from sparkfun as well as one from Amazon.com The code was rearranged some of the Claim code and added a VID:DID to Serial Type table that I use to map, such that I know some of these devices have multiple valid setups. Support Begin/End/Begin - Change baud Added code to support switching baud rates, or more particular be able to call end() and then call begin(...) with same or different baud rate. Hopefully some support for also releasing DTR when the end is called. WIP - Start support for the begin(baud, format) Adding some support to the code to handle some of the different possible format capabilities. In particualar trying to handle the parity, number of bits and number of stop bits. hacked up test app, such that if you type in command line like: "#9600, 7e1" It will extract the 9600 as the new baud and try to use format 7e1. I only hard coded a few of these in the test app (8n1, 7e1, 7e2, 8n2)... Again work in progress. Took me awhile tofigure out how to do this for ch341 boards as I did not see any documents or code that handled this. So had to deduce it from differences in USB packets. --- USBHost_t36.h | 38 +- examples/SerialTest/SerialTest.ino | 83 ++++- serial.cpp | 572 ++++++++++++++++++++++------- 3 files changed, 545 insertions(+), 148 deletions(-) diff --git a/USBHost_t36.h b/USBHost_t36.h index 90355a9..e96ea87 100644 --- a/USBHost_t36.h +++ b/USBHost_t36.h @@ -56,7 +56,7 @@ // your best effort to read chapter 4 before asking USB questions! -//#define USBHOST_PRINT_DEBUG +#define USBHOST_PRINT_DEBUG /************************************************/ /* Data Types */ @@ -91,6 +91,7 @@ class USBDriverTimer; /************************************************/ /* Added Defines */ /************************************************/ +// Keyboard special Keys #define KEYD_UP 0xDA #define KEYD_DOWN 0xD9 #define KEYD_LEFT 0xD8 @@ -114,6 +115,22 @@ class USBDriverTimer; #define KEYD_F11 0xCC #define KEYD_F12 0xCD + +// USBSerial formats - Lets encode format into bits +// Bits: 0-4 - Number of data bits +// Bits: 5-7 - Parity (0=none, 1=odd, 2 = even) +// bits: 8-9 - Stop bits. 0=1, 1=2 + + +#define USBHOST_SERIAL_7E1 0x027 +#define USBHOST_SERIAL_7O1 0x047 +#define USBHOST_SERIAL_8N1 0x08 +#define USBHOST_SERIAL_8N2 0x108 +#define USBHOST_SERIAL_8E1 0x028 +#define USBHOST_SERIAL_8O1 0x048 + + + /************************************************/ /* Data Structure Definitions */ /************************************************/ @@ -889,11 +906,13 @@ private: //-------------------------------------------------------------------------- class USBSerial: public USBDriver, public Stream { -public: + public: + + // FIXME: need different USBSerial, with bigger buffers for 480 Mbit & faster speed enum { BUFFER_SIZE = 648 }; // must hold at least 6 max size packets, plus 2 extra bytes USBSerial(USBHost &host) : txtimer(this) { init(); } - void begin(uint32_t baud, uint32_t format=0); + void begin(uint32_t baud, uint32_t format=USBHOST_SERIAL_8N1); void end(void); virtual int available(void); virtual int peek(void); @@ -916,6 +935,7 @@ private: void init(); static bool check_rxtx_ep(uint32_t &rxep, uint32_t &txep); bool init_buffers(uint32_t rsize, uint32_t tsize); + void ch341_setBaud(uint8_t byte_index); private: Pipe_t mypipes[3] __attribute__ ((aligned(32))); Transfer_t mytransfers[7] __attribute__ ((aligned(32))); @@ -925,6 +945,7 @@ private: setup_t setup; uint8_t setupdata[8]; uint32_t baudrate; + uint32_t format_; Pipe_t *rxpipe; Pipe_t *txpipe; uint8_t *rx1; // location for first incoming packet @@ -947,7 +968,16 @@ private: uint8_t pl2303_v2; uint8_t interface; bool control_queued; - enum { CDCACM, FTDI, PL2303, CH341 } sertype; + typedef enum { UNKNOWN=0, CDCACM, FTDI, PL2303, CH341 } sertype_t; + sertype_t sertype; + + typedef struct { + uint16_t idVendor; + uint16_t idProduct; + sertype_t sertype; + } product_vendor_mapping_t; + static product_vendor_mapping_t pid_vid_mapping[]; + }; //-------------------------------------------------------------------------- diff --git a/examples/SerialTest/SerialTest.ino b/examples/SerialTest/SerialTest.ino index b745e1f..0928ae2 100644 --- a/examples/SerialTest/SerialTest.ino +++ b/examples/SerialTest/SerialTest.ino @@ -4,6 +4,8 @@ #include "USBHost_t36.h" #define USBBAUD 115200 +uint32_t baud = USBBAUD; +uint32_t format = USBHOST_SERIAL_8N1; USBHost myusb; USBHub hub1(myusb); USBHub hub2(myusb); @@ -60,23 +62,8 @@ void loop() // If this is a new Serial device. if (drivers[i] == &userial) { // Lets try first outputting something to our USerial to see if it will go out... - userial.begin(USBBAUD); + userial.begin(baud); -// delay(5); -// userial.println("ver"); -#if 0 - userial.println("abcdefghijklmnopqrstuvwxyz"); - userial.println("ABCDEFGHIJKLMNOPQURSTUVWYZ"); - userial.flush(); // force it out now. - userial.println("0123456789"); - userial.flush(); - delay(2); - userial.println("abcdefghijklmnopqrstuvwxyz"); - userial.println("ABCDEFGHIJKLMNOPQURSTUVWYZ"); - delay(2); - userial.println("!@#$%^&*()"); - userial.flush(); -#endif } } } @@ -89,8 +76,55 @@ void loop() if (ch == '$') { BioloidTest(); while (Serial.read() != -1); + } else if (ch == '#') { + // Lets see if we have a baud rate specified here... + uint32_t new_baud = 0; + for(;;) { + ch = Serial.read(); + if ((ch < '0') || (ch > '9')) + break; + new_baud = new_baud*10 + ch - '0'; + } + // See if the user is specifying a format: 8n1, 7e1, 7e2, 8n2 + // Note this is Quick and very dirty code... + // + if (ch == ',') { + char command_line[10]; + ch = Serial.read(); + while (ch == ' ') Serial.read(); // ignore any spaces. + uint8_t cb = 0; + while ((ch > ' ') && (cb < sizeof(command_line))) { + command_line[cb++] = ch; + ch = Serial.read(); + } + command_line[cb] = '\0'; + if (CompareStrings(command_line, "8N1")) format = USBHOST_SERIAL_8N1; + else if (CompareStrings(command_line, "8N2")) format = USBHOST_SERIAL_8N2; + else if (CompareStrings(command_line, "7E1")) format = USBHOST_SERIAL_7E1; + else if (CompareStrings(command_line, "7O1")) format = USBHOST_SERIAL_7O1; + } + Serial.println("\n*** Set new Baud command ***\n do userial.end()"); + digitalWriteFast(2, HIGH); + userial.end(); // Do the end statement; + digitalWriteFast(2, LOW); + if (new_baud) { + baud = new_baud; + Serial.print(" New Baud: "); + Serial.println(baud); + Serial.print(" Format: "); + Serial.println(format); + digitalWriteFast(3, HIGH); + userial.begin(baud, format); + digitalWriteFast(3, LOW); + Serial.println(" Completed "); + } else { + Serial.println(" New Baud 0 - leave disabled"); + } + + while (Serial.read() != -1); + } else { + userial.write(ch); } - else userial.write(ch); } } @@ -106,14 +140,25 @@ void loop() } } +bool CompareStrings(const char *sz1, const char *sz2) { + while (*sz2 != 0) { + if (toupper(*sz1) != toupper(*sz2)) + return false; + sz1++; + sz2++; + } + return true; // end of string so show as match + + +} + //#define ID_MASTER 200 #define ID_MASTER 0xfd // Extract stuff from Bioloid library.. #define AX12_BUFFER_SIZE 128 #define COUNTER_TIMEOUT 12000 -/** Instruction Set **/ -#define AX_PING 1 +/** Instruction Set **/ #define AX_PING 1 #define AX_READ_DATA 2 #define AX_WRITE_DATA 3 #define AX_REG_WRITE 4 diff --git a/serial.cpp b/serial.cpp index ffd7893..8e7189a 100644 --- a/serial.cpp +++ b/serial.cpp @@ -19,6 +19,8 @@ * 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. + * + * Note: special thanks to the Linux kernel for the CH341's method of operation, particularly how the baud rate is encoded. */ #include @@ -28,14 +30,21 @@ #define println USBHost::println_ /************************************************************/ -// Control Transfer For Configuration +// Define mapping VID/PID - to Serial Device type. /************************************************************/ -typedef struct { - uint32_t dwDTERate; // Data Terminal Rate in bits per second - uint8_t bCharFormat; // 0 - 1 stop bit, 1 - 1.5 stop bits, 2 - 2 stop bits - uint8_t bParityType; // 0 - None, 1 - Odd, 2 - Even, 3 - Mark, 4 - Space - uint8_t bDataBits; // Data bits (5, 6, 7, 8 or 16) -} LINE_CODING; +USBSerial::product_vendor_mapping_t USBSerial::pid_vid_mapping[] = { + // FTDI mappings. + {0x0403, 0x6001, USBSerial::FTDI}, + + // PL2303 + {0x67B,0x2303, USBSerial::PL2303}, + + // CH341 + {0x4348, 0x5523, USBSerial::CH341 }, + {0x1a86, 0x7523, USBSerial::CH341 }, + {0x1a86, 0x5523, USBSerial::CH341 } +}; + /************************************************************/ // Initialization and claiming of devices & interfaces @@ -47,6 +56,7 @@ void USBSerial::init() contribute_Transfers(mytransfers, sizeof(mytransfers)/sizeof(Transfer_t)); contribute_String_Buffers(mystring_bufs, sizeof(mystring_bufs)/sizeof(strbuf_t)); driver_ready_for_device(this); + format_ = USBHOST_SERIAL_8N1; } bool USBSerial::claim(Device_t *dev, int type, const uint8_t *descriptors, uint32_t len) @@ -60,51 +70,9 @@ bool USBSerial::claim(Device_t *dev, int type, const uint8_t *descriptors, uint3 println(", bDeviceProtocol = ", dev->bDeviceProtocol); print_hexbytes(descriptors, len); 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; - } - sertype = FTDI; - 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; - } - txstate = 0; - txpipe->callback_function = tx_callback; - baudrate = 115200; - pending_control = 0x0F; - mk_setup(setup, 0x40, 0, 0, 0, 0); // reset port - queue_Control_Transfer(dev, &setup, NULL, this); - control_queued = true; - return true; - } else if ((dev->bDeviceClass == 2) && (dev->bDeviceSubClass == 0)) { + //--------------------------------------------------------------------- + // CDCACM + if ((dev->bDeviceClass == 2) && (dev->bDeviceSubClass == 0)) { // It is a communication device see if we can extract the data... // Try some ttyACM types? // This code may be similar to MIDI code. @@ -226,72 +194,196 @@ bool USBSerial::claim(Device_t *dev, int type, const uint8_t *descriptors, uint3 return true; } - // TODO: Note: there are probably more vendor/product pairs.. Maybe should create table of them - if (dev->idVendor == 0x67B && dev->idProduct == 0x2303) { - // Prolific Technology, Inc. PL2303 Serial Port - println("len = ", len); - uint8_t count_end_points = descriptors[4]; - if (count_end_points < 2) return false; // not enough end points - if (len < 23) return false; - if (descriptors[0] != 9) return false; // length 9 - - // Lets walk through end points and see if we - // can find an RX and TX bulk transfer end point. - //vid=67B, pid=2303 - // 0 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 20 1 2 3 4 5 6 7 8 9 - //09 04 00 00 03 FF 00 00 00 07 05 81 03 0A 00 01 07 05 02 02 40 00 00 07 05 83 02 40 00 00 - uint32_t rxep = 0; - uint32_t txep = 0; - uint32_t descriptor_index = 9; - while (count_end_points-- && ((rxep == 0) || txep == 0)) { - if (descriptors[descriptor_index] != 7) return false; // length 7 - if (descriptors[descriptor_index+1] != 5) return false; // ep desc - if ((descriptors[descriptor_index+3] == 2) - && (descriptors[descriptor_index+4] == 64) - && (descriptors[descriptor_index+5] == 0)) { - // have a bulk EP size - if (descriptors[descriptor_index+2] & 0x80 ) { - rxep = descriptors[descriptor_index+2]; - } else { - txep = descriptors[descriptor_index+2]; - } + // See if the vendor_id:product_id is in our list of products. + sertype = UNKNOWN; + for (uint8_t i = 0; i < (sizeof(pid_vid_mapping)/sizeof(pid_vid_mapping[0])); i++) { + if ((dev->idVendor == pid_vid_mapping[i].idVendor) && (dev->idProduct == pid_vid_mapping[i].idProduct)) { + sertype = pid_vid_mapping[i].sertype; + break; + } + } + switch (sertype) { + //--------------------------------------------------------------------- + // FTDI + case FTDI: + { + // 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; } - descriptor_index += 7; // setup to look at next one... - } - // Try to verify the end points. - 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; + sertype = FTDI; + rxpipe->callback_function = rx_callback; + rxsize = 64; + queue_Data_Transfer(rxpipe, rx1, 64, this); + rxstate = 1; + txsize = 64; + txstate = 0; + txpipe->callback_function = tx_callback; + baudrate = 115200; + pending_control = 0x0F; + mk_setup(setup, 0x40, 0, 0, 0, 0); // reset port + queue_Control_Transfer(dev, &setup, NULL, this); + control_queued = true; + return true; } + //------------------------------------------------------------------------ + // Prolific + // TODO: Note: there are probably more vendor/product pairs.. Maybe should create table of them + case PL2303: + { + // Prolific Technology, Inc. PL2303 Serial Port + println("len = ", len); + uint8_t count_end_points = descriptors[4]; + if (count_end_points < 2) return false; // not enough end points + if (len < 23) return false; + if (descriptors[0] != 9) return false; // length 9 - sertype = PL2303; - 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; - } - txstate = 0; - txpipe->callback_function = tx_callback; - baudrate = 115200; + // Lets walk through end points and see if we + // can find an RX and TX bulk transfer end point. + //vid=67B, pid=2303 + // 0 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 20 1 2 3 4 5 6 7 8 9 + //09 04 00 00 03 FF 00 00 00 07 05 81 03 0A 00 01 07 05 02 02 40 00 00 07 05 83 02 40 00 00 + uint32_t rxep = 0; + uint32_t txep = 0; + uint32_t descriptor_index = 9; + while (count_end_points-- && ((rxep == 0) || txep == 0)) { + if (descriptors[descriptor_index] != 7) return false; // length 7 + if (descriptors[descriptor_index+1] != 5) return false; // ep desc + if ((descriptors[descriptor_index+3] == 2) + && (descriptors[descriptor_index+4] == 64) + && (descriptors[descriptor_index+5] == 0)) { + // have a bulk EP size + if (descriptors[descriptor_index+2] & 0x80 ) { + rxep = descriptors[descriptor_index+2]; + rxsize = descriptors[descriptor_index+4]; + } else { + txep = descriptors[descriptor_index+2]; + txsize = descriptors[descriptor_index+4]; + } + } + descriptor_index += 7; // setup to look at next one... + } + // Try to verify the end points. + if (!check_rxtx_ep(rxep, txep)) return false; + print("PL2303, 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; + } - // Lets see if it will handle the same CDCACM - messages? - println("PL2303: readRegister(0x04)"); - // Need to setup the data the line coding data - mk_setup(setup, 0xC0, 0x1, 0x8484, 0, 1); - queue_Control_Transfer(dev, &setup, setupdata, this); - control_queued = true; - setup_state = 1; // We are at step one of setup... - pending_control = 0x3f; // Maybe don't need to do... - return true; + sertype = PL2303; + rxpipe->callback_function = rx_callback; + queue_Data_Transfer(rxpipe, rx1, 64, this); + rxstate = 1; + txstate = 0; + txpipe->callback_function = tx_callback; + baudrate = 115200; + + println("PL2303: readRegister(0x04)"); + // Need to setup the data the line coding data + mk_setup(setup, 0xC0, 0x1, 0x8484, 0, 1); + queue_Control_Transfer(dev, &setup, setupdata, this); + control_queued = true; + setup_state = 1; // We are at step one of setup... + pending_control = 0x3f; + return true; + } + //------------------------------------------------------------------------ + // CH341 + case CH341: + { + println("len = ", len); + uint8_t count_end_points = descriptors[4]; + if (count_end_points < 2) return false; // not enough end points + if (len < 23) return false; + if (descriptors[0] != 9) return false; // length 9 + + // Lets walk through end points and see if we + // can find an RX and TX bulk transfer end point. + // vid=1A86, pid=7523, bDeviceClass = 255, bDeviceSubClass = 0, bDeviceProtocol = 0 + // 0 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 20 1 2 3 4 5 6 7 8 9 + //09 04 00 00 03 FF 01 02 00 07 05 82 02 20 00 00 07 05 02 02 20 00 00 07 05 81 03 08 00 01 + uint32_t rxep = 0; + uint32_t txep = 0; + uint32_t descriptor_index = 9; + while (count_end_points-- && ((rxep == 0) || txep == 0)) { + if (descriptors[descriptor_index] != 7) return false; // length 7 + if (descriptors[descriptor_index+1] != 5) return false; // ep desc + if ((descriptors[descriptor_index+3] == 2) + && (descriptors[descriptor_index+4] <= 64) + && (descriptors[descriptor_index+5] == 0)) { + // have a bulk EP size + if (descriptors[descriptor_index+2] & 0x80 ) { + rxep = descriptors[descriptor_index+2]; + rxsize = descriptors[descriptor_index+4]; + } else { + txep = descriptors[descriptor_index+2]; + txsize = descriptors[descriptor_index+4]; + } + } + descriptor_index += 7; // setup to look at next one... + } + // Try to verify the end points. + if (!check_rxtx_ep(rxep, txep)) return false; + print("ch341, rxep=", rxep & 15); + println(", txep=", txep); + if (!init_buffers(rxsize, txsize)) return false; + rxpipe = new_Pipe(dev, 2, rxep & 15, 1, rxsize); + if (!rxpipe) return false; + txpipe = new_Pipe(dev, 2, txep, 0, txsize); + if (!txpipe) { + // TODO: free rxpipe + return false; + } + + rxpipe->callback_function = rx_callback; + queue_Data_Transfer(rxpipe, rx1, rxsize, this); + rxstate = 1; + txstate = 0; + txpipe->callback_function = tx_callback; + baudrate = 115200; + + println("CH341: 0xC0, 0x5f, 0, 0, 8"); + // Need to setup the data the line coding data + mk_setup(setup, 0xC0, 0x5f, 0, 0, sizeof(setupdata)); + queue_Control_Transfer(dev, &setup, setupdata, this); + control_queued = true; + setup_state = 1; // We are at step one of setup... + pending_control = 0x7f; + return true; + } + //------------------------------------------------------------------------ + // PID:VID - not in our product list. + default: + return false; } } else if (type != 1) return false; // TTYACM: @@ -424,7 +516,15 @@ void USBSerial::control(const Transfer_t *transfer) if (pending_control & 1) { pending_control &= ~1; // set data format - mk_setup(setup, 0x40, 4, 8, 0, 0); // data format 8N1 + uint16_t ftdi_format = format_ & 0xf; // This should give us the number of bits. + + // now lets extract the parity from our encoding + ftdi_format |= (format_ & 0xe0) << 3; // they encode bits 9-11 + + // See if two stop bits + if (format_ & 0x100) ftdi_format |= (0x2 << 11); + + mk_setup(setup, 0x40, 4, ftdi_format, 0, 0); // data format 8N1 queue_Control_Transfer(device, &setup, NULL, this); control_queued = true; return; @@ -454,6 +554,15 @@ void USBSerial::control(const Transfer_t *transfer) control_queued = true; return; } + // clear DTR + if (pending_control & 0x80) { + pending_control &= ~0x80; + println("FTDI clear DTR"); + mk_setup(setup, 0x40, 1, 0x0100, 0, 0); + queue_Control_Transfer(device, &setup, NULL, this); + control_queued = true; + return; + } } @@ -467,9 +576,9 @@ void USBSerial::control(const Transfer_t *transfer) setupdata[1] = (baudrate >> 8) & 0xff; setupdata[2] = (baudrate >> 16) & 0xff; setupdata[3] = (baudrate >> 24) & 0xff; - setupdata[4] = 0; // 0 - 1 stop bit, 1 - 1.5 stop bits, 2 - 2 stop bits - setupdata[5] = 0; // 0 - None, 1 - Odd, 2 - Even, 3 - Mark, 4 - Space - setupdata[6] = 8; // Data bits (5, 6, 7, 8 or 16) + setupdata[4] = (format_ & 0x100)? 2 : 0; // 0 - 1 stop bit, 1 - 1.5 stop bits, 2 - 2 stop bits + setupdata[5] = (format_ & 0xe0) >> 5; // 0 - None, 1 - Odd, 2 - Even, 3 - Mark, 4 - Space + setupdata[6] = format_ & 0x1f; // Data bits (5, 6, 7, 8 or 16) print("CDCACM setup: "); print_hexbytes(&setupdata, 7); mk_setup(setup, 0x21, 0x20, 0, 0, 7); @@ -487,6 +596,15 @@ void USBSerial::control(const Transfer_t *transfer) control_queued = true; return; } + if (pending_control & 0x80) { + pending_control &= ~0x80; + println("Control - 0x21,0x22, 0x0 - clear DTR"); + // Need to setup the data the line coding data + mk_setup(setup, 0x21, 0x22, 0, 0, 0); + queue_Control_Transfer(device, &setup, NULL, this); + control_queued = true; + return; + } } //------------------------------------------------------------------------- @@ -607,9 +725,9 @@ void USBSerial::control(const Transfer_t *transfer) setupdata[1] = (baudrate >> 8) & 0xff; setupdata[2] = (baudrate >> 16) & 0xff; setupdata[3] = (baudrate >> 24) & 0xff; - setupdata[4] = 0; // 0 - 1 stop bit, 1 - 1.5 stop bits, 2 - 2 stop bits - setupdata[5] = 0; // 0 - None, 1 - Odd, 2 - Even, 3 - Mark, 4 - Space - setupdata[6] = 8; // Data bits (5, 6, 7, 8 or 16) + setupdata[4] = (format_ & 0x100)? 2 : 0; // 0 - 1 stop bit, 1 - 1.5 stop bits, 2 - 2 stop bits + setupdata[5] = (format_ & 0xe0) >> 5; // 0 - None, 1 - Odd, 2 - Even, 3 - Mark, 4 - Space + setupdata[6] = format_ & 0x1f; // Data bits (5, 6, 7, 8 or 16) print("PL2303: Set baud/control: ", baudrate, HEX); print(" = "); print_hexbytes(&setupdata, 7); @@ -639,20 +757,198 @@ void USBSerial::control(const Transfer_t *transfer) print("PL2303: Returned configuration data: "); print_hexbytes(setupdata, 7); + // This sets the control lines (0x1=DTR, 0x2=RTS) println("PL2303: 0x21, 0x22, 0x3"); mk_setup(setup, 0x21, 0x22, 3, 0, 0); // queue_Control_Transfer(device, &setup, NULL, this); control_queued = true; return; } - if (pending_control & 0x30) { - pending_control &= ~0x30; + if (pending_control & 0x20) { + pending_control &= ~0x20; println("PL2303: 0x21, 0x22, 0x3"); mk_setup(setup, 0x21, 0x22, 3, 0, 0); // queue_Control_Transfer(device, &setup, NULL, this); control_queued = true; } + if (pending_control & 0x80) { + pending_control &= ~0x80; + println("PL2303: 0x21, 0x22, 0x0"); // Clear DTR/RTS + mk_setup(setup, 0x21, 0x22, 0, 0, 0); // + queue_Control_Transfer(device, &setup, NULL, this); + control_queued = true; + } } + + if (sertype == CH341) { +#if 0 + print(" Transfer: "); + print_hexbytes(&transfer->setup, sizeof(setup_t)); + if (transfer->length) { + print(" data: "); + print_hexbytes(transfer->buffer, transfer->length); + } +#endif + if (pending_control & 1) { + // Still in larger setup state mode + switch (setup_state) { + case 1: + print(" Returned: "); + print_hexbytes(transfer->buffer, transfer->length); + println("CH341: 40, a1, 0, 0, 0"); + mk_setup(setup, 0x40, 0xa1, 0, 0, 0); // + queue_Control_Transfer(device, &setup, NULL, this); + setup_state = 2; + control_queued = true; + return; + case 2: + ch341_setBaud(0); // send the first byte of the baud rate + control_queued = true; + setup_state = 3; + return; + case 3: + ch341_setBaud(1); // send the second byte of the baud rate + control_queued = true; + setup_state = 4; + return; + case 4: + println("CH341: c0, 95, 2518, 0, 8"); + mk_setup(setup, 0xc0, 0x95, 0x2518, 0, sizeof(setup)); // + queue_Control_Transfer(device, &setup, setupdata, this); + setup_state = 5; + control_queued = true; + return; + case 5: + print(" Returned: "); + print_hexbytes(transfer->buffer, transfer->length); + println("CH341: 40, 0x9a, 0x2518, 0x0050, 0"); + mk_setup(setup, 0x40, 0x9a, 0x2518, 0x0050, 0); // + queue_Control_Transfer(device, &setup, NULL, this); + setup_state = 6; + control_queued = true; + return; + case 6: + println("CH341: c0, 95, 0x706, 0, 8 - get status"); + mk_setup(setup, 0xc0, 0x95, 0x706, 0, sizeof(setup)); // + queue_Control_Transfer(device, &setup, setupdata, this); + setup_state = 7; + control_queued = true; + return; + case 7: + print(" Returned: "); + print_hexbytes(transfer->buffer, transfer->length); + println("CH341: 40, 0xa1, 0x501f, 0xd90a, 0"); + mk_setup(setup, 0x40, 0xa1, 0x501f, 0xd90a, 0); // + queue_Control_Transfer(device, &setup, NULL, this); + setup_state = 8; + control_queued = true; + break; + } + pending_control &= ~1; // We are finally going to leave this list and join the rest + if (control_queued) return; + } + // set baud rate + if (pending_control & 2) { + pending_control &= ~2; + ch341_setBaud(0); // send the first byte of the baud rate + control_queued = true; + return; + } + if (pending_control & 4) { + pending_control &= ~4; + ch341_setBaud(1); // send the first byte of the baud rate + control_queued = true; + return; + } + + if (pending_control & 8) { + pending_control &= ~8; + uint16_t ch341_format; + switch (format_) { + default: + // These values were observed when used on PC... Need to flush out others. + case USBHOST_SERIAL_8N1: ch341_format = 0xc3; break; + case USBHOST_SERIAL_7E1: ch341_format = 0xda; break; + case USBHOST_SERIAL_7O1: ch341_format = 0xca; break; + case USBHOST_SERIAL_8N2: ch341_format = 0xc7; break; + } + println("CH341: 40, 0x9a, 0x2518: ", ch341_format, HEX); + mk_setup(setup, 0x40, 0x9a, 0x2518, ch341_format, 0); // + queue_Control_Transfer(device, &setup, NULL, this); + control_queued = true; + return; + } + if (pending_control & 0x10) { + pending_control &= ~0x10; + // This is setting handshake need to figure out what... + // 0x20=DTR, 0x40=RTS send ~ of values. + println("CH341: 0x40, 0xa4, 0xff9f, 0, 0 - Handshake"); + mk_setup(setup, 0x40, 0xa4, 0xff9f, 0, 0); // + queue_Control_Transfer(device, &setup, NULL, this); + control_queued = true; + return; + } + if (pending_control & 0x20) { + pending_control &= ~0x20; + // This is setting handshake need to figure out what... + println("CH341: c0, 95, 0x706, 0, 8 - get status"); + mk_setup(setup, 0xc0, 0x95, 0x706, 0, sizeof(setup)); // + queue_Control_Transfer(device, &setup, setupdata, this); + control_queued = true; + return; + } + if (pending_control & 0x40) { + pending_control &= ~0x40; + print(" Returned: "); + print_hexbytes(transfer->buffer, transfer->length); + println("CH341: 0x40, 0x9a, 0x2727, 0, 0"); + mk_setup(setup, 0x40, 0x9a, 0x2727, 0, 0); // + queue_Control_Transfer(device, &setup, NULL, this); + + return; + } + + if (pending_control & 0x80) { + pending_control &= ~0x80; + println("CH341: 0x40, 0xa4, 0xffff, 0, 0 - Handshake"); + mk_setup(setup, 0x40, 0xa4, 0xffff, 0, 0); // + queue_Control_Transfer(device, &setup, NULL, this); + control_queued = true; + return; + } + } +} + +#define CH341_BAUDBASE_FACTOR 1532620800 +#define CH341_BAUDBASE_DIVMAX 3 +void USBSerial::ch341_setBaud(uint8_t byte_index) { + if (byte_index == 0) { + uint32_t factor; + uint16_t divisor; + + factor = (CH341_BAUDBASE_FACTOR / baudrate); + divisor = CH341_BAUDBASE_DIVMAX; + + while ((factor > 0xfff0) && divisor) { + factor >>= 3; + divisor--; + } + + factor = 0x10000 - factor; + + factor = (factor & 0xff00) | divisor; + setupdata[0] = factor & 0xff; // save away the low byte for 2nd message + + + println("CH341: 40, 0x9a, 0x1312... (Baud word 0):", factor, HEX); + mk_setup(setup, 0x40, 0x9a, 0x1312, factor, 0); // + } else { + // Second packet use the byte we saved away during the calculation above + println("CH341: 40, 0x9a, 0x0f2c... (Baud word 1):", setupdata[0], HEX); + mk_setup(setup, 0x40, 0x9a, 0x0f2c, setupdata[0], 0); // + } + queue_Control_Transfer(device, &setup, setupdata, this); + control_queued = true; } @@ -866,14 +1162,40 @@ void USBSerial::begin(uint32_t baud, uint32_t format) { NVIC_DISABLE_IRQ(IRQ_USBHS); baudrate = baud; - pending_control |= 2; + bool format_changed = format != format_; + format_ = format; + switch (sertype) { + default: + case CDCACM: pending_control |= 0x6; break; + case FTDI: pending_control |= (format_changed? 0xf : 0xe); break; // Set BAUD, FLOW, DTR + case PL2303: pending_control |= 0x1e; break; // set more stuff... + case CH341: pending_control |= 0x1e; break; + } if (!control_queued) control(NULL); NVIC_ENABLE_IRQ(IRQ_USBHS); + // Wait until all packets have been queued before we return to caller. + while (pending_control) { + yield(); // not sure if we want to yield or what? + } } void USBSerial::end(void) { - // TODO: lower DTR + NVIC_DISABLE_IRQ(IRQ_USBHS); + switch (sertype) { + default: + case CDCACM: pending_control |= 0x80; break; + case FTDI: pending_control |= 0x80; break; // clear DTR + case PL2303: pending_control |= 0x80; break; + case CH341: pending_control |= 0x80; break; + } + if (!control_queued) control(NULL); + NVIC_ENABLE_IRQ(IRQ_USBHS); + + // Wait until all packets have been queued before we return to caller. + while (pending_control) { + yield(); // not sure if we want to yield or what? + } } int USBSerial::available(void)