实例介绍
【实例截图】
【核心代码】
#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小时内给予删除,不得用于其他任何用途,否则后果自负。基于互联网的特殊性,平台无法对用户传输的作品、信息、内容的权属或合法性、安全性、合规性、真实性、科学性、完整权、有效性等进行实质审查;无论平台是否已进行审查,用户均应自行承担因其传输的作品、信息、内容而可能或已经产生的侵权或权属纠纷等法律责任。本站所有资源不代表本站的观点或立场,基于网友分享,根据中国法律《信息网络传播权保护条例》第二十二与二十三条之规定,若资源存在侵权或相关问题请联系本站客服人员,点此联系我们。关于更多版权及免责申明参见 版权及免责申明


网友评论
我要评论