Cellular library for MTS Socket Modem Arduino Shield devices from Multi-Tech Systems
Dependents: mtsas mtsas mtsas mtsas
Revision 33:3b6f3904dde0, committed 2014-07-16
- Comitter:
- Vanger
- Date:
- Wed Jul 16 14:26:10 2014 +0000
- Parent:
- 32:7d5581159bed
- Child:
- 34:7d412c989964
- Commit message:
- Updating and formatting documentation for EasyIP.h and EasyIP.cpp.; Comment tweak for UIP.h
Changed in this revision
--- a/Cellular/EasyIP.cpp Tue Jul 15 20:37:08 2014 +0000 +++ b/Cellular/EasyIP.cpp Wed Jul 16 14:26:10 2014 +0000 @@ -6,121 +6,10 @@ using namespace mts; -bool EasyIP::sendEscapeCommand() -{ - //string Cellular::sendCommand(const std::string& command, unsigned int timeoutMillis, char esc) - if(io == NULL) { - logError("MTSBufferedIO not set"); - return false; - } - if(!socketOpened) { - logError("Socket is not open. Can not send AT escape sequence (+++)"); - return false; - } - - if(!socketCloseable) { - logError("Socket is not closeable"); - return false; - } - - io->rxClear(); - io->txClear(); - - std::string result; - unsigned int timeoutMillis = 2000; - const int size_cmd = 3; - //Attempt to write command - wait(1); //Format for +++ command is 1 second wait, send +++, then another second wait - //1s wait after command is implemented as a polling function for 2 seconds - //Option: Could change wait periods to be longer/shorter (0-255)*50ms - if(io->write("+++", size_cmd, timeoutMillis) != size_cmd) { - //Failed to write command - logError("failed to send command to radio within %d milliseconds", timeoutMillis); - return false; - } - - int timer = 0; - char tmp[256]; - tmp[255] = 0; - bool done = false; - io->read(tmp,255,0); - bool exitmode = false; - - do { - wait(0.1); - timer += 100; - //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(result.find("OK") != std::string::npos) { - exitmode = true; - done = true; - } else if(result.find("NO CARRIER") != std::string::npos) { - exitmode = true; - done = true; - } else if(result.find("ERROR") != std::string::npos) { - exitmode = false; - done = true; - } - if(timer >= timeoutMillis) { - logDebug("Escape sequence [+++] timed out after %d milliseconds", timeoutMillis); - exitmode = true; - done = true; - } - } while (!done); - - return exitmode; -} -bool EasyIP::socketCheck() { - bool status = false; - std::string socketInfo = "9"; //9 is unrecognized - std::vector<std::string> params; - - if(sendEscapeCommand()) { - socketOpened = false; - if(sendBasicCommand("AT", 1000) == MTS_SUCCESS) { - socketInfo = sendCommand("AT#SS=1", 2000); - if(socketInfo.find("OK") != std::string::npos) { - //Found valid response - params = Text::split(socketInfo, "\r\n"); - params = Text::split(params[1], ","); - socketInfo = params[1]; - //Check comparison of params[1] to response codes - } else { - logError("Could not determine socket status[%s]",socketInfo.c_str()); - socketInfo == "9"; //9 is unrecognized - } - } - } else { - status = false; //Return value of socketOpened when checking - } - //Check socket status query - if(socketInfo == "2" || socketInfo == "3" || socketInfo == "1" || socketInfo == "4") { - status = true; //2 and 3 are suspended connections - } else if(socketInfo == "0" || socketInfo == "5") { - status = false; //0 is closed socket, probably won't occur - } else { - logError("Could not determine socket status"); - status = false; //anything else is unknown status - } - - if(status) { - std::string reconnect = sendCommand("AT#SO=1", 2000); - if(reconnect.find("CONNECT") != std::string::npos || reconnect.find("OK") != std::string::npos) { - } else { - logError("Failed to resume socket connection"); - } - } - return status; -} EasyIP::EasyIP(Radio type) { - //Not sure how the construction process is done, - //but assuming it works for both EasyIP and UIP the same way. this->type = type; io = NULL; dcd = NULL; @@ -138,8 +27,6 @@ EasyIP::~EasyIP() { - //Same reasoning for the destructor as the constructor, - //assuming it works for UIP, it will work for EasyIP if (dtr != NULL) { dtr->write(1); } @@ -166,7 +53,7 @@ bool EasyIP::connect() { - //Check if APN is not set, if so, connect will not work. + //Check if APN is not set, if it is not, connect will not work. if (type == MTSMC_H5_IP || type == MTSMC_H5 || type == MTSMC_G3) { if(apn.size() == 0) { logDebug("APN is not set"); @@ -327,7 +214,7 @@ } } - //Check active mode (SGACT = 1,1) + //Check active context (SGACT = 1,1) reply = sendCommand("AT#SGACT?", 500); if(reply.empty() || (reply.find("ERROR") != std::string::npos)) { active = false; @@ -388,6 +275,18 @@ return pppConnected; } +//Resets the radio +void EasyIP::reset() +{ + disconnect(); + if(sendBasicCommand("AT#REBOOT", 10000) != MTS_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"); + return; + } +} + //Binds the socket to a specific port if able bool EasyIP::bind(unsigned int port) { @@ -678,7 +577,7 @@ //Set IP,PPP,IPv6 Code code = sendBasicCommand("AT+CGDCONT=1,PPP," + apn, 1000); if (code != MTS_SUCCESS) { - return code; + return code; //This will return whatever is not MTS_SUCCESS } this->apn = apn; return code; //This will return MTS_SUCCESS @@ -688,17 +587,6 @@ } } -void EasyIP::reset() -{ - disconnect(); - if(sendBasicCommand("AT#REBOOT", 10000) != MTS_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"); - return; - } -} - std::string EasyIP::getDeviceIP() { return local_address; @@ -776,3 +664,117 @@ return MTS_SUCCESS; } + +bool EasyIP::sendEscapeCommand() +{ + //string Cellular::sendCommand(const std::string& command, unsigned int timeoutMillis, char esc) + if(io == NULL) { + logError("MTSBufferedIO not set"); + return false; + } + if(!socketOpened) { + logError("Socket is not open. Can not send AT escape sequence (+++)"); + return false; + } + + if(!socketCloseable) { + logError("Socket is not closeable"); + return false; + } + + io->rxClear(); + io->txClear(); + + std::string result; + unsigned int timeoutMillis = 2000; + const int size_cmd = 3; + //Attempt to write command + wait(1); //Format for +++ command is 1 second wait, send +++, then another second wait + //1s wait after command is implemented as a polling function for 2 seconds + //Option: Could change wait periods to be longer/shorter (0-255)*50ms + if(io->write("+++", size_cmd, timeoutMillis) != size_cmd) { + //Failed to write command + logError("failed to send command to radio within %d milliseconds", timeoutMillis); + return false; + } + + int timer = 0; + char tmp[256]; + tmp[255] = 0; + bool done = false; + io->read(tmp,255,0); + bool exitmode = false; + + do { + wait(0.1); + timer += 100; + //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(result.find("OK") != std::string::npos) { + exitmode = true; + done = true; + } else if(result.find("NO CARRIER") != std::string::npos) { + exitmode = true; + done = true; + } else if(result.find("ERROR") != std::string::npos) { + exitmode = false; + done = true; + } + if(timer >= timeoutMillis) { + logDebug("Escape sequence [+++] timed out after %d milliseconds", timeoutMillis); + exitmode = true; + done = true; + } + } while (!done); + + return exitmode; +} + +bool EasyIP::socketCheck() { + bool status = false; + std::string socketInfo = "9"; //9 is unrecognized + std::vector<std::string> params; + + //Goes from data mode to command mode + if(sendEscapeCommand()) { + socketOpened = false; + if(sendBasicCommand("AT", 1000) == MTS_SUCCESS) { + socketInfo = sendCommand("AT#SS=1", 2000); + if(socketInfo.find("OK") != std::string::npos) { + //Found valid response + params = Text::split(socketInfo, "\r\n"); + params = Text::split(params[1], ","); + socketInfo = params[1]; + //Check comparison of params[1] to response codes + } else { + logError("Could not determine socket status[%s]",socketInfo.c_str()); + socketInfo == "9"; //9 is unrecognized + } + } + } else { + status = false; //Return value of socketOpened when checking + } + + //Check socket status query + if(socketInfo == "2" || socketInfo == "3" || socketInfo == "1" || socketInfo == "4") { + status = true; //2 and 3 are suspended connections + } else if(socketInfo == "0" || socketInfo == "5") { + status = false; //0 is closed socket, probably won't occur + } else { + logError("Could not determine socket status"); + status = false; //anything else is unknown status + } + + //Reconnects to active socket if able + if(status) { + std::string reconnect = sendCommand("AT#SO=1", 2000); + if(reconnect.find("CONNECT") != std::string::npos || reconnect.find("OK") != std::string::npos) { + } else { + logError("Failed to resume socket connection"); + } + } + return status; +}
--- a/Cellular/EasyIP.h Tue Jul 15 20:37:08 2014 +0000 +++ b/Cellular/EasyIP.h Wed Jul 16 14:26:10 2014 +0000 @@ -9,33 +9,24 @@ namespace mts { -/** This is a class for communicating without a Multi-Tech Systems SocketModem iCell. Instead, -* it uses the hayes command set to implement the same commands and functions as the UIP class. -* (See the UIP class and documentation, "UIP.h") -* This class supports three main types of cellular radio interactions including: -* configuration and status AT command processing, SMS processing, and TCP Socket -* data connections. It should be noted that the radio can not process commands or -* SMS messages while having an open data connection at the same time. The concurrent -* capability may be added in a future release. This class also inherits from IPStack -* providing a common set of commands for communication devices that have an onboard -* IP Stack. It is also integrated with the standard mbed Sockets package and can therefore -* be used seamlessly with clients and services built on top of this interface already within -* the mbed library. -* The default baud rate for the cellular radio is 115200 bps. -*/ -class EasyIP : public Cellular //Inherits from Cellular. + /** This is a class for communicating without a Multi-Tech Systems SocketModem iCell. Instead, + * it uses the hayes command set to directly implement the same UIP interface to the radio. + * (See the UIP class and documentation, "UIP.h") + * This class supports four main types of cellular radio interactions including: + * configuration and status AT-command processing, SMS processing, TCP Socket data connections, + * and UDP data connections. It should be noted that the radio can not process commands or + * SMS messages while having an open data connection at the same time. The concurrent + * capability may be added in a future release. This class also inherits from IPStack + * providing a common set of commands for communication devices that have an onboard + * IP Stack. It is also integrated with the standard mbed Sockets package and can therefore + * be used seamlessly with clients and services built on top of this interface already within + * the mbed library. + * The default baud rate for the cellular radio is 115200 bps. + */ +class EasyIP : public Cellular { -private: - /*Function that sends +++ to radio to exit data mode - returns true if successful exit from online mode, else false - */ - virtual bool sendEscapeCommand(); - /*Switches to command mode, queries socket connection status, - then returns true if there is an active socket connection, - else it returns false.*/ - virtual bool socketCheck(); public: -/** This static function is used to create or get a reference to a + /** This static function is used to create or get a reference to a * Cellular object. Cellular uses the singleton pattern, which means * that you can only have one existing at a time. The first time you * call getInstance this method creates a new uninitialized Cellular @@ -53,13 +44,38 @@ /** Destructs a Cellular object and frees all related resources. */ ~EasyIP(); - + /** Initializes the MTS IO buffer + * INCOMPLETE + */ virtual bool init(MTSBufferedIO* io); - - // Wifi connection based commands derived from CommInterface.h + + /** PPP connect command. + * Connects the radio to the cellular network. + * + * @returns true if PPP connection to the network succeeded, + * false if the PPP connection failed. + */ virtual bool connect(); + + /** PPP disconnect command. + * Disconnects from the PPP network, and will also close active socket + * connection if open. + */ virtual void disconnect(); + + /** Checks if the radio is connected to the cell network. + * Checks antenna signal, cell tower registration, and context activation + * before finally pinging (4 pings, 32 bytes each) to confirm PPP connection + * to network. Will return true if there is an open socket connection as well. + * + * @returns true if there is a PPP connection to the cell network, false + * if there is no PPP connection to the cell network. + */ virtual bool isConnected(); + + /** Resets the radio/modem. + * Disconnects all active PPP and socket connections to do so. + */ virtual void reset(); // TCP and UDP Socket related commands @@ -72,12 +88,19 @@ virtual int write(const char* data, int length, int timeout = -1); virtual unsigned int readable(); virtual unsigned int writeable(); - virtual bool ping(const std::string& address = "8.8.8.8"); //Google DNS server + virtual bool ping(const std::string& address = "8.8.8.8"); //Google DNS server used as default ping address virtual std::string getDeviceIP(); - virtual bool setDeviceIP(std::string address = "DHCP");//Runs DHCP to configure the IP + virtual bool setDeviceIP(std::string address = "DHCP"); - //Sets the APN, also sets mode to IP, might need to change + /** Sets the APN + * + * @param apn c-string of the APN to use + * + * @returns MTS_SUCCESS if the APN was set, or is not needed, else it + * returns the result of the AT command sent to the radio to set the APN + */ virtual Code setApn(const std::string& apn); + /** A method for configuring command ehco capability on the radio. This command * sets whether sent characters are echoed back from the radio, in which case you * will receive back every command you send. @@ -88,18 +111,44 @@ virtual Code echo(bool state); /** This method can be used to trade socket functionality for performance. - * In order to enable a socket connection to be closed by the client side programtically, - * this class must process all read and write data on the socket to guard the special - * escape character used to close an open socket connection. It is recommened that you - * use the default of true unless the overhead of these operations is too significant. + * Can disable checking socket closed messages from the data socket, and thus the socket + * will only be visibly closed to the local side if the radio is explicitly checked, or + * the socket is closed by the local side through the use of physical pin manipulation. + * + * Uses the Hayes escape sequence (1 second pause, "+++", 1 second pause) to exit the socket + * connection to check if a received "NO CARRIER" string is from the radio indicating the socket + * has been closed, or is merely part of the data stream. Should not occur very often, however, if + * data carrying the string "NO CARRIER" is going to be transmitted frequently, then the socket should + * be set closeable and physical-socket-closing-means be used instead to reduce the large amount of + * overhead switching from checking the validity of the "NO CARRIER" message being and indication of + * the socket connection being closed. * * @param enabled set to true if you want the socket closeable, otherwise false. The default * is true. * @returns the standard AT Code enumeration. */ - virtual Code setSocketCloseable(bool enabled = true); //ETX closes socket (ETX and DLE in payload are escaped with DLE) + virtual Code setSocketCloseable(bool enabled = true); + +private: + /** Function that sends +++ to the radio to exit data mode + * returns true if it successfully exits from online mode, else + * it returns false. Used due to the fact that AT commands + * cannot be sent while in data mode. + * + * @returns true if the radio dropped from data mode to commande mode + * or is already in command mode (socket is still open in the background), + * and false if the radio failed to switch to command mode. + */ + virtual bool sendEscapeCommand(); + + /** Switches to command mode, queries the status of the socket connection, + * and then returns back to the active socket connection (if still open) + * + * @returns true if a socket is currently open, otherwise it returns false + */ + virtual bool socketCheck(); }; } -#endif +#endif /* SMC_H */
--- a/Cellular/UIP.h Tue Jul 15 20:37:08 2014 +0000 +++ b/Cellular/UIP.h Wed Jul 16 14:26:10 2014 +0000 @@ -46,7 +46,7 @@ * init method on the returned object first, before even creating the * other objects. * - * @returns a reference to the single Cellular obect that has been created. + * @returns a reference to the single Cellular object that has been created. */ UIP(Radio type);