Thinger IO Cloude Service Test Example with WIZwiki-W7500

Dependencies:   DHT WIZnetInterface mbed-src

Smart WIZwiki_W7500 IoT platform with the Open source IoT Cloud server thinger.io

http://wiznetmuseum.com/wp/wp-content/uploads/2015/09/WIZwiki_W7500_thingerio.png

Overview

This project is based on mbed WIZwiki-W7500 platform launced by WIZnet. WIZwiki-W7500 can connect to the smart IoT cloud server called thinger.io.

Demos

Video

For more detail

http://midnightcow.tistory.com/entry/mbed-WIZwikiW7500-platform-with-Smart-IoT-Cloud-Server-Thingerio

ThingerIO/ThingerMBedClient.h

Committer:
MidnightCow
Date:
2015-09-24
Revision:
5:c4c405bc6e6d
Parent:
1:fa957f28633b

File content as of revision 5:c4c405bc6e6d:

// 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_MBED_CLIENT_H
#define THINGER_MBED_CLIENT_H

#include "thinger/thinger.h"

//#define _DEBUG_

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 5000 // milliseconds

//---For MBED---//

#ifndef Client
    #define Client              TCPSocketConnectionArdu
#endif

#ifndef millis
    #define millis()        us_ticker_read()/1000
#endif

#ifndef delay    
    #define delay               wait_ms
#endif    


class ThingerClient : public thinger::thinger {


public:
    ThingerClient(Client& client, const char* user, const char* device, const char* device_credential) :
            client_(client), username_(user), device_id_(device), device_password_(device_credential),
            temp_data_(NULL), out_size_(0)
    {

    }

    ~ThingerClient()
    {

    }

protected:

    virtual bool read(char* buffer, size_t size)
    {
        size_t total_read = 0;
        while(total_read<size){
            int read = client_.readBytes((uint8_t*)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_ = (uint8_t*) realloc(temp_data_, out_size_ + size);
            memcpy(&temp_data_[out_size_], buffer, size);
            out_size_ += size;
        }
        if(flush && out_size_>0){
            #ifdef _DEBUG_
            printf("[THINGER] Writing bytes: %d", out_size_);
            #endif

            size_t written = client_.write(temp_data_, out_size_);
            bool success = written == out_size_;
            free(temp_data_);
            temp_data_ = NULL;
            out_size_ = 0;

            #ifdef _DEBUG_
            printf(" [%s]\r\n",success ? "OK" : "FAIL");
            #endif

            //FIXME Without this small delay or activating the debug (which takes time), the CC3200 does not work well. Why?
            #ifdef __CC3200R1M1RGC__
            delay(1);
            #endif
            return success;
        }
        return true;
    }

    virtual void disconnected(){
        thinger_state_listener(SOCKET_TIMEOUT);
        client_.stop();
        thinger_state_listener(SOCKET_DISCONNECTED);
    }

    virtual bool connect_network(){
        return true;
    }

    virtual bool network_connected(){
        return true;
    }

    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...\r\n");
                break;
            case NETWORK_CONNECTED:
                printf("[NETWORK] Connected!\r\n");
                break;
            case NETWORK_CONNECT_ERROR:
                printf("[NETWORK] Cannot connect!\r\n");
                break;
            case SOCKET_CONNECTING:
                printf("[_SOCKET] Connecting to %s : %d ...", THINGER_SERVER,THINGER_PORT);                
                break;
            case SOCKET_CONNECTED:
                printf("[_SOCKET] Connected!\r\n");
                break;
            case SOCKET_CONNECTION_ERROR:
                printf("[_SOCKET] Error while connecting!\r\n");
                break;
            case SOCKET_DISCONNECTED:
                printf("[_SOCKET] Is now closed!\r\n");
                break;
            case SOCKET_TIMEOUT:
                printf("[_SOCKET] Timeout!\r\n");
                break;
            case THINGER_AUTHENTICATING:
                printf("[THINGER] Authenticating. User: %s Device: %s\r\n",username_,device_id_);
                break;
            case THINGER_AUTHENTICATED:
                printf("[THINGER] Authenticated!\r\n");
                break;
            case THINGER_AUTH_FAILED:
                printf("[THINGER] Auth Failed! Check username, device id, or device credentials.\r\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 = client_.connected();
        if(!client){
            client = connect_client();
            if(!client){
                return false;
            }
        }
        return network && client;
    }

    bool connect_client(){
        bool connected = false;
        client_.stop(); // cleanup previous socket
        thinger_state_listener(SOCKET_CONNECTING);
        if (client_.connect(THINGER_SERVER, THINGER_PORT) == 0) {
            delay(3000);
            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);
                client_.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_
            if(client_.available()>0){
                printf("[THINGER] Available bytes: %d", client_.available());
            }
            #endif
            thinger::thinger::handle(millis(), client_.available()>0);
        }else{
            delay(RECONNECTION_TIMEOUT); // get some delay for a connection retry
        }
    }

private:

    Client& client_;
    const char* username_;
    const char* device_id_;
    const char* device_password_;
    uint8_t * temp_data_;
    size_t out_size_;
};

#endif