Ashuimei 2023-03-10 17:00 采纳率: 50%
浏览 121
已结题

显示器DDC/CI读取显示器状态,VESA VCP

我在通过软件读取显示器状态时碰见了问题。
我是通过ddc/ci 指令,通过VCP code获取显示器的状态。
我可以通过一些测试软件或者通过自己写代码获取显示器的一些状态,但是当这个VCP code值代表多个功能时(有多个sub-code),读取会读不到内容。
如链接方式:可以获取到显示器功能集合的capability string,然后getVCPFeature获取某个VCP code代表功能的当前值
https://learn.microsoft.com/zh-cn/windows/win32/monitor/using-the-low-level-monitor-configuration-functions

如下是我测试的显示器的capability string:
Capabilities String:
(prot(monitor)type(lcd)model(HP Z24m G3)cmds(01 02 03 07 0C E3 F3)vcp(02 04 05 08 0B 0C 10 12 16 18 1A 2E(00 01 02 03) 52 60(0F 11 13) 62 6C 6E 70 86(01 02 05) 87(01 02 03 04 05 06 07) 8D(01 02) AC AE B2 B6 C0 C6 C8 C9 CA(01 02) CC(01 02 03 04 05 06 09 0A 0D 0E 14) D6(01 02 03 04 05) DC(00( 00 01 02 05 13 14 15 1D 2B)02(00 01 02 03 04) ) DF E0(02(00 01 03))** E1(04(00 01 03 04 06 08 09 0A) 0A(00 01) 0C(20) 0F(00 01) 10(00 01) 27(02 03 04 05 07 09 0A FF) 28(00 01) 2C(00 01) 2D(00 01) 30(00 01) 31(00 01) 32(00 01) 35(00 01 02) 36(00 01) 39(02 03) 3B 3C 3E 3F(02 03 04 05) 40(00 01 02 03) 42(00 01) 43(00 01) 45(00 01) 49(00 01) 4A(00 01) 4C( 00 01 ) 4E(00 01 02 03 04 05 FF) 56 57(00 01) 6E(01) 6F(00) 72(00 01) 73(00 01))** E6(00 01) E7(00 01) E8(18(00 01) 1B( 00 01 02) 1C(00 01) 1E( 00 01 02)) E9(0D(00 01)) EA(00 01) EB(00( 01 02 03 04)) EE(01 02 03) EF(01 02 03 04 05) F0 F5(00 01 02 03 05 06 0A 0B 0C 0D 0E 0F 11 12 13 14 15 18 19 1B 1C 1D 1E) F8(00 01 02(00 01 02) 0A) FA(00 01 02) FB FC FD FE(00 01 02 03 04))mswhql(1)asset_eep(40)mccs_ver(2.2))

img

如图,结合上述Capabilities String,我可以通过读取E6,E7的VCP来直接获取这两个代表功能的当前值--E6(00 01) E7(00 01)
但是由于E1用于多个功能,如上述中加粗部分,直接读取E1只会返回00,并不能直接获取到想要那个功能的值。

我需要的是获取displayport mode 的当前值,也就是Capabilities String中相当于括号嵌套的 E1(35(00 01 02)),请问这能怎么实现?
我这边也用一些测试的软件,直接下DDC/CI指令的,如果能通过修改指令格式或者通过编程解决问题,将不胜感激!!

  • 写回答

5条回答 默认 最新

  • 极客智能体-在线 2023-03-10 21:48
    关注

    以下答案由GPT-3.5大模型与博主波罗歌共同编写:
    在处理这个问题之前,需要先了解一些基础知识。DDC/CI(Display Data Channel/Command Interface)是一串用于控制液晶显示器的信号。使用这个信号,可以做很多东西,如调节亮度、对比度,以及分辨率等等。为了避免混乱,VESA(Video Electronics Standards Association)建立了一套规范,即VESA VCP(VESA Command Set for Video Electronics Standards Association (VESA) Monitor Control Command Set,即VESA监视器控制命令集),该规范定义了各种VCP code及其所代表的功能。每个VCP code都有一个值代表该功能的当前状态。

    根据你提供的信息,可以通过读取E1的值,确定该功能有多个子功能(sub-code)。在这种情况下,需要使用SetVCPFeature命令通过指定sub-code值,选择要控制的子功能。下一步是在使用getVCPFeature命令时,将选择对应的VCP code和对应的sub-code值,以读取正确的显示器状态。

    以下是一个示例代码,它通过DDC/CI命令读取displayport mode(E1(35(00 01 02)))的当前值:

    import win32api, win32con, time
    
    # 定义所有的VCP code和对应的sub-code列表,可以根据实际情况修改
    vcp_dict = {
        0x10: [0x00],          # 亮度
        0x12: [0x00],          # 对比度
        0xe1: [0x35, 0x00, 0x01, 0x02],  # DisplayPort mode
        0x60: [0x0f, 0x11, 0x13],      # 色温
    }
    
    # 定义读取VCP值的函数
    def read_vcp_value(vcp_code, sub_codes):
        ddc_cmd = "\x6e\x01" + chr(vcp_code)           # 6e是附加DDC/CI的指令,01是查询命令,vcp_code是要查询的VCP code
        data_block = [len(sub_codes) + 1] + sub_codes  # 数据块的内容,第一个字节是sub-code的数量,后面的字节是sub-code的值
        crc = 0                                     # 校验码,使用纵向冗余校验(CRC)算法生成
        for byte in data_block:
            ddc_cmd += chr(byte)
            crc ^= byte
            for i in range(8):
                if crc & 0x80:
                    crc = (crc << 1) ^ 0x07
                else:
                    crc <<= 1
                crc &= 0xff
            # 组合DDC command和CRC码
        ddc_cmd += chr(crc)
        # 使用win32api发送DDC命令,并读取显示器响应
        monitor_handle = win32api.EnumDisplayMonitors()[0][0]
        _, res, _ = win32api.MonitorFromHandle(monitor_handle, win32con.MONITOR_DEFAULTTONULL)
        if res:
            return win32api.SendMessage(res, win32con.WM_GETDCCI_REPLY, 0x02, ddc_cmd).encode('hex')[:-4]
        else:
            return None
    
    # 读取DisplayPort mode的当前值
    mode_value = int(read_vcp_value(0xe1, [0x35, 0x02])[6:8], 16)
    print("DisplayPort mode值为:%s" % mode_value)
    

    在代码中,我们首先定义了一个字典(vcp_dict)将VCP code和对应的sub-code列表一一映射起来。这样,我们可以根据需要扩展该字典,随时添加新的VCP code和sub-code。接下来,我们定义了一个read_vcp_value函数,该函数接受VCP code和sub-code的列表作为参数,使用DDC/CI命令读取显示器响应,并返回VCP值。最后,我们通过调用read_vcp_value函数读取DisplayPort mode的当前值,并打印结果。

    注意,在使用win32api发送DDC命令之前,必须先通过win32api.EnumDisplayMonitors函数获取现有的显示器句柄,并使用win32api.MonitorFromHandle函数从句柄获取显示器的RECT结构体。如果我们在发送DDC命令之前没有这些必要的准备工作,那么函数read_vcp_value将返回None值。

    以上代码仅供参考,具体情况需要根据实际情况进行调节。
    如果我的回答解决了您的问题,请采纳!

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(4条)

报告相同问题?

问题事件

  • 已结题 (查看结题原因) 3月11日
  • 已采纳回答 3月11日
  • 创建了问题 3月10日

悬赏问题

  • ¥15 使用ue5插件narrative时如何切换关卡也保存叙事任务记录
  • ¥20 软件测试决策法疑问求解答
  • ¥15 win11 23H2删除推荐的项目,支持注册表等
  • ¥15 matlab 用yalmip搭建模型,cplex求解,线性化处理的方法
  • ¥15 qt6.6.3 基于百度云的语音识别 不会改
  • ¥15 关于#目标检测#的问题:大概就是类似后台自动检测某下架商品的库存,在他监测到该商品上架并且可以购买的瞬间点击立即购买下单
  • ¥15 神经网络怎么把隐含层变量融合到损失函数中?
  • ¥15 lingo18勾选global solver求解使用的算法
  • ¥15 全部备份安卓app数据包括密码,可以复制到另一手机上运行
  • ¥20 测距传感器数据手册i2c