From 6e1f0c379c53bb8d9ad101bbd17773a33d3f0dc9 Mon Sep 17 00:00:00 2001 From: Kurt Eckhardt Date: Fri, 27 Oct 2017 09:35:46 -0700 Subject: [PATCH] CDCACM - Serial support Have some support in place for the CDCACM serial class code. It appears to be working for talking to a Teensy that is programmed USB=Serial or USB=Serial+... Also test with an USB2AX board which is a Servo controller for Dynamixel servos (AX-12), that is an Atmega32u2 board programmed using LUFA as the USB library. --- USBHost_t36.h | 2 + examples/SerialTest/SerialTest.ino | 267 +++++++++++++++++++++++ serial.cpp | 336 +++++++++++++++++++++++++++-- 3 files changed, 587 insertions(+), 18 deletions(-) create mode 100644 examples/SerialTest/SerialTest.ino diff --git a/USBHost_t36.h b/USBHost_t36.h index b0f21d9..f017ae4 100644 --- a/USBHost_t36.h +++ b/USBHost_t36.h @@ -900,6 +900,7 @@ public: virtual int read(void); virtual int availableForWrite(); virtual size_t write(uint8_t c); + using Print::write; protected: virtual bool claim(Device_t *device, int type, const uint8_t *descriptors, uint32_t len); @@ -941,6 +942,7 @@ private: volatile uint8_t rxstate;// bitmask: which receive packets are queued volatile uint8_t txstate; uint8_t pending_control; + uint8_t interface; bool control_queued; enum { CDCACM, FTDI, PL2303, CH341 } sertype; }; diff --git a/examples/SerialTest/SerialTest.ino b/examples/SerialTest/SerialTest.ino new file mode 100644 index 0000000..79639ea --- /dev/null +++ b/examples/SerialTest/SerialTest.ino @@ -0,0 +1,267 @@ +// Simple test of USB Host Mouse/Keyboard +// +// This example is in the public domain + +#include "USBHost_t36.h" + +USBHost myusb; +USBHub hub1(myusb); +USBHub hub2(myusb); +USBHIDParser hid1(myusb); +USBHIDParser hid2(myusb); +USBHIDParser hid3(myusb); +USBSerial userial(myusb); + +USBDriver *drivers[] = {&hub1, &hub2, &hid1, &hid2, &hid3, &userial}; +#define CNT_DEVICES (sizeof(drivers)/sizeof(drivers[0])) +const char * driver_names[CNT_DEVICES] = {"Hub1", "Hub2", "HID1", "HID2", "HID3", "USERIAL1" }; +bool driver_active[CNT_DEVICES] = {false, false, false, false}; + +void setup() +{ + pinMode(13, OUTPUT); + pinMode(2, OUTPUT); + pinMode(3, OUTPUT); + for (int i = 0; i < 5; i++) { + digitalWrite(2, HIGH); + delayMicroseconds(50); + digitalWrite(2, LOW); + delayMicroseconds(50); + } + while (!Serial && (millis() < 5000)) ; // wait for Arduino Serial Monitor + Serial.println("\n\nUSB Host Testing - Serial"); + myusb.begin(); + Serial1.begin(115200); // We will echo stuff Through Serial1... + +} + + +void loop() +{ + digitalWrite(13, !digitalRead(13)); + myusb.Task(); + // Print out information about different devices. + for (uint8_t i = 0; i < CNT_DEVICES; i++) { + if (*drivers[i] != driver_active[i]) { + if (driver_active[i]) { + Serial.printf("*** Device %s - disconnected ***\n", driver_names[i]); + driver_active[i] = false; + } else { + Serial.printf("*** Device %s %x:%x - connected ***\n", driver_names[i], drivers[i]->idVendor(), drivers[i]->idProduct()); + driver_active[i] = true; + + const uint8_t *psz = drivers[i]->manufacturer(); + if (psz && *psz) Serial.printf(" manufacturer: %s\n", psz); + psz = drivers[i]->product(); + if (psz && *psz) Serial.printf(" product: %s\n", psz); + psz = drivers[i]->serialNumber(); + if (psz && *psz) Serial.printf(" Serial: %s\n", psz); + + // 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(1000000); +#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 + } + } + } + } + + while (Serial.available()) { + Serial.println("Serial Available"); + int ch = Serial.read(); + if (ch == '$') { + BioloidTest(); + while (Serial.read() != -1); + } + else userial.write(ch); + } + + while (Serial1.available()) { +// Serial.println("Serial1 Available"); + Serial1.write(Serial1.read()); + } + + while (userial.available()) { +// Serial.println("USerial Available"); + + Serial.write(userial.read()); + } +} + +//#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 +#define AX_READ_DATA 2 +#define AX_WRITE_DATA 3 +#define AX_REG_WRITE 4 +#define AX_ACTION 5 +#define AX_RESET 6 +#define AX_SYNC_WRITE 131 + +#define AX_TORQUE_ENABLE 24 +#define AX_LED 25 +#define AX_CW_COMPLIANCE_MARGIN 26 +#define AX_CCW_COMPLIANCE_MARGIN 27 +#define AX_CW_COMPLIANCE_SLOPE 28 +#define AX_CCW_COMPLIANCE_SLOPE 29 +#define AX_GOAL_POSITION_L 30 +#define AX_GOAL_POSITION_H 31 +#define AX_GOAL_SPEED_L 32 +#define AX_GOAL_SPEED_H 33 +#define AX_TORQUE_LIMIT_L 34 +#define AX_TORQUE_LIMIT_H 35 +#define AX_PRESENT_POSITION_L 36 +#define AX_PRESENT_POSITION_H 37 + + +void BioloidTest() { + uint8_t master_id = 200; + Serial.println("\n*** Bioloid Test ***"); + if (ax12GetRegister(master_id, 0, 1) != -1) { + Serial.println("Controller found at 200"); + } else { + Serial.println("Controller not at 200 try 0xfd"); + master_id = 0xfd; + if (ax12GetRegister(master_id, 0, 1) != -1) { + Serial.println("Controller found at 0xfd"); + } else { + Serial.println("Controller not found"); + } + } + for (uint8_t reg = 0; reg < 10; reg++) { + myusb.Task(); + + Serial.print(ax12GetRegister(master_id, reg, 1), HEX); + Serial.print(" "); + } + Serial.println(); + // Now assuming we found controller... + // May need to turn on power on controller + ax12SetRegister(master_id, AX_TORQUE_ENABLE, 1); + delay(2); + + // Lets see if we can get the current position for any servo + for (int i = 0; i < 254; i++) { + int servo_pos = ax12GetRegister(i, AX_PRESENT_POSITION_L, 2); + if (servo_pos != -1) { + Serial.printf("Servo: %d Pos: %d\n", i, servo_pos); + } + } + +} + + + +unsigned char ax_rx_buffer[AX12_BUFFER_SIZE]; +int ax12GetRegister(int id, int regstart, int length) { + // 0xFF 0xFF ID LENGTH INSTRUCTION PARAM... CHECKSUM + int return_value; + digitalWriteFast(2, HIGH); + int checksum = ~((id + 6 + regstart + length) % 256); + userial.write(0xFF); + userial.write(0xFF); + userial.write(id); + userial.write(4); // length + userial.write(AX_READ_DATA); + userial.write(regstart); + userial.write(length); + userial.write(checksum); + userial.flush(); // make sure the data goes out. + + if (ax12ReadPacket(length + 6) > 0) { + // ax12Error = ax_rx_buffer[4]; + if (length == 1) + return_value = ax_rx_buffer[5]; + else + return_value = ax_rx_buffer[5] + (ax_rx_buffer[6] << 8); + } else { + digitalWriteFast(3, !digitalReadFast(3)); + return_value = -1; + } + digitalWriteFast(2, LOW); + return return_value; + +} + +void ax12SetRegister(int id, int regstart, int data){ + int checksum = ~((id + 4 + AX_WRITE_DATA + regstart + (data&0xff)) % 256); + userial.write(0xFF); + userial.write(0xFF); + userial.write(id); + userial.write(4); // length + userial.write(AX_WRITE_DATA); + userial.write(regstart); + userial.write(data&0xff); + // checksum = + userial.write(checksum); + userial.flush(); + //ax12ReadPacket(); +} + + + +int ax12ReadPacket(int length) { + unsigned long ulCounter; + unsigned char offset, checksum; + unsigned char *psz; + unsigned char *pszEnd; + int ch; + + + offset = 0; + + psz = ax_rx_buffer; + pszEnd = &ax_rx_buffer[length]; + + while (userial.read() != -1) ; + uint32_t ulStart = millis(); + // Need to wait for a character or a timeout... + do { + ulCounter = COUNTER_TIMEOUT; + while ((ch = userial.read()) == -1) { + if ((millis() - ulStart) > 10) { + //if (!--ulCounter) { + // Serial.println("Timeout"); + return 0; // Timeout + } + } + } while (ch != 0xff) ; + *psz++ = 0xff; + while (psz != pszEnd) { + ulCounter = COUNTER_TIMEOUT; + while ((ch = userial.read()) == -1) { + //Serial.printf("Read ch: %x\n", ch); + if (!--ulCounter) { + return 0; // Timeout + } + } + *psz++ = (unsigned char)ch; + } + checksum = 0; + for (offset = 2; offset < length; offset++) + checksum += ax_rx_buffer[offset]; + if (checksum != 255) { + return 0; + } else { + return 1; + } +} + diff --git a/serial.cpp b/serial.cpp index e6a8989..7af7b84 100644 --- a/serial.cpp +++ b/serial.cpp @@ -27,6 +27,16 @@ #define print USBHost::print_ #define println USBHost::println_ +/************************************************************/ +// Control Transfer For Configuration +/************************************************************/ +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; + /************************************************************/ // Initialization and claiming of devices & interfaces /************************************************************/ @@ -44,7 +54,11 @@ bool USBSerial::claim(Device_t *dev, int type, const uint8_t *descriptors, uint3 // only claim at interface level println("USBSerial claim this=", (uint32_t)this, HEX); print("vid=", dev->idVendor, HEX); - println(", pid=", dev->idProduct, HEX); + print(", pid=", dev->idProduct, HEX); + print(", bDeviceClass = ", dev->bDeviceClass); + print(", bDeviceSubClass = ", dev->bDeviceSubClass); + println(", bDeviceProtocol = ", dev->bDeviceProtocol); + print_hexbytes(descriptors, len); if (type == 0) { if (dev->idVendor == 0x0403 && dev->idProduct == 0x6001) { // FTDI FT232 @@ -90,9 +104,266 @@ bool USBSerial::claim(Device_t *dev, int type, const uint8_t *descriptors, uint3 queue_Control_Transfer(dev, &setup, NULL, this); control_queued = true; return true; + } else 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. + // But first pass see if we can simply look at the interface... + // Lets walk through end points and see if we + // can find an RX and TX bulk transfer end point. + // 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*30 1 2 3 4 5 6 7 8 *9 40 1 2 3 4 5 *6 7 8 9 50 1 2 + // USB2AX + //09 04 00 00 01 02 02 01 00 05 24 00 10 01 04 24 02 06 05 24 06 00 01 07 05 82 03 08 00 FF 09 04 01 00 02 0A 00 00 00 07 05 04 02 10 00 01 07 05 83 02 10 00 01 + //09 04 01 00 02 0A 00 00 00 07 05 04 02 10 00 01 07 05 83 02 10 00 01 + // Teensy 3.6 + //09 04 00 00 01 02 02 01 00 05 24 00 10 01 05 24 01 01 01 04 24 02 06 05 24 06 00 01 07 05 82 03 10 00 40 09 04 01 00 02 0A 00 00 00 07 05 03 02 40 00 00 07 05 84 02 40 00 00 + //09 04 01 00 02 0A 00 00 00 07 05 03 02 40 00 00 07 05 84 02 40 00 00 + const uint8_t *p = descriptors; + const uint8_t *end = p + len; + + if (p[0] != 9 || p[1] != 4) return false; // interface descriptor + //println(" bInterfaceClass=", p[5]); + //println(" bInterfaceSubClass=", p[6]); + if (p[5] != 2) return false; // bInterfaceClass: 2 Communications + if (p[6] != 2) return false; // bInterfaceSubClass: 2 serial + p += 9; + println(" Interface is Serial"); + uint8_t rx_ep = 0; + uint8_t tx_ep = 0; + uint16_t rx_size = 0; + uint16_t tx_size = 0; + interface = 0; // clear out any interface numbers passed in. + + while (p < end) { + len = *p; + if (len < 4) return false; + if (p + len > end) return false; // reject if beyond end of data + uint32_t type = p[1]; + //println("type: ", type); + // Unlike Audio, we need to look at Interface as our endpoints are after them... + if (type == 4 ) { // Interface - lets remember it's number... + interface = p[2]; + println(" Interface: ", interface); + } + else if (type == 0x24) { // 0x24 = CS_INTERFACE, + uint32_t subtype = p[2]; + print(" CS_INTERFACE - subtype: ", subtype); + if (len >= 4) print(" ", p[3], HEX); + if (len >= 5) print(" ", p[4], HEX); + if (len >= 6) print(" ", p[5], HEX); + switch (subtype) { + case 0: println(" - Header Functional Descriptor"); break; + case 1: println(" - Call Management Functional"); break; + case 2: println(" - Abstract Control Management"); break; + case 4: println(" - Telephone Ringer"); break; + case 6: println(" - union Functional"); break; + default: println(" - ??? other"); break; + } + // First pass ignore... + } else if (type == 5) { + // endpoint descriptor + if (p[0] < 7) return false; // at least 7 bytes + if (p[3] == 2) { // First try ignore the first one which is interrupt... + println(" Endpoint: ", p[2], HEX); + switch (p[2] & 0xF0) { + case 0x80: + // IN endpoint + if (rx_ep == 0) { + rx_ep = p[2] & 0x0F; + rx_size = p[4] | (p[5] << 8); + println(" rx_size = ", rx_size); + } + break; + case 0x00: + // OUT endpoint + if (tx_ep == 0) { + tx_ep = p[2]; + tx_size = p[4] | (p[5] << 8); + println(" tx_size = ", tx_size); + } + break; + default: + println(" invalid end point: ", p[2]); + return false; + } + } + } else { + println(" Unknown type: ", type); + return false; // unknown + } + p += len; + } + print(" exited loop rx:", rx_ep); + println(", tx:", tx_ep); + if (!rx_ep || !tx_ep) return false; // did not get our two end points + if (!init_buffers(rx_size, tx_size)) return false; + rxpipe = new_Pipe(dev, 2, rx_ep & 15, 1, rx_size); + if (!rxpipe) return false; + txpipe = new_Pipe(dev, 2, tx_ep, 0, tx_size); + if (!txpipe) { + // TODO: free rxpipe + return false; + } + sertype = CDCACM; + rxpipe->callback_function = rx_callback; + queue_Data_Transfer(rxpipe, rx1, (rx_size < 64)? rx_size : 64, this); + rxstate = 1; + if (rx_size > 128) { + queue_Data_Transfer(rxpipe, rx2, rx_size, this); + rxstate = 3; + } + txstate = 0; + txpipe->callback_function = tx_callback; + baudrate = 115200; + // Wish I could just call Control to do the output... Maybe can defer until the user calls begin() + // control requires that device is setup which is not until this call completes... + println("Control - CDCACM DTR..."); + // Need to setup the data the line coding data + mk_setup(setup, 0x21, 0x22, 3, 0, 0); + queue_Control_Transfer(dev, &setup, NULL, this); + control_queued = true; + pending_control = 0x0; // Maybe don't need to do... + return true; } +#if 0 + 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; + uint16_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]; + } + } + 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 = 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; + 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; + } +#endif + } else if (type != 1) return false; +#if 1 + // Try some ttyACM types? + // This code may be similar to MIDI code. + // But first pass see if we can simply look at the interface... + // Lets walk through end points and see if we + // can find an RX and TX bulk transfer end point. + // 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*30 1 2 3 4 5 6 7 8 *9 40 1 2 3 4 5 *6 7 8 9 50 1 2 + // USB2AX + //09 04 00 00 01 02 02 01 00 05 24 00 10 01 04 24 02 06 05 24 06 00 01 07 05 82 03 08 00 FF + //09 04 01 00 02 0A 00 00 00 07 05 04 02 10 00 01 07 05 83 02 10 00 01 + // Teensy 3.6 + //09 04 00 00 01 02 02 01 00 05 24 00 10 01 05 24 01 01 01 04 24 02 06 05 24 06 00 01 07 05 82 03 10 00 40 + //09 04 01 00 02 0A 00 00 00 07 05 03 02 40 00 00 07 05 84 02 40 00 00 + if (descriptors[0] != 9 || descriptors[1] != 4) return false; // interface descriptor + if (descriptors[4] < 2) return false; // less than 2 end points + if (descriptors[5] != 0xA) return false; // bInterfaceClass, 0xa = CDC data + if (descriptors[6] != 0) return false; // bInterfaceSubClass + if (descriptors[7] != 0) return false; // bInterfaceProtocol, 1 = Keyboard + + if (descriptors[9] != 7) return false; // length 7 + if (descriptors[10] != 5) return false; // ep desc + uint32_t txep = descriptors[11]; + uint32_t txsize = descriptors[13]; + if (descriptors[12] != 2) return false; // bulk type + if (descriptors[13] > 64) return false; // size 64 Max + if (descriptors[14] != 0) return false; + + if (descriptors[16] != 7) return false; // length 7 + if (descriptors[17] != 5) return false; // ep desc + uint32_t rxep = descriptors[18]; + uint32_t rxsize = descriptors[20]; + if (descriptors[19] != 2) return false; // bulk type + if (descriptors[20] > 64) return false; // size 64 Max + if (descriptors[21] != 0) return false; + if (!check_rxtx_ep(rxep, txep)) return false; + interface = descriptors[2]; + + print("CDC, 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; } + sertype = CDCACM; + 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; + + // See if we can do just the inteface... + baudrate = 115200; + println("Control - CDCACM LINE_CODING"); + setupdata[0] = 0; // Setup baud rate 115200 - 0x1C200 + setupdata[1] = 0xc2; + setupdata[2] = 0x1; + setupdata[3] = 0; + 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) + mk_setup(setup, 0x21, 0x20, 0, 0, 7); + queue_Control_Transfer(dev, &setup, setupdata, this); + pending_control = 0x04; // Maybe don't need to do... + control_queued = true; + return true; +#else return false; +#endif } // check if two legal endpoints, 1 receive & 1 transmit @@ -115,7 +386,8 @@ bool USBSerial::check_rxtx_ep(uint32_t &rxep, uint32_t &txep) // 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 + // buffer must be able to hold 2 of each packet, plus buffer + // space to hold RX and TX data. if (sizeof(bigbuffer) < (rsize + tsize) * 3 + 2) return false; rx1 = (uint8_t *)bigbuffer; rx2 = rx1 + rsize; @@ -139,14 +411,10 @@ void USBSerial::disconnect() } -/************************************************************/ -// Control Transfer For Configuration -/************************************************************/ - void USBSerial::control(const Transfer_t *transfer) { - println("control callback (serial)"); + println("control callback (serial) ", pending_control, HEX); control_queued = false; // set data format @@ -160,18 +428,45 @@ void USBSerial::control(const Transfer_t *transfer) // set baud rate if (pending_control & 2) { pending_control &= ~2; - uint32_t baudval = 3000000 / baudrate; - mk_setup(setup, 0x40, 3, baudval, 0, 0); - queue_Control_Transfer(device, &setup, NULL, this); - control_queued = true; + if (sertype == FTDI) { + uint32_t baudval = 3000000 / baudrate; + mk_setup(setup, 0x40, 3, baudval, 0, 0); + queue_Control_Transfer(device, &setup, NULL, this); + control_queued = true; + + } else if (sertype == CDCACM) { + // Should probably use data structure, but that may depend on byte ordering... + setupdata[0] = (baudrate) & 0xff; // Setup baud rate 115200 - 0x1C200 + 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) + print("CDCACM setup: "); + print_hexbytes(&setupdata, 7); + mk_setup(setup, 0x21, 0x20, 0, 0, 7); + queue_Control_Transfer(device, &setup, setupdata, this); + control_queued = true; + } return; } // configure flow control if (pending_control & 4) { pending_control &= ~4; - mk_setup(setup, 0x40, 2, 0, 0, 0); - queue_Control_Transfer(device, &setup, NULL, this); - control_queued = true; + if (sertype == FTDI) { + mk_setup(setup, 0x40, 2, 0, 1, 0); + queue_Control_Transfer(device, &setup, NULL, this); + control_queued = true; + } else if (sertype == CDCACM) { + println("Control - CDCACM DTR..."); + // Need to setup the data the line coding data + mk_setup(setup, 0x21, 0x22, 1, interface, 0); + queue_Control_Transfer(device, &setup, NULL, this); + control_queued = true; + return; + } + return; } // set DTR @@ -221,10 +516,10 @@ void USBSerial::rx_data(const Transfer_t *transfer) len = 0; } } - //if (len > 0) { - //print("rx: "); - //print_hexbytes(p, len); - //} + if (len > 0) { + print("rx: "); + print_hexbytes(p, len); + } // Copy data from packet buffer to circular buffer. // Assume the buffer will always have space, since we // check before queuing the buffers @@ -340,6 +635,7 @@ void USBSerial::timer_event(USBDriverTimer *whichTimer) uint32_t head = txhead; uint32_t tail = txtail; if (head == tail) { + println(" *** Empty ***"); return; // nothing to transmit } else if (head > tail) { count = head - tail; @@ -355,6 +651,7 @@ void USBSerial::timer_event(USBDriverTimer *whichTimer) txstate |= 0x02; } else { txtimer.start(1200); + println(" *** No buffers ***"); return; // no outgoing buffers available, try again later } if (++tail >= txsize) tail = 0; @@ -370,6 +667,9 @@ void USBSerial::timer_event(USBDriverTimer *whichTimer) tail = len - 1; } txtail = tail; + print(" TX data (", count); + print(") "); + print_hexbytes(p, count); queue_Data_Transfer(txpipe, p, count, this); }