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

Revision:
0:b75d784c7c1a
Child:
2:8c6f158b95c3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ThingerClient.h	Thu Dec 24 13:18:08 2015 +0000
@@ -0,0 +1,220 @@
+// The MIT License (MIT)
+//
+// Copyright (c) 2015 THINGER LTD
+// Author: alvarolb@gmail.com (Alvaro Luis Bustamante)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef THINGER_CLIENT_H
+#define THINGER_CLIENT_H
+
+#include "thinger/thinger.h"
+
+using namespace protoson;
+
+dynamic_memory_allocator alloc;
+//circular_memory_allocator<512> alloc;
+memory_allocator& protoson::pool = alloc;
+
+#define THINGER_SERVER "iot.thinger.io"
+#define THINGER_PORT 25200
+#define RECONNECTION_TIMEOUT 5 // seconds
+
+class ThingerClient : public thinger::thinger {
+public:
+    ThingerClient(const char* user, const char* device, const char* device_credential) :
+            username_(user), device_id_(device), device_password_(device_credential),
+            temp_data_(NULL), out_size_(0)
+    {}
+
+    virtual ~ThingerClient()
+    {}
+
+protected:
+
+    virtual bool    socket_start(const char* host, int port) = 0;
+    virtual bool    socket_stop() = 0;
+    virtual bool    socket_connected() = 0;
+    virtual size_t  socket_read(char* buffer, size_t size) = 0;
+    virtual size_t  socket_write(char* buffer, size_t size) = 0;
+    virtual size_t  socket_available() = 0;
+    virtual bool    connect_network() = 0;
+    virtual bool    network_connected() = 0;
+
+    virtual bool read(char *buffer, size_t size)
+    {
+        size_t total_read = 0;
+        while(total_read<size){
+            int read = socket_read(buffer, size-total_read);
+            if(read<0) return false;
+            total_read += read;
+        }
+        return total_read == size;
+    }
+
+    // TODO Allow removing this Nagle's algorithm implementation if the underlying device already implements it
+    virtual bool write(const char *buffer, size_t size, bool flush = false){
+        if(size>0){
+            temp_data_ = (char*) realloc(temp_data_, out_size_ + size);
+            memcpy(&temp_data_[out_size_], buffer, size);
+            out_size_ += size;
+        }
+        if(flush && out_size_>0){
+            size_t written = socket_write(temp_data_, out_size_);
+            bool success = written == out_size_;
+            free(temp_data_);
+            temp_data_ = NULL;
+            out_size_ = 0;
+            return success;
+        }
+        return true;
+    }
+
+    virtual void disconnected(){
+        thinger_state_listener(SOCKET_TIMEOUT);
+        socket_stop();
+        thinger_state_listener(SOCKET_DISCONNECTED);
+    }
+    
+    enum THINGER_STATE{
+        NETWORK_CONNECTING,
+        NETWORK_CONNECTED,
+        NETWORK_CONNECT_ERROR,
+        SOCKET_CONNECTING,
+        SOCKET_CONNECTED,
+        SOCKET_CONNECTION_ERROR,
+        SOCKET_DISCONNECTED,
+        SOCKET_TIMEOUT,
+        THINGER_AUTHENTICATING,
+        THINGER_AUTHENTICATED,
+        THINGER_AUTH_FAILED
+    };
+
+    virtual void thinger_state_listener(THINGER_STATE state){
+        #ifdef _DEBUG_
+        switch(state){
+            case NETWORK_CONNECTING:
+                printf("[NETWORK] Starting connection...\n");
+                break;
+            case NETWORK_CONNECTED:
+                printf("[NETWORK] Connected!\n");
+                break;
+            case NETWORK_CONNECT_ERROR:
+                printf("[NETWORK] Cannot connect\n!");
+                break;
+            case SOCKET_CONNECTING:
+                printf("[_SOCKET] Connecting to %s:%d...\n", THINGER_SERVER, THINGER_PORT);
+                break;
+            case SOCKET_CONNECTED:
+                printf("[_SOCKET] Connected!\n");
+                break;
+            case SOCKET_CONNECTION_ERROR:
+                printf("[_SOCKET] Error while connecting!\n");
+                break;
+            case SOCKET_DISCONNECTED:
+                printf("[_SOCKET] Is now closed!\n");
+                break;
+            case SOCKET_TIMEOUT:
+                printf("[_SOCKET] Timeout!\n");
+                break;
+            case THINGER_AUTHENTICATING:
+                printf("[THINGER] Authenticating. User: %s Device: %s\n", username_, device_id_);
+                break;
+            case THINGER_AUTHENTICATED:
+                printf("[THINGER] Authenticated!\n");
+                break;
+            case THINGER_AUTH_FAILED:
+                printf("[THINGER] Auth Failed! Check username, device id, or device credentials.\n");
+                break;
+        }
+        #endif
+    }
+
+    bool handle_connection()
+    {
+        bool network = network_connected();
+
+        if(!network){
+            thinger_state_listener(NETWORK_CONNECTING);
+            network = connect_network();
+            if(!network){
+                thinger_state_listener(NETWORK_CONNECT_ERROR);
+                return false;
+            }
+            thinger_state_listener(NETWORK_CONNECTED);
+        }
+
+        bool client = socket_connected();
+        if(!client){
+            client = connect_client();
+            if(!client){
+                return false;
+            }
+        }
+        return network && client;
+    }
+
+    bool connect_client(){
+        bool connected = false;
+        socket_stop(); // cleanup previous socket
+        thinger_state_listener(SOCKET_CONNECTING);
+        if (socket_start(THINGER_SERVER, THINGER_PORT)) {
+            thinger_state_listener(SOCKET_CONNECTED);
+            thinger_state_listener(THINGER_AUTHENTICATING);
+            connected = thinger::thinger::connect(username_, device_id_, device_password_);
+            if(!connected){
+                thinger_state_listener(THINGER_AUTH_FAILED);
+                socket_stop();
+                thinger_state_listener(SOCKET_DISCONNECTED);
+            }
+            else{
+                thinger_state_listener(THINGER_AUTHENTICATED);
+            }
+        }
+        else{
+            thinger_state_listener(SOCKET_CONNECTION_ERROR);
+        }
+        return connected;
+    }
+
+public:
+
+    void handle(){
+        if(handle_connection()){
+            #ifdef _DEBUG_
+            int available = socket_available();
+            if(available>0){
+                printf("[THINGER] Available bytes: %d\n", available);
+            }
+            #endif
+            thinger::thinger::handle(us_ticker_read()/1000, available>0);
+        }else{
+            wait(RECONNECTION_TIMEOUT); // get some delay for a connection retry
+        }
+    }
+
+private:
+    const char* username_;
+    const char* device_id_;
+    const char* device_password_;
+    char * temp_data_;
+    size_t out_size_;
+};
+
+#endif
\ No newline at end of file