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
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
Generated on Wed Jul 13 2022 01:45:11 by 1.7.2