#include "stdafx.h"
#include "AD539x.h"
#include "Trace.h"

int IoAAD539x::Open( int Verify )
{
    Close( );

    // Fetch control register contents
    if ( ! ReadControlRegister( m_CRBits ) ) return FALSE;

    // If internal reference is enabled, set up selected reference voltage
    if ( IsInternalReferenceSelected( ) )
    {
        m_ReferenceVoltage = Is2V5InternalReferenceSelected( ) ? 2.5 : 1.25;
    }

    // Synchronize software gain, offset and level settings with hardware
    for ( int Register = 0; Register < 2; Register++ )
    {
        for ( int Channel = 0; Channel < ChannelCount( ); Channel++ )
        {
            if ( ! ReadGain  ( Register, Channel, m_Gain  [ Register ][ Channel ] ) ) return FALSE;
            if ( ! ReadOffset( Register, Channel, m_Offset[ Register ][ Channel ] ) ) return FALSE;
            if ( ! ReadLevel ( Register, Channel, m_Level [ Register ][ Channel ] ) ) return FALSE;
        }
    }

    IoADevice::Open( );  // flag device as open

    return TRUE;
}

int IoAAD539x::SetControlRegister( int CRBits )
{
    if ( ! IsOpen( ) ) return FALSE;

    CRBits &= 0xfff;

    if ( CRBits != m_CRBits )
    {
        if ( ! WriteControlRegister( CRBits ) ) return FALSE;

        m_CRBits = CRBits;

        // If internal reference is enabled, set up selected reference voltage
        if ( IsInternalReferenceSelected( ) )
        {
            m_ReferenceVoltage = Is2V5InternalReferenceSelected( ) ? 2.5 : 1.25;
        }
    }

    return TRUE;
}

int IoAAD539x::SetControlRegisterBit( int BitIndex, int BitValue )
{
    if ( ! IsOpen( ) ) return FALSE;

    if ( BitIndex < 0 || BitIndex >= eControlRegisterBits ) return FALSE;

    int BitMask = 0x1 << BitIndex;

    int CRBits = BitValue ? m_CRBits | BitMask : m_CRBits & ~BitMask;  // set/clear register bit

    return SetControlRegister( CRBits );  // update control register
}

void IoAAD539x::Encode( int Bits[ 24 ], int  BNA, int  RNW, int  A, int  REG, int  DB ) const
{
    Bits[ 0 ] = BNA & 0x1;
    Bits[ 1 ] = RNW & 0x1;
    Bits[ 2 ] = 0x0;
    Bits[ 3 ] = 0x0;
    Bits[ 4 ] = (  A  >> 3 ) & 0x1;
    Bits[ 5 ] = (  A  >> 2 ) & 0x1;
    Bits[ 6 ] = (  A  >> 1 ) & 0x1;  // encode MSB -> LSB
    Bits[ 7 ] = (  A  >> 0 ) & 0x1;
    Bits[ 8 ] = ( REG >> 1 ) & 0x1;
    Bits[ 9 ] = ( REG >> 0 ) & 0x1;

    for ( int i = 0; i < 14; i++ )
    {
        Bits[ i + 10 ] = ( DB >> ( 13 - i ) ) & 0x1;  // encode MSB -> LSB
    }
}

void IoAAD539x::Decode( int Bits[ 24 ], int& BNA, int& RNW, int& A, int& REG, int& DB ) const
{
    BNA  = Bits[ 0 ];
    RNW  = Bits[ 1 ];
    A    = Bits[ 4 ] << 3;
    A   |= Bits[ 5 ] << 2;
    A   |= Bits[ 6 ] << 1;  // read MSB -> LSB
    A   |= Bits[ 7 ] << 0;
    REG  = Bits[ 8 ] << 1;
    REG |= Bits[ 9 ] << 0;

    DB = 0x000000;

    for ( int i = 0; i < 14; i++ )
    {
        DB |= Bits[ i + 10 ] << ( 13 - i );  // read MSB -> LSB
    }
}

int IoAAD539x::Read( int &DB ) const
{
    int Bits[ 24 ];

    if ( ! ReadBSP( 0, Bits, 24, 0 ) ) return FALSE;

    int BNA, RNW, A, REG;

    Decode( Bits, BNA, RNW, A, REG, DB );

    return TRUE;
}

int IoAAD539x::Write( int BNA, int RNW, int A, int REG, int DB, int Load ) const
{
    int Bits[ 25 ];

    Encode( Bits, BNA, RNW, A, REG, DB );

//    Bits[ 24 ] = Load != 0;  // append Load bit (if bit is set, the LDAC pin is asserted for the required length of time)

    if ( ! WriteBSP( 0, Bits, 24, 0 ) ) return FALSE;
//    if ( ! WriteBSP( 0, Bits, 25, 0 ) ) return FALSE;  // Load bit not implemented for now

    return TRUE;
}
