add telnet codes for serial port config

pull/236/head
Thorsten von Eicken 8 years ago
parent 5efbf32658
commit de0a093aa7
No known key found for this signature in database
GPG Key ID: C7F972A59D834B46
  1. 100
      serial/serbridge.c

@ -25,6 +25,8 @@ uint8_t in_mcu_flashing; // for disabling slip during MCU flashing
void (*programmingCB)(char *buffer, short length) = NULL; void (*programmingCB)(char *buffer, short length) = NULL;
static sint8 espbuffsend(serbridgeConnData *conn, const char *data, uint16 len);
// Connection pool // Connection pool
serbridgeConnData connData[MAX_CONN]; serbridgeConnData connData[MAX_CONN];
@ -32,10 +34,15 @@ serbridgeConnData connData[MAX_CONN];
// Telnet protocol characters // Telnet protocol characters
#define IAC 255 // escape #define IAC 255 // escape
#define DONT 254 // negotiation
#define DO 253 // negotiation
#define WILL 251 // negotiation #define WILL 251 // negotiation
#define SB 250 // subnegotiation begin #define SB 250 // subnegotiation begin
#define SE 240 // subnegotiation end #define SE 240 // subnegotiation end
#define ComPortOpt 44 // COM port options #define ComPortOpt 44 // COM port options
#define SetBaud 1 // Set baud rate
#define SetDataSize 2 // Set data size
#define SetParity 3 // Set parity
#define SetControl 5 // Set control lines #define SetControl 5 // Set control lines
#define DTR_ON 8 // used here to reset microcontroller #define DTR_ON 8 // used here to reset microcontroller
#define DTR_OFF 9 #define DTR_OFF 9
@ -43,12 +50,17 @@ serbridgeConnData connData[MAX_CONN];
#define RTS_OFF 12 #define RTS_OFF 12
// telnet state machine states // telnet state machine states
enum { TN_normal, TN_iac, TN_will, TN_start, TN_end, TN_comPort, TN_setControl }; enum { TN_normal, TN_iac, TN_will, TN_start, TN_end, TN_comPort, TN_setControl, TN_setBaud,
TN_setDataSize, TN_setParity };
static char tn_baudCnt;
static uint32_t tn_baud; // shared across all sockets, thus possible race condition
// process a buffer-full on a telnet connection and return the ending telnet state // process a buffer-full on a telnet connection
static uint8_t ICACHE_FLASH_ATTR static void ICACHE_FLASH_ATTR
telnetUnwrap(uint8_t *inBuf, int len, uint8_t state) telnetUnwrap(serbridgeConnData *conn, uint8_t *inBuf, int len)
{ {
uint8_t state = conn->telnet_state;
for (int i=0; i<len; i++) { for (int i=0; i<len; i++) {
uint8_t c = inBuf[i]; uint8_t c = inBuf[i];
switch (state) { switch (state) {
@ -77,9 +89,12 @@ telnetUnwrap(uint8_t *inBuf, int len, uint8_t state)
uart0_write_char(c); uart0_write_char(c);
} }
break; break;
case TN_will: case TN_will: { // client announcing it will send telnet cmds, try to respond
state = TN_normal; // yes, we do COM port options, let's go back to normal char respBuf[3] = {IAC, DONT, c};
break; if (c == ComPortOpt) respBuf[1] = DO;
espbuffsend(conn, respBuf, 3);
state = TN_normal; // go back to normal
break; }
case TN_start: // in command seq, now comes the type of cmd case TN_start: // in command seq, now comes the type of cmd
if (c == ComPortOpt) state = TN_comPort; if (c == ComPortOpt) state = TN_comPort;
else state = TN_end; // an option we don't know, skip 'til the end seq else state = TN_end; // an option we don't know, skip 'til the end seq
@ -88,8 +103,13 @@ telnetUnwrap(uint8_t *inBuf, int len, uint8_t state)
if (c == IAC) state = TN_iac; // simple wait to accept end or next escape seq if (c == IAC) state = TN_iac; // simple wait to accept end or next escape seq
break; break;
case TN_comPort: case TN_comPort:
if (c == SetControl) state = TN_setControl; switch (c) {
else state = TN_end; case SetControl: state = TN_setControl; break;
case SetDataSize: state = TN_setDataSize; break;
case SetParity: state = TN_setParity; break;
case SetBaud: state = TN_setBaud; tn_baudCnt = 0; break;
default: state = TN_end; break;
}
break; break;
case TN_setControl: // switch control line and delay a tad case TN_setControl: // switch control line and delay a tad
switch (c) { switch (c) {
@ -134,9 +154,60 @@ telnetUnwrap(uint8_t *inBuf, int len, uint8_t state)
} }
state = TN_end; state = TN_end;
break; break;
case TN_setDataSize:
if (c >= 5 && c <= 8) {
flashConfig.data_bits = c - 5 + FIVE_BITS;
uint32_t conf0 = CALC_UARTMODE(flashConfig.data_bits, flashConfig.parity, flashConfig.stop_bits);
uart_config(0, flashConfig.baud_rate, conf0);
configSave();
} else if (c == 0) {
// data size of zero means we need to send the current data size
char respBuf[7] = { IAC, SB, ComPortOpt, SetDataSize,
flashConfig.data_bits-FIVE_BITS+5, IAC, SE };
espbuffsend(conn, respBuf, 7);
}
state = TN_end;
break;
case TN_setBaud:
tn_baud |= ((uint32_t)c) << (24-8*tn_baudCnt);
tn_baudCnt++;
if (tn_baudCnt == 4) {
// we got all four baud rate bytes (big endian)
if (tn_baud >= 300 && tn_baud <= 1000000) {
uart0_baud(tn_baud);
flashConfig.baud_rate = tn_baud;
configSave();
} else if (tn_baud == 0) {
// baud rate of zero means we need to send the baud rate
uint32_t b = flashConfig.baud_rate;
char respBuf[10] = { IAC, SB, ComPortOpt, SetDataSize, b>>24, b>>16, b>>8, b, IAC, SE };
espbuffsend(conn, respBuf, 10);
}
state = TN_end;
}
break;
case TN_setParity:
if (c == 0) {
// parity of zero means we need to send the parity info
char respBuf[7] = { IAC, SB, ComPortOpt, SetDataSize, 1/*none*/, IAC, SE };
if (flashConfig.parity == ODD_BITS) respBuf[4] = 2;
if (flashConfig.parity == EVEN_BITS) respBuf[4] = 3;
espbuffsend(conn, respBuf, 7);
state = TN_end;
break;
}
uint8_t parity = NONE_BITS;
if (c == 2) parity = ODD_BITS;
if (c == 3) parity = EVEN_BITS;
flashConfig.parity = parity;
uint32_t conf0 = CALC_UARTMODE(flashConfig.data_bits, flashConfig.parity, flashConfig.stop_bits);
uart_config(0, flashConfig.baud_rate, conf0);
configSave();
state = TN_end;
break;
} }
} }
return state; conn->telnet_state = state;
} }
// Generate a reset pulse for the attached microcontroller // Generate a reset pulse for the attached microcontroller
@ -183,7 +254,7 @@ serbridgeRecvCb(void *arg, char *data, unsigned short len)
// If the connection starts with a telnet negotiation we will do telnet // If the connection starts with a telnet negotiation we will do telnet
} }
else if (len >= 3 && strncmp(data, (char[]){IAC, WILL, ComPortOpt}, 3) == 0) { else if (len >= 2 && strncmp(data, (char[]){IAC, WILL}, 2) == 0) {
conn->conn_mode = cmTelnet; conn->conn_mode = cmTelnet;
conn->telnet_state = TN_normal; conn->telnet_state = TN_normal;
// note that the three negotiation chars will be gobbled-up by telnetUnwrap // note that the three negotiation chars will be gobbled-up by telnetUnwrap
@ -228,7 +299,7 @@ serbridgeRecvCb(void *arg, char *data, unsigned short len)
// write the buffer to the uart // write the buffer to the uart
if (conn->conn_mode == cmTelnet) { if (conn->conn_mode == cmTelnet) {
conn->telnet_state = telnetUnwrap((uint8_t *)data, len, conn->telnet_state); telnetUnwrap(conn, (uint8_t *)data, len);
} else { } else {
uart0_tx_buffer(data, len); uart0_tx_buffer(data, len);
} }
@ -405,12 +476,13 @@ serbridgeConnectCb(void *arg)
#ifdef SERBR_DBG #ifdef SERBR_DBG
os_printf("Accept port %d, conn=%p, pool slot %d\n", conn->proto.tcp->local_port, conn, i); os_printf("Accept port %d, conn=%p, pool slot %d\n", conn->proto.tcp->local_port, conn, i);
#endif #endif
syslog(SYSLOG_FAC_USER, SYSLOG_PRIO_NOTICE, "esp-link", "Accept port %d, conn=%p, pool slot %d\n", conn->proto.tcp->local_port, conn, i); syslog(SYSLOG_FAC_USER, SYSLOG_PRIO_NOTICE, "esp-link", "Accept port %d, conn=%p, pool slot %d\n",
conn->proto.tcp->local_port, conn, i);
if (i==MAX_CONN) { if (i==MAX_CONN) {
#ifdef SERBR_DBG #ifdef SERBR_DBG
os_printf("Aiee, conn pool overflow!\n"); os_printf("Aiee, conn pool overflow!\n");
#endif #endif
syslog(SYSLOG_FAC_USER, SYSLOG_PRIO_WARNING, "esp-link", "Aiee, conn pool overflow!\n"); syslog(SYSLOG_FAC_USER, SYSLOG_PRIO_WARNING, "esp-link", "Aiee, conn pool overflow!\n");
espconn_disconnect(conn); espconn_disconnect(conn);
return; return;
} }

Loading…
Cancel
Save