⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sms.c

📁 This is full set of procedures used to communicate with any GSM module for SMS sending/receiving (
💻 C
字号:
/*
 *  FILE:
 *     sms.c (rev. 1.3 - 27.08.2007)
 *
 *  PROJECT:
 *     GSM Communication Module
 *
 *  DESCRIPTION:
 *     See file "sms.h" for details
 *
*/

#include <string.h>
#include <stdlib.h>
#include <pgmspace.h>
#include "gsm-link.h"
#include "types.h"
#include "timer.h"
#include "sms.h"

// AT commands to handle SMS
__flash U8 SMS_AT[]="AT";                   // Attention (check availability of AT modem)
__flash U8 SMS_ATZ[]="ATZ";                 // Reset modem
__flash U8 SMS_ATE0[]="ATE0";               // Echo off
__flash U8 SMS_ATCPBS[]="AT+CPBS=\"SM\"";   // Select SIM Phonebook
__flash U8 SMS_ATCMGF[]="AT+CMGF=0";        // Select PDU SMS mode
__flash U8 SMS_ATCNMI[]="AT+CNMI=1,0,0,2,1";// Turn on new SMS announcement mode
__flash U8 SMS_ATCPMS[]="AT+CPMS=\"ME\"";   // Select SMS memory (ME - Mobile Equipment)
__flash U8 SMS_ATCPBR[]="AT+CPBR=";         // Read phone number from Phonebook
__flash U8 SMS_SEND[]="AT+CMGS=";           // Send SMS
__flash U8 SMS_GET[]="AT+CMGR=";            // Get SMS
__flash U8 SMS_DEL[]="AT+CMGD=";            // Delete SMS
__flash U8 SMS_PDU_part1[]="0011000C91";    // Header of PDU message
__flash U8 SMS_PDU_part2[]="0000AA";        // Middle part of PDU message

// Commands, and its reference notations
__flash U8 SMS_Cmd[7][4]={"ARM","VAC","PAN","DIS","SWT","SCN","IRC"};
__flash U8 SMS_Ref[7][5]={"Arm","Vac","Pan","Dis|","Swt|","Scn|","IRc|"};

// Help string
__flash U8 SMS_Help[]="Arm,DisXXXX,Vac,Pan,SwtXX,ScnXX,IRcXX";

// Service reply messages
__flash U8 SMS_ON[]="Turned ON";
__flash U8 SMS_OFF[]="Turned OFF";
__flash U8 SMS_Feedback[]="Delayed switch";
__flash U8 SMS_Done[]="Done!";
__flash U8 SMS_Wrong[]="Wrong entry! Send ? for help.";

U8* SMS_Buf;    // SMS buffer
U8  SMS_ToDo;   // bits 3:0 keep index of last SMS phone number, bits 7:4 - tracking event

// Read upon startup and keep in CommMemory users phone numbers
U8  SMS_Phone[4][17]={"","","",""};

// Convert hex to string (internal function)
void SMS_Hex2String(U8 hex,U8* string) {
    U8 i;
    i=(hex>>4)&0xF;
    if (i>9) i=i-10+'A';
    else i+='0';
    string[0]=i;
    i=hex&0xF;
    if (i>9) i=i-10+'A';
    else i+='0';
    string[1]=i;
}

// Convert 2-byte string to hex (internal function)
U8 SMS_String2Hex(U8* string) {
    U8 i;
    if ((string[0]>='0') && (string[0]<='9')) i=(string[0]-'0')<<4;
    else if ((string[0]>='A') && (string[0]<='F')) i=(string[0]-'A'+10)<<4;
    else return 0;
    if ((string[1]>='0') && (string[1]<='9')) i|=(string[1]-'0');
    else if ((string[1]>='A') && (string[1]<='F')) i|=(string[1]-'A'+10);
    else return 0;
    return i;
}

// Send AT command (internal function)
U8 SMS_AT_Send(const char __flash * data) {
    strcpy_P(SMS_Buf,data);
    return GSM_TransmitAck(SMS_Buf,strlen(SMS_Buf),1);
}

// Converts plain text to PDU message (internal function)
// Returns output size
U8 SMS_Text2PDU(U8* src,U8* dest,U8 size) {
    U8 shift,ch1,ch2,i,j;
    for (i=0,j=0,shift=0;i<size;i++) {
        ch1=(src[i]&0x7f)>>shift;
        ch2=(src[i+1]&0x7f)<<(7-shift);
        shift++;
        ch1=ch1|ch2;
        if (shift==7) {shift=0; i++;}
        dest[j++]=ch1;
    }
    return (j-1);
}

// Converts PDU message to plain text (internal function)
// Returns output size
U8 SMS_PDU2Text(U8* src,U8* dest,U8 size) {
    U8 i,j;
    for (i=0,j=0;i<size;i++) {
        if (i%7==0) dest[j++]=src[i]&0x7F;
        else if (i%7==6) {
            dest[j++]=((src[i]<<6)|(src[i-1]>>2))&0x7F;
            dest[j++]=(src[i]>>1)&0x7F;
        }
        else dest[j++]=((src[i]<<(i%7)) | (src[i-1]>>(7+1-(i%7))))&0x7F;
    }
    return j;
}

// Transform command to ready for sending form (internal function)
U8 SMS_ProcessCmd(U8* data,U8 size) {
    U8 i,j;
    if (size>9) return FAIL;
    // Convert to upper-case for comparison
    for (i=0;i<3;i++) if (data[i]>0x5A) data[i]-=0x20;
    // Searching for command index
    for (i=0;i<7;i++) if (strncmp_P(data,SMS_Cmd[i],3)==0) break;
    if (i==7) return FAIL;
    // Prepare command for main block
    data[0]='!';
    data[1]='{';
    // Move numeric part of message +1 position right and add leading 0 if necessary
    if (i>3) {
        if (size==4) {
            data[7]=data[3];
            data[6]='0';
        }
        else {
            data[7]=data[4];
            data[6]=data[3];
        }
        strncpy_P(data+2,SMS_Ref[i],4);
        data[8]='}';
        data[9]=0;
    }
    else if (i==3) {
        for (j=size-1;j>2;j--) data[j+3]=data[j];
        strncpy_P(data+2,SMS_Ref[i],4);
        data[size+3]='}';
        data[size+4]=0;
    }
    else {
        strncpy_P(data+2,SMS_Ref[i],3);
        data[5]='}';
        data[6]=0;
    }
    return OK;
}

// Initialize SMS processor
void SMS_Init(void) {
    U8 i,j,k;

    SMS_ToDo=0;
    SMS_Buf=malloc(128);
    if (SMS_Buf==NULL) {
        BIT_CLR(GSM_Status,ST_ENABLED);
        return;
    }
    SMS_AT_Send(SMS_AT);            // Synchronize with GSM modem
    SMS_AT_Send(SMS_ATZ);           // Reset GSM modem
    SMS_AT_Send(SMS_ATE0);          // Echo off
    if (SMS_AT_Send(SMS_AT)!=OK) {  // Check modem answer
        BIT_CLR(GSM_Status,ST_ENABLED);
        free(SMS_Buf);
        return;
    }
    SMS_AT_Send(SMS_ATCPBS);        // Select SIM Phonebook
    SMS_AT_Send(SMS_ATCMGF);        // Select PDU SMS mode
    SMS_AT_Send(SMS_ATCPMS);        // Select SMS memory (ME - Mobile Equipment)

    // Read user phone numbers
    for (i=1;i<5;i++) {
        // Read phone number from SIM memory (AT+CPBR)
        strcpy_P(SMS_Buf,SMS_ATCPBR);
        j=strlen(SMS_Buf);
        SMS_Buf[j++]=i+'0';
        SMS_Buf[j]=0;
        j=GSM_TransmitAck(SMS_Buf,j,5);
        if (j==FAIL) break;
        // Find beginning of phone number in modem answer
        for (j=0;j<GSM_size;j++)
            if ((GSM_Buf[j]=='\"') && (GSM_Buf[j+1]=='+')) break;
        if (j==GSM_size) SMS_Phone[i-1][0]=0;
        else {
            // Copy phone number to internal storage
            j+=2;
            for (k=j;k<GSM_size;k++) {
                if (GSM_Buf[k]=='\"') {
                    // If odd number of digits
                    if ((k-j)&1) {
                        SMS_Phone[i-1][k-j]='F';
                        k++;
                    }
                    SMS_Phone[i-1][k-j]=0;
                    k=k-j;
                    break;
                }
                SMS_Phone[i-1][k-j]=GSM_Buf[k];
            }
            // Swap bytes in number
            for (j=0;j<k;j+=2)
                SMS_Phone[i-1][j]^=SMS_Phone[i-1][j+1]^=SMS_Phone[i-1][j]^=SMS_Phone[i-1][j+1];

        }
    }

    free(SMS_Buf);
}

// Periodically checks for new SMS (period is defined by SMS_CHECK_PERIOD)
// Returns number of SMS in memory
U8 SMS_Check(void) {
    U8  i,j;
    U8* tmpBuf;

    // If GSM function is disabled
    if (!BIT(GSM_Status,ST_ENABLED)) return 0;
    // If there is feedback information to be sent to last sender
    if (SMS_ToDo) {
        tmpBuf=malloc(strlen_P(SMS_Help)+1);
        if (tmpBuf!=NULL) {
            tmpBuf[0]=0;
            if ((SMS_ToDo>>4)==0xF) strcpy_P(tmpBuf,SMS_Wrong);     // Unrecongnized command
            else if ((SMS_ToDo>>4)==0x0) strcpy_P(tmpBuf,SMS_Help); // Send help message
            else {
                if (BIT(MAIN_Status,ST_ACK)) {
                    if (BIT(MAIN_Ack,SV_OK)) strcpy_P(tmpBuf,SMS_Done);
                    else if (BIT(MAIN_Ack,SV_0)) strcpy_P(tmpBuf,SMS_OFF);
                    else if (BIT(MAIN_Ack,SV_1)) strcpy_P(tmpBuf,SMS_ON);
                    else if (BIT(MAIN_Ack,SV_Wrong)) strcpy_P(tmpBuf,SMS_Wrong);
                    else if (BIT(MAIN_Ack,SV_Feedback)) strcpy_P(tmpBuf,SMS_Feedback);
                }

            }
            if (strlen(tmpBuf)) {
                SMS_Send(tmpBuf,strlen(tmpBuf),SMS_ToDo&0xF);
                SMS_ToDo=0;
            }
            free(tmpBuf);
        }
    }

    // Check for new SMS every 10 sec.
    if (TMR_SMS) return 0;
    SMS_Buf=malloc(128);
    if (SMS_Buf==NULL) return 0;
    // Select SMS memory (ME - Mobile Equipment)
    strcpy_P(SMS_Buf,SMS_ATCPMS);
    GSM_TransmitAck(SMS_Buf,strlen(SMS_Buf),2);
    // Extract number of SMS in memory
    for (i=0,j=0;i<GSM_size;i++) {
        if (j==1) {
            SMS_Buf[j]=GSM_Buf[i];
            if (SMS_Buf[j]==',') {
                SMS_Buf[j]=0;
                break;
            }
            j++;
        }
        else if (GSM_Buf[i]==':') SMS_Buf[j++]=GSM_Buf[++i];
    }
    // j will keep the number of SMS in memory
    if (j) {
        for (j=0,i=0;i<3;i++) {
            if (SMS_Buf[i]==0) break;
            if ((SMS_Buf[i]>'9') || (SMS_Buf[i]<'0')) {
                j=0;
                break;
            }
            j*=10;
            j+=SMS_Buf[i]-'0';
        }
    }
    TMR_SMS=SMS_CHECK_PERIOD;
    free(SMS_Buf);
    return j;
}

// Read and interpret new SMS (num - sequence number of SMS, max num: 9)
void SMS_Read(U8 num) {
    U8  i,j,attempt,size,phonepos,phonesize,txtpos,txtsize;
    U8* tmpBuf;

    // If GSM function is disabled
    if (!BIT(GSM_Status,ST_ENABLED)) return;
    // Allocate memory for SMS
    SMS_Buf=malloc(128);
    if (SMS_Buf==NULL) return;

    // Read SMS from memory
    for (attempt=0;attempt<5;attempt++) {
        strcpy_P(SMS_Buf,SMS_GET);
        i=strlen(SMS_Buf);
        SMS_Buf[i++]=num+'0';
        SMS_Buf[i]=0;
        i=GSM_TransmitAck(SMS_Buf,i,5);
        if (i==FAIL) {
            free(SMS_Buf);
            return;
        }

        size=strlen(GSM_Buf);
        // Find phone number and text body in PDU message
        // Initialize i by first position of PDU message
        for (i=0,j=0;i<size;i++){
            if ((GSM_Buf[i]==' ') && j) {
                i++;
                break;
            }
            if (GSM_Buf[i]==',') j++;
        }
        // If not found
        if (i==size) continue;
        // If string is incorrect
        for (j=i;j<size;j++) {
            if ((GSM_Buf[j]<'0') || (GSM_Buf[j]>'F') || ((GSM_Buf[j]>'9') && (GSM_Buf[j]<'A'))) break;
        }
        if (j<size) continue;
        else break;
    }

    if (attempt==5) {
        free(SMS_Buf);
        return;
    }

    i=SMS_String2Hex(GSM_Buf+i)*2+4+i;
    phonesize=SMS_String2Hex(GSM_Buf+i);
    phonepos=i+4;
    if (phonesize&1) phonesize++;

    txtpos=phonepos+phonesize+20;
    txtsize=size-txtpos;

    // Send debug info on terminal
    if (GEN_DebugMode!='-') {
        GSM_Buf[phonepos-1]='6';
        PC_Transmit(GSM_Buf+phonepos-1,phonesize+1,ORIGINAL);
        GSM_Buf[txtpos-1]='6';
        PC_Transmit(GSM_Buf+txtpos-1,txtsize+1,ORIGINAL);
    }

    // Allocate temporary buffer for storing of SMS data
    tmpBuf=malloc(txtsize+10);
    if (tmpBuf==0) {
        free(SMS_Buf);
        return;
    }

    // Transform text to hexadecimal form
    for (i=txtpos;i<txtpos+txtsize;i+=2)
        GSM_Buf[txtpos+((i-txtpos)>>1)]=SMS_String2Hex(GSM_Buf+i);
    // Decode PDU message to text
    txtsize=SMS_PDU2Text(GSM_Buf+txtpos,tmpBuf,txtsize>>1);

    // Send debug info on terminal
    if (GEN_DebugMode!='-') {
        PC_Transmit(tmpBuf,txtsize,ORIGINAL);
    }

    // Check phone of SMS sender
    for (i=1;i<5;i++) {
        if (strncmp(GSM_Buf+phonepos,SMS_Phone[i-1],phonesize)==0) break;
    }
    // If correct number was found
    if (i<5) {
        // If help request
        if (tmpBuf[0]=='?') SMS_ToDo=i;
        else if (SMS_ProcessCmd(tmpBuf,txtsize)==OK) {
            SMS_ToDo=0x10|i;
            MAIN_Ack=0;
            MAIN_Transmit(tmpBuf,strlen(tmpBuf));
        }
        else SMS_ToDo=0xF0|i;
    }

    // Delete processed SMS from memory
    strcpy_P(SMS_Buf,SMS_DEL);
    i=strlen(SMS_Buf);
    SMS_Buf[i++]=num+'0';
    SMS_Buf[i]=0;
    GSM_TransmitAck(SMS_Buf,i,5);
    free(SMS_Buf);
    free(tmpBuf);
}

// Send SMS to specified phone #
U8 SMS_Send(U8* data,U8 size,U8 phone) {
    U8 i,j,k,tmp;
    U8* tmpBuf;

    // If GSM function is disabled
    if (!BIT(GSM_Status,ST_ENABLED)) return FAIL;

    // If there is no phone number in position "phone"
    if (strlen(SMS_Phone[phone-1])==0) return FAIL;

    // Allocate memory for SMS
    SMS_Buf=malloc(128);
    if (SMS_Buf==NULL) return FAIL;

    // Encode SMS text
    for (i=0;i<100;i++) SMS_Buf[i]=0;
    k=SMS_Text2PDU(data,SMS_Buf,size)+15;
    tmpBuf=malloc(k+1);
    if (tmpBuf==NULL) {
        free(SMS_Buf);
        return FAIL;
    }
    for (i=0;i<k;i++) tmpBuf[i]=SMS_Buf[i];
    tmpBuf[i]=0;

    // Send command AT+CMGS
    strcpy_P(SMS_Buf,SMS_SEND);
    j=strlen(SMS_Phone[phone-1]);
    k+=(j/2)-6;
    j=strlen(SMS_Buf);
    SMS_Buf[j++]=(k/100)+'0'; k-=(k/100)*100;
    SMS_Buf[j++]=(k/10)+'0'; k-=(k/10)*10;
    SMS_Buf[j++]=k+'0';
    SMS_Buf[j]=0;
    tmp=GSM_TransmitAck(SMS_Buf,j,2);
    if (tmp==FAIL) {
        free(SMS_Buf);
        free(tmpBuf);
        return FAIL;
    }

    // Submit header and PDU text
    strcpy_P(SMS_Buf,SMS_PDU_part1);
    // Correct phone length
    j=strlen(SMS_Phone[phone-1]);
    if (SMS_Phone[phone-1][j-2]=='F') j--;
    SMS_Hex2String(j,SMS_Buf+6);
    // Copy phone number
    for (j=10;;j++) {
        if (SMS_Phone[phone-1][j-10]==0) break;
        SMS_Buf[j]=SMS_Phone[phone-1][j-10];
    }
    strcpy_P(SMS_Buf+j,SMS_PDU_part2);
    j+=6;
    // Add text message size
    SMS_Hex2String(size,SMS_Buf+j);
    j+=2;

    for (i=0;tmpBuf[i]!=0;i++,j+=2) SMS_Hex2String(tmpBuf[i],SMS_Buf+j);

    SMS_Buf[j++]=0x1A;
    SMS_Buf[j]=0;
    tmp=GSM_TransmitAck(SMS_Buf,j,1);
    free(tmpBuf);
    free(SMS_Buf);
    return OK;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -