Thinger.io Client Library for ARM mbed platform. This is a generic library that provides a base class that can be used to other develop hardware specific libraries.

Fork of ThingerClient by Alvaro Luis Bustamante

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ThingerClient.h Source File

ThingerClient.h

00001 // The MIT License (MIT)
00002 //
00003 // Copyright (c) 2015 THINGER LTD
00004 // Author: alvarolb@gmail.com (Alvaro Luis Bustamante)
00005 //
00006 // Permission is hereby granted, free of charge, to any person obtaining a copy
00007 // of this software and associated documentation files (the "Software"), to deal
00008 // in the Software without restriction, including without limitation the rights
00009 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00010 // copies of the Software, and to permit persons to whom the Software is
00011 // furnished to do so, subject to the following conditions:
00012 //
00013 // The above copyright notice and this permission notice shall be included in
00014 // all copies or substantial portions of the Software.
00015 //
00016 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00017 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00018 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00019 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00020 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00021 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00022 // THE SOFTWARE.
00023 
00024 #ifndef THINGER_CLIENT_H
00025 #define THINGER_CLIENT_H
00026 
00027 #include "thinger/thinger.h"
00028 
00029 using namespace protoson;
00030 
00031 dynamic_memory_allocator alloc;
00032 //circular_memory_allocator<512> alloc;
00033 memory_allocator& protoson::pool = alloc;
00034 
00035 #define THINGER_SERVER "iot.thinger.io"
00036 #define THINGER_PORT 25200
00037 #define RECONNECTION_TIMEOUT 5 // seconds
00038 
00039 class ThingerClient : public thinger::thinger
00040 {
00041 public:
00042     ThingerClient(const char* user, const char* device, const char* device_credential) :
00043         username_(user), device_id_(device), device_password_(device_credential),
00044         temp_data_(NULL), out_size_(0)
00045     {}
00046 
00047     virtual ~ThingerClient()
00048     {}
00049 
00050 protected:
00051     /** Connect to the given host and port
00052     * Initialize a socket and connect it to the given host and port
00053     * \param host the host address to use
00054     * \param port the host port to connect to
00055     * \return true on success, or false on failure
00056     */
00057     virtual bool    socket_start(const char* host, int port) = 0;
00058     
00059     /** Stop the current socket connection
00060     * \return true on success, or false on failure
00061     */
00062     virtual bool    socket_stop() = 0;
00063     
00064     /** Check if the socket is connected
00065     * \return true on socket connected, or false on disconnected
00066     */
00067     virtual bool    socket_connected() = 0;
00068     
00069     /** Read all specified bytes from socket to buffer
00070     * \return the number of bytes read
00071     */
00072     virtual size_t  socket_read(char* buffer, size_t size) = 0;
00073     
00074     /** Write all specified bytes from buffer to socket
00075     * \return the number of bytes written
00076     */
00077     virtual size_t  socket_write(char* buffer, size_t size) = 0;
00078     
00079     /** Check the total available data in the socket
00080     * \return Ideally, the number of bytes available in the socket, or any positive number if there is pending data. 0 Otherwise.
00081     */
00082     virtual size_t  socket_available() = 0;
00083     
00084     /** Initialize the network interface, i.e., initialize ethernet interface, get ip address, etc.
00085     * \return the number of bytes read
00086     */
00087     virtual bool    connect_network() = 0;
00088     
00089     /** Check if the network is still connected
00090     * \return true if the network is connected, or false ortherwise
00091     */
00092     virtual bool    network_connected() = 0;
00093 
00094     virtual bool read(char *buffer, size_t size) {
00095         size_t total_read = 0;
00096         while(total_read<size) {
00097             int read = socket_read(buffer, size-total_read);
00098             if(read<0) return false;
00099             total_read += read;
00100         }
00101         return total_read == size;
00102     }
00103 
00104     // TODO Allow removing this Nagle's algorithm implementation if the underlying device already implements it
00105     virtual bool write(const char *buffer, size_t size, bool flush = false) {
00106         if(size>0) {
00107             temp_data_ = (char*) realloc(temp_data_, out_size_ + size);
00108             memcpy(&temp_data_[out_size_], buffer, size);
00109             out_size_ += size;
00110         }
00111         if(flush && out_size_>0) {
00112             size_t written = socket_write(temp_data_, out_size_);
00113             bool success = written == out_size_;
00114             free(temp_data_);
00115             temp_data_ = NULL;
00116             out_size_ = 0;
00117             return success;
00118         }
00119         return true;
00120     }
00121 
00122     virtual void disconnected() {
00123         thinger_state_listener(SOCKET_TIMEOUT);
00124         socket_stop();
00125         thinger_state_listener(SOCKET_DISCONNECTED);
00126     }
00127 
00128     enum THINGER_STATE {
00129         NETWORK_CONNECTING,
00130         NETWORK_CONNECTED,
00131         NETWORK_CONNECT_ERROR,
00132         SOCKET_CONNECTING,
00133         SOCKET_CONNECTED,
00134         SOCKET_CONNECTION_ERROR,
00135         SOCKET_DISCONNECTED,
00136         SOCKET_TIMEOUT,
00137         THINGER_AUTHENTICATING,
00138         THINGER_AUTHENTICATED,
00139         THINGER_AUTH_FAILED
00140     };
00141 
00142     virtual void thinger_state_listener(THINGER_STATE state) {
00143 #ifdef _DEBUG_
00144         switch(state) {
00145             case NETWORK_CONNECTING:
00146                 printf("[NETWORK] Starting connection...\n");
00147                 break;
00148             case NETWORK_CONNECTED:
00149                 printf("[NETWORK] Connected!\n");
00150                 break;
00151             case NETWORK_CONNECT_ERROR:
00152                 printf("[NETWORK] Cannot connect\n!");
00153                 break;
00154             case SOCKET_CONNECTING:
00155                 printf("[_SOCKET] Connecting to %s:%d...\n", THINGER_SERVER, THINGER_PORT);
00156                 break;
00157             case SOCKET_CONNECTED:
00158                 printf("[_SOCKET] Connected!\n");
00159                 break;
00160             case SOCKET_CONNECTION_ERROR:
00161                 printf("[_SOCKET] Error while connecting!\n");
00162                 break;
00163             case SOCKET_DISCONNECTED:
00164                 printf("[_SOCKET] Is now closed!\n");
00165                 break;
00166             case SOCKET_TIMEOUT:
00167                 printf("[_SOCKET] Timeout!\n");
00168                 break;
00169             case THINGER_AUTHENTICATING:
00170                 printf("[THINGER] Authenticating. User: %s Device: %s\n", username_, device_id_);
00171                 break;
00172             case THINGER_AUTHENTICATED:
00173                 printf("[THINGER] Authenticated!\n");
00174                 break;
00175             case THINGER_AUTH_FAILED:
00176                 printf("[THINGER] Auth Failed! Check username, device id, or device credentials.\n");
00177                 break;
00178         }
00179 #endif
00180     }
00181 
00182     bool handle_connection() {
00183         bool network = network_connected();
00184 
00185         if(!network) {
00186             thinger_state_listener(NETWORK_CONNECTING);
00187             network = connect_network();
00188             if(!network) {
00189                 thinger_state_listener(NETWORK_CONNECT_ERROR);
00190                 return false;
00191             }
00192             thinger_state_listener(NETWORK_CONNECTED);
00193         }
00194 
00195         bool client = socket_connected();
00196         if(!client) {
00197             client = connect_client();
00198             if(!client) {
00199                 return false;
00200             }
00201         }
00202         return network && client;
00203     }
00204 
00205     bool connect_client() {
00206         bool connected = false;
00207         socket_stop(); // cleanup previous socket
00208         thinger_state_listener(SOCKET_CONNECTING);
00209         if (socket_start(THINGER_SERVER, THINGER_PORT)) {
00210             thinger_state_listener(SOCKET_CONNECTED);
00211             thinger_state_listener(THINGER_AUTHENTICATING);
00212             connected = thinger::thinger::connect(username_, device_id_, device_password_);
00213             if(!connected) {
00214                 thinger_state_listener(THINGER_AUTH_FAILED);
00215                 socket_stop();
00216                 thinger_state_listener(SOCKET_DISCONNECTED);
00217             } else {
00218                 thinger_state_listener(THINGER_AUTHENTICATED);
00219             }
00220         } else {
00221             thinger_state_listener(SOCKET_CONNECTION_ERROR);
00222         }
00223         return connected;
00224     }
00225 
00226 public:
00227 
00228     void handle() {
00229         if(handle_connection()) {
00230             int available = socket_available();
00231 #ifdef _DEBUG_
00232             if(available>0) {
00233                 printf("[THINGER] Available bytes: %d\n", available);
00234             }
00235 #endif
00236             thinger::thinger::handle(us_ticker_read()/1000, available>0);
00237         } else {
00238             wait(RECONNECTION_TIMEOUT); // get some delay for a connection retry
00239         }
00240     }
00241 
00242 private:
00243     const char* username_;
00244     const char* device_id_;
00245     const char* device_password_;
00246     char * temp_data_;
00247     size_t out_size_;
00248 };
00249 
00250 #endif