ymodem_tx.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_tx.h"
00034
00035
00036 #include <string.h>
00037
00038
00042 const unsigned SendTimeout = 11*1000;
00043
00044
00054 int YModemTx::ProcessResponse(int c)
00055 {
00056 if(c<0)
00057 return c;
00058 if(c==CAN)
00059 {
00060 if(CancelCount++)
00061 return ErrorTranferTerminatedByReceiver;
00062 return 0;
00063 }
00064 CancelCount = 0;
00065 if(c==ACK)
00066 return 1;
00067 return 0;
00068 }
00069
00070
00078 int YModemTx::SendInitialise(unsigned timeout)
00079 {
00080 if(timeout<SendTimeout)
00081 timeout = SendTimeout;
00082
00083 while(InChar(0)>=0)
00084 {}
00085
00086 CancelCount = 0;
00087
00088 int c;
00089 for(;;)
00090 {
00091 const unsigned timeoutStep = 10;
00092 c = InChar(timeoutStep);
00093 if(c=='G')
00094 {
00095 SendCRC = true;
00096 WaitForBlockACK = false;
00097 break;
00098 }
00099 else if(c=='C')
00100 {
00101 SendCRC = true;
00102 WaitForBlockACK = true;
00103 break;
00104 }
00105 else if(c==NAK)
00106 {
00107 SendCRC = false;
00108 WaitForBlockACK = true;
00109 break;
00110 }
00111 if(c<0 && c!=ErrorTimeout)
00112 return c;
00113 if(timeout<timeoutStep)
00114 return ErrorTimeout;
00115 timeout -= timeoutStep;
00116 }
00117
00118 ModeChar = c;
00119 return 0;
00120 }
00121
00122
00135 int YModemTx::SendBlock(const uint8_t* data, size_t size)
00136 {
00137 uint8_t block[1+2+1024+2];
00138 int retryCount = 10;
00139 bool waitForBlockACK = WaitForBlockACK;
00140
00141 change_mode:
00142
00143 size_t blockSize = (Use1KBlocks && size>=1024) ? 1024 : 128;
00144 size_t dataSize = size<blockSize ? size : blockSize;
00145
00146 if(!dataSize)
00147 {
00148
00149 block[0] = EOT;
00150 blockSize = 1;
00151 waitForBlockACK = true;
00152 }
00153 else
00154 {
00155
00156 block[0] = blockSize==1024 ? STX : SOH;
00157 block[1] = BlockNumber&0xffu;
00158 block[2] = (~BlockNumber)&0xffu;
00159
00160
00161 memcpy(block+3,data,dataSize);
00162 memset(block+3+dataSize,26,blockSize-dataSize);
00163
00164
00165 if(SendCRC)
00166 {
00167 uint16_t crc = CRC16(block+3,blockSize);
00168 blockSize += 3;
00169 block[blockSize++] = (uint8_t)(crc>>8);
00170 block[blockSize++] = (uint8_t)crc;
00171 }
00172 else
00173 {
00174 uint8_t sum = Checksum(block+3,blockSize);
00175 blockSize += 3;
00176 block[blockSize++] = sum;
00177 }
00178 }
00179
00180 do_retry:
00181
00182 if(!retryCount--)
00183 return ErrorBlockRetriesExceded;
00184
00185 uint8_t* out = block;
00186 size_t outSize = blockSize;
00187 for(;;)
00188 {
00189
00190 int result = Port.Out(out,outSize,1000);
00191 if(result<0)
00192 return result;
00193 if(result==0)
00194 return ErrorTimeout;
00195
00196
00197 out += result;
00198 outSize -= result;
00199
00200
00201 if(!outSize)
00202 break;
00203
00204
00205 result = ProcessResponse(InChar(10));
00206 if(result==ErrorTimeout)
00207 continue;
00208 if(result<0)
00209 return result;
00210 if(!result)
00211 goto retry;
00212 }
00213
00214 if(waitForBlockACK)
00215 {
00216
00217 int c = InChar(1000);
00218 int result = ProcessResponse(c);
00219 if(result<0)
00220 return result;
00221 if(!result)
00222 {
00223
00224 if(c=='C' && !SendCRC)
00225 {
00226
00227 SendCRC = true;
00228 goto change_mode;
00229 }
00230 goto retry;
00231 }
00232 }
00233 else
00234 {
00235
00236 int result = ProcessResponse(InChar(0));
00237 if(result<0)
00238 {
00239 if(result!=ErrorTimeout)
00240 return result;
00241 }
00242 else
00243 {
00244
00245 }
00246 }
00247
00248
00249 ++BlockNumber;
00250 return dataSize;
00251
00252 retry:
00253 while(InChar(500)>=0)
00254 {}
00255 goto do_retry;
00256 }
00257
00258
00270 int YModemTx::SendData(const uint8_t* data, size_t size)
00271 {
00272 do
00273 {
00274 int result = SendBlock(data, size);
00275 if(result<0)
00276 return result;
00277 data += result;
00278 size -= result;
00279 }
00280 while(size);
00281 return 0;
00282 }
00283
00284
00294 int YModemTx::SendAll(InStream& in)
00295 {
00296 BlockNumber = 1;
00297 size_t size;
00298 do
00299 {
00300
00301 uint8_t data[1024];
00302 int result = in.In(data,sizeof(data));
00303 if(result<0)
00304 return ErrorInputStreamError;
00305
00306
00307 size = result;
00308 result = SendData(data,size);
00309 if(result<0)
00310 return result;
00311 }
00312 while(size);
00313 return 0;
00314 }
00315
00316
00326 int YModemTx::MakeBlock0(uint8_t* buffer, const char* fileName, size_t fileSize)
00327 {
00328
00329 uint8_t* out = buffer;
00330 uint8_t* outEnd = buffer+128-1;
00331 memset(buffer,0,128);
00332
00333
00334 while(out<outEnd)
00335 {
00336 char c = *fileName++;
00337 if(c>='A' && c<='Z')
00338 c += 'a'-'A';
00339 else if(c=='\\')
00340 c = '/';
00341 *out++ = c;
00342 if(!c)
00343 break;
00344 }
00345
00346
00347 char length[sizeof(size_t)*3+1];
00348 char* lenEnd = length+sizeof(length);
00349 char* len = lenEnd;
00350 do
00351 {
00352 *--len = '0'+fileSize%10;
00353 fileSize /= 10;
00354 }
00355 while(fileSize);
00356
00357
00358 while(out<outEnd && len<lenEnd)
00359 *out++ = *len++;
00360
00361
00362 if(out>=outEnd)
00363 return ErrorFileNameTooLong;
00364
00365 return 0;
00366 }
00367
00368
00369 YModemTx::YModemTx(SerialPort& port)
00370 : YModem(port)
00371 {
00372 }
00373
00374
00375 int YModemTx::SendX(InStream& in, unsigned timeout, bool kMode)
00376 {
00377 Use1KBlocks = kMode;
00378 int result = SendInitialise(timeout);
00379 if(result<0)
00380 return result;
00381 return SendAll(in);
00382 }
00383
00384
00385 int YModemTx::SendY(const char* fileName, size_t size, InStream& in, unsigned timeout)
00386 {
00387 Use1KBlocks = true;
00388 uint8_t buffer[128];
00389 int result = MakeBlock0(buffer,fileName,size);
00390 if(result<0)
00391 return result;
00392
00393 result = SendInitialise(timeout);
00394 if(result<0 && result!=ErrorBlockRetriesExceded)
00395 return result;
00396
00397 BlockNumber = 0;
00398 result = SendBlock(buffer,sizeof(buffer));
00399 if(result<0)
00400 return result;
00401
00402 result = InChar(SendTimeout);
00403 if(result<0)
00404 return result;
00405 if(result!=ModeChar)
00406 return ErrorReceiverNotBehaving;
00407
00408 result = SendAll(in);
00409 if(result<0)
00410 return result;
00411
00412 result = InChar(SendTimeout);
00413 if(result<0)
00414 return result;
00415 if(result!=ModeChar)
00416 return ErrorReceiverNotBehaving;
00417
00418 memset(buffer,0,sizeof(buffer));
00419 BlockNumber = 0;
00420 result = SendBlock(buffer,sizeof(buffer));
00421 if(result<0)
00422 return result;
00423
00424 return 0;
00425 }
00426