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/Cellular.cpp
- Committer:
- Vanger
- Date:
- 2014-07-23
- Revision:
- 37:14f819beeccf
- Parent:
- 36:948d06b3e23c
- Child:
- 38:b2088faa8bfd
File content as of revision 37:14f819beeccf:
#include "mbed.h" #include "Cellular.h" #include "MTSText.h" #include "MTSLog.h" using namespace mts; bool Cellular::init(MTSBufferedIO* io) { if (io == NULL) { return false; } this->io = io; return true; } bool Cellular::configureSignals(unsigned int DCD, unsigned int DTR, unsigned int RESET) { //Set DCD - The radio will raise and lower this line if (DCD != NC) { dcd = new DigitalIn(PinName(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(PinName(DTR)); dtr->write(0); } //Set RESET - Set the hardware reset line to the radio if (RESET != NC) { resetLine = new DigitalOut(PinName(RESET)); } return true; } std::string Cellular::getRegistrationNames(Registration registration) { switch(registration) { case NOT_REGISTERED: return "NOT_REGISTERED"; case REGISTERED: return "REGISTERED"; case SEARCHING: return "SEARCHING"; case DENIED: return "DENIED"; case UNKNOWN: return "UNKNOWN"; case ROAMING: return "ROAMING"; default: return "UNKNOWN ENUM"; } } std::string Cellular::getRadioNames(Radio radio) { switch(radio) { case MTSMC_H5: return "MTSMC-H5"; case MTSMC_EV3: return "MTSMC-EV3"; case MTSMC_G3: return "MTSMC-G3"; case MTSMC_C2: return "MTSMC-C2"; case MTSMC_H5_IP: return "MTSMC-H5-IP"; case MTSMC_EV3_IP: return "MTSMC-EV3-IP"; case MTSMC_C2_IP: return "MTSMC-C2-IP"; default: return "UNKNOWN ENUM"; } } Code Cellular::test() { int i = 0; while (sendBasicCommand("AT", 1000) != MTS_SUCCESS) { i++; if (i >= 30) { logError("Could not talk to radio after 30 tries"); i = 0; } wait(1); } return MTS_SUCCESS; } int Cellular::getSignalStrength() { string response = sendCommand("AT+CSQ", 1000); if (response.find("OK") == string::npos) { return -1; } int start = response.find(':'); int stop = response.find(',', start); string signal = response.substr(start + 2, stop - start - 2); int value; sscanf(signal.c_str(), "%d", &value); return value; } Cellular::Registration Cellular::getRegistration() { string response = sendCommand("AT+CREG?", 5000); if (response.find("OK") == string::npos) { return UNKNOWN; } int start = response.find(','); int stop = response.find(' ', start); string regStat = response.substr(start + 1, stop - start - 1); int value; sscanf(regStat.c_str(), "%d", &value); switch (value) { case 0: return NOT_REGISTERED; case 1: return REGISTERED; case 2: return SEARCHING; case 3: return DENIED; case 4: return UNKNOWN; case 5: return ROAMING; } return UNKNOWN; } //Removed setAPN to be implemented in the individual cellular classes, //as UIP and EasyIP implement it in different ways. Code Cellular::setDns(const std::string& primary, const std::string& secondary) { return sendBasicCommand("AT#DNS=1," + primary + "," + secondary, 1000); } Code Cellular::sendSMS(const Sms& sms) { return sendSMS(sms.phoneNumber, sms.message); } Code Cellular::sendBasicCommand(const std::string& command, unsigned int timeoutMillis, char esc) { if(socketOpened) { logError("socket is open. Can not send AT commands"); return MTS_ERROR; } string response = sendCommand(command, timeoutMillis, esc); if (response.size() == 0) { return MTS_NO_RESPONSE; } else if (response.find("OK") != string::npos) { return MTS_SUCCESS; } else if (response.find("ERROR") != string::npos) { return MTS_ERROR; } else { return MTS_FAILURE; } } string Cellular::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 time_done = 0; //Time in 100s of milliseconds maximum between character transmissions const int MAX_INPUT_DELAY = 2; 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 { //Uses an timer to make sure no characters are received //within a period of time after the last recevied character. if(result.size() == previous) { time_done++; if(time_done > MAX_INPUT_DELAY) { done = true; } } else { time_done = 0; } } 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 Cellular::sendSMS(const std::string& phoneNumber, const std::string& message) { string csmp; if (type == MTSMC_H5_IP || type == MTSMC_H5) { csmp = "AT+CSMP=17,167,0,0"; } else if (type == MTSMC_EV3_IP || type == MTSMC_EV3 || type == MTSMC_C2_IP || type == MTSMC_C2) { csmp = "AT+CSMP=,4098,0,2"; } else if (type == MTSMC_G3) { } else { logError("unknown radio type [%d]", type); return MTS_FAILURE; } Code code = sendBasicCommand("AT+CMGF=1", 1000); if (code != MTS_SUCCESS) { logError("CMGF failed"); return code; } code = sendBasicCommand(csmp, 1000); if (code != MTS_SUCCESS) { logError("CSMP failed [%s]", getRadioNames(type).c_str()); return code; } string cmd = "AT+CMGS=\""; //EasyIP radios do not include the + if(type == MTSMC_H5_IP || type == MTSMC_EV3_IP || type == MTSMC_C2_IP) { cmd.append("+"); } cmd.append(phoneNumber); cmd.append("\",145"); for (int i = 0; i < 5; i++) { string response1 = sendCommand(cmd, 1000); if (response1.find('>') != string::npos) { break; } if (i >= 5) { logError("CMGS phone number failed"); return MTS_NO_RESPONSE; } wait(1); } wait(.2); string response2 = sendCommand(message, 4000, CTRL_Z); logInfo("SMS Response: [%s]", response2.c_str()); if ((response2.find("+CMGS:") == string::npos) || (response2.find("ERROR") != std::string::npos)) { logError("CMGS message failed"); return MTS_FAILURE; } return MTS_SUCCESS; } std::vector<Cellular::Sms> Cellular::getReceivedSms() { int smsNumber = 0; std::vector<Sms> vSms; std::string received; size_t pos; Code code = sendBasicCommand("AT+CMGF=1", 1000); if (code != MTS_SUCCESS) { logError("CMGF failed"); return vSms; } received = sendCommand("AT+CMGL=\"ALL\"", 5000); 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 (type == MTSMC_H5_IP || type == MTSMC_H5) { /* format for H5 and H5-IP radios * <index>, <status>, <oa>, <alpha>, <scts> * scts contains a comma, so splitting on commas should give us 6 items */ if(vSmsParts.size() != 6) { logWarning("Expected 5 commas. SMS[%d] DATA[%s]. Continuing ...", smsNumber, line.c_str()); continue; } sms.phoneNumber = vSmsParts[2]; sms.timestamp = vSmsParts[4] + ", " + vSmsParts[5]; } else if (type == MTSMC_EV3_IP || type == MTSMC_EV3 || type == MTSMC_C2_IP || type == MTSMC_C2) { /* format for EV3 and EV3-IP radios * <index>, <status>, <oa>, <callback>, <date> * splitting on commas should give us 5 items */ if(vSmsParts.size() != 5) { logWarning("Expected 4 commas. SMS[%d] DATA[%s]. Continuing ...", smsNumber, line.c_str()); continue; } sms.phoneNumber = vSmsParts[2]; /* timestamp is in a nasty format * YYYYMMDDHHMMSS * nobody wants to try and decipher that, so format it nicely * YY/MM/DD,HH:MM:SS */ string s = vSmsParts[4]; sms.timestamp = s.substr(2,2) + "/" + s.substr(4,2) + "/" + s.substr(6,2) + ", " + s.substr(8,2) + ":" + s.substr(10,2) + ":" + s.substr(12,2); } 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 Cellular::deleteOnlyReceivedReadSms() { return sendBasicCommand("AT+CMGD=1,1", 1000); } Code Cellular::deleteAllReceivedSms() { return sendBasicCommand("AT+CMGD=1,4", 1000); }