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


#ifndef INCLUDE_ECXX_PLATFORM_SPECIFIC_TWISLAVE_H
#error "this file cannot be included directly"
#endif
#undef INCLUDE_ECXX_PLATFORM_SPECIFIC_TWISLAVE_H


#ifndef ECXX_PLATFORM_AVR_COMMON_TWISLAVE_H
#define ECXX_PLATFORM_AVR_COMMON_TWISLAVE_H


namespace eCxx {


//
// A simple AVR TWI-slave wrapper
//
// WARNING : All functions derived from BasicOutputWriter<T> that accept parameters with data types
//           'PGMCharPointer' and 'PGMCharPointerFar' expect the pointers to come from program
//           memory exclusively!
//
// NOTE    : Whenever possible, use the versions that accept near program pointers because those that
//           accept the far program pointers may have more overhead and restrictions.
//
class TWISlave : public BasicOutputWriter<TWISlave> {
    public:
        using TWIResultCode = eCxx::TWIResultCode;

        using RxCallbackF   = eCxx::FunctionalVoidCallback_UInt8;
        using TxCallbackF   = eCxx::FunctionalVoidCallback;

    private:
        inline TWISlave() = default;

        static void __onRx_internal(const uint8_t* data, uint8_t len);
        static void __onTx_internal();

    public:
        inline ~TWISlave() = default;

        static inline TWISlave& instance() __ECXX_ATTR_ALWAYS_INLINE
        {
            static TWISlave twiSlave;
            return twiSlave;
        }

    public:
        void begin(uint8_t slaveAddress, RxCallbackF rxcb, TxCallbackF txcb);
        void end();

        bool canRead() const;
        bool read(uint8_t& value);
        bool peek(uint8_t& value) const;

        TWIResultCode write(uint8_t value);
        TWIResultCode write(const void* data, uint8_t len);

    private:
        uint8_t                                              _slaveAddress;
        RingBuffer<uint8_t, Application_Base::TWIBufferSize> _buff;

        RxCallbackF _onRx = nullptr;
        TxCallbackF _onTx = nullptr;
};


} // namespace eCxx


#endif
