// Copyright 2015 by Thorsten von Eicken, see LICENSE.txt
# include "esp8266.h"
# include "uart.h"
# include "crc16.h"
# include "serbridge.h"
# include "serled.h"
# include "console.h"
# include "cmd.h"
uint8_t slip_disabled ; // disable slip to allow flashing of attached MCU
extern void ICACHE_FLASH_ATTR console_process ( char * buf , short len ) ;
// This SLIP parser does not conform to RFC 1055 https://tools.ietf.org/html/rfc1055,
// instead, it implements the framing implemented in https://github.com/tuanpmt/esp_bridge
// It accumulates each packet into a static buffer and calls cmd_parse() when the end
// of a packet is reached. It expects cmd_parse() to copy anything it needs from the
// buffer elsewhere as the buffer is immediately reused.
// One special feature is that if the first two characters of a packet are both printable or
// \n or \r then the parser assumes it's dealing with console debug output and calls
// slip_console(c) for each character and does not accumulate chars in the buffer until the
// next SLIP_END marker is seen. This allows random console debug output to come in between
// packets as long as each packet starts *and* ends with SLIP_END (which is an official
// variation on the SLIP protocol).
static bool slip_escaped ; // true when prev char received is escape
static bool slip_inpkt ; // true when we're after SLIP_START and before SLIP_END
# define SLIP_MAX 1024 // max length of SLIP packet
static char slip_buf [ SLIP_MAX ] ; // buffer for current SLIP packet
static short slip_len ; // accumulated length in slip_buf
// SLIP process a packet or a bunch of debug console chars
static void ICACHE_FLASH_ATTR
slip_process ( ) {
if ( slip_len < 1 ) return ;
if ( ! slip_inpkt ) {
// debug console stuff
console_process ( slip_buf , slip_len ) ;
} else {
// proper SLIP packet, invoke command processor after checking CRC
//os_printf("SLIP: rcv %d\n", slip_len);
if ( slip_len > 2 ) {
uint16_t crc = crc16_data ( ( uint8_t * ) slip_buf , slip_len - 2 , 0 ) ;
uint16_t rcv = ( ( uint16_t ) slip_buf [ slip_len - 2 ] ) | ( ( uint16_t ) slip_buf [ slip_len - 1 ] < < 8 ) ;
if ( crc = = rcv ) {
CMD_parse_packet ( ( uint8_t * ) slip_buf , slip_len - 2 ) ;
} else {
os_printf ( " SLIP: bad CRC, crc=%x rcv=%x \n " , crc , rcv ) ;
for ( short i = 0 ; i < slip_len ; i + + ) {
if ( slip_buf [ i ] > = ' ' & & slip_buf [ i ] < = ' ~ ' )
os_printf ( " %c " , slip_buf [ i ] ) ;
else
os_printf ( " \\ %02X " , slip_buf [ i ] ) ;
}
os_printf ( " \n " ) ;
}
}
}
}
#if 0
// determine whether a character is printable or not (or \r \n)
static bool ICACHE_FLASH_ATTR
slip_printable ( char c ) {
return ( c > = ' ' & & c < = ' ~ ' ) | | c = = ' \n ' | | c = = ' \r ' ;
}
# endif
static void ICACHE_FLASH_ATTR
slip_reset ( ) {
//os_printf("SLIP: reset\n");
slip_inpkt = false ;
slip_escaped = false ;
slip_len = 0 ;
}
// SLIP parse a single character
static void ICACHE_FLASH_ATTR
slip_parse_char ( char c ) {
if ( ! slip_inpkt ) {
if ( c = = SLIP_START ) {
if ( slip_len > 0 ) console_process ( slip_buf , slip_len ) ;
slip_reset ( ) ;
slip_inpkt = true ;
os_printf ( " SLIP: start \n " ) ;
return ;
}
} else if ( slip_escaped ) {
// prev char was SLIP_REPL
c = SLIP_ESC ( c ) ;
slip_escaped = false ;
} else {
switch ( c ) {
case SLIP_REPL :
slip_escaped = true ;
return ;
case SLIP_END :
// end of packet, process it and get ready for next one
if ( slip_len > 0 ) slip_process ( ) ;
slip_reset ( ) ;
return ;
case SLIP_START :
os_printf ( " SLIP: got SLIP_START while in packet? \n " ) ;
//os_printf("SLIP: rcv %d:", slip_len);
//for (int i=0; i<slip_len; i++) os_printf(" %02x", slip_buf[i]);
//os_printf("\n");
slip_reset ( ) ;
return ;
}
}
if ( slip_len < SLIP_MAX ) slip_buf [ slip_len + + ] = c ;
}
// callback with a buffer of characters that have arrived on the uart
void ICACHE_FLASH_ATTR
serbridgeUartCb ( char * buf , short length ) {
if ( slip_disabled > 0 ) {
//os_printf("SLIP: disabled got %d\n", length);
console_process ( buf , length ) ;
for ( short i = 0 ; i < length ; i + + )
if ( buf [ i ] = = SLIP_START ) {
os_printf ( " SLIP: START while disabled=%d \n " , slip_disabled ) ;
break ;
}
return ;
}
// do SLIP parsing
for ( short i = 0 ; i < length ; i + + )
slip_parse_char ( buf [ i ] ) ;
// if we're in-between packets (debug console) then print it now
if ( ! slip_inpkt & & length > 0 ) {
slip_process ( ) ;
slip_reset ( ) ;
}
serledFlash ( 50 ) ; // short blink on serial LED
}