|
Linux 4G模块封装发送指令函数以及检测串口和SIM卡是否就绪
一、前言
在前一篇:(四)Linux 4G模块实现短信PDU格式编码,实现了一条短信的PDU格式编码,这样在后面我们就可以发送中英文短信了。但是把短信打包成PDU包后,我们怎么发送出去呢?思路也不难,就是调用前面写的tty_send()函数实现数据发送,再调用tty_recv()去接收串口返回的数据,通过返回的数据就可以判断我们是否发送成功了。这样我们就可以写一个send_at_cmd()函数,来实现数据发送、接收以及判断的功能了。然后再调用send_at_cmd()函数封装Check系列函数,Check系列函数系列函数的作用是在程序启动的时候检测串口和SIM卡是否就绪,如果就绪说明一切正常,可发通信发数据。
二、发送AT指令函数:send_at_cmd()
2.1 设计思路
上面也说到了,send_at_cmd()函数里面调用tty_send()和tty_recv()两个函数,而这两个函数其实是我们前面要发送AT指令而封装的,它们底层是调用了write()和read()这两个系统调用实现的。后来我们需要发送中英文短信,但是在发送短信之前,我们需要检测串口和SIM的状态。每发一条短信就需要调用tty_send()和tty_recv()两个函数,然后还要判断它们的返回值,如果我们不对这一重复性的操作进行封装,那每次发短信的时候就显得繁琐而复杂了。所以send_at_cmd()函数应运而生,实现过程如下。
函数原型:
- int send_at_cmd(ttyusb_ctx_t *ttyusb_ctx, char *at_buf, const char *expect_buf, char *return_buf, int return_buf_size);
复制代码
参数:
ttyusb_ctx_t *ttyusb_ctx 指串口属性结构体的指针,用来传fd和超时时间timeout;
char *at_buf 需要发送的命令;
const char *expect_buf 期望的在返回值中所包含的字符串;
char *return_buf 存放返回值的buf,如果我们需要对返回的数据进一步处理,可以存放到里面,若不需要的话,可以设置为NULL;
int return_buf_size 前一个参数return_buf 的大小。
调用send_at_cmd()函数向串口发送AT指令"AT\r"的过程:
(1) 先向串口发送数据
tty_send(ttyusb_ctx , “AT\r”, strlen(“AT\r”))
判断tty_send()的返回值,<0 说明发送失败。
(2)进行延时
因为4G模块收到指令后,需要消耗时间进行操作,所以需要给它一定的反应时间,不然发完数据立马去读串口的话就可能读不到数据。不过我们前面对tty_recv()函数进行了一个巧妙地设计就是,调用了selcet()。我们可以传参给tty_recv()进行阻塞一段时间。
(3)接收数据
if (tty_recv(ttyusb_ctx, temp_buf, sizeof(temp_buf)) <= 0)
{
printf(“Recving message failed:%s\n”,strerror(errno));
return -3;
}
判断tty_recv()的返回值,<0 说明发送失败。
(4)判断返回值temp_buf,进一步判断数据是否发送成功
if(!strstr(temp_buf, expect_buf))
{
printf(“Can’t find what you expect to receive[%s]\n”, expect_buf);
return -4;
}
2.2 代码实现
int send_at_cmd(ttyusb_ctx_t *ttyusb_ctx, char *at_buf, const char *expect_buf, char *return_buf, int return_buf_size)
{
char temp_buf[512] = {0};
if (!at_buf || !expect_buf)
{
printf("Unable to send AT commond,Invalid parameter.\n");
return -1;
}
if(tty_send(ttyusb_ctx, at_buf, strlen(at_buf)) < 0)
{
printf("Send AT commond failed:%s\n",strerror(errno));
return -2;
}
usleep(10000);
if(return_buf && return_buf_size)//需要接收返回值
{
if (tty_recv(ttyusb_ctx, return_buf, return_buf_size) <= 0)
{
printf("Recving message failed:%s\n",strerror(errno));
return -3;
}
if (!strstr(return_buf, expect_buf))
{
printf("Can't find what you expect to receive[%s]\n", expect_buf);
return -4;
}
}
else//不需要接收返回值
{
if (tty_recv(ttyusb_ctx, temp_buf, sizeof(temp_buf)) <= 0)
{
printf("Recving message failed:%s\n",strerror(errno));
return -3;
}
if (!strstr(temp_buf, expect_buf))
{
printf("Can't find what you expect to receive[%s]\n", expect_buf);
return -4;
}
memset(return_buf, 0, return_buf_size);
strncpy(return_buf,temp_buf,return_buf_size);
}
return 0;
}
做一个判断,因为我们不知道返回值占用字节的大小,所以如果不需要返回值的话,那直接存在一个中间buf里面,只需判断是否有返回对应的关键字段即可,如果需要的话就返回到return_buf里面。
三、Check系列函数——检测串口和SIM卡是否就绪
3.1check_tyy_ready()
确保串口可用
若返回OK则说明串口可用。
int check_tyy_ready(ttyusb_ctx_t *ttyusb_ctx)
{
int send_rv = -1;
if (!ttyusb_ctx)
{
printf("[%s]Invalid argument!\n", __func__);
return -1;
}
send_rv = send_at_cmd(ttyusb_ctx, "AT\r", "OK", NULL, 0);
if (0 != send_rv)
{
printf("[%s]The serial port is not ready!\n", __func__);
return -2;
}
printf("[%s]The serial port is ok!\n", __func__);
return 0;
}
3.2 check_sim_exist()
串口可通信不代表能检测出SIM卡
若返回READY,则说明能检测出SIM卡
int check_sim_exist(ttyusb_ctx_t *ttyusb_ctx)
{
int send_rv = -1;
if (!ttyusb_ctx)
{
printf("[%s]Invalid argument!\n", __func__);
return -1;
}
send_rv = send_at_cmd(ttyusb_ctx, "AT+CPIN?\r", "READY", NULL, 0);
if (send_rv < 0)
{
printf("[%s]The SIM card is not exist\n", __func__);
return -2;
}
printf("[%s]The SIM card is exist!\n", __func__);
return 0;
}
3.3 check_sim_login()
检测SIM卡是否已经注册
若返回0,1 或者返回0,3 则说明SIM卡已注册
int check_sim_login(ttyusb_ctx_t *ttyusb_ctx)
{
int send_rv1 = -1;
int send_rv2 = -1;
if (!ttyusb_ctx)
{
printf("[%s]Invalid argument!\n", __func__);
return -1;
}
send_rv1 = send_at_cmd(ttyusb_ctx, "AT+CREG?\r", "0,1", NULL, 0);
send_rv2 = send_at_cmd(ttyusb_ctx, "AT+CREG?\r", "0,3", NULL, 0);
if (send_rv1 && send_rv2)
{
printf("[%s]The SIM card does not exist!\n", __func__);
return -2;
}
printf("[%s]SIM card is exist!\n", __func__);
return 0;
}
3.4 check_sim_signal()
检测SIM卡信号
命令解释:检查网络信号强度
命令格式:AT+CSQ
命令返回:+CSQ: ** ,##
其中**应在 10 到 31 之间,数值越大表明信号质量越好,##为误码率,值在 0 到 99 之间。
int check_sim_signal(ttyusb_ctx_t *ttyusb_ctx)
{
int send_rv = -1;
char return_buf[256] = {0};
char separator[] = " ,";
int signal = -1;
char *token = NULL;
int i = 1;
if (!ttyusb_ctx)
{
printf("[%s]Invalid argument!\n", __func__);
return -1;
}
send_rv = send_at_cmd(ttyusb_ctx, "AT+CSQ\r", "+CSQ", return_buf, sizeof(return_buf));
if (send_rv < 0)
{
printf("[%s]Not found SIM signal!\n", __func__);
return -2;
}
printf("[%s]return_buf:%s\n", __func__, return_buf);
#if 1
token = strtok(return_buf, separator);
while (token != NULL)
{
++i;
token = strtok(NULL, separator);
printf("i: %d \ntoken:%s\n", i , token);
if(2 == i)
{
signal = atoi(token);
if ((signal < 8) || (signal > 31))
{
printf("[%s]The signal1 value is: %d, is not normal!\n", __func__, signal);
return -3;
}
else
{
printf("[%s]The signal1 value is: %d, normal!\n", __func__, signal);
break;
}
}
}
#endif
return 0;
}
3.5 check_all_ready()
对以上函数进行封装
int check_all_ready(ttyusb_ctx_t *ttyusb_ctx)
{
//确保串口可用
if (check_tyy_ready(ttyusb_ctx) < 0)
return -1;
log_info("[%s]tyy is ok\n", __func__);
//串口可通信不代表能检测出SIM卡
if (check_sim_exist(ttyusb_ctx) < 0)
return -2;
log_info("[%s]SIM is exist!\n", __func__);
//检测SIM卡是否已经注册
if (check_sim_login(ttyusb_ctx) < 0)
return -3;
log_info("[%s]SIM is login!\n", __func__);
//检测SIM卡信号
if (check_sim_signal(ttyusb_ctx) < 0)
return -4;
log_info("[%s]SIM signal is ok!\n", __func__);
printf("[%s]SIM and tty are ready!\n", __func__);
return 0;
}
|
+10
|