DDC/CI协议的简单实现

    DDC/CI协议主要用于控制显示设备的设置,比如亮度(brightness),对比度(Contrast)等。它是基于I 2C 协议的一个半双工的通信协议,一般是PC发起控制请求,显示设备被动应答的模式。本文仅仅是提供一种简单的C语言实现方式,提供大家参考。

    有三个文件,它们依次是MCCS.hDDCCI.HDDCCI.cMCCSMinitor Control Command Set的缩写,定义了spec1.0对应的命令. DDCCI主要定义了DDCCI的发送和接收的接口函数,它覆盖了DDC/CI1.0spec的要求。此外,I 2C 的读写函数在这个简单的实现中没有被实现,因为在不同的平台上,不同的硬件设备上,它们差别较大,可以日后根据情况而分别进行填写。

 

MCCS.h源代码

#ifndef _MCCS_H

#define _MCCS_H

 

#if defined( __cplusplus ) || defined( c_plusplus )

extern "C" {

#endif

 

//==============================================================================//

//                     Continuous Control Code Values                           //

//==============================================================================//

 

#define DDCCI_MCCS_BRIGHTNESS                            0x10

#define DDCCI_MCCS_CONTRAST                                0x12

 

// The level of maximum luminance of RGB pixels

#define DDCCI_MCCS_RED_VIDEO_GAIN                        0x16

#define DDCCI_MCCS_GREEN_VIDEO_GAIN                        0x18

#define DDCCI_MCCS_BLUE_VIDEO_GAIN                        0x 1A

 

// The level of minimum luminance of RGB pixels

#define DDCCI_MCCS_RED_VIDEO_BLACK_LEVEL                0x 6C

#define DDCCI_MCCS_GREEN_VIDEO_BLACK_LEVEL                0x6E

#define DDCCI_MCCS_BLUE_VIDEO_BLACK_LEVEL                0x70

 

// Adjusts the apparent spot size

#define DDCCI_MCCS_FOCUS                                0x 1C

 

#define DDCCI_MCCS_HORIZONTAL_POSITION                    0x20

#define DDCCI_MCCS_HORIZONTAL_SIZE                        0x22

 

// Cause the right and left sides of the image to become more or less convex

#define DDCCI_MCCS_HORIZONTAL_PINCUSHION                0x24

 

// Moves the center section of the image toward the right or left side of display

#define DDCCI_MCCS_HORIZONTAL_BALANCE                    0x26

 

// Increasing(decreasing) this value will shift the red pixels to the right(left)

// accros the image and the blude pixels lef(right) across the image with respect

// to green pixels.

#define DDCCI_MCCS_HORIZONTAL_MISCONVERGENCE            0x28

 

// Shifts the density of pixels from the left and right ends to the center of the image

#define DDCCI_MCCS_HORIZONTAL_LINEARITY                    0x 2A

 

// Increasing(decreasing) this value shifts the density of pixels from the left(right)

// side to the right(left) side fo the image

#define DDCCI_MCCS_HORIZONTAL_LINEARITY_BALANCE            0x 2C

 

#define DDCCI_MCCS_VERTICAL_POSITION                    0x30

#define DDCCI_MCCS_VERTICAL_SIZE                        0x32

 

// Increasing(decreasing) this value causes the top and bottom sides of the image to

// become more(less) convex

#define DDCCI_MCCS_VERTICAL_PINCUSHION                    0x34

 

// Increasing(decreasing) this value moves the center section of the image toward the

// top(bottom) of the display

#define DDCCI_MCCS_VERTICAL_PINCUSHION_BALANCE            0x36

 

// Increase(decreasing) this value shifts the red pixels up(down) across the image

// and the blue pixels down(up) across the image with respect to the green pixels

#define DDCCI_MCCS_VERTICAL_MISCONVERGENCE                0x38

 

// Increasing(decreasing) this value shifts the density of scan lines from the ends

// (center) to the center(ends) of the image

#define DDCCI_MCCS_VERTICAL_LINEARITY                    0x 3A

 

// Increasing(decreasing) this value shifts the density of scan lines from the top

// (bottom) end to the bottom(top) end of the image

#define DDCCI_MCCS_VERTICAL_LINEARITY_BALANCE            0x 3C

 

// Increasing(decreasing) this value shifts the top section of the image to the

// right(left) with respect to the bottom section of image

#define DDCCI_MCCS_PARALLELOGRAM_DISTORTION                0x40

 

// The ratio between the horizontal size at the top of the image relative to the

// horizontal size at the bottom of the image

#define DDCCI_MCCS_TRAPEZOIDAL_DISTORTION                0x42

 

// Increasing(decreasing) this value rotatels the image(counter) clockwise about

// the center point of the image

#define DDCCI_MCCS_TILT                                    0x44

 

#define DDCCI_MCCS_TOP_CORNER_DISTORTION_CONTROL        0x46

#define DDCCI_MCCS_TOP_CORNER_DISTORTION_BALANCE        0x48

#define DDCCI_MCCS_BOTTOM_CORNER_DISTORTION_CONTROL        0x 4A

#define DDCCI_MCCS_BOTTOM_CORNER_DISTORTION_BALANCE        0x 4C

 

// Adjusting this value controls the horizontal/vertical piciture moire cancellation

#define DDCCI_MCCS_HORIZONTAL_MORIE                        0x56

#define DDCCI_MCCS_VERTICAL_MORIE                        0x58

 

// Addressable horinzontal/vertical screen

#define DDCCI_MCCS_HORADD                                0x72

#define DDCCI_MCCS_VERADD                                0x74

 

// Addressable buffer

#define DDCCI_MCCS_BUFFERADD                            0X76

 

// update rate of the screen in 0.01HZ

#define DDCCI_MCCS_UPDATE                                0x78

 

// Changing this value will change the focal plane of the optics

#define DDCCI_MCCS_ADJUST_FOCAL_PLANE                    0x 7A

 

// Changing this value will change the zoom of the optics

#define DDCCI_MCCS_ADJUST_ZOOM                            0x 7C

 

// Changing this value will change the trapezoid adjustment of the optics

#define DDCCI_MCCS_TRAPEZOID                            0x7E

 

// Changing this value will change the keystone adjustment of the optics

#define DDCCI_MCCS_KEYSTONE                                0x80

 

// Changing this value will cause the picutre to flip horizontally by means of

// the optics of the device

#define DDCCI_MCCS_HORFLIP                                0x82

 

// Changing this value will cause the picutre to flip vertically by means of

// the optics of the device

#define DDCCI_MCCS_VERFLIP                                0x84

 

// Changing this value will affect the scaling(input versus output) function of display

#define DDCCI_MCCS_DISPLAY_SCALING                        0x86

 

// Increasing(decreasing) this value will increase(decrease) the velocity modulation of

// the horizontal scan as a function of the luminance level

#define DDCCI_MCCS_VELOCITY_SCAN_MODULATION                0x88

 

// Increasing the control increases the amplitude of the color difference components of

// the video signal. The result is an increase in the amount of pure color relative to

// white in the video. This control does not effect the RGB input, only the TV video

// input.

#define DDCCI_MCCS_TV_COLOR_SATURATION                    0x 8A

 

// Increasing this control increases the amplitude of the hight frequency components of

// the video signal. The result is accentuation of fine details. This control deos not

// effect the RGB input, only the TV video inputs.

#define DDCCI_MCCS_TV_SHARPNESS                            0x 8C

 

// Increasing this control increases the ratio between whites and blacks in the video.

// The control does not effect RGB input, only the TV video inputs.

#define DDCCI_MCCS_TV_CONTRAST                            0x8E

 

// (a.k.a. Tint)Increase this control increase the wavelength of the color component

// of the video signal. The result is a shift towards red in the hue of all colors.

// This control does not effect the RGB input, only the TV video inputs.

#define DDCCI_MCCS_TV_HUE                                0x90

 

// Increasing this control increases the black level of the video. The result is an

// increase of the lumen level of the video. A value of zero represents the darkest

// level possible. This control deos not effect the RGB input, only the TV video inputs.

#define DDCCI_MCCS_TV_BRIGHTNESS                        0x92

 

//==============================================================================//

//                     Non-Continuous Control Code Values                       //

//==============================================================================//

 

//==============================================================================//

//                     Non-Continuous Control Code Values                       //

//                     ( Read and Write controls )                              //

//==============================================================================//

 

// Changing this value chooses a different video input voltage for the display on input

// source select1. Format is reference white above blank, level of sync, below blank.

// 0 none selected

// 1 0.700, 0.300 (1.00 Vpp)

// 2 0.714, 0.286 (1.00 Vpp)

// 3 1.000, 0.400 (1.40 Vpp)

// 4 0.700, 0.000 (0.700 Vpp)

#define DDCCI_MCCS_INPUT_LEVEL_SELECT1                    0x5E

 

// 0 None selected

// 1 OSD is disabled to appear

// 2 OSD is enabled to appear

#define DDCCI_MCCS_ON_SCREEN_DISPLAY                    0xCA

 

// Changing this value chooses a different video input voltage for the display on input

// source select2. Format is reference white above blank, level of sync, below blank.

// 0 none selected

// 1 0.700, 0.300 (1.00 vpp)

// 2 0.714, 0.286 (1.00 vpp)

// 3 1.000, 0.400 (1.40 Vpp)

// 4 0.700, 0.000 (0.800 Vpp)

#define DDCCI_MCCS_INPUT_LEVEL_SELECT2                    0xCC

 

// Changing this value selects a different video input source.

// 0 None selected

// 1 DB-15HD/VGA1

// 2 DB-15HD/VGA2

// 3 DB-15HD/VGA3

// 4 BNC/RGB1

// 5 BNC/RGB2

// 6 BNC/RGB3

// 7 EVC1

// 8 EVC2

// 9 EVC3

// 10 MAC1

// 11 MAC2

// 12 MAC3

// 13 RCA/ Composite Video1

// 14 RCA/ Composite Video2

// 15 RCA/ Composite Video3

// 16 S-Video1

// 17 S-Video2

// 18 S-Video3

// 19 SCART-Composite1

// 20 SCART-Composite2

// 21 SCART-RGB

// 22 SCART-S-video

// 23 Tuner1

// 24 Tuner2

// 25 Tuner3

// 26 YUV1

// 27 YUV2

// 28 YUV3

#define DDCCI_MCCS_INPUT_SOURCE_SELECT1                    0x60

 

// Changing this value selects a different video input source.

// Coding of the different sources to select are the same as

// Input Source Select 1

#define DDCCI_MCCS_INPUT_SOURCE_SELECT2                    0xCE

 

// Changing this value selects a different video input source.

// Coding of the different sources to select are the same as

// Input Source Select 1

#define DDCCI_MCCS_OUTPUT_SOURCE_SELECT1                0xD0

 

// Changing this value selects a different video input source.

// Coding of the different sources to select are the same as

// Input Source Select 1

#define DDCCI_MCCS_OUTPUT_SOURCE_SELECT2                0xD2

 

// Changing this value selects the video mode with respect to 2D or 3D.

// 0 None selected

// 1 Mono Mode

// 2 Enable Field-Sequential Right Eye First

// 3 Enable Field-Sequential Left Eye First

// 4 Enable 2-Way Interleaved Right Eye First

// 5 Enable 2-Way Interleaved Left Eye First

// 6 Enable 4-Way Interleaved, Display Stereo Buffer 0 (even scan lines)

// 7 Enable 4-Way Interleaved, Display Stereo Buffer 1 (odd scan lines)

// 8 Enable Side-by-Side Interleaved

#define DDCCI_MCCS_STEREO_MODE                            0xD4

 

// DPMS Power Status

// 0 none selected

// 1 On

// 2 Standby

// 3 Suspend

// 4 Off

#define DDCCI_MCCS_DISPLAY_POWER_MODE                    0xD6

 

#define DDCCI_MCCS_PRESET_COLOT_TEMP                    0xD8

 

// 0: none selected

// 1: underscan

// 2: overscan

// 3: 16 x 9 letterbox

#define DDCCI_MCCS_SCAN_FORMAT                            0xDA

 

// 0: None selected

// 1: Productivity

// 2: Games

// 3: Movies

#define DDCCI_MCCS_DISPLAY_MODE                            0xDC

 

// 0: None selected

// 1: Stand alone

// 2: Slave (full PC control)

#define DDCCI_MCCS_OPERATION_MODE                        0xDE

 

//==============================================================================//

//                     Non-Continuous Control Code Values                       //

//                     ( Read Only controls )                                   //

//==============================================================================//

 

// 0. None selected

// 1. Disabled

// 2. Enabled

#define DDCCI_MCCS_AUTO_SIZE_CENTER                        0xA2

 

// 3. None selected

// 4. Negative

// 5. Positive

#define DDCCI_MCCS_POLARITY_HORIZONTAL_SYNCHRONIZATION    0xA4

 

// 6. None selected

// 7. Negative

// 8. Positive

#define DDCCI_MCCS_POLARITY_VERTICAL_SYNCHRONIZATION    0xA6

 

// 9. None selected

// 10. Separate

// 11. Digital Composite

// 12. Composite on Green

#define DDCCI_MCCS_SYNCHRONIZATION_TYPE                    0xA8

 

// 13. none selected

// 14. Landscape

// 15. Portrait

#define DDCCI_MCCS_SCREEN_ORIENTATION                    0xAA

 

// Horizontal frequency in Hz.

// The value to indicate the displays information is: FFh FFh FFh

#define DDCCI_MCCS_HORFREQUENCY                            0xAC

 

// Vertical frequency in 0.01Hz

// The value to indicate the displays information is: FFh FFh

#define DDCCI_MCCS_VERTFREQUENCY                        0xAE

 

//==============================================================================//

//                     Non-Continuous Control Code Values                       //

//                     ( Write Only controls )                                  //

//==============================================================================//

 

// This request causes the display to Degauss and does not alter any of its control

// or status values. By any number not equal to zero will make the monitor to degauss.

// The value zero will nullify the degauss request.

#define DDCCI_MCCS_DEGAUSS                                0x01

 

// 0. None selected

// 1. Store Current settings in the monitor

// 2. Restore Factory default belonging to the particular video mode the monitor is in.

// 3. Restore the user saved values belonging to the particular video mode the monitor

//    is in

#define DDCCI_MCCS_SETTINGS                                0xB0

 

#if defined( __cplusplus ) || defined( c_plusplus )

}

#endif

 

#endif

 

 

DDCCI.h源代码:

#ifndef _DDCCI_H

#define _DDCCI_H

 

#include <assert.h>

#include <sys/time.h>

 

#include "MCCS.h"

 

#if defined( __cplusplus ) || defined( c_plusplus )

extern "C" {

#endif

 

#define DDCCI_MSG_SZ                        (32)

#define DDCCI_MSG_PAYLOAD_SZ                (DDCCI_MSG_SZ - 4)

 

// The address of normal working mode for DDC/CI

#define DDCCI_MASTER_I 2C _ADDR                0x50

#define DDCCI_SLAVE_I 2C _ADDR                0x6E

 

// The external display dependent device

#define DDCCI_SLAVE_PRINTER_I 2C _ADDR                0xF0 // Touch Screen, Light pen or Remote Control Track Ball

#define DDCCI_SLAVE_AUDIO_DEV_I 2C _ADDR                0xF2 // Speaker / Microphone

#define DDCCI_SLAVE_SERIAL_COMMUNICATION_I 2C _ADDR    0xF4 // Home Network IF (power line modem)

#define DDCCI_SLAVE_CALIBRATION_DEV_I 2C _ADDR        0xF6 // Luminance Probe or Colorimeter

#define DDCCI_SLAVE_INPUT_DEV_I 2C _ADDR                0xF8 // IR keyboard and remote control pad (shared IR channel)

#define DDCCI_SLAVE_RESERVED1_I 2C _ADDR                0xFA // Reserved for future use

#define DDCCI_SLAVE_RESERVED2_I 2C _ADDR                0xFC // Reserved for future use

#define DDCCI_SLAVE_RESERVED3_I 2C _ADDR                0xFE // Reserved for future use

 

// Fixed address I 2C devices

#define DDCCI_SLAVE_SMART_BATTERY_CHARGER_I 2C _ADDR    0x12

#define DDCCI_SLAVE_SMART_BATTERY_SELECTOR_I 2C _ADDR    0x14

#define DDCCI_SLAVE_SMART_BATTERY_I 2C _ADDR            0x16

#define DDCCI_SLAVE_AUDIO_PROCESSOR_I 2C _ADDR        0x80

#define DDCCI_SLAVE_PAL_NTSC_DECODER_I 2C _ADDR        0x40

#define DDCCI_SLAVE_DDC2B_MONITOR_I 2C _ADDR            0xA0

 

#define DDCCI_VCP_REQUEST                    0x01

#define DDCCI_VCP_REPLY                        0x02

#define DDCCI_VCP_SET                        0x03

#define DDCCI_VCP_RESET                        0x09

 

#define DDCCI_IDENTIFICATION_REQUEST        0xF1

#define DDCCI_IDENTIFICATION_REPLY            0xE1

 

#define DDCCI_CAPABILITIES_REQUEST            0xF3

#define DDCCI_CAPABILITIES_REPLY            0xE3

 

#define DDCCI_DISPLAY_SELF_TEST_REQEUST        0xB1

 

#define DDCCI_TIMING_REQUEST                0x07

#define DDCCI_TIMING_REPLY                    0x06

 

#define DDCCI_TABLE_READ_REQEUST            0xE2

#define DDCCI_TABLE_READ_REPLY                0xE4

#define DDCCI_TABLE_WRITE                    0xE7

 

#define DDCCI_ENABLE_APPLICATION_REPORT        0xF5

#define DDCCI_SAVE_CURRENT_SETTINGS            0x 0C

 

#define DDCCI_TX( pDDCCI, data, len )        do {                        /

        DDCCI_Delay( (pDDCCI) );                                        /

        DDCCI_Send( (pDDCCI), (data), (len) );                            /

    } while ( 0 )

 

#define DDCCI_RX( pDDCCI, data, len )    do {                            /

        DDCCI_Delay( (pDDCCI) );                                        /

        DDCCI_Receive( (pDDCCI), (data), (len) );                        /

    } while ( 0 )

 

#define DDCCI_SendNullMsg( pDDCCI )    do {                                /

        assert( (pDDCCI)->i2cMode == EDDCCI_I 2C _MODE_SLAVE );            /

        if ( (pDDCCI)->i2cMode == EDDCCI_I 2C _MODE_SLAVE )                /

            DDCCI_TX( (pDDCCI), NULL, 0 );                                /

    } while ( 0 )

 

#define DDCCI_SaveCurrentSettings( pDDCCI )    do {                        /

        assert( (pDDCCI)->i2cMode == EDDCCI_I 2C _MODE_MASTER );            /

        if ( (pDDCCI)->i2cMode == EDDCCI_I 2C _MODE_MASTER )                /

        {                                                                /

            unsigned char _buf[ 1 ] = { DDCCI_SAVE_CURRENT_SETTINGS };    /

            DDCCI_TX( (pDDCCI), _buf, sizeof( _buf ) );                    /

        }                                                                /

    } while ( 0 )

 

#define DDCCI_GetVCPFeature( pDDCCI, mccs, valU32 )    do {                /

        assert( (pDDCCI)->i2cMode == EDDCCI_I 2C _MODE_MASTER );            /

        (valU32) = -1;                                                    /

        if ( (pDDCCI)->i2cMode == EDDCCI_I 2C _MODE_MASTER )                /

        {                                                                /

            unsigned char _buf[ DDCCI_MSG_SZ ];                            /

            _buf[ 0 ] = DDCCI_VCP_REQUEST;                                /

            _buf[ 1 ] = (mccs);                                            /

            DDCCI_TX( (pDDCCI), _buf, 2 );                                /

            DDCCI_Delay( (pDDCCI) );                                    /

            if ( DDCCI_Receive( (pDDCCI), _buf, sizeof( _buf ) ) > 0 )    /

            {                                                            /

                if ( _buf[ 0 ] == DDCCI_VCP_REPLY &&                     /

                    _buf[ 1 ] == 0x00 &&                                /

                    _buf[ 2 ] == (mccs) &&                                 /

                    _buf[ 3 ] == 0x01 )                                    /

                {                                                        /

                    (valU32) = ((_buf[ 4 ] << 24) |                        /

                        (_buf[ 5 ] << 16 ) |                            /

                        (_buf[ 6 ] << 8) |                                /

                        (_buf[ 7 ]));                                    /

                }                                                        /

            }                                                            /

        }                                                                /

    } while ( 0 )  

 

#define DDCCI_SetVCPFeature( pDDCCI, mccs, valU16 )    do {            /

        assert( (pDDCCI)->i2cMode == EDDCCI_I 2C _MODE_MASTER );        /

        if ( (pDDCCI)->i2cMode == EDDCCI_I 2C _MODE_MASTER )            /

        {                                                            /

            unsigned char _buf[ 4 ];                                /

            _buf[ 0 ] = DDCCI_VCP_SET;                                /

            _buf[ 1 ] = (mccs);                                        /

            _buf[ 2 ] = ((valU16) >> 8) & 0xFF;                        /

            _buf[ 3 ] = (valU16) & 0xFF;                            /

            DDCCI_TX( (pDDCCI), _buf, sizeof( _buf ) );                /

        }                                                            /

    } while ( 0 )

 

#define DDCCI_GetCapabilities( pDDCCI, offsetU16, buf32 )    do {        /

        assert( (pDDCCI)->i2cMode == EDDCCI_I 2C _MODE_MASTER );            /

        if ( (pDDCCI)->i2cMode == EDDCCI_I 2C _MODE_MASTER )                /

        {                                                                /

            int           _len;                                            /

            unsigned char _buf[ DDCCI_MSG_SZ + 4 ];                        /

            _buf[ 0 ] = DDCCI_CAPABILITIES_REQUEST;                        /

            _buf[ 1 ] = ((offsetU16) >> 8) & 0xFF;                        /

            _buf[ 2 ] = (offsetU16) & 0xFF;                                /

            DDCCI_TX( (pDDCCI), _buf, 3 );                                /

            DDCCI_Delay( (pDDCCI) );                                    /

            _len = DDCCI_Receive( (pDDCCI), _buf, sizeof( _buf ) );        /

            if ( _len > 0 )                                                /

            {                                                            /

                if ( _buf[ 0 ] == DDCCI_CAPABILITIES_REPLY &&            /

                    ((_buf[ 1 ] << 8) | _buf[ 2 ]) == (offsetU16) )        /

                {                                                        /

                    memcpy( (buf32), &_buf[ 3 ], _len );                /

                }                                                        /

            }                                                            /

        }                                                                /

    } while ( 0 )  

 

typedef enum _EDDCCIDispDev

{

    EDDCCI_DISP_DEV_INDEP,     // Independent display device

    EDDCCI_DISP_DEV_EXT_DEP, // External display dependent device

    EDDCCI_DISP_DEV_INT_DEP, // Internal display dependent device

} EDDCCIDispDev;

 

typedef enum _EDDCCII2CMode

{

    EDDCCI_I 2C _MODE_MASTER,

    EDDCCI_I 2C _MODE_SLAVE

} EDDCCII2CMode;

 

typedef struct _SDDCCI

{

    int            flags;

    unsigned char  masterI2CAddr; // 0x6E in normal case

    unsigned char  slaveI2CAddr;  // 0x 50 in normal case

    unsigned char  rDstI2CAddr;

    unsigned char  rSrcI2CAddr;

    unsigned char  wDstI2CAddr;

    unsigned char  wSrcI2CAddr;

    EDDCCIDispDev  dispDev;

    EDDCCII2CMode  i2cMode;

    struct timeval DDCCITimestamp; // The timestamp of last DDC/CI OpCode

    int            DDCCIOpCode;       // Last DDC/CI OpCode

} SDDCCI;

 

typedef struct _SDDCCITimingReport

{

    unsigned char  timingStatus;

    unsigned char  pad;

    unsigned short horFreq;    // Horizontal frequency

    unsigned short verFreq;    // Vertical frequency

} SDDCCITimingReport;

 

int DDCCI_Create( SDDCCI *pDDCCI,

    unsigned char masterI2CAddr, unsigned char slaveI2CAddr,

    EDDCCIDispDev dispDev, EDDCCII2CMode i2cMode );

 

int DDCCI_Destroy( SDDCCI *pDDCCI );

 

int DDCCI_Send( SDDCCI *pDDCCI, unsigned char *data, int len );

 

int DDCCI_Receive( SDDCCI *pDDCCI, unsigned char *data, int len );

 

int DDCCI_Delay( SDDCCI *pDDCCI );

 

int DDCCI_GetTimingReport( SDDCCI *pDDCCI, SDDCCITimingReport *pTimingReport );

 

#if defined( __cplusplus ) || defined( c_plusplus )

}

#endif

 

#endif

 

DDCCI.c源代码:

 

#include <stdio.h>

#include <string.h>

#include <assert.h>

 

#include <unistd.h>

 

#include "DDCCI.h"

 

#define DDCCI_FLG_INITED        0x00000001

#define DDCCI_FLG_READ            0x01000000

#define DDCCI_FLG_WRITE            0x02000000

#define DDCCI_FLG_RW            (DDCCI_FLG_READ | DDCCI_FLG_WRITE)

 

#define DDCCI_LEN_MAGIC            (0x80)

#define DDCCI_GEN_LEN( len )    (DDCCI_LEN_MAGIC | ((len) & (DDCCI_MSG_SZ - 1)))

#define DDCCI_GET_LEN( len )    (((len) & ~DDCCI_LEN_MAGIC) & (DDCCI_MSG_SZ - 1))

 

#define DDCCI_INV_OPCODE        -1

#define DDCCI_MIN_READ_DELAY    35

 

static void _DDCCI_DumpHex( unsigned char *buf, int len );

static int _DDCCI_ReadI 2C ( unsigned char i2cAddr, unsigned char *buf, int len );

static int _DDCCI_WriteI 2C ( unsigned char i2cAddr, unsigned char *buf, int len );

static int _DDCCI_GetDelay( int DDCCIOpCode );

 

int DDCCI_Create( SDDCCI *pDDCCI,

    unsigned char masterI2CAddr, unsigned char slaveI2CAddr,

    EDDCCIDispDev dispDev, EDDCCII2CMode i2cMode )

{

    assert( pDDCCI != NULL );

    assert( (pDDCCI->flags & DDCCI_FLG_INITED) == 0 );

  

    pDDCCI->flags         = 0x01;

    pDDCCI->masterI2CAddr = masterI2CAddr;

    pDDCCI->slaveI2CAddr  = slaveI2CAddr;

    pDDCCI->dispDev       = dispDev;

    pDDCCI->i2cMode       = i2cMode;

 

    if ( pDDCCI->i2cMode == EDDCCI_I 2C _MODE_MASTER )

    {

        pDDCCI->flags |= DDCCI_FLG_RW;

    }

    else

    {

        pDDCCI->flags |= DDCCI_FLG_WRITE;

    }

  

    switch ( pDDCCI->dispDev )

    {

    case EDDCCI_DISP_DEV_INDEP:

        if ( pDDCCI->i2cMode == EDDCCI_I 2C _MODE_MASTER )

        {

            pDDCCI->rDstI2CAddr = pDDCCI->slaveI2CAddr | 0x01;

            pDDCCI->rSrcI2CAddr = pDDCCI->slaveI2CAddr;

          

            pDDCCI->wDstI2CAddr = pDDCCI->slaveI2CAddr;

            // In order to tell the display that the received message is of DDC/CI type,

            // the Source Address Byte bit 0 is set to 1.

            pDDCCI->wSrcI2CAddr = pDDCCI->masterI2CAddr | 0x01;

        }

        else

        {

            // Slave mode can not read

            pDDCCI->rDstI2CAddr = -1;

            pDDCCI->rSrcI2CAddr = -1;

           

            pDDCCI->wDstI2CAddr = pDDCCI->slaveI2CAddr | 0x01;

            pDDCCI->wSrcI2CAddr = pDDCCI->slaveI2CAddr;

        }

        break;

  

    case EDDCCI_DISP_DEV_EXT_DEP:

        if ( pDDCCI->i2cMode == EDDCCI_I 2C _MODE_MASTER )

        {

            pDDCCI->rDstI2CAddr = pDDCCI->slaveI2CAddr | 0x01;

            pDDCCI->rSrcI2CAddr = pDDCCI->slaveI2CAddr;

          

            pDDCCI->wDstI2CAddr = pDDCCI->slaveI2CAddr;

            // In order to tell the display that the received message is of DDC/CI type,

            // the Source Address Byte bit 0 is set to 1.

            pDDCCI->wSrcI2CAddr = pDDCCI->slaveI2CAddr | 0x01;

        }

        else

        {

            // Slave mode can not read

            pDDCCI->rDstI2CAddr = -1;

            pDDCCI->rSrcI2CAddr = -1;

          

            pDDCCI->wDstI2CAddr = pDDCCI->slaveI2CAddr | 0x01;

            pDDCCI->wSrcI2CAddr = pDDCCI->slaveI2CAddr;

        }

        break;

  

    case EDDCCI_DISP_DEV_INT_DEP:

        if ( pDDCCI->i2cMode == EDDCCI_I 2C _MODE_MASTER )

        {

            pDDCCI->rDstI2CAddr = pDDCCI->slaveI2CAddr | 0x01;

            pDDCCI->rSrcI2CAddr = pDDCCI->slaveI2CAddr;

          

            pDDCCI->wDstI2CAddr = 0x6E;

            // In order to tell the display that the received message is of DDC/CI type,

            // the Source Address Byte bit 0 is set to 1.

            pDDCCI->wSrcI2CAddr = pDDCCI->slaveI2CAddr | 0x01;

        }

        else

        {

            // Slave mode can not read

            pDDCCI->rDstI2CAddr = -1;

            pDDCCI->rSrcI2CAddr = -1;

          

            pDDCCI->wDstI2CAddr = 0x 6F ;

            pDDCCI->wSrcI2CAddr = pDDCCI->slaveI2CAddr;

        }

        break;

  

    default:

        assert( 0 );

        printf( "[DDC/CI]: unknown display device/n" );

      

        return -1;

    }

  

    timerclear( (&pDDCCI->DDCCITimestamp) );

    pDDCCI->DDCCIOpCode = DDCCI_INV_OPCODE;

  

    return 0;

}

 

int DDCCI_Destroy( SDDCCI *pDDCCI )

{

    assert( pDDCCI != NULL );

    assert( (pDDCCI->flags & DDCCI_FLG_INITED) == DDCCI_FLG_INITED );

  

    memset( pDDCCI, 0, sizeof( SDDCCI ) );

  

    return 0;

}

 

int DDCCI_Send( SDDCCI *pDDCCI, unsigned char *data, int len )

{

    int           idx;

    int           txLen;

    unsigned char buf[ DDCCI_MSG_SZ ];

    unsigned char checkSum;

  

    assert( pDDCCI != NULL );

    assert( (pDDCCI->flags & (DDCCI_FLG_INITED | DDCCI_FLG_WRITE) ) ==

        (DDCCI_FLG_INITED | DDCCI_FLG_WRITE) );

    assert( len <= DDCCI_MSG_PAYLOAD_SZ );

 

    buf[ 0 ]  = pDDCCI->wDstI2CAddr;

    if ( pDDCCI->i2cMode == EDDCCI_I 2C _MODE_MASTER )

        checkSum = buf[ 0 ];

    else

        checkSum = DDCCI_MASTER_I 2C _ADDR;

  

    buf[ 1 ] = pDDCCI->wSrcI2CAddr;

    checkSum ^= buf[ 1 ];

  

    buf[ 2 ] = DDCCI_GEN_LEN( len );

    checkSum ^= buf[ 2 ];

  

    for ( idx = 0; idx < len; ++ idx )

    {

        buf[ idx + 3 ] = data[ idx ];

        checkSum      ^= data[ idx ];

    }

  

    buf[ len + 3 ] = checkSum;

  

    _DDCCI_DumpHex( buf, len + 4 );

  

    txLen  = _DDCCI_WriteI 2C ( buf[ 0 ], &buf[ 1 ], len + 3 );

    txLen -= 3;

    assert( txLen == len );

    // Trace the OpCode of DDC/CI

    if ( txLen == len && data != NULL )

    {

        gettimeofday( &pDDCCI->DDCCITimestamp, NULL );

        pDDCCI->DDCCIOpCode = data[ 0 ];

    }

  

    return txLen > 0 ? txLen : 0;

}

 

int DDCCI_Receive( SDDCCI *pDDCCI, unsigned char *data, int len )

{

    int           idx;

    int           rxLen;

    int           msgLen;

    unsigned char buf[ 127 + 4 ];

    unsigned char checkSum;

  

    assert( pDDCCI != NULL );

    assert( (pDDCCI->flags & (DDCCI_FLG_INITED | DDCCI_FLG_READ) ) ==

        (DDCCI_FLG_INITED | DDCCI_FLG_READ) );

    assert( data != NULL );

    assert( len > 0 );

  

    assert( pDDCCI->i2cMode == EDDCCI_I 2C _MODE_MASTER );

    if ( pDDCCI->i2cMode != EDDCCI_I 2C _MODE_MASTER )

    {

        printf( "[DDC/CI]: slave mode can not read/n" );

      

        return -1;

    }

  

    rxLen = _DDCCI_ReadI 2C ( pDDCCI->rDstI2CAddr, buf, sizeof( buf ) );

  

    if ( rxLen < 0 )

    {

        printf( "[DDC/CI]: fail to read I 2C bus/n" );

      

        return -2;

    }

  

    _DDCCI_DumpHex( buf, rxLen );

 

    if ( rxLen < 4 )

    {

        printf( "[DDC/CI]: too small size of message/n" );

      

        return -3;

    }

      

    if ( buf[ 0 ] != pDDCCI->rDstI2CAddr )

    {

        printf( "[DDC/CI]: unknown Destination I 2C address(0x%X, 0x%X)/n",

            buf[ 0 ], pDDCCI->rDstI2CAddr );

          

        return -4;

    }

  

    if ( buf[ 1 ] != pDDCCI->rSrcI2CAddr )

    {

        printf( "[DDC/CI]: unknown source I 2C address(0x%X, 0x%X)/n",

            buf[ 1 ], pDDCCI->rSrcI2CAddr );

      

        return -5;

    }

  

    msgLen = DDCCI_GET_LEN( buf[ 2 ] );

    if ( msgLen + 1 > rxLen )

    {

        printf( "[DDC/CI]: message is partitial(msgLen = %d, rxLen = %d)/n",

            msgLen, rxLen );

      

        return -6;

    }

    if ( msgLen > len )

    {

        printf( "[DCC/CI]: buffer is too small(len = %d, rxLen = %d, msgLen = %d)/n",

            len, rxLen, msgLen );

      

        return -7;

    }

  

    if ( pDDCCI->i2cMode == EDDCCI_I 2C _MODE_MASTER )

        checkSum = buf[ 0 ];

    else

        checkSum = DDCCI_MASTER_I 2C _ADDR;

  

    checkSum ^= buf[ 1 ];

    checkSum ^= buf[ 2 ];

    for ( idx = 0; idx < msgLen; ++ idx )

    {

        data[ idx ] = buf[ idx + 3 ];

        checkSum   ^= buf[ idx ];

    }

  

    checkSum ^= buf[ msgLen + 3 ];

  

    if ( checkSum != 0 )

    {

        printf( "[DDC/CI]: checksum has error(checkSum = 0x%X)/n", checkSum );

      

        return -8;

    }

  

    // Trace the OpCode of DDC/CI

    gettimeofday( &pDDCCI->DDCCITimestamp, NULL );

    pDDCCI->DDCCIOpCode = buf[ 3 ];

  

    return msgLen;

}

 

int DDCCI_Delay( SDDCCI *pDDCCI )

{

    int            delayMs;

    int            deltaMs;

    struct timeval tv;

  

    assert( pDDCCI != NULL );

  

    delayMs = _DDCCI_GetDelay( pDDCCI->DDCCIOpCode );

  

    if ( delayMs == 0 )

        return 0;

  

    if ( gettimeofday( &tv, NULL ) != 0 )

    {

        usleep( deltaMs * 1000 );

    }

    else

    {

        int delta;

      

        // Calculate the gap

        if ( tv.tv_sec >= pDDCCI->DDCCITimestamp.tv_sec )

        {

            delta = tv.tv_sec - pDDCCI->DDCCITimestamp.tv_sec;

        }

        else

        {

            delta = ((time_t) -1) - pDDCCI->DDCCITimestamp.tv_sec + tv.tv_sec;

        }

        delta *= 1000;

        delta += ((int) tv.tv_usec - pDDCCI->DDCCITimestamp.tv_usec) / 1000;

        if ( delta < delayMs )

        {

            usleep( (delayMs - delta) * 1000 );

        }

    }

  

    return delayMs;

}

 

int DDCCI_GetTimingReport( SDDCCI *pDDCCI, SDDCCITimingReport *pTimingReport )

{

    int           idx;

    int           rxLen;

    unsigned char buf[ 127 + 4 ];

    unsigned char checkSum;

  

    assert( pDDCCI != NULL );

    assert( pTimingReport != NULL );

  

    assert( (pDDCCI)->i2cMode == EDDCCI_I 2C _MODE_MASTER );

    if ( (pDDCCI)->i2cMode != EDDCCI_I 2C _MODE_MASTER )

    {

        printf( "[DDC/CI]: only master can get timing report/n" );

      

        return -1;

    }

  

    buf[ 0 ] = DDCCI_TIMING_REQUEST;

    DDCCI_TX( pDDCCI, buf, 1 );

  

    DDCCI_Delay( pDDCCI );

    rxLen = DDCCI_Receive( pDDCCI, buf, sizeof( buf ) );

    if ( rxLen <= 0 )

    {

        printf( "[DDC/CI]: fail to receive timing report/n" );

      

        return -2;

    }

  

    _DDCCI_DumpHex( buf, rxLen );

  

    if ( rxLen < 9 )

    {

        printf( "[DDC/CI]: too small size of timing report/n" );

      

        return -3;

    }

  

    if ( buf[ 0 ] != pDDCCI->rDstI2CAddr )

    {

        printf( "[DDC/CI]: unknown Destination I 2C address(0x%X, 0x%X)/n",

            buf[ 0 ], pDDCCI->rDstI2CAddr );

          

        return -4;

    }

  

    if ( buf[ 1 ] != pDDCCI->rSrcI2CAddr )

    {

        printf( "[DDC/CI]: unknown source I 2C address(0x%X, 0x%X)/n",

            buf[ 1 ], pDDCCI->rSrcI2CAddr );

      

        return -5;

    }

  

    if ( buf[ 2 ] != DDCCI_TIMING_REPLY )

    {

        printf( "[DDC/CI]: unknown replay for timing report(0x%X, 0x%X)/n",

            buf[ 2 ], DDCCI_TIMING_REPLY );

      

        return -6;

    }

  

    if ( buf[ 3 ] != 0x04 )

    {

        printf( "[DDC/CI]: unknown opcode of timing report(0x%X, 0x%4)/n", buf[ 3 ] );

      

        return -7;

    }

  

    checkSum = DDCCI_MASTER_I 2C _ADDR;

    for ( idx = 1; idx < 9; ++ idx )

    {

        checkSum ^= buf[ idx ];

    }

    checkSum ^= buf[ 9 ];

  

    if ( checkSum != 0 )

    {

        printf( "[DDC/CI]: checksum has error(checkSum = 0x%X) for timing report./n", checkSum );

      

        return -8;

    }

  

    pTimingReport->timingStatus = buf[ 4 ];

    pTimingReport->horFreq      = (buf[ 5 ] << 8) | buf[ 6 ];

    pTimingReport->verFreq      = (buf[ 7 ] << 8) | buf[ 8 ];

  

    return 0;

}

 

static void _DDCCI_DumpHex( unsigned char *buf, int len )

{

    int idx;

  

    printf( "[DCC/CI]:" );

    for ( idx = 0; idx < len; ++ idx )

    {

        printf( "%s0x%X", (idx ? ", " : " "), buf[ idx ] );

    }

    printf( "/n" );

}

 

static int _DDCCI_ReadI 2C ( unsigned char i2cAddr, unsigned char *buf, int len )

{

    buf[ 0 ] = i2cAddr; // 0 must save i2cAdd to return

  

    return len;

}

 

static int _DDCCI_WriteI 2C ( unsigned char i2cAddr, unsigned char *buf, int len )

{

    return len;

}

 

static int _DDCCI_GetDelay( int DDCCIOpCode )

{

    int delayMs;

  

    switch ( DDCCIOpCode )

    {

    case DDCCI_VCP_REQUEST:

        delayMs = 40;

        break;

 

    case DDCCI_VCP_REPLY:

        delayMs = 0;

        break;

 

    case DDCCI_VCP_SET:

        delayMs = 50;

        break;

  

    case DDCCI_VCP_RESET:

        delayMs = 200;

        break;

  

    case DDCCI_IDENTIFICATION_REQUEST:

        delayMs = DDCCI_MIN_READ_DELAY;

        break;

  

    case DDCCI_IDENTIFICATION_REPLY:

        delayMs = 0;

        break;

  

    case DDCCI_CAPABILITIES_REQUEST:

        delayMs = DDCCI_MIN_READ_DELAY;

        break;

 

    case DDCCI_CAPABILITIES_REPLY:

        delayMs = 50;

        break;

  

    case DDCCI_TIMING_REQUEST:

        delayMs = 40;

        break;

 

    case DDCCI_TIMING_REPLY:

        delayMs = 50;

        break;

  

    case DDCCI_TABLE_READ_REQEUST:

        delayMs = DDCCI_MIN_READ_DELAY;

        break;

 

    case DDCCI_TABLE_READ_REPLY:

        delayMs = 50;

        break;

  

    case DDCCI_TABLE_WRITE:

        delayMs = 50;

        break;

  

    case DDCCI_ENABLE_APPLICATION_REPORT:

        delayMs = DDCCI_MIN_READ_DELAY;

        break;

  

    case DDCCI_SAVE_CURRENT_SETTINGS:

        delayMs = 200;

        break;

  

    case DDCCI_DISPLAY_SELF_TEST_REQEUST:

        delayMs = 200;

        break;

  

    case DDCCI_INV_OPCODE:

        delayMs = 0;

        break;

  

    default:

        delayMs = DDCCI_MIN_READ_DELAY;

        break;

    }

  

    return delayMs;

}

 

 

  • 8
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值