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