Linux串口编程短信篇(四) ——— 实现最简单的4G模块短信发送
一. 像手机一样发送短信1.1 看看效果在介绍main程序之前,先来看一下效果吧~其中,cmgs,pdu 是PDU编码是的中间产物,也就是使用原始AT命令发送PDU短信时,需要自己计算填写到的数值,这个数值只有算的全部正确才能发送成功,打印出来是为了调试所用,也可以将其关闭显示. 可到PDU.c的文件中将1改成0可关闭pdu编码显示:继续测试: 1.2 提出问题前面说了,发送短信有两种格
文章目录
一. 像手机一样发送短信
1.1 看看效果
在介绍main程序之前,先来看一下效果吧~
其中,cmgs,pdu 是PDU编码是的中间产物,也就是使用原始AT命令发送PDU短信时,需要自己计算填写到的数值,这个数值只有算的全部正确才能发送成功,打印出来是为了调试所用,也可以将其关闭显示.
可到PDU.c的文件中将1改成0可关闭pdu编码显示:
继续测试:
1.2 提出问题
- 前面说了,发送短信有两种格式,但是我在这里却没有显示输入要发送哪种格式的短信,这是怎么实现的呢?
- 既然是使用到了串口,那如何不使用默认值来指定串口的属性,如波特率,数据位和奇偶校验等…
- 是如何使用 -n 来指定串口名的呢?
- 这么多功能模块,这么多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 选项打印程序相关信息:
到这里,程序就可以像手机发短信一样发送中英文短信啦,不用再自己编码,计算,拼接,只需要输入手机号码,短信内容,就可以发送短信了…
源码已经在四篇博客中全部给出,代码也还将继续优化,需要源码地址的小伙伴可以私聊我哟…
更多推荐
所有评论(0)