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

thinger/thinger_resource.hpp

Committer:
alvarolb
Date:
2015-12-24
Revision:
0:b75d784c7c1a
Child:
4:de51256455f7

File content as of revision 0:b75d784c7c1a:

// 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_RESOURCE_HPP
#define THINGER_RESOURCE_HPP

#include "thinger_map.hpp"
#include "pson.h"
#include "thinger_message.hpp"

namespace thinger{


class thinger_resource {

public:
    enum io_type {
        none                = 0,
        run                 = 1,
        pson_in             = 2,
        pson_out            = 3,
        pson_in_pson_out    = 4
    };

    enum access_type{
        PRIVATE     = 0,
        PROTECTED   = 1,
        PUBLIC      = 2,
        NONE        = 3
    };

    static int get_streaming_counter(){
        return streaming_count_;
    }

private:

    // calback for function, input, output, or input/output
    union callback{
        void (*run)();
        void (*pson_in)(protoson::pson& in);
        void (*pson_out)(protoson::pson& out);
        void (*pson_in_pson_out)(protoson::pson& in, protoson::pson& out);
    };

    // used for defining the resource
    io_type io_type_;
    access_type access_type_;
    callback callback_;

    // used for allowing resource streaming (both periodically or by events)
    uint16_t stream_id_;

    // used for periodic stream events
    unsigned long streaming_freq_;
    unsigned long last_streaming_;

    // used to know the total number of streams
    static unsigned int streaming_count_;

    // TODO change to pointer so it is not using more than a pointer size if not used?
    thinger_map<thinger_resource> sub_resources_;

    void enable_streaming(uint16_t stream_id, unsigned long streaming_freq){
        stream_id_ = stream_id;
        streaming_freq_ = streaming_freq;
        last_streaming_ = 0;
        streaming_count_++;
    }

public:
    thinger_resource() : io_type_(none), access_type_(PRIVATE), stream_id_(0), streaming_freq_(0), last_streaming_(0)
    {}

    void disable_streaming(){
        stream_id_ = 0;
        streaming_freq_ = 0;
        streaming_count_--;
    }

    bool stream_enabled(){
        return stream_id_ > 0;
    }

    uint32_t get_stream_id(){
        return stream_id_;
    }

    bool stream_required(unsigned long timestamp){
        // sample interval is activated
        if(streaming_freq_>0){
            if(timestamp-last_streaming_>=streaming_freq_){
                last_streaming_ = timestamp;
                return true;
            }
        }
        return false;
    }

    thinger_resource * find(const char* res)
    {
        return sub_resources_.find(res);
    }

    thinger_resource & operator[](const char* res){
        return sub_resources_[res];
    }

    thinger_resource & operator()(access_type type){
        access_type_ = type;
        return *this;
    }

    io_type get_io_type(){
        return io_type_;
    }

    access_type get_access_type(){
        return access_type_;
    }

    void fill_api(protoson::pson_object& content){
        if(io_type_!=none){
            content["al"] = access_type_;
            content["fn"] = io_type_;
        }
        thinger_map<thinger_resource>::entry* current = sub_resources_.begin();
        if(current!=NULL){
            protoson::pson_object& actions = content["/"];
            do{
                current->value_.fill_api(actions[current->key_]);
                current = current->next_;
            }while(current!=NULL);
        }
    }

    void fill_api_io(protoson::pson_object& content){
        if(io_type_ == pson_in){
            callback_.pson_in(content["in"]);
        }else if(io_type_ == pson_out){
            callback_.pson_out(content["out"]);
        }else if(io_type_ == pson_in_pson_out){
            callback_.pson_in_pson_out(content["in"], content["out"]);
        }
    }

public:

    /**
     * Establish a function without input or output parameters
     */
    void operator=(void (*run_function)()){
        io_type_ = run;
        callback_.run = run_function;
    }

    /**
     * Establish a function without input or output parameters
     */
    void set_function(void (*run_function)()){
        io_type_ = run;
        callback_.run = run_function;
    }

    /**
     * Establish a function with input parameters
     */
    void operator<<(void (*in_function)(protoson::pson& in)){
        io_type_ = pson_in;
        callback_.pson_in = in_function;
    }

    /**
     * Establish a function with input parameters
     */
    void set_input(void (*in_function)(protoson::pson& in)){
        io_type_ = pson_in;
        callback_.pson_in = in_function;
    }

    /**
     * Establish a function that only generates an output
     */
    void operator>>(void (*out_function)(protoson::pson& out)){
        io_type_ = pson_out;
        callback_.pson_out = out_function;
    }

    /**
     * Establish a function that only generates an output
     */
    void set_output(void (*out_function)(protoson::pson& out)){
        io_type_ = pson_out;
        callback_.pson_out = out_function;
    }

    /**
     * Establish a function that can receive input parameters and generate an output
     */
    void operator=(void (*pson_in_pson_out_function)(protoson::pson& in, protoson::pson& out)){
        io_type_ = pson_in_pson_out;
        callback_.pson_in_pson_out = pson_in_pson_out_function;
    }

    /**
     * Establish a function that can receive input parameters and generate an output
     */
    void set_input_output(void (*pson_in_pson_out_function)(protoson::pson& in, protoson::pson& out)){
        io_type_ = pson_in_pson_out;
        callback_.pson_in_pson_out = pson_in_pson_out_function;
    }

    /**
     * Handle a request and fill a possible response
     */
    void handle_request(thinger_message& request, thinger_message& response){
        switch(request.get_signal_flag()){
            // default action over the stream (run the resource)
            case thinger_message::NONE:
                switch (io_type_){
                    case run:
                        callback_.run();
                        break;
                    case pson_in:
                        callback_.pson_in(request);
                        break;
                    case pson_out:
                        callback_.pson_out(response);
                        break;
                    case pson_in_pson_out:
                        callback_.pson_in_pson_out(request, response);
                        break;
                    case none:
                        break;
                }
                break;
            // flag for starting a resource stream
            case thinger_message::START_STREAM:
                enable_streaming(request.get_stream_id(), request.get_data());
                break;
            // flat for stopping a resource stream
            case thinger_message::STOP_STREAM:
                disable_streaming();
                break;
            default:
                break;
        }
    }
};

    unsigned int thinger_resource::streaming_count_ = 0;

}

#endif