-
Notifications
You must be signed in to change notification settings - Fork 1
/
xmodem.c
247 lines (224 loc) · 5.16 KB
/
xmodem.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
/*! \file xmodem.c \brief XModem Transmit/Receive Implementation with CRC and 1K support. */
//*****************************************************************************
//
// File Name : 'xmodem.c'
// Title : XModem Transmit/Receive Implementation with CRC and 1K support
// Author : Pascal Stang - Copyright (C) 2006
// Created : 4/22/2006
// Revised : 7/22/2006
// Version : 0.1
// Target MCU : AVR processors
// Editor Tabs : 4
//
// This code is distributed under the GNU Public License
// which can be found at http://www.gnu.org/licenses/gpl.txt
//
//*****************************************************************************
#include <string.h>
#include "rprintf.h"
#include "timer.h"
#include "xmodem.h"
//#define XMODEM_BUFFER_SIZE 128
#define XMODEM_BUFFER_SIZE 1024
// pointers to stream I/O functions
static void (*xmodemOut)(unsigned char c);
static int (*xmodemIn)(void);
void xmodemInit(void (*sendbyte_func)(unsigned char c), int (*getbyte_func)(void))
{
// assign function pointers
xmodemOut = sendbyte_func;
xmodemIn = getbyte_func;
}
long xmodemReceive( int (*write)(unsigned char* buffer, int size) )
{
// create xmodem buffer
// 1024b for Xmodem 1K
// 128 bytes for Xmodem std.
// + 5b header/crc + NULL
unsigned char xmbuf[XMODEM_BUFFER_SIZE+6];
unsigned char seqnum=1; // xmodem sequence number starts at 1
unsigned short pktsize=128; // default packet size is 128 bytes
unsigned char response='C'; // solicit a connection with CRC enabled
char retry=XMODEM_RETRY_LIMIT;
unsigned char crcflag=0;
unsigned long totalbytes=0;
int i,c;
while(retry > 0)
{
// solicit a connection/packet
xmodemOut(response);
// wait for start of packet
if( (c = xmodemInTime(XMODEM_TIMEOUT_DELAY)) >= 0)
{
switch(c)
{
case SOH:
pktsize = 128;
break;
#if(XMODEM_BUFFER_SIZE>=1024)
case STX:
pktsize = 1024;
break;
#endif
case EOT:
xmodemInFlush();
xmodemOut(ACK);
// completed transmission normally
return totalbytes;
case CAN:
if((c = xmodemInTime(XMODEM_TIMEOUT_DELAY)) == CAN)
{
xmodemInFlush();
xmodemOut(ACK);
// transaction cancelled by remote node
return XMODEM_ERROR_REMOTECANCEL;
}
default:
break;
}
}
else
{
// timed out, try again
// no need to flush because receive buffer is already empty
retry--;
//response = NAK;
continue;
}
// check if CRC mode was accepted
if(response == 'C') crcflag = 1;
// got SOH/STX, add it to processing buffer
xmbuf[0] = c;
// try to get rest of packet
for(i=0; i<(pktsize+crcflag+4-1); i++)
{
if((c = xmodemInTime(XMODEM_TIMEOUT_DELAY)) >= 0)
{
xmbuf[1+i] = c;
}
else
{
// timed out, try again
retry--;
xmodemInFlush();
response = NAK;
break;
}
}
// packet was too small, retry
if(i<(pktsize+crcflag+4-1))
continue;
// got whole packet
// check validity of packet
if( (xmbuf[1] == (unsigned char)(~xmbuf[2])) && // sequence number was transmitted w/o error
xmodemCrcCheck(crcflag, &xmbuf[3], pktsize) ) // packet is not corrupt
{
// is this the packet we were waiting for?
if(xmbuf[1] == seqnum)
{
// write/deliver data
write(&xmbuf[3], pktsize);
//spiflashWrite(flashaddr, pktsize, &xmbuf[3]);
totalbytes += pktsize;
// next sequence number
seqnum++;
// reset retries
retry = XMODEM_RETRY_LIMIT;
// reply with ACK
response = ACK;
continue;
}
else if(xmbuf[1] == (unsigned char)(seqnum-1))
{
// this is a retransmission of the last packet
// ACK and move on
response = ACK;
continue;
}
else
{
// we are completely out of sync
// cancel transmission
xmodemInFlush();
xmodemOut(CAN);
xmodemOut(CAN);
xmodemOut(CAN);
return XMODEM_ERROR_OUTOFSYNC;
}
}
else
{
// packet was corrupt
// NAK it and try again
retry--;
xmodemInFlush();
response = NAK;
continue;
}
}
// exceeded retry count
xmodemInFlush();
xmodemOut(CAN);
xmodemOut(CAN);
xmodemOut(CAN);
return XMODEM_ERROR_RETRYEXCEED;
}
long xmodemTransmit( int (*read)(unsigned char* buffer, int size) )
{
// still to be written
return 0;
}
uint16_t crc_xmodem_update(uint16_t crc, uint8_t data)
{
int i;
crc = crc ^ ((uint16_t)data << 8);
for (i=0; i<8; i++)
{
if(crc & 0x8000)
crc = (crc << 1) ^ 0x1021;
else
crc <<= 1;
}
return crc;
}
int xmodemCrcCheck(int crcflag, const unsigned char *buffer, int size)
{
// crcflag=0 - do regular checksum
// crcflag=1 - do CRC checksum
if(crcflag)
{
unsigned short crc=0;
unsigned short pktcrc = (buffer[size]<<8)+buffer[size+1];
// do CRC checksum
while(size--)
crc = crc_xmodem_update(crc, *buffer++);
// check checksum against packet
if(crc == pktcrc)
return 1;
}
else
{
int i;
unsigned char cksum = 0;
// do regular checksum
for(i=0; i<size; ++i)
{
cksum += buffer[i];
}
// check checksum against packet
if(cksum == buffer[size])
return 1;
}
return 0;
}
int xmodemInTime(unsigned short timeout)
{
int c=-1;
while( (timeout--) && ((c=xmodemIn()) < 0) )
timerPause(1);
return c;
}
void xmodemInFlush(void)
{
while(xmodemInTime(XMODEM_TIMEOUT_DELAY) >= 0);
}