Trying to assign to an un-named type

Posted on
Page
of 2
/ 2
Next
  • Hey Guys,

    I'm trying to write a library for my Adafruit Bi-color 8x8 matrix so that I can release it for others to use. As it is a display and so involves drawing shapes and such, I thought a good idea would be to extend off of the Graphics object and some custom methods to that and return that as my modules API, like so:

    // Define global constants
    var LED_OFF = 0;
    var LED_RED = 1;
    var LED_YELLOW = 2;
    var LED_GREEN = 3;
    
    var HT16K33_BLINK_CMD = 0x80;
    var HT16K33_BLINK_DISPLAYON = 0x01;
    var HT16K33_BLINK_OFF = 0;
    var HT16K33_BLINK_2HZ  = 1;
    var HT16K33_BLINK_HALFHZ  = 3;
    var HT16K33_BRIGHTNESS_CMD = 0xE0;
    var HT16K33_ENABLE_OSCILLATOR_CMD = 0x21;
    
    var exports = {};
    exports.connect = function(i2c, address, callback){
    
      // Private methods
      function drawPixel(x,y,col){
          
        // Handle rotation
        switch (rotation) {
        case 1:
          var t1 = x;
          x = 8 - y - 1;
          y = t1;
          break;
        case 2:
          x = 8 - x - 1;
          y = 8 - y - 1;
          break;
        case 3:
          var t2 = x;
          x = y;
          y = 8 - t2 - 1;
          break;
        }
        
        // Handle backwards wiring
        if(x < 4){
          x += 4;
        } else {
          x -= 4;
        }
        
        if(y < 4){
          y += 4;
        } else {
          y -= 4;
        }
        
        // We wamt colours to override
        // so turn the current pixel off by default
        // then set it's colour again
        displaybuffer[y] &= ~(1 << x) & ~(1 << (x+8));
    
        if (col == LED_GREEN) {
          displaybuffer[y] |= (1 << x) & ~(1 << (x+8));
        } else if (col == LED_RED) {
          displaybuffer[y] |= ~(1 << x) & (1 << (x+8));
        } else if (col == LED_YELLOW) {
          displaybuffer[y] |= (1 << x) | (1 << (x+8));
        }
          
      }
      
      function drawRect(x1,y1,x2,y2,col){
        for(var x=x1;x<=x2;x++){
          for(var y=y1;y<=y2;y++){
            drawPixel(x,y,col);
          }
        }
      }
      
      // Create buffer
      var display = Graphics.createCallback(8,8,8,{setPixel:­drawPixel,fillRect:drawRect});
      var displaybuffer = new Uint16Array(8);
      var rotation = 0;
      
      display.setRotation = function(rot){
        rotation = rot;
      };
      
      display.getRotation = function(){
        return rotation;
      };
      
      display.setBlinkRate = function(b) {
        if (b > 3) b = 0; // turn off if not sure
        i2c.writeTo(address, HT16K33_BLINK_CMD | HT16K33_BLINK_DISPLAYON | (b << 1));
      };
        
      display.setBrightness = function(b) {
        if (b > 15) b = 15; // Don't go over max
        i2c.writeTo(address, HT16K33_BRIGHTNESS_CMD | b);
      };
        
      display.clear = function(){
        for (var i=0; i<8; i++) {
          displaybuffer[i] = 0;
        }
        display.write();
      };
      
      display.write = function(){
        var tmp = new Uint8Array(17);
        tmp[0] = 0x00;
        for (var i=0; i<16; i+=2) {
          tmp[i+1] = displaybuffer[i/2] & 0xFF;
          tmp[i+2] = displaybuffer[i/2] >> 8;
        }
        i2c.writeTo(address, tmp);
      };
      
      // Turn on oscillator
      i2c.writeTo(address, HT16K33_ENABLE_OSCILLATOR_CMD);
      
      // Set blink rate
      display.setBlinkRate(HT16K33_BLINK_OFF);­
      
      // Set to full brightness
      display.setBrightness(15);
      
      // Trigger callback
      if (callback!==undefined){
        setTimeout(callback, 100);
      }
      
      return display;
    };
    
    
    // Setup I2C
    I2C2.setup({ scl: B10, sda: B11 });
    
    var matrix = exports.connect(I2C2, 0x70, function(){
      
      var counter = 1;
      setInterval(function(){
        
        matrix.clear();
        
        matrix.setRotation(counter - 1);
        matrix.setColor(counter);
        matrix.fillRect(0,0,7,1);
        matrix.fillRect(0,3,7,4);
        matrix.fillRect(0,6,7,7);
        matrix.fillRect(0,0,1,7);
        
        matrix.write();
        
        counter = (counter == 3) ? 1 : counter + 1;
        
      }, 2000);
      
    });
    

    The problem is, I keep getting errors when I try to add additional methods to my display object. If I extend the Graphics class via prototype then everything works, however I don't won't my methods available to all Graphics objects, just ones returned from my module. Anyone know what I'm doing wrong (I'm sure I saw @Gordon do this kind of thing in the 123-LED demo video).

    Matt

  • Strange! If I use dictionary notation when defining my additional methods, everything seems to work. Does this mean the first way of doing it has a bug?

    // Define global constants
    var LED_OFF = 0;
    var LED_RED = 1;
    var LED_YELLOW = 2;
    var LED_GREEN = 3;
    
    var HT16K33_BLINK_CMD = 0x80;
    var HT16K33_BLINK_DISPLAYON = 0x01;
    var HT16K33_BLINK_OFF = 0;
    var HT16K33_BLINK_2HZ  = 1;
    var HT16K33_BLINK_HALFHZ  = 3;
    var HT16K33_BRIGHTNESS_CMD = 0xE0;
    var HT16K33_ENABLE_OSCILLATOR_CMD = 0x21;
    
    var exports = {};
    exports.connect = function(i2c, address, callback){
    
      // Private methods
      function drawPixel(x,y,col){
          
        // Handle rotation
        switch (rotation) {
        case 1:
          var t1 = x;
          x = 8 - y - 1;
          y = t1;
          break;
        case 2:
          x = 8 - x - 1;
          y = 8 - y - 1;
          break;
        case 3:
          var t2 = x;
          x = y;
          y = 8 - t2 - 1;
          break;
        }
        
        // Handle backwards wiring
        if(x < 4){
          x += 4;
        } else {
          x -= 4;
        }
        
        if(y < 4){
          y += 4;
        } else {
          y -= 4;
        }
        
        // We wamt colours to override
        // so turn the current pixel off by default
        // then set it's colour again
        displaybuffer[y] &= ~(1 << x) & ~(1 << (x+8));
    
        if (col == LED_GREEN) {
          displaybuffer[y] |= (1 << x) & ~(1 << (x+8));
        } else if (col == LED_RED) {
          displaybuffer[y] |= ~(1 << x) & (1 << (x+8));
        } else if (col == LED_YELLOW) {
          displaybuffer[y] |= (1 << x) | (1 << (x+8));
        }
          
      }
      
      function drawRect(x1,y1,x2,y2,col){
        for(var x=x1;x<=x2;x++){
          for(var y=y1;y<=y2;y++){
            drawPixel(x,y,col);
          }
        }
      }
      
      // Create buffer
      var display = Graphics.createCallback(8,8,8,{setPixel:­drawPixel,fillRect:drawRect});
      var displaybuffer = new Uint16Array(8);
      var rotation = 0;
    
      display["setRotation"] = function(rot){
        rotation = rot;
      };
      
      display["getRotation"] = function(){
        return rotation;
      };
      
      display["setBlinkRate"] = function(b) {
        if (b > 3) b = 0; // turn off if not sure
        i2c.writeTo(address, HT16K33_BLINK_CMD | HT16K33_BLINK_DISPLAYON | (b << 1));
      };
        
      display["setBrightness"] = function(b) {
        if (b > 15) b = 15; // Don't go over max
        i2c.writeTo(address, HT16K33_BRIGHTNESS_CMD | b);
      };
    
      display["updateDisplay"] = function(){
        var tmp = new Uint8Array(17);
        tmp[0] = 0x00;
        for (var i=0; i<16; i+=2) {
          tmp[i+1] = displaybuffer[i/2] & 0xFF;
          tmp[i+2] = displaybuffer[i/2] >> 8;
        }
        i2c.writeTo(address, tmp);
      };
    
      display["clearDisplay"] = function(){
        for (var i=0; i<8; i++) {
          displaybuffer[i] = 0;
        }
        display.updateDisplay();
      };
      
      // Turn on oscillator
      i2c.writeTo(address, HT16K33_ENABLE_OSCILLATOR_CMD);
      
      // Set blink rate
      display.setBlinkRate(HT16K33_BLINK_OFF);­
      
      // Set to full brightness
      display.setBrightness(15);
      
      // Trigger callback
      if (callback!==undefined){
        setTimeout(callback, 100);
      }
      
      return display;
    };
    
    
    // Setup I2C
    I2C2.setup({ scl: B10, sda: B11 });
    
    var matrix = exports.connect(I2C2, 0x70, function(){
      
      var counter = 1;
      setInterval(function(){
        
        matrix.clear();
        
        matrix.setRotation(counter - 1);
        matrix.setColor(counter);
        matrix.fillRect(0,0,7,1);
        matrix.fillRect(0,3,7,4);
        matrix.fillRect(0,6,7,7);
        matrix.fillRect(0,0,1,7);
        
        matrix.updateDisplay();
        
        counter = (counter == 3) ? 1 : counter + 1;
        
      }, 2000);
      
    });
    
  • Hmm. I think it's doing the right thing - maybe Rick can say for sure.

    It fails because of writing display.clear - because there's already Graphics.prototype.clear.

    There are some other things though:

    • It's best to leave off the fillRect function. If you don't supply it, Espruino will use its own (which will be native code and so faster).
    • I'd really recommend that in this case you use Graphics.createArrayBuffer because it'll be faster/more efficient. I'm planning on adding rotation to Espruino at some point - but for now you could do rotation more efficiently in a flip function anyway :)
  • @Gordon thanks for the tips. A few things:

    1) Weirdly, if I just had the clear override, that would work, so I don't think that is the reason for it failing.

    2) When I left off fillRect callback, it didn't render any of my calls to fillRect so I assumed it needed supplying (I've raised an issue on Github)

    3) What exactly is a flip function? The function to make it display on screen? Got any examples of something that would be more efficient?

  • Hmm... I did try it out - I deleted that function definition and it worked...

    I just saw the fillRect issue - I'll look into it...

    flip is the name of the function I've been using in display modules when they send the data over to the display. For example PCD8544 and the source.

    You could do something a bit like:

      display.flip = function(){
        var tmp = new Uint8Array(17);
        // tmp[0] = 0x00; // initialiased to 0 anyway
        tmp.set(graphics.buffer, 1);
        i2c.writeTo(address, tmp);
      };
    

    ... assuming you have the buffer - but unfortunately right now graphics can only do 1,8,16,24,32 bits. It'd be good to add more options though.

    at the moment you can use 'ArrayBufferViews' to re-interpret array data very efficiently though:

        var tmp = new Uint8Array(17);
        // tmp[0] = 0x00; // initialiased to 0 anyway
        tmp.set(new Uint8Array(displaybuffer.buffer), 1);
        i2c.writeTo(address, tmp);
    
  • Hey @Gordon

    Regarding switching the callbacks for an array buffer, can you suggest a way to handle the bit of code at line 40? Basically, I wire the LED matrix on the opposite side you are supposed to (the chip is meant to be on the back, but I make it so it sits under the LED matrix leaving me a flat back to mount easily) which means I have to do some shifting.

    Basically what happens is, think of the image being in for segments, top left, top right, bottom right and bottom left, well with this wiring, the top left square swaps with bottom right, and top right swaps with bottom left. So you end up with 4 lots of 4x4 squares rendering correctly, but in the wrong order. In my original code then, I just shift things by 4 pixels, however once it's been converted to a uintarray, I don't know the right way to do this? I'm assuming it'll use some bitshifting, but after playing around with it before, I couldn't come up with the right shift (especially when you take the colours into account aswell).

    You got any suggestions? (Likewise for the rotation too)

    Matt

  • Argh. so you have to send one byte for 8 pixels of green, and one byte for 8 pixels of red?

    I actually updated graphics to handle 2 bit colour (if you try one of the pre-release binaries), but that does the bits all next to each other.

    So... If you assume that we'd use Graphics, and the bits are RGRGRGRG in a byte, I guess each byte is conveniently a set of 4 pixels, so you could actually just hard-code the 16 bytes:

    var a = new Uint8Array(Graphics.buffer);
    display([
    a[9],a[1],
    a[11],a[3],
    a[13],a[5],
    a[15],a[7],
    a[8],a[0],
    a[10],a[2],
    a[12],a[4],
    a[14],a[6],
    ]);
    

    And then you 'just' have to figure out a way of un-interleaving each pair of bytes - from: RGRGRGRGRGRGRGRG into RRRRRRRRGGGGGGGG.

    There are some fun bit hacks that can do things like this using multiply, & and shift - although I only see a way to interleave on that site - not un-interleave.

    It should be possible. Assuming we start with aAbBcCdD and you want to get ABCD:

    x &= 0b01010101; // mask out just the bits we want ( 0A0B0C0D )
    x *= 0b0011; // this makes ( AABBCCDD )
    x &= 0b01100110; // mask out again ( 0AB00CD0 )
    x *= 0b0101; // this makes ( ABABCDCD0 )
    x &= 0b01111000; // mask out again ( 0ABCD000 )
    x >>= 3; // shift back ( 0000ABCD )
    

    And you have 64 bits to play with, so you should be able to do at least 8 pixels in red and green at once (maybe 16 ;).

    All good fun - if you're into that kind of stuff :)

  • Ok, I'm confused :)

    I must confess, this stuff doesn't come naturally to me, but if you look at my drawPixel method, and how it handles colours, this is how I currently understand this, see attached (correct me if I'm wrong).

    So I believe it builds up a matrix where for every Y position, it stores a 16byte value, the bits in that value dictate whether an LED should be on or off. I think the first 8 bytes are for green, and the second 8 are for red, or maybe the other way, I can't tell :) if they are both on at the same time thought, you get yellow. Now when I'm talking segments getting mixed up, see the black lines on the picture, each 4x4 square renders as it should, but each black square is in the wrong location, so the top left green one, is in the bottom right green one and vica-versa for the other opposite corner / colours.

    So, is that how you understood me? and do your examples hold true for this? and also, looking at my code, is my assumption of how this work correct? :)

    Cheers

    Matt


    1 Attachment

    • pic.jpg
  • Holy heck, I think I've just learnt something :)

    So, playing with the buffer array I have, it's seems I was wrong about the order, it's red, then green, but the rest is true :)

    And I've also figured out how to bitshift the segments in an array entry (so the 1st and 3rd block of 4 shift right 4, and the 2nd and 4th shift left 4).

    rowValue  = ((rowValue & 0x0F0F) << 4) | ((rowValue & 0xF0F0) >> 4);
    

    Woo hoo! :)

    So what would be the most performant way to do this within my updateDisplay method? My natural instinct would be to create a new array, and loop the other creating new (shifted) values, then do what I'm currently doing now to render it. Would that be the way to go?

  • So I believe it builds up a matrix where for every Y position, it stores a 16byte value, the bits in that value dictate whether an LED should be on or off. I think the first 8 bytes are for green, and the second 8 are for red, or maybe the other way, I can't tell :) if they are both on at the same time thought, you get yellow. Now when I'm talking segments getting mixed up, see the black lines on the picture, each 4x4 square renders as it should, but each black square is in the wrong location, so the top left green one, is in the bottom right green one and vica-versa for the other opposite corner / colours.

    The first thing I would do is print the data being sent to the display (in the form it's being sent) to the console before sending to display, then convert that to binary and draw out what you'd "expect" based on that on graph paper, and compare it to the pattern on the display.

    That way, you'll know if the issue is that the display doesn't work the way you think it does, or just an issue with the JS that prepares the data to send it.

    Edit: Note - this was posted before your most recent post - it sounds like you've made some progress, so this may not be useful anymore.

  • Right, so what I meant is that while your display accepts the data as you say, the Graphics library in 1v61 will interleave red and green (like it would for any other bit depth). I'm not going to do a fancy colour diagram, but the data will look like:

    RGRGRGRGRGRGRGRG
    RGRGRGRGRGRGRGRG
    RGRGRGRGRGRGRGRG
    RGRGRGRGRGRGRGRG
    RGRGRGRGRGRGRGRG
    RGRGRGRGRGRGRGRG
    RGRGRGRGRGRGRGRG
    RGRGRGRGRGRGRGRG
    

    So the code I had with the crazy shifting stuff will turn that into what you had (eventually).

    If you don't want to use graphics and just want to carry on as you are, and you want to do it quickly, I'd suggest just repeating the code you have 16 times (once for each nibble):

    i2c.writeTo(address, [0,
    ((rowValue & 0x0F) << 4) | ((rowValue & 0xF0) >> 4),
    ((rowValue & 0x0F00) >> 4) | ((rowValue & 0xF000) >> 12),
    ...
    ]);
    

    You might find that putting it into a Uint16Array and doing a view of it was easier, but to be honest you'd have to benchmark:

    var u16 = new Uint16Array([0,
    ((rowValue & 0x0F0F) << 4) | ((rowValue & 0xF0F0) >> 4),
    ...]);
    var u8 = new Uint8Array(u16.buffer, 1); // <-- 1 because the '0' above took up 2 bytes
    i2c.writeTo(address,u8);
    

    PS. Multiply-AND tricks are fun. If you think about what is going on with a multply, it's like a repeated shift-add:

    a * b = 
       (a&1) ? b<<0 : 0 + 
       (a&2) ? b<<1 : 0 + 
       (a&4) ? b<<2 : 0 + 
      ...
    

    So if you multiply by 5 (0b0101) you've got:

    5 * b =  b<<0 + b<<2;
    

    So it's potentially 64 shift and adds in a single operation :)

  • Thanks @Gordon, I get what you mean now with the interleaving. I'll do what you said and take a look at the values being rendered and see what I can come up with.

    Haven't quite got my head around the multiply-AND yet, so I think some experimenting with that is in order too. Sounds powerful though :)

    Matt

  • @Gordon looking at converting the callback to a graphics array then. If I switch the callback to be a buffer array, when I debug out the contents of the buffer, I have an array as follows:

    [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2­,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1­,1,1,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1­,1,1,1,1]
    

    If I format this a little, you'll see it is meant to print out an E with the E in red, and the background yellow:

    [
    1,1,1,1,1,1,1,1,
    1,1,1,1,1,1,1,1,
    1,1,2,2,2,2,2,2,
    1,1,1,1,1,1,1,1,
    1,1,1,1,1,1,1,1,
    1,1,2,2,2,2,2,2,
    1,1,1,1,1,1,1,1,
    1,1,1,1,1,1,1,1
    ]
    

    So, if I look at what was previously being sent down the line, it needs an array with the buffer:

    [0,0,255,0,255,252,255,0,255,0,255,252,2­55,0,255,0,255]
    

    Which should be the buffer of:

    new Uint16Array([65280,65280,65532,65280,652­80,65532,65280,65280])
    

    But with an extra 0 in position 0.

    Converting the Uint16 array to binary, we can see that it is:

    1111111100000000
    1111111100000000 
    1111111111111100 
    1111111100000000 
    1111111100000000 
    1111111111111100 
    1111111100000000 
    1111111100000000 
    

    (Not sure whether the E being backwards is something I've done, or just the way it is, but I'll figure that bit out later).

    So, should I loop through the buffer array and construct a Uint16Array (handling each entry one at a time, kinda like the drawPixel method currently but all in one go at the point of render) and then do what I'm currently doing to create the array buffer with the extra 0 at position 0 with the code:

    var tmp = new Uint8Array(17);
    tmp.set(new Uint8Array(displaybuffer.buffer), 1);
    

    With all of this though, I'm not sure where the interleaved colour handling you were talking about in buffer array comes into play as I can't see it? Am I missing something there?

    Matt

  • If you update to 1v61 now, you can get 2 bit graphics:

    g = Graphics.createArrayBuffer(8,8,2);
    g.setColor(1)      
    g.drawLine(0,0,7,7)
    g.setColor(2)      
    g.drawLine(7,0,0,7)  
    
    a = new Uint16Array(g.buffer)     
    for (i in a) print((a[i]|0x10000).toString(2).substr(­1))         
    1000000000000001
    0010000000000100
    0000100000010000
    0000001001000000
    0000000110000000
    0000010000100000
    0001000000001000
    0100000000000010
    RGRGRGRGRGRGRGRG
    
    

    Does that help? That's why you'd want to un-interleave...

  • Awesome, yea, that's what I was trying to get to :)

    I've got this code now which should do the un-interleaving (per row)

    t = (x ^ (x >> 1)) & 0x2222;  x = x ^ t ^ (t << 1); 
    t = (x ^ (x >> 2)) & 0x0C0C;  x = x ^ t ^ (t << 2); 
    t = (x ^ (x >> 4)) & 0x00F0;  x = x ^ t ^ (t << 4); 
    

    Matt

  • x &= 0b01010101; // mask out just the bits we want ( 0A0B0C0D )
    x *= 0b0011; // this makes ( AABBCCDD )
    x &= 0b01100110; // mask out again ( 0AB00CD0 )
    x *= 0b0101; // this makes ( ABABCDCD0 )
    x &= 0b01111000; // mask out again ( 0ABCD000 )
    x >>= 3; // shift back ( 0000ABCD )
    // to...
    ((((x&0b01010101)*0b0011)&0b01100110)*0b­0101&0b01111000)>>3
    // and pushed through a minifier...
    (5*(3*(x&85)&102)&120)>>3
    

    and then it all got a bit ridiculous:

    g = Graphics.createArrayBuffer(8,8,2);
    g.setColor(1);
    g.drawLine(0,0,7,7);
    g.setColor(2);
    g.drawLine(7,0,0,7);
    
    
    a = g.buffer;
    
    // minified...
    // ((((x&0b01010101)*0b0011)&0b01100110)*0b­0101&0b01111000)>>3  -> 5*(3*(a[0]&85)&102)&120)>>3
    // ((((x&0b10101010)*0b0011)&0b11001100)*0b­0101&0b11110000)>>4  -> 5*(3*(a[0]&170)&204)&240)>>4 
    
    b = new Uint8Array([ 
    (5*(3*(a[0]&85)&102)&120)>>3 | (5*(3*(a[1]&85)&102)&120)<<1, (5*(3*(a[0]&170)&204)&240)>>4 | (5*(3*(a[1]&170)&204)&240), 
    (5*(3*(a[2]&85)&102)&120)>>3 | (5*(3*(a[3]&85)&102)&120)<<1, (5*(3*(a[2]&170)&204)&240)>>4 | (5*(3*(a[3]&170)&204)&240), 
    (5*(3*(a[4]&85)&102)&120)>>3 | (5*(3*(a[5]&85)&102)&120)<<1, (5*(3*(a[4]&170)&204)&240)>>4 | (5*(3*(a[5]&170)&204)&240), 
    (5*(3*(a[6]&85)&102)&120)>>3 | (5*(3*(a[7]&85)&102)&120)<<1, (5*(3*(a[6]&170)&204)&240)>>4 | (5*(3*(a[7]&170)&204)&240), 
    (5*(3*(a[8]&85)&102)&120)>>3 | (5*(3*(a[9]&85)&102)&120)<<1, (5*(3*(a[8]&170)&204)&240)>>4 | (5*(3*(a[9]&170)&204)&240), 
    (5*(3*(a[10]&85)&102)&120)>>3 | (5*(3*(a[11]&85)&102)&120)<<1, (5*(3*(a[10]&170)&204)&240)>>4 | (5*(3*(a[11]&170)&204)&240), 
    (5*(3*(a[12]&85)&102)&120)>>3 | (5*(3*(a[13]&85)&102)&120)<<1, (5*(3*(a[12]&170)&204)&240)>>4 | (5*(3*(a[13]&170)&204)&240), 
    (5*(3*(a[14]&85)&102)&120)>>3 | (5*(3*(a[15]&85)&102)&120)<<1, (5*(3*(a[14]&170)&204)&240)>>4 | (5*(3*(a[15]&170)&204)&240)
    ]);
     
    
    c = new Uint16Array(b.buffer);
    for (i in c) print((c[i]|0x10000).toString(2).substr(­1));
    
    // outputs
    1000000000000001
    0100000000000010
    0010000000000100
    0001000000001000
    0000100000010000
    0000010000100000
    0000001001000000
    0000000110000000
    

    And to swap the quadrants around, all you've got to do is swap the a[0,2,4,6] with a[9,11,13,15] in the insane block of code above.

  • Ahh, I didn't see your last post - I was getting carried away. If I'm honest your un-interleaving looks a lot less insane than mine.

    In the code above, instead of b = new Uint8Array([ you could just send it straight out to I2C.

    I'm unsure if it really is faster than a simple for loop - but it looks like it is :) In both our cases we could actually do more bits in an operation than we have - but then we're back to the problem of swapping the quadrants.

  • Ok, haven't fully read your posts yet, which I will now, but here is what I have currently, which does work:

        var a = new Uint16Array(display2.buffer);
        var b = new Uint16Array(8);
        
        for(var i=0;i<a.length;i++)
        {
          var k = (i + 4) % 8;
          var x = a[i];
          
          // Uninterleave
          var t = (x ^ (x >> 1)) & 0x2222;  x = x ^ t ^ (t << 1); 
          t = (x ^ (x >> 2)) & 0x0C0C;  x = x ^ t ^ (t << 2); 
          t = (x ^ (x >> 4)) & 0x00F0;  x = x ^ t ^ (t << 4); 
          
          // Shift
          b[k] = ((x & 0x0F0F) << 4) | ((x & 0xF0F0) >> 4);
        }
        
        var tmp = new Uint8Array(17);
        tmp.set(new Uint8Array(b.buffer), 1);
        
        i2c.writeTo(address, tmp);
    

    the 'k' and 'shift' part of the sequence do the fixing of quadrents ('k' shifts up / down and the 'shift' code, shifts horizontally). Because I need to write one coordinates value to a different location, that is why I needed the 'b' array otherwise I'd overwrite values in 'a' I hadn't processed yet if I just tried to update 'a'.

  • C00l - to be honest for 8 iterations that's going to be more than fast enough, and it's actually readable :)

    So you can actually write text with the graphics lib and have it display on the matrix?

  • Ok, I've had a read of yours. I guess it comes down to performance vs readability. What kind of performance hit does adding a loop create? What's the best way to test performance of a method?

  • oops, missed your reply. But seems you were of the same mind as me anyway :)

    And in answer to your question, yes, yes you can :)

    Check out the demo http://www.youtube.com/watch?v=rkK0aqxzk­-M&feature=youtu.be

  • Probably best to remove the I2C write, and then just do:

    var a = getTime();
    for (var i=0;i<100;i++) doFunc();
    var b = getTime();
    console.log((b-a)/100);
    

    For 8 iterations the performance hit of a loop won't be that great at all - I was just getting carried away :)

  • That looks great! So did you hack it onto the existing game shield?

  • Yup :) I did a write up for the creators here (need to update my project page with the same), but I basically removed the original matrix, stuck the adafruit shield in place, and hot wired it the the relevant pins. Works a treat :)

    The great thing is, it's got it's own internal oscilator, so I only have to send it something when I want it to update, not like the previous one that required every line updating every ms.

    Matt

  • @gordon regarding rotation, would this be something easy enough to add to arrayBuffer? or should I implement my own solution for now? (I've created an issue for it on GitHub)

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

Trying to assign to an un-named type

Posted by Avatar for mattbrailsford @mattbrailsford

Actions