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