xref: /plan9/sys/src/cmd/con/xms.c (revision 5d459b5a09e427ae1acd4e6afcf028853c73946e)
1 #include <u.h>
2 #include <libc.h>
3 #include <ctype.h>
4 
5 enum {
6 	Soh=	0x1,
7 	Stx=	0x2,
8 	Eot=	0x4,
9 	Ack=	0x6,
10 	Nak=	0x15,
11 	Cancel=	0x18,
12 };
13 
14 int send(uchar*, int);
15 int notifyf(void*, char*);
16 
17 int debug, progress, onek;
18 
19 void
errorout(int ctl,int bytes)20 errorout(int ctl, int bytes)
21 {
22 	uchar buf[2];
23 
24 	buf[0] = Cancel;
25 	write(1, buf, 1);
26 	fprint(2, "\nxms: gave up after %d bytes\n", bytes);
27 	write(ctl, "rawoff", 6);
28 	exits("cancel");
29 }
30 
31 ushort
updcrc(int c,ushort crc)32 updcrc(int c, ushort crc)
33 {
34 	int count;
35 
36 	for (count=8; --count>=0;) {
37 		if (crc & 0x8000) {
38 			crc <<= 1;
39 			crc += (((c<<=1) & 0400)  !=  0);
40 			crc ^= 0x1021;
41 		}
42 		else {
43 			crc <<= 1;
44 			crc += (((c<<=1) & 0400)  !=  0);
45 		}
46 	}
47 	return crc;
48 }
49 
50 void
main(int argc,char ** argv)51 main(int argc, char **argv)
52 {
53 	uchar c;
54 	uchar buf[1024+5];
55 	uchar seqno;
56 	int fd, ctl;
57 	long n;
58 	int sum;
59 	uchar *p;
60 	int bytes;
61 	int crcmode;
62 
63 	ARGBEGIN{
64 	case 'd':
65 		debug = 1;
66 		break;
67 	case 'p':
68 		progress = 1;
69 		break;
70 	case '1':
71 		onek = 1;
72 		break;
73 	}ARGEND
74 
75 	if(argc != 1){
76 		fprint(2, "usage: xms filename\n");
77 		exits("usage");
78 	}
79 	fd = open(argv[0], OREAD);
80 	if(fd < 0){
81 		perror("xms");
82 		exits("open");
83 	}
84 
85 	ctl = open("/dev/consctl", OWRITE);
86 	if(ctl < 0){
87 		perror("xms");
88 		exits("consctl");
89 	}
90 	write(ctl, "rawon", 5);
91 
92 	/* give the other side a 30 seconds to signal ready */
93 	atnotify(notifyf, 1);
94 	alarm(30*1000);
95 	crcmode = 0;
96 	for(;;){
97 		if(read(0, &c, 1) != 1){
98 			fprint(2, "xms: timeout\n");
99 			exits("timeout");
100 		}
101 		c = c & 0x7f;
102 		if(c == Nak)
103 			break;
104 		if(c == 'C') {
105 			if (debug)
106 				fprint(2, "crc mode engaged\n");
107 			crcmode = 1;
108 			break;
109 		}
110 	}
111 	alarm(0);
112 
113 	/* send the file in 128/1024 byte chunks */
114 	for(bytes = 0, seqno = 1; ; bytes += n, seqno++){
115 		n = read(fd, buf+3, onek ? 1024 : 128);
116 		if(n < 0)
117 			exits("read");
118 		if(n == 0)
119 			break;
120 		if(n < (onek ? 1024 : 128))
121 			memset(&buf[n+3], 0, (onek ? 1024 : 128)-n);
122 		buf[0] = onek ? Stx : Soh;
123 		buf[1] = seqno;
124 		buf[2] = 255 - seqno;
125 
126 		/* calculate checksum and stuff into last byte */
127 		if (crcmode) {
128 			unsigned short crc;
129 			crc = 0;
130 			for(p = buf + 3; p < &buf[(onek ? 1024 : 128)+3]; p++)
131 				crc = updcrc(*p, crc);
132 			crc = updcrc(0, crc);
133 			crc = updcrc(0, crc);
134 			buf[(onek ? 1024 : 128) + 3] = crc >> 8;
135 			buf[(onek ? 1024 : 128) + 4] = crc;
136 		}
137 		else {
138 			sum = 0;
139 			for(p = buf + 3; p < &buf[(onek ? 1024 : 128)+3]; p++)
140 				sum += *p;
141 			buf[(onek ? 1024 : 128) + 3] = sum;
142 		}
143 
144 		if(send(buf, (onek ? 1024 : 128) + 4 + crcmode) < 0)
145 			errorout(ctl, bytes);
146 		if (progress && bytes % 10240 == 0)
147 			fprint(2, "%dK\n", bytes / 1024);
148 	}
149 
150 	/* tell other side we're done */
151 	buf[0] = Eot;
152 	if(send(buf, 1) < 0)
153 		errorout(ctl, bytes);
154 
155 	fprint(2, "xms: %d bytes transmitted\n", bytes);
156 	write(ctl, "rawoff", 6);
157 	exits(0);
158 }
159 
160 /*
161  *  send a message till it's acked or we give up
162  */
163 int
send(uchar * buf,int len)164 send(uchar *buf, int len)
165 {
166 	int tries;
167 	int n;
168 	uchar c;
169 
170 	for(tries = 0;; tries++, sleep(2*1000)){
171 		if(tries == 10)
172 			return -1;
173 		if(write(1, buf, len) != len)
174 			return -1;
175 
176 		alarm(30*1000);
177 		n = read(0, &c, 1);
178 		alarm(0);
179 		if(debug) switch(c){
180 		case Soh:
181 			fprint(2, " Soh");
182 			break;
183 		case Eot:
184 			fprint(2, " Eot");
185 			break;
186 		case Ack:
187 			fprint(2, " Ack");
188 			break;
189 		case Nak:
190 			fprint(2, " Nak");
191 			break;
192 		case Cancel:
193 			fprint(2, "\nremote Cancel\n");
194 			return -1;
195 		default:
196 			if(isprint(c))
197 				fprint(2, "%c", c);
198 			else
199 				fprint(2, " \\0%o", c);
200 		}
201 		c = c & 0x7f;
202 		if(n == 1 && c == Ack)
203 			break;
204 	}
205 	return 0;
206 }
207 
208 int
notifyf(void * a,char * msg)209 notifyf(void *a, char *msg)
210 {
211 	USED(a);
212 	if(strcmp(msg, "alarm") == 0)
213 		return 1;
214 	return 0;
215 }
216