RFC2217 option value stored in connection object. Acknowledged baudrate value escaped. Code reorganized.

pull/140/merge^2
Christophe Duparquet 9 years ago
parent 291b55cb4d
commit 076391bb62
  1. 457
      serial/serbridge.c
  2. 3
      serial/serbridge.h

@ -1,7 +1,6 @@
// Copyright 2015 by Thorsten von Eicken, see LICENSE.txt // Copyright 2015 by Thorsten von Eicken, see LICENSE.txt
/* Modified by Christophe Duparquet: implementation of RFC 2217 to use the /* Modified by Christophe Duparquet: extended implementation of RFC 2217
* Diabolo bootloader through pySerial-3.0.
* *
* Verified on ESP-WROOM-02 with the following configuration: * Verified on ESP-WROOM-02 with the following configuration:
* Reset: gpio5 * Reset: gpio5
@ -41,6 +40,9 @@
#define SKIP_AT_RESET #define SKIP_AT_RESET
/* ESP8266
*/
#define IROM ICACHE_FLASH_ATTR #define IROM ICACHE_FLASH_ATTR
#define REG_BRR (*(volatile uint32_t*)0x60000014) #define REG_BRR (*(volatile uint32_t*)0x60000014)
#define REG_CONF0 (*(volatile uint32_t*)0x60000020) #define REG_CONF0 (*(volatile uint32_t*)0x60000020)
@ -60,6 +62,7 @@ void (*programmingCB)(char *buffer, short length) = NULL;
serbridgeConnData connData[MAX_CONN]; serbridgeConnData connData[MAX_CONN];
static sint8 IROM espbuffsend(serbridgeConnData *conn, const char *data, uint16 len) ; static sint8 IROM espbuffsend(serbridgeConnData *conn, const char *data, uint16 len) ;
static sint8 IROM espbuffsend_tn(serbridgeConnData *conn, const char *data, uint16 len) ;
// Telnet protocol (RFC854) characters // Telnet protocol (RFC854) characters
@ -84,7 +87,6 @@ static sint8 IROM espbuffsend(serbridgeConnData *conn, const char *data, uint16
#define SET_CONTROL 5 // suboption "CONTROL" #define SET_CONTROL 5 // suboption "CONTROL"
#define PURGE_DATA 12 // suboption "PURGE" #define PURGE_DATA 12 // suboption "PURGE"
#define SERBR_DBG
#ifdef SERBR_DBG #ifdef SERBR_DBG
# define dbgf(...) do { os_printf(__VA_ARGS__); }while(0) # define dbgf(...) do { os_printf(__VA_ARGS__); }while(0)
@ -111,37 +113,31 @@ enum {
}; };
/* Process bytes comming from a telnet connection /* Telnet state machine: process one byte comming from a telnet connection
*/ */
static void IROM telnet_unwrap ( serbridgeConnData *conn, uint8_t *buf, int len ) static void IROM telnet_process_char ( serbridgeConnData *conn, char c )
{ {
#define state conn->tn_state #define state conn->tn_state
#define opt conn->tn_opt #define opt conn->tn_opt
#define vlen conn->tn_vlen #define vlen conn->tn_vlen
#define value conn->tn_value
static uint32_t value ; // Value of subnegociated paramater
dbgf("TELNET:");
for ( int i=0; i<len; i++ ) {
dbgf(" %02X", buf[i]);
}
dbgf(" \n");
for ( int i=0 ; i<len ; i++ ) {
uint8_t c = buf[i];
if ( state == ST_NORMAL ) { if ( state == ST_NORMAL ) {
if ( c == IAC ) if ( c == IAC )
state = ST_IAC ; state = ST_IAC ;
else else
uart0_write_char(c) ; uart0_write_char(c) ;
return ;
} }
else if ( state == ST_IAC ) {
if ( state == ST_IAC ) {
if ( c == IAC ) { if ( c == IAC ) {
/* /*
* Dual IAC means char \xFF * Dual IAC means char \xFF
*/ */
uart0_write_char(0xFF); uart0_write_char(0xFF);
state = ST_NORMAL ;
return ;
} }
else if ( c == DONT || c == DO || c == WONT || c == WILL ) { else if ( c == DONT || c == DO || c == WONT || c == WILL ) {
/* /*
@ -149,6 +145,7 @@ static void IROM telnet_unwrap ( serbridgeConnData *conn, uint8_t *buf, int len
*/ */
opt = c ; opt = c ;
state = ST_NEGO ; state = ST_NEGO ;
return ;
} }
else if ( c == SB ) { else if ( c == SB ) {
/* /*
@ -156,6 +153,7 @@ static void IROM telnet_unwrap ( serbridgeConnData *conn, uint8_t *buf, int len
*/ */
opt = c ; opt = c ;
state = ST_SB ; state = ST_SB ;
return ;
} }
else if ( c == SE ) { else if ( c == SE ) {
/* /*
@ -163,9 +161,12 @@ static void IROM telnet_unwrap ( serbridgeConnData *conn, uint8_t *buf, int len
*/ */
opt = c ; opt = c ;
state = ST_NORMAL ; state = ST_NORMAL ;
return ;
} }
return ;
} }
else if ( state == ST_NEGO ) {
if ( state == ST_NEGO ) {
dbgf("TELNET: IAC NEGO (%02X)", c); dbgf("TELNET: IAC NEGO (%02X)", c);
if ( c == BINARY || if ( c == BINARY ||
c == ECHO || c == ECHO ||
@ -195,21 +196,27 @@ static void IROM telnet_unwrap ( serbridgeConnData *conn, uint8_t *buf, int len
*/ */
espbuffsend( conn, (char[]){IAC,opt,c}, 3 ); espbuffsend( conn, (char[]){IAC,opt,c}, 3 );
state = ST_NORMAL ; state = ST_NORMAL ;
return ;
} }
else if ( state == ST_SB ) {
if ( state == ST_SB ) {
if ( c == COM_PORT_OPTION ) if ( c == COM_PORT_OPTION )
state = ST_COMPORT ; state = ST_COMPORT ;
else else
state = ST_WAIT_IAC ; state = ST_WAIT_IAC ;
return ;
} }
else if ( state == ST_WAIT_IAC ) {
if ( state == ST_WAIT_IAC ) {
if ( c == IAC ) if ( c == IAC )
state = ST_IAC ; state = ST_IAC ;
return ;
} }
else if ( state == ST_COMPORT ) {
vlen = 0 ; if ( state == ST_COMPORT ) {
if ( c == SET_BAUDRATE ) { if ( c == SET_BAUDRATE ) {
dbgf(" BAUDRATE:"); dbgf(" BAUDRATE:");
vlen = 0 ;
state = ST_BAUDRATE ; state = ST_BAUDRATE ;
} else if ( c == SET_DATASIZE ) { } else if ( c == SET_DATASIZE ) {
dbgf(" DATASIZE:"); dbgf(" DATASIZE:");
@ -230,8 +237,10 @@ static void IROM telnet_unwrap ( serbridgeConnData *conn, uint8_t *buf, int len
dbgf("UNKNOWN: %02X\n", c); dbgf("UNKNOWN: %02X\n", c);
state = ST_WAIT_IAC ; state = ST_WAIT_IAC ;
} }
return ;
} }
else if ( state == ST_BAUDRATE ) {
if ( state == ST_BAUDRATE ) {
/* /*
* Get 4 bytes of baudrate (MSB first) * Get 4 bytes of baudrate (MSB first)
*/ */
@ -241,61 +250,66 @@ static void IROM telnet_unwrap ( serbridgeConnData *conn, uint8_t *buf, int len
value += c ; value += c ;
vlen++ ; vlen++ ;
if ( vlen == 4 ) { if ( vlen == 4 ) {
if ( value == 0 ) {
/* /*
* Null value means the client requests the actual value * 4 bytes received, process the value
*
* Note: must acknowledge with the value that was set otherwise the
* pyserial client considers that the set value is rejected.
*/ */
value = (int)(0.5 + 80e6 / REG_BRR ); if ( value == 0 )
}
else {
/* /*
* Write non-null value * Get actual baudrate
*/ */
REG_BRR = (int)(0.5 + 80e6/value) ; value = (int)(0.5 + 80e6/REG_BRR);
} else
/* /*
* Acknowledge * Set baudrate
*/
REG_BRR = (int)(0.5 + 80e6/value);
/* Acknowledge
*/ */
dbgf(" = %ld\n", value); dbgf(" = %ld\n", value);
char v0 = value ; char v0 = value ;
char v1 = value >> 8 ; char v1 = value >> 8 ;
char v2 = value >> 16 ; char v2 = value >> 16 ;
char v3 = value >> 24 ; char v3 = value >> 24 ;
espbuffsend( conn, espbuffsend( conn, (char[]){IAC,SB,COM_PORT_OPTION,100+SET_BAUDRATE}, 4 );
(char[]){IAC,SB,COM_PORT_OPTION,100+SET_BAUDRATE,v3,v2,v1,v0,IAC,SE}, espbuffsend_tn( conn, (char[]){v3,v2,v1,v0}, 4 );
10 ); espbuffsend( conn, (char[]){IAC,SE}, 2 );
state = ST_WAIT_IAC ; state = ST_WAIT_IAC ;
return ;
} }
return ;
} }
else if ( state == ST_DATASIZE ) {
if ( c == 0 ) { if ( state == ST_DATASIZE ) {
/* if ( c >= 5 && c <= 8 ) {
* Null value means the client requests the actual value
*/
c = 5 + ((REG_CONF0>>2) & 0x03) ;
}
else if ( c >= 5 && c <= 8 ) {
/* /*
* Set data size
* Store databits in bits 3..2 of register conf0 * Store databits in bits 3..2 of register conf0
*/ */
REG_CONF0 = (REG_CONF0 & ~0xC) | ((c-5)<<2) ; REG_CONF0 = (REG_CONF0 & ~0xC) | ((c-5)<<2) ;
} }
if ( c >= 5 && c <= 8 ) { else {
/* /*
* Acknowledge * Get data size
*/
c = 5 + ((REG_CONF0>>2) & 0x03) ;
}
/* Acknowledge datasize
*/ */
dbgf(" %d\n", c ); dbgf(" %d\n", c );
espbuffsend( conn, (char[]){IAC,SB,COM_PORT_OPTION,100+SET_DATASIZE,c,IAC,SE},7 ); espbuffsend( conn, (char[]){IAC,SB,COM_PORT_OPTION,100+SET_DATASIZE,c,IAC,SE},7 );
}
state = ST_WAIT_IAC ; state = ST_WAIT_IAC ;
return ;
} }
else if ( state == ST_PARITY ) {
/* if ( state == ST_PARITY ) {
* CONF0 bits 1..0
*/
if ( c == 0 ) { if ( c == 0 ) {
/* /*
* Request Current Parity * Get actual parity: CONF0 bits 1..0
*/ */
c = (REG_CONF0>>2) & 0x03 ; c = (REG_CONF0>>2) & 0x03 ;
if ( c==2 ) if ( c==2 )
@ -304,10 +318,10 @@ static void IROM telnet_unwrap ( serbridgeConnData *conn, uint8_t *buf, int len
c = 2 ; c = 2 ;
else else
c = 3 ; c = 3 ;
goto parity_notify ;
} }
if ( c==1 || c==2 || c==3 ) { else if ( c==1 || c==2 || c==3 ) {
/* /*
* Set parity
* 1 NONE * 1 NONE
* 2 ODD * 2 ODD
* 3 EVEN * 3 EVEN
@ -320,23 +334,27 @@ static void IROM telnet_unwrap ( serbridgeConnData *conn, uint8_t *buf, int len
else else
d = 2 ; d = 2 ;
REG_CONF0 = (REG_CONF0 & ~0x3) | d ; REG_CONF0 = (REG_CONF0 & ~0x3) | d ;
goto parity_notify ;
} }
else {
/*
* Do not acknowledge unknown parity value
*/
state = ST_WAIT_IAC ; state = ST_WAIT_IAC ;
return ; return ;
}
parity_notify: /* Acknowledge parity
*/
dbgf(" %d\n", c ); dbgf(" %d\n", c );
espbuffsend( conn, (char[]){IAC,SB,COM_PORT_OPTION,100+SET_PARITY,c,IAC,SE},7 ); espbuffsend( conn, (char[]){IAC,SB,COM_PORT_OPTION,100+SET_PARITY,c,IAC,SE},7 );
state = ST_WAIT_IAC ; state = ST_WAIT_IAC ;
return ;
} }
else if ( state == ST_STOPSIZE ) {
/* if ( state == ST_STOPSIZE ) {
* CONF0 bits 5..4
*/
if ( c == 0 ) { if ( c == 0 ) {
/* /*
* 0 Request Current Stop Bit Size * Get actual stop bits: CONF0 bits 5..4
*/ */
c = REG_CONF0>>4 & 0x03 ; c = REG_CONF0>>4 & 0x03 ;
if ( c==2 ) if ( c==2 )
@ -346,6 +364,7 @@ static void IROM telnet_unwrap ( serbridgeConnData *conn, uint8_t *buf, int len
} }
else if ( c >= 1 && c <= 3 ) { else if ( c >= 1 && c <= 3 ) {
/* /*
* Set stop bits
* 1 1 bit * 1 1 bit
* 2 2 bits * 2 2 bits
* 3 1.5 bit * 3 1.5 bit
@ -357,44 +376,51 @@ static void IROM telnet_unwrap ( serbridgeConnData *conn, uint8_t *buf, int len
d = 2 ; d = 2 ;
REG_CONF0 = (REG_CONF0 & ~0x30) | (d<<4) ; REG_CONF0 = (REG_CONF0 & ~0x30) | (d<<4) ;
} }
if ( c >= 1 && c <= 3 ) { else {
/*
* Do not acknowledge unknown stop bits value
*/
state = ST_WAIT_IAC ;
return ;
}
/* Acknowledge stop bits
*/
dbgf(" %d\n", c ); dbgf(" %d\n", c );
espbuffsend( conn, (char[]){IAC,SB,COM_PORT_OPTION,100+SET_STOPSIZE,c,IAC,SE},7 ); espbuffsend( conn, (char[]){IAC,SB,COM_PORT_OPTION,100+SET_STOPSIZE,c,IAC,SE},7 );
}
state = ST_WAIT_IAC ; state = ST_WAIT_IAC ;
return ;
} }
else if ( state == ST_CONTROL ) {
if ( state == ST_CONTROL ) {
if ( c == 1 ) { if ( c == 1 ) {
/* /*
* Use No Flow Control (outbound/both) * Use No Flow Control (outbound/both)
* *
* Disable TX hardware flow: conf0 bit 15 = 0 * Disable TX hardware flow: CONF0 bit 15 = 0
* Disable RX hardware flow: conf1 bit 23 = 0 * Disable RX hardware flow: CONF1 bit 23 = 0
*/ */
REG_CONF0 &= ~(1ULL<<15) ; REG_CONF0 &= ~(1ULL<<15) ;
REG_CONF1 &= ~(1ULL<<23) ; REG_CONF1 &= ~(1ULL<<23) ;
goto control_notify ;
} }
else if ( c == 5 ) { else if ( c == 5 ) {
/* /*
* Set BREAK State ON * Set BREAK State ON
*/ */
REG_CONF0 |= (1ULL<<8) ; REG_CONF0 |= (1ULL<<8) ;
goto control_notify ;
} }
else if ( c == 6 ) { else if ( c == 6 ) {
/* /*
* Set BREAK State OFF * Set BREAK State OFF
*/ */
REG_CONF0 &= ~(1ULL<<8) ; REG_CONF0 &= ~(1ULL<<8) ;
goto control_notify ;
} }
else if ( c == 8 ) { else if ( c == 8 ) {
#if 0 #ifdef USE_UART_CONTROL_LINES
/* /*
* Set DTR Signal State ON * Set DTR Signal State ON
* *
* Assert DTR: conf0 bit 7 * Assert DTR: CONF0 bit 7
*/ */
REG_CONF0 |= (1ULL<<7) ; REG_CONF0 |= (1ULL<<7) ;
#else #else
@ -407,16 +433,16 @@ static void IROM telnet_unwrap ( serbridgeConnData *conn, uint8_t *buf, int len
dbgf("MCU reset gpio%d\n", mcu_reset_pin); dbgf("MCU reset gpio%d\n", mcu_reset_pin);
GPIO_OUTPUT_SET(mcu_reset_pin, 0); GPIO_OUTPUT_SET(mcu_reset_pin, 0);
} }
else dbgf("MCU reset: no pin\n"); else
dbgf("MCU reset: no pin\n");
#endif #endif
goto control_notify ;
} }
else if ( c == 9 ) { else if ( c == 9 ) {
#if 0 #ifdef USE_UART_CONTROL_LINES
/* /*
* Set DTR Signal State OFF * Set DTR Signal State OFF
* *
* Assert DTR: conf0 bit 7 * Assert DTR: CONF0 bit 7
*/ */
REG_CONF0 &= ~(1ULL<<7) ; REG_CONF0 &= ~(1ULL<<7) ;
#else #else
@ -429,183 +455,127 @@ static void IROM telnet_unwrap ( serbridgeConnData *conn, uint8_t *buf, int len
dbgf("MCU reset gpio%d\n", mcu_reset_pin); dbgf("MCU reset gpio%d\n", mcu_reset_pin);
GPIO_OUTPUT_SET(mcu_reset_pin, 1); GPIO_OUTPUT_SET(mcu_reset_pin, 1);
} }
else dbgf("MCU reset: no pin\n"); else
dbgf("MCU reset: no pin\n");
#endif #endif
goto control_notify ;
} }
else if ( c == 11 ) { else if ( c == 11 ) {
#ifdef USE_UART_CONTROL_LINES
/* /*
* Set RTS Signal State ON * Set RTS Signal State ON
* *
* Assert RTS: conf0 bit 6 = 1 * Assert RTS: CONF0 bit 6 = 1
*/ */
REG_CONF0 |= (1ULL<<6) ; REG_CONF0 |= (1ULL<<6) ;
goto control_notify ; #else
/*
* Set RTS Signal State ON
*
* Drive MCU ISP pin LOW
*/
if (mcu_isp_pin >= 0) {
dbgf("MCU ISP gpio%d\n", mcu_isp_pin);
GPIO_OUTPUT_SET(mcu_isp_pin, 0);
os_delay_us(100L);
}
else
dbgf("MCU isp: no pin\n");
slip_disabled++;
#endif
} }
else if ( c == 12 ) { else if ( c == 12 ) {
#ifdef USE_UART_CONTROL_LINES
/* /*
* Set RTS Signal State OFF * Set RTS Signal State OFF
* *
* Assert RTS: conf0 bit 6 = 0 * Assert RTS: CONF0 bit 6 = 0
*/ */
REG_CONF0 &= ~(1ULL<<6) ; REG_CONF0 &= ~(1ULL<<6) ;
goto control_notify ; #else
/*
* Set RTS Signal State OFF
*
* Drive MCU ISP pin HIGH
*/
if (mcu_isp_pin >= 0) {
GPIO_OUTPUT_SET(mcu_isp_pin, 1);
os_delay_us(100L);
} }
if (slip_disabled > 0) slip_disabled--;
#endif
}
else {
/*
* Do not acknowledge unknown control
*/
state = ST_WAIT_IAC ; state = ST_WAIT_IAC ;
return ; return ;
}
control_notify: /* Acknowledge control
*/
dbgf(" %d\n", c ); dbgf(" %d\n", c );
espbuffsend( conn, (char[]){IAC,SB,COM_PORT_OPTION,100+SET_CONTROL,c,IAC,SE},7 ); espbuffsend( conn, (char[]){IAC,SB,COM_PORT_OPTION,100+SET_CONTROL,c,IAC,SE},7 );
state = ST_WAIT_IAC ; state = ST_WAIT_IAC ;
return ;
} }
else if ( state == ST_PURGE ) {
if ( state == ST_PURGE ) {
if ( c == 1 ) { if ( c == 1 ) {
/* /*
* Purge access server receive data buffer * Purge access server receive data buffer
* *
* Reset RX FIFO: conf0 bit 17 = 1 * Reset RX FIFO: CONF0 bit 17 = 1
*/ */
// REG_CONF0 |= (1ULL<<17) ; // REG_CONF0 |= (1ULL<<17) ;
goto purge_notify ;
} }
else if ( c == 2 ) { else if ( c == 2 ) {
/* /*
* Purge access server transmit data buffer * Purge access server transmit data buffer
* *
* Reset TX FIFO: conf0 bit 18 = 1 * Reset TX FIFO: CONF0 bit 18 = 1
*/ */
// REG_CONF0 |= (1ULL<<18) ; // REG_CONF0 |= (1ULL<<18) ;
goto purge_notify ;
} }
else {
state = ST_WAIT_IAC ; state = ST_WAIT_IAC ;
return ; return ;
}
purge_notify: /* Acknowledge purge
*/
dbgf(" %d\n", c ); dbgf(" %d\n", c );
espbuffsend( conn, (char[]){IAC,SB,COM_PORT_OPTION,100+PURGE_DATA,c,IAC,SE},7 ); espbuffsend( conn, (char[]){IAC,SB,COM_PORT_OPTION,100+PURGE_DATA,c,IAC,SE},7 );
state = ST_WAIT_IAC ; state = ST_WAIT_IAC ;
return ;
} }
}
/* Unexpected char
*/
state = ST_WAIT_IAC ;
#undef state #undef state
#undef opt #undef opt
#undef vlen #undef vlen
#undef value
} }
#if 0 /* OLD TELNET */ /* Process bytes comming from a telnet connection
//===== TCP -> UART */
static void IROM telnet_process_buf ( serbridgeConnData *conn, uint8_t *buf, int len )
// Telnet protocol characters
#define IAC 255 // escape
#define WILL 251 // negotiation
#define SB 250 // subnegotiation begin
#define SE 240 // subnegotiation end
#define ComPortOpt 44 // COM port options
#define SetControl 5 // Set control lines
#define DTR_ON 8 // used here to reset microcontroller
#define DTR_OFF 9
#define RTS_ON 11 // used here to signal ISP (in-system-programming) to uC
#define RTS_OFF 12
// telnet state machine states
enum { TN_normal, TN_iac, TN_will, TN_start, TN_end, TN_comPort, TN_setControl };
// process a buffer-full on a telnet connection and return the ending telnet state
static uint8_t ICACHE_FLASH_ATTR
telnetUnwrap(uint8_t *inBuf, int len, uint8_t state)
{ {
for (int i=0; i<len; i++) {
uint8_t c = inBuf[i];
switch (state) {
default:
case TN_normal:
if (c == IAC) state = TN_iac; // escape char: see what's next
else uart0_write_char(c); // regular char
break;
case TN_iac:
switch (c) {
case IAC: // second escape -> write one to outbuf and go normal again
state = TN_normal;
uart0_write_char(c);
break;
case WILL: // negotiation
state = TN_will;
break;
case SB: // command sequence begin
state = TN_start;
break;
case SE: // command sequence end
state = TN_normal;
break;
default: // not sure... let's ignore
uart0_write_char(IAC);
uart0_write_char(c);
}
break;
case TN_will:
state = TN_normal; // yes, we do COM port options, let's go back to normal
break;
case TN_start: // in command seq, now comes the type of cmd
if (c == ComPortOpt) state = TN_comPort;
else state = TN_end; // an option we don't know, skip 'til the end seq
break;
case TN_end: // wait for end seq
if (c == IAC) state = TN_iac; // simple wait to accept end or next escape seq
break;
case TN_comPort:
if (c == SetControl) state = TN_setControl;
else state = TN_end;
break;
case TN_setControl: // switch control line and delay a tad
switch (c) {
case DTR_ON:
if (mcu_reset_pin >= 0) {
#ifdef SERBR_DBG
os_printf("MCU reset gpio%d\n", mcu_reset_pin);
#endif
GPIO_OUTPUT_SET(mcu_reset_pin, 0);
os_delay_us(100L);
}
#ifdef SERBR_DBG
else { os_printf("MCU reset: no pin\n"); }
#endif
break;
case DTR_OFF:
if (mcu_reset_pin >= 0) {
GPIO_OUTPUT_SET(mcu_reset_pin, 1);
os_delay_us(100L);
}
break;
case RTS_ON:
if (mcu_isp_pin >= 0) {
#ifdef SERBR_DBG #ifdef SERBR_DBG
os_printf("MCU ISP gpio%d\n", mcu_isp_pin); os_printf("TELNET:");
#endif for ( int i=0; i<len; i++ ) {
GPIO_OUTPUT_SET(mcu_isp_pin, 0); os_printf(" %02X", buf[i]);
os_delay_us(100L);
} }
#ifdef SERBR_DBG os_printf(" \n");
else { os_printf("MCU isp: no pin\n"); }
#endif #endif
slip_disabled++;
break; for ( int i=0 ; i<len ; i++ )
case RTS_OFF: telnet_process_char( conn, buf[i] );
if (mcu_isp_pin >= 0) {
GPIO_OUTPUT_SET(mcu_isp_pin, 1);
os_delay_us(100L);
}
if (slip_disabled > 0) slip_disabled--;
break;
}
state = TN_end;
break;
}
}
return state;
} }
#endif /* OLD TELNET */
// Generate a reset pulse for the attached microcontroller // Generate a reset pulse for the attached microcontroller
@ -697,12 +667,14 @@ serbridgeRecvCb(void *arg, char *data, unsigned short len)
#endif #endif
} }
if ( conn->conn_mode == cmTelnet ) {
// write the buffer to the uart /*
if (conn->conn_mode == cmTelnet) { * Process Telnet protocol
telnet_unwrap(conn, (uint8_t *)data, len); */
telnet_process_buf( conn, (uint8_t *)data, len );
} else { } else {
uart0_tx_buffer(data, len); // write the buffer to the uart
uart0_tx_buffer( data, len );
} }
serledFlash(50); // short blink on serial LED serledFlash(50); // short blink on serial LED
@ -735,13 +707,54 @@ sendtxbuffer(serbridgeConnData *conn)
return result; return result;
} }
// Escape '\xFF' bytes in buffer for Telnet protocol before sending it over the
// air
//
static sint8 ICACHE_FLASH_ATTR
espbuffsend_tn ( serbridgeConnData *conn, const char *data, uint16 len )
{
// How many bytes for the new buffer?
//
int n = 0 ;
for ( int i=0 ; i<len ; i++ )
if ( data[i] == 0xFF )
n++ ;
// Allocate and populate new buffer if necessary
//
if ( n ) {
char *tnbuf = os_zalloc(len+n);
if ( tnbuf == NULL ) {
os_printf("espbuffsend: could not allocate buffer for telnet escape\n");
return -128;
}
n = 0 ;
for ( int i=0 ; i<len ; i++ ) {
tnbuf[n++] = data[i] ;
if ( data[i] == 0xFF )
tnbuf[n++] = 0xFF ;
}
// Send buffer
//
sint8 result = espbuffsend( conn, tnbuf, n );
os_free( tnbuf );
return result ;
}
return espbuffsend( conn, data, len );
}
// espbuffsend adds data to the send buffer. If the previous send was completed it calls // espbuffsend adds data to the send buffer. If the previous send was completed it calls
// sendtxbuffer and espconn_sent. // sendtxbuffer and espconn_sent.
// Returns ESPCONN_OK (0) for success, -128 if buffer is full or error from espconn_sent // Returns ESPCONN_OK (0) for success, -128 if buffer is full or error from espconn_sent
// Use espbuffsend instead of espconn_sent as it solves the problem that espconn_sent must // Use espbuffsend instead of espconn_sent as it solves the problem that espconn_sent must
// only be called *after* receiving an espconn_sent_callback for the previous packet. // only be called *after* receiving an espconn_sent_callback for the previous packet.
static sint8 ICACHE_FLASH_ATTR static sint8 ICACHE_FLASH_ATTR
espbuffsend(serbridgeConnData *conn, const char *data, uint16 len) espbuffsend(serbridgeConnData *conn, const char *data, uint16 len )
{ {
if (conn->txbufferlen >= MAX_TXBUFFER) goto overflow; if (conn->txbufferlen >= MAX_TXBUFFER) goto overflow;
@ -771,7 +784,7 @@ espbuffsend(serbridgeConnData *conn, const char *data, uint16 len)
} }
return result; return result;
overflow: overflow:
if (conn->txoverflow_at) { if (conn->txoverflow_at) {
// we've already been overflowing // we've already been overflowing
if (system_get_time() - conn->txoverflow_at > 10*1000*1000) { if (system_get_time() - conn->txoverflow_at > 10*1000*1000) {
@ -812,44 +825,8 @@ console_process(char *buf, short len)
// push the buffer into each open connection // push the buffer into each open connection
for (short i=0; i<MAX_CONN; i++) { for (short i=0; i<MAX_CONN; i++) {
if (connData[i].conn) { if (connData[i].conn) {
if ( connData[i].conn_mode == cmTelnet ) { if ( connData[i].conn_mode == cmTelnet )
/* espbuffsend_tn( &connData[i], buf, len );
* Double 0xFF bytes in buf of Telnet connections
*/
// How many bytes for the new buffer?
//
int n = 0 ;
for ( int i=0 ; i<len ; i++ )
if ( buf[i] == 0xFF )
n++ ;
// Allocate and populate new buffer if necessary
//
if ( n ) {
char *tmpbuf = os_zalloc(len+n);
if ( tmpbuf == NULL ) {
os_printf("serbridge: could not allocate buffer for telnet "
"escape, conn %p\n", &connData[i]);
connData[i].txoverflow_at = system_get_time();
return ;
}
n = 0 ;
for ( int i=0 ; i<len ; i++ ) {
tmpbuf[n++] = buf[i] ;
if ( buf[i] == 0xFF )
tmpbuf[n++] = 0xFF ;
}
// Send buffer
//
espbuffsend( &connData[i], tmpbuf, n );
os_free( tmpbuf );
}
else
espbuffsend( &connData[i], buf, len );
}
else else
espbuffsend( &connData[i], buf, len ); espbuffsend( &connData[i], buf, len );
} }

@ -24,7 +24,8 @@ typedef struct serbridgeConnData {
enum connModes conn_mode; // connection mode enum connModes conn_mode; // connection mode
uint8_t tn_state; // Telnet state machine state uint8_t tn_state; // Telnet state machine state
char tn_opt ; // Telnet option char tn_opt ; // Telnet option
int tn_vlen ; // Telnet option value length uint32_t tn_value ; // Telnet option value
char tn_vlen ; // Telnet option value length
uint16 txbufferlen; // length of data in txbuffer uint16 txbufferlen; // length of data in txbuffer
char *txbuffer; // buffer for the data to send char *txbuffer; // buffer for the data to send
char *sentbuffer; // buffer sent, awaiting callback to get freed char *sentbuffer; // buffer sent, awaiting callback to get freed

Loading…
Cancel
Save