简单的AT指令解析

制作一个简单的AT指令解析

最近在开发nrf51822工作上需要搭建一个简单的AT指令库,突然灵机一动想到了这个样一个简单的AT解析函数,虽然不是特别完美但还需各位大神多多指教。

一般,我们的AT命令组成为:
1、查询命令 AT+instruction\r\n
2、设置命令AT+instruction= <param>\r\n

举个栗子:我要通过AT查询波特率以及设置波特率
1、查询 AT+BAUD\r\n
2、设置 AT+BAUD= 115200\r\n

好知道这种格式之后我们发现这个命令都有些规律。
第一:指令头都是固定的为"AT+"
第二:尾部都是固定的为"\r\n"
第三:如果要接参数的话都是"= "(注意等于号后面接了空格)
第四:我们的可以通过命令的首字母来建立一个AT索引表,正是这样我 们的可以建立一个长度为26的索引表(A~Z),在通过相应的索引表存放相应的指令,例如BAUD,我们就可以存在指令表的第二个位置(B在字母表中排第二)。
找到这种规律我们就知道该怎么去拆分AT指令是作为查询命令还是设置命令,接下来就开始析构代码。

第一、创建两个结构体

//第一个用来存放AT的指令
typedef struct node{
	  uint8_t position;   //位置根据命令首字母来进行位置区分 B = 2
      uint8_t *at_str;    //存放AT命令
	  void (*function)(uint8_t *str);  //存放命令所用的函数
	  struct node *next;  //链接下一个同位置的命令
}AT_DEAL;
//第二个用来构建一个索引表
typedef struct{
	 AT_DEAL *next;
}INDEX_NODE

第二、开始构建索引表以及AT库

#define MAX_AT_INSTRUCTION    32                         //AT指令数量
#define LAST_INST             MAX_AT_INSTRUCTION - 1     //最后条语句表示AT指令输入错误
#define MAX_RECEIVE_LENGTH    28                         //接送数据的最大长度
#define CONNECT_DATA(str1,str2,str3)   (str1##str2##str3)           //字符串连接

#define MAX_RECEIVE_LENGTH    28                         //接送数据的最大长度

//此下这个结构体必须创建为一个全局变量、
static AT_DEAL at_deal[MAX_AT_INSTRUCTION] = {
	 { 1,  (uint8_t*)"ADVI",    get_advi,     NULL },
	 { 2,  (uint8_t*)"BAUD",    get_baud,     NULL },
	 { 3,  (uint8_t*)"CONA",    set_cona,     NULL },
	 { 3,  (uint8_t*)"CONN",    set_conn,     NULL },
	 { 3,  (uint8_t*)"CHAR",    get_char,     NULL },
	 { 4,  (uint8_t*)"DEFAULT", set_default,  NULL },
	 { 7,  (uint8_t*)"HELP",    get_help,     NULL },   //获取指令集
	 { 8,  (uint8_t*)"IMME",    get_imme,     NULL },
	 { 8,  (uint8_t*)"IBE0",    get_ibe0,     NULL },
	 { 8,  (uint8_t*)"IBE1",    get_ibe1,     NULL },
	 { 8,  (uint8_t*)"IBE2",    get_ibe2,     NULL },
	 { 8,  (uint8_t*)"IBE3",    get_ibe3,     NULL },
	 { 8,  (uint8_t*)"IBEA",    get_ibea,     NULL },
	 { 12, (uint8_t*)"LADDR",   get_laddr,    NULL },
	 { 13, (uint8_t*)"MARJ",    get_marj,     NULL },
	 { 13, (uint8_t*)"MEA",     get_mea,      NULL },
	 { 13, (uint8_t*)"MINO",    get_mino,     NULL },
	 { 14, (uint8_t*)"NAME",    get_name,     NULL },   //获取蓝牙设备名称
	 ( 14, (uint8_t*)"NOTI",    get_noti,     NULL ),
	 ( 14, (uint8_t*)"NOTP",    get_notp,     NULL ),
	 ( 16, (uint8_t*)"PWRM",    set_pwrm,     NULL ),
	 { 16, (uint8_t*)"POWE",    get_powe,     NULL },
	 { 16, (uint8_t*)"PIN",     get_pin,      NULL },
	 { 16, (uint8_t*)"PARI",    get_pari,     NULL },
	 { 18, (uint8_t*)"ROLE",    set_role,     NULL },
	 { 18, (uint8_t*)"RESET",   reset,        NULL },
	 { 19, (uint8_t*)"SLEEP",   set_sleep,    NULL },
	 { 19, (uint8_t*)"STOP",    get_stop,     NULL },
	 { 19, (uint8_t*)"START",   get_start,    NULL },
	 { 21, (uint8_t*)"UUID",    get_uuid,     NULL },
	 { 22, (uint8_t*)"VERSION", version,      NULL },    //获取版本号
	 { 0,  (uint8_t*)"AT\r\n",  test_inst,    NULL },    //测试指令  
	 { 0,  (uint8_t*)NULL,      inst_error,   NULL }     //指令错误
};
//接着就开始注册 索引表
void enroll_at_instruction_index(void)   //注册AT指令索引表
{
	unsigned char i;
    AT_DEAL *deal = NULL;
    
    for(i=0;i<INDEX_TABLE_NUMBER;i++)  //先初始化索引表
       index_node[i].next = NULL;
    
    //开始构建索引表
	for(i=0;i<MAX_AT_INSTRUCTION-2;i++) {  //此处减二是因为AT库最后两个不加入索引表
		if(at_deal[i].position != 0) {
			at_deal[i].next = index_node[at_deal[i].position].next;
	        index_node[at_deal[i].position].next = &at_deal[i]; 
		}
	}

	//测试链表链接情况
	/*
	printf("**********************\r\n");
	
    for(i=0;i<INDEX_TABLE_NUMBER;i++) {
	   deal = index_node[i+1].next;
	     if(deal != NULL) {
	         printf("%c\r\n",'A'+i);
			 while(deal != NULL) {
			     printf("%5d %s\r\n",deal->position,deal->at_str);
				 deal = deal->next;
			 }
		 }
	}
	
	printf("**********************\r\n");
    */
}

第三、开始构建解析AT以及跳转相应指令函数

void chansfer_char(unsigned char*data_array,unsigned char index)
{
	uint8_t i;
	for(i=0;i<index;i++) {     //大小写强制转换
			 if(data_array[i] == ' ' || data_array[i] == '\\')   //遇到空格
				 break;
			 if(data_array[i] >= 'a' && data_array[i] <= 'z')
				 data_array[i] = data_array[i]-32;
			 else
				data_array[i] = data_array[i];
	}
}
//此处的str最长为28
void at_info_deal(unsigned char*str,uint8_t len)  //AT指令处理
{
	AT_DEAL *node = NULL;
    unsigned char position = 0;
	chansfer_char(str,len);

	if(len == 4) {       //判断是否为指令测试"AT\r\n"
	   if(memcmp(str,at_deal[LAST_INST-1].at_str,strlen((char *)at_deal[LAST_INST-1].at_str)) == 0)
		  at_deal[LAST_INST-1].function(NULL);
	   else
		  at_deal[LAST_INST].function(NULL);
	}
    else if(len > 4){   //指令验证
		if(memcmp(str,"AT+",3) == 0) {   //命令头是否为"AT+"
		   switch(str[3])
		   {
			   case 'A':
			       node = index_node[1].next;
				   flag = 1;
			   break;
			   case 'B':
			       node = index_node[2].next;
				   flag = 1;
			   break;
			   case 'C':
			       node = index_node[3].next;
				   flag = 1;
			   break;
			   case 'D':
			       node = index_node[4].next;
				   flag = 1;
			   break;
			   case 'H':
			       node = index_node[7].next;
				   flag = 1;
			   break;
               case 'I':
			       node = index_node[8].next;
				   flag = 1;
			   break;
			   case 'L':
			       node = index_node[12].next;
				   flag = 1;
			   break;
			   case 'M':
			       node = index_node[13].next;
				   flag = 1;
			   break;
			   case 'N':
			       node = index_node[14].next;
				   flag = 1;
			   break;
			   case 'P':
			       node = index_node[16].next;
				   flag = 1;
			   break;
			   case 'R':
			       node = index_node[18].next;
				   flag = 1;
			   break;
			   case 'S':
			       node = index_node[19].next;
				   flag = 1;
			   break;
			   case 'U':
			       node = index_node[21].next;
				   flag = 1;
			   break;
			   case 'V':
			       node = index_node[22].next;
				   flag = 1;
			   break;
		   }
		}
		else  //错误指令 
		  at_deal[LAST_INST].function(NULL); 
	} 
	else   //错误指令 
		at_deal[LAST_INST].function(NULL);
    
    if(flag == 1) {
       flag = 0;
       while(node != NULL) {
       	  if(memcmp(str+3,node->at_str,strlen((char *)node->at_str)) == 0) {   //找到相应指令 
	   	      str = str+3;
	   	      position = strlen((char *)node->at_str) + 1;
	   	      if(str[position] == '\r' && str[position+1] == '\n')  //指令后无参数 
	   	          node->function(NULL);
			  else if(str[position] == '=' && str[len-1] == '\r' && str[len] == '\n')   //指令后有参数 
			      node->function(str);
			  break;
       	  }
       	  node = node->next;
       }
       node = NULL;
    } 
}

第四、创建指令函数(所有指令函数大同小异,就以BAUD和LADDR指令为例)

//LADDR
//将16进制数转换成字符串
uint8_t hex_to_char(unsigned char dat)
{
	 if(dat > 9)
		  return (dat+55);
	 else
		  return (dat+0x30);
}
void get_laddr(unsigned char*str) //获取蓝牙地址
{
	unsigned char temp,i;
	ble_gap_addr_t get_addr;
	if(str == NULL) {   //此指令是无参数的
		sd_ble_gap_address_get(&get_addr);
		for(i=0;i<6;i++) {
				temp = get_addr.addr[BLE_GAP_ADDR_LEN-i] & 0xf0;
				chansfer[2*i] = hex_to_char(temp >> 4);
				temp = get_addr.addr[BLE_GAP_ADDR_LEN-i] & 0x0f;
			    chansfer[2*i+1] = hex_to_char(temp);
		}
		printf("+LADDR=%s\r\n",chansfer);
	}
	else {  //否则命令错误
	    at_deal[LAST_INST].function(NULL); 
	}
}
//BAUD
void get_baud(unsigned char *str)
{
     unsigned char *baud=NULL;
     if(str == NULL) {  //无参数输出当前的波特率
          //从内存中读取
          baud = flash_read(addr);
          printf("+BUAD=%s\r\n",baud);
     }
     else {   //有参数则更新
         /*
           此处要做一个波特率处理。判断是否传入的参数是否是真的波特率
         */
         flash_write(addr,str,strlen(str));
         printf("+BAUD=%s OK\r\n",str);
     }
}

第五、开始执行main

static uint8_t index = 0;     //接收字符
static uint8_t data_array[MAX_RECEIVE_LENGTH];   //存储接收的字符

static void timers_init(void)
{
    uint32_t err_code = 0;
    ...
    err_code = app_timer_create(&uart_receive_timeout,
                                 APP_TIMER_MODE_SINGLE_SHOT,
                                 receive_timeout);
	APP_ERROR_CHECK(err_code);
}
static void receive_timeout(void * p_context)
{
	app_timer_stop(uart_receive_timeout);
	at_info_deal(data_array,index);
	index = 0;
	memset(data_array,'\0',MAX_RECEIVE_LENGTH);
}

void uart_event_handle(app_uart_evt_t * p_event)
{
    uint32_t err_code;
    
    switch (p_event->evt_type)
    {
        case APP_UART_DATA_READY:
            UNUSED_VARIABLE(app_uart_get(&data_array[index])); 
            index++;
			app_timer_stop(uart_receive_timeout);				
			if(index>=MAX_RECEIVE_LENGTH) {
				receive_timeout(NULL);
			}
			else {  //判断是否接收完成
				//SEGGER_RTT_TRC("--%d--",index);
				err_code = app_timer_start(uart_receive_timeout,  APP_TIMER_TICKS(9/*ms*/, APP_TIMER_PRESCALER), NULL);
				PP_ERROR_CHECK(err_code);
		    }
            break;

        case APP_UART_COMMUNICATION_ERROR:
            APP_ERROR_HANDLER(p_event->data.error_communication);
            break;

        case APP_UART_FIFO_ERROR:
            APP_ERROR_HANDLER(p_event->data.error_code);
            break;
		case APP_UART_TX_EMPTY:
					  index = 0;
			break;
				
        default:
            break;
    }
}

int main(void)
{
    timers_init();
    uart_init();
    ...
    enroll_at_instruction_index();
    for (;;)
    {
        power_manage();
    }
}

最后便可以执行成功了。

  • 12
    点赞
  • 90
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值