GD32通过蓝牙透传模块 IAP升级
1、思路
上一节手机App可以通过HC-08模块控制mcu的开锁,关锁的动作,那么我们是不是可以将mcu的升级文件通过hc-08模块发送给gd32,完成gd32程序的自升级呢?
2、命令协议
蓝牙透传模块每次只能发20字节的数据,去掉头跟checksum四个字节,实际上每包的数据为16个字节。
/*串口升级协议如下:
cmd + data length + data0 + ....+ data_n + checksum
1、获取版本号 0x01 0x02 0x00 0x00 checksum
2、升级
1、进入升级模式 0x02 0x02 0x00 0x00 checksum
2、升级文件大小 0x03 0x04 0x00 0x00 0x00 0x00 checksum
3、数据包发送 0x04 0x10 0x00 0x00 0x00 0x00 ..... checksum
4、数据包发送完成 0x05 0x02 0x00 0x00 checksum
3、开锁
0x06 0x02 0x00 0x00 checksum
4、关门
0x07 0x02 0x00 0x00 checksum
*/
3、App的开发以及gd32代码添加
1、在上一节的基础上增加UpdateCommand.java文件,
对所有发送命令进行一个封装。
2、重新封装开锁函数
App代码:
public void openLockCmd(BluetoothLeService bluetoothLeService){
byte [] lockOn = {0x06,0x02,0x00,0x00,0x00,0x00};
int crc = UpdateCommand.getInstance().getCRC(lockOn);
lockOn[lockOn.length-1] = (byte)(crc >> 8);
lockOn[lockOn.length-2] = (byte)(crc & (0xff));
bluetoothLeService.writeSpecialCharacteristic(lockOn);
}
GD32代码:
3、重新封装关门代码:
App代码
public void closeLockCmd(BluetoothLeService bluetoothLeService){
byte [] lockOff = {0x07,0x02,0x00,0x00,0x00,0x00};
int crc = UpdateCommand.getInstance().getCRC(lockOff);
lockOff[lockOff.length-1] = (byte)(crc >> 8);
lockOff[lockOff.length-2] = (byte)(crc & (0xff));
bluetoothLeService.writeSpecialCharacteristic(lockOff);
}
GD32:
4、App代码升级文件发送封装:
a、根据协议,先发送进入升级模式命令:
代码如下:
public void uartSendUpgradeCmd(BluetoothLeService bluetoothLeService){
byte[] upgradeCmd = new byte[]{0x02,0x02,0x00,0x00,(byte)0xa0,0x5c};
bluetoothLeService.writeSpecialCharacteristic(upgradeCmd);
}
b、获取文件大小以及发送文件大小命令:
我们将gd32的升级文件打包内apk内,直接二进制读取文件,按协议分发数据。实际这里可换成ota服务器,从ota服务器上抓取升级文件,然后分包发给gd32。
获取文件大小函数如下:
private int getUpgradeFileLength(Context context)
{
InputStream inputStream;
int fileSize;
AssetManager assetManager = context.getAssets();
try {
inputStream = assetManager.open("Application.bin");
} catch (IOException e) {
throw new RuntimeException(e);
}
try {
fileSize = inputStream.available();
inputStream.close();
return fileSize;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public void uartSendFileSize(Context context,BluetoothLeService bluetoothLeService){
int fileSize = UpdateCommand.getInstance().getUpgradeFileLength(context);
byte [] fileSizeCmd = new byte[]{0x03,0x04,0x00,0x00,0x00,0x00,(byte)0xc2,0x42};
fileSizeCmd[2] = (byte)((fileSize >> 24) & 0xff);
fileSizeCmd[3] = (byte)((fileSize >> 16) & 0xff);
fileSizeCmd[4] = (byte)((fileSize >> 8) & 0xff);
fileSizeCmd[5] = (byte)((fileSize) & 0xff);
int crcSize = UpdateCommand.getInstance().getCRC(fileSizeCmd);
fileSizeCmd[fileSizeCmd.length-1] = (byte)(crcSize >> 8);
fileSizeCmd[fileSizeCmd.length-2] = (byte)(crcSize & (0xff));
bluetoothLeService.writeSpecialCharacteristic(fileSizeCmd);
}
c、分包发送数据函数:
public void uartSendFile(Context context,BluetoothLeService bluetoothLeService){
int fileSize = UpdateCommand.getInstance().getUpgradeFileLength(context);
wTimer = 0;
AssetManager assetManager = context.getAssets();
if (fileSize % EVERY_PACKAGE_DATA_LENGTH == 0){
filePackages = fileSize / EVERY_PACKAGE_DATA_LENGTH;
}else{
filePackages = fileSize / EVERY_PACKAGE_DATA_LENGTH + 1;
}
InputStream inputStream = null;
try {
inputStream = assetManager.open("Application.bin");
byte buffer[] = new byte[EVERY_PACKAGE_DATA_LENGTH];
byte buffer2[] = new byte[EVERY_PACKAGE_DATA_LENGTH + 4];
int len = 0;
while ((len = inputStream.read(buffer,0,buffer.length))>0) {
//buffer为读出来的二进制数据,长度1024,最后一段数据小于1024
if (len != EVERY_PACKAGE_DATA_LENGTH){
for (int i=len;i<EVERY_PACKAGE_DATA_LENGTH;i++){
buffer[i] = (byte) 0xff;
}
}
System.arraycopy(buffer,0,buffer2,2,buffer.length);
buffer2[0] = 0x04;
buffer2[1] = (byte)0x80;
int crc = UpdateCommand.getInstance().getCRC(buffer2);
buffer2[buffer2.length-1] = (byte)(crc >> 8);
buffer2[buffer2.length-2] = (byte)(crc & (0xff));
LogUtil.d(TAG,"need send data " + ChangeTool.getInstance().byte2HexStr(buffer2));
bluetoothLeService.writeSpecialCharacteristic(buffer2);
Thread.sleep(20);
wTimer++;
if(this.mOnReceiveUartUpgradeListener != null)
mOnReceiveUartUpgradeListener.OnReceiveUartUpgradeProcess((int)((wTimer * 100)/filePackages));
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
if (inputStream!=null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
d、发送升级完成命令:
public void uartUpgradeCompleted(BluetoothLeService bluetoothLeService) {
byte[] complete_cmd = new byte[]{0x05,0x02,0x00,0x00,(byte)0xa0,0x5c};
int crc = UpdateCommand.getInstance().getCRC(complete_cmd);
complete_cmd[complete_cmd.length-1] = (byte)(crc >> 8);
complete_cmd[complete_cmd.length-2] = (byte)(crc & (0xff));
bluetoothLeService.writeSpecialCharacteristic(complete_cmd);
}
e、获取版本号函数:
public void uartGetMcuVersion(BluetoothLeService bluetoothLeService)
{
byte[] versionCmd = new byte[]{0x01,0x02,0x00,0x00,(byte)0xa0,0x18};
bluetoothLeService.writeSpecialCharacteristic(versionCmd);
}
Gd32相关函数添加:
a、获取版本号: