For a PR
Fork of ublox-at-cellular-interface by
Diff: UbloxATCellularInterface.h
- Revision:
- 0:7ccf0e7e8a83
- Child:
- 1:bc228becc45d
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UbloxATCellularInterface.h Mon Jun 12 21:32:21 2017 +0000 @@ -0,0 +1,625 @@ +/* Copyright (c) 2017 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _UBLOX_CELLULAR_DRIVER_GEN_AT_DATA_ +#define _UBLOX_CELLULAR_DRIVER_GEN_AT_DATA_ + +#include "ublox_modem_driver/UbloxCellularBase.h" +#include "netsocket/CellularBase.h" +#include "NetworkStack.h" + +/** UbloxATCellularInterface class. + * + * This uses the cellular-tuned IP stack that + * is on-board the cellular modem instead of the + * LWIP stack on the mbed MCU. + * + * There are three advantages to using this mechanism: + * + * 1. Since the modem interface remains in AT mode + * throughout, it is possible to continue using + * any AT commands (e.g. send SMS, use the module's + * file system, etc.) while the connection is up. + * + * 2. The UbloxATCellularInterfaceExt class can + * be used to perform very simple HTTP and FTP + * operations using the modem's on-board clients. + * + * 3. LWIP is not required (and hence RAM is saved). + * + * The disadvantage is that some additional parsing + * (at the AT interface) has to go on in order to exchange + * IP packets, so this is less efficient under heavy loads. + * Also TCP Server and getting/setting of socket options is + * currently not supported. + */ + +// Forward declaration +class NetworkStack; + +/* + * NOTE: order is important in the inheritance below! PAL takes this class + * and casts it to CellularInterface and so CellularInterface has to be first + * in the last for that to work. + */ + +/** UbloxATCellularInterface class. + * + * This class implements the network stack interface into the cellular + * modems on the C030 and C027 boards for 2G/3G/4G modules using + * the IP stack running on the cellular module. + */ +class UbloxATCellularInterface : public CellularBase, public NetworkStack, virtual public UbloxCellularBase { + +public: + /** Constructor. + * + * @param tx the UART TX data pin to which the modem is attached. + * @param rx the UART RX data pin to which the modem is attached. + * @param baud the UART baud rate. + * @param debug_on true to switch AT interface debug on, otherwise false. + */ + UbloxATCellularInterface(PinName tx = MDMTXD, + PinName rx = MDMRXD, + int baud = MBED_CONF_UBLOX_CELL_BAUD_RATE, + bool debug_on = false); + + /* Destructor. + */ + virtual ~UbloxATCellularInterface(); + + /** The amount of extra space needed in terms of AT interface + * characters to get a chunk of user data (i.e. one UDP packet + * or a portion of a TCP packet) across the AT interface. + */ + #define AT_PACKET_OVERHEAD 77 + + /** The profile to use (on board the modem). + */ + #define PROFILE "0" + + /** Translates a host name to an IP address with specific IP version. + * + * The host name may be either a domain name or an IP address. If the + * host name is an IP address, no network transactions will be performed. + * + * If no stack-specific DNS resolution is provided, the host name + * will be resolved using a UDP socket on the stack. + * + * @param host Host name to resolve. + * @param address Destination for the host SocketAddress. + * @param version IP version of address to resolve, NSAPI_UNSPEC indicates + * version is chosen by the stack (defaults to NSAPI_UNSPEC). + * @return 0 on success, negative error code on failure. + */ + virtual nsapi_error_t gethostbyname(const char *host, + SocketAddress *address, + nsapi_version_t version = NSAPI_UNSPEC); + + /** Set the authentication scheme. + * + * @param auth The authentication scheme, chose from + * NSAPI_SECURITY_NONE, NSAPI_SECURITY_PAP, + * NSAPI_SECURITY_CHAP or NSAPI_SECURITY_UNKNOWN; + * use NSAPI_SECURITY_UNKNOWN to try all of none, + * PAP and CHAP. + */ + virtual void set_authentication(nsapi_security_t auth); + + /** Set the cellular network credentials. + * + * Please check documentation of connect() for default behaviour of APN settings. + * + * @param apn Access point name. + * @param uname Optionally, user name. + * @param pwd Optionally, password. + */ + virtual void set_credentials(const char *apn, const char *uname = 0, + const char *pwd = 0); + + /** Set the PIN code for the SIM card. + * + * @param sim_pin PIN for the SIM card. + */ + virtual void set_sim_pin(const char *sim_pin); + + /** Connect to the cellular network and start the interface. + * + * Attempts to connect to a cellular network. Note: if init() has + * not been called beforehand, connect() will call it first. + * + * @param sim_pin PIN for the SIM card. + * @param apn Optionally, access point name. + * @param uname Optionally, user name. + * @param pwd Optionally, password. + * @return NSAPI_ERROR_OK on success, or negative error code on failure. + */ + virtual nsapi_error_t connect(const char *sim_pin, const char *apn = 0, + const char *uname = 0, const char *pwd = 0); + + /** Attempt to connect to the cellular network. + * + * Brings up the network interface. Connects to the cellular radio + * network and then brings up IP stack on the cellular modem to be used + * indirectly via AT commands, rather than LWIP. Note: if init() has + * not been called beforehand, connect() will call it first. + * NOTE: even a failed attempt to connect will cause the modem to remain + * powered up. To power it down, call deinit(). + * + * For APN setup, default behaviour is to use 'internet' as APN string + * and assuming no authentication is required, i.e., user name and password + * are not set. Optionally, a database lookup can be requested by turning + * on the APN database lookup feature. The APN database is by no means + * exhaustive (feel free to submit a pull request with additional values). + * It contains a short list of some public APNs with publicly available + * user names and passwords (if required) in some particular countries only. + * Lookup is done using IMSI (International mobile subscriber identifier). + * + * The preferred method is to setup APN using 'set_credentials()' API. + * + * If you find that the AT interface returns "CONNECT" but shortly afterwards + * drops the connection then 99% of the time this will be because the APN + * is incorrect. + * + * @return 0 on success, negative error code on failure. + */ + virtual nsapi_error_t connect(); + + /** Attempt to disconnect from the network. + * + * Brings down the network interface. + * Does not bring down the Radio network. + * + * @return 0 on success, negative error code on failure. + */ + virtual nsapi_error_t disconnect(); + + /** Adds or removes a SIM facility lock. + * + * Can be used to enable or disable SIM PIN check at device startup. + * + * @param set Can be set to true if the SIM PIN check is supposed + * to be enabled and vice versa. + * @param immediate If true, change the SIM PIN now, else set a flag + * and make the change only when connect() is called. + * If this is true and init() has not been called previously, + * it will be called first. + * @param sim_pin The current SIM PIN, must be a const. If this is not + * provided, the SIM PIN must have previously been set by a + * call to set_sim_pin(). + * @return 0 on success, negative error code on failure. + */ + nsapi_error_t set_sim_pin_check(bool set, bool immediate = false, + const char *sim_pin = NULL); + + /** Change the PIN for the SIM card. + * + * Provide the new PIN for your SIM card with this API. It is ONLY possible to + * change the SIM PIN when SIM PIN checking is ENABLED. + * + * @param new_pin New PIN to be used in string format, must be a const. + * @param immediate If true, change the SIM PIN now, else set a flag + * and make the change only when connect() is called. + * If this is true and init() has not been called previously, + * it will be called first. + * @param old_pin Old PIN, must be a const. If this is not provided, the SIM PIN + * must have previously been set by a call to set_sim_pin(). + * @return 0 on success, negative error code on failure. + */ + nsapi_error_t set_new_sim_pin(const char *new_pin, bool immediate = false, + const char *old_pin = NULL); + + /** Check if the connection is currently established or not. + * + * @return True if connected to a data network, otherwise false. + */ + virtual bool is_connected(); + + /** Get the local IP address + * + * @return Null-terminated representation of the local IP address + * or null if no IP address has been received. + */ + virtual const char *get_ip_address(); + + /** Get the local network mask. + * + * @return Null-terminated representation of the local network mask + * or null if no network mask has been received. + */ + virtual const char *get_netmask(); + + /** Get the local gateways. + * + * @return Null-terminated representation of the local gateway + * or null if no network mask has been received. + */ + virtual const char *get_gateway(); + + /** Call back in case connection is lost. + * + * @param cb The function to call. + */ + void connection_status_cb(Callback<void(nsapi_error_t)> cb); + +protected: + + /** Socket "unused" value. + */ + #define SOCKET_UNUSED -1 + + /** Socket timeout value in milliseconds. + * Note: the sockets layer above will retry the + * call to the functions here when they return NSAPI_ERROR_WOULD_BLOCK + * and the user has set a larger timeout or full blocking. + */ + #define SOCKET_TIMEOUT 1000 + + /** The maximum number of bytes in a packet that can be written + * to the AT interface in one go. + */ + #define MAX_WRITE_SIZE 1024 + + /** The maximum number of bytes in a packet that can be read from + * from the AT interface in one go. + */ + #define MAX_READ_SIZE 1024 + + /** Management structure for sockets. + */ + typedef struct { + int modem_handle; //!< The modem's handle for the socket. + volatile nsapi_size_t pending; //!< The number of received bytes pending. + void (*callback)(void *); //!< A callback for events. + void *data; //!< A data pointer that must be passed to the callback. + } SockCtrl; + + /** Sockets storage. + */ + SockCtrl _sockets[7]; + + /** Storage for a single IP address. + */ + char *_ip; + + /** The APN to use. + */ + const char *_apn; + + /** The user name to use. + */ + const char *_uname; + + /** The password to use. + */ + const char *_pwd; + + /** The type of authentication to use. + */ + nsapi_security_t _auth; + + /** Get the next set of credentials from the database. + */ + virtual void get_next_credentials(const char * config); + + /** Activate one of the on-board modem's connection profiles. + * + * @param apn The APN to use. + * @param username The user name to use. + * @param password The password to use. + * @param auth The authentication method to use + * (NSAPI_SECURITY_NONE, NSAPI_SECURITY_PAP, + * NSAPI_SECURITY_CHAP or NSAPI_SECURITY_UNKNOWN). + * @return True if successful, otherwise false. + */ + virtual bool activate_profile(const char* apn, const char* username, + const char* password, nsapi_security_t auth); + + /** Activate a profile using the existing external connection. + * + * @return true if successful, otherwise false. + */ + virtual bool activate_profile_reuse_external(void); + + /** Activate a profile based on connection ID. + * + * @param cid The connection ID. + * @param apn The APN to use. + * @param username The user name to use. + * @param password The password to use. + * @param auth The authentication method to use. + * @return True if successful, otherwise false. + */ + virtual bool activate_profile_by_cid(int cid, const char* apn, const char* username, + const char* password, nsapi_security_t auth); + + /** Connect the on board IP stack of the modem. + * + * @return True if successful, otherwise false. + */ + virtual bool connect_modem_stack(); + + /** Disconnect the on board IP stack of the modem. + * + * @return True if successful, otherwise false. + */ + virtual bool disconnect_modem_stack(); + + /** Provide access to the NetworkStack object + * + * @return The underlying NetworkStack object. + */ + virtual NetworkStack *get_stack(); + +protected: + + /** Open a socket. + * + * Creates a network socket and stores it in the specified handle. + * The handle must be passed to following calls on the socket. + * + * @param handle Destination for the handle to a newly created socket. + * @param proto Protocol of socket to open, NSAPI_TCP or NSAPI_UDP. + * @return 0 on success, negative error code on failure. + */ + virtual nsapi_error_t socket_open(nsapi_socket_t *handle, + nsapi_protocol_t proto); + + /** Close a socket. + * + * Closes any open connection and deallocates any memory associated + * with the socket. + * + * @param handle Socket handle. + * @return 0 on success, negative error code on failure. + */ + virtual nsapi_error_t socket_close(nsapi_socket_t handle); + + /** Bind a specific port to a socket. + * + * Binding a socket specifies port on which to receive + * data. The IP address is ignored. Note that binding + * a socket involves closing it and reopening and so the + * bind operation should be carried out before any others. + * + * @param handle Socket handle. + * @param address Local address to bind (of which only the port is used). + * @return 0 on success, negative error code on failure. + */ + virtual nsapi_error_t socket_bind(nsapi_socket_t handle, + const SocketAddress &address); + + /** Connects TCP socket to a remote host. + * + * Initiates a connection to a remote server specified by the + * indicated address. + * + * @param handle Socket handle. + * @param address The SocketAddress of the remote host. + * @return 0 on success, negative error code on failure. + */ + virtual nsapi_error_t socket_connect(nsapi_socket_t handle, + const SocketAddress &address); + + /** Send data over a TCP socket. + * + * The socket must be connected to a remote host. Returns the number of + * bytes sent from the buffer. This class sets no upper buffer limit on + * buffer size and the maximum packet size is not connected with the + * platform.buffered-serial-txbuf-size/platform.buffered-serial-rxbuf-size + * definitions. + * + * @param handle Socket handle. + * @param data Buffer of data to send to the host. + * @param size Size of the buffer in bytes. + * @return Number of sent bytes on success, negative error + * code on failure. + */ + virtual nsapi_size_or_error_t socket_send(nsapi_socket_t handle, + const void *data, nsapi_size_t size); + + /** Send a packet over a UDP socket. + * + * Sends data to the specified address. Returns the number of bytes + * sent from the buffer. + * + * PACKET SIZES: the maximum packet size that can be sent in a single + * UDP packet is limited by the configuration value + * platform.buffered-serial-txbuf-size (defaults to 256). + * The maximum UDP packet size is: + * + * platform.buffered-serial-txbuf-size - AT_PACKET_OVERHEAD + * + * ...with a limit of 1024 bytes (at the AT interface). So, to allow sending + * of a 1024 byte UDP packet, edit your mbed_app.json to add a target override + * setting platform.buffered-serial-txbuf-size to 1101. However, for + * UDP packets, 508 bytes is considered a more realistic size, taking into + * account fragmentation sizes over the public internet, which leads to a + * platform.buffered-serial-txbuf-size/platform.buffered-serial-rxbuf-size + * setting of 585. + * + * If size is larger than this limit, the data will be split across separate + * UDP packets. + * + * @param handle Socket handle. + * @param address The SocketAddress of the remote host. + * @param data Buffer of data to send to the host. + * @param size Size of the buffer in bytes. + * @return Number of sent bytes on success, negative error + * code on failure. + */ + virtual nsapi_size_or_error_t socket_sendto(nsapi_socket_t handle, + const SocketAddress &address, + const void *data, + nsapi_size_t size); + + /** Receive data over a TCP socket. + * + * The socket must be connected to a remote host. Returns the number of + * bytes received into the buffer. This class sets no upper limit on the + * buffer size and the maximum packet size is not connected with the + * platform.buffered-serial-txbuf-size/platform.buffered-serial-rxbuf-size + * definitions. + * + * @param handle Socket handle. + * @param data Destination buffer for data received from the host. + * @param size Size of the buffer in bytes. + * @return Number of received bytes on success, negative error + * code on failure. + */ + virtual nsapi_size_or_error_t socket_recv(nsapi_socket_t handle, + void *data, nsapi_size_t size); + + /** Receive a packet over a UDP socket. + * + * Receives data and stores the source address in address if address + * is not NULL. Returns the number of bytes received into the buffer. + * + * PACKET SIZES: the maximum packet size that can be retrieved in a + * single call to this method is limited by the configuration value + * platform.buffered-serial-rxbuf-size (default 256). The maximum + * UDP packet size is: + * + * platform.buffered-serial-rxbuf-size - AT_PACKET_OVERHEAD + * + * ...with a limit of 1024 (at the AT interface). So to allow reception of a + * 1024 byte UDP packet in a single call, edit your mbed_app.json to add a + * target override setting platform.buffered-serial-rxbuf-size to 1101. + * + * If the received packet is larger than this limit, any remainder will + * be returned in subsequent calls to this method. Once a single UDP + * packet has been received, this method will return. + * + * @param handle Socket handle. + * @param address Destination for the source address or NULL. + * @param data Destination buffer for data received from the host. + * @param size Size of the buffer in bytes. + * @return Number of received bytes on success, negative error + * code on failure. + */ + virtual nsapi_size_or_error_t socket_recvfrom(nsapi_socket_t handle, + SocketAddress *address, + void *data, nsapi_size_t size); + + /** Register a callback on state change of the socket. + * + * The specified callback will be called on state changes such as when + * the socket can recv/send/accept successfully and on when an error + * occurs. The callback may also be called spuriously without reason. + * + * The callback may be called in an interrupt context and should not + * perform expensive operations such as recv/send calls. + * + * @param handle Socket handle. + * @param callback Function to call on state change. + * @param data Argument to pass to callback. + */ + virtual void socket_attach(nsapi_socket_t handle, void (*callback)(void *), + void *data); + + /** Listen for connections on a TCP socket. + * + * Marks the socket as a passive socket that can be used to accept + * incoming connections. + * + * @param handle Socket handle. + * @param backlog Number of pending connections that can be queued + * simultaneously, defaults to 1. + * @return 0 on success, negative error code on failure. + */ + virtual nsapi_error_t socket_listen(nsapi_socket_t handle, int backlog); + + /** Accepts a connection on a TCP socket. + * + * The server socket must be bound and set to listen for connections. + * On a new connection, creates a network socket and stores it in the + * specified handle. The handle must be passed to following calls on + * the socket. + * + * A stack may have a finite number of sockets, in this case + * NSAPI_ERROR_NO_SOCKET is returned if no socket is available. + * + * This call is non-blocking. If accept would block, + * NSAPI_ERROR_WOULD_BLOCK is returned immediately. + * + * @param server Socket handle to server to accept from. + * @param handle Destination for a handle to the newly created socket. + * @param address Destination for the remote address or NULL. + * @return 0 on success, negative error code on failure. + */ + virtual nsapi_error_t socket_accept(nsapi_socket_t server, + nsapi_socket_t *handle, + SocketAddress *address = 0); + + /** Set stack-specific socket options. + * + * The setsockopt allow an application to pass stack-specific hints + * to the underlying stack. For unsupported options, + * NSAPI_ERROR_UNSUPPORTED is returned and the socket is unmodified. + * + * @param handle Socket handle. + * @param level Stack-specific protocol level. + * @param optname Stack-specific option identifier. + * @param optval Option value. + * @param optlen Length of the option value. + * @return 0 on success, negative error code on failure. + */ + virtual nsapi_error_t setsockopt(nsapi_socket_t handle, int level, + int optname, const void *optval, + unsigned optlen); + + /** Get stack-specific socket options. + * + * The getstackopt allow an application to retrieve stack-specific hints + * from the underlying stack. For unsupported options, + * NSAPI_ERROR_UNSUPPORTED is returned and optval is unmodified. + * + * @param handle Socket handle. + * @param level Stack-specific protocol level. + * @param optname Stack-specific option identifier. + * @param optval Destination for option value. + * @param optlen Length of the option value. + * @return 0 on success, negative error code on failure. + */ + virtual nsapi_error_t getsockopt(nsapi_socket_t handle, int level, + int optname, void *optval, + unsigned *optlen); + +private: + + // u_ added to namespace us somewhat as this darned macro + // is defined by everyone and their dog + #define u_stringify(a) str(a) + #define str(a) #a + + bool _sim_pin_check_change_pending; + bool _sim_pin_check_change_pending_enabled_value; + bool _sim_pin_change_pending; + const char *_sim_pin_change_pending_new_pin_value; + Thread event_thread; + void handle_event(); + SockCtrl * find_socket(int modem_handle = SOCKET_UNUSED); + void clear_socket(SockCtrl * socket); + bool check_socket(SockCtrl * socket); + int nsapi_security_to_modem_security(nsapi_security_t nsapi_security); + Callback<void(nsapi_error_t)> _connection_status_cb; + void UUSORD_URC(); + void UUSORF_URC(); + void UUSOCL_URC(); + void UUPSDD_URC(); +}; + +#endif // _UBLOX_CELLULAR_DRIVER_GEN_AT_DATA_ +