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-26
Revision:
4:de51256455f7
Parent:
0:b75d784c7c1a

File content as of revision 4:de51256455f7:

// 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;
            if(streaming_freq_==0 && streaming_freq>0){
                streaming_count_++;
            }else if(streaming_freq_>0 && streaming_freq==0){
                streaming_count_--;
            }
            streaming_freq_ = streaming_freq;
            last_streaming_ = 0;
        }

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

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

        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