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:
mfiore
Date:
Wed Dec 18 16:04:57 2013 +0000
Revision:
29:7408b1bdad37
Parent:
23:bc6f98a1eb22
Child:
30:06c756af6c5c
add cellular->reset() function (may need to be changed to HW reset); fixed bug in Endpoint code; added correct handling of DCD and DTR lines to/from radio

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 17:2d7c4ea7491b 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 19:38794784e009 252 if (io->readable()) {
sgodinez 19:38794784e009 253 if(io->read(data[bytesRead]) == 1) {
sgodinez 17:2d7c4ea7491b 254 bytesRead++;
sgodinez 17:2d7c4ea7491b 255 }
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 17:2d7c4ea7491b 264 return bytesRead;
sgodinez 11:134435d8a2d5 265 }
sgodinez 11:134435d8a2d5 266
sgodinez 11:134435d8a2d5 267 int Cellular::write(char* data, int length, int timeout) {
sgodinez 19:38794784e009 268 if(io == NULL) {
sgodinez 19:38794784e009 269 printf("[ERROR] MTSBufferedIO not set\r\n");
sgodinez 19:38794784e009 270 return -1;
sgodinez 19:38794784e009 271 }
sgodinez 19:38794784e009 272
sgodinez 17:2d7c4ea7491b 273 if(!socketOpened) {
sgodinez 17:2d7c4ea7491b 274 printf("[ERROR] Socket is not open\r\n");
sgodinez 17:2d7c4ea7491b 275 return -1;
sgodinez 17:2d7c4ea7491b 276 }
sgodinez 17:2d7c4ea7491b 277
sgodinez 17:2d7c4ea7491b 278 int bytesWritten = 0;
sgodinez 17:2d7c4ea7491b 279
sgodinez 17:2d7c4ea7491b 280 if(timeout >= 0) {
sgodinez 17:2d7c4ea7491b 281 Timer tmr;
sgodinez 17:2d7c4ea7491b 282 tmr.start();
sgodinez 17:2d7c4ea7491b 283 while (tmr.read_ms() <= timeout && bytesWritten < length) {
sgodinez 19:38794784e009 284 if (io->writeable()) {
sgodinez 19:38794784e009 285 if(io->write(*data) == 1) {
sgodinez 17:2d7c4ea7491b 286 data++;
sgodinez 17:2d7c4ea7491b 287 bytesWritten++;
sgodinez 17:2d7c4ea7491b 288 }
sgodinez 17:2d7c4ea7491b 289 } else {
sgodinez 17:2d7c4ea7491b 290 wait(0.05);
sgodinez 17:2d7c4ea7491b 291 }
sgodinez 17:2d7c4ea7491b 292 }
sgodinez 17:2d7c4ea7491b 293 } else {
sgodinez 19:38794784e009 294 bytesWritten = io->write(data, length);
sgodinez 17:2d7c4ea7491b 295 }
sgodinez 17:2d7c4ea7491b 296
sgodinez 17:2d7c4ea7491b 297 return bytesWritten;
sgodinez 11:134435d8a2d5 298 }
sgodinez 11:134435d8a2d5 299
sgodinez 11:134435d8a2d5 300 unsigned int Cellular::readable() {
sgodinez 19:38794784e009 301 if(io == NULL) {
sgodinez 19:38794784e009 302 printf("[ERROR] MTSBufferedIO not set\r\n");
sgodinez 19:38794784e009 303 return 0;
sgodinez 19:38794784e009 304 }
sgodinez 17:2d7c4ea7491b 305 if(!socketOpened) {
sgodinez 17:2d7c4ea7491b 306 printf("[ERROR] Socket is not open\r\n");
sgodinez 17:2d7c4ea7491b 307 return 0;
sgodinez 17:2d7c4ea7491b 308 }
sgodinez 19:38794784e009 309 return io->readable();
sgodinez 11:134435d8a2d5 310 }
sgodinez 11:134435d8a2d5 311
sgodinez 11:134435d8a2d5 312 unsigned int Cellular::writeable() {
sgodinez 19:38794784e009 313 if(io == NULL) {
sgodinez 19:38794784e009 314 printf("[ERROR] MTSBufferedIO not set\r\n");
sgodinez 19:38794784e009 315 return 0;
sgodinez 19:38794784e009 316 }
sgodinez 17:2d7c4ea7491b 317 if(!socketOpened) {
sgodinez 17:2d7c4ea7491b 318 printf("[ERROR] Socket is not open\r\n");
sgodinez 17:2d7c4ea7491b 319 return 0;
sgodinez 17:2d7c4ea7491b 320 }
sgodinez 17:2d7c4ea7491b 321
sgodinez 19:38794784e009 322 return io->writeable();
sgodinez 11:134435d8a2d5 323 }
sgodinez 11:134435d8a2d5 324
sgodinez 11:134435d8a2d5 325 void Cellular::reset() {
mfiore 29:7408b1bdad37 326 disconnect();
mfiore 29:7408b1bdad37 327 Code code = sendBasicCommand("AT#RESET=0", 10000);
mfiore 29:7408b1bdad37 328 if(code != OK) {
mfiore 29:7408b1bdad37 329 printf("[ERROR] Socket Modem did not accept RESET command\n\r");
mfiore 29:7408b1bdad37 330 } else {
mfiore 29:7408b1bdad37 331 printf("[WARNING] Socket Modem is resetting, allow 30 seconds for it to come back\n\r");
mfiore 29:7408b1bdad37 332 }
sgodinez 11:134435d8a2d5 333 }
sgodinez 11:134435d8a2d5 334
sgodinez 11:134435d8a2d5 335 Cellular::Code Cellular::test()
jengbrecht 0:563b70517320 336 {
sgodinez 11:134435d8a2d5 337 Code code = sendBasicCommand("AT", 1000);
sgodinez 11:134435d8a2d5 338
sgodinez 11:134435d8a2d5 339 if(code != OK) {
sgodinez 11:134435d8a2d5 340 printf("[Error] Failed basic AT command");
sgodinez 11:134435d8a2d5 341 return code;
sgodinez 11:134435d8a2d5 342 }
sgodinez 11:134435d8a2d5 343
sgodinez 11:134435d8a2d5 344 //AT#VSTATE != "CHECKING"
sgodinez 11:134435d8a2d5 345
sgodinez 11:134435d8a2d5 346 //AT#GPRSMODE ==
sgodinez 12:40ac31a09132 347 return OK;
jengbrecht 0:563b70517320 348 }
jengbrecht 0:563b70517320 349
mfiore 29:7408b1bdad37 350 Cellular::Code Cellular::echo(bool state)
jengbrecht 0:563b70517320 351 {
sgodinez 13:0af863114629 352 Code code;
jengbrecht 0:563b70517320 353 if (state) {
sgodinez 13:0af863114629 354 code = sendBasicCommand("ATE0", 1000);
sgodinez 13:0af863114629 355 echoMode = (code == OK) ? false : echoMode;
jengbrecht 0:563b70517320 356 } else {
sgodinez 13:0af863114629 357 code = sendBasicCommand("ATE1", 1000);
sgodinez 13:0af863114629 358 echoMode = (code == OK) ? true : echoMode;
jengbrecht 0:563b70517320 359 }
sgodinez 13:0af863114629 360 return code;
jengbrecht 0:563b70517320 361 }
jengbrecht 0:563b70517320 362
jengbrecht 0:563b70517320 363 int Cellular::getSignalStrength()
jengbrecht 0:563b70517320 364 {
jengbrecht 0:563b70517320 365 string response = sendCommand("AT+CSQ", 1000);
jengbrecht 0:563b70517320 366 if (response.find("OK") == string::npos) {
jengbrecht 0:563b70517320 367 return -1;
jengbrecht 0:563b70517320 368 }
jengbrecht 0:563b70517320 369 int start = response.find(':');
jengbrecht 0:563b70517320 370 int stop = response.find(',', start);
jengbrecht 0:563b70517320 371 string signal = response.substr(start + 2, stop - start - 2);
jengbrecht 0:563b70517320 372 int value;
jengbrecht 0:563b70517320 373 sscanf(signal.c_str(), "%d", &value);
jengbrecht 0:563b70517320 374 return value;
jengbrecht 0:563b70517320 375 }
jengbrecht 0:563b70517320 376
sgodinez 5:93e889a5abc6 377 std::string Cellular::getPhoneNumber() {
sgodinez 5:93e889a5abc6 378 return "unknown";
sgodinez 5:93e889a5abc6 379 }
sgodinez 5:93e889a5abc6 380
jengbrecht 0:563b70517320 381 Cellular::Registration Cellular::getRegistration()
jengbrecht 0:563b70517320 382 {
jengbrecht 0:563b70517320 383 string response = sendCommand("AT+CREG?", 1000);
jengbrecht 0:563b70517320 384 if (response.find("OK") == string::npos) {
jengbrecht 0:563b70517320 385 return UNKNOWN;
jengbrecht 0:563b70517320 386 }
jengbrecht 0:563b70517320 387 int start = response.find(',');
jengbrecht 0:563b70517320 388 int stop = response.find(' ', start);
jengbrecht 0:563b70517320 389 string regStat = response.substr(start + 1, stop - start - 1);
jengbrecht 0:563b70517320 390 int value;
jengbrecht 0:563b70517320 391 sscanf(regStat.c_str(), "%d", &value);
jengbrecht 0:563b70517320 392 switch (value) {
jengbrecht 0:563b70517320 393 case 0:
jengbrecht 0:563b70517320 394 return NOT_REGISTERED;
jengbrecht 0:563b70517320 395 case 1:
jengbrecht 0:563b70517320 396 return REGISTERED;
jengbrecht 0:563b70517320 397 case 2:
jengbrecht 0:563b70517320 398 return SEARCHING;
jengbrecht 0:563b70517320 399 case 3:
jengbrecht 0:563b70517320 400 return DENIED;
jengbrecht 0:563b70517320 401 case 4:
jengbrecht 0:563b70517320 402 return UNKNOWN;
jengbrecht 0:563b70517320 403 case 5:
jengbrecht 0:563b70517320 404 return ROAMING;
jengbrecht 0:563b70517320 405 }
sgodinez 4:6561c9128c6f 406 return UNKNOWN;
jengbrecht 0:563b70517320 407 }
jengbrecht 0:563b70517320 408
jengbrecht 0:563b70517320 409 Cellular::Code Cellular::sendBasicCommand(string command, int timeoutMillis, ESC_CHAR esc)
jengbrecht 0:563b70517320 410 {
sgodinez 17:2d7c4ea7491b 411 if(socketOpened) {
sgodinez 17:2d7c4ea7491b 412 printf("[ERROR] socket is open. Can not send AT commands\r\n");
sgodinez 17:2d7c4ea7491b 413 return ERROR;
sgodinez 17:2d7c4ea7491b 414 }
sgodinez 17:2d7c4ea7491b 415
jengbrecht 0:563b70517320 416 string response = sendCommand(command, timeoutMillis, esc);
jengbrecht 0:563b70517320 417 if (response.size() == 0) {
jengbrecht 0:563b70517320 418 return NO_RESPONSE;
jengbrecht 0:563b70517320 419 } else if (response.find("OK") != string::npos) {
jengbrecht 0:563b70517320 420 return OK;
jengbrecht 0:563b70517320 421 } else if (response.find("ERROR") != string::npos) {
jengbrecht 0:563b70517320 422 return ERROR;
jengbrecht 0:563b70517320 423 } else {
jengbrecht 0:563b70517320 424 return FAILURE;
jengbrecht 0:563b70517320 425 }
jengbrecht 0:563b70517320 426 }
jengbrecht 0:563b70517320 427
sgodinez 11:134435d8a2d5 428 Cellular::Code Cellular::setApn(const std::string& apn) {
sgodinez 11:134435d8a2d5 429 Code code = sendBasicCommand("AT#APNSERV=\"" + apn + "\"", 1000);
sgodinez 11:134435d8a2d5 430 if (code != OK) {
sgodinez 11:134435d8a2d5 431 return code;
sgodinez 11:134435d8a2d5 432 }
sgodinez 11:134435d8a2d5 433 this->apn = apn;
sgodinez 11:134435d8a2d5 434 return code;
sgodinez 11:134435d8a2d5 435 }
sgodinez 11:134435d8a2d5 436
sgodinez 11:134435d8a2d5 437 Cellular::Code Cellular::setDns(const std::string& apn) {
sgodinez 12:40ac31a09132 438 return FAILURE;
sgodinez 11:134435d8a2d5 439 }
sgodinez 11:134435d8a2d5 440
jengbrecht 23:bc6f98a1eb22 441 bool Cellular::ping(const std::string& address) {
jengbrecht 23:bc6f98a1eb22 442 char buffer[256] = {0};
jengbrecht 23:bc6f98a1eb22 443 Code code;
jengbrecht 23:bc6f98a1eb22 444
jengbrecht 23:bc6f98a1eb22 445 code = sendBasicCommand("AT#PINGREMOTE=\"" + address + "\"", 1000);
jengbrecht 23:bc6f98a1eb22 446 if (code != OK) {
jengbrecht 23:bc6f98a1eb22 447 return false;
jengbrecht 23:bc6f98a1eb22 448 }
jengbrecht 23:bc6f98a1eb22 449
jengbrecht 23:bc6f98a1eb22 450 sprintf(buffer, "AT#PINGNUM=%d", 1);
jengbrecht 23:bc6f98a1eb22 451 code = sendBasicCommand(buffer , 1000);
jengbrecht 23:bc6f98a1eb22 452 if (code != OK) {
jengbrecht 23:bc6f98a1eb22 453 return false;
jengbrecht 23:bc6f98a1eb22 454 }
jengbrecht 23:bc6f98a1eb22 455
jengbrecht 23:bc6f98a1eb22 456 sprintf(buffer, "AT#PINGDELAY=%d", PINGDELAY);
jengbrecht 23:bc6f98a1eb22 457 code = sendBasicCommand(buffer , 1000);
jengbrecht 23:bc6f98a1eb22 458 if (code != OK) {
jengbrecht 23:bc6f98a1eb22 459 return false;
jengbrecht 23:bc6f98a1eb22 460 }
jengbrecht 23:bc6f98a1eb22 461
jengbrecht 23:bc6f98a1eb22 462 std::string response;
jengbrecht 23:bc6f98a1eb22 463 for (int i = 0; i < PINGNUM; i++) {
jengbrecht 23:bc6f98a1eb22 464 response = sendCommand("AT#PING", PINGDELAY * 1000);
jengbrecht 23:bc6f98a1eb22 465 if (response.find("alive") != std::string::npos) {
jengbrecht 23:bc6f98a1eb22 466 return true;
jengbrecht 23:bc6f98a1eb22 467 }
jengbrecht 23:bc6f98a1eb22 468 }
jengbrecht 23:bc6f98a1eb22 469 return false;
jengbrecht 23:bc6f98a1eb22 470 }
jengbrecht 23:bc6f98a1eb22 471
sgodinez 17:2d7c4ea7491b 472 Cellular::Code Cellular::setSocketCloseable(bool enabled) {
sgodinez 17:2d7c4ea7491b 473 if(socketCloseable == enabled) {
sgodinez 17:2d7c4ea7491b 474 return OK;
sgodinez 17:2d7c4ea7491b 475 }
sgodinez 17:2d7c4ea7491b 476
sgodinez 17:2d7c4ea7491b 477 if(socketOpened) {
sgodinez 17:2d7c4ea7491b 478 printf("[ERROR] socket is already opened. Can not set closeable\r\n");
sgodinez 17:2d7c4ea7491b 479 return ERROR;
sgodinez 17:2d7c4ea7491b 480 }
sgodinez 17:2d7c4ea7491b 481
sgodinez 17:2d7c4ea7491b 482 socketCloseable = enabled;
sgodinez 17:2d7c4ea7491b 483
sgodinez 17:2d7c4ea7491b 484 return OK;
sgodinez 17:2d7c4ea7491b 485 }
sgodinez 17:2d7c4ea7491b 486
sgodinez 4:6561c9128c6f 487 Cellular::Code Cellular::sendSMS(const Sms& sms) {
sgodinez 4:6561c9128c6f 488 return sendSMS(sms.phoneNumber, sms.message);
sgodinez 4:6561c9128c6f 489 }
sgodinez 4:6561c9128c6f 490
sgodinez 4:6561c9128c6f 491 Cellular::Code Cellular::sendSMS(const std::string& phoneNumber, const std::string& message)
sgodinez 17:2d7c4ea7491b 492 {
jengbrecht 0:563b70517320 493 Code code = sendBasicCommand("AT+CMGF=1", 1000);
jengbrecht 0:563b70517320 494 if (code != OK) {
jengbrecht 0:563b70517320 495 return code;
jengbrecht 0:563b70517320 496 }
jengbrecht 0:563b70517320 497 string cmd = "AT+CMGS=\"+";
jengbrecht 0:563b70517320 498 cmd.append(phoneNumber);
jengbrecht 0:563b70517320 499 cmd.append("\"");
jengbrecht 0:563b70517320 500 string response1 = sendCommand(cmd, 1000);
jengbrecht 0:563b70517320 501 if (response1.find('>') == string::npos) {
jengbrecht 0:563b70517320 502 return NO_RESPONSE;
jengbrecht 0:563b70517320 503 }
jengbrecht 0:563b70517320 504 wait(.2);
jengbrecht 0:563b70517320 505 string response2 = sendCommand(message, 4000, CTRL_Z);
sgodinez 17:2d7c4ea7491b 506 printf("SMS Response: %s\r\n", response2.c_str());
jengbrecht 0:563b70517320 507 if (response2.find("+CMGS:") == string::npos) {
jengbrecht 0:563b70517320 508 return FAILURE;
jengbrecht 0:563b70517320 509 }
jengbrecht 0:563b70517320 510 return OK;
jengbrecht 0:563b70517320 511 }
jengbrecht 0:563b70517320 512
sgodinez 4:6561c9128c6f 513 std::vector<Cellular::Sms> Cellular::getReceivedSms() {
sgodinez 9:5b12c5a8dde4 514 int smsNumber = 0;
sgodinez 4:6561c9128c6f 515 std::vector<Sms> vSms;
sgodinez 4:6561c9128c6f 516 std::string received = sendCommand("AT+CMGL=\"ALL\"", 4000);
sgodinez 5:93e889a5abc6 517 size_t pos = received.find("+CMGL: ");
sgodinez 4:6561c9128c6f 518
sgodinez 5:93e889a5abc6 519 while (pos != std::string::npos) {
sgodinez 4:6561c9128c6f 520 Cellular::Sms sms;
sgodinez 4:6561c9128c6f 521 std::string line(Text::getLine(received, pos, pos));
sgodinez 17:2d7c4ea7491b 522 //printf("[DEBUG] Top of SMS Parse Loop. LINE[%s]\r\n", line.c_str());
sgodinez 9:5b12c5a8dde4 523 if(line.find("+CMGL: ") == std::string::npos) {
sgodinez 4:6561c9128c6f 524 continue;
sgodinez 4:6561c9128c6f 525 }
sgodinez 4:6561c9128c6f 526
sgodinez 4:6561c9128c6f 527 //Start of SMS message
sgodinez 4:6561c9128c6f 528 std::vector<std::string> vSmsParts = Text::split(line, ',');
sgodinez 4:6561c9128c6f 529 if(vSmsParts.size() != 6) {
sgodinez 17:2d7c4ea7491b 530 printf("[WARNING] Expected 6 commas. SMS[%d] DATA[%s]. Continuing ...\r\n", smsNumber, line.c_str());
sgodinez 4:6561c9128c6f 531 continue;
sgodinez 4:6561c9128c6f 532 }
sgodinez 4:6561c9128c6f 533
sgodinez 4:6561c9128c6f 534 sms.phoneNumber = vSmsParts[2];
sgodinez 4:6561c9128c6f 535 sms.timestamp = vSmsParts[4] + ", " + vSmsParts[5];
sgodinez 4:6561c9128c6f 536
sgodinez 8:3fe68d6130a8 537 if(pos == std::string::npos) {
sgodinez 17:2d7c4ea7491b 538 printf("[WARNING] Expected SMS body. SMS[%d]. Leaving ...\r\n", smsNumber);
sgodinez 8:3fe68d6130a8 539 break;
sgodinez 8:3fe68d6130a8 540 }
sgodinez 9:5b12c5a8dde4 541 //Check for the start of the next SMS message
sgodinez 9:5b12c5a8dde4 542 size_t bodyEnd = received.find("\r\n+CMGL: ", pos);
sgodinez 8:3fe68d6130a8 543 if(bodyEnd == std::string::npos) {
sgodinez 17:2d7c4ea7491b 544 //printf("[DEBUG] Parsing Last SMS. SMS[%d]\r\n", smsNumber);
sgodinez 9:5b12c5a8dde4 545 //This must be the last SMS message
sgodinez 9:5b12c5a8dde4 546 bodyEnd = received.find("\r\n\r\nOK", pos);
sgodinez 8:3fe68d6130a8 547 }
sgodinez 9:5b12c5a8dde4 548
sgodinez 9:5b12c5a8dde4 549 //Safety check that we found the boundary of this current SMS message
sgodinez 9:5b12c5a8dde4 550 if(bodyEnd != std::string::npos) {
sgodinez 9:5b12c5a8dde4 551 sms.message = received.substr(pos, bodyEnd - pos);
sgodinez 9:5b12c5a8dde4 552 } else {
sgodinez 8:3fe68d6130a8 553 sms.message = received.substr(pos);
sgodinez 17:2d7c4ea7491b 554 printf("[WARNING] Expected to find end of SMS list. SMS[%d] DATA[%s].\r\n", smsNumber, sms.message.c_str());
sgodinez 8:3fe68d6130a8 555 }
sgodinez 5:93e889a5abc6 556 vSms.push_back(sms);
sgodinez 4:6561c9128c6f 557 pos = bodyEnd;
sgodinez 17:2d7c4ea7491b 558 //printf("[DEBUG] Parsed SMS[%d]. Starting Next at position [%d]\r\n", smsNumber, pos);
sgodinez 9:5b12c5a8dde4 559 smsNumber++;
sgodinez 4:6561c9128c6f 560 }
sgodinez 17:2d7c4ea7491b 561 printf("Received %d SMS\r\n", smsNumber);
sgodinez 4:6561c9128c6f 562 return vSms;
sgodinez 4:6561c9128c6f 563 }
sgodinez 4:6561c9128c6f 564
sgodinez 4:6561c9128c6f 565 Cellular::Code Cellular::deleteOnlyReceivedReadSms() {
sgodinez 4:6561c9128c6f 566 return sendBasicCommand("AT+CMGD=1,1", 1000);
sgodinez 4:6561c9128c6f 567 }
sgodinez 4:6561c9128c6f 568
sgodinez 4:6561c9128c6f 569 Cellular::Code Cellular::deleteAllReceivedSms() {
sgodinez 4:6561c9128c6f 570 return sendBasicCommand("AT+CMGD=1,4", 1000);
sgodinez 4:6561c9128c6f 571 }
sgodinez 4:6561c9128c6f 572
sgodinez 4:6561c9128c6f 573
jengbrecht 0:563b70517320 574 string Cellular::sendCommand(string command, int timeoutMillis, ESC_CHAR esc)
jengbrecht 0:563b70517320 575 {
sgodinez 19:38794784e009 576 if(io == NULL) {
sgodinez 19:38794784e009 577 printf("[ERROR] MTSBufferedIO not set\r\n");
sgodinez 19:38794784e009 578 return "";
sgodinez 19:38794784e009 579 }
sgodinez 17:2d7c4ea7491b 580 if(socketOpened) {
sgodinez 17:2d7c4ea7491b 581 printf("[ERROR] socket is open. Can not send AT commands\r\n");
sgodinez 17:2d7c4ea7491b 582 return "";
sgodinez 17:2d7c4ea7491b 583 }
sgodinez 17:2d7c4ea7491b 584
jengbrecht 0:563b70517320 585 int size = command.size() + 1;
jengbrecht 0:563b70517320 586 char cmd[size];
jengbrecht 0:563b70517320 587 strcpy(cmd, command.c_str());
jengbrecht 0:563b70517320 588 if (esc == CR) {
jengbrecht 0:563b70517320 589 cmd[size -1] = '\r';
jengbrecht 0:563b70517320 590 } else if (esc == CTRL_Z) {
jengbrecht 0:563b70517320 591 cmd[size -1] = 0x1A;
sgodinez 13:0af863114629 592 } else if(esc == NONE) {
sgodinez 13:0af863114629 593 cmd[size -1] = '\0';
jengbrecht 0:563b70517320 594 }
jengbrecht 0:563b70517320 595
sgodinez 19:38794784e009 596 io->rxClear();
sgodinez 19:38794784e009 597 io->txClear();
sgodinez 8:3fe68d6130a8 598 std::string result;
sgodinez 19:38794784e009 599 int status = io->write(cmd, size);
sgodinez 19:38794784e009 600 int available = io->rxAvailable();
jengbrecht 0:563b70517320 601 int previous = -1;
jengbrecht 0:563b70517320 602 int timer = 0;
sgodinez 8:3fe68d6130a8 603 char tmp[256];
sgodinez 8:3fe68d6130a8 604 tmp[255] = 0;
sgodinez 13:0af863114629 605 bool started = !echoMode;
sgodinez 13:0af863114629 606 bool done = false;
sgodinez 8:3fe68d6130a8 607 do {
jengbrecht 0:563b70517320 608 wait(.1);
jengbrecht 0:563b70517320 609 timer = timer + 100;
jengbrecht 0:563b70517320 610 previous = available;
sgodinez 19:38794784e009 611 available = io->rxAvailable();
sgodinez 8:3fe68d6130a8 612
sgodinez 19:38794784e009 613 int size = io->read(tmp,255); //1 less than allocated
sgodinez 8:3fe68d6130a8 614 if(size > 0) {
sgodinez 8:3fe68d6130a8 615 result.append(tmp, size);
sgodinez 8:3fe68d6130a8 616 }
sgodinez 13:0af863114629 617
sgodinez 13:0af863114629 618 if(!started) {
sgodinez 13:0af863114629 619 //In Echo Mode (Command will have echo'd + 2 characters for \r\n)
sgodinez 13:0af863114629 620 if(result.size() > command.size() + 2) {
sgodinez 13:0af863114629 621 started = true;
sgodinez 13:0af863114629 622 }
sgodinez 13:0af863114629 623 } else {
sgodinez 13:0af863114629 624 done = (available == previous);
sgodinez 13:0af863114629 625 }
sgodinez 13:0af863114629 626 if(timer >= timeoutMillis) {
sgodinez 17:2d7c4ea7491b 627 printf("[WARNING] sendCommand timed out after %d milliseconds\r\n", timeoutMillis);
sgodinez 13:0af863114629 628 done = true;
sgodinez 13:0af863114629 629 }
sgodinez 13:0af863114629 630 } while (!done);
sgodinez 8:3fe68d6130a8 631
sgodinez 8:3fe68d6130a8 632 return result;
jengbrecht 0:563b70517320 633 }
jengbrecht 0:563b70517320 634
jengbrecht 0:563b70517320 635 #endif /* CELLULAR_CPP */