单片机GD32F303RCT6 (Macos环境)开发 (二十九)—— GD32通过蓝牙透传模块 IAP升级

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)0x10;
            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、获取版本号:
在这里插入图片描述
b、接收到进入升级命令后,灯由500ms变为100ms快速闪烁,代码如下:

在这里插入图片描述
c、接收文件大小命令:
在这里插入图片描述
d、分包接收升级包数据。

在这里插入图片描述
e、接收升级完成命令。
在这里插入图片描述
f、Bootloader程序main.c修改:

在这里插入图片描述
在这里插入图片描述

4、视频如下:

app:

AndroidApp蓝牙透传模块升级GD32F303过程演示

GD32:

gd32f303通过蓝牙透传模块升级过程演示

5、代码路径:

Android App:https://gitee.com/xiaoguo-tec_0/hc-08-app.git
Gd32 Code: https://gitee.com/xiaoguo-tec_0/gd32-iap-code.git

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值