1,简介
2,传输过程
3,代码实现 (我们是使用 android 设备USB 和主板通讯,当然串口也可以.基础知识自行百度)
在串口通信中广泛使用的异步文件传输协议有Xmodem,Ymodem,Zmodem.本文只介绍 Xmodem,其他两种,未用过,没研究.Xmodem协议分为两种,一种是标准的 Xmode和Xmodem-1k 两个版本.
Xmodem内容固定长度为 128 个字节,格式如下:
| Byte0 | Byte1 | Byte2 | Byte3~Byte130 | (Byte131~Byte132)/(Byte131) |
|---|---|---|---|---|
| SOH | 数据包序号 | 数据包序号补码 | 数据包内容(128字节) | 数据校验 |
Xmodem-1k内容固定长度为 1024个字节,格式如下:
| Byte0 | Byte1 | Byte2 | Byte3~Byte1026 | (Byte1027~Byte1028)/(Byte 1027) |
|---|---|---|---|---|
| STX | 数据包序号 | 数据包序号补码 | 数据包内容(1024字节) | 数据校验 |
控制符定义:
| 控制符 | 值 | 含义 |
|---|---|---|
| SOH | 0X01 | Xmodme 数据头 |
| STX | 0X02 | Xmodme -1k 数据头 |
| EOT | 0X04 | 发送结束/数据发送完毕 |
| ACK | 0X06 | 应答标志/数据正确 |
| NAK | 0X15 | 非应答标志,重传(使用 CheckSum 数据校验) |
| CAN | 0X18 | 取消发送/终止发送 |
| CRC16 | 0X43 | 使用 CRC16 数据校验 |
数据包序号:
据包序号下标是从0x01开始向上递增的,累加到0XFF后将循环反复. (0~255)
数据包序号补码:
数据包序号按位取反,即 ~数据包序号
校验和的方式有CRC校验和 CheckSum校验:
使用不同的校验方式,占的字节数不一样哦~
CRC校验:
占 2 个字节,,CRC多项式公式为X16+X12+X5+1然后取低16位数据.(网上说的,我也不理解,没研究)
@JvmStatic
fun calc16(bytes: ByteArray): ByteArray? {
var crc = 0x0000.toChar()
for (b in bytes) {
crc = (crc.toInt() shl 8 xor crctable[crc.toInt() shr 8 xor b.toInt() and 0x00ff].toInt()).toChar()
}
return intToByteArray(crc.toInt() and 0x00ffff)
}
@JvmStatic
fun intToByteArray(i: Int): ByteArray? {
val result = ByteArray(2)
result[0] = (i shr 8 and 0xFF).toByte()
result[1] = (i and 0xFF).toByte()
return result
}
CheckSum校验:
占1 个字节,对传输的数据进行累加和,然后转成16 进制,用两个字节的来表示,取第 1 位.
@JvmStatic
fun getCheckSum(bytes: ByteArray): Byte {
var checkSum = 0
for (aByte in bytes) {
checkSum += aByte.toInt()
}
val bytes1 = intToByteArray(checkSum.toLong())
return bytes1!![1]
}
//将 int 转成 byte 数组,文件大小,用两个字节表示
@JvmStatic
fun intToByteArray(i: Int): ByteArray? {
val result = ByteArray(2)
result[0] = (i shr 8 and 0xFF).toByte()
result[1] = (i and 0xFF).toByte()
return result
}
| android 程序 | Flow | 主板 |
|---|---|---|
| <— CRC16 (0X43)/NAK (0X15) | ||
| SOH+0x01+0xFE+Data[0-127]+数据校验 | —> | Packet ok |
| <— ACK(0X06) | ||
| SOH+0x02+ 0xFD+Data[0-127]+数据校验 | —> | Packet ok |
| <— ACK(0X06) | ||
| SOH+0x03+0xFC+Data[0-127]+数据校验 | —> | Packet ok |
| <— ACK(0X06) | ||
| .... | .... | .... |
| EOT | —> | Packet ok |
| Finished | <— ACK |
1、当主板给 Android 设备发送的C或者NAK后,android设备则知道主板已开启 Xmodem 协议传输,然后开始发送数据:SOH/STX+0x01+0xFE+Data[0-127]/Data[0-1024]+数据校验
2、主板接收到数据后,对数据进行校验,数据正确则回复ACK确认字节,android 设备接收到ACK确认后,就认为数据包被接收方正确接收了,接着发送下一包数据.
3、如果android设备NAK字节,则表示需要重新传输刚才的数据包;如果android 设备收到的CAN字节,则表示无条件停止传输。
4、传输完毕后,等待主板唤醒 android 设备,判断固件是否更新成功.(这部分跟主板开发进行协商吧~~)
随意写写,可自行进行封装~~~
public class Xmodem2 {
public static int checkType = 1; //校验类型 1是csc/2是check-sum,由主板回复值,判断赋值
public static int transType = 2; //传输类型 Xmodem/1K-Xmodem ,android 设备主动触发
public static final byte SOH = 0x01; // 开始 Xmodem数据头
public static final byte STX = 0x02; // 开始 1K-Xmodem数据头
public static final byte EOT = 0x04; // 结束
public static final byte ACK = 0x06; // 应答
public static final byte NAK = 0x15; // 重传
public static final byte CAN = 0x18; // 无条件结束
public static final byte C = 0x43; // csc校验
public static int SECTOR_SIZE = 0;// 以128字节块的形式传输数据
public static final int MAX_ERRORS = 10; // 最大错误(无应答)包数
public static UsbSerialPort port; //写入数据
public static String filePath; //文件路径
public static byte responseACK; //由主板是否回复 ACK,由主板回复值,判断赋值
public static boolean finishAck = false; //数据传输结束ACK
private final ExecutorService executor = Executors.newFixedThreadPool(5);
public Xmodem2(String path, UsbSerialPort usbSerialPort) {
filePath = path;
port = usbSerialPort;
if (transType == 1)
SECTOR_SIZE = 128;
else
SECTOR_SIZE = 1024;
}
public void send() {
executor.submit(() -> {
try {
int errorCount;// 错误包数
byte blockNumber = 0x01;// 包序号
int nbytes; // 读取到缓冲区的字节数量
byte[] sector = new byte[SECTOR_SIZE]; // 初始化数据缓冲区
// 读取文件初始化
DataInputStream inputStream = new DataInputStream(new FileInputStream(filePath));
while ((nbytes = inputStream.read(sector)) > 0) {
// 如果最后一包数据小于128个字节,以0xff补齐
if (nbytes < SECTOR_SIZE) {
for (int i = nbytes; i < SECTOR_SIZE; i++) {
sector[i] = (byte) 0X1A;
}
}
// 同一包数据最多发送10次
errorCount = 0;
while (errorCount < MAX_ERRORS) {
// 组包
// 控制字符1 + 包序号1 + 包序号的反码1 + 数据128 + 校验 1->crc/2-> check-sum
byte[] sendData = new byte[SECTOR_SIZE + (checkType == 1 ? 5 : 4)];
sendData[0] = SECTOR_SIZE == 128 ? SOH : STX;
sendData[1] = blockNumber;
sendData[2] = (byte) ~blockNumber;
System.arraycopy(sector, 0, sendData, 3, sector.length);
if (checkType == 1) { //CRC
byte[] crc16 = CRC16.calc16(sector);
if (transType == 1) {
System.arraycopy(crc16, 0, sendData, 131, crc16.length); //C+128+ CRC
} else {
System.arraycopy(crc16, 0, sendData, 1027, crc16.length); //C+1014+ CRC
}
} else { // checkSum
if (transType == 1) {
sendData[131] = CRC16.getCheckSum(sector); //15+128+ Check-Sum
} else {
sendData[1027] = CRC16.getCheckSum(sector); //15+1014+ Check-Sum
}
}
//==============================================
String s = Utils.INSTANCE.toHexString(sendData);
Log.e("11111", "传输的数据: " + s);
//===============================================
port.write(sendData, 5000);
// 获取应答数据
// 如果收到应答数据则跳出循环,发送下一包数据
// 未收到应答,错误包数+1,继续重发
Thread.sleep(50);
if (responseACK == ACK) {
responseACK = 0;
break;
} else {
errorCount++;
}
}
// 包序号自增
blockNumber = (byte) ((++blockNumber) % 256);
}
// 所有数据发送完成后,发送结束标识
errorCount = 0;
while (errorCount < MAX_ERRORS) {
Log.e("11111", "发送结束标志啦");
port.write(new byte[]{EOT}, 5000);
Thread.sleep(50);
if (responseACK == ACK) {
finishAck = true;
break;
} else {
errorCount++;
}
}
} catch (Exception e) {
e.printStackTrace();
}
});
}
}
使用:
Xmodem2(path, UsbHelper.INSTANCE.port).send()
尝试通过RVM将RubyGems升级到版本1.8.10并出现此错误:$rvmrubygemslatestRemovingoldRubygemsfiles...Installingrubygems-1.8.10forruby-1.9.2-p180...ERROR:Errorrunning'GEM_PATH="/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/ruby-1.9.2-p180@global:/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/rub
我在我的Rails项目中使用Pow和powifygem。现在我尝试升级我的ruby版本(从1.9.3到2.0.0,我使用RVM)当我切换ruby版本、安装所有gem依赖项时,我通过运行railss并访问localhost:3000确保该应用程序正常运行以前,我通过使用pow访问http://my_app.dev来浏览我的应用程序。升级后,由于错误Bundler::RubyVersionMismatch:YourRubyversionis1.9.3,butyourGemfilespecified2.0.0,此url不起作用我尝试过的:重新创建pow应用程序重启pow服务器更新战俘
我实际上是在尝试使用RVM在我的OSX10.7.5上更新ruby,并在输入以下命令后:rvminstallruby我得到了以下回复:Searchingforbinaryrubies,thismighttakesometime.Checkingrequirementsforosx.Installingrequirementsforosx.Updatingsystem.......Errorrunning'requirements_osx_brew_update_systemruby-2.0.0-p247',pleaseread/Users/username/.rvm/log/138121
我最近决定从我的系统中卸载RVM。在thispage提出的一些论点说服我:实际上,我的决定是,我根本不想担心Ruby的多个版本。我只想使用1.9.2-p290版本而不用担心其他任何事情。但是,当我在我的Mac上运行ruby--version时,它告诉我我的版本是1.8.7。我四处寻找如何简单地从我的Mac上卸载这个Ruby,但奇怪的是我没有找到任何东西。似乎唯一想卸载Ruby的人运行linux,而使用Mac的每个人都推荐RVM。如何从我的Mac上卸载Ruby1.8.7?我想升级到1.9.2-p290版本,并且我希望我的系统上只有一个版本。 最佳答案
最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路
我完全不是程序员,正在学习使用Ruby和Rails框架进行编程。我目前正在使用Ruby1.8.7和Rails3.0.3,但我想知道我是否应该升级到Ruby1.9,因为我真的没有任何升级的“遗留”成本。缺点是什么?我是否会遇到与普通gem的兼容性问题,或者甚至其他我不太了解甚至无法预料的问题? 最佳答案 你应该升级。不要坚持从1.8.7开始。如果您发现不支持1.9.2的gem,请避免使用它们(因为它们很可能不被维护)。如果您对gem是否兼容1.9.2有任何疑问,您可以在以下位置查看:http://www.railsplugins.or
我们有一个目前在Rails2.3.12版和Ruby1.8.7版上运行的应用程序。我们想将我们的应用程序更新到Rails4.0和Ruby2.1.0。我们有大约200个模型和150个Controller。我想知道升级过程需要多大的努力。您还可以提供升级可以遵循的步骤。我们应该先升级Ruby然后再升级Rails还是相反? 最佳答案 您想要实现的目标将是史诗般的努力。我无法为您提供分步说明,因为不可能在一个答案中涵盖所有情况。我建议不要同时升级Ruby和Rails,而是分步升级。升级本身的复杂性是巨大的,但只要您的应用程序具有合理的测试覆盖
我最近尝试安装rails4.1.0.beta1,但是railss导致以下错误。[RVM]/gems/ruby-2.0.0-p247/gems/activesupport-4.1.0.beta1/lib/active_support/core_ext/module/aliasing.rb:32:in`alias_method':undefinedmethod`graft'forclass`ActiveRecord::Associations::JoinDependency'(NameError)[RVM]/gems/ruby-2.0.0-p247/gems/activesupport-4
我目前有一个运行在4.2.5上的Rails应用程序,我想使用ActionCable而不必将整个应用程序升级到Rails5.0.0.beta3版本并冒破坏所有其他gem的风险。按照我在互联网上看到的指南,我已经尝试过gem'actioncable',github:'rails/actioncable'这不起作用,因为ActionCable存储库已合并到Rails存储库中。我什至试过gem'actioncable',github:'rails/rails'但这似乎不适用于ActionCable合并到Rails时发生的版本重新编号。(唯一低于5.0.0.beta*的版本是0.0.0,这似乎是
我最近正在进行Rails5升级,当我尝试启动Rails控制台时遇到了这个错误:/actionpack-5.0.0/lib/action_controller/test_case.rb:49:ininitialize':wrongnumberofarguments(0for2)(ArgumentError)当前bundleupdaterails已经完成了gem依赖项的解决,足以更新到5.0.0,rspec正在运行(尽管我正在修复很多中断)。我也可以运行railss没有错误。这里是代码中断行:https://github.com/rails/rails/blob/master/action