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


#ifndef ECXX_PLATFORM_AVRX_TWI_DRIVER_H
#define ECXX_PLATFORM_AVRX_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:
        TWIDriver();

        static void __twi_master_isr_handler();
        static void __twi_slave_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:
        enum class TWIMode : uint8_t {
            Unknown,
            Master,
            Slave,
            MasterTransmitter,
            MasterReceiver,
            SlaveTransmitter,
            SlaveReceiver
        };

        volatile TWIMode                                _twiMode;
        volatile uint8_t                                _twiResult;

        volatile uint8_t                                _transStatus;
        volatile uint8_t                                _bytesToRead;
        volatile uint8_t                                _bytesToWrite;
        volatile uint8_t                                _bytesRead;
        volatile uint8_t                                _bytesWritten;

        volatile uint8_t*                               _rwBuffer;       // Used by master Rx and Tx
        volatile uint8_t                                _slaveAddress;
        volatile bool                                   _masterSendStop;

        volatile bool                                   _slaveCallRXUCB;
        SlaveRxCallbackF                                _rxucbSlave;
        SlaveTxCallbackF                                _txucbSlave;
        RingBuffer<uint8_t, Application::TWIBufferSize> _rxBuffSlave;    // Used by slave Rx
        RingBuffer<uint8_t, Application::TWIBufferSize> _txBuffSlave;    // Used by slave Tx

    private:
        void masterSetFrequency(uint32_t frequency);
        void masterTransactionFinished(uint8_t result);

        void slaveAddressMatch();
        void slaveTransactionFinished(uint8_t result);
};


} // namespace eCxx


#endif
