xref: /plan9/sys/src/cmd/con/xms.c (revision 5d459b5a09e427ae1acd4e6afcf028853c73946e)
13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
33e12c5d1SDavid du Colombier #include <ctype.h>
43e12c5d1SDavid du Colombier 
53e12c5d1SDavid du Colombier enum {
63e12c5d1SDavid du Colombier 	Soh=	0x1,
7*5d459b5aSDavid du Colombier 	Stx=	0x2,
83e12c5d1SDavid du Colombier 	Eot=	0x4,
93e12c5d1SDavid du Colombier 	Ack=	0x6,
103e12c5d1SDavid du Colombier 	Nak=	0x15,
113e12c5d1SDavid du Colombier 	Cancel=	0x18,
123e12c5d1SDavid du Colombier };
133e12c5d1SDavid du Colombier 
143e12c5d1SDavid du Colombier int send(uchar*, int);
153e12c5d1SDavid du Colombier int notifyf(void*, char*);
163e12c5d1SDavid du Colombier 
17*5d459b5aSDavid du Colombier int debug, progress, onek;
183e12c5d1SDavid du Colombier 
193e12c5d1SDavid du Colombier void
errorout(int ctl,int bytes)203e12c5d1SDavid du Colombier errorout(int ctl, int bytes)
213e12c5d1SDavid du Colombier {
223e12c5d1SDavid du Colombier 	uchar buf[2];
233e12c5d1SDavid du Colombier 
243e12c5d1SDavid du Colombier 	buf[0] = Cancel;
253e12c5d1SDavid du Colombier 	write(1, buf, 1);
263e12c5d1SDavid du Colombier 	fprint(2, "\nxms: gave up after %d bytes\n", bytes);
273e12c5d1SDavid du Colombier 	write(ctl, "rawoff", 6);
283e12c5d1SDavid du Colombier 	exits("cancel");
293e12c5d1SDavid du Colombier }
303e12c5d1SDavid du Colombier 
31*5d459b5aSDavid du Colombier ushort
updcrc(int c,ushort crc)32*5d459b5aSDavid du Colombier updcrc(int c, ushort crc)
33*5d459b5aSDavid du Colombier {
34*5d459b5aSDavid du Colombier 	int count;
35*5d459b5aSDavid du Colombier 
36*5d459b5aSDavid du Colombier 	for (count=8; --count>=0;) {
37*5d459b5aSDavid du Colombier 		if (crc & 0x8000) {
38*5d459b5aSDavid du Colombier 			crc <<= 1;
39*5d459b5aSDavid du Colombier 			crc += (((c<<=1) & 0400)  !=  0);
40*5d459b5aSDavid du Colombier 			crc ^= 0x1021;
41*5d459b5aSDavid du Colombier 		}
42*5d459b5aSDavid du Colombier 		else {
43*5d459b5aSDavid du Colombier 			crc <<= 1;
44*5d459b5aSDavid du Colombier 			crc += (((c<<=1) & 0400)  !=  0);
45*5d459b5aSDavid du Colombier 		}
46*5d459b5aSDavid du Colombier 	}
47*5d459b5aSDavid du Colombier 	return crc;
48*5d459b5aSDavid du Colombier }
49*5d459b5aSDavid du Colombier 
503e12c5d1SDavid du Colombier void
main(int argc,char ** argv)513e12c5d1SDavid du Colombier main(int argc, char **argv)
523e12c5d1SDavid du Colombier {
533e12c5d1SDavid du Colombier 	uchar c;
54*5d459b5aSDavid du Colombier 	uchar buf[1024+5];
553e12c5d1SDavid du Colombier 	uchar seqno;
563e12c5d1SDavid du Colombier 	int fd, ctl;
573e12c5d1SDavid du Colombier 	long n;
583e12c5d1SDavid du Colombier 	int sum;
593e12c5d1SDavid du Colombier 	uchar *p;
603e12c5d1SDavid du Colombier 	int bytes;
61*5d459b5aSDavid du Colombier 	int crcmode;
623e12c5d1SDavid du Colombier 
633e12c5d1SDavid du Colombier 	ARGBEGIN{
643e12c5d1SDavid du Colombier 	case 'd':
653e12c5d1SDavid du Colombier 		debug = 1;
663e12c5d1SDavid du Colombier 		break;
67*5d459b5aSDavid du Colombier 	case 'p':
68*5d459b5aSDavid du Colombier 		progress = 1;
69*5d459b5aSDavid du Colombier 		break;
70*5d459b5aSDavid du Colombier 	case '1':
71*5d459b5aSDavid du Colombier 		onek = 1;
72*5d459b5aSDavid du Colombier 		break;
733e12c5d1SDavid du Colombier 	}ARGEND
743e12c5d1SDavid du Colombier 
753e12c5d1SDavid du Colombier 	if(argc != 1){
763e12c5d1SDavid du Colombier 		fprint(2, "usage: xms filename\n");
773e12c5d1SDavid du Colombier 		exits("usage");
783e12c5d1SDavid du Colombier 	}
793e12c5d1SDavid du Colombier 	fd = open(argv[0], OREAD);
803e12c5d1SDavid du Colombier 	if(fd < 0){
813e12c5d1SDavid du Colombier 		perror("xms");
823e12c5d1SDavid du Colombier 		exits("open");
833e12c5d1SDavid du Colombier 	}
843e12c5d1SDavid du Colombier 
853e12c5d1SDavid du Colombier 	ctl = open("/dev/consctl", OWRITE);
86*5d459b5aSDavid du Colombier 	if(ctl < 0){
87*5d459b5aSDavid du Colombier 		perror("xms");
88*5d459b5aSDavid du Colombier 		exits("consctl");
89*5d459b5aSDavid du Colombier 	}
903e12c5d1SDavid du Colombier 	write(ctl, "rawon", 5);
913e12c5d1SDavid du Colombier 
923e12c5d1SDavid du Colombier 	/* give the other side a 30 seconds to signal ready */
933e12c5d1SDavid du Colombier 	atnotify(notifyf, 1);
943e12c5d1SDavid du Colombier 	alarm(30*1000);
95*5d459b5aSDavid du Colombier 	crcmode = 0;
963e12c5d1SDavid du Colombier 	for(;;){
973e12c5d1SDavid du Colombier 		if(read(0, &c, 1) != 1){
983e12c5d1SDavid du Colombier 			fprint(2, "xms: timeout\n");
993e12c5d1SDavid du Colombier 			exits("timeout");
1003e12c5d1SDavid du Colombier 		}
1013e12c5d1SDavid du Colombier 		c = c & 0x7f;
1023e12c5d1SDavid du Colombier 		if(c == Nak)
1033e12c5d1SDavid du Colombier 			break;
104*5d459b5aSDavid du Colombier 		if(c == 'C') {
105*5d459b5aSDavid du Colombier 			if (debug)
106*5d459b5aSDavid du Colombier 				fprint(2, "crc mode engaged\n");
107*5d459b5aSDavid du Colombier 			crcmode = 1;
108*5d459b5aSDavid du Colombier 			break;
109*5d459b5aSDavid du Colombier 		}
1103e12c5d1SDavid du Colombier 	}
1113e12c5d1SDavid du Colombier 	alarm(0);
1123e12c5d1SDavid du Colombier 
113*5d459b5aSDavid du Colombier 	/* send the file in 128/1024 byte chunks */
1143e12c5d1SDavid du Colombier 	for(bytes = 0, seqno = 1; ; bytes += n, seqno++){
115*5d459b5aSDavid du Colombier 		n = read(fd, buf+3, onek ? 1024 : 128);
1163e12c5d1SDavid du Colombier 		if(n < 0)
1173e12c5d1SDavid du Colombier 			exits("read");
1183e12c5d1SDavid du Colombier 		if(n == 0)
1193e12c5d1SDavid du Colombier 			break;
120*5d459b5aSDavid du Colombier 		if(n < (onek ? 1024 : 128))
121*5d459b5aSDavid du Colombier 			memset(&buf[n+3], 0, (onek ? 1024 : 128)-n);
122*5d459b5aSDavid du Colombier 		buf[0] = onek ? Stx : Soh;
1233e12c5d1SDavid du Colombier 		buf[1] = seqno;
1243e12c5d1SDavid du Colombier 		buf[2] = 255 - seqno;
1253e12c5d1SDavid du Colombier 
1263e12c5d1SDavid du Colombier 		/* calculate checksum and stuff into last byte */
127*5d459b5aSDavid du Colombier 		if (crcmode) {
128*5d459b5aSDavid du Colombier 			unsigned short crc;
129*5d459b5aSDavid du Colombier 			crc = 0;
130*5d459b5aSDavid du Colombier 			for(p = buf + 3; p < &buf[(onek ? 1024 : 128)+3]; p++)
131*5d459b5aSDavid du Colombier 				crc = updcrc(*p, crc);
132*5d459b5aSDavid du Colombier 			crc = updcrc(0, crc);
133*5d459b5aSDavid du Colombier 			crc = updcrc(0, crc);
134*5d459b5aSDavid du Colombier 			buf[(onek ? 1024 : 128) + 3] = crc >> 8;
135*5d459b5aSDavid du Colombier 			buf[(onek ? 1024 : 128) + 4] = crc;
136*5d459b5aSDavid du Colombier 		}
137*5d459b5aSDavid du Colombier 		else {
1383e12c5d1SDavid du Colombier 			sum = 0;
139*5d459b5aSDavid du Colombier 			for(p = buf + 3; p < &buf[(onek ? 1024 : 128)+3]; p++)
1403e12c5d1SDavid du Colombier 				sum += *p;
141*5d459b5aSDavid du Colombier 			buf[(onek ? 1024 : 128) + 3] = sum;
142*5d459b5aSDavid du Colombier 		}
1433e12c5d1SDavid du Colombier 
144*5d459b5aSDavid du Colombier 		if(send(buf, (onek ? 1024 : 128) + 4 + crcmode) < 0)
1453e12c5d1SDavid du Colombier 			errorout(ctl, bytes);
146*5d459b5aSDavid du Colombier 		if (progress && bytes % 10240 == 0)
147*5d459b5aSDavid du Colombier 			fprint(2, "%dK\n", bytes / 1024);
1483e12c5d1SDavid du Colombier 	}
1493e12c5d1SDavid du Colombier 
1503e12c5d1SDavid du Colombier 	/* tell other side we're done */
1513e12c5d1SDavid du Colombier 	buf[0] = Eot;
1523e12c5d1SDavid du Colombier 	if(send(buf, 1) < 0)
1533e12c5d1SDavid du Colombier 		errorout(ctl, bytes);
1543e12c5d1SDavid du Colombier 
1553e12c5d1SDavid du Colombier 	fprint(2, "xms: %d bytes transmitted\n", bytes);
1563e12c5d1SDavid du Colombier 	write(ctl, "rawoff", 6);
1573e12c5d1SDavid du Colombier 	exits(0);
1583e12c5d1SDavid du Colombier }
1593e12c5d1SDavid du Colombier 
1603e12c5d1SDavid du Colombier /*
1613e12c5d1SDavid du Colombier  *  send a message till it's acked or we give up
1623e12c5d1SDavid du Colombier  */
1633e12c5d1SDavid du Colombier int
send(uchar * buf,int len)1643e12c5d1SDavid du Colombier send(uchar *buf, int len)
1653e12c5d1SDavid du Colombier {
1663e12c5d1SDavid du Colombier 	int tries;
1673e12c5d1SDavid du Colombier 	int n;
1683e12c5d1SDavid du Colombier 	uchar c;
1693e12c5d1SDavid du Colombier 
1703e12c5d1SDavid du Colombier 	for(tries = 0;; tries++, sleep(2*1000)){
1713e12c5d1SDavid du Colombier 		if(tries == 10)
1723e12c5d1SDavid du Colombier 			return -1;
1733e12c5d1SDavid du Colombier 		if(write(1, buf, len) != len)
1743e12c5d1SDavid du Colombier 			return -1;
1753e12c5d1SDavid du Colombier 
1763e12c5d1SDavid du Colombier 		alarm(30*1000);
1773e12c5d1SDavid du Colombier 		n = read(0, &c, 1);
1783e12c5d1SDavid du Colombier 		alarm(0);
1793e12c5d1SDavid du Colombier 		if(debug) switch(c){
1803e12c5d1SDavid du Colombier 		case Soh:
1813e12c5d1SDavid du Colombier 			fprint(2, " Soh");
1823e12c5d1SDavid du Colombier 			break;
1833e12c5d1SDavid du Colombier 		case Eot:
1843e12c5d1SDavid du Colombier 			fprint(2, " Eot");
1853e12c5d1SDavid du Colombier 			break;
1863e12c5d1SDavid du Colombier 		case Ack:
1873e12c5d1SDavid du Colombier 			fprint(2, " Ack");
1883e12c5d1SDavid du Colombier 			break;
1893e12c5d1SDavid du Colombier 		case Nak:
1903e12c5d1SDavid du Colombier 			fprint(2, " Nak");
1913e12c5d1SDavid du Colombier 			break;
1923e12c5d1SDavid du Colombier 		case Cancel:
1933e12c5d1SDavid du Colombier 			fprint(2, "\nremote Cancel\n");
1943e12c5d1SDavid du Colombier 			return -1;
1953e12c5d1SDavid du Colombier 		default:
1963e12c5d1SDavid du Colombier 			if(isprint(c))
1973e12c5d1SDavid du Colombier 				fprint(2, "%c", c);
1983e12c5d1SDavid du Colombier 			else
1997dd7cddfSDavid du Colombier 				fprint(2, " \\0%o", c);
2003e12c5d1SDavid du Colombier 		}
2013e12c5d1SDavid du Colombier 		c = c & 0x7f;
2023e12c5d1SDavid du Colombier 		if(n == 1 && c == Ack)
2033e12c5d1SDavid du Colombier 			break;
2043e12c5d1SDavid du Colombier 	}
2053e12c5d1SDavid du Colombier 	return 0;
2063e12c5d1SDavid du Colombier }
2073e12c5d1SDavid du Colombier 
2083e12c5d1SDavid du Colombier int
notifyf(void * a,char * msg)2093e12c5d1SDavid du Colombier notifyf(void *a, char *msg)
2103e12c5d1SDavid du Colombier {
2113e12c5d1SDavid du Colombier 	USED(a);
2123e12c5d1SDavid du Colombier 	if(strcmp(msg, "alarm") == 0)
2133e12c5d1SDavid du Colombier 		return 1;
2143e12c5d1SDavid du Colombier 	return 0;
2153e12c5d1SDavid du Colombier }
216