YModem协议
源:YModem协议
YModem协议:
YModem协议是由XModem协议演变而来的,每包数据可以达到1024字节,是一个非常高效的文件传输协议。
下面先看下YModem协议传输的完整的握手过程:先看下图
SENDER:发送方。
RECEIVER:接收方。
第一步先由接收方,发送一个字符'C'
发送方收到'C'后,发送第一帧数据包,内容如下:
SOH 00 FF Foo.c NUL[123] CRC CRC
第1字节SOH:表示本包数据区大小有128字节。如果头为STX表示本包数据区大小为1024
第2字节00: 编号,第一包为00,第二包为01,第三包为02依次累加。到FF后继续从0循环递增。
第3字节FF: 编号的反码。 编号为00 对应FF,为01对应FE,以此类推。
第4字节到最后两字节:若第1字节为SOH时有128字节,为STX时有1024字节,这部分为数据区。“Foo.c” 文件名, 超级终端下,在文件名后还有文件大小。官方dome也是因为使用了这个文件大小进行比对。这就是为什么用SecureCRT中的YMODEM协议而无法正确传输的原因。在文件名和文件大小之后,如果不满128字节,以0补满。
最后两字节:这里需要注意,只有数据部分参与了效CRC验,不包括头和编码部分。
16位CRC效验,高字节在前,低字节在后。
接收方收到第一帧数据包后,发送ACK正确应答。
然后再发送一个字符'C'。
发送方收到'C'后,开始发送第二帧,第二帧中的数据存放的是第一包数据。
接收方收到数据后,发送一个ACK然后等待下一包数据传送完毕,继续ACK应答。直到所有数据传输完毕。
数据传输完毕后,发送方发EOT,第一次接收方以NAK应答,进行二次确认。
发送方收到NAK后,重发EOT,接收方第二次收到结束符,就以ACK应答。
最后接收方再发送一个'C',发送方在没有第二个文件要传输的情况下,
发送如下数据
SOH 00 FF 00~00(共128个) CRCH CRCL
接收方应答ACK后,正式结束数据传输。
以上部分,为YMODEM协议的基本操作流程。
/****************************************Copyright (c)**************************************************
** Henan Star Hi-Tech CO.,LTD
** All rights reserved.
**
**----------------------------------------File Info-----------------------------------------------------
** 文件名称:
** 工程项目:
** 说 明:
**
** 作 者: 日 期:
** 建立版本:
**
**----------------------------------------modification--------------------------------------------------
** 作 者:
** 日 期:
** 版 本: 标 记:
** 说 明:
**
********************************************************************************************************/ #ifndef __XYMODEM_H_
#define __XYMODEM_H_ #define MODEM_MAX_RETRIES 50 //接收等待延时时间
#define MODEM_CRC_RETRIES 51 //>MODEM_MAX_RETRIES固定为CRC校验
#define MODEM_CAN_COUNT 3 //Wait for 3 times CAN before quiting
#define MODEM_EOT_COUNT 1 #define MODEM_SOH 0x01 //数据块起始字符
#define MODEM_STX 0x02
#define MODEM_EOT 0x04
#define MODEM_ACK 0x06
#define MODEM_NAK 0x15
#define MODEM_CAN 0x18
#define MODEM_C 0x43 typedef struct{
int modemtype;
int crc_mode;
int nxt_num; //下一数据块序号
int cur_num; //当块序号
int len;
int rec_err; //数据块接收状态
unsigned char buf[]; //数据
unsigned int filelen; //Ymodem可有带文件名称和长度
unsigned char filename[];
}modem_struct; #ifdef __cplusplus
extern "C"{
#endif int ymodem_init(modem_struct *mblock);
int modem_recvdata(modem_struct *mblock);
//int crc_16(unsigned char *buf, int len);
void modem_cancle(void);
#ifdef __cplusplus
}
#endif #endif
/****************************************Copyright (c)**************************************************
** Henan Star Hi-Tech CO.,LTD
** All rights reserved.
**
**----------------------------------------File Info-----------------------------------------------------
** 文件名称:
** 工程项目:
** 说 明:
**
** 作 者: 日 期:
** 建立版本:
**
**----------------------------------------modification--------------------------------------------------
** 作 者:
** 日 期:
** 版 本: 标 记:
** 说 明:
**
********************************************************************************************************/ #include "xymodem1.h"
#include "heads.h" unsigned int buf_filelen(unsigned char *ptr); /*****************************************************************************************
** 函数名称:
** 函数功能:
** 入口参数:
** 返 回 值:
** 编 写: 日 期: 版 本 号:
** 修改历史:
******************************************************************************************/
int ymodem_init(modem_struct *mblock)
{
int stat;
int max_tries = MODEM_MAX_RETRIES;
int crc_tries =MODEM_CRC_RETRIES;
unsigned char *bufptr = mblock->buf;
unsigned char *namptr = mblock->filename; mblock->nxt_num = ;
mblock->modemtype = ;
mblock->rec_err = ;
mblock->crc_mode = ; while (max_tries-- > )
{
stat = modem_recvdata(mblock);
if ( == stat) //接收成功
{
//file name
while (*bufptr != '\0')
{
*namptr++ = *bufptr++;
}
*namptr = '\0';
bufptr++;
while (*bufptr == ' ')
{
bufptr++;
}
//file length
mblock->filelen = buf_filelen(bufptr);
//other data;
Uart_SendByte(MODEM_ACK);
return ;
}
else if ( == stat) //取消传输
{
return ;
}
else if (- == stat)
{
if (mblock->cur_num == )
{
mblock->modemtype = ;
mblock->nxt_num = ;
return ;
}
}
else //超时或校验方式不对
{
if (crc_tries-- <= )
{
crc_tries = MODEM_CRC_RETRIES;
mblock->crc_mode = (mblock->crc_mode+) & ;
}
}
}
return -;
} /*****************************************************************************************
** 函数名称:
** 函数功能:
** 入口参数:
** 返 回 值:0:成功接收数据 -1:接收超时 -2:帧错误
-3:帧序号序号错误(严重错误) 1:消息结束 2:取消发送
** 编 写: 日 期: 版 本 号:
** 修改历史:
******************************************************************************************/
int modem_recvdata(modem_struct *mblock)
{
int stat, hd_found=, i;
int can_counter=, eot_counter=;
unsigned char *in_ptr = mblock->buf;
int cksum;
unsigned char ch, blk, cblk, crch, crcl; Uart_RxEmpty(); //接收缓冲区清空 if (mblock->nxt_num == )
{
if (mblock->crc_mode)
{
Uart_SendByte(MODEM_C);
}
else
{
Uart_SendByte(MODEM_NAK);
}
}
else
{
if (mblock->rec_err)
{
Uart_SendByte(MODEM_NAK);
}
else
{
if (mblock->nxt_num == )
{
if (mblock->crc_mode)
{
Uart_SendByte(MODEM_C);
}
else
{
Uart_SendByte(MODEM_NAK);
}
}
else
{
Uart_SendByte(MODEM_ACK);
}
}
}
while (!hd_found) //头字节
{
stat = Uart_RecvByteTimeout(&ch);
if (stat == )
{
switch (ch)
{
case MODEM_SOH :
hd_found = ;
mblock->len = ;
break;
case MODEM_STX :
hd_found = ;
mblock->len = ;
break;
case MODEM_CAN :
if ((++can_counter) >= MODEM_CAN_COUNT)
{
return ;
}
break;
case MODEM_EOT : //文件传输结束
if ((++eot_counter) >= MODEM_EOT_COUNT)
{
Uart_SendByte(MODEM_ACK);
if (mblock->modemtype == ) //Ymodem协议为批文件传输协议
{
Uart_SendByte(MODEM_C); //单个文件需 C ACK C后会自动停止传输
Uart_SendByte(MODEM_ACK);
Uart_SendByte(MODEM_C);
modem_cancle(); //多个文件强制停止传输
}
return ;
}
break;
default:
break;
}
}
else
{
return -;
}
} stat = Uart_RecvByteTimeout(&blk); //数据块错误或超时
if (stat != )
{
return -;
} stat = Uart_RecvByteTimeout(&cblk); //数块补码
if (stat != )
{
return -;
} for (i=; i < mblock->len ; i++)
{
stat = Uart_RecvByteTimeout(in_ptr++);
if (stat != )
{
return -;
}
} stat = Uart_RecvByteTimeout(&crch); //CRC
if (stat != )
{
return -;
} if (mblock->crc_mode)
{
stat = Uart_RecvByteTimeout(&crcl);
if (stat != )
{
return -;
}
} if (blk^cblk != 0xff)
{
return (-);
} if (mblock->crc_mode)
{
in_ptr = mblock->buf;
cksum = ; for (stat=mblock->len ; stat>; stat--)
{
cksum = cksum^(int)(*in_ptr++) << ;
for (i=; i!=; i--)
{
if (cksum & 0x8000)
cksum = cksum << ^ 0x1021;
else
cksum = cksum << ;
}
}
cksum &= 0xffff; if (cksum != (crch<< | crcl))
{
mblock->rec_err = ;
return (-);
}
}
else
{
for (i=; i<mblock->len; i++) //和校验方式
{
cksum += mblock->buf[i];
}
if ((cksum&0xff)!=crch)
{
mblock->rec_err = ;
return (-);
}
} mblock->cur_num = blk;
if (blk != mblock->nxt_num) //blk检查
{
return (-);
} mblock->nxt_num++;
mblock->rec_err = ;
return ;
} unsigned int buf_filelen(unsigned char *ptr)
{
int datatype=, result=; if (ptr[]=='' && (ptr[]=='x' && ptr[]=='X'))
{
datatype = ;
ptr += ;
} for ( ; *ptr!='\0'; ptr++)
{
if (*ptr>= '' && *ptr<='')
{
result =result*datatype+*ptr-'';
}
else
{
if (datatype == )
{
return result;
}
else
{
if (*ptr>='A' && *ptr<='F')
{
result = result* + *ptr-; //55 = 'A'-10
}
else if (*ptr>='a' && *ptr<='f')
{
result = result* + *ptr-; //87 = 'a'-10
}
else
{
return result;
}
}
}
}
return result;
} void modem_cancle(void)
{
Uart_SendByte(0x18);
Uart_SendByte(0x18);
Uart_SendByte(0x18);
Uart_SendByte(0x18);
Uart_SendByte(0x18);
}
YModem协议的更多相关文章
- stm32 Bootloader设计(YModem协议) (转)
源:stm32 Bootloader设计(YModem协议) 相信很多人都希望,不开盖就可以对固件进行升级吧,就像手机那些.下文中的bootload就来实现这样的功能. 前段时间有项目关于Bootlo ...
- ymodem协议c实现(转)
源:ymodem协议c实现 /****************************************Copyright (c)******************************** ...
- Ymodem协议说明
模块的固件烧录过程,由Term(发送方)发送固件文件,模块(接收方)接收并写入MCU,期间使用的数据传输协议是ymodem协议. 一.概述 ymodem协议是一种发送并等待的协议,即发送方发送一个 ...
- Ymodem协议(参考STM32)
相信很多人都希望,不开盖就可以对固件进行升级吧,就像手机那些.下文中的bootload就来实现这样的功能. 前段时间有项目关于Bootload设计.所以就仔细的去了研究了一翻.以前都是用的stm32官 ...
- ZYNQ使用ymodem协议传输文件
SDK: V2014.4 协议: Ymodem 工具: USB转UART转接线.xshell6软件 可实现各种文件传输,大小不限,只是速度很慢 参考原代码如下: /****************** ...
- python调用Moxa PCOMM Lite通过串口Ymodem协议发送文件
本文采用python 2.7编写. 经过长期搜寻,终于找到了Moxa PCOMM Lite.调用PCOMM.DLL可以非常方便的通过串口的Xmodem.Ymodem.Zmodem等协议传输文件,而无需 ...
- Kermit,Xmodem,1K-Xmodem,Ymodem,Zmodem传输协议小结
来自:http://blog.163.com/czblaze_3333/blog/static/208996228201272295236713/ Kermit协议 报文格式: 1. MA ...
- STM32 Bootloader基于ymodem传输协议串口IAP升级详解
硬件:stm32f103cbt6 软件:STM32F10x_StdPeriph_Lib_V3.5.0 文章目录 1 预备知识 2 Bootloader 2.1 启动流程 2.2 校验跳转地址是否有效 ...
- STM32F103/429串口IAP+Ymodem升级
起因: 串口IAP升级在正点原子的例程中有讲解,正点原子的方法是:在RAM中开辟一个120K的数据空间,用来存放bin文件,bin文件通过串口一次性发送到单片机,然后再实现程序的跳转.但是这种方法在实 ...
随机推荐
- php模拟post 提交表单
<?php header('Content-type: text/html;charset=UTF-8'); $action=$_REQUEST['action']; //获取验证码 if($a ...
- hibernate的批量更新、批量删除
hibernate的批处理API:session.createQuery(hql).executeUpdate(),如果有参数则在执行之前设置参数. 批量更新示例: @Test public void ...
- HDU3371--Connect the Cities(最小生成树)
Problem Description In 2100, since the sea level rise, most of the cities disappear. Though some sur ...
- loadrunner使用socket协议来实现客户端对服务器产生压力实例。(通过发送心跳包,达到连接多个客户端的目的)
#include "lrs.h" vuser_init(){ char *ip; int handler; //编写获取LR分配的Vuser IP函数,将IP保存在ip变量中. i ...
- windows做时间服务器,linux和windows时间同步
找了很多的资料,都没有windows做时间服务,linux同步windows的时间的,最后自己找了一些软件,终于搞定了,写出来给大家共享,以免大家多走弯路 首先在http://www.meinberg ...
- redis运维的一些知识点
恰好看到一些redis需要主要的东西 记下 供参考 原文地址 http://hi.baidu.com/ywdblog/item/1a8c6ed42edf01866dce3fe3 最近在线上实际使用了一 ...
- 第十六节,基本数据类型,字典dict
字典 常用操作: 索引 新增 删除 键.值.键值对 循环 长度 字典由键值对组成,由一个键(名称)和 一个值组成,与列表和元组不同的是里面的元素是有键的(名称) 所以当要打印字典时,打印字典变量加[键 ...
- centos 7 切换运行模式
如设置命令行级别方法: systemctl set-default multi-user.target 设置窗口级别方法: systemctl set-default graphical.target
- vs设计界面出现“建控件时出错 响应在此上下文中不可用”
使用VS2010设计Asp.net时出现: 只有在配置文件或 Page 指令中将 enableSessionState 设置为 true 时,才能使用会话状态.还请确保在应用程序配置的 \\ 节中包括 ...
- PHP中GD库安装
安装gd库扩展不能像其他扩展安装一样,直接./configure --prefix=/xxx 还需要激活png,jpeg,字库等支持 ./configure --prefix=/xxx --with- ...