|
|
|
|
|
|
|
|
#define print USBHost::print_ |
|
|
#define print USBHost::print_ |
|
|
#define println USBHost::println_ |
|
|
#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 |
|
|
// Initialization and claiming of devices & interfaces |
|
|
/************************************************************/ |
|
|
/************************************************************/ |
|
|
|
|
|
|
|
|
// only claim at interface level |
|
|
// only claim at interface level |
|
|
println("USBSerial claim this=", (uint32_t)this, HEX); |
|
|
println("USBSerial claim this=", (uint32_t)this, HEX); |
|
|
print("vid=", dev->idVendor, 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 (type == 0) { |
|
|
if (dev->idVendor == 0x0403 && dev->idProduct == 0x6001) { |
|
|
if (dev->idVendor == 0x0403 && dev->idProduct == 0x6001) { |
|
|
// FTDI FT232 |
|
|
// FTDI FT232 |
|
|
|
|
|
|
|
|
queue_Control_Transfer(dev, &setup, NULL, this); |
|
|
queue_Control_Transfer(dev, &setup, NULL, this); |
|
|
control_queued = true; |
|
|
control_queued = true; |
|
|
return 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; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 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]; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
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; |
|
|
|
|
|
|
|
|
|
|
|
// 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; |
|
|
|
|
|
} |
|
|
|
|
|
} else if (type != 1) return false; |
|
|
|
|
|
// TTYACM: <Composit device> |
|
|
|
|
|
// |
|
|
|
|
|
// We first tried to claim a simple ttyACM device like a teensy who is configured |
|
|
|
|
|
// only as Serial at the device level like what was done for midi |
|
|
|
|
|
// |
|
|
|
|
|
// However some devices are a compisit of multiple Interfaces, so see if this Interface |
|
|
|
|
|
// is of the CDC Interface class and 0 for SubClass and protocol |
|
|
|
|
|
// Todo: some of this can maybe be combined with the Whole device code above. |
|
|
|
|
|
|
|
|
|
|
|
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 |
|
|
|
|
|
|
|
|
|
|
|
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; |
|
|
} |
|
|
} |
|
|
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; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// check if two legal endpoints, 1 receive & 1 transmit |
|
|
// check if two legal endpoints, 1 receive & 1 transmit |
|
|
|
|
|
|
|
|
// initialize buffer sizes and pointers |
|
|
// initialize buffer sizes and pointers |
|
|
bool USBSerial::init_buffers(uint32_t rsize, uint32_t tsize) |
|
|
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; |
|
|
if (sizeof(bigbuffer) < (rsize + tsize) * 3 + 2) return false; |
|
|
rx1 = (uint8_t *)bigbuffer; |
|
|
rx1 = (uint8_t *)bigbuffer; |
|
|
rx2 = rx1 + rsize; |
|
|
rx2 = rx1 + rsize; |
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/************************************************************/ |
|
|
|
|
|
// Control Transfer For Configuration |
|
|
|
|
|
/************************************************************/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void USBSerial::control(const Transfer_t *transfer) |
|
|
void USBSerial::control(const Transfer_t *transfer) |
|
|
{ |
|
|
{ |
|
|
println("control callback (serial)"); |
|
|
|
|
|
|
|
|
println("control callback (serial) ", pending_control, HEX); |
|
|
control_queued = false; |
|
|
control_queued = false; |
|
|
|
|
|
|
|
|
// set data format |
|
|
|
|
|
if (pending_control & 1) { |
|
|
|
|
|
pending_control &= ~1; |
|
|
|
|
|
mk_setup(setup, 0x40, 4, 8, 0, 0); // data format 8N1 |
|
|
|
|
|
queue_Control_Transfer(device, &setup, NULL, this); |
|
|
|
|
|
control_queued = true; |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
// 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; |
|
|
|
|
|
return; |
|
|
|
|
|
|
|
|
// We will split this up by Serial type, maybe different functions? |
|
|
|
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------- |
|
|
|
|
|
// First FTDI |
|
|
|
|
|
if (sertype == FTDI) { |
|
|
|
|
|
if (pending_control & 1) { |
|
|
|
|
|
pending_control &= ~1; |
|
|
|
|
|
// set data format |
|
|
|
|
|
mk_setup(setup, 0x40, 4, 8, 0, 0); // data format 8N1 |
|
|
|
|
|
queue_Control_Transfer(device, &setup, NULL, this); |
|
|
|
|
|
control_queued = true; |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
// 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; |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
// configure flow control |
|
|
|
|
|
if (pending_control & 4) { |
|
|
|
|
|
pending_control &= ~4; |
|
|
|
|
|
mk_setup(setup, 0x40, 2, 0, 1, 0); |
|
|
|
|
|
queue_Control_Transfer(device, &setup, NULL, this); |
|
|
|
|
|
control_queued = true; |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
// set DTR |
|
|
|
|
|
if (pending_control & 8) { |
|
|
|
|
|
pending_control &= ~8; |
|
|
|
|
|
mk_setup(setup, 0x40, 1, 0x0101, 0, 0); |
|
|
|
|
|
queue_Control_Transfer(device, &setup, NULL, 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; |
|
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------- |
|
|
|
|
|
// Now CDCACM |
|
|
|
|
|
if (sertype == CDCACM) { |
|
|
|
|
|
if (pending_control & 2) { |
|
|
|
|
|
pending_control &= ~2; |
|
|
|
|
|
// 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; |
|
|
|
|
|
println("Control - 0x21,0x22, 0x3"); |
|
|
|
|
|
// Need to setup the data the line coding data |
|
|
|
|
|
mk_setup(setup, 0x21, 0x22, 3, 0, 0); |
|
|
|
|
|
queue_Control_Transfer(device, &setup, NULL, this); |
|
|
|
|
|
control_queued = true; |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
// set DTR |
|
|
|
|
|
if (pending_control & 8) { |
|
|
|
|
|
pending_control &= ~8; |
|
|
|
|
|
mk_setup(setup, 0x40, 1, 0x0101, 0, 0); |
|
|
|
|
|
queue_Control_Transfer(device, &setup, NULL, this); |
|
|
|
|
|
control_queued = true; |
|
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------- |
|
|
|
|
|
// Now PL2303 - Which appears to be a little more complicated |
|
|
|
|
|
if (sertype == PL2303) { |
|
|
|
|
|
if (pending_control & 1) { |
|
|
|
|
|
// Still in larger setup state mode |
|
|
|
|
|
switch (setup_state) { |
|
|
|
|
|
case 1: |
|
|
|
|
|
println("PL2303: writeRegister(0x04, 0x00)"); |
|
|
|
|
|
mk_setup(setup, 0x40, 1, 0x0404, 0, 0); // |
|
|
|
|
|
queue_Control_Transfer(device, &setup, NULL, this); |
|
|
|
|
|
setup_state = 2; |
|
|
|
|
|
control_queued = true; |
|
|
|
|
|
return; |
|
|
|
|
|
case 2: |
|
|
|
|
|
println("PL2303: readRegister(0x04)"); |
|
|
|
|
|
mk_setup(setup, 0xC0, 0x1, 0x8484, 0, 1); |
|
|
|
|
|
queue_Control_Transfer(device, &setup, setupdata, this); |
|
|
|
|
|
control_queued = true; |
|
|
|
|
|
setup_state = 3; |
|
|
|
|
|
return; |
|
|
|
|
|
case 3: |
|
|
|
|
|
println("PL2303: v1 = readRegister(0x03)"); |
|
|
|
|
|
mk_setup(setup, 0xC0, 0x1, 0x8383, 0, 1); |
|
|
|
|
|
queue_Control_Transfer(device, &setup, setupdata, this); |
|
|
|
|
|
control_queued = true; |
|
|
|
|
|
setup_state = 4; |
|
|
|
|
|
return; |
|
|
|
|
|
case 4: |
|
|
|
|
|
println("PL2303: readRegister(0x04)"); |
|
|
|
|
|
// Do we need this value long term or we could just leave in setup data? |
|
|
|
|
|
pl2303_v1 = setupdata[0]; // save the first bye of version |
|
|
|
|
|
mk_setup(setup, 0xC0, 0x1, 0x8484, 0, 1); |
|
|
|
|
|
queue_Control_Transfer(device, &setup, setupdata, this); |
|
|
|
|
|
control_queued = true; |
|
|
|
|
|
setup_state = 5; |
|
|
|
|
|
return; |
|
|
|
|
|
case 5: |
|
|
|
|
|
println("PL2303: writeRegister(0x04, 0x01)"); |
|
|
|
|
|
mk_setup(setup, 0x40, 1, 0x0404, 1, 0); // |
|
|
|
|
|
queue_Control_Transfer(device, &setup, NULL, this); |
|
|
|
|
|
setup_state = 6; |
|
|
|
|
|
control_queued = true; |
|
|
|
|
|
return; |
|
|
|
|
|
case 6: |
|
|
|
|
|
println("PL2303: readRegister(0x04)"); |
|
|
|
|
|
mk_setup(setup, 0xC0, 0x1, 0x8484, 0, 1); |
|
|
|
|
|
queue_Control_Transfer(device, &setup, setupdata, this); |
|
|
|
|
|
control_queued = true; |
|
|
|
|
|
setup_state = 7; |
|
|
|
|
|
return; |
|
|
|
|
|
case 7: |
|
|
|
|
|
println("PL2303: v2 = readRegister(0x03)"); |
|
|
|
|
|
mk_setup(setup, 0xC0, 0x1, 0x8383, 0, 1); |
|
|
|
|
|
queue_Control_Transfer(device, &setup, setupdata, this); |
|
|
|
|
|
control_queued = true; |
|
|
|
|
|
setup_state = 8; |
|
|
|
|
|
return; |
|
|
|
|
|
case 8: |
|
|
|
|
|
pl2303_v2 = setupdata[0]; // save the first bye of version |
|
|
|
|
|
print(" PL2303 Version ", pl2303_v1, HEX); |
|
|
|
|
|
println(":", pl2303_v2, HEX); |
|
|
|
|
|
println("PL2303: writeRegister(0, 1)"); |
|
|
|
|
|
mk_setup(setup, 0x40, 1, 0, 1, 0); // |
|
|
|
|
|
queue_Control_Transfer(device, &setup, NULL, this); |
|
|
|
|
|
setup_state = 9; |
|
|
|
|
|
control_queued = true; |
|
|
|
|
|
return; |
|
|
|
|
|
case 9: |
|
|
|
|
|
println("PL2303: writeRegister(1, 0)"); |
|
|
|
|
|
mk_setup(setup, 0x40, 1, 1, 0, 0); // |
|
|
|
|
|
queue_Control_Transfer(device, &setup, NULL, this); |
|
|
|
|
|
setup_state = 10; |
|
|
|
|
|
control_queued = true; |
|
|
|
|
|
return; |
|
|
|
|
|
case 10: |
|
|
|
|
|
println("PL2303: writeRegister(2, 44)"); |
|
|
|
|
|
mk_setup(setup, 0x40, 1, 2, 0x44, 0); // |
|
|
|
|
|
queue_Control_Transfer(device, &setup, NULL, this); |
|
|
|
|
|
setup_state = 11; |
|
|
|
|
|
control_queued = true; |
|
|
|
|
|
return; |
|
|
|
|
|
case 11: |
|
|
|
|
|
println("PL2303: writeRegister(8, 0)"); |
|
|
|
|
|
mk_setup(setup, 0x40, 1, 8, 0, 0); // |
|
|
|
|
|
queue_Control_Transfer(device, &setup, NULL, this); |
|
|
|
|
|
setup_state = 12; |
|
|
|
|
|
control_queued = true; |
|
|
|
|
|
return; |
|
|
|
|
|
case 12: |
|
|
|
|
|
println("PL2303: writeRegister(9, 0)"); |
|
|
|
|
|
mk_setup(setup, 0x40, 1, 9, 0, 0); // |
|
|
|
|
|
queue_Control_Transfer(device, &setup, NULL, this); |
|
|
|
|
|
setup_state = 13; |
|
|
|
|
|
control_queued = true; |
|
|
|
|
|
return; |
|
|
|
|
|
case 13: |
|
|
|
|
|
println("PL2303: Read current Baud/control"); |
|
|
|
|
|
mk_setup(setup, 0xA1, 0x21, 0, 0, 7); |
|
|
|
|
|
queue_Control_Transfer(device, &setup, setupdata, this); |
|
|
|
|
|
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; |
|
|
|
|
|
// See what the read returned earlier |
|
|
|
|
|
print("PL2303: Returned configuration data: "); |
|
|
|
|
|
print_hexbytes(setupdata, 7); |
|
|
|
|
|
|
|
|
|
|
|
// 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("PL2303: Set baud/control: ", baudrate, HEX); |
|
|
|
|
|
print(" = "); |
|
|
|
|
|
print_hexbytes(&setupdata, 7); |
|
|
|
|
|
mk_setup(setup, 0x21, 0x20, 0, 0, 7); |
|
|
|
|
|
queue_Control_Transfer(device, &setup, setupdata, this); |
|
|
|
|
|
control_queued = true; |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
if (pending_control & 4) { |
|
|
|
|
|
pending_control &= ~4; |
|
|
|
|
|
println("PL2303: writeRegister(0, 0)"); |
|
|
|
|
|
mk_setup(setup, 0x40, 1, 0, 0, 0); // |
|
|
|
|
|
queue_Control_Transfer(device, &setup, NULL, this); |
|
|
|
|
|
control_queued = true; |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
if (pending_control & 8) { |
|
|
|
|
|
pending_control &= ~8; |
|
|
|
|
|
println("PL2303: Read current Baud/control"); |
|
|
|
|
|
memset(setupdata, 0, sizeof(setupdata)); // clear it to see if we read it... |
|
|
|
|
|
mk_setup(setup, 0xA1, 0x21, 0, 0, 7); |
|
|
|
|
|
queue_Control_Transfer(device, &setup, setupdata, this); |
|
|
|
|
|
control_queued = true; |
|
|
|
|
|
} |
|
|
|
|
|
if (pending_control & 0x10) { |
|
|
|
|
|
pending_control &= ~0x10; |
|
|
|
|
|
print("PL2303: Returned configuration data: "); |
|
|
|
|
|
print_hexbytes(setupdata, 7); |
|
|
|
|
|
|
|
|
|
|
|
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; |
|
|
|
|
|
println("PL2303: 0x21, 0x22, 0x3"); |
|
|
|
|
|
mk_setup(setup, 0x21, 0x22, 3, 0, 0); // |
|
|
|
|
|
queue_Control_Transfer(device, &setup, NULL, this); |
|
|
|
|
|
control_queued = true; |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
((USBSerial *)(transfer->driver))->tx_data(transfer); |
|
|
((USBSerial *)(transfer->driver))->tx_data(transfer); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void USBSerial::rx_data(const Transfer_t *transfer) |
|
|
void USBSerial::rx_data(const Transfer_t *transfer) |
|
|
{ |
|
|
{ |
|
|
uint32_t len = transfer->length - ((transfer->qtd.token >> 16) & 0x7FFF); |
|
|
uint32_t len = transfer->length - ((transfer->qtd.token >> 16) & 0x7FFF); |
|
|
|
|
|
|
|
|
len = 0; |
|
|
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. |
|
|
// Copy data from packet buffer to circular buffer. |
|
|
// Assume the buffer will always have space, since we |
|
|
// Assume the buffer will always have space, since we |
|
|
// check before queuing the buffers |
|
|
// check before queuing the buffers |
|
|
|
|
|
|
|
|
uint32_t count; |
|
|
uint32_t count; |
|
|
uint32_t head = txhead; |
|
|
uint32_t head = txhead; |
|
|
uint32_t tail = txtail; |
|
|
uint32_t tail = txtail; |
|
|
|
|
|
if (pending_control) { |
|
|
|
|
|
// We are still doing setup postpone for awhile.. |
|
|
|
|
|
txtimer.start(1200); |
|
|
|
|
|
println(" Postpone: setup pending_control"); |
|
|
|
|
|
return; // no outgoing buffers available, try again later |
|
|
|
|
|
} |
|
|
if (head == tail) { |
|
|
if (head == tail) { |
|
|
|
|
|
println(" *** Empty ***"); |
|
|
return; // nothing to transmit |
|
|
return; // nothing to transmit |
|
|
} else if (head > tail) { |
|
|
} else if (head > tail) { |
|
|
count = head - tail; |
|
|
count = head - tail; |
|
|
|
|
|
|
|
|
txstate |= 0x02; |
|
|
txstate |= 0x02; |
|
|
} else { |
|
|
} else { |
|
|
txtimer.start(1200); |
|
|
txtimer.start(1200); |
|
|
|
|
|
println(" *** No buffers ***"); |
|
|
return; // no outgoing buffers available, try again later |
|
|
return; // no outgoing buffers available, try again later |
|
|
} |
|
|
} |
|
|
if (++tail >= txsize) tail = 0; |
|
|
if (++tail >= txsize) tail = 0; |
|
|
|
|
|
|
|
|
tail = len - 1; |
|
|
tail = len - 1; |
|
|
} |
|
|
} |
|
|
txtail = tail; |
|
|
txtail = tail; |
|
|
|
|
|
print(" TX data (", count); |
|
|
|
|
|
print(") "); |
|
|
|
|
|
print_hexbytes(p, count); |
|
|
queue_Data_Transfer(txpipe, p, count, this); |
|
|
queue_Data_Transfer(txpipe, p, count, this); |
|
|
} |
|
|
} |
|
|
|
|
|
|