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


#ifndef ECXX_PLATFORM_CHARACTER_LCD_TWI_H
#define ECXX_PLATFORM_CHARACTER_LCD_TWI_H


#include <eCxx/Platform/CharacterLCD.h>

#include <eCxx/Platform/Common/TWIMaster.h>


namespace eCxx {


//
// A simple character LCD driver using TWI output method (such as using PCF8574A)
//
// WARNING : The TWIMaster must be initialized independently.
//
class CharacterLCD_TWI : public CharacterLCD<CharacterLCD_TWI> {
    public:
        inline ~CharacterLCD_TWI() = default;

    public:
       inline CharacterLCD_TWI(
           uint8_t     twiAddress = 0x27,
           uint8_t     pinEN      = 2,
           uint8_t     pinRW      = 1,
           uint8_t     pinRS      = 0,
           uint8_t     pinD4      = 4,
           uint8_t     pinD5      = 5,
           uint8_t     pinD6      = 6,
           uint8_t     pinD7      = 7,
           uint8_t     pinBL      = 3,
           ActiveState atsBL      = ActiveState::High
       );

       void setBacklight(bool on, bool immediate = true);

       void sendLNibble(uint8_t value) const noexcept;

       void sendCommand(uint8_t value) const noexcept;
       void sendData(uint8_t value) const noexcept;

    private:
        void init();
        void uninit();

        inline bool initialized() const;
        inline void useRWAsE2(bool val) noexcept;

        void pulseData(uint8_t composite) const noexcept;

        friend class CharacterLCD<CharacterLCD_TWI>;

    private:
       uint8_t _twiAddress;
       bool    _slaveFound;

       uint8_t _pinEN;
       uint8_t _pinRW;
       uint8_t _pinRS;
       uint8_t _pinD4;
       uint8_t _pinD5;
       uint8_t _pinD6;
       uint8_t _pinD7;
       uint8_t _pinBL;

       bool    _blActvHigh;
       uint8_t _blState;

       bool    _useRWAsE2;
};


inline CharacterLCD_TWI::CharacterLCD_TWI(
    uint8_t     twiAddress,
    uint8_t     pinEN,
    uint8_t     pinRW,
    uint8_t     pinRS,
    uint8_t     pinD4,
    uint8_t     pinD5,
    uint8_t     pinD6,
    uint8_t     pinD7,
    uint8_t     pinBL,
    ActiveState atsBL
)
: _twiAddress(twiAddress)
, _slaveFound(false)
, _pinEN     ( _BV(pinEN) )
, _pinRW     ( _BV(pinRW) )
, _pinRS     ( _BV(pinRS) )
, _pinD4     ( _BV(pinD4) )
, _pinD5     ( _BV(pinD5) )
, _pinD6     ( _BV(pinD6) )
, _pinD7     ( _BV(pinD7) )
, _pinBL     ( _BV(pinBL) )
, _blActvHigh(atsBL == ActiveState::High)
, _blState   (_blActvHigh ? _pinBL : 0)
, _useRWAsE2 (false)
{}


inline bool CharacterLCD_TWI::initialized() const
{ return _slaveFound; }


inline void CharacterLCD_TWI::useRWAsE2(bool val) noexcept
{ _useRWAsE2 = val; }


} // namespace eCxx


#endif
