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@4:de51256455f7, 2015-12-26 (annotated)
- Committer:
- alvarolb
- Date:
- Sat Dec 26 13:18:01 2015 +0000
- Revision:
- 4:de51256455f7
- Parent:
- 3:58e0153dbb37
Adapter pson to properly work in ARM Mbed old compiler
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 | 2:8c6f158b95c3 | 39 | class ThingerClient : public thinger::thinger |
alvarolb | 2:8c6f158b95c3 | 40 | { |
alvarolb | 0:b75d784c7c1a | 41 | public: |
alvarolb | 0:b75d784c7c1a | 42 | ThingerClient(const char* user, const char* device, const char* device_credential) : |
alvarolb | 2:8c6f158b95c3 | 43 | username_(user), device_id_(device), device_password_(device_credential), |
alvarolb | 2:8c6f158b95c3 | 44 | temp_data_(NULL), out_size_(0) |
alvarolb | 0:b75d784c7c1a | 45 | {} |
alvarolb | 0:b75d784c7c1a | 46 | |
alvarolb | 0:b75d784c7c1a | 47 | virtual ~ThingerClient() |
alvarolb | 0:b75d784c7c1a | 48 | {} |
alvarolb | 0:b75d784c7c1a | 49 | |
alvarolb | 0:b75d784c7c1a | 50 | protected: |
alvarolb | 2:8c6f158b95c3 | 51 | /** Connect to the given host and port |
alvarolb | 2:8c6f158b95c3 | 52 | * Initialize a socket and connect it to the given host and port |
alvarolb | 2:8c6f158b95c3 | 53 | * \param host the host address to use |
alvarolb | 2:8c6f158b95c3 | 54 | * \param port the host port to connect to |
alvarolb | 2:8c6f158b95c3 | 55 | * \return true on success, or false on failure |
alvarolb | 2:8c6f158b95c3 | 56 | */ |
alvarolb | 0:b75d784c7c1a | 57 | virtual bool socket_start(const char* host, int port) = 0; |
alvarolb | 2:8c6f158b95c3 | 58 | |
alvarolb | 2:8c6f158b95c3 | 59 | /** Stop the current socket connection |
alvarolb | 2:8c6f158b95c3 | 60 | * \return true on success, or false on failure |
alvarolb | 2:8c6f158b95c3 | 61 | */ |
alvarolb | 0:b75d784c7c1a | 62 | virtual bool socket_stop() = 0; |
alvarolb | 2:8c6f158b95c3 | 63 | |
alvarolb | 2:8c6f158b95c3 | 64 | /** Check if the socket is connected |
alvarolb | 2:8c6f158b95c3 | 65 | * \return true on socket connected, or false on disconnected |
alvarolb | 2:8c6f158b95c3 | 66 | */ |
alvarolb | 0:b75d784c7c1a | 67 | virtual bool socket_connected() = 0; |
alvarolb | 2:8c6f158b95c3 | 68 | |
alvarolb | 2:8c6f158b95c3 | 69 | /** Read all specified bytes from socket to buffer |
alvarolb | 2:8c6f158b95c3 | 70 | * \return the number of bytes read |
alvarolb | 2:8c6f158b95c3 | 71 | */ |
alvarolb | 0:b75d784c7c1a | 72 | virtual size_t socket_read(char* buffer, size_t size) = 0; |
alvarolb | 2:8c6f158b95c3 | 73 | |
alvarolb | 3:58e0153dbb37 | 74 | /** Write all specified bytes from buffer to socket |
alvarolb | 2:8c6f158b95c3 | 75 | * \return the number of bytes written |
alvarolb | 2:8c6f158b95c3 | 76 | */ |
alvarolb | 0:b75d784c7c1a | 77 | virtual size_t socket_write(char* buffer, size_t size) = 0; |
alvarolb | 2:8c6f158b95c3 | 78 | |
alvarolb | 3:58e0153dbb37 | 79 | /** Check the total available data in the socket |
alvarolb | 2:8c6f158b95c3 | 80 | * \return Ideally, the number of bytes available in the socket, or any positive number if there is pending data. 0 Otherwise. |
alvarolb | 2:8c6f158b95c3 | 81 | */ |
alvarolb | 0:b75d784c7c1a | 82 | virtual size_t socket_available() = 0; |
alvarolb | 2:8c6f158b95c3 | 83 | |
alvarolb | 3:58e0153dbb37 | 84 | /** Initialize the network interface, i.e., initialize ethernet interface, get ip address, etc. |
alvarolb | 2:8c6f158b95c3 | 85 | * \return the number of bytes read |
alvarolb | 2:8c6f158b95c3 | 86 | */ |
alvarolb | 0:b75d784c7c1a | 87 | virtual bool connect_network() = 0; |
alvarolb | 2:8c6f158b95c3 | 88 | |
alvarolb | 3:58e0153dbb37 | 89 | /** Check if the network is still connected |
alvarolb | 2:8c6f158b95c3 | 90 | * \return true if the network is connected, or false ortherwise |
alvarolb | 2:8c6f158b95c3 | 91 | */ |
alvarolb | 0:b75d784c7c1a | 92 | virtual bool network_connected() = 0; |
alvarolb | 0:b75d784c7c1a | 93 | |
alvarolb | 2:8c6f158b95c3 | 94 | virtual bool read(char *buffer, size_t size) { |
alvarolb | 0:b75d784c7c1a | 95 | size_t total_read = 0; |
alvarolb | 2:8c6f158b95c3 | 96 | while(total_read<size) { |
alvarolb | 0:b75d784c7c1a | 97 | int read = socket_read(buffer, size-total_read); |
alvarolb | 0:b75d784c7c1a | 98 | if(read<0) return false; |
alvarolb | 0:b75d784c7c1a | 99 | total_read += read; |
alvarolb | 0:b75d784c7c1a | 100 | } |
alvarolb | 0:b75d784c7c1a | 101 | return total_read == size; |
alvarolb | 0:b75d784c7c1a | 102 | } |
alvarolb | 0:b75d784c7c1a | 103 | |
alvarolb | 0:b75d784c7c1a | 104 | // TODO Allow removing this Nagle's algorithm implementation if the underlying device already implements it |
alvarolb | 2:8c6f158b95c3 | 105 | virtual bool write(const char *buffer, size_t size, bool flush = false) { |
alvarolb | 2:8c6f158b95c3 | 106 | if(size>0) { |
alvarolb | 0:b75d784c7c1a | 107 | temp_data_ = (char*) realloc(temp_data_, out_size_ + size); |
alvarolb | 0:b75d784c7c1a | 108 | memcpy(&temp_data_[out_size_], buffer, size); |
alvarolb | 0:b75d784c7c1a | 109 | out_size_ += size; |
alvarolb | 0:b75d784c7c1a | 110 | } |
alvarolb | 2:8c6f158b95c3 | 111 | if(flush && out_size_>0) { |
alvarolb | 0:b75d784c7c1a | 112 | size_t written = socket_write(temp_data_, out_size_); |
alvarolb | 0:b75d784c7c1a | 113 | bool success = written == out_size_; |
alvarolb | 0:b75d784c7c1a | 114 | free(temp_data_); |
alvarolb | 0:b75d784c7c1a | 115 | temp_data_ = NULL; |
alvarolb | 0:b75d784c7c1a | 116 | out_size_ = 0; |
alvarolb | 0:b75d784c7c1a | 117 | return success; |
alvarolb | 0:b75d784c7c1a | 118 | } |
alvarolb | 0:b75d784c7c1a | 119 | return true; |
alvarolb | 0:b75d784c7c1a | 120 | } |
alvarolb | 0:b75d784c7c1a | 121 | |
alvarolb | 2:8c6f158b95c3 | 122 | virtual void disconnected() { |
alvarolb | 0:b75d784c7c1a | 123 | thinger_state_listener(SOCKET_TIMEOUT); |
alvarolb | 0:b75d784c7c1a | 124 | socket_stop(); |
alvarolb | 0:b75d784c7c1a | 125 | thinger_state_listener(SOCKET_DISCONNECTED); |
alvarolb | 0:b75d784c7c1a | 126 | } |
alvarolb | 2:8c6f158b95c3 | 127 | |
alvarolb | 2:8c6f158b95c3 | 128 | enum THINGER_STATE { |
alvarolb | 0:b75d784c7c1a | 129 | NETWORK_CONNECTING, |
alvarolb | 0:b75d784c7c1a | 130 | NETWORK_CONNECTED, |
alvarolb | 0:b75d784c7c1a | 131 | NETWORK_CONNECT_ERROR, |
alvarolb | 0:b75d784c7c1a | 132 | SOCKET_CONNECTING, |
alvarolb | 0:b75d784c7c1a | 133 | SOCKET_CONNECTED, |
alvarolb | 0:b75d784c7c1a | 134 | SOCKET_CONNECTION_ERROR, |
alvarolb | 0:b75d784c7c1a | 135 | SOCKET_DISCONNECTED, |
alvarolb | 0:b75d784c7c1a | 136 | SOCKET_TIMEOUT, |
alvarolb | 0:b75d784c7c1a | 137 | THINGER_AUTHENTICATING, |
alvarolb | 0:b75d784c7c1a | 138 | THINGER_AUTHENTICATED, |
alvarolb | 0:b75d784c7c1a | 139 | THINGER_AUTH_FAILED |
alvarolb | 0:b75d784c7c1a | 140 | }; |
alvarolb | 0:b75d784c7c1a | 141 | |
alvarolb | 2:8c6f158b95c3 | 142 | virtual void thinger_state_listener(THINGER_STATE state) { |
alvarolb | 2:8c6f158b95c3 | 143 | #ifdef _DEBUG_ |
alvarolb | 2:8c6f158b95c3 | 144 | switch(state) { |
alvarolb | 0:b75d784c7c1a | 145 | case NETWORK_CONNECTING: |
alvarolb | 0:b75d784c7c1a | 146 | printf("[NETWORK] Starting connection...\n"); |
alvarolb | 0:b75d784c7c1a | 147 | break; |
alvarolb | 0:b75d784c7c1a | 148 | case NETWORK_CONNECTED: |
alvarolb | 0:b75d784c7c1a | 149 | printf("[NETWORK] Connected!\n"); |
alvarolb | 0:b75d784c7c1a | 150 | break; |
alvarolb | 0:b75d784c7c1a | 151 | case NETWORK_CONNECT_ERROR: |
alvarolb | 0:b75d784c7c1a | 152 | printf("[NETWORK] Cannot connect\n!"); |
alvarolb | 0:b75d784c7c1a | 153 | break; |
alvarolb | 0:b75d784c7c1a | 154 | case SOCKET_CONNECTING: |
alvarolb | 0:b75d784c7c1a | 155 | printf("[_SOCKET] Connecting to %s:%d...\n", THINGER_SERVER, THINGER_PORT); |
alvarolb | 0:b75d784c7c1a | 156 | break; |
alvarolb | 0:b75d784c7c1a | 157 | case SOCKET_CONNECTED: |
alvarolb | 0:b75d784c7c1a | 158 | printf("[_SOCKET] Connected!\n"); |
alvarolb | 0:b75d784c7c1a | 159 | break; |
alvarolb | 0:b75d784c7c1a | 160 | case SOCKET_CONNECTION_ERROR: |
alvarolb | 0:b75d784c7c1a | 161 | printf("[_SOCKET] Error while connecting!\n"); |
alvarolb | 0:b75d784c7c1a | 162 | break; |
alvarolb | 0:b75d784c7c1a | 163 | case SOCKET_DISCONNECTED: |
alvarolb | 0:b75d784c7c1a | 164 | printf("[_SOCKET] Is now closed!\n"); |
alvarolb | 0:b75d784c7c1a | 165 | break; |
alvarolb | 0:b75d784c7c1a | 166 | case SOCKET_TIMEOUT: |
alvarolb | 0:b75d784c7c1a | 167 | printf("[_SOCKET] Timeout!\n"); |
alvarolb | 0:b75d784c7c1a | 168 | break; |
alvarolb | 0:b75d784c7c1a | 169 | case THINGER_AUTHENTICATING: |
alvarolb | 0:b75d784c7c1a | 170 | printf("[THINGER] Authenticating. User: %s Device: %s\n", username_, device_id_); |
alvarolb | 0:b75d784c7c1a | 171 | break; |
alvarolb | 0:b75d784c7c1a | 172 | case THINGER_AUTHENTICATED: |
alvarolb | 0:b75d784c7c1a | 173 | printf("[THINGER] Authenticated!\n"); |
alvarolb | 0:b75d784c7c1a | 174 | break; |
alvarolb | 0:b75d784c7c1a | 175 | case THINGER_AUTH_FAILED: |
alvarolb | 0:b75d784c7c1a | 176 | printf("[THINGER] Auth Failed! Check username, device id, or device credentials.\n"); |
alvarolb | 0:b75d784c7c1a | 177 | break; |
alvarolb | 0:b75d784c7c1a | 178 | } |
alvarolb | 2:8c6f158b95c3 | 179 | #endif |
alvarolb | 0:b75d784c7c1a | 180 | } |
alvarolb | 0:b75d784c7c1a | 181 | |
alvarolb | 2:8c6f158b95c3 | 182 | bool handle_connection() { |
alvarolb | 0:b75d784c7c1a | 183 | bool network = network_connected(); |
alvarolb | 0:b75d784c7c1a | 184 | |
alvarolb | 2:8c6f158b95c3 | 185 | if(!network) { |
alvarolb | 0:b75d784c7c1a | 186 | thinger_state_listener(NETWORK_CONNECTING); |
alvarolb | 0:b75d784c7c1a | 187 | network = connect_network(); |
alvarolb | 2:8c6f158b95c3 | 188 | if(!network) { |
alvarolb | 0:b75d784c7c1a | 189 | thinger_state_listener(NETWORK_CONNECT_ERROR); |
alvarolb | 0:b75d784c7c1a | 190 | return false; |
alvarolb | 0:b75d784c7c1a | 191 | } |
alvarolb | 0:b75d784c7c1a | 192 | thinger_state_listener(NETWORK_CONNECTED); |
alvarolb | 0:b75d784c7c1a | 193 | } |
alvarolb | 0:b75d784c7c1a | 194 | |
alvarolb | 0:b75d784c7c1a | 195 | bool client = socket_connected(); |
alvarolb | 2:8c6f158b95c3 | 196 | if(!client) { |
alvarolb | 0:b75d784c7c1a | 197 | client = connect_client(); |
alvarolb | 2:8c6f158b95c3 | 198 | if(!client) { |
alvarolb | 0:b75d784c7c1a | 199 | return false; |
alvarolb | 0:b75d784c7c1a | 200 | } |
alvarolb | 0:b75d784c7c1a | 201 | } |
alvarolb | 0:b75d784c7c1a | 202 | return network && client; |
alvarolb | 0:b75d784c7c1a | 203 | } |
alvarolb | 0:b75d784c7c1a | 204 | |
alvarolb | 2:8c6f158b95c3 | 205 | bool connect_client() { |
alvarolb | 0:b75d784c7c1a | 206 | bool connected = false; |
alvarolb | 0:b75d784c7c1a | 207 | socket_stop(); // cleanup previous socket |
alvarolb | 0:b75d784c7c1a | 208 | thinger_state_listener(SOCKET_CONNECTING); |
alvarolb | 0:b75d784c7c1a | 209 | if (socket_start(THINGER_SERVER, THINGER_PORT)) { |
alvarolb | 0:b75d784c7c1a | 210 | thinger_state_listener(SOCKET_CONNECTED); |
alvarolb | 0:b75d784c7c1a | 211 | thinger_state_listener(THINGER_AUTHENTICATING); |
alvarolb | 0:b75d784c7c1a | 212 | connected = thinger::thinger::connect(username_, device_id_, device_password_); |
alvarolb | 2:8c6f158b95c3 | 213 | if(!connected) { |
alvarolb | 0:b75d784c7c1a | 214 | thinger_state_listener(THINGER_AUTH_FAILED); |
alvarolb | 0:b75d784c7c1a | 215 | socket_stop(); |
alvarolb | 0:b75d784c7c1a | 216 | thinger_state_listener(SOCKET_DISCONNECTED); |
alvarolb | 2:8c6f158b95c3 | 217 | } else { |
alvarolb | 0:b75d784c7c1a | 218 | thinger_state_listener(THINGER_AUTHENTICATED); |
alvarolb | 0:b75d784c7c1a | 219 | } |
alvarolb | 2:8c6f158b95c3 | 220 | } else { |
alvarolb | 0:b75d784c7c1a | 221 | thinger_state_listener(SOCKET_CONNECTION_ERROR); |
alvarolb | 0:b75d784c7c1a | 222 | } |
alvarolb | 0:b75d784c7c1a | 223 | return connected; |
alvarolb | 0:b75d784c7c1a | 224 | } |
alvarolb | 0:b75d784c7c1a | 225 | |
alvarolb | 0:b75d784c7c1a | 226 | public: |
alvarolb | 0:b75d784c7c1a | 227 | |
alvarolb | 2:8c6f158b95c3 | 228 | void handle() { |
alvarolb | 2:8c6f158b95c3 | 229 | if(handle_connection()) { |
alvarolb | 0:b75d784c7c1a | 230 | int available = socket_available(); |
alvarolb | 2:8c6f158b95c3 | 231 | #ifdef _DEBUG_ |
alvarolb | 2:8c6f158b95c3 | 232 | if(available>0) { |
alvarolb | 0:b75d784c7c1a | 233 | printf("[THINGER] Available bytes: %d\n", available); |
alvarolb | 0:b75d784c7c1a | 234 | } |
alvarolb | 2:8c6f158b95c3 | 235 | #endif |
alvarolb | 0:b75d784c7c1a | 236 | thinger::thinger::handle(us_ticker_read()/1000, available>0); |
alvarolb | 2:8c6f158b95c3 | 237 | } else { |
alvarolb | 0:b75d784c7c1a | 238 | wait(RECONNECTION_TIMEOUT); // get some delay for a connection retry |
alvarolb | 0:b75d784c7c1a | 239 | } |
alvarolb | 0:b75d784c7c1a | 240 | } |
alvarolb | 0:b75d784c7c1a | 241 | |
alvarolb | 0:b75d784c7c1a | 242 | private: |
alvarolb | 0:b75d784c7c1a | 243 | const char* username_; |
alvarolb | 0:b75d784c7c1a | 244 | const char* device_id_; |
alvarolb | 0:b75d784c7c1a | 245 | const char* device_password_; |
alvarolb | 0:b75d784c7c1a | 246 | char * temp_data_; |
alvarolb | 0:b75d784c7c1a | 247 | size_t out_size_; |
alvarolb | 0:b75d784c7c1a | 248 | }; |
alvarolb | 0:b75d784c7c1a | 249 | |
alvarolb | 0:b75d784c7c1a | 250 | #endif |