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:
Thu Dec 24 13:18:08 2015 +0000
Revision:
0:b75d784c7c1a
Child:
2:8c6f158b95c3
Initial Commit

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