C语言memmem函数参数详解,NB-IOT开发|nbiot开发教程《三》AT指令类模组驱动-STM32实现AT指令状态机...

嵌入式开发中我们要时刻保持代码的高效与整洁

看之前,先点赞

好习惯,要养成

一、前言

嵌入式开发中我们要时刻保持代码的高效与整洁。在第一节中“NB-IOT开发|nbiot开发教程《一》AT指令类模组驱动解析”我们说到AT指令模组最好的驱动-状态机。本节我们就开始编写状态机。

59565b33d73cace4e71a593ee1524977.png

目前网上可以看到的状态机如下图:

u8 NB_IoT_ack_chack(u8 *str)

{

delay_ms(10);

if(USART2_RX_STA!=0)

{

USART2_RX_STA=0;

if(strstr((const char*)USART2_RX_BUF,(const char*)str))//符合预期

{

memset(USART2_RX_BUF,0, sizeof USART2_RX_BUF);

return 0;

}

else //不符合预期

{

memset(USART2_RX_BUF,0, sizeof USART2_RX_BUF);

return 1;

}

}

else

{

memset(USART2_RX_BUF,0, sizeof USART2_RX_BUF); //清空数组

return 1;

}

}

u8 NB_IoT_ZDFW()

{

u8 x=0;

cmd1: send_NB_IoT("AT+NCONFIG=AUTOCONNECT,TRUE\r\n") ;

if(!NB_IoT_ack_chack("OK")) x++ ;

else goto cmd1;

cmd2: send_NB_IoT("AT+CFUN=1\r\n") ;

if(!NB_IoT_ack_chack("OK")) x++ ;

else goto cmd2;

cmd3: send_NB_IoT("AT+NRB\r\n") ;

if(!NB_IoT_ack_chack("REBOOTING")) x++ ;

else goto cmd3;

}

delay_ms(10);对,你没有看错就是delay,死等,多么可怕的应用。而且死等10ms就一定能收到数据吗,有些模组中的指令返回时间并不是固定的,可见delay并不是很合适的使用,如果延时1s呢?????,如果此时有按键或者有屏幕刷新,1s的延时能接受吗??,显然是不能的。本次状态机拒绝使用死等!

二、代码实现

举例:

状态:

1.发送AT确认模组是否正常;2.配置模组参数;3.发送数据;(暂定三个状态)

动作:

1.发送AT确认模组是否正常->通过串口发送AT\r\n,模组正常会返回OK,模组不正常返回非OK数据或者不返回。

2.配置模组参数->通过串口发送AT+PARAM=10\r\n,模组正常会返回OK,模组不正常返回非OK数据或者不返回。

3.发送数据->通过串口发送AT+SEND=2030559498473738292929394\r\n,模组正常会返回OK,模组不正常返回非OK数据或者不返回。

事件:

状态机进行状态切换需要事件驱动。

事件1:状态强制切换事件(event_change_state),用于将状态机强制切换到某个指定状态或者下一状态。

事件2:串口接收到完整数据包事件(event_uart_data),模组返回数据。

事件3:超时事件(event_timeout),例如发送AT后模组在1s或者指定时间内没有返回任何数据。

状态:

typedef enum

{

STATE_HAL_RESET= 0x01, /*模组复位*/

STATE_AT, /*发送AT指令测试*/

STATE_SET_PARAM, /*设置参数*/

STATE_SEND_DATA, /*发送数据*/

STATE_IDEL, /*空闲状态*/

} nbiot_state_e;

结合上图1中状态机我们用语言描述下AT指令。例如发送AT模组返回OK,首先这个具有两个状态,一个是当前状态,一个是下一状态;具有的动作就是发送AT,模组返回OK,两个执行动作;在实际使用时可能会存在模组不回复或者回复错误的时候,所以要尝试,尝试要记录重试次数try_cnt;发送完AT后模组要有一个反应时间,就是MCU等待时间,这个时间不确定,每条指令等待时间不一样,计做wait_time;

现在用C语言结构体描述上述文字

typedef struct

{

nbiot_state_e cur_state; /*当前状态*/

nbiot_state_e next_state; /*下一个状态*/

int try_cnt; /*重试次数*/

int wait_time; /*等待时间*/

int (*action1)(void); /*动作1:发送AT*/

int (*action2)(const void *arg,int len); /*动作2:判断接收到的数据是否为OK或者未接收到*/

} nbiot_fsm_state_t;

状态描述完了,还需要有一个游动指针指向当前正在执行的状态。

typedef struct

{

int cur_state; /*当前状态*/

int trycnt; /*当前状态已经重试的次数*/

uint32_t init; /*当前状态是执行action1还是执行action2*/

const nbiot_fsm_state_t *fsm_state; /*当前状态是功能参数*/

} nbiot_fsm_state_index_t;

static nbiot_fsm_state_index_t nbiot_fsm_state_index;

状态中的两个执行动作C语言描述:action1->发送AT

action2:->判断接收到的数据是否为OK,如果是则执行下一状态,如果不是则等待,如果超时未收到数据就重试。

/*

* AT

*/

static int at_action1(void)

{

const char *cmd = "AT\r\n";

return cola_device_write(uart_dev,0,cmd,strlen(cmd));

}

static int at_action2(const void *arg,int len)

{

if(!len)

return STATE_RETRY;

char *pt = memmem(arg, len, "OK", strlen("OK"));

if (pt)

{

return STATE_NEXT;

}

return STATE_WAIT;

}

每一个状态都写两个执行动作。

全部的状态列表:

static const nbiot_fsm_state_t nbiot_state_list[] =

{

{STATE_HAL_RESET,STATE_AT, 1, 300,nbiot_reset_action1,nbiot_reset_action2},

{STATE_AT, STATE_SET_PARAM,3, 3000,at_action1, at_action2 },

{STATE_SET_PARAM,STATE_SEND_DATA,4, 3000,set_param_action1, set_param_action2 },

{STATE_SEND_DATA,STATE_IDEL, 5, 3000,send_data_action1, send_data_action2 },

{STATE_IDEL, STATE_IDEL, 100,3000,state_idel_action1, state_idel_action2 },

};

状态写完了接下来还需要一个状态管理的函数,负责管理是执行action1还是执行action2;

状态管理函数:状态管理函数中等待模组返回数据采用的是软定时器,该方式很好的避免了死等问题。

状态和执行动作完成了,接下来就是事件,驱动状态机运行的驱动力--------事件。

事件1:状态强制切换事件

更新游动状态指针,并且给任务发送状态改变的信号cola_set_event(&nbiot_task,SIG_CHANGE_STATE);

static void nbiot_change_state(nbiot_state_e state)

{

const nbiot_fsm_state_t *fsm_state = nbiot_get_state(state);

if(fsm_state)

{

nbiot_fsm_state_index.init = ACTION1;

if(nbiot_fsm_state_index.cur_state != state)

{

nbiot_fsm_state_index.cur_state = state;

nbiot_fsm_state_index.trycnt = 0;

nbiot_fsm_state_index.fsm_state = fsm_state;

}

cola_set_event(&nbiot_task,SIG_CHANGE_STATE);

}

}

事件2:串口接收到完整数据包事件

上一节“NB-IOT开发|nbiot开发教程《二》AT指令类模组驱动-STM32串口实现接收不定长度数据”中提到的,不明白可以再看下。

串口接收到完整数据包后通知nbiot任务,cola_set_event(uart1_dev.owner,SIG_DATA);

static void uart_timer_cb(uint32_t event)

{

if(uart1_dev.owner)

{

cola_set_event(uart1_dev.owner,SIG_DATA);

}

}

事件3:超时事件

static void nbiot_timer_cb(uint32_t event)

{

cola_set_event(&nbiot_task,SIG_TIMEOUT);

}

三个驱动状态机运行的时间就完成了,既然这三个事件是驱动力,那么就需要在任务中管理这三个驱动事件。

事件管理

static void nbiot_task_cb(uint32_t event)

{

int err = 0;

if(event & SIG_CHANGE_STATE)

{

nbiot_fsm_schedule(NULL,0);

}

if(event & SIG_TIMEOUT)

{

nbiot_fsm_schedule(NULL,0);

}

if(event & SIG_DATA)

{

err = cola_device_read(uart_dev,0,g_buf,sizeof(g_buf));

if(err)

{

nbiot_fsm_schedule(g_buf,err);

}

}

}

三、调试4b5785fddd16ee00cb32388500cadd98.png

状态机已经跑起来了,确实按照我们状态列表中编写的在跑,首先运行第一个状态硬件复位,300ms后执行AT指令发送,发送一次AT,尝试3次,而且等待时间为3000ms,如果尝试超过最大次数,则从新复位nbiot模组。如果接收到OK则执行下一个状态。

四、代码下载

重要的就是代码下载了,不知道有木有人在看呀,等评论超100再上传吧,要不然没有动力写下去了。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,针对您的问题,我可以给您提供一个基于C语言实现的简单病毒检测代码。 首先,我们需要一些关于病毒检测的基础知识。病毒检测主要是检查系统中的文件是否含有病毒代码,这些病毒代码可以通过特定的模式来匹配。 我们可以通过一个简单的例子来说明病毒检测的原理,以及如何使用C语言实现。以下是一个基于病毒特征码的简单病毒检测代码: ```c #include <stdio.h> #include <string.h> #define MAX_VIRUS_SIZE 1024 char virus[MAX_VIRUS_SIZE] = { // 病毒特征码 // 这里只是举个例子,实际上病毒特征码可能非常复杂 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64 }; int virus_size = sizeof(virus); int scan_file(char *filename) { FILE *fp; char buffer[MAX_VIRUS_SIZE]; int read_size; fp = fopen(filename, "r"); if (fp == NULL) { return 0; } while ((read_size = fread(buffer, 1, MAX_VIRUS_SIZE, fp)) > 0) { // 查找病毒特征码 if (memmem(buffer, read_size, virus, virus_size) != NULL) { printf("Found virus in file: %s\n", filename); fclose(fp); return 1; } } fclose(fp); return 0; } int main(int argc, char *argv[]) { if (argc != 2) { printf("Usage: %s filename\n", argv[0]); return 1; } if (scan_file(argv[1])) { printf("Virus found\n"); } else { printf("File is safe\n"); } return 0; } ``` 以上代码中,我们定义了一个病毒特征码,并且在检测文件的时候查找这个特征码。如果在文件中找到了这个特征码,就表明该文件含有病毒代码。 需要注意的是,这只是一个简单的病毒检测例子,实际上对于更复杂的病毒来说,病毒特征码可能非常复杂,原理和实现方法也可能会有所不同。 希望以上代码和解释可以对您有所帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值