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
Diff: ThingerClient.h
- Revision:
- 0:b75d784c7c1a
- Child:
- 2:8c6f158b95c3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ThingerClient.h Thu Dec 24 13:18:08 2015 +0000 @@ -0,0 +1,220 @@ +// 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: + + virtual bool socket_start(const char* host, int port) = 0; + virtual bool socket_stop() = 0; + virtual bool socket_connected() = 0; + virtual size_t socket_read(char* buffer, size_t size) = 0; + virtual size_t socket_write(char* buffer, size_t size) = 0; + virtual size_t socket_available() = 0; + virtual bool connect_network() = 0; + 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()){ + #ifdef _DEBUG_ + int available = socket_available(); + 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 \ No newline at end of file