/*
 * Copyright (C) 2020-2021 Aloysius Indrayanto
 *
 * This file is part of the eCxx library, see LICENSE file for the license details.
 */


#ifndef ECXX_PLATFORM_COMMON_APPLICATION_CRTP_BASE_H
#define ECXX_PLATFORM_COMMON_APPLICATION_CRTP_BASE_H


//
// Include the header for the proper AtomicGuard class implementation
//
#include "AtomicGuard.h"


namespace eCxx {


//
// An application CRTP base class that contains common member types/constants/variables/functions/etc.
//
template <typename ImplementationT>
class Application_CRTPBase : public Uninstantiable {
    public:
        static constexpr uint8_t ActivityIndicatorLEDBlinkDelay = 200;

    public:
        // Shift-out bits, for example using:
        //     # 74HC595 (shift at clock rising edge ; latch pin is active high)
        static inline void shiftOut(uint8_t pinData, uint8_t pinClock, ActiveClockEdge clockEdge, BitOrder bitOrder, uint8_t value);

        static inline void shiftOut(uint8_t pinData, uint8_t pinClock, ActiveClockEdge clockEdge, uint8_t pinLatch, ActiveState pinLatchState, BitOrder bitOrder, const uint8_t* value, uint8_t count);

        template <uint8_t N>
        static inline void shiftOut(uint8_t pinData, uint8_t pinClock, ActiveClockEdge clockEdge, uint8_t pinLatch, ActiveState pinLatchState, BitOrder bitOrder, const uint8_t (&value)[N]);

        // Shift-in bits, for example using:
        //     # 74HC165 (load pin is active low ; shift at clock falling edge)
        static inline uint8_t shiftIn(uint8_t pinData, uint8_t pinClock, ActiveClockEdge clockEdge, BitOrder bitOrder);

        static inline void shiftIn(uint8_t pinData, uint8_t pinClock, ActiveClockEdge clockEdge, uint8_t pinLoad, ActiveState pinLoadState, BitOrder bitOrder, uint8_t* value, uint8_t count);

        template <uint8_t N>
        static inline void shiftIn(uint8_t pinData, uint8_t pinClock, ActiveClockEdge clockEdge, uint8_t pinLoad, ActiveState pinLoadState, BitOrder bitOrder, uint8_t (&value)[N]);

        // Shift-out-and-in bits
        //    # The latch and load pins are assumed to have the same active state
        //    # The hardware must ensure the above condition is met
        template <typename ValueT>

        static inline void shiftOutIn(
            ValueT          valueOut,
            ValueT&         valueIn,
            uint8_t         pinDataOut,
            uint8_t         pinDataIn,
            uint8_t         pinClock,
            uint8_t         pinLatchLoad,
            ActiveState     pinLatchLoadState = ActiveState::Low,         // "IO_Expander"
            ActiveClockEdge shitOutClockEdge  = ActiveClockEdge::Rising,  // 74HC595
            ActiveClockEdge shitInClockEdge   = ActiveClockEdge::Falling, // 74HC165
            BitOrder        bitOrder          = BitOrder::MSBFirst        // eCxx "IO_Expander" board
        );

        // Measure pulse (do not disable interrupt when calling this function)
        static inline uint32_t measurePulse(uint8_t pin, ActiveState pulseAS, uint32_t timeoutUS) __ECXX_ATTR_OPTIMIZE_2;

    protected:
        static inline void callScheduledAtomicUserCallback() noexcept;
        static inline uint32_t blinkActivityIndicatorLEDAndGetMillis() noexcept;
};


//
// Include the implementation file
//
#define INCLUDE_ECXX_APPLICATION_CRTP_BASE_TPP
#include "Application_CRTPBase.tpp"


} // namespace eCxx


#endif
