Skip to content
This repository was archived by the owner on Feb 16, 2024. It is now read-only.

Commit 3ded729

Browse files
committed
Added controller for the GSM module. Software power control has been tested. Voice calls and text SMS are awaiting testing and geolocation is to be implemented.
Signed-off-by: Eneko Cruz <eneko.cruz@opendeusto.es>
1 parent a7217be commit 3ded729

2 files changed

Lines changed: 220 additions & 0 deletions

File tree

gsm/GSMDevice.cpp

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
#include "GSMDevice.hpp"
2+
3+
using namespace std;
4+
5+
GSMDevice::GSMDevice(){ //Instantiates a GSM device controlled using GPIO 4 (default, software pwr control) and /dev/ttyAMA0 for UART
6+
GSMDevice(DEFAULT_GPIO,DEFAULT_UART);
7+
}
8+
9+
//WARNING: May take up to six seconds
10+
GSMDevice::GSMDevice(int gpio, string serial){ //Instantiates a GSM device controlled using a GPIO pin (given by GPIO parameter) and a UART port (given by serial){
11+
gpionum = gpio;
12+
serialPort = serial;
13+
InitSerial();
14+
InitGSMModule();
15+
delay(3000); //Allow some time for the GSM module to connect to the network.
16+
}
17+
18+
void GSMDevice::TogglePWR(){
19+
//Toggles the power status of the GSM module. Turns it on if it is off and turns it off if it is on.
20+
//WARNING: Takes 2500 miliseconds to complete
21+
22+
digitalWrite(gpionum, LOW); //Spec says that the adafruit FONA expects a 2000ms low pulse
23+
delay(2000);
24+
digitalWrite(gpionum, HIGH);
25+
delay(500); //Give the module some time to turn on, ensure that when
26+
//function returns the module is operational.
27+
}
28+
29+
bool GSMDevice::Call(string num){ //Establishes a voice connection with a phone number. The function
30+
char *number = new char[num.length() + 1]; //will return when the voice connection is established. Note that
31+
strcpy(number, num.c_str()); //having a voice connection does not mean that both parties are
32+
char send[20]; //ready to exchange data. In fact, the sender should allow for some
33+
//time before transmitting so that the receiver can answer.
34+
35+
if(strlen(number)>(sizeof(send)/sizeof(char))-(3+1)){ //If the number does not fit into the buffer, reject it, as
36+
if(OPENSTRATOS_GSM_DEBUG_){ //phone numbers (without C.C.) take 9 chars.
37+
printf("[!] Number too long. Aborting call\n");
38+
}
39+
return false;
40+
}
41+
strncpy(send, "ATD", strlen("ATD")); //AT command preamble: ATD
42+
strncpy(send+3, number, strlen(number)); //Number to dial
43+
int length = strlen(send);
44+
send[length] = (char)0x3b;//ascii for semicolon //Semicolon ending command
45+
send[length+1] = (char)0x0;//terminate string with null byte
46+
bool success = SerialSendCompareResponse(send, "OK"); //Modem will reply OK if a voice connection was established.
47+
if(OPENSTRATOS_GSM_DEBUG_ && !success){
48+
printf("[!] ATD+number+; did not reply OK\n");
49+
}
50+
return success;
51+
}
52+
53+
bool GSMDevice::AbortCall(){ //Aborts a phone call. No effect if not in a call.
54+
bool success = SerialSendCompareResponse("ATH","OK"); //Returns true if call aborted or if not in a call.
55+
if(OPENSTRATOS_GSM_DEBUG_ && !success){ //Expecting the modem to return OK.
56+
printf("[!] ATH did not reply OK\n");
57+
}
58+
return success;
59+
}
60+
61+
bool GSMDevice::SendSMS(string message, string n){ //Sends a short message to a phone number
62+
char *destnum = new char[n.length() + 1];
63+
strcpy(destnum, n.c_str());
64+
char *messagechar = new char[message.length() + 1];
65+
strcpy(messagechar, message.c_str());
66+
67+
if (SerialSendCompareResponse("AT+CMGF=1", "OK")==false){ //Select SMS message format
68+
if(OPENSTRATOS_GSM_DEBUG_){ //Abort if the modem cannot be set to text mode.
69+
printf("[!] AT+CMFG=1 did not reply OK to SMS format selection\n");
70+
}
71+
return false;
72+
}
73+
74+
char send[30] = "AT+CMGS=\""; //SMS command preamble: AT+CMGS="
75+
strncpy(send+9 , destnum, 19); //SMS destination (actual phone number)
76+
send[strlen(send)] = (char)0x22;//ascii for " (double quote) //SMS command termination: "
77+
78+
if (!SerialSendCompareResponse(send, "> ")){ //Input prompt should be open and expecting text input
79+
if(OPENSTRATOS_GSM_DEBUG_){
80+
printf("[!] Failed SMS attempt. SIM800L did not provide input prompt\n");
81+
}
82+
return false; //If there is not any input prompt, abort.
83+
}
84+
85+
serialPrintf(fdesc,messagechar); //Send message
86+
serialPrintf(fdesc,"\r\n"); //Return
87+
FlushSerialInput(); //Module will reply with "+CMGS<length>". Not interested in that, so flush.
88+
return true; //Message sent.
89+
}
90+
91+
void GSMDevice::BroadcastGeolocation(string n){ //Tries to perform geolocation and sends coordinates to a phone number via SMS.
92+
//TODO
93+
}
94+
95+
bool GSMDevice::CheckGSMModule(){ //Returns true if module is up and running, false if it is not.
96+
if(SerialSendCompareResponse("AT","OK")){ //Probe the SIM800L, see AT command reference for more info.
97+
return true;
98+
}
99+
return false;
100+
}
101+
102+
bool GSMDevice::InitSerial(){
103+
char *cstr = new char[serialPort.length() + 1];
104+
strcpy(cstr, serialPort.c_str());
105+
fdesc = serialOpen(cstr, UART_BAUDRATE);
106+
if(fdesc==-1){ //serialOpen returns a standard linux file descriptor. -1 means failed
107+
;/*EXCEPTION: NO SERIAL PORT AVAILABLE*/
108+
if(OPENSTRATOS_GSM_DEBUG_){
109+
printf("[!] Serial port open error\n");
110+
}
111+
return false;
112+
}
113+
return true;
114+
}
115+
116+
bool GSMDevice::InitGSMModule(){
117+
if (wiringPiSetup() == -1){
118+
/*EXCEPTION: UNABLE TO ACCESS GPIOS*/;
119+
return false;
120+
}
121+
pinMode(gpionum, OUTPUT); //Set GPIO as digital output
122+
digitalWrite(gpionum, HIGH); //Set to high so that GSM module stays in standby until TogglePWR is called
123+
return true;
124+
}
125+
126+
bool GSMDevice::SerialSendCompareResponse(char *send, char *expected){
127+
SerialSendRead(send); //Send a string via serial.
128+
return (strcmp(serialin, expected) == 0); //Compare what got placed in serialin with the expected answer
129+
}
130+
131+
uint16_t GSMDevice::SerialSendRead(char *send) {
132+
FlushSerialInput();
133+
if(OPENSTRATOS_GSM_DEBUG_){
134+
printf("[i] Sending: %s", send);
135+
}
136+
serialPrintf(fdesc, send);
137+
uint16_t readlength = SerialReadLine();
138+
if(OPENSTRATOS_GSM_DEBUG_){
139+
printf("[i] Received: %s\n", serialin);
140+
}
141+
return readlength;
142+
}
143+
144+
void GSMDevice::FlushSerialInput() {
145+
serialFlush(fdesc);
146+
}
147+
148+
uint16_t GSMDevice::SerialReadLine() {
149+
uint16_t i = 0;
150+
while(serialDataAvail(fdesc)&&i<254) {
151+
char c = serialGetchar(fdesc);
152+
serialin[i++] = c;
153+
}
154+
serialin[i] = 0x0;
155+
return i;
156+
}

gsm/GSMDevice.hpp

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
#ifndef OPENSTRATOS_WIRINGPI_H_
2+
#define OPENSTRATOS_WIRINGPI_H_
3+
#include <wiringPi.h>
4+
#endif
5+
6+
#ifndef OPENSTRATOS_WIRINGSERIAL_H
7+
#define OPENSTRATOS_WIRINGSERIAL_H
8+
#include <wiringSerial.h>
9+
#endif
10+
11+
#ifndef OPENSTRATOS_GSM_INCLUDE_ALL_
12+
#define OPENSTRATOS_GSM_INCLUDE_ALL_
13+
#include <string.h>
14+
#include <stdlib.h>
15+
#include <iostream>
16+
#include <stdint.h>
17+
#include <algorithm>
18+
#include <stdio.h>
19+
#endif
20+
21+
#define OPENSTRATOS_GSM_DEBUG_ 0
22+
//0 = disable debug mode
23+
//1 = enable debug mode
24+
25+
#ifndef OPENSTRATOS_GSM_GSMDEVICE_CLASS_
26+
#define OPENSTRATOS_GSM_GSMDEVICE_CLASS_
27+
using namespace std;
28+
29+
class GSMDevice{
30+
public:
31+
GSMDevice(); //Instantiates a GSM device controlled using GPIO 4 (default, software pwr control) and /dev/ttyAMA0 for UART
32+
GSMDevice(int gpio, string serial); //Instantiates a GSM device controlled using a GPIO pin (given by GPIO parameter) and a UART port (given by serial);
33+
void TogglePWR(); //Toggles the power status of the GSM module. Turns it on if it is off and turns it off if it is on.
34+
bool Call(string number); //Calls a given phone number. Returns true if suceeded, false if failed.
35+
bool AbortCall(); //Aborts a phone call. Returns true if suceeded, false if failed or not in a call.
36+
bool SendSMS(string message, string n); //Sends a short message to a phone number. Returns true if suceeded, false if failed
37+
void BroadcastGeolocation(string n); //Tries to perform geolocation and sends coordinates to a phone number via SMS.
38+
bool CheckGSMModule(); //Returns true if module is up and running, false if it is not
39+
private:
40+
uint16_t SerialReadLine();
41+
uint16_t SerialSendRead(char *);
42+
void FlushSerialInput(); //Discards all data received from the serial port.
43+
bool SerialSendCompareResponse(char*, char*); //Sends a string of data via serial port. Checks that the reply matches with another string.
44+
bool InitGSMModule(); //Initializes the gsm module. Returns true if successful. False if failed.
45+
bool InitSerial(); //Initializes the serial interface. Returns true if successful. False if failed.
46+
int gpionum; //GPIO pin used for software power control
47+
string serialPort; //Serial port identifier. Tipically /dev/ttyAMA0 in Raspbian.
48+
int fdesc; //Standard unix file descriptor associated with the serial port (see serialPort)
49+
char serialin[255]; //Buffer on which data received via the serial port is placed
50+
};
51+
#endif
52+
53+
#ifndef OPENSTRATOS_GSM_DEFAULT_PARAMETERS_
54+
#define OPENSTRATOS_GSM_DEFAULT_PARAMETERS_
55+
#define DEFAULT_UART "/dev/ttyAMA0"
56+
#define DEFAULT_GPIO 4
57+
#define UART_BAUDRATE 4800
58+
#endif
59+
60+
#ifndef OPENSTRATOS_GSM_GPIO_VALUES_
61+
#define OPENSTRATOS_GSM_GPIO_VALUES_
62+
#define HIGH 1
63+
#define LOW 0
64+
#endif

0 commit comments

Comments
 (0)