ymodem_rx.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00032 #include "../common/common.h"
00033 #include "ymodem_rx.h"
00034
00035
00036 #include <string.h>
00037
00038
00042 const unsigned ReceiveTimeout = 1*1000;
00043
00044
00045 YModemRx::YModemRx(SerialPort& port)
00046 : YModem(port)
00047 {
00048 }
00049
00050
00058 int YModemRx::OutChar(uint8_t c)
00059 {
00060 int result = Port.Out(&c,1,1000);
00061 if(result==0)
00062 return ErrorTimeout;
00063 return result;
00064 }
00065
00066
00082 int YModemRx::ReceiveBlock(OutStream& out)
00083 {
00084 uint8_t block[1+2+1024+2];
00085
00086 int retryCount = 10;
00087 do_retry:
00088
00089 if(!retryCount--)
00090 return ErrorBlockRetriesExceded;
00091
00092 size_t blockSize = 128;
00093 uint8_t* data = block;
00094 size_t size = 1+2+blockSize+1+ExpectCRC;
00095 do
00096 {
00097
00098 int result = Port.In(data,size,ReceiveTimeout);
00099 if(result<0)
00100 return result;
00101
00102
00103 if(result==0)
00104 {
00105 if(data==block)
00106 return ErrorTimeout;
00107
00108 goto retry;
00109 }
00110
00111
00112 if(block[0]==EOT)
00113 {
00114 int result = OutChar(ACK);
00115 if(result<0)
00116 return result;
00117 return out.Out(0,0);
00118 }
00119
00120
00121 if(block[0]==STX && blockSize!=1024)
00122 {
00123 blockSize = 1024;
00124 size += 1024-128;
00125 }
00126
00127
00128 data += result;
00129 size -= result;
00130 }
00131 while(size);
00132
00133 if(block[0] != (blockSize==1024 ? STX : SOH))
00134 goto retry;
00135 if(block[1] != (block[2]^0xff))
00136 goto retry;
00137 if(block[1] != (BlockNumber&0xffu))
00138 goto retry;
00139
00140 if(ExpectCRC)
00141 {
00142 uint16_t crc = CRC16(block+1+2,blockSize);
00143 uint16_t receiveCrc = (block[1+2+blockSize+0]<<8)+block[1+2+blockSize+1];
00144 if(crc!=receiveCrc)
00145 goto retry;
00146 }
00147 else
00148 {
00149 uint8_t sum = Checksum(block+1+2,blockSize);
00150 if(sum!=block[1+2+blockSize])
00151 goto retry;
00152 }
00153
00154 {
00155
00156 int result = out.Out(block+3,blockSize);
00157 if(result<0)
00158 return result;
00159
00160
00161 if(SendBlockACK)
00162 {
00163 result = OutChar(ACK);
00164 if(result<0)
00165 return result;
00166 }
00167 ++BlockNumber;
00168 return blockSize;
00169 }
00170
00171 retry:
00172 while(InChar(ReceiveTimeout)>=0)
00173 {}
00174 int result = OutChar(NAKChar);
00175 if(result<0)
00176 return result;
00177 goto do_retry;
00178 }
00179
00180
00189 int YModemRx::ReceiveInitialise(OutStream& out, unsigned timeout)
00190 {
00191 for(;;)
00192 {
00193 int result = OutChar(ModeChar);
00194 if(result!=ErrorTimeout)
00195 {
00196 if(result<0)
00197 return result;
00198 result = ReceiveBlock(out);
00199 if(result!=ErrorTimeout)
00200 return result;
00201 }
00202 if(timeout<ReceiveTimeout)
00203 return ErrorTimeout;
00204 timeout -= ReceiveTimeout;
00205 }
00206 }
00207
00208
00209 int YModemRx::ReceiveX(OutStream& out, unsigned timeout, bool useCrc)
00210 {
00211 ModeChar = useCrc ? (uint8_t)'C' : (uint8_t)NAK;
00212 ExpectCRC = useCrc;
00213 SendBlockACK = true;
00214 NAKChar = ModeChar;
00215
00216
00217 BlockNumber = 1;
00218 int result = ReceiveInitialise(out,timeout);
00219 if(result==ErrorTimeout)
00220 return result;
00221
00222
00223 while(result)
00224 {
00225 if(result<0)
00226 goto error;
00227 result = ReceiveBlock(out);
00228 }
00229
00230
00231 return 0;
00232
00233 error:
00234 Cancel();
00235 return result;
00236 }
00237
00238
00242 inline YModemRx::OutBlock0::OutBlock0()
00243 : Size(0)
00244 {}
00245
00246
00247 int YModemRx::OutBlock0::Open(const char* , size_t )
00248 {
00249 return ErrorOutputStreamError;
00250 }
00251
00252
00261 int YModemRx::OutBlock0::Out(const uint8_t* data, size_t size)
00262 {
00263 memcpy(Buffer,data,size);
00264 Size = size;
00265 return 0;
00266 }
00267
00268
00277 int YModemRx::OutBlock0::Parse(const char*& fileName, size_t& fileSize)
00278 {
00279 const char* buffer = (char*)Buffer;
00280 size_t bufferSize = Size;
00281
00282
00283 fileName = (char*)buffer;
00284 const char* bufferEnd = buffer+bufferSize;
00285 while(*buffer++)
00286 {
00287 if(buffer>=bufferEnd)
00288 return YModemRx::ErrorReceivedBadData;
00289 }
00290
00291
00292 size_t size = 0;
00293 while(buffer<bufferEnd)
00294 {
00295 unsigned digit = *buffer++;
00296 if(!digit)
00297 break;
00298 if(digit==' ')
00299 break;
00300 digit -= '0';
00301 if(digit>9)
00302 return YModemRx::ErrorReceivedBadData;
00303 size_t oldSize = size;
00304 size = size*10+digit;
00305 if(size<oldSize)
00306 return YModemRx::ErrorReceivedBadData;
00307 }
00308 fileSize = size;
00309
00310
00311 return 0;
00312 }
00313
00314
00315 int YModemRx::ReceiveY(OutStream& out, unsigned timeout, bool gMode)
00316 {
00317 ModeChar = gMode ? 'G' : 'C';
00318 ExpectCRC = true;
00319 SendBlockACK = !gMode;
00320 NAKChar = ModeChar;
00321 unsigned fileCount = 0;
00322 int result;
00323
00324 for(;;)
00325 {
00326
00327 YModemRx::OutBlock0 block0;
00328 BlockNumber = 0;
00329 result = ReceiveInitialise(block0,timeout);
00330 if(result==ErrorTimeout && !fileCount)
00331 return result;
00332 if(result<0)
00333 goto error;
00334 if(result!=128)
00335 return 0;
00336
00337
00338 const char* fileName;
00339 size_t size;
00340 result = block0.Parse(fileName,size);
00341 if(result<0)
00342 goto error;
00343 if(fileName[0]==0)
00344 return 0;
00345 if(fileCount)
00346 return ErrorMultipleFilesSent;
00347 result = out.Open(fileName,size);
00348 if(result<0)
00349 goto error;
00350
00351
00352 NAKChar = NAK;
00353 result = OutChar(ModeChar);
00354 while(result)
00355 {
00356 if(result<0)
00357 goto error;
00358 result = ReceiveBlock(out);
00359 }
00360
00361
00362 ++fileCount;
00363 }
00364 error:
00365 Cancel();
00366 return result;
00367 }