Serial cleanup - flush, timeout

As per the forum posts, worked on combining the claim code for extracting which endpoints are RX and TX and create the pipes and the like.

Also worked on live cases.  Reading and writing to AX servos... Found some issues Probably more to find.

I left in some debug code to help find cases of deleting a pipe may hang.  Also macros in serial.cpp to set or toggle IO pins (when in debug mode). This helps find where things are happing using Logic Analyzer as a way to find the approriate USB packets.
This commit is contained in:
Kurt Eckhardt 2017-11-10 16:37:12 -08:00
parent d3e21b04c0
commit 4eee8627d2
3 changed files with 138 additions and 207 deletions

View File

@ -909,14 +909,18 @@ class USBSerial: public USBDriver, public Stream {
// 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
enum { DEFAULT_WRITE_TIMEOUT = 3500};
USBSerial(USBHost &host) : txtimer(this) { init(); }
void begin(uint32_t baud, uint32_t format=USBHOST_SERIAL_8N1);
void end(void);
uint32_t writeTimeout() {return write_timeout_;}
void writeTimeOut(uint32_t write_timeout) {write_timeout_ = write_timeout;} // Will not impact current ones.
virtual int available(void);
virtual int peek(void);
virtual int read(void);
virtual int availableForWrite();
virtual size_t write(uint8_t c);
virtual void flush(void);
using Print::write;
protected:
@ -944,6 +948,7 @@ private:
uint8_t setupdata[16]; //
uint32_t baudrate;
uint32_t format_;
uint32_t write_timeout_ = DEFAULT_WRITE_TIMEOUT;
Pipe_t *rxpipe;
Pipe_t *txpipe;
uint8_t *rx1; // location for first incoming packet

View File

@ -289,7 +289,7 @@ int ax12ReadPacket(int length) {
while ((ch = userial.read()) == -1) {
if ((millis() - ulStart) > 10) {
//if (!--ulCounter) {
// Serial.println("Timeout");
Serial.println("Timeout");
return 0; // Timeout
}
}

View File

@ -29,6 +29,16 @@
#define print USBHost::print_
#define println USBHost::println_
//#define ENABLE_DEBUG_PINS
#ifdef ENABLE_DEBUG_PINS
#define debugDigitalToggle(pin) {digitalWriteFast(pin, !digitalReadFast(pin));}
#define debugDigitalWrite(pin, state) {digitalWriteFast(pin, state);}
#else
#define debugDigitalToggle(pin) {;}
#define debugDigitalWrite(pin, state) {;}
#endif
/************************************************************/
// Define mapping VID/PID - to Serial Device type.
/************************************************************/
@ -168,6 +178,8 @@ bool USBSerial::claim(Device_t *dev, int type, const uint8_t *descriptors, uint3
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;
println(" rx buffer size:", rxsize);
println(" tx buffer size:", txsize);
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);
@ -205,47 +217,74 @@ bool USBSerial::claim(Device_t *dev, int type, const uint8_t *descriptors, uint3
break;
}
}
if (sertype == UNKNOWN) return false; // not one of ours
// Lets try to locate the end points. Code is common across these devices
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.
//Example 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 rx_size = 0;
uint16_t tx_size = 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];
rx_size = descriptors[descriptor_index+4];
} else {
txep = descriptors[descriptor_index+2];
tx_size = 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("USBSerial, rxep=", rxep & 15);
print("(", rx_size);
print("), txep=", txep);
print("(", tx_size);
println(")");
if (!init_buffers(rx_size, tx_size)) return false;
println(" rx buffer size:", rxsize);
println(" tx buffer size:", txsize);
rxpipe = new_Pipe(dev, 2, rxep & 15, 1, rx_size);
if (!rxpipe) return false;
txpipe = new_Pipe(dev, 2, txep, 0, tx_size);
if (!txpipe) {
//free_Pipe(rxpipe);
return false;
}
rxpipe->callback_function = rx_callback;
queue_Data_Transfer(rxpipe, rx1, rx_size, this);
rxstate = 1;
txstate = 0;
txpipe->callback_function = tx_callback;
baudrate = 115200;
// Now do specific setup per type
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;
}
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);
@ -257,59 +296,6 @@ bool USBSerial::claim(Device_t *dev, int type, const uint8_t *descriptors, uint3
// 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
// 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;
}
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;
// First attempt keep it simple...
println("PL2303: readRegister(0x04)");
// Need to setup the data the line coding data
@ -324,57 +310,6 @@ bool USBSerial::claim(Device_t *dev, int type, const uint8_t *descriptors, uint3
// 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));
@ -388,58 +323,6 @@ bool USBSerial::claim(Device_t *dev, int type, const uint8_t *descriptors, uint3
// CP210X
case CP210X:
{
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.
// BUGBUG: should factor out this code as duplicated...
// vid=10C4, pid=EA60, bDeviceClass = 0, 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 02 FF 00 00 02 07 05 81 02 40 00 00 07 05 01 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("CP210X, 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("CP210X: 0x41, 0x11, 0, 0, 0 - reset port");
// Need to setup the data the line coding data
mk_setup(setup, 0x41, 0x11, 0, 0, 0);
@ -1102,6 +985,7 @@ void USBSerial::rx_data(const Transfer_t *transfer)
{
uint32_t len = transfer->length - ((transfer->qtd.token >> 16) & 0x7FFF);
debugDigitalToggle(6);
// first update rxstate bitmask, since buffer is no longer queued
if (transfer->buffer == rx1) {
rxstate &= 0xFE;
@ -1119,6 +1003,11 @@ void USBSerial::rx_data(const Transfer_t *transfer)
}
}
if (len > 0) {
print("rx token: ", transfer->qtd.token, HEX);
print(" transfer length: ", transfer->length, DEC);
print(" len:", len, DEC);
print(" - ", *p, HEX);
println(" ", *(p+1), HEX);
print("rx: ");
print_hexbytes(p, len);
}
@ -1185,6 +1074,7 @@ void USBSerial::tx_data(const Transfer_t *transfer)
{
uint32_t mask;
uint8_t *p = (uint8_t *)transfer->buffer;
debugDigitalWrite(5, HIGH);
if (p == tx1) {
println("tx1:");
mask = 1;
@ -1194,6 +1084,7 @@ void USBSerial::tx_data(const Transfer_t *transfer)
mask = 2;
//txstate &= 0xFD;
} else {
debugDigitalWrite(5, LOW);
return; // should never happen
}
// check how much more data remains in the transmit buffer
@ -1206,50 +1097,72 @@ void USBSerial::tx_data(const Transfer_t *transfer)
count = txsize + head - tail;
}
uint32_t packetsize = tx2 - tx1;
if (count < packetsize) {
// Only output full packets unless the flush bit was set.
if ((count == 0) || ((count < packetsize) && ((txstate & 0x4) == 0) )) {
// not enough data in buffer to fill a full packet
txstate &= ~mask;
txstate &= ~(mask | 4); // turn off that transfer and make sure the flush bit is not set
debugDigitalWrite(5, LOW);
return;
}
// immediately transmit another full packet, if we have enough data
if (count >= packetsize) count = packetsize;
else txstate &= ~(mask | 4); // This packet will complete any outstanding flush
println("TX:moar data!!!!");
if (++tail >= txsize) tail = 0;
uint32_t n = txsize - tail;
if (n > packetsize) n = packetsize;
if (n > count) n = count;
memcpy(p, txbuf + tail, n);
if (n >= packetsize) {
if (n >= count) {
tail += n - 1;
if (tail >= txsize) tail = 0;
} else {
uint32_t len = packetsize - n;
uint32_t len = count - n;
memcpy(p + n, txbuf, len);
tail = len - 1;
}
txtail = tail;
queue_Data_Transfer(txpipe, p, packetsize, this);
queue_Data_Transfer(txpipe, p, count, this);
debugDigitalWrite(5, LOW);
}
void USBSerial::flush()
{
print("USBSerial::flush");
if (txhead == txtail) {
println(" - Empty");
return; // empty.
}
debugDigitalWrite(32, HIGH);
NVIC_DISABLE_IRQ(IRQ_USBHS);
txtimer.stop(); // Stop longer timer.
txtimer.start(100); // Start a mimimal timeout
// timer_event(nullptr); // Try calling direct - fails to work
NVIC_ENABLE_IRQ(IRQ_USBHS);
while (txstate & 3) ; // wait for all of the USB packets to be sent.
println(" completed");
debugDigitalWrite(32, LOW);
}
void USBSerial::timer_event(USBDriverTimer *whichTimer)
{
debugDigitalWrite(7, HIGH);
println("txtimer");
uint32_t count;
uint32_t head = txhead;
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) {
println(" *** Empty ***");
debugDigitalWrite(7, LOW);
return; // nothing to transmit
} else if (head > tail) {
count = head - tail;
} else {
count = txsize + head - tail;
}
uint8_t *p;
if ((txstate & 0x01) == 0) {
p = tx1;
@ -1258,10 +1171,20 @@ void USBSerial::timer_event(USBDriverTimer *whichTimer)
p = tx2;
txstate |= 0x02;
} else {
txtimer.start(1200);
txstate |= 4; // Tell the TX code to do flush code.
println(" *** No buffers ***");
debugDigitalWrite(7, LOW);
return; // no outgoing buffers available, try again later
}
uint32_t packetsize = tx2 - tx1;
// Possible for remaining ? packet size and not have both?
if (count > packetsize) {
txstate |= 4; // One of the active transfers will handle the remaining parts
count = packetsize;
}
if (++tail >= txsize) tail = 0;
uint32_t n = txsize - tail;
if (n > count) n = count;
@ -1279,6 +1202,7 @@ void USBSerial::timer_event(USBDriverTimer *whichTimer)
print(") ");
print_hexbytes(p, count);
queue_Data_Transfer(txpipe, p, count, this);
debugDigitalWrite(7, LOW);
}
@ -1427,14 +1351,16 @@ size_t USBSerial::write(uint8_t c)
}
txtail = tail;
//println("queue tx packet, newtail=", tail);
debugDigitalWrite(7, HIGH);
queue_Data_Transfer(txpipe, p, packetsize, this);
debugDigitalWrite(7, LOW);
NVIC_ENABLE_IRQ(IRQ_USBHS);
return 1;
}
}
// otherwise, set a latency timer to later transmit partial packet
txtimer.stop();
txtimer.start(3500);
txtimer.start(write_timeout_);
NVIC_ENABLE_IRQ(IRQ_USBHS);
return 1;
}