Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
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
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
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
209
notifyf(void *a, char *msg)
210
{
211
	USED(a);
212
	if(strcmp(msg, "alarm") == 0)
213
		return 1;
214
	return 0;
215
}