0

我正在从 SetupAPI 调用中收集 EDID 块(作为字节),以获取一些详细的监视器信息。

正如EDID 文档所说,某些字节在其中存储“5 位字母”。

只是为了让您免于头痛,我附上了一个易于理解的方案:

2 个字节代表 3 个字母

如您所见,我需要从字节中提取 5 位字母。

我可以设法将字节拆分为 BitArray,但是我不知道如何将这些位转换为字母。

维基还说:

"00001=A”; “00010=B”; ... “11010=Z”.

那么,转换这些位的最快和最轻松的方法是什么?

我想我可以预定义一个 Dictionary 对象,例如:

Dictionary<BitArray, char> letters = new Dictionary<BitArray, char>();
letters.Add(new BitArray(new int[] { 0, 0, 0, 1 }),  Convert.ToChar("A"));
letters.Add(new BitArray(new int[] { 0, 0, 1, 0 }),  Convert.ToChar("B"));

然后在其中搜索,但首先我不知道如何从“00010=B”到“11010=Z”,其次我确定必须有更合适的方法。

谢谢你的帮助。

4

3 回答 3

1

要回答这个问题,必须了解 C# 中的位操作以及 little-endian 机器中的位和字节布局。字节中的第 0 位是最低有效的奇数/偶数位,而不是符号位,如果您想将其视为 16 位的数量,则第二个字节是第 15 位(符号)到第 8 位,其中最低有效字节。但更重要的是,眼前的问题。

在上面的漂亮图片中,#s 位是错误的。即使从规范中我们也可以看到这一点。例如:“第二个字符(字母)位于位 1 和 0(地址 08h)和位 7 → 5(地址 09h)”。更正的图表是: 在此处输入图像描述

工作代码是(是的,我在我的软件中正是使用这个):

// in 2 bytes, [8,9], ignore top bit then three 5 bit characters
char[] convert = " ABCDEFGHIJKLMNOPQRSTUVWXYZ01234".ToCharArray();
result.AppendFormat("-8: Vendor ID#: {0}{1}{2}\n",
convert[(edid[8] >> 2) & 0x1F],
convert[((edid[8] << 3) & 0x18) | ((edid[9] >> 5) & 0x07)],
convert[edid[9] & 0x1F]);

我剩下的一个问题是,上面字符串中的“01234”应该是什么?我只使用“01234”作为占位符。它们是未定义的特殊字符($_-@#)吗?

于 2015-10-26T19:28:35.980 回答
0

顺便说一句,对于任何感兴趣的人,我刚刚编写了一个 C# EDIDParser,它可以以一种很好的方式为您提供来自 EDID 二进制文件的所有提供信息。

项目:https ://github.com/falahati/EDIDParser

NuGet:https ://www.nuget.org/packages/EDIDParser


您需要做的就是创建一个EDID提供二进制数据的类型的实例,然后使用该类的属性来获取信息,包括供应商 3 字母代码。

var edid = new EDID(bytes);
var vendorCode = edid.ManufacturerCode;

但是,如果您只对从供应商标识号中提取代码的部分感兴趣,您可以从这里查看源代码: https ://github.com/falahati/EDIDParser/blob/master/EDIDParser/EDID 。CS

    /// <summary>
    ///     Gets the manufacturer identification assigned by Microsoft to the device vendors in string
    /// </summary>
    public string ManufacturerCode
    {
        get
        {
            var edidCode = ManufacturerId;
            edidCode = ((edidCode & 0xff00) >> 8) | ((edidCode & 0x00ff) << 8);
            var byte1 = (byte) 'A' + ((edidCode >> 0) & 0x1f) - 1;
            var byte2 = (byte) 'A' + ((edidCode >> 5) & 0x1f) - 1;
            var byte3 = (byte) 'A' + ((edidCode >> 10) & 0x1f) - 1;
            return $"{Convert.ToChar(byte3)}{Convert.ToChar(byte2)}{Convert.ToChar(byte1)}";
        }
    }
于 2017-05-18T11:30:37.237 回答
0

要提取 5 位组,可以使用标准的“从比特流中提取内容”技术(它更通用,但没关系),其中一个版本如下所示:(未经测试,无论如何都不是真正的代码,更多像一个低级伪代码)

uint buffer = 0;
int emptybits = 32;
while (want_more_symbols) {
    while (emptybits >= 8 && can_read_more) {
        emptybits -= 8;
        buffer = buffer | ((uint)readByte() << emptybits)
    }
    int symbol = (int)(buffer >> (32 - 5));
    buffer <<= 5;
    emptybits += 5;
    use(symbol);
}

一般来说,你可以放任何不超过 25 的东西,而不是 5,它可以是可变的。

或者更具体地说,对于这种情况,您可以计算必须在数组中查找的位置并直接提取它:(未测试)

// extract symbol n
int bitindex = n * 5;
int arrayindex = bitindex / 8;
int leftover = bitindex & 7;
if (leftover <= 3)
    // it's in one byte
    return (array[arrayindex] >> (3 - leftover)) & 32;
else
    // crosses byte boundary
    return ((array[arrayindex] << (leftover - 3)) | 
            (array[arrayindex + 1] >> (11 - leftover))) & 32;

要将 5 位值转换为字母,请将其添加到“A”中。但它们从 A=1 开始,所以减去 1:

char letter = (char)('A' + x - 1);
于 2015-09-19T15:05:17.547 回答