📄 sms.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 + -