YModen协议下载实现C源码

通过串口对STM32进行程序升级,采用Y-modem 协议进行升级。

1.协议中的宏定义:

SOH (0x01)  //128字节数据包开始

STX (0x02)  //1024字节的数据包开始

EOT (0x04)  //结束传输

ACK (0x06)  //回应

NAK (0x15)  //没回应

C (0x43)  //'C' == 0x4

2.传输过程:(一般都会设计某个指令,使下位机进入0x43状态)

1)下位机进入0x43状态,表示进入开始传输状态,等待上位机发送SOH状态;

2)上位机在等待中,接受到0x43后,就发送以SOH开头的数据包开始信号,发送序号为0x00,补码0xFF,文件名、0x00,、以及文件大小,除去序号外,需要补满128个字节,CRC校验2个字节,然后进入等待0x06应答;

数据包头

数据(128个字节)

CRC校验

 

序号

补码

文件名

 

文件大小

用0x00 补齐128

2Byte

SOH

0x00

0xFF

filename

0x00

filesize

3)下位机接收到SOH并且CRC校验通过后,开始发送0x06。上位机接收到0x06后,开始正文传输,形式如下:

序号定义 : char index_h = 0x00;       补码定义:char index_t = 0xFF;

数据包头

数据(1024个字节)

CRC校验

 

序号

补码

从 bin 文件中读取的数据(读取的数据不满足1024 Byte 用0x00补齐)

2Byte

STX

index_h++

0xFF--

高位在前

4)文件传输完成后,上位机需要发送0x04结束符,通知下位机,下位机在发送0x06告知上位机,最后上位机需要发送一个全0包,通知下位机本次通信结束;全0包如下:

数据包头

数据(128个字节)

CRC校验

 

序号

补码

全0x00

2Byte

SOH

0x00

0xFF

高位在前

 

下面就直接贴代码:比较粗糙

 

#define CONNECT_FLAG      0x43
#define PACKAGE_NULL      0x00
#define PACKAGE_SOH       0x01
#define PACKAGE_STX       0x02
#define PACKAGE_ETX       0x03
#define PACKAGE_EOT       0x04
#define PACKAGE_ACK       0x06
/*********************************************************************
*函数名称:ComputeCRC(byte[] bufDate)
*函数功能:CRC校验函数
*参    数:bufDate 传送的数据
*返 回 值:CRC校验值
**********************************************************************/
short ComputeCRC(unsigned char *bufDate, unsigned int len)
{
   short cksum = 0;
   int i, j = 0;

   for(i = 0; i < len; i++)
   {
      cksum = cksum ^ bufDate[i] << 8;
      for(j = 8; j != 0; j--)
      {
         if ((cksum & 0x8000) != 0)
            cksum = (cksum << 1 ^ 0x1021);
         else
            cksum = (cksum << 1);
      }
   }
   return cksum;
}
/********************************************************************* 
*函数名称:DownLoad(const char *path, const char *name)
*函数功能:下载函数 
*参 数:path 文件路径    name  文件名
*返 回 值:
**********************************************************************/


int DownLoad(const char *path, const char *name)
{
   unsigned char rbuf[2];
   unsigned char data[2048];
   unsigned char WriteBuf[1200];
   unsigned char readBuf[1200];
   unsigned char NameBuf[100];
   unsigned char buf[10];
   unsigned char crc_dat[2];

   unsigned long filesize = 0;
   long cyc_res = 0;
   long cyc_remain = 0;
   int i = 0;
   int crc;

   FILE *fp;

   char index_h = 0x00;
   char index_t = 0xFF;

   memcpy(NameBuf, name, strlen(name));

   filesize = get_file_size(path);

   fp = fopen(path, "rb");

   if(NULL == fp)
   {
      return -1;
   }

   cyc_res = filesize / 1024;        //文件大小,决定循环次数
   cyc_remain = filesize % 1024;     //决定是否不满1024,要补齐1024
   memset(WriteBuf, 0x00, 1200);
   memset(data, 0, 2048);

   while(1) {
        UhfUartDataRst();
        for (i = 0; i < 1000; i++) {                        //是否超时
            receive_serial_bytes(rbuf, 1, uhf_uart_fd);     //从缓存中获取一个字节

            if (CONNECT_FLAG == rbuf[0]) {                  //检验是否进入等待
                flg++;
                if (5 == flg) {
                    flg = 0;
                    break;
                }
            }
        }
        usleep(200000);                                   //预留下位机的响应时间
        receive_serial_bytes(rbuf, 1, uhf_uart_fd);

        if (CONNECT_FLAG == rbuf[0])                             //接收对接口令0x43
        {
            UhfUartDataRst();
            //memcpy(WriteBuf, name, strlen(name));               //数据包的文件名
            for (i = 0; i < strlen(name); i++) {
                WriteBuf[i] = NameBuf[i];
            }
            WriteBuf[strlen(name)] = PACKAGE_NULL;              //协议要求0x00

            sprintf(&WriteBuf[strlen(name) + 1], "%d", filesize); //数据包的文件大小

            crc = ComputeCRC(WriteBuf, 128);
            crc_dat[1] = crc >> 8;
            crc_dat[0] = crc & 0xFF;

            data[0] = PACKAGE_SOH;                              //数据头
            data[1] = index_h++;
            data[2] = index_t--;

            for (i = 0; i < 128; i++) {
                data[3 + i] = WriteBuf[i];
            }

            for (i = 0; i < 2; i++) {
                data[131 + i] = crc_dat[i];
            }

            SendCommand_R2000(data, 133);                   // 发送第一包数据包

            while (res < cyc_res) {
                usleep(200000);
                if (receive_serial_bytes(rbuf, 1, uhf_uart_fd) != 0) {
                    memset(readBuf, 0, 1200);
                    memset(data, 0, 2048);
                    if (PACKAGE_ACK == rbuf[0])             //等待接收方0x06的应答
                    {
                        fread(readBuf, 1024, 1, fp);
                        crc = ComputeCRC(readBuf, 1024);

                        crc_dat[1] = crc >> 8;
                        crc_dat[0] = crc & 0xFF;

                        data[0] = PACKAGE_STX;                           //协议头
                        data[1] = index_h++;
                        data[2] = index_t--;

                        for (i = 0; i < 1024; i++)                           //组包
                        {
                            data[3 + i] = readBuf[i];
                        }

                        for (i = 0; i < 2; i++) {
                            data[1027 + i] = crc_dat[i];
                        }

                        SendCommand_R2000(data, 1029);                    //正文数据包开始发送
                        res++;
                        for(i = 0; i < 100; i++){}
                    }
                }
            }

     //如果最后不够1024字节,后面补00,凑够1024个字节

            if (cyc_remain > 0)
            {
                usleep(200000);
                receive_serial_bytes(rbuf, 1, uhf_uart_fd);

                if (PACKAGE_ACK == rbuf[0])             //等待接收方0x06的应答
                {
                    memset(readBuf, 0, 1200);
                    memset(data, 0, 2048);
                    fread(readBuf, 1024, 1, fp);

                    crc = ComputeCRC(readBuf, 1024);
                    crc_dat[1] = crc >> 8;
                    crc_dat[0] = crc & 0xFF;

                    data[0] = PACKAGE_STX;                           //协议头
                    data[1] = index_h++;
                    data[2] = index_t--;

                    for (i = 0; i < 1024; i++)                           //组包
                    {
                        data[3 + i] = readBuf[i];
                    }
                    for (i = 0; i < 2; i++)
                    {
                        data[1027 + i] = crc_dat[i];
                    }

                    SendCommand_R2000(data, 1029);                    //数据包开始发送
                }

                buf[0] = PACKAGE_EOT;
                SendCommand_R2000(buf, 1);
                usleep(200000);
                receive_serial_bytes(rbuf, 1, uhf_uart_fd);

                if (PACKAGE_ACK == rbuf[0])
                {
                    unsigned char endbuf[128];
                    memset(endbuf, 0x00, 128);
                    data[0] = PACKAGE_SOH;                           //协议头
                    data[1] = 0x00;
                    data[2] = 0xff;

                    for (i = 0; i < 128; i++)                           //组包
                    {
                        data[3 + i] = endbuf[i];
                    }
                    crc = ComputeCRC(WriteBuf, 128);                         //传输数据的CRC值
                    crc_dat[1] = crc >> 8;
                    crc_dat[0] = crc & 0xFF;

                    for (i = 0; i < 2; i++)
                    {
                        data[131 + i] = crc_dat[i];
                    }

                    SendCommand_R2000(data, 133);                    //数据包开始发送
                    buf[0] = PACKAGE_EOT;
                    SendCommand_R2000(buf, 1);
                    usleep(200000);
                    receive_serial_bytes(rbuf, 1, uhf_uart_fd);

                    if (PACKAGE_ACK == rbuf[0])
                    {
                        buf[0] = PACKAGE_EOT;
                        SendCommand_R2000(buf, 1);
                    }
                    res = 0;
                    fclose(fp);

                    break;
                }
            }
            else
            {
                buf[0] = PACKAGE_EOT;
                SendCommand_R2000(buf, 1);
                usleep(200000);
                receive_serial_bytes(rbuf, 1, uhf_uart_fd);
                if(PACKAGE_ACK == rbuf[0])
                {
                    unsigned char endbuf[128];
                    memset(endbuf, 0x00, 128);
                    data[0] = PACKAGE_SOH;                           //协议头
                    data[1] = 0x00;
                    data[2] = 0xff;

                    for (i = 0; i < 128; i++)                           //组包
                    {
                        data[3 + i] = endbuf[i];
                    }
                    crc = ComputeCRC(WriteBuf, 128);                         //传输数据的CRC值
                    crc_dat[1] = crc >> 8;
                    crc_dat[0] = crc & 0xFF;

                    for (i = 0; i < 2; i++) {
                        data[131 + i] = crc_dat[i];
                    }

                    SendCommand_R2000(data, 133);                    //第一包数据包开始发送
                    res = 0;
                    fclose(fp);
                    break;
                }

            }
        }
    }
   return 1;
}

 

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
源码是经过本地编译可运行的,下载完成之后配置相应环境即可使用。源码功能都是经过老师肯定的,都能满足要求,有需要放心下载即可。源码是经过本地编译可运行的,下载完成之后配置相应环境即可使用。源码功能都是经过老师肯定的,都能满足要求,有需要放心下载即可。源码是经过本地编译可运行的,下载完成之后配置相应环境即可使用。源码功能都是经过老师肯定的,都能满足要求,有需要放心下载即可。源码是经过本地编译可运行的,下载完成之后配置相应环境即可使用。源码功能都是经过老师肯定的,都能满足要求,有需要放心下载即可。源码是经过本地编译可运行的,下载完成之后配置相应环境即可使用。源码功能都是经过老师肯定的,都能满足要求,有需要放心下载即可。源码是经过本地编译可运行的,下载完成之后配置相应环境即可使用。源码功能都是经过老师肯定的,都能满足要求,有需要放心下载即可。源码是经过本地编译可运行的,下载完成之后配置相应环境即可使用。源码功能都是经过老师肯定的,都能满足要求,有需要放心下载即可。源码是经过本地编译可运行的,下载完成之后配置相应环境即可使用。源码功能都是经过老师肯定的,都能满足要求,有需要放心下载即可。源码是经

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

KingOTC

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

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

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

打赏作者

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

抵扣说明:

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

余额充值