STM32hal库版本ymode简化协议
·
最近把MQTT和阿里云中介服务器写的差不多了,后面调试stm32的ymode出了点问题。
因为一开始我ymode用的是串口中断写的,我发现那时候写的ymode虽然也能用超级终端进行读写,但是本身存在一些问题,比如说第二个EOT之后,应该回ACK,C,我程序里是直接在中断里send(ACK),send(C),这么写其实还是存在问题的,中间应该延时个比如100ms,但是如果在中断里延时,又需要开个定时器,因为hal_delay在中断里用不了,这就很蛋疼。
现在STM32程序写多了,感觉中断确实是能不用最好不用,以前我不懂为什么要用freertos,现在我明白了,这玩意最大的好处不是多任务,而是能减少大伙对中断的使用,我觉得这个才是最重要的。
于是我参照官方的IAP写了一个不用中断的ymode协议的hal库简化版本
下面是主要操作
#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 ((uint32_t)64)
#define FILE_SIZE_LENGTH ((uint32_t)16)
#define SOH (0x01) /* start of 128-byte data packet */
#define STX (0x02) /* start of 1024-byte data packet */
#define EOT (0x04) /* end of transmission */
#define ACK (0x06) /* acknowledge */
#define NAK (0x15) /* negative acknowledge */
#define CA (0x18) /* two of these in succession aborts transfer */
#define CRC16 (0x43) /* 'C' == 0x43, request 16-bit CRC */
int32_t size = 0; //文件大小
uint16_t pack_no;
volatile uint16_t sta_flag; //状态机
//0-7位:包号
//8:接收到首包
//9:接收完毕
//10:第一个EOT
//11:第二个EOT
uint8_t receive[2048] = {0};
void ymode_handle(void){
int ret = 0;
while((ret = Receive_Packet()) != 2){
switch(ret){
case -3:
sta_flag = 0;
size = pack_no = 0;
Send_Res(CRC16);
memset(receive, 0, sizeof(receive));
break;
case -2:
sta_flag = 0;
size = pack_no = 0;
Send_Res(CA);
memset(receive, 0, sizeof(receive));
break;
case -1:
Send_Res(NAK);
memset(receive, 0, sizeof(receive));
break;
case 0:
Send_Res(ACK);
memset(receive, 0, sizeof(receive));
break;
case 1:
sta_flag |= (1<<8);
Send_Res(ACK);
HAL_Delay(100);
Send_Res(CRC16);
memset(receive, 0, sizeof(receive));
break;
default:
memset(receive, 0, sizeof(receive));
break;
}
}
//接收成功后的操作,jump to app
}
//返回值:-3:CRC -2:CA -1:出错(NAK) 0:接收成功 1:首帧 2:session_done
int Receive_Packet (void)
{
uint16_t packet_size;
uint8_t end_flag = 0;
while(HAL_UART_Receive(&huart1, (unsigned char *)receive, 1, 1000) != HAL_OK){
return -3;
}
switch(receive[0])
{
case SOH:
packet_size = PACKET_SIZE;
break;
case STX:
packet_size = PACKET_1K_SIZE;
break;
case EOT:
if(sta_flag & (1<<10)){
Send_Res(ACK);
HAL_Delay(100);
Send_Res(CRC16);
}else{
sta_flag = sta_flag&0xF0;
sta_flag |= (1<<10);
Send_Res(NAK);
}
return 0;
case CA:
return -2;
default:
return -1;
}
if(HAL_UART_Receive(&huart1, (unsigned char *)&receive[1], packet_size + 4, 1000) != HAL_OK){
return -1;
}
//校验包号和
uint16_t crc_val= (uint16_t)HAL_CRC_Calculate(&hcrc, (uint32_t*)&receive[3], packet_size);
uint16_t receive_crc_temp = receive[packet_size+3] << 8 | receive[packet_size+4];
uint8_t crc_flag = crc_val == receive_crc_temp ? 1 : 0;
uint16_t write_size; //本次应该写入多大的数据
if(receive[1] < pack_no){
write_size = 1024;
}else if(receive[1] == pack_no){
write_size = size % 1024;
end_flag = 1;
}else{ //包号超出
return -2;
}
if((sta_flag & 0x0f) == receive[1] && crc_flag){
if(packet_size == PACKET_SIZE){
if(receive[1] == 0x00){ //首帧或尾帧
if(receive[3] != 0x00){
sta_flag++; //首帧
return orgin_handle();
}else{ //尾帧
return 2;
}
}else{ //数据帧,也是结束帧
Flash_Write(&receive[3], write_size, receive[1], end_flag);
sta_flag++;
return 0;
}
}else if(packet_size == PACKET_1K_SIZE){
Flash_Write(&receive[3], write_size, receive[1], end_flag);
sta_flag++;
return 0;
}
}else{
return -1;
}
return -1;
}
int orgin_handle(void)
{
uint8_t i = 0;
uint8_t j = 3;
uint8_t aFileName[FILE_NAME_LENGTH] = {0}, file_size[FILE_SIZE_LENGTH] = {0};
//memset(aFileName, FILE_NAME_LENGTH, 0);
//memset(file_size, FILE_SIZE_LENGTH, 0);
while ( (receive[j] != 0) && (i < FILE_NAME_LENGTH)){
aFileName[i++] = receive[j++];
}
/* File size extraction */
aFileName[i++] = '\0';
//这里把文件版本号写入flash
i = 0;
j ++;
while((receive[j] != ' ') && (i < FILE_SIZE_LENGTH)){
file_size[i++] = receive[j++];
}
file_size[i++] = '\0';
Str2Int(file_size, &size);
//为后续做准备
if(size % 1024){
pack_no = size / 1024 + 1;
}else{
pack_no = size / 1024;
}
if(size > FLASH_SIZE1 - 1){ //升级程序过大,CA取消传输
return -1;
}else{
return 1;
}
}
void Send_Res(uint8_t ch)
{
uint8_t cht[2] = {0x0A};
cht[0] = ch;
cht[1] = '\n'; //我是AT穿透,所以需要\n,正常IAP这边不需要\n
HAL_UART_Transmit(&huart1, cht, 2, 1000);
}
下面是抄的一点官方的代码,这个代码主要是用于解算首包数据的文件名和大小
#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))
uint32_t Str2Int(uint8_t *inputstr, int32_t *intnum)
{
uint32_t i = 0, res = 0;
uint32_t 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;
/* return 1; */
res = 1;
break;
}
if (ISVALIDHEX(inputstr[i]))
{
val = (val << 4) + CONVERTHEX(inputstr[i]);
}
else
{
/* return 0, Invalid input */
res = 0;
break;
}
}
/* over 8 digit hex --invalid */
if (i >= 11)
{
res = 0;
}
}
else /* max 10-digit decimal input */
{
for (i = 0;i < 11;i++)
{
if (inputstr[i] == '\0')
{
*intnum = val;
/* return 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
{
/* return 0, Invalid input */
res = 0;
break;
}
}
/* Over 10 digit decimal --invalid */
if (i >= 11)
{
res = 0;
}
}
return res;
}
更多推荐
所有评论(0)