实例介绍
【实例截图】
【核心代码】
#include "stdafx.h" #include "ymodem_tx.h" #include <string.h> // for memcpy and memset /** Minimum time in milli-seconds to wait for response from receiver. */ const unsigned SendTimeout = 11*1000; /** Process response from receiver. @param c Value received from InChar. @return One if received an ACKnowledge, zero if received a Negative AcKnowledge, or a negative error value. */ int YModemTx::ProcessResponse(int c) { if(c<0) return c; if(c==CAN) { if(CancelCount ) return ErrorTranferTerminatedByReceiver; return 0; } CancelCount = 0; if(c==ACK) return 1; return 0; } /** Begin the Y-Modem transfer. @param timeout Time in milliseconds to wait receiver to become ready. @return Zero if transfer initialisation was successful, or an error code on failure. */ int YModemTx::SendInitialise(unsigned timeout) { if(timeout<SendTimeout) timeout = SendTimeout; while(InChar(0)>=0) // flush input buffers {} CancelCount = 0; int c; for(;;) { const unsigned timeoutStep = 10; c = InChar(timeoutStep); if(c=='G') { SendCRC = true; WaitForBlockACK = false; break; } else if(c=='C') { SendCRC = true; WaitForBlockACK = true; break; } else if(c==NAK) { SendCRC = false; WaitForBlockACK = true; break; } if(c<0 && c!=ErrorTimeout) return c; if(timeout<timeoutStep) return ErrorTimeout; timeout -= timeoutStep; } ModeChar = c; return 0; } /** Send a single block of data. A zero sized block terminates the transfer. @param data The data to transfer. @param size Size of data. @return The number of transfered, or an error code on failure. The number of bytes may be less than \a size. @pre SendInitialise() must have been successful. */ int YModemTx::SendBlock(const uint8_t* data, size_t size) { uint8_t block[1 2 1024 2]; // buffer to hold data in the block int retryCount = 10; // number of attempts to send the block bool waitForBlockACK = WaitForBlockACK; change_mode: size_t blockSize = (Use1KBlocks && size>=1024) ? 1024 : 128; size_t dataSize = size<blockSize ? size : blockSize; // size of data to send in block if(!dataSize) { // all bytes sent, so end transfer by sending a single EOT... block[0] = EOT; blockSize = 1; waitForBlockACK = true; } else { // make block header... block[0] = blockSize==1024 ? STX : SOH; block[1] = BlockNumber&0xffu; block[2] = (~BlockNumber)&0xffu; // copy data for block (padding with EOF)... memcpy(block 3,data,dataSize); memset(block 3 dataSize,26,blockSize-dataSize); // append checksum/crc... if(SendCRC) { uint16_t crc = CRC16(block 3,blockSize); blockSize = 3; block[blockSize ] = (uint8_t)(crc>>8); block[blockSize ] = (uint8_t)crc; } else { uint8_t sum = Checksum(block 3,blockSize); blockSize = 3; block[blockSize ] = sum; } } do_retry: // count attenpts... if(!retryCount--) return ErrorBlockRetriesExceded; uint8_t* out = block; size_t outSize = blockSize; for(;;) { // send some data... int result = Port.Out(out,outSize,1000); if(result<0) return result; // return error if(result==0) return ErrorTimeout; // adjust for data remaining... out = result; outSize -= result; // end if done... if(!outSize) break; // poll for signal from receiver... result = ProcessResponse(InChar(10)); if(result==ErrorTimeout) continue; // nothing received if(result<0) return result; // return error if(!result) goto retry; // negative acknowledge received } if(waitForBlockACK) { // wait for up to one second for block to be acknowledged... int c = InChar(1000); int result = ProcessResponse(c); if(result<0) return result; // return error if(!result) { // negagtive acknowledge received... if(c=='C' && !SendCRC) { // change to CRC mode if receiver sent 'C', and retry... SendCRC = true; goto change_mode; } goto retry; } } else { // check for receiver sending a cancel byte... int result = ProcessResponse(InChar(0)); if(result<0) { if(result!=ErrorTimeout) return result; // return error if it's not a timeout } else { // ignore other responses } } // block transferred OK... BlockNumber; return dataSize; retry: while(InChar(500)>=0) // flush input buffers {} goto do_retry; } /** Send data. A zero sized block terminates the transfer. @param data The data to transfer. @param size Size of data. @return Zero if successful, or a negative error value if failed. @pre SendInitialise() must have been successful. */ int YModemTx::SendData(const uint8_t* data, size_t size) { do { int result = SendBlock(data, size); if(result<0) return result; data = result; size -= result; } while(size); return 0; } /** Send an entire stread of data. @param in The stream of data to send. @return Zero if successful, or a negative error value if failed. @pre SendInitialise() must have been successful. */ int YModemTx::SendAll(InStream& in) { BlockNumber = 1; // first block to send is number one size_t size; do { // get data from input stream... uint8_t data[1024]; int result = in.In(data,sizeof(data)); if(result<0) return ErrorInputStreamError; // send data... size = result; result = SendData(data,size); if(result<0) return result; } while(size); // end when no more data left return 0; } /** Construct the data for the first block of a Y-Modem transfer. @param[out] buffer The buffer to store the constructed block. Size must be >=128 bytes. @param fileName The name of the file being transferred. @param fileSize The size of the file being transferred. @return Zero if successful, or a negative error value if failed. */ int YModemTx::MakeBlock0(uint8_t* buffer, const char* fileName, size_t fileSize) { // setup buffer for block 0... uint8_t* out = buffer; uint8_t* outEnd = buffer 128-1; memset(buffer,0,128); // copy file name to block data... while(out<outEnd) { char c = *fileName ; if(c>='A' && c<='Z') c = 'a'-'A'; // convert name to lower-case else if(c=='\\') c = '/'; // convert back-slash to forward-slash *out = c; if(!c) break; // end of name } // convert fileSize to a decimal number... char length[sizeof(size_t)*3 1]; // buffer big enough to hold length as decimal number char* lenEnd = length sizeof(length); char* len = lenEnd; do { *--len = '0' fileSize%10; // prepend digit to buffer fileSize /= 10; } while(fileSize); // end when all digits done // append file length to block data... while(out<outEnd && len<lenEnd) *out = *len ; // check that buffer was big enough... if(out>=outEnd) return ErrorFileNameTooLong; return 0; // OK } YModemTx::YModemTx(SerialPort& port) : YModem(port) { } int YModemTx::SendX(InStream& in, unsigned timeout, bool kMode) { Use1KBlocks = kMode; int result = SendInitialise(timeout); if(result<0) return result; return SendAll(in); } int YModemTx::SendY(const char* fileName, size_t size, InStream& in, unsigned timeout) { Use1KBlocks = true; uint8_t buffer[128]; int result = MakeBlock0(buffer,fileName,size); if(result<0) return result; result = SendInitialise(timeout); if(result<0 && result!=ErrorBlockRetriesExceded) return result; BlockNumber = 0; result = SendBlock(buffer,sizeof(buffer)); if(result<0) return result; result = InChar(SendTimeout); if(result<0) return result; if(result!=ModeChar) return ErrorReceiverNotBehaving; result = SendAll(in); if(result<0) return result; result = InChar(SendTimeout); if(result<0) return result; if(result!=ModeChar) return ErrorReceiverNotBehaving; memset(buffer,0,sizeof(buffer)); BlockNumber = 0; result = SendBlock(buffer,sizeof(buffer)); if(result<0) return result; return 0; }
标签: 串口 更新 自串口自动更新动 上位机.ymodem
小贴士
感谢您为本站写下的评论,您的评论对其它用户来说具有重要的参考价值,所以请认真填写。
- 类似“顶”、“沙发”之类没有营养的文字,对勤劳贡献的楼主来说是令人沮丧的反馈信息。
- 相信您也不想看到一排文字/表情墙,所以请不要反馈意义不大的重复字符,也请尽量不要纯表情的回复。
- 提问之前请再仔细看一遍楼主的说明,或许是您遗漏了。
- 请勿到处挖坑绊人、招贴广告。既占空间让人厌烦,又没人会搭理,于人于己都无利。
关于好例子网
本站旨在为广大IT学习爱好者提供一个非营利性互相学习交流分享平台。本站所有资源都可以被免费获取学习研究。本站资源来自网友分享,对搜索内容的合法性不具有预见性、识别性、控制性,仅供学习研究,请务必在下载后24小时内给予删除,不得用于其他任何用途,否则后果自负。基于互联网的特殊性,平台无法对用户传输的作品、信息、内容的权属或合法性、安全性、合规性、真实性、科学性、完整权、有效性等进行实质审查;无论平台是否已进行审查,用户均应自行承担因其传输的作品、信息、内容而可能或已经产生的侵权或权属纠纷等法律责任。本站所有资源不代表本站的观点或立场,基于网友分享,根据中国法律《信息网络传播权保护条例》第二十二与二十三条之规定,若资源存在侵权或相关问题请联系本站客服人员,点此联系我们。关于更多版权及免责申明参见 版权及免责申明
网友评论
我要评论