ymodem协议!!

前言

在实习公司遇到一个需求,需要用到ymodem协议来传输文件(仪表传输到控制器)。在网上找了很多资料,但是符合的不太多
于是写下这个博客来记录一下。


一、ymodem协议是什么?

这个就直接打开浏览器,然后百度或者啥,一搜索就一大推,我就不废话再去讲什么是ymodem协议了。
简单的附上一个图片:
简略协议流程图

二、直接贴代码

#include "ymodem_read_file.h"
#include "ymodem.h"
//#include "ebike_util.h"
//#include "..\..\ebike_uart.h"
#include "string.h"

// #include "..\..\ebike_list.h"

#define UPDATA_FILE_NAME 'u', 'p', 'd', 'a', 't', 'a', '.', 'b', 'i', 'n', 0x00, '1', 'f', '4', 0x00
#define UART_YMODEM_READ_BUFFER_LENGTH 1
#define UART_YMODEM_READ_OK_BUFFER_LENGTH 2
#define UART_YMODEM_WRITE_BUFFER_LENGTH 128
#define UART_YMODEM_ALL_WRITE_BUFFER_LENGTH 133
#define UART_YMODEM_BOOT_SEND_COUNT 120
#define UART_YMODEM_BOOTING_READ_BUFFER_LENGTH 80

static kal_uint8 blockon = 0x00;
static kal_uint8 files_size = 500; // byte

static kal_bool files_over_flag = KAL_FALSE;

static kal_uint8 ymodem_read_buffer[UART_YMODEM_READ_BUFFER_LENGTH] = {0};                 // 装CAN,NAK,ACK,C
static kal_uint8 ymodem_read_OK_signal[UART_YMODEM_READ_OK_BUFFER_LENGTH] = {0};           // 装ok
static kal_uint8 ymodem_booting_read_buffer[UART_YMODEM_BOOTING_READ_BUFFER_LENGTH] = {0}; // 版本号厂家序列号、

static kal_bool first_pkg_flag = KAL_FALSE;
static kal_bool last_pkg_flag = KAL_FALSE;

static ymodem_send_data ymodem_send_data_pkg = {0};
static kal_uint8 ymodem_wrote_len = 0;
static kal_uint8 ymodem_unwrite_len = 0;
static kal_uint8 ymodem_write_buffer[UART_YMODEM_ALL_WRITE_BUFFER_LENGTH] = {0};
static ymodem_crc_chk ymodem_crc_check = {0};
static EBIKE_TIMER_ID boot_timer_id;
static kal_uint8 status = STEP_0;

// kal_bool go_on_read_flag = KAL_FALSE;

// extern kal_uint8 read_buffer[];
extern read_updata_file read_updata_file_info;
extern kal_uint16 *bin_file_size;

// 校验计算crc。
static kal_uint16
YModemCrc(kal_uint8 *pdata, kal_uint16 slen)
{
    kal_uint16 crc = 0;
    kal_uint16 i;
    if (slen)
    {
        crc = crc ^ (kal_uint32)(*pdata++) << 8;
        for (i = 8; i != 0; i--)
        {
            if (crc & 0x8000)
                crc = crc << 1;
            else
                crc = crc << 1;
        }
    }
    return crc;
}

// 发送数据包到串口。
void ymodem_send_pgk(kal_uint8 *data, kal_uint8 data_len)
{
    kal_uint8 unwrite;
    kal_uint8 *ptr = NULL;
    kal_int16 wrote = 0;
    ptr = data;

    unwrite = ymodem_unwrite_len - ymodem_wrote_len;
    if (0 == unwrite)
    {
        wrote = ebike_uart_write_data(ptr, data_len);//这个是向串口发送的函数
        if (wrote < data_len)
        {
            kal_uint8 need_write = data_len - wrote;
            if (ymodem_unwrite_len + need_write <= UART_YMODEM_WRITE_BUFFER_LENGTH)
            {
                memcpy(ymodem_write_buffer + ymodem_unwrite_len, ptr + wrote, need_write);
                ymodem_unwrite_len += need_write;
                DBG("uart writing is not completed.");
            }
            else
            {
                DBG("the write buffer is full.");
            }
        }
    }
    else if (0 < unwrite)
    {
        if (ymodem_unwrite_len + data_len <= UART_YMODEM_WRITE_BUFFER_LENGTH)
        {
            memcpy(ymodem_write_buffer + ymodem_unwrite_len, ptr, data_len);
            ymodem_unwrite_len += data_len;
        }
        else
        {
            DBG("the write buffer is full.");
        }
    }
}

/* memcpy memset 的头文件string.h还没有确定加了没*/

// 发送!@#$ 让从机进入boost。
static void ymodem_send_boot_signal()
{
    kal_uint8 boost_signal[] = {0x21, 0x40, 0x23, 0x24};

    // 每120ms发送一次。
    ymodem_send_pgk(boost_signal, sizeof(boost_signal));

    boot_timer_id = ebike_timer_start(ymodem_send_boot_signal, NULL, UART_YMODEM_BOOT_SEND_COUNT);
}

// 主机接收到ok后发送?。
static void ymodem_send_question_mark()
{
    kal_uint8 question_marksignal[] = {0x3f}; // ?

    ymodem_send_pgk(ymodem_send_question_mark, sizeof(ymodem_send_question_mark));
    return;
}

// 文件传输结束后主机发送EOT
static void ymodem_send_EOT()
{
    kal_uint8 EOTsignal[] = {0x04}; // EOT命令

    ymodem_send_pgk(EOTsignal, sizeof(EOTsignal));
    return;
}

// 接收串口函数
static void ymodem_read_uart_info(kal_uint8 *dptr, kal_uint16 data_size)
{
    kal_uint16 read_length;

    memset(dptr, 0, data_size); // 先clean存放数据的buffer,免得干扰。
    read_length = ebike_uart_read_data(dptr, data_size);
    if (0 >= read_length)
    {
        DBG("dnot read anything\n");
    }
    return;
}

// 发送第1帧
static void ymodem_send_first_pkg()
{
    kal_uint8 blockoff = (~blockon & 0xff);

    // 发送第一帧。初始化。
    memset(&ymodem_send_data_pkg, 0, sizeof(ymodem_send_data)); // clean数据帧。

    ymodem_crc_check.summary = YModemCrc(ymodem_send_data_pkg.data, sizeof(ymodem_send_data_pkg.data)); // 注意大小端。

    ymodem_send_data_pkg.total_bytes = YMODEM_CODE_SOH;
    ymodem_send_data_pkg.block_on = blockon;
    ymodem_send_data_pkg.block_off = blockoff;
    ymodem_send_data_pkg.data[UART_YMODEM_WRITE_BUFFER_LENGTH] = {UPDATA_FILE_NAME}; // 文件名与文件大小具体还需要考虑。
    ymodem_send_data_pkg.crc_h = ymodem_crc_check.crc_h_byte;
    ymodem_send_data_pkg.crc_l = ymodem_crc_check.crc_l_byte;

    // 发送第一帧
    ymodem_send_pgk((kal_uint8 *)&ymodem_send_data_pkg, sizeof(ymodem_send_data_pkg));
}

static void ymodem_send_old_pkg()
{
    ymodem_send_pgk((kal_uint8 *)&ymodem_send_data_pkg, sizeof(ymodem_send_data_pkg));
}

static void ymodem_send_new_pkg()
{
    kal_uint8 blockoff;

    blockon++;
    blockoff = (~blockon & 0xff);

    memset(ymodem_send_data_pkg.data, 0, sizeof(ymodem_send_data_pkg.data));

    ymodem_read_file();

    if (read_updata_file_info.data_filled)//数据填充完成标志位
    {
        ymodem_crc_check.summary = YModemCrc(ymodem_send_data_pkg.data, sizeof(ymodem_send_data_pkg.data));
        ymodem_send_data_pkg.block_on = blockon;
        ymodem_send_data_pkg.block_off = blockoff;
        ymodem_send_data_pkg.data = read_updata_file_info.read_buffer;
        ymodem_send_data_pkg.crc_h = ymodem_crc_check.crc_h_byte;
        ymodem_send_data_pkg.crc_l = ymodem_crc_check.crc_l_byte;
    }

    /*
    if (files_size > UART_YMODEM_WRITE_BUFFER_LENGTH)
    {
        // 判断文件是否发送完成。
        if (blockon * 128 < files_size)
        {
            // 写入:500/128=取整。

            // memset( ymodem_send_data_pkg.data, 0, sizeof( ymodem_send_data_pkg.data));
            memcpy(ymodem_send_data_pkg.data, files_ptr, UART_YMODEM_WRITE_BUFFER_LENGTH);
            ymodem_crc_check.summary = YModemCrc(ymodem_send_data_pkg.data, sizeof(ymodem_send_data_pkg.data));
            ymodem_send_data_pkg.crc_h = ymodem_crc_check.crc_h_byte;
            ymodem_send_data_pkg.crc_l = ymodem_crc_check.crc_l_byte;

            files_ptr = files_ptr + UART_YMODEM_WRITE_BUFFER_LENGTH;
        }
        else
        {

            // 写入的500%128=116,余数。写入的最后一次,可以判断为文件结束。
            memcpy(ymodem_send_data_pkg.data, files_ptr, files_size - (blockon - 1) * 128);
            ymodem_crc_check.summary = YModemCrc(ymodem_send_data_pkg.data, sizeof(ymodem_send_data_pkg.data));
            ymodem_send_data_pkg.crc_h = ymodem_crc_check.crc_h_byte;
            ymodem_send_data_pkg.crc_l = ymodem_crc_check.crc_l_byte;

            files_over_flag = KAL_TRUE;
        }
    }
    else // 文件总共字节数不足128
    {
        memcpy(ymodem_send_data_pkg.data, files_ptr, files_size);
        ymodem_crc_check.summary = YModemCrc(ymodem_send_data_pkg.data, sizeof(ymodem_send_data_pkg.data));
        ymodem_send_data_pkg.crc_h = ymodem_crc_check.crc_h_byte;
        ymodem_send_data_pkg.crc_l = ymodem_crc_check.crc_l_byte;

        files_over_flag = KAL_TRUE; 
    }
    */

    ymodem_send_pgk((kal_uint8 *)&ymodem_send_data_pkg, sizeof(ymodem_send_data_pkg));
}

static void ymodem_send_last_pkg()
{

    memset(&ymodem_send_data_pkg, 0, sizeof(ymodem_send_data)); // 清除数据帧。

    ymodem_crc_check.summary = YModemCrc(ymodem_send_data_pkg.data, sizeof(ymodem_send_data_pkg.data)); // 注意大小端。
    ymodem_send_data_pkg.total_bytes = YMODEM_CODE_SOH;
    ymodem_send_data_pkg.block_on = 0x00;
    ymodem_send_data_pkg.block_off = 0xff;
    ymodem_send_data_pkg.data[UART_YMODEM_WRITE_BUFFER_LENGTH] = {0};
    ymodem_send_data_pkg.crc_h = ymodem_crc_check.crc_h_byte;
    ymodem_send_data_pkg.crc_l = ymodem_crc_check.crc_l_byte;

    // 发送结束帧
    ymodem_send_pgk((kal_uint8 *)&ymodem_send_data_pkg, sizeof(ymodem_send_data_pkg));
}

static void ymodem_recv_signal()
{
    kal_uint16 read_length;
    kal_uint16 pre_read_signl = 0;
    kal_uint16 pre_read_old_signl = 0;

    kal_uint8 OKsignal[] = {0x4f, 0x4b}; // OK
    kal_uint8 cmp_result = 1;

    switch (status)
    {
    case STEP_0:
        ymodem_send_boot_signal();
        status = STEP_1;
        break;

    case STEP_1:
        ymodem_read_uart_info(ymodem_read_OK_signal, sizeof(ymodem_read_OK_signal));
        cmp_result = memcmp(OKsignal, ymodem_read_OK_signal, 2);
        if (cmp_result == 0) // 主机接收到的是OK。
        {
            ebike_timer_stop(boot_timer_id); // 关闭120ms发送的timer。
            ymodem_send_question_mark();
            status = STEP_2;
        }
        break;

    case STEP_2:
        ymodem_read_uart_info(ymodem_booting_read_buffer, sizeof(ymodem_booting_read_buffer)); // 接收从机发送过来的版本号厂家序列号等、
        status = STEP_3;
        break;

    case STEP_3:
        ymodem_read_uart_info(ymodem_read_buffer, sizeof(ymodem_read_buffer));
        pre_read_signl = ymodem_read_buffer[0];
        if (pre_read_signl == YMODEM_CODE_CRC)
        {
            ymodem_send_first_pkg();
            status = STEP_4;
        }
        break;

    case STEP_4:
        ymodem_read_uart_info(ymodem_read_buffer, sizeof(ymodem_read_buffer));
        pre_read_signl = ymodem_read_buffer[0];

        if (pre_read_signl == YMODEM_CODE_CAN)
        {
            return; // 结束通信
        }
        if (pre_read_signl == YMODEM_CODE_CRC || pre_read_signl == YMODEM_CODE_NAK)
        {
            // 重新发送第一帧。
            ymodem_send_first_pkg();
        }
        if (pre_read_signl == YMODEM_CODE_ACK)
        {
            pre_read_old_signl = pre_read_signl;
            status = STEP_5;
        }
        break;

    case STEP_5:
        ymodem_read_uart_info(ymodem_read_buffer, sizeof(ymodem_read_buffer));
        pre_read_signl = ymodem_read_buffer[0];
        if (pre_read_signl == YMODEM_CODE_CAN || pre_read_signl == YMODEM_CODE_ACK)
        {
            return; // 结束通信
        }
        if (pre_read_signl == YMODEM_CODE_CRC && pre_read_old_signl == YMODEM_CODE_ACK) // pre_read_old_signl这里用完后要不要fu0?
        {
            // 发送接下来的帧。
            ymodem_send_new_pkg();
            pre_read_old_signl = 0;
            status = STEP_6;
        }
        break;

    case STEP_6:
        ymodem_read_uart_info(ymodem_read_buffer, sizeof(ymodem_read_buffer));
        pre_read_signl = ymodem_read_buffer[0];

        if (pre_read_signl == YMODEM_CODE_CAN)
        {
            return;
        }
        if (pre_read_signl == YMODEM_CODE_NAK)
        {
            ymodem_send_old_pkg();
        }

        if (pre_read_signl == YMODEM_CODE_ACK)
        {
            if (read_updata_file_info.file_over)
            {

                read_updata_file_info.file_over = KAL_FALSE;
                ymodem_send_EOT();
                status = STEP_7;
            }
            else
            {
                ymodem_send_new_pkg();
                // return;
            }
        }
        break;

    case STEP_7:
        ymodem_read_uart_info(ymodem_read_buffer, sizeof(ymodem_read_buffer));
        pre_read_signl = ymodem_read_buffer[0];
        if (pre_read_signl == YMODEM_CODE_CAN)
        {
            return;
        }
        if (pre_read_signl == YMODEM_CODE_NAK)
        {
            ymodem_send_EOT();
            status = STEP_8;
        }
        break;

    case STEP_8:
        ymodem_read_uart_info(ymodem_read_buffer, sizeof(ymodem_read_buffer));
        pre_read_signl = ymodem_read_buffer[0];
        if (pre_read_signl == YMODEM_CODE_CAN)
        {
            return;
        }
        if (pre_read_signl == YMODEM_CODE_ACK)
        {
            pre_read_old_signl = pre_read_signl;
            status = STEP_9;
        }
        if (pre_read_signl == YMODEM_CODE_NAK)
        {
            ymodem_send_EOT();
        }
        break;

    case STEP_9:
        ymodem_read_uart_info(ymodem_read_buffer, sizeof(ymodem_read_buffer));
        pre_read_signl = ymodem_read_buffer[0];
        if (pre_read_signl == YMODEM_CODE_CAN)
        {
            return;
        }
        if (pre_read_signl == YMODEM_CODE_CRC && pre_read_old_signl == YMODEM_CODE_ACK)
        {
            // 发送最后一帧。
            ymodem_send_last_pkg();
            pre_read_old_signl = 0;
        }
        if (pre_read_signl == YMODEM_CODE_ACK)
            return;

        break;
    }
}

// 升级init.
void controller_upgrade()
{
    ymodem_send_boot_signal();
    ymodem_recv_signal();
}

#ifndef _YMODEM_H_
#define _YMODEM_H_

#include "kal_public_defs.h"

#pragma pack(1)
typedef enum
{
    YMODEM_CODE_NONE = 0x0,
    YMODEM_CODE_SOH = 0x01,  /* start of 128-byte data packet */
    YMODEM_CODE_STX = 0x02,  /* start of 1024-byte data packet */
    YMODEM_CODE_EOT = 0x04,  /* end of transmission */
    YMODEM_CODE_ACK = 0x06,  /* receive OK */
    YMODEM_CODE_NAK = 0x015, /* receiver error; retry */
    YMODEM_CODE_CAN = 0x018, /* two of these in succession aborts transfer */
    YMODEM_CODE_CRC = 0x43,  /* use in place of first NAK for CRC mode */
} ymodem_cmd;

typedef enum
{
    STEP_0,
    STEP_1,
    STEP_2,
    STEP_3,
    STEP_4,
    STEP_5,
    STEP_6,
    STEP_7,
    STEP_8,
    STEP_9,
} ymodem_step;

typedef struct
{
    kal_uint16 total_bytes;
    kal_uint8 block_on;
    kal_uint8 block_off;
    kal_uint8 data[128]; //
    kal_uint8 crc_h;
    kal_uint8 crc_l;
} ymodem_send_data, *ymodem_send_data_ptr;

typedef union
{
    kal_uint16 summary;

    struct
    {
        kal_uint8 crc_h_byte;
        kal_uint8 crc_l_byte;
    } check;
} ymodem_crc_chk;

#pragma pack()

void controller_upgrade();

#endif

读文件操作:(传输这个文件之前要先进行读文件大小和读文件内容)

#include "ymodem_read_file.h"

#include "fs_func.h"

#define EBIKE_YMODEM_UPDATA_PATH L"Z:\\update.bin"
#define READ_UPDATA_FILE_BUF_LENGTH 128

static FS_HANDLE file_handle = -1;
kal_uint16 *bin_file_size = NULL;
read_updata_file read_updata_file_info = {0};
int pos = 0;

void ymodem_open_file()
{

    file_handle = FS_Open(EBIKE_YMODEM_UPDATA_PATH, FS_READ_ONLY);

    if (file_handle == FS_NO_ERROR)
    {
        FS_GetFileSize(file_handle, bin_file_size);
    }
    else if (file_handle == FS_FILE_NOT_FOUND)
    {
        DBG("this uodate file dont find\n");

        FS_Close(file_handle);
        return;
    }
}
void ymodem_read_file()
{
    unsigned int *rely_read_length = NULL;

    memset(&read_updata_file_info, 0, sizeof(read_updata_file_info)); // clean数据帧。

    if (*bin_file_size - pos > 128)
    {
        FS_Seek(file_handle, pos, FS_FILE_BEGIN);
        FS_Read(file_handle, read_updata_file_info.read_buffer, READ_UPDATA_FILE_BUF_LENGTH, rely_read_length);
        pos += 128;
    }
    else
    {
        FS_Seek(file_handle, pos, FS_FILE_BEGIN);
        FS_Read(file_handle, read_updata_file_info.read_buffer, *bin_file_size - pos, rely_read_length);

        // read end.
        read_updata_file_info.file_over = KAL_TRUE;
        FS_Close(file_handle);
    }

    // if (*rely_read_length < READ_UPDATA_FILE_BUF_LENGTH)
    // {
    //     // read end.
    //     read_updata_file_info.file_over = KAL_TRUE;
    //     FS_Close(file_handle);
    // }
}

/*
读bin文件,将文件内容读到一个缓冲区,然后再发送这个缓冲区。再seek后读,在发送。

*/
#ifndef __YMODEM_READ_FILE_H__
#define __YMODEM_READ_FILE_H__

#include "kal_public_defs.h"

#pragma pack(1)
typedef struct
{
    kal_uint16 read_buffer[128];
    kal_bool file_over;
    kal_bool data_filled;
} read_updata_file;
// 文件总共大小,文件128字节的数组(这样就不需要extern这个数组了),是否文件传输结束,128填充是否完成,
#pragma pack()

void ymodem_open_file();
void ymodem_read_file();
#endif

结束:
希望接下来的事情顺利!!!!

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值