GPRS-SIM900模块应用程序——双线程支持发短信接打电话

之前分别写了两个功能类别的代码。。今天来吧这两个整合一下。。

#include<termios.h>      //save struct from serial_init tcgetattr
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include <pthread.h>

#define len_number  16
#define len_message 128
#define len_swap    32

int choice=0;              //输入选择的全局变量

pthread_mutex_t mutex;      //线程锁

int thread(void); //声明线程函数 

struct message_info{                //信息结构体。。包括号码和信息
    char cnnu[len_number];
    char phnu[len_number];
    char message[len_message];
};

struct pdu_info{                    //转换号码的结构体。。中文短信用到
    char cnswap[len_swap];
    char phswap[len_swap];
};
  
void serial_init(int fd)                   //初始化串口
{
    struct termios options;
    tcgetattr(fd, &options);
    options.c_cflag |= (CLOCAL | CREAD);
    options.c_cflag &= ~CSIZE;
    options.c_cflag &= ~CRTSCTS;
    options.c_cflag |= CS8;
    options.c_cflag &= ~CSTOPB;
    options.c_iflag |= IGNPAR;
    options.c_oflag  = 0;
    options.c_lflag  = 0;

    cfsetispeed(&options, B115200);          //根据自己的波特率进行相应更改
    cfsetospeed(&options, B115200);
    tcsetattr(fd, TCSANOW, &options);
}

//************************下面是打电话和发短信的部分*******************//
 
void swap(char number[], char swap[])              //发送中文短信时用到的函数
{
    char ch1[] = "86";
    char tmp[len_number];
    int i;

    memset(swap, 0, len_swap);
    memset(tmp, 0, len_number);
    strcpy(swap, number);
    strcat(swap, "f");    //our phnu is 11 less then 12 so add "f" in the end
    strcat(ch1, swap);
    strcpy(swap, ch1);

    for(i=0; i<strlen(swap)-1; i+=2)
    {
        tmp[i+1] = swap[i];
        tmp[i] = swap[i+1];
    }

    strcpy(swap, tmp);
}

int send(int fd, char *cmgf, char *cmgs, char *message)           //发送函数
{
    int nread;
    int nwrite;
    char buff[len_message];
    char reply[len_message];

    memset(buff, 0, len_message); //输入“at+回车”。。并读取返回结果。。将其打印到屏幕上
    strcpy(buff, "at\r");
    nwrite = write(fd, buff, strlen(buff));
    printf("nwrite = %d,%s\n",nwrite, buff);

    memset(reply, 0, len_message);
    sleep(1);
    nread = read(fd, reply, sizeof(reply));
    printf("nread = %d,%s\n",nread, reply);

    memset(buff, 0, len_message); //输入"AT+CMGF="。。选择短消息格式。。
    strcpy(buff, "AT+CMGF="); //1对应文本格式。。不支持中文。。0对应PDU模式。。支持中文
    strcat(buff, cmgf); //并读取返回信息。。将其打印到屏幕上
    strcat(buff, "\r");
    nwrite = write(fd, buff, strlen(buff));
    printf("nwrite = %d,%s\n", nwrite, buff);

    memset(reply, 0, len_message);
    sleep(1);
    nread = read(fd, reply, sizeof(reply));
    printf("nread = %d,%s\n", nread, reply);

    memset(buff, 0, len_message); //输入"AT+CMGS="。。设置字符格式为GSM 模式。。可不用
    strcpy(buff, "AT+CMGS=");
    strcat(buff, cmgs);
    strcat(buff, "\r");
    nwrite = write(fd, buff, strlen(buff));
    printf("nwrite = %d,%s\n",nwrite, buff);

    memset(reply, 0, len_message);
    sleep(1);
    nread = read(fd, reply, sizeof(reply));
    printf("nread = %d,%s\n",nread, reply);
    
    memset(buff, 0, len_message); //输入信息字符串。。
    strcpy(buff, message);
    nwrite = write(fd, buff, strlen(buff));
    printf("nwrite = %d,%s\n",nwrite, buff);

    memset(reply, 0, len_message);
    sleep(1);
    nread = read(fd, reply, sizeof(reply));
    printf("nread = %d,%s\n",nread, reply);
}


int call(int fd, char *atd) //打电话子函数
{
    int nread;
    int nwrite;
    char buff[len_message];
    char reply[len_message];

    memset(buff, 0, len_message); //发送“at+回车”
    strcpy(buff, "at\r");
    nwrite = write(fd, buff, strlen(buff));
    printf("nwrite = %d,%s\n", nwrite, buff);

    memset(reply, 0, len_message);
    sleep(1);
    nread = read(fd, reply, sizeof(reply));
    printf("nread = %d,%s\n" , nread, reply);

    memset(buff, 0, len_message); //发送“atd+处理好格式的号码字符串”
    strcpy(buff, "atd");
    strcat(buff, atd);
    strcat(buff, "\r");
    nwrite = write(fd, buff, strlen(buff));
    printf("nwrite = %d,%s\n" , nwrite, buff);

    memset(reply, 0, len_message);
    sleep(1);
    nread = read(fd, reply, sizeof(reply));
    printf("nread = %d,%s\n", nread, reply);
}

int call_phone(int fd, struct message_info info) //打电话函数
{
    int conter = 0;
    char atd[16] = {'\0'};
    
    getchar(); //吃掉回车
    printf("enter your phonenumber:\n");
    fgets(info.phnu, (len_message - 1), stdin); //对输入的电话号码进行处理
    while(strlen(info.phnu) != 12)
    {
        if(conter >= 3) //超过三次输入错误即退出
        {
            printf("conter out!\n");
            return -1;
        }
        printf("number should be --11-- bits, enter again:");
        fgets(info.phnu, (len_message - 1), stdin);
        conter++;
    }
    strcat(atd, info.phnu);
    atd[11] =(char){';'};

    call(fd, atd); //处理完号码之后调用打电话子函数
}


int send_en_message(int fd, struct message_info info)//发送英文短信
{
    getchar();
    char cmgf[] = "1";
    int conter = 0;
    char cmgs[16] = {'\0'};

    printf("enter your number:\n");
    fgets(info.phnu, (len_number - 1), stdin); //接受号码
    while(strlen(info.phnu) != 12)
    {
        if(conter == 3)
        {
            printf("contr out!\n");
            return -1;
        }
        printf("number should be --11-- bits ! enter again:");
        fgets(info.phnu, (len_number - 1), stdin);
        conter++;
    }
    printf("enter your message:\n"); //接受短信字符串
    fgets(info.message, (len_message), stdin);
    strcat(info.message, "\x1a"); //at命令发送短信时。。输入短信字符串之后要求
    strcat(cmgs, "\""); //输入ctrl+z而不是回车。。所以这里不加“\r”而是加“\x1a”
    strcat(cmgs, info.phnu); //这里的电话号码也要用“”变形。。所以加入转意”
    cmgs[12] =(char) {'\"'};

    send(fd, cmgf, cmgs, info.message);
}

int send_ch_message(int fd, struct message_info info)//发送中文短信
{
    char cmgf[] = "0";
    char cmgs[4] = {'\0'};
    char ch2[] = "0891";
    char ch3[] = "1100";
    char ch4[] = "000800";
    char ch5[] = "0d91";
    char final[128];
    char *message[3] = {
        "0a5bb691cc7740706bff01", //中文短信这里进行的转码。。本人没做详细实验仅仅是借鉴了网络。。
        "0a5bb691cc67098d3cff01", //这里需要根据自己输入的号码进行修改。。而不是这串数字固定不变
        "1a676866539e4fff0c4f605988558a4f6056de5bb65403996dff01"
    };
    struct pdu_info pdu;
    int conter = 0;
    int flag, len,d;
    
    getchar();
    memset(final, 0, 80);

    printf("enter your centre phnumber:\n");
    fgets(info.cnnu, (len_number - 1), stdin);
    while(strlen(info.cnnu) != 11)
    {
        if(conter == 3)
        {
            printf("conter out!\n");
            return -1;
        }
        printf("number should be --11-- bits!enter again:\n");
        fgets(info.cnnu, (len_number - 1), stdin);
        conter++;
    }
   
    conter = 0;
    printf("enter your recever number:\n");
    fgets(info.phnu, (len_number - 1), stdin);
    while(strlen(info.phnu) != 11)
    {
        if(conter == 3)
        {
            printf("conter out!\n");
            return -1;
        }
        printf("number should be --11-- bits!enter again:\n");
        fgets(info.phnu, (len_number - 1), stdin);
        conter++;
    }

    printf("choice message:\n");
    printf("1.fire.\n");
    printf("2.theif.\n");
    printf("3.mother@home.\n");
    scanf("%d", &flag);
    swap(info.phnu, pdu.phswap);
    swap(info.cnnu, pdu.cnswap);

    strcpy(final, ch2);
    strcat(final, pdu.cnswap);
    strcat(final, ch3);
    strcat(final, ch5);
    strcat(final, pdu.cnswap);
    strcat(final, ch4);
    strcat(final, message[flag - 1]);
    strcat(final, "\x1a");

    len = strlen(ch3)+strlen(ch4)+strlen(ch5)+strlen(pdu.phswap)+strlen(message[flag - 1]);
    puts(final);
    sprintf(cmgs, "%d", len/2);
    puts(final);
    send(fd, cmgf, cmgs, final);
}

//******************下面是接电话部分*****************//

int receive(int fd) //接电话函数
{
    char reply1[16];
    char buff1[16];
    int nread1;
    int nwrite1;
    int choice;

    getchar();
    memset(buff1, 0, 16); //当电话来临时候。。输入“ata\r”代表接听
    strcpy(buff1, "ata\r");
    nwrite1 = write(fd, buff1, strlen(buff1));
    printf("nwrite1 = %d,%s\n", nwrite1, buff1);

    memset(reply1, 0, 16);
    sleep(1);
    nread1 = read(fd, reply1, sizeof(reply1));
    printf("nread1 = %d,%s\n", nread1, reply1);

    printf("input 1 to ath!\n");
    choice = getchar();
    getchar();
    switch(choice) //接听之后输入“ath\r”表示挂断
    {
        case '1':memset(buff1, 0, 16);
                 strcpy(buff1, "ath\r");
                 nwrite1 = write(fd, buff1, strlen(buff1));
                 printf("nwrite1 = %d,%s\n", nwrite1, buff1);
                 break;
        default:break;
    }
}

int not(int fd) //不接听函数
{
    char reply1[16];
    char buff1[16];
    int nread1;
    int nwrite1;
    
    getchar();
    memset(buff1, 0, 16); //当不需要接听时。。直接输入"ath\r"即可挂断
    strcpy(buff1, "ath\r");
    nwrite1 = write(fd, buff1, strlen(buff1));
    printf("nwrite1 = %d,%s\n", nwrite1, buff1);

    memset(reply1, 0, 16);
    sleep(1);
    nread1 = read(fd, reply1, sizeof(reply1));
    printf("nread1 = %d,%s\n", nread1, reply1);
}

int main(int argc, char **argv) //main函数
{
    int fd;
    struct message_info info;
    int ret;

    pthread_t id;

    fd = open ("/dev/ttyS1", O_RDWR|O_NOCTTY|O_NDELAY);//我的模块外接串口是ttyS1

    if (fd < 0)
    {
        perror("Can't open ttyS1!\n");
return -1;
    }
    serial_init(fd); //初始化串口
ret=pthread_create(&id,NULL,(void *) thread,NULL);//创建线程
if(ret!=0)
{
          printf ("Create pthread error!\n");
          return -1;
    }
while(1)
{
            pthread_mutex_lock (&mutex); //线程锁。。当打电话进来时启用接电话线程。。
//当发短信打电话时不能进入接电话线程。。模块不允许同时两个功能
printf("enter your selete 1 is english, 2 is chinese, 3 is call:\n");

            if ((choice>3)||(choice<1)) //这里当我的全局变量不是我这个进程需要的值得时候..选择接受输入
            { //如果是我需要的值。。就不输入了。。因为双线程共享缓冲区
                scanf("%d",&choice); //这里是防止另一个进程接收到本想传给本进程的参数使用的算法
            }
switch(choice)//功能选择
{
case 1:send_en_message(fd, info);
break;
case 2:send_ch_message(fd, info);
break;
case 3:call_phone(fd, info);
break;
default:break;
}
pthread_mutex_unlock(&mutex);//当完成一个功能之后解锁。。进入下一次循环
            sleep(1); //一定要有休眠。。不然线程调度会出错

}
pthread_join(id,NULL);//当程序退出时关闭线程


    close (fd); //关闭文件描述符
    return 0;
}

int thread(void) //接电话线程
{
char reply[16];
char str[] = "\n\nRING";//检测接电话时模块显示的字符串。。我的模块显示RING之前有两个换行
int nread; //其余模块这里可能不一样
int nwrite;
char buff[16];
        int ret;
int fd;

fd = open ("/dev/ttyS1", O_RDWR|O_NOCTTY|O_NDELAY);

if (fd < 0)
        {
               perror("Can't open ttyS1!\n");
               return -1;                        
        }

memset(buff, 0, 16);
strcpy(buff, "at\r");
nwrite = write(fd, buff, strlen(buff));

memset(reply, 0, 16);
sleep(1);
nread = read(fd, reply, sizeof(reply));

while(1)
{
memset(reply, 0, 16);
sleep(1);
nread = read(fd, reply, sizeof(reply));
if(!(strncmp(reply, str, 6)))//循环检测串口输出的字符串
{
printf("this is a phone 4 is receive 5 is not\n");

pthread_mutex_lock (&mutex);//如果是电话打进来即上锁

                if((choice !=4)&&(choice != 5)) //功能函数。。同主线程
                {
scanf("%d", &choice);
}

switch(choice)//选择函数
{
case 4:receive(fd);
break;
case 5:not(fd);
break;
default:break;
}
pthread_mutex_unlock(&mutex);                     //解锁

choice = 0;
}
}
}

因为接电话没办法设置一个中断。。所以不能用中断调用函数。。只能用while循环一直检测。。同时又不能放在一个进程或者线程里面。。所以想到了多线程。。

其实初期想到的是多进程。。但是百度了一下多进程没有锁函数。。而自己实现一个锁又比较难。。反正我试了一个晚上也没太多眉目。。就放弃了。。采用了多线程。。

至于为什么加锁。。模拟显示。。当有电话打来时候优先选择接电话。。此时需要加锁吧缓冲区锁住。。试函数一直运行在子线程中。。

至于为什么这个里面给刚一进入选择发短信还是打电话的界面就上锁。。是因为我用的模块的串口线是单线。。也就是说同一时间只能存在一种工作方式。。换言之接电话时候不能发短信。。同理发短信时候也不能接听电话。。这虽然和实际生活中的智能机不一样。。单是我们的硬件也不是那么高端。。就退一步采用了这种处理措施。。

子函数部分和之前两篇一样。。这里就大概说明一下多线程的使用和锁的使用。。

多线程。。顾名思义两个线程。。每个执行执行一项功能。。用在这里一个执行循环检测。。一个执行发短信打电话

ret=pthread_create(&id,NULL,(void *) thread,NULL);进程的创建函数。。在main里面创建了进程。。进程名为thread。。

然后用这个进程名作为一个函数名。。里面执行另一个进程要执行的事情。。

这里所有的从标准输入读进来的数都保存到全局变量choice之中。。公用一套编码。。以免出现混淆。。

再说一下我对接收的choice的处理。。这里先给choice一个初值。。使其进入到主线程。。上锁。。并且等待输入的状态。。因为按理说肯定是主线程在缓冲区队列排在前面。。这时如果来了电话。。我输入了一个和接电话有关的参数。。这个参数不满足我这个线程的需求参数。。解锁开始下一次循环。。这里解锁之后sleep一秒是有必要的。。如果不sleep很可能程序顺序执行继续给这个进程上锁。。需要sleep一秒。。让另一个线程上锁。。这时检测到这个choice是符合条件的。。不用scanf直接处理数字。。就达到了从一个线程通过参数调到另一个线程并执行想要的程序的效果

需要说明的是。。每一个功能函数调用之后。。如接打电话发短信。。之后要把choice值设置为初值


特别提醒。。加了线程之后注意编译格式。。

gcc main.c -o main -pthread

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值