一. 像手机一样发送短信

1.1 看看效果

在介绍main程序之前,先来看一下效果吧~

在这里插入图片描述
其中,cmgs,pdu 是PDU编码是的中间产物,也就是使用原始AT命令发送PDU短信时,需要自己计算填写到的数值,这个数值只有算的全部正确才能发送成功,打印出来是为了调试所用,也可以将其关闭显示.


在这里插入图片描述



可到PDU.c的文件中将1改成0可关闭pdu编码显示:
在这里插入图片描述
继续测试:
在这里插入图片描述
在这里插入图片描述

1.2 提出问题

  1. 前面说了,发送短信有两种格式,但是我在这里却没有显示输入要发送哪种格式的短信,这是怎么实现的呢?
  2. 既然是使用到了串口,那如何不使用默认值来指定串口的属性,如波特率,数据位和奇偶校验等…
  3. 是如何使用 -n 来指定串口名的呢?
  4. 这么多功能模块,这么多c文件,如何编译呢?

下面,就来看一下main函数是怎么写的吧~

二. 主程序的实现

2.1 获取并解析命令行参数

 因为要使用到串口,就不得不提到串口的属性,在 Linux串口编程短信篇(一)中,提到了串口相关属性的设置,函数中都用到了一个结构体,comport,再来看一下他的定义:

typedef struct _st_ComportAttr {
    int               fd;        //串口文件描述符
    int               BaudRate;  //波特率
    int               DataBits;  //数据位
    char              Parity;    //奇偶校验位
    int               StopBits;  //停止位
    int               mSend_Len; //单次最大发送长度
    char              SerialName[SERIALNAME_LEN];  //串口名称
    struct termios    OldTermios;  //串口的原始属性
}ComportAttr;

comport_init() 函数就是使用的结构体中的值来对串口进行初始化,若其中结构体成员的值没有满足设置要求的,则按照默认值来设置,结构体中的值,是通过函数 getopt_long()函数实现,通过指定选项,获取命令行参数来设置结构体中的成员的值.

函数定义:

int getopt_long(int argc, char * const argv[],
                const char *optstring,
                const struct option *longopts, int *longindex);

该函数需要配合struct option 类型的结构体数组来使用,通过对数组的赋值,来指定选项以及选项是否需要参数,具体实现请看主程序

2.2 识别中英文短信

其实很简单,前面 Linux串口编程短信篇(二)已经介绍了,TEXT格式的字符串都可以用ASCII码表示,其二进制的值都是小于127的,所以,只需要遍历SMS字符串,如果遇到大于127的字符,就需要使用PDU格式来发送短信,否则就可以使用TEXT格式来发送啦!

三. 流程图和源码

3.1 流程图

在这里插入图片描述

3.2 主程序代码

sms_main.c

/*********************************************************************************
 *      Copyright:  (C) 2020 LuXiaoyang<920916829@qq.com>
 *                  All rights reserved.
 *
 *       Filename:  comport.c
 *    Description:  This file Send TEXT or PDU SMS
 *                 
 *        Version:  1.0.0(04/07/20)
 *         Author:  LuXiaoyang <920916829@qq.com>
 *      ChangeLog:  1, Release initial version on "04/07/20 03:02:28"
 *                 
 ********************************************************************************/
#include "comport.h"
#include "sms.h"
#include <getopt.h>
#include <signal.h>
#include "PDU.h"

void help_information();
void List_Sms_type();
int identify_sms_type(const char *sms_buf,int buf_len);  //检查短信类型


int  g_stop = 0;

void signal_capture(int signal_num)
{
    if(SIGINT == signal_num)
        g_stop = 1;
}

int main(int argc, char *argv[])
{
    int                  i;
    int                  ch;
    int                  chose;
    int                  retval;
    int                  sms_type;
    char                 sms_buf[256] = {0};
    char                 phone_number[256] = {0};
    ComportAttr         *comport;

    struct option    options[] = {
        {"help",no_argument,NULL,'h'},
        {"baudrate",required_argument,NULL,'b'},
        {"databits",required_argument,NULL,'d'},
        {"parity",required_argument,NULL,'p'},
        {"stopbits",required_argument,NULL,'s'},
        {"name",required_argument,NULL,'n'},
        {NULL,0,NULL,0}
    };

    comport = (ComportAttr *)malloc(sizeof(ComportAttr));
    memset(comport,0,sizeof(ComportAttr));
    
    /* Get command line parameters */
    while((ch = getopt_long(argc,argv,"hb:d:p:s:n:",options,NULL)) != -1)  //: means required_argument
    {
        switch(ch)
        {
            case 'h':
                help_information();
                return 0;

            case 'b':
                comport->BaudRate = atoi(optarg);
                break;

            case 'd':
                comport->DataBits = atoi(optarg);
                break;

            case 'p':
                comport->Parity = optarg[0];
                break;

            case 's':
                comport->StopBits = atoi(optarg);
                break;

            case 'n':
                strncpy(comport->SerialName,optarg,SERIALNAME_LEN);
                break;
                
        }
    }


    /* 没有传入串口名 */
    if(strlen(comport->SerialName) == 0)
    {
        help_information();
        return 0;
    }

    if(comport_open(comport) != 0)
    {
        printf("Open %s failed!\n",comport->SerialName);
        return -1;
    }

    retval = comport_init(comport);
    if(retval < 0)
        goto cleanup;

    signal(SIGINT,signal_capture);

    if(check_sim_allready < 0)
    {
        printf("SIM card is not available, please check\n");
        goto cleanup;
    }

    else 
        printf("SIM card is allready!\n");

    printf("\nThis program supports TEXT SMS and PDU SMS.\nSMS format is automatically determined.\nWhen entering the phone number, please pay attention to input \"+86\"!\nStart texting....\n");

    while(!g_stop)
    {
        bzero(phone_number,sizeof(phone_number));
        bzero(sms_buf,sizeof(sms_buf));

        printf("\n\t<1>  Send message\t<other>   Quit\n");
        scanf("%d",&chose);
        getchar();  //Refresh LF 

        if( 1 != chose )
            goto cleanup;

        printf("Enter phone number:  ");
        scanf("%s",phone_number);
        getchar();

        printf("\nEnter SMS:  ");
        fgets(sms_buf,sizeof(sms_buf),stdin);

        /* Delete the LF brought by fgets() */
        for(i = 0; i < sizeof(sms_buf); i++)
        {
            if(sms_buf[i] == 0x0a)
            {
                sms_buf[i] = 0;
                break;
            }
        }

        printf("\n");

        /* Identify whether the text message format is TEXT or PDU */
        sms_type = identify_sms_type(sms_buf,strlen(sms_buf));

        /* PDU */
        if(0 == sms_type)
        {
            if(pdu_sms_send(comport,sms_buf,phone_number) < 0)
            {
                printf("PDU SMS Sent failed\n");
                continue;
            }
        }

        /* TEXT */
        else if(1 == sms_type)
        {
            if(text_sms_send(comport,sms_buf,phone_number) < 0)
            {
                printf("TEXT SMS Sent failed\n");
                continue;
            }
        }

        else 
            continue;

    }


cleanup:
    comport_close(comport);

    return 0;
}

void help_information()
{
    printf("SMS Sending System v1.0.2(Mon 13 Jul 05:08:24 BST 2020)\n");
    printf("\nUsage:./sms [-b BaudRate] [-d Databits] [-p Parity] [-s StopBits] [-n SerialName]\n\n");
    printf("\t-b   Set BaudRate\n");
    printf("\t-d   Set Databits\n");
    printf("\t-p   Set Parity,0 for no parity,1 for Odd parity,2 for Evev parity\n");
    printf("\t-s   Set StopBits\n");
    printf("\t-n   Set the name of the serial port you want to use\n");
    printf("\nCtrl + c to exit the program\n");
    printf("\n\tIf you do not specify parameters,The default parameters of the program are as follows:\n\n");
    printf("\tBaudRate: 1115200\n\tDatabits: 8bits\n\tParity:   no parity\n\tStopBits: 1bits\n");
}

int identify_sms_type(const char *sms_buf,int buf_len)
{
    int     i;

    for(i = 0; i < buf_len; i++)
    {
        if( (int)sms_buf[i] > 0x7F)
            return 0;
    }

    return 1;
}

四. makefile 及 其他功能

makefile

(CC) = gcc

sms: sms_main.c comport.o PDU.o sms.o
    $(CC) sms_main.c comport.o PDU.o sms.o -o sms -Wall -Werror

comport.o: comport.c
    $(CC) -c comport.c

PUD.o: PUD.c
    $(CC) -c PDU.c

sms.o: sms.c
    $(CC) -c sms.c

clear:
    rm *.o sms

不指定串口名或使用 -h 选项打印程序相关信息:
在这里插入图片描述
到这里,程序就可以像手机发短信一样发送中英文短信啦,不用再自己编码,计算,拼接,只需要输入手机号码,短信内容,就可以发送短信了…

源码已经在四篇博客中全部给出,代码也还将继续优化,需要源码地址的小伙伴可以私聊我哟…

Logo

更多推荐