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