关于stm的串口boot使用完善ymodem协议,以及xshell终端结束

通过研究stm的ymodem协议,发现EOT之后直接就进行ACK回复确认了,没有进行NAK反复确认

所以具体需要修改:

主要是修改Ymodem_Receive函数

首先EOT 之后 直接默认结束传输,所以将ACK修改为NAK

最后在该函数的最后,模拟再次ACK C确认

然后接收一包结束帧,再回复ACK确认

注意:如果是xshell等终端需要再发送一个结束,提示ymodem协议结束

添加基础的注释,便于理解,目前代码还没整理完成,先暂时不上传了,只是上传官方的标准库

链接:https://pan.baidu.com/s/1Y4jVoSSPUTceuIA-O6X6Fg
提取码:n0kw
--来自百度网盘超级会员V4的分享

 /**
   * @brief  使用ymodem接受一个文件
   * @param  buf: 第一个字节的地址.
   * @retval 文件的大小.
   */
 LONG Ymodem_Receive (UCHAR *buf)
 {
    UCHAR packet_data[PACKET_1K_SIZE + PACKET_OVERHEAD], file_size[FILE_SIZE_LENGTH], *file_ptr, *buf_ptr;
    LONG i, packet_length, session_done, file_done, packets_received, errors, session_begin, size = 0;
    ULONG flashdestination, ramsource;
    ULONG t = 0;
    UCHAR c = 0;
 
    /* 初始化flash地址 */
    flashdestination = APPLICATION_ADDRESS;
 
    for (session_done = 0, errors = 0, session_begin = 0; ;)
    {
        for (packets_received = 0, file_done = 0, buf_ptr = buf; ;)
        {
            switch (Receive_Packet(packet_data, &packet_length, NAK_TIMEOUT))
            {
                /* 如果接收成功 */
                case 0:
                {
                    /* 错误标志清零 */
                    errors = 0;
                    switch (packet_length)
                    {
                        /* 被发送者终止 */
                        case - 1:
                        {
                            Send_Byte(ACK);
                            return 0;
                        }
                        /* 结束传输 */
                        case 0:
                        {
                            /* 修改该地方 */
                            Send_Byte(NAK);
                            file_done = 1;
                            break;
                        }
                        default:
                            /* 正常包 */
                            if ((packet_data[PACKET_SEQNO_INDEX] & 0xff) != (packets_received & 0xff))
                            {
                                Send_Byte(NAK);
                            }
                            else
                            {
                            /* 如果是第一个起始帧 */
                            if (packets_received == 0)
                            {
                                /* 文件名字包 */
                                if (packet_data[PACKET_HEADER] != 0)
                                {
                                    /* file_ptr+3 因为前三个字节是首部 再就是文件名字 */
                                    for (i = 0, file_ptr = packet_data + PACKET_HEADER; (*file_ptr != 0) && (i < FILE_NAME_LENGTH);)
                                    {
                                        FileName[i++] = *file_ptr++;
                                    }
                                    /* 获取到的文件名字字符串 */
                                    FileName[i++] = '\0';

                                    /* 文件名字之后紧接着就是文件大小 */
                                    for (i = 0, file_ptr ++; (*file_ptr != ' ') && (i < FILE_SIZE_LENGTH);)
                                    {
                                        file_size[i++] = *file_ptr++;
                                    }
                                    file_size[i++] = '\0';
                                    /* 将文件大小转换为字符串 */
                                    Str2Int(file_size, &size);

                                    /* 检测被发送镜像bin文件的大小 */
                                    /* 如果镜像bin文件比flash大 */
                                    if (size > (USER_FLASH_SIZE + 1))
                                    {
                                        /* End session */
                                        Send_Byte(CA);
                                        Send_Byte(CA);

                                        /*debug 文件太大 flash太小 没有合适的空间 */
                                        return -1;
                                    }
                                    /* 擦除flash */
                                    FLASH_If_Erase(APPLICATION_ADDRESS);
                                    Send_Byte(ACK);


                                    /* 收到第起始帧后立马回应 发送c */
                                    Send_Byte(CRC16);
                                    }
                                    /* 文件名字包为空,结束传输 */
                                    else
                                    {
                                        Send_Byte(ACK);
                                        file_done = 1;
                                        session_done = 1;
                                        break;
                                    }
                            }
                            /* 数据帧 */
                            else
                            {
                                /* 拷贝当前的数据 */
                                memcpy(buf_ptr, packet_data + PACKET_HEADER, packet_length);
                                ramsource = (ULONG)buf;

                                /* 往flash里边写数据 packet_length/4的原因是一个字占4个字节 */
                                if (FLASH_If_Write(&flashdestination, (ULONG *) ramsource, (USHORT) packet_length/4)  == 0)
                                {
                                    Send_Byte(ACK);
                                }
                                else /* 当往flash写的时候,出现错误 */
                                {
                                    /* 结束传输 */
                                    Send_Byte(CA);
                                    Send_Byte(CA);
                                    return -2;
                                }
                            }
                        packets_received ++;
                        session_begin = 1;
                    }
                }
                break;
            }
            case 1:
            {
                Send_Byte(CA);
                Send_Byte(CA);
                return -3;
            }
            default:
            {
                if (session_begin > 0)
                {
                    errors ++;
                }
                if (errors > MAX_ERRORS)
                {
                    Send_Byte(CA);
                    Send_Byte(CA);
                    return 0;
                }
                Send_Byte(CRC16);
                break;
            }
        }
        if (file_done != 0)
        {
            break;
        }
        }
        if (session_done != 0)
        {
            break;
        }
    }
    Send_Byte(ACK);
    Send_Byte(CRC16);
    /* 最后接收结束帧 该帧其实不管对错 都已经传输完成 */
    Receive_Packet(packet_data, &packet_length, NAK_TIMEOUT);
    Send_Byte(ACK);

    return (LONG)size;
}

版权声明:本文为CSDN博主「IT小生lkc」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_20017379/article/details/122768524

通过研究stm的ymodem协议,发现EOT之后直接就进行ACK回复确认了,没有进行NAK反复确认

所以具体需要修改:

主要是修改Ymodem_Receive函数

首先EOT 之后 直接默认结束传输,所以将ACK修改为NAK

最后在该函数的最后,模拟再次ACK C确认

然后接收一包结束帧,再回复ACK确认

注意:如果是xshell等终端需要再发送一个结束,提示ymodem协议结束

添加基础的注释,便于理解,目前代码还没整理完成,先暂时不上传了,只是上传官方的标准库

链接:https://pan.baidu.com/s/1Y4jVoSSPUTceuIA-O6X6Fg
提取码:n0kw
--来自百度网盘超级会员V4的分享

 /**
   * @brief  使用ymodem接受一个文件
   * @param  buf: 第一个字节的地址.
   * @retval 文件的大小.
   */
 LONG Ymodem_Receive (UCHAR *buf)
 {
    UCHAR packet_data[PACKET_1K_SIZE + PACKET_OVERHEAD], file_size[FILE_SIZE_LENGTH], *file_ptr, *buf_ptr;
    LONG i, packet_length, session_done, file_done, packets_received, errors, session_begin, size = 0;
    ULONG flashdestination, ramsource;
    ULONG t = 0;
    UCHAR c = 0;
 
    /* 初始化flash地址 */
    flashdestination = APPLICATION_ADDRESS;
 
    for (session_done = 0, errors = 0, session_begin = 0; ;)
    {
        for (packets_received = 0, file_done = 0, buf_ptr = buf; ;)
        {
            switch (Receive_Packet(packet_data, &packet_length, NAK_TIMEOUT))
            {
                /* 如果接收成功 */
                case 0:
                {
                    /* 错误标志清零 */
                    errors = 0;
                    switch (packet_length)
                    {
                        /* 被发送者终止 */
                        case - 1:
                        {
                            Send_Byte(ACK);
                            return 0;
                        }
                        /* 结束传输 */
                        case 0:
                        {
                            /* 修改该地方 */
                            Send_Byte(NAK);
                            file_done = 1;
                            break;
                        }
                        default:
                            /* 正常包 */
                            if ((packet_data[PACKET_SEQNO_INDEX] & 0xff) != (packets_received & 0xff))
                            {
                                Send_Byte(NAK);
                            }
                            else
                            {
                            /* 如果是第一个起始帧 */
                            if (packets_received == 0)
                            {
                                /* 文件名字包 */
                                if (packet_data[PACKET_HEADER] != 0)
                                {
                                    /* file_ptr+3 因为前三个字节是首部 再就是文件名字 */
                                    for (i = 0, file_ptr = packet_data + PACKET_HEADER; (*file_ptr != 0) && (i < FILE_NAME_LENGTH);)
                                    {
                                        FileName[i++] = *file_ptr++;
                                    }
                                    /* 获取到的文件名字字符串 */
                                    FileName[i++] = '\0';

                                    /* 文件名字之后紧接着就是文件大小 */
                                    for (i = 0, file_ptr ++; (*file_ptr != ' ') && (i < FILE_SIZE_LENGTH);)
                                    {
                                        file_size[i++] = *file_ptr++;
                                    }
                                    file_size[i++] = '\0';
                                    /* 将文件大小转换为字符串 */
                                    Str2Int(file_size, &size);

                                    /* 检测被发送镜像bin文件的大小 */
                                    /* 如果镜像bin文件比flash大 */
                                    if (size > (USER_FLASH_SIZE + 1))
                                    {
                                        /* End session */
                                        Send_Byte(CA);
                                        Send_Byte(CA);

                                        /*debug 文件太大 flash太小 没有合适的空间 */
                                        return -1;
                                    }
                                    /* 擦除flash */
                                    FLASH_If_Erase(APPLICATION_ADDRESS);
                                    Send_Byte(ACK);


                                    /* 收到第起始帧后立马回应 发送c */
                                    Send_Byte(CRC16);
                                    }
                                    /* 文件名字包为空,结束传输 */
                                    else
                                    {
                                        Send_Byte(ACK);
                                        file_done = 1;
                                        session_done = 1;
                                        break;
                                    }
                            }
                            /* 数据帧 */
                            else
                            {
                                /* 拷贝当前的数据 */
                                memcpy(buf_ptr, packet_data + PACKET_HEADER, packet_length);
                                ramsource = (ULONG)buf;

                                /* 往flash里边写数据 packet_length/4的原因是一个字占4个字节 */
                                if (FLASH_If_Write(&flashdestination, (ULONG *) ramsource, (USHORT) packet_length/4)  == 0)
                                {
                                    Send_Byte(ACK);
                                }
                                else /* 当往flash写的时候,出现错误 */
                                {
                                    /* 结束传输 */
                                    Send_Byte(CA);
                                    Send_Byte(CA);
                                    return -2;
                                }
                            }
                        packets_received ++;
                        session_begin = 1;
                    }
                }
                break;
            }
            case 1:
            {
                Send_Byte(CA);
                Send_Byte(CA);
                return -3;
            }
            default:
            {
                if (session_begin > 0)
                {
                    errors ++;
                }
                if (errors > MAX_ERRORS)
                {
                    Send_Byte(CA);
                    Send_Byte(CA);
                    return 0;
                }
                Send_Byte(CRC16);
                break;
            }
        }
        if (file_done != 0)
        {
            break;
        }
        }
        if (session_done != 0)
        {
            break;
        }
    }
    Send_Byte(ACK);
    Send_Byte(CRC16);
    /* 最后接收结束帧 该帧其实不管对错 都已经传输完成 */
    Receive_Packet(packet_data, &packet_length, NAK_TIMEOUT);
    Send_Byte(ACK);

    return (LONG)size;
}

版权声明:本文为CSDN博主「IT小生lkc」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_20017379/article/details/122768524

生成海报
点赞 0

IT小生lkc

我还没有学会写个人说明!

暂无评论

发表评论

相关推荐