Clion开发STM32之OTA升级模块(最新完整版)

前言

  1. 程序分为上位机部分、BootLoader、App程序
  2. 上位机程序使用的是C#进行开发,目前只做成控制台部分
  3. 开发环境依然选择Clion
  4. 芯片采用的是stm32f103vet6
  5. 升级模块已和驱动层逻辑进行分离

BootLoader程序

Flash分区定义

头文件

#ifndef STM32F103VET6_PROJECT_APP_FLASH_CONF_H
#define STM32F103VET6_PROJECT_APP_FLASH_CONF_H

#include "stm32f1xx_hal.h"

#define SIZE_8B (8)
#define SIZE_256B (256)
#define SIZE_512B (512)
#define SIZE_1K   (1024)
#define SIZE_2K   (2048)
#define SIZE_3K   (3072)
#define SIZE_4K   (4092)
#define SYS_CONVERT(type, val) ((type)(val))
// 引导程序大小: 10KB
#define BOOT_AREA_SIZE (SIZE_1K*10)
#define BOOT_START_ADDR FLASH_BASE
// APP: 150KB (应用程序)
#define APP_AREA_SIZE (SIZE_1K*150)
#define APP_START_ADDR SYS_CONVERT(uint32_t,BOOT_START_ADDR+BOOT_AREA_SIZE)
// APP UPGRADE: 150KB (应用升级)
#define APP_UPGRADE_AREA_SIZE (SIZE_1K*150)
#define APP_UPGRADE_START_ADDR SYS_CONVERT(uint32_t,APP_START_ADDR+APP_AREA_SIZE)
// 配置区域: 50KB
#define CONF_AREA_SIZE (SIZE_1K*50)
#define CONF_START_ADDR SYS_CONVERT(uint32_t,APP_UPGRADE_START_ADDR+APP_UPGRADE_AREA_SIZE)
// 数据区域: 130KB
#define DATA_AREA_SIZE (SIZE_1K*130)
#define DATA_START_ADDR SYS_CONVERT(uint32_t,CONF_START_ADDR+CONF_AREA_SIZE)
// 引导数据配置信息:
#define BOOT_INF_ADDR SYS_CONVERT(uint32_t,DATA_START_ADDR+DATA_AREA_SIZE)
#endif //STM32F103VET6_PROJECT_APP_FLASH_CONF_H

固件信息读取

注意: 此处操作Flash驱动参考

头文件

#ifndef STM32F103VET6_PROJECT_OTA_BOOT_INFO_H
#define STM32F103VET6_PROJECT_OTA_BOOT_INFO_H

#include "stm32f1xx_hal.h"
// 定义升级标志位,确保唯一性
#define OTA_UPGRADE_FLAG (0x1389)
typedef struct {
    uint8_t app_version[6]; // 应用版本
    uint32_t app_new_version_flag; // 应用新版本标志位
    uint32_t app_upgrade_data_size; // 应用升级数据大小
} APP_Info_t;

void Load_App_Info(APP_Info_t *info);

void Update_App_Info(APP_Info_t *info);
void Jump_To_App(uint32_t run_addr);
void Jump_To_BootLoader(void);
#endif //STM32F103VET6_PROJECT_OTA_BOOT_INFO_H

源文件

#include "ota_boot_info.h"
#include "bsp_flash.h"
#include "app_flash_conf.h"

typedef void (*pFunction)(void);

/**
 * 加载APP信息
 * @param dst
 */
void Load_App_Info(APP_Info_t *info) {
    STMFLASH_Read_Base(BOOT_INF_ADDR, info, sizeof(APP_Info_t));
}

/**
 * 更新APP信息
 * @param dst
 */
void Update_App_Info(APP_Info_t *info) {
    STMFLASH_Write_Base(BOOT_INF_ADDR, info, sizeof(APP_Info_t));
}

void Jump_To_BootLoader(void) {
    __disable_irq();
    uint32_t JumpAddress;
    pFunction Jump_To_Application;
    JumpAddress = *(volatile uint32_t *) (0x00000004);
    Jump_To_Application = (pFunction) JumpAddress;
    __set_MSP(*(volatile uint32_t *) JumpAddress);
    __set_PSP(*(volatile uint32_t *) JumpAddress);
    Jump_To_Application();
}

void Jump_To_App(uint32_t run_addr) {
    __disable_irq();
    pFunction jump_app;
    jump_app = (pFunction) (*(volatile uint32_t *) (run_addr + 0x04));
    __set_MSP(*(volatile uint32_t *) run_addr);
    jump_app();
}

主入口方法逻辑

int main(void) {
    /* USER CODE BEGIN 1 */
    APP_Info_t app_info;
    Load_App_Info(&app_info);
    if (app_info.app_new_version_flag == OTA_UPGRADE_FLAG) {
        app_info.app_new_version_flag = 0x0;
        STMFLASH_Data_Copy(APP_UPGRADE_START_ADDR, APP_START_ADDR, app_info.app_upgrade_data_size);
        Update_App_Info(&app_info);
    }
    Jump_To_App(APP_START_ADDR);
    /* USER CODE END 1 */

    /* MCU Configuration--------------------------------------------------------*/

    /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
    HAL_Init();

    /* USER CODE BEGIN Init */

    /* USER CODE END Init */

    /* Configure the system clock */
    SystemClock_Config();

    /* USER CODE BEGIN SysInit */

    /* USER CODE END SysInit */

    /* Initialize all configured peripherals */
    MX_GPIO_Init();
    /* USER CODE BEGIN 2 */

    /* USER CODE END 2 */

    /* Infinite loop */
    /* USER CODE BEGIN WHILE */
    while (1) {
        /* USER CODE END WHILE */

        /* USER CODE BEGIN 3 */
    }
    /* USER CODE END 3 */
}

链接文件中对FLASH 限制大小(10KB)

链接文件中对FLASH 限制大小(10KB)

App程序

远程升级协议

头文件(upgrade_core.h)
#ifndef STM32_LIB_UPGRADE_CORE_H
#define STM32_LIB_UPGRADE_CORE_H

#include "sys_core.h"


#define OTA_UPGRADE_VERSION_LIN (6) /** @brief 升级版本长度*/

typedef struct {
    uint8_t app_version[OTA_UPGRADE_VERSION_LIN]; // 应用版本
    uint32_t app_new_version_flag; // 应用新版本标志位
    uint32_t app_upgrade_data_size; // 应用升级数据大小
} app_info_t;

/**
 * @brief 升级数据处理
 * @param data 接收到的数据
 * @param len 数据长度
 */
void device_upgrade_handle(u8 *data, u16 len);


extern void upgrade_resp(u8 status_code);

/**
 * 获取当前设备类型
 * @return 设备类型
 */
extern u8 get_cur_device_type(void);

/**
 * 获取当前版本(长度固定为6)
 * @return
 */
extern u8 *get_cur_version(void);

/**
 * 获取升级写入地址
 * @return
 */
extern u32 get_upgrade_write_addr(void);

/**
 * 写入bin 数据
 * @param addr
 * @param data
 * @param len
 */
extern void upgrade_write_bin(u32 addr, u8 *data, u16 len);

/**
 * 写入app 更新信息
 * @param data
 */
extern void upgrade_write_app_info(app_info_t *data);

/**
 *
 * @return 获取升级数据帧大小
 */
extern u32 get_upgrade_data_size(void);

#endif //STM32_LIB_UPGRADE_CORE_H


源文件(upgrade_core.c)
#include "upgrade_core.h"

#define upgrade_assert(condition, dst, resp_code) \
                        do{\
                            if (!(condition)) {\
                            dst = resp_code;\
                            goto end;\
                        }}while(0)
#define upgrade_assert_return(condition, resp_code)\
                        do{                       \
                        if(!(condition)){         \
                        return resp_code;         \
                        }                         \
                        }while(0)
typedef enum {
    UPGRADE_START_PACKET, /**@brief 开始包*/
    UPGRADE_DATA_PACKET, /**@brief 数据包*/
    UPGRADE_END_PACKET, /**@brief 结束包*/
} packet_type;
typedef enum {
    status_ok,/**@brief 正确*/
    packet_type_error,/**@brief 包类型错误*/
    param_error,/**@brief 参数错误*/
    data_len_error,/**@brief 数据长度错误*/
    device_type_error,/**@brief 设备类型错误*/
    upgrade_version_low, /**@brief 升级版本过低*/
    upgrade_packet_no_error,/**@brief 包号错误*/
    upgrade_data_not_complete, /** 升级数据不完整*/
    start_request_not_send, /**@brief 未发送开始请求*/

} resp_status_code;
typedef struct {
    u8 device_type;/** @brief 设备类型*/
    u8 upgrade_version[OTA_UPGRADE_VERSION_LIN]; /** @brief 升级版本*/
    u32 upgrade_file_size;  /** @brief 升级文件大小 */
} upgrade_info_t; /** @brief 升级帧信息*/
typedef struct {
    u8 current_packet_no;   /** @brief 当前包号*/
    u8 total_packet_num;   /** @brief 总包数*/
    u8 *upgrade_data;     /** @brief 升级数据*/
    u16 upgrade_data_size; /** @brief 升级数据大小(字节数)*/
} upgrade_frame_t; /** @brief 升级帧结构体*/


typedef struct {
    u8 start_upgrade_flag;        /** @brief 开始升级标志位*/
    packet_type pkt_type;/** @brief 包类型*/
    upgrade_info_t base_info; /** @brief 基础信息*/
    upgrade_frame_t upgrade_info; /** @brief 升级信息*/
} upgrade_context_t;
static u8 cur_packet_no = 1;     // 当前升级包号
static __IO u32 rec_upgrade_data_size = 0;
static app_info_t app_info;
static upgrade_context_t context; /** @brief 升级上下文*/
/**
 * 数据解析
 * @param data 
 * @param len 
 * @return 
 */
static resp_status_code upgrade_data_parse_handle(u8 *data, u16 len);

/**
 * 数据处理
 * @param ctx 
 * @return 
 */
static resp_status_code upgrade_core_exec(upgrade_context_t *ctx);

// 版本比较
static int version_cmp(const u8 *v1, const u8 *v2);

// 数据转换
static inline u32 u8_to_u32(u8 *data);

void device_upgrade_handle(u8 *data, u16 len) {
    resp_status_code tmp_status;
    resp_status_code resp_status = status_ok;
    // 验证参数是否为空
    upgrade_assert(data != NULL, resp_status, param_error);
    // 数据解析处理
    tmp_status = upgrade_data_parse_handle(data, len);
    // 验证数据解析
    upgrade_assert(resp_status == tmp_status, resp_status, tmp_status);
    // 数据解析处理
    resp_status = upgrade_core_exec(&context);
    end:
    upgrade_resp(resp_status);
}

static resp_status_code upgrade_data_parse_handle(u8 *data, u16 len) {
    uint16_t idx = 0;
    switch (data[idx]) {
        case UPGRADE_START_PACKET: {
            upgrade_assert_return(len == 12, data_len_error); // 验证数据长度
            // 数据解析
            context.pkt_type = data[idx++];   // 包类型
            context.base_info.device_type = data[idx++];// 设备类型
            context.base_info.upgrade_file_size = u8_to_u32(data + idx); // 升级文件大小
            idx += 4;
            memcpy(context.base_info.upgrade_version, data + idx, OTA_UPGRADE_VERSION_LIN);

            break;
        }
        case UPGRADE_DATA_PACKET: {
            upgrade_assert_return(context.start_upgrade_flag, start_request_not_send); // 是否已经初始化
            upgrade_assert_return(len == get_upgrade_data_size() + 3, data_len_error); // 验证数据长度
            context.pkt_type = data[idx++];   // 包类型
            context.upgrade_info.total_packet_num = data[idx++]; // 总包数
            context.upgrade_info.current_packet_no = data[idx++]; // 当前包号
            context.upgrade_info.upgrade_data = data + idx; // 升级数据
            context.upgrade_info.upgrade_data_size = len - idx; // 升级数据大小(数据长度-前缀长度)
            break;
        }
        case UPGRADE_END_PACKET: {
            upgrade_assert_return(context.start_upgrade_flag, start_request_not_send); // 是否已经初始化
            upgrade_assert_return(len == 6, data_len_error); // 验证数据长度
            context.pkt_type = data[idx++];   // 包类型
            context.base_info.device_type = data[idx++];// 设备类型
            context.base_info.upgrade_file_size = u8_to_u32(data + idx); // 升级文件大小
            break;
        }
        default: {
            return packet_type_error;
        }

    }
    return status_ok;
}

/**
 * 核心逻辑执行
 * @param ctx 
 * @return 
 */
static resp_status_code upgrade_core_exec(upgrade_context_t *ctx) {
    switch (ctx->pkt_type) {
        case UPGRADE_START_PACKET: {
            // 解析之后校验
            // 设备类型校验
            upgrade_assert_return(get_cur_device_type() == ctx->base_info.device_type, device_type_error);
            // 版本校验
            upgrade_assert_return(version_cmp(ctx->base_info.upgrade_version, get_cur_version()) > 0,
                                  upgrade_version_low);
            // 开始更新标志位置位
            ctx->start_upgrade_flag = true;
            memset(&app_info, 0, sizeof(app_info_t));
            app_info.app_upgrade_data_size = ctx->base_info.upgrade_file_size;
            cur_packet_no = 1;
            rec_upgrade_data_size = 0;
            break;
        }
        case UPGRADE_DATA_PACKET: {
            // 升级包序号与当前需要的包序号是否对应
            upgrade_assert_return(cur_packet_no == ctx->upgrade_info.current_packet_no, upgrade_packet_no_error);
            // 获取升级数据地址
            u32 upgrade_data_addr = get_upgrade_write_addr();
            upgrade_write_bin(rec_upgrade_data_size + upgrade_data_addr,
                              ctx->upgrade_info.upgrade_data,
                              ctx->upgrade_info.upgrade_data_size);

            rec_upgrade_data_size = rec_upgrade_data_size + ctx->upgrade_info.upgrade_data_size;
            cur_packet_no += 1;
            break;
        }
        case UPGRADE_END_PACKET:
            upgrade_assert_return(app_info.app_upgrade_data_size == context.base_info.upgrade_file_size,
                                  upgrade_data_not_complete);
            memcpy(app_info.app_version, ctx->base_info.upgrade_version, OTA_UPGRADE_VERSION_LIN);
            app_info.app_new_version_flag = true;
            app_info.app_upgrade_data_size = rec_upgrade_data_size;
            upgrade_write_app_info(&app_info);


            rec_upgrade_data_size = 0;
            cur_packet_no = 1;
            break;
    }
    return status_ok;
}

/**
 *
 * @param v1
 * @param v2
 * @return 0 v1=v2 1 v1>v2 -1 v1<v2
 */
static int version_cmp(const u8 *v1, const u8 *v2) {
    for (int i = 0; i < OTA_UPGRADE_VERSION_LIN; ++i) {
        if (v1[i] > v2[i]) {
            return 1;
        } else if (v1[i] < v2[i]) {
            return -1;
        }
    }
    return 0;
}

static inline u32 u8_to_u32(u8 *data) {
    return (uint32_t) (data[0] << 24) + (uint32_t) (data[1] << 16) + (uint32_t) (data[2] << 8) + data[3];
}
升级协议接口实现
/*
 © Copyright (c) [scl]。保留所有权利。
     本文仅供个人学习和研究使用,禁止用于商业用途。

 */

#include "upgrade_core.h"
#include "app_gb_conf.h"
#include "bsp_flash.h"

#define OTA_UPGRADE_FLAG (0x1389)
u8 cur_version[] = {20, 23, 01, 01, 01, 01};

void upgrade_resp(u8 status_code) {
    os_log(&status_code, 1);
}

/**
 * 获取当前设备类型
 * @return 设备类型
 */
u8 get_cur_device_type(void) {
    return 1;
}

/**
 * 获取当前版本(长度固定为6)
 * @return
 */
u8 *get_cur_version(void) {
    return cur_version;
}

/**
 * 获取升级写入地址
 * @return
 */
u32 get_upgrade_write_addr(void) {
    return APP_UPGRADE_START_ADDR;
}

/**
 * 写入bin 数据
 * @param addr
 * @param data
 * @param len
 */
void upgrade_write_bin(u32 addr, u8 *data, u16 len) {
    STMFLASH_Write_Base(addr, data, len);
}

/**
 * 写入app 更新信息
 * @param data
 */
void upgrade_write_app_info(app_info_t *data) {
    data->app_new_version_flag = OTA_UPGRADE_FLAG;
    STMFLASH_Write_Base(BOOT_INF_ADDR, data, sizeof(app_info_t));
}

u32 get_upgrade_data_size(void) {
    return SIZE_1K;
}

测试(此处是模仿RT-Thread的写法)

/*
 © Copyright (c) [scl]。保留所有权利。
     本文仅供个人学习和研究使用,禁止用于商业用途。

 */

#include "app_gb_conf.h"
#include "upgrade_core.h"

static u8 dma_buf[SIZE_2K];

// 执行之前
static void invoke_before(void) {
    // todo 网络配置加载
}

// 执行
static void invoke(void) {
    com_init_set_baud(com1_cnf, 115200);
//    dma_init_set_direction(com1_rx_dma_cnf, DMA_PERIPH_TO_MEMORY);
    COM1_OpenIRQ(0, 0);
    com1_init();
}

// 执行之后
static void invoke_after(void) {
    HAL_UARTEx_ReceiveToIdle_IT(&com1_handle, dma_buf, SIZE_2K);
    os_ps("app upgrade demo123231123\r\n");
}


void RxEventCallback_USART1(uint16_t size) {
    device_upgrade_handle(dma_buf, size);
    HAL_UARTEx_ReceiveToIdle_IT(&com1_handle, dma_buf, SIZE_2K);


}


void ErrorCallback_USART1() {
    os_ps("ErrorCallback_USART1\r\n");
    HAL_UARTEx_ReceiveToIdle_DMA(&com1_handle, dma_buf, SIZE_2K);

}

CMD_EXPORT(app_upgrade, invoke_before, invoke, invoke_after);

上位机程序(采用的C#)

OtaPacketHelper帮助类

using CommonLib.BaseConvert;
using CommonLib.Basic;

namespace ModbusConsole.Upgrade;

/// <summary>
/// 包帮助类
/// </summary>
public static class OtaPacketHelper
{
    /// <summary>
    /// 构建起始包请求
    /// </summary>
    /// <param name="deviceType"></param>
    /// <param name="upgradePacketSize"></param>
    /// <param name="version"></param>
    /// <returns></returns>
    public static byte[] BuildOtaStartPacketRequest(byte deviceType, uint upgradePacketSize, string version)
    {
        var versionData = CommonSoftBasicHelper.HexStringToBytes(version);
        var upgradeByteNum = ByteTransConvertHelper.ConvertToByte(upgradePacketSize);
        var request = new OtaPacket.OtaStartPacketRequest
        {
            DeviceType = deviceType,
            PacketType = (byte)OtaPacket.OtaPacketTypeEnum.StartPacket,
        };
        unsafe
        {
            CommonUnsafeBasicHelper.ArrayToPointer(request.DeviceVersion, versionData,
                OtaPacket.Define.UpgradePacketVersionNum);
            CommonUnsafeBasicHelper.ArrayToPointer(request.UpgradeDataPacketSize, upgradeByteNum,
                upgradeByteNum.Length);

            var pktLen = sizeof(OtaPacket.OtaStartPacketRequest);
            var dstBuf = new byte[pktLen];

            if (CommonUnsafeBasicHelper.PointerToArray(request.buf, dstBuf, dstBuf.Length))
            {
                return dstBuf;
            }
        }

        return Array.Empty<byte>();
    }
    /// <summary>
    /// 构建结束包请求
    /// </summary>
    /// <param name="deviceType"></param>
    /// <param name="upgradePacketSize"></param>
    /// <returns></returns>
    public static byte[] BuildOtaEndPacketRequest(byte deviceType, uint upgradePacketSize)
    {
        var upgradeByteNum = ByteTransConvertHelper.ConvertToByte(upgradePacketSize);
        var request = new OtaPacket.OtaEndPacketRequest
        {
            DeviceType = deviceType,
            PacketType = (byte)OtaPacket.OtaPacketTypeEnum.EndPacket,
        };
        unsafe
        {
            CommonUnsafeBasicHelper.ArrayToPointer(request.UpgradeDataPacketSize, upgradeByteNum,upgradeByteNum.Length);
            var pktLen = sizeof(OtaPacket.OtaEndPacketRequest);
            var dstBuf = new byte[pktLen];

            if (CommonUnsafeBasicHelper.PointerToArray(request.buf, dstBuf, dstBuf.Length))
            {
                return dstBuf;
            }
        }

        return Array.Empty<byte>();
    }
    

    /// <summary>
    /// 构建数据包
    /// </summary>
    /// <param name="curPacketNo"></param>
    /// <param name="totalPacketNo"></param>
    /// <param name="data"></param>
    /// <returns></returns>
    public static byte[] BuildOtaDataPacketRequest(byte curPacketNo, byte totalPacketNo, byte[] data)
    {
        var request = new OtaPacket.OtaDataPacketRequest()
        {
            PacketType = (byte)OtaPacket.OtaPacketTypeEnum.DataPacket,
            NowPackNum = curPacketNo,
            TotalPackNum = totalPacketNo
        };
        unsafe
        {
            CommonUnsafeBasicHelper.ArrayToPointer(request.UpgradeData, data,
                Math.Min(data.Length, OtaPacket.Define.UpgradeDataPacketNum));
            var pktLen = sizeof(OtaPacket.OtaDataPacketRequest);
            var dstBuf = new byte[pktLen];
            if (CommonUnsafeBasicHelper.PointerToArray(request.buf, dstBuf, dstBuf.Length))
            {
                return dstBuf;
            }
        }

        return Array.Empty<byte>();
    }
    
}

OtaPacket包类

using System.Runtime.InteropServices;

namespace ModbusConsole.Upgrade;

/// <summary>
/// 远程升级包
/// </summary>
public class OtaPacket
{
    public class Define
    {
        public const int UpgradeDataPacketNum = 1024;
        public const int UpgradePacketVersionNum = 6;
        public const int UpgradePacketSize = 4;
    }

    public enum OtaPacketTypeEnum : byte
    {
        StartPacket = 0x00,
        DataPacket = 0x01,
        EndPacket = 0x02,
    }

    /// <summary>
    /// OTA 升级信息请求包
    /// </summary>
    [StructLayout(LayoutKind.Explicit, Size = Define.UpgradePacketVersionNum + Define.UpgradePacketSize + 2)]
    public unsafe struct OtaStartPacketRequest
    {
        [FieldOffset(0)] public fixed byte buf[Define.UpgradePacketVersionNum + Define.UpgradePacketSize + 2];

        /// <summary>
        /// 包类型
        /// </summary>
        [FieldOffset(0)] public byte PacketType;

        /// <summary>
        /// 设备类型
        /// </summary>
        [FieldOffset(1)] public byte DeviceType;

        /// <summary>
        /// 升级数据包大小
        /// </summary>
        [FieldOffset(2)] public fixed byte UpgradeDataPacketSize[Define.UpgradePacketSize];

        /// <summary>
        /// 设备版本号
        /// </summary>
        [FieldOffset(2 + Define.UpgradePacketSize)]
        public fixed byte DeviceVersion[Define.UpgradePacketVersionNum];
    }
    /// <summary>
    /// OTA 升级结束包
    /// </summary>
    [StructLayout(LayoutKind.Explicit, Size =  Define.UpgradePacketSize + 2)]
    public unsafe struct OtaEndPacketRequest
    {
        [FieldOffset(0)] public fixed byte buf[ Define.UpgradePacketSize + 2];
        /// <summary>
        /// 包类型
        /// </summary>
        [FieldOffset(0)] public byte PacketType;
        /// <summary>
        /// 设备类型
        /// </summary>
        [FieldOffset(1)] public byte DeviceType;
        /// <summary>
        /// 升级数据包大小
        /// </summary>
        [FieldOffset(2)] public fixed byte UpgradeDataPacketSize[Define.UpgradePacketSize];
    }


    /// <summary>
    /// OTA 数据请求包
    /// </summary>
    [StructLayout(LayoutKind.Explicit, Size = Define.UpgradeDataPacketNum + 3)]
    public unsafe struct OtaDataPacketRequest
    {
        [FieldOffset(0)] public fixed byte buf[Define.UpgradeDataPacketNum + 3];

        /// <summary>
        /// 包类型
        /// </summary>
        [FieldOffset(0)] public byte PacketType;

        [FieldOffset(1)] public byte TotalPackNum;
        [FieldOffset(2)] public byte NowPackNum;
        [FieldOffset(3)] public fixed byte UpgradeData[Define.UpgradeDataPacketNum];
    }

    [StructLayout(LayoutKind.Explicit, Size = 1)]
    public unsafe struct OtaPackResponse
    {
        [FieldOffset(0)] public fixed byte buf[1];

        /// <summary>
        /// 执行结果 0xFE时执行开机成功 0xFD时开启失败 0xFC表示当前已处于开启状态
        /// </summary>
        [FieldOffset(0)] public byte resp_code;
    }
}

主入口函数

using System.IO.Ports;
using CommonLib.Basic;
using Modbus.Device;
using ModbusConsole.Helper;
using ModbusConsole.Upgrade;

namespace ModbusConsole;

public static class Program
{
    public static void Main(string[] args)
    {
        var binFile =
            @"E:\scl\gitee\stm32f103vet6-project\cmake-build-debug\stm32f103vet6-project.bin";
        var binData = CommonFileBasicHelper.GetFileSize(binFile);
        Console.WriteLine($"bin data size: {binData}");
        var packetData = OtaPacketHelper.BuildOtaStartPacketRequest(0x01, (uint)binData, "202301020101");
        Console.WriteLine(packetData.ToHexString());
        var binDataList = CommonFileBasicHelper.LoadBinFile(binFile,1024);
        var client = new SerialPort("COM17",115200);
        client.Open();
        client.Write(packetData, 0, packetData.Length);
        Thread.Sleep(500);
        var status = client.ReadByte();
        Console.WriteLine(status);
        for (var i = 0; i < binDataList.Count; i++)
        {
            var upgradeData =
                OtaPacketHelper.BuildOtaDataPacketRequest((byte)(i + 1), (byte)binDataList.Count, binDataList[i]);
            client.Write(upgradeData, 0, upgradeData.Length);
            var result = client.ReadByte();
            Console.WriteLine($"result: {result:X2}");
            Thread.Sleep(50);
        }

        packetData = OtaPacketHelper.BuildOtaEndPacketRequest(0x1, (uint)binData);
        client.Write(packetData, 0, packetData.Length);
         status = client.ReadByte();
        Console.WriteLine($"result: {status:X2}");
        Console.Read();
    }

  
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

詩不诉卿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值