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 Alvaro Luis Bustamante

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?

UserRevisionLine numberNew 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