目录

  • 1.协议介绍
  • 2.协议解析
    • 2.1 控制字符定义
    • 2.2 帧包格式
    • 2.3交互流程
      • Xmodem 校验和交互流程
      • Xmodem CRC16 交互流程
      • 2.4 Ymodem 交互流程
    • 3.超时处理
  • 3.状态机介绍
    • 3.1 状态图的画图规范
    • 3.2 状态图的翻译规范
    • 3.3 总结状态机设计步骤
  • 4.使用状态机实现XMODEM和YMODEM协议
    • 4.1 任务拆分

1.协议介绍

Xmodem 协议最早是以 128 字节块的形式传输数据,并且每个块都使用校验和进行错误检测。后面衍生出使用循环冗余校验方式 (CRC16) 和支持 1024 字节块的传输协议 (Xmodem-1k)。

YMODEM 以三种方式扩展了 XMODEM。与 XMODEM-CRC 一样,YMODEM 用16 位循环冗余校验(CRC)替换了 8 位校验和,但使其成为默认的纠正形式而不是可选形式。从 TeLink 中,它添加了发送文件名和大小的“块 0”标头,这允许批量传输(单个会话中的多个文件)并消除了在文件末尾添加填充的需要。最后,YMODEM 允许将数据块大小从原始的 128 字节增加到 1024,如XMODEM-1k,这大大提高了更快调制解调器的吞吐量。
详细文档请查看:http://pauillac.inria.fr/~doligez/zmodem/ymodem.txt

2.协议解析

Xmodem 和 Ymodem 从控制符定义和帧包格式上是基本一致的。

2.1 控制字符定义

定义 取值 作用
SOH 0X01 modem 128 字节头标志
STX 0X02 modem 1024字节头标志
EOT 0X04 发送结束标志
ACK 0X06 应答标志
NAK 0X15 非应答标志
CAN 0X18 取消发送标志
CRC16 0X43 使用CRC16校验标志

2.2 帧包格式

Byte1 Byte2 Byte3 Byte4-Byte131 Byte132-Byte133
头标志 包序列 ~包序列 包数据 CRC16(2 Byte)

说明: - 该帧是 Xmodem 使用 CRC16 校验方式,如果使用 Xmodem-1k 或者 Ymodem,帧格式 Byte 4 - Byte 131 (128 字节) 需要增大为 Byte 4 - Byte 1027 (1024字节)。 - Xmodem 如果使用校验和,帧格式 Byte 132 - Byte 133 只需要占用一个字节。 - Byte 3 是 Byte 2 按位取反,Byte 2 取值范围 0 - 255,超过 255 后从 0 递增。

2.3交互流程

Xmodem 校验和交互流程

Sender Flow Receiver
< NAK
Timeout after 3 seconds
< Timeout after 3 seconds
SOH 0X01 0XFE DATA[0-127] Checksum > Packet ok
< ACK
SOH 0X02 0XFD DATA[0-127] Checksum > Miss the Packet
< NAK
SOH 0X02 0XFD DATA[0-127] Checksum > Packet ok
< ACK
EOT > Packet ok
Finshed < ACK

Xmodem CRC16 交互流程

说明: - 相比于 Xmodem 校验和, Xmodem CRC16 是发送控制字符 C,而校验和发送控制字符 NAK,并且 CRC16 校验字段占 2 Byte。 - 如果使用 Xmodem-1k 协议发送 1024 字节的数据,只需要将数据头标志由 SOH 替换为 STX,数据部分占 1024 字节。 - 如果发送的数据不满 128 字节或者 1024 字节,使用 0x1A 填充。

2.4 Ymodem 交互流程

Ymodem 协议的起始帧并不直接传输文件的数据,而是将文件名与文件的大小放在数据帧中传输。它的数据帧结构如下:

Byte1 Byte2 Byte3 Byte4-Byte131 Byte132-Byte133
SOH 0X00 0XFF Filename/ ilesize/ NUL CRC16(2 Byte)

说明: - 头标志是 SOH,包序列固定是 0x00。 - Filename 是传输的文件名字,比如 hello_world.bin,它在起始帧中的格式为: 68 65 6c 6c 6f 5f 77 6f 72 6c 64 2e 62 69 6e 00,也就是把 ASCII 码转成十六进制,最后的 0x00 代表文件名结束。 - Filesize 是要传输的文件的大小,比如文件大小为 120 KB,转换为 120 * 1024 = 122880 Byte,转化为十六进制为 0x1E00,它在起始帧中的格式为: 31 45 30 30 00,对应 ASCII 1E00,最后的 0x00 代表文件长度结束。 - 最后 NUL 代表剩余不足 128 Byte 部分用 0x00 填充。
Ymodem 协议的结束帧与起始帧类似,结构如下:

Byte1 Byte2 Byte3 Byte4-Byte131 Byte132-Byte133
SOH 0X00 0XFF NUL CRC16(2 Byte)

文件传输流程:

3.超时处理

1> 接收方等待一个信息包的到来所具有的超时时限为 3 秒,每个超时后发送 NAK
2> 当收到包时,接收过程中每个字符的超时间隔为 1 秒
3> 为保持“接收方驱动”,发送方在等待一个启动字节时不应该采用超时处理
4> 一旦传输开始,发送方采用单独的 1 分钟超时时限,给接收方充足的时间做发送
ACK ,NAK ,CAN 之前的必须处理
5> 所有的超时及错误事件至少重试 10 次

参考:https://zhuanlan.zhihu.com/p/349921713

3.状态机介绍

以下内容是我根据个人的理解对裸机思维公众号文章状态机系列文章的一个笔记,请务必以原作者文章内容为准。

状态机是一种思维方式、一种工具,同时它也是一种拥有极高自由度的语言。状态图是“新的源代码”,根据一定规则翻译状态图为C代码的过程就是”新的编译“。

状态机本身是一种编程语言;状态图是描述状态机的最常见方式之一;绘制状态图的图例规范有很多种,比如UML规范等等,本文是结合状态机的常见画法并针对嵌入式软件开发习惯简化后的图例规范,简单、明确、有效,并且可以毫无歧义的严格且无脑的翻译成包括switch状态机在内的多种C语言实现。

3.1 状态图的画图规范

使用状态图来设计状态机,其本意就是利用人类的视觉优于阅读能力的特性来降低设计难度。为了确保这一初衷能够贯彻始终,“逻辑清晰”是状态图设计的核心原则。

  1. 规范一:功能单一原则:
    每个状态的功能要尽可能单一,要避免将多个功能复合在同一个状态上,从而产生所谓的“超级状态”的情况。
    比如以下状态图实际上拥有两个功能:1. 通过serial_out()函数输出字符;2. 判断字符串的尾部


更好的设计如下:

  1. 规范二:状态机的起点和终点
    一个状态机可以没有终点,但一定有一个起点,我们称之为 start。

    START是状态机的起点、同时也兼任跃迁条件——换句话说:START 不是一个可以保持的状态,它也不能被看作一个特殊的状态;因此,翻译代码的时候,虽然START是0,但在对应的case分支中,一定要自动切换到下一个状态而绝对不能在此停留。

  2. 规范三:子状态机


如图所示:

  • 子状态机是被圆角矩形包裹的

  • 子状态机的右上角有一个自反的状态迁移,条件是“on going”意味子状态机正在执行,还未得出一个结果;

  • 子状态机的右下角(或者别的什么位置)需要有一个标记有cpl条件的状态迁移,表示当子状态机内部达到了终点cpl以后,子状态机从这里退出并跃迁到指定的状态;

  • 子状态机有一个标题栏,里面分别列举了状态机的名称以及传递给当前子状态机的形参列表。(状态机的返回值只能是类似cpl, on-going这样的状态,所以不需要特别标记)

  1. 规范四:简化公共条件
    对于源自同一个状态的动作而产生的多个返回值,我们可以借助“公共条件”和“子条件”的方式加以简化:


比如:

  1. 规范五:合理使用虚线提升性能
    我们知道,非必要的频繁任务切换会浪费大量的处理器时间,从而影响系统的实时性,这里由状态切换导致的频繁CPU出让(yield)实际上并非好事。我们把此类切换从实线箭头修改为虚线箭头——表示此类切换不“主动”出让CPU控制权。例如:

3.2 状态图的翻译规范

  • 用圆圈来表示一个状态;

  • 圆圈中心我们会写一些注释性质的内容用来帮助人们理解这个状态是做什么的;

  • 图中有三个箭头,最左上角单纯“指向”状态的箭头表示从别的什么地方“跃迁”到了当前状态——我们称为“扇入”;下方从当前状态指向别的什么地方的箭头表示从当前状态离开;——我们成为“扇出”;右上角从当前状态“扇出”后又“返回到”当前状态的情况,我们称之为“自返”——也就是返回自己的意思。

针对上面的一个状态示意图,它可以简单的对应到下面的代码结构:

    case <状态名称>:状态具体执行了什么有返回值d的动作;if (返回值 满足 跃迁条件1) {s_tState = XXXXX;   //!< 执行状态跃迁执行对应的跃迁动作} else if (返回值 满足 跃迁条件2) {s_tState = XXXXX;   //!< 执行状态跃迁执行对应的跃迁动作        }break;

状态图的所表达的逻辑是唯一的,但翻译它的方法从来都不是唯一的,一般来说,我们既可以用上面的公式无脑翻译代码,也可以进行必要的等效改编。比如:状态图可以根据需要翻译成阻塞的,或者非阻塞的代码

翻译成下面的C语言代码,就是阻塞的


#include <stdbool.h>
#include <stdint.h>void print_hello(void)
{//! 对应 start部分uint8_t *s_pchSrc = "Hello";do {    //! 对应 Print Hello 状态while(!serial_out(*s_pchSrc));//! serial_out返回值为true的状态迁移s_pchSrc++;//! 对应 "Is End of String"状态if (*s_pchSrc == '\0') {//! true分支,结束状态机return ;}//! false分支,跳转到 "Print Hello" 状态} while(true);
}

翻译成下面的C语言代码,就是非阻塞的

#include <stdbool.h>
#include <stdint.h>typedef enum {fsm_rt_err = -1,fsm_rt_on_going = 0,fsm_rt_cpl = 1,
} fsm_rt_t;#define PRINT_HELLO_RESET_FSM() \do {s_tState = START;} while(0)fsm_rt_t print_hello(void)
{static enum {START = 0,PRINT_HELLO,IS_END_OF_STRING,} s_tState = {START};static const uint8_t *s_pchSrc = NULL;switch (s_tState) {case START://! 这个赋值写法只在嵌入式环境下“可能”是安全的s_pchSrc = "Hello world";  s_tState++;//break;case PRINT_HELLO:if (!serial_out(*s_pchSrc)) {break;         };s_tState = IS_END_OF_STRING;s_pchSrc++;            //break;            case IS_END_OF_STRING:if (*s_pchSrc == '\0') {PRINT_HELLO_RESET_FSM();return fsm_rt_cpl;}s_tState = PRINT_HELLO;break;            }return fsm_rt_on_going;
}

3.3 总结状态机设计步骤

  1. 按照状态功能单一原则,以逻辑清晰为基本目标,再完全不考虑优化的情况下,完成状态机的设计和调试;

  2. 在完成了状态机逻辑正确性验证的前提下,在必要的情况下,可以对状态图进行性能优化;

  3. 如果经过上述步骤,性能仍然达不到要求,可以对翻译后的代码进行进一步的等效优化。

4.使用状态机实现XMODEM和YMODEM协议

使用状态机思维编程的方式是对任务进行化整为零,逐个攻破。也就是说将某一复杂问题分解为若干部分,通过分析处理各个部分而最终解决整个问题的思维方法。

4.1 任务拆分

观察XMODEM和YMODEM的传输协议可以发现,它们都有握手,传输数据和传输完成三个阶段,所以就以这三个阶段分别建立状态图,然后组装起来,就是一个完整的协议,比如下图:

基于状态机实现XMODEM和YMODEM协议相关推荐

  1. 【转】Xmodem、Ymodem协议总结

    原文:https://blog.csdn.net/hkh5730/article/details/25145651 Xmodem.Ymodem协议总结 写在前面: 本文包含如下内容: 一.文件传输简介 ...

  2. STM32F103代码远程升级(三)基于YModem协议串口升级程序的实现

    文章目录 一.YModem协议简介 二.YModem的数据格式 1.起始帧的数据格式 2.数据帧的数据格式 3.结束帧的数据格式 4.文件传输过程 三.基于Ymodem协议串口升级程序的实现过程 1. ...

  3. Kermit,Xmodem,1K-Xmodem,Ymodem,Zmodem传输协议小结

    来自:http://blog.163.com/czblaze_3333/blog/static/208996228201272295236713/ Kermit协议 报文格式: 1.       MA ...

  4. 野火串口助手协议发送文件通讯协议——XMODEM协议——YMODEM协议

    野火串口助手协议发送文件通讯协议 修订历史 日期 版本 更新内容 2020/6/22 0.0.1 首次发布 XMODEM协议 上位机是现实了XModem-CRC16和XModem-1K; XModem ...

  5. 基于Ymodem协议的stm32f405rgt6+CubeMx+IAP在线升级

    基于Ymodem协议的stm32f405rgt6+CubeMx+IAP在线升级 目录 一.CubeMX的配置 1.IAP 2.APP 二.移植Ymodem官方代码 1.文件移植 2.MDK文件.路径添 ...

  6. ymodem android,【安卓相关】蓝牙基于Ymodem协议发送bin文件,对硬件设备进行升级。...

    最近做的一个安卓项目是使用蓝牙基于Ymodem协议传输bin文件,实现对硬件设备进行升级. 做的过程中遇到了不少困难,用我这半吊子的语文水平,记录一下吧 怎么办,平时对各种文件传输协议真的是知之甚少啊 ...

  7. java ymodem协议,anroid ymodem 实现单片机固件升级

    Android端对单片机升级其实Android端只需要实现文件传输并在界面上显示传输进度. Android 端和单片机通信是串口进行通信的,通信数据协议基于Ymodem 由于Ymodem协议本身就是采 ...

  8. Ymodem协议学习笔记

    介绍   Xmodem.Ymodem和Zmodem协议是最常用的三种通信协议.   Xmodem协议是最早的,支持传输128字节信息块.   Ymodem是Xmodem的改进版协议,具有传输快速稳定的 ...

  9. stm32 Bootloader设计(YModem协议)

    相信很多人都希望,不开盖就可以对固件进行升级吧,就像手机那些.下文中的bootload就来实现这样的功能. 前段时间有项目关于Bootload设计.所以就仔细的去了研究了一翻.以前都是用的stm32官 ...

最新文章

  1. linux笔记 1-13-软件安装
  2. C++学习点滴(多次调用同一个类)
  3. 无法去掉自增标识_为什么 MySQL 的自增主键不单调也不连续
  4. 儿童吹泡泡水简单配方_儿童吹泡泡水简单配方[组图]
  5. 关于汉语转换拼音的组件
  6. 关于PHP代码写的下载文件打不开的问题,自己备忘!(韩老师2011年的例子)
  7. pandas根据某列值为key整合其他列值,拆分某列值增加多行数据
  8. 关于es6中新增的一些方法----数组篇
  9. noip模拟赛 SAC E#1 - 一道中档题 Factorial
  10. 与孩子一起学编程01章
  11. 数学建模论文排版大总结
  12. 接口中的变量public static final
  13. 基于51单片机的无线遥控门铃仿真程序原理图设计
  14. 二、Vue 属性绑定、v-model的原理、绑定class、绑定style
  15. java请输入三个成绩 求平均分_Java编程,定义一个学生类,输入3个学生数据,输出平均分和总分...
  16. 解决word2013老是打开未响应情况
  17. spring不停机部署_spring cloud 学习(7) - 生产环境如何不停机热发布? - 菩提树下的杨过 - 博客园...
  18. 跳线架和配线架,二者你分得清吗?
  19. 第八篇:深入 React-Hooks 工作机制:“原则”的背后,是“原理”
  20. 小企业网络拓扑图服务器位置,中小型企业网络架构拓扑图搭建过程

热门文章

  1. 60秒链快讯|苹果联合创始人将加入区块链公司;由星云实验室联合xGoogler孵化的星途协议ATP获千万种子轮投资
  2. c语言编写平方根函数不用库函数,不使用库函数sqrt实现求一个数的平方根
  3. 浅谈支付业务的分表方案
  4. APP开发流程实例讲解-儒释道网络电台八天开发全程-实现功能代码:播放控制
  5. 写给金融危机下年轻人的16条忠告
  6. RE-RC4加密分析
  7. STC89C52系列单片机内部资源——串口通信
  8. 计算机图形学 文字裁剪
  9. C#中在图片上定位画图以及画文本
  10. TVM TIR 各种Node类型举例