cb77
Published

Raspberry pi SMS

Software for Raspberry pi to send and receive SMS. Also you can send commands to the raspberry pi to do specific actions.

IntermediateProtip1 hour2,375
Raspberry pi SMS

Things used in this project

Story

Read more

Code

Rsspberry PI SMS Code for C and C++

C/C++
Please look at the end of this file for the C++ code.
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <pthread.h>
#include <wiringSerial.h>
#include <termios.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
//************************************************************************

#define true (1==1)
#define false !true
#define READ_BUF_LEN 1024
#define SEND_SMS_LEN 160
#define MAX_STR_LEN 20
#define MAXELEMENTS 10
#define SERIAL_DEVICE "/dev/ttyAMA0"	//RaspberryPi 2 Serial
#define SERIAL_BAUD 115200

#define ACTION_START 1
#define ACTION_STOP 2
#define ACTION_REBOOT 3
#define ACTION_ISUP 4
#define ACTION_GETINFO 5
#define ACTION_SHUTDOWN 6

int commandReceived;
int isStop;

void processCommand();

void upperStr(char *s) {
	// Convert to upper case
while(*s) {
		*s = (char) toupper((unsigned char) *s);
		s++;
	}

}

//************************************************************************

 
int fd;
int SMSSentOK = 0; 	//flag SMS send Ok
int isSending = false;   //Flag SMS is sending 
char *authNumbers[5];   //pointer to array of  Authorized Phone Numbers

struct send_routine_tool {
		//structure to pass argument to threads
	char *Msg;
	char *numberToCall;
};
struct send_routine_tool tools;

void rstBuffer(char *buffer) {
	//empty receive buffer
	int i;
	for (i = 0; i < READ_BUF_LEN; i++)
		buffer[i] = '\0';
}

int parseNumbers(char *authNumbStr) {
	//convert list of authtorized numbers to an array
	char* token, * tmp, * last_comma;
	int i, j = 0, count = 0;
    
	//initialize array of pointers
	for(i = 0 ; i < 5 ; i++)
	    authNumbers[i] = (char *) calloc(20, sizeof(char));
    
	/* Count how many elements will be extracted. */
	tmp = authNumbStr;
	while (*tmp) {
		if (*tmp == ',') {
			count++;
			last_comma = tmp;
		}
		tmp++;
	}
	if (count > 4) {
		printf("Error: There are more than 5 phones numbers or problems with the List\n");
		return -1;
	}
    
	// Returns first token 
	token = strtok(authNumbStr, ",");

	// Keep extracting tokens while there is one delimiter present in the string. 
	while(token != NULL) { 
		authNumbers[j] = strdup(token); 
		token = strtok(NULL, ","); 
		j++;
	}
	return 1;
}

char *getPhoneNumber(char * buffer) {
	//get phone number enclosed between " " and return them in an array
	int i = 0, j = 0;
	char *start, *end, *ret;
	start = strchr(buffer, '\"');
	if (start == NULL)
		return NULL;
	end = strchr(start + 1, '\"');
	if (end == NULL)
		return NULL;
	
	ret = (char*) calloc(20, sizeof(char));
	for (i = 1; i < end - start; i++) {
		ret[j] = start[i];
		j++;
	}

	ret[j] = '\0';
	
	return ret;

}
	
int isAuthNumber(char *number) {
	//Check if calling number is in the authorized array of phone numbers
	int i = 0;
	while (authNumbers[i]) {
		if (strcmp(authNumbers[i], number) == 0)
			return 1;
		i++;
	}
	
	return -1;
}

static void *sendCMDfn(void *tool_in) {
	//Send AT command to modem

	struct send_routine_tool *tool = tool_in;
	int wcnt;

	SMSSentOK = 0;
	//send AT Command
	wcnt = write(fd, tool->Msg, strlen(tool->Msg));  

	if (wcnt < 0) {
		return NULL;
	}
	sleep(2);
    
	//flag end of thread
	isSending = false;

	return NULL;

}

int sendCMD(char *msg) {
	// create thread to send AT command to modem
	char msg1[SEND_SMS_LEN + 2];
	pthread_t serialSend;
	snprintf(msg1, SEND_SMS_LEN, "%s\r", msg);
	tools.Msg = msg1;

	isSending = true;

	if (pthread_create(&serialSend, NULL, sendCMDfn, &tools)) {
		printf("Error Creating thread\n");
		return 1;
	}

	pthread_detach(serialSend);
     
	return 0;
}

static void writeSend(struct send_routine_tool *tool) {
	// send SMS message
	int wcnt;
	char ATMsg[30];

	SMSSentOK = 0;

	
	snprintf(ATMsg, 29, "AT+CMGS=\"%s\"\r", tool->numberToCall); 
	//write AT Command + Number
	wcnt = write(fd, ATMsg, strlen(ATMsg));  
	
	if(wcnt < 0) {
		return;
	}
	
	sleep(1);
    
	//Write message
	wcnt = write(fd, tool->Msg, strlen(tool->Msg)); 
	if (wcnt < 0) {
		return;
	}
	sleep(1);

	tcflush(fd, TCIOFLUSH);
    
}

static void *sendSMSfn(void *tool_in)
{
	struct send_routine_tool *tool = tool_in;
	//message must not be longer than 160char, if not carrier rejected (at leat in my carrier company)

   //send AT Command 
 
	writeSend(tool);
   	
	//flag  end of thread
	isSending = false;

	return NULL;

}

int sendSMS(char * msg)  
{
	//Create thread to send message
	pthread_t serialSend;
	char msg1[SEND_SMS_LEN + 2];

	snprintf(msg1, SEND_SMS_LEN, "%s\x1A\r", msg);
	tools.Msg = msg1;
	
	//flag  start of thread
	isSending = true;

	if (pthread_create(&serialSend, NULL, sendSMSfn, &tools)) {
		printf("Error Creating thread\n");
		return 1;
	}

	pthread_detach(serialSend);
     
	return 0;
}

void *receiving(void *ptr)
{
	//thread of receiving SMS 
	int gotData = 0;
	char buffer[READ_BUF_LEN];
	int pos = 0;
	double timeout = 0.5, elapsed;
	clock_t start = 0;
	int cmt = 0;
	char *callingNumber;
	
	rstBuffer(buffer);

	for (;;) {
		
		if(serialDataAvail(fd)) {
			if (start == 0)
				start = clock();

			while (serialDataAvail(fd)) {
				//printf ("%c", serialGetchar (fd)) ;
				buffer[pos++] = (char) serialGetchar(fd);      
				gotData = 1;
			}
		}

		if (gotData) {
			elapsed = ((double) clock() - (double) start) / CLOCKS_PER_SEC;
			if (elapsed > timeout) {
				//*** this is only for debug purpose. Print Message received on the screen.
				printf("==>%s\n", buffer);
				printf("********************************\n");
				fflush(stdout);
				//***
				upperStr(buffer);
                
				if (strstr(buffer, "+CMGS:") != 0 || strstr(buffer, "OK") != 0)
					SMSSentOK = 1;
                
				if (strstr(buffer, "+CMT") != 0)
					cmt = 1;
				
				if (cmt) {
					//if the sender number is not in the authorized list of phones, wait for another message
					callingNumber = getPhoneNumber(buffer);
					if (isAuthNumber(callingNumber) == -1) {
						break;
					}												
					else {
						tools.numberToCall = callingNumber; 	//save calling number if it is authorized to answer a message later
					}	
					//delete SMS once is in the buffer. My modem support only 50 messages
					sendCMD("AT+CMGDA=\"DEL ALL\"\r");   // Command depends of the modem 
	
					//process mesagges received
					if(strstr(buffer, "STOP SMS") != 0) {
						commandReceived = ACTION_STOP;
					}
					if (strstr(buffer, "START SMS") != 0) {
						commandReceived = ACTION_START;
					}
					if (strstr(buffer, "ISUP") != 0) {
						commandReceived = ACTION_ISUP;
					}
					if (strstr(buffer, "REBOOT") != 0) {
						commandReceived = ACTION_REBOOT;
					}
					if (strstr(buffer, "ERROR") != 0) {
						//if modem send error, we can process it
					}
				}

				//reset buffer and variales to start listenning again
				rstBuffer(buffer);
				pos = 0;
				gotData = 0;
				start = 0;		   
				cmt = 0; 		
			}
		}
	}
	return NULL;
}

int setupSMS()
{
	//opem serial device and Setup modem
	fd = serialOpen(SERIAL_DEVICE, SERIAL_BAUD);

	if (fd < 0)
	{
		printf("Serial opening error\n");
		return 1;
	}
    
	pthread_t recThrd;
	//printf("-----\n");
	int thr = pthread_create(&recThrd, NULL, receiving, NULL);
	//printf("%i",thr);
	if(thr != 0)
	{
		printf("Error during creating serialReceiver thread.");
		return 1;
	}

	//pthread_join(recThrd,(void **)&status);

	pthread_detach(recThrd);

	isSending = true;
	//Setup SMS Store @ ME
    
	tools.Msg = "AT+CPMS=\"ME\"\r"; 	//choose the internal memory of the SIM card
	sendCMDfn(&tools);
	if (SMSSentOK == 0) {
		printf("Error settting AT+CPMS=\"ME\". Abort\n");
		return 1;
	} else
		SMSSentOK = 0;


	tools.Msg = "AT+CNMI=2,2,0,0\r"; 	// to receive messages in the TE
	sendCMDfn(&tools);
	if (SMSSentOK == 0) {
		printf("Error settting AT+CNMI=2,2,0,0. Abort\n");
		return 1;
	} else
		SMSSentOK = 0;


	tools.Msg = "AT+CMGF=1\r"; 	//receive and send message in text mode
	sendCMDfn(&tools);
	if (SMSSentOK == 0) {
		printf("Error settting AT+CMGF=1. Abort\n");
		return 1;
	} else
		SMSSentOK = 0;

	isSending = false;
	
	return 0;
}

void processCommand()
{
	//Process all accepted message received. Add the cooamnd you need here
	if (commandReceived == 0)
		return;
	//If SMS was stopped by a command, process only the START command
	if(!isStop || commandReceived == ACTION_START)
	{
		switch (commandReceived) {
		case ACTION_STOP:			//We stop te process of received messages
			while (isSending) {}	//we don't want to send a message while another is in the sending process.
			sendSMS("SMS Stoppped");
			isStop = true;
			printf("Stop received\n");
			break;
		case ACTION_START:			//We re-start te process of received messages
			while (isSending) {}
			sendSMS("SMS Started");
			isStop = false;
			printf("Started received\n"); 
			break;
		case ACTION_ISUP:			//Check if modem is receiving messages
			while (isSending) {}
			sendSMS("Up & Running");
			printf("IsUp received\n"); 
			break;
		case ACTION_REBOOT:			
			while (isSending) {}
			sendSMS("SMS Rebooting");
			printf("Reboot received\n");
			while (isSending) {}
			close(fd);
			system("sudo reboot now");
			break;
		default:
			break;
		}
	}
	
	commandReceived = 0;
}


char phonenumbers[] = "+XXXXXXXXXXXXX,+YYYYYYYYYY";  //Authorized Phone Numbers List 

int main()
{
	//open and setup modem to receive SMS
	fd = -1;
	if (setupSMS() == 1) {
		close(fd);
		exit(1);
	}
	
	//Process list of authorized phone numbers from where to receive SMS (maximum 5).
	parseNumbers(phonenumbers); 
    
	printf("Waiting SMS ...\n\n");
	
	//this is the main loop, you have to insert your code inside processcommand() to process SMS
	for(;  ;) {
		//process command sent by SMS to your modem
		processCommand();
		sleep(1);
	}
	
	printf("\n");
	return 0 ;
	
	
}

************************************
***********  C++ Code **************
************************************

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <pthread.h>
#include <wiringSerial.h>
#include <termios.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
//************************************************************************

#define true (1==1)
#define false !true
#define READ_BUF_LEN 1024
#define SEND_SMS_LEN 160
#define MAX_STR_LEN 20
#define SERIAL_DEVICE "/dev/ttyAMA0"	//RaspberryPi 2 Serial
#define SERIAL_BAUD 115200

#define ACTION_START 1
#define ACTION_STOP 2
#define ACTION_REBOOT 3
#define ACTION_ISUP 4
#define ACTION_GETINFO 5
#define ACTION_SHUTDOWN 6

//using namespace std;



class SMS {

private:
	char* serial_Dev;
	int serial_Baud;
	int fd;					//serial id
	int SMSSentOK;			//flag SMS send Ok
	int isSending;			//Flag SMS is sending 
	char* authNumbers[5];   //pointer to array of  Authorized Phone Numbers
	char* Msg;
	char* numberToCall;		//number to call to answer SMS
	char* authNumbersStr;   //String of autorized phone numbers
	int commandReceived;	// to process received commands
	int isStop;				//when received stop sms this one is true.

	void upperStr(char* s) {
	// Convert string to upper case
	while (*s) {
		*s = (char)toupper((unsigned char)*s);
		s++;
	}

}
	void rstBuffer(char* buffer) {
	//empty reicecive buffer
	int i;
	for (i = 0; i < READ_BUF_LEN; i++)
		buffer[i] = '\0';
}
	char* getPhoneNumber(char* buffer) {
		//get phone number enclosed between " " and return them in an array
		int i = 0, j = 0;
		char* start, * end, * ret;
		start = strchr(buffer, '\"');
		if (start == NULL)
			return NULL;
		end = strchr(start + 1, '\"');
		if (end == NULL)
			return NULL;

		ret = (char*)calloc(20, sizeof(char));
		for (i = 1; i < end - start; i++) {
			ret[j] = start[i];
			j++;
		}

		ret[j] = '\0';

		return ret;

	}
	int isAuthNumber(char* number) {
		 //Check if calling number is in the authorized array of phone numbers
		 int i = 0;
		 while (authNumbers[i]) {
			 if (strcmp(authNumbers[i], number) == 0)
				 return 1;
			 i++;
		 }

		 return -1;
	 }
	void writeSend(char *msg) {
		 // Send SMS message
		 int wcnt;
		 char ATMsg[30];

		 SMSSentOK = 0;

		 ///write Send command
		 snprintf(ATMsg, 29, "AT+CMGS=\"%s\"\r", numberToCall);
		 //send AT Command + Number
		 wcnt = write(fd, ATMsg, strlen(ATMsg));
		 
		 if (wcnt < 0) {
			 return;
		 }

		 sleep(1);

		 //Write message
		 wcnt = write(fd, msg, strlen(msg));
		 if (wcnt < 0) {
			 return;
		 }
		 sleep(1);

		 tcflush(fd, TCIOFLUSH);

	 }
	int setupSMS()
	{
		fd = serialOpen(serial_Dev, serial_Baud);

		if (fd < 0)
		{
			printf("Serial opening error\n");
			return 1;
		}
		
		//Create receiving message thread
		pthread_t recThrd;
		int thr = pthread_create(&recThrd, NULL, &SMS::receiving, this);
		if (thr != 0)
		{
			printf("Error during creating serialReceiver thread.");
			return 1;
		}

		pthread_detach(recThrd);

		isSending = true;

		Msg = "AT+CPMS=\"ME\"\r"; 	//choose the internal memory of the SIM card
		sendCMDfn(this);
		if (SMSSentOK == 0) {
			printf("Error settting AT+CPMS=\"ME\"\n");
			return 1;
		}
		else
			SMSSentOK = 0;


		Msg = "AT+CNMI=2,2,0,0\r"; 	// to receive messages in the TE
		sendCMDfn(this);
		if (SMSSentOK == 0) {
			printf("Error settting AT+CNMI=2,2,0,0\n");
			return 1;
		}
		else
			SMSSentOK = 0;


		Msg = "AT+CMGF=1\r"; 	//receive and send message in text mode
		sendCMDfn(this);
		if (SMSSentOK == 0) {
			printf("Error settting AT+CMGF=1\n");
			return 1;
		}
		else
			SMSSentOK = 0;

		isSending = false;

		return 0;
	}
	int parseNumbers(char* authNumbStr) {
		//convert List of authtorized numbers to an array
		char* token, * tmp, * last_comma;
		int i, j = 0, count = 0;

		//initialize array of pointers
		for (i = 0; i < 5; i++)
			SMS::authNumbers[i] = (char*)calloc(20, sizeof(char));

		/* Count how many elements will be extracted. */
		tmp = authNumbStr;
		while (*tmp) {
			if (*tmp == ',') {
				count++;
				last_comma = tmp;
			}
			tmp++;
		}
		if (count > 4) {
			printf("Error: There are more than 5 phones numbers or problems with the List\n");
			return -1;
		}

		// Returns first token 
		token = strtok(authNumbStr, ",");

		// Keep extracting tokens while one of the delimiters present in the string. 
		while (token != NULL) {
			authNumbers[j] = strdup(token);
			token = strtok(NULL, ",");
			j++;
		}

		return 1;
	}


protected:
	static void* receiving(void* thr)
{
	int gotData = 0;
	char buffer[READ_BUF_LEN];
	int pos = 0;
	double timeout = 0.5, elapsed;
	clock_t start = 0;
	int cmt = 0;
	char* callingNumber;

	SMS* th = (SMS*)thr;
	th->rstBuffer(buffer);

	for (;;) {

		if (serialDataAvail(th->fd)) {
			if (start == 0)
				start = clock();

			while (serialDataAvail(th->fd)) {
				buffer[pos++] = (char)serialGetchar(th->fd);
				gotData = 1;
			}
		}

		if (gotData) {
			elapsed = ((double)clock() - (double)start) / CLOCKS_PER_SEC;
			if (elapsed > timeout) {
				//*** this is for debug purpose. Print Message received on the screen.
				printf("==>%s\n", buffer);
				printf("********************************\n");
				fflush(stdout);
				//***
				th->upperStr(buffer);

				if (strstr(buffer, "+CMGS:") != 0 || strstr(buffer, "OK") != 0)
					th->SMSSentOK = 1;

				if (strstr(buffer, "+CMT") != 0)
					cmt = 1;

				if (cmt) {
					//if the sender number is not in the authorized list of phones, wait for another message
					callingNumber = th->getPhoneNumber(buffer);
					if (th->isAuthNumber(callingNumber) == -1) {
						break;
					}
					else {
						th->numberToCall = callingNumber; 	//save calling number if is authorized to answer message later
					}
					//delete SMS once is in the buffer. My modem support only 50 messages
					th->sendCMD("AT+CMGDA=\"DEL ALL\"\r");   // Command depends of the modem

					//process mesagges received
					if (strstr(buffer, "STOP SMS") != 0) {
						th->commandReceived = ACTION_STOP;
					}
					if (strstr(buffer, "START SMS") != 0) {
						th->commandReceived = ACTION_START;
					}
					if (strstr(buffer, "ISUP") != 0) {
						th->commandReceived = ACTION_ISUP;
					}
					if (strstr(buffer, "REBOOT") != 0) {
						th->commandReceived = ACTION_REBOOT;
					}
					if (strstr(buffer, "ERROR") != 0) {
						//if modem send error, we can process it
					}
				}

				//Reset buffer and variales to start listenning again
				th->rstBuffer(buffer);
				pos = 0;
				gotData = 0;
				start = 0;
				cmt = 0;
			}
		}
	}
	return NULL;
}
	static void* sendCMDfn(void* thr) {
	//Send AT command to modem

	int wcnt;
	SMS *th = (SMS*)thr;
	th->SMSSentOK = 0;
	
	//send AT Command
	wcnt = write(th->fd, th->Msg, strlen(th->Msg));

	if (wcnt < 0) {
		return NULL;
	}
	sleep(2);

	//flag end of thread
	th->isSending = false;

	return NULL;

}
	static void* sendSMSfn(void* thr)
{
	//message must not be longer than 160char, if not, carrier will reject (at least in my carrier company)
	SMS* th = (SMS*)thr;
	th->SMSSentOK = 0;

   //send AT Command 

	th->writeSend(th->Msg);

	//flag  end of thread
	th->isSending = false;

	return NULL;

}
	 
public: 
	SMS(char* serial, int baud, char* phones) {
		serial_Dev = serial;
		serial_Baud = baud;
		authNumbersStr = (char*)calloc(50, sizeof(char));
		//strtok need char no literal
		strncpy(authNumbersStr, phones, 49);
		parseNumbers(authNumbersStr);
		fd = -1;
		if ( setupSMS() == 1)
			exit(1);
	}
	~SMS() {
		if(fd<0) 
			close(fd);

	}

	 int sendCMD(char* msg) {
	// create thread to send AT command to modem
	char msg1[SEND_SMS_LEN + 2];
	pthread_t serialSend;

	snprintf(msg1, SEND_SMS_LEN, "%s\r", msg);
	Msg = msg1;

	//flag  start of thread
	isSending = true;

	if (pthread_create(&serialSend, NULL, &SMS::sendCMDfn, this)) {
		printf("Error Creating thread\n");
		return 1;
	}

	pthread_detach(serialSend);

	return 0;
}
	 int sendSMS(char* msg)  // Create thread to send SMS
	 {
		 pthread_t serialSend;
		 char msg1[SEND_SMS_LEN + 2];

		 snprintf(msg1, SEND_SMS_LEN, "%s\x1A\r", msg);
		 Msg = msg1;

		 //flag  start of thread
		 isSending = true;

		 if (pthread_create(&serialSend, NULL, &SMS::sendSMSfn, this)) {
			 printf("Error Creating thread\n");
			 return 1;
		 }

		 pthread_detach(serialSend);

		 return 0;
	 }

	 void processCommand()
	 {
		 if (commandReceived == 0)
			 return;
		 //If SMS was stopped by a command, process only the START command
		 if (!isStop || commandReceived == ACTION_START)
		 {
			 switch (commandReceived) {
			 case ACTION_STOP:
				 while (isSending) {}
				 sendSMS("SMS Stoppped");
				 isStop = true;
				 printf("Stop received\n");
				 break;
			 case ACTION_START:
				 while (isSending) {}
				 sendSMS("SMS Started");
				 isStop = false;
				 printf("Started received\n");
				 break;
			 case ACTION_ISUP:
				 while (isSending) {}
				 sendSMS("Up & Running");
				 printf("IsUp received\n");
				 break;
			 case ACTION_REBOOT:
				 while (isSending) {}
				 sendSMS("SMS Rebooting");
				 printf("Reboot received\n");
				 sleep(2);
				 close(fd);
				 system("sudo reboot now");
				 break;
			 default:
				 break;
			 }
		 }

		 commandReceived = 0;
	 }

};

int main()
{
	
	//open serial ,setup modem and send lits of approved phone numbers to receive SMS (maximum 5).
	SMS sms(SERIAL_DEVICE, SERIAL_BAUD, "+XXXXXXXXXX,+YYYYYYYYYY");

	printf("Waiting SMS ...\n\n");

	//this is the main loop, you have to insert your code inside processcommand()
	for (; ;) {
		//process command sent by SMS to your modem
		sms.processCommand();
		sleep(1);
	}

	printf("\n");
	return 0;


}

Credits

cb77

cb77

6 projects • 5 followers

Comments