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

Dependents:   M2X_dev axeda_wrapper_dev MTS_M2x_Example1 MTS_Cellular_Connect_Example ... more

Committer:
jengbrecht
Date:
Thu Dec 19 16:47:26 2013 +0000
Revision:
36:bb6b293c7495
Parent:
33:e04aa7c013c9
Child:
37:61373f492403
Added a ton more documentation to most of the headers files. Also removed the capacity and available functions from MTSBufferedIO in favor of readable and writeable. Removed the single available method call from the cellular class.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
jengbrecht 0:563b70517320 1 #ifndef CELLULAR_CPP
jengbrecht 0:563b70517320 2 #define CELLULAR_CPP
jengbrecht 0:563b70517320 3
jengbrecht 0:563b70517320 4 #include "Cellular.h"
sgodinez 4:6561c9128c6f 5 #include "MTSText.h"
sgodinez 19:38794784e009 6 #include "MTSSerial.h"
jengbrecht 0:563b70517320 7
sgodinez 19:38794784e009 8 Cellular* Cellular::instance = NULL;
sgodinez 19:38794784e009 9
sgodinez 19:38794784e009 10 Cellular* Cellular::getInstance() {
sgodinez 19:38794784e009 11 if(instance == NULL) {
sgodinez 19:38794784e009 12 instance = new Cellular(NULL);
sgodinez 19:38794784e009 13 }
sgodinez 19:38794784e009 14 return instance;
sgodinez 19:38794784e009 15 }
sgodinez 19:38794784e009 16
sgodinez 19:38794784e009 17
sgodinez 19:38794784e009 18 Cellular* Cellular::getInstance(MTSBufferedIO* io) {
sgodinez 19:38794784e009 19 if(instance == NULL) {
sgodinez 19:38794784e009 20 instance = new Cellular(io);
sgodinez 19:38794784e009 21 }
sgodinez 19:38794784e009 22 instance->io = io;
sgodinez 19:38794784e009 23 return instance;
sgodinez 19:38794784e009 24 }
sgodinez 19:38794784e009 25
sgodinez 19:38794784e009 26 Cellular::Cellular(MTSBufferedIO* io)
sgodinez 11:134435d8a2d5 27 : io(io)
sgodinez 13:0af863114629 28 , echoMode(true)
sgodinez 11:134435d8a2d5 29 , pppConnected(false)
sgodinez 11:134435d8a2d5 30 , mode(TCP)
sgodinez 11:134435d8a2d5 31 , socketOpened(false)
sgodinez 17:2d7c4ea7491b 32 , socketCloseable(false)
sgodinez 11:134435d8a2d5 33 , local_port(0)
sgodinez 11:134435d8a2d5 34 , host_port(0)
jengbrecht 0:563b70517320 35 {
mfiore 29:7408b1bdad37 36 // the radio's DCD signal is mapped to PTA4
mfiore 29:7408b1bdad37 37 // the radio will raise and lower this line
mfiore 29:7408b1bdad37 38 dcd = new DigitalIn(PTA4);
mfiore 29:7408b1bdad37 39 // the DTR line to the radio is mapped PTC9
mfiore 29:7408b1bdad37 40 // this line should be lowered when we want to talk to the radio and raised when we're done
mfiore 29:7408b1bdad37 41 // for now we will lower it in the constructor and raise it in the destructor
mfiore 29:7408b1bdad37 42 dtr = new DigitalOut(PTC9);
mfiore 29:7408b1bdad37 43 dtr->write(0);
jengbrecht 0:563b70517320 44 }
jengbrecht 0:563b70517320 45
jengbrecht 0:563b70517320 46 Cellular::~Cellular()
jengbrecht 0:563b70517320 47 {
mfiore 29:7408b1bdad37 48 dtr->write(1);
jengbrecht 0:563b70517320 49 }
jengbrecht 0:563b70517320 50
sgodinez 11:134435d8a2d5 51 bool Cellular::connect() {
sgodinez 13:0af863114629 52 //Check if socket is open
sgodinez 13:0af863114629 53 if(socketOpened) {
sgodinez 13:0af863114629 54 return true;
sgodinez 13:0af863114629 55 }
sgodinez 13:0af863114629 56
sgodinez 11:134435d8a2d5 57 //Run Test first to validate a good state
sgodinez 13:0af863114629 58 if(isConnected()) {
sgodinez 13:0af863114629 59 return true;
sgodinez 13:0af863114629 60 }
sgodinez 13:0af863114629 61
sgodinez 11:134435d8a2d5 62 //Check RSSI: AT+CSQ
sgodinez 13:0af863114629 63 int rssi = getSignalStrength();
sgodinez 17:2d7c4ea7491b 64 printf("[DEBUG] Signal strength: %d\r\n", rssi);
sgodinez 13:0af863114629 65
sgodinez 11:134435d8a2d5 66 //Check Registration: AT+CREG? == 0,1
sgodinez 13:0af863114629 67 Registration registration = getRegistration();
sgodinez 13:0af863114629 68 if(registration != REGISTERED) {
sgodinez 17:2d7c4ea7491b 69 printf("[WARNING] Not Registered [%d]\r\n", (int)registration);
sgodinez 13:0af863114629 70 }
sgodinez 11:134435d8a2d5 71
sgodinez 11:134435d8a2d5 72 //AT#CONNECTIONSTART: Make a PPP connection
sgodinez 17:2d7c4ea7491b 73 printf("[DEBUG] Making PPP Connection Attempt. APN[%s]\r\n", apn.c_str());
sgodinez 13:0af863114629 74 std::string pppResult = sendCommand("AT#CONNECTIONSTART", 120000);
sgodinez 17:2d7c4ea7491b 75 std::vector<std::string> parts = Text::split(pppResult, "\r\n");
sgodinez 13:0af863114629 76
sgodinez 17:2d7c4ea7491b 77 //printf("[DEBUG] PPP CONNECT RESULT [%s]\r\n", pppResult.c_str());
sgodinez 17:2d7c4ea7491b 78 // for(uint32_t i = 0; i < parts.size(); i++) {
sgodinez 17:2d7c4ea7491b 79 // printf("[%d] [%s]\r\n", i, parts[i].c_str());
sgodinez 17:2d7c4ea7491b 80 // }
sgodinez 13:0af863114629 81
sgodinez 13:0af863114629 82 if(pppResult.find("Ok_Info_GprsActivation") != std::string::npos) {
sgodinez 13:0af863114629 83 if(parts.size() >= 2) {
sgodinez 13:0af863114629 84 local_address = parts[1];
sgodinez 13:0af863114629 85 }
sgodinez 17:2d7c4ea7491b 86 printf("[INFO] PPP Connection Established: IP[%s]\r\n", local_address.c_str());
sgodinez 13:0af863114629 87 pppConnected = true;
sgodinez 13:0af863114629 88
sgodinez 13:0af863114629 89 } else {
sgodinez 13:0af863114629 90 pppConnected = false;
sgodinez 13:0af863114629 91 }
sgodinez 11:134435d8a2d5 92
sgodinez 13:0af863114629 93 return pppConnected;
sgodinez 11:134435d8a2d5 94 }
sgodinez 11:134435d8a2d5 95
sgodinez 11:134435d8a2d5 96 void Cellular::disconnect() {
sgodinez 17:2d7c4ea7491b 97 //AT#CONNECTIONSTOP: Close a PPP connection
sgodinez 17:2d7c4ea7491b 98 printf("[DEBUG] Closing PPP Connection\r\n");
sgodinez 11:134435d8a2d5 99
sgodinez 17:2d7c4ea7491b 100 if(socketOpened) {
sgodinez 17:2d7c4ea7491b 101 close();
sgodinez 17:2d7c4ea7491b 102 }
sgodinez 17:2d7c4ea7491b 103
sgodinez 17:2d7c4ea7491b 104 Code code = sendBasicCommand("AT#CONNECTIONSTOP", 10000);
sgodinez 17:2d7c4ea7491b 105 if(code == OK) {
sgodinez 17:2d7c4ea7491b 106 printf("[DEBUG] Successfully closed PPP Connection\r\n");
sgodinez 17:2d7c4ea7491b 107 } else {
sgodinez 17:2d7c4ea7491b 108 printf("[ERROR] Closing PPP Connection [%d]. Continuing ...\r\n", (int)code);
sgodinez 17:2d7c4ea7491b 109 }
sgodinez 17:2d7c4ea7491b 110
sgodinez 17:2d7c4ea7491b 111 pppConnected = false;
sgodinez 11:134435d8a2d5 112 }
sgodinez 11:134435d8a2d5 113
sgodinez 11:134435d8a2d5 114 bool Cellular::isConnected() {
sgodinez 11:134435d8a2d5 115 //1) Check if APN was set
sgodinez 11:134435d8a2d5 116 if(apn.size() == 0) {
sgodinez 17:2d7c4ea7491b 117 printf("[DEBUG] APN is not set\r\n");
sgodinez 11:134435d8a2d5 118 return false;
sgodinez 11:134435d8a2d5 119 }
sgodinez 11:134435d8a2d5 120
sgodinez 11:134435d8a2d5 121 //1) Check that we do not have a live connection up
sgodinez 11:134435d8a2d5 122 if(socketOpened) {
sgodinez 17:2d7c4ea7491b 123 printf("[DEBUG] Socket is opened\r\n");
sgodinez 11:134435d8a2d5 124 return true;
sgodinez 11:134435d8a2d5 125 }
sgodinez 11:134435d8a2d5 126 //2) Query the radio
sgodinez 11:134435d8a2d5 127 pppConnected = false;
sgodinez 11:134435d8a2d5 128 std::string result = sendCommand("AT#VSTATE", 1000);
sgodinez 11:134435d8a2d5 129 if(result.find("CONNECTED") != std::string::npos) {
sgodinez 11:134435d8a2d5 130 pppConnected = true;
sgodinez 11:134435d8a2d5 131 }
sgodinez 11:134435d8a2d5 132
sgodinez 11:134435d8a2d5 133 return pppConnected;
sgodinez 11:134435d8a2d5 134 }
sgodinez 11:134435d8a2d5 135
sgodinez 11:134435d8a2d5 136 bool Cellular::bind(unsigned int port) {
sgodinez 11:134435d8a2d5 137 return false;
sgodinez 11:134435d8a2d5 138 }
sgodinez 11:134435d8a2d5 139
sgodinez 11:134435d8a2d5 140 bool Cellular::open(const std::string& address, unsigned int port, Mode mode) {
sgodinez 17:2d7c4ea7491b 141 char buffer[256] = {0};
sgodinez 11:134435d8a2d5 142 Code portCode, addressCode;
sgodinez 17:2d7c4ea7491b 143 printf("[DEBUG] Attempting to Open Socket\r\n");
sgodinez 11:134435d8a2d5 144
sgodinez 11:134435d8a2d5 145 //1) Check that we do not have a live connection up
sgodinez 11:134435d8a2d5 146 if(socketOpened) {
sgodinez 17:2d7c4ea7491b 147 printf("[DEBUG] Socket already opened\r\n");
sgodinez 11:134435d8a2d5 148 return true;
sgodinez 11:134435d8a2d5 149 }
sgodinez 11:134435d8a2d5 150
sgodinez 11:134435d8a2d5 151 //2) Check PPP connection
sgodinez 11:134435d8a2d5 152 if(!isConnected()) {
sgodinez 17:2d7c4ea7491b 153 printf("[ERROR] PPP not established. Attempting to connect\r\n");
sgodinez 11:134435d8a2d5 154 if(!connect()) {
sgodinez 17:2d7c4ea7491b 155 printf("[ERROR] PPP connection failed\r\n");
sgodinez 11:134435d8a2d5 156 return false;
sgodinez 11:134435d8a2d5 157 } else {
sgodinez 17:2d7c4ea7491b 158 printf("[DEBUG] PPP connection established\r\n");
sgodinez 11:134435d8a2d5 159 }
sgodinez 11:134435d8a2d5 160 }
sgodinez 11:134435d8a2d5 161
sgodinez 17:2d7c4ea7491b 162 ////Setup IP Connection
sgodinez 11:134435d8a2d5 163 if(mode == TCP) {
sgodinez 17:2d7c4ea7491b 164 if(socketCloseable) {
sgodinez 17:2d7c4ea7491b 165 Code code = sendBasicCommand("AT#DLEMODE=1,0", 1000);
sgodinez 17:2d7c4ea7491b 166 if(code != OK) {
sgodinez 17:2d7c4ea7491b 167 printf("[WARNING] Unable to set socket closeable [%d]\r\n", (int) code);
sgodinez 17:2d7c4ea7491b 168 }
sgodinez 17:2d7c4ea7491b 169 }
sgodinez 17:2d7c4ea7491b 170 sprintf(buffer, "AT#TCPPORT=1,%d", port);
sgodinez 17:2d7c4ea7491b 171 portCode = sendBasicCommand(buffer, 1000);
sgodinez 17:2d7c4ea7491b 172 addressCode = sendBasicCommand("AT#TCPSERV=1,\"" + address + "\"", 1000);
sgodinez 11:134435d8a2d5 173 } else {
sgodinez 17:2d7c4ea7491b 174 if(socketCloseable) {
sgodinez 17:2d7c4ea7491b 175 Code code = sendBasicCommand("AT#UDPDLEMODE=1", 1000);
sgodinez 17:2d7c4ea7491b 176 if(code != OK) {
sgodinez 17:2d7c4ea7491b 177 printf("[WARNING] Unable to set socket closeable [%d]\r\n", (int) code);
sgodinez 17:2d7c4ea7491b 178 }
sgodinez 17:2d7c4ea7491b 179 }
sgodinez 17:2d7c4ea7491b 180 sprintf(buffer, "AT#UDPPORT=1,%d", port);
sgodinez 17:2d7c4ea7491b 181 portCode = sendBasicCommand(buffer, 1000);
sgodinez 17:2d7c4ea7491b 182 addressCode = sendBasicCommand("AT#UDPSERV=1,\"" + address + "\"", 1000);
sgodinez 11:134435d8a2d5 183 }
sgodinez 11:134435d8a2d5 184
sgodinez 11:134435d8a2d5 185 if(portCode == OK) {
sgodinez 11:134435d8a2d5 186 host_port = port;
sgodinez 11:134435d8a2d5 187 } else {
sgodinez 17:2d7c4ea7491b 188 printf("[ERROR] Host port could not be set\r\n");
sgodinez 11:134435d8a2d5 189 }
sgodinez 11:134435d8a2d5 190
sgodinez 11:134435d8a2d5 191 if(addressCode == OK) {
sgodinez 11:134435d8a2d5 192 host_address = address;
sgodinez 11:134435d8a2d5 193 } else {
sgodinez 17:2d7c4ea7491b 194 printf("[ERROR] Host address could not be set\r\n");
sgodinez 11:134435d8a2d5 195 }
sgodinez 11:134435d8a2d5 196
sgodinez 13:0af863114629 197 // Try and Connect
sgodinez 13:0af863114629 198 string response = sendCommand("AT#OTCP=1", 30000);
sgodinez 13:0af863114629 199 if (response.find("Ok_Info_WaitingForData") != string::npos) {
sgodinez 17:2d7c4ea7491b 200 printf("[INFO] Opened TCP Socket [%s:%d]\r\n", address.c_str(), port);
sgodinez 13:0af863114629 201 socketOpened = true;
sgodinez 13:0af863114629 202 } else {
sgodinez 17:2d7c4ea7491b 203 printf("[WARNING] Unable to open TCP Socket [%s:%d]\r\n", address.c_str(), port);
sgodinez 13:0af863114629 204 socketOpened = false;
sgodinez 13:0af863114629 205 }
sgodinez 11:134435d8a2d5 206
sgodinez 13:0af863114629 207 return socketOpened;
sgodinez 11:134435d8a2d5 208 }
sgodinez 11:134435d8a2d5 209
sgodinez 11:134435d8a2d5 210 bool Cellular::isOpen() {
sgodinez 17:2d7c4ea7491b 211 return socketOpened;
sgodinez 11:134435d8a2d5 212 }
sgodinez 11:134435d8a2d5 213
sgodinez 17:2d7c4ea7491b 214 bool Cellular::close() {
sgodinez 13:0af863114629 215 if(!socketOpened) {
sgodinez 17:2d7c4ea7491b 216 printf("[ERROR] Socket is not open\r\n");
sgodinez 17:2d7c4ea7491b 217 return false;
sgodinez 13:0af863114629 218 }
sgodinez 11:134435d8a2d5 219
sgodinez 17:2d7c4ea7491b 220 if(!socketCloseable) {
sgodinez 17:2d7c4ea7491b 221 printf("[ERROR] Socket is not closeable\r\n");
sgodinez 17:2d7c4ea7491b 222 return false;
sgodinez 17:2d7c4ea7491b 223 }
sgodinez 17:2d7c4ea7491b 224
sgodinez 17:2d7c4ea7491b 225 //Build Escape Message => ETX
sgodinez 17:2d7c4ea7491b 226 char buffer[2] = { 0x03, 0x00 };
sgodinez 13:0af863114629 227 Code code = sendBasicCommand(buffer, 1000, NONE);
sgodinez 13:0af863114629 228 if(code != OK) {
mfiore 29:7408b1bdad37 229 printf("[ERROR] Radio did not accept close socket command\r\n");
sgodinez 17:2d7c4ea7491b 230 return false;
sgodinez 13:0af863114629 231 }
sgodinez 17:2d7c4ea7491b 232 socketOpened = false;
sgodinez 17:2d7c4ea7491b 233 return true;
sgodinez 11:134435d8a2d5 234 }
sgodinez 11:134435d8a2d5 235
sgodinez 11:134435d8a2d5 236 int Cellular::read(char* data, int max, int timeout) {
sgodinez 19:38794784e009 237 if(io == NULL) {
sgodinez 19:38794784e009 238 printf("[ERROR] MTSBufferedIO not set\r\n");
sgodinez 19:38794784e009 239 return -1;
sgodinez 19:38794784e009 240 }
sgodinez 19:38794784e009 241
sgodinez 17:2d7c4ea7491b 242 if(!socketOpened) {
sgodinez 17:2d7c4ea7491b 243 printf("[ERROR] Socket is not open\r\n");
sgodinez 17:2d7c4ea7491b 244 return -1;
sgodinez 17:2d7c4ea7491b 245 }
sgodinez 17:2d7c4ea7491b 246 int bytesRead = 0;
sgodinez 32:629e6b1c8e22 247
sgodinez 17:2d7c4ea7491b 248 if(timeout >= 0) {
sgodinez 17:2d7c4ea7491b 249 Timer tmr;
sgodinez 17:2d7c4ea7491b 250 tmr.start();
sgodinez 17:2d7c4ea7491b 251 while (tmr.read_ms() <= timeout && bytesRead < max) {
sgodinez 32:629e6b1c8e22 252 int available = io->readable();
sgodinez 32:629e6b1c8e22 253 if (available > 0) {
sgodinez 32:629e6b1c8e22 254 int size = MIN(available, max - bytesRead);
sgodinez 32:629e6b1c8e22 255 bytesRead += io->read(&data[bytesRead], size);
sgodinez 17:2d7c4ea7491b 256 } else {
sgodinez 17:2d7c4ea7491b 257 wait(0.05);
sgodinez 17:2d7c4ea7491b 258 }
sgodinez 17:2d7c4ea7491b 259 }
sgodinez 17:2d7c4ea7491b 260 } else {
sgodinez 19:38794784e009 261 bytesRead = io->read(data, max);
sgodinez 17:2d7c4ea7491b 262 }
sgodinez 17:2d7c4ea7491b 263
sgodinez 32:629e6b1c8e22 264 if(bytesRead > 0 && socketCloseable) {
sgodinez 32:629e6b1c8e22 265 //Remove escape characters
sgodinez 32:629e6b1c8e22 266 int index = 0;
sgodinez 32:629e6b1c8e22 267 bool escapeFlag = false;
sgodinez 32:629e6b1c8e22 268 for(int i = 0; i < bytesRead; i++) {
sgodinez 32:629e6b1c8e22 269 if(data[i] == DLE || data[i] == ETX) {
sgodinez 32:629e6b1c8e22 270 if(escapeFlag == true) {
sgodinez 32:629e6b1c8e22 271 //This character has been escaped
sgodinez 32:629e6b1c8e22 272 escapeFlag = false;
sgodinez 32:629e6b1c8e22 273 } else if(data[bytesRead] == DLE) {
sgodinez 32:629e6b1c8e22 274 //Found escape character
sgodinez 32:629e6b1c8e22 275 escapeFlag = true;
sgodinez 32:629e6b1c8e22 276 continue;
sgodinez 32:629e6b1c8e22 277 } else {
sgodinez 32:629e6b1c8e22 278 //ETX sent without escape -> Socket closed
sgodinez 32:629e6b1c8e22 279 printf("[INFO] Read ETX character without DLE escape. Socket closed\r\n");
sgodinez 32:629e6b1c8e22 280 socketOpened = false;
sgodinez 32:629e6b1c8e22 281 continue;
sgodinez 32:629e6b1c8e22 282 }
sgodinez 32:629e6b1c8e22 283 }
sgodinez 32:629e6b1c8e22 284
sgodinez 32:629e6b1c8e22 285 if(index != i) {
sgodinez 32:629e6b1c8e22 286 data[index] = data[i];
sgodinez 32:629e6b1c8e22 287 }
sgodinez 32:629e6b1c8e22 288 index++;
sgodinez 32:629e6b1c8e22 289 }
sgodinez 32:629e6b1c8e22 290 bytesRead = index;
sgodinez 32:629e6b1c8e22 291 }
sgodinez 32:629e6b1c8e22 292
sgodinez 32:629e6b1c8e22 293 printf("[DEBUG] Scanning received data for socket closed message\r\n");
sgodinez 32:629e6b1c8e22 294 //Scan for socket closed message
sgodinez 32:629e6b1c8e22 295 for(size_t i = 0; i < bytesRead; i++) {
sgodinez 32:629e6b1c8e22 296 if(data[i] == 'O') {
sgodinez 32:629e6b1c8e22 297 if(strstr(&data[i], "Ok_Info_SocketClosed")) {
sgodinez 32:629e6b1c8e22 298 printf("[INFO] Found socket closed message. Socket closed\r\n");
sgodinez 32:629e6b1c8e22 299 //Close socket and Cut Off End of Message
sgodinez 32:629e6b1c8e22 300 socketOpened = false;
sgodinez 32:629e6b1c8e22 301 data[i] = '\0';
sgodinez 32:629e6b1c8e22 302 bytesRead = i;
sgodinez 32:629e6b1c8e22 303 break;
sgodinez 32:629e6b1c8e22 304 }
sgodinez 32:629e6b1c8e22 305 }
sgodinez 32:629e6b1c8e22 306 }
sgodinez 17:2d7c4ea7491b 307 return bytesRead;
sgodinez 11:134435d8a2d5 308 }
sgodinez 11:134435d8a2d5 309
sgodinez 11:134435d8a2d5 310 int Cellular::write(char* data, int length, int timeout) {
sgodinez 19:38794784e009 311 if(io == NULL) {
sgodinez 19:38794784e009 312 printf("[ERROR] MTSBufferedIO not set\r\n");
sgodinez 19:38794784e009 313 return -1;
sgodinez 19:38794784e009 314 }
sgodinez 19:38794784e009 315
sgodinez 17:2d7c4ea7491b 316 if(!socketOpened) {
sgodinez 17:2d7c4ea7491b 317 printf("[ERROR] Socket is not open\r\n");
sgodinez 17:2d7c4ea7491b 318 return -1;
sgodinez 17:2d7c4ea7491b 319 }
sgodinez 17:2d7c4ea7491b 320
sgodinez 17:2d7c4ea7491b 321 int bytesWritten = 0;
sgodinez 17:2d7c4ea7491b 322
sgodinez 17:2d7c4ea7491b 323 if(timeout >= 0) {
sgodinez 17:2d7c4ea7491b 324 Timer tmr;
sgodinez 17:2d7c4ea7491b 325 tmr.start();
sgodinez 17:2d7c4ea7491b 326 while (tmr.read_ms() <= timeout && bytesWritten < length) {
sgodinez 19:38794784e009 327 if (io->writeable()) {
sgodinez 19:38794784e009 328 if(io->write(*data) == 1) {
sgodinez 17:2d7c4ea7491b 329 data++;
sgodinez 17:2d7c4ea7491b 330 bytesWritten++;
sgodinez 17:2d7c4ea7491b 331 }
sgodinez 17:2d7c4ea7491b 332 } else {
sgodinez 17:2d7c4ea7491b 333 wait(0.05);
sgodinez 17:2d7c4ea7491b 334 }
sgodinez 17:2d7c4ea7491b 335 }
sgodinez 17:2d7c4ea7491b 336 } else {
sgodinez 19:38794784e009 337 bytesWritten = io->write(data, length);
sgodinez 17:2d7c4ea7491b 338 }
sgodinez 17:2d7c4ea7491b 339
sgodinez 17:2d7c4ea7491b 340 return bytesWritten;
sgodinez 11:134435d8a2d5 341 }
sgodinez 11:134435d8a2d5 342
sgodinez 11:134435d8a2d5 343 unsigned int Cellular::readable() {
sgodinez 19:38794784e009 344 if(io == NULL) {
sgodinez 19:38794784e009 345 printf("[ERROR] MTSBufferedIO not set\r\n");
sgodinez 19:38794784e009 346 return 0;
sgodinez 19:38794784e009 347 }
sgodinez 17:2d7c4ea7491b 348 if(!socketOpened) {
sgodinez 17:2d7c4ea7491b 349 printf("[ERROR] Socket is not open\r\n");
sgodinez 17:2d7c4ea7491b 350 return 0;
sgodinez 17:2d7c4ea7491b 351 }
sgodinez 19:38794784e009 352 return io->readable();
sgodinez 11:134435d8a2d5 353 }
sgodinez 11:134435d8a2d5 354
sgodinez 11:134435d8a2d5 355 unsigned int Cellular::writeable() {
sgodinez 19:38794784e009 356 if(io == NULL) {
sgodinez 19:38794784e009 357 printf("[ERROR] MTSBufferedIO not set\r\n");
sgodinez 19:38794784e009 358 return 0;
sgodinez 19:38794784e009 359 }
sgodinez 17:2d7c4ea7491b 360 if(!socketOpened) {
sgodinez 17:2d7c4ea7491b 361 printf("[ERROR] Socket is not open\r\n");
sgodinez 17:2d7c4ea7491b 362 return 0;
sgodinez 17:2d7c4ea7491b 363 }
sgodinez 17:2d7c4ea7491b 364
sgodinez 19:38794784e009 365 return io->writeable();
sgodinez 11:134435d8a2d5 366 }
sgodinez 11:134435d8a2d5 367
sgodinez 11:134435d8a2d5 368 void Cellular::reset() {
mfiore 29:7408b1bdad37 369 disconnect();
mfiore 29:7408b1bdad37 370 Code code = sendBasicCommand("AT#RESET=0", 10000);
mfiore 29:7408b1bdad37 371 if(code != OK) {
mfiore 29:7408b1bdad37 372 printf("[ERROR] Socket Modem did not accept RESET command\n\r");
mfiore 29:7408b1bdad37 373 } else {
mfiore 29:7408b1bdad37 374 printf("[WARNING] Socket Modem is resetting, allow 30 seconds for it to come back\n\r");
mfiore 29:7408b1bdad37 375 }
sgodinez 11:134435d8a2d5 376 }
sgodinez 11:134435d8a2d5 377
sgodinez 11:134435d8a2d5 378 Cellular::Code Cellular::test()
jengbrecht 0:563b70517320 379 {
sgodinez 11:134435d8a2d5 380 Code code = sendBasicCommand("AT", 1000);
sgodinez 11:134435d8a2d5 381
sgodinez 11:134435d8a2d5 382 if(code != OK) {
sgodinez 11:134435d8a2d5 383 printf("[Error] Failed basic AT command");
sgodinez 11:134435d8a2d5 384 return code;
sgodinez 11:134435d8a2d5 385 }
sgodinez 11:134435d8a2d5 386
sgodinez 11:134435d8a2d5 387 //AT#VSTATE != "CHECKING"
sgodinez 11:134435d8a2d5 388
sgodinez 11:134435d8a2d5 389 //AT#GPRSMODE ==
sgodinez 12:40ac31a09132 390 return OK;
jengbrecht 0:563b70517320 391 }
jengbrecht 0:563b70517320 392
mfiore 29:7408b1bdad37 393 Cellular::Code Cellular::echo(bool state)
jengbrecht 0:563b70517320 394 {
sgodinez 13:0af863114629 395 Code code;
jengbrecht 0:563b70517320 396 if (state) {
sgodinez 13:0af863114629 397 code = sendBasicCommand("ATE0", 1000);
sgodinez 13:0af863114629 398 echoMode = (code == OK) ? false : echoMode;
jengbrecht 0:563b70517320 399 } else {
sgodinez 13:0af863114629 400 code = sendBasicCommand("ATE1", 1000);
sgodinez 13:0af863114629 401 echoMode = (code == OK) ? true : echoMode;
jengbrecht 0:563b70517320 402 }
sgodinez 13:0af863114629 403 return code;
jengbrecht 0:563b70517320 404 }
jengbrecht 0:563b70517320 405
jengbrecht 0:563b70517320 406 int Cellular::getSignalStrength()
jengbrecht 0:563b70517320 407 {
jengbrecht 0:563b70517320 408 string response = sendCommand("AT+CSQ", 1000);
jengbrecht 0:563b70517320 409 if (response.find("OK") == string::npos) {
jengbrecht 0:563b70517320 410 return -1;
jengbrecht 0:563b70517320 411 }
jengbrecht 0:563b70517320 412 int start = response.find(':');
jengbrecht 0:563b70517320 413 int stop = response.find(',', start);
jengbrecht 0:563b70517320 414 string signal = response.substr(start + 2, stop - start - 2);
jengbrecht 0:563b70517320 415 int value;
jengbrecht 0:563b70517320 416 sscanf(signal.c_str(), "%d", &value);
jengbrecht 0:563b70517320 417 return value;
jengbrecht 0:563b70517320 418 }
jengbrecht 0:563b70517320 419
sgodinez 5:93e889a5abc6 420 std::string Cellular::getPhoneNumber() {
sgodinez 5:93e889a5abc6 421 return "unknown";
sgodinez 5:93e889a5abc6 422 }
sgodinez 5:93e889a5abc6 423
jengbrecht 0:563b70517320 424 Cellular::Registration Cellular::getRegistration()
jengbrecht 0:563b70517320 425 {
jengbrecht 0:563b70517320 426 string response = sendCommand("AT+CREG?", 1000);
jengbrecht 0:563b70517320 427 if (response.find("OK") == string::npos) {
jengbrecht 0:563b70517320 428 return UNKNOWN;
jengbrecht 0:563b70517320 429 }
jengbrecht 0:563b70517320 430 int start = response.find(',');
jengbrecht 0:563b70517320 431 int stop = response.find(' ', start);
jengbrecht 0:563b70517320 432 string regStat = response.substr(start + 1, stop - start - 1);
jengbrecht 0:563b70517320 433 int value;
jengbrecht 0:563b70517320 434 sscanf(regStat.c_str(), "%d", &value);
jengbrecht 0:563b70517320 435 switch (value) {
jengbrecht 0:563b70517320 436 case 0:
jengbrecht 0:563b70517320 437 return NOT_REGISTERED;
jengbrecht 0:563b70517320 438 case 1:
jengbrecht 0:563b70517320 439 return REGISTERED;
jengbrecht 0:563b70517320 440 case 2:
jengbrecht 0:563b70517320 441 return SEARCHING;
jengbrecht 0:563b70517320 442 case 3:
jengbrecht 0:563b70517320 443 return DENIED;
jengbrecht 0:563b70517320 444 case 4:
jengbrecht 0:563b70517320 445 return UNKNOWN;
jengbrecht 0:563b70517320 446 case 5:
jengbrecht 0:563b70517320 447 return ROAMING;
jengbrecht 0:563b70517320 448 }
sgodinez 4:6561c9128c6f 449 return UNKNOWN;
jengbrecht 0:563b70517320 450 }
jengbrecht 0:563b70517320 451
jengbrecht 0:563b70517320 452 Cellular::Code Cellular::sendBasicCommand(string command, int timeoutMillis, ESC_CHAR esc)
jengbrecht 0:563b70517320 453 {
sgodinez 17:2d7c4ea7491b 454 if(socketOpened) {
sgodinez 17:2d7c4ea7491b 455 printf("[ERROR] socket is open. Can not send AT commands\r\n");
sgodinez 17:2d7c4ea7491b 456 return ERROR;
sgodinez 17:2d7c4ea7491b 457 }
sgodinez 17:2d7c4ea7491b 458
jengbrecht 0:563b70517320 459 string response = sendCommand(command, timeoutMillis, esc);
jengbrecht 0:563b70517320 460 if (response.size() == 0) {
jengbrecht 0:563b70517320 461 return NO_RESPONSE;
jengbrecht 0:563b70517320 462 } else if (response.find("OK") != string::npos) {
jengbrecht 0:563b70517320 463 return OK;
jengbrecht 0:563b70517320 464 } else if (response.find("ERROR") != string::npos) {
jengbrecht 0:563b70517320 465 return ERROR;
jengbrecht 0:563b70517320 466 } else {
jengbrecht 0:563b70517320 467 return FAILURE;
jengbrecht 0:563b70517320 468 }
jengbrecht 0:563b70517320 469 }
jengbrecht 0:563b70517320 470
sgodinez 11:134435d8a2d5 471 Cellular::Code Cellular::setApn(const std::string& apn) {
sgodinez 11:134435d8a2d5 472 Code code = sendBasicCommand("AT#APNSERV=\"" + apn + "\"", 1000);
sgodinez 11:134435d8a2d5 473 if (code != OK) {
sgodinez 11:134435d8a2d5 474 return code;
sgodinez 11:134435d8a2d5 475 }
sgodinez 11:134435d8a2d5 476 this->apn = apn;
sgodinez 11:134435d8a2d5 477 return code;
sgodinez 11:134435d8a2d5 478 }
sgodinez 11:134435d8a2d5 479
jengbrecht 27:8e6188cbcfd4 480 Cellular::Code Cellular::setDns(const std::string& address) {
sgodinez 12:40ac31a09132 481 return FAILURE;
sgodinez 11:134435d8a2d5 482 }
sgodinez 11:134435d8a2d5 483
jengbrecht 23:bc6f98a1eb22 484 bool Cellular::ping(const std::string& address) {
jengbrecht 23:bc6f98a1eb22 485 char buffer[256] = {0};
jengbrecht 23:bc6f98a1eb22 486 Code code;
jengbrecht 23:bc6f98a1eb22 487
jengbrecht 23:bc6f98a1eb22 488 code = sendBasicCommand("AT#PINGREMOTE=\"" + address + "\"", 1000);
jengbrecht 23:bc6f98a1eb22 489 if (code != OK) {
jengbrecht 23:bc6f98a1eb22 490 return false;
jengbrecht 23:bc6f98a1eb22 491 }
jengbrecht 23:bc6f98a1eb22 492
jengbrecht 23:bc6f98a1eb22 493 sprintf(buffer, "AT#PINGNUM=%d", 1);
jengbrecht 23:bc6f98a1eb22 494 code = sendBasicCommand(buffer , 1000);
jengbrecht 23:bc6f98a1eb22 495 if (code != OK) {
jengbrecht 23:bc6f98a1eb22 496 return false;
jengbrecht 23:bc6f98a1eb22 497 }
jengbrecht 23:bc6f98a1eb22 498
jengbrecht 23:bc6f98a1eb22 499 sprintf(buffer, "AT#PINGDELAY=%d", PINGDELAY);
jengbrecht 23:bc6f98a1eb22 500 code = sendBasicCommand(buffer , 1000);
jengbrecht 23:bc6f98a1eb22 501 if (code != OK) {
jengbrecht 23:bc6f98a1eb22 502 return false;
jengbrecht 23:bc6f98a1eb22 503 }
jengbrecht 23:bc6f98a1eb22 504
jengbrecht 23:bc6f98a1eb22 505 std::string response;
jengbrecht 23:bc6f98a1eb22 506 for (int i = 0; i < PINGNUM; i++) {
jengbrecht 23:bc6f98a1eb22 507 response = sendCommand("AT#PING", PINGDELAY * 1000);
jengbrecht 23:bc6f98a1eb22 508 if (response.find("alive") != std::string::npos) {
jengbrecht 23:bc6f98a1eb22 509 return true;
jengbrecht 23:bc6f98a1eb22 510 }
jengbrecht 23:bc6f98a1eb22 511 }
jengbrecht 23:bc6f98a1eb22 512 return false;
jengbrecht 23:bc6f98a1eb22 513 }
jengbrecht 23:bc6f98a1eb22 514
sgodinez 17:2d7c4ea7491b 515 Cellular::Code Cellular::setSocketCloseable(bool enabled) {
sgodinez 17:2d7c4ea7491b 516 if(socketCloseable == enabled) {
sgodinez 17:2d7c4ea7491b 517 return OK;
sgodinez 17:2d7c4ea7491b 518 }
sgodinez 17:2d7c4ea7491b 519
sgodinez 17:2d7c4ea7491b 520 if(socketOpened) {
sgodinez 17:2d7c4ea7491b 521 printf("[ERROR] socket is already opened. Can not set closeable\r\n");
sgodinez 17:2d7c4ea7491b 522 return ERROR;
sgodinez 17:2d7c4ea7491b 523 }
sgodinez 17:2d7c4ea7491b 524
sgodinez 17:2d7c4ea7491b 525 socketCloseable = enabled;
sgodinez 17:2d7c4ea7491b 526
sgodinez 17:2d7c4ea7491b 527 return OK;
sgodinez 17:2d7c4ea7491b 528 }
sgodinez 17:2d7c4ea7491b 529
sgodinez 4:6561c9128c6f 530 Cellular::Code Cellular::sendSMS(const Sms& sms) {
sgodinez 4:6561c9128c6f 531 return sendSMS(sms.phoneNumber, sms.message);
sgodinez 4:6561c9128c6f 532 }
sgodinez 4:6561c9128c6f 533
sgodinez 4:6561c9128c6f 534 Cellular::Code Cellular::sendSMS(const std::string& phoneNumber, const std::string& message)
sgodinez 17:2d7c4ea7491b 535 {
jengbrecht 0:563b70517320 536 Code code = sendBasicCommand("AT+CMGF=1", 1000);
jengbrecht 0:563b70517320 537 if (code != OK) {
jengbrecht 0:563b70517320 538 return code;
jengbrecht 0:563b70517320 539 }
jengbrecht 0:563b70517320 540 string cmd = "AT+CMGS=\"+";
jengbrecht 0:563b70517320 541 cmd.append(phoneNumber);
jengbrecht 0:563b70517320 542 cmd.append("\"");
jengbrecht 0:563b70517320 543 string response1 = sendCommand(cmd, 1000);
jengbrecht 0:563b70517320 544 if (response1.find('>') == string::npos) {
jengbrecht 0:563b70517320 545 return NO_RESPONSE;
jengbrecht 0:563b70517320 546 }
jengbrecht 0:563b70517320 547 wait(.2);
jengbrecht 0:563b70517320 548 string response2 = sendCommand(message, 4000, CTRL_Z);
sgodinez 17:2d7c4ea7491b 549 printf("SMS Response: %s\r\n", response2.c_str());
jengbrecht 0:563b70517320 550 if (response2.find("+CMGS:") == string::npos) {
jengbrecht 0:563b70517320 551 return FAILURE;
jengbrecht 0:563b70517320 552 }
jengbrecht 0:563b70517320 553 return OK;
jengbrecht 0:563b70517320 554 }
jengbrecht 0:563b70517320 555
sgodinez 4:6561c9128c6f 556 std::vector<Cellular::Sms> Cellular::getReceivedSms() {
sgodinez 9:5b12c5a8dde4 557 int smsNumber = 0;
sgodinez 4:6561c9128c6f 558 std::vector<Sms> vSms;
sgodinez 4:6561c9128c6f 559 std::string received = sendCommand("AT+CMGL=\"ALL\"", 4000);
sgodinez 5:93e889a5abc6 560 size_t pos = received.find("+CMGL: ");
sgodinez 4:6561c9128c6f 561
sgodinez 5:93e889a5abc6 562 while (pos != std::string::npos) {
sgodinez 4:6561c9128c6f 563 Cellular::Sms sms;
sgodinez 4:6561c9128c6f 564 std::string line(Text::getLine(received, pos, pos));
sgodinez 17:2d7c4ea7491b 565 //printf("[DEBUG] Top of SMS Parse Loop. LINE[%s]\r\n", line.c_str());
sgodinez 9:5b12c5a8dde4 566 if(line.find("+CMGL: ") == std::string::npos) {
sgodinez 4:6561c9128c6f 567 continue;
sgodinez 4:6561c9128c6f 568 }
sgodinez 4:6561c9128c6f 569
sgodinez 4:6561c9128c6f 570 //Start of SMS message
sgodinez 4:6561c9128c6f 571 std::vector<std::string> vSmsParts = Text::split(line, ',');
sgodinez 4:6561c9128c6f 572 if(vSmsParts.size() != 6) {
sgodinez 17:2d7c4ea7491b 573 printf("[WARNING] Expected 6 commas. SMS[%d] DATA[%s]. Continuing ...\r\n", smsNumber, line.c_str());
sgodinez 4:6561c9128c6f 574 continue;
sgodinez 4:6561c9128c6f 575 }
sgodinez 4:6561c9128c6f 576
sgodinez 4:6561c9128c6f 577 sms.phoneNumber = vSmsParts[2];
sgodinez 4:6561c9128c6f 578 sms.timestamp = vSmsParts[4] + ", " + vSmsParts[5];
sgodinez 4:6561c9128c6f 579
sgodinez 8:3fe68d6130a8 580 if(pos == std::string::npos) {
sgodinez 17:2d7c4ea7491b 581 printf("[WARNING] Expected SMS body. SMS[%d]. Leaving ...\r\n", smsNumber);
sgodinez 8:3fe68d6130a8 582 break;
sgodinez 8:3fe68d6130a8 583 }
sgodinez 9:5b12c5a8dde4 584 //Check for the start of the next SMS message
sgodinez 9:5b12c5a8dde4 585 size_t bodyEnd = received.find("\r\n+CMGL: ", pos);
sgodinez 8:3fe68d6130a8 586 if(bodyEnd == std::string::npos) {
sgodinez 17:2d7c4ea7491b 587 //printf("[DEBUG] Parsing Last SMS. SMS[%d]\r\n", smsNumber);
sgodinez 9:5b12c5a8dde4 588 //This must be the last SMS message
sgodinez 9:5b12c5a8dde4 589 bodyEnd = received.find("\r\n\r\nOK", pos);
sgodinez 8:3fe68d6130a8 590 }
sgodinez 9:5b12c5a8dde4 591
sgodinez 9:5b12c5a8dde4 592 //Safety check that we found the boundary of this current SMS message
sgodinez 9:5b12c5a8dde4 593 if(bodyEnd != std::string::npos) {
sgodinez 9:5b12c5a8dde4 594 sms.message = received.substr(pos, bodyEnd - pos);
sgodinez 9:5b12c5a8dde4 595 } else {
sgodinez 8:3fe68d6130a8 596 sms.message = received.substr(pos);
sgodinez 17:2d7c4ea7491b 597 printf("[WARNING] Expected to find end of SMS list. SMS[%d] DATA[%s].\r\n", smsNumber, sms.message.c_str());
sgodinez 8:3fe68d6130a8 598 }
sgodinez 5:93e889a5abc6 599 vSms.push_back(sms);
sgodinez 4:6561c9128c6f 600 pos = bodyEnd;
sgodinez 17:2d7c4ea7491b 601 //printf("[DEBUG] Parsed SMS[%d]. Starting Next at position [%d]\r\n", smsNumber, pos);
sgodinez 9:5b12c5a8dde4 602 smsNumber++;
sgodinez 4:6561c9128c6f 603 }
sgodinez 17:2d7c4ea7491b 604 printf("Received %d SMS\r\n", smsNumber);
sgodinez 4:6561c9128c6f 605 return vSms;
sgodinez 4:6561c9128c6f 606 }
sgodinez 4:6561c9128c6f 607
sgodinez 4:6561c9128c6f 608 Cellular::Code Cellular::deleteOnlyReceivedReadSms() {
sgodinez 4:6561c9128c6f 609 return sendBasicCommand("AT+CMGD=1,1", 1000);
sgodinez 4:6561c9128c6f 610 }
sgodinez 4:6561c9128c6f 611
sgodinez 4:6561c9128c6f 612 Cellular::Code Cellular::deleteAllReceivedSms() {
sgodinez 4:6561c9128c6f 613 return sendBasicCommand("AT+CMGD=1,4", 1000);
sgodinez 4:6561c9128c6f 614 }
sgodinez 4:6561c9128c6f 615
sgodinez 4:6561c9128c6f 616
jengbrecht 0:563b70517320 617 string Cellular::sendCommand(string command, int timeoutMillis, ESC_CHAR esc)
jengbrecht 0:563b70517320 618 {
sgodinez 19:38794784e009 619 if(io == NULL) {
sgodinez 19:38794784e009 620 printf("[ERROR] MTSBufferedIO not set\r\n");
sgodinez 19:38794784e009 621 return "";
sgodinez 19:38794784e009 622 }
sgodinez 17:2d7c4ea7491b 623 if(socketOpened) {
sgodinez 17:2d7c4ea7491b 624 printf("[ERROR] socket is open. Can not send AT commands\r\n");
sgodinez 17:2d7c4ea7491b 625 return "";
sgodinez 17:2d7c4ea7491b 626 }
sgodinez 17:2d7c4ea7491b 627
jengbrecht 0:563b70517320 628 int size = command.size() + 1;
jengbrecht 0:563b70517320 629 char cmd[size];
jengbrecht 0:563b70517320 630 strcpy(cmd, command.c_str());
jengbrecht 0:563b70517320 631 if (esc == CR) {
jengbrecht 0:563b70517320 632 cmd[size -1] = '\r';
jengbrecht 0:563b70517320 633 } else if (esc == CTRL_Z) {
jengbrecht 0:563b70517320 634 cmd[size -1] = 0x1A;
sgodinez 13:0af863114629 635 } else if(esc == NONE) {
sgodinez 13:0af863114629 636 cmd[size -1] = '\0';
jengbrecht 0:563b70517320 637 }
jengbrecht 0:563b70517320 638
sgodinez 19:38794784e009 639 io->rxClear();
sgodinez 19:38794784e009 640 io->txClear();
sgodinez 8:3fe68d6130a8 641 std::string result;
sgodinez 19:38794784e009 642 int status = io->write(cmd, size);
jengbrecht 36:bb6b293c7495 643 int available = io->readable();
jengbrecht 0:563b70517320 644 int previous = -1;
jengbrecht 0:563b70517320 645 int timer = 0;
sgodinez 8:3fe68d6130a8 646 char tmp[256];
sgodinez 8:3fe68d6130a8 647 tmp[255] = 0;
sgodinez 13:0af863114629 648 bool started = !echoMode;
sgodinez 13:0af863114629 649 bool done = false;
sgodinez 8:3fe68d6130a8 650 do {
jengbrecht 0:563b70517320 651 wait(.1);
jengbrecht 0:563b70517320 652 timer = timer + 100;
jengbrecht 0:563b70517320 653 previous = available;
sgodinez 19:38794784e009 654 available = io->rxAvailable();
sgodinez 8:3fe68d6130a8 655
sgodinez 19:38794784e009 656 int size = io->read(tmp,255); //1 less than allocated
sgodinez 8:3fe68d6130a8 657 if(size > 0) {
sgodinez 8:3fe68d6130a8 658 result.append(tmp, size);
sgodinez 8:3fe68d6130a8 659 }
sgodinez 13:0af863114629 660
sgodinez 13:0af863114629 661 if(!started) {
sgodinez 13:0af863114629 662 //In Echo Mode (Command will have echo'd + 2 characters for \r\n)
sgodinez 13:0af863114629 663 if(result.size() > command.size() + 2) {
sgodinez 13:0af863114629 664 started = true;
sgodinez 13:0af863114629 665 }
sgodinez 13:0af863114629 666 } else {
sgodinez 13:0af863114629 667 done = (available == previous);
sgodinez 13:0af863114629 668 }
sgodinez 13:0af863114629 669 if(timer >= timeoutMillis) {
sgodinez 17:2d7c4ea7491b 670 printf("[WARNING] sendCommand timed out after %d milliseconds\r\n", timeoutMillis);
sgodinez 13:0af863114629 671 done = true;
sgodinez 13:0af863114629 672 }
sgodinez 13:0af863114629 673 } while (!done);
sgodinez 8:3fe68d6130a8 674
sgodinez 8:3fe68d6130a8 675 return result;
jengbrecht 0:563b70517320 676 }
jengbrecht 0:563b70517320 677
jengbrecht 0:563b70517320 678 #endif /* CELLULAR_CPP */