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:
jengbrecht
Date:
Thu Jan 02 15:45:52 2014 +0000
Revision:
122:5f95f81a8b03
Parent:
110:8f3149c99112
Child:
123:a84f6b89132b
Added to Wifi and Cellular that isOpen will return true if data is in the receive buffer.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
jengbrecht 0:563b70517320 1 #include "Cellular.h"
sgodinez 4:6561c9128c6f 2 #include "MTSText.h"
sgodinez 19:38794784e009 3 #include "MTSSerial.h"
jengbrecht 0:563b70517320 4
mfiore 39:6e94520a3217 5 using namespace mts;
mfiore 39:6e94520a3217 6
sgodinez 19:38794784e009 7 Cellular* Cellular::instance = NULL;
sgodinez 19:38794784e009 8
jengbrecht 82:5aa75004e553 9 Cellular* Cellular::getInstance()
jengbrecht 82:5aa75004e553 10 {
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 96:27bdf4aa3a31 17 Cellular::Cellular(MTSBufferedIO* io)
sgodinez 96:27bdf4aa3a31 18 : io(io)
sgodinez 96:27bdf4aa3a31 19 , echoMode(true)
sgodinez 96:27bdf4aa3a31 20 , pppConnected(false)
sgodinez 96:27bdf4aa3a31 21 , mode(TCP)
sgodinez 96:27bdf4aa3a31 22 , socketOpened(false)
sgodinez 96:27bdf4aa3a31 23 , socketCloseable(true)
sgodinez 96:27bdf4aa3a31 24 , local_port(0)
sgodinez 96:27bdf4aa3a31 25 , host_port(0)
sgodinez 96:27bdf4aa3a31 26 , dcd(NULL)
sgodinez 96:27bdf4aa3a31 27 , dtr(NULL)
sgodinez 96:27bdf4aa3a31 28 {
sgodinez 96:27bdf4aa3a31 29 }
sgodinez 96:27bdf4aa3a31 30
sgodinez 96:27bdf4aa3a31 31 Cellular::~Cellular()
sgodinez 96:27bdf4aa3a31 32 {
sgodinez 96:27bdf4aa3a31 33 if (dtr != NULL) {
sgodinez 96:27bdf4aa3a31 34 dtr->write(1);
sgodinez 96:27bdf4aa3a31 35 }
jengbrecht 122:5f95f81a8b03 36
sgodinez 96:27bdf4aa3a31 37 delete dcd;
sgodinez 96:27bdf4aa3a31 38 delete dtr;
sgodinez 96:27bdf4aa3a31 39 }
sgodinez 19:38794784e009 40
jengbrecht 82:5aa75004e553 41 bool Cellular::init(MTSBufferedIO* io, PinName DCD, PinName DTR)
jengbrecht 82:5aa75004e553 42 {
jengbrecht 56:e5e5351f14b3 43 if (io == NULL) {
jengbrecht 56:e5e5351f14b3 44 return false;
sgodinez 19:38794784e009 45 }
jengbrecht 122:5f95f81a8b03 46
sgodinez 96:27bdf4aa3a31 47 if(dcd) {
sgodinez 96:27bdf4aa3a31 48 delete dcd;
jengbrecht 122:5f95f81a8b03 49 dcd = NULL;
sgodinez 96:27bdf4aa3a31 50 }
sgodinez 96:27bdf4aa3a31 51 if(dtr) {
sgodinez 96:27bdf4aa3a31 52 delete dtr;
sgodinez 96:27bdf4aa3a31 53 dtr = NULL;
sgodinez 96:27bdf4aa3a31 54 }
jengbrecht 122:5f95f81a8b03 55
jengbrecht 82:5aa75004e553 56 if (DCD != NC) {
jengbrecht 82:5aa75004e553 57 // the radio will raise and lower this line
jengbrecht 82:5aa75004e553 58 dcd = new DigitalIn(DCD); //PTA4 - KL46
jengbrecht 82:5aa75004e553 59 }
jengbrecht 82:5aa75004e553 60 if (DTR != NC) {
jengbrecht 82:5aa75004e553 61 dtr = new DigitalOut(DTR); //PTC9 - KL46
jengbrecht 82:5aa75004e553 62 /* This line should be lowered when we want to talk to the radio and raised when we're done
jengbrecht 82:5aa75004e553 63 for now we will lower it in the constructor and raise it in the destructor
jengbrecht 82:5aa75004e553 64 */
jengbrecht 82:5aa75004e553 65 dtr->write(0);
jengbrecht 82:5aa75004e553 66 }
jengbrecht 56:e5e5351f14b3 67 instance->io = io;
jengbrecht 122:5f95f81a8b03 68
sgodinez 96:27bdf4aa3a31 69 return (test() == SUCCESS);
sgodinez 19:38794784e009 70 }
sgodinez 19:38794784e009 71
jengbrecht 0:563b70517320 72
jengbrecht 82:5aa75004e553 73 bool Cellular::connect()
jengbrecht 82:5aa75004e553 74 {
sgodinez 13:0af863114629 75 //Check if socket is open
sgodinez 13:0af863114629 76 if(socketOpened) {
jengbrecht 82:5aa75004e553 77 return true;
sgodinez 13:0af863114629 78 }
jengbrecht 82:5aa75004e553 79
sgodinez 96:27bdf4aa3a31 80 //Check if already connected
sgodinez 13:0af863114629 81 if(isConnected()) {
sgodinez 13:0af863114629 82 return true;
sgodinez 13:0af863114629 83 }
jengbrecht 122:5f95f81a8b03 84
sgodinez 96:27bdf4aa3a31 85 Timer tmr;
jengbrecht 122:5f95f81a8b03 86
sgodinez 96:27bdf4aa3a31 87 //Check Registration: AT+CREG? == 0,1
sgodinez 96:27bdf4aa3a31 88 tmr.start();
sgodinez 96:27bdf4aa3a31 89 do {
sgodinez 96:27bdf4aa3a31 90 Registration registration = getRegistration();
sgodinez 96:27bdf4aa3a31 91 if(registration != REGISTERED) {
sgodinez 96:27bdf4aa3a31 92 printf("[WARNING] Not Registered [%d] ... waiting\r\n", (int)registration);
sgodinez 96:27bdf4aa3a31 93 wait(1);
sgodinez 96:27bdf4aa3a31 94 } else {
sgodinez 96:27bdf4aa3a31 95 break;
sgodinez 96:27bdf4aa3a31 96 }
sgodinez 96:27bdf4aa3a31 97 } while(tmr.read() < 30);
jengbrecht 82:5aa75004e553 98
jengbrecht 82:5aa75004e553 99 //Check RSSI: AT+CSQ
sgodinez 96:27bdf4aa3a31 100 tmr.reset();
sgodinez 96:27bdf4aa3a31 101 do {
sgodinez 96:27bdf4aa3a31 102 int rssi = getSignalStrength();
sgodinez 96:27bdf4aa3a31 103 printf("[DEBUG] Signal strength: %d\r\n", rssi);
sgodinez 96:27bdf4aa3a31 104 if(rssi == 99) {
jengbrecht 122:5f95f81a8b03 105 printf("[WARNING] No Signal ... waiting\r\n");
jengbrecht 122:5f95f81a8b03 106 wait(1);
sgodinez 96:27bdf4aa3a31 107 } else {
jengbrecht 122:5f95f81a8b03 108 break;
sgodinez 96:27bdf4aa3a31 109 }
jengbrecht 122:5f95f81a8b03 110 } while(tmr.read() < 30);
jengbrecht 82:5aa75004e553 111
sgodinez 11:134435d8a2d5 112 //AT#CONNECTIONSTART: Make a PPP connection
sgodinez 17:2d7c4ea7491b 113 printf("[DEBUG] Making PPP Connection Attempt. APN[%s]\r\n", apn.c_str());
sgodinez 13:0af863114629 114 std::string pppResult = sendCommand("AT#CONNECTIONSTART", 120000);
sgodinez 17:2d7c4ea7491b 115 std::vector<std::string> parts = Text::split(pppResult, "\r\n");
jengbrecht 82:5aa75004e553 116
sgodinez 13:0af863114629 117 if(pppResult.find("Ok_Info_GprsActivation") != std::string::npos) {
sgodinez 13:0af863114629 118 if(parts.size() >= 2) {
jengbrecht 82:5aa75004e553 119 local_address = parts[1];
sgodinez 13:0af863114629 120 }
sgodinez 17:2d7c4ea7491b 121 printf("[INFO] PPP Connection Established: IP[%s]\r\n", local_address.c_str());
sgodinez 13:0af863114629 122 pppConnected = true;
jengbrecht 82:5aa75004e553 123
sgodinez 13:0af863114629 124 } else {
jengbrecht 82:5aa75004e553 125 pppConnected = false;
sgodinez 13:0af863114629 126 }
jengbrecht 82:5aa75004e553 127
sgodinez 13:0af863114629 128 return pppConnected;
sgodinez 11:134435d8a2d5 129 }
sgodinez 11:134435d8a2d5 130
jengbrecht 82:5aa75004e553 131 void Cellular::disconnect()
jengbrecht 82:5aa75004e553 132 {
sgodinez 17:2d7c4ea7491b 133 //AT#CONNECTIONSTOP: Close a PPP connection
sgodinez 17:2d7c4ea7491b 134 printf("[DEBUG] Closing PPP Connection\r\n");
jengbrecht 82:5aa75004e553 135
jengbrecht 82:5aa75004e553 136 if(socketOpened) {
jengbrecht 82:5aa75004e553 137 close();
sgodinez 17:2d7c4ea7491b 138 }
jengbrecht 82:5aa75004e553 139
sgodinez 17:2d7c4ea7491b 140 Code code = sendBasicCommand("AT#CONNECTIONSTOP", 10000);
sgodinez 71:82205735732b 141 if(code == SUCCESS) {
sgodinez 17:2d7c4ea7491b 142 printf("[DEBUG] Successfully closed PPP Connection\r\n");
sgodinez 17:2d7c4ea7491b 143 } else {
jengbrecht 82:5aa75004e553 144 printf("[ERROR] Closing PPP Connection [%d]. Continuing ...\r\n", (int)code);
sgodinez 17:2d7c4ea7491b 145 }
jengbrecht 82:5aa75004e553 146
sgodinez 17:2d7c4ea7491b 147 pppConnected = false;
sgodinez 11:134435d8a2d5 148 }
sgodinez 11:134435d8a2d5 149
jengbrecht 82:5aa75004e553 150 bool Cellular::isConnected()
jengbrecht 82:5aa75004e553 151 {
sgodinez 11:134435d8a2d5 152 //1) Check if APN was set
sgodinez 11:134435d8a2d5 153 if(apn.size() == 0) {
sgodinez 17:2d7c4ea7491b 154 printf("[DEBUG] APN is not set\r\n");
sgodinez 11:134435d8a2d5 155 return false;
sgodinez 11:134435d8a2d5 156 }
jengbrecht 82:5aa75004e553 157
sgodinez 11:134435d8a2d5 158 //1) Check that we do not have a live connection up
sgodinez 11:134435d8a2d5 159 if(socketOpened) {
sgodinez 17:2d7c4ea7491b 160 printf("[DEBUG] Socket is opened\r\n");
sgodinez 11:134435d8a2d5 161 return true;
sgodinez 11:134435d8a2d5 162 }
sgodinez 11:134435d8a2d5 163 //2) Query the radio
sgodinez 110:8f3149c99112 164 std::string result = sendCommand("AT#VSTATE", 3000);
sgodinez 11:134435d8a2d5 165 if(result.find("CONNECTED") != std::string::npos) {
sgodinez 110:8f3149c99112 166 if(pppConnected == false) {
sgodinez 110:8f3149c99112 167 printf("[WARNING] Internal PPP state tracking differs from radio (DISCONNECTED:CONNECTED)\r\n");
sgodinez 110:8f3149c99112 168 }
sgodinez 11:134435d8a2d5 169 pppConnected = true;
sgodinez 110:8f3149c99112 170 } else {
sgodinez 110:8f3149c99112 171 if(pppConnected == true) {
sgodinez 110:8f3149c99112 172 //Find out what state is
sgodinez 110:8f3149c99112 173 size_t pos = result.find("STATE:");
sgodinez 110:8f3149c99112 174 if(pos != std::string::npos) {
sgodinez 110:8f3149c99112 175 result = Text::getLine(result, pos + sizeof("STATE:"), pos);
jengbrecht 122:5f95f81a8b03 176 printf("[WARNING] Internal PPP state tracking differs from radio (CONNECTED:%s)\r\n", result.c_str());
sgodinez 110:8f3149c99112 177 } else {
jengbrecht 122:5f95f81a8b03 178 printf("[ERROR] Unable to parse radio state: [%s]\r\n", result.c_str());
sgodinez 110:8f3149c99112 179 }
jengbrecht 122:5f95f81a8b03 180
sgodinez 110:8f3149c99112 181 }
sgodinez 110:8f3149c99112 182 pppConnected = false;
sgodinez 11:134435d8a2d5 183 }
jengbrecht 82:5aa75004e553 184
sgodinez 11:134435d8a2d5 185 return pppConnected;
sgodinez 11:134435d8a2d5 186 }
sgodinez 11:134435d8a2d5 187
jengbrecht 82:5aa75004e553 188 bool Cellular::bind(unsigned int port)
jengbrecht 82:5aa75004e553 189 {
sgodinez 53:27c9622de0f9 190 if(socketOpened) {
jengbrecht 82:5aa75004e553 191 printf("[ERROR] socket is open. Can not set local port\r\n");
sgodinez 53:27c9622de0f9 192 return false;
sgodinez 53:27c9622de0f9 193 }
sgodinez 53:27c9622de0f9 194 if(port > 65535) {
jengbrecht 82:5aa75004e553 195 printf("[ERROR] port out of range (0-65535)\r\n");
sgodinez 53:27c9622de0f9 196 return false;
sgodinez 53:27c9622de0f9 197 }
sgodinez 53:27c9622de0f9 198 local_port = port;
sgodinez 53:27c9622de0f9 199 return true;
sgodinez 11:134435d8a2d5 200 }
sgodinez 11:134435d8a2d5 201
jengbrecht 82:5aa75004e553 202 bool Cellular::open(const std::string& address, unsigned int port, Mode mode)
jengbrecht 82:5aa75004e553 203 {
sgodinez 17:2d7c4ea7491b 204 char buffer[256] = {0};
sgodinez 11:134435d8a2d5 205 Code portCode, addressCode;
jengbrecht 82:5aa75004e553 206
sgodinez 11:134435d8a2d5 207 //1) Check that we do not have a live connection up
sgodinez 11:134435d8a2d5 208 if(socketOpened) {
sgodinez 41:81d035fb0b6a 209 //Check that the address, port, and mode match
sgodinez 41:81d035fb0b6a 210 if(host_address != address || host_port != port || this->mode != mode) {
sgodinez 41:81d035fb0b6a 211 if(this->mode == TCP) {
sgodinez 96:27bdf4aa3a31 212 printf("[ERROR] TCP socket already opened [%s:%d]\r\n", host_address.c_str(), host_port);
sgodinez 41:81d035fb0b6a 213 } else {
sgodinez 96:27bdf4aa3a31 214 printf("[ERROR] UDP socket already opened [%s:%d]\r\n", host_address.c_str(), host_port);
sgodinez 41:81d035fb0b6a 215 }
sgodinez 41:81d035fb0b6a 216 return false;
sgodinez 41:81d035fb0b6a 217 }
jengbrecht 82:5aa75004e553 218
sgodinez 17:2d7c4ea7491b 219 printf("[DEBUG] Socket already opened\r\n");
sgodinez 11:134435d8a2d5 220 return true;
sgodinez 11:134435d8a2d5 221 }
jengbrecht 82:5aa75004e553 222
sgodinez 53:27c9622de0f9 223 //2) Check Parameters
sgodinez 53:27c9622de0f9 224 if(port > 65535) {
jengbrecht 82:5aa75004e553 225 printf("[ERROR] port out of range (0-65535)\r\n");
sgodinez 53:27c9622de0f9 226 return false;
sgodinez 53:27c9622de0f9 227 }
jengbrecht 82:5aa75004e553 228
sgodinez 53:27c9622de0f9 229 //3) Check PPP connection
sgodinez 11:134435d8a2d5 230 if(!isConnected()) {
sgodinez 17:2d7c4ea7491b 231 printf("[ERROR] PPP not established. Attempting to connect\r\n");
sgodinez 11:134435d8a2d5 232 if(!connect()) {
sgodinez 17:2d7c4ea7491b 233 printf("[ERROR] PPP connection failed\r\n");
sgodinez 11:134435d8a2d5 234 return false;
sgodinez 11:134435d8a2d5 235 } else {
sgodinez 17:2d7c4ea7491b 236 printf("[DEBUG] PPP connection established\r\n");
sgodinez 11:134435d8a2d5 237 }
sgodinez 11:134435d8a2d5 238 }
jengbrecht 122:5f95f81a8b03 239
sgodinez 55:56d9a9d98079 240 //Set Local Port
sgodinez 55:56d9a9d98079 241 if(local_port != 0) {
sgodinez 55:56d9a9d98079 242 //Attempt to set local port
sgodinez 55:56d9a9d98079 243 sprintf(buffer, "AT#OUTPORT=%d", local_port);
sgodinez 55:56d9a9d98079 244 Code code = sendBasicCommand(buffer, 1000);
sgodinez 71:82205735732b 245 if(code != SUCCESS) {
jengbrecht 82:5aa75004e553 246 printf("[WARNING] Unable to set local port (%d) [%d]\r\n", local_port, (int) code);
sgodinez 55:56d9a9d98079 247 }
sgodinez 55:56d9a9d98079 248 }
jengbrecht 82:5aa75004e553 249
sgodinez 55:56d9a9d98079 250 //Set TCP/UDP parameters
sgodinez 11:134435d8a2d5 251 if(mode == TCP) {
sgodinez 17:2d7c4ea7491b 252 if(socketCloseable) {
sgodinez 48:dad1e780cb1c 253 Code code = sendBasicCommand("AT#DLEMODE=1,1", 1000);
sgodinez 71:82205735732b 254 if(code != SUCCESS) {
jengbrecht 82:5aa75004e553 255 printf("[WARNING] Unable to set socket closeable [%d]\r\n", (int) code);
sgodinez 17:2d7c4ea7491b 256 }
sgodinez 17:2d7c4ea7491b 257 }
sgodinez 17:2d7c4ea7491b 258 sprintf(buffer, "AT#TCPPORT=1,%d", port);
sgodinez 17:2d7c4ea7491b 259 portCode = sendBasicCommand(buffer, 1000);
sgodinez 17:2d7c4ea7491b 260 addressCode = sendBasicCommand("AT#TCPSERV=1,\"" + address + "\"", 1000);
sgodinez 11:134435d8a2d5 261 } else {
sgodinez 17:2d7c4ea7491b 262 if(socketCloseable) {
sgodinez 17:2d7c4ea7491b 263 Code code = sendBasicCommand("AT#UDPDLEMODE=1", 1000);
sgodinez 71:82205735732b 264 if(code != SUCCESS) {
jengbrecht 82:5aa75004e553 265 printf("[WARNING] Unable to set socket closeable [%d]\r\n", (int) code);
sgodinez 17:2d7c4ea7491b 266 }
sgodinez 17:2d7c4ea7491b 267 }
sgodinez 55:56d9a9d98079 268 sprintf(buffer, "AT#UDPPORT=%d", port);
sgodinez 17:2d7c4ea7491b 269 portCode = sendBasicCommand(buffer, 1000);
sgodinez 55:56d9a9d98079 270 addressCode = sendBasicCommand("AT#UDPSERV=\"" + address + "\"", 1000);
sgodinez 11:134435d8a2d5 271 }
jengbrecht 82:5aa75004e553 272
sgodinez 71:82205735732b 273 if(portCode == SUCCESS) {
sgodinez 11:134435d8a2d5 274 host_port = port;
sgodinez 11:134435d8a2d5 275 } else {
sgodinez 17:2d7c4ea7491b 276 printf("[ERROR] Host port could not be set\r\n");
sgodinez 11:134435d8a2d5 277 }
jengbrecht 82:5aa75004e553 278
sgodinez 71:82205735732b 279 if(addressCode == SUCCESS) {
sgodinez 11:134435d8a2d5 280 host_address = address;
sgodinez 11:134435d8a2d5 281 } else {
sgodinez 17:2d7c4ea7491b 282 printf("[ERROR] Host address could not be set\r\n");
sgodinez 11:134435d8a2d5 283 }
jengbrecht 82:5aa75004e553 284
sgodinez 13:0af863114629 285 // Try and Connect
sgodinez 55:56d9a9d98079 286 std::string sMode;
sgodinez 55:56d9a9d98079 287 std::string sOpenSocketCmd;
sgodinez 55:56d9a9d98079 288 if(mode == TCP) {
sgodinez 55:56d9a9d98079 289 sOpenSocketCmd = "AT#OTCP=1";
sgodinez 55:56d9a9d98079 290 sMode = "TCP";
sgodinez 55:56d9a9d98079 291 } else {
sgodinez 55:56d9a9d98079 292 sOpenSocketCmd = "AT#OUDP";
sgodinez 55:56d9a9d98079 293 sMode = "UDP";
sgodinez 55:56d9a9d98079 294 }
jengbrecht 122:5f95f81a8b03 295
sgodinez 55:56d9a9d98079 296 string response = sendCommand(sOpenSocketCmd, 30000);
sgodinez 13:0af863114629 297 if (response.find("Ok_Info_WaitingForData") != string::npos) {
sgodinez 55:56d9a9d98079 298 printf("[INFO] Opened %s Socket [%s:%d]\r\n", sMode.c_str(), address.c_str(), port);
sgodinez 13:0af863114629 299 socketOpened = true;
sgodinez 13:0af863114629 300 } else {
sgodinez 55:56d9a9d98079 301 printf("[WARNING] Unable to open %s Socket [%s:%d]\r\n", sMode.c_str(), address.c_str(), port);
sgodinez 13:0af863114629 302 socketOpened = false;
sgodinez 13:0af863114629 303 }
jengbrecht 82:5aa75004e553 304
sgodinez 13:0af863114629 305 return socketOpened;
sgodinez 11:134435d8a2d5 306 }
sgodinez 11:134435d8a2d5 307
jengbrecht 82:5aa75004e553 308 bool Cellular::isOpen()
jengbrecht 82:5aa75004e553 309 {
jengbrecht 122:5f95f81a8b03 310 if(io->readable()) {
jengbrecht 122:5f95f81a8b03 311 printf("[DEBUG] Assuming open, data available to read.\n\r");
jengbrecht 122:5f95f81a8b03 312 return true;
jengbrecht 122:5f95f81a8b03 313 }
sgodinez 17:2d7c4ea7491b 314 return socketOpened;
sgodinez 11:134435d8a2d5 315 }
sgodinez 11:134435d8a2d5 316
jengbrecht 82:5aa75004e553 317 bool Cellular::close()
jengbrecht 82:5aa75004e553 318 {
sgodinez 35:f28acb1be52d 319 if(io == NULL) {
sgodinez 35:f28acb1be52d 320 printf("[ERROR] MTSBufferedIO not set\r\n");
sgodinez 17:2d7c4ea7491b 321 return false;
sgodinez 13:0af863114629 322 }
sgodinez 35:f28acb1be52d 323
sgodinez 35:f28acb1be52d 324 if(!socketOpened) {
sgodinez 35:f28acb1be52d 325 printf("[WARNING] Socket close() called, but socket was not open\r\n");
sgodinez 35:f28acb1be52d 326 return true;
sgodinez 35:f28acb1be52d 327 }
sgodinez 35:f28acb1be52d 328
sgodinez 17:2d7c4ea7491b 329 if(!socketCloseable) {
sgodinez 17:2d7c4ea7491b 330 printf("[ERROR] Socket is not closeable\r\n");
sgodinez 17:2d7c4ea7491b 331 return false;
sgodinez 17:2d7c4ea7491b 332 }
jengbrecht 82:5aa75004e553 333
jengbrecht 122:5f95f81a8b03 334
jengbrecht 122:5f95f81a8b03 335
sgodinez 110:8f3149c99112 336 if(io->write(ETX, 1000) != 1) {
sgodinez 35:f28acb1be52d 337 printf("[ERROR] Timed out attempting to close socket\r\n");
sgodinez 17:2d7c4ea7491b 338 return false;
sgodinez 13:0af863114629 339 }
jengbrecht 122:5f95f81a8b03 340
sgodinez 110:8f3149c99112 341 Timer tmr;
sgodinez 110:8f3149c99112 342 int counter = 0;
sgodinez 110:8f3149c99112 343 char tmp[256];
sgodinez 110:8f3149c99112 344 tmr.start();
sgodinez 110:8f3149c99112 345 do {
sgodinez 110:8f3149c99112 346 if(socketOpened == false) {
jengbrecht 122:5f95f81a8b03 347 break;
sgodinez 110:8f3149c99112 348 }
sgodinez 110:8f3149c99112 349 read(tmp, 256, 1000);
sgodinez 110:8f3149c99112 350 } while(counter++ < 10);
jengbrecht 122:5f95f81a8b03 351
sgodinez 110:8f3149c99112 352 io->rxClear();
sgodinez 110:8f3149c99112 353 io->txClear();
jengbrecht 122:5f95f81a8b03 354
sgodinez 17:2d7c4ea7491b 355 socketOpened = false;
sgodinez 17:2d7c4ea7491b 356 return true;
sgodinez 11:134435d8a2d5 357 }
sgodinez 11:134435d8a2d5 358
jengbrecht 82:5aa75004e553 359 int Cellular::read(char* data, int max, int timeout)
jengbrecht 82:5aa75004e553 360 {
sgodinez 19:38794784e009 361 if(io == NULL) {
sgodinez 19:38794784e009 362 printf("[ERROR] MTSBufferedIO not set\r\n");
sgodinez 19:38794784e009 363 return -1;
sgodinez 19:38794784e009 364 }
jengbrecht 82:5aa75004e553 365
jengbrecht 82:5aa75004e553 366 //Check that nothing is in the rx buffer
sgodinez 58:408f67fa292f 367 if(!socketOpened && !io->readable()) {
sgodinez 17:2d7c4ea7491b 368 printf("[ERROR] Socket is not open\r\n");
sgodinez 17:2d7c4ea7491b 369 return -1;
sgodinez 17:2d7c4ea7491b 370 }
sgodinez 84:77c5ab16534d 371
sgodinez 17:2d7c4ea7491b 372 int bytesRead = 0;
jengbrecht 82:5aa75004e553 373
sgodinez 17:2d7c4ea7491b 374 if(timeout >= 0) {
sgodinez 68:c490e4a51778 375 bytesRead = io->read(data, max, static_cast<unsigned int>(timeout));
sgodinez 17:2d7c4ea7491b 376 } else {
sgodinez 19:38794784e009 377 bytesRead = io->read(data, max);
sgodinez 17:2d7c4ea7491b 378 }
jengbrecht 82:5aa75004e553 379
sgodinez 32:629e6b1c8e22 380 if(bytesRead > 0 && socketCloseable) {
jengbrecht 82:5aa75004e553 381 //Remove escape characters
sgodinez 32:629e6b1c8e22 382 int index = 0;
sgodinez 32:629e6b1c8e22 383 bool escapeFlag = false;
sgodinez 32:629e6b1c8e22 384 for(int i = 0; i < bytesRead; i++) {
jengbrecht 82:5aa75004e553 385 if(data[i] == DLE || data[i] == ETX) {
jengbrecht 82:5aa75004e553 386 if(escapeFlag == true) {
sgodinez 32:629e6b1c8e22 387 //This character has been escaped
sgodinez 32:629e6b1c8e22 388 escapeFlag = false;
sgodinez 32:629e6b1c8e22 389 } else if(data[bytesRead] == DLE) {
sgodinez 32:629e6b1c8e22 390 //Found escape character
sgodinez 32:629e6b1c8e22 391 escapeFlag = true;
sgodinez 32:629e6b1c8e22 392 continue;
sgodinez 32:629e6b1c8e22 393 } else {
jengbrecht 82:5aa75004e553 394 //ETX sent without escape -> Socket closed
jengbrecht 82:5aa75004e553 395 printf("[INFO] Read ETX character without DLE escape. Socket closed\r\n");
sgodinez 32:629e6b1c8e22 396 socketOpened = false;
sgodinez 32:629e6b1c8e22 397 continue;
sgodinez 32:629e6b1c8e22 398 }
sgodinez 32:629e6b1c8e22 399 }
sgodinez 32:629e6b1c8e22 400
sgodinez 32:629e6b1c8e22 401 if(index != i) {
sgodinez 32:629e6b1c8e22 402 data[index] = data[i];
sgodinez 32:629e6b1c8e22 403 }
sgodinez 32:629e6b1c8e22 404 index++;
sgodinez 32:629e6b1c8e22 405 }
sgodinez 32:629e6b1c8e22 406 bytesRead = index;
sgodinez 32:629e6b1c8e22 407 }
jengbrecht 82:5aa75004e553 408
sgodinez 32:629e6b1c8e22 409 //Scan for socket closed message
sgodinez 32:629e6b1c8e22 410 for(size_t i = 0; i < bytesRead; i++) {
sgodinez 32:629e6b1c8e22 411 if(data[i] == 'O') {
sgodinez 32:629e6b1c8e22 412 if(strstr(&data[i], "Ok_Info_SocketClosed")) {
jengbrecht 82:5aa75004e553 413 printf("[INFO] Found socket closed message. Socket closed\r\n");
sgodinez 32:629e6b1c8e22 414 //Close socket and Cut Off End of Message
sgodinez 32:629e6b1c8e22 415 socketOpened = false;
sgodinez 32:629e6b1c8e22 416 data[i] = '\0';
sgodinez 32:629e6b1c8e22 417 bytesRead = i;
sgodinez 32:629e6b1c8e22 418 break;
sgodinez 32:629e6b1c8e22 419 }
sgodinez 32:629e6b1c8e22 420 }
sgodinez 32:629e6b1c8e22 421 }
sgodinez 17:2d7c4ea7491b 422 return bytesRead;
sgodinez 11:134435d8a2d5 423 }
sgodinez 11:134435d8a2d5 424
jengbrecht 82:5aa75004e553 425 int Cellular::write(const char* data, int length, int timeout)
jengbrecht 82:5aa75004e553 426 {
sgodinez 19:38794784e009 427 if(io == NULL) {
sgodinez 19:38794784e009 428 printf("[ERROR] MTSBufferedIO not set\r\n");
sgodinez 19:38794784e009 429 return -1;
sgodinez 19:38794784e009 430 }
jengbrecht 82:5aa75004e553 431
sgodinez 17:2d7c4ea7491b 432 if(!socketOpened) {
sgodinez 17:2d7c4ea7491b 433 printf("[ERROR] Socket is not open\r\n");
sgodinez 17:2d7c4ea7491b 434 return -1;
sgodinez 17:2d7c4ea7491b 435 }
jengbrecht 82:5aa75004e553 436
sgodinez 35:f28acb1be52d 437 //In order to avoid allocating another buffer, capture indices of
sgodinez 35:f28acb1be52d 438 //characters to escape during write
sgodinez 35:f28acb1be52d 439 int specialWritten = 0;
sgodinez 35:f28acb1be52d 440 std::vector<int> vSpecial;
sgodinez 35:f28acb1be52d 441 if(socketCloseable) {
sgodinez 35:f28acb1be52d 442 for(int i = 0; i < length; i++) {
sgodinez 35:f28acb1be52d 443 if(data[i] == ETX || data[i] == DLE) {
sgodinez 35:f28acb1be52d 444 //Push back index of special characters
sgodinez 35:f28acb1be52d 445 vSpecial.push_back(i);
jengbrecht 82:5aa75004e553 446 }
sgodinez 35:f28acb1be52d 447 }
sgodinez 35:f28acb1be52d 448 }
jengbrecht 82:5aa75004e553 449
sgodinez 17:2d7c4ea7491b 450 int bytesWritten = 0;
sgodinez 17:2d7c4ea7491b 451 if(timeout >= 0) {
sgodinez 17:2d7c4ea7491b 452 Timer tmr;
sgodinez 17:2d7c4ea7491b 453 tmr.start();
sgodinez 35:f28acb1be52d 454 do {
sgodinez 67:1003b410f781 455 int available = io->writeable();
sgodinez 67:1003b410f781 456 if (available > 0) {
sgodinez 35:f28acb1be52d 457 if(specialWritten < vSpecial.size()) {
sgodinez 35:f28acb1be52d 458 //Check if current index is at a special character
sgodinez 35:f28acb1be52d 459 if(bytesWritten == vSpecial[specialWritten]) {
sgodinez 67:1003b410f781 460 if(available < 2) {
sgodinez 35:f28acb1be52d 461 //Requires at least two bytes of space
sgodinez 35:f28acb1be52d 462 wait(0.05);
jengbrecht 82:5aa75004e553 463 continue;
sgodinez 35:f28acb1be52d 464 }
jengbrecht 82:5aa75004e553 465 //Ready to write special character
sgodinez 35:f28acb1be52d 466 if(io->write(DLE)) {
sgodinez 35:f28acb1be52d 467 specialWritten++;
sgodinez 35:f28acb1be52d 468 if(io->write(data[bytesWritten])) {
sgodinez 35:f28acb1be52d 469 bytesWritten++;
sgodinez 35:f28acb1be52d 470 }
sgodinez 35:f28acb1be52d 471 } else {
sgodinez 35:f28acb1be52d 472 //Unable to write escape character, try again next round
sgodinez 35:f28acb1be52d 473 wait(0.05);
sgodinez 35:f28acb1be52d 474 }
sgodinez 35:f28acb1be52d 475 } else {
jengbrecht 82:5aa75004e553 476 //We want to write all the way up to the next special character
sgodinez 35:f28acb1be52d 477 int relativeIndex = vSpecial[specialWritten] - bytesWritten;
sgodinez 67:1003b410f781 478 int size = MIN(available, relativeIndex);
sgodinez 35:f28acb1be52d 479 bytesWritten += io->write(&data[bytesWritten], size);
jengbrecht 82:5aa75004e553 480 }
jengbrecht 82:5aa75004e553 481 } else {
sgodinez 67:1003b410f781 482 int size = MIN(available, length - bytesWritten);
sgodinez 35:f28acb1be52d 483 bytesWritten += io->write(&data[bytesWritten], size);
sgodinez 17:2d7c4ea7491b 484 }
sgodinez 17:2d7c4ea7491b 485 } else {
jengbrecht 82:5aa75004e553 486 wait(0.05);
sgodinez 35:f28acb1be52d 487 }
sgodinez 35:f28acb1be52d 488 } while (tmr.read_ms() <= timeout && bytesWritten < length);
sgodinez 35:f28acb1be52d 489 } else {
sgodinez 35:f28acb1be52d 490 for(int i = 0; i < vSpecial.size(); i++) {
sgodinez 35:f28acb1be52d 491 //Write up to the special character, then write the special character
sgodinez 35:f28acb1be52d 492 int size = vSpecial[i] - bytesWritten;
sgodinez 35:f28acb1be52d 493 int currentWritten = io->write(&data[bytesWritten], size);
sgodinez 35:f28acb1be52d 494 bytesWritten += currentWritten;
sgodinez 35:f28acb1be52d 495 if(currentWritten != size) {
sgodinez 35:f28acb1be52d 496 //Failed to write up to the special character.
sgodinez 35:f28acb1be52d 497 return bytesWritten;
sgodinez 35:f28acb1be52d 498 }
sgodinez 35:f28acb1be52d 499 if(io->write(DLE) && io->write(data[bytesWritten])) {
sgodinez 35:f28acb1be52d 500 bytesWritten++;
sgodinez 35:f28acb1be52d 501 } else {
sgodinez 35:f28acb1be52d 502 //Failed to write the special character.
sgodinez 35:f28acb1be52d 503 return bytesWritten;
sgodinez 17:2d7c4ea7491b 504 }
sgodinez 17:2d7c4ea7491b 505 }
jengbrecht 82:5aa75004e553 506
sgodinez 35:f28acb1be52d 507 bytesWritten = io->write(&data[bytesWritten], length - bytesWritten);
sgodinez 17:2d7c4ea7491b 508 }
jengbrecht 82:5aa75004e553 509
sgodinez 17:2d7c4ea7491b 510 return bytesWritten;
sgodinez 11:134435d8a2d5 511 }
sgodinez 11:134435d8a2d5 512
jengbrecht 82:5aa75004e553 513 unsigned int Cellular::readable()
jengbrecht 82:5aa75004e553 514 {
sgodinez 19:38794784e009 515 if(io == NULL) {
sgodinez 96:27bdf4aa3a31 516 printf("[WARNING] MTSBufferedIO not set\r\n");
sgodinez 19:38794784e009 517 return 0;
sgodinez 19:38794784e009 518 }
sgodinez 96:27bdf4aa3a31 519 if(!socketOpened && !io->readable()) {
sgodinez 96:27bdf4aa3a31 520 printf("[WARNING] Socket is not open\r\n");
sgodinez 17:2d7c4ea7491b 521 return 0;
sgodinez 17:2d7c4ea7491b 522 }
sgodinez 19:38794784e009 523 return io->readable();
sgodinez 11:134435d8a2d5 524 }
sgodinez 11:134435d8a2d5 525
jengbrecht 82:5aa75004e553 526 unsigned int Cellular::writeable()
jengbrecht 82:5aa75004e553 527 {
sgodinez 19:38794784e009 528 if(io == NULL) {
sgodinez 96:27bdf4aa3a31 529 printf("[WARNING] MTSBufferedIO not set\r\n");
sgodinez 19:38794784e009 530 return 0;
sgodinez 19:38794784e009 531 }
sgodinez 17:2d7c4ea7491b 532 if(!socketOpened) {
sgodinez 96:27bdf4aa3a31 533 printf("[WARNING] Socket is not open\r\n");
sgodinez 17:2d7c4ea7491b 534 return 0;
sgodinez 17:2d7c4ea7491b 535 }
jengbrecht 82:5aa75004e553 536
sgodinez 19:38794784e009 537 return io->writeable();
sgodinez 11:134435d8a2d5 538 }
sgodinez 11:134435d8a2d5 539
jengbrecht 82:5aa75004e553 540 void Cellular::reset()
jengbrecht 82:5aa75004e553 541 {
mfiore 29:7408b1bdad37 542 disconnect();
mfiore 29:7408b1bdad37 543 Code code = sendBasicCommand("AT#RESET=0", 10000);
sgodinez 71:82205735732b 544 if(code != SUCCESS) {
mfiore 29:7408b1bdad37 545 printf("[ERROR] Socket Modem did not accept RESET command\n\r");
mfiore 29:7408b1bdad37 546 } else {
mfiore 29:7408b1bdad37 547 printf("[WARNING] Socket Modem is resetting, allow 30 seconds for it to come back\n\r");
mfiore 29:7408b1bdad37 548 }
sgodinez 11:134435d8a2d5 549 }
sgodinez 11:134435d8a2d5 550
sgodinez 71:82205735732b 551 Code Cellular::test()
jengbrecht 0:563b70517320 552 {
sgodinez 96:27bdf4aa3a31 553 bool basicRadioComms = false;
sgodinez 96:27bdf4aa3a31 554 Code code;
sgodinez 96:27bdf4aa3a31 555 Timer tmr;
sgodinez 96:27bdf4aa3a31 556 tmr.start();
sgodinez 96:27bdf4aa3a31 557 do {
sgodinez 96:27bdf4aa3a31 558 printf("[DEBUG] Attempting basic radio communication\r\n");
sgodinez 96:27bdf4aa3a31 559 code = sendBasicCommand("AT", 1000);
sgodinez 96:27bdf4aa3a31 560 if(code == SUCCESS) {
sgodinez 96:27bdf4aa3a31 561 basicRadioComms = true;
jengbrecht 122:5f95f81a8b03 562 break;
sgodinez 96:27bdf4aa3a31 563 } else {
jengbrecht 122:5f95f81a8b03 564 wait(1);
sgodinez 96:27bdf4aa3a31 565 }
sgodinez 96:27bdf4aa3a31 566 } while(tmr.read() < 15);
jengbrecht 82:5aa75004e553 567
sgodinez 96:27bdf4aa3a31 568 if(!basicRadioComms) {
sgodinez 96:27bdf4aa3a31 569 printf("[ERROR] Unable to communicate with the radio\r\n");
sgodinez 96:27bdf4aa3a31 570 return FAILURE;
sgodinez 11:134435d8a2d5 571 }
jengbrecht 122:5f95f81a8b03 572
sgodinez 71:82205735732b 573 return SUCCESS;
jengbrecht 0:563b70517320 574 }
jengbrecht 0:563b70517320 575
sgodinez 71:82205735732b 576 Code Cellular::echo(bool state)
jengbrecht 0:563b70517320 577 {
sgodinez 13:0af863114629 578 Code code;
jengbrecht 0:563b70517320 579 if (state) {
sgodinez 13:0af863114629 580 code = sendBasicCommand("ATE0", 1000);
sgodinez 71:82205735732b 581 echoMode = (code == SUCCESS) ? false : echoMode;
jengbrecht 0:563b70517320 582 } else {
sgodinez 13:0af863114629 583 code = sendBasicCommand("ATE1", 1000);
sgodinez 71:82205735732b 584 echoMode = (code == SUCCESS) ? true : echoMode;
jengbrecht 0:563b70517320 585 }
sgodinez 13:0af863114629 586 return code;
jengbrecht 0:563b70517320 587 }
jengbrecht 0:563b70517320 588
jengbrecht 0:563b70517320 589 int Cellular::getSignalStrength()
jengbrecht 0:563b70517320 590 {
jengbrecht 0:563b70517320 591 string response = sendCommand("AT+CSQ", 1000);
jengbrecht 0:563b70517320 592 if (response.find("OK") == string::npos) {
jengbrecht 0:563b70517320 593 return -1;
jengbrecht 0:563b70517320 594 }
jengbrecht 0:563b70517320 595 int start = response.find(':');
jengbrecht 0:563b70517320 596 int stop = response.find(',', start);
jengbrecht 0:563b70517320 597 string signal = response.substr(start + 2, stop - start - 2);
jengbrecht 0:563b70517320 598 int value;
jengbrecht 0:563b70517320 599 sscanf(signal.c_str(), "%d", &value);
jengbrecht 0:563b70517320 600 return value;
jengbrecht 0:563b70517320 601 }
jengbrecht 0:563b70517320 602
jengbrecht 0:563b70517320 603 Cellular::Registration Cellular::getRegistration()
jengbrecht 0:563b70517320 604 {
sgodinez 96:27bdf4aa3a31 605 string response = sendCommand("AT+CREG?", 5000);
jengbrecht 0:563b70517320 606 if (response.find("OK") == string::npos) {
jengbrecht 0:563b70517320 607 return UNKNOWN;
jengbrecht 0:563b70517320 608 }
jengbrecht 0:563b70517320 609 int start = response.find(',');
jengbrecht 0:563b70517320 610 int stop = response.find(' ', start);
jengbrecht 0:563b70517320 611 string regStat = response.substr(start + 1, stop - start - 1);
jengbrecht 0:563b70517320 612 int value;
jengbrecht 0:563b70517320 613 sscanf(regStat.c_str(), "%d", &value);
jengbrecht 0:563b70517320 614 switch (value) {
jengbrecht 0:563b70517320 615 case 0:
jengbrecht 0:563b70517320 616 return NOT_REGISTERED;
jengbrecht 0:563b70517320 617 case 1:
jengbrecht 0:563b70517320 618 return REGISTERED;
jengbrecht 0:563b70517320 619 case 2:
jengbrecht 0:563b70517320 620 return SEARCHING;
jengbrecht 0:563b70517320 621 case 3:
jengbrecht 0:563b70517320 622 return DENIED;
jengbrecht 0:563b70517320 623 case 4:
jengbrecht 0:563b70517320 624 return UNKNOWN;
jengbrecht 0:563b70517320 625 case 5:
jengbrecht 0:563b70517320 626 return ROAMING;
jengbrecht 0:563b70517320 627 }
sgodinez 4:6561c9128c6f 628 return UNKNOWN;
jengbrecht 0:563b70517320 629 }
jengbrecht 0:563b70517320 630
jengbrecht 82:5aa75004e553 631 Code Cellular::setApn(const std::string& apn)
jengbrecht 82:5aa75004e553 632 {
sgodinez 11:134435d8a2d5 633 Code code = sendBasicCommand("AT#APNSERV=\"" + apn + "\"", 1000);
sgodinez 71:82205735732b 634 if (code != SUCCESS) {
sgodinez 11:134435d8a2d5 635 return code;
sgodinez 11:134435d8a2d5 636 }
sgodinez 11:134435d8a2d5 637 this->apn = apn;
sgodinez 11:134435d8a2d5 638 return code;
sgodinez 11:134435d8a2d5 639 }
sgodinez 11:134435d8a2d5 640
sgodinez 43:3cacf019ed7d 641
jengbrecht 82:5aa75004e553 642 Code Cellular::setDns(const std::string& primary, const std::string& secondary)
jengbrecht 82:5aa75004e553 643 {
sgodinez 41:81d035fb0b6a 644 return sendBasicCommand("AT#DNS=1," + primary + "," + secondary, 1000);
sgodinez 11:134435d8a2d5 645 }
sgodinez 11:134435d8a2d5 646
jengbrecht 82:5aa75004e553 647 bool Cellular::ping(const std::string& address)
jengbrecht 82:5aa75004e553 648 {
jengbrecht 23:bc6f98a1eb22 649 char buffer[256] = {0};
jengbrecht 23:bc6f98a1eb22 650 Code code;
jengbrecht 82:5aa75004e553 651
jengbrecht 23:bc6f98a1eb22 652 code = sendBasicCommand("AT#PINGREMOTE=\"" + address + "\"", 1000);
sgodinez 71:82205735732b 653 if (code != SUCCESS) {
jengbrecht 23:bc6f98a1eb22 654 return false;
jengbrecht 23:bc6f98a1eb22 655 }
jengbrecht 82:5aa75004e553 656
jengbrecht 23:bc6f98a1eb22 657 sprintf(buffer, "AT#PINGNUM=%d", 1);
jengbrecht 23:bc6f98a1eb22 658 code = sendBasicCommand(buffer , 1000);
sgodinez 71:82205735732b 659 if (code != SUCCESS) {
jengbrecht 23:bc6f98a1eb22 660 return false;
jengbrecht 23:bc6f98a1eb22 661 }
jengbrecht 82:5aa75004e553 662
jengbrecht 23:bc6f98a1eb22 663 sprintf(buffer, "AT#PINGDELAY=%d", PINGDELAY);
jengbrecht 23:bc6f98a1eb22 664 code = sendBasicCommand(buffer , 1000);
sgodinez 71:82205735732b 665 if (code != SUCCESS) {
jengbrecht 23:bc6f98a1eb22 666 return false;
jengbrecht 23:bc6f98a1eb22 667 }
jengbrecht 82:5aa75004e553 668
jengbrecht 23:bc6f98a1eb22 669 std::string response;
jengbrecht 23:bc6f98a1eb22 670 for (int i = 0; i < PINGNUM; i++) {
jengbrecht 23:bc6f98a1eb22 671 response = sendCommand("AT#PING", PINGDELAY * 1000);
jengbrecht 23:bc6f98a1eb22 672 if (response.find("alive") != std::string::npos) {
jengbrecht 23:bc6f98a1eb22 673 return true;
jengbrecht 23:bc6f98a1eb22 674 }
jengbrecht 23:bc6f98a1eb22 675 }
jengbrecht 23:bc6f98a1eb22 676 return false;
jengbrecht 23:bc6f98a1eb22 677 }
jengbrecht 23:bc6f98a1eb22 678
jengbrecht 82:5aa75004e553 679 Code Cellular::setSocketCloseable(bool enabled)
jengbrecht 82:5aa75004e553 680 {
sgodinez 17:2d7c4ea7491b 681 if(socketCloseable == enabled) {
jengbrecht 82:5aa75004e553 682 return SUCCESS;
sgodinez 17:2d7c4ea7491b 683 }
jengbrecht 82:5aa75004e553 684
sgodinez 17:2d7c4ea7491b 685 if(socketOpened) {
jengbrecht 82:5aa75004e553 686 printf("[ERROR] socket is already opened. Can not set closeable\r\n");
sgodinez 71:82205735732b 687 return ERROR;
sgodinez 17:2d7c4ea7491b 688 }
jengbrecht 82:5aa75004e553 689
sgodinez 17:2d7c4ea7491b 690 socketCloseable = enabled;
jengbrecht 82:5aa75004e553 691
sgodinez 71:82205735732b 692 return SUCCESS;
sgodinez 17:2d7c4ea7491b 693 }
sgodinez 17:2d7c4ea7491b 694
jengbrecht 82:5aa75004e553 695 Code Cellular::sendSMS(const Sms& sms)
jengbrecht 82:5aa75004e553 696 {
sgodinez 4:6561c9128c6f 697 return sendSMS(sms.phoneNumber, sms.message);
sgodinez 4:6561c9128c6f 698 }
sgodinez 4:6561c9128c6f 699
sgodinez 71:82205735732b 700 Code Cellular::sendSMS(const std::string& phoneNumber, const std::string& message)
jengbrecht 82:5aa75004e553 701 {
jengbrecht 0:563b70517320 702 Code code = sendBasicCommand("AT+CMGF=1", 1000);
sgodinez 71:82205735732b 703 if (code != SUCCESS) {
jengbrecht 0:563b70517320 704 return code;
jengbrecht 0:563b70517320 705 }
jengbrecht 0:563b70517320 706 string cmd = "AT+CMGS=\"+";
jengbrecht 0:563b70517320 707 cmd.append(phoneNumber);
jengbrecht 0:563b70517320 708 cmd.append("\"");
jengbrecht 0:563b70517320 709 string response1 = sendCommand(cmd, 1000);
jengbrecht 0:563b70517320 710 if (response1.find('>') == string::npos) {
sgodinez 71:82205735732b 711 return NO_RESPONSE;
jengbrecht 0:563b70517320 712 }
jengbrecht 0:563b70517320 713 wait(.2);
jengbrecht 0:563b70517320 714 string response2 = sendCommand(message, 4000, CTRL_Z);
sgodinez 17:2d7c4ea7491b 715 printf("SMS Response: %s\r\n", response2.c_str());
jengbrecht 0:563b70517320 716 if (response2.find("+CMGS:") == string::npos) {
sgodinez 71:82205735732b 717 return FAILURE;
jengbrecht 0:563b70517320 718 }
sgodinez 71:82205735732b 719 return SUCCESS;
jengbrecht 0:563b70517320 720 }
jengbrecht 0:563b70517320 721
jengbrecht 82:5aa75004e553 722 std::vector<Cellular::Sms> Cellular::getReceivedSms()
jengbrecht 82:5aa75004e553 723 {
sgodinez 9:5b12c5a8dde4 724 int smsNumber = 0;
sgodinez 4:6561c9128c6f 725 std::vector<Sms> vSms;
sgodinez 4:6561c9128c6f 726 std::string received = sendCommand("AT+CMGL=\"ALL\"", 4000);
sgodinez 5:93e889a5abc6 727 size_t pos = received.find("+CMGL: ");
jengbrecht 82:5aa75004e553 728
sgodinez 5:93e889a5abc6 729 while (pos != std::string::npos) {
sgodinez 4:6561c9128c6f 730 Cellular::Sms sms;
sgodinez 4:6561c9128c6f 731 std::string line(Text::getLine(received, pos, pos));
sgodinez 17:2d7c4ea7491b 732 //printf("[DEBUG] Top of SMS Parse Loop. LINE[%s]\r\n", line.c_str());
jengbrecht 82:5aa75004e553 733 if(line.find("+CMGL: ") == std::string::npos) {
sgodinez 4:6561c9128c6f 734 continue;
sgodinez 4:6561c9128c6f 735 }
jengbrecht 82:5aa75004e553 736
sgodinez 4:6561c9128c6f 737 //Start of SMS message
sgodinez 4:6561c9128c6f 738 std::vector<std::string> vSmsParts = Text::split(line, ',');
sgodinez 4:6561c9128c6f 739 if(vSmsParts.size() != 6) {
sgodinez 17:2d7c4ea7491b 740 printf("[WARNING] Expected 6 commas. SMS[%d] DATA[%s]. Continuing ...\r\n", smsNumber, line.c_str());
sgodinez 4:6561c9128c6f 741 continue;
sgodinez 4:6561c9128c6f 742 }
jengbrecht 82:5aa75004e553 743
sgodinez 4:6561c9128c6f 744 sms.phoneNumber = vSmsParts[2];
sgodinez 4:6561c9128c6f 745 sms.timestamp = vSmsParts[4] + ", " + vSmsParts[5];
jengbrecht 82:5aa75004e553 746
sgodinez 8:3fe68d6130a8 747 if(pos == std::string::npos) {
sgodinez 17:2d7c4ea7491b 748 printf("[WARNING] Expected SMS body. SMS[%d]. Leaving ...\r\n", smsNumber);
sgodinez 8:3fe68d6130a8 749 break;
sgodinez 8:3fe68d6130a8 750 }
sgodinez 9:5b12c5a8dde4 751 //Check for the start of the next SMS message
sgodinez 9:5b12c5a8dde4 752 size_t bodyEnd = received.find("\r\n+CMGL: ", pos);
sgodinez 8:3fe68d6130a8 753 if(bodyEnd == std::string::npos) {
sgodinez 17:2d7c4ea7491b 754 //printf("[DEBUG] Parsing Last SMS. SMS[%d]\r\n", smsNumber);
sgodinez 9:5b12c5a8dde4 755 //This must be the last SMS message
sgodinez 9:5b12c5a8dde4 756 bodyEnd = received.find("\r\n\r\nOK", pos);
sgodinez 8:3fe68d6130a8 757 }
jengbrecht 82:5aa75004e553 758
sgodinez 9:5b12c5a8dde4 759 //Safety check that we found the boundary of this current SMS message
sgodinez 9:5b12c5a8dde4 760 if(bodyEnd != std::string::npos) {
sgodinez 9:5b12c5a8dde4 761 sms.message = received.substr(pos, bodyEnd - pos);
sgodinez 9:5b12c5a8dde4 762 } else {
sgodinez 8:3fe68d6130a8 763 sms.message = received.substr(pos);
sgodinez 17:2d7c4ea7491b 764 printf("[WARNING] Expected to find end of SMS list. SMS[%d] DATA[%s].\r\n", smsNumber, sms.message.c_str());
sgodinez 8:3fe68d6130a8 765 }
sgodinez 5:93e889a5abc6 766 vSms.push_back(sms);
sgodinez 4:6561c9128c6f 767 pos = bodyEnd;
sgodinez 17:2d7c4ea7491b 768 //printf("[DEBUG] Parsed SMS[%d]. Starting Next at position [%d]\r\n", smsNumber, pos);
sgodinez 9:5b12c5a8dde4 769 smsNumber++;
sgodinez 4:6561c9128c6f 770 }
sgodinez 17:2d7c4ea7491b 771 printf("Received %d SMS\r\n", smsNumber);
sgodinez 4:6561c9128c6f 772 return vSms;
sgodinez 4:6561c9128c6f 773 }
sgodinez 4:6561c9128c6f 774
jengbrecht 82:5aa75004e553 775 Code Cellular::deleteOnlyReceivedReadSms()
jengbrecht 82:5aa75004e553 776 {
sgodinez 4:6561c9128c6f 777 return sendBasicCommand("AT+CMGD=1,1", 1000);
sgodinez 4:6561c9128c6f 778 }
sgodinez 4:6561c9128c6f 779
jengbrecht 82:5aa75004e553 780 Code Cellular::deleteAllReceivedSms()
jengbrecht 82:5aa75004e553 781 {
sgodinez 4:6561c9128c6f 782 return sendBasicCommand("AT+CMGD=1,4", 1000);
sgodinez 4:6561c9128c6f 783 }
sgodinez 4:6561c9128c6f 784
sgodinez 96:27bdf4aa3a31 785 Code Cellular::sendBasicCommand(const std::string& command, unsigned int timeoutMillis, char esc)
sgodinez 96:27bdf4aa3a31 786 {
sgodinez 96:27bdf4aa3a31 787 if(socketOpened) {
sgodinez 96:27bdf4aa3a31 788 printf("[ERROR] socket is open. Can not send AT commands\r\n");
sgodinez 96:27bdf4aa3a31 789 return ERROR;
sgodinez 96:27bdf4aa3a31 790 }
sgodinez 96:27bdf4aa3a31 791
sgodinez 96:27bdf4aa3a31 792 string response = sendCommand(command, timeoutMillis, esc);
sgodinez 96:27bdf4aa3a31 793 if (response.size() == 0) {
sgodinez 96:27bdf4aa3a31 794 return NO_RESPONSE;
sgodinez 96:27bdf4aa3a31 795 } else if (response.find("OK") != string::npos) {
sgodinez 96:27bdf4aa3a31 796 return SUCCESS;
sgodinez 96:27bdf4aa3a31 797 } else if (response.find("ERROR") != string::npos) {
sgodinez 96:27bdf4aa3a31 798 return ERROR;
sgodinez 96:27bdf4aa3a31 799 } else {
sgodinez 96:27bdf4aa3a31 800 return FAILURE;
sgodinez 96:27bdf4aa3a31 801 }
sgodinez 96:27bdf4aa3a31 802 }
sgodinez 4:6561c9128c6f 803
sgodinez 71:82205735732b 804 string Cellular::sendCommand(const std::string& command, unsigned int timeoutMillis, char esc)
jengbrecht 0:563b70517320 805 {
sgodinez 19:38794784e009 806 if(io == NULL) {
sgodinez 19:38794784e009 807 printf("[ERROR] MTSBufferedIO not set\r\n");
sgodinez 19:38794784e009 808 return "";
sgodinez 19:38794784e009 809 }
sgodinez 17:2d7c4ea7491b 810 if(socketOpened) {
jengbrecht 82:5aa75004e553 811 printf("[ERROR] socket is open. Can not send AT commands\r\n");
sgodinez 17:2d7c4ea7491b 812 return "";
sgodinez 17:2d7c4ea7491b 813 }
sgodinez 17:2d7c4ea7491b 814
sgodinez 19:38794784e009 815 io->rxClear();
sgodinez 19:38794784e009 816 io->txClear();
sgodinez 8:3fe68d6130a8 817 std::string result;
jengbrecht 82:5aa75004e553 818
sgodinez 68:c490e4a51778 819 //Attempt to write command
sgodinez 68:c490e4a51778 820 if(io->write(command.data(), command.size(), timeoutMillis) != command.size()) {
sgodinez 68:c490e4a51778 821 //Failed to write command
sgodinez 68:c490e4a51778 822 printf("[ERROR] failed to send command to radio within %d milliseconds\r\n", timeoutMillis);
sgodinez 68:c490e4a51778 823 return "";
sgodinez 68:c490e4a51778 824 }
jengbrecht 82:5aa75004e553 825
sgodinez 68:c490e4a51778 826 //Send Escape Character
sgodinez 71:82205735732b 827 if (esc != 0x00) {
sgodinez 71:82205735732b 828 if(io->write(esc, timeoutMillis) != 1) {
sgodinez 101:27bb34e23304 829 printf("[ERROR] failed to send character '%c' (0x%02X) to radio within %d milliseconds\r\n", esc, esc, timeoutMillis);
sgodinez 68:c490e4a51778 830 return "";
sgodinez 68:c490e4a51778 831 }
sgodinez 68:c490e4a51778 832 }
sgodinez 68:c490e4a51778 833
jengbrecht 0:563b70517320 834 int timer = 0;
sgodinez 68:c490e4a51778 835 size_t previous = 0;
sgodinez 8:3fe68d6130a8 836 char tmp[256];
sgodinez 8:3fe68d6130a8 837 tmp[255] = 0;
sgodinez 13:0af863114629 838 bool started = !echoMode;
sgodinez 13:0af863114629 839 bool done = false;
sgodinez 8:3fe68d6130a8 840 do {
sgodinez 91:9439ad14d7f0 841 wait(0.1);
sgodinez 91:9439ad14d7f0 842 timer += 100;
jengbrecht 122:5f95f81a8b03 843
sgodinez 68:c490e4a51778 844 previous = result.size();
sgodinez 91:9439ad14d7f0 845 //Make a non-blocking read call by passing timeout of zero
sgodinez 91:9439ad14d7f0 846 int size = io->read(tmp,255,0); //1 less than allocated (timeout is instant)
sgodinez 8:3fe68d6130a8 847 if(size > 0) {
sgodinez 8:3fe68d6130a8 848 result.append(tmp, size);
sgodinez 8:3fe68d6130a8 849 }
sgodinez 13:0af863114629 850 if(!started) {
sgodinez 13:0af863114629 851 //In Echo Mode (Command will have echo'd + 2 characters for \r\n)
sgodinez 13:0af863114629 852 if(result.size() > command.size() + 2) {
sgodinez 13:0af863114629 853 started = true;
sgodinez 13:0af863114629 854 }
sgodinez 13:0af863114629 855 } else {
sgodinez 68:c490e4a51778 856 done = (result.size() == previous);
sgodinez 13:0af863114629 857 }
sgodinez 13:0af863114629 858 if(timer >= timeoutMillis) {
sgodinez 110:8f3149c99112 859 printf("[WARNING] sendCommand [%s] timed out after %d milliseconds\r\n", command.c_str(), timeoutMillis);
sgodinez 13:0af863114629 860 done = true;
sgodinez 13:0af863114629 861 }
sgodinez 13:0af863114629 862 } while (!done);
jengbrecht 82:5aa75004e553 863
sgodinez 8:3fe68d6130a8 864 return result;
jengbrecht 0:563b70517320 865 }
jengbrecht 0:563b70517320 866
jengbrecht 56:e5e5351f14b3 867 std::string Cellular::getRegistrationNames(Registration registration)
jengbrecht 56:e5e5351f14b3 868 {
jengbrecht 56:e5e5351f14b3 869 switch(registration) {
jengbrecht 56:e5e5351f14b3 870 case NOT_REGISTERED:
jengbrecht 56:e5e5351f14b3 871 return "NOT_REGISTERED";
jengbrecht 56:e5e5351f14b3 872 case REGISTERED:
jengbrecht 56:e5e5351f14b3 873 return "REGISTERED";
jengbrecht 56:e5e5351f14b3 874 case SEARCHING:
jengbrecht 56:e5e5351f14b3 875 return "SEARCHING";
jengbrecht 56:e5e5351f14b3 876 case DENIED:
jengbrecht 56:e5e5351f14b3 877 return "DENIED";
jengbrecht 56:e5e5351f14b3 878 case UNKNOWN:
jengbrecht 56:e5e5351f14b3 879 return "UNKNOWN";
jengbrecht 56:e5e5351f14b3 880 case ROAMING:
jengbrecht 56:e5e5351f14b3 881 return "ROAMING";
jengbrecht 56:e5e5351f14b3 882 default:
jengbrecht 56:e5e5351f14b3 883 return "UNKNOWN ENUM";
jengbrecht 56:e5e5351f14b3 884 }
jengbrecht 56:e5e5351f14b3 885 }