Fix for UIP read of DLE escape character.
Fork of MTS-Cellular by
Cellular/UIP.h
- Committer:
- Vanger
- Date:
- 2014-08-01
- Revision:
- 46:56ab41157957
- Parent:
- 34:7d412c989964
- Child:
- 52:2cb58398a4f9
File content as of revision 46:56ab41157957:
#ifndef UIP_H #define UIP_H #include <string> #include <vector> #include "MTSBufferedIO.h" #include "Cellular.h" namespace mts { /** This is a class for communicating with a Multi-Tech Systems SocketModem iCell. The * SocketModem iCell is a family of carrier certified embedded cellular radio modules with * a common hardware footprint and AT command set for built in IP-stack functionality. * 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. * * All of the following examples use the Pin Names for the STMicro Nucleo F401RE board coupled with * the SocketModem Shield Arduino compatible board. Please chage Pin Names accordingly to * match your hardware configuration. It also assumes the use of RTS/CTS hardware handshaking * using GPIOs. To disable this you will need to change settings on the radio module and * and use the MTSSerial class instead of MTSSerialFlowControl. The default baud rate for the * cellular radio is 115200 bps. * * @code * #include "mbed.h" * #include "mtsas.h" * #include "TCPSocketConnection.h" * * int main(){ * //Modify to match your apn if you are using an HSPA radio with a SIM card * const char APN[] = ""; * * //Sets the log level to INFO, which is about midway on priority levels * //Possible levels: FATAL, ERROR, WARNING, INFO, DEBUG, TRACE, NONE * MTSLog::setLogLevel(MTSLog::TRACE_LEVEL); * * // STMicro Nucelo F401RE * // The supported jumper configurations of the MTSAS do not line up with * // the pin mapping of the Nucleo F401RE. Therefore, the MTSAS serial TX * // pin (JP8 Pin 2) must be manually jumped to Serial1 RX (Shield pin D2) * // and the MTSAS serial RX pin (JP9 Pin 2) pin must be manually jumped to * // Serial1 TX (Shield pin D8). * // Uncomment the following line to use the STMicro Nuceleo F401RE * MTSSerialFlowControl* io = new MTSSerialFlowControl(D8, D2, D3, D6); * * // Freescale KL46Z * // To configure the pins for the Freescale KL46Z board, use configuration B * // for the SocketModem. * // Uncomment the following line to use the Freescale KL46Z board * // MTSSerialFlowControl* io = new MTSSerialFlowControl(D2, D9, D3, D6); * * // Freescale KL64F * // To configure the pins for the Freescale KL46Z board, use configuration A * // for the SocketModem. * // Uncomment te following line to use the Freescale KL46F board * // MTSSerialFlowControl* io = new MTSSerialFlowControl(D1, D0, D3, D6); * * // Sets the baudrate for communicating with the radio * io->baud(115200); * * // Sets up the interfacing with the radio through the MTS library * Cellular* radio = CellularFactory::create(io); * radio->configureSignals(D4, D7, RESET); * Transport::setTransport(radio); * * // Sets the APN on the device (if necessary) * for (int i = 0; i < 10; i++) { * if (i >= 10) { * logError("Failed to set APN to %s", APN); * } * if (radio->setApn(APN) == MTS_SUCCESS) { * logInfo("Successfully set APN to %s", APN); * break; * } else { * wait(1); * } * } * * //Establish PPP link * for (int i = 0; i < 10; i++) { * if (i >= 10) { * logError("Failed to establish PPP link"); * } * if (radio->connect() == true) { * logInfo("Successfully established PPP link"); * break; * } else { * wait(1); * } * } * * //Ping google.com (optional) * for (int i = 0; i < 10; i++) { * if (i >= 10) { * logError("Failed to ping www.google.com"); * } * if (radio->ping("www.google.com") == true) { * logInfo("Successfully pinged www.google.com"); * break; * } else { * wait(1); * } * } * * //Used for packet verification from server's data response * const char PATTERN_LINE1[] = "abcdefghijklmnopqrstuvwzyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*()[]{}|"; * const char PATTERN[] = "abcdefghijklmnopqrstuvwzyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*()[]{}|\r\n" * "abcdefghijklmnopqrstuvwzyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*()[]{}/\r\n" * "abcdefghijklmnopqrstuvwzyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*()[]{}-\r\n" * "abcdefghijklmnopqrstuvwzyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*()[]{}\\\r\n" * "abcdefghijklmnopqrstuvwzyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*()[]{}|\r\n" * "abcdefghijklmnopqrstuvwzyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*()[]{}/\r\n" * "abcdefghijklmnopqrstuvwzyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*()[]{}-\r\n" * "abcdefghijklmnopqrstuvwzyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*()[]{}\\\r\n" * "abcdefghijklmnopqrstuvwzyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*()[]{}*\r\n"; * * const char MENU_LINE1[] = "send ascii pattern until keypress"; * const char MENU[] = "1 send ascii pattern until keypress" * "2 send ascii pattern (numbered)" * "3 send pattern and close socket" * "4 send [ETX] and wait for keypress" * "5 send [DLE] and wait for keypress" * "6 send all hex values (00-FF)" * "q quit" * ">:"; * * const char TCP_TEST_SERVER[] = "204.26.122.5"; * const int TCP_TEST_PORT = 7000; * * //Creates TCP socket pointer instance * TCPSocketConnection* sock = new TCPSocketConnection(); * //Turns off read_blocking and sets socket timeout to 2s * sock->set_blocking(false, 2); * * Timer tmr; //Used for timeouts * int bytesRead = 0; //Number of bytes read * const int readSize = 1024; //Size of buffer * char buffer[readSize] = {0}; //Read buffer * string result; //Result as a string * * //Open TCP socket * for (int i = 0; i < 5; i++) { * if (i >= 5) { * logError("Failed to open socket"); * } * if (! sock->connect(TCP_TEST_SERVER, TCP_TEST_PORT)) { * logInfo("Opened TCP server"); * break; * } else { * wait(1); * } * } * * //Waiting for menu from remote server * logInfo("Receiving Menu"); * tmr.reset(); * tmr.start(); * do { * bytesRead = sock->receive(buffer, readSize); * if (bytesRead > 0) { * result.append(buffer, bytesRead); * } * logInfo("Total Bytes Read: %d", result.size()); * if(result.find(MENU_LINE1) != std::string::npos) { * break; * } * } while(tmr.read() <= 40); * * wait(5); * * logInfo("Received: [%d] [%s]", result.size(), result.c_str()); * * //Checking that menu was successfully received * size_t pos = result.find(MENU_LINE1); * if(pos != string::npos) { * logInfo("Found Menu 1st Line"); * } else { * logError("Failed To Find Menu 1st Line"); * sock->close(); * return 0; * } * * result.clear(); * * //Sends a response of '2' back to choose option 2 from the menu * logInfo("Writing To Socket: 2"); * if(sock->send("2\r\n", 3) == 3) { * logInfo("Successfully Wrote '2'"); * } else { * logError("Failed To Write '2'"); * sock->close(); * return 0; * } * logInfo("Expecting 'how many ? >:'"); * tmr.reset(); * tmr.start(); * do { * bytesRead = sock->receive(buffer, readSize); * if (bytesRead > 0) { * result.append(buffer, bytesRead); * } * logInfo("Total Bytes Read: %d", result.size()); * if(result.find("how many") != std::string::npos) { * break; * } * } while(tmr.read() <= 40); * * logInfo("Received: [%d] [%s]", result.size(), result.c_str()); * * //Sends 2 to have the server send the pattern twice * if(result.find("how many") != std::string::npos) { * logInfo("Successfully Found 'how many'"); * logInfo("Writing To Socket: 2"); * if(sock->send("2\r\n", 3) == 3) { * logInfo("Successfully wrote '2'"); * } else { * logError("Failed to write '2'"); * sock->close(); * return 0; * } * } else { * logError("didn't receive 'how many'"); * sock->close(); * return 0; * } * * result.clear(); * * //Receives data from request sent to server * logInfo("Receiving Data"); * tmr.reset(); * tmr.start(); * do { * bytesRead = sock->receive(buffer, readSize); * if (bytesRead > 0) { * result.append(buffer, bytesRead); * } * logInfo("Total Bytes Read: %d", result.size()); * if(result.size() >= 1645) { * break; * } * } while(tmr.read() <= 40); * * logInfo("Received Data: [%d] [%s]", result.size(), result.c_str()); * * //Compares received data with expected data * pos = result.find(PATTERN_LINE1); * if(pos != string::npos) { * int patternSize = sizeof(PATTERN) - 1; * const char* ptr = &result.data()[pos]; * bool match = true; * for(int i = 0; i < patternSize; i++) { * if(PATTERN[i] != ptr[i]) { * logError("1st Pattern Doesn't Match At [%d]", i); * logError("Pattern [%02X] Buffer [%02X]", PATTERN[i], ptr[i]); * match = false; * break; * } * } * if(match) { * logInfo("Found 1st Pattern"); * } else { * logError("Failed To Find 1st Pattern"); * sock->close(); * return 0; * } * * pos = result.find(PATTERN_LINE1, pos + patternSize); * if(pos != std::string::npos) { * ptr = &result.data()[pos]; * match = true; * for(int i = 0; i < patternSize; i++) { * if(PATTERN[i] != ptr[i]) { * logError("2nd Pattern Doesn't Match At [%d]", i); * logError("Pattern [%02X] Buffer [%02X]", PATTERN[i], ptr[i]); * match = false; * break; * } * } * if(match) { * logInfo("Found 2nd Pattern"); * } else { * logError("Failed To Find 2nd Pattern"); * sock->close(); * return 0; * } * } * } else { * logError("Failed To Find Pattern 1st Line"); * sock->close(); * return 0; * } * * //Clears the result, and closes the socket connection. * result.clear(); * sock->close(); * * //Disconnect ppp link * radio->disconnect(); * * logInfo("End of example code"); * return 0; * } * @endcode */ class UIP : public Cellular { public: /** 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 * object and returns it. All future calls to this method will return * a reference to the instance created during the first call. Note that * you must call init on the returned instance before mnaking any other * calls. If using this class's bindings to any of the Socket package * classes like TCPSocketConnection, you must call this method and the * init method on the returned object first, before even creating the * other objects. * * @returns a reference to the single Cellular object that has been created. */ UIP(Radio type); /** Destructs a Cellular object and frees all related resources. */ ~UIP(); virtual bool init(MTSBufferedIO* io); // Cell connection based commands derived from CommInterface.h /** Initiates a PPP connection between the radio and the cell network */ virtual bool connect(); /** Disconnects the PPP connection between the radio and the cell network */ virtual void disconnect(); /** Checks if the radio has a PPP connection established with the cell network * (Can reach the internet essentially) */ virtual bool isConnected(); /** Resets the radio, must first close active socket and PPP connections * to do so */ virtual void reset(); // TCP and UDP Socket related commands // For behavior of the following methods refer to IPStack.h documentation virtual bool bind(unsigned int port); virtual bool open(const std::string& address, unsigned int port, Mode mode); virtual bool isOpen(); virtual bool close(); virtual int read(char* data, int max, int timeout = -1); 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"); virtual std::string getDeviceIP(); virtual bool setDeviceIP(std::string address = "DHCP"); /** A method for setting the APN * * @param apn APN to be passed as a c-string * @returns the standard AT Code enumeration */ 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. * * @param state if true echo will be turned off, otherwise it will be turned on. * @returns the standard AT Code enumeration. */ 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. * If set to false, socket must be closed using physical pin signals rather than through * the use of the ETX data character * * @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) }; } #endif