(五)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;
}

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 如果你想开发 Linux 4G 模块的代码,你需要确保你已经安装了必要的开发工具,包括编译器、内核开发文档和其他必要的库。 在开始编写代码之前,你还需要了解 Linux 内核架构,特别是内核模块的工作原理。这样你才能编写出能够有效地集成到内核的代码。 你可以在网上找到很多资料和教程,帮助你了解 Linux 内核模块的开发。有一些网站提供了详细的文档和示例代码,这些资源可以帮助你快速入门。 ### 回答2: 开发Linux 4G模块的代码主要包括以下几个部分。 1. 驱动程序开发:Linux操作系统需要对4G模块进行驱动程序的开发,以实现与模块的通信和控制。驱动程序应该能够识别并与4G模块进行通信,包括发送AT指令,接收模块返回的数据等。 2. AT指令解析:4G模块Linux系统之间的通信一般使用AT指令。因此需要编写代码解析AT指令,根据不同的指令类型执行相应的操作,如发送短信、接收短信、建立数据连接等。 3. 数据封装与解封装:在4G模块Linux系统之间的数据传输过程,需要对数据进行封装和解封装封装过程将待发送的数据打包成符合协议要求的格式,解封装过程则将接收到的数据从协议格式还原为原始数据。 4. 串口通信:4G模块一般通过串口Linux系统进行通信。因此需要编写代码实现串口的配置和数据传输。包括设置波特率、数据位、校验位等串口参数,以及读写串口接收和发送的数据。 5. 错误处理和异常处理:开发4G模块的代码还需要考虑错误和异常情况的处理。包括对于AT指令执行失败的情况进行错误处理,如重新发送指令、返回错误码等;对于串口通信的错误和异常情况进行处理,如串口接收错误、超时等。 以上是开发Linux 4G模块的代码大致内容。具体的实现需要根据具体的模块和需求进行详细设计和编码。 ### 回答3: 开发Linux 4G模块的代码需要考虑多个方面。首先,我们需要了解Linux内核的基础知识,包括模块的加载和卸载,以及与其他内核子系统的交互方式。然后,我们需要针对特定的4G模块进行驱动程序的开发。 驱动程序是连接硬件和操作系统之间的关键组件。对于4G模块,我们需要开发一个适配器驱动程序,以便通过该驱动程序与模块进行通信。 在驱动程序的制作,我们需要编写适当的代码来初始化4G模块,并设置必要的参数,如APN、IP地址等。此外,我们还需要编写代码来处理不同的命令和事件,例如发送和接收数据请求,处理链接状态变化等。 另外,为了使代码更加模块化和可维护,我们还应该考虑使用适当的API和库,例如Linux提供的网络套接字库,以简化与4G模块的通信。 在开发过程,我们应该保持代码的可移植性和可扩展性,以应对各种4G模块和不同版本的Linux内核的变化。为了确保代码质量,我们应该进行适当的单元测试和集成测试,并遵循良好的编码规范和开发实践。 最后,在代码的文档,我们应该提供清晰的注释和说明,以便其他开发人员能够理解和使用我们的代码。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值