** 文件名: ymodem.c
** 版本: 1.0
** 工作环境: RealView MDK-ARM 4.14
** 生成日期: 2011-04-29
** 功能: 和Ymodem.c的相关的协议文件
负责从超级终端接收数据(使用Ymodem协议),并将数据加载到内部RAM中。
如果接收数据正常,则将数据编程到Flash中;如果发生错误,则提示出错。
** 相关文件: stm32f10x.h
** 修改日志: 2011-04-29 创建文档
*******************************************************************************/
/* 包含头文件 *****************************************************************/
#if 1
#include "ymodem.h"
#include "stm32f10x.h"
#include "stm32f10x_conf.h"
#include "ff.h" /* FatFs configurations and declarations */
#include "diskio.h" /* Declarations of low level disk I/O functions */
#include "usart.h"
#include <string.h>
#include <stdio.h>
#define ApplicationAddress 0
#define PAGE_SIZE (0x400) /* 1 Kbyte */
#define FLASH_SIZE (0x20000) /* 128 KBytes */
//计算上传文件大小
#define FLASH_IMAGE_SIZE (u32) (FLASH_SIZE - (ApplicationAddress - 0x08000000))
#define IS_AF(c) ((c >= 'A') && (c <= 'F'))
#define IS_af(c) ((c >= 'a') && (c <= 'f'))
#define IS_09(c) ((c >= '0') && (c <= '9'))
#define ISVALIDHEX(c) IS_AF(c) || IS_af(c) || IS_09(c)
#define ISVALIDDEC(c) IS_09(c)
#define CONVERTDEC(c) (c - '0')
#define CONVERTHEX_alpha(c) (IS_AF(c) ? (c - 'A'+10) : (c - 'a'+10))
#define CONVERTHEX(c) (IS_09(c) ? (c - '0') : CONVERTHEX_alpha(c))
#define SerialPutString(x) Serial_PutString((u8*)(x))
/* 变量声明 -----------------------------------------------------------------*/
u8 file_name[FILE_NAME_LENGTH];
u8 file_type[FILE_TYPE];
//用户程序Flash偏移
u32 FlashDestination = ApplicationAddress;
u16 PageSize = PAGE_SIZE;
u32 EraseCounter = 0x0;
u32 NbrOfPage = 0;
FLASH_Status FLASHStatus = FLASH_COMPLETE;
u32 RamSource;
u8 tab_1024[1024];
static u8 packet_data[PACKET_1K_SIZE + PACKET_OVERHEAD];
static u8 file_size[FILE_SIZE_LENGTH];
FIL bmpfsrc;
extern UINT br,bw;
void Int2Str(u8* str, s32 intnum)
{
u32 i, Div = 1000000000, j = 0, Status = 0;
for (i = 0; i < 10; i++)
{
str[j++] = (intnum / Div) + 48;
intnum = intnum % Div;
Div /= 10;
if ((str[j-1] == '0') & (Status == 0))
{
j = 0;
}
else
{
Status++;
}
}
}
uint32_t Str2Int(u8 *inputstr, s32 *intnum)
{
u32 i = 0, res = 0;
u32 val = 0;
if (inputstr[0] == '0' && (inputstr[1] == 'x' || inputstr[1] == 'X'))
{
if (inputstr[2] == '\0')
{
return 0;
}
for (i = 2; i < 11; i++)
{
if (inputstr[i] == '\0')
{
*intnum = val;
//返回1
res = 1;
break;
}
if (ISVALIDHEX(inputstr[i]))
{
val = (val << 4) + CONVERTHEX(inputstr[i]);
}
else
{
//无效输入返回0
res = 0;
break;
}
}
if (i >= 11)
{
res = 0;
}
}
else//最多10为2输入
{
for (i = 0; i < 11; i++)
{
if (inputstr[i] == '\0')
{
*intnum = val;
//返回1
res = 1;
break;
}
else if ((inputstr[i] == 'k' || inputstr[i] == 'K') && (i > 0))
{
val = val << 10;
*intnum = val;
res = 1;
break;
}
else if ((inputstr[i] == 'm' || inputstr[i] == 'M') && (i > 0))
{
val = val << 20;
*intnum = val;
res = 1;
break;
}
else if (ISVALIDDEC(inputstr[i]))
{
val = val * 10 + CONVERTDEC(inputstr[i]);
}
else
{
//无效输入返回0
res = 0;
break;
}
}
//超过10位无效,返回0
if (i >= 11)
{
res = 0;
}
}
return res;
}
u32 FLASH_PagesMask(__IO u32 Size)
{
u32 pagenumber = 0x0;
u32 size = Size;
if ((size % PAGE_SIZE) != 0)
{
pagenumber = (size / PAGE_SIZE) + 1;
}
else
{
pagenumber = size / PAGE_SIZE;
}
return pagenumber;
}
void Serial_PutString(u8 *s)
{
while (*s != '\0')
{
SerialPutChar(*s);
s++;
}
}
u32 SerialKeyPressed(uint8_t *key)
{
if ( USART_GetFlagStatus(USART1, USART_FLAG_RXNE) != RESET)
{
*key = (u8)USART1->DR;
return 1;
}
else
{
return 0;
}
}
u8 GetKey(void)
{
u8 key = 0;
//等待按键按下
while (1)
{
if (SerialKeyPressed( (u8*)&key) )
break;
}
return key;
}
/*******************************************************************************
* @函数名称 Receive_Byte
* @函数说明 从发送端接收一个字节
* @输入参数 c: 接收字符
timeout: 超时时间
* @输出参数 无
* @返回参数 接收的结果
0:成功接收
1:时间超时
*******************************************************************************/
static s32 Receive_Byte (u8 *c, u32 timeout)
{
while (timeout-- > 0)
{
if (SerialKeyPressed(c) == 1)
{
return 0;
}
}
return -1;
}
/*******************************************************************************
* @函数名称 Send_Byte
* @函数说明 发送一个字符
* @输入参数 c: 发送的字符
* @输出参数 无
* @返回参数 发送的结果
0:成功发送
*******************************************************************************/
static u32 Send_Byte (u8 c)
{
SerialPutChar(c);
return 0;
}
/*******************************************************************************
* @函数名称 Receive_Packet
* @函数说明 从发送端接收一个数据包
* @输入参数 data :数据指针
length:长度
timeout :超时时间
* @输出参数 无
* @返回参数 接收的结果
0: 正常返回
-1: 超时或者数据包错误
1: 用户取消
*******************************************************************************/
static s32 Receive_Packet (u8 *data, s32 *length, u32 timeout)
{
u16 i, packet_size;
u8 c;
*length = 0;
if (Receive_Byte(&c, timeout) != 0)
{
return -1;
}
switch (c)
{
case SOH:
packet_size = PACKET_SIZE;
break;
case STX:
packet_size = PACKET_1K_SIZE;
break;
case EOT:
return 0;
case CA:
if ((Receive_Byte(&c, timeout) == 0) && (c == CA))
{
*length = -1;
return 0;
}
else
{
return -1;
}
case ABORT1:
case ABORT2:
return 1;
default:
return -1;
}
*data = c;
for (i = 1; i < (packet_size + PACKET_OVERHEAD); i ++)
{
if (Receive_Byte(data + i, timeout) != 0)
{
return -1;
}
}
if (data[PACKET_SEQNO_INDEX] != ((data[PACKET_SEQNO_COMP_INDEX] ^ 0xff) & 0xff))
{
return -1;
}
*length = packet_size;
return 0;
}
/*******************************************************************************
* @函数名称 Ymodem_Receive
* @函数说明 通过 ymodem协议接收一个文件
* @输入参数 buf: 首地址指针
* @输出参数 无
* @返回参数 文件长度
*******************************************************************************/
s32 Ymodem_Receive (u8 *buf)
{
//u8 packet_data[PACKET_1K_SIZE + PACKET_OVERHEAD], file_size[FILE_SIZE_LENGTH],
u8 *file_ptr, *buf_ptr;
s32 i, j, packet_length, session_done, file_done, packets_received, errors, session_begin, size = 0;
FRESULT result;
//初始化Flash地址变量
FlashDestination = ApplicationAddress;
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(ACK);
file_done = 1;
size=2;
///f_lseek(&bmpfsrc,f_size(&bmpfsrc));
f_close(&bmpfsrc );
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)
{
//文件名数据包有效数据区域
for (i = 0, file_ptr = packet_data + PACKET_HEADER; (*file_ptr != 0) && (i < FILE_NAME_LENGTH);)
{
file_name[i++] = *file_ptr++;
}
file_name[i++] = '\0';
result = f_open(&bmpfsrc, file_name, FA_OPEN_ALWAYS | FA_WRITE);
///f_lseek(&bmpfsrc,f_size(&bmpfsrc));
//f_close(&bmpfsrc);
f_sync(&bmpfsrc);
Send_Byte(ACK);
Send_Byte(CRC16);
}
//文件名数据包空,结束传输
else
{
Send_Byte(ACK);
file_done = 1;
session_done = 1;
break;
}
}
//数据包
else
{
memcpy(buf_ptr, packet_data + PACKET_HEADER, packet_length);
if(packet_length>512){
result=f_write(&bmpfsrc,buf_ptr,512,&br);
result=f_lseek(&bmpfsrc,f_size(&bmpfsrc));
result=f_write(&bmpfsrc,buf_ptr+512,packet_length-512,&br);
result=f_lseek(&bmpfsrc,f_size(&bmpfsrc));
}
else{
result=f_write(&bmpfsrc,buf_ptr,packet_length,&br);
result=f_lseek(&bmpfsrc,f_size(&bmpfsrc));
}
///f_close(&bmpfsrc );
f_sync(&bmpfsrc);
Send_Byte(ACK);
}
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;
}
}
return (s32)size;
}
/*******************************************************************************
* @函数名称 Ymodem_CheckResponse
* @函数说明 通过 ymodem协议检测响应
* @输入参数 c
* @输出参数 无
* @返回参数 0
*******************************************************************************/
s32 Ymodem_CheckResponse(u8 c)
{
return 0;
}
/*******************************************************************************
* @函数名称 Ymodem_PrepareIntialPacket
* @函数说明 准备第一个数据包
* @输入参数 data:数据包
fileName :文件名
length :长度
* @输出参数 无
* @返回参数 无
*******************************************************************************/
void Ymodem_PrepareIntialPacket(u8 *data, const u8* fileName, u32 *length)
{
u16 i, j;
u8 file_ptr[10];
//制作头3个数据包
data[0] = SOH;
data[1] = 0x00;
data[2] = 0xff;
//文件名数据包有效数据
for (i = 0; (fileName[i] != '\0') && (i < FILE_NAME_LENGTH); i++)
{
data[i + PACKET_HEADER] = fileName[i];
}
data[i + PACKET_HEADER] = 0x00;
Int2Str (file_ptr, *length);
for (j =0, i = i + PACKET_HEADER + 1; file_ptr[j] != '\0' ; )
{
data[i++] = file_ptr[j++];
}
for (j = i; j < PACKET_SIZE + PACKET_HEADER; j++)
{
data[j] = 0;
}
}
/*******************************************************************************
* @函数名称 Ymodem_PreparePacket
* @函数说明 准备数据包
* @输入参数 SourceBuf:数据源缓冲
data:数据包
pktNo :数据包编号
sizeBlk :长度
* @输出参数 无
* @返回参数 无
*******************************************************************************/
void Ymodem_PreparePacket(u8 *SourceBuf, u8 *data, u8 pktNo, u32 sizeBlk)
{
u16 i, size, packetSize;
u8* file_ptr;
//制作头3个数据包
packetSize = sizeBlk >= PACKET_1K_SIZE ? PACKET_1K_SIZE : PACKET_SIZE;
size = sizeBlk < packetSize ? sizeBlk :packetSize;
if (packetSize == PACKET_1K_SIZE)
{
data[0] = STX;
}
else
{
data[0] = SOH;
}
data[1] = pktNo;
data[2] = (~pktNo);
file_ptr = SourceBuf;
//文件名数据包有效数据
for (i = PACKET_HEADER; i < size + PACKET_HEADER; i++)
{
data[i] = *file_ptr++;
}
if ( size <= packetSize)
{
for (i = size + PACKET_HEADER; i < packetSize + PACKET_HEADER; i++)
{
data[i] = 0x1A; //结束
}
}
}
/*******************************************************************************
* @函数名称 UpdateCRC16
* @函数说明 更新输入数据的CRC校验
* @输入参数 crcIn
byte
* @输出参数 无
* @返回参数 CRC校验值
*******************************************************************************/
u16 UpdateCRC16(u16 crcIn, u8 byte)
{
u32 crc = crcIn;
u32 in = byte|0x100;
do
{
crc <<= 1;
in <<= 1;
if (in&0x100)
++crc;
if (crc&0x10000)
crc ^= 0x1021;
}
while (!(in&0x10000));
return crc&0xffffu;
}
/*******************************************************************************
* @函数名称 UpdateCRC16
* @函数说明 更新输入数据的CRC校验
* @输入参数 data :数据
size :长度
* @输出参数 无
* @返回参数 CRC校验值
*******************************************************************************/
u16 Cal_CRC16(const u8* data, u32 size)
{
u32 crc = 0;
const u8* dataEnd = data+size;
while (data<dataEnd)
crc = UpdateCRC16(crc,*data++);
crc = UpdateCRC16(crc,0);
crc = UpdateCRC16(crc,0);
return crc&0xffffu;
}
/*******************************************************************************
* @函数名称 CalChecksum
* @函数说明 计算YModem数据包的总大小
* @输入参数 data :数据
size :长度
* @输出参数 无
* @返回参数 数据包的总大小
*******************************************************************************/
u8 CalChecksum(const u8* data, u32 size)
{
u32 sum = 0;
const u8* dataEnd = data+size;
while (data < dataEnd )
sum += *data++;
return sum&0xffu;
}
/*******************************************************************************
* @函数名称 Ymodem_SendPacket
* @函数说明 通过ymodem协议传输一个数据包
* @输入参数 data :数据地址指针
length:长度
* @输出参数 无
* @返回参数 无
*******************************************************************************/
#if 0
void Ymodem_SendPacket(u8 *data, u16 length)
{
u16 i;
i = 0;
while (i < length)
{
Send_Byte(data[i]);
i++;
}
}
/*******************************************************************************
* @函数名称 Ymodem_Transmit
* @函数说明 通过ymodem协议传输一个文件
* @输入参数 buf :数据地址指针
sendFileName :文件名
sizeFile:文件长度
* @输出参数 无
* @返回参数 是否成功
0:成功
*******************************************************************************/
u8 Ymodem_Transmit (u8 *buf, const u8* sendFileName, u32 sizeFile)
{
u8 packet_data[PACKET_1K_SIZE + PACKET_OVERHEAD];
u8 FileName[FILE_NAME_LENGTH];
u8 *buf_ptr, tempCheckSum ;
u16 tempCRC, blkNumber;
u8 receivedC[2], CRC16_F = 0, i;
u32 errors, ackReceived, size = 0, pktSize;
errors = 0;
ackReceived = 0;
for (i = 0; i < (FILE_NAME_LENGTH - 1); i++)
{
FileName[i] = sendFileName[i];
}
CRC16_F = 1;
//准备第一个数据包
Ymodem_PrepareIntialPacket(&packet_data[0], FileName, &sizeFile);
do
{
//发送数据包
Ymodem_SendPacket(packet_data, PACKET_SIZE + PACKET_HEADER);
//发送CRC校验
if (CRC16_F)
{
tempCRC = Cal_CRC16(&packet_data[3], PACKET_SIZE);
Send_Byte(tempCRC >> 8);
Send_Byte(tempCRC & 0xFF);
}
else
{
tempCheckSum = CalChecksum (&packet_data[3], PACKET_SIZE);
Send_Byte(tempCheckSum);
}
//等待响应
if (Receive_Byte(&receivedC[0], 10000) == 0)
{
if (receivedC[0] == ACK)
{
//数据包正确传输
ackReceived = 1;
}
}
else
{
errors++;
}
} while (!ackReceived && (errors < 0x0A));
if (errors >= 0x0A)
{
return errors;
}
buf_ptr = buf;
size = sizeFile;
blkNumber = 0x01;
//1024字节的数据包发送
while (size)
{
//准备下一个数据包
Ymodem_PreparePacket(buf_ptr, &packet_data[0], blkNumber, size);
ackReceived = 0;
receivedC[0]= 0;
errors = 0;
do
{
//发送下一个数据包
if (size >= PACKET_1K_SIZE)
{
pktSize = PACKET_1K_SIZE;
}
else
{
pktSize = PACKET_SIZE;
}
Ymodem_SendPacket(packet_data, pktSize + PACKET_HEADER);
//发送CRC校验
if (CRC16_F)
{
tempCRC = Cal_CRC16(&packet_data[3], pktSize);
Send_Byte(tempCRC >> 8);
Send_Byte(tempCRC & 0xFF);
}
else
{
tempCheckSum = CalChecksum (&packet_data[3], pktSize);
Send_Byte(tempCheckSum);
}
//等待响应
if ((Receive_Byte(&receivedC[0], 100000) == 0) && (receivedC[0] == ACK))
{
ackReceived = 1;
if (size > pktSize)
{
buf_ptr += pktSize;
size -= pktSize;
if (blkNumber == (FLASH_IMAGE_SIZE/1024))
{
return 0xFF; //错误
}
else
{
blkNumber++;
}
}
else
{
buf_ptr += pktSize;
size = 0;
}
}
else
{
errors++;
}
} while (!ackReceived && (errors < 0x0A));
//如果没响应10次就返回错误
if (errors >= 0x0A)
{
return errors;
}
}
ackReceived = 0;
receivedC[0] = 0x00;
errors = 0;
do
{
Send_Byte(EOT);
//发送 (EOT);
//等待回应
if ((Receive_Byte(&receivedC[0], 10000) == 0) && receivedC[0] == ACK)
{
ackReceived = 1;
}
else
{
errors++;
}
} while (!ackReceived && (errors < 0x0A));
if (errors >= 0x0A)
{
return errors;
}
//准备最后一个包
ackReceived = 0;
receivedC[0] = 0x00;
errors = 0;
packet_data[0] = SOH;
packet_data[1] = 0;
packet_data [2] = 0xFF;
for (i = PACKET_HEADER; i < (PACKET_SIZE + PACKET_HEADER); i++)
{
packet_data [i] = 0x00;
}
do
{
//发送数据包
Ymodem_SendPacket(packet_data, PACKET_SIZE + PACKET_HEADER);
//发送CRC校验
tempCRC = Cal_CRC16(&packet_data[3], PACKET_SIZE);
Send_Byte(tempCRC >> 8);
Send_Byte(tempCRC & 0xFF);
//等待响应
if (Receive_Byte(&receivedC[0], 10000) == 0)
{
if (receivedC[0] == ACK)
{
//包传输正确
ackReceived = 1;
}
}
else
{
errors++;
}
} while (!ackReceived && (errors < 0x0A));
//如果没响应10次就返回错误
if (errors >= 0x0A)
{
return errors;
}
do
{
Send_Byte(EOT);
//发送 (EOT);
//等待回应
if ((Receive_Byte(&receivedC[0], 10000) == 0) && receivedC[0] == ACK)
{
ackReceived = 1;
}
else
{
errors++;
}
} while (!ackReceived && (errors < 0x0A));
if (errors >= 0x0A)
{
return errors;
}
return 0;//文件传输成功
}
#endif
void SerialDownload(void)
{
u8 Number[10] = " ";
s32 Size = 0;
SerialPutString("Waiting for the file to be sent ... (press 'a' to abort)\n\r");
Size = Ymodem_Receive(&tab_1024[0]);
if (Size > 0)
{
SerialPutString("\n\n\r Programming Completed Successfully!\n\r--------------------------------\r\n Name: ");
SerialPutString(file_name);
Int2Str(Number, Size);
SerialPutString("\n\r Size: ");
SerialPutString(Number);
SerialPutString(" Bytes\r\n");
SerialPutString("-------------------\n");
}
else if (Size == -1)
{
SerialPutString("\n\n\rThe image size is higher than the allowed space memory!\n\r");
}
else if (Size == -2)
{
SerialPutString("\n\n\rVerification failed!\n\r");
}
else if (Size == -3)
{
SerialPutString("\r\n\nAborted by user.\n\r");
}
else
{
SerialPutString("\n\rFailed to receive the file!\n\r");
}
}
#endif
/*******************************文件结束***************************************/
/*******************************************************************************
** 文件名: ymodem.c
** 版本: 1.0
** 工作环境: RealView MDK-ARM 4.14
** 作者: wuguoyana
** 生成日期: 2011-04-29
** 功能: 和Ymodem.c的相关的头文件
** 相关文件: stm32f10x.h
** 修改日志: 2011-04-29 创建文档
*******************************************************************************/
/* 防止重定义 *****************************************************************/
#ifndef _YMODEM_H_
#define _YMODEM_H_
#include "stm32f10x.h"
/* 宏 ------------------------------------------------------------------------*/
#define PACKET_SEQNO_INDEX (1)
#define PACKET_SEQNO_COMP_INDEX (2)
#define PACKET_HEADER (3)
#define PACKET_TRAILER (2)
#define PACKET_OVERHEAD (PACKET_HEADER + PACKET_TRAILER)
#define PACKET_SIZE (128)
#define PACKET_1K_SIZE (1024)
#define FILE_NAME_LENGTH (256)
#define FILE_SIZE_LENGTH (16)
#define FILE_TYPE (4)
#define SOH (0x01) //128字节数据包开始
#define STX (0x02) //1024字节的数据包开始
#define EOT (0x04) //结束传输
#define ACK (0x06) //回应
#define NAK (0x15) //没回应
#define CA (0x18) //这两个相继中止转移
#define CRC16 (0x43) //'C' == 0x43, 需要 16-bit CRC
#define ABORT1 (0x41) //'A' == 0x41, 用户终止
#define ABORT2 (0x61) //'a' == 0x61, 用户终止
#define NAK_TIMEOUT (0x100000)
#define MAX_ERRORS (5)
/* 函数声明 ------------------------------------------------------------------*/
s32 Ymodem_Receive (u8 *);
u8 Ymodem_Transmit (u8 *,const u8* , uint32_t );
void SerialDownload(void);
#endif /* _YMODEM_H_ */
/*******************************文件结束***************************************/