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

#include "picccpunit.h"
#include "picicunit.h"
#include "picocunit.h"
#include "datautils.h"
#include "mcupin.h"
#include "e_mcu.h"
#include "simulator.h"

PicCcpUnit::PicCcpUnit( eMcu* mcu, QString name, int type )
          : McuModule( mcu, name )
          , eElement( name )
{
    QString n = m_name.right(1); // name="CCP1" => n="1"
    QString e = m_name.contains("+") ? "+" : "";

    m_capUnit = new PicIcUnit( m_mcu, "IC"+n );
    m_comUnit = new PicOcUnit( m_mcu, "OC"+e+n );
    m_pwmUnit = PicOcUnit::createPwmUnit( m_mcu, "PWM"+e+n, type  );

}
PicCcpUnit::~PicCcpUnit()
{
    delete m_capUnit;
}

void PicCcpUnit::setup()
{
    McuTimer* timer1 = m_mcu->getTimer("TIMER1");
    McuTimer* timer2 = m_mcu->getTimer("TIMER2");

    m_capUnit->m_timer = timer1;
    m_comUnit->m_timer = timer1;
    if( timer1 ) timer1->addOcUnit( m_comUnit );

    m_pwmUnit->m_timer = timer2;
    if( timer2 ) timer2->addOcUnit( m_pwmUnit );

    QString n = m_name.right(1);
    m_CCPxM = getRegBits( "CCP"+n+"M0,CCP"+n+"M1,CCP"+n+"M2,CCP"+n+"M3", m_mcu );

    m_mode = 0;
}

void PicCcpUnit::initialize()
{
    m_mode = 0;
    m_ccpMode = ccpOFF;
}

void PicCcpUnit::ccprWriteL( uint8_t val )
{
    m_pwmUnit->ocrWriteL( val );
    m_comUnit->ocrWriteL( val );
}

void PicCcpUnit::ccprWriteH( uint8_t val )
{
    if( m_ccpMode == ccpPWM ) m_mcu->m_regOverride = *m_ccpRegH; // Read only
    else                      m_comUnit->ocrWriteH( val );
}

void PicCcpUnit::configureA( uint8_t CCPxCON ) //
{
    if( CCPxCON == m_mode ) return;
    m_mode = CCPxCON;

    uint8_t CCPxM = getRegBitsVal( CCPxCON, m_CCPxM );

    if( CCPxM == 0 ){
        m_ccpMode = ccpOFF;
        m_capUnit->initialize();
        m_comUnit->initialize();
        m_pwmUnit->initialize();
    }
    else if( CCPxM < 4  ) { m_ccpMode = ccpCOM; m_comUnit->configure( CCPxM ); } // Compare Mode (Enhanced):
    else if( CCPxM < 8  ) { m_ccpMode = ccpCAP; m_capUnit->configure( CCPxM ); } // Capture Mode:
    else if( CCPxM < 12 ) { m_ccpMode = ccpCOM; m_comUnit->configure( CCPxM ); } // Compare Mode:
    else                  { m_ccpMode = ccpPWM; m_pwmUnit->configure( CCPxCON );}// PWM Mode
}

void PicCcpUnit::setInterrupt( Interrupt* i )
{
    m_capUnit->m_interrupt = i;
    m_comUnit->m_interrupt = i;
    m_pwmUnit->m_interrupt = i;
}

void PicCcpUnit::setPin( McuPin* pin )
{
    m_capUnit->m_icPin = pin;
    m_comUnit->m_ocPin = pin;
    m_pwmUnit->m_ocPin = pin;
}
