--- picocom.c.orig	2015-06-03 22:20:37.875258061 +0200
+++ picocom.c	2021-04-17 20:16:03.266438635 +0200
@@ -37,28 +37,69 @@
 #include <sys/stat.h>
 #include <sys/wait.h>
 #include <limits.h>
+#include <time.h>
+#include <sys/time.h>
 
 #define _GNU_SOURCE
 #include <getopt.h>
 
+
+#ifdef __linux__
+#include <termio.h>
+#else
+#include <termios.h>
+#endif /* of __linux__ */
+
 #include "term.h"
 
+// Date of compilation, created by ccc script; added in order to track changes during rapid development phases.
+// Not placed to makefile in order to save the changes.
+#include "compiledate.h"
+#define VERSION_STR_SHAD VERSION_STR"-Shad-"VERSION_DATE
+
+
+
 /**********************************************************************/
 
-#define KEY_EXIT    '\x18' /* C-x: exit picocom */
-#define KEY_QUIT    '\x11' /* C-q: exit picocom without reseting port */
+//#define KEY_EXIT    '\x18' /* C-x: exit picocom */
+//#define KEY_QUIT    '\x11' /* C-q: exit picocom without reseting port */
+//#define KEY_PULSE   '\x10' /* C-p: pulse DTR */
+//#define KEY_TOGGLE  '\x14' /* C-t: toggle DTR */
+//#define KEY_BAUD_UP '\x15' /* C-u: increase baudrate (up) */
+//#define KEY_BAUD_DN '\x04' /* C-d: decrase baudrate (down) */ 
+//#define KEY_FLOW    '\x06' /* C-f: change flowcntrl mode */ 
+//#define KEY_PARITY  '\x19' /* C-y: change parity mode */ 
+//#define KEY_BITS    '\x02' /* C-b: change number of databits */ 
+//#define KEY_LECHO   '\x03' /* C-c: toggle local echo */ 
+//#define KEY_STATUS  '\x16' /* C-v: show program option */
+//#define KEY_SEND    '\x13' /* C-s: send file */
+//#define KEY_RECEIVE '\x12' /* C-r: receive file */
+//#define KEY_BREAK   '\x1c' /* C-\: break */
+
+#define KEY_BITS    '\x02' /* C-b: change number of databits */ 
+#define KEY_LECHO   '\x03' /* C-c: toggle local echo */ 
+#define KEY_BAUD_DN '\x04' /* C-d: decrase baudrate (down) */ 
+//#define KEY_RTS     '\x05' /* C-e: toggle RTS */ 
+#define KEY_RECEIVE '\x05' /* C-e: receive file */
+#define KEY_FLOW    '\x06' /* C-f: change flowcntrl mode */ 
+#define KEY_SETBAUD '\x07' /* C-g: enter arbitrary baud rate */ 
+#define KEY_HEX     '\x08' /* C-h: enter hex string, send as binary */ 
+#define KEY_PULSERTS   '\x09' /* C-i: pulse DTR */
+#define KEY_TERMRESET '\x0f' /* C-o: reset terminal */
 #define KEY_PULSE   '\x10' /* C-p: pulse DTR */
+#define KEY_QUIT    '\x11' /* C-q: exit picocom without reseting port */
+//#define KEY_RECEIVE '\x12' /* C-r: receive file */
+#define KEY_RTS     '\x12' /* C-r: toggle RTS */ 
+#define KEY_SEND    '\x13' /* C-s: send file */
 #define KEY_TOGGLE  '\x14' /* C-t: toggle DTR */
 #define KEY_BAUD_UP '\x15' /* C-u: increase baudrate (up) */
-#define KEY_BAUD_DN '\x04' /* C-d: decrase baudrate (down) */ 
-#define KEY_FLOW    '\x06' /* C-f: change flowcntrl mode */ 
-#define KEY_PARITY  '\x19' /* C-y: change parity mode */ 
-#define KEY_BITS    '\x02' /* C-b: change number of databits */ 
-#define KEY_LECHO   '\x03' /* C-c: toggle local echo */ 
 #define KEY_STATUS  '\x16' /* C-v: show program option */
-#define KEY_SEND    '\x13' /* C-s: send file */
-#define KEY_RECEIVE '\x12' /* C-r: receive file */
+#define KEY_LFDELAY '\x17' /* C-w: set LF delay in msec */
+#define KEY_EXIT    '\x18' /* C-x: exit picocom */
+#define KEY_PARITY  '\x19' /* C-y: change parity mode */ 
+#define KEY_SHELL   '\x1a' /* C-z: spawn shell */ 
 #define KEY_BREAK   '\x1c' /* C-\: break */
+#define KEY_HELP    '?'    /* ?:   show key mapping */
 
 #define STO STDOUT_FILENO
 #define STI STDIN_FILENO
@@ -74,31 +115,56 @@
 #define M_IGNLF  (1 << 5) /* map LF  --> <nothing> */
 #define M_DELBS  (1 << 6) /* map DEL --> BS */
 #define M_BSDEL  (1 << 7) /* map BS  --> DEL */
-#define M_NFLAGS 8
+#define M_HEX    (1 << 8) /* enable hex dump as specified by opts.hexmap */
+#define M_SWCASE (1 << 9) /* convert lowercase to uppercase, for gcode */
+//#define M_NFLAGS 9
+#define M_REVBITS (1 << 10 ) /* reverse bit order, MSB/LSB */
+#define M_INVBITS (1 << 10 ) /* invert bits */
+#define M_NFLAGS 12
 
 /* default character mappings */
-#define M_I_DFL 0
+#define M_I_DFL M_HEX
 #define M_O_DFL 0
-#define M_E_DFL (M_DELBS | M_CRCRLF)
+#define M_E_DFL (M_DELBS | M_CRCRLF | M_HEX)
+
+/* hex dump handling */
+#define HEX_NONE 0
+#define HEX_NOASCII 1
+#define HEX_ALL 255
+
+/* color handling */
+#define COLOR_NONE 0
+#define COLOR_NORMAL 1
+#define COLOR_BRIGHT 2
+
+
 
 /* character mapping names */
 struct map_names_s {
 	char *name;
 	int flag;
 } map_names[] = {
-	{ "crlf", M_CRLF },
+	{ "crlf"  , M_CRLF },
 	{ "crcrlf", M_CRCRLF },
-	{ "igncr", M_IGNCR },
-    { "lfcr", M_LFCR },
+	{ "igncr" , M_IGNCR },
+	{ "lfcr"  , M_LFCR },
 	{ "lfcrlf", M_LFCRLF },
-	{ "ignlf", M_IGNLF },
-	{ "delbs", M_DELBS },
-	{ "bsdel", M_BSDEL },
+	{ "ignlf" , M_IGNLF },
+	{ "delbs" , M_DELBS },
+	{ "bsdel" , M_BSDEL },
+	{ "hexmap", M_HEX },
+	{ "swcase", M_SWCASE },
+        { "msb"   , M_REVBITS },
+        { "inv"   , M_INVBITS },
 	/* Sentinel */
 	{ NULL, 0 } 
 };
 
 int
+fd_printf (int fd, const char *format, ...);
+
+
+int
 parse_map (char *s)
 {
 	char *m, *t;
@@ -123,12 +189,14 @@
 void
 print_map (int flags)
 {
-	int i;
+	int i,j=0;
 
 	for (i = 0; i < M_NFLAGS; i++)
-		if ( flags & (1 << i) )
-			printf("%s,", map_names[i].name);
-	printf("\n");
+		if ( flags & (1 << i) ) {
+			if(j)fd_printf(STO,",");
+			fd_printf(STO,"%s", map_names[i].name); j++;
+		}
+	fd_printf(STO,"\r\n");
 }
 
 /**********************************************************************/
@@ -141,6 +209,7 @@
 	enum parity_e parity;
 	char *parity_str;
 	int databits;
+        int stopbits;
 	int lecho;
 	int noinit;
 	int noreset;
@@ -150,9 +219,17 @@
 	unsigned char escape;
 	char send_cmd[128];
 	char receive_cmd[128];
+	char terminal_reset_cmd[128];
 	int imap;
 	int omap;
 	int emap;
+	int hexmap;
+	int color;
+	int initdtr;
+	int initrts;
+	int watchmodemlines;
+        useconds_t lfdelay;
+        long autolf;
 } opts = {
 	.port = "",
 	.baud = 9600,
@@ -161,6 +238,7 @@
 	.parity = P_NONE,
 	.parity_str = "none",
 	.databits = 8,
+        .stopbits = 1,
 	.lecho = 0,
 	.noinit = 0,
 	.noreset = 0,
@@ -170,9 +248,17 @@
 	.escape = '\x01',
 	.send_cmd = "sz -vv",
 	.receive_cmd = "rz -vv",
+	.terminal_reset_cmd = "reset",
+	.hexmap = HEX_NOASCII,
+	.color = COLOR_NONE,
+	.initdtr = -1,
+	.initrts = -1,
+	.watchmodemlines = 1,
 	.imap = M_I_DFL,
 	.omap = M_O_DFL,
-	.emap = M_E_DFL
+	.emap = M_E_DFL,
+        .lfdelay = 0,
+        .autolf = 0
 };
 
 int tty_fd;
@@ -261,6 +347,17 @@
 
 /**********************************************************************/
 
+#define COL_RESET 0
+#define COL_IN  1
+#define COL_IN_HEX 2
+#define COL_OUT 3
+#define COL_OUT_HEX 4
+#define COL_SYS 5
+#define COL_MODEMLINES 6
+
+int color_last=COL_RESET;
+int color=COL_RESET;
+
 ssize_t
 writen_ni(int fd, const void *buff, size_t n)
 {
@@ -282,21 +379,106 @@
 	return n - nl;
 }
 
+#define ANSI_COLOR_RED      "\x1b[0;31m"
+#define ANSI_COLOR_GREEN    "\x1b[0;32m"
+#define ANSI_COLOR_YELLOW   "\x1b[0;33m"
+#define ANSI_COLOR_BLUE     "\x1b[0;34m"
+#define ANSI_COLOR_MAGENTA  "\x1b[0;35m"
+#define ANSI_COLOR_CYAN     "\x1b[0;36m"
+#define ANSI_COLOR_BRED     "\x1b[1;31m"
+#define ANSI_COLOR_BGREEN   "\x1b[1;32m"
+#define ANSI_COLOR_BYELLOW  "\x1b[1;33m"
+#define ANSI_COLOR_BBLUE    "\x1b[1;34m"
+#define ANSI_COLOR_BMAGENTA "\x1b[1;35m"
+#define ANSI_COLOR_BCYAN    "\x1b[1;36m"
+#define ANSI_COLOR_RESET    "\x1b[0m"
+
+
+char*getcolor(int color)
+{
+	switch(color) {
+	case COL_IN:
+		if(opts.color==COLOR_BRIGHT)return ANSI_COLOR_BGREEN;
+		return ANSI_COLOR_GREEN;
+	case COL_OUT:
+		if(opts.color==COLOR_BRIGHT)return ANSI_COLOR_BRED;
+		return ANSI_COLOR_RED;
+	case COL_IN_HEX:
+		if(opts.color==COLOR_BRIGHT)return ANSI_COLOR_GREEN;
+		return ANSI_COLOR_BGREEN;
+	case COL_OUT_HEX:
+		if(opts.color==COLOR_BRIGHT)return ANSI_COLOR_RED;
+		return ANSI_COLOR_BRED;
+	case COL_SYS:
+		return ANSI_COLOR_BYELLOW;
+	case COL_MODEMLINES:
+		return ANSI_COLOR_CYAN;
+	default:
+		return ANSI_COLOR_RESET;
+	}
+}
+
+void printcolor()
+{
+	char*sp;
+	if(opts.color==COLOR_NONE)return;
+	if(color_last==color)return;
+	sp=getcolor(color);
+	writen_ni(STO,sp,strlen(sp));
+//char s[32];sprintf(s,"[col:%i:%i]",color,color_last);writen_ni(STO,s,strlen(s));
+	color_last=color;
+}
+
+void printsetcolor(int col)
+{
+	char*sp;
+	if(opts.color==COLOR_NONE)return;
+	color=col;
+//char s[32];sprintf(s,"{%i}",col);writen_ni(STO,s,strlen(s));
+//char s[32];sprintf(s,"[col:%i:%i[%c]]",color,color_last,c);writen_ni(STO,s,strlen(s));
+	if(color_last==color)return;
+	sp=getcolor(color);
+	writen_ni(STO,sp,strlen(sp));
+	color_last=color;
+}
+
+/*
+void printsetcolor2(int col)
+{
+	char*sp;
+	color=col;
+char s[32];sprintf(s,"[col:%i:%i:%i]",color,color_last,col);writen_ni(STO,s,strlen(s));
+	if(color_last==color)return;
+	sp=getcolor(color);
+	writen_ni(STO,sp,strlen(sp));
+	color_last=color;
+}
+*/
+
+void printdebug(char c,char c2,char*s1)
+{
+char s[32];sprintf(s,"{%c|%c|%s}",c,c2,s1);writen_ni(STO,s,strlen(s));
+}
+
+
+
 int
 fd_printf (int fd, const char *format, ...)
 {
 	char buf[256];
 	va_list args;
 	int len;
-	
+
 	va_start(args, format);
 	len = vsnprintf(buf, sizeof(buf), format, args);
 	buf[sizeof(buf) - 1] = '\0';
 	va_end(args);
-	
+
+	if(fd==STO)printcolor();
 	return writen_ni(fd, buf, len);
 }
 
+
 void
 fatal (const char *format, ...)
 {
@@ -306,12 +488,13 @@
 
 	term_reset(STO);
 	term_reset(STI);
-	
+
 	va_start(args, format);
 	len = vsnprintf(buf, sizeof(buf), format, args);
 	buf[sizeof(buf) - 1] = '\0';
 	va_end(args);
 	
+	printsetcolor(COL_SYS);
 	s = "\r\nFATAL: ";
 	writen_ni(STO, s, strlen(s));
 	writen_ni(STO, buf, len);
@@ -370,15 +553,72 @@
 
 #undef cput
 
+int ishexdigit(char c)
+{ if(c>='0')if(c<='9')return 1;
+  if(c>='A')if(c<='F')return 1;
+  if(c>='a')if(c<='f')return 1;
+  return 0;
+}
+
+int gethexdigit(char c)
+{ if(c>='0')if(c<='9')return c-'0';
+  if(c>='A')if(c<='F')return c-'A'+0x0a;
+  if(c>='a')if(c<='f')return c-'a'+0x0a;
+  return 0;
+}
+
+int gethex(char*sp)
+{ //int c=0;
+  return (gethexdigit(sp[0])<<4) + gethexdigit(sp[1]);
+}
+
+
 /* maximum number of chars that can replace a single characted
    due to mapping */
-#define M_MAXMAP 4
+#define M_MAXMAP 6
+
+int do_map_hex(char*b,char c)
+{
+	if(color==COL_IN) color=COL_IN_HEX; else
+	if(color==COL_OUT) color=COL_OUT_HEX;
+	sprintf(b,"[%02X]",(unsigned char)c);
+	return 4;
+}
+
+char revbits(char c)
+{
+  char c2=0;
+  int t;
+  char b1=1,b2=0x80;
+  for(t=0;t<8;t++){
+    if(c&b1)c2|=b2;
+    b1=b1<<1;
+    b2=b2>>1;
+  }
+  return c2;
+}
+
+char invbits(char c)
+{
+  return ~c;
+}
 
 int
 do_map (char *b, int map, char c)
 {
 	int n;
 
+        if (map & M_REVBITS ) c=revbits(c);
+        if (map & M_INVBITS ) c=invbits(c);
+
+	if( map & M_HEX ) if(opts.hexmap==HEX_ALL) {
+		return do_map_hex(b,c);
+	}
+        if( map & M_SWCASE ){
+           if(isupper(c))c=tolower(c);
+                    else c=toupper(c);
+        }
+
 	switch (c) {
 	case '\x7f':
 		/* DEL mapings */
@@ -421,6 +661,14 @@
 		}
 		break;
 	default:
+		if( map & M_HEX ) if(opts.hexmap) {
+//			if((c<0x20)||((c>=0x80)&&(c<0xA0))){
+			if(((unsigned char)c<0x20)||((unsigned char)c>=0x80)){
+//				sprintf(b,"[%02X]",(unsigned char)c);
+				n=do_map_hex(b,c);
+				break;
+			}
+		}
 		b[0] = c; n = 1;
 		break;
 	}
@@ -433,56 +681,147 @@
 {
 	char b[M_MAXMAP];
 	int n;
-		
+
 	n = do_map(b, map, c);
-	if ( n )
+	if(fd==STO)printcolor();
+	if ( n ){
 		if ( writen_ni(fd, b, n) < n )
-			fatal("write to stdout failed: %s", strerror(errno));		
+			fatal("write to stdout failed: %s", strerror(errno));
+                if(fd!=STO){usleep(opts.lfdelay);fd_printf(STO,"[SLEEP]\r\n");}
+        }
 }
 
+void 
+map_and_write_color (int fd, int map, char c,int col)
+{
+//	printsetcolor(col);
+	color=col;
+	map_and_write(fd,map,c);
+}
+
+
 /**********************************************************************/
 
-int
-baud_up (int baud)
+#define BAUDCOUNT 64
+
+/*
+int baudrates[BAUDCOUNT]={
+  75, 150, 300, 600, 1200, 2400, 4800, 9600,
+  19200, 38400, 57600, 115200, 230400, 250000, 460800, 921600,
+  0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0
+};*/
+int baudrates[BAUDCOUNT];
+
+// list the baud rates in the array
+void baud_dump()
+{
+	int t;
+	fd_printf(STO,"baudrates: ");
+	for(t=0;t<BAUDCOUNT;t++){
+		if(!baudrates[t])continue;
+		if(t)fd_printf(STO,",");
+		fd_printf(STO,"%i",baudrates[t]);
+	}
+	fd_printf(STO,"\r\n");
+}
+
+void baud_clear()
 {
-	if ( baud < 300 )
-		baud = 300;
-	else if ( baud == 38400 )
-		baud = 57600;
-	else	
-		baud = baud * 2;
-#ifndef HIGH_BAUD
-	if ( baud > 115200 )
-		baud = 115200;
-#else
-	if ( baud > 921600 )
-		baud = 921600;
-#endif
+	int t;
+//fd_printf(STO,"baudrates clear\n");
+	for(t=0;t<BAUDCOUNT;t++)baudrates[t]=0;
+}
 
-	return baud;
+// add a value to the array
+void baud_add(int baud)
+{
+	int t,t1;
+//	if(baud<baudrates[0])return;
+	if(baud<0)return;
+	for(t=0;t<BAUDCOUNT;t++){
+		if(baudrates[t]==baud)return;
+		if(baudrates[t]>baud){
+			for(t1=BAUDCOUNT-1;t1>t;t1--){
+				baudrates[t1]=baudrates[t1-1];
+			}
+			baudrates[t]=baud;
+			return;
+		}
+		if(baudrates[t]==0){baudrates[t]=baud;return;}
+	}
 }
 
-int
-baud_down (int baud)
+// see list of baud rates for CP2102: https://www.silabs.com/Support%20Documents/TechnicalDocs/an205.pdf
+// modem - from http://digital.ni.com/public.nsf/allkb/D37754FFA24F7C3F86256706005B9BE7
+//#define BAUDLIST_DEFAULT "300,600,1200,2400,4800,9600,19200,38400,57600,115200,230400,460800,921600"
+#define BAUDLIST_DEFAULT "300,600,1200,2400,4800,9600,19200,38400,57600,115200,230400,250000,460800,500000,921600"
+#define BAUDLIST_CP2101_ADD "1800,7200,14400,28800,56000,128000"
+#define BAUDLIST_CP2102_ADD "4000,16000,51200,64000,76800,153600,250000,256000,500000,576000"
+#define BAUDLIST_MIDI "31250,125000,250000"
+#define BAUDLIST_CAN_ADD "128000,153600,250000,256000,500000,1000000"
+#define BAUDLIST_ESP8266_ADD "74880,1843200,2686400"
+#define BAUDLIST_ESP8266ONLY_ADD "9600,74880,115200"
+#define BAUDLIST_NICAN "5000,6150,7813,8000,10000,12500,15625,16000,20000,25000,31250,40000,50000,62500,80000,100000,125000,160000,200000,250000,400000,500000,800000,1000000"
+
+
+void baud_addstrstr(char*s)
 {
-#ifndef HIGH_BAUD
-	if ( baud > 115200 )
-		baud = 115200;
-#else
-	if ( baud > 921600 )
-		baud = 921600;
-#endif
-	else if ( baud == 57600 )
-		baud = 38400;
-	else
-		baud = baud / 2;
+	char*sp;
+	int i;
+	do{
+		sp=strchr(s,',');
+		i=atoi(s);
+		s=sp;s++;
+		if(!i)continue;
+		baud_add(i);
+	}while(sp);
+}
+
+void baud_addstr(char*s,int clear)
+{
+//baud_dump();
+//fd_printf(STO,"baudrates addstr: %i : %s\n",clear,s);
+	if(clear)baud_clear();
+//baud_dump();
+	if(!strcasecmp(s,"DEFAULT")){baud_addstrstr(BAUDLIST_DEFAULT);return;}
+	if(!strcasecmp(s,"CP2101")){baud_addstrstr(BAUDLIST_DEFAULT);baud_addstrstr(BAUDLIST_CP2101_ADD);return;}
+	if(!strcasecmp(s,"CP2102")){baud_addstrstr(BAUDLIST_DEFAULT);baud_addstrstr(BAUDLIST_CP2101_ADD);baud_addstrstr(BAUDLIST_CP2102_ADD);return;}
+	if(!strcasecmp(s,"CP"))    {baud_addstrstr(BAUDLIST_DEFAULT);baud_addstrstr(BAUDLIST_CP2101_ADD);baud_addstrstr(BAUDLIST_CP2102_ADD);return;}
+	if(!strcasecmp(s,"MIDI")){baud_addstrstr(BAUDLIST_MIDI);return;}
+	if(!strcasecmp(s,"CAN")){baud_addstrstr(BAUDLIST_DEFAULT);baud_addstrstr(BAUDLIST_CAN_ADD);return;}
+	if(!strcasecmp(s,"ESP8266")){baud_addstrstr(BAUDLIST_DEFAULT);baud_addstrstr(BAUDLIST_ESP8266_ADD);return;}
+	if(!strcasecmp(s,"ESP"))    {baud_addstrstr(BAUDLIST_DEFAULT);baud_addstrstr(BAUDLIST_ESP8266_ADD);return;}
+	if(!strcasecmp(s,"ESPONLY")){baud_addstrstr(BAUDLIST_ESP8266ONLY_ADD);return;}
+// NI-CAN baud rates from National Instruments - http://www.ni.com/tutorial/4304/en/
+	if(!strcasecmp(s,"NICAN")){baud_addstrstr(BAUDLIST_NICAN);return;}
+	baud_addstrstr(s);
+//baud_dump();
+}
 
-	if ( baud < 300)
-		baud = 300;
 
+int baud_up (int baud)
+{
+	int t;
+	if(baud<baudrates[0])return baudrates[0];
+	for(t=0;t<BAUDCOUNT;t++){
+		if(baudrates[t]==0)break;
+		if(baudrates[t]>baud)return baudrates[t];
+	}
 	return baud;
 }
 
+int baud_down (int baud)
+{
+	int t;
+	if(baud<baudrates[0])return baudrates[0];
+	for(t=BAUDCOUNT-1;t>=0;t--){
+		if(baudrates[t]==0)continue;
+		if(baudrates[t]<baud)return baudrates[t];
+	}
+	return baudrates[0];
+}
+
 int
 flow_next (int flow, char **flow_str)
 {
@@ -542,6 +881,14 @@
 	return bits;
 }
 
+
+void getportopts()
+{
+
+}
+
+
+
 /**********************************************************************/
 
 void
@@ -553,12 +900,12 @@
 establish_child_signal_handlers (void)
 {
 	struct sigaction empty_action;
-	
+
 	/* Set up the structure to specify the "empty" action. */
-    empty_action.sa_handler = child_empty_handler;
+        empty_action.sa_handler = child_empty_handler;
 	sigemptyset (&empty_action.sa_mask);
 	empty_action.sa_flags = 0;
-	
+
 	sigaction (SIGINT, &empty_action, NULL);
 	sigaction (SIGTERM, &empty_action, NULL);
 }
@@ -625,7 +972,7 @@
 			const char *s;
 			int n;
 			va_list vls;
-			
+
 			c = cmd;
 			ce = cmd + sizeof(cmd) - 1;
 			va_start(vls, fd);
@@ -657,6 +1004,121 @@
 
 /**********************************************************************/
 
+void printhelp(char*key,char*desc)
+{
+	fd_printf(STO,"    %-6s:  %s\r\n",key,desc);
+}
+
+void printhelp_section(char*desc)
+{
+	fd_printf(STO,"%s\r\n",desc);
+}
+
+int getdtr(int tty)
+{
+	int i;
+	i=term_get_modem_flags(tty);
+	if(i&TIOCM_DTR)return 1;
+	return 0;
+}
+
+int getrts(int tty)
+{
+	int i;
+	i=term_get_modem_flags(tty);
+	if(i&TIOCM_RTS)return 1;
+	return 0;
+}
+
+void print_modem_flags_raw(int tty)
+{
+	int i;
+	i=term_get_modem_flags(tty);
+	//fd_printf(STO,"[%02X] ",i);
+	if(i&TIOCM_DTR)fd_printf(STO,"DTR+ ");else fd_printf(STO,"dtr- ");
+	if(i&TIOCM_RTS)fd_printf(STO,"RTS+ ");else fd_printf(STO,"rts- ");
+	if(i&TIOCM_CTS)fd_printf(STO,"CTS+ ");else fd_printf(STO,"cts- ");
+	if(i&TIOCM_CAR)fd_printf(STO,"DCD+ ");else fd_printf(STO,"dcd- ");
+	if(i&TIOCM_DSR)fd_printf(STO,"DSR+ ");else fd_printf(STO,"dsr- ");
+	if(i&TIOCM_RNG)fd_printf(STO,"RI+ "); else fd_printf(STO,"ri- ");
+}
+
+void print_modem_flags(int tty, int laststars)
+{
+	fd_printf(STO,"*** modem: ");
+	print_modem_flags_raw(tty);
+	if(laststars)fd_printf(STO,"***");
+	fd_printf(STO,"\r\n");
+}
+
+int modemflags_old;
+
+void modemflags_printdiff(int old,int i,int flag,char*nameu,char*namel)
+{
+	int bitnew,bitold;
+	bitold=old&flag;
+	bitnew=i&flag;
+	if(bitold==bitnew)return;
+	if(bitnew){fd_printf(STO,"[%s+]",nameu);return;}
+	fd_printf(STO,"[%s-]",namel);
+}
+
+void printmodemflagsdiff(int tty)
+{
+	int i;
+	i=term_get_modem_flags(tty);
+	if(modemflags_old!=i){
+		printsetcolor(COL_MODEMLINES);
+		modemflags_printdiff(modemflags_old,i,TIOCM_DTR,"DTR","dtr");
+		modemflags_printdiff(modemflags_old,i,TIOCM_RTS,"RTS","rts");
+		modemflags_printdiff(modemflags_old,i,TIOCM_CTS,"CTS","cts");
+		modemflags_printdiff(modemflags_old,i,TIOCM_CAR,"DCD","dcd");
+		modemflags_printdiff(modemflags_old,i,TIOCM_DSR,"DSR","dsr");
+		modemflags_printdiff(modemflags_old,i,TIOCM_RNG,"RI" ,"ri" );
+	}
+	modemflags_old=i;
+}
+
+void get_opts_from_port(int tty)
+{
+	int cflag,iflag;
+	int f;
+	opts.baud=term_get_baudrate(tty);
+	cflag=term_get_cflag(tty);
+	iflag=term_get_iflag(tty);
+	f=cflag&CSIZE;
+	if(f==CS5)opts.databits=5;else
+	if(f==CS6)opts.databits=6;else
+	if(f==CS7)opts.databits=7;else
+	if(f==CS8)opts.databits=8;
+	if(!(cflag&PARENB)){opts.parity=P_NONE;opts.parity_str="none";}else {
+			if(cflag&PARODD){opts.parity=P_EVEN;opts.parity_str="even";}
+				else    {opts.parity=P_ODD;opts.parity_str="odd";}
+	}
+        if(cflag&CSTOPB)opts.stopbits=2;else opts.stopbits=1;
+	opts.flow=FC_NONE;opts.flow_str="none";
+	if(iflag&IXON){opts.flow=FC_XONXOFF;opts.flow_str="xon/xoff";}
+	if(cflag&CRTSCTS){opts.flow=FC_RTSCTS;opts.flow_str="RTS/CTS";}
+}
+
+long time_start;
+
+void abs_clk_init(){
+        struct timeval t;
+        gettimeofday(&t,NULL);
+        time_start=t.tv_sec;
+}
+
+long abs_clk(){
+        struct timeval t;
+        long l;
+        gettimeofday(&t,NULL);
+        l=t.tv_sec-time_start;
+        l*=1000;
+        l+=t.tv_usec/1000;
+        return l;
+}
+
 void
 loop(void)
 {
@@ -665,17 +1127,38 @@
 		ST_TRANSPARENT
 	} state;
 	int dtr_up;
+	int rts_up;
 	fd_set rdset, wrset;
 	int newbaud, newflow, newparity, newbits;
+        int newlfdelay;
+        int islfdelay=0;
 	char *newflow_str, *newparity_str;
 	char fname[128];
 	int r, n;
 	unsigned char c;
+        clock_t clk_lastin; // last time a byte came in from the port
+        int delaylfsent=1;
+        // on raspi linux, CLOCKS_PER_SEC = 1,000,000
+//        clock_t clk_lfdiff=1000; // 1 second for a time-forced newline
+        clock_t clk_lastmodem; // last time we checked the modem flags
+        clock_t clk_now;
+        clock_t clk_modemdiff=25; // check 20 times per second - takes long time!
+//	struct timeval tv = {0,100000}; // timeout 100 msec (in usec) for the read loop, to monitor modem lines
+//	struct timeval tv = {0,25000000}; // timeout 25 msec (in nsec) for the read loop, to monitor modem lines
+	struct timespec tv = {0,100000000}; // timeout 1s (in nsec) for the read loop, to monitor modem lines
 
+        abs_clk_init();
 
 	tty_q.len = 0;
 	state = ST_TRANSPARENT;
-	dtr_up = 0;
+	//dtr_up = 0;
+	dtr_up = getdtr(tty_fd);
+	rts_up = getrts(tty_fd);
+	modemflags_old=term_get_modem_flags(tty_fd);
+        clk_lastmodem=abs_clk();
+        clk_lastin=abs_clk();
+
+//fd_printf(STO,"clk:%d,CPS=%d\r\n",clock(),CLOCKS_PER_SEC);
 
 	for (;;) {
 		FD_ZERO(&rdset);
@@ -684,21 +1167,47 @@
 		FD_SET(tty_fd, &rdset);
 		if ( tty_q.len ) FD_SET(tty_fd, &wrset);
 
-		if (select(tty_fd + 1, &rdset, &wrset, NULL, NULL) < 0)
+//		if (select(tty_fd + 1, &rdset, &wrset, NULL, NULL) < 0)
+		if (pselect(tty_fd + 1, &rdset, &wrset, NULL, &tv,NULL) < 0)
 			fatal("select failed: %d : %s", errno, strerror(errno));
 
+                clk_now=abs_clk();
+//                fd_printf(STO,".");
+
+//fd_printf(STO,"CLK:%d,D=%d\r\n",clk_now,clk_now-clk_lastin);
+
+        	if(opts.watchmodemlines)
+                  if(clk_now-clk_lastmodem>clk_modemdiff){
+                    printmodemflagsdiff(tty_fd);
+                    clk_lastmodem=clk_now;}
+
+                //if(delaylfsent==0)
+//                  fd_printf(STO,".");
+                if(opts.autolf)
+                  if(delaylfsent==0)if(clk_now-clk_lastin>opts.autolf){
+                    printsetcolor(COL_SYS);
+                    fd_printf(STO,"<\r\n");
+//                    fsync(STO);
+                    delaylfsent=1;
+//clk_lastin=abs_clk();
+                  }
+
+                if(islfdelay)goto skip_proc_STI;
+
 		if ( FD_ISSET(STI, &rdset) ) {
 
 			/* read from terminal */
 
 			do {
 				n = read(STI, &c, 1);
+//Shad's mod
+//fd_printf(STO,"[%02x]",c);
 			} while (n < 0 && errno == EINTR);
 			if (n == 0) {
 				fatal("stdin closed");
 			} else if (n < 0) {
 				/* is this really necessary? better safe than sory! */
-				if ( errno != EAGAIN && errno != EWOULDBLOCK ) 
+				if ( errno != EAGAIN && errno != EWOULDBLOCK )
 					fatal("read from stdin failed: %s", strerror(errno));
 				else
 					goto skip_proc_STI;
@@ -711,16 +1220,17 @@
 					state = ST_TRANSPARENT;
 					/* pass the escape character down */
 					if (tty_q.len + M_MAXMAP <= TTY_Q_SZ) {
-						n = do_map((char *)tty_q.buff + tty_q.len, 
+						n = do_map((char *)tty_q.buff + tty_q.len,
 								   opts.omap, c);
 						tty_q.len += n;
-						if ( opts.lecho ) 
+						if ( opts.lecho )
 							map_and_write(STO, opts.emap, c);
 					} else 
 						fd_printf(STO, "\x07");
 					break;
 				}
 				state = ST_TRANSPARENT;
+				color=COL_SYS;
 				switch (c) {
 				case KEY_EXIT:
 					return;
@@ -731,32 +1241,79 @@
 					term_erase(tty_fd);
 					return;
 				case KEY_STATUS:
+					opts.baud=term_get_baudrate(tty_fd); // reread, to be sure
+					get_opts_from_port(tty_fd); // reread, to be sure
+					dtr_up=getdtr(tty_fd);
+					printsetcolor(COL_SYS);
 					fd_printf(STO, "\r\n");
 					fd_printf(STO, "*** baud: %d\r\n", opts.baud);
 					fd_printf(STO, "*** flow: %s\r\n", opts.flow_str);
 					fd_printf(STO, "*** parity: %s\r\n", opts.parity_str);
 					fd_printf(STO, "*** databits: %d\r\n", opts.databits);
+					fd_printf(STO, "*** stopbits: %d\r\n", opts.stopbits);
 					fd_printf(STO, "*** dtr: %s\r\n", dtr_up ? "up" : "down");
+					print_modem_flags(tty_fd,0);
 					break;
 				case KEY_PULSE:
-					fd_printf(STO, "\r\n*** pulse DTR ***\r\n");
-					if ( term_pulse_dtr(tty_fd) < 0 )
-						fd_printf(STO, "*** FAILED\r\n");
+					dtr_up=getdtr(tty_fd);
+					if ( dtr_up )r = term_lower_dtr(tty_fd);
+						else r = term_raise_dtr(tty_fd);
+					if ( r >= 0 ) dtr_up = ! dtr_up;
+					printsetcolor(COL_SYS);
+					if(opts.watchmodemlines)printmodemflagsdiff(tty_fd);
+					sleep(1);
+					if ( dtr_up )r = term_lower_dtr(tty_fd);
+						else r = term_raise_dtr(tty_fd);
+					if ( r >= 0 ) dtr_up = ! dtr_up;
+					printsetcolor(COL_SYS);
+					if(opts.watchmodemlines)printmodemflagsdiff(tty_fd);
+					break;
+				case KEY_PULSERTS:
+					rts_up=getrts(tty_fd);
+					if ( rts_up )r = term_lower_rts(tty_fd);
+						else r = term_raise_rts(tty_fd);
+					if ( r >= 0 ) rts_up = ! rts_up;
+					printsetcolor(COL_SYS);
+					if(opts.watchmodemlines)printmodemflagsdiff(tty_fd);
+					sleep(1);
+					if ( rts_up )r = term_lower_rts(tty_fd);
+						else r = term_raise_rts(tty_fd);
+					if ( r >= 0 ) rts_up = ! rts_up;
+					printsetcolor(COL_SYS);
+					if(opts.watchmodemlines)printmodemflagsdiff(tty_fd);
 					break;
 				case KEY_TOGGLE:
+					dtr_up=getdtr(tty_fd);
 					if ( dtr_up )
 						r = term_lower_dtr(tty_fd);
 					else
 						r = term_raise_dtr(tty_fd);
 					if ( r >= 0 ) dtr_up = ! dtr_up;
-					fd_printf(STO, "\r\n*** DTR: %s ***\r\n", 
+					printsetcolor(COL_SYS);
+					if(opts.watchmodemlines)printmodemflagsdiff(tty_fd);
+					else fd_printf(STO, "\r\n*** DTR: %s ***\r\n", 
 							  dtr_up ? "up" : "down");
+					//print_modem_flags(tty_fd,1);
+					break;
+				case KEY_RTS:
+					rts_up=getrts(tty_fd);
+					if ( rts_up )
+						r = term_lower_rts(tty_fd);
+					else
+						r = term_raise_rts(tty_fd);
+					if ( r >= 0 ) rts_up = ! rts_up;
+					printsetcolor(COL_SYS);
+					if(opts.watchmodemlines)printmodemflagsdiff(tty_fd);
+					else fd_printf(STO, "\r\n*** RTS: %s ***\r\n", 
+							  rts_up ? "up" : "down");
+					//print_modem_flags(tty_fd,1);
 					break;
 				case KEY_BAUD_UP:
 					newbaud = baud_up(opts.baud);
 					term_set_baudrate(tty_fd, newbaud);
 					tty_q.len = 0; term_flush(tty_fd);
 					if ( term_apply(tty_fd) >= 0 ) opts.baud = newbaud;
+					printsetcolor(COL_SYS);
 					fd_printf(STO, "\r\n*** baud: %d ***\r\n", opts.baud);
 					break;
 				case KEY_BAUD_DN:
@@ -764,6 +1321,7 @@
 					term_set_baudrate(tty_fd, newbaud);
 					tty_q.len = 0; term_flush(tty_fd);
 					if ( term_apply(tty_fd) >= 0 ) opts.baud = newbaud;
+					printsetcolor(COL_SYS);
 					fd_printf(STO, "\r\n*** baud: %d ***\r\n", opts.baud);
 					break;
 				case KEY_FLOW:
@@ -774,6 +1332,7 @@
 						opts.flow = newflow;
 						opts.flow_str = newflow_str;
 					}
+					printsetcolor(COL_SYS);
 					fd_printf(STO, "\r\n*** flow: %s ***\r\n", opts.flow_str);
 					break;
 				case KEY_PARITY:
@@ -784,6 +1343,7 @@
 						opts.parity = newparity;
 						opts.parity_str = newparity_str;
 					}
+					printsetcolor(COL_SYS);
 					fd_printf(STO, "\r\n*** parity: %s ***\r\n", 
 							  opts.parity_str);
 					break;
@@ -792,11 +1352,14 @@
 					term_set_databits(tty_fd, newbits);
 					tty_q.len = 0; term_flush(tty_fd);
 					if ( term_apply(tty_fd) >= 0 ) opts.databits = newbits;
+					get_opts_from_port(tty_fd); // read actual bits from the port
+					printsetcolor(COL_SYS);
 					fd_printf(STO, "\r\n*** databits: %d ***\r\n", 
 							  opts.databits);
 					break;
 				case KEY_LECHO:
 					opts.lecho = ! opts.lecho;
+					printsetcolor(COL_SYS);
 					fd_printf(STO, "\r\n*** local echo: %s ***\r\n", 
 							  opts.lecho ? "yes" : "no");
 					break;
@@ -821,8 +1384,125 @@
 					else
 						run_cmd(tty_fd, opts.receive_cmd, NULL);
 					break;
+
+				case KEY_TERMRESET:
+					printsetcolor(COL_RESET);
+					fd_printf(STO, "\r\n*** resetting terminal... ***\r\n");
+					run_cmd(STO, opts.terminal_reset_cmd, NULL);
+					printsetcolor(COL_SYS);
+					fd_printf(STO, "*** terminal reset ***\r\n");
+					break;
+				case KEY_SHELL:
+					printsetcolor(COL_SYS);
+					//fd_printf(STO,"\r\n*** Command to send: ");
+					//r=fd_readline(STI,STO,fname,sizeof(fname));
+					fd_printf(STO, "\r\n*** running shell, return back via \"exit\" ***\r\n");
+					printsetcolor(COL_RESET);
+					run_cmd(STDERR_FILENO, getenv("SHELL"), NULL);
+					//if(fname[0])run_cmd(STDERR_FILENO, fname, NULL);
+					//if(fname[0])run_cmd(tty_fd, fname, NULL);
+					//run_cmd(STO, "/bin/bash --debug --verbose -c \"exec /bin/bash\"", NULL);
+					printsetcolor(COL_SYS);
+					fd_printf(STO, "*** return from shell ***\r\n");
+					break;
+				case KEY_HEX:
+					printsetcolor(COL_SYS);
+					fd_printf(STO,"Hex to send: ");
+					r=fd_readline(STI,STO,fname,sizeof(fname));
+					fd_printf(STO, "\r\n");
+					if ( r < -1 && errno == EINTR ) break;
+					if ( r <= -1 )
+						fatal("cannot read string: %s", strerror(errno));
+					char*sp;
+					unsigned char c;
+					sp=fname;
+					while(sp[0]) {
+						if(!ishexdigit(sp[0])){sp++;continue;}
+						c=gethex(sp);if(sp[0])sp++;if(sp[0])sp++;
+						//printdebug('x',c,sp);
+						if (tty_q.len + M_MAXMAP <= TTY_Q_SZ) {
+							tty_q.buff[tty_q.len]=c;
+							tty_q.len += 1;
+							if ( opts.lecho ) 
+								map_and_write_color(STO, opts.emap, c,COL_OUT);
+						} else 
+							fd_printf(STO, "\x07");
+					}
+					//printdebug('1','2',fname);
+					break;
+				case KEY_SETBAUD:
+					printsetcolor(COL_SYS);
+					fd_printf(STO,"Set baud rate: ");
+					r=fd_readline(STI,STO,fname,sizeof(fname));
+					fd_printf(STO, "\r\n");
+					if ( r < -1 && errno == EINTR ) break;
+					if ( r <= -1 )
+						fatal("cannot read string: %s", strerror(errno));
+					newbaud=atoi(fname);
+					if(newbaud<=0){
+						fd_printf(STO,"Invalid baudrate: %i\r\n",newbaud);
+					} else {
+						term_set_baudrate(tty_fd, newbaud);
+						tty_q.len = 0; term_flush(tty_fd);
+						if ( term_apply(tty_fd) >= 0 ) opts.baud = term_get_baudrate(tty_fd);
+						fd_printf(STO, "\r\n*** baud: %d ***\r\n", opts.baud);
+						baud_add(opts.baud);
+					}
+					break;
+				case KEY_LFDELAY:
+					printsetcolor(COL_SYS);
+					fd_printf(STO,"msec delay on LF: ");
+					r=fd_readline(STI,STO,fname,sizeof(fname));
+					fd_printf(STO, "\r\n");
+					if ( r < -1 && errno == EINTR ) break;
+					if ( r <= -1 )
+						fatal("cannot read string: %s", strerror(errno));
+					newlfdelay=atoi(fname);
+					if(newlfdelay<=0){
+						fd_printf(STO,"Invalid milliseconds: %i\r\n",newlfdelay);
+					} else {
+                                                opts.lfdelay=newlfdelay;
+						fd_printf(STO, "\r\n*** LF delay msec: %d ***\r\n", opts.lfdelay);
+					}
+					break;
+				case KEY_HELP:
+					printsetcolor(COL_SYS);
+					fd_printf(STO,"\r\n");
+
+					printhelp_section("Port setting");
+					printhelp("Ctrl-D","baudrate decrease");
+					printhelp("Ctrl-U","baudrate increase");
+					printhelp("Ctrl-G","set arbitrary baudrate");
+					printhelp("Ctrl-B","cycle through databits (5,6,7,8)");
+					printhelp("Ctrl-F","cycle through flowcontrol modes");
+					printhelp("Ctrl-Y","cycle through parity modes");
+
+					printhelp_section("Control signals, data send/receive");
+					printhelp("Ctrl-I","pulse RTS");
+					printhelp("Ctrl-R","toggle RTS");
+					printhelp("Ctrl-P","pulse DTR");
+					printhelp("Ctrl-T","toggle DTR");
+					printhelp("Ctrl-H","enter hex string to send as binary");
+					printhelp("Ctrl-E","receive file");
+					printhelp("Ctrl-S","send file");
+					printhelp("Ctrl-\\","send break");
+					printhelp("Ctrl-W","set wait on LF");
+
+					printhelp_section("Terminal");
+					printhelp("Ctrl-C","toggle local echo");
+					printhelp("Ctrl-O","reset terminal");
+
+					printhelp_section("Other");
+					printhelp("Ctrl-Q","quit without reseting port");
+					printhelp("Ctrl-X","exit");
+					printhelp("Ctrl-Z","run shell");
+					printhelp("Ctrl-V","show current options");
+					printhelp("?","this help");
+					break;
+
 				case KEY_BREAK:
 					term_break(tty_fd);
+					printsetcolor(COL_SYS);
 					fd_printf(STO, "\r\n*** break sent ***\r\n");
 					break;
 				default:
@@ -834,12 +1514,13 @@
 				if ( c == opts.escape ) {
 					state = ST_COMMAND;
 				} else {
+                                        if((c==0x0D)||(c==0x0A))if(opts.lfdelay)islfdelay=1;
 					if (tty_q.len + M_MAXMAP <= TTY_Q_SZ) {
 						n = do_map((char *)tty_q.buff + tty_q.len, 
 								   opts.omap, c);
 						tty_q.len += n;
 						if ( opts.lecho ) 
-							map_and_write(STO, opts.emap, c);
+							map_and_write_color(STO, opts.emap, c,COL_OUT);
 					} else 
 						fd_printf(STO, "\x07");
 				}
@@ -853,11 +1534,14 @@
 	skip_proc_STI:
 
 		if ( FD_ISSET(tty_fd, &rdset) ) {
+                        char s[64];
 
+                        delaylfsent=0;
+                        clk_lastin=clk_now;
 			/* read from port */
 
 			do {
-				n = read(tty_fd, &c, 1);
+				n = read(tty_fd, &s, 64);
 			} while (n < 0 && errno == EINTR);
 			if (n == 0) {
 				fatal("term closed");
@@ -865,14 +1549,15 @@
 				if ( errno != EAGAIN && errno != EWOULDBLOCK )
 					fatal("read from term failed: %s", strerror(errno));
 			} else {
-				map_and_write(STO, opts.imap, c);
+                            int t;
+                            for(t=0;t<n;t++)
+				map_and_write_color(STO, opts.imap, s[t],COL_IN);
 			}
 		}
 
 		if ( FD_ISSET(tty_fd, &wrset) ) {
 
 			/* write to port */
-
 			do {
 				n = write(tty_fd, tty_q.buff, tty_q.len);
 			} while ( n < 0 && errno == EINTR );
@@ -880,6 +1565,16 @@
 				fatal("write to term failed: %s", strerror(errno));
 			memcpy(tty_q.buff, tty_q.buff + n, tty_q.len - n);
 			tty_q.len -= n;
+
+                        // LF write delay:
+                        if(islfdelay) {
+                                islfdelay=0;
+                                printsetcolor(COL_SYS);
+                                fd_printf(STO, "[w]\r");
+                                usleep(opts.lfdelay*1000);
+                                fd_printf(STO, "\r   \r");
+                        }
+
 		}
 	}
 }
@@ -914,8 +1609,8 @@
 
         sigaction (SIGTERM, &exit_action, NULL);
 
-        sigaction (SIGINT, &ign_action, NULL); 
-        sigaction (SIGHUP, &ign_action, NULL);
+        sigaction (SIGINT,  &ign_action, NULL); 
+        sigaction (SIGHUP,  &ign_action, NULL);
         sigaction (SIGALRM, &ign_action, NULL);
         sigaction (SIGUSR1, &ign_action, NULL);
         sigaction (SIGUSR2, &ign_action, NULL);
@@ -932,7 +1627,7 @@
 	s = strrchr(name, '/');
 	s = s ? s+1 : name;
 
-	printf("picocom v%s\n", VERSION_STR);
+	printf("picocom v" VERSION_STR_SHAD "\n");
 	printf("Usage is: %s [options] <tty device>\n", s);
 	printf("Options are:\n");
 	printf("  --<b>aud <baudrate>\n");
@@ -946,30 +1641,47 @@
 	printf("  --no<l>ock\n");
 	printf("  --<s>end-cmd <command>\n");
 	printf("  --recei<v>e-cmd <command>\n");
+	printf("  --nohex, --hexall\n");
+	printf("  --color (-C), --colorbright (-B)\n");
+	printf("  --dtr <1|0>\n");
+	printf("  --rts <1|0>\n");
+	printf("  --nomodem\n");
+	printf("  --baudadd <list_of_baudrates|set_name>\n");
+	printf("  --baudlist <list_of_baudrates|set_name>\n");
+	printf("  --lf<w>ait <msec of wait after CR/LF from terminal>\n");
 	printf("  --imap <map> (input mappings)\n");
 	printf("  --omap <map> (output mappings)\n");
 	printf("  --emap <map> (local-echo mappings)\n");
+	printf("  --<A>utoargs <name> (set arguments by name from picocom_autoport)\n");
+	printf("  --<a>utoport  (set by keyword match on port name from picocom_autoport)\n");
 	printf("  --<h>elp\n");
 	printf("<map> is a comma-separated list of one or more of:\n");
-	printf("  crlf : map CR --> LF\n");
+	printf("  crlf   : map CR --> LF\n");
 	printf("  crcrlf : map CR --> CR + LF\n");
-	printf("  igncr : ignore CR\n");
-	printf("  lfcr : map LF --> CR\n");
+	printf("  igncr  : ignore CR\n");
+	printf("  lfcr   : map LF --> CR\n");
 	printf("  lfcrlf : map LF --> CR + LF\n");
-	printf("  ignlf : ignore LF\n");
-	printf("  bsdel : map BS --> DEL\n");
-	printf("  delbs : map DEL --> BS\n");
+	printf("  ignlf  : ignore LF\n");
+	printf("  bsdel  : map BS --> DEL\n");
+	printf("  delbs  : map DEL --> BS\n");
+	printf("  swcase : lowercase <--> uppercase\n");
 	printf("<?> indicates the equivalent short option.\n");
 	printf("Short options are prefixed by \"-\" instead of by \"--\".\n");
 }
 
 /**********************************************************************/
 
+int autoargs_load();
+int do_autoargs=0;
+char autoargs_named[256]="";
+
 void
-parse_args(int argc, char *argv[])
+parse_args(int argc, char *argv[], int noport)
 {
 	static struct option longOptions[] =
 	{
+		{"autoport", no_argument, 0, 'a'},
+		{"autoargs", no_argument, 0, 'A'},
 		{"receive-cmd", required_argument, 0, 'v'},
 		{"send-cmd", required_argument, 0, 's'},
         {"imap", required_argument, 0, 'I' },
@@ -984,66 +1696,139 @@
 		{"baud", required_argument, 0, 'b'},
 		{"parity", required_argument, 0, 'p'},
 		{"databits", required_argument, 0, 'd'},
+		{"stopbits", required_argument, 0, 'S'},
+		{"nohex", no_argument, 0, 'N'},
+		{"hexall", no_argument, 0, 'H'},
+		{"color", no_argument, 0, 'C'},
+		{"colorbright", no_argument, 0, 'B'},
+		{"dtr", required_argument, 0, 'D'},
+		{"rts", required_argument, 0, 'R'},
+		{"nomodem", no_argument, 0, 'M'},
+		{"baudadd", required_argument, 0, 'K'},
+		{"baudlist", required_argument, 0, 'L'},
+		{"lfwait", required_argument, 0, 'w'},
+		{"autonew", required_argument, 0, 'F'},  // newline in $arg milliseconds
 		{"help", no_argument, 0, 'h'},
 		{0, 0, 0, 0}
 	};
 
+/*
+int t;
+fprintf(stderr,"[argc:%i]\n",argc);
+for(t=0;t<argc;t++){
+  fprintf(stderr,"[%2i]'%s'\n",t,argv[t]);
+}
+*/
+
+
+        optind=1; // init loop for multi calls
+
+//fprintf(stderr,"[argc:%i]\n",argc);
 	while (1) {
 		int optionIndex = 0;
 		int c;
 		int map;
 
 		/* no default error messages printed. */
-		opterr = 0;
+		//opterr = 0;
+		opterr = 1;
 
-		c = getopt_long(argc, argv, "hirlcv:s:r:e:f:b:p:d:",
+//fprintf(stderr,"(%2i)%-10s %i\n",optind,argv[optind],optopt);
+
+		c = getopt_long(argc, argv, "ahirlcCBMNHSA:v:s:r:e:f:b:p:d:D:K:L:F:R:w:",
 						longOptions, &optionIndex);
 
 		if (c < 0)
 			break;
 
+//fprintf(stderr,"idx:%2i c'%c' optind:%i argv:'%s'\n",optionIndex,c,optind,argv[optind]);
+//fprintf(stderr,"      ['%c'] optarg:'%10s'      optind:%i argv:'%s'\n",c,optarg,optind,argv[optind]);
+//fprintf(stderr," ['%c'] optarg:'%s'\n\n",c,optarg);
+
 		switch (c) {
-		case 's':
+		case 's': // send-cmd
 			strncpy(opts.send_cmd, optarg, sizeof(opts.send_cmd));
 			opts.send_cmd[sizeof(opts.send_cmd) - 1] = '\0';
 			break;
-		case 'v':
+		case 'v': // receive-cmd
 			strncpy(opts.receive_cmd, optarg, sizeof(opts.receive_cmd));
 			opts.receive_cmd[sizeof(opts.receive_cmd) - 1] = '\0';
 			break;
-		case 'I':
+		case 'a': // autoport
+                        do_autoargs++;
+                        break;
+		case 'A': // autoargs
+                        //do_autoargs++;
+                        strncpy(autoargs_named,optarg,255);
+                        break;
+		case 'N': // nohex
+			opts.hexmap=HEX_NONE;
+			break;
+		case 'M': // nomodem
+			opts.watchmodemlines=0;
+			break;
+		case 'H': // hexall
+			opts.hexmap=HEX_ALL;
+			break;
+		case 'C': // color
+			opts.color=COLOR_NORMAL;
+			break;
+		case 'B': // colorbright
+			opts.color=COLOR_BRIGHT;
+			break;
+		case 'D': // dtr
+			if(atoi(optarg))opts.initdtr=1;
+				else opts.initdtr=0;
+			break;
+		case 'K': // baudadd
+			baud_addstr(optarg,0);
+			break;
+		case 'L': // baudlist
+			baud_addstr(optarg,1);
+			break;
+		case 'F': // newline on input idle
+			opts.autolf = atoi(optarg);
+			break;
+		case 'R': // rts
+			if(atoi(optarg))opts.initrts=1;
+				else opts.initrts=0;
+			break;
+		case 'I': // imap
 			map = parse_map(optarg);
 			if (map >= 0) opts.imap = map;
 			else fprintf(stderr, "Invalid imap, ignored\n");
 			break;
-		case 'O':
+		case 'O': // omap
 			map = parse_map(optarg);
 			if (map >= 0) opts.omap = map;
 			else fprintf(stderr, "Invalid omap, ignored\n");
 			break;
-		case 'E':
+		case 'E': // emap
 			map = parse_map(optarg);
 			if (map >= 0) opts.emap = map;
 			else fprintf(stderr, "Invalid emap, ignored\n");
 			break;
-		case 'c':
+		case 'S': // two stopbits
+			opts.stopbits=2;
+			break;
+		case 'c': // echo
 			opts.lecho = 1;
 			break;
-		case 'i':
+		case 'i': // noinit
 			opts.noinit = 1;
 			break;
-		case 'r':
+		case 'r': // noreset
 			opts.noreset = 1;
 			break;
-		case 'l':
+		case 'l': // nolock
 #ifdef UUCP_LOCK_DIR
 			opts.nolock = 1;
 #endif
 			break;
-		case 'e':
+		case 'e': // escape
 			opts.escape = optarg[0] & 0x1f;
 			break;
-		case 'f':
+		case 'f': // flow
 			switch (optarg[0]) {
 			case 'X':
 			case 'x':
@@ -1066,10 +1851,10 @@
 				break;
 			}
 			break;
-		case 'b':
+		case 'b': // baud
 			opts.baud = atoi(optarg);
 			break;
-		case 'p':
+		case 'p': // parity
 			switch (optarg[0]) {
 			case 'e':
 				opts.parity_str = "even";
@@ -1089,7 +1874,7 @@
 				break;
 			}
 			break;
-		case 'd':
+		case 'd': // databits
 			switch (optarg[0]) {
 			case '5':
 				opts.databits = 5;
@@ -1105,11 +1890,14 @@
 				break;
 			default:
 				fprintf(stderr, "--databits '%c' ignored.\n", optarg[0]);
-				fprintf(stderr, "--databits can be one off: 5, 6, 7 or 8\n");
+				fprintf(stderr, "--databits can be one of: 5, 6, 7 or 8\n");
 				break;
 			}
 			break;
-		case 'h':
+		case 'w': // lfwait
+			opts.lfdelay=atoi(optarg);
+			break;
+		case 'h': // help
 			show_usage(argv[0]);
 			exit(EXIT_SUCCESS);
 		case '?':
@@ -1120,33 +1908,290 @@
 		}
 	} /* while */
 
-	if ( (argc - optind) < 1) {
+//fprintf(stderr,"===\nargc:%i optind:%i diff:%i\n",argc,optind,argc-optind);
+//fprintf(stderr,"port:'%s'\n",argv[optind]);
+
+        if(noport){
+	  if ( (argc - optind) < 1) {
 		fprintf(stderr, "No port given\n");
 		exit(EXIT_FAILURE);
-	}
-	strncpy(opts.port, argv[optind], sizeof(opts.port) - 1);
-	opts.port[sizeof(opts.port) - 1] = '\0';
+	  }
+	  strncpy(opts.port, argv[optind], sizeof(opts.port) - 1);
+	  opts.port[sizeof(opts.port) - 1] = '\0';
+	  if(baudrates[0]==0)baud_addstr("DEFAULT",1);
+        }
+}
+
+#define MAXAUTOARGS 32
+#define MAXAUTOARGLEN 256
+#define AUTOARGS_PATH1 "./.picocom_autoargs"
+#define AUTOARGS_PATH2 "~/.picocom_autoargs"
+#define AUTOARGS_PATH3 "/etc/picocom_autoargs"
+int aa_debug=0;
+#define aa_FILES 1
+#define aa_TRACE 2
+#define aa_MATCH 3
+
+
+int autoargs_ismatch(char*sig,char*name,int strict){
+//fprintf(stderr,"%s\n",sig,name);
+        char*sp;
+        if(strict){
+          if(sig[0]!='$')return 0; // strict only for full match
+          if(!strcmp(sig+1,name))return 1;
+          return 0;
+        }
+        switch(sig[0]){
+          // any substring
+          case '$':  return 0; // strict checking done above
+          case '*':  if(sig[1]=='*'){
+                       if(strstr(name,sig+2)!=NULL)return 1;
+                       return 0;
+                     }
+                     sp=strstr(name,sig+1);if(!sp)return 0;
+                     if(strlen(sp)==strlen(sig+1))return 1;
+                     return 0;
+          default:   fprintf(stderr,"autoargs signature rule unknown: '%c' (%s)\n",sig[0],sig);
+                     return 0;
+        }
+}
+
+char* autoargs_load_cfg_file(char*fn,char*name,int strict){
+        FILE*f;
+        char s[256];
+        char*sp;
+        f=fopen(fn,"r");
+        if(!f){
+          if(aa_debug>=aa_MATCH)fprintf(stderr,"    autoargs: cannot open file '%s'\n",fn);
+          return "";
+        }
+        if(aa_debug>=aa_FILES)fprintf(stderr,"  autoargs: reading from '%s'\n",fn);
+        while(!feof(f)){
+          fgets(s,255,f);
+          if(s[0]==0)continue;
+          if(s[0]=='\r')continue;
+          if(s[0]=='\n')continue;
+          if(s[0]==' ')continue;
+          if(s[0]==';')continue;
+          if(s[0]=='#')continue;
+          sp=strchr(s,'\n');if(sp)sp[0]=0;
+          sp=strchr(s,' ');if(!sp)continue;
+          sp[0]=0;sp++;while(sp[0]==' ')sp++;
+          if(!autoargs_ismatch(s,name,strict)){
+            if(aa_debug>=aa_MATCH)fprintf(stderr,"      autoargs: rule '%s'\n",s);
+            continue;
+          }
+          if(aa_debug>=aa_TRACE)fprintf(stderr,"    autoargs: match on '%s'\n",s);
+          fclose(f);
+          return sp;
+        }
+        if(aa_debug>=aa_TRACE)fprintf(stderr,"    autoargs: ...no match\n");
+        fclose(f);
+        return "";
+}
+
+char* autoargs_loadfiles(char*name,int strict){
+        char*sp;
+        if(aa_debug>=aa_FILES)fprintf(stderr,"\n  autoargs: matching against '%s'\n",name);
+        sp=autoargs_load_cfg_file(AUTOARGS_PATH1,name,strict);
+          if(sp)if(sp[0])return sp;
+        sp=autoargs_load_cfg_file(AUTOARGS_PATH2,name,strict);
+          if(sp)if(sp[0])return sp;
+        sp=autoargs_load_cfg_file(AUTOARGS_PATH3,name,strict);
+          if(sp)if(sp[0])return sp;
+        return "";
+}
+
+int autoargs_load_for_match(char*name,int strict){
+        static char argsstr[MAXAUTOARGLEN];
+        char *argsarr[MAXAUTOARGS];
+        int argcnt=0;
+        char*sp,*sp1;
+        //int t;
+
+        if(strict){
+          if(!strcmp(name,"-v")){aa_debug=aa_FILES;return 0;}
+          if(!strcmp(name,"-V")){aa_debug=aa_MATCH;return 0;}
+          if(!strcmp(name,"_PORT")){name=opts.port;strict=0;} // magic
+        }
+
+        //strcpy(argsstr,"-b 128000 --dtr 7");
+        strncpy(argsstr,autoargs_loadfiles(name,strict),MAXAUTOARGLEN);
+
+        fprintf(stderr,"autoargs on '%s': ",name);
+        if(argsstr[0]==0){fprintf(stderr," (no match)\n");return 0;}
+        fprintf(stderr,"  %s\n",argsstr);
+
+        // break mercilessly into arrays, screw escapes and quotes
+        sp=argsstr;
+        argsarr[0]=sp;
+        argcnt=1;
+        while(sp){
+            argsarr[argcnt]=sp;
+            argcnt++;
+            sp1=strchr(sp,' ');
+            if(sp1){sp1[0]=0;sp1++;while(sp1[0]==' ')sp1++;}
+            sp=sp1;
+            if(argcnt>MAXAUTOARGS-2)break; // one-off guard, better safe than sorry, i feel like crap and cannot focus
+        }
+	argsarr[argcnt]=argsstr;//just to be sure we aren't off-by-one
+
+        parse_args(argcnt,argsarr,0);
+        return 1;
+}
+
+int autoargs_load(){
+        int matches=0;
+        char*sp,*sp1;
+        // load explicitly named presets
+        if(autoargs_named[0]){
+          sp=autoargs_named;
+          while(sp){
+            sp1=strchr(sp,',');if(sp1){sp1[0]=0;sp1++;}
+            if(sp[0])matches+=autoargs_load_for_match(sp,1);
+            sp=sp1;
+          }
+        }
+        if(do_autoargs){matches+=autoargs_load_for_match(opts.port,0);}
+        if(aa_debug>=aa_FILES)fprintf(stderr,"\n");
+        return matches;
+}
+
+
+#define SHAD_LOOSEMATCH
+
+#ifdef SHAD_LOOSEMATCH
+#include <dirent.h>
+#define LOOSEMATCHDIR "/dev/serial/by-id/"
+//#define LOOSEMATCHDIR "/dev/"
+
+void loosematch_ls(){
+        DIR *dp;
+        struct dirent *ep;
+        dp = opendir (LOOSEMATCHDIR);
+
+        if (dp == NULL) return;
+
+        fprintf(stderr,"\nListing of " LOOSEMATCHDIR ":\n");
+        while (1){
+          ep = readdir (dp);
+          if(!ep)break;
+          if(!strcmp(ep->d_name,"."))continue;
+          if(!strcmp(ep->d_name,".."))continue;
+          fprintf(stderr,"  %s\n", ep->d_name);
+        }
+
+        (void) closedir (dp);
+}
+
+void autoargs_autoportmatch(int talk){
+        struct stat st;
+        DIR *dp;
+        struct dirent *ep;
+        char s[256];
+        int match=0;
+
+        if(stat(opts.port,&st)!=-1)
+          return;  // file exists, lets not check more now
+
+        s[0]=0;
+
+        if(talk)fprintf(stderr,"'%s' not found, trying loose match in "LOOSEMATCHDIR"\n",opts.port);
+
+        dp = opendir (LOOSEMATCHDIR);
+
+        if (dp == NULL) {
+          perror ("Couldn't open " LOOSEMATCHDIR ", cannot perform loose match");
+          exit(EXIT_FAILURE);
+        }
+
+        while (1){
+          ep = readdir (dp);
+          if(!ep)break;
+          if(!strcmp(ep->d_name,"."))continue;
+          if(!strcmp(ep->d_name,".."))continue;
+          if(!strstr(ep->d_name,opts.port))continue;
+          // match
+          if(!match){strncpy(s,ep->d_name,255);s[254]=0;}
+          match++;
+          if(talk)fprintf(stderr,"match %i: %s in %s\n",match,opts.port,ep->d_name);
+//          puts (ep->d_name);
+        }
+
+        (void) closedir (dp);
+
+        if(match==1){
+          snprintf(opts.port,sizeof(opts.port)-1,"%s%s",LOOSEMATCHDIR,s);
+          opts.port[sizeof(opts.port) - 1] = '\0';
+          if(talk)fprintf(stderr,"\nSingle match found: %s\n\n",opts.port);
+          return;
+        }
+
+        loosematch_ls();
+        fprintf(stderr,"\n");
+        if(match==0)fprintf(stderr,"No matching port found in "LOOSEMATCHDIR".\n");
+               else fprintf(stderr,"Ambiguous matches in "LOOSEMATCHDIR".\n");
+        exit(EXIT_FAILURE);
+
+/*
+   switch (sb.st_mode & S_IFMT) {
+    case S_IFBLK:  printf("block device\n");            break;
+    case S_IFCHR:  printf("character device\n");        break;
+    case S_IFDIR:  printf("directory\n");               break;
+    case S_IFIFO:  printf("FIFO/pipe\n");               break;
+    case S_IFLNK:  printf("symlink\n");                 break;
+    case S_IFREG:  printf("regular file\n");            break;
+    case S_IFSOCK: printf("socket\n");                  break;
+    default:       printf("unknown?\n");                break;
+}
+*/
 
-	printf("picocom v%s\n", VERSION_STR);
-	printf("\n");
-	printf("port is        : %s\n", opts.port);
-	printf("flowcontrol    : %s\n", opts.flow_str);
-	printf("baudrate is    : %d\n", opts.baud);
-	printf("parity is      : %s\n", opts.parity_str);
-	printf("databits are   : %d\n", opts.databits);
-	printf("escape is      : C-%c\n", 'a' + opts.escape - 1);
-	printf("local echo is  : %s\n", opts.lecho ? "yes" : "no");
-	printf("noinit is      : %s\n", opts.noinit ? "yes" : "no");
-	printf("noreset is     : %s\n", opts.noreset ? "yes" : "no");
+
+//                fprintf(stderr, "No port given\n");
+//                exit(EXIT_FAILURE);
+
+}
+#endif
+
+
+/**********************************************************************/
+
+
+
+void
+show_settings(int tty)
+{
+	fd_printf(STO,"picocom v%s\n", VERSION_STR_SHAD);
+	fd_printf(STO,"\r\n");
+	fd_printf(STO,"port is        : %s\r\n", opts.port);
+	fd_printf(STO,"flowcontrol    : %s\r\n", opts.flow_str);
+//	fd_printf(STO,"baudrate is    : %d (real?)\r\n", opts.baud);
+//	fd_printf(STO,"parity is      : %s\r\n", opts.parity_str);
+//	fd_printf(STO,"databits are   : %d\r\n", opts.databits);
+	fd_printf(STO,"baudrate is    : %d (%d)\r\n", opts.baud,term_get_baudrate(tty));
+	fd_printf(STO,"parity is      : %s\r\n", opts.parity_str);
+	fd_printf(STO,"databits are   : %d (%d)\r\n", opts.databits,term_get_databits(tty));
+	fd_printf(STO,"stopbits       : %d\r\n", opts.stopbits);
+	fd_printf(STO,"escape is      : C-%c\r\n", 'a' + opts.escape - 1);
+	fd_printf(STO,"local echo is  : %s\r\n", opts.lecho ? "yes" : "no");
+	fd_printf(STO,"noinit is      : %s\r\n", opts.noinit ? "yes" : "no");
+	fd_printf(STO,"noreset is     : %s\r\n", opts.noreset ? "yes" : "no");
 #ifdef UUCP_LOCK_DIR
-	printf("nolock is      : %s\n", opts.nolock ? "yes" : "no");
+	fd_printf(STO,"nolock is      : %s\r\n", opts.nolock ? "yes" : "no");
 #endif
-	printf("send_cmd is    : %s\n", opts.send_cmd);
-	printf("receive_cmd is : %s\n", opts.receive_cmd);
-	printf("imap is        : "); print_map(opts.imap);
-	printf("omap is        : "); print_map(opts.omap);
-	printf("emap is        : "); print_map(opts.emap);
-	printf("\n");
+	fd_printf(STO,"send_cmd is    : %s\r\n", opts.send_cmd);
+	fd_printf(STO,"receive_cmd is : %s\r\n", opts.receive_cmd);
+	fd_printf(STO,"imap is        : "); print_map(opts.imap);
+	fd_printf(STO,"omap is        : "); print_map(opts.omap);
+	fd_printf(STO,"emap is        : "); print_map(opts.emap);
+        fd_printf(STO,"LF delay is    : %d\r\n", opts.lfdelay);
+	fd_printf(STO,"modem flags are: "); print_modem_flags_raw(tty);
+	fd_printf(STO,"\r\n");
+        fd_printf(STO,"   DTR: toggle ^T, pulse ^P\r\n");
+        fd_printf(STO,"   RTS: toggle ^R, pulse ^I\r\n");
+        // baud_dump();
+	fd_printf(STO,"\r\n");
+	fd_printf(STO,"\r\n");
 }
 
 /**********************************************************************/
@@ -1157,7 +2202,21 @@
 {
 	int r;
 
-	parse_args(argc, argv);
+	baud_addstr("DEFAULT",1); // populate baud rates array for modifications
+	parse_args(argc, argv, 1);
+
+        #ifdef SHAD_LOOSEMATCH
+          autoargs_autoportmatch(1);
+        #endif
+
+        // if autoargs specified, load the presets, THEN optionally override
+        if(autoargs_load()){
+	      parse_args(argc, argv, 1);
+              #ifdef SHAD_LOOSEMATCH
+                  autoargs_autoportmatch(0); // repeat! second parse_args broke our alias
+              #endif
+              if(aa_debug)show_settings(0);
+        }
 
 	establish_signal_handlers();
 
@@ -1177,12 +2236,15 @@
 
 	if ( opts.noinit ) {
 		r = term_add(tty_fd);
+		//opts.baud=term_get_baudrate(tty_fd);
+		get_opts_from_port(tty_fd);
 	} else {
 		r = term_set(tty_fd,
 					 1,              /* raw mode. */
 					 opts.baud,      /* baud rate. */
 					 opts.parity,    /* parity. */
 					 opts.databits,  /* data bits. */
+					 opts.stopbits,  /* stop bits. */
 					 opts.flow,      /* flow control. */
 					 1,              /* local or modem */
 					 !opts.noreset); /* hup-on-close. */
@@ -1205,9 +2267,20 @@
 		fatal("failed to set I/O device to raw mode: %s",
 			  term_strerror(term_errno, errno));
 
+	//get_opts_from_port(tty_fd); // make sure we have real values from the port
+	color=COL_SYS;
+	//if value=-1 then do not set
+	if(opts.initdtr==0)term_lower_dtr(tty_fd);else
+	if(opts.initdtr==1)term_raise_dtr(tty_fd);
+	if(opts.initrts==0)term_lower_rts(tty_fd);else
+	if(opts.initrts==1)term_raise_rts(tty_fd);
+	baud_add(opts.baud); // if port runs on nonstandard baud rate, set it into the up/down array
+	show_settings(tty_fd);
+	//baud_dump();
 	fd_printf(STO, "Terminal ready\r\n");
 	loop();
 
+	color=COL_SYS;
 	fd_printf(STO, "\r\n");
 	if ( opts.noreset ) {
 		fd_printf(STO, "Skipping tty reset...\r\n");
@@ -1222,6 +2295,7 @@
 	uucp_unlock();
 #endif
 
+	printsetcolor(COL_RESET);
 	return EXIT_SUCCESS;
 }
 
