在工作时串口通信的过程中需要传输文件,这里就就需要使用通信协议,此时选择的是Xmodem协议作简要研究

1、什么是Xmodem协议

Xmodem协议是串口通信中广泛使用到的异步文件传输协议。以128字节块的形式传输数据,并且每个块都使用一个校验过程来进行错误检测。在校验过程中如果接收方关于一个块的检验和与它在发送方的检验相同时,接收方就向发送方发送一个确认字节<ACK>。如果有错则发送一个字节<NAK>要求重发。以保证传输过程中的正确性,但是由于需要对每个块都要进行检验,显得效率比较低。

2、Xmodem协议相关控制字符

SOH              0x01          //Xmodem数据头
STX              0x02           //1K-Xmodem数据头
EOT              0x04           //发送结束
ACK             0x06           //认可响应
NAK             0x15           //不认可响应
CAN             0x18           //撤销传送
CTRLZ         0x1A          //填充数据包

3、标准Xmodem协议(每个数据包含有128字节数据)帧格

Xmodem包格式

Byte1                         Byte2                           Byte3                     Byte4~131            Byte132~133

Start Of Header          Packet Number          ~(Packet Number)          Packet Data            16-Bit CRC

Xmodem协议的传输数据单位为信息包,包含一个标题开始字符<SOH>或者<STX>,一个单字节包序号,一个单字节包包序号的补码,128个字节数据和一个双字节的CRC16校验

4、数据包说明

对于标准Xmodem协议来说,如果传送的文件不是128的整数倍,那么最后一个数据包的有效内容肯定小于帧长,不足的部分需要用CTRL-Z(0x1A)来填充

5、如何启动传输

Xmodem协议的传输由接收方启动,接收方向发送方发送"C"或者NAK(这里的NAK是用来启动传输的。下面我们用到的NAK是用来对数据产生重传机制)。其中接收方发送NAK信号表示接收方打算用累加和校验;发送字符"C"则表示接收方打算使用CRC校验。

6、传输过程

当接收方发送的第一个"C"或者NAK到达发送方,发送方认为可以发送第一个数据包了,传输启动。发送方接着接着应该将数据以每次128字节的数据加上包头,包号,包号补码,末尾加上校验和,打包成帧格式传送。发送方发了第一个包后就等待接收方的确认字节<ACK>,收到接收方传来的<ACK>确认,就认为数据包被接收方正确接收,并且接收方要求发送方继续发送下一个包;如果发送方收到接收方传来的<NAK>(这里的表示重发),则表示接收方请求重发刚才的数据包;如果发送方收到接收方传来的<CAN>字节,则表示接收方请求无条件停止传输。

7、结束传输

如果发送方正常传输完全部数据,需要结束传输,正常结束需要发送方发送<EOT>通知接收方。接收方回以<ACK>进行确认。如果接收方发送<CAN>给发送方也可以强制停止传输,发送方受到<CAN>后不需要发送<EOT>确认,此时传输已经结束。

8、Xmodem协议代码:

#include "BA_UART_CONFIG.h"
#include "BA_XModem.h" #define SOH 0x01
#define STX 0x02
#define EOT 0x04
#define ACK 0x06
#define NAK 0x15
#define CAN 0x18
#define CTRLZ 0x1A
#define DLY_1S 1000
#define MAXRETRANS 25 static int last_error = ; void out_buff(unsigned char *buff, int size)
{
int arg = ;
UART_HANDLER uart = getUartHandler(); writeSysUart(uart, buff, size, &arg);
} struct sysUartWaitArgStruct sysXmodemUartArg =
{
OS_OPT_PEND_BLOCKING,
,
NULL,
};
int in_buff(unsigned char *buff, int time_out)
{
int arg = ;
int qSize = ;
int readSize = ;
UART_HANDLER uart = getUartHandler(); last_error = ; sysXmodemUartArg.timeout = time_out; if(RETURN_RESULT_ERROR_NOERR ==
ctrlSysUart(uart, DEVICE_CONTROL_WAIT_EVENT, (UART_ARG)(&sysXmodemUartArg)))
{
qSize = uart->recvDQ.q.curSize;
if(qSize > )
{
readSize = readSysUart(uart, buff, qSize, &arg);
}
} if(readSize == )
last_error = ; return (readSize);
}
int calcrc(const unsigned char *ptr, int count)
{
int crc;
char i; crc = ;
while (--count >= )
{
crc = crc ^ (int) *ptr++ << ;
i = ;
do
{
if (crc & 0x8000)
crc = crc << ^ 0x1021;
else
crc = crc << ;
} while (--i);
} return (crc);
}
static int check(int crc, const unsigned char *buf, int sz)
{
if(crc)
{
unsigned short crc = calcrc(buf, sz);
unsigned short tcrc = (buf[sz]<<)+buf[sz+]; if (crc == tcrc)
return ;
}
else
{
int i = ;
unsigned char cks = ; for(i = ; i < sz; i ++)
{
cks += buf[i];
} if (cks == buf[sz])
return ;
} return ; }
//recv_buff_size == 384
int xmodemReceive(unsigned char *dest, int destsz)
{
unsigned char xbuff[];
int bufsz = ;
int crc = ;
unsigned char trychar = 'C';
unsigned char packetno = ;
int c = ;
int len = ;
int retry = ;
int retrans = MAXRETRANS;
int recvSize = ; for(;;)
{
for(retry = ; retry < ; retry ++)
{
if(trychar)
{
xbuff[] = trychar;
out_buff(xbuff, );
} recvSize = in_buff(xbuff, (DLY_1S)<<);
c = xbuff[]; if (last_error == )
{
switch(c)
{
case SOH:
bufsz = ;
goto start_recv;
case STX: {
xbuff[] = CAN;
out_buff(xbuff, );
}
return -;
case EOT: {
xbuff[] = ACK;
out_buff(xbuff, );
}
return len;
case CAN: in_buff(xbuff, DLY_1S);
c = xbuff[];
if(c == CAN)
{
{
xbuff[] = ACK;
out_buff(xbuff, );
}
return -;
}
break;
default:
break;
}
}
} if (trychar == 'C')
{
trychar = NAK;
continue;
} {
xbuff[] = CAN;
out_buff(xbuff, );
out_buff(xbuff, );
out_buff(xbuff, );
} return -; start_recv:
if(trychar == 'C')
crc = ; trychar = ; if(recvSize != (bufsz + (crc ? : ) + ))
goto reject; if(xbuff[] == (unsigned char)(~xbuff[]) &&
(xbuff[] == packetno || xbuff[] == (unsigned char)packetno - ) &&
check(crc, &xbuff[], bufsz))
{
if(xbuff[] == packetno)
{
int count = destsz - len; if (count > bufsz)
count = bufsz; if (count > )
{
memcpy(&dest[len], &xbuff[], count);
len += count;
} packetno ++; retrans = MAXRETRANS+;
} if(-- retrans <= )
{
{
xbuff[] = CAN;
out_buff(xbuff, );
out_buff(xbuff, );
out_buff(xbuff, );
}
return -;
} {
xbuff[] = ACK;
out_buff(xbuff, );
} continue;
} reject:
{
xbuff[] = NAK;
out_buff(xbuff, );
} }
} //send_buff_size == 140
int xmodemTransmit(unsigned char *src, int srcsz)
{
unsigned char xbuff[];
int bufsz = ;
int crc = -;
unsigned char packetno = ;
int i = ;
int c = ;
int len = ;
int retry = ; for(;;)
{
for( retry = ; retry < ; ++retry)
{
in_buff(xbuff, (DLY_1S)<<);
c = xbuff[]; if(last_error == )
{
switch(c)
{
case 'C':
crc = ;
goto start_trans;
case NAK:
crc = ;
goto start_trans;
case CAN:
in_buff(xbuff, DLY_1S);
c = xbuff[];
if(c == CAN)
{
{
xbuff[] = ACK;
out_buff(xbuff, );
}
return -;
}
break;
default:
break;
}
}
} {
xbuff[] = CAN;
out_buff(xbuff, );
out_buff(xbuff, );
out_buff(xbuff, );
} return -; for(;;)
{
start_trans:
xbuff[] = SOH;
bufsz = ;
xbuff[] = packetno;
xbuff[] = ~packetno; c = srcsz - len;
if(c > bufsz)
c = bufsz; if(c >= )
{
memset(&xbuff[], , bufsz); if (c == )
{
xbuff[] = CTRLZ;
}
else
{
memcpy(&xbuff[], &src[len], c); if (c < bufsz)
xbuff[ + c] = CTRLZ;
} if(crc)
{
unsigned short ccrc = calcrc(&xbuff[], bufsz); xbuff[bufsz + ] = (ccrc>>) & 0xFF;
xbuff[bufsz + ] = ccrc & 0xFF;
}
else
{
unsigned char ccks = ; for(i = ; i < bufsz + ; i ++)
{
ccks += xbuff[i];
} xbuff[bufsz + ] = ccks;
} for(retry = ; retry < MAXRETRANS; retry ++)
{
out_buff(xbuff, bufsz + + (crc ? : )); in_buff(xbuff, DLY_1S);
c = xbuff[]; if(last_error == )
{
switch(c)
{
case ACK:
packetno ++;
len += bufsz;
goto start_trans;
case CAN:
in_buff(xbuff, DLY_1S);
c = xbuff[];
if(c == CAN)
{
{
xbuff[] = ACK;
out_buff(xbuff, );
} return -;
}
break;
case NAK:
break;
default:
break;
}
}
}
{
xbuff[] = CAN;
out_buff(xbuff, );
out_buff(xbuff, );
out_buff(xbuff, );
} return -;
}
else
{
for(retry = ; retry < ; retry ++)
{
{
xbuff[] = EOT;
out_buff(xbuff, );
} in_buff(xbuff, (DLY_1S)<<);
c = xbuff[]; if(c == ACK)
break;
} return ((c == ACK) ? len : -);
}
}
}
}

Xmodem通信协议实例的更多相关文章

  1. AVR之BOOTLOADER技术详解(转)

    源:http://blog.csdn.net/zhenhua10/article/details/6442412 ATmega128具备引导加载支持的用户程序自编程功能(In-System Progr ...

  2. WSDL 文档-一个简单的 XML 文档

    WSDL 文档是利用这些主要的元素来描述某个 web service 的: <portType>-web service 执行的操作 <message>-web service ...

  3. CAN总线协议 学习笔记

    1.CAN总线网络 CAN总线网络主要挂在CAN_H和CAN_L,各个节点通过这两条线实现信号的串行差分传输,为了避免信号的反射和干扰,还需要在CAN_H和CAN_L之间接上120欧姆的终端电阻,但是 ...

  4. MapReduce源码分析之新API作业提交(二):连接集群

    MapReduce作业提交时连接集群是通过Job的connect()方法实现的,它实际上是构造集群Cluster实例cluster,代码如下: private synchronized void co ...

  5. 最近学习工作流 推荐一个activiti 的教程文档

    全文地址:http://www.mossle.com/docs/activiti/ Activiti 5.15 用户手册 Table of Contents 1. 简介 协议 下载 源码 必要的软件 ...

  6. 通过实例来分析I2C基本通信协议

    本文旨在用最通俗易懂的方式.让大家明确I2C通信的过程到底是怎么回事. I2C起源于飞利浦公司的电视设计,但之后朝通用路线发展,各种电子设计都有机会用到I2C 总的来说,I2C能够简单归纳为,两根线, ...

  7. 简述移动端IM开发的那些坑:架构设计、通信协议和客户端

    1.前言 有过移动端开发经历的开发者都深有体会:移动端IM的开发,与传统PC端IM有很大的不同,尤其无线网络的不可靠性.移动端硬件设备资源的有限性等问题,导致一个完整的移动端IM架构设计和实现都充满着 ...

  8. 多平台下Modbus通信协议库的设计(一)

    1.背景 1.1.范围 MODBUS 是 OSI 模型第 7 层上的应用层报文传输协议, 它在连接至不同类型总线或网络的设备之间提供客户机/服务器通信. 自从 1979 年出现工业串行链路的事实标准以 ...

  9. JAVA上百实例源码以及开源项目

    简介 笔者当初为了学习JAVA,收集了很多经典源码,源码难易程度分为初级.中级.高级等,详情看源码列表,需要的可以直接下载! 这些源码反映了那时那景笔者对未来的盲目,对代码的热情.执着,对IT的憧憬. ...

随机推荐

  1. shell中的$()、${}、$(())、(())

    $( ) 与 ` ` (反引号)在 bash shell 中,$( ) 与 ` ` (反引号) 都是用来做命令替换用(command substitution)的. 所谓的命令替换与我们第五章学过的变 ...

  2. debian内核代码执行流程(二)

    继续上一篇文章<debian内核代码执行流程(一)>未完成部分. acpi_bus_init调用acpi_initialize_objects,经过一系列复杂调用后输出下面信息: [ IN ...

  3. iOS_AutoLayout自动布局

    目录: 一.什么是AutoLayout? 二.创建autoLayout的方法 三.VFL语言     一.什么是AutoLayout? Autolayout是一种“自动布局”技术,专门用来布局UI界面 ...

  4. char,uchar,0xff

    如果:char test = 0xFF: 此时:test != 0xFF://因为test为char类型,0xFF为int,所以编译器会将test转为int(-1),所以不等于 如果:uchar te ...

  5. springcloud-搭建服务注册中心

    创建服务注册中心 1.创建一个springboot 命名为eureka-server 1)添加Eureka依赖 pom.xml <?xml version="1.0" enc ...

  6. 发现程序bug思路

    大家有没有遇到过项目,程序出现个bug,但花了好久(真的是a long long time啊)才发现引发这个问题的原因,心想原来就这个原因导致的啊,要是早想到就好了! 其实我们确实的是方法,希望我的抛 ...

  7. react列表中,当key改变后发生的事情

    Main.jsx export default class Main extends PureComponent { constructor(props) { super(props); this.s ...

  8. node操作mongdb的常用函数示例

    node操作mongdb的常用函数示例 链接数据库 var mongoose = require('mongoose'); //引用数据库模块 mongoose.connect('mongodb:// ...

  9. java之 Timer 类的简单使用案例

              (如果您看到本文章务必看结尾!) 第一次用Timer类,记录一下个人理解. 场景:做苹果内容结果验证时,根据苹果支付凭证去苹果官方服务器验证是否支付成功.但因为苹果服务器比较慢,第 ...

  10. [转载]java读写word文档,完美解决方案

    做项目的过程中,经常需要把数据里里的数据读出来,经过加工,以word格式输出. 在网上找了很多解决方案都不太理想,偶尔发现了PageOffice,一个国产的Office插件,开发调用非常简单!比网上介 ...