A library for talking to Multi-Tech's Cellular SocketModem Devices.

Dependents:   M2X_dev axeda_wrapper_dev MTS_M2x_Example1 MTS_Cellular_Connect_Example ... more

Committer:
sgodinez
Date:
Wed Dec 18 22:47:24 2013 +0000
Revision:
33:e04aa7c013c9
Parent:
30:06c756af6c5c
Parent:
32:629e6b1c8e22
Child:
35:f28acb1be52d
Child:
36:bb6b293c7495
Merged

Who changed what in which revision?

UserRevisionLine numberNew contents of line
jengbrecht 0:563b70517320 1 #ifndef CELLULAR_CPP
jengbrecht 0:563b70517320 2 #define CELLULAR_CPP
jengbrecht 0:563b70517320 3
jengbrecht 0:563b70517320 4 #include "Cellular.h"
sgodinez 4:6561c9128c6f 5 #include "MTSText.h"
sgodinez 19:38794784e009 6 #include "MTSSerial.h"
jengbrecht 0:563b70517320 7
sgodinez 19:38794784e009 8 Cellular* Cellular::instance = NULL;
sgodinez 19:38794784e009 9
sgodinez 19:38794784e009 10 Cellular* Cellular::getInstance() {
sgodinez 19:38794784e009 11 if(instance == NULL) {
sgodinez 19:38794784e009 12 instance = new Cellular(NULL);
sgodinez 19:38794784e009 13 }
sgodinez 19:38794784e009 14 return instance;
sgodinez 19:38794784e009 15 }
sgodinez 19:38794784e009 16
sgodinez 19:38794784e009 17
sgodinez 19:38794784e009 18 Cellular* Cellular::getInstance(MTSBufferedIO* io) {
sgodinez 19:38794784e009 19 if(instance == NULL) {
sgodinez 19:38794784e009 20 instance = new Cellular(io);
sgodinez 19:38794784e009 21 }
sgodinez 19:38794784e009 22 instance->io = io;
sgodinez 19:38794784e009 23 return instance;
sgodinez 19:38794784e009 24 }
sgodinez 19:38794784e009 25
sgodinez 19:38794784e009 26 Cellular::Cellular(MTSBufferedIO* io)
sgodinez 11:134435d8a2d5 27 : io(io)
sgodinez 13:0af863114629 28 , echoMode(true)
sgodinez 11:134435d8a2d5 29 , pppConnected(false)
sgodinez 11:134435d8a2d5 30 , mode(TCP)
sgodinez 11:134435d8a2d5 31 , socketOpened(false)
sgodinez 17:2d7c4ea7491b 32 , socketCloseable(false)
sgodinez 11:134435d8a2d5 33 , local_port(0)
sgodinez 11:134435d8a2d5 34 , host_port(0)
jengbrecht 0:563b70517320 35 {
mfiore 29:7408b1bdad37 36 // the radio's DCD signal is mapped to PTA4
mfiore 29:7408b1bdad37 37 // the radio will raise and lower this line
mfiore 29:7408b1bdad37 38 dcd = new DigitalIn(PTA4);
mfiore 29:7408b1bdad37 39 // the DTR line to the radio is mapped PTC9
mfiore 29:7408b1bdad37 40 // this line should be lowered when we want to talk to the radio and raised when we're done
mfiore 29:7408b1bdad37 41 // for now we will lower it in the constructor and raise it in the destructor
mfiore 29:7408b1bdad37 42 dtr = new DigitalOut(PTC9);
mfiore 29:7408b1bdad37 43 dtr->write(0);
jengbrecht 0:563b70517320 44 }
jengbrecht 0:563b70517320 45
jengbrecht 0:563b70517320 46 Cellular::~Cellular()
jengbrecht 0:563b70517320 47 {
mfiore 29:7408b1bdad37 48 dtr->write(1);
jengbrecht 0:563b70517320 49 }
jengbrecht 0:563b70517320 50
sgodinez 11:134435d8a2d5 51 bool Cellular::connect() {
sgodinez 13:0af863114629 52 //Check if socket is open
sgodinez 13:0af863114629 53 if(socketOpened) {
sgodinez 13:0af863114629 54 return true;
sgodinez 13:0af863114629 55 }
sgodinez 13:0af863114629 56
sgodinez 11:134435d8a2d5 57 //Run Test first to validate a good state
sgodinez 13:0af863114629 58 if(isConnected()) {
sgodinez 13:0af863114629 59 return true;
sgodinez 13:0af863114629 60 }
sgodinez 13:0af863114629 61
sgodinez 11:134435d8a2d5 62 //Check RSSI: AT+CSQ
sgodinez 13:0af863114629 63 int rssi = getSignalStrength();
sgodinez 17:2d7c4ea7491b 64 printf("[DEBUG] Signal strength: %d\r\n", rssi);
sgodinez 13:0af863114629 65
sgodinez 11:134435d8a2d5 66 //Check Registration: AT+CREG? == 0,1
sgodinez 13:0af863114629 67 Registration registration = getRegistration();
sgodinez 13:0af863114629 68 if(registration != REGISTERED) {
sgodinez 17:2d7c4ea7491b 69 printf("[WARNING] Not Registered [%d]\r\n", (int)registration);
sgodinez 13:0af863114629 70 }
sgodinez 11:134435d8a2d5 71
sgodinez 11:134435d8a2d5 72 //AT#CONNECTIONSTART: Make a PPP connection
sgodinez 17:2d7c4ea7491b 73 printf("[DEBUG] Making PPP Connection Attempt. APN[%s]\r\n", apn.c_str());
sgodinez 13:0af863114629 74 std::string pppResult = sendCommand("AT#CONNECTIONSTART", 120000);
sgodinez 17:2d7c4ea7491b 75 std::vector<std::string> parts = Text::split(pppResult, "\r\n");
sgodinez 13:0af863114629 76
sgodinez 17:2d7c4ea7491b 77 //printf("[DEBUG] PPP CONNECT RESULT [%s]\r\n", pppResult.c_str());
sgodinez 17:2d7c4ea7491b 78 // for(uint32_t i = 0; i < parts.size(); i++) {
sgodinez 17:2d7c4ea7491b 79 // printf("[%d] [%s]\r\n", i, parts[i].c_str());
sgodinez 17:2d7c4ea7491b 80 // }
sgodinez 13:0af863114629 81
sgodinez 13:0af863114629 82 if(pppResult.find("Ok_Info_GprsActivation") != std::string::npos) {
sgodinez 13:0af863114629 83 if(parts.size() >= 2) {
sgodinez 13:0af863114629 84 local_address = parts[1];
sgodinez 13:0af863114629 85 }
sgodinez 17:2d7c4ea7491b 86 printf("[INFO] PPP Connection Established: IP[%s]\r\n", local_address.c_str());
sgodinez 13:0af863114629 87 pppConnected = true;
sgodinez 13:0af863114629 88
sgodinez 13:0af863114629 89 } else {
sgodinez 13:0af863114629 90 pppConnected = false;
sgodinez 13:0af863114629 91 }
sgodinez 11:134435d8a2d5 92
sgodinez 13:0af863114629 93 return pppConnected;
sgodinez 11:134435d8a2d5 94 }
sgodinez 11:134435d8a2d5 95
sgodinez 11:134435d8a2d5 96 void Cellular::disconnect() {
sgodinez 17:2d7c4ea7491b 97 //AT#CONNECTIONSTOP: Close a PPP connection
sgodinez 17:2d7c4ea7491b 98 printf("[DEBUG] Closing PPP Connection\r\n");
sgodinez 11:134435d8a2d5 99
sgodinez 17:2d7c4ea7491b 100 if(socketOpened) {
sgodinez 17:2d7c4ea7491b 101 close();
sgodinez 17:2d7c4ea7491b 102 }
sgodinez 17:2d7c4ea7491b 103
sgodinez 17:2d7c4ea7491b 104 Code code = sendBasicCommand("AT#CONNECTIONSTOP", 10000);
sgodinez 17:2d7c4ea7491b 105 if(code == OK) {
sgodinez 17:2d7c4ea7491b 106 printf("[DEBUG] Successfully closed PPP Connection\r\n");
sgodinez 17:2d7c4ea7491b 107 } else {
sgodinez 17:2d7c4ea7491b 108 printf("[ERROR] Closing PPP Connection [%d]. Continuing ...\r\n", (int)code);
sgodinez 17:2d7c4ea7491b 109 }
sgodinez 17:2d7c4ea7491b 110
sgodinez 17:2d7c4ea7491b 111 pppConnected = false;
sgodinez 11:134435d8a2d5 112 }
sgodinez 11:134435d8a2d5 113
sgodinez 11:134435d8a2d5 114 bool Cellular::isConnected() {
sgodinez 11:134435d8a2d5 115 //1) Check if APN was set
sgodinez 11:134435d8a2d5 116 if(apn.size() == 0) {
sgodinez 17:2d7c4ea7491b 117 printf("[DEBUG] APN is not set\r\n");
sgodinez 11:134435d8a2d5 118 return false;
sgodinez 11:134435d8a2d5 119 }
sgodinez 11:134435d8a2d5 120
sgodinez 11:134435d8a2d5 121 //1) Check that we do not have a live connection up
sgodinez 11:134435d8a2d5 122 if(socketOpened) {
sgodinez 17:2d7c4ea7491b 123 printf("[DEBUG] Socket is opened\r\n");
sgodinez 11:134435d8a2d5 124 return true;
sgodinez 11:134435d8a2d5 125 }
sgodinez 11:134435d8a2d5 126 //2) Query the radio
sgodinez 11:134435d8a2d5 127 pppConnected = false;
sgodinez 11:134435d8a2d5 128 std::string result = sendCommand("AT#VSTATE", 1000);
sgodinez 11:134435d8a2d5 129 if(result.find("CONNECTED") != std::string::npos) {
sgodinez 11:134435d8a2d5 130 pppConnected = true;
sgodinez 11:134435d8a2d5 131 }
sgodinez 11:134435d8a2d5 132
sgodinez 11:134435d8a2d5 133 return pppConnected;
sgodinez 11:134435d8a2d5 134 }
sgodinez 11:134435d8a2d5 135
sgodinez 11:134435d8a2d5 136 bool Cellular::bind(unsigned int port) {
sgodinez 11:134435d8a2d5 137 return false;
sgodinez 11:134435d8a2d5 138 }
sgodinez 11:134435d8a2d5 139
sgodinez 11:134435d8a2d5 140 bool Cellular::open(const std::string& address, unsigned int port, Mode mode) {
sgodinez 17:2d7c4ea7491b 141 char buffer[256] = {0};
sgodinez 11:134435d8a2d5 142 Code portCode, addressCode;
sgodinez 17:2d7c4ea7491b 143 printf("[DEBUG] Attempting to Open Socket\r\n");
sgodinez 11:134435d8a2d5 144
sgodinez 11:134435d8a2d5 145 //1) Check that we do not have a live connection up
sgodinez 11:134435d8a2d5 146 if(socketOpened) {
sgodinez 17:2d7c4ea7491b 147 printf("[DEBUG] Socket already opened\r\n");
sgodinez 11:134435d8a2d5 148 return true;
sgodinez 11:134435d8a2d5 149 }
sgodinez 11:134435d8a2d5 150
sgodinez 11:134435d8a2d5 151 //2) Check PPP connection
sgodinez 11:134435d8a2d5 152 if(!isConnected()) {
sgodinez 17:2d7c4ea7491b 153 printf("[ERROR] PPP not established. Attempting to connect\r\n");
sgodinez 11:134435d8a2d5 154 if(!connect()) {
sgodinez 17:2d7c4ea7491b 155 printf("[ERROR] PPP connection failed\r\n");
sgodinez 11:134435d8a2d5 156 return false;
sgodinez 11:134435d8a2d5 157 } else {
sgodinez 17:2d7c4ea7491b 158 printf("[DEBUG] PPP connection established\r\n");
sgodinez 11:134435d8a2d5 159 }
sgodinez 11:134435d8a2d5 160 }
sgodinez 11:134435d8a2d5 161
sgodinez 17:2d7c4ea7491b 162 ////Setup IP Connection
sgodinez 11:134435d8a2d5 163 if(mode == TCP) {
sgodinez 17:2d7c4ea7491b 164 if(socketCloseable) {
sgodinez 17:2d7c4ea7491b 165 Code code = sendBasicCommand("AT#DLEMODE=1,0", 1000);
sgodinez 17:2d7c4ea7491b 166 if(code != OK) {
sgodinez 17:2d7c4ea7491b 167 printf("[WARNING] Unable to set socket closeable [%d]\r\n", (int) code);
sgodinez 17:2d7c4ea7491b 168 }
sgodinez 17:2d7c4ea7491b 169 }
sgodinez 17:2d7c4ea7491b 170 sprintf(buffer, "AT#TCPPORT=1,%d", port);
sgodinez 17:2d7c4ea7491b 171 portCode = sendBasicCommand(buffer, 1000);
sgodinez 17:2d7c4ea7491b 172 addressCode = sendBasicCommand("AT#TCPSERV=1,\"" + address + "\"", 1000);
sgodinez 11:134435d8a2d5 173 } else {
sgodinez 17:2d7c4ea7491b 174 if(socketCloseable) {
sgodinez 17:2d7c4ea7491b 175 Code code = sendBasicCommand("AT#UDPDLEMODE=1", 1000);
sgodinez 17:2d7c4ea7491b 176 if(code != OK) {
sgodinez 17:2d7c4ea7491b 177 printf("[WARNING] Unable to set socket closeable [%d]\r\n", (int) code);
sgodinez 17:2d7c4ea7491b 178 }
sgodinez 17:2d7c4ea7491b 179 }
sgodinez 17:2d7c4ea7491b 180 sprintf(buffer, "AT#UDPPORT=1,%d", port);
sgodinez 17:2d7c4ea7491b 181 portCode = sendBasicCommand(buffer, 1000);
sgodinez 17:2d7c4ea7491b 182 addressCode = sendBasicCommand("AT#UDPSERV=1,\"" + address + "\"", 1000);
sgodinez 11:134435d8a2d5 183 }
sgodinez 11:134435d8a2d5 184
sgodinez 11:134435d8a2d5 185 if(portCode == OK) {
sgodinez 11:134435d8a2d5 186 host_port = port;
sgodinez 11:134435d8a2d5 187 } else {
sgodinez 17:2d7c4ea7491b 188 printf("[ERROR] Host port could not be set\r\n");
sgodinez 11:134435d8a2d5 189 }
sgodinez 11:134435d8a2d5 190
sgodinez 11:134435d8a2d5 191 if(addressCode == OK) {
sgodinez 11:134435d8a2d5 192 host_address = address;
sgodinez 11:134435d8a2d5 193 } else {
sgodinez 17:2d7c4ea7491b 194 printf("[ERROR] Host address could not be set\r\n");
sgodinez 11:134435d8a2d5 195 }
sgodinez 11:134435d8a2d5 196
sgodinez 13:0af863114629 197 // Try and Connect
sgodinez 13:0af863114629 198 string response = sendCommand("AT#OTCP=1", 30000);
sgodinez 13:0af863114629 199 if (response.find("Ok_Info_WaitingForData") != string::npos) {
sgodinez 17:2d7c4ea7491b 200 printf("[INFO] Opened TCP Socket [%s:%d]\r\n", address.c_str(), port);
sgodinez 13:0af863114629 201 socketOpened = true;
sgodinez 13:0af863114629 202 } else {
sgodinez 17:2d7c4ea7491b 203 printf("[WARNING] Unable to open TCP Socket [%s:%d]\r\n", address.c_str(), port);
sgodinez 13:0af863114629 204 socketOpened = false;
sgodinez 13:0af863114629 205 }
sgodinez 11:134435d8a2d5 206
sgodinez 13:0af863114629 207 return socketOpened;
sgodinez 11:134435d8a2d5 208 }
sgodinez 11:134435d8a2d5 209
sgodinez 11:134435d8a2d5 210 bool Cellular::isOpen() {
sgodinez 17:2d7c4ea7491b 211 return socketOpened;
sgodinez 11:134435d8a2d5 212 }
sgodinez 11:134435d8a2d5 213
sgodinez 17:2d7c4ea7491b 214 bool Cellular::close() {
sgodinez 13:0af863114629 215 if(!socketOpened) {
sgodinez 17:2d7c4ea7491b 216 printf("[ERROR] Socket is not open\r\n");
sgodinez 17:2d7c4ea7491b 217 return false;
sgodinez 13:0af863114629 218 }
sgodinez 11:134435d8a2d5 219
sgodinez 17:2d7c4ea7491b 220 if(!socketCloseable) {
sgodinez 17:2d7c4ea7491b 221 printf("[ERROR] Socket is not closeable\r\n");
sgodinez 17:2d7c4ea7491b 222 return false;
sgodinez 17:2d7c4ea7491b 223 }
sgodinez 17:2d7c4ea7491b 224
sgodinez 17:2d7c4ea7491b 225 //Build Escape Message => ETX
sgodinez 17:2d7c4ea7491b 226 char buffer[2] = { 0x03, 0x00 };
sgodinez 13:0af863114629 227 Code code = sendBasicCommand(buffer, 1000, NONE);
sgodinez 13:0af863114629 228 if(code != OK) {
mfiore 29:7408b1bdad37 229 printf("[ERROR] Radio did not accept close socket command\r\n");
sgodinez 17:2d7c4ea7491b 230 return false;
sgodinez 13:0af863114629 231 }
sgodinez 17:2d7c4ea7491b 232 socketOpened = false;
sgodinez 17:2d7c4ea7491b 233 return true;
sgodinez 11:134435d8a2d5 234 }
sgodinez 11:134435d8a2d5 235
sgodinez 11:134435d8a2d5 236 int Cellular::read(char* data, int max, int timeout) {
sgodinez 19:38794784e009 237 if(io == NULL) {
sgodinez 19:38794784e009 238 printf("[ERROR] MTSBufferedIO not set\r\n");
sgodinez 19:38794784e009 239 return -1;
sgodinez 19:38794784e009 240 }
sgodinez 19:38794784e009 241
sgodinez 17:2d7c4ea7491b 242 if(!socketOpened) {
sgodinez 17:2d7c4ea7491b 243 printf("[ERROR] Socket is not open\r\n");
sgodinez 17:2d7c4ea7491b 244 return -1;
sgodinez 17:2d7c4ea7491b 245 }
sgodinez 17:2d7c4ea7491b 246 int bytesRead = 0;
sgodinez 32:629e6b1c8e22 247
sgodinez 17:2d7c4ea7491b 248 if(timeout >= 0) {
sgodinez 17:2d7c4ea7491b 249 Timer tmr;
sgodinez 17:2d7c4ea7491b 250 tmr.start();
sgodinez 17:2d7c4ea7491b 251 while (tmr.read_ms() <= timeout && bytesRead < max) {
sgodinez 32:629e6b1c8e22 252 int available = io->readable();
sgodinez 32:629e6b1c8e22 253 if (available > 0) {
sgodinez 32:629e6b1c8e22 254 int size = MIN(available, max - bytesRead);
sgodinez 32:629e6b1c8e22 255 bytesRead += io->read(&data[bytesRead], size);
sgodinez 17:2d7c4ea7491b 256 } else {
sgodinez 17:2d7c4ea7491b 257 wait(0.05);
sgodinez 17:2d7c4ea7491b 258 }
sgodinez 17:2d7c4ea7491b 259 }
sgodinez 17:2d7c4ea7491b 260 } else {
sgodinez 19:38794784e009 261 bytesRead = io->read(data, max);
sgodinez 17:2d7c4ea7491b 262 }
sgodinez 17:2d7c4ea7491b 263
sgodinez 32:629e6b1c8e22 264 if(bytesRead > 0 && socketCloseable) {
sgodinez 32:629e6b1c8e22 265 //Remove escape characters
sgodinez 32:629e6b1c8e22 266 int index = 0;
sgodinez 32:629e6b1c8e22 267 bool escapeFlag = false;
sgodinez 32:629e6b1c8e22 268 for(int i = 0; i < bytesRead; i++) {
sgodinez 32:629e6b1c8e22 269 if(data[i] == DLE || data[i] == ETX) {
sgodinez 32:629e6b1c8e22 270 if(escapeFlag == true) {
sgodinez 32:629e6b1c8e22 271 //This character has been escaped
sgodinez 32:629e6b1c8e22 272 escapeFlag = false;
sgodinez 32:629e6b1c8e22 273 } else if(data[bytesRead] == DLE) {
sgodinez 32:629e6b1c8e22 274 //Found escape character
sgodinez 32:629e6b1c8e22 275 escapeFlag = true;
sgodinez 32:629e6b1c8e22 276 continue;
sgodinez 32:629e6b1c8e22 277 } else {
sgodinez 32:629e6b1c8e22 278 //ETX sent without escape -> Socket closed
sgodinez 32:629e6b1c8e22 279 printf("[INFO] Read ETX character without DLE escape. Socket closed\r\n");
sgodinez 32:629e6b1c8e22 280 socketOpened = false;
sgodinez 32:629e6b1c8e22 281 continue;
sgodinez 32:629e6b1c8e22 282 }
sgodinez 32:629e6b1c8e22 283 }
sgodinez 32:629e6b1c8e22 284
sgodinez 32:629e6b1c8e22 285 if(index != i) {
sgodinez 32:629e6b1c8e22 286 data[index] = data[i];
sgodinez 32:629e6b1c8e22 287 }
sgodinez 32:629e6b1c8e22 288 index++;
sgodinez 32:629e6b1c8e22 289 }
sgodinez 32:629e6b1c8e22 290 bytesRead = index;
sgodinez 32:629e6b1c8e22 291 }
sgodinez 32:629e6b1c8e22 292
sgodinez 32:629e6b1c8e22 293 printf("[DEBUG] Scanning received data for socket closed message\r\n");
sgodinez 32:629e6b1c8e22 294 //Scan for socket closed message
sgodinez 32:629e6b1c8e22 295 for(size_t i = 0; i < bytesRead; i++) {
sgodinez 32:629e6b1c8e22 296 if(data[i] == 'O') {
sgodinez 32:629e6b1c8e22 297 if(strstr(&data[i], "Ok_Info_SocketClosed")) {
sgodinez 32:629e6b1c8e22 298 printf("[INFO] Found socket closed message. Socket closed\r\n");
sgodinez 32:629e6b1c8e22 299 //Close socket and Cut Off End of Message
sgodinez 32:629e6b1c8e22 300 socketOpened = false;
sgodinez 32:629e6b1c8e22 301 data[i] = '\0';
sgodinez 32:629e6b1c8e22 302 bytesRead = i;
sgodinez 32:629e6b1c8e22 303 break;
sgodinez 32:629e6b1c8e22 304 }
sgodinez 32:629e6b1c8e22 305 }
sgodinez 32:629e6b1c8e22 306 }
sgodinez 17:2d7c4ea7491b 307 return bytesRead;
sgodinez 11:134435d8a2d5 308 }
sgodinez 11:134435d8a2d5 309
sgodinez 11:134435d8a2d5 310 int Cellular::write(char* data, int length, int timeout) {
sgodinez 19:38794784e009 311 if(io == NULL) {
sgodinez 19:38794784e009 312 printf("[ERROR] MTSBufferedIO not set\r\n");
sgodinez 19:38794784e009 313 return -1;
sgodinez 19:38794784e009 314 }
sgodinez 19:38794784e009 315
sgodinez 17:2d7c4ea7491b 316 if(!socketOpened) {
sgodinez 17:2d7c4ea7491b 317 printf("[ERROR] Socket is not open\r\n");
sgodinez 17:2d7c4ea7491b 318 return -1;
sgodinez 17:2d7c4ea7491b 319 }
sgodinez 17:2d7c4ea7491b 320
sgodinez 17:2d7c4ea7491b 321 int bytesWritten = 0;
sgodinez 17:2d7c4ea7491b 322
sgodinez 17:2d7c4ea7491b 323 if(timeout >= 0) {
sgodinez 17:2d7c4ea7491b 324 Timer tmr;
sgodinez 17:2d7c4ea7491b 325 tmr.start();
sgodinez 17:2d7c4ea7491b 326 while (tmr.read_ms() <= timeout && bytesWritten < length) {
sgodinez 19:38794784e009 327 if (io->writeable()) {
sgodinez 19:38794784e009 328 if(io->write(*data) == 1) {
sgodinez 17:2d7c4ea7491b 329 data++;
sgodinez 17:2d7c4ea7491b 330 bytesWritten++;
sgodinez 17:2d7c4ea7491b 331 }
sgodinez 17:2d7c4ea7491b 332 } else {
sgodinez 17:2d7c4ea7491b 333 wait(0.05);
sgodinez 17:2d7c4ea7491b 334 }
sgodinez 17:2d7c4ea7491b 335 }
sgodinez 17:2d7c4ea7491b 336 } else {
sgodinez 19:38794784e009 337 bytesWritten = io->write(data, length);
sgodinez 17:2d7c4ea7491b 338 }
sgodinez 17:2d7c4ea7491b 339
sgodinez 17:2d7c4ea7491b 340 return bytesWritten;
sgodinez 11:134435d8a2d5 341 }
sgodinez 11:134435d8a2d5 342
sgodinez 11:134435d8a2d5 343 unsigned int Cellular::readable() {
sgodinez 19:38794784e009 344 if(io == NULL) {
sgodinez 19:38794784e009 345 printf("[ERROR] MTSBufferedIO not set\r\n");
sgodinez 19:38794784e009 346 return 0;
sgodinez 19:38794784e009 347 }
sgodinez 17:2d7c4ea7491b 348 if(!socketOpened) {
sgodinez 17:2d7c4ea7491b 349 printf("[ERROR] Socket is not open\r\n");
sgodinez 17:2d7c4ea7491b 350 return 0;
sgodinez 17:2d7c4ea7491b 351 }
sgodinez 19:38794784e009 352 return io->readable();
sgodinez 11:134435d8a2d5 353 }
sgodinez 11:134435d8a2d5 354
sgodinez 11:134435d8a2d5 355 unsigned int Cellular::writeable() {
sgodinez 19:38794784e009 356 if(io == NULL) {
sgodinez 19:38794784e009 357 printf("[ERROR] MTSBufferedIO not set\r\n");
sgodinez 19:38794784e009 358 return 0;
sgodinez 19:38794784e009 359 }
sgodinez 17:2d7c4ea7491b 360 if(!socketOpened) {
sgodinez 17:2d7c4ea7491b 361 printf("[ERROR] Socket is not open\r\n");
sgodinez 17:2d7c4ea7491b 362 return 0;
sgodinez 17:2d7c4ea7491b 363 }
sgodinez 17:2d7c4ea7491b 364
sgodinez 19:38794784e009 365 return io->writeable();
sgodinez 11:134435d8a2d5 366 }
sgodinez 11:134435d8a2d5 367
sgodinez 11:134435d8a2d5 368 void Cellular::reset() {
mfiore 29:7408b1bdad37 369 disconnect();
mfiore 29:7408b1bdad37 370 Code code = sendBasicCommand("AT#RESET=0", 10000);
mfiore 29:7408b1bdad37 371 if(code != OK) {
mfiore 29:7408b1bdad37 372 printf("[ERROR] Socket Modem did not accept RESET command\n\r");
mfiore 29:7408b1bdad37 373 } else {
mfiore 29:7408b1bdad37 374 printf("[WARNING] Socket Modem is resetting, allow 30 seconds for it to come back\n\r");
mfiore 29:7408b1bdad37 375 }
sgodinez 11:134435d8a2d5 376 }
sgodinez 11:134435d8a2d5 377
sgodinez 11:134435d8a2d5 378 Cellular::Code Cellular::test()
jengbrecht 0:563b70517320 379 {
sgodinez 11:134435d8a2d5 380 Code code = sendBasicCommand("AT", 1000);
sgodinez 11:134435d8a2d5 381
sgodinez 11:134435d8a2d5 382 if(code != OK) {
sgodinez 11:134435d8a2d5 383 printf("[Error] Failed basic AT command");
sgodinez 11:134435d8a2d5 384 return code;
sgodinez 11:134435d8a2d5 385 }
sgodinez 11:134435d8a2d5 386
sgodinez 11:134435d8a2d5 387 //AT#VSTATE != "CHECKING"
sgodinez 11:134435d8a2d5 388
sgodinez 11:134435d8a2d5 389 //AT#GPRSMODE ==
sgodinez 12:40ac31a09132 390 return OK;
jengbrecht 0:563b70517320 391 }
jengbrecht 0:563b70517320 392
mfiore 29:7408b1bdad37 393 Cellular::Code Cellular::echo(bool state)
jengbrecht 0:563b70517320 394 {
sgodinez 13:0af863114629 395 Code code;
jengbrecht 0:563b70517320 396 if (state) {
sgodinez 13:0af863114629 397 code = sendBasicCommand("ATE0", 1000);
sgodinez 13:0af863114629 398 echoMode = (code == OK) ? false : echoMode;
jengbrecht 0:563b70517320 399 } else {
sgodinez 13:0af863114629 400 code = sendBasicCommand("ATE1", 1000);
sgodinez 13:0af863114629 401 echoMode = (code == OK) ? true : echoMode;
jengbrecht 0:563b70517320 402 }
sgodinez 13:0af863114629 403 return code;
jengbrecht 0:563b70517320 404 }
jengbrecht 0:563b70517320 405
jengbrecht 0:563b70517320 406 int Cellular::getSignalStrength()
jengbrecht 0:563b70517320 407 {
jengbrecht 0:563b70517320 408 string response = sendCommand("AT+CSQ", 1000);
jengbrecht 0:563b70517320 409 if (response.find("OK") == string::npos) {
jengbrecht 0:563b70517320 410 return -1;
jengbrecht 0:563b70517320 411 }
jengbrecht 0:563b70517320 412 int start = response.find(':');
jengbrecht 0:563b70517320 413 int stop = response.find(',', start);
jengbrecht 0:563b70517320 414 string signal = response.substr(start + 2, stop - start - 2);
jengbrecht 0:563b70517320 415 int value;
jengbrecht 0:563b70517320 416 sscanf(signal.c_str(), "%d", &value);
jengbrecht 0:563b70517320 417 return value;
jengbrecht 0:563b70517320 418 }
jengbrecht 0:563b70517320 419
sgodinez 5:93e889a5abc6 420 std::string Cellular::getPhoneNumber() {
sgodinez 5:93e889a5abc6 421 return "unknown";
sgodinez 5:93e889a5abc6 422 }
sgodinez 5:93e889a5abc6 423
jengbrecht 0:563b70517320 424 Cellular::Registration Cellular::getRegistration()
jengbrecht 0:563b70517320 425 {
jengbrecht 0:563b70517320 426 string response = sendCommand("AT+CREG?", 1000);
jengbrecht 0:563b70517320 427 if (response.find("OK") == string::npos) {
jengbrecht 0:563b70517320 428 return UNKNOWN;
jengbrecht 0:563b70517320 429 }
jengbrecht 0:563b70517320 430 int start = response.find(',');
jengbrecht 0:563b70517320 431 int stop = response.find(' ', start);
jengbrecht 0:563b70517320 432 string regStat = response.substr(start + 1, stop - start - 1);
jengbrecht 0:563b70517320 433 int value;
jengbrecht 0:563b70517320 434 sscanf(regStat.c_str(), "%d", &value);
jengbrecht 0:563b70517320 435 switch (value) {
jengbrecht 0:563b70517320 436 case 0:
jengbrecht 0:563b70517320 437 return NOT_REGISTERED;
jengbrecht 0:563b70517320 438 case 1:
jengbrecht 0:563b70517320 439 return REGISTERED;
jengbrecht 0:563b70517320 440 case 2:
jengbrecht 0:563b70517320 441 return SEARCHING;
jengbrecht 0:563b70517320 442 case 3:
jengbrecht 0:563b70517320 443 return DENIED;
jengbrecht 0:563b70517320 444 case 4:
jengbrecht 0:563b70517320 445 return UNKNOWN;
jengbrecht 0:563b70517320 446 case 5:
jengbrecht 0:563b70517320 447 return ROAMING;
jengbrecht 0:563b70517320 448 }
sgodinez 4:6561c9128c6f 449 return UNKNOWN;
jengbrecht 0:563b70517320 450 }
jengbrecht 0:563b70517320 451
jengbrecht 0:563b70517320 452 Cellular::Code Cellular::sendBasicCommand(string command, int timeoutMillis, ESC_CHAR esc)
jengbrecht 0:563b70517320 453 {
sgodinez 17:2d7c4ea7491b 454 if(socketOpened) {
sgodinez 17:2d7c4ea7491b 455 printf("[ERROR] socket is open. Can not send AT commands\r\n");
sgodinez 17:2d7c4ea7491b 456 return ERROR;
sgodinez 17:2d7c4ea7491b 457 }
sgodinez 17:2d7c4ea7491b 458
jengbrecht 0:563b70517320 459 string response = sendCommand(command, timeoutMillis, esc);
jengbrecht 0:563b70517320 460 if (response.size() == 0) {
jengbrecht 0:563b70517320 461 return NO_RESPONSE;
jengbrecht 0:563b70517320 462 } else if (response.find("OK") != string::npos) {
jengbrecht 0:563b70517320 463 return OK;
jengbrecht 0:563b70517320 464 } else if (response.find("ERROR") != string::npos) {
jengbrecht 0:563b70517320 465 return ERROR;
jengbrecht 0:563b70517320 466 } else {
jengbrecht 0:563b70517320 467 return FAILURE;
jengbrecht 0:563b70517320 468 }
jengbrecht 0:563b70517320 469 }
jengbrecht 0:563b70517320 470
sgodinez 11:134435d8a2d5 471 Cellular::Code Cellular::setApn(const std::string& apn) {
sgodinez 11:134435d8a2d5 472 Code code = sendBasicCommand("AT#APNSERV=\"" + apn + "\"", 1000);
sgodinez 11:134435d8a2d5 473 if (code != OK) {
sgodinez 11:134435d8a2d5 474 return code;
sgodinez 11:134435d8a2d5 475 }
sgodinez 11:134435d8a2d5 476 this->apn = apn;
sgodinez 11:134435d8a2d5 477 return code;
sgodinez 11:134435d8a2d5 478 }
sgodinez 11:134435d8a2d5 479
jengbrecht 27:8e6188cbcfd4 480 Cellular::Code Cellular::setDns(const std::string& address) {
sgodinez 12:40ac31a09132 481 return FAILURE;
sgodinez 11:134435d8a2d5 482 }
sgodinez 11:134435d8a2d5 483
jengbrecht 23:bc6f98a1eb22 484 bool Cellular::ping(const std::string& address) {
jengbrecht 23:bc6f98a1eb22 485 char buffer[256] = {0};
jengbrecht 23:bc6f98a1eb22 486 Code code;
jengbrecht 23:bc6f98a1eb22 487
jengbrecht 23:bc6f98a1eb22 488 code = sendBasicCommand("AT#PINGREMOTE=\"" + address + "\"", 1000);
jengbrecht 23:bc6f98a1eb22 489 if (code != OK) {
jengbrecht 23:bc6f98a1eb22 490 return false;
jengbrecht 23:bc6f98a1eb22 491 }
jengbrecht 23:bc6f98a1eb22 492
jengbrecht 23:bc6f98a1eb22 493 sprintf(buffer, "AT#PINGNUM=%d", 1);
jengbrecht 23:bc6f98a1eb22 494 code = sendBasicCommand(buffer , 1000);
jengbrecht 23:bc6f98a1eb22 495 if (code != OK) {
jengbrecht 23:bc6f98a1eb22 496 return false;
jengbrecht 23:bc6f98a1eb22 497 }
jengbrecht 23:bc6f98a1eb22 498
jengbrecht 23:bc6f98a1eb22 499 sprintf(buffer, "AT#PINGDELAY=%d", PINGDELAY);
jengbrecht 23:bc6f98a1eb22 500 code = sendBasicCommand(buffer , 1000);
jengbrecht 23:bc6f98a1eb22 501 if (code != OK) {
jengbrecht 23:bc6f98a1eb22 502 return false;
jengbrecht 23:bc6f98a1eb22 503 }
jengbrecht 23:bc6f98a1eb22 504
jengbrecht 23:bc6f98a1eb22 505 std::string response;
jengbrecht 23:bc6f98a1eb22 506 for (int i = 0; i < PINGNUM; i++) {
jengbrecht 23:bc6f98a1eb22 507 response = sendCommand("AT#PING", PINGDELAY * 1000);
jengbrecht 23:bc6f98a1eb22 508 if (response.find("alive") != std::string::npos) {
jengbrecht 23:bc6f98a1eb22 509 return true;
jengbrecht 23:bc6f98a1eb22 510 }
jengbrecht 23:bc6f98a1eb22 511 }
jengbrecht 23:bc6f98a1eb22 512 return false;
jengbrecht 23:bc6f98a1eb22 513 }
jengbrecht 23:bc6f98a1eb22 514
sgodinez 17:2d7c4ea7491b 515 Cellular::Code Cellular::setSocketCloseable(bool enabled) {
sgodinez 17:2d7c4ea7491b 516 if(socketCloseable == enabled) {
sgodinez 17:2d7c4ea7491b 517 return OK;
sgodinez 17:2d7c4ea7491b 518 }
sgodinez 17:2d7c4ea7491b 519
sgodinez 17:2d7c4ea7491b 520 if(socketOpened) {
sgodinez 17:2d7c4ea7491b 521 printf("[ERROR] socket is already opened. Can not set closeable\r\n");
sgodinez 17:2d7c4ea7491b 522 return ERROR;
sgodinez 17:2d7c4ea7491b 523 }
sgodinez 17:2d7c4ea7491b 524
sgodinez 17:2d7c4ea7491b 525 socketCloseable = enabled;
sgodinez 17:2d7c4ea7491b 526
sgodinez 17:2d7c4ea7491b 527 return OK;
sgodinez 17:2d7c4ea7491b 528 }
sgodinez 17:2d7c4ea7491b 529
sgodinez 4:6561c9128c6f 530 Cellular::Code Cellular::sendSMS(const Sms& sms) {
sgodinez 4:6561c9128c6f 531 return sendSMS(sms.phoneNumber, sms.message);
sgodinez 4:6561c9128c6f 532 }
sgodinez 4:6561c9128c6f 533
sgodinez 4:6561c9128c6f 534 Cellular::Code Cellular::sendSMS(const std::string& phoneNumber, const std::string& message)
sgodinez 17:2d7c4ea7491b 535 {
jengbrecht 0:563b70517320 536 Code code = sendBasicCommand("AT+CMGF=1", 1000);
jengbrecht 0:563b70517320 537 if (code != OK) {
jengbrecht 0:563b70517320 538 return code;
jengbrecht 0:563b70517320 539 }
jengbrecht 0:563b70517320 540 string cmd = "AT+CMGS=\"+";
jengbrecht 0:563b70517320 541 cmd.append(phoneNumber);
jengbrecht 0:563b70517320 542 cmd.append("\"");
jengbrecht 0:563b70517320 543 string response1 = sendCommand(cmd, 1000);
jengbrecht 0:563b70517320 544 if (response1.find('>') == string::npos) {
jengbrecht 0:563b70517320 545 return NO_RESPONSE;
jengbrecht 0:563b70517320 546 }
jengbrecht 0:563b70517320 547 wait(.2);
jengbrecht 0:563b70517320 548 string response2 = sendCommand(message, 4000, CTRL_Z);
sgodinez 17:2d7c4ea7491b 549 printf("SMS Response: %s\r\n", response2.c_str());
jengbrecht 0:563b70517320 550 if (response2.find("+CMGS:") == string::npos) {
jengbrecht 0:563b70517320 551 return FAILURE;
jengbrecht 0:563b70517320 552 }
jengbrecht 0:563b70517320 553 return OK;
jengbrecht 0:563b70517320 554 }
jengbrecht 0:563b70517320 555
sgodinez 4:6561c9128c6f 556 std::vector<Cellular::Sms> Cellular::getReceivedSms() {
sgodinez 9:5b12c5a8dde4 557 int smsNumber = 0;
sgodinez 4:6561c9128c6f 558 std::vector<Sms> vSms;
sgodinez 4:6561c9128c6f 559 std::string received = sendCommand("AT+CMGL=\"ALL\"", 4000);
sgodinez 5:93e889a5abc6 560 size_t pos = received.find("+CMGL: ");
sgodinez 4:6561c9128c6f 561
sgodinez 5:93e889a5abc6 562 while (pos != std::string::npos) {
sgodinez 4:6561c9128c6f 563 Cellular::Sms sms;
sgodinez 4:6561c9128c6f 564 std::string line(Text::getLine(received, pos, pos));
sgodinez 17:2d7c4ea7491b 565 //printf("[DEBUG] Top of SMS Parse Loop. LINE[%s]\r\n", line.c_str());
sgodinez 9:5b12c5a8dde4 566 if(line.find("+CMGL: ") == std::string::npos) {
sgodinez 4:6561c9128c6f 567 continue;
sgodinez 4:6561c9128c6f 568 }
sgodinez 4:6561c9128c6f 569
sgodinez 4:6561c9128c6f 570 //Start of SMS message
sgodinez 4:6561c9128c6f 571 std::vector<std::string> vSmsParts = Text::split(line, ',');
sgodinez 4:6561c9128c6f 572 if(vSmsParts.size() != 6) {
sgodinez 17:2d7c4ea7491b 573 printf("[WARNING] Expected 6 commas. SMS[%d] DATA[%s]. Continuing ...\r\n", smsNumber, line.c_str());
sgodinez 4:6561c9128c6f 574 continue;
sgodinez 4:6561c9128c6f 575 }
sgodinez 4:6561c9128c6f 576
sgodinez 4:6561c9128c6f 577 sms.phoneNumber = vSmsParts[2];
sgodinez 4:6561c9128c6f 578 sms.timestamp = vSmsParts[4] + ", " + vSmsParts[5];
sgodinez 4:6561c9128c6f 579
sgodinez 8:3fe68d6130a8 580 if(pos == std::string::npos) {
sgodinez 17:2d7c4ea7491b 581 printf("[WARNING] Expected SMS body. SMS[%d]. Leaving ...\r\n", smsNumber);
sgodinez 8:3fe68d6130a8 582 break;
sgodinez 8:3fe68d6130a8 583 }
sgodinez 9:5b12c5a8dde4 584 //Check for the start of the next SMS message
sgodinez 9:5b12c5a8dde4 585 size_t bodyEnd = received.find("\r\n+CMGL: ", pos);
sgodinez 8:3fe68d6130a8 586 if(bodyEnd == std::string::npos) {
sgodinez 17:2d7c4ea7491b 587 //printf("[DEBUG] Parsing Last SMS. SMS[%d]\r\n", smsNumber);
sgodinez 9:5b12c5a8dde4 588 //This must be the last SMS message
sgodinez 9:5b12c5a8dde4 589 bodyEnd = received.find("\r\n\r\nOK", pos);
sgodinez 8:3fe68d6130a8 590 }
sgodinez 9:5b12c5a8dde4 591
sgodinez 9:5b12c5a8dde4 592 //Safety check that we found the boundary of this current SMS message
sgodinez 9:5b12c5a8dde4 593 if(bodyEnd != std::string::npos) {
sgodinez 9:5b12c5a8dde4 594 sms.message = received.substr(pos, bodyEnd - pos);
sgodinez 9:5b12c5a8dde4 595 } else {
sgodinez 8:3fe68d6130a8 596 sms.message = received.substr(pos);
sgodinez 17:2d7c4ea7491b 597 printf("[WARNING] Expected to find end of SMS list. SMS[%d] DATA[%s].\r\n", smsNumber, sms.message.c_str());
sgodinez 8:3fe68d6130a8 598 }
sgodinez 5:93e889a5abc6 599 vSms.push_back(sms);
sgodinez 4:6561c9128c6f 600 pos = bodyEnd;
sgodinez 17:2d7c4ea7491b 601 //printf("[DEBUG] Parsed SMS[%d]. Starting Next at position [%d]\r\n", smsNumber, pos);
sgodinez 9:5b12c5a8dde4 602 smsNumber++;
sgodinez 4:6561c9128c6f 603 }
sgodinez 17:2d7c4ea7491b 604 printf("Received %d SMS\r\n", smsNumber);
sgodinez 4:6561c9128c6f 605 return vSms;
sgodinez 4:6561c9128c6f 606 }
sgodinez 4:6561c9128c6f 607
sgodinez 4:6561c9128c6f 608 Cellular::Code Cellular::deleteOnlyReceivedReadSms() {
sgodinez 4:6561c9128c6f 609 return sendBasicCommand("AT+CMGD=1,1", 1000);
sgodinez 4:6561c9128c6f 610 }
sgodinez 4:6561c9128c6f 611
sgodinez 4:6561c9128c6f 612 Cellular::Code Cellular::deleteAllReceivedSms() {
sgodinez 4:6561c9128c6f 613 return sendBasicCommand("AT+CMGD=1,4", 1000);
sgodinez 4:6561c9128c6f 614 }
sgodinez 4:6561c9128c6f 615
sgodinez 4:6561c9128c6f 616
jengbrecht 0:563b70517320 617 string Cellular::sendCommand(string command, int timeoutMillis, ESC_CHAR esc)
jengbrecht 0:563b70517320 618 {
sgodinez 19:38794784e009 619 if(io == NULL) {
sgodinez 19:38794784e009 620 printf("[ERROR] MTSBufferedIO not set\r\n");
sgodinez 19:38794784e009 621 return "";
sgodinez 19:38794784e009 622 }
sgodinez 17:2d7c4ea7491b 623 if(socketOpened) {
sgodinez 17:2d7c4ea7491b 624 printf("[ERROR] socket is open. Can not send AT commands\r\n");
sgodinez 17:2d7c4ea7491b 625 return "";
sgodinez 17:2d7c4ea7491b 626 }
sgodinez 17:2d7c4ea7491b 627
jengbrecht 0:563b70517320 628 int size = command.size() + 1;
jengbrecht 0:563b70517320 629 char cmd[size];
jengbrecht 0:563b70517320 630 strcpy(cmd, command.c_str());
jengbrecht 0:563b70517320 631 if (esc == CR) {
jengbrecht 0:563b70517320 632 cmd[size -1] = '\r';
jengbrecht 0:563b70517320 633 } else if (esc == CTRL_Z) {
jengbrecht 0:563b70517320 634 cmd[size -1] = 0x1A;
sgodinez 13:0af863114629 635 } else if(esc == NONE) {
sgodinez 13:0af863114629 636 cmd[size -1] = '\0';
jengbrecht 0:563b70517320 637 }
jengbrecht 0:563b70517320 638
sgodinez 19:38794784e009 639 io->rxClear();
sgodinez 19:38794784e009 640 io->txClear();
sgodinez 8:3fe68d6130a8 641 std::string result;
sgodinez 19:38794784e009 642 int status = io->write(cmd, size);
sgodinez 19:38794784e009 643 int available = io->rxAvailable();
jengbrecht 0:563b70517320 644 int previous = -1;
jengbrecht 0:563b70517320 645 int timer = 0;
sgodinez 8:3fe68d6130a8 646 char tmp[256];
sgodinez 8:3fe68d6130a8 647 tmp[255] = 0;
sgodinez 13:0af863114629 648 bool started = !echoMode;
sgodinez 13:0af863114629 649 bool done = false;
sgodinez 8:3fe68d6130a8 650 do {
jengbrecht 0:563b70517320 651 wait(.1);
jengbrecht 0:563b70517320 652 timer = timer + 100;
jengbrecht 0:563b70517320 653 previous = available;
sgodinez 19:38794784e009 654 available = io->rxAvailable();
sgodinez 8:3fe68d6130a8 655
sgodinez 19:38794784e009 656 int size = io->read(tmp,255); //1 less than allocated
sgodinez 8:3fe68d6130a8 657 if(size > 0) {
sgodinez 8:3fe68d6130a8 658 result.append(tmp, size);
sgodinez 8:3fe68d6130a8 659 }
sgodinez 13:0af863114629 660
sgodinez 13:0af863114629 661 if(!started) {
sgodinez 13:0af863114629 662 //In Echo Mode (Command will have echo'd + 2 characters for \r\n)
sgodinez 13:0af863114629 663 if(result.size() > command.size() + 2) {
sgodinez 13:0af863114629 664 started = true;
sgodinez 13:0af863114629 665 }
sgodinez 13:0af863114629 666 } else {
sgodinez 13:0af863114629 667 done = (available == previous);
sgodinez 13:0af863114629 668 }
sgodinez 13:0af863114629 669 if(timer >= timeoutMillis) {
sgodinez 17:2d7c4ea7491b 670 printf("[WARNING] sendCommand timed out after %d milliseconds\r\n", timeoutMillis);
sgodinez 13:0af863114629 671 done = true;
sgodinez 13:0af863114629 672 }
sgodinez 13:0af863114629 673 } while (!done);
sgodinez 8:3fe68d6130a8 674
sgodinez 8:3fe68d6130a8 675 return result;
jengbrecht 0:563b70517320 676 }
jengbrecht 0:563b70517320 677
jengbrecht 0:563b70517320 678 #endif /* CELLULAR_CPP */