Roni Tovi
Roni Tovi

Reputation: 886

Extract info from EDID blocks: 5 bits to letters?

I'm collecting EDID blocks (as bytes) from SetupAPI calls in order to get some detailed Monitor information.

As the EDID documentation says, some bytes stores "5-bits letters" inside them.

Just to save you from headache, I'm attaching a scheme to understand easily:

2 bytes representing 3 letters in their bits

As you can see, I need to extract 5-bits letters from the bytes.

I could managed to split the bytes into the BitArray but then I don't know how to convert those bits to letters.

Wiki also says:

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

Well, what is the fastest and most painless way to convert those bits?

I guess I could predefine a Dictionary object like:

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"));

and then search in it but first I don't know how to follow after “00010=B” to “11010=Z” and second I'm sure there must be more proper way.

Thanks for your help.

Upvotes: 0

Views: 896

Answers (3)

Soroush Falahati
Soroush Falahati

Reputation: 2327

BTW, for anyone interested, I just wrote a C# EDIDParser that can give you all of the provided information from the EDID binary in a nice way.

Project: https://github.com/falahati/EDIDParser

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


All you need to do is to create an instance of the EDID type providing the binary data and then use the properties of the class to get information, including the vendor 3 letter code.

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

However, if you are only interested in the part about the extracting the code from the vendor identification number, you can check out the source code from here: 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)}";
        }
    }

Upvotes: 1

Henri Socha
Henri Socha

Reputation: 11

To answer this question one must understand bit manipulation in C# and bit & byte layout in a little-endian machine. Bit 0 in a byte is the least significant odd/even bit, not the sign bit and if you want to think of it as a 16 bit quantity, the second byte is bits 15 (sign) to bit 8, least-significant in that byte. But more importantly, the problem at hand.

In the nice picture above, the bit #s are wrong. Even from the spec we can see this. EX: "the second character (letter) is located at bits 1 & 0 (at address 08h) and bits 7 → 5 (at address 09h)". A corrected diagram is: enter image description here

Working code is (and yes, I am using exactly this in my s/w):

// 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]);

My one remaining question is, what should the "01234" in the above string be? I used "01234" only as a placeholder. Are they undefined special characters ($_-@#), what?

Upvotes: 1

user555045
user555045

Reputation: 64904

To extract the groups of 5 bits, the standard "extract stuff from bitstream" technique can be used (it's more general, but that's OK), one version of which goes like this: (not tested and not really meant as code anyway, more like a low-level pseudocode)

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);
}

In general, instead of 5 you can put anything up to and including 25 and it can be variable.

Or more specifically for this case, you can calculate where you have to look in the array and extract it directly: (not tested)

// 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;

To convert a 5 bit value to a letter, add it to 'A', sort of. But they start at A=1, so subtract 1:

char letter = (char)('A' + x - 1);

Upvotes: 0

Related Questions