鸣涧_GC96O 发表于 2023-8-25 17:36:12

Linux 4G模块封装发送指令函数以及检测串口和SIM卡是否就绪


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 = {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 = {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;
}


页: [1]
查看完整版本: Linux 4G模块封装发送指令函数以及检测串口和SIM卡是否就绪