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


#ifndef ECXX_PLATFORM_AVR_TWI_DRIVER_H
#define ECXX_PLATFORM_AVR_TWI_DRIVER_H


#include <eCxx/eCxx_Internal.h>
#include <eCxx/Platform/Common/Application.h>


namespace eCxx {


//
// A simple AVR TWI driver
//
class TWIDriver {
    public:
        using TWIResultCode    = TWIMaster::TWIResultCode;

        using SlaveRxCallbackF = eCxx::VoidCallback_ConstUInt8Ptr_UInt8;
        using SlaveTxCallbackF = eCxx::VoidCallback;

    public:
        TWIDriver(const TWIDriver& ) = delete;
        TWIDriver(      TWIDriver&&) = delete;

        TWIDriver& operator=(const TWIDriver& ) = delete;
        TWIDriver& operator=(      TWIDriver&&) = delete;

    private:
        inline TWIDriver() = default;

        static void __twi_isr_handler();

    public:
        inline ~TWIDriver() = default;

        static inline TWIDriver& instance() __ECXX_ATTR_ALWAYS_INLINE
        {
            static TWIDriver twiDriver;
            return twiDriver;
        }

    public:
        void begin(uint8_t address, SlaveRxCallbackF rxucb, SlaveTxCallbackF txucb, uint32_t frequency);
        void end();

        TWIResultCode writeTo(uint8_t address, const uint8_t* data, uint8_t len, bool wait, bool sendStop);
        uint8_t readFrom(uint8_t address, uint8_t* data, uint8_t len, bool sendStop);

        TWIResultCode transmitToMaster(const uint8_t* data, uint8_t len);

    private:
        void ack(bool ack);

        void sendStopCondition();
        void releaseBusControl();

    private:
        enum class TWIState : uint8_t {
            Ready, // Ready (idle)
            MRx,   // Master receiver
            MTx,   // Master transmitter
            SRx,   // Slave  receiver
            STx    // Slave  transmitter
        };

        volatile TWIState                               _state;
        volatile uint8_t                                _expectedReadBytes;
        volatile uint8_t                                _slaveAddressRWBit;
        volatile bool                                   _sendStop;
        volatile bool                                   _repeatedStart;

        volatile TWIResultCode                          _resultCode;

        RingBuffer<uint8_t, Application::TWIBufferSize> _msBuff; // Used by master Rx and Tx
        RingBuffer<uint8_t, Application::TWIBufferSize> _rxBuff; // Used by slave  Rx
        RingBuffer<uint8_t, Application::TWIBufferSize> _txBuff; // Used by slave  Tx

        SlaveRxCallbackF                                _rxucbSlave;
        SlaveTxCallbackF                                _txucbSlave;
};


} // namespace eCxx


#endif
