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
Diff: cellular/Cellular.cpp
- Revision:
- 82:5aa75004e553
- Parent:
- 71:82205735732b
- Child:
- 85:b17ad6781c5b
- Child:
- 87:5db6c084adc7
--- a/cellular/Cellular.cpp Fri Dec 27 15:19:49 2013 +0000 +++ b/cellular/Cellular.cpp Fri Dec 27 15:41:24 2013 +0000 @@ -9,7 +9,8 @@ Cellular* Cellular::instance = NULL; -Cellular* Cellular::getInstance() { +Cellular* Cellular::getInstance() +{ if(instance == NULL) { instance = new Cellular(NULL); } @@ -17,109 +18,118 @@ } -bool Cellular::init(MTSBufferedIO* io) { +bool Cellular::init(MTSBufferedIO* io, PinName DCD, PinName DTR) +{ if (io == NULL) { return false; } + if (DCD != NC) { + // the radio will raise and lower this line + dcd = new DigitalIn(DCD); //PTA4 - KL46 + } + if (DTR != NC) { + dtr = new DigitalOut(DTR); //PTC9 - KL46 + /* 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 + */ + dtr->write(0); + } instance->io = io; return true; } -Cellular::Cellular(MTSBufferedIO* io) -: io(io) -, echoMode(true) -, pppConnected(false) -, mode(TCP) -, socketOpened(false) -, socketCloseable(true) -, local_port(0) -, host_port(0) +Cellular::Cellular(MTSBufferedIO* io) + : io(io) + , echoMode(true) + , pppConnected(false) + , mode(TCP) + , socketOpened(false) + , socketCloseable(true) + , local_port(0) + , host_port(0) { - // the radio's DCD signal is mapped to PTA4 - // the radio will raise and lower this line - dcd = new DigitalIn(PTA4); - // the DTR line to the radio is mapped PTC9 - // 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 - dtr = new DigitalOut(PTC9); - dtr->write(0); } Cellular::~Cellular() { - dtr->write(1); + if (dtr != NULL) { + dtr->write(1); + } } -bool Cellular::connect() { +bool Cellular::connect() +{ //Check if socket is open if(socketOpened) { - return true; + return true; } - + //Run Test first to validate a good state if(isConnected()) { return true; } - - //Check RSSI: AT+CSQ + + //Check RSSI: AT+CSQ int rssi = getSignalStrength(); printf("[DEBUG] Signal strength: %d\r\n", rssi); - + //Check Registration: AT+CREG? == 0,1 Registration registration = getRegistration(); if(registration != REGISTERED) { - printf("[WARNING] Not Registered [%d]\r\n", (int)registration); + printf("[WARNING] Not Registered [%d]\r\n", (int)registration); } - + //AT#CONNECTIONSTART: Make a PPP connection printf("[DEBUG] Making PPP Connection Attempt. APN[%s]\r\n", apn.c_str()); std::string pppResult = sendCommand("AT#CONNECTIONSTART", 120000); std::vector<std::string> parts = Text::split(pppResult, "\r\n"); - + //printf("[DEBUG] PPP CONNECT RESULT [%s]\r\n", pppResult.c_str()); // for(uint32_t i = 0; i < parts.size(); i++) { -// printf("[%d] [%s]\r\n", i, parts[i].c_str()); +// printf("[%d] [%s]\r\n", i, parts[i].c_str()); // } - + if(pppResult.find("Ok_Info_GprsActivation") != std::string::npos) { if(parts.size() >= 2) { - local_address = parts[1]; + local_address = parts[1]; } printf("[INFO] PPP Connection Established: IP[%s]\r\n", local_address.c_str()); pppConnected = true; - + } else { - pppConnected = false; + pppConnected = false; } - + return pppConnected; } -void Cellular::disconnect() { +void Cellular::disconnect() +{ //AT#CONNECTIONSTOP: Close a PPP connection printf("[DEBUG] Closing PPP Connection\r\n"); - - if(socketOpened) { - close(); + + if(socketOpened) { + close(); } - + Code code = sendBasicCommand("AT#CONNECTIONSTOP", 10000); if(code == SUCCESS) { printf("[DEBUG] Successfully closed PPP Connection\r\n"); } else { - printf("[ERROR] Closing PPP Connection [%d]. Continuing ...\r\n", (int)code); + printf("[ERROR] Closing PPP Connection [%d]. Continuing ...\r\n", (int)code); } - + pppConnected = false; } -bool Cellular::isConnected() { +bool Cellular::isConnected() +{ //1) Check if APN was set if(apn.size() == 0) { printf("[DEBUG] APN is not set\r\n"); return false; } - + //1) Check that we do not have a live connection up if(socketOpened) { printf("[DEBUG] Socket is opened\r\n"); @@ -131,28 +141,30 @@ if(result.find("CONNECTED") != std::string::npos) { pppConnected = true; } - + return pppConnected; } -bool Cellular::bind(unsigned int port) { +bool Cellular::bind(unsigned int port) +{ if(socketOpened) { - printf("[ERROR] socket is open. Can not set local port\r\n"); + printf("[ERROR] socket is open. Can not set local port\r\n"); return false; } if(port > 65535) { - printf("[ERROR] port out of range (0-65535)\r\n"); + printf("[ERROR] port out of range (0-65535)\r\n"); return false; } local_port = port; return true; } -bool Cellular::open(const std::string& address, unsigned int port, Mode mode) { +bool Cellular::open(const std::string& address, unsigned int port, Mode mode) +{ char buffer[256] = {0}; Code portCode, addressCode; printf("[DEBUG] Attempting to Open Socket\r\n"); - + //1) Check that we do not have a live connection up if(socketOpened) { //Check that the address, port, and mode match @@ -164,18 +176,18 @@ } return false; } - + printf("[DEBUG] Socket already opened\r\n"); return true; } - + //2) Check Parameters if(port > 65535) { - printf("[ERROR] port out of range (0-65535)\r\n"); + printf("[ERROR] port out of range (0-65535)\r\n"); return false; } - - + + //3) Check PPP connection if(!isConnected()) { printf("[ERROR] PPP not established. Attempting to connect\r\n"); @@ -186,23 +198,23 @@ printf("[DEBUG] PPP connection established\r\n"); } } - + //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) { - printf("[WARNING] Unable to set local port (%d) [%d]\r\n", local_port, (int) code); + printf("[WARNING] Unable to set local port (%d) [%d]\r\n", local_port, (int) code); } } - + //Set TCP/UDP parameters if(mode == TCP) { if(socketCloseable) { Code code = sendBasicCommand("AT#DLEMODE=1,1", 1000); if(code != SUCCESS) { - printf("[WARNING] Unable to set socket closeable [%d]\r\n", (int) code); + printf("[WARNING] Unable to set socket closeable [%d]\r\n", (int) code); } } sprintf(buffer, "AT#TCPPORT=1,%d", port); @@ -212,28 +224,28 @@ if(socketCloseable) { Code code = sendBasicCommand("AT#UDPDLEMODE=1", 1000); if(code != SUCCESS) { - printf("[WARNING] Unable to set socket closeable [%d]\r\n", (int) code); + printf("[WARNING] Unable to set socket closeable [%d]\r\n", (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 { printf("[ERROR] Host port could not be set\r\n"); } - + if(addressCode == SUCCESS) { host_address = address; } else { printf("[ERROR] Host address could not be set\r\n"); } - - - + + + // Try and Connect std::string sMode; std::string sOpenSocketCmd; @@ -252,15 +264,17 @@ printf("[WARNING] Unable to open %s Socket [%s:%d]\r\n", sMode.c_str(), address.c_str(), port); socketOpened = false; } - + return socketOpened; } -bool Cellular::isOpen() { +bool Cellular::isOpen() +{ return socketOpened; } -bool Cellular::close() { +bool Cellular::close() +{ if(io == NULL) { printf("[ERROR] MTSBufferedIO not set\r\n"); return false; @@ -275,7 +289,7 @@ printf("[ERROR] Socket is not closeable\r\n"); return false; } - + Timer tmr; int timeout = 1000; int written = 0; @@ -284,7 +298,7 @@ written = io->write(ETX); if(written < 0) { printf("[ERROR] Failed to write to MTSBufferedIO\r\n"); - return false; + return false; } wait(0.05); } while(tmr.read_ms() <= timeout && written != 1); @@ -293,37 +307,38 @@ printf("[ERROR] Timed out attempting to close socket\r\n"); return false; } - + socketOpened = false; return true; } -int Cellular::read(char* data, int max, int timeout) { +int Cellular::read(char* data, int max, int timeout) +{ if(io == NULL) { printf("[ERROR] MTSBufferedIO not set\r\n"); return -1; } - - //Check that nothing is in the rx buffer + + //Check that nothing is in the rx buffer if(!socketOpened && !io->readable()) { printf("[ERROR] Socket is not open\r\n"); 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 + //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) { + if(data[i] == DLE || data[i] == ETX) { + if(escapeFlag == true) { //This character has been escaped escapeFlag = false; } else if(data[bytesRead] == DLE) { @@ -331,8 +346,8 @@ escapeFlag = true; continue; } else { - //ETX sent without escape -> Socket closed - printf("[INFO] Read ETX character without DLE escape. Socket closed\r\n"); + //ETX sent without escape -> Socket closed + printf("[INFO] Read ETX character without DLE escape. Socket closed\r\n"); socketOpened = false; continue; } @@ -345,12 +360,12 @@ } 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")) { - printf("[INFO] Found socket closed message. Socket closed\r\n"); + printf("[INFO] Found socket closed message. Socket closed\r\n"); //Close socket and Cut Off End of Message socketOpened = false; data[i] = '\0'; @@ -362,17 +377,18 @@ return bytesRead; } -int Cellular::write(const char* data, int length, int timeout) { +int Cellular::write(const char* data, int length, int timeout) +{ if(io == NULL) { printf("[ERROR] MTSBufferedIO not set\r\n"); return -1; } - + if(!socketOpened) { printf("[ERROR] Socket is not open\r\n"); return -1; } - + //In order to avoid allocating another buffer, capture indices of //characters to escape during write int specialWritten = 0; @@ -382,10 +398,10 @@ 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; @@ -399,9 +415,9 @@ if(available < 2) { //Requires at least two bytes of space wait(0.05); - continue; + continue; } - //Ready to write special character + //Ready to write special character if(io->write(DLE)) { specialWritten++; if(io->write(data[bytesWritten])) { @@ -412,17 +428,17 @@ wait(0.05); } } else { - //We want to write all the way up to the next special character + //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 { + } + } else { int size = MIN(available, length - bytesWritten); bytesWritten += io->write(&data[bytesWritten], size); } } else { - wait(0.05); + wait(0.05); } } while (tmr.read_ms() <= timeout && bytesWritten < length); } else { @@ -442,14 +458,15 @@ return bytesWritten; } } - + bytesWritten = io->write(&data[bytesWritten], length - bytesWritten); } - + return bytesWritten; } -unsigned int Cellular::readable() { +unsigned int Cellular::readable() +{ if(io == NULL) { printf("[ERROR] MTSBufferedIO not set\r\n"); return 0; @@ -461,7 +478,8 @@ return io->readable(); } -unsigned int Cellular::writeable() { +unsigned int Cellular::writeable() +{ if(io == NULL) { printf("[ERROR] MTSBufferedIO not set\r\n"); return 0; @@ -470,11 +488,12 @@ printf("[ERROR] Socket is not open\r\n"); return 0; } - + return io->writeable(); } -void Cellular::reset() { +void Cellular::reset() +{ disconnect(); Code code = sendBasicCommand("AT#RESET=0", 10000); if(code != SUCCESS) { @@ -487,15 +506,15 @@ Code Cellular::test() { Code code = sendBasicCommand("AT", 1000); - + if(code != SUCCESS) { printf("[Error] Failed basic AT command"); return code; } //AT#VSTATE != "CHECKING" - - //AT#GPRSMODE == + + //AT#GPRSMODE == return SUCCESS; } @@ -557,7 +576,7 @@ Code Cellular::sendBasicCommand(const std::string& command, unsigned int timeoutMillis, char esc) { if(socketOpened) { - printf("[ERROR] socket is open. Can not send AT commands\r\n"); + printf("[ERROR] socket is open. Can not send AT commands\r\n"); return ERROR; } @@ -573,7 +592,8 @@ } } -Code Cellular::setApn(const std::string& apn) { +Code Cellular::setApn(const std::string& apn) +{ Code code = sendBasicCommand("AT#APNSERV=\"" + apn + "\"", 1000); if (code != SUCCESS) { return code; @@ -583,31 +603,33 @@ } -Code Cellular::setDns(const std::string& primary, const std::string& secondary) { +Code Cellular::setDns(const std::string& primary, const std::string& secondary) +{ return sendBasicCommand("AT#DNS=1," + primary + "," + secondary, 1000); } -bool Cellular::ping(const std::string& address) { +bool Cellular::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); @@ -618,27 +640,29 @@ return false; } -Code Cellular::setSocketCloseable(bool enabled) { +Code Cellular::setSocketCloseable(bool enabled) +{ if(socketCloseable == enabled) { - return SUCCESS; + return SUCCESS; } - + if(socketOpened) { - printf("[ERROR] socket is already opened. Can not set closeable\r\n"); + printf("[ERROR] socket is already opened. Can not set closeable\r\n"); return ERROR; } - + socketCloseable = enabled; - + return SUCCESS; } -Code Cellular::sendSMS(const Sms& sms) { +Code Cellular::sendSMS(const Sms& sms) +{ return sendSMS(sms.phoneNumber, sms.message); } Code Cellular::sendSMS(const std::string& phoneNumber, const std::string& message) -{ +{ Code code = sendBasicCommand("AT+CMGF=1", 1000); if (code != SUCCESS) { return code; @@ -659,30 +683,31 @@ return SUCCESS; } -std::vector<Cellular::Sms> Cellular::getReceivedSms() { +std::vector<Cellular::Sms> Cellular::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)); //printf("[DEBUG] Top of SMS Parse Loop. LINE[%s]\r\n", line.c_str()); - if(line.find("+CMGL: ") == std::string::npos) { + if(line.find("+CMGL: ") == std::string::npos) { continue; } - + //Start of SMS message std::vector<std::string> vSmsParts = Text::split(line, ','); if(vSmsParts.size() != 6) { printf("[WARNING] Expected 6 commas. SMS[%d] DATA[%s]. Continuing ...\r\n", smsNumber, line.c_str()); continue; } - + sms.phoneNumber = vSmsParts[2]; sms.timestamp = vSmsParts[4] + ", " + vSmsParts[5]; - + if(pos == std::string::npos) { printf("[WARNING] Expected SMS body. SMS[%d]. Leaving ...\r\n", smsNumber); break; @@ -694,7 +719,7 @@ //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); @@ -711,11 +736,13 @@ return vSms; } -Code Cellular::deleteOnlyReceivedReadSms() { +Code Cellular::deleteOnlyReceivedReadSms() +{ return sendBasicCommand("AT+CMGD=1,1", 1000); } -Code Cellular::deleteAllReceivedSms() { +Code Cellular::deleteAllReceivedSms() +{ return sendBasicCommand("AT+CMGD=1,4", 1000); } @@ -727,21 +754,21 @@ return ""; } if(socketOpened) { - printf("[ERROR] socket is open. Can not send AT commands\r\n"); + printf("[ERROR] socket is open. Can not send AT commands\r\n"); 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 printf("[ERROR] failed to send command to radio within %d milliseconds\r\n", timeoutMillis); return ""; } - + //Send Escape Character if (esc != 0x00) { if(io->write(esc, timeoutMillis) != 1) { @@ -764,7 +791,7 @@ 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) { @@ -778,7 +805,7 @@ done = true; } } while (!done); - + return result; }