#if !defined( _IOAKSC1000_H )
#define _IOAKSC1000_H

#include "BitArray.h"

// Enumerate states for PowerMode variable contained in the General Control register
enum IoAKSC1000PowerModeEnum
{
    eHighPowerMode,
    eLowPowerMode
};

// Enumerate operation states for OperationMode variable contained in the General Control register
enum IoAKSC1000OperationModeEnum
{
    eProgrammingMode,
    eExecutionMode
};

// Enumerate registers
enum IoAKSC1000RegisterEnum
{
    eR0, eFTP = eR0,  eFrameTablePointer = eR0,
    eR1, eGSR = eR1,  eGeneralSetup = eR1,
    eR2, eGCR = eR2,  eGeneralControl = eR2,
    eR3, eISR = eR3,  eINTG_STRTSetup = eR3,
    eR4, eILR = eR4,  eINTG_STRTLine = eR4,
    eR5, eSPR = eR5,  eSignalPolarity = eR5,
    eR6, eOR  = eR6,  eOffset = eR6,
    eR7, eWR  = eR7,  eWidth = eR7,
    eR8, eFTs = eR8,  eFrameTableAccessRegister = eR8, eFrameTables = eR8,
    eR9, eLTs = eR9,  eLineTableAccessRegister = eR9, eLineTables = eR9,
    eR10, eSR = eR10, eStatusRegister = eR10,

    eCRs, eControlRegisters = eCRs,  // virtual register

    // Total number of registers = 12
    nKSC1000RegisterCount,

    nKSC1000ControlRegisterCount = eWidth - eFrameTablePointer + 1,

    nKSC1000INIRegisterCount = eLineTableAccessRegister - eFrameTablePointer + 1,

    eInvalidKSC1000Register = -1
};

// Enumerate frame tables
enum IoAKSC1000FrameTableEnum
{
    // Frame table index values
    eFT0, eFT1, eFT2, eFT3, eFT4, eFT5, eFT6, eFT7, 

    // Number of frame tables
    nFrameTableCount,

    eInvalidFrameTable = -1
};

// Enumerate frame table entries
enum IoAKSC1000FrameTableEntryEnum
{
    // Frame table entry index values
    eFTE0, eFTE1, eFTE2, eFTE3, eFTE4, eFTE5, eFTE6, eFTE7, eFTE8, eFTE9, eFTE10, eFTE11, eFTE12, eFTE13, eFTE14, eFTE15,

    // Number of entries in each frame table
    nFrameTableEntryCount,

    eInvalidFrameTableEntry = -1
};

// Enumerate line tables
enum IoAKSC1000LineTableEnum
{
    // Line table index values
    eLT0, eLT1, eLT2, eLT3, eLT4, eLT5, eLT6, eLT7, eLT8, eLT9, eLT10, eLT11, eLT12, eLT13, eLT14, eLT15,

    // Number of line tables
    nLineTableCount,

    eInvalidLineTable = -1
};

// Enumerate line table entries
enum IoAKSC1000LineTableEntryEnum
{
    // Line table entry index values
    eLTE0, eLTE1, eLTE2, eLTE3, eLTE4, eLTE5, eLTE6, eLTE7, eLTE8, eLTE9, eLTE10, eLTE11, eLTE12, eLTE13, eLTE14, eLTE15,

    // Number of entries in each line table
    nLineTableEntryCount,

    eInvalidLineTableEntry = -1
};

// Enumerate variable index relative to given control register
enum IoAKSC1000CRVariableIndex { };

// Enumerate control register variables
enum IoAKSC1000CRVariableEnum
{ 
    // Frame Table Pointer register
    eFrameTableAddress,

    // General Setup register
    ePixelsPerLine, eLineValidPixelStart, eLineValidPixelQuadratureStart, eLineValidPixelEnd,
    eCLPOB1PixelStart, eCLPOB1PixelEnd, eCLPOB2PixelStart, eCLPOB2PixelEnd,
    eCLPDM1PixelStart, eCLPDM1PixelEnd, eCLPDM2PixelStart, eCLPDM2PixelEnd,
    ePBLKPixelStart, ePBLKPixelEnd, eRGEnable, eH6Enable, eH4Enable, eH5Enable, eSH2Enable, eSH4Enable,
    eDATACLK1Enable, eDATACLK2Enable, ePIXCLKEnable, eH3Enable, eH1Enable, eH2Enable, eSH1Enable, eSH3Enable,
    eH6Enable24mAOutput, eH4Enable24mAOutput, eH5Enable24mAOutput, eRGEnable24mAOutput,
    eSH2Enable24mAOutput, eSH4Enable24mAOutput, eDATACLK1Enable24mAOutput, eDATACLK2Enable24mAOutput,
    eH3Enable24mAOutput, eH1Enable24mAOutput, eH2Enable24mAOutput, eSH1Enable24mAOutput, eSH3Enable24mAOutput,
    eDLLFrequencyRangeIndex, 

    // General Control register
    ePowerMode, eOperationMode, 

    // INTG_STRT Setup register
    eElectronicShutterSetupClocks, eElectronicShutterPulseWidth, eElectronicShutterHoldClocks,

    // INTG_STRT Line register
    eIntegrateStartPulseLineNumber,

    // Signal Polarity register
    eH6IdleValue, eH3IdleValue, eH4IdleValue, eH1IdleValue, eH5IdleValue, eH2IdleValue, eRGIdleValue,
    eSH2IdleValue, eSH1IdleValue, eSH4IdleValue, eSH3IdleValue, eDATACLK1IdleValue, eDATACLK2IdleValue,
    eCLPOBIdleValue, eCLPDMIdleValue, eAMP_ENABLEIdleValue, eFRAME_VALIDIdleValue, eLINE_VALIDIdleValue,
    eINTG_STRTIdleValue, eV1IdleValue, eV2IdleValue, eV3IdleValue, eV4IdleValue, eV5IdleValue, eV6IdleValue,

    // Offset register
    eH6Offset, eH3Offset, eH4Offset, eH1Offset, eH5Offset, eH2Offset, eRGOffset,
    eSH2Offset, eSH1Offset, eSH4Offset, eSH3Offset, eDATACLK1Offset, eDATACLK2Offset,

    // Width register
    eH6Width, eH3Width, eH4Width, eH1Width, eH5Width, eH2Width, eRGWidth,
    eSH2Width, eSH1Width, eSH4Width, eSH3Width, eDATACLK1Width, eDATACLK2Width,

    // Total number of variables = 100
    nKSC1000ControlVariableCount,

    eInvalidControlVariable = -1
};

// Enumerate frame table variables
enum IoAKSC1000FTVariableEnum
{ 
    eCheckAndIncrementLineCounter, eClearLineCounter, eForceINTG_STRT, eHorizontalBinningFactor,
    eHCLK_VEnable, eLINE_VALIDEnable, eFRAME_VALIDAssert, eVideoAmplifierAssert, eAFEClockEnable,
    eCLPDM2Enable, eCLPDM1Enable, eCLPOB2Enable, eCLPOB1Enable, ePBLKEnable, ePBLKIdleValue,
    eEventDescriptor, eEventFlag, eEventCount, eEventAddress, eFrameTable, eLineTable, eFrameTableEntry,

    // Total number of frame table variables = 22
    nKSC1000FrameTableVariableCount
};

// Enumerate line table variables
enum IoAKSC1000LTVariableEnum
{ 
    ePixelClockCount, eHCLK_HEnable, eV6Asserted, eV5Asserted,
    eV4Asserted, eV3Asserted, eV2Asserted, eV1Asserted, eLineTableEntryBits,

    // Total number of line table variables = 9
    nKSC1000LineTableVariableCount
};

// Enumerate status register variables
enum IoAKSC1000SRVariableEnum
{ 
    eDLLLocked, eCurrentFrameTableAddress, eCurrentLineTableAddress, eVDRegistered, eVDWaiting, eLineCounterValue,

    // Total number of status register variables = 6
    nKSC1000StatusVariableCount
};

// Enumerate register variables
enum IoAKSC1000VariableEnum
{ 
    // Total number of variables = 136
    nKSC1000VariableCount = nKSC1000ControlVariableCount + nKSC1000FrameTableVariableCount +
                            nKSC1000LineTableVariableCount + nKSC1000StatusVariableCount
};

// Enumerate INI file variable index relative to given control register
enum IoAKSC1000INI_CRVariableIndex { };

// Enumerate INI file control register variables
enum IoAKSC1000INI_CRVariableEnum
{ 
    // Frame Table Pointer register
    eINI_ftpaddr,

    // General Setup register
    eINI_pixperline, eINI_linvalpixst, eINI_linvalpixquast, eINI_linvalpixed,
    eINI_clpob1pixst, eINI_clpob1pixed, eINI_clpob2pixst, eINI_clpob2pixed,
    eINI_clpdm1pixst, eINI_clpdm1pixed, eINI_clpdm2pixst, eINI_clpdm2pixed,
    eINI_pblkpixst, eINI_pblkpixed, eINI_rgena, eINI_h6ena, eINI_h4ena, eINI_h5ena, eINI_sh2ena, eINI_sh4ena,
    eINI_dataclk1ena, eINI_dataclk2ena, eINI_pixclkena, eINI_h3ena, eINI_h1ena, eINI_h2ena, eINI_sh1ena, eINI_sh3ena,
    eINI_h6_24maoutena, eINI_h4_24maoutena, eINI_h5_24maoutena, eINI_rg24maoutena,
    eINI_sh2_24maoutena, eINI_sh4_24maoutena, eINI_dataclk124maoutena, eINI_dataclk224maoutena,
    eINI_h3_24maoutena, eINI_h1_24maoutena, eINI_h2_24maoutena, eINI_sh1_24maoutena, eINI_sh3_24maoutena,
    eINI_DLLfrqsel, 

    // General Control register
    eINI_lowpwrena, eINI_memtblmode, 

    // INTG_STRT Setup register
    eINI_shutset, eINI_shutpulswid, eINI_shuthold,

    // INTG_STRT Line register
    eINI_intgpulslinnum,

    // Signal Polarity register
    eINI_h6idleval, eINI_h3idleval, eINI_h4idleval, eINI_h1idleval, eINI_h5idleval, eINI_h2idleval, eINI_rgidleval,
    eINI_sh2idleval, eINI_sh1idleval, eINI_sh4idleval, eINI_sh3idleval, eINI_dataclk1idleval, eINI_dataclk2idleval,
    eINI_clpobidleval, eINI_clpdmidleval, eINI_ampenaidleval, eINI_frmvalidleval, eINI_linvalidleval, eINI_integstidleval,
    eINI_v1idleval, eINI_v2idleval, eNI_v3idleval, eINI_v4idleval, eINI_v5idleval, eINI_v6idleval,

    // Offset register
    eINI_h6off, eINI_h3off, eINI_h4off, eINI_h1off, eINI_h5off, eINI_h2off, eINI_rgoff,
    eINI_sh2off, eINI_sh1off, eINI_sh4off, eINI_sh3off, eINI_dataclk1off, eINI_dataclk2off,

    // Width register
    eINI_h6width, eINI_h3width, eINI_h4width, eINI_h1width, eINI_h5width, eINI_h2width, eINI_rgwidth,
    eINI_sh2width, eINI_sh1width, eINI_sh4width, eINI_sh3width, eINI_dataclk1width, eINI_dataclk2width,

    // Total number of control register variables = 100
    nKSC1000INI_ControlVariableCount
};

// Enumerate INI file frame table variables
enum IoAKSC1000INI_FTVariableEnum
{ 
    eINI_chkcnt, eINI_forceshut, eINI_horibin, eINI_hclk_v_ena, eINI_valena, eINI_videoamfena,
    eINI_afeena, eINI_clpena, eINI_pblk, eINI_flag, eINI_count, eINI_address,

    // Total number of frame table variables = 12
    nKSC1000INI_FrameTableVariableCount
};

// Enumerate INI file line table variables
enum IoAKSC1000INI_LTVariableEnum
{ 
    eINI_pixcnt, eINI_hclk_h_ena, eINI_v6, eINI_v5, eINI_v4, eINI_v3, eINI_v2, eINI_v1,

    // Total number of line table variables = 8
    nKSC1000INI_LineTableVariableCount
};

// Enumerate INI file variables
enum IoAKSC1000INI_VariableEnum
{ 
    // Total number of variables = 136
    nKSC1000INI_VariableCount = nKSC1000INI_ControlVariableCount + nKSC1000INI_FrameTableVariableCount +
                                nKSC1000INI_LineTableVariableCount
};

// Enumerate bit offsets and counts
enum IoAKSC1000BitEnum
{
    iKSC1000RegistersBitOffset = 0,

    // Control registers
    iKSC1000ControlRegistersBitOffset = iKSC1000RegistersBitOffset,

    nKSC1000ControlRegistersBitCount = 418,

    // Frame tables
    iKSC1000FrameTablesBitOffset = iKSC1000ControlRegistersBitOffset + nKSC1000ControlRegistersBitCount,

    nKSC1000FrameTableEntryBitCount = 34,
    nKSC1000FrameTableBitCount = nFrameTableEntryCount * nKSC1000FrameTableEntryBitCount,
    nKSC1000FrameTablesBitCount = nFrameTableCount * nKSC1000FrameTableBitCount,

    // Line tables
    iKSC1000LineTablesBitOffset = iKSC1000FrameTablesBitOffset + nKSC1000FrameTablesBitCount,

    nKSC1000LineTableEntryBitCount = 20,
    nKSC1000LineTableBitCount = nLineTableEntryCount * nKSC1000LineTableEntryBitCount,
    nKSC1000LineTablesBitCount = nLineTableCount * nKSC1000LineTableBitCount,

    // Status register
    iKSC1000StatusRegisterBitOffset = iKSC1000LineTablesBitOffset + nKSC1000LineTablesBitCount,

    nKSC1000StatusRegisterBitCount = 31,

    // Grand total
    nKSC1000RegistersBitCount = nKSC1000ControlRegistersBitCount + nKSC1000FrameTablesBitCount +
                                nKSC1000LineTablesBitCount + nKSC1000StatusRegisterBitCount
};

// Enumerate byte counts
enum IoAKSC1000ByteEnum
{
    nKSC1000ControlRegistersByteCount = nKSC1000ControlRegistersBitCount / 8,
    nKSC1000FrameTablesByteCount      = nKSC1000FrameTablesBitCount      / 8,
    nKSC1000LineTablesByteCount       = nKSC1000LineTablesBitCount       / 8
};

class IoAKSC1000Data
{
    friend class IoAKSC1000RegisterArray;  // for benefit of IoAKSC1000RegisterArray( ) constructor 

protected:
    IoABitArray& BitArray( ) const { return m_BitArray; }

    IoAKSC1000Data( IoABitArray& BitArray ) : m_BitArray( BitArray ) { }

    int IsValid( ) const { return m_BitArray.IsAllocated( ); }

    int Size( ) const { return m_BitArray.Size( ); }

    // Set/get bitfield value
    void SetValue( int Offset, int Count, int Value ) { if ( Count > 0 ) m_BitArray.SetValue( Value, Offset, Count ); }
    int  GetValue( int Offset, int Count ) const { return ( Count > 0 ) ? m_BitArray.Value( Offset, Count ) : 0; }

    // Set/get bit value
    void SetBit( int Offset, int Count, int Value ) { if ( Count == 1 ) m_BitArray.SetBit( Offset, Value ); }
    int  GetBit( int Offset, int Count ) const { return ( Count == 1 ) ? m_BitArray.Bit( Offset ) : 0; }

    // Test bitfield/bit for equality
    int IsBitFieldEqual( int Offset, int Count, const IoAKSC1000Data& Other, int OtherOffset, int OtherCount ) const
    {
        return Count == OtherCount && Count > 0 && m_BitArray.IsBitFieldEqual( Offset, Count, Other.m_BitArray, OtherOffset );
    }

    int IsBitEqual( int Offset, int Count, const IoAKSC1000Data& Other, int OtherOffset, int OtherCount ) const
    {
        return Count == OtherCount && Count == 1 && m_BitArray.IsBitEqual( Offset, Other.m_BitArray, OtherOffset );
    }

    int IsEqual( const IoAKSC1000Data& Other ) const { return m_BitArray.IsEqual( Other.m_BitArray ); }

    // Clear data
    int Clear( ) const { return m_BitArray.Clear( ); }

    int ClearBitField( int Offset, int Count ) const
    {
       return Count > 0 && m_BitArray.ClearBitField( Offset, Count );
    }

    // Copy data
    int Copy( const IoAKSC1000Data& Other ) const { return m_BitArray.Copy( Other.m_BitArray ); }

    int CopyBitField( int Offset, int Count, const IoAKSC1000Data& Other, int OtherOffset, int OtherCount ) const
    {
       return Count == OtherCount && Count > 0 && m_BitArray.CopyBitField( Offset, Count, Other.m_BitArray, OtherOffset );
    }

private:
    IoABitArray& m_BitArray;
};

class IoAKSC1000Bit : public IoAKSC1000Data
{
public:
    int IsDefined( ) const { return m_Count >= 0; }

    // Set and get
    void Set( int Value ) { IoAKSC1000Data::SetBit( m_Offset, m_Count, Value ); }
    int Value( ) const { return IoAKSC1000Data::GetBit( m_Offset, m_Count ); }

    // Assignment and cast operator functions to simplify set and get
    IoAKSC1000Bit& operator=( int Value ) { Set( Value ); return *this; }
    operator int( ) const { return Value( ); }

    // Test for equality
    int IsEqual( const IoAKSC1000Bit& Other ) const
    {
        return IoAKSC1000Data::IsBitEqual( m_Offset, m_Count, Other, Other.m_Offset, Other.m_Count );
    }

    int operator==( const IoAKSC1000Bit& Other ) const { return   IsEqual( Other ); }
    int operator!=( const IoAKSC1000Bit& Other ) const { return ! IsEqual( Other ); }

protected:
    IoAKSC1000Bit( IoABitArray& BitArray ) : IoAKSC1000Data( BitArray ), m_Offset( 0 ), m_Count( 0 ) { }

    // Bit reference (located relative to start of parent object)
    IoAKSC1000Bit& SetIndex( int Index, int Offset, int Count )
    {
        m_Offset = 0;
        m_Count  = 0;

        if ( 0 <= Index && Index < Count )
        {
            m_Offset = Offset + Index;  // relative offset
            m_Count  = 1;
        }

        return *this;
    }

private:
    int m_Offset, m_Count;
};

class IoAKSC1000Byte : public IoAKSC1000Bit
{
public:
    int IsDefined( ) const { return m_Count > 0; }
    int BitCount( ) const { return m_Count; }
    int BitOffset( ) const { return m_Offset; }

    // Array operator for accessing individual bits
    IoAKSC1000Bit& operator[]( IoAKSC1000BitEnum Index ) { return IoAKSC1000Bit::SetIndex( Index, m_Offset, m_Count ); }

    // Overload bit array operator with one taking (int) argument
    IoAKSC1000Bit& operator[]( int Index ) { return operator[]( (IoAKSC1000BitEnum) Index ); }

    // Same array operators modified to work with const source objects and returning const reference
    const IoAKSC1000Bit& operator[]( IoAKSC1000BitEnum Index ) const { return This( )->operator[]( Index ); }
    const IoAKSC1000Bit& operator[]( int               Index ) const { return This( )->operator[]( Index ); }

    // Set and get
    void Set( char Value ) { IoAKSC1000Data::SetValue( m_Offset, m_Count, (int) Value ); }
    char Value( ) const { return (char) IoAKSC1000Data::GetValue( m_Offset, m_Count ); }

    // Assignment and cast operator functions to simplify set and get
    IoAKSC1000Byte& operator=( char Value ) { Set( Value ); return *this; }
    operator char( ) const { return Value( ); }

    // Test for equality
    int IsEqual( const IoAKSC1000Byte& Other ) const
    {
        return IoAKSC1000Data::IsBitFieldEqual( m_Offset, m_Count, Other, Other.m_Offset, Other.m_Count );
    }

    int operator==( const IoAKSC1000Byte& Other ) const { return   IsEqual( Other ); }
    int operator!=( const IoAKSC1000Byte& Other ) const { return ! IsEqual( Other ); }

protected:
    IoAKSC1000Byte( IoABitArray& BitArray ) : IoAKSC1000Bit( BitArray ), m_Offset( 0 ), m_Count( 0 ) { }

    // Byte reference (located relative to start of parent object)
    IoAKSC1000Byte& SetIndex( int Index, int Offset, int Count )
    {
        m_Offset = 0;
        m_Count  = 0;

        if ( 0 <= Index && Index < Count / 8 )
        {
            m_Offset = Offset + Index * 8;  // relative offset
            m_Count  = 8;
        }

        return *this;
    }

private:
    IoAKSC1000Byte *This( ) const { return (IoAKSC1000Byte *) this; }  // helper function to cast-away const

    int m_Offset, m_Count;
};

class IoAKSC1000Variable : public IoAKSC1000Byte
{
public:
    int IsDefined( ) const { return m_Count > 0; }
    int BitCount( ) const { return m_Count; }
    int BitOffset( ) const { return m_Offset; }

    const char *Name( ) const { return m_Name; }

    // Array operator for accessing individual bits
    IoAKSC1000Bit& operator[]( IoAKSC1000BitEnum Index ) { return IoAKSC1000Bit::SetIndex( Index, m_Offset, m_Count ); }

    // Overload bit array operator with one taking (int) argument
    IoAKSC1000Bit& operator[]( int Index ) { return operator[]( (IoAKSC1000BitEnum) Index ); }

    // Same array operators modified to work with const source objects and returning const reference
    const IoAKSC1000Bit& operator[]( IoAKSC1000BitEnum Index ) const { return This( )->operator[]( Index ); }
    const IoAKSC1000Bit& operator[]( int               Index ) const { return This( )->operator[]( Index ); }

    // Set and get
    void Set( int Value ) { IoAKSC1000Data::SetValue( m_Offset, m_Count, Value ); }
    int Value( ) const { return IoAKSC1000Data::GetValue( m_Offset, m_Count ); }

    // Assignment and cast operator to simplify set and get
    IoAKSC1000Variable& operator=( int Value ) { Set( Value ); return *this; }
    operator int( ) const { return Value( ); }

    // Test for equality
    int IsEqual( const IoAKSC1000Variable& Other ) const
    {
        return IoAKSC1000Data::IsBitFieldEqual( m_Offset, m_Count, Other, Other.m_Offset, Other.m_Count );
    }

    int operator==( const IoAKSC1000Variable& Other ) const { return   IsEqual( Other ); }
    int operator!=( const IoAKSC1000Variable& Other ) const { return ! IsEqual( Other ); }

    // Comparison operator functions (==) and (!=) accepting (int) as second argument
    int IsEqual( int Integer ) const { return Value( ) == Integer; }

    int operator==( int Integer ) const { return   IsEqual( Integer ); }
    int operator!=( int Integer ) const { return ! IsEqual( Integer ); }

    // Clear data => Set(0)
    int Clear( ) { return IoAKSC1000Data::ClearBitField( m_Offset, m_Count ); }

    // Copy data => Set( Get( ) )
    int Copy( const IoAKSC1000Variable& Other )
    {
        return IoAKSC1000Data::CopyBitField( m_Offset, m_Count, Other, Other.m_Offset, Other.m_Count );
    }

    // Assignment operator => Set( Get( ) )
    IoAKSC1000Variable& operator=( const IoAKSC1000Variable& Other ) { Copy( Other ); return *this; }

protected:
    IoAKSC1000Variable( IoABitArray& BitArray ) : IoAKSC1000Byte( BitArray ), m_Offset( 0 ), m_Count( 0 ) { }

    // Control register variable
    IoAKSC1000Variable& SetCRIndex( int Index, int Offset, int Count )
    {
        m_Offset = 0;
        m_Count  = 0;
        m_Name   = NULL;

        if ( 0 <= Index && Index < nKSC1000ControlVariableCount )
        {
            ASSERT( Offset <= m_OffsetLUT[ Index ] && Offset + Count >= m_OffsetLUT[ Index ] + m_CountLUT[ Index ] );

            m_Offset = m_OffsetLUT[ Index ];  // absolute offset
            m_Count  = m_CountLUT[ Index ];
            m_Name   = m_NameLUT[ Index ];
        }

        return *this;
    }

    // Frame table variable
    IoAKSC1000Variable& SetFTIndex( int Index, int Offset, int Count )
    {
        m_Offset = 0;
        m_Count  = 0;
        m_Name   = NULL;

        if ( 0 <= Index && Index < nKSC1000FrameTableVariableCount )
        {
            Index += nKSC1000ControlVariableCount;

            // Offset and count must refer to frame table entry
            ASSERT( ( Offset - iKSC1000FrameTablesBitOffset ) % nKSC1000FrameTableEntryBitCount == 0 && Count == nKSC1000FrameTableEntryBitCount );

            m_Offset = m_OffsetLUT[ Index ] + Offset;  // offset relative to frame table entry
            m_Count  = m_CountLUT[ Index ];
            m_Name   = m_NameLUT[ Index ];
        }

        return *this;
    }

    // Line table variable
    IoAKSC1000Variable& SetLTIndex( int Index, int Offset, int Count )
    {
        m_Offset = 0;
        m_Count  = 0;
        m_Name   = NULL;

        if ( 0 <= Index && Index < nKSC1000LineTableVariableCount )
        {
            Index += nKSC1000ControlVariableCount + nKSC1000FrameTableVariableCount;

            // Offset and count must refer to line table entry
            ASSERT( ( Offset - iKSC1000LineTablesBitOffset ) % nKSC1000LineTableEntryBitCount == 0 && Count == nKSC1000LineTableEntryBitCount );

            m_Offset = m_OffsetLUT[ Index ] + Offset;  // offset relative to line table entry
            m_Count  = m_CountLUT[ Index ];
            m_Name   = m_NameLUT[ Index ];
        }

        return *this;
    }

    // Status register variable
    IoAKSC1000Variable& SetSRIndex( int Index, int Offset, int Count )
    {
        m_Offset = 0;
        m_Count  = 0;
        m_Name   = NULL;

        if ( 0 <= Index && Index < nKSC1000StatusVariableCount )
        {
            Index += nKSC1000ControlVariableCount + nKSC1000FrameTableVariableCount + nKSC1000LineTableVariableCount;

            ASSERT( Offset <= m_OffsetLUT[ Index ] && Offset + Count >= m_OffsetLUT[ Index ] + m_CountLUT[ Index ] );

            m_Offset = m_OffsetLUT[ Index ];  // absolute offset
            m_Count  = m_CountLUT[ Index ];
            m_Name   = m_NameLUT[ Index ];
        }

        return *this;
    }

private:
    IoAKSC1000Variable *This( ) const { return (IoAKSC1000Variable *) this; }  // helper function to cast-away const

    int m_Offset, m_Count;
    const char *m_Name;

    // Bit offset for each register
    static const int m_OffsetLUT[ nKSC1000VariableCount ];

    // Numbers of bits in each register
    static const int m_CountLUT[ nKSC1000VariableCount ];

    // String to identify each register
    static const char *m_NameLUT[ nKSC1000VariableCount ];
};

// Comparison operator functions (==) and (!=) accepting (int) as first argument
inline int operator==( int Integer, const IoAKSC1000Variable& Other ) { return   Other.IsEqual( Integer ); }
inline int operator!=( int Integer, const IoAKSC1000Variable& Other ) { return ! Other.IsEqual( Integer ); }

class IoAKSC1000INIVariable : public IoAKSC1000Variable
{
public:
    const char *Name( ) const { return m_Name; }

    // Set and get
    void Set( int Value ) { IoAKSC1000Data::SetValue( m_Offset, m_Count, Value ); }
    int Value( ) const { return IoAKSC1000Data::GetValue( m_Offset, m_Count ); }

    // Assignment and cast operator to simplify set and get
    IoAKSC1000INIVariable& operator=( int Value ) { Set( Value ); return *this; }
    operator int( ) const { return Value( ); }

protected:
    IoAKSC1000INIVariable( IoABitArray& BitArray ) : IoAKSC1000Variable( BitArray ), m_Offset( 0 ), m_Count( 0 ) { }

    // Control register variable (located at fixed absolute location in data array)
    IoAKSC1000INIVariable& SetCRIndex( int Index, int Offset, int Count )
    {
        m_Offset = 0;
        m_Count  = 0;
        m_Name   = NULL;

        if ( 0 <= Index && Index < nKSC1000INI_ControlVariableCount )
        {
            ASSERT( Offset <= m_OffsetLUT[ Index ] && Offset + Count >= m_OffsetLUT[ Index ] + m_CountLUT[ Index ] );

            m_Offset = m_OffsetLUT[ Index ];  // absolute offset
            m_Count  = m_CountLUT[ Index ];
            m_Name   = m_NameLUT[ Index ];
        }

        return *this;
    }

    // Frame table variable (located relative to parent frame table entry)
    IoAKSC1000INIVariable& SetFTIndex( int Index, int Offset, int Count )
    {
        m_Offset = 0;
        m_Count  = 0;
        m_Name   = NULL;

        if ( 0 <= Index && Index < nKSC1000INI_FrameTableVariableCount )
        {
            Index += nKSC1000INI_ControlVariableCount;

            // Offset and count must refer to frame table entry
            ASSERT( ( Offset - iKSC1000FrameTablesBitOffset ) % nKSC1000FrameTableEntryBitCount == 0 && Count == nKSC1000FrameTableEntryBitCount );

            m_Offset = m_OffsetLUT[ Index ] + Offset;  // offset relative to frame table entry
            m_Count  = m_CountLUT[ Index ];
            m_Name   = m_NameLUT[ Index ];
        }

        return *this;
    }

    // Line table variable (located relative to parent line table entry)
    IoAKSC1000INIVariable& SetLTIndex( int Index, int Offset, int Count )
    {
        m_Offset = 0;
        m_Count  = 0;
        m_Name   = NULL;

        if ( 0 <= Index && Index < nKSC1000INI_LineTableVariableCount )
        {
            Index += nKSC1000INI_ControlVariableCount + nKSC1000INI_FrameTableVariableCount;

            // Offset and count must refer to line table entry
            ASSERT( ( Offset - iKSC1000LineTablesBitOffset ) % nKSC1000LineTableEntryBitCount == 0 && Count == nKSC1000LineTableEntryBitCount );

            m_Offset = m_OffsetLUT[ Index ] + Offset;  // offset relative to line table entry
            m_Count  = m_CountLUT[ Index ];
            m_Name   = m_NameLUT[ Index ];
        }

        return *this;
    }

private:
    int m_Offset, m_Count;
    const char *m_Name;

    // Bit offset for each register
    static const int m_OffsetLUT[ nKSC1000INI_VariableCount ];

    // Numbers of bits in each register
    static const int m_CountLUT[ nKSC1000INI_VariableCount ];

    // String to identify each register
    static const char *m_NameLUT[ nKSC1000INI_VariableCount ];
};

class IoAKSC1000LineTableEntry : public IoAKSC1000INIVariable
{
public:
    int IsDefined( ) const { return m_Count > 0; }
    int BitCount( ) const { return m_Count; }
    int BitOffset( ) const { return m_Offset; }

    int TableNumber( ) const { return IsDefined( ) ? ( m_Offset - iKSC1000LineTablesBitOffset ) / nKSC1000LineTableBitCount : -1; }
    int EntryNumber( ) const { return IsDefined( ) ? m_Index : -1; }

    IoAKSC1000LineTableEnum      TableEnum( ) const { return (IoAKSC1000LineTableEnum)      TableNumber( ); }
    IoAKSC1000LineTableEntryEnum EntryEnum( ) const { return (IoAKSC1000LineTableEntryEnum) EntryNumber( ); }

    int VariableCount( ) const { return m_Count > 0 ? nKSC1000LineTableVariableCount : 0; }

    // Array operators for accessing individual variables and bits
    IoAKSC1000Variable& operator[]( IoAKSC1000LTVariableEnum Index ) { return IoAKSC1000Variable::SetLTIndex( Index, m_Offset, m_Count ); }
    IoAKSC1000Bit&      operator[]( IoAKSC1000BitEnum        Index ) { return IoAKSC1000Bit     ::SetIndex( Index, m_Offset, m_Count ); }

    // Overload bit array operator with one taking (int) argument
    IoAKSC1000Bit& operator[]( int Index ) { return operator[]( (IoAKSC1000BitEnum) Index ); }

    // Same array operators modified to work with const source objects and returning const reference
    const IoAKSC1000Variable& operator[]( IoAKSC1000LTVariableEnum Index ) const { return This( )->operator[]( Index ); }
    const IoAKSC1000Bit&      operator[]( IoAKSC1000BitEnum        Index ) const { return This( )->operator[]( Index ); }
    const IoAKSC1000Bit&      operator[]( int                      Index ) const { return This( )->operator[]( Index ); }

    // Add support for INI file variables
    IoAKSC1000INIVariable& operator[]( IoAKSC1000INI_LTVariableEnum Index ) { return IoAKSC1000INIVariable::SetLTIndex( Index, m_Offset, m_Count ); }

    // Test for equality
    int IsEqual( const IoAKSC1000LineTableEntry& Other ) const
    {
        return IoAKSC1000Data::IsBitFieldEqual( m_Offset, m_Count, Other, Other.m_Offset, Other.m_Count );
    }

    int operator==( const IoAKSC1000LineTableEntry& Other ) const { return   IsEqual( Other ); }
    int operator!=( const IoAKSC1000LineTableEntry& Other ) const { return ! IsEqual( Other ); }

    // Clear data
    int Clear( ) { return IoAKSC1000Data::ClearBitField( m_Offset, m_Count ); }

    // Copy data
    int Copy( const IoAKSC1000LineTableEntry& Other )
    {
        return IoAKSC1000Data::CopyBitField( m_Offset, m_Count, Other, Other.m_Offset, Other.m_Count );
    }

    // Assignment operator
    IoAKSC1000LineTableEntry& operator=( const IoAKSC1000LineTableEntry& Other ) { Copy( Other ); return *this; }

    // Set whole entry
    void Set( int Count, int HCLK_HEnable = 0, int V1 = 0, int V2 = 0, int V3 = 0, int V4 = 0, int V5 = 0, int V6 = 0 )
    {
//        ( *this )[ ePixelClockCount ] = Count & 0x1fff;

//        ( *this )[ eHCLK_HEnable ] = HCLK_HEnable != 0;

//        ( *this )[ eV1Asserted ] = V1 != 0;
//        ( *this )[ eV2Asserted ] = V2 != 0;
//        ( *this )[ eV3Asserted ] = V3 != 0;
//        ( *this )[ eV4Asserted ] = V4 != 0
//        ( *this )[ eV5Asserted ] = V5 != 0;
//        ( *this )[ eV6Asserted ] = V6 != 0;

        int Bits = Count & 0x01fff;

        if ( HCLK_HEnable ) Bits |= 0x02000;

        if ( V1 ) Bits |= 0x80000;
        if ( V2 ) Bits |= 0x40000;
        if ( V3 ) Bits |= 0x20000;
        if ( V4 ) Bits |= 0x10000;
        if ( V5 ) Bits |= 0x08000;
        if ( V6 ) Bits |= 0x04000;

        ( *this )[ eLineTableEntryBits ] = Bits;
    }

    // End of Line Table <= all zero entry
    void EndOfLineTable( ) { Clear( ); }
    void EOLT( ) { EndOfLineTable( ); }

protected:
    IoAKSC1000LineTableEntry( IoABitArray& BitArray ) : IoAKSC1000INIVariable( BitArray ), m_Offset( 0 ), m_Count( 0 ) { }

    // Line table entry (located relative to parent line table)
    IoAKSC1000LineTableEntry& SetIndex( int Index, int Offset, int Count )
    {
        m_Offset = 0;
        m_Count  = 0;

        if ( 0 <= Index && Index < nLineTableEntryCount )
        {
            // Offset and Count must refer to line table
            ASSERT( ( Offset - iKSC1000LineTablesBitOffset ) % nKSC1000LineTableBitCount == 0 && Count == nKSC1000LineTableBitCount );

            m_Offset = Offset + Index * nKSC1000LineTableEntryBitCount;  // relative offset
            m_Count  = nKSC1000LineTableEntryBitCount;

            m_Index = Index;
        }

        return *this;
    }

private:
    IoAKSC1000LineTableEntry *This( ) const { return (IoAKSC1000LineTableEntry *) this; }  // helper function to cast-away const

    int m_Offset, m_Count, m_Index;
};

class IoAKSC1000LineTable : public IoAKSC1000LineTableEntry
{
public:
    int IsDefined( ) const { return m_Count > 0; }
    int BitCount( ) const { return m_Count; }
    int BitOffset( ) const { return m_Offset; }

    int TableNumber( ) const { return IsDefined( ) ? m_Index : -1; }

    IoAKSC1000LineTableEnum TableEnum( ) const { return (IoAKSC1000LineTableEnum) TableNumber( ); }

    int EntryCount( ) const { return m_Count > 0 ? nLineTableEntryCount : 0; }
    int ByteCount( ) const { return m_Count / 8; }

    // Array operators for accessing individual line table entries, bytes and bits
    IoAKSC1000LineTableEntry& operator[]( IoAKSC1000LineTableEntryEnum Index ) { return IoAKSC1000LineTableEntry::SetIndex( Index, m_Offset, m_Count ); }
    IoAKSC1000Byte&           operator[]( IoAKSC1000ByteEnum           Index ) { return IoAKSC1000Byte          ::SetIndex( Index, m_Offset, m_Count ); }
    IoAKSC1000Bit&            operator[]( IoAKSC1000BitEnum            Index ) { return IoAKSC1000Bit           ::SetIndex( Index, m_Offset, m_Count ); }

    // Overload bit array operator with one taking (int) argument
    IoAKSC1000Bit& operator[]( int Index ) { return operator[]( (IoAKSC1000BitEnum) Index ); }

    // Same array operators modified to work with const source objects and returning const reference
    const IoAKSC1000LineTableEntry& operator[]( IoAKSC1000LineTableEntryEnum Index ) const { return This( )->operator[]( Index ); }
    const IoAKSC1000Byte&           operator[]( IoAKSC1000ByteEnum           Index ) const { return This( )->operator[]( Index ); }
    const IoAKSC1000Bit&            operator[]( IoAKSC1000BitEnum            Index ) const { return This( )->operator[]( Index ); }
    const IoAKSC1000Bit&            operator[]( int                          Index ) const { return This( )->operator[]( Index ); }

    // Test for equality
    int IsEqual( const IoAKSC1000LineTable& Other ) const
    {
        return IoAKSC1000Data::IsBitFieldEqual( m_Offset, m_Count, Other, Other.m_Offset, Other.m_Count );
    }

    int operator==( const IoAKSC1000LineTable& Other ) const { return   IsEqual( Other ); }
    int operator!=( const IoAKSC1000LineTable& Other ) const { return ! IsEqual( Other ); }

    // Clear data
    int Clear( ) { return IoAKSC1000Data::ClearBitField( m_Offset, m_Count ); }

    // Copy data
    int Copy( const IoAKSC1000LineTable& Other )
    {
        return IoAKSC1000Data::CopyBitField( m_Offset, m_Count, Other, Other.m_Offset, Other.m_Count );
    }

    // Assignment operator
    IoAKSC1000LineTable& operator=( const IoAKSC1000LineTable& Other ) { Copy( Other ); return *this; }

    // Set up line table for time delay (up to limit imposed by line table size)
    void Set( int Count, int HCLK_HEnable = 0, int V1 = 0, int V2 = 0, int V3 = 0, int V4 = 0, int V5 = 0, int V6 = 0 )
    {
        if ( 0 < Count && Count <= ( EntryCount( ) - 1 ) * 8191 )
        {
            IoAKSC1000LineTableEntryEnum Entry;

            int e;
			
			for ( e = 0; Count > 8191 && e < ( EntryCount( ) - 1 ); Count -= 8191 )
            {
                Entry = (IoAKSC1000LineTableEntryEnum) e++;

                ( *this )[ Entry ].Set( 8191, HCLK_HEnable, V1, V2, V3, V4, V5, V6 );
            }

            Entry = (IoAKSC1000LineTableEntryEnum) e++;

            ( *this )[ Entry ].Set( Count, HCLK_HEnable, V1, V2, V3, V4, V5, V6 );

            Entry = (IoAKSC1000LineTableEntryEnum) e;

            ( *this )[ Entry ].EOLT( );
        }
    }

protected:
    IoAKSC1000LineTable( IoABitArray& BitArray ) : IoAKSC1000LineTableEntry( BitArray ), m_Offset( 0 ), m_Count( 0 ) { }

    // Line table (located at fixed absolute location in data array)
    IoAKSC1000LineTable& SetIndex( int Index, int Offset, int Count )
    {
        m_Offset = 0;
        m_Count  = 0;

        if ( 0 <= Index && Index < nLineTableCount )
        {
            // Offset and count must encompass line tables
            ASSERT( Offset <= iKSC1000LineTablesBitOffset && Offset + Count >= iKSC1000LineTablesBitOffset + nKSC1000LineTablesBitCount );

            m_Offset = iKSC1000LineTablesBitOffset + Index * nKSC1000LineTableBitCount;  // absolute offset
            m_Count  = nKSC1000LineTableBitCount;

            m_Index = Index;
        }

        return *this;
    }

private:
    IoAKSC1000LineTable *This( ) const { return (IoAKSC1000LineTable *) this; }  // helper function to cast-away const

    int m_Offset, m_Count, m_Index;
};

class IoAKSC1000FrameTableEntry : public IoAKSC1000LineTable
{
public:
    int IsDefined( ) const { return m_Count > 0; }
    int BitCount( ) const { return m_Count; }
    int BitOffset( ) const { return m_Offset; }

    int TableNumber( ) const { return IsDefined( ) ? ( m_Offset - iKSC1000FrameTablesBitOffset ) / nKSC1000FrameTableBitCount : -1; }
    int EntryNumber( ) const { return IsDefined( ) ? m_Index : -1; }

    IoAKSC1000FrameTableEnum      TableEnum( ) const { return (IoAKSC1000FrameTableEnum)      TableNumber( ); }
    IoAKSC1000FrameTableEntryEnum EntryEnum( ) const { return (IoAKSC1000FrameTableEntryEnum) EntryNumber( ); }

    int VariableCount( ) const { return m_Count > 0 ? nKSC1000FrameTableVariableCount : 0; }

    // Array operators for accessing individual variables and bits
    IoAKSC1000Variable& operator[]( IoAKSC1000FTVariableEnum Index ) { return IoAKSC1000Variable::SetFTIndex( Index, m_Offset, m_Count ); }
    IoAKSC1000Bit&      operator[]( IoAKSC1000BitEnum        Index ) { return IoAKSC1000Bit     ::SetIndex( Index, m_Offset, m_Count ); }

    // Overload bit array operator with one taking (int) argument
    IoAKSC1000Bit& operator[]( int Index ) { return operator[]( (IoAKSC1000BitEnum) Index ); }

    // Same array operators modified to work with const source objects and returning const reference
    const IoAKSC1000Variable& operator[]( IoAKSC1000FTVariableEnum Index ) const { return This( )->operator[]( Index ); }
    const IoAKSC1000Bit&      operator[]( IoAKSC1000BitEnum        Index ) const { return This( )->operator[]( Index ); }
    const IoAKSC1000Bit&      operator[]( int                      Index ) const { return This( )->operator[]( Index ); }

    // Add support for INI file variables
    IoAKSC1000INIVariable& operator[]( IoAKSC1000INI_FTVariableEnum Index ) { return IoAKSC1000INIVariable::SetFTIndex( Index, m_Offset, m_Count ); }

    // Test for equality
    int IsEqual( const IoAKSC1000FrameTableEntry& Other ) const
    {
        return IoAKSC1000Data::IsBitFieldEqual( m_Offset, m_Count, Other, Other.m_Offset, Other.m_Count );
    }

    int operator==( const IoAKSC1000FrameTableEntry& Other ) const { return   IsEqual( Other ); }
    int operator!=( const IoAKSC1000FrameTableEntry& Other ) const { return ! IsEqual( Other ); }

    // Clear data
    int Clear( ) { return IoAKSC1000Data::ClearBitField( m_Offset, m_Count ); }

    // Copy data
    int Copy( const IoAKSC1000FrameTableEntry& Other )
    {
        return IoAKSC1000Data::CopyBitField( m_Offset, m_Count, Other, Other.m_Offset, Other.m_Count );
    }

    // Assignment operator
    IoAKSC1000FrameTableEntry& operator=( const IoAKSC1000FrameTableEntry& Other ) { Copy( Other ); return *this; }

    // Setting up of Event Descriptor
    void JmpFT( int FrameTable )
    {
        ( *this )[ eEventFlag    ] = 0;
        ( *this )[ eEventCount   ] = 0;
        ( *this )[ eEventAddress ] = FrameTable & 0x7;  // 0 <= FrameTable < 8, high-order address bit = 0
    }

    void JmpFTVD( int FrameTable )
    {
        ( *this )[ eEventFlag    ] = 0;
        ( *this )[ eEventCount   ] = 0;
        ( *this )[ eEventAddress ] = ( FrameTable & 0x7 ) | 0x8;  // 0 <= FrameTable < 8, high-order address bit = 1
    }

    void ExLTNVD( int LineTable )
    {
        ( *this )[ eEventFlag    ] = 1;
        ( *this )[ eEventCount   ] = 0;
        ( *this )[ eEventAddress ] = LineTable & 0xf;  // 0 <= LineTable < 16
    }

    void ExLT( int Count, int LineTable )
    {
        ( *this )[ eEventFlag    ] = 0;
        ( *this )[ eEventCount   ] = Count & 0x1fff;   // 0 < Count < 8192
        ( *this )[ eEventAddress ] = LineTable & 0xf;  // 0 <= LineTable < 16
    }

    void Loop( int Count, int FrameTableEntry )
    {
        ( *this )[ eEventFlag    ] = 1;
        ( *this )[ eEventCount   ] = Count & 0x1fff;         // 0 < Count < 8192
        ( *this )[ eEventAddress ] = FrameTableEntry & 0xf;  // 0 <= FrameTableEntry < 16
    }

protected:
    IoAKSC1000FrameTableEntry( IoABitArray& BitArray ) : IoAKSC1000LineTable( BitArray ), m_Offset( 0 ), m_Count( 0 ) { }

    // Frame table entry (located relative to parent frame table)
    IoAKSC1000FrameTableEntry& SetIndex( int Index, int Offset, int Count )
    {
        m_Offset = 0;
        m_Count  = 0;

        if ( 0 <= Index && Index < nFrameTableEntryCount )
        {
            // Offset and Count must refer to frame table
            ASSERT( ( Offset - iKSC1000FrameTablesBitOffset ) % nKSC1000FrameTableBitCount == 0 && Count == nKSC1000FrameTableBitCount );

            m_Offset = Offset + Index * nKSC1000FrameTableEntryBitCount;  // relative offset
            m_Count  = nKSC1000FrameTableEntryBitCount;

            m_Index = Index;
        }

        return *this;
    }

private:
    IoAKSC1000FrameTableEntry *This( ) const { return (IoAKSC1000FrameTableEntry *) this; }  // helper function to cast-away const

    int m_Offset, m_Count, m_Index;
};

class IoAKSC1000FrameTable : public IoAKSC1000FrameTableEntry
{
public:
    int IsDefined( ) const { return m_Count > 0; }
    int BitCount( ) const { return m_Count; }
    int BitOffset( ) const { return m_Offset; }

    int TableNumber( ) const { return IsDefined( ) ? m_Index : -1; }

    IoAKSC1000FrameTableEnum TableEnum( ) const { return (IoAKSC1000FrameTableEnum) TableNumber( ); }

    int EntryCount( ) const { return m_Count > 0 ? nFrameTableEntryCount : 0; }
    int ByteCount( ) const { return m_Count / 8; }

    // Array operators for accessing individual frame table entries, bytes and bits
    IoAKSC1000FrameTableEntry& operator[]( IoAKSC1000FrameTableEntryEnum Index ) { return IoAKSC1000FrameTableEntry::SetIndex( Index, m_Offset, m_Count ); }
    IoAKSC1000Byte&            operator[]( IoAKSC1000ByteEnum            Index ) { return IoAKSC1000Byte           ::SetIndex( Index, m_Offset, m_Count ); }
    IoAKSC1000Bit&             operator[]( IoAKSC1000BitEnum             Index ) { return IoAKSC1000Bit            ::SetIndex( Index, m_Offset, m_Count ); }

    // Overload bit array operator with one taking (int) argument
    IoAKSC1000Bit& operator[]( int Index ) { return operator[]( (IoAKSC1000BitEnum) Index ); }

    // Same array operators modified to work with const source objects and returning const reference
    const IoAKSC1000FrameTableEntry& operator[]( IoAKSC1000FrameTableEntryEnum Index ) const { return This( )->operator[]( Index ); }
    const IoAKSC1000Byte&            operator[]( IoAKSC1000ByteEnum            Index ) const { return This( )->operator[]( Index ); }
    const IoAKSC1000Bit&             operator[]( IoAKSC1000BitEnum             Index ) const { return This( )->operator[]( Index ); }
    const IoAKSC1000Bit&             operator[]( int                           Index ) const { return This( )->operator[]( Index ); }

    // Test for equality
    int IsEqual( const IoAKSC1000FrameTable& Other ) const
    {
        return IoAKSC1000Data::IsBitFieldEqual( m_Offset, m_Count, Other, Other.m_Offset, Other.m_Count );
    }

    int operator==( const IoAKSC1000FrameTable& Other ) const { return   IsEqual( Other ); }
    int operator!=( const IoAKSC1000FrameTable& Other ) const { return ! IsEqual( Other ); }

    // Clear data
    int Clear( ) { return IoAKSC1000Data::ClearBitField( m_Offset, m_Count ); }

    // Copy data
    int Copy( const IoAKSC1000FrameTable& Other )
    {
        return IoAKSC1000Data::CopyBitField( m_Offset, m_Count, Other, Other.m_Offset, Other.m_Count );
    }

    // Assignment operator
    IoAKSC1000FrameTable& operator=( const IoAKSC1000FrameTable& Other ) { Copy( Other ); return *this; }

protected:
    IoAKSC1000FrameTable( IoABitArray& BitArray ) : IoAKSC1000FrameTableEntry( BitArray ), m_Offset( 0 ), m_Count( 0 ) { }

    // Frame table (located at fixed absolute location in data array)
    IoAKSC1000FrameTable& SetIndex( int Index, int Offset, int Count )
    {
        m_Offset = 0;
        m_Count  = 0;

        if ( 0 <= Index && Index < nFrameTableCount )
        {
            // Offset and count must encompass frame tables
            ASSERT( Offset <= iKSC1000FrameTablesBitOffset && Offset + Count >= iKSC1000FrameTablesBitOffset + nKSC1000FrameTablesBitCount );

            m_Index = Index;

            m_Offset = iKSC1000FrameTablesBitOffset + Index * nKSC1000FrameTableBitCount;  // absolute offset
            m_Count  = nKSC1000FrameTableBitCount;
        }

        return *this;
    }

private:
    IoAKSC1000FrameTable *This( ) const { return (IoAKSC1000FrameTable *) this; }  // helper function to cast-away const

    int m_Offset, m_Count, m_Index;
};

class IoAKSC1000Register : public IoAKSC1000FrameTable
{
public:
    int IsDefined( ) const { return m_Count > 0; }
    int BitCount( ) const { return m_Count; }
    int BitOffset( ) const { return m_Offset; }

    int IsControlRegister( ) const { return IsDefined( ) && 0 <= m_Index && m_Index < (int) nKSC1000ControlRegisterCount; }
    int IsFrameTableRegister( ) const { return IsDefined( ) && m_Index == (int) eFrameTableAccessRegister; }
    int IsLineTableRegister( ) const { return IsDefined( ) && m_Index == (int) eLineTableAccessRegister; }
    int IsStatusRegister( ) const { return IsDefined( ) && m_Index == (int) eStatusRegister; }

    const char *Name( ) const { return m_Name; }

//    int Number( ) const { return IsDefined( ) ? m_Index : -1; }

    int Number( ) const
    {
        int Number = -1;

        if ( IsDefined( ) ) Number = m_Index != eControlRegisters ? m_Index : 0;

        return Number;
    }

//    IoAKSC1000RegisterEnum Enum( ) const { return (IoAKSC1000RegisterEnum) ( IsDefined( ) ? m_Index : -1 ); }

    IoAKSC1000RegisterEnum Enum( ) const
    {
        int Enum = -1;

        if ( IsDefined( ) ) Enum = m_Index;

        return (IoAKSC1000RegisterEnum) Enum;
    }

    int TableCount( ) const
    {
        int Count = 0;

        if ( IsDefined( ) )
        {
            if ( m_Index == eFrameTableAccessRegister ) Count = nFrameTableCount;
            if ( m_Index == eLineTableAccessRegister  ) Count = nLineTableCount;
        }

        return Count;
    }

    int TableEntryCount( ) const
    {
        int Count = 0;

        if ( IsDefined( ) )
        {
            if ( m_Index == eFrameTableAccessRegister ) Count = nFrameTableEntryCount;
            if ( m_Index == eLineTableAccessRegister  ) Count = nLineTableEntryCount;
        }

        return Count;
    }

    int VariableCount( ) const { return m_VariableCount; }

    int FrameTableCount( ) const { return m_Count > 0 ? nFrameTableCount : 0; }
    int LineTableCount( ) const { return m_Count > 0 ? nLineTableCount : 0; }
    int ByteCount( ) const { return m_Count / 8; }

    // Array operator for accessing individual frame tables, line tables, variables, bytes and bits
    IoAKSC1000FrameTable& operator[]( IoAKSC1000FrameTableEnum Index ) { return IoAKSC1000FrameTable::SetIndex  ( Index, m_Offset, m_Count ); }
    IoAKSC1000LineTable&  operator[]( IoAKSC1000LineTableEnum  Index ) { return IoAKSC1000LineTable ::SetIndex  ( Index, m_Offset, m_Count ); }
    IoAKSC1000Variable&   operator[]( IoAKSC1000CRVariableEnum Index ) { return IoAKSC1000Variable  ::SetCRIndex( Index, m_Offset, m_Count ); }
    IoAKSC1000Variable&   operator[]( IoAKSC1000SRVariableEnum Index ) { return IoAKSC1000Variable  ::SetSRIndex( Index, m_Offset, m_Count ); }
    IoAKSC1000Byte&       operator[]( IoAKSC1000ByteEnum       Index ) { return IoAKSC1000Byte      ::SetIndex  ( Index, m_Offset, m_Count ); }
    IoAKSC1000Bit&        operator[]( IoAKSC1000BitEnum        Index ) { return IoAKSC1000Bit       ::SetIndex  ( Index, m_Offset, m_Count ); }

    // Overload variable array operator with one taking index relative to given control register
    IoAKSC1000Variable& operator[]( IoAKSC1000CRVariableIndex Index )
    {
        int AbsoluteIndex = ( 0 <= Index && Index < m_VariableCount ) ? m_VariableOffset + Index : eInvalidControlVariable;

        return IoAKSC1000Variable::SetCRIndex( AbsoluteIndex, m_Offset, m_Count );
    }

    // Overload bit array operator with one taking (int) argument
    IoAKSC1000Bit& operator[]( int Index ) { return operator[]( (IoAKSC1000BitEnum) Index ); }

    // Same array operators modified to work with const source objects and returning const reference
    const IoAKSC1000FrameTable&  operator[]( IoAKSC1000FrameTableEnum  Index ) const { return This( )->operator[]( Index ); }
    const IoAKSC1000LineTable&   operator[]( IoAKSC1000LineTableEnum   Index ) const { return This( )->operator[]( Index ); }
    const IoAKSC1000Variable&    operator[]( IoAKSC1000CRVariableIndex Index ) const { return This( )->operator[]( Index ); }
    const IoAKSC1000Variable&    operator[]( IoAKSC1000CRVariableEnum  Index ) const { return This( )->operator[]( Index ); }
    const IoAKSC1000Variable&    operator[]( IoAKSC1000SRVariableEnum  Index ) const { return This( )->operator[]( Index ); }
    const IoAKSC1000Byte&        operator[]( IoAKSC1000ByteEnum        Index ) const { return This( )->operator[]( Index ); }
    const IoAKSC1000Bit&         operator[]( IoAKSC1000BitEnum         Index ) const { return This( )->operator[]( Index ); }
    const IoAKSC1000Bit&         operator[]( int                       Index ) const { return This( )->operator[]( Index ); }

    // Add support for INI file variables (see IoAKSC1000Registers::Load( ) function)
    IoAKSC1000INIVariable& operator[]( IoAKSC1000INI_CRVariableIndex Index )
    {
        return IoAKSC1000INIVariable::SetCRIndex( m_INIVariableOffset + Index, m_Offset, m_Count );
    }

    int INIVariableCount( ) const { return m_INIVariableCount; }

    // Test for equality
    int IsEqual( const IoAKSC1000Register& Other ) const
    {
        return IoAKSC1000Data::IsBitFieldEqual( m_Offset, m_Count, Other, Other.m_Offset, Other.m_Count );
    }

    int operator==( const IoAKSC1000Register& Other ) const { return   IsEqual( Other ); }
    int operator!=( const IoAKSC1000Register& Other ) const { return ! IsEqual( Other ); }

    // Clear data
    int Clear( ) { return IoAKSC1000Data::ClearBitField( m_Offset, m_Count ); }

    // Copy data
    int Copy( const IoAKSC1000Register& Other )
    {
        return m_Offset == Other.m_Offset && IoAKSC1000Data::CopyBitField( m_Offset, m_Count, Other, Other.m_Offset, Other.m_Count );
    }

    // Assignment operator
    IoAKSC1000Register& operator=( const IoAKSC1000Register& Other ) { Copy( Other ); return *this; }

protected:
    IoAKSC1000Register( IoABitArray& BitArray ) : IoAKSC1000FrameTable( BitArray ), m_Offset( 0 ), m_Count( 0 ) { }

    // Register (located at fixed absolute location in data array)
    IoAKSC1000Register& SetIndex( int Index, int Offset, int Count )
    {
        m_Offset = 0;
        m_Count  = 0;
        m_Name   = NULL;

        m_VariableOffset = 0;
        m_VariableCount  = 0;

        m_INIVariableOffset = 0;
        m_INIVariableCount  = 0;

        if ( 0 <= Index && Index < nKSC1000RegisterCount )
        {
            // Offset and count must encompass entire data array
            ASSERT( Offset == 0 && Count > 0 && Count == IoAKSC1000Data::Size( ) );

            m_Offset = m_OffsetLUT[ Index ];  // absolute offset
            m_Count  = m_CountLUT[ Index ];
            m_Name   = m_NameLUT[ Index ];

            m_VariableOffset = m_VariableOffsetLUT[ Index ];
            m_VariableCount  = m_VariableCountLUT[ Index ];

            m_INIVariableOffset = m_INIVariableOffsetLUT[ Index ];
            m_INIVariableCount  = m_INIVariableCountLUT[ Index ];

            m_Index = Index;
        }

        return *this;
    }

private:
    IoAKSC1000Register *This( ) const { return (IoAKSC1000Register *) this; }  // helper function to cast-away const

    int m_Offset, m_Count, m_Index;
    const char *m_Name;
    int m_VariableOffset, m_VariableCount;
    int m_INIVariableOffset, m_INIVariableCount;

    // Bit offset for each register
    static const int m_OffsetLUT[ nKSC1000RegisterCount ];

    // Numbers of bits in each register
    static const int m_CountLUT[ nKSC1000RegisterCount ];

    // String to identify each register
    static const char *m_NameLUT[ nKSC1000RegisterCount ];

    // Variable offset for each register
    static const int m_VariableOffsetLUT[ nKSC1000RegisterCount ];

    // Numbers of variables in each register
    static const int m_VariableCountLUT[ nKSC1000RegisterCount ];

    // INI variable offset for each register
    static const int m_INIVariableOffsetLUT[ nKSC1000INIRegisterCount ];

    // Numbers of INI file variables in each register
    static const int m_INIVariableCountLUT[ nKSC1000INIRegisterCount ];
};

class IoAKSC1000RegisterArray : public IoAKSC1000Register
{
public:
    IoAKSC1000RegisterArray( IoABitArray& BitArray ) : IoAKSC1000Register( BitArray ) { }

    // Provides valid conversion from any base class object (direct or indirect down to IoAKSC1000Data base class)
    // Should also function as copy constructor
    IoAKSC1000RegisterArray( const IoAKSC1000Data& Other ) : IoAKSC1000Register( Other.BitArray( ) ) { }

    int IsValid( ) const { return IoAKSC1000Data::IsValid( ); }

    int BitCount( ) const { return IoAKSC1000Data::Size( ); }

    int ByteCount( ) const { return BitCount( ) / 8; }

    int IsDefined( ) const { return BitCount( ) == nKSC1000RegistersBitCount; }

    int RegisterCount( )   const { return IsDefined( ) ? nKSC1000RegisterCount : 0; }
    int FrameTableCount( ) const { return IsDefined( ) ? nFrameTableCount      : 0; }
    int LineTableCount( )  const { return IsDefined( ) ? nLineTableCount       : 0; }

    int ControlRegisterCount( ) const { return IsDefined( ) ? nKSC1000ControlRegisterCount : 0; }
    int ControlVariableCount( ) const { return IsDefined( ) ? nKSC1000ControlVariableCount : 0; }
    int StatusVariableCount( )  const { return IsDefined( ) ? nKSC1000StatusVariableCount  : 0; }

    // Array operators for accessing individual registers, frame tables, line tables, control/status variables, bytes and bits
    IoAKSC1000Register&   operator[]( IoAKSC1000RegisterEnum    Index ) { return IoAKSC1000Register  ::SetIndex  ( Index, 0, BitCount( ) ); }
    IoAKSC1000FrameTable& operator[]( IoAKSC1000FrameTableEnum  Index ) { return IoAKSC1000FrameTable::SetIndex  ( Index, 0, BitCount( ) ); }
    IoAKSC1000LineTable&  operator[]( IoAKSC1000LineTableEnum   Index ) { return IoAKSC1000LineTable ::SetIndex  ( Index, 0, BitCount( ) ); }
    IoAKSC1000Variable&   operator[]( IoAKSC1000CRVariableIndex Index ) { return IoAKSC1000Variable  ::SetCRIndex( Index, 0, BitCount( ) ); }
    IoAKSC1000Variable&   operator[]( IoAKSC1000CRVariableEnum  Index ) { return IoAKSC1000Variable  ::SetCRIndex( Index, 0, BitCount( ) ); }
    IoAKSC1000Variable&   operator[]( IoAKSC1000SRVariableEnum  Index ) { return IoAKSC1000Variable  ::SetSRIndex( Index, 0, BitCount( ) ); }
    IoAKSC1000Byte&       operator[]( IoAKSC1000ByteEnum        Index ) { return IoAKSC1000Byte      ::SetIndex  ( Index, 0, BitCount( ) ); }
    IoAKSC1000Bit&        operator[]( IoAKSC1000BitEnum         Index ) { return IoAKSC1000Bit       ::SetIndex  ( Index, 0, BitCount( ) ); }

    // Overload bit array operator with one taking (int) argument
    IoAKSC1000Bit& operator[]( int Index ) { return operator[]( (IoAKSC1000BitEnum) Index ); }

    // Same array operators modified to work with const source objects and returning const reference
    const IoAKSC1000Register&    operator[]( IoAKSC1000RegisterEnum    Index ) const { return This( )->operator[]( Index ); }
    const IoAKSC1000FrameTable&  operator[]( IoAKSC1000FrameTableEnum  Index ) const { return This( )->operator[]( Index ); }
    const IoAKSC1000LineTable&   operator[]( IoAKSC1000LineTableEnum   Index ) const { return This( )->operator[]( Index ); }
    const IoAKSC1000Variable&    operator[]( IoAKSC1000CRVariableIndex Index ) const { return This( )->operator[]( Index ); }
    const IoAKSC1000Variable&    operator[]( IoAKSC1000CRVariableEnum  Index ) const { return This( )->operator[]( Index ); }
    const IoAKSC1000Variable&    operator[]( IoAKSC1000SRVariableEnum  Index ) const { return This( )->operator[]( Index ); }
    const IoAKSC1000Byte&        operator[]( IoAKSC1000ByteEnum        Index ) const { return This( )->operator[]( Index ); }
    const IoAKSC1000Bit&         operator[]( IoAKSC1000BitEnum         Index ) const { return This( )->operator[]( Index ); }
    const IoAKSC1000Bit&         operator[]( int                       Index ) const { return This( )->operator[]( Index ); }

    // Test for equality
    int IsEqual( const IoAKSC1000RegisterArray& Other ) const { return IoAKSC1000Data::IsEqual( Other ); }

    int operator==( const IoAKSC1000RegisterArray& Other ) const { return   IsEqual( Other ); }
    int operator!=( const IoAKSC1000RegisterArray& Other ) const { return ! IsEqual( Other ); }

    // Clear data
    int Clear( ) { return IoAKSC1000Data::Clear( ); }

    // Copy data
    int Copy( const IoAKSC1000RegisterArray& Other ) { return IoAKSC1000Data::Copy( Other ); }

    // Assignment operator
    IoAKSC1000RegisterArray& operator=( const IoAKSC1000RegisterArray& Other ) { Copy( Other ); return *this; }

private:
    IoAKSC1000RegisterArray *This( ) const { return (IoAKSC1000RegisterArray *) this; }  // helper function to cast-away const
};

// Register data storage class
class IoAKSC1000Registers : public IoAKSC1000RegisterArray
{
public:
    // Constructor (including default constructor)
    IoAKSC1000Registers( ) : IoAKSC1000RegisterArray( m_BitArray )
    {
        // Allocate memory for bit array to hold register bits
        if ( m_BitArray.Allocate( nKSC1000RegistersBitCount ) ) SetDefaults( );
    }

    // Copy constructor
    IoAKSC1000Registers( const IoAKSC1000Registers& Other ) : IoAKSC1000RegisterArray( m_BitArray ) { Copy( Other ); }

    // Assignment operator
    IoAKSC1000Registers& operator=( const IoAKSC1000Registers& Other ) { Copy( Other ); return *this; }

    // Default register settings
    void SetDefaults( );

    // Copy function
    int Copy( const IoAKSC1000Registers& Other ) { return IoAKSC1000Data::Copy( Other ); }

private:
    // Register data
    IoABitArray m_BitArray;
};

#include "Device.h"

class IoAKSC1000 : public IoADevice
{
public:
    IoAKSC1000( int Index = 0 ) : IoADevice( "KSC1000", Index ), m_PixelClockFrequency( 0.0 ) { }

    IoAKSC1000( const IoAKSC1000Registers& Registers, int Index = 0 ) :
        IoADevice( "KSC1000", Index ), m_PixelClockFrequency( 0.0 ), m_Registers( Registers ) { }

    ~IoAKSC1000( ) { Close( ); }  // because base class destructor cannot call IoAKSC1000::Close( )

    // Register access
    const IoAKSC1000Registers& Registers( ) const { return m_Registers; }
    operator const IoAKSC1000Registers&( ) const { return Registers( ); }

    const IoAKSC1000Register& Register( IoAKSC1000RegisterEnum RegisterEnum ) const { return m_Registers[ RegisterEnum ]; }

    // Register groups
    const IoAKSC1000Register& ControlRegisters( ) const { return m_Registers[ eControlRegisters ]; }
    const IoAKSC1000Register& FrameTables     ( ) const { return m_Registers[ eFrameTableAccessRegister ]; }
    const IoAKSC1000Register& LinrTables      ( ) const { return m_Registers[ eLineTableAccessRegister ]; }
    const IoAKSC1000Register& StatusRegister  ( ) const { return m_Registers[ eStatusRegister ]; }

    // Individual control registers
    const IoAKSC1000Register& FrameTablePointer     ( ) const { return m_Registers[ eFrameTablePointer ]; }
    const IoAKSC1000Register& GeneralSetupRegister  ( ) const { return m_Registers[ eGeneralSetup ]; }
    const IoAKSC1000Register& GeneralControlRegister( ) const { return m_Registers[ eGeneralControl ]; }
    const IoAKSC1000Register& INTG_STRTSetupRegister( ) const { return m_Registers[ eINTG_STRTSetup ]; }
    const IoAKSC1000Register& INTG_STRTLineRegister ( ) const { return m_Registers[ eINTG_STRTLine ]; }
    const IoAKSC1000Register& SignalPolarityRegister( ) const { return m_Registers[ eSignalPolarity ]; }
    const IoAKSC1000Register& OffsetRegister        ( ) const { return m_Registers[ eOffset ]; }
    const IoAKSC1000Register& WidthRegister         ( ) const { return m_Registers[ eWidth ]; }

    // Open + close
    int Open( int Verify = FALSE );  // have to override IoADevice::Open( ) (hardware initialisation + verify function)

    void Close( int Stop = FALSE )  // override IoADevice::Close( ) (additional stop function)
    {
        if ( Stop )
        {
            IoAKSC1000::Stop( );
        }

        IoADevice::Close( );
    }

    void Detach( ) { Close( ); IoADevice::Detach( ); }  // have to override IoADevice::Detach( )

    // Synchronize specified register (can also specify all control registers/frame tables/line tables)
    int Synchronize( const IoAKSC1000Register& Register );

    // Synchronize specified frame/line table
    int Synchronize( const IoAKSC1000FrameTable& FrameTable );
    int Synchronize( const IoAKSC1000LineTable&  LineTable  );

    // Synchronize specified frame/line table entry
    int Synchronize( const IoAKSC1000FrameTableEntry& FrameTableEntry );
    int Synchronize( const IoAKSC1000LineTableEntry&  LineTableEntry  );

    // Synchronize everything (except General Control register)
    int Synchronize( const IoAKSC1000Registers& Registers )
    {
        return Synchronize( Registers[ eControlRegisters         ] ) &&
               Synchronize( Registers[ eFrameTableAccessRegister ] ) &&
               Synchronize( Registers[ eLineTableAccessRegister  ] );
    }

    // Synchronize status register (read back current state)
    int SynchronizeStatusRegister( ) { return IsOpen( ) && Read( m_Registers[ eStatusRegister ] ); }

    // Verify registers (control registers, frame tables, line tables or single control register)
    int Verify( const IoAKSC1000Register& Register );

    // Verify specified frame/line table
    int Verify( const IoAKSC1000FrameTable& FrameTable );
    int Verify( const IoAKSC1000LineTable&  LineTable  );

    // Verify specified frame/line table entry
    int Verify( const IoAKSC1000FrameTableEntry& FrameTableEntry );
    int Verify( const IoAKSC1000LineTableEntry&  LineTableEntry  );

    // Verify everything (except General Control register)
    int Verify( const IoAKSC1000Registers& Registers )
    {
        return Verify( Registers[ eControlRegisters         ] ) &&
               Verify( Registers[ eFrameTableAccessRegister ] ) &&
               Verify( Registers[ eLineTableAccessRegister  ] );
    }

    // DLL frequency range index
    static int GetDLLFrequencyRangeIndex( double PixelClockHz, int& DLLFrequencyRangeIndex )
    {
        if ( PixelClockHz >= m_DLLHz[ 4 ] )
        {
            for ( DLLFrequencyRangeIndex = 4; DLLFrequencyRangeIndex < 12; DLLFrequencyRangeIndex++ )
            {
                if ( PixelClockHz <= m_DLLHz[ DLLFrequencyRangeIndex + 1 ] ) return TRUE;
            }
        }

        return FALSE;
    }

    static int GetDLLFrequencyRange( int DLLFrequencyRangeIndex, double DLLFrequencyRange[ 2 ] )
    {
        if ( DLLFrequencyRangeIndex < 4 || DLLFrequencyRangeIndex > 11 ) return FALSE;

        DLLFrequencyRange[ 0 ] = m_DLLHz[ DLLFrequencyRangeIndex + 0 ];
        DLLFrequencyRange[ 1 ] = m_DLLHz[ DLLFrequencyRangeIndex + 1 ];

        return TRUE;
    }

    // DLL setup and status
    static int IsValidPixelClockFrequency( double PixelClockHz )
    {
        return m_DLLHz[ 4 ] <= PixelClockHz && PixelClockHz <= m_DLLHz[ 12 ];
    }

    int SetDLLFrequencyRangeIndex( double PixelClockHz );

    int DLLFrequencyRangeIndex( ) const { return m_Registers[ eDLLFrequencyRangeIndex ].Value( ); }

    int IsDLLLocked( );

    int WaitForDLLLock( double TimeLimit = 1.0 );

    //Pixel clock frequency
    int SetPixelClockFrequency( double PixelClockHz )
    {
        if ( ! SetDLLFrequencyRangeIndex( PixelClockHz ) ) return FALSE;

        m_PixelClockFrequency = PixelClockHz;

        return TRUE;
    }

    double PixelClockFrequency( ) const { return m_PixelClockFrequency; }

    int IsClockFrequencyDefined( ) const { return m_PixelClockFrequency > 0.0; }

    double PixelClockHz ( ) const { return m_PixelClockFrequency; }
    double PixelClockKHz( ) const { return m_PixelClockFrequency / 1000.0; }
    double PixelClockMHz( ) const { return m_PixelClockFrequency / 1000000.0; }

    double MilliSecondClockCount( ) const { return PixelClockKHz( ); }
    double MicroSecondClockCount( ) const { return PixelClockMHz( ); }

    //Input clock frequency = 2 * pixel clock frequency
    double InputClockFrequency( ) const { return 2.0 * PixelClockFrequency( ); }

    double InputClockHz ( ) const { return 2.0 * PixelClockHz( ); }
    double InputClockKHz( ) const { return 2.0 * PixelClockKHz( ); }
    double InputClockMHz( ) const { return 2.0 * PixelClockMHz( ); }

    // Frame Table Pointer register
    int SetFrameTablePointer( int FrameTableAddress );

    int FrameTableAddress( ) const { return m_Registers[ eFrameTablePointer ][ eFrameTableAddress ].Value( ); }

    // General Control register (controls operation of delay-locked loop (DLL) + frame table execution)
    int SetPowerMode( IoAKSC1000PowerModeEnum PowerMode );

    int SetOperationMode( IoAKSC1000OperationModeEnum OperationMode );

    int SetGeneralControlRegister( IoAKSC1000PowerModeEnum PowerMode, IoAKSC1000OperationModeEnum OperationMode );

    IoAKSC1000PowerModeEnum PowerMode( ) const
    {
        return (IoAKSC1000PowerModeEnum) m_Registers[ eGeneralControl ][ ePowerMode ].Value( );
    }

    int InLowPowerMode ( ) const { return PowerMode( ) == eLowPowerMode;  }
    int InHighPowerMode( ) const { return PowerMode( ) == eHighPowerMode; }

    IoAKSC1000OperationModeEnum OperationMode( ) const
    {
        return (IoAKSC1000OperationModeEnum) m_Registers[ eGeneralControl ][ eOperationMode ].Value( );
    }

    int InProgrammingMode( ) const { return OperationMode( ) == eProgrammingMode; }
    int InExecutionMode  ( ) const { return OperationMode( ) == eExecutionMode;   }

    // Execution control
    int Program( const IoAKSC1000Registers& Registers )
    {
        return SetOperationMode( eProgrammingMode ) &&      // temporarily stop frame table execution
               Synchronize( Registers ) &&                  // update all device register contents
               Synchronize( Registers[ eGeneralControl] );  // set General Control register to required state
    }

    int Start( ) { return IsOpen( ) && SetGeneralControlRegister( eHighPowerMode, eExecutionMode ); }

    int Stop( ) { return IsOpen( ) && SetOperationMode( eProgrammingMode ); }

    int Start( int FrameTableAddress )
    {
        return Stop( ) && SetFrameTablePointer( FrameTableAddress ) && Start( );
    }

    int Start( const IoAKSC1000Registers& Registers )
    {
        return Stop( ) && Synchronize( Registers ) && Start( );
    }

    int Started( ) const { return InExecutionMode( ); }
    int Stopped( ) const { return InProgrammingMode( ); }

private:
    // Unconditional read/write of control register contents
    int Read( IoAKSC1000Register& Register, int nRegisters = 1 ) const;
    int Write( const IoAKSC1000Register& Register, int nRegisters = 1 ) const;

    // Unconditional read/write of frame table contents
    int Read( IoAKSC1000FrameTable& FrameTable ) const;
    int Write( const IoAKSC1000FrameTable& FrameTable ) const;

    // Unconditional read/write of frame table entry contents
    int Read( IoAKSC1000FrameTableEntry& FrameTableEntry, int nFrameTableEntries = 1 ) const;
    int Write( const IoAKSC1000FrameTableEntry& FrameTableEntry, int nFrameTableEntries = 1 ) const;

    // Unconditional read/write of line table contents
    int Read( IoAKSC1000LineTable& LineTable ) const;
    int Write( const IoAKSC1000LineTable& LineTable ) const;

    // Unconditional read/write of line table entry contents
    int Read( IoAKSC1000LineTableEntry& LineTableEntry, int nLineTableEntries = 1  ) const;
    int Write( const IoAKSC1000LineTableEntry& LineTableEntry, int nLineTableEntries = 1 ) const;

    // Unconditional read of contents of all registers
    int Read( IoAKSC1000Registers& Registers ) const
    {
        return Read( Registers[ eControlRegisters         ] ) &&
               Read( Registers[ eFrameTableAccessRegister ] ) &&
               Read( Registers[ eLineTableAccessRegister  ] ) &&
               Read( Registers[ eStatusRegister           ] );
    }

    // Unconditional write of contents of all registers
    int Write( const IoAKSC1000Registers& Registers ) const
    {
        return Write( Registers[ eControlRegisters         ] ) &&
               Write( Registers[ eFrameTableAccessRegister ] ) &&
               Write( Registers[ eLineTableAccessRegister  ] );
    }

    // Register data
    IoAKSC1000Registers m_Registers;

    // Pixel clock frequency
    double m_PixelClockFrequency;

    // DLL frequency range thresholds
    static const double m_DLLHz[ 17 ];
};

#endif
