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

Dependents:   M2X_dev axeda_wrapper_dev MTS_M2x_Example1 MTS_Cellular_Connect_Example ... more

Committer:
mfiore
Date:
Fri Jul 11 16:45:35 2014 +0000
Revision:
148:df9feef182b4
Parent:
146:efc4db23a564
prepend status enum with "MTS_" to avoid conflicts with ST's SUCCESS, ERROR, etc

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