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@0:b75d784c7c1a, 2015-12-24 (annotated)
- Committer:
- alvarolb
- Date:
- Thu Dec 24 13:18:08 2015 +0000
- Revision:
- 0:b75d784c7c1a
- Child:
- 2:8c6f158b95c3
Initial Commit
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
alvarolb | 0:b75d784c7c1a | 1 | // The MIT License (MIT) |
alvarolb | 0:b75d784c7c1a | 2 | // |
alvarolb | 0:b75d784c7c1a | 3 | // Copyright (c) 2015 THINGER LTD |
alvarolb | 0:b75d784c7c1a | 4 | // Author: alvarolb@gmail.com (Alvaro Luis Bustamante) |
alvarolb | 0:b75d784c7c1a | 5 | // |
alvarolb | 0:b75d784c7c1a | 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy |
alvarolb | 0:b75d784c7c1a | 7 | // of this software and associated documentation files (the "Software"), to deal |
alvarolb | 0:b75d784c7c1a | 8 | // in the Software without restriction, including without limitation the rights |
alvarolb | 0:b75d784c7c1a | 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
alvarolb | 0:b75d784c7c1a | 10 | // copies of the Software, and to permit persons to whom the Software is |
alvarolb | 0:b75d784c7c1a | 11 | // furnished to do so, subject to the following conditions: |
alvarolb | 0:b75d784c7c1a | 12 | // |
alvarolb | 0:b75d784c7c1a | 13 | // The above copyright notice and this permission notice shall be included in |
alvarolb | 0:b75d784c7c1a | 14 | // all copies or substantial portions of the Software. |
alvarolb | 0:b75d784c7c1a | 15 | // |
alvarolb | 0:b75d784c7c1a | 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
alvarolb | 0:b75d784c7c1a | 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
alvarolb | 0:b75d784c7c1a | 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
alvarolb | 0:b75d784c7c1a | 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
alvarolb | 0:b75d784c7c1a | 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
alvarolb | 0:b75d784c7c1a | 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
alvarolb | 0:b75d784c7c1a | 22 | // THE SOFTWARE. |
alvarolb | 0:b75d784c7c1a | 23 | |
alvarolb | 0:b75d784c7c1a | 24 | #ifndef THINGER_CLIENT_H |
alvarolb | 0:b75d784c7c1a | 25 | #define THINGER_CLIENT_H |
alvarolb | 0:b75d784c7c1a | 26 | |
alvarolb | 0:b75d784c7c1a | 27 | #include "thinger/thinger.h" |
alvarolb | 0:b75d784c7c1a | 28 | |
alvarolb | 0:b75d784c7c1a | 29 | using namespace protoson; |
alvarolb | 0:b75d784c7c1a | 30 | |
alvarolb | 0:b75d784c7c1a | 31 | dynamic_memory_allocator alloc; |
alvarolb | 0:b75d784c7c1a | 32 | //circular_memory_allocator<512> alloc; |
alvarolb | 0:b75d784c7c1a | 33 | memory_allocator& protoson::pool = alloc; |
alvarolb | 0:b75d784c7c1a | 34 | |
alvarolb | 0:b75d784c7c1a | 35 | #define THINGER_SERVER "iot.thinger.io" |
alvarolb | 0:b75d784c7c1a | 36 | #define THINGER_PORT 25200 |
alvarolb | 0:b75d784c7c1a | 37 | #define RECONNECTION_TIMEOUT 5 // seconds |
alvarolb | 0:b75d784c7c1a | 38 | |
alvarolb | 0:b75d784c7c1a | 39 | class ThingerClient : public thinger::thinger { |
alvarolb | 0:b75d784c7c1a | 40 | public: |
alvarolb | 0:b75d784c7c1a | 41 | ThingerClient(const char* user, const char* device, const char* device_credential) : |
alvarolb | 0:b75d784c7c1a | 42 | username_(user), device_id_(device), device_password_(device_credential), |
alvarolb | 0:b75d784c7c1a | 43 | temp_data_(NULL), out_size_(0) |
alvarolb | 0:b75d784c7c1a | 44 | {} |
alvarolb | 0:b75d784c7c1a | 45 | |
alvarolb | 0:b75d784c7c1a | 46 | virtual ~ThingerClient() |
alvarolb | 0:b75d784c7c1a | 47 | {} |
alvarolb | 0:b75d784c7c1a | 48 | |
alvarolb | 0:b75d784c7c1a | 49 | protected: |
alvarolb | 0:b75d784c7c1a | 50 | |
alvarolb | 0:b75d784c7c1a | 51 | virtual bool socket_start(const char* host, int port) = 0; |
alvarolb | 0:b75d784c7c1a | 52 | virtual bool socket_stop() = 0; |
alvarolb | 0:b75d784c7c1a | 53 | virtual bool socket_connected() = 0; |
alvarolb | 0:b75d784c7c1a | 54 | virtual size_t socket_read(char* buffer, size_t size) = 0; |
alvarolb | 0:b75d784c7c1a | 55 | virtual size_t socket_write(char* buffer, size_t size) = 0; |
alvarolb | 0:b75d784c7c1a | 56 | virtual size_t socket_available() = 0; |
alvarolb | 0:b75d784c7c1a | 57 | virtual bool connect_network() = 0; |
alvarolb | 0:b75d784c7c1a | 58 | virtual bool network_connected() = 0; |
alvarolb | 0:b75d784c7c1a | 59 | |
alvarolb | 0:b75d784c7c1a | 60 | virtual bool read(char *buffer, size_t size) |
alvarolb | 0:b75d784c7c1a | 61 | { |
alvarolb | 0:b75d784c7c1a | 62 | size_t total_read = 0; |
alvarolb | 0:b75d784c7c1a | 63 | while(total_read<size){ |
alvarolb | 0:b75d784c7c1a | 64 | int read = socket_read(buffer, size-total_read); |
alvarolb | 0:b75d784c7c1a | 65 | if(read<0) return false; |
alvarolb | 0:b75d784c7c1a | 66 | total_read += read; |
alvarolb | 0:b75d784c7c1a | 67 | } |
alvarolb | 0:b75d784c7c1a | 68 | return total_read == size; |
alvarolb | 0:b75d784c7c1a | 69 | } |
alvarolb | 0:b75d784c7c1a | 70 | |
alvarolb | 0:b75d784c7c1a | 71 | // TODO Allow removing this Nagle's algorithm implementation if the underlying device already implements it |
alvarolb | 0:b75d784c7c1a | 72 | virtual bool write(const char *buffer, size_t size, bool flush = false){ |
alvarolb | 0:b75d784c7c1a | 73 | if(size>0){ |
alvarolb | 0:b75d784c7c1a | 74 | temp_data_ = (char*) realloc(temp_data_, out_size_ + size); |
alvarolb | 0:b75d784c7c1a | 75 | memcpy(&temp_data_[out_size_], buffer, size); |
alvarolb | 0:b75d784c7c1a | 76 | out_size_ += size; |
alvarolb | 0:b75d784c7c1a | 77 | } |
alvarolb | 0:b75d784c7c1a | 78 | if(flush && out_size_>0){ |
alvarolb | 0:b75d784c7c1a | 79 | size_t written = socket_write(temp_data_, out_size_); |
alvarolb | 0:b75d784c7c1a | 80 | bool success = written == out_size_; |
alvarolb | 0:b75d784c7c1a | 81 | free(temp_data_); |
alvarolb | 0:b75d784c7c1a | 82 | temp_data_ = NULL; |
alvarolb | 0:b75d784c7c1a | 83 | out_size_ = 0; |
alvarolb | 0:b75d784c7c1a | 84 | return success; |
alvarolb | 0:b75d784c7c1a | 85 | } |
alvarolb | 0:b75d784c7c1a | 86 | return true; |
alvarolb | 0:b75d784c7c1a | 87 | } |
alvarolb | 0:b75d784c7c1a | 88 | |
alvarolb | 0:b75d784c7c1a | 89 | virtual void disconnected(){ |
alvarolb | 0:b75d784c7c1a | 90 | thinger_state_listener(SOCKET_TIMEOUT); |
alvarolb | 0:b75d784c7c1a | 91 | socket_stop(); |
alvarolb | 0:b75d784c7c1a | 92 | thinger_state_listener(SOCKET_DISCONNECTED); |
alvarolb | 0:b75d784c7c1a | 93 | } |
alvarolb | 0:b75d784c7c1a | 94 | |
alvarolb | 0:b75d784c7c1a | 95 | enum THINGER_STATE{ |
alvarolb | 0:b75d784c7c1a | 96 | NETWORK_CONNECTING, |
alvarolb | 0:b75d784c7c1a | 97 | NETWORK_CONNECTED, |
alvarolb | 0:b75d784c7c1a | 98 | NETWORK_CONNECT_ERROR, |
alvarolb | 0:b75d784c7c1a | 99 | SOCKET_CONNECTING, |
alvarolb | 0:b75d784c7c1a | 100 | SOCKET_CONNECTED, |
alvarolb | 0:b75d784c7c1a | 101 | SOCKET_CONNECTION_ERROR, |
alvarolb | 0:b75d784c7c1a | 102 | SOCKET_DISCONNECTED, |
alvarolb | 0:b75d784c7c1a | 103 | SOCKET_TIMEOUT, |
alvarolb | 0:b75d784c7c1a | 104 | THINGER_AUTHENTICATING, |
alvarolb | 0:b75d784c7c1a | 105 | THINGER_AUTHENTICATED, |
alvarolb | 0:b75d784c7c1a | 106 | THINGER_AUTH_FAILED |
alvarolb | 0:b75d784c7c1a | 107 | }; |
alvarolb | 0:b75d784c7c1a | 108 | |
alvarolb | 0:b75d784c7c1a | 109 | virtual void thinger_state_listener(THINGER_STATE state){ |
alvarolb | 0:b75d784c7c1a | 110 | #ifdef _DEBUG_ |
alvarolb | 0:b75d784c7c1a | 111 | switch(state){ |
alvarolb | 0:b75d784c7c1a | 112 | case NETWORK_CONNECTING: |
alvarolb | 0:b75d784c7c1a | 113 | printf("[NETWORK] Starting connection...\n"); |
alvarolb | 0:b75d784c7c1a | 114 | break; |
alvarolb | 0:b75d784c7c1a | 115 | case NETWORK_CONNECTED: |
alvarolb | 0:b75d784c7c1a | 116 | printf("[NETWORK] Connected!\n"); |
alvarolb | 0:b75d784c7c1a | 117 | break; |
alvarolb | 0:b75d784c7c1a | 118 | case NETWORK_CONNECT_ERROR: |
alvarolb | 0:b75d784c7c1a | 119 | printf("[NETWORK] Cannot connect\n!"); |
alvarolb | 0:b75d784c7c1a | 120 | break; |
alvarolb | 0:b75d784c7c1a | 121 | case SOCKET_CONNECTING: |
alvarolb | 0:b75d784c7c1a | 122 | printf("[_SOCKET] Connecting to %s:%d...\n", THINGER_SERVER, THINGER_PORT); |
alvarolb | 0:b75d784c7c1a | 123 | break; |
alvarolb | 0:b75d784c7c1a | 124 | case SOCKET_CONNECTED: |
alvarolb | 0:b75d784c7c1a | 125 | printf("[_SOCKET] Connected!\n"); |
alvarolb | 0:b75d784c7c1a | 126 | break; |
alvarolb | 0:b75d784c7c1a | 127 | case SOCKET_CONNECTION_ERROR: |
alvarolb | 0:b75d784c7c1a | 128 | printf("[_SOCKET] Error while connecting!\n"); |
alvarolb | 0:b75d784c7c1a | 129 | break; |
alvarolb | 0:b75d784c7c1a | 130 | case SOCKET_DISCONNECTED: |
alvarolb | 0:b75d784c7c1a | 131 | printf("[_SOCKET] Is now closed!\n"); |
alvarolb | 0:b75d784c7c1a | 132 | break; |
alvarolb | 0:b75d784c7c1a | 133 | case SOCKET_TIMEOUT: |
alvarolb | 0:b75d784c7c1a | 134 | printf("[_SOCKET] Timeout!\n"); |
alvarolb | 0:b75d784c7c1a | 135 | break; |
alvarolb | 0:b75d784c7c1a | 136 | case THINGER_AUTHENTICATING: |
alvarolb | 0:b75d784c7c1a | 137 | printf("[THINGER] Authenticating. User: %s Device: %s\n", username_, device_id_); |
alvarolb | 0:b75d784c7c1a | 138 | break; |
alvarolb | 0:b75d784c7c1a | 139 | case THINGER_AUTHENTICATED: |
alvarolb | 0:b75d784c7c1a | 140 | printf("[THINGER] Authenticated!\n"); |
alvarolb | 0:b75d784c7c1a | 141 | break; |
alvarolb | 0:b75d784c7c1a | 142 | case THINGER_AUTH_FAILED: |
alvarolb | 0:b75d784c7c1a | 143 | printf("[THINGER] Auth Failed! Check username, device id, or device credentials.\n"); |
alvarolb | 0:b75d784c7c1a | 144 | break; |
alvarolb | 0:b75d784c7c1a | 145 | } |
alvarolb | 0:b75d784c7c1a | 146 | #endif |
alvarolb | 0:b75d784c7c1a | 147 | } |
alvarolb | 0:b75d784c7c1a | 148 | |
alvarolb | 0:b75d784c7c1a | 149 | bool handle_connection() |
alvarolb | 0:b75d784c7c1a | 150 | { |
alvarolb | 0:b75d784c7c1a | 151 | bool network = network_connected(); |
alvarolb | 0:b75d784c7c1a | 152 | |
alvarolb | 0:b75d784c7c1a | 153 | if(!network){ |
alvarolb | 0:b75d784c7c1a | 154 | thinger_state_listener(NETWORK_CONNECTING); |
alvarolb | 0:b75d784c7c1a | 155 | network = connect_network(); |
alvarolb | 0:b75d784c7c1a | 156 | if(!network){ |
alvarolb | 0:b75d784c7c1a | 157 | thinger_state_listener(NETWORK_CONNECT_ERROR); |
alvarolb | 0:b75d784c7c1a | 158 | return false; |
alvarolb | 0:b75d784c7c1a | 159 | } |
alvarolb | 0:b75d784c7c1a | 160 | thinger_state_listener(NETWORK_CONNECTED); |
alvarolb | 0:b75d784c7c1a | 161 | } |
alvarolb | 0:b75d784c7c1a | 162 | |
alvarolb | 0:b75d784c7c1a | 163 | bool client = socket_connected(); |
alvarolb | 0:b75d784c7c1a | 164 | if(!client){ |
alvarolb | 0:b75d784c7c1a | 165 | client = connect_client(); |
alvarolb | 0:b75d784c7c1a | 166 | if(!client){ |
alvarolb | 0:b75d784c7c1a | 167 | return false; |
alvarolb | 0:b75d784c7c1a | 168 | } |
alvarolb | 0:b75d784c7c1a | 169 | } |
alvarolb | 0:b75d784c7c1a | 170 | return network && client; |
alvarolb | 0:b75d784c7c1a | 171 | } |
alvarolb | 0:b75d784c7c1a | 172 | |
alvarolb | 0:b75d784c7c1a | 173 | bool connect_client(){ |
alvarolb | 0:b75d784c7c1a | 174 | bool connected = false; |
alvarolb | 0:b75d784c7c1a | 175 | socket_stop(); // cleanup previous socket |
alvarolb | 0:b75d784c7c1a | 176 | thinger_state_listener(SOCKET_CONNECTING); |
alvarolb | 0:b75d784c7c1a | 177 | if (socket_start(THINGER_SERVER, THINGER_PORT)) { |
alvarolb | 0:b75d784c7c1a | 178 | thinger_state_listener(SOCKET_CONNECTED); |
alvarolb | 0:b75d784c7c1a | 179 | thinger_state_listener(THINGER_AUTHENTICATING); |
alvarolb | 0:b75d784c7c1a | 180 | connected = thinger::thinger::connect(username_, device_id_, device_password_); |
alvarolb | 0:b75d784c7c1a | 181 | if(!connected){ |
alvarolb | 0:b75d784c7c1a | 182 | thinger_state_listener(THINGER_AUTH_FAILED); |
alvarolb | 0:b75d784c7c1a | 183 | socket_stop(); |
alvarolb | 0:b75d784c7c1a | 184 | thinger_state_listener(SOCKET_DISCONNECTED); |
alvarolb | 0:b75d784c7c1a | 185 | } |
alvarolb | 0:b75d784c7c1a | 186 | else{ |
alvarolb | 0:b75d784c7c1a | 187 | thinger_state_listener(THINGER_AUTHENTICATED); |
alvarolb | 0:b75d784c7c1a | 188 | } |
alvarolb | 0:b75d784c7c1a | 189 | } |
alvarolb | 0:b75d784c7c1a | 190 | else{ |
alvarolb | 0:b75d784c7c1a | 191 | thinger_state_listener(SOCKET_CONNECTION_ERROR); |
alvarolb | 0:b75d784c7c1a | 192 | } |
alvarolb | 0:b75d784c7c1a | 193 | return connected; |
alvarolb | 0:b75d784c7c1a | 194 | } |
alvarolb | 0:b75d784c7c1a | 195 | |
alvarolb | 0:b75d784c7c1a | 196 | public: |
alvarolb | 0:b75d784c7c1a | 197 | |
alvarolb | 0:b75d784c7c1a | 198 | void handle(){ |
alvarolb | 0:b75d784c7c1a | 199 | if(handle_connection()){ |
alvarolb | 0:b75d784c7c1a | 200 | #ifdef _DEBUG_ |
alvarolb | 0:b75d784c7c1a | 201 | int available = socket_available(); |
alvarolb | 0:b75d784c7c1a | 202 | if(available>0){ |
alvarolb | 0:b75d784c7c1a | 203 | printf("[THINGER] Available bytes: %d\n", available); |
alvarolb | 0:b75d784c7c1a | 204 | } |
alvarolb | 0:b75d784c7c1a | 205 | #endif |
alvarolb | 0:b75d784c7c1a | 206 | thinger::thinger::handle(us_ticker_read()/1000, available>0); |
alvarolb | 0:b75d784c7c1a | 207 | }else{ |
alvarolb | 0:b75d784c7c1a | 208 | wait(RECONNECTION_TIMEOUT); // get some delay for a connection retry |
alvarolb | 0:b75d784c7c1a | 209 | } |
alvarolb | 0:b75d784c7c1a | 210 | } |
alvarolb | 0:b75d784c7c1a | 211 | |
alvarolb | 0:b75d784c7c1a | 212 | private: |
alvarolb | 0:b75d784c7c1a | 213 | const char* username_; |
alvarolb | 0:b75d784c7c1a | 214 | const char* device_id_; |
alvarolb | 0:b75d784c7c1a | 215 | const char* device_password_; |
alvarolb | 0:b75d784c7c1a | 216 | char * temp_data_; |
alvarolb | 0:b75d784c7c1a | 217 | size_t out_size_; |
alvarolb | 0:b75d784c7c1a | 218 | }; |
alvarolb | 0:b75d784c7c1a | 219 | |
alvarolb | 0:b75d784c7c1a | 220 | #endif |