/***************************************************************************
 *   Copyright (C) 2021 by Santiago González                               *
 *                                                                         *
 ***( see copyright.txt file at root folder )*******************************/

#pragma once

#include "e-clocked_device.h"
#include "avrtwicodes.h" // Using AVR states comes at hand
#include "transmodule.h"

enum twiMode_t{
    TWI_OFF=0,
    TWI_MASTER,
    TWI_SLAVE
}; 

class eSource; 

class TwiModule : public eClockedDevice, public TransModule
{
    public:
        TwiModule( QString name ); 
        ~TwiModule(); 

        enum i2cState_t{
            I2C_IDLE=0,
            I2C_STOP,
            I2C_START,
            I2C_READ,
            I2C_WRITE,
            I2C_ACK,
            I2C_ENDACK,
            I2C_READACK
        }; 

        virtual void initialize() override; 
        virtual void stamp() override; 
        virtual void runEvent() override; 
        virtual void voltChanged() override; 

        int cCode() { return m_cCode;  }
        void setCcode( int code ) { m_cCode = m_address = code;  }

        virtual double freqKHz() { return m_freq/1e3;  }
        virtual void setFreqKHz( double f ); 

        virtual void startWrite(){; } // Notify posible child class
        virtual void writeByte() { m_bitPtr = 7;  }
        virtual void bufferEmpty(){; }
        virtual void readByte(); 

        //uint8_t byteReceived() { return m_rxReg;  }

        void setSdaPin( IoPin* pin ); 
        void setSclPin( IoPin* pin ); 
        void setPins( IoPin* scl, IoPin* sda ); 
        virtual void setMode( twiMode_t mode ); 

        void masterStart(); 
        void masterWrite( uint8_t data, bool isAddr, bool write ); 
        void masterRead( bool ack ); 
        void masterStop(); 
        void slaveWrite(); 

        virtual void I2Cstop() { m_i2cState = I2C_STOP;  }

        uint64_t getTrasferTime(); 

    protected:
        inline void setSCL( bool st ); 
        inline void setSDA( bool st ); 
        inline void getSdaState(); 
        inline void scheduleSDA( bool state ); 
        inline void readBit(); 
        inline void writeBit(); 
        inline void waitACK(); 
        inline void ACK(); 

        virtual void setTwiState( twiState_t state ) { m_twiState = state;  }

        uint m_cCode; 
        uint m_address;            // Device Address
        int  m_addrBits; 

        double m_freq; 
        uint64_t m_clockPeriod;    // TWI Clock half period in ps

        bool m_lastSDA; 
        bool m_sdaState; 
        bool m_toggleScl; 
        bool m_isAddr; 
        bool m_write; 
        bool m_sendACK; 
        bool m_masterACK; 
        bool m_addrMatch; 
        bool m_genCall; 
        bool m_enabled; 

        int m_bitPtr;        // Bit Pointer

        uint8_t m_txReg;     // Byte to Send
        uint8_t m_rxReg;     // Byte Received

        twiMode_t  m_mode; 
        twiState_t m_twiState; 
        twiState_t m_nextState; 
        i2cState_t m_i2cState;    // Current State of i2c
        i2cState_t m_lastState;   // Last State of i2c

        IoPin* m_sda; 
        IoPin* m_scl; 
}; 
