/*
 * guards.hpp
 *
 *  Created on: 31 мая 2020 г.
 *      Author: netuser
 */

#ifndef LIB_GUARDS_HPP_
#define LIB_GUARDS_HPP_



// восстанавливает значение переменной по выходе из блока.
template <typename T, T out_value>
class ValueScopeGuard {
public:
    typedef T type_t;
    ValueScopeGuard(T& _x):x(&_x){}
    ~ValueScopeGuard() {*x = out_value;}
protected:
    type_t* x;
};



//-----------------------------------------------------------------------------

// this is lock with value, wich is keep after release, and assigns on lock aquire
// need for some confurable connection sharing

struct ValuedLock{
    public:
    //конструктор добавляет лишнего в структуру
    //ValuedLock(): value(NULL), lock(false) {};

    public:
        typedef void* value_t;

        value_t  value;

        inline
        bool     is_locked() const {return lock;}

        inline
        bool     aquire( value_t x ) {
            if (!lock){
                lock = true;
                value = x;
                return true;
            }
            else
                return false;
        }

        inline
        void     release(){
            lock = false;
        }

    protected:
        bool     lock;
};

// синглетный селектор с флагом блокировки на порт
// позволит произвольно устанавливать точки доступа блокировке на один общий порт.
//  ИСПОЛЬЗОВАНИЕ:
//      class dev1{
//          // доступ к общей блокировке UART1_port
//          PortSingleLock<UARTDevicce, UART1_port> access;
//          ...
//      };
//      class dev2{
//          // доступ к общей блокировке UART1_port
//          PortSingleLock<UARTDevicce, UART1_port> access;
//          ...
//      };
//      void touch_uart1(){
//          // доступ к общей блокировке UART1_port
//          PortSingleLock<UARTDevicce, UART1_port> access;
//
//          //свободный порт хранит свое последнее состояние
//          bool same = (access.value() == uartsel);
//          access.aquire( uartsel );
//          ...
//          access.release();
//      }
template<typename T, T& adress>
class PortSingleLock{
    public:
        //static const u32 port_addr = (u32)(adress);
        typedef T port_t;
        static T&  port() {return adress;}
    public:
        typedef ValuedLock self_t;

        static bool     is_locked() {return single().is_locked();}
        static bool     aquire( self_t::value_t x ) {return single().aquire(x);}
        static void     release(){single().release();}
        static self_t::value_t value() {return single().value;}

    protected:
        static self_t& single(){
            static self_t value;
            return value;
        }
};



// глобальный асинхронный сигнал сделан по мотиву contiki semaphore:
//      глобальный счетчик источника сигнала, и локальный счетчик просмотреного
//      сигнала     - догоняет источник.
//      give()      - сигналит всем обозревателям сигнала
//      try_take()  - true если был новый сигнал, и запоминает что он получен
template<int id>
class GlogalSignal {
    public:

    // забирает имеющийся сигнал
    // \return true - есть непросмотреный глобальный сигнал
    bool try_take(){
        unsigned now = single().stamp;
        if (now == my_stamp)
            return false;
        my_stamp = now;
        return true;
    }

    // сигналит всем обозревателям сигнала
    static bool give(){
        // TODO: сделать атомарно!!!
        single().stamp++;
        return ptOK;
    }

    protected:
        unsigned    my_stamp;
        struct self_t{
            unsigned stamp;
        };

        static self_t& single(){
            static self_t value = {0};
            return value;
        }
};



#endif /* LIB_GUARDS_HPP_ */
