#include "stdafx.h"
#include "KSC1000.h"
#include "Timeout.h"
#include "Trace.h"

// Declare and initialise static data members

// Bit offset for each register
const int IoAKSC1000Register::m_OffsetLUT[ nKSC1000RegisterCount ] =
{
    0, 3, 205, 207, 237, 250, 275, 353,
    iKSC1000FrameTablesBitOffset,
    iKSC1000LineTablesBitOffset,
    iKSC1000StatusRegisterBitOffset,
    iKSC1000ControlRegistersBitOffset
};

// Number of bits in each register
const int IoAKSC1000Register::m_CountLUT[ nKSC1000RegisterCount ] =
{
    3, 202, 2, 30, 13, 25, 78, 65,  // individual control registers = 418 bits
    nKSC1000FrameTablesBitCount,
    nKSC1000LineTablesBitCount,
    nKSC1000StatusRegisterBitCount,
    nKSC1000ControlRegistersBitCount  // all control registers combined = 418 bits
};

// String to identify each register
const char *IoAKSC1000Register::m_NameLUT[ nKSC1000RegisterCount ] =
{
    "FrameTablePointer",
    "GeneralSetup",
    "GeneralControl",
    "INTG_STRTSetup",
    "INTG_STRTLine",
    "SignalPolarity",
    "Offset",
    "Width",
    "FrameTableAccessRegister",
    "LineTableAccessRegister",
    "StatusRegister",
    "ControlRegisters"
};

// Variable offset for each register
const int IoAKSC1000Register::m_VariableOffsetLUT[ nKSC1000RegisterCount ] =
{
    eFrameTableAddress,
    ePixelsPerLine,
    ePowerMode,
    eElectronicShutterSetupClocks,
    eIntegrateStartPulseLineNumber,
    eH6IdleValue,
    eH6Offset,
    eH6Width,
    eCheckAndIncrementLineCounter,
    ePixelClockCount,
    eDLLLocked,
    eFrameTableAddress
};

// Number of variables in each register
const int IoAKSC1000Register::m_VariableCountLUT[ nKSC1000RegisterCount ] =
{
    eFrameTableAddress             - eFrameTableAddress             + 1,
    eDLLFrequencyRangeIndex        - ePixelsPerLine                 + 1,
    eOperationMode                 - ePowerMode                     + 1,
    eElectronicShutterHoldClocks   - eElectronicShutterSetupClocks  + 1,
    eIntegrateStartPulseLineNumber - eIntegrateStartPulseLineNumber + 1,
    eV6IdleValue                   - eH6IdleValue                   + 1,
    eDATACLK2Offset                - eH6Offset                      + 1,
    eDATACLK2Width                 - eH6Width                       + 1,
    eFrameTableEntry               - eCheckAndIncrementLineCounter  + 1,
    eLineTableEntryBits            - ePixelClockCount               + 1,
    eLineCounterValue              - eDLLLocked                     + 1,
    eDATACLK2Width                 - eFrameTableAddress             + 1
};

// INI variable offset for each register
const int IoAKSC1000Register::m_INIVariableOffsetLUT[ nKSC1000INIRegisterCount ] =
{
    eINI_ftpaddr,
    eINI_pixperline,
    eINI_lowpwrena,
    eINI_shutset,
    eINI_intgpulslinnum,
    eINI_h6idleval,
    eINI_h6off,
    eINI_h6width,
    eINI_chkcnt,
    eINI_pixcnt
};

// Number of INI file variables in each register
const int IoAKSC1000Register::m_INIVariableCountLUT[ nKSC1000INIRegisterCount ] =
{
    eINI_ftpaddr        - eINI_ftpaddr        + 1,
    eINI_DLLfrqsel      - eINI_pixperline     + 1,
    eINI_memtblmode     - eINI_lowpwrena      + 1,
    eINI_shuthold       - eINI_shutset        + 1,
    eINI_intgpulslinnum - eINI_intgpulslinnum + 1,
    eINI_v6idleval      - eINI_h6idleval      + 1,
    eINI_dataclk2off    - eINI_h6off          + 1,
    eINI_dataclk2width  - eINI_h6width        + 1,
    eINI_address        - eINI_chkcnt         + 1,
    eINI_v1             - eINI_pixcnt         + 1
};

// Bit offset for each register variable
const int IoAKSC1000Variable::m_OffsetLUT[ nKSC1000VariableCount ] =
{
    // Control register variables
      0,   3,  16,  29,  31,  44,  57,  70,  83,  96,  // absolute offsets
    109, 122, 135, 148, 161, 174, 175, 176, 177, 178,
    179, 180, 181, 182, 183, 184, 185, 186, 187, 188,
    189, 190, 191, 192, 193, 194, 195, 196, 197, 198,
    199, 200, 201, 205, 206, 207, 217, 227, 237, 250,
    251, 252, 253, 254, 255, 256, 257, 258, 259, 260,
    261, 262, 263, 264, 265, 266, 267, 268, 269, 270,
    271, 272, 273, 274, 275, 281, 287, 293, 299, 305,
    311, 317, 323, 329, 335, 341, 347, 353, 358, 363,
    368, 373, 378, 383, 388, 393, 398, 403, 408, 413,

    // Frame table variables
    0, 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 16, 17, 30, 30, 30, 30,  // relative offsets

    // Line table variables
    0, 13, 14, 15, 16, 17, 18, 19, 0,  // relative offsets

    // Status register variables
    iKSC1000StatusRegisterBitOffset + 0,  // absolute offsets
    iKSC1000StatusRegisterBitOffset + 1,
    iKSC1000StatusRegisterBitOffset + 8,
    iKSC1000StatusRegisterBitOffset + 16,
    iKSC1000StatusRegisterBitOffset + 17,
    iKSC1000StatusRegisterBitOffset + 18
};

// Numbers of bits in each register variable
const int IoAKSC1000Variable::m_CountLUT[ nKSC1000VariableCount ] =
{
    // Control register variables
     3, 13, 13,  2, 13, 13, 13, 13, 13, 13,
    13, 13, 13, 13, 13,  1,  1,  1,  1,  1,
     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
     1,  1,  4,  1,  1, 10, 10, 10, 13,  1,
     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
     1,  1,  1,  1,  6,  6,  6,  6,  6,  6,
     6,  6,  6,  6,  6,  6,  6,  5,  5,  5,
     5,  5,  5,  5,  5,  5,  5,  5,  5,  5,

    // Frame table variables
     1,  1,  1,  2,  1,  1,  1,  1,  1,  1,
     1,  1,  1,  1,  1, 18,  1, 13,  4,  3,
     4,  4,

    // Line table variables
    13,  1,  1,  1,  1,  1,  1,  1, 20,

    // Status register variables
     1,  7,  8,  1,  1, 13
};

// String to identify each register variable
const char *IoAKSC1000Variable::m_NameLUT[ nKSC1000VariableCount ] =
{
    // Frame Table Pointer register
    "FrameTableAddress",

    // General Setup register
    "PixelsPerLine", "LineValidPixelStart", "LineValidPixelQuadratureStart", "LineValidPixelEnd",
    "CLPOB1PixelStart", "CLPOB1PixelEnd", "CLPOB2PixelStart", "CLPOB2PixelEnd",
    "CLPDM1PixelStart", "CLPDM1PixelEnd", "CLPDM2PixelStart", "CLPDM2PixelEnd",
    "PBLKPixelStart", "PBLKPixelEnd",
    "RGEnable", "H6Enable", "H4Enable", "H5Enable", "SH2Enable", "SH4Enable",
    "DATACLK1Enable", "DATACLK2Enable", "PIXCLKEnable",
    "H3Enable", "H1Enable", "H2Enable", "SH1Enable", "SH3Enable",
    "H6Enable24mAOutput", "H4Enable24mAOutput", "H5Enable24mAOutput", "RGEnable24mAOutput",
    "SH2Enable24mAOutput", "SH4Enable24mAOutput", "DATACLK1Enable24mAOutput", "DATACLK2Enable24mAOutput",
    "H3Enable24mAOutput", "H1Enable24mAOutput", "H2Enable24mAOutput", "SH1Enable24mAOutput", "SH3Enable24mAOutput",
    "DLLFrequencyRangeIndex",

    // General Control register
    "PowerMode", "OperationMode",

    // INTG_STRT Setup register
    "ElectronicShutterSetupClocks", "ElectronicShutterPulseWidth", "ElectronicShutterHoldClocks",

    // INTG_STRT Line register
    "IntegrateStartPulseLineNumber",

    // Signal Polarity register
    "H6IdleValue", "H3IdleValue", "H4IdleValue", "H1IdleValue", "H5IdleValue", "H2IdleValue", "RGIdleValue",
    "SH2IdleValue", "SH1IdleValue", "SH4IdleValue", "SH3IdleValue", "DATACLK1IdleValue", "DATACLK2IdleValue",
    "CLPOBIdleValue", "CLPDMIdleValue", "AMP_ENABLEIdleValue", "FRAME_VALIDIdleValue", "LINE_VALIDIdleValue",
    "INTG_STRTIdleValue", "V1IdleValue", "V2IdleValue", "V3IdleValue", "V4IdleValue", "V5IdleValue", "V6IdleValue",

    // Offset register
    "H6Offset", "H3Offset", "H4Offset", "H1Offset", "H5Offset", "H2Offset", "RGOffset",
    "SH2Offset", "SH1Offset", "SH4Offset", "SH3Offset", "DATACLK1Offset", "DATACLK2Offset",

    // Width register
    "H6Width", "H3Width", "H4Width", "H1Width", "H5Width", "H2Width", "RGWidth",
    "SH2Width", "SH1Width", "SH4Width", "SH3Width", "DATACLK1Width", "DATACLK2Width",

    // Frame table variables
    "CheckAndIncrementLineCounter", "ClearLineCounter", "ForceINTG_STRT", "HorizontalBinningFactor",
    "HCLK_VEnable", "LINE_VALIDEnable", "FRAME_VALIDEnable", "VideoAmplifierEnable", "AFEClockEnable",
    "CLPDM2Enable", "CLPDM1Enable", "CLPOB2Enable", "CLPOB1Enable", "PBLKEnable", "PBLKIdleValue",
    "EventDescriptor", "EventFlag", "EventCount", "EventAddress", "FrameTable", "LineTable", "FrameTableEntry",

    // Line table variables
    "PixelClockCount", "HCLK_HEnable", "V6Asserted", "V5Asserted",
    "V4Asserted", "V3Asserted", "V2Asserted", "V1Asserted", "LineTableEntryBits",

    // Status register variables
    "DLLLocked", "CurrentFrameTableAddress", "CurrentLineTableAddress", "VDRegistered", "VDWait", "LineCounterValue"
};

// Bit offset for each INI file variable
const int IoAKSC1000INIVariable::m_OffsetLUT[ nKSC1000INI_VariableCount ] =
{
    // Control register variables
      0,   3,  16,  29,  31,  44,  57,  70,  83,  96,  // absolute offsets
    109, 122, 135, 148, 161, 174, 175, 176, 177, 178,
    179, 180, 181, 182, 183, 184, 185, 186, 187, 188,
    189, 190, 191, 192, 193, 194, 195, 196, 197, 198,
    199, 200, 201, 205, 206, 207, 217, 227, 237, 250,
    251, 252, 253, 254, 255, 256, 257, 258, 259, 260,
    261, 262, 263, 264, 265, 266, 267, 268, 269, 270,
    271, 272, 273, 274, 275, 281, 287, 293, 299, 305,
    311, 317, 323, 329, 335, 341, 347, 353, 358, 363,
    368, 373, 378, 383, 388, 393, 398, 403, 408, 413,

    // Frame table variables
      0,   2,   3,   5,   6,   8,   9,  10,  14,  16,  // relative offsets
     17,  30,

    // Line table variables
      0,  13,  14,  15,  16,  17,  18,  19,            // relative offsets
};

// Number of bits in each INI file variable
const int IoAKSC1000INIVariable::m_CountLUT[ nKSC1000INI_VariableCount ] =
{
    // Control register variables
     3, 13, 13,  2, 13, 13, 13, 13, 13, 13,
    13, 13, 13, 13, 13,  1,  1,  1,  1,  1,
     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
     1,  1,  4,  1,  1, 10, 10, 10, 13,  1,
     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
     1,  1,  1,  1,  6,  6,  6,  6,  6,  6,
     6,  6,  6,  6,  6,  6,  6,  5,  5,  5,
     5,  5,  5,  5,  5,  5,  5,  5,  5,  5,

    // Frame table variables
     2,  1,  2,  1,  2,  1,  1,  4,  2,  1,
    13,  4,

    // Line table variables
    13,  1,  1,  1,  1,  1,  1,  1,
};

// String to identify each INI file variable
const char *IoAKSC1000INIVariable::m_NameLUT[ nKSC1000INI_VariableCount ] =
{
    // Frame Table Pointer register
    "ftpaddr",

    // General Setup register
    "pixperline", "linvalpixst", "linvalpixquast", "linvalpixed",
    "clpob1pixst", "clpob1pixed", "clpob2pixst", "clpob2pixed",
    "clpdm1pixst", "clpdm1pixed", "clpdm2pixst", "clpdm2pixed",
    "pblkpixst", "pblkpixed", "rgena", "h6ena", "h4ena", "h5ena", "sh2ena", "sh4ena",
    "dataclk1ena", "dataclk2ena", "pixclkena", "h3ena", "h1ena", "h2ena", "sh1ena", "sh3ena",
    "h6_24maoutena", "h4_24maoutena", "h5_24maoutena", "rg24maoutena",
    "sh2_24maoutena", "sh4_24maoutena", "dataclk124maoutena", "dataclk224maoutena",
    "h3_24maoutena", "h1_24maoutena", "h2_24maoutena", "sh1_24maoutena", "sh3_24maoutena",
    "DLLfrqsel", 

    // General Control register
    "lowpwrena", "memtblmode", 

    // INTG_STRT Setup register
    "shutset", "shutpulswid", "shuthold",

    // INTG_STRT Line register
    "intgpulslinnum",

    // Signal Polarity register
    "h6idleval", "h3idleval", "h4idleval", "h1idleval", "h5idleval", "h2idleval", "rgidleval",
    "sh2idleval", "sh1idleval", "sh4idleval", "sh3idleval", "dataclk1idleval", "dataclk2idleval",
    "clpobidleval", "clpdmidleval", "ampenaidleval", "frmvalidleval", "linvalidleval", "integstidleval",
    "v1idleval", "v2idleval", "v3idleval", "v4idleval", "v5idleval", "v6idleval",

    // Offset register
    "h6off", "h3off", "h4off", "h1off", "h5off", "h2off", "rgoff",
    "sh2off", "sh1off", "sh4off", "sh3off", "dataclk1off", "dataclk2off",

    // Width register
    "h6wid", "h3wid", "h4wid", "h1wid", "h5wid", "h2wid", "rgwid",
    "sh2wid", "sh1wid", "sh4wid", "sh3wid", "dataclk1wid", "dataclk2wid",

    // Frame table variables
    "chkcnt", "forceshut", "horibin", "hclkena", "valena", "videoamfena",
    "afeena", "clpena", "pblk", "flag", "count", "address",

    // Line table variables
    "pixcnt", "hclkena", "v6", "v5", "v4", "v3", "v2", "v1"
};

void IoAKSC1000Registers::SetDefaults( )
{
//    ( *this )[ eControlRegisters ].Clear( );

    // Frame Table Pointer register
//    ( *this )[ eFrameTableAddress ] = 0;

    // General Setup register
//    ( *this )[ ePixelsPerLine                 ] = 1024;
//    ( *this )[ eLineValidPixelStart           ] = 0;
//    ( *this )[ eLineValidPixelQuadratureStart ] = 0;
//    ( *this )[ eLineValidPixelEnd             ] = 0;
//    ( *this )[ eCLPOB1PixelStart              ] = 0;
//    ( *this )[ eCLPOB1PixelEnd                ] = 0;
//    ( *this )[ eCLPOB2PixelStart              ] = 0;
//    ( *this )[ eCLPOB2PixelEnd                ] = 0;
//    ( *this )[ eCLPDM1PixelStart              ] = 0;
//    ( *this )[ eCLPDM1PixelEnd                ] = 0;
//    ( *this )[ eCLPDM2PixelStart              ] = 0;
//    ( *this )[ eCLPDM2PixelEnd                ] = 0;
//    ( *this )[ ePBLKPixelStart                ] = 0;
//    ( *this )[ ePBLKPixelEnd                  ] = 0;
//    ( *this )[ eRGEnable                      ] = 1;
//    ( *this )[ eH6Enable                      ] = 1;
//    ( *this )[ eH4Enable                      ] = 1;
//    ( *this )[ eH5Enable                      ] = 0;
//    ( *this )[ eSH2Enable                     ] = 1;
//    ( *this )[ eSH4Enable                     ] = 1;
//    ( *this )[ eDATACLK1Enable                ] = 1;
//    ( *this )[ eDATACLK2Enable                ] = 1;
//    ( *this )[ ePIXCLKEnable                  ] = 1;
//    ( *this )[ eH3Enable                      ] = 0;
//    ( *this )[ eH1Enable                      ] = 0;
//    ( *this )[ eH2Enable                      ] = 0;
//    ( *this )[ eSH1Enable                     ] = 0;
//    ( *this )[ eSH3Enable                     ] = 0;
//    ( *this )[ eH6Enable24mAOutput            ] = 0;
//    ( *this )[ eH4Enable24mAOutput            ] = 0;
//    ( *this )[ eH5Enable24mAOutput            ] = 0;
//    ( *this )[ eRGEnable24mAOutput            ] = 0;
//    ( *this )[ eSH2Enable24mAOutput           ] = 0;
//    ( *this )[ eSH4Enable24mAOutput           ] = 0;
//    ( *this )[ eDATACLK1Enable24mAOutput      ] = 0;
//    ( *this )[ eDATACLK2Enable24mAOutput      ] = 0;
//    ( *this )[ eH3Enable24mAOutput            ] = 0;
//    ( *this )[ eH1Enable24mAOutput            ] = 0;
//    ( *this )[ eH2Enable24mAOutput            ] = 0;
//    ( *this )[ eSH1Enable24mAOutput           ] = 0;
//    ( *this )[ eSH3Enable24mAOutput           ] = 0;
//    ( *this )[ eDLLFrequencyRangeIndex        ] = 9;

    // General Control register
//    ( *this )[ ePowerMode     ] = 1;
//    ( *this )[ eOperationMode ] = 0;

    // INTG_STRT Setup register
//    ( *this )[ eElectronicShutterSetupClocks ] = 0;
//    ( *this )[ eElectronicShutterPulseWidth  ] = 0;
//    ( *this )[ eElectronicShutterHoldClocks  ] = 0;

    // INTG_STRT Line register
//    ( *this )[ eIntegrateStartPulseLineNumber ] = 0;

    // Signal Polarity register
//    ( *this )[ eH6IdleValue          ] = 0;
//    ( *this )[ eH3IdleValue          ] = 0;
//    ( *this )[ eH4IdleValue          ] = 1;
//    ( *this )[ eH1IdleValue          ] = 1;
//    ( *this )[ eH5IdleValue          ] = 0;
//    ( *this )[ eH2IdleValue          ] = 0;
//    ( *this )[ eRGIdleValue          ] = 0;
//    ( *this )[ eSH2IdleValue         ] = 1;
//    ( *this )[ eSH1IdleValue         ] = 1;
//    ( *this )[ eSH4IdleValue         ] = 1;
//    ( *this )[ eSH3IdleValue         ] = 1;
//    ( *this )[ eDATACLK1IdleValue    ] = 0;
//    ( *this )[ eDATACLK2IdleValue    ] = 0;
//    ( *this )[ eCLPOBIdleValue       ] = 1;
//    ( *this )[ eCLPDMIdleValue       ] = 1;
//    ( *this )[ eAMP_ENABLEIdleValue  ] = 0;
//    ( *this )[ eFRAME_VALIDIdleValue ] = 0;
//    ( *this )[ eLINE_VALIDIdleValue  ] = 0;
//    ( *this )[ eINTG_STRTIdleValue   ] = 0;
//    ( *this )[ eV1IdleValue          ] = 0;
//    ( *this )[ eV2IdleValue          ] = 0;
//    ( *this )[ eV3IdleValue          ] = 0;
//    ( *this )[ eV4IdleValue          ] = 0;
//    ( *this )[ eV5IdleValue          ] = 0;
//    ( *this )[ eV6IdleValue          ] = 0;

    // Offset register
//    ( *this )[ eH6Offset       ] = 0;
//    ( *this )[ eH3Offset       ] = 0;
//    ( *this )[ eH4Offset       ] = 0;
//    ( *this )[ eH1Offset       ] = 0;
//    ( *this )[ eH5Offset       ] = 0;
//    ( *this )[ eH2Offset       ] = 0;
//    ( *this )[ eRGOffset       ] = 0;
//    ( *this )[ eSH2Offset      ] = 0;
//    ( *this )[ eSH1Offset      ] = 0;
//    ( *this )[ eSH4Offset      ] = 32;
//    ( *this )[ eSH3Offset      ] = 32;
//    ( *this )[ eDATACLK1Offset ] = 0;
//    ( *this )[ eDATACLK2Offset ] = 0;

    // Width register
//    ( *this )[ eH6Width       ] = 16;
//    ( *this )[ eH3Width       ] = 16;
//    ( *this )[ eH4Width       ] = 16;
//    ( *this )[ eH1Width       ] = 16;
//    ( *this )[ eH5Width       ] = 16;
//    ( *this )[ eH2Width       ] = 16;
//    ( *this )[ eRGWidth       ] = 7;
//    ( *this )[ eSH2Width      ] = 14;
//    ( *this )[ eSH1Width      ] = 14;
//    ( *this )[ eSH4Width      ] = 14;
//    ( *this )[ eSH3Width      ] = 14;
//    ( *this )[ eDATACLK1Width ] = 16;
//    ( *this )[ eDATACLK2Width ] = 16;

    // Default value for each control register variable
    const int VariableDefaultValue[ nKSC1000ControlVariableCount ] =
    {
         0, 1024,    0,    0,    0,    0,    0,    0,    0,    0,
         0,    0,    0,    0,    0,    1,    1,    1,    0,    1,
         1,    1,    1,    1,    0,    0,    0,    0,    0,    0,
         0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
         0,    0,    9,    1,    0,    0,    0,    0,    0,    0,
         0,    1,    1,    0,    0,    0,    1,    1,    1,    1,
         0,    0,    1,    1,    0,    0,    0,    0,    0,    0,
         0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
         0,    0,    0,   32,   32,    0,    0,   16,   16,   16,
        16,   16,   16,    7,   14,   14,   14,   14,   16,   16
    };

    // Assign default values to control register variables
    for ( int v = 0; v < nKSC1000ControlVariableCount; v++ )
    {
        IoAKSC1000CRVariableEnum Variable = (IoAKSC1000CRVariableEnum) v;

        ( *this )[ Variable ] = VariableDefaultValue[ v ];
    }
}

// DLL frequency range thresholds
const double IoAKSC1000::m_DLLHz[ 17 ] =
{
    0.0, 0.0, 0.0, 0.0,  // invalid
    4130000.0, 5940000.0, 8530000.0, 13520000.0, 17550000.0, 26040000.0, 31880000.0, 42220000.0, 60000000.0,
    0.0, 0.0, 0.0, 0.0   // invalid
};

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

    // Synchronize software and hardware registers
    if ( ! Write( m_Registers ) ) return FALSE;

    // Verify synchronization process by reading back and comparing register contents
    if ( Verify )
    {
        IoAKSC1000Registers Registers;

        // Read hardware register contents
        if ( ! Read( Registers ) ) return FALSE;

        // Verify (compare) register contents (not including status register)
        if ( ( Registers[ eControlRegisters         ] != m_Registers[ eControlRegisters         ] ) ||
             ( Registers[ eFrameTableAccessRegister ] != m_Registers[ eFrameTableAccessRegister ] ) ||
             ( Registers[ eLineTableAccessRegister  ] != m_Registers[ eLineTableAccessRegister  ] ) ) return FALSE;
    }

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

    return TRUE;
}

int IoAKSC1000::Synchronize( const IoAKSC1000Register& Register )
{
    IoAKSC1000RegisterEnum RegisterEnum = Register.Enum( );

    // Synchronize control registers (excluding General Control register)
    if ( RegisterEnum == eControlRegisters )
    {
        // Construct IoAKSC1000RegisterArray object to gain access to individual control registers
        IoAKSC1000RegisterArray Registers( Register );

        // Save DLL frequency range index value
        int DLLFrequencyRangeIndex = Registers[ eDLLFrequencyRangeIndex ].Value( );

        // Suppress any change in DLL frequency range index
        Registers[ eDLLFrequencyRangeIndex ] = m_Registers[ eDLLFrequencyRangeIndex ];

        // Find out which control registers have changed
        int pRegisterDelta[ nKSC1000ControlRegisterCount + 2 ];

        int *RegisterDelta = pRegisterDelta + 1;

        RegisterDelta[ -1 ] = FALSE;

		{
			for ( int r = 0; r < nKSC1000ControlRegisterCount; r++ )
			{
				IoAKSC1000RegisterEnum Register = (IoAKSC1000RegisterEnum) r;

				RegisterDelta[ r ] = m_Registers[ Register ] != Registers[ Register ];
			}
		}

        RegisterDelta[ nKSC1000ControlRegisterCount ] = FALSE;

        // Exclude Frame Table Pointer register - that way, the device's frame table execution won't be disturbed
        RegisterDelta[ eFrameTablePointer ] = FALSE;

        // Exclude General Control register - that way, the device's power and operation modes won't be disturbed
        RegisterDelta[ eGeneralControl ] = FALSE;

        IoAKSC1000RegisterEnum FirstRegister;

        int nRegisters;

        // Update only changed registers
        for ( int r = 0; r < nKSC1000ControlRegisterCount; r++ )
        {
            IoAKSC1000RegisterEnum Register = (IoAKSC1000RegisterEnum) r;

            // See if register has changed
            if ( RegisterDelta[ r ] )
            {
                // See if first of new batch of registers to update
                if ( ! RegisterDelta[ r - 1 ] )
                {
                    FirstRegister = Register;

                    nRegisters = 0;
                }

                nRegisters++;

                // See if last of batch of registers to update
                if ( ! RegisterDelta[ r + 1 ] )
                {
                    if ( IsOpen( ) )
                    {
                        if ( ! Write( Registers[ FirstRegister ], nRegisters ) )
                        {
                            Read( m_Registers[ FirstRegister ], nRegisters );  // try to resynchronize with device settings

                            Registers[ eDLLFrequencyRangeIndex ] = DLLFrequencyRangeIndex;

                            return FALSE;
                        }
                    }

                    for ( int i = 0, r = (int) FirstRegister; i < nRegisters; i++, r++ )
                    {
                        IoAKSC1000RegisterEnum Register = (IoAKSC1000RegisterEnum) r;

                        m_Registers[ Register ] = Registers[ Register ];
                    }
                }
            }
        }

        // Restore DLL frequency range index value
        Registers[ eDLLFrequencyRangeIndex ] = DLLFrequencyRangeIndex;
    }

    // Synchronize frame tables
    else if ( RegisterEnum == eFrameTableAccessRegister )
    {
        // Find out which frame table entries have changed
        int pEntryDelta[ nFrameTableCount * nFrameTableEntryCount + 2 ];

        int *EntryDelta = pEntryDelta + 1;

        EntryDelta[ -1 ] = FALSE;

		{
			for ( int t = 0, d = 0; t < nFrameTableCount; t++ )
			{
				IoAKSC1000FrameTableEnum Table = (IoAKSC1000FrameTableEnum) t;

				for ( int e = 0; e < nFrameTableEntryCount; d++, e++ )
				{
					IoAKSC1000FrameTableEntryEnum Entry = (IoAKSC1000FrameTableEntryEnum) e;

					EntryDelta[ d ] = m_Registers[ Table ][ Entry ] != Register[ Table ][ Entry ];
				}
			}
		}

        EntryDelta[ nFrameTableCount * nFrameTableEntryCount ] = FALSE;

        IoAKSC1000FrameTableEnum      FirstTable;
        IoAKSC1000FrameTableEntryEnum FirstEntry;

        int nFrameTableEntries;

        // Update only changed frame table entries
        for ( int t = 0, d = 0; t < nFrameTableCount; t++ )
        {
            IoAKSC1000FrameTableEnum Table = (IoAKSC1000FrameTableEnum) t;

            for ( int e = 0; e < nFrameTableEntryCount; d++, e++ )
            {
                IoAKSC1000FrameTableEntryEnum Entry = (IoAKSC1000FrameTableEntryEnum) e;

                // See if frame table entry has changed
                if ( EntryDelta[ d ] )
                {
                    // See if first of new batch of frame table entries to update
                    if ( ! EntryDelta[ d - 1 ] )
                    {
                        FirstTable = Table;
                        FirstEntry = Entry;

                        nFrameTableEntries = 0;
                    }

                    nFrameTableEntries++;

                    // See if last of batch of frame table entries to update
                    if ( ! EntryDelta[ d + 1 ] )
                    {
                        if ( IsOpen( ) )
                        {
                            if ( ! Write( Register[ FirstTable ][ FirstEntry ], nFrameTableEntries ) )
                            {
                                Read( m_Registers[ FirstTable ][ FirstEntry ], nFrameTableEntries );  // try to resynchronize

                                return FALSE;
                            }
                        }

                        for ( int i = 0, t = (int) FirstTable, e = (int) FirstEntry; i < nFrameTableEntries; i++, e++ )
                        {
                            if ( e == 16 ) { t += 1; e = 0; }

                            IoAKSC1000FrameTableEnum      Table = (IoAKSC1000FrameTableEnum     ) t;
                            IoAKSC1000FrameTableEntryEnum Entry = (IoAKSC1000FrameTableEntryEnum) e;

                            m_Registers[ Table ][ Entry ] = Register[ Table ][ Entry ];
                        }
                    }
                }
            }
        }
    }

    // Synchronize line tables
    else if ( RegisterEnum == eLineTableAccessRegister )
    {
        // Find out which line table entries have changed
        int pEntryDelta[ nLineTableCount * nLineTableEntryCount + 2 ];

        int *EntryDelta = pEntryDelta + 1;

        EntryDelta[ -1 ] = FALSE;

		{
			for ( int t = 0, d = 0; t < nLineTableCount; t++ )
			{
				IoAKSC1000LineTableEnum Table = (IoAKSC1000LineTableEnum) t;

				for ( int e = 0; e < nLineTableEntryCount; d++, e++ )
				{
					IoAKSC1000LineTableEntryEnum Entry = (IoAKSC1000LineTableEntryEnum) e;

					EntryDelta[ d ] = m_Registers[ Table ][ Entry ] != Register[ Table ][ Entry ];
				}
			}
		}

        EntryDelta[ nLineTableCount * nLineTableEntryCount ] = FALSE;

        IoAKSC1000LineTableEnum      FirstTable;
        IoAKSC1000LineTableEntryEnum FirstEntry;

        int nLineTableEntries;

        // Update only changed line table entries
        for ( int t = 0, d = 0; t < nLineTableCount; t++ )
        {
            IoAKSC1000LineTableEnum Table = (IoAKSC1000LineTableEnum) t;

            for ( int e = 0; e < nLineTableEntryCount; d++, e++ )
            {
                IoAKSC1000LineTableEntryEnum Entry = (IoAKSC1000LineTableEntryEnum) e;

                // See if line table entry has changed
                if ( EntryDelta[ d ] )
                {
                    // See if first of new batch of line table entries to update
                    if ( ! EntryDelta[ d - 1 ] )
                    {
                        FirstTable = Table;
                        FirstEntry = Entry;

                        nLineTableEntries = 0;
                    }

                    nLineTableEntries++;

                    // See if last of batch of line table entries to update
                    if ( ! EntryDelta[ d + 1 ] )
                    {
                        if ( IsOpen( ) )
                        {
                            if ( ! Write( Register[ FirstTable ][ FirstEntry ], nLineTableEntries ) )
                            {
                                Read( m_Registers[ FirstTable ][ FirstEntry ], nLineTableEntries );  // try to resynchronize

                                return FALSE;
                            }
                        }

                        for ( int i = 0, t = (int) FirstTable, e = (int) FirstEntry; i < nLineTableEntries; i++, e++ )
                        {
                            if ( e == 16 ) { t += 1; e = 0; }

                            IoAKSC1000LineTableEnum      Table = (IoAKSC1000LineTableEnum     ) t;
                            IoAKSC1000LineTableEntryEnum Entry = (IoAKSC1000LineTableEntryEnum) e;

                            m_Registers[ Table ][ Entry ] = Register[ Table ][ Entry ];
                        }
                    }
                }
            }
        }
    }

    // Synchronize status register
    else if ( RegisterEnum == eStatusRegister )
    {
        if ( ! IsOpen( ) ) return FALSE;

        //  Register is read only => can only synchronize by physically reading its contents
        if ( ! Read( m_Registers[ eStatusRegister ] ) ) return FALSE;

        // Cast-away const type for register reference => can return status info even though argument is (logically) const
        (IoAKSC1000Register&) Register = m_Registers[ eStatusRegister ];
    }

    // Synchronize General Setup register (leaving DLL frequency range index unchanged)
    else if ( RegisterEnum == eGeneralSetup )
    {
        IoAKSC1000Register& GeneralSetupRegister = (IoAKSC1000Register&) Register;  // cast-away const reference

        // Save DLL frequency range index value
        int DLLFrequencyRangeIndex = GeneralSetupRegister[ eDLLFrequencyRangeIndex ].Value( );

        // Suppress any change in DLL frequency range index
        GeneralSetupRegister[ eDLLFrequencyRangeIndex ] = m_Registers[ eDLLFrequencyRangeIndex ];

        // Update register
        if ( GeneralSetupRegister != m_Registers[ RegisterEnum ] )
        {
            if ( IsOpen( ) )
            {
                if ( ! Write( GeneralSetupRegister ) )
                {
                    Read( m_Registers[ RegisterEnum ] );  // try to resynchronize with device settings

                    GeneralSetupRegister[ eDLLFrequencyRangeIndex ] = DLLFrequencyRangeIndex;

                    return FALSE;
                }
            }

            m_Registers[ RegisterEnum ] = Register;
        }

        // Restore DLL frequency range index value
        GeneralSetupRegister[ eDLLFrequencyRangeIndex ] = DLLFrequencyRangeIndex;
    }

    // Synchronize single control register
    else
    {
        if ( Register != m_Registers[ RegisterEnum ] )
        {
            if ( IsOpen( ) )
            {
                if ( ! Write( Register ) )
                {
                    Read( m_Registers[ RegisterEnum ] );  // try to resynchronize with device settings

                    return FALSE;
                }
            }

            m_Registers[ RegisterEnum ] = Register;
        }
    }

    return TRUE;
}

int IoAKSC1000::Synchronize( const IoAKSC1000FrameTable& FrameTable )
{
    IoAKSC1000FrameTableEnum Table = FrameTable.TableEnum( );

    if ( FrameTable != m_Registers[ Table ] )
    {
        if ( IsOpen( ) )
        {
            if ( ! Write( FrameTable ) )
            {
                Read( m_Registers[ Table ] );  // try to resynchronize with device settings

                return FALSE;
            }
        }

        m_Registers[ Table ] = FrameTable;
    }

    return TRUE;
}

int IoAKSC1000::Synchronize( const IoAKSC1000FrameTableEntry& FrameTableEntry )
{
    IoAKSC1000FrameTableEnum      Table = FrameTableEntry.TableEnum( );
    IoAKSC1000FrameTableEntryEnum Entry = FrameTableEntry.EntryEnum( );

    if ( FrameTableEntry != m_Registers[ Table ][ Entry ] )
    {
        if ( IsOpen( ) )
        {
            if ( ! Write( FrameTableEntry ) )
            {
                Read( m_Registers[ Table ][ Entry ] );  // try to resynchronize with device settings

                return FALSE;
            }
        }

        m_Registers[ Table ][ Entry ] = FrameTableEntry;
    }

    return TRUE;
}

int IoAKSC1000::Synchronize( const IoAKSC1000LineTable& LineTable )
{
    IoAKSC1000LineTableEnum Table = LineTable.TableEnum( );

    if ( LineTable != m_Registers[ Table ] )
    {
        if ( IsOpen( ) )
        {
            if ( ! Write( LineTable ) )
            {
                Read( m_Registers[ Table ] );  // try to resynchronize with device settings

                return FALSE;
            }
        }

        m_Registers[ Table ] = LineTable;
    }

    return TRUE;
}

int IoAKSC1000::Synchronize( const IoAKSC1000LineTableEntry& LineTableEntry )
{
    IoAKSC1000LineTableEnum      Table = LineTableEntry.TableEnum( );
    IoAKSC1000LineTableEntryEnum Entry = LineTableEntry.EntryEnum( );

    if ( LineTableEntry != m_Registers[ Table ][ Entry ] )
    {
        if ( IsOpen( ) )
        {
            if ( ! Write( LineTableEntry ) )
            {
                Read( m_Registers[ Table ][ Entry ] );  // try to resynchronize with device settings

                return FALSE;
            }
        }

        m_Registers[ Table ][ Entry ] = LineTableEntry;
    }

    return TRUE;
}

int IoAKSC1000::Verify( const IoAKSC1000Register& Register )
{
    if ( ! IsOpen( ) ) return FALSE;

    // Cannot verify contents of status register (it has no known, pre-determined state)
    if ( Register.IsStatusRegister( ) ) return FALSE;

    IoAKSC1000RegisterEnum RegisterEnum = Register.Enum( );

    // Read register data
    if ( ! Read( m_Registers[ RegisterEnum ] ) ) return FALSE;

    int OK = TRUE;

    // Verify control registers (excluding General Control register)
    if ( RegisterEnum == eControlRegisters )
    {
        // Construct IoAKSC1000RegisterArray object to gain access to individual control registers
        IoAKSC1000RegisterArray Registers( Register );

        // Verify contents of each register
        for ( int r = 0; r < nKSC1000ControlRegisterCount; r++ )
        {
            IoAKSC1000RegisterEnum Register = (IoAKSC1000RegisterEnum) r;

            // Exclude Frame Table Pointer register and General Control register - reflects special cases in Synchronize( )
            if ( Register != eGeneralControl && Register != eFrameTablePointer )
            {
                int DLLFrequencyRangeIndex;

                if ( Register == eGeneralSetup )
                {
                    // Suppress comparison of DLL frequency range index
                    DLLFrequencyRangeIndex = Registers[ eDLLFrequencyRangeIndex ].Value( );

                    Registers[ eDLLFrequencyRangeIndex ] = m_Registers[ eDLLFrequencyRangeIndex ];
                }

                // Verify register data
                if ( Registers[ Register ] == m_Registers[ Register ] )
                {
                    IoATrace( eTraceKSC1000Diagnostic, "IoAKSC1000::Verify( ): successfully verified register => %s\n",
                                                       Registers[ Register ].Name( ) );
                }
                else
                {
                    IoATrace( eTraceKSC1000Error, "IoAKSC1000::Verify( ): failed to verify register => %s\n", Registers[ Register ].Name( ) );

                    for ( int v = 0; v < Registers[ Register ].VariableCount( ); v++ )
                    {
                        IoAKSC1000CRVariableIndex Index = (IoAKSC1000CRVariableIndex) v;

                        if ( Registers[ Register ][ Index ].Value( ) != m_Registers[ Register ][ Index ].Value( ) )
                        {
                            IoATrace( eTraceKSC1000Error, "IoAKSC1000::Verify( ): %s = %d != %d\n",
                                                          Registers[ Register ][ Index ].Name( ),
                                                          Registers[ Register ][ Index ].Value( ),
                                                          m_Registers[ Register ][ Index ].Value( ) );
                        }
                    }

                    OK = FALSE;
                }

                if ( Register == eGeneralSetup )
                {
                    // Restore DLL frequency range index value
                    Registers[ eDLLFrequencyRangeIndex ] = DLLFrequencyRangeIndex;
                }
            }
        }
    }

    // Verify frame tables
    else if ( RegisterEnum == eFrameTableAccessRegister )
    {
        // Verify contents of each frame table entry
        for ( int t = 0; t < nFrameTableCount; t++ )
        {
            IoAKSC1000FrameTableEnum Table = (IoAKSC1000FrameTableEnum) t;

            for ( int e = 0; e < nFrameTableEntryCount; e++ )
            {
                IoAKSC1000FrameTableEntryEnum Entry = (IoAKSC1000FrameTableEntryEnum) e;

                // Verify frame table entry data
                if ( Register[ Table ][ Entry ] == m_Registers[ Table ][ Entry ] )
                {
                    IoATrace( eTraceKSC1000Diagnostic, "IoAKSC1000::Verify( ): successfully verified frame table entry => [%d][%d]\n", t, e );
                }
                else
                {
                    IoATrace( eTraceKSC1000Error, "IoAKSC1000::Verify( ): failed to verify frame table entry => [%d][%d]\n", t, e );

                    for ( int v = 0; v < Register[ Table ][ Entry ].VariableCount( ); v++ )
                    {
                        IoAKSC1000FTVariableEnum Variable = (IoAKSC1000FTVariableEnum) v;

                        if ( Register[ Table ][ Entry ][ Variable ].Value( ) != m_Registers[ eFrameTableAccessRegister ][ Table ][ Entry ][ Variable ].Value( ) )
                        {
                            IoATrace( eTraceKSC1000Error, "IoAKSC1000::Verify( ): %s = %d != %d\n",
                                                          Register[ Table ][ Entry ][ Variable ].Name( ),
                                                          Register[ Table ][ Entry ][ Variable ].Value( ),
                                                          m_Registers[ eFrameTableAccessRegister ][ Table ][ Entry ][ Variable ].Value( ) );
                        }
                    }

                    OK = FALSE;
                }
            }
        }
    }

    // Verify line tables
    else if ( RegisterEnum == eLineTableAccessRegister )
    {
        // Verify conbtnets of each line table entry
        for ( int t = 0; t < nLineTableCount; t++ )
        {
            IoAKSC1000LineTableEnum Table = (IoAKSC1000LineTableEnum) t;

            for ( int e = 0; e < nLineTableEntryCount; e++ )
            {
                IoAKSC1000LineTableEntryEnum Entry = (IoAKSC1000LineTableEntryEnum) e;

                // Verify line table entry data
                if ( Register[ Table ][ Entry ] == m_Registers[ Table ][ Entry ] )
                {
                    IoATrace( eTraceKSC1000Diagnostic, "IoAKSC1000::Verify( ): successfully verified line table entry => [%d][%d]\n", t, e );
                }
                else
                {
                    IoATrace( eTraceKSC1000Error, "IoAKSC1000::Verify( ): failed to verify line table entry => [%d][%d]\n", t, e );

                    for ( int v = 0; v < Register[ Table ][ Entry ].VariableCount( ); v++ )
                    {
                        IoAKSC1000LTVariableEnum Variable = (IoAKSC1000LTVariableEnum) v;

                        if ( Register[ Table ][ Entry ][ Variable ].Value( ) != m_Registers[ eLineTableAccessRegister ][ Table ][ Entry ][ Variable ].Value( ) )
                        {
                            IoATrace( eTraceKSC1000Error, "IoAKSC1000::Verify( ): %s = %d != %d\n",
                                                          Register[ Table ][ Entry ][ Variable ].Name( ),
                                                          Register[ Table ][ Entry ][ Variable ].Value( ),
                                                          m_Registers[ eLineTableAccessRegister ][ Table ][ Entry ][ Variable ].Value( ) );

                        }
                    }

                    OK = FALSE;
                }
            }
        }
    }

    // Verify single control register
    else
    {
        // Verify contents of register
        if ( Register == m_Registers[ RegisterEnum ] )
        {
            IoATrace( eTraceKSC1000Diagnostic, "IoAKSC1000::Verify( ): successfully verified register => %s\n", Register.Name( ) );
        }
        else
        {
            IoATrace( eTraceKSC1000Error, "IoAKSC1000::Verify( ): failed to verify register => %s\n", Register.Name( ) );

            for ( int v = 0; v < Register.VariableCount( ); v++ )
            {
                IoAKSC1000CRVariableIndex Index = (IoAKSC1000CRVariableIndex) v;

                IoATrace( eTraceKSC1000Error, "IoAKSC1000::Verify( ): %s = %d != %d\n",
                                              Register[ Index ].Name( ),
                                              Register[ Index ].Value( ),
                                              m_Registers[ RegisterEnum ][ Index ].Value( ) );
            }

            OK = FALSE;
        }
    }

    return OK;
}

int IoAKSC1000::Verify( const IoAKSC1000FrameTable& FrameTable )
{
    if ( ! IsOpen( ) ) return FALSE;

    IoAKSC1000FrameTableEnum Table = FrameTable.TableEnum( );

    if ( ! Read( m_Registers[ Table ] ) ) return FALSE;

    if ( FrameTable == m_Registers[ Table ] )
    {
        IoATrace( eTraceKSC1000Diagnostic, "IoAKSC1000::Verify( ): successfully verified frame table => [%d]\n", (int) Table );

        return TRUE;
    }
    else
    {
        IoATrace( eTraceKSC1000Error, "IoAKSC1000::Verify( ): failed to verify frame table => [%d]\n", (int) Table );

        for ( int e = 0; e < FrameTable.EntryCount( ); e++ )
        {
            IoAKSC1000FrameTableEntryEnum Entry = (IoAKSC1000FrameTableEntryEnum) e;

            for ( int v = 0; v < FrameTable[ Entry ].VariableCount( ); v++ )
            {
                IoAKSC1000FTVariableEnum Variable = (IoAKSC1000FTVariableEnum) v;

                if ( FrameTable[ Entry ][ Variable ].Value( ) != m_Registers[ Table ][ Entry ][ Variable ].Value( ) )
                {
                    IoATrace( eTraceKSC1000Error, "IoAKSC1000::Verify( ): [%d]%s = %d != %d\n", e,
                                                  FrameTable[ Entry ][ Variable ].Name( ),
                                                  FrameTable[ Entry ][ Variable ].Value( ),
                                                  m_Registers[ Table ][ Entry ][ Variable ].Value( ) );
                }
            }
        }

        return FALSE;
    }
}

int IoAKSC1000::Verify( const IoAKSC1000FrameTableEntry& FrameTableEntry )
{
    if ( ! IsOpen( ) ) return FALSE;

    IoAKSC1000FrameTableEnum      Table = FrameTableEntry.TableEnum( );
    IoAKSC1000FrameTableEntryEnum Entry = FrameTableEntry.EntryEnum( );

    if ( ! Read( m_Registers[ Table ][ Entry ] ) ) return FALSE;

    if ( FrameTableEntry == m_Registers[ Table ][ Entry ] )
    {
        IoATrace( eTraceKSC1000Diagnostic, "IoAKSC1000::Verify( ): successfully verified frame table entry => [%d][%d]\n", (int) Table, (int) Entry );

        return TRUE;
    }
    else
    {
        IoATrace( eTraceKSC1000Error, "IoAKSC1000::Verify( ): failed to verify frame table entry => [%d][%d]\n", (int) Table, (int) Entry );

        for ( int v = 0; v < FrameTableEntry.VariableCount( ); v++ )
        {
            IoAKSC1000FTVariableEnum Variable = (IoAKSC1000FTVariableEnum) v;

            if ( FrameTableEntry[ Variable ].Value( ) != m_Registers[ Table ][ Entry ][ Variable ].Value( ) )
            {
                IoATrace( eTraceKSC1000Error, "IoAKSC1000::Verify( ): %s = %d != %d\n",
                                              FrameTableEntry[ Variable ].Name( ),
                                              FrameTableEntry[ Variable ].Value( ),
                                              m_Registers[ Table ][ Entry ][ Variable ].Value( ) );
            }
        }

        return FALSE;
    }
}

int IoAKSC1000::Verify( const IoAKSC1000LineTable& LineTable  )
{
    if ( ! IsOpen( ) ) return FALSE;

    IoAKSC1000LineTableEnum Table = LineTable.TableEnum( );

    if ( ! Read( m_Registers[ Table ] ) ) return FALSE;

    if ( LineTable == m_Registers[ Table ] )
    {
        IoATrace( eTraceKSC1000Diagnostic, "IoAKSC1000::Verify( ): successfully verified line table => [%d]\n", (int) Table );

        return TRUE;
    }
    else
    {
        IoATrace( eTraceKSC1000Error, "IoAKSC1000::Verify( ): failed to verify line table => [%d]\n", (int) Table );

        for ( int e = 0; e < LineTable.EntryCount( ); e++ )
        {
            IoAKSC1000LineTableEntryEnum Entry = (IoAKSC1000LineTableEntryEnum) e;

            for ( int v = 0; v < LineTable[ Entry ].VariableCount( ); v++ )
            {
                IoAKSC1000LTVariableEnum Variable = (IoAKSC1000LTVariableEnum) v;

                if ( LineTable[ Entry ][ Variable ].Value( ) != m_Registers[ Table ][ Entry ][ Variable ].Value( ) )
                {
                    IoATrace( eTraceKSC1000Error, "IoAKSC1000::Verify( ): [%d]%s = %d != %d\n", e,
                                                  LineTable[ Entry ][ Variable ].Name( ),
                                                  LineTable[ Entry ][ Variable ].Value( ),
                                                  m_Registers[ Table ][ Entry ][ Variable ].Value( ) );
                }
            }
        }

        return FALSE;
    }
}

int IoAKSC1000::Verify( const IoAKSC1000LineTableEntry& LineTableEntry  )
{
    if ( ! IsOpen( ) ) return FALSE;

    IoAKSC1000LineTableEnum      Table = LineTableEntry.TableEnum( );
    IoAKSC1000LineTableEntryEnum Entry = LineTableEntry.EntryEnum( );

    if ( ! Read( m_Registers[ Table ][ Entry ] ) ) return FALSE;

    if ( LineTableEntry == m_Registers[ Table ][ Entry ] )
    {
        IoATrace( eTraceKSC1000Diagnostic, "IoAKSC1000::Verify( ): successfully verified line table entry => [%d][%d]\n", (int) Table, (int) Entry );

        return TRUE;
    }
    else
    {
        IoATrace( eTraceKSC1000Error, "IoAKSC1000::Verify( ): failed to verify line table entry => [%d][%d]\n", (int) Table, (int) Entry );

        for ( int v = 0; v < LineTableEntry.VariableCount( ); v++ )
        {
            IoAKSC1000LTVariableEnum Variable = (IoAKSC1000LTVariableEnum) v;

            if ( LineTableEntry[ Variable ].Value( ) != m_Registers[ Table ][ Entry ][ Variable ].Value( ) )
            {
                IoATrace( eTraceKSC1000Error, "IoAKSC1000::Verify( ): %s = %d != %d\n",
                                              LineTableEntry[ Variable ].Name( ),
                                              LineTableEntry[ Variable ].Value( ),
                                              m_Registers[ Table ][ Entry ][ Variable ].Value( ) );
            }
        }

        return FALSE;
    }
}

int IoAKSC1000::SetDLLFrequencyRangeIndex( double PixelClockHz )
{
    int DLLFrequencyRangeIndex;

    if ( ! GetDLLFrequencyRangeIndex( PixelClockHz, DLLFrequencyRangeIndex ) ) return FALSE;

    IoAKSC1000Register& GeneralSetupRegister = m_Registers[ eGeneralSetup ];

    if ( GeneralSetupRegister[ eDLLFrequencyRangeIndex ].Value( ) != DLLFrequencyRangeIndex )
    {
        GeneralSetupRegister[ eDLLFrequencyRangeIndex ] = DLLFrequencyRangeIndex;

        if ( IsOpen( ) )
        {
            if ( ! Write( GeneralSetupRegister ) )
            {
                Read( GeneralSetupRegister );  // try to resynchronize with device settings

                return FALSE;
            }
        }
    }

    return TRUE;
}

int IoAKSC1000::IsDLLLocked( )
{
    if ( InHighPowerMode( ) )  // => DLL is powered up
    {
        if ( ! SynchronizeStatusRegister( ) ) return FALSE;

        if ( m_Registers[ eDLLLocked ].Value( ) ) return TRUE;
    }

    return FALSE;
}

int IoAKSC1000::WaitForDLLLock( double TimeLimit )
{
    if ( InHighPowerMode( ) )  // => DLL is powered up
    {
        for ( IoATimeout Timeout( TimeLimit ); Timeout.IsActive( ); ::Sleep( 1 ) )
        {
            if ( ! SynchronizeStatusRegister( ) ) return FALSE;

            if ( m_Registers[ eDLLLocked ].Value( ) ) return TRUE;
        }

        IoATrace( eTraceKSC1000Error, "IoAKSC1000::WaitForDLLLock( ) timed out.\n" );
    }

    return FALSE;
}

int IoAKSC1000::SetFrameTablePointer( int FrameTableAddress )
{
    if ( FrameTableAddress < 0 || FrameTableAddress > 7 ) return FALSE;

    // Unconditionally update Frame Table Pointer register
    IoAKSC1000Register& FrameTablePointer = m_Registers[ eFrameTablePointer ];

    FrameTablePointer[ eFrameTableAddress ] = FrameTableAddress;

    if ( IsOpen( ) )
    {
        if ( ! Write( FrameTablePointer ) )  // writing to this register overrides frame table execution
        {
            Read( FrameTablePointer );  // try to resynchronize with device settings

            return FALSE;
        }
    }

    return TRUE;
}

int IoAKSC1000::SetPowerMode( IoAKSC1000PowerModeEnum PowerMode )
{
    IoAKSC1000Register& GeneralControlRegister = m_Registers[ eGeneralControl ];

    if ( GeneralControlRegister[ ePowerMode ].Value( ) != PowerMode )
    {
        GeneralControlRegister[ ePowerMode ] = PowerMode;

        if ( IsOpen( ) )
        {
            if ( ! Write( GeneralControlRegister ) )
            {
                Read( GeneralControlRegister );  // try to resynchronize with device settings

                return FALSE;
            }
        }
    }

    return TRUE;
}

int IoAKSC1000::SetOperationMode( IoAKSC1000OperationModeEnum OperationMode )
{
    IoAKSC1000Register& GeneralControlRegister = m_Registers[ eGeneralControl ];

    if ( GeneralControlRegister[ eOperationMode ].Value( ) != OperationMode )
    {
        GeneralControlRegister[ eOperationMode ] = OperationMode;

        if ( IsOpen( ) )
        {
            if ( ! Write( GeneralControlRegister ) )
            {
                Read( GeneralControlRegister );  // try to resynchronize with device settings

                return FALSE;
            }
        }
    }

    return TRUE;
}

int IoAKSC1000::SetGeneralControlRegister( IoAKSC1000PowerModeEnum PowerMode, IoAKSC1000OperationModeEnum OperationMode )
{
    IoAKSC1000Register& GeneralControlRegister = m_Registers[ eGeneralControl ];

    if ( GeneralControlRegister[ ePowerMode     ].Value( ) != PowerMode ||
         GeneralControlRegister[ eOperationMode ].Value( ) != OperationMode )
    {
        GeneralControlRegister[ ePowerMode     ] = PowerMode;
        GeneralControlRegister[ eOperationMode ] = OperationMode;

        if ( IsOpen( ) )
        {
            if ( ! Write( GeneralControlRegister ) )
            {
                Read( GeneralControlRegister );  // try to resynchronize with device settings

                return FALSE;
            }
        }
    }

    return TRUE;
}

int IoAKSC1000::Read( IoAKSC1000Register& Register, int nRegisters ) const
{
    int Bits[ 16 * 16 * 20 ];  // line tables require the most space

    // Fault bad register count
    if ( nRegisters < 1 ) return FALSE;

    // Assemble header bits
    int nBits = 0;

    // RNW = 1, read operation
    Bits[ nBits++ ] = 1;

    // Register address bits = rrrr
    for ( int i = 0; i < 4; i++ ) Bits[ nBits++ ] = ( Register.Number( ) >> i ) & 0x1;

    // Frame table or line table address bits
    if ( Register.IsFrameTableRegister( ) )
    {
        // Frame table entry number = 0000
        for ( int i = 0; i < 4; i++ ) Bits[ nBits++ ] = 0;

        // Frame table number = 000
        for ( int j = 0; j < 3; j++ ) Bits[ nBits++ ] = 0;
    }
    else if ( Register.IsLineTableRegister( ) )
    {
        // Line table entry number = 0000
        for ( int i = 0; i < 4; i++ ) Bits[ nBits++ ] = 0;

        // Line table number = 0000
        for ( int j = 0; j < 4; j++ ) Bits[ nBits++ ] = 0;
    }

    // Write header bits
    if ( ! WriteBSP( 0, Bits, nBits, 1 ) ) return FALSE;

    // Read + copy register data bits
    if ( nRegisters == 1 )
    {
        int BitCount = Register.BitCount( );

        if ( ! ReadBSP( 1, Bits, BitCount, 0 ) ) return FALSE;

        for ( int i = 0; i < BitCount; i++ ) Register[ i ] = Bits[ i ];
    }
    else  // reading of multiple registers used in Synchronize( ) function
    {
        if ( ! Register.IsControlRegister( ) ) return FALSE;  // only multiple control registers supported

        IoAKSC1000RegisterEnum RegisterEnum = Register.Enum( );

        if ( nRegisters > (int) nKSC1000ControlRegisterCount - (int) RegisterEnum ) return FALSE;

        IoAKSC1000RegisterEnum NextRegisterEnum = (IoAKSC1000RegisterEnum) ( (int) RegisterEnum + nRegisters );

        IoAKSC1000RegisterArray Registers( Register );

        int BitOffset = Register.BitOffset( );
        int BitCount  = Registers[ NextRegisterEnum ].BitOffset( ) - BitOffset;

        IoAKSC1000Register& ControlRegisters = Registers[ eControlRegisters ];

        if ( BitOffset + BitCount > ControlRegisters.BitOffset( ) + ControlRegisters.BitCount( ) ) return FALSE;

        if ( ! ReadBSP( 1, Bits, BitCount, 0 ) ) return FALSE;

        for ( int i = 0; i < BitCount; i++ ) Registers[ BitOffset + i ] = Bits[ nBits++ ];
    }

    return TRUE;
}

int IoAKSC1000::Write( const IoAKSC1000Register& Register, int nRegisters ) const
{
    int Bits[ 13 + 16 * 16 * 20 ];  // line tables require the most space

    // Fault bad register count
    if ( nRegisters < 1 ) return FALSE;

    // Fault attempt to write to status register
    if ( Register.IsStatusRegister( ) ) return FALSE;

    // Assemble header + data bits
    int nBits = 0;

    // RNW = 0, write operation
    Bits[ nBits++ ] = 0;

    // Register address bits = rrrr
    for ( int i = 0; i < 4; i++ ) Bits[ nBits++ ] = ( Register.Number( ) >> i ) & 0x1;

    // Frame table or line table address bits
    if ( Register.IsFrameTableRegister( ) )
    {
        // Frame table entry number = 0000
        for ( int i = 0; i < 4; i++ ) Bits[ nBits++ ] = 0;

        // Frame table number = 000
        for ( int j = 0; j < 3; j++ ) Bits[ nBits++ ] = 0;
    }
    else if ( Register.IsLineTableRegister( ) )
    {
        // Line table entry number = 0000
        for ( int i = 0; i < 4; i++ ) Bits[ nBits++ ] = 0;

        // Line table number = 0000
        for ( int j = 0; j < 4; j++ ) Bits[ nBits++ ] = 0;
    }

    // Register data bits
    if ( nRegisters == 1 )
    {
        int BitCount = Register.BitCount( );

        for ( int i = 0; i < BitCount; i++ ) Bits[ nBits++ ] = Register[ i ];
    }
    else  // writing of multiple (control) registers used in Synchronize( ) function
    {
        if ( ! Register.IsControlRegister( ) ) return FALSE;  // only multiple control registers supported

        IoAKSC1000RegisterEnum RegisterEnum = Register.Enum( );

        if ( nRegisters > (int) nKSC1000ControlRegisterCount - (int) RegisterEnum ) return FALSE;

        IoAKSC1000RegisterEnum NextRegisterEnum = (IoAKSC1000RegisterEnum) ( (int) RegisterEnum + nRegisters );

        IoAKSC1000RegisterArray Registers( Register );

        int BitOffset = Register.BitOffset( );
        int BitCount  = Registers[ NextRegisterEnum ].BitOffset( ) - BitOffset;

        IoAKSC1000Register& ControlRegisters = Registers[ eControlRegisters ];

        if ( BitOffset + BitCount > ControlRegisters.BitOffset( ) + ControlRegisters.BitCount( ) ) return FALSE;

        for ( int i = 0; i < BitCount; i++ ) Bits[ nBits++ ] = Registers[ BitOffset + i ];
    }

    // Write header + data bits
    if ( ! WriteBSP( 0, Bits, nBits, 0 ) ) return FALSE;

    return TRUE;
}

int IoAKSC1000::Read( IoAKSC1000FrameTable& FrameTable ) const
{
    int Bits[ 544 ];

    // Assemble header bits
    int nBits = 0;

    // RNW = 1, read operation
    Bits[ nBits++ ] = 1;

    // Frame table access register address bits = 0001 = LSB .... MSB
    for ( int i = 0; i < 4; i++ ) Bits[ nBits++ ] = ( (int) eFrameTableAccessRegister >> i ) & 0x1;

    // Frame table entry number = 0000
    for ( int j = 0; j < 4; j++ ) Bits[ nBits++ ] = 0;

    // Frame table number = tttt
    for ( int k = 0; k < 3; k++ ) Bits[ nBits++ ] = ( FrameTable.TableNumber( ) >> k ) & 0x1;

    // Write header bits
    if ( ! WriteBSP( 0, Bits, nBits, 1 ) ) return FALSE;

    // Read data bits
    if ( ! ReadBSP( 1, Bits, FrameTable.BitCount( ), 0 ) ) return FALSE;

    // Copy frame table data bits
    for ( int l = 0; l < FrameTable.BitCount( ); l++ ) FrameTable[ l ] = Bits[ l ];

    return TRUE;
}

int IoAKSC1000::Write( const IoAKSC1000FrameTable& FrameTable ) const
{
    int Bits[ 12 + 544 ];

    // Assemble header + data bits
    int nBits = 0;

    // RNW = 0, write operation
    Bits[ nBits++ ] = 0;

    // Frame table access register address bits = 0001 = LSB .... MSB
    for ( int i = 0; i < 4; i++ ) Bits[ nBits++ ] = ( (int) eFrameTableAccessRegister >> i ) & 0x1;

    // Frame table entry number = 0000
    for ( int j = 0; j < 4; j++ ) Bits[ nBits++ ] = 0;

    // Frame table number = ttt
    for ( int k = 0; k < 3; k++ ) Bits[ nBits++ ] = ( FrameTable.TableNumber( ) >> k ) & 0x1;

    // Frame table data bits
    for ( int l = 0; l < FrameTable.BitCount( ); l++ ) Bits[ nBits++ ] = FrameTable[ l ];

    // Write header + data bits
    if ( ! WriteBSP( 0, Bits, nBits, 0 ) ) return FALSE;

    return TRUE;
}

int IoAKSC1000::Read( IoAKSC1000FrameTableEntry& FrameTableEntry, int nFrameTableEntries ) const
{
    int Bits[ 8 * 16 * 34 ];

    // Fault bad frame table count
    if ( nFrameTableEntries < 1 ) return FALSE;

    // Assemble header bits
    int nBits = 0;

    // RNW = 1, read operation
    Bits[ nBits++ ] = 1;

    // Frame table access register address bits = 0001 = LSB .... MSB
    for ( int i = 0; i < 4; i++ ) Bits[ nBits++ ] = ( (int) eFrameTableAccessRegister >> i ) & 0x1;

    // Frame table entry number = eeee
    for ( int j = 0; j < 4; j++ ) Bits[ nBits++ ] = ( FrameTableEntry.EntryNumber( ) >> j ) & 0x1;

    // Frame table number = ttt
    for ( int k = 0; k < 3; k++ ) Bits[ nBits++ ] = ( FrameTableEntry.TableNumber( ) >> k ) & 0x1;

    // Write header bits
    if ( ! WriteBSP( 0, Bits, nBits, 1 ) ) return FALSE;

    // Read + copy line table entry data bits
    if ( nFrameTableEntries == 1 )
    {
        int BitCount = FrameTableEntry.BitCount( );

        if ( ! ReadBSP( 1, Bits, BitCount, 0 ) ) return FALSE;

        for ( int i = 0; i < BitCount; i++ ) FrameTableEntry[ i ] = Bits[ i ];
    }
    else  // reading of multiple frame table entries used in Synchronize( ) function
    {
        int BitOffset = FrameTableEntry.BitOffset( );
        int BitCount  = FrameTableEntry.BitCount( ) * nFrameTableEntries;

        IoAKSC1000RegisterArray Registers( FrameTableEntry );

        IoAKSC1000Register& FrameTables = Registers[ eFrameTables ];

        if ( BitOffset + BitCount > FrameTables.BitOffset( ) + FrameTables.BitCount( ) ) return FALSE;

        if ( ! ReadBSP( 1, Bits, BitCount, 0 ) ) return FALSE;

        for ( int i = 0; i < BitCount; i++ ) Registers[ BitOffset + i ] = Bits[ i ];
    }

    return TRUE;
}

int IoAKSC1000::Write( const IoAKSC1000FrameTableEntry& FrameTableEntry, int nFrameTableEntries ) const
{
    int Bits[ 12 + 8 * 16 * 34 ];

    // Fault bad frame table count
    if ( nFrameTableEntries < 1 ) return FALSE;

    // Assemble header + data bits
    int nBits = 0;

    // RNW = 0, write operation
    Bits[ nBits++ ] = 0;

    // Frame table access register address bits = 0001 = LSB .... MSB
    for ( int i = 0; i < 4; i++ ) Bits[ nBits++ ] = ( (int) eFrameTableAccessRegister >> i ) & 0x1;

    // Frame table entry number = eeee
    for ( int j = 0; j < 4; j++ ) Bits[ nBits++ ] = ( FrameTableEntry.EntryNumber( ) >> j ) & 0x1;

    // Frame table number = ttt
    for ( int k = 0; k < 3; k++ ) Bits[ nBits++ ] = ( FrameTableEntry.TableNumber( ) >> k ) & 0x1;

    // Frame table entry data bits
    if ( nFrameTableEntries == 1 )
    {
        int BitCount = FrameTableEntry.BitCount( );

        for ( int i = 0; i < BitCount; i++ ) Bits[ nBits++ ] = FrameTableEntry[ i ];
    }
    else  // writing of multiple frame table entries used in Synchronize( ) function
    {
        int BitOffset = FrameTableEntry.BitOffset( );
        int BitCount  = FrameTableEntry.BitCount( ) * nFrameTableEntries;

        IoAKSC1000RegisterArray Registers( FrameTableEntry );

        IoAKSC1000Register& FrameTables = Registers[ eFrameTables ];

        if ( BitOffset + BitCount > FrameTables.BitOffset( ) + FrameTables.BitCount( ) ) return FALSE;

        for ( int i = 0; i < BitCount; i++ ) Bits[ nBits++ ] = Registers[ BitOffset + i ];
    }

    // Write header + data bits
    if ( ! WriteBSP( 0, Bits, nBits, 0 ) ) return FALSE;

    return TRUE;
}

int IoAKSC1000::Read( IoAKSC1000LineTable& LineTable ) const
{
    int Bits[ 16 * 20 ];

    // Assemble header bits
    int nBits = 0;

    // RNW = 1, read operation
    Bits[ nBits++ ] = 1;

    // Line table access register address bits = 1001 = LSB .... MSB
    for ( int i = 0; i < 4; i++ ) Bits[ nBits++ ] = ( (int) eLineTableAccessRegister >> i ) & 0x1;

    // Line table entry number = 0000
    for ( int j = 0; j < 4; j++ ) Bits[ nBits++ ] = 0;

    // Line table number = tttt
    for ( int k = 0; k < 4; k++ ) Bits[ nBits++ ] = ( LineTable.TableNumber( ) >> k ) & 0x1;

    // Write header bits
    if ( ! WriteBSP( 0, Bits, nBits, 1 ) ) return FALSE;

    // Read data bits
    if ( ! ReadBSP( 1, Bits, LineTable.BitCount( ), 0 ) ) return FALSE;

    // Copy line table data bits
    for ( int l = 0; l < LineTable.BitCount( ); l++ ) LineTable[ l ] = Bits[ l ];

    return TRUE;
}

int IoAKSC1000::Write( const IoAKSC1000LineTable& LineTable ) const
{
    int Bits[ 13 + 16 * 20 ];

    // Assemble header + data bits
    int nBits = 0;

    // RNW = 0, write operation
    Bits[ nBits++ ] = 0;

    // Line table access register address bits = 1001 = LSB .... MSB
    for ( int i = 0; i < 4; i++ ) Bits[ nBits++ ] = ( (int) eLineTableAccessRegister >> i ) & 0x1;

    // Line table entry number = 0000
    for ( int j = 0; j < 4; j++ ) Bits[ nBits++ ] = 0;

    // Line table number = tttt
    for ( int k = 0; k < 4; k++ ) Bits[ nBits++ ] = ( LineTable.TableNumber( ) >> k ) & 0x1;

    // Line table data bits
    for ( int l = 0; l < LineTable.BitCount( ); l++ ) Bits[ nBits++ ] = LineTable[ l ];

    // Write header + data bits
    if ( ! WriteBSP( 0, Bits, nBits, 0 ) ) return FALSE;

    return TRUE;
}

int IoAKSC1000::Read( IoAKSC1000LineTableEntry& LineTableEntry, int nLineTableEntries ) const
{
    int Bits[ 16 * 16 * 20 ];

    // Fault bad line table count
    if ( nLineTableEntries < 1 ) return FALSE;

    // Assemble header bits
    int nBits = 0;

    // RNW = 1, read operation
    Bits[ nBits++ ] = 1;

    // Line table access register address bits = 1001 = LSB .... MSB
    for ( int i = 0; i < 4; i++ ) Bits[ nBits++ ] = ( (int) eLineTableAccessRegister >> i ) & 0x1;

    // Line table entry number = eeee
    for ( int j = 0; j < 4; j++ ) Bits[ nBits++ ] = ( LineTableEntry.EntryNumber( ) >> j ) & 0x1;

    // Line table number = tttt
    for ( int k = 0; k < 4; k++ ) Bits[ nBits++ ] = ( LineTableEntry.TableNumber( ) >> k ) & 0x1;

    // Write header bits
    if ( ! WriteBSP( 0, Bits, nBits, 1 ) ) return FALSE;

    // Read + copy line table entry data bits
    if ( nLineTableEntries == 1 )
    {
        int BitCount = LineTableEntry.BitCount( );

        if ( ! ReadBSP( 1, Bits, BitCount, 0 ) ) return FALSE;

        for ( int i = 0; i < BitCount; i++ ) LineTableEntry[ i ] = Bits[ i ];
    }
    else  // reading of multiple line table entries used in Synchronize( ) function
    {
        int BitOffset = LineTableEntry.BitOffset( );
        int BitCount  = LineTableEntry.BitCount( ) * nLineTableEntries;

        IoAKSC1000RegisterArray Registers( LineTableEntry );

        IoAKSC1000Register& LineTables = Registers[ eLineTables ];

        if ( BitOffset + BitCount > LineTables.BitOffset( ) + LineTables.BitCount( ) ) return FALSE;

        if ( ! ReadBSP( 1, Bits, BitCount, 0 ) ) return FALSE;

        for ( int i = 0; i < BitCount; i++ ) Registers[ BitOffset + i ] = Bits[ i ];
    }

    return TRUE;
}

int IoAKSC1000::Write( const IoAKSC1000LineTableEntry& LineTableEntry, int nLineTableEntries ) const
{
    int Bits[ 13 + 16 * 16 * 20 ];

    // Fault bad line table count
    if ( nLineTableEntries < 1 ) return FALSE;

    // Assemble header + data bits
    int nBits = 0;

    // RNW = 0, write operation
    Bits[ nBits++ ] = 0;

    // Line table access register address bits = 1001 = LSB .... MSB
    for ( int i = 0; i < 4; i++ ) Bits[ nBits++ ] = ( (int) eLineTableAccessRegister >> i ) & 0x1;

    // Line table entry number = eeee
    for ( int j = 0; j < 4; j++ ) Bits[ nBits++ ] = ( LineTableEntry.EntryNumber( ) >> j ) & 0x1;

    // Line table number = tttt
    for ( int k = 0; k < 4; k++ ) Bits[ nBits++ ] = ( LineTableEntry.TableNumber( ) >> k ) & 0x1;

    // Line table entry data bits
    if ( nLineTableEntries == 1 )
    {
        int BitCount = LineTableEntry.BitCount( );

        for ( int i = 0; i < BitCount; i++ ) Bits[ nBits++ ] = LineTableEntry[ i ];
    }
    else  // writing of multiple line table entries used in Synchronize( ) function
    {
        int BitOffset = LineTableEntry.BitOffset( );
        int BitCount  = LineTableEntry.BitCount( ) * nLineTableEntries;

        IoAKSC1000RegisterArray Registers( LineTableEntry );

        IoAKSC1000Register& LineTables = Registers[ eLineTables ];

        if ( BitOffset + BitCount > LineTables.BitOffset( ) + LineTables.BitCount( ) ) return FALSE;

        for ( int i = 0; i < BitCount; i++ ) Bits[ nBits++ ] = Registers[ BitOffset + i ];
    }

    // Write header + data bits
    if ( ! WriteBSP( 0, Bits, nBits, 0 ) ) return FALSE;

    return TRUE;
}
