Cellular library for MTS Socket Modem Arduino Shield devices from Multi-Tech Systems

Dependents:   mtsas mtsas mtsas mtsas

Committer:
mfiore
Date:
Mon Feb 09 20:47:37 2015 +0000
Revision:
73:bba8669d36f7
Parent:
72:7862171b277d
Parent:
71:8e8152d955d1
Child:
76:6eeffc10739d
merge changes

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Vanger 26:2b769ed8de4f 1 #include "mbed.h"
Vanger 26:2b769ed8de4f 2 #include "EasyIP.h"
Vanger 26:2b769ed8de4f 3 #include "MTSText.h"
Vanger 26:2b769ed8de4f 4 #include "MTSLog.h"
Vanger 26:2b769ed8de4f 5 #include "CellUtils.h"
Vanger 26:2b769ed8de4f 6
Vanger 26:2b769ed8de4f 7 using namespace mts;
Vanger 26:2b769ed8de4f 8
Vanger 26:2b769ed8de4f 9 EasyIP::EasyIP(Radio type)
Vanger 26:2b769ed8de4f 10 {
Vanger 26:2b769ed8de4f 11 this->type = type;
Vanger 26:2b769ed8de4f 12 io = NULL;
Vanger 26:2b769ed8de4f 13 dcd = NULL;
Vanger 26:2b769ed8de4f 14 dtr = NULL;
Vanger 26:2b769ed8de4f 15 resetLine = NULL;
Vanger 26:2b769ed8de4f 16 echoMode = true;
Vanger 26:2b769ed8de4f 17 pppConnected = false;
Vanger 26:2b769ed8de4f 18 socketMode = TCP;
Vanger 26:2b769ed8de4f 19 socketOpened = false;
Vanger 26:2b769ed8de4f 20 socketCloseable = true;
Vanger 26:2b769ed8de4f 21 local_port = 0;
Vanger 26:2b769ed8de4f 22 local_address = "";
Vanger 26:2b769ed8de4f 23 host_port = 0;
Vanger 26:2b769ed8de4f 24 }
Vanger 26:2b769ed8de4f 25
Vanger 26:2b769ed8de4f 26 EasyIP::~EasyIP()
Vanger 26:2b769ed8de4f 27 {
Vanger 26:2b769ed8de4f 28 if (dtr != NULL) {
Vanger 26:2b769ed8de4f 29 dtr->write(1);
Vanger 26:2b769ed8de4f 30 }
Vanger 26:2b769ed8de4f 31
Vanger 26:2b769ed8de4f 32 delete dcd;
Vanger 26:2b769ed8de4f 33 delete dtr;
Vanger 26:2b769ed8de4f 34 delete resetLine;
Vanger 26:2b769ed8de4f 35 }
Vanger 26:2b769ed8de4f 36
Vanger 26:2b769ed8de4f 37 //Initializes the MTS IO Buffer
Vanger 26:2b769ed8de4f 38 bool EasyIP::init(MTSBufferedIO* io)
Vanger 26:2b769ed8de4f 39 {
Vanger 26:2b769ed8de4f 40 if (! Cellular::init(io)) {
Vanger 26:2b769ed8de4f 41 return false;
Vanger 26:2b769ed8de4f 42 }
Vanger 26:2b769ed8de4f 43
Vanger 26:2b769ed8de4f 44 logDebug("radio type: %s", Cellular::getRadioNames(type).c_str());
Vanger 49:1fc51c53cebf 45 //Turns on the HW flow control
Vanger 56:43205bd2752a 46 if(sendBasicCommand("AT+IFC=2,2", 2000) != MTS_SUCCESS) {
Vanger 52:2cb58398a4f9 47 logWarning("Failed to enable serial flow control");
Vanger 35:257eb41405e1 48 }
mfiore 71:8e8152d955d1 49 // Shorten data sending timeout from 5s to 100ms
mfiore 71:8e8152d955d1 50 // Some servers won't handle a timeout that long
mfiore 71:8e8152d955d1 51 if (sendBasicCommand("AT#SCFG=1,1,300,90,600,1", 2000) != MTS_SUCCESS) {
mfiore 71:8e8152d955d1 52 logWarning("Failed to reconfigure socket timeout parameters");
mfiore 71:8e8152d955d1 53 }
Vanger 26:2b769ed8de4f 54 return true;
Vanger 26:2b769ed8de4f 55 }
Vanger 26:2b769ed8de4f 56
Vanger 26:2b769ed8de4f 57 bool EasyIP::connect()
Vanger 26:2b769ed8de4f 58 {
Vanger 33:3b6f3904dde0 59 //Check if APN is not set, if it is not, connect will not work.
Vanger 69:93dace69ee98 60 if (type == MTSMC_H5_IP || type == MTSMC_H5 || type == MTSMC_G3 || type == MTSMC_LAT1) {
Vanger 29:edc613ed3f2e 61 if(apn.size() == 0) {
Vanger 29:edc613ed3f2e 62 logDebug("APN is not set");
Vanger 29:edc613ed3f2e 63 return false;
Vanger 29:edc613ed3f2e 64 }
Vanger 29:edc613ed3f2e 65 }
Vanger 29:edc613ed3f2e 66
Vanger 26:2b769ed8de4f 67 //Check if socket is open
Vanger 26:2b769ed8de4f 68 if(socketOpened) {
Vanger 26:2b769ed8de4f 69 return true;
Vanger 26:2b769ed8de4f 70 }
Vanger 26:2b769ed8de4f 71
Vanger 26:2b769ed8de4f 72 //Check if already connected
Vanger 26:2b769ed8de4f 73 if(isConnected()) {
Vanger 26:2b769ed8de4f 74 return true;
Vanger 26:2b769ed8de4f 75 }
Vanger 51:ffc556ba33f7 76
Vanger 26:2b769ed8de4f 77 Timer tmr;
Vanger 26:2b769ed8de4f 78 //Check Registration: AT+CREG? == 0,1
Vanger 26:2b769ed8de4f 79 tmr.start();
Vanger 26:2b769ed8de4f 80 do {
Vanger 26:2b769ed8de4f 81 Registration registration = getRegistration();
Vanger 56:43205bd2752a 82 if(registration != REGISTERED && registration != ROAMING) {
Vanger 26:2b769ed8de4f 83 logTrace("Not Registered [%d] ... waiting", (int)registration);
Vanger 26:2b769ed8de4f 84 wait(1);
Vanger 26:2b769ed8de4f 85 } else {
Vanger 26:2b769ed8de4f 86 break;
Vanger 26:2b769ed8de4f 87 }
Vanger 30:1326b623919a 88 } while(tmr.read() < 30);
Vanger 51:ffc556ba33f7 89
Vanger 26:2b769ed8de4f 90 //Check RSSI: AT+CSQ
Vanger 26:2b769ed8de4f 91 tmr.reset();
Vanger 26:2b769ed8de4f 92 do {
Vanger 26:2b769ed8de4f 93 int rssi = getSignalStrength();
Vanger 26:2b769ed8de4f 94 logDebug("Signal strength: %d", rssi);
Vanger 51:ffc556ba33f7 95 if(rssi == 99 || rssi == -1) {
Vanger 26:2b769ed8de4f 96 logTrace("No Signal ... waiting");
Vanger 26:2b769ed8de4f 97 wait(1);
Vanger 26:2b769ed8de4f 98 } else {
Vanger 26:2b769ed8de4f 99 break;
Vanger 26:2b769ed8de4f 100 }
Vanger 26:2b769ed8de4f 101 } while(tmr.read() < 30);
Vanger 26:2b769ed8de4f 102
Vanger 52:2cb58398a4f9 103 //Make PPP connection
Vanger 69:93dace69ee98 104 if (type == MTSMC_H5 || type == MTSMC_G3 || type == MTSMC_LAT1) {
Vanger 26:2b769ed8de4f 105 logDebug("Making PPP Connection Attempt. APN[%s]", apn.c_str());
Vanger 26:2b769ed8de4f 106 } else {
Vanger 26:2b769ed8de4f 107 logDebug("Making PPP Connection Attempt");
Vanger 26:2b769ed8de4f 108 }
Vanger 59:5535f14e3cc4 109 std::string pppResult = sendCommand("AT#SGACT=1,1", 15000);
Vanger 30:1326b623919a 110 std::vector<std::string> parts;
Vanger 26:2b769ed8de4f 111 if(pppResult.find("OK") != std::string::npos) {
Vanger 30:1326b623919a 112 parts = Text::split(pppResult, "\r\n");
Vanger 26:2b769ed8de4f 113 if(parts.size() >= 2) {
Vanger 26:2b769ed8de4f 114 parts = Text::split(parts[1], " ");
Vanger 26:2b769ed8de4f 115 local_address = parts[1];
Vanger 26:2b769ed8de4f 116 }
Vanger 26:2b769ed8de4f 117 logInfo("PPP Connection Established: IP[%s]", local_address.c_str());
Vanger 26:2b769ed8de4f 118 pppConnected = true;
Vanger 26:2b769ed8de4f 119
Vanger 26:2b769ed8de4f 120 } else {
Vanger 30:1326b623919a 121 pppResult = sendCommand("AT#SGACT?", 2000);
Vanger 52:2cb58398a4f9 122 if(pppResult.find("1,1") != std::string::npos) {
Vanger 52:2cb58398a4f9 123 logDebug("Radio is already connected");
Vanger 52:2cb58398a4f9 124 pppConnected = true;
Vanger 30:1326b623919a 125 } else {
Vanger 52:2cb58398a4f9 126 logError("PPP connection attempt failed");
Vanger 52:2cb58398a4f9 127 pppConnected = false;
Vanger 30:1326b623919a 128 }
Vanger 26:2b769ed8de4f 129 }
Vanger 26:2b769ed8de4f 130
Vanger 26:2b769ed8de4f 131 return pppConnected;
Vanger 26:2b769ed8de4f 132 }
Vanger 26:2b769ed8de4f 133
Vanger 26:2b769ed8de4f 134 void EasyIP::disconnect()
Vanger 26:2b769ed8de4f 135 {
Vanger 52:2cb58398a4f9 136 //AT#SGACT=1,0: Close PPP connection
Vanger 52:2cb58398a4f9 137 logDebug("Closing PPP Connection");
Vanger 35:257eb41405e1 138 std::string result;
Vanger 35:257eb41405e1 139 Timer tmr;
Vanger 52:2cb58398a4f9 140
Vanger 52:2cb58398a4f9 141 if(socketOpened) {
Vanger 66:8c55e2bf7270 142 close(true);
Vanger 52:2cb58398a4f9 143 }
Vanger 52:2cb58398a4f9 144
Vanger 26:2b769ed8de4f 145 //Sends AT#SGACT=1,0 command
Vanger 54:a6c738bfc391 146 for (int y = 0; y < 5; y++) {
Vanger 54:a6c738bfc391 147 Code code = sendBasicCommand("AT#SGACT=1,0", 1000);
Vanger 54:a6c738bfc391 148 if (code == MTS_SUCCESS) {
Vanger 54:a6c738bfc391 149 logDebug("Successfully closed PPP Connection");
Vanger 54:a6c738bfc391 150 break;
Vanger 54:a6c738bfc391 151 }
Vanger 30:1326b623919a 152 }
Vanger 35:257eb41405e1 153
Vanger 52:2cb58398a4f9 154 /* Ensure PPP link is down, else ping commands will put radio in unknown state
Vanger 52:2cb58398a4f9 155 * (Link is not immediate in disconnection, even though OK is returned)
Vanger 51:ffc556ba33f7 156 */
Vanger 35:257eb41405e1 157 tmr.start();
Vanger 35:257eb41405e1 158 while(tmr.read() < 30) {
Vanger 35:257eb41405e1 159 result = sendCommand("AT#SGACT?", 1000);
Vanger 35:257eb41405e1 160 if(result.find("1,0") != std::string::npos) {
Vanger 35:257eb41405e1 161 break;
Vanger 35:257eb41405e1 162 } else if(result.find("ERROR") != std::string::npos) {
Vanger 35:257eb41405e1 163 break;
Vanger 35:257eb41405e1 164 } else {
Vanger 35:257eb41405e1 165 wait(1);
Vanger 35:257eb41405e1 166 }
Vanger 35:257eb41405e1 167 }
Vanger 35:257eb41405e1 168
Vanger 52:2cb58398a4f9 169 pppConnected = false;
Vanger 30:1326b623919a 170 return;
Vanger 26:2b769ed8de4f 171 }
Vanger 27:ec44d5a9544f 172
Vanger 26:2b769ed8de4f 173 bool EasyIP::isConnected()
Vanger 26:2b769ed8de4f 174 {
Vanger 52:2cb58398a4f9 175 enum RadioState {IDLE, CONNECTING, CONNECTED, DISCONNECTED};
Vanger 51:ffc556ba33f7 176 //state flags for various connection components
Vanger 30:1326b623919a 177 bool signal = false, regist = false, active = false;
Vanger 26:2b769ed8de4f 178
Vanger 29:edc613ed3f2e 179 //1) Check if APN was set if we're on an HSPA radio
Vanger 69:93dace69ee98 180 if (type == MTSMC_H5_IP || type == MTSMC_H5 || type == MTSMC_G3 || type == MTSMC_LAT1) {
Vanger 29:edc613ed3f2e 181 if(apn.size() == 0) {
Vanger 29:edc613ed3f2e 182 logDebug("APN is not set");
Vanger 29:edc613ed3f2e 183 return false;
Vanger 29:edc613ed3f2e 184 }
Vanger 29:edc613ed3f2e 185 }
Vanger 29:edc613ed3f2e 186
Vanger 29:edc613ed3f2e 187 //2) Check that we do not have a live connection up
Vanger 52:2cb58398a4f9 188 if (socketOpened) {
Vanger 29:edc613ed3f2e 189 logDebug("Socket is opened");
Vanger 29:edc613ed3f2e 190 return true;
Vanger 29:edc613ed3f2e 191 }
Vanger 29:edc613ed3f2e 192
Vanger 29:edc613ed3f2e 193 //3) Query the radio
Vanger 52:2cb58398a4f9 194 int rssi = getSignalStrength();
Vanger 52:2cb58398a4f9 195 if (rssi == 99 || rssi == -1) {
Vanger 52:2cb58398a4f9 196 //Signal strength is nonexistent
Vanger 29:edc613ed3f2e 197 signal = false;
Vanger 29:edc613ed3f2e 198 } else {
Vanger 52:2cb58398a4f9 199 signal = true;
Vanger 29:edc613ed3f2e 200 }
Vanger 27:ec44d5a9544f 201
Vanger 52:2cb58398a4f9 202 Registration creg = getRegistration();
Vanger 52:2cb58398a4f9 203 if (creg == REGISTERED) {
Vanger 52:2cb58398a4f9 204 regist = true;
Vanger 29:edc613ed3f2e 205 } else {
Vanger 52:2cb58398a4f9 206 regist = false;
Vanger 29:edc613ed3f2e 207 }
Vanger 27:ec44d5a9544f 208
Vanger 56:43205bd2752a 209 string reply = sendCommand("AT#SGACT?", 1000);
Vanger 52:2cb58398a4f9 210 if (reply.find("1,1") != std::string::npos) {
Vanger 52:2cb58398a4f9 211 active = true;
Vanger 29:edc613ed3f2e 212 } else {
Vanger 52:2cb58398a4f9 213 active = false;
Vanger 29:edc613ed3f2e 214 }
Vanger 52:2cb58398a4f9 215
Vanger 60:250c17af30fb 216 //Updates pppConnected to reflect current connection state
Vanger 52:2cb58398a4f9 217 RadioState state;
Vanger 52:2cb58398a4f9 218 bool ppp = pppConnected;
Vanger 52:2cb58398a4f9 219 if (signal && regist && active) {
Vanger 52:2cb58398a4f9 220 state = CONNECTED;
Vanger 52:2cb58398a4f9 221 pppConnected = true;
Vanger 52:2cb58398a4f9 222 } else if (signal && !regist && !active) {
Vanger 52:2cb58398a4f9 223 state = IDLE;
Vanger 52:2cb58398a4f9 224 pppConnected = false;
Vanger 52:2cb58398a4f9 225 } else if (active) {
Vanger 52:2cb58398a4f9 226 state = CONNECTING;
Vanger 52:2cb58398a4f9 227 } else {
Vanger 52:2cb58398a4f9 228 state = DISCONNECTED;
Vanger 30:1326b623919a 229 pppConnected = false;
Vanger 30:1326b623919a 230 }
Vanger 35:257eb41405e1 231
Vanger 60:250c17af30fb 232 //Compares current connection state with previous pppConnected variable state
Vanger 52:2cb58398a4f9 233 if (!ppp && state == CONNECTED) {
Vanger 52:2cb58398a4f9 234 logWarning("Internal PPP state tracking differs from radio (DISCONNECTED:CONNECTED)");
Vanger 52:2cb58398a4f9 235 } else if (ppp && state != CONNECTED) {
Vanger 56:43205bd2752a 236 string stateStr;
Vanger 56:43205bd2752a 237 switch (state) {
Vanger 56:43205bd2752a 238 case IDLE:
Vanger 56:43205bd2752a 239 stateStr = "IDLE";
Vanger 56:43205bd2752a 240 break;
Vanger 56:43205bd2752a 241 case CONNECTING:
Vanger 56:43205bd2752a 242 stateStr = "CONNECTING";
Vanger 56:43205bd2752a 243 break;
Vanger 56:43205bd2752a 244 case DISCONNECTED:
Vanger 56:43205bd2752a 245 stateStr = "DISCONNECTED";
Vanger 56:43205bd2752a 246 break;
Vanger 56:43205bd2752a 247 case CONNECTED:
Vanger 56:43205bd2752a 248 stateStr = "CONNECTED";
Vanger 56:43205bd2752a 249 break;
Vanger 56:43205bd2752a 250 default:
Vanger 56:43205bd2752a 251 stateStr = "UKNOWN";
Vanger 56:43205bd2752a 252 break;
Vanger 56:43205bd2752a 253 }
Vanger 56:43205bd2752a 254 logWarning("Internal PPP state tracking differs from radio (CONNECTED:%s)", stateStr.c_str());
Vanger 29:edc613ed3f2e 255 }
Vanger 52:2cb58398a4f9 256
Vanger 26:2b769ed8de4f 257 return pppConnected;
Vanger 26:2b769ed8de4f 258 }
Vanger 30:1326b623919a 259
Vanger 33:3b6f3904dde0 260 void EasyIP::reset()
Vanger 33:3b6f3904dde0 261 {
Vanger 33:3b6f3904dde0 262 disconnect();
Vanger 52:2cb58398a4f9 263
Vanger 33:3b6f3904dde0 264 if(sendBasicCommand("AT#REBOOT", 10000) != MTS_SUCCESS) {
Vanger 52:2cb58398a4f9 265 logError("Socket Modem did not accept RESET command");
Vanger 33:3b6f3904dde0 266 } else {
Vanger 52:2cb58398a4f9 267 logWarning("Socket Modem is resetting, allow 30 seconds for it to come back");
Vanger 33:3b6f3904dde0 268 return;
Vanger 33:3b6f3904dde0 269 }
Vanger 33:3b6f3904dde0 270 }
Vanger 33:3b6f3904dde0 271
Vanger 60:250c17af30fb 272 //Opens socket connection
Vanger 26:2b769ed8de4f 273 bool EasyIP::open(const std::string& address, unsigned int port, Mode mode)
Vanger 26:2b769ed8de4f 274 {
Vanger 30:1326b623919a 275 char sOpenSocketCmd[256] = {0}; //String for AT command
Vanger 30:1326b623919a 276 std::string sMode = "";
Vanger 31:529db15abda7 277 int typeSocket = 0;
Vanger 31:529db15abda7 278 int closeType = 0;
Vanger 30:1326b623919a 279
Vanger 30:1326b623919a 280 //1) Check that we do not have a live connection up
Vanger 30:1326b623919a 281 if(socketOpened) {
Vanger 30:1326b623919a 282 //Check that the address, port, and mode match
Vanger 30:1326b623919a 283 if(host_address != address || host_port != port || socketMode != mode) {
Vanger 30:1326b623919a 284 if(socketMode == TCP) {
Vanger 30:1326b623919a 285 logError("TCP socket already opened [%s:%d]", host_address.c_str(), host_port);
Vanger 30:1326b623919a 286 } else {
Vanger 30:1326b623919a 287 logError("UDP socket already opened [%s:%d]", host_address.c_str(), host_port);
Vanger 30:1326b623919a 288 }
Vanger 30:1326b623919a 289 return false;
Vanger 30:1326b623919a 290 }
Vanger 30:1326b623919a 291
Vanger 30:1326b623919a 292 logDebug("Socket already opened");
Vanger 30:1326b623919a 293 return true;
Vanger 30:1326b623919a 294 }
Vanger 30:1326b623919a 295
Vanger 30:1326b623919a 296 //2) Check Parameters
Vanger 30:1326b623919a 297 if(port > 65535) {
Vanger 30:1326b623919a 298 logError("port out of range (0-65535)");
Vanger 30:1326b623919a 299 return false;
Vanger 30:1326b623919a 300 }
Vanger 41:8b9b5098696f 301
Vanger 70:c0c621f88330 302 if(type == MTSMC_EV3 || type == MTSMC_LAT1) {
Vanger 41:8b9b5098696f 303 if(!local_port) {
Vanger 70:c0c621f88330 304 logDebug("Local port set to 1, port 0 not supported for %s", getRadioNames(type).c_str());
Vanger 69:93dace69ee98 305 local_port = 1;
Vanger 69:93dace69ee98 306 }
Vanger 41:8b9b5098696f 307 }
Vanger 30:1326b623919a 308
Vanger 30:1326b623919a 309 //3) Check PPP connection
Vanger 30:1326b623919a 310 if(!isConnected()) {
Vanger 30:1326b623919a 311 logError("PPP not established. Attempting to connect");
Vanger 30:1326b623919a 312 if(!connect()) {
Vanger 30:1326b623919a 313 logError("PPP connection failed");
Vanger 30:1326b623919a 314 return false;
Vanger 30:1326b623919a 315 } else {
Vanger 30:1326b623919a 316 logDebug("PPP connection established");
Vanger 30:1326b623919a 317 }
Vanger 30:1326b623919a 318 }
Vanger 30:1326b623919a 319
Vanger 56:43205bd2752a 320 //4) Set escape sequence to not be transmitted through socket
Vanger 30:1326b623919a 321 if(sendBasicCommand("AT#SKIPESC=1", 2000) != MTS_SUCCESS) {
Vanger 30:1326b623919a 322 logWarning("Failed to disable escape sequence transmission on data mode suspension");
Vanger 30:1326b623919a 323 }
Vanger 30:1326b623919a 324
Vanger 30:1326b623919a 325 if(mode == TCP) {
Vanger 30:1326b623919a 326 typeSocket = 0;
Vanger 30:1326b623919a 327 sMode = "TCP";
Vanger 30:1326b623919a 328 } else {
Vanger 30:1326b623919a 329 typeSocket = 1;
Vanger 30:1326b623919a 330 sMode = "UDP";
Vanger 30:1326b623919a 331 }
Vanger 31:529db15abda7 332
Vanger 31:529db15abda7 333 if(socketCloseable) {
Vanger 31:529db15abda7 334 closeType = 0;
Vanger 31:529db15abda7 335 } else {
Vanger 31:529db15abda7 336 closeType = 255;
Vanger 31:529db15abda7 337 }
Vanger 60:250c17af30fb 338
Vanger 31:529db15abda7 339 //5) Open Socket
Vanger 69:93dace69ee98 340 sprintf(sOpenSocketCmd, "AT#SD=1,%d,%d,\"%s\",%d,%d,0", typeSocket, port, address.c_str(), closeType, local_port);
Vanger 38:b2088faa8bfd 341 std::string response = sendCommand(sOpenSocketCmd, 60000);
Vanger 30:1326b623919a 342
Vanger 30:1326b623919a 343 if(response.find("CONNECT") != std::string::npos) {
Vanger 30:1326b623919a 344 host_address = address;
Vanger 30:1326b623919a 345 host_port = port;
Vanger 30:1326b623919a 346
Vanger 30:1326b623919a 347 logInfo("Opened %s Socket [%s:%d]", sMode.c_str(), address.c_str(), port);
Vanger 30:1326b623919a 348 socketOpened = true;
Vanger 30:1326b623919a 349 socketMode = mode;
Vanger 30:1326b623919a 350 } else {
Vanger 30:1326b623919a 351 logWarning("Unable to open %s Socket [%s:%d]", sMode.c_str(), address.c_str(), port);
Vanger 30:1326b623919a 352 socketOpened = false;
Vanger 30:1326b623919a 353 }
Vanger 30:1326b623919a 354
Vanger 26:2b769ed8de4f 355 return socketOpened;
Vanger 26:2b769ed8de4f 356 }
Vanger 27:ec44d5a9544f 357
Vanger 60:250c17af30fb 358 //Closes socket connection
Vanger 67:7c705fe2acec 359 bool EasyIP::close(bool shutdown)
Vanger 26:2b769ed8de4f 360 {
Vanger 26:2b769ed8de4f 361
Vanger 30:1326b623919a 362 if(io == NULL) {
Vanger 30:1326b623919a 363 logError("MTSBufferedIO not set");
Vanger 30:1326b623919a 364 return false;
Vanger 30:1326b623919a 365 }
Vanger 30:1326b623919a 366
Vanger 30:1326b623919a 367 if(!socketOpened) {
Vanger 30:1326b623919a 368 logWarning("Socket close() called, but socket was not open");
Vanger 30:1326b623919a 369 return true;
Vanger 30:1326b623919a 370 }
Vanger 30:1326b623919a 371
Vanger 30:1326b623919a 372 if(!socketCloseable) {
Vanger 30:1326b623919a 373 logError("Socket is not closeable");
Vanger 30:1326b623919a 374 return false;
Vanger 30:1326b623919a 375 }
Vanger 30:1326b623919a 376
Vanger 30:1326b623919a 377 if(!sendEscapeCommand()) {
Vanger 30:1326b623919a 378 logError("Failed to exit online mode");
Vanger 30:1326b623919a 379 return false;
Vanger 30:1326b623919a 380 } else {
Vanger 30:1326b623919a 381 socketOpened = false;
Vanger 30:1326b623919a 382 }
Vanger 30:1326b623919a 383
Vanger 54:a6c738bfc391 384 if (sendBasicCommand("AT#SH=1", 2000) != MTS_SUCCESS) {
Vanger 30:1326b623919a 385 logDebug("Failed to close socket connection");
Vanger 30:1326b623919a 386 }
Vanger 30:1326b623919a 387
Vanger 60:250c17af30fb 388 //Clear receive buffer
Vanger 67:7c705fe2acec 389 if (shutdown) {
Vanger 66:8c55e2bf7270 390 int counter = 0;
Vanger 66:8c55e2bf7270 391 char tmp[256];
Vanger 66:8c55e2bf7270 392 do {
Vanger 66:8c55e2bf7270 393 if(socketOpened == false) {
Vanger 66:8c55e2bf7270 394 break;
Vanger 66:8c55e2bf7270 395 }
Vanger 66:8c55e2bf7270 396 read(tmp, 256, 1000);
Vanger 66:8c55e2bf7270 397 } while(counter++ < 10);
Vanger 66:8c55e2bf7270 398
Vanger 66:8c55e2bf7270 399 io->rxClear();
Vanger 66:8c55e2bf7270 400 io->txClear();
Vanger 66:8c55e2bf7270 401 }
Vanger 30:1326b623919a 402
Vanger 30:1326b623919a 403 return !socketOpened;
Vanger 26:2b769ed8de4f 404 }
Vanger 26:2b769ed8de4f 405
Vanger 60:250c17af30fb 406 //Read from socket
Vanger 26:2b769ed8de4f 407 int EasyIP::read(char* data, int max, int timeout)
Vanger 26:2b769ed8de4f 408 {
Vanger 30:1326b623919a 409 if(io == NULL) {
Vanger 30:1326b623919a 410 logError("MTSBufferedIO not set");
Vanger 30:1326b623919a 411 return -1;
Vanger 30:1326b623919a 412 }
Vanger 30:1326b623919a 413
Vanger 30:1326b623919a 414 //Check that nothing is in the rx buffer
Vanger 30:1326b623919a 415 if(!socketOpened && !io->readable()) {
Vanger 30:1326b623919a 416 logError("Socket is not open");
Vanger 30:1326b623919a 417 return -1;
Vanger 30:1326b623919a 418 }
Vanger 30:1326b623919a 419
Vanger 30:1326b623919a 420 int bytesRead = 0;
Vanger 30:1326b623919a 421
Vanger 30:1326b623919a 422 if(timeout >= 0) {
Vanger 30:1326b623919a 423 bytesRead = io->read(data, max, static_cast<unsigned int>(timeout));
Vanger 30:1326b623919a 424 } else {
Vanger 30:1326b623919a 425 bytesRead = io->read(data, max);
Vanger 30:1326b623919a 426 }
Vanger 35:257eb41405e1 427
Vanger 35:257eb41405e1 428 //Scan for socket closed message
Vanger 31:529db15abda7 429 if(bytesRead > 0 && socketCloseable) {
Vanger 35:257eb41405e1 430 for(int i = 0; i < bytesRead; i++) {
Vanger 31:529db15abda7 431 if(data[i] == 'N') {
Vanger 31:529db15abda7 432 if(strstr(&data[i], "NO CARRIER")) {
Vanger 31:529db15abda7 433 logTrace("Found socket closed message. Checking validity");
Vanger 31:529db15abda7 434 //Close socket and Cut Off End of Message
Vanger 31:529db15abda7 435 socketOpened = socketCheck(); //Verifies legitimacy of socket disconnect
Vanger 31:529db15abda7 436 if(socketOpened) {
Vanger 31:529db15abda7 437 logDebug("Socket still open");
Vanger 31:529db15abda7 438 continue;
Vanger 31:529db15abda7 439 } else {
Vanger 31:529db15abda7 440 logDebug("Socket closed");
Vanger 31:529db15abda7 441 data[i] = '\0';
Vanger 31:529db15abda7 442 bytesRead = i;
Vanger 31:529db15abda7 443 break;
Vanger 31:529db15abda7 444 }
Vanger 30:1326b623919a 445 }
Vanger 30:1326b623919a 446 }
Vanger 30:1326b623919a 447 }
Vanger 30:1326b623919a 448 }
Vanger 30:1326b623919a 449 return bytesRead;
Vanger 26:2b769ed8de4f 450 }
Vanger 26:2b769ed8de4f 451
Vanger 60:250c17af30fb 452 //Write to socket
Vanger 26:2b769ed8de4f 453 int EasyIP::write(const char* data, int length, int timeout)
Vanger 26:2b769ed8de4f 454 {
Vanger 30:1326b623919a 455 if(io == NULL) {
Vanger 30:1326b623919a 456 logError("MTSBufferedIO not set");
Vanger 30:1326b623919a 457 return -1;
Vanger 30:1326b623919a 458 }
Vanger 30:1326b623919a 459
Vanger 30:1326b623919a 460 if(!socketOpened) {
Vanger 30:1326b623919a 461 logError("Socket is not open");
Vanger 30:1326b623919a 462 return -1;
Vanger 30:1326b623919a 463 }
Vanger 30:1326b623919a 464
Vanger 30:1326b623919a 465 int bytesWritten = 0;
Vanger 31:529db15abda7 466 int size = length;
Vanger 31:529db15abda7 467 int failedWrites = 0;
Vanger 30:1326b623919a 468 if(timeout >= 0) {
Vanger 30:1326b623919a 469 Timer tmr;
Vanger 30:1326b623919a 470 tmr.start();
Vanger 30:1326b623919a 471 do {
Vanger 30:1326b623919a 472 int available = io->writeable();
Vanger 30:1326b623919a 473 if (available > 0) {
Mike Fiore 72:7862171b277d 474 size = mts_min(available, length - bytesWritten);
Vanger 31:529db15abda7 475 bytesWritten += io->write(&data[bytesWritten], size);
Vanger 30:1326b623919a 476 } else {
Vanger 30:1326b623919a 477 wait(0.05);
Vanger 30:1326b623919a 478 }
Vanger 30:1326b623919a 479 } while (tmr.read_ms() <= timeout && bytesWritten < length);
Vanger 30:1326b623919a 480 } else {
Vanger 31:529db15abda7 481 //If timeout is -1:
Vanger 31:529db15abda7 482 do {
Vanger 31:529db15abda7 483 int available = io->writeable();
Vanger 31:529db15abda7 484 if(available > 0) {
Mike Fiore 72:7862171b277d 485 size = mts_min(available, length - bytesWritten);
Vanger 31:529db15abda7 486 int currentWritten = io->write(&data[bytesWritten], size);
Vanger 31:529db15abda7 487 bytesWritten += currentWritten;
Vanger 31:529db15abda7 488 if(!currentWritten) {
Vanger 31:529db15abda7 489 failedWrites++;
Vanger 31:529db15abda7 490 }
Vanger 31:529db15abda7 491 if(failedWrites > 10) {
Vanger 31:529db15abda7 492 logError("Couldn't write any characters");
Vanger 31:529db15abda7 493 return bytesWritten;
Vanger 31:529db15abda7 494 }
Vanger 31:529db15abda7 495 } else {
Vanger 31:529db15abda7 496 wait(0.05);
Vanger 30:1326b623919a 497 }
Vanger 31:529db15abda7 498 } while (bytesWritten < length);
Vanger 30:1326b623919a 499 }
Vanger 30:1326b623919a 500 return bytesWritten;
Vanger 26:2b769ed8de4f 501 }
Vanger 26:2b769ed8de4f 502
Vanger 26:2b769ed8de4f 503 Code EasyIP::setApn(const std::string& apn)
Vanger 26:2b769ed8de4f 504 {
Vanger 26:2b769ed8de4f 505 if (type == MTSMC_H5 || type == MTSMC_G3) {
Vanger 56:43205bd2752a 506 //CGDCONT has options: IP,PPP,IPv6
Vanger 56:43205bd2752a 507 Code code = sendBasicCommand("AT+CGDCONT=1,IP," + apn, 1000);
Vanger 26:2b769ed8de4f 508 if (code != MTS_SUCCESS) {
Vanger 56:43205bd2752a 509 return code;
Vanger 26:2b769ed8de4f 510 }
Vanger 26:2b769ed8de4f 511 this->apn = apn;
Vanger 56:43205bd2752a 512 return code;
Vanger 69:93dace69ee98 513 } else if (type == MTSMC_LAT1) {
Vanger 69:93dace69ee98 514 //CGDCONT has options: IP,PPP,IPv6
Vanger 69:93dace69ee98 515 Code code = sendBasicCommand("AT+CGDCONT=1,\"IP\",\"" + apn + "\"", 1000);
Vanger 69:93dace69ee98 516 if (code != MTS_SUCCESS) {
Vanger 69:93dace69ee98 517 return code;
Vanger 69:93dace69ee98 518 }
Vanger 69:93dace69ee98 519 this->apn = apn;
Vanger 69:93dace69ee98 520 return code;
Vanger 26:2b769ed8de4f 521 } else {
Vanger 26:2b769ed8de4f 522 logInfo("CDMA radios don't need an APN");
Vanger 26:2b769ed8de4f 523 return MTS_SUCCESS;
Vanger 26:2b769ed8de4f 524 }
Vanger 26:2b769ed8de4f 525 }
Vanger 27:ec44d5a9544f 526
Vanger 26:2b769ed8de4f 527 bool EasyIP::ping(const std::string& address)
Vanger 26:2b769ed8de4f 528 {
Vanger 26:2b769ed8de4f 529 char buffer[256] = {0};
Vanger 27:ec44d5a9544f 530 std::vector<std::string> parts;
Vanger 27:ec44d5a9544f 531 int TTL=0;
Vanger 27:ec44d5a9544f 532 int Timeout=0;
Vanger 27:ec44d5a9544f 533
Vanger 27:ec44d5a9544f 534 //Format parameters for sending to radio
Vanger 30:1326b623919a 535 sprintf(buffer, "AT#PING=%s,1,32,%d", address.c_str(), (PINGDELAY*10));
Vanger 26:2b769ed8de4f 536
Vanger 27:ec44d5a9544f 537 for(int pngs=0; pngs<PINGNUM; pngs++) {
Vanger 35:257eb41405e1 538 std::string response = sendCommand(buffer, (PINGDELAY*2000)); //Send 1 ping
Vanger 52:2cb58398a4f9 539 if(response.empty() || response.find("ERROR") != std::string::npos) {
Vanger 28:f93d7b3f7c2e 540 continue; //Skip current loop if send command fails
Vanger 28:f93d7b3f7c2e 541 }
Vanger 27:ec44d5a9544f 542 parts = Text::split(response, "\r\n");
Vanger 28:f93d7b3f7c2e 543 if(parts.size() < 2) {
Vanger 28:f93d7b3f7c2e 544 continue;
Vanger 28:f93d7b3f7c2e 545 }
Vanger 27:ec44d5a9544f 546 parts = Text::split(parts[1], ",");
Vanger 28:f93d7b3f7c2e 547 if(parts.size() < 4) {
Vanger 28:f93d7b3f7c2e 548 continue;
Vanger 28:f93d7b3f7c2e 549 }
Vanger 27:ec44d5a9544f 550 //Parse TTL and Timeout values
Vanger 27:ec44d5a9544f 551 Timeout = std::atoi(parts[2].c_str());
Vanger 27:ec44d5a9544f 552 TTL = std::atoi(parts[3].c_str());
Vanger 27:ec44d5a9544f 553
Vanger 27:ec44d5a9544f 554 if((Timeout < 600) && (TTL < 255)) {
Vanger 27:ec44d5a9544f 555 return true;
Vanger 27:ec44d5a9544f 556 }
Vanger 52:2cb58398a4f9 557 }
Vanger 26:2b769ed8de4f 558 return false;
Vanger 26:2b769ed8de4f 559 }
Vanger 26:2b769ed8de4f 560
Vanger 33:3b6f3904dde0 561 bool EasyIP::sendEscapeCommand()
Vanger 33:3b6f3904dde0 562 {
Vanger 33:3b6f3904dde0 563 //string Cellular::sendCommand(const std::string& command, unsigned int timeoutMillis, char esc)
Vanger 33:3b6f3904dde0 564 if(io == NULL) {
Vanger 33:3b6f3904dde0 565 logError("MTSBufferedIO not set");
Vanger 33:3b6f3904dde0 566 return false;
Vanger 33:3b6f3904dde0 567 }
Vanger 33:3b6f3904dde0 568 if(!socketOpened) {
Vanger 52:2cb58398a4f9 569 logError("Socket is not open.");
Vanger 52:2cb58398a4f9 570 return false;
Vanger 33:3b6f3904dde0 571 }
Vanger 33:3b6f3904dde0 572
Vanger 33:3b6f3904dde0 573 if(!socketCloseable) {
Vanger 33:3b6f3904dde0 574 logError("Socket is not closeable");
Vanger 33:3b6f3904dde0 575 return false;
Vanger 33:3b6f3904dde0 576 }
Vanger 33:3b6f3904dde0 577
Vanger 33:3b6f3904dde0 578 io->rxClear();
Vanger 33:3b6f3904dde0 579 io->txClear();
Vanger 33:3b6f3904dde0 580
Vanger 33:3b6f3904dde0 581 std::string result;
Vanger 52:2cb58398a4f9 582 unsigned int timeoutMillis = 10000;
Vanger 33:3b6f3904dde0 583 //Attempt to write command
Vanger 52:2cb58398a4f9 584 //Format for +++ command is 1 second wait, send +++, then another second wait
Vanger 52:2cb58398a4f9 585 wait(1.2);
Vanger 49:1fc51c53cebf 586 if(io->write("+++", 3, timeoutMillis) != 3) {
Vanger 33:3b6f3904dde0 587 //Failed to write command
Vanger 33:3b6f3904dde0 588 logError("failed to send command to radio within %d milliseconds", timeoutMillis);
Vanger 33:3b6f3904dde0 589 return false;
Vanger 33:3b6f3904dde0 590 }
Vanger 33:3b6f3904dde0 591
Vanger 52:2cb58398a4f9 592 Timer tmr;
Vanger 33:3b6f3904dde0 593 char tmp[256];
Vanger 33:3b6f3904dde0 594 tmp[255] = 0;
Vanger 33:3b6f3904dde0 595 bool done = false;
Vanger 33:3b6f3904dde0 596 bool exitmode = false;
Vanger 52:2cb58398a4f9 597 tmr.start();
Vanger 33:3b6f3904dde0 598 do {
Vanger 33:3b6f3904dde0 599 //Make a non-blocking read call by passing timeout of zero
Vanger 52:2cb58398a4f9 600 int size = io->read(tmp,255,0); //1 less than allocated (timeout is instant)
Vanger 52:2cb58398a4f9 601 if(size > 0) {
Vanger 52:2cb58398a4f9 602 result.append(tmp, size);
Vanger 52:2cb58398a4f9 603 }
Vanger 54:a6c738bfc391 604 if(result.find("OK\r\n") != std::string::npos) {
Vanger 33:3b6f3904dde0 605 exitmode = true;
Vanger 33:3b6f3904dde0 606 done = true;
Vanger 54:a6c738bfc391 607 } else if(result.find("NO CARRIER\r\n") != std::string::npos) {
Vanger 52:2cb58398a4f9 608 socketOpened = false;
Vanger 33:3b6f3904dde0 609 exitmode = true;
Vanger 33:3b6f3904dde0 610 done = true;
Vanger 33:3b6f3904dde0 611 } else if(result.find("ERROR") != std::string::npos) {
Vanger 33:3b6f3904dde0 612 exitmode = false;
Vanger 33:3b6f3904dde0 613 done = true;
Vanger 33:3b6f3904dde0 614 }
Vanger 52:2cb58398a4f9 615 if(tmr.read_ms() >= timeoutMillis) {
Vanger 33:3b6f3904dde0 616 logDebug("Escape sequence [+++] timed out after %d milliseconds", timeoutMillis);
Vanger 33:3b6f3904dde0 617 exitmode = true;
Vanger 33:3b6f3904dde0 618 done = true;
Vanger 33:3b6f3904dde0 619 }
Vanger 33:3b6f3904dde0 620 } while (!done);
Vanger 33:3b6f3904dde0 621
Vanger 54:a6c738bfc391 622 wait(0.1); //Without a slight wait time after receiving OK, radio would
Vanger 54:a6c738bfc391 623 //fail to correctly receive and respond to the next AT command
Vanger 33:3b6f3904dde0 624 return exitmode;
Vanger 33:3b6f3904dde0 625 }
Vanger 33:3b6f3904dde0 626
Vanger 33:3b6f3904dde0 627 bool EasyIP::socketCheck() {
Vanger 57:7eb2eb536d4a 628 enum SocketStatus {SOCKETCLOSED = 0, SOCKETACTIVEDATA = 1, SOCKETSUSPEND = 2, SOCKETSUSPENDDATA = 3, SOCKETLISTEN = 4, SOCKETINCOMING = 5, ERROR = 9};
Vanger 33:3b6f3904dde0 629 bool status = false;
Vanger 56:43205bd2752a 630 int socketInfo = ERROR;
Vanger 33:3b6f3904dde0 631 std::vector<std::string> params;
Vanger 33:3b6f3904dde0 632
Vanger 33:3b6f3904dde0 633 //Goes from data mode to command mode
Vanger 33:3b6f3904dde0 634 if(sendEscapeCommand()) {
Vanger 52:2cb58398a4f9 635 std::string reply = sendCommand("AT#SS=1", 2000);
Vanger 52:2cb58398a4f9 636 if(reply.find("OK") != std::string::npos) {
Vanger 52:2cb58398a4f9 637 //Found valid response
Vanger 52:2cb58398a4f9 638 params = Text::split(reply, "\r\n");
Vanger 52:2cb58398a4f9 639 params = Text::split(params[1], ",");
Vanger 52:2cb58398a4f9 640 socketInfo = atoi(params[1].c_str());
Vanger 52:2cb58398a4f9 641 } else {
Vanger 52:2cb58398a4f9 642 logError("Could not determine socket status[%d]",socketInfo);
Vanger 56:43205bd2752a 643 socketInfo = ERROR;
Vanger 33:3b6f3904dde0 644 }
Vanger 33:3b6f3904dde0 645 } else {
Vanger 33:3b6f3904dde0 646 status = false; //Return value of socketOpened when checking
Vanger 33:3b6f3904dde0 647 }
Vanger 33:3b6f3904dde0 648
Vanger 33:3b6f3904dde0 649 //Check socket status query
Vanger 56:43205bd2752a 650 if(socketInfo == SOCKETINCOMING || socketInfo == SOCKETACTIVEDATA || socketInfo == SOCKETSUSPEND || socketInfo == SOCKETSUSPENDDATA || socketInfo == SOCKETLISTEN) { //Socket opened responses
Vanger 52:2cb58398a4f9 651 status = true;
Vanger 52:2cb58398a4f9 652 } else if(socketInfo == SOCKETCLOSED || socketInfo == SOCKETINCOMING) {
Vanger 52:2cb58398a4f9 653 status = false;
Vanger 33:3b6f3904dde0 654 } else {
Vanger 54:a6c738bfc391 655 logError("Could not determine socket status[%d]",socketInfo);
Vanger 52:2cb58398a4f9 656 status = false;
Vanger 33:3b6f3904dde0 657 }
Vanger 33:3b6f3904dde0 658
Vanger 52:2cb58398a4f9 659 //Reconnect to active socket if able
Vanger 33:3b6f3904dde0 660 if(status) {
Vanger 33:3b6f3904dde0 661 std::string reconnect = sendCommand("AT#SO=1", 2000);
Vanger 33:3b6f3904dde0 662 if(reconnect.find("CONNECT") != std::string::npos || reconnect.find("OK") != std::string::npos) {
Vanger 33:3b6f3904dde0 663 } else {
Vanger 33:3b6f3904dde0 664 logError("Failed to resume socket connection");
Vanger 33:3b6f3904dde0 665 }
Vanger 33:3b6f3904dde0 666 }
Vanger 33:3b6f3904dde0 667 return status;
Vanger 33:3b6f3904dde0 668 }