initial
[fpgammix.git] / workloads / xmodem / xmodem.c
blob651830006a59a10774c8af2b1fb47dcb1c4a1217
1 /*
2 Copyright 2001, 2002 Georges Menie (www.menie.org)
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 /* this code needs standard functions memcpy() and memset()
20 and input/output functions _inbyte() and _outbyte().
22 the prototypes of the input/output functions are:
23 int _inbyte(unsigned short timeout); // msec timeout
24 void _outbyte(int c);
28 #include "xmodem.h"
29 #include "crc16.h"
30 #include "host.h"
32 #define SOH 0x01
33 #define STX 0x02
34 #define EOT 0x04
35 #define ACK 0x06
36 #define NAK 0x15
37 #define CAN 0x18
38 #define CTRLZ 0x1A
40 #define DLY_1S 1000
41 #define MAXRETRANS 25
43 static int check(int crc, const unsigned char *buf, int sz)
45 if (crc) {
46 unsigned short crc = crc16_ccitt(buf, sz);
47 unsigned short tcrc = (buf[sz]<<8)+buf[sz+1];
48 if (crc == tcrc)
49 return 1;
50 } else {
51 int i;
52 unsigned char cks = 0;
53 for (i = 0; i < sz; ++i) {
54 cks += buf[i];
56 if (cks == buf[sz])
57 return 1;
60 return 0;
63 static void flushinput(void)
65 while (_inbyte(((DLY_1S)*3)>>1) >= 0)
69 int xmodemReceive(unsigned char *dest, int destsz)
71 unsigned char xbuff[1030]; /* 1024 for XModem 1k + 3 head chars + 2 crc + nul */
72 unsigned char *p;
73 int bufsz, crc = 0;
74 unsigned char trychar = 'C';
75 unsigned char packetno = 1;
76 int i, c, len = 0;
77 int retry, retrans = MAXRETRANS;
79 for (;;) {
80 for ( retry = 0; retry < 16; ++retry) {
81 if (trychar) _outbyte(trychar);
82 if ((c = _inbyte((DLY_1S)<<1)) >= 0) {
83 switch (c) {
84 case SOH:
85 bufsz = 128;
86 goto start_recv;
87 case STX:
88 bufsz = 1024;
89 goto start_recv;
90 case EOT:
91 flushinput();
92 _outbyte(ACK);
93 return len; /* normal end */
94 case CAN:
95 if ((c = _inbyte(DLY_1S)) == CAN) {
96 flushinput();
97 _outbyte(ACK);
98 return -1; /* canceled by remote */
100 break;
101 default:
102 break;
106 if (trychar == 'C') { trychar = NAK; continue; }
107 flushinput();
108 _outbyte(CAN);
109 _outbyte(CAN);
110 _outbyte(CAN);
111 return -2; /* sync error */
113 start_recv:
114 if (trychar == 'C') crc = 1;
115 trychar = 0;
116 p = xbuff;
117 *p++ = c;
118 for (i = 0; i < (bufsz+(crc?1:0)+3); ++i) {
119 if ((c = _inbyte(DLY_1S)) < 0) goto reject;
120 *p++ = c;
123 if (xbuff[1] == (unsigned char)(~xbuff[2]) &&
124 (xbuff[1] == packetno || xbuff[1] == (unsigned char)packetno-1) &&
125 check(crc, &xbuff[3], bufsz)) {
126 if (xbuff[1] == packetno) {
127 register int count = destsz - len;
128 if (count > bufsz) count = bufsz;
129 if (count > 0) {
130 memcpy(&dest[len], &xbuff[3], count);
131 len += count;
133 ++packetno;
134 retrans = MAXRETRANS+1;
136 if (--retrans <= 0) {
137 flushinput();
138 _outbyte(CAN);
139 _outbyte(CAN);
140 _outbyte(CAN);
141 return -3; /* too many retry error */
143 _outbyte(ACK);
144 continue;
146 reject:
147 flushinput();
148 _outbyte(NAK);
152 #if 0
153 int xmodemTransmit(unsigned char *src, int srcsz)
155 unsigned char xbuff[1030]; /* 1024 for XModem 1k + 3 head chars + 2 crc + nul */
156 int bufsz, crc = -1;
157 unsigned char packetno = 1;
158 int i, c, len = 0;
159 int retry;
161 for (;;) {
162 for ( retry = 0; retry < 16; ++retry) {
163 if ((c = _inbyte((DLY_1S)<<1)) >= 0) {
164 switch (c) {
165 case 'C':
166 crc = 1;
167 goto start_trans;
168 case NAK:
169 crc = 0;
170 goto start_trans;
171 case CAN:
172 if ((c = _inbyte(DLY_1S)) == CAN) {
173 _outbyte(ACK);
174 flushinput();
175 return -1; /* canceled by remote */
177 break;
178 default:
179 break;
183 _outbyte(CAN);
184 _outbyte(CAN);
185 _outbyte(CAN);
186 flushinput();
187 return -2; /* no sync */
189 for (;;) {
190 start_trans:
191 xbuff[0] = SOH; bufsz = 128;
192 xbuff[1] = packetno;
193 xbuff[2] = ~packetno;
194 c = srcsz - len;
195 if (c > bufsz) c = bufsz;
196 if (c >= 0) {
197 memset(&xbuff[3], 0, bufsz);
198 if (c == 0) {
199 xbuff[3] = CTRLZ;
200 } else {
201 memcpy(&xbuff[3], &src[len], c);
202 if (c < bufsz) xbuff[3+c] = CTRLZ;
204 if (crc) {
205 unsigned short ccrc = crc16_ccitt(&xbuff[3], bufsz);
206 xbuff[bufsz+3] = (ccrc>>8) & 0xFF;
207 xbuff[bufsz+4] = ccrc & 0xFF;
208 } else {
209 unsigned char ccks = 0;
210 for (i = 3; i < bufsz+3; ++i) {
211 ccks += xbuff[i];
213 xbuff[bufsz+3] = ccks;
215 for (retry = 0; retry < MAXRETRANS; ++retry) {
216 for (i = 0; i < bufsz+4+(crc?1:0); ++i) {
217 _outbyte(xbuff[i]);
219 if ((c = _inbyte(DLY_1S)) >= 0 ) {
220 switch (c) {
221 case ACK:
222 ++packetno;
223 len += bufsz;
224 goto start_trans;
225 case CAN:
226 if ((c = _inbyte(DLY_1S)) == CAN) {
227 _outbyte(ACK);
228 flushinput();
229 return -1; /* canceled by remote */
231 break;
232 case NAK:
233 default:
234 break;
238 _outbyte(CAN);
239 _outbyte(CAN);
240 _outbyte(CAN);
241 flushinput();
242 return -4; /* xmit error */
243 } else {
244 for (retry = 0; retry < 10; ++retry) {
245 _outbyte(EOT);
246 if ((c = _inbyte((DLY_1S)<<1)) == ACK) break;
248 flushinput();
249 return (c == ACK)?len:-5;
254 #endif
256 #ifdef TEST_XMODEM_RECEIVE
257 int main(void)
259 int st;
261 printf("Send data using the xmodem protocol from your terminal emulator now...\n");
262 /* the following should be changed for your environment:
263 0x30000 is the download address,
264 65536 is the maximum size to be written at this address
266 st = xmodemReceive((char *)0x30000, 65536);
267 if (st < 0) {
268 printf("Xmodem receive error: status: %d\n", st);
269 } else {
270 printf("Xmodem successfully received %d bytes\n", st);
273 return 0;
275 #endif
276 #ifdef TEST_XMODEM_SEND
277 int main(void)
279 int st;
281 printf("Prepare your terminal emulator to receive data now...\n");
282 /* the following should be changed for your environment:
283 0x30000 is the download address,
284 12000 is the maximum size to be send from this address
286 st = xmodemTransmit((char *)0x30000, 12000);
287 if (st < 0) {
288 printf("Xmodem transmit error: status: %d\n", st);
289 } else {
290 printf("Xmodem successfully transmitted %d bytes\n", st);
293 return 0;
295 #endif