/*
 * dlpc350_api.cpp
 *
 * This module provides C callable APIs for each of the command supported
 * by LightCrafter4500 platform and detailed in the programmer's guide.
 *
 * Copyright (C) {2015} Texas Instruments Incorporated - http://www.ti.com/
 *
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *    Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 *    Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the
 *    distribution.
 *
 *    Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
*/


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "dlpc350_common.h"
#include "dlpc350_api.h"
#include "dlpc350_usb.h"

#define SOURCE_LOCK_MASK 0x03
#define SOURCE_LOCKED 0x02

extern unsigned char g_OutputBuffer[];
extern unsigned char g_InputBuffer[];

CmdFormat CmdList[255] =
{
    {   0x07,  0x1C,  0x1C   },      //VID_SIG_STAT,
    {   0x1A,  0x00,  0x01   },      //SOURCE_SEL,
    {   0x1A,  0x02,  0x01   },      //PIXEL_FORMAT,
    {   0x1A,  0x03,  0x01   },      //CLK_SEL,
    {   0x1A,  0x37,  0x01   },      //CHANNEL_SWAP,
    {   0x1A,  0x04,  0x01   },      //FPD_MODE,
    {   0,  0,  0   },      //CURTAIN_COLOR,
    {   0x02,  0x00,  0x01   },      //POWER_CONTROL,
    {   0x10,  0x08,  0x01   },      //FLIP_LONG,
    {   0x10,  0x09,  0x01   },      //FLIP_SHORT,
    {   0x12,  0x03,  0x01   },      //TPG_SEL,
    {   0x1A,  0x05,  0x01   },      //PWM_INVERT,
    {   0x1A,  0x07,  0x01   },      //LED_ENABLE,
    {   0x02,  0x05,  0x00   },      //GET_VERSION,
    {   0x1A,  0xFF,  0x00   },      //GET_FIRMWAE_TAG_INFO
    {   0x08,  0x02,  0x00   },      //SW_RESET,
    {   0,  0,  0   },      //DMD_PARK,
    {   0x10,  0x0A,  0x01   },      //BUFFER_FREEZE,
    {   0x1A,  0x0A,  0x00   },      //STATUS_HW,
    {   0x1A,  0x0B,  0x00   },      //STATUS_SYS,
    {   0x1A,  0x0C,  0x00   },      //STATUS_MAIN,
    {   0,  0,  0   },      //CSC_DATA,
    {   0,  0,  0   },      //GAMMA_CTL,
    {   0,  0,  0   },      //BC_CTL,
    {   0x1A,  0x10,  0x01   },      //PWM_ENABLE,
    {   0x1A,  0x11,  0x06   },      //PWM_SETUP,
    {   0x1A,  0x12,  0x05   },      //PWM_CAPTURE_CONFIG,
    {   0x1A,  0x38,  0x02   },      //GPIO_CONFIG,
    {   0x0B,  0x01,  0x03   },      //LED_CURRENT,
    {   0x10,  0x00,  0x10   },      //DISP_CONFIG,
    {   0,  0,  0   },      //TEMP_CONFIG,
    {   0,  0,  0   },      //TEMP_READ,
    {   0x1A,  0x16,  0x09   },      //MEM_CONTROL,
    {   0,  0,  0   },      //I2C_CONTROL,
    {   0x1A,  0x1A,  0x01   },      //LUT_VALID,
    {   0x1A,  0x1B,  0x01   },      //DISP_MODE,
    {   0x1A,  0x1D,  0x03   },      //TRIG_OUT1_CTL,
    {   0x1A,  0x1E,  0x02   },      //TRIG_OUT2_CTL,
    {   0x1A,  0x1F,  0x02   },      //RED_STROBE_DLY,
    {   0x1A,  0x20,  0x02   },      //GRN_STROBE_DLY,
    {   0x1A,  0x21,  0x02   },      //BLU_STROBE_DLY,
    {   0x1A,  0x22,  0x01   },      //PAT_DISP_MODE,
    {   0x1A,  0x23,  0x01   },      //PAT_TRIG_MODE,
    {   0x1A,  0x24,  0x01   },      //PAT_START_STOP,
    {   0,  0,  0   },      //BUFFER_SWAP,
    {   0,  0,  0   },      //BUFFER_WR_DISABLE,
    {   0,  0,  0   },      //CURRENT_RD_BUFFER,
    {   0x1A,  0x29,  0x08   },      //PAT_EXPO_PRD,
    {   0x1A,  0x30,  0x01   },      //INVERT_DATA,
    {   0x1A,  0x31,  0x04   },      //PAT_CONFIG,
    {   0x1A,  0x32,  0x01   },      //MBOX_ADDRESS,
    {   0x1A,  0x33,  0x01   },      //MBOX_CONTROL,
    {   0x1A,  0x34,  0x00   },      //MBOX_DATA,
    {   0x1A,  0x35,  0x04   },      //TRIG_IN1_DELAY,
    {   0x1A,  0x36,  0x01   },      //TRIG_IN2_CONTROL,
    {   0x1A,  0x39,  0x01   },      //IMAGE_LOAD,
    {   0x1A,  0x3A,  0x02   },      //IMAGE_LOAD_TIMING,
    {   0x1A,  0x3B,  0x00   },      //I2C0_CTRL,
    {   0x1A,  0x3E,  0x0C   },      //MBOX_EXP_DATA,
    {   0x1A,  0x3F,  0x02   },      //MBOX_EXP_ADDRESS,
    {   0x1A,  0x40,  0x06   },      //EXP_PAT_CONFIG
    {   0x1A,  0x42,  0x01   },      //NUM_IMAGE_IN_FLASH,
    {   0x1A,  0x43,  0x01   },      //I2C0_STAT,
    {   0x08,  0x07,  0x03   },      //GPCLK_CONFIG,
    {   0,  0,  0   },      //PULSE_GPIO_23,
    {   0,  0,  0   },      //ENABLE_DLPC350_DEBUG,
    {   0x12,  0x04,  0x0C   },      //TPG_COLOR,
    {   0x1A,  0x13,  0x05   },     //PWM_CAPTURE_READ,
    {   0x30,  0x01,  0x00   },     //PROG_MODE,
    {   0x00,  0x00,  0x00   },     //BL_STATUS
    {   0x00,  0x23,  0x01   },     //BL_SPL_MODE
    {   0x00,  0x15,  0x01   },     //BL_GET_MANID,
    {   0x00,  0x15,  0x01   },     //BL_GET_DEVID,
    {   0x00,  0x15,  0x01   },     //BL_GET_CHKSUM,
    {   0x00,  0x29,  0x04   },     //BL_SETSECTADDR,
    {   0x00,  0x28,  0x00   },     //BL_SECT_ERASE,
    {   0x00,  0x2C,  0x04   },     //BL_SET_DNLDSIZE,
    {   0x00,  0x25,  0x00   },     //BL_DNLD_DATA,
    {   0x00,  0x2F,  0x01   },     //BL_FLASH_TYPE,
    {   0x00,  0x26,  0x00   },     //BL_CALC_CHKSUM,
    {   0x00,  0x30,  0x01   }     //BL_PROG_MODE,
};

static unsigned char g_SeqNum=0;
static unsigned long int g_PatLut[MAX_PAT_LUT_ENTRIES] = {0};
static unsigned int g_PatLutIndex = 0;
static unsigned long int g_ExpLut[MAX_VAR_EXP_PAT_LUT_ENTRIES*3] = {0};
static unsigned int g_ExpLutIndex = 0;

/* Local functions */
static int DLPC350_Write(bool ackRequired);
static int DLPC350_Read();
static int DLPC350_ContinueRead();
static int DLPC350_SendMsg(hidMessageStruct *pMsg, bool ackRequired);
static int DLPC350_PrepReadCmd(DLPC350_CMD cmd);
static int DLPC350_PrepReadCmdWithParam(DLPC350_CMD cmd, unsigned char param);
static int DLPC350_PrepMemReadCmd(unsigned int addr);
static int DLPC350_PrepWriteCmd(hidMessageStruct *pMsg, DLPC350_CMD cmd);


static int DLPC350_Write(bool ackRequired)
{
    int ret_val;
    hidMessageStruct *pMsg;

    if(ackRequired)
    {
        pMsg = (hidMessageStruct *)g_InputBuffer;
        if((ret_val = DLPC350_USB_Write()) > 0)
        {
            //Check for ACK or NACK response
            if(DLPC350_USB_Read() > 0)
            {
                if(pMsg->head.flags.nack == 1)
                    return -2;
                else
                    return ret_val;
            }
        }
    }
    else
    {
       ret_val = DLPC350_USB_Write();
    }

    return ret_val;
}

static int DLPC350_Read()
/**
 * This function is private to this file. This function is called to write the read control command and then read back 64 bytes over USB
 * to g_InputBuffer.
 *
 * @return  number of bytes read
 *          -2 = nack from target
 *          -1 = error reading
 *
 */
{
    int ret_val;
    hidMessageStruct *pMsg = (hidMessageStruct *)g_InputBuffer;
    if(DLPC350_USB_Write() > 0)
    {
        ret_val =  DLPC350_USB_Read();

        if((pMsg->head.flags.nack == 1) || (pMsg->head.length == 0))
            return -2;
        else
            return ret_val;
    }
    return -1;
}

static int DLPC350_ContinueRead()
{
    return DLPC350_USB_Read();
}

static int DLPC350_SendMsg(hidMessageStruct *pMsg, bool ackRequired)
/**
 * This function is private to this file. This function is called to send a message over USB; in chunks of 64 bytes.
 *
 * @return  number of bytes sent
 *          -1 = FAIL
 *
 */
{
    int maxDataSize = USB_MAX_PACKET_SIZE-sizeof(pMsg->head);
    int dataBytesSent = MIN(pMsg->head.length, maxDataSize);    //Send all data or max possible

    // Default the DLPC350_PrepWriteCmd() update write message for ACK
    // if user not expecting adjust accordingly
    if(!ackRequired)
        pMsg->head.flags.reply = 0;

    g_OutputBuffer[0]=0; // First byte is the report number
    memcpy(&g_OutputBuffer[1], pMsg, (sizeof(pMsg->head) + dataBytesSent));

    //Single packet transaction
    if(dataBytesSent >= pMsg->head.length)
    {
        if(DLPC350_Write(ackRequired) < 0)
            return -1;
    }
    else
    {
        //Send ACK request only for the last packet
        if(DLPC350_Write(0) < 0)
            return -1;

        while(dataBytesSent < pMsg->head.length)
        {
            memcpy(&g_OutputBuffer[1], &pMsg->text.data[dataBytesSent], USB_MAX_PACKET_SIZE);

            if((dataBytesSent+USB_MAX_PACKET_SIZE) >= (pMsg->head.length))
            {
                //last packet request for ACK
                if(DLPC350_Write(ackRequired) < 0)
                    return -1;
            }
            else
            {
                //middle packet
                if(DLPC350_Write(0) < 0)
                    return -1;
            }

            dataBytesSent += USB_MAX_PACKET_SIZE;
        }
    }

    return dataBytesSent+sizeof(pMsg->head);
}

static int DLPC350_PrepReadCmd(DLPC350_CMD cmd)
/**
 * This function is private to this file. Prepares the read-control command packet for the given command code and copies it to g_OutputBuffer.
 *
 * @param   cmd  - I - USB command code.
 *
 * @return  0 = PASS
 *          -1 = FAIL
 *
 */
{
    hidMessageStruct msg;

    msg.head.flags.rw = 1; //Read
    msg.head.flags.reply = 1; //Host wants a reply from device
    msg.head.flags.dest = 0; //Projector Control Endpoint
    msg.head.flags.reserved = 0;
    msg.head.flags.nack = 0;
    msg.head.seq = 0;

    msg.text.cmd = (CmdList[cmd].CMD2 << 8) | CmdList[cmd].CMD3;
    msg.head.length = 2;

    if(cmd == BL_GET_MANID)
    {
        msg.text.data[2] = 0x0C;
        msg.head.length += 1;
    }
    else if (cmd == BL_GET_DEVID)
    {
        msg.text.data[2] = 0x0D;
        msg.head.length += 1;
    }
    else if (cmd == BL_GET_CHKSUM)
    {
        msg.text.data[2] = 0x00;
        msg.head.length += 1;
    }

    g_OutputBuffer[0]=0; // First byte is the report number
    memcpy(&g_OutputBuffer[1], &msg, (sizeof(msg.head)+sizeof(msg.text.cmd) + msg.head.length));
    return 0;
}

static int DLPC350_PrepReadCmdWithParam(DLPC350_CMD cmd, unsigned char param)
/**
 * This function is private to this file. Prepares the read-control command packet for the given command code and parameter and copies it to g_OutputBuffer.
 *
 * @param   cmd  - I - USB command code.
 * @param   param - I - parameter to be used for tis read command.
 *
 * @return  0 = PASS
 *          -1 = FAIL
 *
 */
{
    hidMessageStruct msg;

    msg.head.flags.rw = 1; //Read
    msg.head.flags.reply = 1; //Host wants a reply from device
    msg.head.flags.dest = 0; //Projector Control Endpoint
    msg.head.flags.reserved = 0;
    msg.head.flags.nack = 0;
    msg.head.seq = 0;

    msg.text.cmd = (CmdList[cmd].CMD2 << 8) | CmdList[cmd].CMD3;
    msg.head.length = 3;

    msg.text.data[2] = param;

    g_OutputBuffer[0]=0; // First byte is the report number
    memcpy(&g_OutputBuffer[1], &msg, (sizeof(msg.head)+sizeof(msg.text.cmd) + msg.head.length));
    return 0;
}

static int DLPC350_PrepMemReadCmd(unsigned int addr)
/**
 * This function is private to this file. Prepares the memory read command packet with the given address and copies it to g_OutputBuffer.
 *
 * @param   addr  - I - memory address in controller to be read.
 *
 * @return  0 = PASS
 *          -1 = FAIL
 *
 */
{
    hidMessageStruct msg;

    msg.head.flags.rw = 1; //Read
    msg.head.flags.reply = 1; //Host wants a reply from device
    msg.head.flags.dest = 0; //Projector Control Endpoint
    msg.head.flags.reserved = 0;
    msg.head.flags.nack = 0;
    msg.head.seq = 0;

    msg.text.cmd = (CmdList[MEM_CONTROL].CMD2 << 8) | CmdList[MEM_CONTROL].CMD3;
    msg.head.length = 6;

    msg.text.data[2] = addr;
    msg.text.data[3] = addr >>8;
    msg.text.data[4] = addr >>16;
    msg.text.data[5] = addr >>24;

    g_OutputBuffer[0]=0; // First byte is the report number
    memcpy(&g_OutputBuffer[1], &msg, (sizeof(msg.head)+sizeof(msg.text.cmd) + msg.head.length));
    return 0;
}

int DLPC350_PrepWriteCmd(hidMessageStruct *pMsg, DLPC350_CMD cmd)
/**
 * This function is private to this file. Prepares the write command packet with given command code in the message structure pointer passed.
 *
 * @param   cmd  - I - USB command code.
 * @param   pMsg - I - Pointer to the message.
 *
 * @return  0 = PASS
 *          -1 = FAIL
 *
 */
{
    pMsg->head.flags.rw = 0; //Write
    pMsg->head.flags.reply = 1; //Host wants a reply from device
    pMsg->head.flags.dest = 0; //Projector Control Endpoint
    pMsg->head.flags.reserved = 0;
    pMsg->head.flags.nack = 0;
    pMsg->head.seq = g_SeqNum++;

    pMsg->text.cmd = (CmdList[cmd].CMD2 << 8) | CmdList[cmd].CMD3;
    pMsg->head.length = CmdList[cmd].len + 2;

    return 0;
}

int DLPC350_GetFirmwareVersion(unsigned int *pFW_ver)
/**
 * This command reads the version information of the DLPC350 firmware.
 *
 * @param   pFW_ver  - O - Firmware Revision BITS 0:15 PATCH NUMBER, BITS 16:23 MINOR REVISION, BIS 24:31 MAJOR REVISION
 *
 * @return  0 = PASS    <BR>
 *          -1 = FAIL  <BR>
 *
 */
{
	//Firware revision is loaded at this location in flash in v2.0.0 F/W it is @ 0xF902C000
	//in v3.0.0 F/W it is @ 0xF9093400   
	return DLPC350_MemRead(0xF9093400, pFW_ver); 
}

int DLPC350_GetVersion(unsigned int *pApp_ver, unsigned int *pAPI_ver, unsigned int *pSWConfig_ver, unsigned int *pSeqConfig_ver)
/**
 * This command reads the version information of the various components of DLPC350 firmware.
 * (I2C: 0x11)
 * (USB: CMD2: 0x02, CMD3: 0x05)
 *
 * @param   pApp_ver  - O - Application Software Revision BITS 0:15 PATCH NUMBER, BITS 16:23 MINOR REVISION, BIS 24:31 MAJOR REVISION
 * @param   pAPI_ver  - O - API Software Revision BITS 0:15 PATCH NUMBER, BITS 16:23 MINOR REVISION, BIS 24:31 MAJOR REVISION
 * @param   pSWConfig_ver  - O - Software Configuration Revision BITS 0:15 PATCH NUMBER, BITS 16:23 MINOR REVISION, BIS 24:31 MAJOR REVISION
 * @param   pSeqConfig_ver  - O - Sequence Configuration Revision BITS 0:15 PATCH NUMBER, BITS 16:23 MINOR REVISION, BIS 24:31 MAJOR REVISION
 *
 * @return  0 = PASS    <BR>
 *          -1 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    DLPC350_PrepReadCmd(GET_VERSION);

    if(DLPC350_Read() > 0)
    {
        memcpy(&msg, g_InputBuffer, 65);

        *pApp_ver = *(unsigned int *)&msg.text.data[0];
        *pAPI_ver = *(unsigned int *)&msg.text.data[4];
        *pSWConfig_ver = *(unsigned int *)&msg.text.data[8];
        *pSeqConfig_ver = *(unsigned int *)&msg.text.data[12];
        return 0;
    }
    return -1;
}


int DLPC350_GetFirmwareTagInfo(unsigned char *pFwTagInfo)
/**
 * This command reads the firmware tag information of the DLPC350 firmware.
 * (I2C: 0x5E)
 * (USB: CMD2: 0x1A, CMD3: 0xFF)
 *
 * @param   pFwTagInfo  - O - Firmware Tag information as string of characters.
 *
 * @return  0 = PASS    <BR>
 *          -1 = FAIL  <BR>
 *
 */
{
    int i = 0;
    hidMessageStruct msg;

    DLPC350_PrepReadCmd(GET_FIRMWAE_TAG_INFO);

    if(DLPC350_Read() > 0)
    {
        memcpy(&msg, g_InputBuffer, 65);

        while((msg.text.data[i] != '\0') && (i < 32))
        {
            *pFwTagInfo = msg.text.data[i];
            pFwTagInfo ++;
            i++;
        }

        *pFwTagInfo = '\0';

        return 0;
    }

    return -1;
}

int DLPC350_GetLedEnables(bool *pSeqCtrl, bool *pRed, bool *pGreen, bool *pBlue)
/**
 * This command reads back the state of LED control method as well as the enabled/disabled status of all LEDs.
 * (I2C: 0x10)
 * (USB: CMD2: 0x1A, CMD3: 0x07)
 *
 * @param   pSeqCtrl  - O - 1 - All LED enables are controlled by the Sequencer and ignore the other LED enable settings.
 *                          0 - All LED enables are controlled by pRed, pGreen and pBlue seetings and ignore Sequencer control
 * @param   pRed  - O - 0 - Red LED is disabled
 *                      1 - Red LED is enabled
 * @param   pGreen  - O - 0 - Green LED is disabled
 *                      1 - Green LED is enabled
 * @param   pBlue  - O - 0 - Blue LED is disabled
 *                      1 - Blue LED is enabled]
 *
 * @return  0 = PASS    <BR>
 *          -1 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    DLPC350_PrepReadCmd(LED_ENABLE);

    if(DLPC350_Read() > 0)
    {
        memcpy(&msg, g_InputBuffer, 65);

        if(msg.text.data[0] & BIT0)
            *pRed = true;
        else
            *pRed = false;

        if(msg.text.data[0] & BIT1)
            *pGreen = true;
        else
            *pGreen = false;

        if(msg.text.data[0] & BIT2)
            *pBlue = true;
        else
            *pBlue = false;

        if(msg.text.data[0] & BIT3)
            *pSeqCtrl = true;
        else
            *pSeqCtrl = false;
        return 0;
    }
    return -1;
}


int DLPC350_SetLedEnables(bool SeqCtrl, bool Red, bool Green, bool Blue)
/**
 * This command sets the state of LED control method as well as the enabled/disabled status of all LEDs.
 * (I2C: 0x10)
 * (USB: CMD2: 0x1A, CMD3: 0x07)
 *
 * @param   pSeqCtrl  - I - 1 - All LED enables are controlled by the Sequencer and ignore the other LED enable settings.
 *                          0 - All LED enables are controlled by pRed, pGreen and pBlue seetings and ignore Sequencer control
 * @param   pRed  - I - 0 - Red LED is disabled
 *                      1 - Red LED is enabled
 * @param   pGreen  - I - 0 - Green LED is disabled
 *                      1 - Green LED is enabled
 * @param   pBlue  - I - 0 - Blue LED is disabled
 *                      1 - Blue LED is enabled]
 *
 * @return  0 = PASS    <BR>
 *          -1 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;
    unsigned char Enable=0;

    if(SeqCtrl)
        Enable |= BIT3;
    if(Red)
        Enable |= BIT0;
    if(Green)
        Enable |= BIT1;
    if(Blue)
        Enable |= BIT2;

    msg.text.data[2] = Enable;
    DLPC350_PrepWriteCmd(&msg, LED_ENABLE);

    return DLPC350_SendMsg(&msg, true);
}

int DLPC350_GetLedCurrents(unsigned char *pRed, unsigned char *pGreen, unsigned char *pBlue)
/**
 * (I2C: 0x4B)
 * (USB: CMD2: 0x0B, CMD3: 0x01)
 * This parameter controls the pulse duration of the specific LED PWM modulation output pin. The resolution
 * is 8 bits and corresponds to a percentage of the LED current. The PWM value can be set from 0 to 100%
 * in 256 steps . If the LED PWM polarity is set to normal polarity, a setting of 0xFF gives the maximum
 * PWM current. The LED current is a function of the specific LED driver design.
 *
 * @param   pRed  - O - Red LED PWM current control Valid range, assuming normal polarity of PWM signals, is:
 *                      0x00 (0% duty cycle → Red LED driver generates no current
 *                      0xFF (100% duty cycle → Red LED driver generates maximum current))
 *                      The current level corresponding to the selected PWM duty cycle is a function of the specific LED driver design and thus varies by design.
 * @param   pGreen  - O - Green LED PWM current control Valid range, assuming normal polarity of PWM signals, is:
 *                      0x00 (0% duty cycle → Red LED driver generates no current
 *                      0xFF (100% duty cycle → Red LED driver generates maximum current))
 *                      The current level corresponding to the selected PWM duty cycle is a function of the specific LED driver design and thus varies by design.
 * @param   pBlue  - O - Blue LED PWM current control Valid range, assuming normal polarity of PWM signals, is:
 *                      0x00 (0% duty cycle → Red LED driver generates no current
 *                      0xFF (100% duty cycle → Red LED driver generates maximum current))
 *                      The current level corresponding to the selected PWM duty cycle is a function of the specific LED driver design and thus varies by design.
 *
 * @return  0 = PASS    <BR>
 *          -1 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    DLPC350_PrepReadCmd(LED_CURRENT);
    if(DLPC350_Read() > 0)
    {
        memcpy(&msg, g_InputBuffer, 65);

        *pRed = msg.text.data[0];
        *pGreen = msg.text.data[1];
        *pBlue = msg.text.data[2];

        return 0;
    }
    return -1;
}


int DLPC350_SetLedCurrents(unsigned char RedCurrent, unsigned char GreenCurrent, unsigned char BlueCurrent)
/**
 * (I2C: 0x4B)
 * (USB: CMD2: 0x0B, CMD3: 0x01)
 * This parameter controls the pulse duration of the specific LED PWM modulation output pin. The resolution
 * is 8 bits and corresponds to a percentage of the LED current. The PWM value can be set from 0 to 100%
 * in 256 steps . If the LED PWM polarity is set to normal polarity, a setting of 0xFF gives the maximum
 * PWM current. The LED current is a function of the specific LED driver design.
 *
 * @param   RedCurrent  - I - Red LED PWM current control Valid range, assuming normal polarity of PWM signals, is:
 *                      0x00 (0% duty cycle → Red LED driver generates no current
 *                      0xFF (100% duty cycle → Red LED driver generates maximum current))
 *                      The current level corresponding to the selected PWM duty cycle is a function of the specific LED driver design and thus varies by design.
 * @param   GreenCurrent  - I - Green LED PWM current control Valid range, assuming normal polarity of PWM signals, is:
 *                      0x00 (0% duty cycle → Red LED driver generates no current
 *                      0xFF (100% duty cycle → Red LED driver generates maximum current))
 *                      The current level corresponding to the selected PWM duty cycle is a function of the specific LED driver design and thus varies by design.
 * @param   BlueCurrent  - I - Blue LED PWM current control Valid range, assuming normal polarity of PWM signals, is:
 *                      0x00 (0% duty cycle → Red LED driver generates no current
 *                      0xFF (100% duty cycle → Red LED driver generates maximum current))
 *                      The current level corresponding to the selected PWM duty cycle is a function of the specific LED driver design and thus varies by design.
 *
 * @return  0 = PASS    <BR>
 *          -1 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    msg.text.data[2] = RedCurrent;
    msg.text.data[3] = GreenCurrent;
    msg.text.data[4] = BlueCurrent;

    DLPC350_PrepWriteCmd(&msg, LED_CURRENT);

    return DLPC350_SendMsg(&msg, true);
}

bool DLPC350_GetLongAxisImageFlip(void)
/**
 * (I2C: 0x08)
 * (USB: CMD2: 0x10, CMD3: 0x08)
 * The Long-Axis Image Flip defines whether the input image is flipped across the long axis of the DMD. If
 * this parameter is changed while displaying a still image, the input still image should be re-sent. If the
 * image is not re-sent, the output image might be slightly corrupted. In Structured Light mode, the image
 * flip will take effect on the next bit-plane, image, or video frame load.
 *
 * @return  TRUE = Image flipped along long axis    <BR>
 *          FALSE = Image not flipped  <BR>
 *
 */
{
    hidMessageStruct msg;

    DLPC350_PrepReadCmd(FLIP_LONG);
    if(DLPC350_Read() > 0)
    {
        memcpy(&msg, g_InputBuffer, 65);

        if ((msg.text.data[0] & BIT0) == BIT0)
            return true;
        else
            return false;
    }
    return false;
}

bool DLPC350_GetShortAxisImageFlip(void)
/**
 * (I2C: 0x09)
 * (USB: CMD2: 0x10, CMD3: 0x09)
 * The Short-Axis Image Flip defines whether the input image is flipped across the short axis of the DMD. If
 * this parameter is changed while displaying a still image, the input still image should be re-sent. If the
 * image is not re-sent, the output image might be slightly corrupted. In Structured Light mode, the image
 * flip will take effect on the next bit-plane, image, or video frame load.
 *
 * @return  TRUE = Image flipped along short axis    <BR>
 *          FALSE = Image not flipped  <BR>
 *
 */
{
    hidMessageStruct msg;

    DLPC350_PrepReadCmd(FLIP_SHORT);
    if(DLPC350_Read() > 0)
    {
        memcpy(&msg, g_InputBuffer, 65);

        if ((msg.text.data[0] & BIT0) == BIT0)
            return true;
        else
            return false;
    }
    return false;
}


int DLPC350_SetFreeze(bool Freeze)
/**
 * (I2C: 0x7C)
 * (USB: CMD2: 0x10, CMD3: 0x0A)
 * The freeze command disables swapping the memory buffers. When frozen the last
 * image streamed to the DMD continuese to be displayed.
 * @param   Freeze -I TRUE = Freeze display buffer <BR>
 *                  FALSE = No freeze. Display buffer swap keeps happening <BR>
 *
 * @return >=0 PASS <BR>
 *         <0 FAIL <BR>
 *
 */
{
    hidMessageStruct msg;

    if(Freeze)
        msg.text.data[2] = BIT0;
    else
        msg.text.data[2] = 0;

    DLPC350_PrepWriteCmd(&msg, BUFFER_FREEZE);

    return DLPC350_SendMsg(&msg, true);
}

int DLPC350_SetLongAxisImageFlip(bool Flip)
/**
 * (I2C: 0x08)
 * (USB: CMD2: 0x10, CMD3: 0x08)
 * The Long-Axis Image Flip defines whether the input image is flipped across the long axis of the DMD. If
 * this parameter is changed while displaying a still image, the input still image should be re-sent. If the
 * image is not re-sent, the output image might be slightly corrupted. In Structured Light mode, the image
 * flip will take effect on the next bit-plane, image, or video frame load.
 *
 * @param   Flip -I TRUE = Image flipped along long axis enable    <BR>
 *                  FALSE = Do not flip image <BR>
 *
 * @return >=0 PASS <BR>
 *         <0 FAIL <BR>
 *
 */
{
    hidMessageStruct msg;

    if(Flip)
        msg.text.data[2] = BIT0;
    else
        msg.text.data[2] = 0;

    DLPC350_PrepWriteCmd(&msg, FLIP_LONG);

    return DLPC350_SendMsg(&msg,true);
}

int DLPC350_SetShortAxisImageFlip(bool Flip)
/**
 * (I2C: 0x09)
 * (USB: CMD2: 0x10, CMD3: 0x09)
 * The Long-Axis Image Flip defines whether the input image is flipped across the long axis of the DMD. If
 * this parameter is changed while displaying a still image, the input still image should be re-sent. If the
 * image is not re-sent, the output image might be slightly corrupted. In Structured Light mode, the image
 * flip will take effect on the next bit-plane, image, or video frame load.
 *
 * @param   Flip -I TRUE = Image flipped along long axis enable    <BR>
 *                  FALSE = Do not flip image <BR>
 *
 * @return >=0 PASS <BR>
 *         <0 FAIL <BR>
 *
 */
{
    hidMessageStruct msg;

    if(Flip)
        msg.text.data[2] = BIT0;
    else
        msg.text.data[2] = 0;

    DLPC350_PrepWriteCmd(&msg, FLIP_SHORT);

    return DLPC350_SendMsg(&msg,true);
}

int DLPC350_EnterProgrammingMode()
/**
 * This function is to be called to put the unit in programming mode. Only programming mode APIs will work once
 * in this mode.
 *
 * @return >=0 PASS <BR>
 *         <0 FAIL <BR>
 *
 */
{
    hidMessageStruct msg;

    msg.text.data[2] = 1;

    DLPC350_PrepWriteCmd(&msg, PROG_MODE);

    return DLPC350_SendMsg(&msg,false);
}

int DLPC350_ExitProgrammingMode(void)
/**
 * This function works only in prorgamming mode.
 * This function is to be called to exit programming mode and resume normal operation with the new downloaded firmware.
 *
 * @return >=0 PASS <BR>
 *         <0 FAIL <BR>
 *
 */
{
    hidMessageStruct msg;

    msg.text.data[2] = 2;
    DLPC350_PrepWriteCmd(&msg, BL_PROG_MODE);

    return DLPC350_SendMsg(&msg,false);
}

int DLPC350_GetFlashManID(unsigned short *pManID)
/**
 * This function works only in prorgamming mode.
 * This function returns the manufacturer ID of the flash part interfaced with the controller.
 *
 * @param pManID - O - Manufacturer ID of the flash part
 *
 * @return 0 PASS <BR>
 *         -1 FAIL <BR>
 *
 */
{
    hidMessageStruct msg;

    DLPC350_PrepReadCmd(BL_GET_MANID);
    if(DLPC350_Read() > 0)
    {
        memcpy(&msg, g_InputBuffer, 65);

        *pManID = msg.text.data[6];
        *pManID |= (unsigned short)msg.text.data[7] << 8;
        return 0;
    }
    return -1;
}

int DLPC350_GetFlashDevID(unsigned long long *pDevID)
/**
 * This function works only in prorgamming mode.
 * This function returns the device ID of the flash part interfaced with the controller.
 *
 * @param pDevID - O - Device ID of the flash part
 *
 * @return 0 PASS <BR>
 *         -1 FAIL <BR>
 *
 */
{
    hidMessageStruct msg;

    DLPC350_PrepReadCmd(BL_GET_DEVID);
    if(DLPC350_Read() > 0)
    {
        memcpy(&msg, g_InputBuffer, 65);

        *pDevID = msg.text.data[6];
        *pDevID |= (unsigned long long)msg.text.data[7] << 8;
        *pDevID |= (unsigned long long)msg.text.data[8] << 16;
        *pDevID |= (unsigned long long)msg.text.data[9] << 24;
        *pDevID |= (unsigned long long)msg.text.data[12] << 32;
        *pDevID |= (unsigned long long)msg.text.data[13] << 40;
        *pDevID |= (unsigned long long)msg.text.data[14] << 48;
        *pDevID |= (unsigned long long)msg.text.data[15] << 56;
        return 0;
    }
    return -1;
}

int DLPC350_GetBLStatus(unsigned char *BL_Status)
/**
 * This function works only in prorgamming mode.
 * This function returns the device ID of the flash part interfaced with the controller.
 *
 * @param BL_Status - O - BIT3 of the status byte when set indicates that the program is busy
 *                        with exectuing the previous command. When BIT3 is reset, it means the
 *                        program is ready for the next command.
 *
 * @return 0 PASS <BR>
 *         -1 FAIL <BR>
 *
 */
{
    hidMessageStruct msg;

    /* For some reason BL_STATUS readback is not working properly.
     * However, after going through the bootloader code, I have ascertained that any
     * readback is fine - Byte 0 is always the bootloader status */
    DLPC350_PrepReadCmd(BL_GET_CHKSUM);
    if(DLPC350_Read() > 0)
    {
        memcpy(&msg, g_InputBuffer, 65);

        *BL_Status = msg.text.data[0];
        return 0;
    }
    return -1;
}

int DLPC350_SetFlashAddr(unsigned int Addr)
/**
 * This function works only in prorgamming mode.
 * This function is to be called to set the address prior to calling DLPC350_FlashSectorErase or DLPC350_DownloadData APIs.
 *
 * @param Addr - I - 32-bit absolute address.
 *
 * @return >=0 PASS <BR>
 *         <0 FAIL <BR>
 *
 */
{
    hidMessageStruct msg;

    msg.text.data[2] = Addr;
    msg.text.data[3] = Addr >> 8;
    msg.text.data[4] = Addr >> 16;
    msg.text.data[5] = Addr >> 24;

    DLPC350_PrepWriteCmd(&msg, BL_SET_SECTADDR);

    return DLPC350_SendMsg(&msg,true);
}

int DLPC350_FlashSectorErase(void)
/**
  * This function works only in prorgamming mode.
  * This function is to be called to erase a sector of flash. The address of the sector to be erased
  * is to be set by using the DLPC350_SetFlashAddr() API
  *
  * @return >=0 PASS <BR>
  *         <0 FAIL <BR>
  *
  */
{
    hidMessageStruct msg;

    DLPC350_PrepWriteCmd(&msg, BL_SECT_ERASE);
    return DLPC350_SendMsg(&msg,true);
}

int DLPC350_SetUploadSize(unsigned long int dataLen)
/**
 * This function works only in prorgamming mode.
 * This function is to be called to set the payload size of data to be sent using DLPC350_DownloadData API.
 *
 * @param dataLen -I - length of download data payload in bytes.
 *
 * @return >=0 PASS <BR>
 *         <0 FAIL <BR>
 *
 */
{
    hidMessageStruct msg;

    msg.text.data[2] = dataLen;
    msg.text.data[3] = dataLen >> 8;
    msg.text.data[4] = dataLen >> 16;
    msg.text.data[5] = dataLen >> 24;

    DLPC350_PrepWriteCmd(&msg, BL_SET_DNLDSIZE);

    return DLPC350_SendMsg(&msg,true);
}

int DLPC350_UploadData(unsigned char *pByteArray, unsigned int dataLen)
/**
 * This function works only in prorgamming mode.
 * This function sends one payload of data to the controller at a time. takes the total size of payload
 * in the parameter dataLen and returns the actual number of bytes that was sent in the return value.
 * This function needs to be called multiple times until all of the desired bytes are sent.
 *
 * @param pByteArray - I - Pointer to where the data to be downloaded is to be fetched from
 * @param dataLen -I - length in bytes of the total payload data to download.
 *
 * @return number of bytes actually downloaded <BR>
 *         <0 FAIL <BR>
 *
 */
{
    hidMessageStruct msg;
    int retval;
    unsigned int sendSize;

    //The last -2 is to workaround a bug in bootloader.
    sendSize = HID_MESSAGE_MAX_SIZE - sizeof(msg.head)- sizeof(msg.text.cmd) - 2;

    if(dataLen > sendSize)
        dataLen = sendSize;

    CmdList[BL_DNLD_DATA].len = dataLen;
    memcpy(&msg.text.data[2], pByteArray, dataLen);

    DLPC350_PrepWriteCmd(&msg, BL_DNLD_DATA);

    retval = DLPC350_SendMsg(&msg,false);
    if(retval > 0)
        return dataLen;

    return -1;
}

void DLPC350_WaitForFlashReady()
/**
 * This function works only in prorgamming mode.
 * This function polls the status bit and returns only when the controller is ready for next command.
 *
 */
{
    unsigned char BLstatus=STAT_BIT_FLASH_BUSY;

    do
    {
        DLPC350_GetBLStatus(&BLstatus);
    }
    while((BLstatus & STAT_BIT_FLASH_BUSY) == STAT_BIT_FLASH_BUSY);//Wait for flash busy flag to go off
}

int DLPC350_SetFlashType(unsigned char Type)
/**
 * This function works only in prorgamming mode.
 * This function is to be used to set the programming type of the flash device attached to the controller.
 *
 * @param Type - I - Type of the flash device.
 *
 * @return >=0 PASS <BR>
 *         <0 FAIL <BR>
 *
 */
{
    hidMessageStruct msg;

    msg.text.data[2] = Type;

    DLPC350_PrepWriteCmd(&msg, BL_FLASH_TYPE);

    return DLPC350_SendMsg(&msg,true);
}

int DLPC350_CalculateFlashChecksum(void)
/**
 * This function works only in prorgamming mode.
 * This function is to be issued to instruct the controller to calculate the flash checksum.
 * DLPC350_WaitForFlashReady() is then to be called to ensure that the controller is done and then call
 * DLPC350_GetFlashChecksum() API to retrieve the actual checksum from the controller.
 *
 * @return 0 = PASS <BR>
 *         -1 = FAIL <BR>
 *
 */
{
    hidMessageStruct msg;

    DLPC350_PrepWriteCmd(&msg, BL_CALC_CHKSUM);

    if(DLPC350_SendMsg(&msg,false) <= 0)
        return -1;

    return 0;

}

int DLPC350_GetFlashChecksum(unsigned int*checksum)
/**
 * This function works only in prorgamming mode.
 * This function is to be used to retrieve the flash checksum from the controller.
 * DLPC350_CalculateFlashChecksum() and DLPC350_WaitForFlashReady() must be called before using this API.
 *
 * @param checksum - O - variable in which the flash checksum is to be returned
 *
 * @return >=0 PASS <BR>
 *         <0 FAIL <BR>
 *
 */
{
    hidMessageStruct msg;
#if 0
    DLPC350_PrepWriteCmd(&msg, BL_CALC_CHKSUM);

    if(DLPC350_SendMsg(&msg,true) <= 0)
        return -1;

    DLPC350_WaitForFlashReady();
#endif
    DLPC350_PrepReadCmd(BL_GET_CHKSUM);
    if(DLPC350_Read() > 0)
    {
        memcpy(&msg, g_InputBuffer, 65);

        *checksum = msg.text.data[6];
        *checksum |= (unsigned int)msg.text.data[7] << 8;
        *checksum |= (unsigned int)msg.text.data[8] << 16;
        *checksum |= (unsigned int)msg.text.data[9] << 24;
        return 0;
    }
    return -1;
}

int DLPC350_GetStatus(unsigned char *pHWStatus, unsigned char *pSysStatus, unsigned char *pMainStatus)
/**
 * This function is to be used to check the various status indicators from the controller.
 * Refer to DLPC350 Programmer's guide section 2.1 "DLPC350 Status Commands" for detailed description of each byte.
 *
 * @param pHWStatus - O - provides status information on the DLPC350's sequencer, DMD controller and initialization.
 * @param pSysStatus - O - provides DLPC350 status on internal memory tests..
 * @param pMainStatus - O - provides DMD park status and DLPC350 sequencer, frame buffer, and gamma correction status.
 *
 * @return 0 PASS <BR>
 *         -1 FAIL <BR>
 *
 */
{
    hidMessageStruct msg;

    DLPC350_PrepReadCmd(STATUS_HW);
    if(DLPC350_Read() > 0)
    {
        memcpy(&msg, g_InputBuffer, 65);

        *pHWStatus = msg.text.data[0];
    }
    else
        return -1;

    DLPC350_PrepReadCmd(STATUS_SYS);
    if(DLPC350_Read() > 0)
    {
        memcpy(&msg, g_InputBuffer, 65);

        *pSysStatus = msg.text.data[0];
    }
    else
        return -1;

    DLPC350_PrepReadCmd(STATUS_MAIN);
    if(DLPC350_Read() > 0)
    {
        memcpy(&msg, g_InputBuffer, 65);

        *pMainStatus = msg.text.data[0];
    }
    else
        return -1;

    return 0;
}

int DLPC350_SoftwareReset(void)
/**
 * Use this API to reset the controller
 *
 */
{
    hidMessageStruct msg;

    DLPC350_PrepWriteCmd(&msg, SW_RESET);

    return DLPC350_SendMsg(&msg,false);
}

int DLPC350_SetMode(bool SLmode)
/**
 * The Display Mode Selection Command enables the DLPC350 internal image processing functions for
 * video mode or bypasses them for pattern display mode. This command selects between video or pattern
 * display mode of operation.
 *
 * @param   SLmode  - I - TRUE = Pattern Display mode. Assumes a 1-bit through 8-bit image with a pixel
 *                              resolution of 912 x 1140 and bypasses all the image processing functions of DLPC350
 *                          FALSE = Video Display mode. Assumes streaming video image from the 30-bit
 *                              RGB or FPD-link interface with a pixel resolution of up to 1280 x 800 up to 120 Hz.
 *
 * @return  0 = PASS    <BR>
 *          -1 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    msg.text.data[2] = SLmode;
    DLPC350_PrepWriteCmd(&msg, DISP_MODE);

    return DLPC350_SendMsg(&msg,true);
}

int DLPC350_GetMode(bool *pMode)
/**
 * The Display Mode Selection Command enables the DLPC350 internal image processing functions for
 * video mode or bypasses them for pattern display mode. This command selects between video or pattern
 * display mode of operation.
 *
 * @param   SLmode  - O - TRUE = Pattern Display mode. Assumes a 1-bit through 8-bit image with a pixel
 *                              resolution of 912 x 1140 and bypasses all the image processing functions of DLPC350
 *                        FALSE = Video Display mode. Assumes streaming video image from the 30-bit
 *                              RGB or FPD-link interface with a pixel resolution of up to 1280 x 800 up to 120 Hz.
 *
 * @return  0 = PASS    <BR>
 *          -1 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    DLPC350_PrepReadCmd(DISP_MODE);
    if(DLPC350_Read() > 0)
    {
        memcpy(&msg, g_InputBuffer, 65);
        *pMode = (msg.text.data[0] != 0);
        return 0;
    }
    return -1;
}

int DLPC350_SetPowerMode(bool Standby)
/**
 * (I2C: 0x07)
 * (USB: CMD2: 0x02, CMD3: 0x00)
 * The Power Control places the DLPC350 in a low-power state and powers down the DMD interface.
 * Standby mode should only be enabled after all data for the last frame to be displayed has been
 * transferred to the DLPC350. Standby mode must be disabled prior to sending any new data.
 *
 * @param   Standby  - I - TRUE = Standby mode. Places DLPC350 in low power state and powers down the DMD interface
 *                         FALSE = Normal operation. The selected external source will be displayed
 *
 * @return  >=0 = PASS    <BR>
 *          <0 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    msg.text.data[2] = Standby;
    DLPC350_PrepWriteCmd(&msg, POWER_CONTROL);

    return DLPC350_SendMsg(&msg,true);
}


int DLPC350_GetPowerMode(bool *Standby)
/**
 * (I2C: 0x07)
 * (USB: CMD2: 0x02, CMD3: 0x00)
 * The Power Control places the DLPC350 in a low-power state and powers down the DMD interface.
 * Standby mode should only be enabled after all data for the last frame to be displayed has been
 * transferred to the DLPC350. Standby mode must be disabled prior to sending any new data.
 *
 * @param   Standby  - 0 - TRUE = Standby mode. Places DLPC350 in low power state and powers down the DMD interface
 *                         FALSE = Normal operation. The selected external source will be displayed
 *
 * @return  >=0 = PASS    <BR>
 *          <0 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    DLPC350_PrepReadCmd(POWER_CONTROL);

    if(DLPC350_Read() > 0)
    {
        memcpy(&msg, g_InputBuffer, 65);

        //bit1:0 - show Power On/Standby state
        if(msg.text.data[0] & 0x03)
        {
            *Standby = true;
        }
        else
        {
            *Standby = false;
        }
    }
    else
    {
        return -1;
    }

    return 0;
}


int DLPC350_SetRedLEDStrobeDelay(unsigned char rising, unsigned char falling)
/**
 * (I2C: 0x6C)
 * (USB: CMD2: 0x1A, CMD3: 0x1F)
 * The Red LED Enable Delay Control command sets the rising and falling edge delay of the Red LED enable signal.
 *
 * @param   rising  - I - Red LED enable rising edge delay control. Each bit adds 107.2 ns.
 *                        0x00 = -20.05 μs, 0x01 = -19.9428 μs, ......0xBB=0.00 μs, ......, 0xFE = +7.1828 μs, 0xFF = +7.29 μs
 * @param   falling  - I - Red LED enable falling edge delay control. Each bit adds 107.2 ns.
 *                        0x00 = -20.05 μs, 0x01 = -19.9428 μs, ......0xBB=0.00 μs, ......, 0xFE = +7.1828 μs, 0xFF = +7.29 μs
 *
 * @return  >=0 = PASS    <BR>
 *          <0 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    msg.text.data[2] = rising;
    msg.text.data[3] = falling;

    DLPC350_PrepWriteCmd(&msg, RED_STROBE_DLY);

    return DLPC350_SendMsg(&msg,true);
}

int DLPC350_SetGreenLEDStrobeDelay(unsigned char rising, unsigned char falling)
/**
 * (I2C: 0x6D)
 * (USB: CMD2: 0x1A, CMD3: 0x20)
 * The Green LED Enable Delay Control command sets the rising and falling edge delay of the Green LED enable signal.
 *
 * @param   rising  - I - Green LED enable rising edge delay control. Each bit adds 107.2 ns.
 *                        0x00 = -20.05 μs, 0x01 = -19.9428 μs, ......0xBB=0.00 μs, ......, 0xFE = +7.1828 μs, 0xFF = +7.29 μs
 * @param   falling  - I - Green LED enable falling edge delay control. Each bit adds 107.2 ns.
 *                        0x00 = -20.05 μs, 0x01 = -19.9428 μs, ......0xBB=0.00 μs, ......, 0xFE = +7.1828 μs, 0xFF = +7.29 μs
 *
 * @return  >=0 = PASS    <BR>
 *          <0 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    msg.text.data[2] = rising;
    msg.text.data[3] = falling;

    DLPC350_PrepWriteCmd(&msg, GRN_STROBE_DLY);

    return DLPC350_SendMsg(&msg,true);
}

int DLPC350_SetBlueLEDStrobeDelay(unsigned char rising, unsigned char falling)
/**
 * (I2C: 0x6E)
 * (USB: CMD2: 0x1A, CMD3: 0x21)
 * The Blue LED Enable Delay Control command sets the rising and falling edge delay of the Blue LED enable signal.
 *
 * @param   rising  - I - Blue LED enable rising edge delay control. Each bit adds 107.2 ns.
 *                        0x00 = -20.05 μs, 0x01 = -19.9428 μs, ......0xBB=0.00 μs, ......, 0xFE = +7.1828 μs, 0xFF = +7.29 μs
 * @param   falling  - I - Blue LED enable falling edge delay control. Each bit adds 107.2 ns.
 *                        0x00 = -20.05 μs, 0x01 = -19.9428 μs, ......0xBB=0.00 μs, ......, 0xFE = +7.1828 μs, 0xFF = +7.29 μs
 *
 * @return  >=0 = PASS    <BR>
 *          <0 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    msg.text.data[2] = rising;
    msg.text.data[3] = falling;

    DLPC350_PrepWriteCmd(&msg, BLU_STROBE_DLY);

    return DLPC350_SendMsg(&msg,true);
}

int DLPC350_GetRedLEDStrobeDelay(unsigned char *pRising, unsigned char *pFalling)
/**
 * (I2C: 0x6C)
 * (USB: CMD2: 0x1A, CMD3: 0x1F)
 * This command reads back the rising and falling edge delay of the Red LED enable signal.
 *
 * @param   pRising  - O - Red LED enable rising edge delay value. Each bit adds 107.2 ns.
 *                        0x00 = -20.05 μs, 0x01 = -19.9428 μs, ......0xBB=0.00 μs, ......, 0xFE = +7.1828 μs, 0xFF = +7.29 μs
 * @param   pFalling  - O - Red LED enable falling edge delay value. Each bit adds 107.2 ns.
 *                        0x00 = -20.05 μs, 0x01 = -19.9428 μs, ......0xBB=0.00 μs, ......, 0xFE = +7.1828 μs, 0xFF = +7.29 μs
 *
 * @return  >=0 = PASS    <BR>
 *          <0 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    DLPC350_PrepReadCmd(RED_STROBE_DLY);

    if(DLPC350_Read() > 0)
    {
        memcpy(&msg, g_InputBuffer, 65);
        *pRising = msg.text.data[0];
        *pFalling = msg.text.data[1];
        return 0;
    }
    return -1;
}

int DLPC350_GetGreenLEDStrobeDelay(unsigned char *pRising, unsigned char *pFalling)
/**
 * (I2C: 0x6D)
 * (USB: CMD2: 0x1A, CMD3: 0x20)
 * This command reads back the rising and falling edge delay of the Green LED enable signal.
 *
 * @param   pRising  - O - Green LED enable rising edge delay value. Each bit adds 107.2 ns.
 *                        0x00 = -20.05 μs, 0x01 = -19.9428 μs, ......0xBB=0.00 μs, ......, 0xFE = +7.1828 μs, 0xFF = +7.29 μs
 * @param   pFalling  - O - Green LED enable falling edge delay value. Each bit adds 107.2 ns.
 *                        0x00 = -20.05 μs, 0x01 = -19.9428 μs, ......0xBB=0.00 μs, ......, 0xFE = +7.1828 μs, 0xFF = +7.29 μs
 *
 * @return  >=0 = PASS    <BR>
 *          <0 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    DLPC350_PrepReadCmd(GRN_STROBE_DLY);

    if(DLPC350_Read() > 0)
    {
        memcpy(&msg, g_InputBuffer, 65);
        *pRising = msg.text.data[0];
        *pFalling = msg.text.data[1];
        return 0;
    }
    return -1;
}

int DLPC350_GetBlueLEDStrobeDelay(unsigned char *pRising, unsigned char *pFalling)
/**
 * (I2C: 0x6E)
 * (USB: CMD2: 0x1A, CMD3: 0x21)
 * This command reads back the rising and falling edge delay of the Blue LED enable signal.
 *
 * @param   pRising  - O - Blue LED enable rising edge delay value. Each bit adds 107.2 ns.
 *                        0x00 = -20.05 μs, 0x01 = -19.9428 μs, ......0xBB=0.00 μs, ......, 0xFE = +7.1828 μs, 0xFF = +7.29 μs
 * @param   pFalling  - O - Blue LED enable falling edge delay value. Each bit adds 107.2 ns.
 *                        0x00 = -20.05 μs, 0x01 = -19.9428 μs, ......0xBB=0.00 μs, ......, 0xFE = +7.1828 μs, 0xFF = +7.29 μs
 *
 * @return  >=0 = PASS    <BR>
 *          <0 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    DLPC350_PrepReadCmd(BLU_STROBE_DLY);

    if(DLPC350_Read() > 0)
    {
        memcpy(&msg, g_InputBuffer, 65);
        *pRising = msg.text.data[0];
        *pFalling = msg.text.data[1];
        return 0;
    }
    return -1;
}


int  DLPC350_GetVideoSignalStatus(VideoSigStatus *pVidSigStat)
/**
 * (I2C: 0x01)
 * (USB: CMD2: 0x07, CMD3: 0x1C)
 * This command reads back the incoming video signal timing infomration.
 *
 * @param *pVidSigStat - O - The VideoSigStatus structure contains the following
 *          parameters to describe the area to be cropped:
 *              - Status <BR>
 *              - HRes <BR>
 *              - VRes <BR>
 *              - RSVD <BR>
 *              - HSyncPol <BR>
 *              - VSyncPol <BR>
 *              - PixClock <BR>
 *              - HFreq <BR>
 *              - VFreq <BR>
 *              - TotPixPerLine <BR>
 *              - TotLinPerFrame <BR>
 *              - ActvPixPerLine <BR>
 *              - ActvLinePerFrame <BR>
 *              - FirstActvPix <BR>
 *              - FirstActvLine <BR>
 *
 * @return  0 = PASS    <BR>
 *          -1 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    DLPC350_PrepReadCmd(VID_SIG_STAT);

    if(DLPC350_Read() > 0)
    {
        memcpy(&msg, g_InputBuffer, 65);

        //Copy data into structure
        pVidSigStat->Status = (msg.text.data[0] & 0x03);
        pVidSigStat->HRes = (unsigned int)((msg.text.data[2] << 8) | (msg.text.data[1]));
        pVidSigStat->VRes = (unsigned int)((msg.text.data[4] << 8) | (msg.text.data[3]));
        pVidSigStat->RSVD = (msg.text.data[5]);
        pVidSigStat->HSyncPol = (msg.text.data[6]);
        pVidSigStat->VSyncPol = (msg.text.data[7]);
        pVidSigStat->PixClock = (unsigned long int)((msg.text.data[11] << 24) | (msg.text.data[10] << 16) | (msg.text.data[9] << 8)  | (msg.text.data[8]));
        pVidSigStat->HFreq = (unsigned int)((msg.text.data[13] << 8) | (msg.text.data[12]));
        pVidSigStat->VFreq = (unsigned int)((msg.text.data[15] << 8) | (msg.text.data[14]));
        pVidSigStat->TotPixPerLine = (unsigned int)((msg.text.data[17] << 8) | (msg.text.data[16]));
        pVidSigStat->TotLinPerFrame = (unsigned int)((msg.text.data[19] << 8) | (msg.text.data[18]));
        pVidSigStat->ActvPixPerLine = (unsigned int)((msg.text.data[21] << 8) | (msg.text.data[20]));
        pVidSigStat->ActvLinePerFrame = (unsigned int)((msg.text.data[23] << 8) | (msg.text.data[22]));
        pVidSigStat->FirstActvPix = (unsigned int)((msg.text.data[25] << 8) | (msg.text.data[24]));
        pVidSigStat->FirstActvLine = (unsigned int)((msg.text.data[27] << 8) | (msg.text.data[26]));
        return 0;
    }

    return -1;
}

int DLPC350_SetInputSource(unsigned int source, unsigned int portWidth)
/**
 * (I2C: 0x00)
 * (USB: CMD2: 0x1A, CMD3: 0x00)
 * The Input Source Selection command selects the input source to be displayed by the DLPC350: 30-bit
 * Parallel Port, Internal Test Pattern, Flash memory, or FPD-link interface.
 *
 * @param   source  - I - Select the input source and interface mode:
 *                        0 = Parallel interface with 8-bit, 16-bit, 20-bit, 24-bit, or 30-bit RGB or YCrCb data formats
 *                        1 = Internal test pattern; Use DLPC350_SetTPGSelect() API to select pattern
 *                        2 = Flash. Images are 24-bit single-frame, still images stored in flash that are uploaded on command.
 *                        3 = FPD-link interface
 * @param   portWidth  - I - Parallel Interface bit depth
 *                           0 = 30-bits
 *                           1 = 24-bits
 *                           2 = 20-bits
 *                           3 = 16-bits
 *                           4 = 10-bits
 *                           5 = 8-bits
 *
 * @return  >=0 = PASS    <BR>
 *          <0 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    msg.text.data[2] = source;
    msg.text.data[2] |= portWidth << 3;
    DLPC350_PrepWriteCmd(&msg, SOURCE_SEL);

    return DLPC350_SendMsg(&msg,true);
}

int DLPC350_GetInputSource(unsigned int *pSource, unsigned int *pPortWidth)
/**
 * (I2C: 0x00)
 * (USB: CMD2: 0x1A, CMD3: 0x00)
 * Thisn command reads back the input source to be displayed by the DLPC350
 *
 * @param   pSource  - O - Input source and interface mode:
 *                        0 = Parallel interface with 8-bit, 16-bit, 20-bit, 24-bit, or 30-bit RGB or YCrCb data formats
 *                        1 = Internal test pattern; Use DLPC350_SetTPGSelect() API to select pattern
 *                        2 = Flash. Images are 24-bit single-frame, still images stored in flash that are uploaded on command.
 *                        3 = FPD-link interface
 * @param   pPortWidth  - O - Parallel Interface bit depth
 *                           0 = 30-bits
 *                           1 = 24-bits
 *                           2 = 20-bits
 *                           3 = 16-bits
 *                           4 = 10-bits
 *                           5 = 8-bits
 *
 * @return  0 = PASS    <BR>
 *          -1 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    DLPC350_PrepReadCmd(SOURCE_SEL);

    if(DLPC350_Read() > 0)
    {
        memcpy(&msg, g_InputBuffer, 65);
        *pSource = msg.text.data[0] & (BIT0 | BIT1 | BIT2);
        *pPortWidth = msg.text.data[0] >> 3;
        return 0;
    }
    return -1;
}

int DLPC350_SetPatternDisplayMode(bool external)
/**
 * The Pattern Display Data Input Source command selects the source of the data for pattern display:
 * streaming through the 24-bit RGB/FPD-link interface or stored data in the flash image memory area from
 * external Flash. Before executing this command, stop the current pattern sequence. After executing this
 * command, send the Validation command (I2C: 0x7D or USB: 0x1A1A) once before starting the pattern
 * sequence.
 *
 * @param   external  - I - TRUE = Pattern Display Data is streamed through the 24-bit RGB/FPD-link interface
 *                          FALSE = Pattern Display Data is fetched from flash memory
 *
 * @return  0 = PASS    <BR>
 *          -1 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    if(external)
        msg.text.data[2] = 0;
    else
        msg.text.data[2] = 3;

    DLPC350_PrepWriteCmd(&msg, PAT_DISP_MODE);

    return DLPC350_SendMsg(&msg,true);
}

int DLPC350_GetPatternDisplayMode(bool *external)
/**
 * The Pattern Display Data Input Source command selects the source of the data for pattern display:
 * streaming through the 24-bit RGB/FPD-link interface or stored data in the flash image memory area from
 * external Flash. Before executing this command, stop the current pattern sequence. After executing this
 * command, send the Validation command (I2C: 0x7D or USB: 0x1A1A) once before starting the pattern
 * sequence.
 *
 * @param   external  - O - TRUE = Pattern Display Data is streamed through the 24-bit RGB/FPD-link interface
 *                          FALSE = Pattern Display Data is fetched from flash memory
 *
 * @return  0 = PASS    <BR>
 *          -1 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    DLPC350_PrepReadCmd(PAT_DISP_MODE);

    if(DLPC350_Read() > 0)
    {
        memcpy(&msg, g_InputBuffer, 65);
        if(msg.text.data[0] == 0)
            *external = true;
        else
            *external = false;
        return 0;
    }
    return -1;
}

int DLPC350_SetPixelFormat(unsigned int format)
/**
 * (I2C: 0x02)
 * (USB: CMD2: 0x1A, CMD3: 0x02)
 * This API defines the pixel data format input into the DLPC350.Refer to programmer's guide for supported pixel formats
 * for each source type.
 *
 * @param   format  - I - Select the pixel data format:
 *                        0 = RGB 4:4:4 (30-bit)
 *                        1 = YCrCb 4:4:4 (30-bit)
 *                        2 = YCrCb 4:2:2
 *
 * @return  >=0 = PASS    <BR>
 *          <0 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    msg.text.data[2] = format;
    DLPC350_PrepWriteCmd(&msg, PIXEL_FORMAT);

    return DLPC350_SendMsg(&msg,true);
}

int DLPC350_GetPixelFormat(unsigned int *pFormat)
/**
 * (I2C: 0x02)
 * (USB: CMD2: 0x1A, CMD3: 0x02)
 * This API returns the defined the pixel data format input into the DLPC350.Refer to programmer's guide for supported pixel formats
 * for each source type.
 *
 * @param   pFormat  - O - Pixel data format:
 *                        0 = RGB 4:4:4 (30-bit)
 *                        1 = YCrCb 4:4:4 (30-bit)
 *                        2 = YCrCb 4:2:2
 *
 * @return  0 = PASS    <BR>
 *          -1 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    DLPC350_PrepReadCmd(PIXEL_FORMAT);

    if(DLPC350_Read() > 0)
    {
        memcpy(&msg, g_InputBuffer, 65);
        *pFormat = msg.text.data[0] & (BIT0 | BIT1 | BIT2);
        return 0;
    }
    return -1;
}

int DLPC350_SetPortClock(unsigned int clock)
/**
 * (I2C: 0x03)
 * (USB: CMD2: 0x1A, CMD3: 0x03)
 * This API selects the Port 1 clock for the parallel interface. For the FPD-Link, the Port Clock is
 * automatically set to Port 2.
 *
 * @param   clock  - I - Selects the port input clock:
 *                        0 = Port1, clock A
 *                        1 = Port1, clock B
 *                        2 = Port1, clock C
 *
 * @return  >=0 = PASS    <BR>
 *          <0 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    msg.text.data[2] = clock;
    DLPC350_PrepWriteCmd(&msg, CLK_SEL);

    return DLPC350_SendMsg(&msg,true);
}

int DLPC350_GetPortClock(unsigned int *pClock)
/**
 * (I2C: 0x03)
 * (USB: CMD2: 0x1A, CMD3: 0x03)
 * This API reads the Port 1 clock for the parallel interface.
 *
 * @param   pClock  - O - Selected port input clock:
 *                        0 = Port1, clock A
 *                        1 = Port1, clock B
 *                        2 = Port1, clock C
 *
 * @return  0 = PASS    <BR>
 *          -1 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    DLPC350_PrepReadCmd(CLK_SEL);

    if(DLPC350_Read() > 0)
    {
        memcpy(&msg, g_InputBuffer, 65);
        *pClock = msg.text.data[0] & (BIT0 | BIT1 | BIT2);
        return 0;
    }
    return -1;
}

int DLPC350_SetDataChannelSwap(unsigned int port, unsigned int swap)
/**
 * (I2C: 0x04)
 * (USB: CMD2: 0x1A, CMD3: 0x37)
 * This API configures the specified input data port and map the data subchannels.
 * The DLPC350 interprets Channel A as Green, Channel B as Red, and Channel C as Blue.
 *
 * @param   port  - I - Selects the port:
 *                        0 = Port1, parallel interface
 *                        1 = Port2, FPD-link interface
 * @param   swap - I - Swap Data Sub-Channel:
 *                     0 - ABC = ABC, No swapping of data sub-channels
 *                     1 - ABC = CAB, Data sub-channels are right shifted and circularly rotated
 *                     2 - ABC = BCA, Data sub-channels are left shifted and circularly rotated
 *                     3 - ABC = ACB, Data sub-channels B and C are swapped
 *                     4 - ABC = BAC, Data sub-channels A and B are swapped
 *                     5 - ABC = CBA, Data sub-channels A and C are swapped
 *
 * @return  >=0 = PASS    <BR>
 *          <0 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    msg.text.data[2] = port << 7;
    msg.text.data[2] |= swap & (BIT0 | BIT1 | BIT2);
    DLPC350_PrepWriteCmd(&msg, CHANNEL_SWAP);

    return DLPC350_SendMsg(&msg,true);
}

int DLPC350_GetDataChannelSwap(unsigned int *pPort, unsigned int *pSwap)
/**
 * (I2C: 0x04)
 * (USB: CMD2: 0x1A, CMD3: 0x37)
 * This API reads the data subchannel mapping for the specified input data port and map the data subchannels
 *
 * @param   *pPort  - O - Selected port:
 *                        0 = Port1, parallel interface
 *                        1 = Port2, FPD-link interface
 * @param   *pSwap - O - Swap Data Sub-Channel:
 *                     0 - ABC = ABC, No swapping of data sub-channels
 *                     1 - ABC = CAB, Data sub-channels are right shifted and circularly rotated
 *                     2 - ABC = BCA, Data sub-channels are left shifted and circularly rotated
 *                     3 - ABC = ACB, Data sub-channels B and C are swapped
 *                     4 - ABC = BAC, Data sub-channels A and B are swapped
 *                     5 - ABC = CBA, Data sub-channels A and C are swapped
 *
 * @return  0 = PASS    <BR>
 *          -1 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    DLPC350_PrepReadCmd(CHANNEL_SWAP);

    if(DLPC350_Read() > 0)
    {
        memcpy(&msg, g_InputBuffer, 65);
        *pSwap = msg.text.data[0] & (BIT0 | BIT1 | BIT2);
        if(msg.text.data[0] & BIT7)
            *pPort = 1;
        else
            *pPort = 0;
        return 0;
    }
    return -1;
}

int DLPC350_SetFPD_Mode_Field(unsigned int PixelMappingMode, bool SwapPolarity, unsigned int FieldSignalSelect)
/**
 * (I2C: 0x05)
 * (USB: CMD2: 0x1A, CMD3: 0x04)
 * The FPD-Link Mode and Field Select command configures the FPD-link pixel map, polarity, and signal select.
 *
 * @param   PixelMappingMode  - I - FPD-link Pixel Mapping Mode: See table 2-21 in programmer's guide for more details
 *                                  0 = Mode 1
 *                                  1 = Mode 2
 *                                  2 = Mode 3
 *                                  3 = Mode 4
 * @param   SwapPolarity - I - Polarity select
 *                             true = swap polarity
 *                             false = do not swap polarity
 *
 * @param   FieldSignalSelect -I -  Field Signal Select
 *                              0 - Map FPD-Link output from CONT1 onto Field Signal for FPD-link interface port
 *                              1 - Map FPD-Link output from CONT2 onto Field Signal for FPD-link interface port
 *                              2 - Force 0 onto Field Signal for FPD-link interface port
 *
 * @return  >=0 = PASS    <BR>
 *          <0 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    msg.text.data[2] = PixelMappingMode << 6;
    msg.text.data[2] |= FieldSignalSelect & (BIT0 | BIT1 | BIT2);
    if(SwapPolarity)
        msg.text.data[2] |= BIT3;
    DLPC350_PrepWriteCmd(&msg, FPD_MODE);

    return DLPC350_SendMsg(&msg,true);
}

int DLPC350_GetFPD_Mode_Field(unsigned int *pPixelMappingMode, bool *pSwapPolarity, unsigned int *pFieldSignalSelect)
/**
 * (I2C: 0x05)
 * (USB: CMD2: 0x1A, CMD3: 0x04)
 * This command reads back the configuration of FPD-link pixel map, polarity, and signal select.
 *
 * @param   PixelMappingMode  - O - FPD-link Pixel Mapping Mode: See table 2-21 in programmer's guide for more details
 *                                  0 = Mode 1
 *                                  1 = Mode 2
 *                                  2 = Mode 3
 *                                  3 = Mode 4
 * @param   SwapPolarity - O - Polarity select
 *                             true = swap polarity
 *                             false = do not swap polarity
 *
 * @param   FieldSignalSelect - O -  Field Signal Select
 *                              0 - Map FPD-Link output from CONT1 onto Field Signal for FPD-link interface port
 *                              1 - Map FPD-Link output from CONT2 onto Field Signal for FPD-link interface port
 *                              2 - Force 0 onto Field Signal for FPD-link interface port
 *
 * @return  0 = PASS    <BR>
 *          -1 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    DLPC350_PrepReadCmd(FPD_MODE);

    if(DLPC350_Read() > 0)
    {
        memcpy(&msg, g_InputBuffer, 65);
        *pFieldSignalSelect = msg.text.data[0] & (BIT0 | BIT1 | BIT2);
        if(msg.text.data[0] & BIT3)
            *pSwapPolarity = 1;
        else
            *pSwapPolarity = 0;
        *pPixelMappingMode = msg.text.data[0] >> 6;
        return 0;
    }
    return -1;
}

int DLPC350_SetTPGSelect(unsigned int pattern)
/**
 * (I2C: 0x0A)
 * (USB: CMD2: 0x12, CMD3: 0x03)
 * When the internal test pattern is the selected input, the Internal Test Patterns Select defines the test
 * pattern displayed on the screen. These test patterns are internally generated and injected into the
 * beginning of the DLPC350 image processing path. Therefore, all image processing is performed on the
 * test images. All command registers should be set up as if the test images are input from an RGB 8:8:8
 * external source.
 *
 * @param   pattern  - I - Selects the internal test pattern:
 *                         0x0 = Solid Field
 *                         0x1 = Horizontal Ramp
 *                         0x2 = Vertical Ramp
 *                         0x3 = Horizontal Lines
 *                         0x4 = Diagonal Lines
 *                         0x5 = Vertical Lines
 *                         0x6 = Grid
 *                         0x7 = Checkerboard
 *                         0x8 = RGB Ramp
 *                         0x9 = Color Bars
 *                         0xA = Step Bars
 *
 * @return  >=0 = PASS    <BR>
 *          <0 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    msg.text.data[2] = pattern;
    DLPC350_PrepWriteCmd(&msg, TPG_SEL);

    return DLPC350_SendMsg(&msg,true);
}

int DLPC350_GetTPGSelect(unsigned int *pPattern)
/**
 * (I2C: 0x0A)
 * (USB: CMD2: 0x12, CMD3: 0x03)
 * This command reads back the selected internal test pattern.
 *
 * @param   pattern  - O - Selected internal test pattern:
 *                         0x0 = Solid Field
 *                         0x1 = Horizontal Ramp
 *                         0x2 = Vertical Ramp
 *                         0x3 = Horizontal Lines
 *                         0x4 = Diagonal Lines
 *                         0x5 = Vertical Lines
 *                         0x6 = Grid
 *                         0x7 = Checkerboard
 *                         0x8 = RGB Ramp
 *                         0x9 = Color Bars
 *                         0xA = Step Bars
 *
 * @return  0 = PASS    <BR>
 *          -1 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    DLPC350_PrepReadCmd(TPG_SEL);

    if(DLPC350_Read() > 0)
    {
        memcpy(&msg, g_InputBuffer, 65);
        *pPattern = msg.text.data[0] & (BIT0 | BIT1 | BIT2 | BIT3);
        return 0;
    }
    return -1;
}

int DLPC350_LoadImageIndex(unsigned int index)
/**
 * (I2C: 0x7F)
 * (USB: CMD2: 0x1A, CMD3: 0x39)
 * This command loads an image from flash memory and then performs a buffer swap to display the loaded
 * image on the DMD.
 *
 * @param   index  - I - Image Index. Loads the image at this index from flash.
 *
 * @return  >=0 = PASS    <BR>
 *          <0 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    msg.text.data[2] = index;
    DLPC350_PrepWriteCmd(&msg, IMAGE_LOAD);

    return DLPC350_SendMsg(&msg,true);
}

int DLPC350_GetImageIndex(unsigned int *pIndex)
/**
 * (I2C: 0x7F)
 * (USB: CMD2: 0x1A, CMD3: 0x39)
 * This command loads reads back the index that was loaded most recently via DLPC350_LoadImageIndex() API.
 *
 * @param   *pIndex  - O - Image Index. Image at this index is loaded from flash.
 *
 * @return  >=0 = PASS    <BR>
 *          <0 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    DLPC350_PrepReadCmd(IMAGE_LOAD);

    if(DLPC350_Read() > 0)
    {
        memcpy(&msg, g_InputBuffer, 65);
        *pIndex = msg.text.data[0];
        return 0;
    }
    return -1;
}

int  DLPC350_GetNumImagesInFlash(unsigned int *pNumImgInFlash)
/**
 * (I2C: 0x0C)
 * (USB: CMD2: 0x1A, CMD3: 0x42)
 * This command reads number of images in the firmware running in DLPC350 controller.
 *
 * @param   *pNumImgInFlash  - O - Number of Images in the Flash.
 *
 * @return  >=0 = PASS    <BR>
 *          <0 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    DLPC350_PrepReadCmd(NUM_IMAGE_IN_FLASH);

    if(DLPC350_Read() > 0)
    {
        memcpy(&msg, g_InputBuffer, 65);
        *pNumImgInFlash = (msg.text.data[0]&0xFF);
        return 0;
    }

    return -1;
}

int DLPC350_SetDisplay(rectangle croppedArea, rectangle displayArea)
/**
 * (I2C: 0x7E)
 * (USB: CMD2: 0x10, CMD3: 0x00)
 * The Input Display Resolution command defines the active input resolution and active output (displayed)
 * resolution. The maximum supported input and output resolutions for the DLP4500 0.45 WXGA DMD is
 * 1280 pixels (columns) by 800 lines (rows). This command provides the option to define a subset of active
 * input frame data using pixel (column) and line (row) counts relative to the source-data enable signal
 * (DATEN). In other words, this feature allows the source image to be cropped as the first step in the
 * processing chain.
 *
 * @param croppedArea - I - The rectagle structure contains the following
 *          parameters to describe the area to be cropped:
 *              - FirstPixel <BR>
 *              - FirstLine <BR>
 *              - PixelsPerLine <BR>
 *              - LinesPerFrame <BR>
 * @param displayArea - I - The rectagle structure contains the following
 *          parameters to describe the display area:
 *              - FirstPixel <BR>
 *              - FirstLine <BR>
 *              - PixelsPerLine <BR>
 *              - LinesPerFrame <BR>
 *
 * @return  >=0 = PASS    <BR>
 *          <0 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    msg.text.data[2] = croppedArea.firstPixel & 0xFF;
    msg.text.data[3] = croppedArea.firstPixel >> 8;
    msg.text.data[4] = croppedArea.firstLine & 0xFF;
    msg.text.data[5] = croppedArea.firstLine >> 8;
    msg.text.data[6] = croppedArea.pixelsPerLine & 0xFF;
    msg.text.data[7] = croppedArea.pixelsPerLine >> 8;
    msg.text.data[8] = croppedArea.linesPerFrame & 0xFF;
    msg.text.data[9] = croppedArea.linesPerFrame >> 8;
    msg.text.data[10] = displayArea.firstPixel & 0xFF;
    msg.text.data[11] = displayArea.firstPixel >> 8;
    msg.text.data[12] = displayArea.firstLine & 0xFF;
    msg.text.data[13] = displayArea.firstLine >> 8;
    msg.text.data[14] = displayArea.pixelsPerLine & 0xFF;
    msg.text.data[15] = displayArea.pixelsPerLine >> 8;
    msg.text.data[16] = displayArea.linesPerFrame & 0xFF;
    msg.text.data[17] = displayArea.linesPerFrame >> 8;

    DLPC350_PrepWriteCmd(&msg, DISP_CONFIG);

    return DLPC350_SendMsg(&msg,true);
}

int DLPC350_GetDisplay(rectangle *pCroppedArea, rectangle *pDisplayArea)
/**
 * (I2C: 0x7E)
 * (USB: CMD2: 0x10, CMD3: 0x00)
 * This command reads back the active input resolution and active output (displayed) resolution.
 *
 * @param *pCroppedArea - O - The rectagle structure contains the following
 *          parameters to describe the area to be cropped:
 *              - FirstPixel <BR>
 *              - FirstLine <BR>
 *              - PixelsPerLine <BR>
 *              - LinesPerFrame <BR>
 * @param *pDisplayArea - O - The rectagle structure contains the following
 *          parameters to describe the display area:
 *              - FirstPixel <BR>
 *              - FirstLine <BR>
 *              - PixelsPerLine <BR>
 *              - LinesPerFrame <BR>
 *
 * @return  0 = PASS    <BR>
 *          -1 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    DLPC350_PrepReadCmd(DISP_CONFIG);

    if(DLPC350_Read() > 0)
    {
        memcpy(&msg, g_InputBuffer, 65);
        pCroppedArea->firstPixel = msg.text.data[0] | msg.text.data[1] << 8;
        pCroppedArea->firstLine = msg.text.data[2] | msg.text.data[3] << 8;
        pCroppedArea->pixelsPerLine = msg.text.data[4] | msg.text.data[5] << 8;
        pCroppedArea->linesPerFrame = msg.text.data[6] | msg.text.data[7] << 8;
        pDisplayArea->firstPixel = msg.text.data[8] | msg.text.data[9] << 8;
        pDisplayArea->firstLine = msg.text.data[10] | msg.text.data[11] << 8;
        pDisplayArea->pixelsPerLine = msg.text.data[12] | msg.text.data[13] << 8;
        pDisplayArea->linesPerFrame = msg.text.data[14] | msg.text.data[15] << 8;

        return 0;
    }
    return -1;
}

int DLPC350_SetTPGColor(unsigned short redFG, unsigned short greenFG, unsigned short blueFG, unsigned short redBG, unsigned short greenBG, unsigned short blueBG)
/**
 * (I2C: 0x1A)
 * (USB: CMD2: 0x12, CMD3: 0x04)
 * When the internal test pattern is the selected input, the Internal Test Patterns Color Control defines the
 * colors of the test pattern displayed on the screen. The foreground color setting affects all test patterns. The background color
 * setting affects those test patterns that have a foreground and background component, such as, Horizontal
 * Lines, Diagonal Lines, Vertical Lines, Grid, and Checkerboard.
 *
 * @param   redFG  - I - Red Foreground Color intensity in a scale from 0 to 1023
 *                       0x0 = No Red Foreground color intensity
 *                       0x3FF = Full Red Foreground color intensity
 * @param   greenFG  - I - Green Foreground Color intensity in a scale from 0 to 1023
 *                       0x0 = No Green Foreground color intensity
 *                       0x3FF = Full Green Foreground color intensity
 * @param   blueFG  - I - Blue Foreground Color intensity in a scale from 0 to 1023
 *                       0x0 = No Blue Foreground color intensity
 *                       0x3FF = Full Blue Foreground color intensity
 * @param   redBG  - I - Red Foreground Color intensity in a scale from 0 to 1023
 *                       0x0 = No Red Foreground color intensity
 *                       0x3FF = Full Red Foreground color intensity
 * @param   greenBG  - I - Green Foreground Color intensity in a scale from 0 to 1023
 *                       0x0 = No Green Foreground color intensity
 *                       0x3FF = Full Red Foreground color intensity
 * @param   blueBG  - I - Red Foreground Color intensity in a scale from 0 to 1023
 *                       0x0 = No Blue Foreground color intensity
 *                       0x3FF = Full Blue Foreground color intensity
 *
 * @return  >=0 = PASS    <BR>
 *          <0 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    msg.text.data[2] = (char)redFG;
    msg.text.data[3] = (char)(redFG >> 8);
    msg.text.data[4] = (char)greenFG;
    msg.text.data[5] = (char)(greenFG >> 8);
    msg.text.data[6] = (char)blueFG;
    msg.text.data[7] = (char)(blueFG >> 8);
    msg.text.data[8] = (char)redBG;
    msg.text.data[9] = (char)(redBG >> 8);
    msg.text.data[10] = (char)greenBG;
    msg.text.data[11] = (char)(greenBG >> 8);
    msg.text.data[12] = (char)blueBG;
    msg.text.data[13] = (char)(blueBG >> 8);

    DLPC350_PrepWriteCmd(&msg, TPG_COLOR);

    return DLPC350_SendMsg(&msg,true);
}

int DLPC350_GetTPGColor(unsigned short *pRedFG, unsigned short *pGreenFG, unsigned short *pBlueFG, unsigned short *pRedBG, unsigned short *pGreenBG, unsigned short *pBlueBG)
/**
 * (I2C: 0x1A)
 * (USB: CMD2: 0x12, CMD3: 0x04)
 * When the internal test pattern is the selected input, the Internal Test Patterns Color Control defines the
 * colors of the test pattern displayed on the screen. The foreground color setting affects all test patterns. The background color
 * setting affects those test patterns that have a foreground and background component, such as, Horizontal
 * Lines, Diagonal Lines, Vertical Lines, Grid, and Checkerboard.
 *
 * @param   *pRedFG  - O - Red Foreground Color intensity in a scale from 0 to 1023
 *                       0x0 = No Red Foreground color intensity
 *                       0x3FF = Full Red Foreground color intensity
 * @param   *pGreenFG  - O - Green Foreground Color intensity in a scale from 0 to 1023
 *                       0x0 = No Green Foreground color intensity
 *                       0x3FF = Full Green Foreground color intensity
 * @param   *pBlueFG  - O - Blue Foreground Color intensity in a scale from 0 to 1023
 *                       0x0 = No Blue Foreground color intensity
 *                       0x3FF = Full Blue Foreground color intensity
 * @param   *pRedBG  - O - Red Foreground Color intensity in a scale from 0 to 1023
 *                       0x0 = No Red Foreground color intensity
 *                       0x3FF = Full Red Foreground color intensity
 * @param   *pGreenBG  - O - Green Foreground Color intensity in a scale from 0 to 1023
 *                       0x0 = No Green Foreground color intensity
 *                       0x3FF = Full Red Foreground color intensity
 * @param   *pBlueBG  - O - Red Foreground Color intensity in a scale from 0 to 1023
 *                       0x0 = No Blue Foreground color intensity
 *                       0x3FF = Full Blue Foreground color intensity
 *
 * @return  0 = PASS    <BR>
 *          -1 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    DLPC350_PrepReadCmd(TPG_COLOR);

    if(DLPC350_Read() > 0)
    {
        memcpy(&msg, g_InputBuffer, 65);
        *pRedFG = msg.text.data[0] | msg.text.data[1] << 8;
        *pGreenFG = msg.text.data[2] | msg.text.data[3] << 8;
        *pBlueFG = msg.text.data[4] | msg.text.data[5] << 8;
        *pRedBG = msg.text.data[6] | msg.text.data[7] << 8;
        *pGreenBG = msg.text.data[8] | msg.text.data[9] << 8;
        *pBlueBG = msg.text.data[10] | msg.text.data[11] << 8;

        return 0;
    }
    return -1;
}

int DLPC350_ClearPatLut(void)
/**
 * This API does not send any commands to the controller.It clears the locally (in the GUI program) stored pattern LUT.
 * See table 2-65 in programmer's guide for detailed desciprtion of pattern LUT entries.
 *
 * @return  0 = PASS    <BR>
 *          -1 = FAIL  <BR>
 *
 */
{
    g_PatLutIndex = 0;
    return 0;
}

int DLPC350_ClearExpLut(void)
/**
 * This API does not send any commands to the controller.It clears the locally (in the GUI program) stored exposure LUT.
 *
 * @return  0 = PASS    <BR>
 *          -1 = FAIL  <BR>
 *
 */
{
    g_ExpLutIndex = 0;
    return 0;
}

int DLPC350_AddToPatLut(int TrigType, int PatNum,int BitDepth,int LEDSelect,bool InvertPat, bool InsertBlack,bool BufSwap, bool trigOutPrev)
/**
 * This API does not send any commands to the controller.
 * It makes an entry (appends) in the locally stored (in the GUI program) pattern LUT as per the input arguments passed to this function.
 * See table 2-65 in programmer's guide for detailed desciprtion of pattern LUT entries.
 *
 * @param   TrigType  - I - Select the trigger type for the pattern
 *                          0 = Internal trigger
 *                          1 = External positive
 *                          2 = External negative
 *                          3 = No Input Trigger (Continue from previous; Pattern still has full exposure time)
 *                       0x3FF = Full Red Foreground color intensity
 * @param   PatNum  - I - Pattern number (0 based index). For pattern number 0x3F, there is no
 *                          pattern display. The maximum number supported is 24 for 1 bit-depth
 *                          patterns. Setting the pattern number to be 25, with a bit-depth of 1 will insert
 *                          a white-fill pattern. Inverting this pattern will insert a black-fill pattern. These w
 *                          patterns will have the same exposure time as defined in the Pattern Display
 *                          Exposure and Frame Period command. Table 2-66 in the programmer's guide illustrates which bit
 *                          planes are illuminated by each pattern number.
 * @param   BitDepth  - I - Select desired bit-depth
 *                          0 = Reserved
 *                          1 = 1-bit
 *                          2 = 2-bit
 *                          3 = 3-bit
 *                          4 = 4-bit
 *                          5 = 5-bit
 *                          6 = 6-bit
 *                          7 = 7-bit
 *                          8 = 8-bit
 * @param   LEDSelect  - I -  Choose the LEDs that are on: b0 = Red, b1 = Green, b2 = Blue
 *                          0 = No LED (Pass Through)
 *                          1 = Red
 *                          2 = Green
 *                          3 = Yellow (Green + Red)
 *                          4 = Blue
 *                          5 = Magenta (Blue + Red)
 *                          6 = Cyan (Blue + Green)
 *                          7 = White (Red + Blue + Green)
 * @param   InvertPat  - I - true = Invert pattern
 *                           false = do not invert pattern
 * @param   InsertBlack  - I - true = Insert black-fill pattern after current pattern. This setting requires 230 μs
 *                                      of time before the start of the next pattern
 *                           false = do not insert any post pattern
 * @param   BufSwap  - I - true = perform a buffer swap
 *                           false = do not perform a buffer swap
 * @param   trigOutPrev  - I - true = Trigger Out 1 will continue to be high. There will be no falling edge
 *                                       between the end of the previous pattern and the start of the current pattern. w
 *                                       Exposure time is shared between all patterns defined under a common
 *                                       trigger out). This setting cannot be combined with the black-fill pattern
 *                           false = Trigger Out 1 has a rising edge at the start of a pattern, and a falling
 *                                       edge at the end of the pattern
 *
 * @return  0 = PASS    <BR>
 *          -1 = FAIL  <BR>
 *
 */
{
    unsigned long int lutWord = 0;

    lutWord = TrigType & 3;
    if(PatNum > 24)
        return -1;

    lutWord |= ((PatNum & 0x3F) << 2);
    if( (BitDepth > 8) || (BitDepth <= 0))
        return -1;
    lutWord |= ((BitDepth & 0xF) << 8);
    if(LEDSelect > 7)
        return -1;
    lutWord |= ((LEDSelect & 0x7) << 12);
    if(InvertPat)
        lutWord |= BIT16;
    if(InsertBlack)
        lutWord |= BIT17;
    if(BufSwap)
        lutWord |= BIT18;
    if(trigOutPrev)
        lutWord |= BIT19;

    g_PatLut[g_PatLutIndex++] = lutWord;
    return 0;
}

int DLPC350_AddToExpLut(int TrigType, int PatNum,int BitDepth,int LEDSelect,bool InvertPat, bool InsertBlack,bool BufSwap, bool trigOutPrev, unsigned int exp_time_us, unsigned int ptn_frame_period_us)
/**
 * This API does not send any commands to the controller.
 * It makes an entry (appends) in the locally stored (in the GUI program) pattern LUT as per the input arguments passed to this function.
 * See table 2-65 in programmer's guide for detailed desciprtion of pattern LUT entries.
 *
 * @param   TrigType  - I - Select the trigger type for the pattern
 *                          0 = Internal trigger
 *                          1 = External positive
 *                          2 = External negative
 *                          3 = No Input Trigger (Continue from previous; Pattern still has full exposure time)
 *                       0x3FF = Full Red Foreground color intensity
 * @param   PatNum  - I - Pattern number (0 based index). For pattern number 0x3F, there is no
 *                          pattern display. The maximum number supported is 24 for 1 bit-depth
 *                          patterns. Setting the pattern number to be 25, with a bit-depth of 1 will insert
 *                          a white-fill pattern. Inverting this pattern will insert a black-fill pattern. These w
 *                          patterns will have the same exposure time as defined in the Pattern Display
 *                          Exposure and Frame Period command. Table 2-66 in the programmer's guide illustrates which bit
 *                          planes are illuminated by each pattern number.
 * @param   BitDepth  - I - Select desired bit-depth
 *                          0 = Reserved
 *                          1 = 1-bit
 *                          2 = 2-bit
 *                          3 = 3-bit
 *                          4 = 4-bit
 *                          5 = 5-bit
 *                          6 = 6-bit
 *                          7 = 7-bit
 *                          8 = 8-bit
 * @param   LEDSelect  - I -  Choose the LEDs that are on: b0 = Red, b1 = Green, b2 = Blue
 *                          0 = No LED (Pass Through)
 *                          1 = Red
 *                          2 = Green
 *                          3 = Yellow (Green + Red)
 *                          4 = Blue
 *                          5 = Magenta (Blue + Red)
 *                          6 = Cyan (Blue + Green)
 *                          7 = White (Red + Blue + Green)
 * @param   InvertPat  - I - true = Invert pattern
 *                           false = do not invert pattern
 * @param   InsertBlack  - I - true = Insert black-fill pattern after current pattern. This setting requires 230 μs
 *                                      of time before the start of the next pattern
 *                           false = do not insert any post pattern
 * @param   BufSwap  - I - true = perform a buffer swap
 *                           false = do not perform a buffer swap
 * @param   trigOutPrev  - I - true = Trigger Out 1 will continue to be high. There will be no falling edge
 *                                       between the end of the previous pattern and the start of the current pattern. w
 *                                       Exposure time is shared between all patterns defined under a common
 *                                       trigger out). This setting cannot be combined with the black-fill pattern
 *                           false = Trigger Out 1 has a rising edge at the start of a pattern, and a falling
 *                                       edge at the end of the pattern
 * @param   exp_time_us     -I expsoure time in microseconds for this pattern
 * @param   ptn_frame_period_us     -I frame time in microseconds for this pattern
 *
 * @return  0 = PASS    <BR>
 *          -1 = FAIL  <BR>
 *
 */
{
    unsigned long int lutWord = 0;

    lutWord = TrigType & 3;
    if(PatNum > 24)
        return -1;

    lutWord |= ((PatNum & 0x3F) << 2);
    if( (BitDepth > 8) || (BitDepth <= 0))
        return -1;
    lutWord |= ((BitDepth & 0xF) << 8);
    if(LEDSelect > 7)
        return -1;
    lutWord |= ((LEDSelect & 0x7) << 12);
    if(InvertPat)
        lutWord |= BIT16;
    if(InsertBlack)
        lutWord |= BIT17;
    if(BufSwap)
        lutWord |= BIT18;
    if(trigOutPrev)
        lutWord |= BIT19;

    g_ExpLut[g_ExpLutIndex++] = lutWord;
    g_ExpLut[g_ExpLutIndex++] = exp_time_us;
    g_ExpLut[g_ExpLutIndex++] = ptn_frame_period_us;
    return 0;
}

int DLPC350_GetPatLutItem(int index, int *pTrigType, int *pPatNum,int *pBitDepth,int *pLEDSelect,bool *pInvertPat, bool *pInsertBlack,bool *pBufSwap, bool *pTrigOutPrev)
/**
 * This API does not send any commands to the controller.
 * It reads back an entry at the specified index from the locally stored (in the GUI program) pattern LUT and populates the input arguments passed to this function.
 * See table 2-65 in programmer's guide for detailed desciprtion of pattern LUT entries.
 *
 * @param   index  - I - Entry at this index from pattern LUT to be read back.
 * @param   *pTrigType  - O - Select the trigger type for the pattern
 *                          0 = Internal trigger
 *                          1 = External positive
 *                          2 = External negative
 *                          3 = No Input Trigger (Continue from previous; Pattern still has full exposure time)
 *                       0x3FF = Full Red Foreground color intensity
 * @param   *pPatNum  - O - Pattern number (0 based index). For pattern number 0x3F, there is no
 *                          pattern display. The maximum number supported is 24 for 1 bit-depth
 *                          patterns. Setting the pattern number to be 25, with a bit-depth of 1 will insert
 *                          a white-fill pattern. Inverting this pattern will insert a black-fill pattern. These w
 *                          patterns will have the same exposure time as defined in the Pattern Display
 *                          Exposure and Frame Period command. Table 2-66 in the programmer's guide illustrates which bit
 *                          planes are illuminated by each pattern number.
 * @param   *pBitDepth  - O - Select desired bit-depth
 *                          0 = Reserved
 *                          1 = 1-bit
 *                          2 = 2-bit
 *                          3 = 3-bit
 *                          4 = 4-bit
 *                          5 = 5-bit
 *                          6 = 6-bit
 *                          7 = 7-bit
 *                          8 = 8-bit
 * @param   *pLEDSelect  - O -  Choose the LEDs that are on: b0 = Red, b1 = Green, b2 = Blue
 *                          0 = No LED (Pass Through)
 *                          1 = Red
 *                          2 = Green
 *                          3 = Yellow (Green + Red)
 *                          4 = Blue
 *                          5 = Magenta (Blue + Red)
 *                          6 = Cyan (Blue + Green)
 *                          7 = White (Red + Blue + Green)
 * @param   *pInvertPat  - O - true = Invert pattern
 *                           false = do not invert pattern
 * @param   *pInsertBlack  - O - true = Insert black-fill pattern after current pattern. This setting requires 230 μs
 *                                      of time before the start of the next pattern
 *                           false = do not insert any post pattern
 * @param   *pBufSwap  - O - true = perform a buffer swap
 *                           false = do not perform a buffer swap
 * @param   *pTrigOutPrev  - O - true = Trigger Out 1 will continue to be high. There will be no falling edge
 *                                       between the end of the previous pattern and the start of the current pattern. w
 *                                       Exposure time is shared between all patterns defined under a common
 *                                       trigger out). This setting cannot be combined with the black-fill pattern
 *                           false = Trigger Out 1 has a rising edge at the start of a pattern, and a falling
 *                                       edge at the end of the pattern
 *
 * @return  0 = PASS    <BR>
 *          -1 = FAIL  <BR>
 *
 */
{
    unsigned int lutWord;

    lutWord = g_PatLut[index];

    *pTrigType = lutWord & 3;
    *pPatNum = (lutWord >> 2) & 0x3F;
    *pBitDepth = (lutWord >> 8) & 0xF;
    *pLEDSelect = (lutWord >> 12) & 7;
    *pInvertPat = ((lutWord & BIT16) == BIT16);
    *pInsertBlack = ((lutWord & BIT17) == BIT17);
    *pBufSwap = ((lutWord & BIT18) == BIT18);
    *pTrigOutPrev = ((lutWord & BIT19) == BIT19);

    return 0;
}

int DLPC350_GetVarExpPatLutItem(int index, int *pTrigType, int *pPatNum,int *pBitDepth,int *pLEDSelect,bool *pInvertPat, bool *pInsertBlack,bool *pBufSwap, bool *pTrigOutPrev, int *pPatExp, int *pPatPeriod)
/**
 * This API does not send any commands to the controller.
 * It reads back an entry at the specified index from the locally stored (in the GUI program) pattern LUT and populates the input arguments passed to this function.
 * See table 2-65 in programmer's guide for detailed desciprtion of pattern LUT entries.
 *
 * @param   index  - I - Entry at this index from pattern LUT to be read back.
 * @param   *pTrigType  - O - Select the trigger type for the pattern
 *                          0 = Internal trigger
 *                          1 = External positive
 *                          2 = External negative
 *                          3 = No Input Trigger (Continue from previous; Pattern still has full exposure time)
 *                       0x3FF = Full Red Foreground color intensity
 * @param   *pPatNum  - O - Pattern number (0 based index). For pattern number 0x3F, there is no
 *                          pattern display. The maximum number supported is 24 for 1 bit-depth
 *                          patterns. Setting the pattern number to be 25, with a bit-depth of 1 will insert
 *                          a white-fill pattern. Inverting this pattern will insert a black-fill pattern. These w
 *                          patterns will have the same exposure time as defined in the Pattern Display
 *                          Exposure and Frame Period command. Table 2-66 in the programmer's guide illustrates which bit
 *                          planes are illuminated by each pattern number.
 * @param   *pBitDepth  - O - Select desired bit-depth
 *                          0 = Reserved
 *                          1 = 1-bit
 *                          2 = 2-bit
 *                          3 = 3-bit
 *                          4 = 4-bit
 *                          5 = 5-bit
 *                          6 = 6-bit
 *                          7 = 7-bit
 *                          8 = 8-bit
 * @param   *pLEDSelect  - O -  Choose the LEDs that are on: b0 = Red, b1 = Green, b2 = Blue
 *                          0 = No LED (Pass Through)
 *                          1 = Red
 *                          2 = Green
 *                          3 = Yellow (Green + Red)
 *                          4 = Blue
 *                          5 = Magenta (Blue + Red)
 *                          6 = Cyan (Blue + Green)
 *                          7 = White (Red + Blue + Green)
 * @param   *pInvertPat  - O - true = Invert pattern
 *                           false = do not invert pattern
 * @param   *pInsertBlack  - O - true = Insert black-fill pattern after current pattern. This setting requires 230 μs
 *                                      of time before the start of the next pattern
 *                           false = do not insert any post pattern
 * @param   *pBufSwap  - O - true = perform a buffer swap
 *                           false = do not perform a buffer swap
 * @param   *pTrigOutPrev  - O - true = Trigger Out 1 will continue to be high. There will be no falling edge
 *                                       between the end of the previous pattern and the start of the current pattern. w
 *                                       Exposure time is shared between all patterns defined under a common
 *                                       trigger out). This setting cannot be combined with the black-fill pattern
 *                           false = Trigger Out 1 has a rising edge at the start of a pattern, and a falling
 *                                       edge at the end of the pattern
 * @param   *pPatExp  - O - Pattern Expsoure Time in us
 *
 * @param   *pPatPeriod - O - Total Pattern Period in us
 *
 * @return  0 = PASS    <BR>
 *          -1 = FAIL  <BR>
 *
 */
{
    unsigned long int lutWord;

    lutWord = g_ExpLut[(index*3)];

    *pTrigType = lutWord & 3;
    *pPatNum = (lutWord >> 2) & 0x3F;
    *pBitDepth = (lutWord >> 8) & 0xF;
    *pLEDSelect = (lutWord >> 12) & 7;
    *pInvertPat = ((lutWord & BIT16) == BIT16);
    *pInsertBlack = ((lutWord & BIT17) == BIT17);
    *pBufSwap = ((lutWord & BIT18) == BIT18);
    *pTrigOutPrev = ((lutWord & BIT19) == BIT19);
    *pPatExp = g_ExpLut[(index*3)+1];
    *pPatPeriod = g_ExpLut[(index*3)+2];

    return 0;
}

int DLPC350_OpenMailbox(int MboxNum)
/**
 * (I2C: 0x77)
 * (USB: CMD2: 0x1A, CMD3: 0x33)
 * This API opens the specified Mailbox within the DLPC350 controller. This API must be called
 * before sending data to the mailbox/LUT using DLPC350_SendPatLut() or DLPC350_SendImageLut() APIs.
 *
 * @param MboxNum - I - 1 = Open the mailbox for image index configuration
 *                      2 = Open the mailbox for pattern definition.
 *                      3 = Open the mailbox for the Variable Exposure
 *
 * @return  >=0 = PASS    <BR>
 *          <0 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    msg.text.data[2] = MboxNum;
    DLPC350_PrepWriteCmd(&msg, MBOX_CONTROL);

    return DLPC350_SendMsg(&msg,true);
}

int DLPC350_CloseMailbox(void)
/**
 * (I2C: 0x77)
 * (USB: CMD2: 0x1A, CMD3: 0x33)
 * This API is internally used by other APIs within this file. There is no need for user application to
 * call this API separately.
 * This API closes all the Mailboxes within the DLPC350 controller.
 *
 * @return  >=0 = PASS    <BR>
 *          <0 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    msg.text.data[2] = 0;
    DLPC350_PrepWriteCmd(&msg, MBOX_CONTROL);

    return DLPC350_SendMsg(&msg,true);
}

int DLPC350_MailboxSetAddr(int Addr)
/**
 * (I2C: 0x76)
 * (USB: CMD2: 0x1A, CMD3: 0x32)
 * This API defines the offset location within the DLPC350 mailboxes to write data into or to read data from
 *
 * @param Addr - I - 0-127 - Defines the offset within the selected (opened) LUT to write/read data to/from.
 *
 * @return  >=0 = PASS    <BR>
 *          <0 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    if(Addr > 127)
        return -1;

    msg.text.data[2] = Addr;
    DLPC350_PrepWriteCmd(&msg, MBOX_ADDRESS);

    return DLPC350_SendMsg(&msg,true);
}

int DLPC350_SetVarExpMboxAddr(int Addr)
/**
 * (I2C: 0x5D)
 * (USB: CMD2: 0x1A, CMD3: 0x32)
 * This API defines the offset location within the DLPC350 mailboxes to write data into or to read data from
 *
 * @param Addr - I - 0-1823 - Defines the offset within the selected (opened) LUT to write/read data to/from.
 *
 * @return  >=0 = PASS    <BR>
 *          <0 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    if(Addr > 1823)
        return -1;

    msg.text.data[2] = Addr;
    msg.text.data[3] = Addr >> 8;
    DLPC350_PrepWriteCmd(&msg, MBOX_EXP_ADDRESS);

    return DLPC350_SendMsg(&msg,true);
}

int DLPC350_SendVarExpPatLut(void)
/**
 * (I2C: 0x5c)
 * (USB: CMD2: 0x1A, CMD3: 0x3E)
 * This API sends the pattern LUT created by calling DLPC350_AddToExpLut() API to the DLPC350 controller.
 *
 * @return  0 = PASS    <BR>
 *          -1 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;
    unsigned int i;

#if 0
    printf("VarExpPatLut Send\n");
    for(i=0;i<g_ExpLutIndex;i++)
    {
        printf("VarExpPatLut[%04d] = 0x%X\n",i,g_ExpLut[i]);
    }
#endif

    if(DLPC350_OpenMailbox(3) < 0)
        return -1;

    DLPC350_PrepWriteCmd(&msg, MBOX_EXP_DATA);

    for(i=0; i<g_ExpLutIndex; i+=3)
    {
        if(DLPC350_SetVarExpMboxAddr(i/3) < 0)
            return -1;

        msg.text.data[2] = g_ExpLut[i];
        msg.text.data[3] = g_ExpLut[i]>>8;
        msg.text.data[4] = g_ExpLut[i]>>16;
        msg.text.data[5] = g_ExpLut[i]>>24;

        msg.text.data[6] = g_ExpLut[i+1];
        msg.text.data[7] = g_ExpLut[i+1]>>8;
        msg.text.data[8] = g_ExpLut[i+1]>>16;
        msg.text.data[9] = g_ExpLut[i+1]>>24;

        msg.text.data[10] = g_ExpLut[i+2];
        msg.text.data[11] = g_ExpLut[i+2]>>8;
        msg.text.data[12] = g_ExpLut[i+2]>>16;
        msg.text.data[13] = g_ExpLut[i+2]>>24;
        DLPC350_SendMsg(&msg,true);
    }

    DLPC350_CloseMailbox();

    return 0;
}


int DLPC350_SendVarExpImageLut(unsigned char *lutEntries, unsigned int numEntries)
/**
 * (I2C: )
 * (USB: CMD2:  CMD3: )
 * This API sends the image LUT to the DLPC350 controller.
 *
 * @param   *lutEntries - I - Pointer to the array in which LUT entries to be sent are stored
 *
 * @param   numEntries - I - number of entries to be sent to the controller
 *
 * @return  0 = PASS    <BR>
 *          -1 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;
    unsigned int i;
    unsigned int bytes_sent = 0;

    if(numEntries < 1 || numEntries > MAX_VAR_EXP_IMAGE_LUT_ENTRIES)
        return -1;

#if 0
    printf("VarExpImageLut Send\n");
    for(i=0;i<numEntries;i++)
    {
        printf("varExpImageLut[%02d] = %d\n",i,lutEntries[i]);
    }
#endif

    DLPC350_OpenMailbox(1);
    DLPC350_SetVarExpMboxAddr(0);

    // Check for special case of 2 entries
    if( numEntries == 2)
    {
        msg.text.data[2] = lutEntries[1];
        msg.text.data[3] = lutEntries[0];
    }
    else
    {
        for(i=0; i<numEntries; i++)
        {
            msg.text.data[2+i] = lutEntries[i];
        }
    }

    CmdList[MBOX_DATA].len = numEntries;
    DLPC350_PrepWriteCmd(&msg, MBOX_DATA);
    bytes_sent = DLPC350_SendMsg(&msg,true);
    DLPC350_CloseMailbox();

    return bytes_sent;
}



int DLPC350_SendPatLut(void)
/**
 * (I2C: 0x78)
 * (USB: CMD2: 0x1A, CMD3: 0x34)
 * This API sends the pattern LUT created by calling DLPC350_AddToPatLut() API to the DLPC350 controller.
 *
 * @return  0 = PASS    <BR>
 *          -1 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;
    int bytesToSend=g_PatLutIndex*3;
    unsigned int i;

#if 0
    printf("PatLut Send\n");
    for(i=0;i<g_PatLutIndex;i++)
    {
        printf("PatLut[%03d] = 0x%X\n",i,g_PatLut[i]);
    }
#endif

    if(DLPC350_OpenMailbox(2) < 0)
        return -1;
    DLPC350_MailboxSetAddr(0);

    CmdList[MBOX_DATA].len = bytesToSend;
    DLPC350_PrepWriteCmd(&msg, MBOX_DATA);

    for(i=0; i<g_PatLutIndex; i++)
    {
        msg.text.data[2+3*i] = g_PatLut[i];
        msg.text.data[2+3*i+1] = g_PatLut[i]>>8;
        msg.text.data[2+3*i+2] = g_PatLut[i]>>16;
    }

    DLPC350_SendMsg(&msg,true);
    DLPC350_CloseMailbox();
    return 0;
}

int DLPC350_SendImageLut(unsigned char *lutEntries, unsigned int numEntries)
/**
 * (I2C: 0x78)
 * (USB: CMD2: 0x1A, CMD3: 0x34)
 * This API sends the image LUT to the DLPC350 controller.
 *
 * @param   *lutEntries - I - Pointer to the array in which LUT entries to be sent are stored
 *
 * @param   numEntries - I - number of entries to be sent to the controller
 *
 * @return  0 = PASS    <BR>
 *          -1 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;
    unsigned int i;
    unsigned int bytes_sent = 0;

#if 0
    printf("ImageLut Send\n");
    for(i=0;i<numEntries;i++)
    {
        printf("ImageLut[%03d] = %d\n",i,lutEntries[i]);
    }
#endif

    if(numEntries < 1 || numEntries > MAX_IMAGE_LUT_ENTRIES)
        return -1;

    DLPC350_OpenMailbox(1);
    DLPC350_MailboxSetAddr(0);

    // Check for special case of 2 entries
    if( numEntries == 2)
    {
        msg.text.data[2+0] = lutEntries[1];
        msg.text.data[2+1] = lutEntries[0];
    }
    else
    {
        for(i=0; i < numEntries; i++)
        {
            msg.text.data[2+i] = lutEntries[i];
        }
    }

    CmdList[MBOX_DATA].len = numEntries;
    DLPC350_PrepWriteCmd(&msg, MBOX_DATA);
    bytes_sent = DLPC350_SendMsg(&msg,true);
    DLPC350_CloseMailbox();

    return bytes_sent;
}

int DLPC350_GetPatLut(int numEntries)
/**
 * (I2C: 0x78)
 * (USB: CMD2: 0x1A, CMD3: 0x34)
 * This API reads the pattern LUT from the DLPC350 controller and stores it in the local array.
 * The pattern LUT entries could be queried using the API DLPC350_GetPatLutItem().
 *
 * @param   numEntries - I - Number of entries expected in pattern LUT.
 *
 * @return  number of bytes actually read from the controller LUT.
 *
 */
{
    hidMessageStruct msg;
    unsigned int lutWord = 0;
    int numBytes, i;
    unsigned char *readBuf;

    if(numEntries > 128)
        return -1;

    if(DLPC350_OpenMailbox(2) < 0)
        return -1;

    if(DLPC350_MailboxSetAddr(0) < 0)
        return -1;

    numBytes = sizeof(msg.head)+numEntries*3;
    readBuf = (unsigned char *)&msg;
    DLPC350_PrepReadCmd(MBOX_DATA);


    if(DLPC350_Read() > 0)
    {
        memcpy(readBuf, g_InputBuffer, MIN(numBytes,64));
        readBuf+=64;
        numBytes -=64;
    }
    else
    {
        DLPC350_CloseMailbox();
        return -1;
    }
    /* If packet is greater than 64 bytes, continue to read */
    while(numBytes > 0)
    {
        if(DLPC350_ContinueRead() < 0)
            return -1;
        memcpy(readBuf, g_InputBuffer, MIN(numBytes,64));
        readBuf+=64;
        numBytes -=64;
    }

    DLPC350_ClearPatLut();

    for(i=0; i<numEntries*3; i+=3)
    {
        lutWord = msg.text.data[i] | msg.text.data[i+1] << 8 | msg.text.data[i+2] << 16;
        g_PatLut[g_PatLutIndex++] = lutWord;
    }

    if(DLPC350_CloseMailbox() < 0)
        return -1;

#if 0
    printf("PatLut Receive\n");
    for(unsigned i=0;i<g_PatLutIndex;i++)
    {
        printf("PatLut[%03d] = 0x%X\n",i,g_PatLut[i]);
    }
#endif

    return (int)msg.head.length;
}

int DLPC350_GetVarExpPatLut(int numEntries)
/**
 * (I2C: 0x5D)
 * (USB: CMD2: 0x1A, CMD3: 0x3E)
 * This API reads the pattern LUT from the DLPC350 controller and stores it in the local array.
 * The pattern LUT entries could be queried using the API DLPC350_GetVarExpPatLutItem().
 *
 * @param   numEntries - I - Number of entries expected in pattern LUT.
 *
 * @return  0 = PASS   <BR>
 *          -1 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;
    int numBytes, i;
    unsigned char *readBuf;
    int numLutEntrRead = 0;

    if(numEntries > MAX_VAR_EXP_PAT_LUT_ENTRIES)
        return -1;

    if(DLPC350_OpenMailbox(3) < 0)
        return -1;

    DLPC350_ClearExpLut();

    i = 0;
    readBuf = (unsigned char *)&msg;
    numBytes = sizeof(msg.head)+12;
    do
    {
        if(DLPC350_SetVarExpMboxAddr(i) < 0)
            return -1;

        DLPC350_PrepReadCmd(MBOX_EXP_DATA);

        if(DLPC350_Read() > 0)
        {
            memcpy(readBuf, g_InputBuffer, numBytes);
            g_ExpLut[g_ExpLutIndex++] = (msg.text.data[0] | msg.text.data[1] << 8 | msg.text.data[2] << 16 | msg.text.data[3] << 24);
            g_ExpLut[g_ExpLutIndex++] = (msg.text.data[4] | msg.text.data[5] << 8 | msg.text.data[6] << 16 | msg.text.data[7] << 24); //Pattern Exposure
            g_ExpLut[g_ExpLutIndex++] = (msg.text.data[8] | msg.text.data[9] << 8 | msg.text.data[10] << 16 | msg.text.data[11] << 24);; //Total Pattern Period
            numLutEntrRead++;
        }

        if(numLutEntrRead == numEntries)
        {
            break;
        }
        else
        {
            i++;
        }

    }while(1);

    if(DLPC350_CloseMailbox() < 0)
        return -1;

#if 0
    printf("VarExpPatLut Receive\n");
    for(unsigned i=0;i<g_ExpLutIndex;i++)
    {
        printf("varExpPatLut[%04d] = 0x%X\n",i,g_ExpLut[i]);
    }
#endif

    return 0;
}


int DLPC350_GetImageLut(unsigned char *pLut, int numEntries)
/**
 * (I2C: 0x78)
 * (USB: CMD2: 0x1A, CMD3: 0x34)
 * This API reads the image LUT from the DLPC350 controller.
 *
 * @param   *pLut - I - Pointer to the array in which the read entries should be stored
 *
 * @param   numEntries - I - Number of image LUT entries to be read from the controller
 *
 * @return  0 = PASS    <BR>
 *          -1 = FAIL  <BR>
 *
 */
{
    int retval;

    if(DLPC350_OpenMailbox(1) < 0)
        return -1;

    if(DLPC350_MailboxSetAddr(0) < 0)
        return -1;

    DLPC350_PrepReadCmd(MBOX_DATA);

    if((retval = DLPC350_Read()) > 0)
    {
        hidMessageStruct *pMsg = (hidMessageStruct *)g_InputBuffer;
        if(pMsg != NULL)
        {
            memcpy(pLut, g_InputBuffer+sizeof(pMsg->head), MIN((unsigned int)numEntries,64-sizeof(pMsg->head)));
            pLut+= (64-sizeof(pMsg->head));
            numEntries -= (64-sizeof(pMsg->head));
        }
    }
    else
    {
        DLPC350_CloseMailbox();
        return retval;
    }

    /* If packet is greater than 64 bytes, continue to read */
    while(numEntries > 0)
    {
        DLPC350_ContinueRead();
        memcpy(pLut, g_InputBuffer, MIN(numEntries,64));
        pLut+=64;
        numEntries -= 64;
    }

    if(DLPC350_CloseMailbox() < 0)
        return -1;

    return 0;
}

int DLPC350_GetvarExpImageLut(unsigned char *pLut, int numEntries)
/**
 * (I2C: 0x78)
 * (USB: CMD2: 0x1A, CMD3: 0x34)
 * This API reads the image LUT from the DLPC350 controller.
 *
 * @param   *pLut - I - Pointer to the array in which the read entries should be stored
 *
 * @param   numEntries - I - Number of image LUT entries to be read from the controller
 *
 * @return  0 = PASS    <BR>
 *          -1 = FAIL  <BR>
 *
 */
{
    int retval;

    if(DLPC350_OpenMailbox(1) < 0)
        return -1;

    if(DLPC350_SetVarExpMboxAddr(0) < 0)
        return -1;

    DLPC350_PrepReadCmd(MBOX_DATA);

    if((retval = DLPC350_Read()) > 0)
    {
        hidMessageStruct *pMsg = (hidMessageStruct *)g_InputBuffer;
        if(pMsg != NULL)
        {
            memcpy(pLut, g_InputBuffer+sizeof(pMsg->head), MIN((unsigned int)numEntries,64-sizeof(pMsg->head)));
            pLut+= (64-sizeof(pMsg->head));
            numEntries -= (64-sizeof(pMsg->head));
        }
    }
    else
    {
        DLPC350_CloseMailbox();
        return retval;
    }

    /* If packet is greater than 64 bytes, continue to read */
    while(numEntries > 0)
    {
        DLPC350_ContinueRead();
        memcpy(pLut, g_InputBuffer, MIN(numEntries,64));
        pLut+=64;
        numEntries -= 64;
    }

    if(DLPC350_CloseMailbox() < 0)
        return -1;

    return 0;
}

int DLPC350_SetPatternTriggerMode(int trigMode)
/**
 * The Pattern Trigger Mode Selection command selects between one of the three pattern Trigger Modes.
 * Before executing this command, stop the current pattern sequence. After executing this command, send
 * the Validation command (I2C: 0x7D or USB: 0x1A1A) once before starting the pattern sequence.
 *
 * @param   trigMode  - I - 0 = Pattern Trigger Mode 0: VSYNC serves to trigger the pattern display sequence.
 *                          1 = Pattern Trigger Mode 1: Internally or Externally (through TRIG_IN1 and TRIG_IN2) generated trigger.
 *                          2 = Pattern Trigger Mode 2: TRIG_IN_1 alternates between two patterns,while TRIG_IN_2 advances to the next pair of patterns.
 *                          3 = Pattern Trigger Mode 3: Internally or externally generated trigger for Variable Exposure display sequence.
 *                          4 = Pattern Trigger Mode 4: VSYNC triggered for Variable Exposure display sequence.
 * @return  0 = PASS    <BR>
 *          -1 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    msg.text.data[2] = trigMode;
    DLPC350_PrepWriteCmd(&msg, PAT_TRIG_MODE);

    return DLPC350_SendMsg(&msg,true);
}

int DLPC350_GetPatternTriggerMode(int *trigMode)
/**
 * The Pattern Trigger Mode Selection command selects between one of the three pattern Trigger Modes.
 *
 * @param   trigMode  - O - 0 = Pattern Trigger Mode 0: VSYNC serves to trigger the pattern display sequence.
 *                          1 = Pattern Trigger Mode 1: Internally or Externally (through TRIG_IN1 and TRIG_IN2) generated trigger.
 *                          2 = Pattern Trigger Mode 2: TRIG_IN_1 alternates between two patterns,while TRIG_IN_2 advances to the next pair of patterns.
 *                          3 = Pattern Trigger Mode 3: Internally or externally generated trigger for Variable Exposure display sequence.
 *                          4 = Pattern Trigger Mode 4: VSYNC triggered for Variable Exposure display sequence.
 *
 * @return  0 = PASS    <BR>
 *          -1 = FAIL  <BR>
 *
 */
{    hidMessageStruct msg;

     DLPC350_PrepReadCmd(PAT_TRIG_MODE);

      if(DLPC350_Read() > 0)
      {
          memcpy(&msg, g_InputBuffer, 65);
          *trigMode = (msg.text.data[0] & 0xFF);
          return 0;
      }
      return -1;
}


int DLPC350_PatternDisplay(unsigned int Action)
/**
 * (I2C: 0x65)
 * (USB: CMD2: 0x1A, CMD3: 0x24)
 * This API starts or stops the programmed patterns sequence.
 *
 * @param   Action - I - Pattern Display Start/Stop Pattern Sequence
 *                          0 = Stop Pattern Display Sequence. The next "Start" command will
 *                              restart the pattern sequence from the beginning.
 *                          1 = Pause Pattern Display Sequence. The next "Start" command will
 *                              start the pattern sequence by re-displaying the current pattern in the sequence.
 *                          2 = Start Pattern Display Sequence
 *
 * @return  >=0 = PASS    <BR>
 *          <0 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    msg.text.data[2] = (Action&0x03);
    DLPC350_PrepWriteCmd(&msg, PAT_START_STOP);

    return DLPC350_SendMsg(&msg,true);
}

int  DLPC350_GetPatternDisplay(unsigned int *pAction)
/**
 * (I2C: 0x65)
 * (USB: CMD2: 0x1A, CMD3: 0x24)
 * This API starts or stops the programmed patterns sequence.
 *
 * @param   *pAction - O - Returns the state of the Pattern Display
 *                          0 = Stop Pattern Display Sequence. The next "Start" command will
 *                              restart the pattern sequence from the beginning.
 *                          1 = Pause Pattern Display Sequence. The next "Start" command will
 *                              start the pattern sequence by re-displaying the current pattern in the sequence.
 *                          2 = Start Pattern Display Sequence
 *
 * @return  >=0 = PASS    <BR>
 *          <0 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

     DLPC350_PrepReadCmd(PAT_START_STOP);

      if(DLPC350_Read() > 0)
      {
          memcpy(&msg, g_InputBuffer, 65);
          *pAction = (msg.text.data[0] & 0xFF);
          return 0;
      }
      return -1;
}


int DLPC350_SetPatternConfig(unsigned int numLutEntries, bool repeat, unsigned int numPatsForTrigOut2, unsigned int numImages)
/**
 * (I2C: 0x75)
 * (USB: CMD2: 0x1A, CMD3: 0x31)
 * This API controls the execution of patterns stored in the lookup table.
 * Before using this API, stop the current pattern sequence using DLPC350_PatternDisplay() API
 * After calling this API, send the Validation command using the API DLPC350_ValidatePatLutData() before starting the pattern sequence
 *
 * @param   numLutEntries - I - Number of LUT entries
 * @param   repeat - I - 0 = execute the pattern sequence once; 1 = repeat the pattern sequnce.
 * @param   numPatsForTrigOut2 - I - Number of patterns to display(range 1 through 256).
 *                                   If in repeat mode, then this value dictates how often TRIG_OUT_2 is generated.
 * @param   numImages - I - Number of Image Index LUT Entries(range 1 through 64).
 *                          This Field is irrelevant for Pattern Display Data Input Source set to a value other than internal.
 *
 * @return  >=0 = PASS    <BR>
 *          <0 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    msg.text.data[2] = numLutEntries-1;         /* -1 because the firmware command takes 0-based indices (0 means 1) */
    msg.text.data[3] = repeat;
    msg.text.data[4] = numPatsForTrigOut2 - 1;  /* -1 because the firmware command takes 0-based indices (0 means 1) */
    msg.text.data[5] = numImages - 1;           /* -1 because the firmware command takes 0-based indices (0 means 1) */
    DLPC350_PrepWriteCmd(&msg, PAT_CONFIG);

    return DLPC350_SendMsg(&msg,true);
}

int DLPC350_SetVarExpPatternConfig(unsigned int numLutEntries, unsigned int numPatsForTrigOut2, unsigned int numImages, bool repeat)
/**
 * (I2C: 0x5B)
 * (USB: CMD2: 0x1A, CMD3: 0x40)
 * This API controls the execution of patterns stored in the lookup table.
 * Before using this API, stop the current pattern sequence using DLPC350_PatternDisplay() API
 * After calling this API, send the Validation command using the API DLPC350_ValidatePatLutData() before starting the pattern sequence
 *
 * @param   numLutEntries - I - Number of LUT entries
 * @param   repeat - I - 0 = execute the pattern sequence once; 1 = repeat the pattern sequnce.
 * @param   numPatsForTrigOut2 - I - Number of patterns to display(range 1 through 256).
 *                                   If in repeat mode, then this value dictates how often TRIG_OUT_2 is generated.
 * @param   numImages - I - Number of Image Index LUT Entries(range 1 through 64).
 *                          This Field is irrelevant for Pattern Display Data Input Source set to a value other than internal.
 *
 * @return  >=0 = PASS    <BR>
 *          <0 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    msg.text.data[2] = numLutEntries-1;             /* -1 because the firmware command takes 0-based indices (0 means 1) */
    msg.text.data[3] = (numLutEntries-1)>>8;
    msg.text.data[4] = numPatsForTrigOut2 - 1;      /* -1 because the firmware command takes 0-based indices (0 means 1) */
    msg.text.data[5] = (numPatsForTrigOut2-1)>>8;
    msg.text.data[6] = (numImages - 1) & 0xFF;               /* -1 because the firmware command takes 0-based indices (0 means 1) */
    (repeat == true) ? (msg.text.data[7] = 0x01) : (msg.text.data[7] = 0x00);
    DLPC350_PrepWriteCmd(&msg, EXP_PAT_CONFIG);

    return DLPC350_SendMsg(&msg,true);
}

int DLPC350_GetVarExpPatternConfig(unsigned int *pNumLutEntries, unsigned int *pNumPatsForTrigOut2, unsigned int *pNumImages,  bool *pRepeat)
/**
 * (I2C: 0x5B)
 * (USB: CMD2: 0x1A, CMD3: 0x40)
 * This API controls the execution of patterns stored in the lookup table.
 * Before using this API, stop the current pattern sequence using DLPC350_PatternDisplay() API
 * After calling this API, send the Validation command using the API DLPC350_ValidatePatLutData() before starting the pattern sequence
 *
 * @param   numLutEntries - I - Number of LUT entries
 * @param   repeat - I - 0 = execute the pattern sequence once; 1 = repeat the pattern sequnce.
 * @param   numPatsForTrigOut2 - I - Number of patterns to display(range 1 through 256).
 *                                   If in repeat mode, then this value dictates how often TRIG_OUT_2 is generated.
 * @param   numImages - I - Number of Image Index LUT Entries(range 1 through 64).
 *                          This Field is irrelevant for Pattern Display Data Input Source set to a value other than internal.
 *
 * @return  >=0 = PASS    <BR>
 *          <0 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    DLPC350_PrepReadCmd(EXP_PAT_CONFIG);

    if(DLPC350_Read() > 0)
    {
        memcpy(&msg, g_InputBuffer, 65);
        *pNumLutEntries = ((unsigned int)msg.text.data[1] << 8) + msg.text.data[0] + 1; /* +1 because the firmware gives 0-based indices (0 means 1) */
        *pNumPatsForTrigOut2 = ((unsigned int)msg.text.data[3] << 8) + msg.text.data[2] + 1; /* +1 because the firmware gives 0-based indices (0 means 1) */
        *pNumImages = msg.text.data[4]+1;     /* +1 because the firmware gives 0-based indices (0 means 1) */
        *pRepeat = (msg.text.data[5] != 0);
        return 0;
    }
    return -1;
}

int DLPC350_GetPatternConfig(unsigned int *pNumLutEntries, bool *pRepeat, unsigned int *pNumPatsForTrigOut2, unsigned int *pNumImages)
/**
 * (I2C: 0x75)
 * (USB: CMD2: 0x1A, CMD3: 0x31)
 * This API controls the execution of patterns stored in the lookup table.
 * Before using this API, stop the current pattern sequence using DLPC350_PatternDisplay() API
 * After calling this API, send the Validation command using the API DLPC350_ValidatePatLutData() before starting the pattern sequence
 *
 * @param   *pNumLutEntries - O - Number of LUT entries
 * @param   *pRepeat - O - 0 = execute the pattern sequence once; 1 = repeat the pattern sequnce.
 * @param   *pNumPatsForTrigOut2 - O - Number of patterns to display(range 1 through 256).
 *                                   If in repeat mode, then this value dictates how often TRIG_OUT_2 is generated.
 * @param   *pNumImages - O - Number of Image Index LUT Entries(range 1 through 64).
 *                          This Field is irrelevant for Pattern Display Data Input Source set to a value other than internal.
 *
 * @return  0 = PASS    <BR>
 *          -1 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    DLPC350_PrepReadCmd(PAT_CONFIG);

    if(DLPC350_Read() > 0)
    {
        memcpy(&msg, g_InputBuffer, 65);
        *pNumLutEntries = msg.text.data[0] + 1; /* +1 because the firmware gives 0-based indices (0 means 1) */
        *pRepeat = (msg.text.data[1] != 0);
        *pNumPatsForTrigOut2 = msg.text.data[2]+1;    /* +1 because the firmware gives 0-based indices (0 means 1) */
        *pNumImages = msg.text.data[3]+1;     /* +1 because the firmware gives 0-based indices (0 means 1) */
        return 0;
    }
    return -1;
}

int DLPC350_SetExposure_FramePeriod(unsigned int exposurePeriod, unsigned int framePeriod)
/**
 * (I2C: 0x66)
 * (USB: CMD2: 0x1A, CMD3: 0x29)
 * The Pattern Display Exposure and Frame Period dictates the time a pattern is exposed and the frame
 * period. Either the exposure time must be equivalent to the frame period, or the exposure time must be
 * less than the frame period by 230 microseconds. Before executing this command, stop the current pattern
 * sequence. After executing this command, call DLPC350_ValidatePatLutData() API before starting the pattern sequence.
 *
 * @param   exposurePeriod - I - Exposure time in microseconds.
 * @param   framePeriod - I - Frame period in microseconds.
 *
 * @return  >=0 = PASS    <BR>
 *          <0 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    msg.text.data[2] = exposurePeriod;
    msg.text.data[3] = exposurePeriod>>8;
    msg.text.data[4] = exposurePeriod>>16;
    msg.text.data[5] = exposurePeriod>>24;
    msg.text.data[6] = framePeriod;
    msg.text.data[7] = framePeriod>>8;
    msg.text.data[8] = framePeriod>>16;
    msg.text.data[9] = framePeriod>>24;
    DLPC350_PrepWriteCmd(&msg, PAT_EXPO_PRD);

    return DLPC350_SendMsg(&msg,true);
}

int DLPC350_GetExposure_FramePeriod(unsigned int *pExposure, unsigned int *pFramePeriod)
/**
 * (I2C: 0x66)
 * (USB: CMD2: 0x1A, CMD3: 0x29)
 * This API reads back the exposure time and frame period settings from the controller.
 *
 * @param   exposurePeriod - O - Exposure time in microseconds.
 * @param   framePeriod - O - Frame period in microseconds.
 *
 * @return  0 = PASS    <BR>
 *          -1 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    DLPC350_PrepReadCmd(PAT_EXPO_PRD);

    if(DLPC350_Read() > 0)
    {
        memcpy(&msg, g_InputBuffer, 65);
        *pExposure = msg.text.data[0] | msg.text.data[1] << 8 | msg.text.data[2] << 16 | msg.text.data[3] << 24;
        *pFramePeriod = msg.text.data[4] | msg.text.data[5] << 8 | msg.text.data[6] << 16 | msg.text.data[7] << 24;
        return 0;
    }
    return -1;
}


int DLPC350_SetTrigOutConfig(unsigned int trigOutNum, bool invert, unsigned int rising, unsigned int falling)
/**
 * (I2C: 0x6A)
 * (USB: CMD2: 0x1A, CMD3: 0x1D)
 * This API sets the polarity, rising edge delay, and falling edge delay of the DLPC350's TRIG_OUT_1 or TRIG_OUT_2 signal.
 * The delays are compared to when the pattern is displayed on the DMD. Before executing this command,
 * stop the current pattern sequence. After executing this command, call DLPC350_ValidatePatLutData() API before starting the pattern sequence.
 *
 * @param   trigOutNum - I - 1 = TRIG_OUT_1; 2 = TRIG_OUT_2
 * @param   invert - I - 0 = active High signal; 1 = Active Low signal
 * @param   rising - I - rising edge delay control. Each bit adds 107.2 ns
 *                      0x00 = -20.05 μs, 0x01 = -19.9428 μs, ......0xBB=0.00 μs, ......, 0xD4 = +2.68 μs, 0xD5 = +2.787 μs
 * @param   falling- I - falling edge delay control. Each bit adds 107.2 ns (This field is not applcable for TRIG_OUT_2)
 *                      0x00 = -20.05 μs, 0x01 = -19.9428 μs, ......0xBB=0.00 μs, ......, 0xD4 = +2.68 μs, 0xD5 = +2.787 μs
 *
 * @return  >=0 = PASS    <BR>
 *          <0 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    if(trigOutNum == 1)
    {
        msg.text.data[2] = invert;
        msg.text.data[3] = rising;
        msg.text.data[4] = falling;
        DLPC350_PrepWriteCmd(&msg, TRIG_OUT1_CTL);
    }
    else if(trigOutNum==2)
    {
        msg.text.data[2] = invert;
        msg.text.data[3] = rising;
        DLPC350_PrepWriteCmd(&msg, TRIG_OUT2_CTL);
    }
    else
        return -1;

    return DLPC350_SendMsg(&msg,true);
}

int DLPC350_GetTrigOutConfig(unsigned int trigOutNum, bool *pInvert,unsigned int *pRising, unsigned int *pFalling)
/**
 * (I2C: 0x6A)
 * (USB: CMD2: 0x1A, CMD3: 0x1D)
 * This API readsback the polarity, rising edge delay, and falling edge delay of the DLPC350's TRIG_OUT_1 or TRIG_OUT_2 signal.
 * The delays are compared to when the pattern is displayed on the DMD.
 *
 * @param   trigOutNum - I - 1 = TRIG_OUT_1; 2 = TRIG_OUT_2
 * @param   *pInvert - O - 0 = active High signal; 1 = Active Low signal
 * @param   *pRising - O - rising edge delay control. Each bit adds 107.2 ns
 *                      0x00 = -20.05 μs, 0x01 = -19.9428 μs, ......0xBB=0.00 μs, ......, 0xD4 = +2.68 μs, 0xD5 = +2.787 μs
 * @param   *pFalling- O - falling edge delay control. Each bit adds 107.2 ns (This field is not applcable for TRIG_OUT_2)
 *                      0x00 = -20.05 μs, 0x01 = -19.9428 μs, ......0xBB=0.00 μs, ......, 0xD4 = +2.68 μs, 0xD5 = +2.787 μs
 *
 * @return  0 = PASS    <BR>
 *          -1 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    if(trigOutNum == 1)
        DLPC350_PrepReadCmd(TRIG_OUT1_CTL);
    else if(trigOutNum==2)
        DLPC350_PrepReadCmd(TRIG_OUT2_CTL);
    else
        return -1;

    if(DLPC350_Read() > 0)
    {
        memcpy(&msg, g_InputBuffer, 65);
        if(trigOutNum == 1)
        {
            *pInvert = (msg.text.data[0] != 0);
            *pRising = msg.text.data[1];
            *pFalling = msg.text.data[2];
        }
        else
        {
            *pInvert = (msg.text.data[0] != 0);
            *pRising = msg.text.data[1];
            *pFalling = 0;
        }

        return 0;
    }
    return -1;
}


int DLPC350_ValidatePatLutData(unsigned int *pStatus)
{
    hidMessageStruct msg;

    DLPC350_PrepWriteCmd(&msg, LUT_VALID);
    if(DLPC350_SendMsg(&msg,true) < 0)
        return -1;

    DLPC350_PrepReadCmd(LUT_VALID);

    //Poll for completion of validation
    do
    {
        if(DLPC350_Read() > 0)
        {
            memcpy(&msg, g_InputBuffer, 65);
            if(((uint8)msg.text.data[0]&0x80) == 0)
            {
                *pStatus = msg.text.data[0];
                break;
            }
            else
            {
                continue;
            }
        }
        else
            return -1;

    } while(1);

    return 0;
}


int DLPC350_StartPatLutValidate()
/**
 * (I2C: 0x7D)
 * (USB: CMD2: 0x1A, CMD3: 0x1A)
 * This API checks the programmed pattern display modes and indicates any invalid settings.
 * This command needs to be executed after all pattern display configurations have been completed.
 *
 * @param   *pStatus - O
 *                      BIT0 = Validity of exposure or frame period settings
 *                             1 = Selected exposure or frame period settings are invalid
 *                             0 =Selected exposure or frame period settings are valid
 *                      BIT1 = Validity of pattern numbers in lookup table (LUT)
 *                             1 = Selected pattern numbers in LUT are invalid
 *                             0 = Selected pattern numbers in LUT are valid
 *                      BIT2 = Status of Trigger Out1
 *                             1 = Warning, continuous Trigger Out1 request or overlapping black sectors
 *                             0 = Trigger Out1 settings are valid
 *                      BIT3 = Status of post sector settings
 *                             1 = Warning, post vector was not inserted prior to external triggered vector
 *                             0 = Post vector settings are valid
 *                      BIT4 = Status of frame period and exposure difference
 *                             1 = Warning, frame period or exposure difference is less than 230usec
 *                             0 = Frame period or exposure difference is valid
 *
 * @return  0 = PASS    <BR>
 *          -1 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    DLPC350_PrepWriteCmd(&msg, LUT_VALID);
    if(DLPC350_SendMsg(&msg,true) < 0)
        return -1;

    //    DLPC350_PrepReadCmd(LUT_VALID);

    //    //Poll for completion of validation
    //    do
    //    {
    //        if(DLPC350_Read() > 0)
    //        {
    //            memcpy(&msg, InputBuffer, 65);
    //            if(((uint8)msg.text.data[0]&0x80) == 0)
    //            {
    //                *pStatus = msg.text.data[0];
    //                break;
    //            }
    //            else
    //                continue;
    //        }
    //        else{
    //            return -1;
    //        }
    //    } while(1);

    return 0;
}


int DLPC350_CheckPatLutValidate(bool *ready, unsigned int *pStatus)
/**
 * (I2C: 0x7D)
 * (USB: CMD2: 0x1A, CMD3: 0x1A)
 * This API checks the programmed pattern display modes and indicates any invalid settings.
 * This command needs to be executed after all pattern display configurations have been completed.
 *
 * @param   *pStatus - O
 *                      BIT0 = Validity of exposure or frame period settings
 *                             1 = Selected exposure or frame period settings are invalid
 *                             0 =Selected exposure or frame period settings are valid
 *                      BIT1 = Validity of pattern numbers in lookup table (LUT)
 *                             1 = Selected pattern numbers in LUT are invalid
 *                             0 = Selected pattern numbers in LUT are valid
 *                      BIT2 = Status of Trigger Out1
 *                             1 = Warning, continuous Trigger Out1 request or overlapping black sectors
 *                             0 = Trigger Out1 settings are valid
 *                      BIT3 = Status of post sector settings
 *                             1 = Warning, post vector was not inserted prior to external triggered vector
 *                             0 = Post vector settings are valid
 *                      BIT4 = Status of frame period and exposure difference
 *                             1 = Warning, frame period or exposure difference is less than 230usec
 *                             0 = Frame period or exposure difference is valid
 *
 * @return  0 = PASS    <BR>
 *          -1 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    DLPC350_PrepReadCmd(LUT_VALID);

    if(DLPC350_Read() > 0)
    {
        memcpy(&msg, g_InputBuffer, 65);
        if(((uint8)msg.text.data[0]&0x80) == 0)
        {
            *pStatus = msg.text.data[0];
            *ready = true;
        }
        else
        {
            *ready = false;
        }
    }
    else{
        return -1;
    }


    return 0;
}

int DLPC350_SetTrigIn1Delay(unsigned int Delay)
/**
 * (I2C: 0x79)
 * (USB: CMD2: 0x1A, CMD3: 0x35)
 * This API sets the rising edge delay of the DLPC350's TRIG_OUT_1 signal compared to when the pattern is displayed on the DMD.
 * The polarity of TRIG_IN_1 is set in the lookup table of the pattern sequence.Before executing this command,
 * stop the current pattern sequence. After executing this command, call DLPC350_ValidatePatLutData() API before starting the pattern sequence.
 *
 * @param   Delay - I - rising edge delay control. 0=0ns. Each bit adds 107.2 ns
 *
 * @return  >=0 = PASS    <BR>
 *          <0 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    //BIT18:0 is Valid data
    Delay &= 0x7FFFF;

    msg.text.data[2] = Delay;
    msg.text.data[3] = Delay >> 8;
    msg.text.data[4] = Delay >> 16;
    msg.text.data[5] = Delay >> 24;
    DLPC350_PrepWriteCmd(&msg, TRIG_IN1_DELAY);

    return DLPC350_SendMsg(&msg,true);
}

int DLPC350_GetTrigIn1Delay(unsigned int *pDelay)
/**
 * (I2C: 0x79)
 * (USB: CMD2: 0x1A, CMD3: 0x35)
 * This API reads back the rising edge delay of the DLPC350's TRIG_OUT_1 signal compared to when the pattern is displayed on the DMD.
 *
 * @param   *pDelay - O - rising edge delay control. 0=0ns. Each bit adds 107.2 ns
 *
 * @return  0 = PASS    <BR>
 *          -1 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    DLPC350_PrepReadCmd(TRIG_IN1_DELAY);

    if(DLPC350_Read() > 0)
    {
        memcpy(&msg, g_InputBuffer, 65);
        *pDelay = msg.text.data[0] | msg.text.data[1]<<8 | msg.text.data[2]<<16 | msg.text.data[3]<<24;
        return 0;
    }
    return -1;
}

int  DLPC350_SetTrigIn2Pol(bool isFallingEdge)
/**
 * (I2C: 0x7A)
 * (USB: CMD2: 0x1A, CMD3: 0x36)
 * This API sets the TRIG_IN_2 intepreation for pattern advancement.It can be configured to advace on raising or falling edge.
 * Before executing this command,stop the current pattern sequence. After executing this command, call DLPC350_ValidatePatLutData() API before starting the pattern sequence.
 * NOTE: This option is applicable only in Trigger Mode = 2.
 * @param   isFallingEdge - I - TRUE  - Advance pattern on falling edge
 *                              FALSE - Advance pattern on rising edge
 *
 * @return  >=0 = PASS    <BR>
 *          <0 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    if(isFallingEdge)
        msg.text.data[2] = 0x01;
    else
        msg.text.data[2] = 0x00;

    DLPC350_PrepWriteCmd(&msg, TRIG_IN2_CONTROL);

    return DLPC350_SendMsg(&msg,true);
}

int  DLPC350_GetTrigIn2Pol(bool *pIsFallingEdge)
/**
 * (I2C: 0x7A)
 * (USB: CMD2: 0x1A, CMD3: 0x36)
 * This API reads back the rising/falling edge configuration setting for advacing the pattern.
 *
 * @param   *pIsFallingEdge - O - TRUE: Falling edge
 *                                FALSE: Rising edge
 *
 * @return  0 = PASS    <BR>
 *          -1 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    DLPC350_PrepReadCmd(TRIG_IN2_CONTROL);

    if(DLPC350_Read() > 0)
    {
        memcpy(&msg, g_InputBuffer, 65);
        if(msg.text.data[0])
        {
            *pIsFallingEdge = true;
        }
        else
        {
            *pIsFallingEdge = false;
        }
        return 0;
    }
    return -1;
}



int DLPC350_SetInvertData(bool invert)
/**
 * (I2C: 0x74)
 * (USB: CMD2: 0x1A, CMD3: 0x30)
 * This API dictates how the DLPC350 interprets a value of 0 or 1 to control mirror position for displayed patterns.
 * Before executing this command, stop the current pattern sequence. After executing this command, call
 * DLPC350_ValidatePatLutData() API before starting the pattern sequence.
 *
 * @param   invert - I - Pattern Display Invert Data
 *                      0 = Normal operation. A data value of 1 will flip the mirror to output light,
 *                          while a data value of 0 will flip the mirror to block light
 *                      1 = Inverted operation. A data value of 0 will flip the mirror to output light,
 *                          while a data value of 1 will flip the mirror to block light
 *
 * @return  >=0 = PASS    <BR>
 *          <0 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    msg.text.data[2] = invert;
    DLPC350_PrepWriteCmd(&msg, INVERT_DATA);

    return DLPC350_SendMsg(&msg,true);
}

int DLPC350_SetPWMConfig(unsigned int channel, unsigned int pulsePeriod, unsigned int dutyCycle)
/**
 * (I2C: 0x41)
 * (USB: CMD2: 0x1A, CMD3: 0x11)
 * This API sets the clock period and duty cycle of the specified PWM channel. The PWM
 * frequency and duty cycle is derived from an internal 18.67MHz clock. To calculate the desired PWM
 * period, divide the desired clock frequency from the internal 18.67Mhz clock. For example, a PWM
 * frequency of 2kHz, requires pulse period to be set to 18666667 / 2000 = 9333.
 *
 * @param   channel - I - PWM Channel Select
 *                      0 - PWM channel 0 (GPIO_0)
 *                      1 - Reserved
 *                      2 - PWM channel 2 (GPIO_2)
 *
 * @param   pulsePeriod - I - Clock Period in increments of 53.57ns. Clock Period = (value + 1) * 53.5ns
 *
 * @param   dutyCycle - I - Duty Cycle = (value + 1)% Value range is 1%-99%
 *
 * @return  >=0 = PASS    <BR>
 *          <0 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    msg.text.data[2] = channel;
    msg.text.data[3] = pulsePeriod;
    msg.text.data[4] = pulsePeriod >> 8;
    msg.text.data[5] = pulsePeriod >> 16;
    msg.text.data[6] = pulsePeriod >> 24;
    msg.text.data[7] = dutyCycle;

    DLPC350_PrepWriteCmd(&msg, PWM_SETUP);

    return DLPC350_SendMsg(&msg,true);
}

int DLPC350_GetPWMConfig(unsigned int channel, unsigned int *pPulsePeriod, unsigned int *pDutyCycle)
/**
 * (I2C: 0x41)
 * (USB: CMD2: 0x1A, CMD3: 0x11)
 * This API reads back the clock period and duty cycle of the specified PWM channel. The PWM
 * frequency and duty cycle is derived from an internal 18.67MHz clock. To calculate the desired PWM
 * period, divide the desired clock frequency from the internal 18.67Mhz clock. For example, a PWM
 * frequency of 2kHz, requires pulse period to be set to 18666667 / 2000 = 9333.
 *
 * @param   channel - I - PWM Channel Select
 *                      0 - PWM channel 0 (GPIO_0)
 *                      1 - Reserved
 *                      2 - PWM channel 2 (GPIO_2)
 *
 * @param   *pPulsePeriod - O - Clock Period in increments of 53.57ns. Clock Period = (value + 1) * 53.5ns
 *
 * @param   *pDutyCycle - O - Duty Cycle = (value + 1)% Value range is 1%-99%
 *
 * @return  0 = PASS    <BR>
 *          -1 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    DLPC350_PrepReadCmdWithParam(PWM_SETUP, (unsigned char)channel);
    if(DLPC350_Read() > 0)
    {
        memcpy(&msg, g_InputBuffer, 65);
        *pPulsePeriod = msg.text.data[1] | msg.text.data[2] << 8 | msg.text.data[3] << 16 | msg.text.data[4] << 24;
        *pDutyCycle = msg.text.data[5];
        return 0;
    }
    return -1;
}

int DLPC350_SetPWMEnable(unsigned int channel, bool Enable)
/**
 * (I2C: 0x40)
 * (USB: CMD2: 0x1A, CMD3: 0x10)
 * After the PWM Setup command configures the clock period and duty cycle, the PWM Enable command
 * activates the PWM signals.
 *
 * @param   channel - I - PWM Channel Select
 *                      0 - PWM channel 0 (GPIO_0)
 *                      1 - Reserved
 *                      2 - PWM channel 2 (GPIO_2)
 *
 * @param   Enable - I - PWM Channel enable 0=disable; 1=enable
 *
 * @return  >=0 = PASS    <BR>
 *          <0 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;
    unsigned char value = 0;

    if(Enable)
        value = BIT7;

    if(channel == 2)
        value |= 2;
    else if (channel != 0)
        return -1;

    msg.text.data[2] = value;
    DLPC350_PrepWriteCmd(&msg, PWM_ENABLE);

    return DLPC350_SendMsg(&msg,true);
}

int DLPC350_GetPWMEnable(unsigned int channel, bool *pEnable)
/**
 * (I2C: 0x40)
 * (USB: CMD2: 0x1A, CMD3: 0x10)
 * Reads back the enabled/disabled status of the given PWM channel.
 *
 * @param   channel - I - PWM Channel Select
 *                      0 - PWM channel 0 (GPIO_0)
 *                      1 - Reserved
 *                      2 - PWM channel 2 (GPIO_2)
 *
 * @param   *pEnable - O - PWM Channel enable 0=disable; 1=enable
 *
 * @return  0 = PASS    <BR>
 *          -1 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    DLPC350_PrepReadCmdWithParam(PWM_ENABLE, (unsigned char)channel);

    if(DLPC350_Read() > 0)
    {
        memcpy(&msg, g_InputBuffer, 65);
        if(msg.text.data[0] & BIT7)
            *pEnable =  true;
        else
            *pEnable = false;

        return 0;
    }
    return -1;
}

int DLPC350_SetPWMCaptureConfig(unsigned int channel, bool enable, unsigned int sampleRate)
/**
 * (I2C: 0x43)
 * (USB: CMD2: 0x1A, CMD3: 0x12)
 * This API samples the specified PWM input signals and returns the PWM clock period.
 *
 * @param   channel - I - PWM Capture Port
 *                      0 - PWM input channel 0 (GPIO_5)
 *                      1 - PWM input channel 1 (GPIO_6)
 *
 * @param   enable - I - PWM Channel enable 0=disable; 1=enable
 *
 * @param   sampleRate - I - PWM Sample Rate (285 Hz to 18,666,667 Hz) - Sample Rate = Pulse Frequency / Duty Cycle
 *
 * @return  >=0 = PASS    <BR>
 *          <0 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;
    unsigned char value = 0;

    value = channel & 1;

    if(enable)
        value |= BIT7;

    msg.text.data[2] = value;
    msg.text.data[3] = sampleRate;
    msg.text.data[4] = sampleRate >> 8;
    msg.text.data[5] = sampleRate >> 16;
    msg.text.data[6] = sampleRate >> 24;
    DLPC350_PrepWriteCmd(&msg, PWM_CAPTURE_CONFIG);

    return DLPC350_SendMsg(&msg,true);
}

int DLPC350_GetPWMCaptureConfig(unsigned int channel, bool *pEnabled, unsigned int *pSampleRate)
/**
 * (I2C: 0x43)
 * (USB: CMD2: 0x1A, CMD3: 0x12)
 * This API reads back the configuration of the specified PWM capture channel.
 *
 * @param   channel - I - PWM Capture Port
 *                      0 - PWM input channel 0 (GPIO_5)
 *                      1 - PWM input channel 1 (GPIO_6)
 *
 * @param   *pEnabled - O - PWM Channel enable 0=disable; 1=enable
 *
 * @param   *pSampleRate - O - PWM Sample Rate (285 Hz to 18,666,667 Hz) - Sample Rate = Pulse Frequency / Duty Cycle
 *
 * @return  >=0 = PASS    <BR>
 *          <0 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    DLPC350_PrepReadCmdWithParam(PWM_CAPTURE_CONFIG, (unsigned char)channel);

    if(DLPC350_Read() > 0)
    {
        memcpy(&msg, g_InputBuffer, 65);
        if(msg.text.data[0] & BIT7)
            *pEnabled =  true;
        else
            *pEnabled = false;

        *pSampleRate = msg.text.data[1] | msg.text.data[2] << 8 | msg.text.data[3] << 16 | msg.text.data[4] << 24;

        return 0;
    }
    return -1;
}

int DLPC350_PWMCaptureRead(unsigned int channel, unsigned int *pLowPeriod, unsigned int *pHighPeriod)
/**
 * (I2C: 0x4E)
 * (USB: CMD2: 0x1A, CMD3: 0x13)
 * This API returns both the number of clock cycles the signal was low and high.
 *
 * @param   channel - I - PWM Capture Port
 *                      0 - PWM input channel 0 (GPIO_5)
 *                      1 - PWM input channel 1 (GPIO_6)
 *
 * @param   *pLowPeriod - O - indicates how many samples were taken during a low signal
 *
 * @param   *pHighPeriod - O - indicates how many samples were taken during a high signal
 *
 * @return  0 = PASS    <BR>
 *          -1 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    DLPC350_PrepReadCmdWithParam(PWM_CAPTURE_READ, (unsigned char)channel);

    if(DLPC350_Read() > 0)
    {
        memcpy(&msg, g_InputBuffer, 65);
        *pLowPeriod = msg.text.data[1] | msg.text.data[2] << 8;
        *pHighPeriod = msg.text.data[3] | msg.text.data[4] << 8;
        return 0;
    }
    return -1;
}

int DLPC350_SetGPIOConfig(unsigned int pinNum, bool enAltFunc, bool altFunc1, bool dirOutput, bool outTypeOpenDrain, bool pinState)
/**
 * (I2C: 0x44)
 * (USB: CMD2: 0x1A, CMD3: 0x38)
 *
 * This API enables GPIO functionality on a specific set of DLPC350 pins. The
 * command sets their direction, output buffer type, and output state.
 *
 * @param   pinNum - I - GPIO selection. See Table 2-38 in the programmer's guide for description of available pins
 *
 * @param   enAltFunc - I - 0=disable alternative function; enable GPIO; 1=enable alternative function; disable GPIO
 *
 * @param   altFunc1 - I - must be set to false
 *
 * @param   dirOutput - I - 0=input; 1=output
 *
 * @param   outTypeOpenDrain - I - 0=Standard buffer (drives high or low); 1=open drain buffer (drives low only)
 *
 * @param   pinState - I - 0=LOW; 1=HIGH
 *
 * @return  >=0 = PASS    <BR>
 *          <0 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;
    unsigned char value = 0;

    if(enAltFunc)
        value |= BIT7;
    if(altFunc1)
        value |= BIT6;
    if(dirOutput)
        value |= BIT5;
    if(outTypeOpenDrain)
        value |= BIT4;
    if(pinState)
        value |= BIT3;

    msg.text.data[2] = pinNum;
    msg.text.data[3] = value;
    DLPC350_PrepWriteCmd(&msg, GPIO_CONFIG);

    return DLPC350_SendMsg(&msg,true);
}

int DLPC350_GetGPIOConfig(unsigned int pinNum, bool *pEnAltFunc, bool *pAltFunc1, bool *pDirOutput, bool *pOutTypeOpenDrain, bool *pState)
/**
 * (I2C: 0x44)
 * (USB: CMD2: 0x1A, CMD3: 0x38)
 *
 * This API reads back the GPIO configuration on a specific set of DLPC350 pins. The
 * command reads back their direction, output buffer type, and  state.
 *
 * @param   pinNum - I - GPIO selection. See Table 2-38 in the programmer's guide for description of available pins
 *
 * @param   *pEnAltFunc - O - 0=disable alternative function; enable GPIO; 1=enable alternative function; disable GPIO
 *
 * @param   *pAltFunc1 - O - must be set to false
 *
 * @param   *pDirOutput - O - 0=input; 1=output
 *
 * @param   *pOutTypeOpenDrain - O - 0=Standard buffer (drives high or low); 1=open drain buffer (drives low only)
 *
 * @param   *pState - O - 0=LOW; 1=HIGH
 *
 * @return  0 = PASS    <BR>
 *          -1 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    DLPC350_PrepReadCmdWithParam(GPIO_CONFIG, (unsigned char)pinNum);

    if(DLPC350_Read() > 0)
    {
        memcpy(&msg, g_InputBuffer, 65);
        *pEnAltFunc = ((msg.text.data[1] & BIT7) == BIT7);
        *pAltFunc1 = ((msg.text.data[1] & BIT6) == BIT6);
        *pDirOutput = ((msg.text.data[1] & BIT5) == BIT5);
        *pOutTypeOpenDrain = ((msg.text.data[1] & BIT4) == BIT4);
        if(*pDirOutput)
            *pState = ((msg.text.data[1] & BIT3) == BIT3);
        else
            *pState = ((msg.text.data[1] & BIT2) == BIT2);
        return 0;
    }
    return -1;
}

int DLPC350_SetGeneralPurposeClockOutFreq(unsigned int clkId, bool enable, unsigned int clkDivider)
/**
 * (I2C: 0x48)
 * (USB: CMD2: 0x08, CMD3: 0x07)
 *
 * DLPC350 supports two pins with clock output capabilities: GPIO_11 and GPIO_12.
 * This API enables the clock output functionality and sets the clock frequency.
 *
 * @param   clkId - I - Clock selection. 1=GPIO_11; 2=GPIO_12
 *
 * @param   enable - I - 0=disable clock functionality on selected pin; 1=enable clock functionality on selected pin
 *
 * @param   clkDivider - I - Allowed values in the range of 2 to 127. Output frequency = 96MHz / (Clock Divider)
 *
 * @return  >=0 = PASS    <BR>
 *          <0 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    msg.text.data[2] = clkId;
    msg.text.data[3] = enable;
    msg.text.data[4] = clkDivider;
    DLPC350_PrepWriteCmd(&msg, GPCLK_CONFIG);

    return DLPC350_SendMsg(&msg,true);
}

int DLPC350_GetGeneralPurposeClockOutFreq(unsigned int clkId, bool *pEnabled, unsigned int *pClkDivider)
/**
 * (I2C: 0x48)
 * (USB: CMD2: 0x08, CMD3: 0x07)
 *
 * DLPC350 supports two pins with clock output capabilities: GPIO_11 and GPIO_12.
 * This API reads back the clock output enabled status and the clock frequency.
 *
 * @param   clkId - I - Clock selection. 1=GPIO_11; 2=GPIO_12
 *
 * @param   *pEnabled - O - 0=disable clock functionality on selected pin; 1=enable clock functionality on selected pin
 *
 * @param   *pClkDivider - O - Allowed values in the range of 2 to 127. Output frequency = 96MHz / (Clock Divider)
 *
 * @return  >=0 = PASS    <BR>
 *          <0 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    DLPC350_PrepReadCmdWithParam(GPCLK_CONFIG, (unsigned char)clkId);

    if(DLPC350_Read() > 0)
    {
        memcpy(&msg, g_InputBuffer, 65);
        *pEnabled = (msg.text.data[0] != 0);
        *pClkDivider = msg.text.data[1];
        return 0;
    }
    return -1;
}

int DLPC350_SetLEDPWMInvert(bool invert)
/**
 * (I2C: 0x0B)
 * (USB: CMD2: 0x1A, CMD3: 0x05)
 *
 * This API sets the polarity of all LED PWM signals. This API must be called before powering up the LED drivers.
 *
 * @param   invert - I - 0 = Normal polarity, PWM 0 value corresponds to no current while PWM 255 value corresponds to maximum current
 *                       1 = Inverted polarity. PWM 0 value corresponds to maximum current while PWM 255 value corresponds to no current.
 *
 * @return  >=0 = PASS    <BR>
 *          <0 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    msg.text.data[2] = invert;
    DLPC350_PrepWriteCmd(&msg, PWM_INVERT);

    return DLPC350_SendMsg(&msg,true);
}

int DLPC350_GetLEDPWMInvert(bool *inverted)
/**
 * (I2C: 0x0B)
 * (USB: CMD2: 0x1A, CMD3: 0x05)
 *
 * This API reads the polarity of all LED PWM signals.
 *
 * @param   invert - O - 0 = Normal polarity, PWM 0 value corresponds to no current while PWM 255 value corresponds to maximum current
 *                       1 = Inverted polarity. PWM 0 value corresponds to maximum current while PWM 255 value corresponds to no current.
 *
 * @return  >=0 = PASS    <BR>
 *          <0 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    DLPC350_PrepReadCmd(PWM_INVERT);

    if(DLPC350_Read() > 0)
    {
        memcpy(&msg, g_InputBuffer, 65);
        *inverted = (msg.text.data[0] != 0);
        return 0;
    }
    return -1;
}

int DLPC350_MemRead(unsigned int addr, unsigned int *readWord)
/**
 *
 * This API reads back the content at a specified memory location from the controller.
 *
 * @param   addr - I - address from which to read contents
 *
 * @param   readWord - O - 32-bit word read from the given address
 *
 * @return  >=0 = PASS    <BR>
 *          <0 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    DLPC350_PrepMemReadCmd(addr);
    if(DLPC350_Read() > 0)
    {
        memcpy(&msg, g_InputBuffer, 65);
        *readWord = msg.text.data[0] | msg.text.data[1] << 8 | msg.text.data[2] << 16 | msg.text.data[3] << 24;
        //*readWord = msg.text.data[3] | msg.text.data[2] << 8 | msg.text.data[1] << 16 | msg.text.data[0] << 24; //MSB first
        return 0;
    }
    return -1;
}

int DLPC350_MemWrite(unsigned int addr, unsigned int data)
/**
 *
 * This API writes the given content at a specified memory location from the controller.
 *
 * @param   addr - I - address to write to
 *
 * @param   data - I - 32-bit word to be written at given address
 *
 * @return  >=0 = PASS    <BR>
 *          <0 = FAIL  <BR>
 *
 */
{
    hidMessageStruct msg;

    msg.text.data[2] = 0; //absolute write
    msg.text.data[6] = addr >> 24;
    msg.text.data[5] = addr >> 16;
    msg.text.data[4] = addr >> 8;
    msg.text.data[3] = addr;  //LSB first
    msg.text.data[10] = data >> 24;
    msg.text.data[9] = data >> 16;
    msg.text.data[8] = data >> 8;
    msg.text.data[7] = data;  //LSB first
    DLPC350_PrepWriteCmd(&msg, MEM_CONTROL);

    return DLPC350_SendMsg(&msg,true);
}

int DLPC350_MeasureImageLoadTiming(unsigned int startIndex, unsigned int numFlash)
/**
  * This API instructs the controller to measure the load time for the image(s) stored starting at specified index.
  * The result of measuement can be read back using the DLPC350_ReadImageLoadTiming() API.
  *
  * @param   startIndex - I - index of the first image whose load time is to be measured
  *
  * @param   numFlash - I - number of images for which load time is to be measured.
  *
  * @return  >=0 = PASS    <BR>
  *          <0 = FAIL  <BR>
  *
  */
{
    hidMessageStruct msg;

    msg.text.data[2] = startIndex;
    msg.text.data[3] = numFlash;
    DLPC350_PrepWriteCmd(&msg, IMAGE_LOAD_TIMING);

    return DLPC350_SendMsg(&msg,true);
}

int DLPC350_ReadImageLoadTiming(unsigned int *pTimingData)
/**
  * This API reads back the mesasured load time for the image specified by DLPC350_MeasureImageLoadTiming() API.
  *
  * @param   *pTimingData - I - time taken to load the specified image in milliseconds = value/18667.
  *
  * @return  >=0 = PASS    <BR>
  *          <0 = FAIL  <BR>
  *
  */
{
    hidMessageStruct msg;

    DLPC350_PrepReadCmd(IMAGE_LOAD_TIMING);

    if(DLPC350_Read() > 0)
    {
        memcpy(&msg, g_InputBuffer, 65);
        *pTimingData = (msg.text.data[0] | msg.text.data[1] << 8 | msg.text.data[2] << 16 | msg.text.data[3] << 24);
        return 0;
    }
    return -1;
}

int  DLPC350_I2C0WriteData(bool is7Bit, unsigned int sclClk, unsigned int devAddr, unsigned int numWriteBytes, unsigned char *pWData)
/**
  * This API makes a I2C Master write transcation via the I2C0 port of DLPC350.
  *
  * @param   is7Bit - I - true - For 7bit device addressing
  *                       false - For 10bit device addressing
  *
  * @param   sclClk - I - I2C master clock setting 18194 to 400000
  *
  * @param   devAddress - I - I2C slave device address to which message to be sent.
  *
  * @param   numWriteBytes  - I - Number of data bytes to be sent in write transcation
  *
  * @param   *pWdata - I - pointer to data bytes array to be sent
  *
  *
  * @return  >=0 = PASS    <BR>
  *          <0 = FAIL  <BR>
  */
{
    unsigned int i;
    hidMessageStruct msg;

    msg.text.data[2] = (is7Bit == true) ? 0x00 : 0x01;
    msg.text.data[3] = sclClk;  //LSB first
    msg.text.data[4] = sclClk >> 8;
    msg.text.data[5] = sclClk >> 16;
    msg.text.data[6] = sclClk >> 24;
    //RFU
    msg.text.data[7] = 0x00;
    msg.text.data[8] = 0x00;
    msg.text.data[9] = 0x00;
    msg.text.data[10] = 0x00;

    msg.text.data[11] = devAddr;  //LSB first
    msg.text.data[12] = devAddr >> 8;
    msg.text.data[13] = numWriteBytes;  //LSB first
    msg.text.data[14] = numWriteBytes >> 8;

    for(i=0;i<numWriteBytes;i++)
        msg.text.data[15+i] = pWData[i];

    g_SeqNum = 0;
    DLPC350_PrepWriteCmd(&msg, I2C0_CTRL);
    msg.head.length += (13 + numWriteBytes);
    if(DLPC350_SendMsg(&msg,true) < 0)
        return -1;

    return 0;
}

int  DLPC350_I2C0ReadData(bool is7Bit, unsigned int sclClk, unsigned int devAddr, unsigned int numWriteBytes, unsigned int numReadBytes, unsigned char *pWData, unsigned char *pRdata)
/**
  * This API makes a I2C Master write transcation via the I2C0 port of DLPC350.
  *
  * @param   is7Bit - I - true - For 7bit device addressing
  *                       false - For 10bit device addressing
  *
  * @param   sclClk - I - I2C master clock setting 18194 to 400000
  *
  * @param   devAddress - I - I2C slave device address to which message to be sent.
  *
  * @param   numWriteBytes  - I - Number of data bytes to be sent as part of write before reading the response
  *
  * @param   numReadBytes  - I - Number of data bytes to be read as part of read transcation
  *
  * @param   *pWdata - I - pointer to data bytes array to be sent
  *
  * @param   *pRdata - I - pointer to data bytes array where the response is copied
  *
  * @return  >=0 = PASS    <BR>
  *          <0 = FAIL  <BR>
  */
{
    unsigned int i;
    unsigned int tmpUIntVar;

    hidMessageStruct msg;
    msg.head.flags.rw = 1; //Read
    msg.head.flags.reply = 1; //Host wants a reply from device
    msg.head.flags.dest = 0; //Projector Control Endpoint
    msg.head.flags.reserved = 0;
    msg.head.flags.nack = 0;
    msg.head.seq = 0;
    msg.text.cmd = (CmdList[I2C0_CTRL].CMD2 << 8) | CmdList[I2C0_CTRL].CMD3;

    msg.text.data[2] = (is7Bit == true) ? 0x00 : 0x01;
    msg.text.data[3] = sclClk;  //LSB first
    msg.text.data[4] = sclClk >> 8;
    msg.text.data[5] = sclClk >> 16;
    msg.text.data[6] = sclClk >> 24;

    //RFU
    msg.text.data[7] = 0x00;
    msg.text.data[8] = 0x00;
    msg.text.data[9] = 0x00;
    msg.text.data[10] = 0x00;

    msg.text.data[11] = devAddr;  //LSB first
    msg.text.data[12] = devAddr >> 8;
    msg.text.data[13] = numWriteBytes;  //LSB first
    msg.text.data[14] = numWriteBytes >> 8;
    msg.text.data[15] = numReadBytes;  //LSB first
    msg.text.data[16] = numReadBytes >> 8;

    //Copy number of bytes to written before reading
    for(i=0;i<numWriteBytes;i++)
    {
        msg.text.data[17+i] = pWData[i];
    }
    msg.head.length = (2 + 15 + numWriteBytes);

    int maxDataSize = USB_MAX_PACKET_SIZE-sizeof(msg.head);
    int dataBytesSent = MIN(msg.head.length, maxDataSize);

    g_OutputBuffer[0]=0; // First byte is the report number
    memcpy(&g_OutputBuffer[1], &msg, (sizeof(msg.head) + dataBytesSent));

    //Check if it is single or multiple packet transaction
    if(dataBytesSent < msg.head.length)
    {
        //Send first packet
        if(DLPC350_USB_Write() < 0)
            return -1;

        //Send all intermediate packets
        while(dataBytesSent < msg.head.length)
        {
            memcpy(&g_OutputBuffer[1], &msg.text.data[dataBytesSent], USB_MAX_PACKET_SIZE);

            if((dataBytesSent+USB_MAX_PACKET_SIZE) >= (msg.head.length))
            {
                //last packet
                break;
            }
            else
            {
                if(DLPC350_USB_Write() < 0)
                    return -1;
            }

            dataBytesSent += USB_MAX_PACKET_SIZE;
        }
    }

    //Begin reading the response

    tmpUIntVar = numReadBytes;

    if(DLPC350_Read() < 0)
        return -1;

    hidMessageStruct *pMsg = (hidMessageStruct *)g_InputBuffer;
    if(pMsg != NULL)
    {
        memcpy(pRdata, g_InputBuffer+sizeof(pMsg->head), MIN((unsigned int)tmpUIntVar,64-sizeof(pMsg->head)));
        pRdata+= (64-sizeof(pMsg->head));
        if(tmpUIntVar > 64)
            tmpUIntVar -= (64-sizeof(pMsg->head));
        else
           tmpUIntVar = 0;
    }

    /* If number of bytes to be read in response is > 64 bytes */
    while(tmpUIntVar > 0)
    {
        DLPC350_ContinueRead();
        memcpy(pRdata, g_InputBuffer, MIN(tmpUIntVar,64));
        pRdata+=64;
        tmpUIntVar -= 64;
    }

    return 0;
}

int  DLPC350_I2C0TranStat(unsigned char *pStat)
/**
  * This API returns I2C0 Master write transcation status on I2C0 port of DLPC350.
  *
  * @param   *pStats - I - pointer to the status
  *                        0x00 - NO Error occured
  *                        0x01 - NO ACK Received from slave
  *                        0x02 - Arbitration lost
  *                        0x04 - Write timeout error
  *                        0x08 - Read timeout error
  *                        0x10 - Reserved
  *                        0x20 - I2C0 Internal error occurred
  *
  * @return  >=0 = PASS    <BR>
  *          <0 = FAIL  <BR>
  */
{
    hidMessageStruct msg;

    DLPC350_PrepReadCmd(I2C0_STAT);

    if(DLPC350_Read() > 0)
    {
        memcpy(&msg, g_InputBuffer, 65);
        *pStat = msg.text.data[0];
        return 0;
    }

    return -1;
}

bool DLPC350_isSourceLocked(VideoSigStatus VidSig)
{
	return (VidSig.Status & SOURCE_LOCK_MASK) == SOURCE_LOCKED ;
}
