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
ThingerClient.h
- Committer:
- alvarolb
- Date:
- 2015-12-25
- Revision:
- 3:58e0153dbb37
- Parent:
- 2:8c6f158b95c3
File content as of revision 3:58e0153dbb37:
// The MIT License (MIT) // // Copyright (c) 2015 THINGER LTD // Author: alvarolb@gmail.com (Alvaro Luis Bustamante) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. #ifndef THINGER_CLIENT_H #define THINGER_CLIENT_H #include "thinger/thinger.h" using namespace protoson; dynamic_memory_allocator alloc; //circular_memory_allocator<512> alloc; memory_allocator& protoson::pool = alloc; #define THINGER_SERVER "iot.thinger.io" #define THINGER_PORT 25200 #define RECONNECTION_TIMEOUT 5 // seconds class ThingerClient : public thinger::thinger { public: ThingerClient(const char* user, const char* device, const char* device_credential) : username_(user), device_id_(device), device_password_(device_credential), temp_data_(NULL), out_size_(0) {} virtual ~ThingerClient() {} protected: /** Connect to the given host and port * Initialize a socket and connect it to the given host and port * \param host the host address to use * \param port the host port to connect to * \return true on success, or false on failure */ virtual bool socket_start(const char* host, int port) = 0; /** Stop the current socket connection * \return true on success, or false on failure */ virtual bool socket_stop() = 0; /** Check if the socket is connected * \return true on socket connected, or false on disconnected */ virtual bool socket_connected() = 0; /** Read all specified bytes from socket to buffer * \return the number of bytes read */ virtual size_t socket_read(char* buffer, size_t size) = 0; /** Write all specified bytes from buffer to socket * \return the number of bytes written */ virtual size_t socket_write(char* buffer, size_t size) = 0; /** Check the total available data in the socket * \return Ideally, the number of bytes available in the socket, or any positive number if there is pending data. 0 Otherwise. */ virtual size_t socket_available() = 0; /** Initialize the network interface, i.e., initialize ethernet interface, get ip address, etc. * \return the number of bytes read */ virtual bool connect_network() = 0; /** Check if the network is still connected * \return true if the network is connected, or false ortherwise */ virtual bool network_connected() = 0; virtual bool read(char *buffer, size_t size) { size_t total_read = 0; while(total_read<size) { int read = socket_read(buffer, size-total_read); if(read<0) return false; total_read += read; } return total_read == size; } // TODO Allow removing this Nagle's algorithm implementation if the underlying device already implements it virtual bool write(const char *buffer, size_t size, bool flush = false) { if(size>0) { temp_data_ = (char*) realloc(temp_data_, out_size_ + size); memcpy(&temp_data_[out_size_], buffer, size); out_size_ += size; } if(flush && out_size_>0) { size_t written = socket_write(temp_data_, out_size_); bool success = written == out_size_; free(temp_data_); temp_data_ = NULL; out_size_ = 0; return success; } return true; } virtual void disconnected() { thinger_state_listener(SOCKET_TIMEOUT); socket_stop(); thinger_state_listener(SOCKET_DISCONNECTED); } enum THINGER_STATE { NETWORK_CONNECTING, NETWORK_CONNECTED, NETWORK_CONNECT_ERROR, SOCKET_CONNECTING, SOCKET_CONNECTED, SOCKET_CONNECTION_ERROR, SOCKET_DISCONNECTED, SOCKET_TIMEOUT, THINGER_AUTHENTICATING, THINGER_AUTHENTICATED, THINGER_AUTH_FAILED }; virtual void thinger_state_listener(THINGER_STATE state) { #ifdef _DEBUG_ switch(state) { case NETWORK_CONNECTING: printf("[NETWORK] Starting connection...\n"); break; case NETWORK_CONNECTED: printf("[NETWORK] Connected!\n"); break; case NETWORK_CONNECT_ERROR: printf("[NETWORK] Cannot connect\n!"); break; case SOCKET_CONNECTING: printf("[_SOCKET] Connecting to %s:%d...\n", THINGER_SERVER, THINGER_PORT); break; case SOCKET_CONNECTED: printf("[_SOCKET] Connected!\n"); break; case SOCKET_CONNECTION_ERROR: printf("[_SOCKET] Error while connecting!\n"); break; case SOCKET_DISCONNECTED: printf("[_SOCKET] Is now closed!\n"); break; case SOCKET_TIMEOUT: printf("[_SOCKET] Timeout!\n"); break; case THINGER_AUTHENTICATING: printf("[THINGER] Authenticating. User: %s Device: %s\n", username_, device_id_); break; case THINGER_AUTHENTICATED: printf("[THINGER] Authenticated!\n"); break; case THINGER_AUTH_FAILED: printf("[THINGER] Auth Failed! Check username, device id, or device credentials.\n"); break; } #endif } bool handle_connection() { bool network = network_connected(); if(!network) { thinger_state_listener(NETWORK_CONNECTING); network = connect_network(); if(!network) { thinger_state_listener(NETWORK_CONNECT_ERROR); return false; } thinger_state_listener(NETWORK_CONNECTED); } bool client = socket_connected(); if(!client) { client = connect_client(); if(!client) { return false; } } return network && client; } bool connect_client() { bool connected = false; socket_stop(); // cleanup previous socket thinger_state_listener(SOCKET_CONNECTING); if (socket_start(THINGER_SERVER, THINGER_PORT)) { thinger_state_listener(SOCKET_CONNECTED); thinger_state_listener(THINGER_AUTHENTICATING); connected = thinger::thinger::connect(username_, device_id_, device_password_); if(!connected) { thinger_state_listener(THINGER_AUTH_FAILED); socket_stop(); thinger_state_listener(SOCKET_DISCONNECTED); } else { thinger_state_listener(THINGER_AUTHENTICATED); } } else { thinger_state_listener(SOCKET_CONNECTION_ERROR); } return connected; } public: void handle() { if(handle_connection()) { int available = socket_available(); #ifdef _DEBUG_ if(available>0) { printf("[THINGER] Available bytes: %d\n", available); } #endif thinger::thinger::handle(us_ticker_read()/1000, available>0); } else { wait(RECONNECTION_TIMEOUT); // get some delay for a connection retry } } private: const char* username_; const char* device_id_; const char* device_password_; char * temp_data_; size_t out_size_; }; #endif