Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of MTS-Cellular by
Cellular/UIP.cpp
- Committer:
- Mike Fiore
- Date:
- 2014-05-20
- Revision:
- 4:1f63354b8d1b
- Parent:
- 3:04046eebaef5
- Child:
- 7:0ee8e69a3e9c
File content as of revision 4:1f63354b8d1b:
#include "mbed.h" #include "UIP.h" #include "MTSText.h" #include "MTSLog.h" #include "CellUtils.h" using namespace mts; UIP::UIP() : dcd(NULL), dtr(NULL), resetLine(NULL) { io = NULL; echoMode = true; pppConnected = false; mode = TCP; socketOpened = false; socketCloseable = true; local_port = 0; local_address = ""; host_port = 0; } UIP::~UIP() { if (dtr != NULL) { dtr->write(1); } delete dcd; delete dtr; delete resetLine; } bool UIP::init(MTSBufferedIO* io) { if (io == NULL) { return false; } this->io = io; test(); // Reset radio to make sure it's in a good state and wait for it to come back reset(); test(); return SUCCESS; } bool UIP::configureSignals(PinName DCD, PinName DTR, PinName RESET) { //Set DCD - The radio will raise and lower this line if (DCD != NC) { dcd = new DigitalIn(DCD); } /* Set DTR - This line should be lowered when we want to talk to the radio and raised when we're done * for now we will lower it in the constructor and raise it in the destructor. */ if (DTR != NC) { dtr = new DigitalOut(DTR); dtr->write(0); } //Set RESET - Set the hardware reset line to the radio if (RESET != NC) { resetLine = new DigitalOut(RESET); } return true; } bool UIP::connect() { //Check if socket is open if(socketOpened) { return true; } //Check if already connected if(isConnected()) { return true; } Timer tmr; //Check Registration: AT+CREG? == 0,1 tmr.start(); do { Registration registration = getRegistration(); if(registration != REGISTERED) { logWarning("Not Registered [%d] ... waiting", (int)registration); wait(1); } else { break; } } while(tmr.read() < 30); //Check RSSI: AT+CSQ tmr.reset(); do { int rssi = getSignalStrength(); logDebug("Signal strength: %d", rssi); if(rssi == 99) { logWarning("No Signal ... waiting"); wait(1); } else { break; } } while(tmr.read() < 30); //AT#CONNECTIONSTART: Make a PPP connection logDebug("Making PPP Connection Attempt. APN[%s]", apn.c_str()); std::string pppResult = sendCommand("AT#CONNECTIONSTART", 120000); std::vector<std::string> parts = Text::split(pppResult, "\r\n"); if(pppResult.find("Ok_Info_GprsActivation") != std::string::npos) { if(parts.size() >= 2) { local_address = parts[1]; } logInfo("PPP Connection Established: IP[%s]", local_address.c_str()); pppConnected = true; } else { pppConnected = false; } return pppConnected; } void UIP::disconnect() { //AT#CONNECTIONSTOP: Close a PPP connection logDebug("Closing PPP Connection"); if(socketOpened) { close(); } Code code = sendBasicCommand("AT#CONNECTIONSTOP", 10000); if(code == SUCCESS) { logDebug("Successfully closed PPP Connection"); } else { logError("Closing PPP Connection [%d]. Continuing ...", (int)code); } pppConnected = false; } bool UIP::isConnected() { //1) Check if APN was set if(apn.size() == 0) { logDebug("APN is not set"); return false; } //1) Check that we do not have a live connection up if(socketOpened) { logDebug("Socket is opened"); return true; } //2) Query the radio std::string result = sendCommand("AT#VSTATE", 3000); if(result.find("CONNECTED") != std::string::npos) { if(pppConnected == false) { logWarning("Internal PPP state tracking differs from radio (DISCONNECTED:CONNECTED)"); } pppConnected = true; } else { if(pppConnected == true) { //Find out what state is size_t pos = result.find("STATE:"); if(pos != std::string::npos) { result = Text::getLine(result, pos + sizeof("STATE:"), pos); logWarning("Internal PPP state tracking differs from radio (CONNECTED:%s)", result.c_str()); } else { logError("Unable to parse radio state: [%s]", result.c_str()); } } pppConnected = false; } return pppConnected; } bool UIP::bind(unsigned int port) { if(socketOpened) { logError("socket is open. Can not set local port"); return false; } if(port > 65535) { logError("port out of range (0-65535)"); return false; } local_port = port; return true; } bool UIP::open(const std::string& address, unsigned int port, Mode mode) { char buffer[256] = {0}; Code portCode, addressCode; //1) Check that we do not have a live connection up if(socketOpened) { //Check that the address, port, and mode match if(host_address != address || host_port != port || this->mode != mode) { if(this->mode == TCP) { logError("TCP socket already opened [%s:%d]", host_address.c_str(), host_port); } else { logError("UDP socket already opened [%s:%d]", host_address.c_str(), host_port); } return false; } logDebug("Socket already opened"); return true; } //2) Check Parameters if(port > 65535) { logError("port out of range (0-65535)"); return false; } //3) Check PPP connection if(!isConnected()) { logError("PPP not established. Attempting to connect"); if(!connect()) { logError("PPP connection failed"); return false; } else { logDebug("PPP connection established"); } } //Set Local Port if(local_port != 0) { //Attempt to set local port sprintf(buffer, "AT#OUTPORT=%d", local_port); Code code = sendBasicCommand(buffer, 1000); if(code != SUCCESS) { logWarning("Unable to set local port (%d) [%d]", local_port, (int) code); } } //Set TCP/UDP parameters if(mode == TCP) { if(socketCloseable) { Code code = sendBasicCommand("AT#DLEMODE=1,1", 1000); if(code != SUCCESS) { logWarning("Unable to set socket closeable [%d]", (int) code); } } sprintf(buffer, "AT#TCPPORT=1,%d", port); portCode = sendBasicCommand(buffer, 1000); addressCode = sendBasicCommand("AT#TCPSERV=1,\"" + address + "\"", 1000); } else { if(socketCloseable) { Code code = sendBasicCommand("AT#UDPDLEMODE=1", 1000); if(code != SUCCESS) { logWarning("Unable to set socket closeable [%d]", (int) code); } } sprintf(buffer, "AT#UDPPORT=%d", port); portCode = sendBasicCommand(buffer, 1000); addressCode = sendBasicCommand("AT#UDPSERV=\"" + address + "\"", 1000); } if(portCode == SUCCESS) { host_port = port; } else { logError("Host port could not be set"); } if(addressCode == SUCCESS) { host_address = address; } else { logError("Host address could not be set"); } // Try and Connect std::string sMode; std::string sOpenSocketCmd; if(mode == TCP) { sOpenSocketCmd = "AT#OTCP=1"; sMode = "TCP"; } else { sOpenSocketCmd = "AT#OUDP"; sMode = "UDP"; } string response = sendCommand(sOpenSocketCmd, 30000); if (response.find("Ok_Info_WaitingForData") != string::npos) { logInfo("Opened %s Socket [%s:%d]", sMode.c_str(), address.c_str(), port); socketOpened = true; } else { logWarning("Unable to open %s Socket [%s:%d]", sMode.c_str(), address.c_str(), port); socketOpened = false; } return socketOpened; } bool UIP::isOpen() { if(io->readable()) { logDebug("Assuming open, data available to read.\n\r"); return true; } return socketOpened; } bool UIP::close() { if(io == NULL) { logError("MTSBufferedIO not set"); return false; } if(!socketOpened) { logWarning("Socket close() called, but socket was not open"); return true; } if(!socketCloseable) { logError("Socket is not closeable"); return false; } if(io->write(ETX, 1000) != 1) { logError("Timed out attempting to close socket"); return false; } Timer tmr; int counter = 0; char tmp[256]; tmr.start(); do { if(socketOpened == false) { break; } read(tmp, 256, 1000); } while(counter++ < 10); io->rxClear(); io->txClear(); socketOpened = false; return true; } int UIP::read(char* data, int max, int timeout) { if(io == NULL) { logError("MTSBufferedIO not set"); return -1; } //Check that nothing is in the rx buffer if(!socketOpened && !io->readable()) { logError("Socket is not open"); return -1; } int bytesRead = 0; if(timeout >= 0) { bytesRead = io->read(data, max, static_cast<unsigned int>(timeout)); } else { bytesRead = io->read(data, max); } if(bytesRead > 0 && socketCloseable) { //Remove escape characters int index = 0; bool escapeFlag = false; for(int i = 0; i < bytesRead; i++) { if(data[i] == DLE || data[i] == ETX) { if(escapeFlag == true) { //This character has been escaped escapeFlag = false; } else if(data[bytesRead] == DLE) { //Found escape character escapeFlag = true; continue; } else { //ETX sent without escape -> Socket closed logInfo("Read ETX character without DLE escape. Socket closed"); socketOpened = false; continue; } } if(index != i) { data[index] = data[i]; } index++; } bytesRead = index; } //Scan for socket closed message for(size_t i = 0; i < bytesRead; i++) { if(data[i] == 'O') { if(strstr(&data[i], "Ok_Info_SocketClosed")) { logInfo("Found socket closed message. Socket closed"); //Close socket and Cut Off End of Message socketOpened = false; data[i] = '\0'; bytesRead = i; break; } } } return bytesRead; } int UIP::write(const char* data, int length, int timeout) { if(io == NULL) { logError("MTSBufferedIO not set"); return -1; } if(!socketOpened) { logError("Socket is not open"); return -1; } //In order to avoid allocating another buffer, capture indices of //characters to escape during write int specialWritten = 0; std::vector<int> vSpecial; if(socketCloseable) { for(int i = 0; i < length; i++) { if(data[i] == ETX || data[i] == DLE) { //Push back index of special characters vSpecial.push_back(i); } } } int bytesWritten = 0; if(timeout >= 0) { Timer tmr; tmr.start(); do { int available = io->writeable(); if (available > 0) { if(specialWritten < vSpecial.size()) { //Check if current index is at a special character if(bytesWritten == vSpecial[specialWritten]) { if(available < 2) { //Requires at least two bytes of space wait(0.05); continue; } //Ready to write special character if(io->write(DLE)) { specialWritten++; if(io->write(data[bytesWritten])) { bytesWritten++; } } else { //Unable to write escape character, try again next round wait(0.05); } } else { //We want to write all the way up to the next special character int relativeIndex = vSpecial[specialWritten] - bytesWritten; int size = MIN(available, relativeIndex); bytesWritten += io->write(&data[bytesWritten], size); } } else { int size = MIN(available, length - bytesWritten); bytesWritten += io->write(&data[bytesWritten], size); } } else { wait(0.05); } } while (tmr.read_ms() <= timeout && bytesWritten < length); } else { for(int i = 0; i < vSpecial.size(); i++) { //Write up to the special character, then write the special character int size = vSpecial[i] - bytesWritten; int currentWritten = io->write(&data[bytesWritten], size); bytesWritten += currentWritten; if(currentWritten != size) { //Failed to write up to the special character. return bytesWritten; } if(io->write(DLE) && io->write(data[bytesWritten])) { bytesWritten++; } else { //Failed to write the special character. return bytesWritten; } } bytesWritten = io->write(&data[bytesWritten], length - bytesWritten); } return bytesWritten; } unsigned int UIP::readable() { if(io == NULL) { logWarning("MTSBufferedIO not set"); return 0; } if(!socketOpened && !io->readable()) { logWarning("Socket is not open"); return 0; } return io->readable(); } unsigned int UIP::writeable() { if(io == NULL) { logWarning("MTSBufferedIO not set"); return 0; } if(!socketOpened) { logWarning("Socket is not open"); return 0; } return io->writeable(); } bool UIP::setDeviceIP(std::string address) { if (address.compare("DHCP") == 0) { return true; } else { logWarning("Radio does not support static IPs, using DHCP.\n\r"); return false; } } void UIP::reset() { disconnect(); Code code = sendBasicCommand("AT#RESET=0", 10000); if(code != SUCCESS) { logError("Socket Modem did not accept RESET command\n\r"); } else { logWarning("Socket Modem is resetting, allow 30 seconds for it to come back\n\r"); } } std::string UIP::getDeviceIP() { return local_address; } Code UIP::echo(bool state) { Code code; if (state) { code = sendBasicCommand("ATE0", 1000); echoMode = (code == SUCCESS) ? false : echoMode; } else { code = sendBasicCommand("ATE1", 1000); echoMode = (code == SUCCESS) ? true : echoMode; } return code; } Code UIP::setApn(const std::string& apn) { Code code = sendBasicCommand("AT#APNSERV=\"" + apn + "\"", 1000); if (code != SUCCESS) { return code; } this->apn = apn; return code; } Code UIP::setDns(const std::string& primary, const std::string& secondary) { return sendBasicCommand("AT#DNS=1," + primary + "," + secondary, 1000); } bool UIP::ping(const std::string& address) { char buffer[256] = {0}; Code code; code = sendBasicCommand("AT#PINGREMOTE=\"" + address + "\"", 1000); if (code != SUCCESS) { return false; } sprintf(buffer, "AT#PINGNUM=%d", 1); code = sendBasicCommand(buffer , 1000); if (code != SUCCESS) { return false; } sprintf(buffer, "AT#PINGDELAY=%d", PINGDELAY); code = sendBasicCommand(buffer , 1000); if (code != SUCCESS) { return false; } std::string response; for (int i = 0; i < PINGNUM; i++) { response = sendCommand("AT#PING", PINGDELAY * 1000); if (response.find("alive") != std::string::npos) { return true; } } return false; } Code UIP::setSocketCloseable(bool enabled) { if(socketCloseable == enabled) { return SUCCESS; } if(socketOpened) { logError("socket is already opened. Can not set closeable"); return ERROR; } socketCloseable = enabled; return SUCCESS; } Code UIP::sendBasicCommand(const std::string& command, unsigned int timeoutMillis, char esc) { if(socketOpened) { logError("socket is open. Can not send AT commands"); return ERROR; } string response = sendCommand(command, timeoutMillis, esc); if (response.size() == 0) { return NO_RESPONSE; } else if (response.find("OK") != string::npos) { return SUCCESS; } else if (response.find("ERROR") != string::npos) { return ERROR; } else { return FAILURE; } } string UIP::sendCommand(const std::string& command, unsigned int timeoutMillis, char esc) { if(io == NULL) { logError("MTSBufferedIO not set"); return ""; } if(socketOpened) { logError("socket is open. Can not send AT commands"); return ""; } io->rxClear(); io->txClear(); std::string result; //Attempt to write command if(io->write(command.data(), command.size(), timeoutMillis) != command.size()) { //Failed to write command if (command != "AT" && command != "at") { logError("failed to send command to radio within %d milliseconds", timeoutMillis); } return ""; } //Send Escape Character if (esc != 0x00) { if(io->write(esc, timeoutMillis) != 1) { if (command != "AT" && command != "at") { logError("failed to send character '%c' (0x%02X) to radio within %d milliseconds", esc, esc, timeoutMillis); } return ""; } } int timer = 0; size_t previous = 0; char tmp[256]; tmp[255] = 0; bool started = !echoMode; bool done = false; do { wait(0.1); timer += 100; previous = result.size(); //Make a non-blocking read call by passing timeout of zero int size = io->read(tmp,255,0); //1 less than allocated (timeout is instant) if(size > 0) { result.append(tmp, size); } if(!started) { //In Echo Mode (Command will have echo'd + 2 characters for \r\n) if(result.size() > command.size() + 2) { started = true; } } else { done = (result.size() == previous); } if(timer >= timeoutMillis) { if (command != "AT" && command != "at") { logWarning("sendCommand [%s] timed out after %d milliseconds", command.c_str(), timeoutMillis); } done = true; } } while (!done); return result; } Code UIP::sendSMS(const Sms& sms) { return sendSMS(sms.phoneNumber, sms.message); } Code UIP::sendSMS(const std::string& phoneNumber, const std::string& message) { Code code = sendBasicCommand("AT+CMGF=1", 1000); if (code != SUCCESS) { return code; } string cmd = "AT+CMGS=\"+"; cmd.append(phoneNumber); cmd.append("\""); string response1 = sendCommand(cmd, 1000); if (response1.find('>') == string::npos) { return NO_RESPONSE; } wait(.2); string response2 = sendCommand(message, 4000, CTRL_Z); logInfo("SMS Response: %s", response2.c_str()); if (response2.find("+CMGS:") == string::npos) { return FAILURE; } return SUCCESS; } std::vector<Cellular::Sms> UIP::getReceivedSms() { int smsNumber = 0; std::vector<Sms> vSms; std::string received = sendCommand("AT+CMGL=\"ALL\"", 4000); size_t pos = received.find("+CMGL: "); while (pos != std::string::npos) { Cellular::Sms sms; std::string line(Text::getLine(received, pos, pos)); if(line.find("+CMGL: ") == std::string::npos) { continue; } //Start of SMS message std::vector<std::string> vSmsParts = Text::split(line, ','); if(vSmsParts.size() != 6) { logWarning("Expected 6 commas. SMS[%d] DATA[%s]. Continuing ...", smsNumber, line.c_str()); continue; } sms.phoneNumber = vSmsParts[2]; sms.timestamp = vSmsParts[4] + ", " + vSmsParts[5]; if(pos == std::string::npos) { logWarning("Expected SMS body. SMS[%d]. Leaving ...", smsNumber); break; } //Check for the start of the next SMS message size_t bodyEnd = received.find("\r\n+CMGL: ", pos); if(bodyEnd == std::string::npos) { //This must be the last SMS message bodyEnd = received.find("\r\n\r\nOK", pos); } //Safety check that we found the boundary of this current SMS message if(bodyEnd != std::string::npos) { sms.message = received.substr(pos, bodyEnd - pos); } else { sms.message = received.substr(pos); logWarning("Expected to find end of SMS list. SMS[%d] DATA[%s].", smsNumber, sms.message.c_str()); } vSms.push_back(sms); pos = bodyEnd; smsNumber++; } logInfo("Received %d SMS", smsNumber); return vSms; } Code UIP::deleteOnlyReceivedReadSms() { return sendBasicCommand("AT+CMGD=1,1", 1000); } Code UIP::deleteAllReceivedSms() { return sendBasicCommand("AT+CMGD=1,4", 1000); }