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

#include "picspi.h"
#include "datautils.h"
#include "iopin.h"
#include "e_mcu.h"
#include "mcuinterrupts.h"
#include "simulator.h"

PicSpi::PicSpi( eMcu* mcu, QString name )
      : McuSpi( mcu, name )
{
}
PicSpi::~PicSpi(){}

void PicSpi::setup()
{
    m_sleepMode = 0xFF;

    m_SSPEN = getRegBits("SSPEN", m_mcu );
    m_CKP   = getRegBits("CKP", m_mcu );
    m_CKE   = getRegBits("CKE", m_mcu );
}

void PicSpi::setMode( spiMode_t mode )
{
    m_clockPeriod = 4*m_mcu->psInst()*m_prescaler/2;

    if( mode == m_mode ) return;
    m_mode = mode;

    m_dataOutPin = m_MOSI;
    m_dataInPin  = m_MISO;
    Simulator::self()->cancelEvents( this );

    if( mode == SPI_OFF )
    {
        m_MOSI->controlPin( false, false );
        m_MISO->controlPin( false, false );
        m_clkPin->controlPin( false, false );
        m_SS->controlPin( false, false );
        return;
    }
    m_dataOutPin->controlPin( true, false );
    m_dataInPin->setPinMode( input );
    m_dataInPin->controlPin( true, true );
    m_SS->controlPin( true, false );

    if( mode == SPI_MASTER )
    {
        m_clkPin->controlPin( true, false );
        m_dataOutPin->setOutState( true );
    }
    else if( mode == SPI_SLAVE )
    {
        m_clkPin->controlPin( false, false );
        m_clkPin->changeCallBack( this, true );
        if( m_useSS && m_SS ) m_SS->changeCallBack( this, true );
    }
}

void PicSpi::configureA( uint8_t newSSPCON ) // SSPCON is being written
{
    m_clkPol = getRegBitsBool( newSSPCON, m_CKP ); // Clock polarity
    m_sampleEdge = ( m_clkPol == m_clkPha ) ? Clock_Rising : Clock_Falling;
    m_leadEdge = m_clkPol ? Clock_Falling : Clock_Rising;
    m_tailEdge = m_clkPol ? Clock_Rising  : Clock_Falling;

    if( m_mode == SPI_MASTER ) m_clkPin->setOutState( m_clkPol );
}

void PicSpi::writeStatus( uint8_t newSSPSTAT ) // SSPSTAT is being written
{
    m_clkPha = getRegBitsBool( newSSPSTAT, m_CKE ); // Clock phase
    m_sampleEdge = ( m_clkPol == m_clkPha ) ? Clock_Rising : Clock_Falling;

}

void PicSpi::writeSpiReg( uint8_t newSSPBUF ) // SSPBUF is being written
{
    m_srReg = newSSPBUF;
    *m_statReg |= 1;

    if( m_mode == SPI_MASTER ) StartTransaction();
}

void PicSpi::endTransaction()
{
    SpiModule::endTransaction();
    *m_dataReg = m_srReg;
    *m_statReg &= ~1;
    m_interrupt->raise();
}

void PicSpi::sleep( int mode )
{
    McuModule::sleep( mode );
    if( m_sleeping ) pauseEvents();
    else             resumeEvents();
}

