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

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers Cellular.h Source File

Cellular.h

00001 /* Universal Socket Modem Interface Library
00002 * Copyright (c) 2013 Multi-Tech Systems
00003 *
00004 * Licensed under the Apache License, Version 2.0 (the "License");
00005 * you may not use this file except in compliance with the License.
00006 * You may obtain a copy of the License at
00007 *
00008 *     http://www.apache.org/licenses/LICENSE-2.0
00009 *
00010 * Unless required by applicable law or agreed to in writing, software
00011 * distributed under the License is distributed on an "AS IS" BASIS,
00012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013 * See the License for the specific language governing permissions and
00014 * limitations under the License.
00015 */
00016 
00017 #ifndef CELLULAR_H
00018 #define CELLULAR_H
00019 
00020 #include "IPStack.h"
00021 #include "MTSBufferedIO.h"
00022 #include "mbed.h"
00023 #include <string>
00024 #include <vector>
00025 
00026 namespace mts
00027 {
00028 
00029 /** This is a class for communicating with a Multi-Tech Systems SocketModem iCell. The
00030 * SocketModem iCell is a family of carrier certified embedded cellular radio modules with
00031 * a common hardware footprint and AT command set for built in IP-stack functionality.
00032 * This class supports three main types of cellular radio interactions including:
00033 * configuration and status AT command processing, SMS processing, and TCP Socket
00034 * data connections. It should be noted that the radio can not process commands or
00035 * SMS messages while having an open data connection at the same time. The concurrent
00036 * capability may be added in a future release. This class also inherits from IPStack
00037 * providing a common set of commands for communication devices that have an onboard
00038 * IP Stack. It is also integrated with the standard mbed Sockets package and can therefore
00039 * be used seamlessly with clients and services built on top of this interface already within
00040 * the mbed library.
00041 *
00042 * All of the following examples use the Pin Names for the Freedom KL46Z board coupled with
00043 * the SocketModem Shield Arduino compatible board. Please chage Pin Names accordingly to
00044 * match your hardware configuration. It also assumes the use of RTS/CTS hardware handshaking
00045 * using GPIOs. To disable this you will need to change settings on the radio module and
00046 * and use the MTSSerial class instead of MTSSerialFlowControl. The default baud rate for the
00047 * cellular radio is 115200 bps.
00048 *
00049 * The following set of example code demonstrates how to send and receive configuration and
00050 * status AT commands with the radio, create a data connection and test it:
00051 * @code
00052 * #include "mbed.h"
00053 * #include "Cellular.h"
00054 * #include "MTSSerialFlowControl.h"
00055 *
00056 * using namespace mts;
00057 *
00058 * main() {
00059 *   //Setup serial interface to radio
00060 *   MTSSerialFlowControl* serial = new MTSSerialFlowControl(PTD3, PTD2, PTA12, PTC8);
00061 *   serial->baud(115200);
00062 *
00063 *   //Setup Cellular class
00064 *   Cellular* cellular = Cellular::getInstance();
00065 *   cellular->init(serial, PTA4, PTC9); //DCD and DTR pins for KL46Z
00066 *
00067 *   //Run status and configuration commands
00068 *   printf("\n\r////Start Status and Configuration Commands////\n\r");
00069 *   printf("Command Test: %s\n\r", getCodeNames(cellular->test()).c_str());
00070 *   printf("Signal Strength: %d\n\r", cellular->getSignalStrength());
00071 *   printf("Registration State: %s\n\r", Cellular::getRegistrationNames(cellular->getRegistration()).c_str());
00072 *   printf("Send Basic Command (AT): %s\n\r", getCodeNames(cellular->sendBasicCommand("AT", 1000)).c_str());
00073 *   printf("Send Command (AT+CSQ): %s\n\r", cellular->sendCommand("AT+CSQ", 1000).c_str());
00074 *
00075 *   //Start Test
00076 *   printf("\n\r////Start Network Connectivity Test////\n\r");
00077 *   printf("Set APN: %s\n\r", getCodeNames(cellular->setApn("wap.cingular")).c_str()); //Use APN from service provider!!!
00078 *
00079 *   //Setup a data connection
00080 *   printf("Attempting to Connect, this may take some time...\n\r");
00081 *   while (!cellular->connect()) {
00082 *       printf("Failed to connect... Trying again.\n\r");
00083 *       wait(1);
00084 *   }
00085 *   printf("Connected to the Network!\n\r");
00086 *
00087 *   //Try pinging default server "8.8.8.8"
00088 *   printf("Ping Valid: %s\n\r", cellular->ping() ? "true" : "false");
00089 *
00090 *   printf("End Program\n\r");
00091 * }
00092 * @endcode
00093 *
00094 * The following set of example code demonstrates how process SMS messages:
00095 * @code
00096 * #include "mbed.h"
00097 * #include "Cellular.h"
00098 * #include "MTSSerialFlowControl.h"
00099 *
00100 * using namespace mts;
00101 *
00102 * main() {
00103 *   //Setup serial interface to radio
00104 *   MTSSerialFlowControl* serial = new MTSSerialFlowControl(PTD3, PTD2, PTA12, PTC8);
00105 *   serial->baud(115200);
00106 *
00107 *   //Setup Cellular class
00108 *   Cellular* cellular = Cellular::getInstance();
00109 *   cellular->init(serial, PTA4, PTC9); //DCD and DTR pins for KL46Z
00110 *
00111 *   //Start test
00112 *   printf("AT Test: %s\n\r", getCodeNames(cellular->test()).c_str());
00113 *
00114 *   //Waiting for network registration
00115 *   printf("Checking Network Registration, this may take some time...\n\r");
00116 *   while (cellular->getRegistration() != Cellular::REGISTERED) {
00117 *       printf("Still waiting... Checking again.\n\r");
00118 *       wait(1);
00119 *   }
00120 *   printf("Connected to the Network!\n\r");
00121 *
00122 *   //Send SMS Message
00123 *   Code code;
00124 *   std::string sMsg("Hello from Multi-Tech MBED!");
00125 *   std::string sPhoneNum("16128675309"); //Put your phone number here or leave Jenny's...
00126 *
00127 *   printf("Sending message [%s] to [%s]\r\n", sMsg.c_str(), sPhoneNum.c_str());
00128 *   code = cellular->sendSMS(sPhoneNum, sMsg);
00129 *
00130 *   if(code != SUCCESS) {
00131 *       printf("Error during SMS send [%s]\r\n", getCodeNames(code).c_str());
00132 *   } else {
00133 *       printf("Success!\r\n");
00134 *   }
00135 *
00136 *   //Try and receive SMS messages
00137 *   //To determine your radio's phone number send yourself an SMS and check the received #
00138 *   printf("Checking Received Messages\r\n");
00139 *   std::vector<Cellular::Sms> vSms = cellular->getReceivedSms();
00140 *   printf("\r\n");
00141 *   for(unsigned int i = 0; i < vSms.size(); i++) {
00142 *       printf("[%d][%s][%s][%s]\r\n", i, vSms[i].timestamp.c_str(),
00143 *               vSms[i].phoneNumber.c_str(), vSms[i].message.c_str());
00144 *   }
00145 *   printf("End Program\n\r");
00146 * }
00147 * @endcode
00148 *
00149 * The following set of example code demonstrates how to setup and use a TCP socket connection
00150 * using the native commands from this class:
00151 * @code
00152 * #include "mbed.h"
00153 * #include "Cellular.h"
00154 * #include "MTSSerialFlowControl.h"
00155 *
00156 * using namespace mts;
00157 *
00158 * main() {
00159 *   //Define connection parameters
00160 *   Code code;
00161 *   const int TEST_PORT = 5798;
00162 *   const std::string TEST_SERVER("204.26.122.96");
00163 *
00164 *   //Setup serial interface to radio
00165 *   MTSSerialFlowControl* serial = new MTSSerialFlowControl(PTD3, PTD2, PTA12, PTC8);
00166 *   serial->baud(115200);
00167 *
00168 *   //Setup Cellular class
00169 *   Cellular* cellular = Cellular::getInstance();
00170 *   cellular->init(serial, PTA4, PTC9); //DCD and DTR pins for KL46Z
00171 *
00172 *   //Start test
00173 *   printf("AT Test: %s\n\r", getCodeNames(cellular->test()).c_str());
00174 *
00175 *   printf("Setting APN\r\n");
00176 *   code = cellular->setApn("wap.cingular"); // Use from your service provider!
00177 *   if(code == SUCCESS) {
00178 *       printf("Success!\r\n");
00179 *   } else {
00180 *       printf("Error during APN setup [%s]\r\n", getCodeNames(code).c_str());
00181 *   }
00182 *
00183 *   //Setup a data connection
00184 *   printf("Attempting to Connect, this may take some time...\n\r");
00185 *   while (!cellular->connect()) {
00186 *       printf("Failed to connect... Trying again.\n\r");
00187 *       wait(1);
00188 *   }
00189 *   printf("Connected to the Network!\n\r");
00190 *
00191 *   printf("Opening a TCP Socket...\r\n");
00192 *   if(cellular->open(TEST_SERVER, TEST_PORT, IPStack::TCP)) {
00193 *       printf("Success!\r\n");
00194 *   } else {
00195 *       printf("Error during TCP socket open [%s:%d]\r\n", TEST_SERVER.c_str(), TEST_PORT);
00196 *   }
00197 *
00198 *   char data[] = "My Test Echo Message";
00199 *   int size = sizeof(data);
00200 *   printf("WRITE: [%d] [%s]\r\n", size, data);
00201 *   int bytesWritten = cellular->write(data, size, 10000);
00202 *   if(bytesWritten == size) {
00203 *       printf("Successfully wrote message!\r\n");
00204 *   } else {
00205 *       printf("Failed to write message!\r\n");
00206 *   }
00207 *
00208 *   printf("Waiting 5 seconds\r\n");
00209 *   wait(5);
00210 *
00211 *   printf("Reading from socket for 10 seconds\r\n");
00212 *   char response[size];
00213 *   int bytesRead = cellular->read(response, size, 10000);
00214 *   response[size - 1] = '\0';
00215 *   printf("READ: [%d] [%s]\r\n", bytesRead, response);
00216 *
00217 *   //Check to see if echo was successful
00218 *   if (strcmp(data, response) == 0) {
00219 *       printf("Echo Successful!\n\r");
00220 *   } else {
00221 *       printf("Echo failed!\n\r");
00222 *   }
00223 *
00224 *   //Cleaning up the connection
00225 *   printf("Closing socket: %s\r\n", cellular->close() ? "Success" : "Failure");
00226 *   printf("Disconnecting...\r\n");
00227 *   cellular->disconnect();
00228 *   printf("End Program\n\r");
00229 * }
00230 * @endcode
00231 */
00232 
00233 class Cellular : virtual mts::IPStack
00234 {
00235 public:
00236 
00237     /// An enumeration of radio registration states with a cell tower.
00238     enum Registration {
00239         NOT_REGISTERED, REGISTERED, SEARCHING, DENIED, UNKNOWN, ROAMING
00240     };
00241 
00242     /** This structure contains the data for an SMS message.
00243     */
00244     struct Sms {
00245         /// Message Phone Number
00246         std::string phoneNumber;
00247         /// Message Body
00248         std::string message;
00249         /// Message Timestamp
00250         std::string timestamp;
00251     };
00252 
00253     /** Destructs a Cellular object and frees all related resources.
00254     */
00255     ~Cellular();
00256 
00257     /** This static function is used to create or get a reference to a
00258     * Cellular object. Cellular uses the singleton pattern, which means
00259     * that you can only have one existing at a time. The first time you
00260     * call getInstance this method creates a new uninitialized Cellular
00261     * object and returns it. All future calls to this method will return
00262     * a reference to the instance created during the first call. Note that
00263     * you must call init on the returned instance before mnaking any other
00264     * calls. If using this class's bindings to any of the Socket package
00265     * classes like TCPSocketConnection, you must call this method and the
00266     * init method on the returned object first, before even creating the
00267     * other objects.
00268     *
00269     * @returns a reference to the single Cellular obect that has been created.
00270     */
00271     static Cellular* getInstance();
00272 
00273     /** This method initializes the object with the underlying radio
00274     * interface to use. Note that this function MUST be called before
00275     * any other calls will function correctly on a Cellular object. Also
00276     * note that MTSBufferedIO is abstract, so you must use one of
00277     * its inherited classes like MTSSerial or MTSSerialFlowControl.
00278     *
00279     * @param io the buffered io interface that is attached to the cellular
00280     * radio.
00281     * @param DCD this is the dcd signal from the radio. If attached the
00282     * the pin must be passed in here for this class to operate correctly.
00283     * The default is not connected.
00284     * @param DTR this is the dtr signal from the radio. If attached the
00285     * the pin must be passed in here for this class to operate correctly.
00286     * The default is not connected.
00287     * @returns true if the init was successful, otherwise false.
00288     */
00289     bool init(MTSBufferedIO* io, PinName DCD = NC, PinName DTR = NC);
00290 
00291     // Radio link related commands
00292     /** This method establishes a data connection on the cellular radio.
00293     * Note that before calling you must have an activated radio and if
00294     * using a SIM card set the APN using the setApn method. The APN can
00295     * be obtained from your cellular service provider.
00296     *
00297     * @returns true if the connection was successfully established, otherwise
00298     * false on an error.
00299     */
00300     virtual bool connect();
00301 
00302     /** This method is used to stop a previously established cellular data connection.
00303     */
00304     virtual void disconnect();
00305 
00306     /** This method is used to check if the radio currently has a data connection
00307     * established.
00308     *
00309     * @returns true if a data connection exists, otherwise false.
00310     */
00311     virtual bool isConnected();
00312 
00313     // TCP and UDP Socket related commands
00314     // For behavior of the following methods refer to IPStack.h documentation
00315     virtual bool bind(unsigned int port);
00316     virtual bool open(const std::string& address, unsigned int port, Mode mode);
00317     virtual bool isOpen();
00318     virtual bool close();
00319     virtual int read(char* data, int max, int timeout = -1);
00320     virtual int write(const char* data, int length, int timeout = -1);
00321     virtual unsigned int readable();
00322     virtual unsigned int writeable();
00323 
00324     //Other
00325     /** A method to reset the Multi-Tech Socket Modem.  This command brings down the
00326     * PPP link if it is up.  After this function is called, at least 30 seconds should
00327     * be allowed for the cellular radio to come back up before any other Cellular
00328     * functions are called.
00329     */
00330     virtual void reset();
00331 
00332     //Cellular Radio Specific
00333     /** A method for sending a generic AT command to the radio. Note that you cannot
00334     * send commands and have a data connection at the same time.
00335     *
00336     * @param command the command to send to the radio without the escape character.
00337     * @param timeoutMillis the time in millis to wait for a response before returning.
00338     * @param esc escape character to add at the end of the command, defaults to
00339     * carriage return (CR).  Does not append any character if esc == 0.
00340     * @returns all data received from the radio after the command as a string.
00341     */
00342     std::string sendCommand(const std::string& command, unsigned int timeoutMillis, char esc = CR);
00343 
00344     /** A method for sending a basic AT command to the radio. A basic AT command is
00345     * one that simply has a response of either OK or ERROR without any other information.
00346     * Note that you cannot send commands and have a data connection at the same time.
00347     *
00348     * @param command the command to send to the radio without the escape character.
00349     * @param timeoutMillis the time in millis to wait for a response before returning.
00350     * @param esc escape character to add at the end of the command, defaults to
00351     * carriage return (CR).
00352     * @returns the standard Code enumeration.
00353     */
00354     Code sendBasicCommand(const std::string& command, unsigned int timeoutMillis, char esc = CR);
00355 
00356     /** This method is used to get the IP address of the device, which is determined
00357     * via DHCP by the cellular carrier.
00358     *
00359     * @returns the devices IP address.
00360     */
00361     std::string getDeviceIP();
00362     
00363     /** A method for testing command access to the radio.  This method sends the
00364     * command "AT" to the radio, which is a standard radio test to see if you
00365     * have command access to the radio.  The function returns when it receives
00366     * the expected response from the radio.
00367     *
00368     * @returns the standard AT Code enumeration.
00369     */
00370     Code test();
00371 
00372     /** A method for configuring command ehco capability on the radio. This command
00373     * sets whether sent characters are echoed back from the radio, in which case you
00374     * will receive back every command you send.
00375     *
00376     * @param state if true echo will be turned off, otherwise it will be turned on.
00377     * @returns the standard AT Code enumeration.
00378     */
00379     Code echo(bool state);
00380 
00381     /** A method for getting the signal strength of the radio. This method allows you to
00382     * get a value that maps to signal strength in dBm. Here 0-1 is Poor, 2-9 is Marginal,
00383     * 10-14 is Ok, 15-19 is Good, and 20+ is Excellent.  If you get a result of 99 the
00384     * signal strength is not known or not detectable.
00385     *
00386     * @returns an integer representing the signal strength.
00387     */
00388     int getSignalStrength();
00389 
00390     /** This method is used to check the registration state of the radio with the cell tower.
00391     * If not appropriatley registered with the tower you cannot make a cellular connection.
00392     *
00393     * @returns the registration state as an enumeration type.
00394     */
00395     Registration getRegistration();
00396 
00397     /** This method is used to set the radios APN if using a SIM card. Note that the APN
00398     * must be set correctly before you can make a data connection. The APN for your SIM
00399     * can be obtained by contacting your cellular service provider.
00400     *
00401     * @param the APN as a string.
00402     * @returns the standard AT Code enumeration.
00403     */
00404     Code setApn(const std::string& apn);
00405 
00406     /** This method is used to set the DNS which enables the use of URLs instead
00407     * of IP addresses when making a socket connection.
00408     *
00409     * @param the DNS server address as a string in form xxx.xxx.xxx.xxx.
00410     * @returns the standard AT Code enumeration.
00411     */
00412     Code setDns(const std::string& primary, const std::string& secondary = "0.0.0.0");
00413 
00414     /** This method is used test network connectivity by pinging a server.
00415     *
00416     * @param address the address of the server in format xxx.xxx.xxx.xxx.
00417     * @returns true if the ping was successful, otherwise false.
00418     */
00419     bool ping(const std::string& address = "8.8.8.8");
00420 
00421     /** This method can be used to trade socket functionality for performance.
00422     * In order to enable a socket connection to be closed by the client side programtically,
00423     * this class must process all read and write data on the socket to guard the special
00424     * escape character used to close an open socket connection. It is recommened that you
00425     * use the default of true unless the overhead of these operations is too significant.
00426     *
00427     * @param enabled set to true if you want the socket closeable, otherwise false. The default
00428     * is true.
00429     * @returns the standard AT Code enumeration.
00430     */
00431     Code setSocketCloseable(bool enabled = true);  //ETX closes socket (ETX and DLE in payload are escaped with DLE)
00432 
00433     /** This method is used to send an SMS message. Note that you cannot send an
00434     * SMS message and have a data connection open at the same time.
00435     *
00436     * @param phoneNumber the phone number to send the message to as a string.
00437     * @param message the text message to be sent.
00438     * @returns the standard AT Code enumeration.
00439     */
00440     Code sendSMS(const std::string& phoneNumber, const std::string& message);
00441 
00442     /** This method is used to send an SMS message. Note that you cannot send an
00443     * SMS message and have a data connection open at the same time.
00444     *
00445     * @param sms an Sms struct that contains all SMS transaction information.
00446     * @returns the standard AT Code enumeration.
00447     */
00448     Code sendSMS(const Sms& sms);
00449 
00450     /** This method retrieves all of the SMS messages currently available for
00451     * this phone number.
00452     *
00453     * @returns a vector of existing SMS messages each as an Sms struct.
00454     */
00455     std::vector<Cellular::Sms> getReceivedSms();
00456 
00457     /** This method can be used to remove/delete all received SMS messages
00458     * even if they have never been retrieved or read.
00459     *
00460     * @returns the standard AT Code enumeration.
00461     */
00462     Code deleteAllReceivedSms();
00463 
00464     /** This method can be used to remove/delete all received SMS messages
00465     * that have been retrieved by the user through the getReceivedSms method.
00466     * Messages that have not been retrieved yet will be unaffected.
00467     *
00468     * @returns the standard AT Code enumeration.
00469     */
00470     Code deleteOnlyReceivedReadSms();
00471 
00472     /** A static method for getting a string representation for the Registration
00473     * enumeration.
00474     *
00475     * @param code a Registration enumeration.
00476     * @returns the enumeration name as a string.
00477     */
00478     static std::string getRegistrationNames(Registration registration);
00479 
00480 private:
00481     static Cellular* instance; //Static pointer to the single Cellular object.
00482 
00483     MTSBufferedIO* io; //IO interface obect that the radio is accessed through.
00484     bool echoMode; //Specifies if the echo mode is currently enabled.
00485 
00486     bool pppConnected; //Specifies if a PPP session is currently connected.
00487     std::string apn; //A string that holds the APN for the radio.
00488 
00489     Mode mode; //The current socket Mode.
00490     bool socketOpened; //Specifies if a Socket is presently opened.
00491     bool socketCloseable; //Specifies is a Socket can be closed.
00492     unsigned int local_port; //Holds the local port for socket connections.
00493     std::string local_address; //Holds the local address for socket connections.
00494     unsigned int host_port; //Holds the remote port for socket connections.
00495     std::string host_address; //Holds the remote address for socket connections.
00496     DigitalIn* dcd; //Maps to the radios dcd signal
00497     DigitalOut* dtr; //Maps to the radios dtr signal
00498 
00499     Cellular(); //Private constructor, use the getInstance() method.
00500     Cellular(MTSBufferedIO* io); //Private constructor, use the getInstance() method.
00501 };
00502 
00503 }
00504 
00505 #endif /* CELLULAR_H */