在工作时串口通信的过程中需要传输文件,这里就就需要使用通信协议,此时选择的是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. Linux 调优

    一.系统优化 1.硬件优化 增加内存 更换速度跟高磁盘(sata->sas)可以增加固态硬盘 更换更高校率的网卡,或者双网卡绑定,两个网卡作为一个网卡使用.服务器网卡一般为千兆 2.系统层优化 ...

  2. 20145240 《Java程序设计》第八周学习总结

    20145240 <Java程序设计>第八周学习总结 教材学习内容总结 15.1日志 15.1.1日志API简介 java.util.logging包提供了日志功能相关类与接口,不必额外配 ...

  3. Go Concurrency or Parallel

    关于并发和并行,先看两个示例 示例1: package main import "fmt" var quit = make(chan int) func foo6(){ for i ...

  4. 安装使用snmp监控命令

    1.安装snmp windows下载安装https://sourceforge.net/projects/net-snmp/ centos yum install -y net-snmp net-sn ...

  5. Myeclipse中Tomcat的两种部署方式

    一.在Myeclipse软件中部署 1. 在Myeclipse中,创建好工程后,在Myeclipse菜单栏中选择 Windows -> Preferences -> Myeclipse - ...

  6. R语言学习笔记(4)

    第四章:基本数据管理 一 贯穿整章的示例 二 变量的创建.重编码和重命名 三 日期值与缺失值 四 数据类型和类型转换 五 数据集的排序.合并与取子集 一 贯穿整章的示例(leadership)  ,, ...

  7. Spring初学之使用JdbcTemplate

    Spring中使用JdbcTemplate.JdbcDaoSupport和NamedParameterJdbcTemplate来操作数据库,但是JdbcTemplate最常用,最易用. jdbc.pr ...

  8. vue v-if with v-for

    遍历和条件判断混合使用示例. <!DOCTYPE html> <html> <head lang="en"> <meta charset= ...

  9. 语音01_TTS

    1.http://blog.csdn.net/u010176014/article/details/47428595 2.家里 Win7x64 安装“微软TTS5.1语音引擎(中文).msi”之后,搜 ...

  10. Eclipse导出apk

    http://jingyan.baidu.com/article/7908e85c8dea30af491ad24f.html