一、xdmodem1k的具体协议介绍这里不再做详细的解释只简单描述
xmodem1k协议发送数据的数据包格式:
<STX><包序号><包序号反码><文件数据(1024字节)><校验位>
0x02
STX: 包头
0x04
EOT: 结束文件传输
0x06
ACK: 正常响应,如:数据包正确接收
0x15
NACK: 非正常响应
0x18
CAN: 取消文件传输
0x43
C: ASCII字符C
二、xmodem1k发送的流程(Mina socket作为发送方)
1:建立Socket连接
2:接收方发送C到服务端 0x43
3:服务端接收到43开始解析文件发送第一帧包的数据到接收方
4:接收方收到正确数据返回0x06即ACK
6:如果发送方收到0x15则需要重发上一次发的包
7:如果发送方收到0x18则需要无条件终止发送,出现了严重错误。
三、JAVA代码示例:
// 开始
private final byte SOH = 0x01;
// 结束
private final byte EOT = 0x04;
// 应答
private final byte ACK = 0x06;
// 重传
private final byte NAK = 0x15;
// 无条件结束
private final byte CAN = 0x18;
// 开始
private final byte STX=0x02;
// 以128字节块的形式传输数据private final int SECTOR_SIZE = 1024;
// 最大错误(无应答)包数
private final int MAX_ERRORS = 10;
//path要发送的文件的路径,deviceNo是设备唯一编号
public void saveXmodemData(Path path,String deviceNo){
// 包序号
byte blockNumber = 0x01;
// 校验和
int checkSum;
// 读取到缓冲区的字节数量
int nbytes;
// 初始化数据缓冲区
byte[] sector = new byte[SECTOR_SIZE];
int num=1;
try {
DataInputStream inputStream = new DataInputStream(Files.newInputStream(path));
IoBuffer iobuffer=null;
while ((nbytes = inputStream.read(sector)) > 0) {
int inputLenth=inputStream.available();
// 如果数据包小于1024个字节,以0x1A补齐
if (nbytes < SECTOR_SIZE) {
for (int i = nbytes; i < SECTOR_SIZE; i++) {
sector[i] = (byte) 0x1A;
}
}
StringBuffer result=new StringBuffer();
result.append(HexUtil.BytetoHexString(STX));
result.append(HexUtil.BytetoHexString(blockNumber));
result.append(HexUtil.BytetoHexString(((byte)~blockNumber)));
result.append(HexUtil.Bytes2HexString(sector));
String checkNum=byteToCrcNum(HexUtil.Bytes2HexString(sector));
result.append(checkNum);
byte[] resultData=HexUtil.HexString2Bytes(result.toString());
//可以根据设备编号和序列将resultData保存起来,后面在Handler类中根据接收方返回的数据
//根据序号排序发送给设备
save(resultData,deviceNo,blockNumber);
blockNumber = (byte) ((++blockNumber) % 256);result=null;
}
inputStream.close();
} catch (Exception e) {
log.error("{保存升级数据错误}");
//其他业务处理
}}
注意:上面方式中的byteToCrcNum这个方式是用于计算他们的CRC16的效验,将16进制字符串转成字节数组计算CRC16的效验码。
private String byteToCrcNum(String HexStr){
String listStr=HexStr.replaceAll(" ","")
byte[] data=HexUtil.HexString2Bytes(listStr);
Long checkNumCrc=new CRC16().calcCRC(data);
String HexNum=Long.toHexString(checkNumCrc);
return padLeft(HexNum,4).toUpperCase();//不足4位的左边自动补充0
}
至于收到接收端以后发送数据写到mina的Handler类里面去。