ARM单片机通用IAP在线升级YMODEM协议

ARM单片机通用IAP在线升级YMODEM协议

效果

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

YMODEM协议格式

/*
接收开始流程:
接收者1HZ发送接收状态:
      /-----------/
    /     C     /
  /-----------/
C:代表字符'C',进入接收状态

发送者发送起始帧:
      /-----------/-----------/-----------/-----------/-----------/-----------/-----------/-----------/
    /    SOH    /    00     /     FF    / FILE_NAME / FILE_SIZE /    NULL   /   CRC_H   /   CRC_L   /
  /-----------/-----------/-----------/-----------/-----------/-----------/-----------/-----------/
/                                   /     C            R           C    /
SOH:代表起始帧,十六进制:0x01,也代表传输数据128字节
CRC:丢弃前三字节,后面为CRC数据区域
帧大小:128+5=133Bytes
NULL:0

接收应答发送:
      /-----------/
    /    ACK    /
  /-----------/
ACK:0x06

接收者发送开始接收标识ONCE:
      /-----------/
    /     C     /
  /-----------/
C:代表字符'C',进入接收状态

发送者发送数据帧:
      /-----------/-----------/-----------/-----------/-----------/-----------/-----------/-----------/
    /  SOH/STX  /  帧编号   / 帧编号反码 /      D       A       T       A    /   CRC_H   /   CRC_L   /
  /-----------/-----------/-----------/-----------/-----------/-----------/-----------/-----------/
/                                   /     C            R           C    /
SOH:十六进制:0x01,也代表传输数据128字节,STX 表示有1024个字节
CRC:丢弃前三字节,后面为CRC数据区域
帧大小:最小128+5=133Bytes 最大1024+5=1029Bytes
帧数据不足:使用0X1A填充

接收应答发送:
      /-----------/
    /    ACK    /
  /-----------/
ACK:0x06

发送结束流程:
发送者发送结束标识:
      /-----------/
    /    EOT    /
  /-----------/
EOT:代表0x04

接收者应答:
      /-----------/
    /    NAK    /
  /-----------/
NAK:代表0x15

发送者再次发送结束标识:
      /-----------/
    /    EOT    /
  /-----------/
EOT:代表0x04

接收应答发送:
      /-----------/
    /    ACK    /
  /-----------/
ACK:0x06

接收者发送开始接收结束帧:
      /-----------/
    /     C     /
  /-----------/
C:代表字符'C',进入接收状态

发送者发送结束帧:
      /-----------/-----------/-----------/-----------/-----------/-----------/-----------/-----------/
    /    SOH    /    00     /     FF    /         N   U   L   L[128]        /   CRC_H   /   CRC_L   /
  /-----------/-----------/-----------/-----------/-----------/-----------/-----------/-----------/
/                                   /     C            R           C    /
SOH:代表结束帧,十六进制:0x01,也代表传输数据128字节
CRC:丢弃前三字节,后面为CRC数据区域
帧大小:128+5=133Bytes
NULL:0

接收应答发送:
      /-----------/
    /    ACK    /
  /-----------/
ACK:0x06

流程结束!
*/

移植修改接口

/**                                                                             
 *  @file YModem.h                                                    
 *                                                                              
 *  @date 2021年01月11日 23:18:49 星期一
 *                                                                              
 *  @author aron566                                                             
 *                                                                              
 *  @brief Ymodem 传输协议.                                                                
 *                                                                              
 *  @version V1.0                                                               
 */                                                                             
#ifndef YMODEM_H                                                          
#define YMODEM_H                                                          
#ifdef __cplusplus ///<use C compiler                                           
extern "C" {                                                                   
#endif                                                                          
/** Includes -----------------------------------------------------------------*/
#include <stdint.h> /**< need definition of uint8_t */                          
#include <stddef.h> /**< need definition of NULL    */                          
#include <stdbool.h>/**< need definition of BOOL    */                        
#include <stdio.h>  /**< if need printf             */                          
#include <stdlib.h>                                                             
#include <string.h>                                                             
#include <limits.h> /**< need variable max value    */                          
/** Private includes ---------------------------------------------------------*/

/** Private defines ----------------------------------------------------------*/
#define FILE_NAME_LEN_MAX       64
#define FILE_SIZE_LEN_MAX       64
#define ENABLE_CRC_START_FRAME  1
/** Exported typedefines -----------------------------------------------------*/
/*Ymodem 帧检测结果*/                                                                
typedef enum                                                               
{                                                                               
  YMODEM_IS_YMODEM_FRAME = 0,  /**< 是Ymodem数据帧 */ 
  YMODEM_IS_NOT_YMODEM_FRAME,                                                
}YMODEM_FRAME_CHECK_STATE_Typedef_t;

/*Ymodem 帧CRC校验结果*/
typedef enum                                                               
{                                                                               
  YMODEM_CRC_OK = 0,          /**< Ymodem数据帧校验正确 */ 
  YMODEM_CRC_ERROR,                                                
}YMODEM_FRAME_CRC_STATE_Typedef_t;

/*Ymodem 运行状态*/
typedef enum
{
  YMODEM_NO_RUNNING = 0,
  /*接收方*/
  YMODEM_START_SEND_C_LOOP,    /**< 启动发 C字符*/
  YMODEM_WAIT_START_SOH,
  YMODEM_REPLY_START_SOH_ACK,
  YMODEM_SEND_SIGNAL_ONE_C,
  YMODEM_WAIT_DATA_FRAME,
  YMODEM_REPLY_DATA_ACK,
  YMODEM_WAIT_START_EOT_FLAG,
  YMODEM_REPLY_START_EOT_NAK,
  YMODEM_WAIT_END_EOT_FLAG,
  YMODEM_REPLY_END_EOT_ACK,
  YMODEM_SEND_ONE_C_END,
  YMODEM_WAIT_END_SOH,
  YMODEM_REPLY_END_SOH_ACK,

  /*发送方*/
  YMODEM_WAIT_START_C,      /**< 等待起始 C字符*/
  YMODEM_SEND_START_FRAME,  /**< 发送起始帧*/
  YMODEM_WAIT_START_ACK,    /**< 等待ACK*/
  YMODEM_WAIT_START_REC,    /**< 等待接收C字符发送数据起始*/
  YMODEM_SEND_DATA_FRAME,
  YMODEM_WAIT_DATA_ACK,
  YMOMDE_SEND_EOT_FRAME,
  YMODEM_WAIT_NAK,
  YMODEM_SEND_EOT_END,
  YMODEM_WAIT_EOT_ACK,
  YMODEM_WAIT_REC_END_C,  	/**< 等待接收结束帧信号*/
  YMODEM_SEND_END_FRAME,
  YMODEM_WAIT_END_ACK,

  YMODEM_COMPLETE
}YMODEM_TRANSFER_STEP_Typedef_t;

/*Ymodem 运行结果*/
typedef enum
{
  YMODEM_SUCCESSFUL = 0,      /**< 运行成功*/
  YMODEM_RUN_TIMEOUT,         /**< 运行超时*/
  YMODEM_IS_RUNNING,          /**< 运行中*/
  YMODEM_ABORT_ERROR,         /**< 运行中止*/
  YMODEM_FRAME_NOT_MATCH,     /**< 帧不匹配*/
  YMODEM_UNKNOW_ERROR,        /**< 未知错误*/
}YMODEM_RUN_RESULT_Typedef_t;

/*Ymodem 句柄*/
/*Ymodem 模式选择状态*/
typedef enum
{
  YMODEM_REC_MODE = 0,
  YMODEM_SEND_MODE,
}YMODEM_MODE_Typedef_t;
/*Ymodem 数据接收回调*/
/**
 * @brief 接收数据回调
 * @param data 数据
 * @param size 数据长度
 * @param packet_num 第几包数据
 * @return 接收数据大小
 */
typedef uint32_t (*YMODEM_REC_DATA_CALLBACK)(const uint8_t *data, uint32_t size, uint8_t packet_num);
/*Ymodem 数据发送回调*/
/**
 * @brief 填充发送数据回调
 * @param dest_buf 数据存储区
 * @param size 存储区大小
 * @param packet_num 填充本次数据包号
 * @return 本次填充数据大小
 */
typedef uint32_t (*YMODEM_SEND_DATA_CALLBACK)(uint8_t *dest_buf, uint32_t size, uint8_t *packet_num);
/*Ymodem 答复接口回调*/
/**
 * @brief 发送数据接口
 * @param data 数据
 * @param size 数据长度
 * @return None
 */
typedef void (*YMODEM_REPLY_DATA_CALLBACK)(const uint8_t *data, uint32_t size);

typedef struct 
{
  char file_name[FILE_NAME_LEN_MAX];              /**< 发送/接收文件名*/
  uint32_t file_size;                             /**< 发送/接收文件大小*/
  float current_progress;                         /**< 当前文件发送/接收进度*/
  float last_progress;                            /**< 上次文件发送/接收进度*/
  uint32_t time_cnt;                              /**< 时间计时*/
  uint32_t set_time_out;                          /**< 任务超时*/
  uint32_t last_time;                             /**< 上次运行时间*/
  uint32_t file_size_cnt;                         /**< 当前发送/接收报总大小*/
  YMODEM_REC_DATA_CALLBACK set_rec_data_func;     /**< 接收数据回调*/
  YMODEM_SEND_DATA_CALLBACK set_send_data_func;   /**< 发送数据回调*/
  YMODEM_REPLY_DATA_CALLBACK set_reply_data_func; /**< 答复数据回调*/
  YMODEM_MODE_Typedef_t set_mode;                 /**< Ymodem模式状态*/
  YMODEM_TRANSFER_STEP_Typedef_t run_step;        /**< Ymodem运行状态*/
}YMODEM_HANDLE_Typedef_t;
/** Exported constants -------------------------------------------------------*/

/** Exported macros-----------------------------------------------------------*/
#ifndef ASSERT_PAR
#define ASSERT_PAR(par, value, out) do{ \
                                        if(par == value) \
                                        { \
                                          out; \
                                        }}while(0)
#endif
/** Exported variables -------------------------------------------------------*/
/** Exported functions prototypes --------------------------------------------*/

/*Ymodem ms计时接口回调-放入systick或者1ms定时器中断中*/
void ymodem_update_time_ms_Port(void);

/*Ymodem 初始化*/
/**
 * @brief Ymodem 初始化
 * 
 * @param handle Ymodem句柄
 * @param mode 运行模式:YMODEM_REC_MODE接收模式/YMODEM_SEND_MODE发送模式
 * @param rec_func 接收数据回调
 * @param send_func 发送数据时的填充数据回调
 * @param reply_func 回复数据回调
 * @param time_out 超时时间
 * @return true 
 * @return false 
 */
bool ymodem_init(YMODEM_HANDLE_Typedef_t *handle, YMODEM_MODE_Typedef_t mode, YMODEM_REC_DATA_CALLBACK rec_func
                  ,YMODEM_SEND_DATA_CALLBACK send_func, YMODEM_REPLY_DATA_CALLBACK reply_func, uint32_t time_out);
/*Ymodem 启动*/
/**
 * @brief Ymodem 启动,循环调用,注意数据一帧大小接收缓冲区应大于133
 * 
 * @param handle Ymodem句柄
 * @param data 将接收到的数据帧传递
 * @param len 数据帧大小字节数
 * @return YMODEM_RUN_RESULT_Typedef_t 
 */
YMODEM_RUN_RESULT_Typedef_t ymodem_task_run(YMODEM_HANDLE_Typedef_t *handle, uint8_t *data, uint32_t len);

/*Ymodem 获取文件名及大小*/
/**
 * @brief Ymodem 获取文件名及大小
 * 
 * @param handle Ymodem句柄
 * @param file_size 获得文件大小
 * @return const char* 
 */
const char *ymodem_get_file_info(YMODEM_HANDLE_Typedef_t *handle, uint32_t *file_size);

/*Ymodem 获得当前发送或接收进度*/
/**
 * @brief Ymodem 获得当前发送或接收进度
 * 
 * @param handle Ymodem句柄
 * @return float 当前进度
 */
float ymodem_get_progress(YMODEM_HANDLE_Typedef_t *handle);

/*Ymodem 发送文件信息设置*/
/**
 * @brief Ymodem 发送文件信息设置
 * 
 * @param handle Ymodem句柄
 * @param file_name 设置发送的文件名
 * @param file_size 设置发送的文件大小
 */
void ymodem_set_send_file_info(YMODEM_HANDLE_Typedef_t *handle, const char *file_name, uint32_t file_size);

#ifdef __cplusplus ///<end extern c                                             
}                                                                               
#endif                                                                          
#endif                                                                          
/******************************** End of file *********************************/
                                                                                

测试代码

/*STEP 1 创建句柄对象*/
YMODEM_HANDLE_Typedef_t ymodem_handle;

int main(void)
{
  uint8_t data[133] = {0};
  uint32_t len = 0;
  Uart_Dev_Handle_t *uart_handle = Uart_Port_Get_Handle(UART_NUM_1);
  /*STEP 2 初始化为接收,60s为超时退出*/
  ymodem_init(&ymodem_handle, YMODEM_REC_MODE, ymodem_get_data, NULL, ymodem_send_data, 60);
  /* Infinite loop */
  for(;;)
  {
    len = CQ_getLength(uart_handle->cb);
    len = (len > 133)?133:len;
    CQ_getData(uart_handle->cb, data, len);
    /*STEP 3 将来自发送方的数据传递给ymodem执行解析运行 返回 YMODEM_IS_RUNNING代表正常,YMODEM_SUCCESSFUL代表完成 YMODEM_RUN_TIMEOUT代表超时 YMODEM_ABORT_ERROR代表异常中止*/
    ymodem_task_run(&ymodem_handle, data, 133);
    HAL_GPIO_TogglePin(LED0_GPIO_Port, LED0_Pin);
    osDelay(10);
  }
}
/*提供接收文件数据的接口*/
static uint32_t ymodem_get_data(const uint8_t *data, uint32_t size, uint8_t packet_num)
{
  static uint32_t size_cnt = 0;
  printf("ymodem rec:%uBytes PacketNum: %hhu \r\n", size, packet_num);
  size_cnt += size;
  printf("ymodem rec cnt:%uBytes \r\n", size_cnt);
  return size;
}
/*提供发送响应数据的接口*/
static void ymodem_send_data(const uint8_t *data, uint32_t size)
{
//  printf("ymodem send: 0x%02X, Size:%u\r\n", data[0], size);
  Uart_Dev_Handle_t *uart_handle = Uart_Port_Get_Handle(UART_NUM_1);
  Uart_Port_Transmit_Data(uart_handle, (uint8_t *)data, (uint16_t)size);
}

代码获取

github Ymodem

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
### 回答1: 51单片机iap(In-Application Programming)在线升级是一种在单片机系统中通过编程的方式对在线设备进行升级的技术。 通过IAP技术,在单片机系统运行的过程中,对内部存储器进行读取和修改,并将新的程序代码下载到内存中,从而实现在线升级IAP不需要擦除内存,能够有效地避免数据丢失,提高系统的稳定性和安全性。 51单片机IAP在线升级技术可以在系统运行时进行程序升级,更新新的功能,增强系统性能,并具有快速、灵活、方便的特点。但是,IAP技术需要对硬件进行支持,如双系统设计和FLASH存储器等。 因此,在进行51单片机IAP在线升级时,需要根据硬件支持条件选择不同的技术实现方案。同时,在进行在线升级时,需要注意保护程序的完整性和安全性,以免出现不良影响。 总之,51单片机IAP在线升级技术是一种便捷、灵活、高效、先进的升级方式,广泛应用于各类嵌入式系统中,有利于实现软件功能的快速升级和系统的优化。 ### 回答2: 51单片机指的是一种基于Intel 8051指令集的单片机,它是广泛应用于嵌入式系统中的一种芯片。而IAP(In-Application Programming)在线升级则是指在不需要任何外部设备的情况下,通过程序自身对芯片中的代码进行更新。 在51单片机中,实现IAP在线升级需要结合程序设计和硬件电路设计两个方面。首先,程序中需要预留出一定的存储空间,用于存储升级程序的代码。其次,需要设计一个与单片机相连的串行接口,如UART或SPI等,以便实现与外界通信,接收升级程序的数据。 整个IAP升级的流程如下:首先,单片机在运行过程中通过串口接收到升级程序的数据,将数据暂存至内部存储器。然后,单片机停止当前程序执行,切换到专门的IAP程序,读取内部存储器中的升级程序数据,并将其写入到指定的程序存储区。最后,单片机重新启动程序执行,完成升级。 通过IAP在线升级技术,可以大大简化芯片升级的操作流程,并节省升级的时间和成本,适用于各种嵌入式场景的应用。 ### 回答3: 51单片机iap在线升级是通过网络或串口实现对51单片机程序的在线更新和升级。它可以通过服务器端的推送或客户端的请求,将新的程序固件通过网络传送到目标单片机,然后在单片机中通过IAP(In-Application Programming)实现程序的自我升级。这种在线升级方式可以极大地简化单片机的维护和升级,提升单片机的灵活性和可用性。它适用于广泛的应用场景,如远程设备控制、智能家居、远程医疗等。同时,为了保证在线升级的安全性和准确性,需要特别注意数据传输的可靠性和过程的安全性。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

aron566

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

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

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

打赏作者

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

抵扣说明:

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

余额充值