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

猜你喜欢

转载自blog.csdn.net/weixin_42892101/article/details/112501803
今日推荐