javascriptedid

EDID edit in javascript


I'd like to generate an Eisa 3 chars Id but it seems I'm too tired to see where exactly I'm messing up .. plus bitshifting in js or anything else is not yet my top cup of tea ;)

anyone interested ? :)

As it seems I need to add some more details: I'm currently having fun / messing with an EDID .bin using vim & xxd, and now that I got stuff ok on the checksum side of things ( not yet in js ) & saving that .bin, I wanted to try building on dgallegos work by writing web-based EDID modification tool ( to generate the correct hex for at least manufacturer, serial, etc .. )

nb: big thanks to dgallegos for his Web-based EDID reader ;)

var getEisaId = function()
{
  var FIVE_BIT_LETTER_MASK = 0x1F;
  var EISA_ID_BYTE1 = 8;
  var EISA_ID_BYTE2 = 9;
  var EISA_LETTER1_OFF = 2
  var EISA_LETTER2_OFF = 5;
  var LETTER2_TOP_BYTES = 3;
  var LETTER2_TOP_MASK = 0x03;
  var LETTER2_BOT_MASK = 0x07;

  var firstLetter = (0xA1 >> EISA_LETTER1_OFF) &
                                            FIVE_BIT_LETTER_MASK;

  // Get the first two bits [2:0] of the top byte
  var secondLetterTop = 0xA1 & LETTER2_TOP_MASK;
  // Get the last three bits [7:5] of the bottom byte
  var secondLetterBottom = (0x00 >> EISA_LETTER2_OFF) &
                                            LETTER2_BOT_MASK;
  // Combine the top and bottom
  var secondLetter = (secondLetterTop << LETTER2_TOP_BYTES) | secondLetterBottom;

  var thirdLetter = 0x00 & FIVE_BIT_LETTER_MASK;

  return intToAscii(firstLetter)+intToAscii(secondLetter)+intToAscii(thirdLetter);
}

function intToAscii(intCode)
{
    var abc = "0ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("");
    return abc[intCode];
}

getEisaId();


/* ====  this is fine ;p ====*/
function asciiToInt(asciiChar){
  return "0ABCDEFGHIJKLMNOPQRSTUVWXYZ".indexOf(asciiChar);
}
//var byte9 = ( asciiToInt("0").toString(2) & 0x1F ).toString(16)

/* ====  this is not yet aside for "HHH" :/ ====*/
var generateEisaId = function(threeCharsId){
  var FIVE_BIT_LETTER_MASK = 0x1F;
  var EISA_LETTER1_OFF = 2;
  var EISA_LETTER2_OFF = 5;
  var LETTER2_TOP_BYTES = 3;
  var LETTER2_TOP_MASK = 0x03;
  var LETTER2_BOT_MASK = 0x07; // 111 in base 2

  var charsArr = threeCharsId.split('').splice(0, 3); // delete anything after 3rd char
  
  // format 1st char
  var firstLetterBin = asciiToInt(charsArr[0]); //.toString(2); // get index from letter, and get its binary representation
  console.log('1st letter: ' + charsArr[0] + ' > ' + asciiToInt(charsArr[0]) + ' (int/base10) > ' + firstLetterBin.toString(2) + ' (bin/base2)');

  // format 2nd char
  var secondLetterBin = asciiToInt(charsArr[1]); //.toString(2);
  console.log('2nd letter: ' + charsArr[1] + ' > ' + asciiToInt(charsArr[1]) + ' (int/base10) > ' + secondLetterBin.toString(2) + ' (bin/base2)');
  // get the second letter binary chunk for the 1st two bits of the top byte
  //var secondLetterTopBin = secondLetterBin >> LETTER2_TOP_MASK;
  //var secondLetterTopBin = secondLetterBin & LETTER2_TOP_MASK;
  //var secondLetterTopBin = secondLetterBin & LETTER2_TOP_MASK;
  var secondLetterTopBin = secondLetterBin >> 3; // shift 3 positions right ( drop stuff )
  console.log('2nd letter top bin: ' + secondLetterTopBin.toString(2));

  // get the second letter binary chunk for the last three bits of the bottom byte
  //var secondLetterBottomBin = secondLetterBin & LETTER2_BOT_MASK;
  var secondLetterBottomBin = ( secondLetterBin << 2 ) & 0x07;
  console.log('2nd letter bottom bin: ' + secondLetterBottomBin.toString(2));

  // format Last char
  var thirdLetterBin = asciiToInt(charsArr[2]); //.toString(2);
  console.log('3rd letter: ' + charsArr[2] + ' > ' + asciiToInt(charsArr[2]) + ' (int/base10) > ' + thirdLetterBin.toString(2) + ' (bin/base2)');

  // 1st byte - add 1st char binary to top byte & shift it 2 positions left to make room for 2nd char 1st binary chunk of 2 bits
  var firstLetterOnceOffset = ( firstLetterBin << EISA_LETTER1_OFF ) & FIVE_BIT_LETTER_MASK;
  //var firstLetterOnceOffset = ( firstLetterBin & 0xA0 );

  console.log('1st letter once offset: ' + firstLetterOnceOffset.toString(2));
  //var topByte = ( ( firstLetterBin << EISA_LETTER1_OFF ) | secondLetterTopBin ) >> 2;
  var topByte = ( firstLetterBin << EISA_LETTER1_OFF ) | secondLetterTopBin;
  console.log('top byte: ' + topByte.toString(2) );

  // 2nd byte - add 3rd char binary to bottom byte & shift it 3 positions right to make room for 2nd char 2nd binary chunk of 3 bits
  //var bottomByte = ( thirdLetterBin & FIVE_BIT_LETTER_MASK ) | ( secondLetterBottomBin << EISA_LETTER2_OFF )
  //var bottomByte = ( thirdLetterBin & FIVE_BIT_LETTER_MASK ) | ( secondLetterBottomBin << EISA_LETTER2_OFF );
  //var bottomByte = ( thirdLetterBin & FIVE_BIT_LETTER_MASK );
  var bottomByte = thirdLetterBin | ( secondLetterBottomBin << EISA_LETTER2_OFF ); // & 0xA0;
  //var bottomByte = ( thirdLetterBin & FIVE_BIT_LETTER_MASK ) | ( secondLetterBottomBin << 8 );
  //var bottomByte = ( thirdLetterBin & FIVE_BIT_LETTER_MASK ) | ( secondLetterBottomBin << 8 ); // &0x1F;
  console.log('bottom byte: ' + bottomByte.toString(2));

  // padding ? 
  var n1 = topByte.toString(2);
  n1 = "00000000".substr(n1.length) + n1;
  console.log('padded top byte: ' + n1);
  var n2 = bottomByte.toString(2);
  n2 = "00000000".substr(n2.length) + n2;
  console.log('padded bottom byte: ' + n2);
  
  // get hex's of the padded versions ?
  var eisaIdP = '0x' + parseInt(n1, 2).toString(16) + ' 0x' + parseInt(n2, 2).toString(16);
  console.log('padded: ' + eisaIdP);

  // get hex's for both of the aboves
  var eisaId = '0x' + topByte.toString(16) + bottomByte.toString(16);
  return eisaId;

}
var myId = generateEisaId('HHH');
var myId = generateEisaId('AAA');
console.log('generated Eisa Id hex: ' + myId);


Solution

  • All right, after some sleep & looking back at that stuff, "it got clear" ;)

    For a little background, 3 letters are split across 2 bytes. We have a "dictionnary" of indexed letters as an array of integers. From the length of the array that store their indexes, we know that the bits available for each letter is 5 bits max ( which gives us one unset bit on the 1st byte if we were to store those 3 letters in the said 2 bytes ), since the integer used as index for the last character in our "dictionnary" takes 5 bits in a byte ( hence considered the maximum )

    Trying to get the letter 'Z' displayed 3 times ( so 'ZZZ' ) would therefore lead to the following process:

    /*
      Z -> 26    (dec/base10)
           0x1A  (hex/base16)
           11010 ( bin/base2)
    
      Z:              11010
      padded Z:    00011010
      bytes:       00000000 | 00000000
      split:     0 00000 00 | 000 00000
      result:    0 11010 11 | 010 11010
      formatted:   01101011 | 01011010
      hex:             0x6b | 0x5a
      -> SUCCESS! ==> gives us 'ZZZ'
    */

    anything being a LOT clearer ( at least for me ) with a littl' colors, the following was indeed helpful ( yet not higlighting 'lose 0's between two bit manipulations' .. yet ? .. )

    R: check the actual browser console ;)

    var logBits = function(num, showHex){
      var numBits = num.toString(2);
      //var prefixLen = 8 - numBits;
      var prefixStr = '';
      //console.log(8 - numBits.length);
      for(var i=0; i< 8 - numBits.length; i++){ prefixStr +='0'; }
      if(showHex === true) console.log('0b%c' + prefixStr + '%c' + numBits + ' 0x' + num.toString(16), 'color: blue;', 'color: black;');
      else console.log('0b%c' + prefixStr + '%c' + numBits, 'color: blue;', 'color: black;');
    }
    // to do: alternate version that colors in other color ( or doesn't color at all )
    // "leading zeros that were lost we manipulating bits" to better perceive the changes in logs
    
    // usage:
    logBits(26);

    Once the above was written, the rest followed, so here it is:

    // helper
    function asciiToInt(asciiChar){
      return "0ABCDEFGHIJKLMNOPQRSTUVWXYZ".indexOf(asciiChar);
    }
    
    var genEisaId = function(threeCharsId, arr){
      var charsArr = threeCharsId.split('').splice(0, 3); // delete anything after 3rd char
      
      // get mapping idx's
      var firstLetterBin = asciiToInt(charsArr[0]);
      var secondLetterBin = asciiToInt(charsArr[1]);
      var thirdLetterBin = asciiToInt(charsArr[2]);
      
      // process
      var secondLetter1stChunk = secondLetterBin >> 3; // discard the three last bits
      var secondLetter2ndChunk = secondLetterBin & 0x07; //0b00111; // gets only the three last bits
      
      // build
      var firstByte = (firstLetterBin << 2 ) | secondLetter1stChunk;
      var secondByte = (secondLetter2ndChunk << 5) | thirdLetterBin;
      
      // post-proc
      //var firstByteHex = firstByte.toString(16);
      //var secondByteHex = secondByte.toString(16);
      var firstByteHex = (firstByte.toString(16).length == 2 )? firstByte.toString(16) : '0' + firstByte.toString(16);
      var secondByteHex = (secondByte.toString(16).length == 2) ? secondByte.toString(16) : '0' + secondByte.toString(16);
      
      // return hex's
      if(arr === true) return['0x' + firstByteHex, '0x' + secondByteHex];
      else return '0x' + firstByteHex + ' 0x' + secondByteHex;
    }
    
    // usage:
    console.log ( genEisaId('TEF') )

    The above function 'll gladly generate any 3-letter EISA ID hexs when given a string of chars ( some may be dropped if too long ;) )

    Again, bit thanks to @dgallegos for his work on http://www.edidreader.com/ & sharing it on github ( helped a lot by diving into "getEisaId()" & "intToAscii" to get the bases for mapping & decoding ).

    I hope posting the 'll help someone else to gen an Id as well or dicover his useful tool :)