最近把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;
}

Logo

社区规范:仅讨论OpenHarmony相关问题。

更多推荐