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:
kranjan
Date:
Sat Jan 04 05:28:45 2014 +0000
Revision:
141:571e0ef6c8dc
Parent:
123:a84f6b89132b
Child:
143:c7d8fe37981b
Added licensing header to all files in the library

Who changed what in which revision?

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