• Back with an alpha ( some things doesn't work as they should, and I'm still missing the finalized data ( timed mouth indices & mouths data ) ), but it's cleaner than previously ;)

    also, I managed to wreck my code somehow somewhere & now I can't control the last led any more :|

    if anyone's feeling brave enough to visually troubleshoot, be my guest ;)
    ( as always, I'll do so after some rest ;) )

    this being said, the pre-pre-pre-alpha code

    /* ==== Akali's Mask V0.1a ==== */
    
    // -- MODULES --
    // - little 'dotstar' module -
    // usage:
    // var dotStar = exports(spi); // pass spi obj
    //dotStar.write(ledsValues); // pass array of leds colors
    var exports = function (spi) {
      return { 
        write: function(ledsData){
          spi.write([0x00,0x00,0x00,0x00]); // start frame
          spi.write(ledsData); // led frames
          for(var y=0; y<(ledsData.length/2)/8; y++){ spi.write(0x00); } // end frame
        }
      };
    };
    
    // -- COLORS/PATTERNS HELPER --
    // R: APA102 are BGR for me
    function getColoredPattern(colR, colG, colB, start, end, clear) {
      var tstart = (start > 0)? start*4-3 : 0 || 0;
      var tend = end*4 || ledsBuff.length;
      for (var i=0;i<ledsBuff.length;i+=4) { // Q: is it where my 'one less led' comes from ? :/
        if(i>=tstart && i < tend){
          ledsBuff[i] = 0xe0+31;
          ledsBuff[i+1] = colB;
          ledsBuff[i+2] = colG;
          ledsBuff[i+3] = colR;
        } else if(clear) { // doesn't work ? :/
          ledsBuff[i] = 0xe0+31;
          ledsBuff[i+1] = 0;
          ledsBuff[i+2] = 0;
          ledsBuff[i+3] = 0;
        }
      }
      return ledsBuff;
    }
    
    // R: steps may (later ) be used to either:
    // - map '0' to '255, 0, 0, 0' & '1' to '255, 255, 255, 255' ( by def we store 1 & 0's, but lookup table set with R,G,B vals at each index can be used )
    //   Nb: we could then for example get the color of the item above a dot on Illustrator as an idx of its color in our 'shared' palette
    // - map 'R, G, B' to '255, B, G, R', what we currently do
    var colorsPalette = [[0, 0, 0], [255, 255, 255]];
    function getPattern(array, steps) {
      for (var i=0, y=0; i<ledsBuff.length;i+=4, y+=steps) {
        if(steps == 1){
          ledsBuff[i] = 0xe0+31;
          //var val = (array[y] == 1)? 255 : 0; // would only support on/ff instead of paletted idx which offer 255 choices
          ledsBuff[i+1] = colorsPalette[array[y]][2]; // B
          ledsBuff[i+2] = colorsPalette[array[y]][1]; // G
          ledsBuff[i+3] = colorsPalette[array[y]][0]; // R
        } else if(steps == 3){
          ledsBuff[i] = 0xe0+31;
          ledsBuff[i+1] = array[y+2]; // B
          ledsBuff[i+2] = array[y+1]; // G
          ledsBuff[i+3] = array[y]; // R
        } else if(steps == 4){
          ledsBuff[i] = array[y]; // brightness
          ledsBuff[i+1] = array[y+1]; // R
          ledsBuff[i+2] = array[y+2]; // G
          ledsBuff[i+3] = array[y+3]; // B
        }
      }
      return ledsBuff;
    }
    
    
    // -- LEDS WORKING CHECK --
    function checkLeds(delay){
      setTimeout(function(){
        dotStar.write(getColoredPattern(255, 0, 0, 0, ledsCount));
        setTimeout(function(){
          dotStar.write(getColoredPattern(0, 255, 0, 0, ledsCount));
          setTimeout(function(){
            dotStar.write(getColoredPattern(0, 0, 255, 0, ledsCount));
            setTimeout(function(){
              dotStar.write(getColoredPattern(255, 255, 255, 0, ledsCount));
              setTimeout(function(){
                dotStar.write(getColoredPattern(0, 0, 0, 0, ledsCount));
              },delay);
            },delay);
          },delay);
        },delay);
      },delay);
    }
    
    
    // -- MOUTHS --
    // TODO: generate dummys & finalize the leds mouths in Illustrator
    // for finalized: how many ? number of leds in each ? which leds are on for each ?
    // R: since we have to store at least 8 different mouths ( and by default, only on/off states of leds in those ),  storing 1's & 0's ( or paletted color idx)
    //    make more sense to lessen the space taken
    // ex: leds * BrRGB * mouths = 45 * 4 * 8 = 1440 bytes ( with brightness control )
    //     leds * RGB * mouths = 45 * 3 * 8 = 1080 bytes ( any color, no brightness control )
    //     leds * paletted idx * mouths = 45 * 1 * 8 = 360 bytes ( 255 possible colors )
    var ledsBuff = new Uint8ClampedArray(45*4); // used as tmp to fill in /map in values while keeping constant brightness
    var mouthsLedsArrays = [
      //new Uint8ClampedArray([0,0,0,0,0,0,255,255,2­55,255,255,255,255,255,255,0,0,0,0,0,0,0­,0,0,0,0,0,255,255,255,255,255,255,255,2­55,255,0,0,0,0,0,0]),
      //new Uint8ClampedArray(45*3),
    ];
    // dummies generator, to test stuff before finalizing the mouths leds arrays
    function generateDummies(howMany){
      for(var i=0; i<howMany; i++){ // R/ testing with 45 leds
        console.log('pushing dummy: [' + (i*9) + '..' + (i*9+9) + ']' );
        //ledsBuff = new Uint8ClampedArray(45*4); // fill buff with 0's
        getColoredPattern(0, 0, 0, 0, ledsCount); // same as above, faster way that doesn't re-allocate a clamped array
        //mouthsLedsArrays.push(getColoredPatter­n(255, 255, 255, i*9, i*9+9)); // push 9/45 of leds to our array ( uses buff internally ) - increasing
        //mouthsLedsArrays.push(getColoredPatter­n(255, 255, 255, i*9, i*9+9)); // push 9/45 of leds to our array ( uses buff internally ) - moving .. not ? :/
        mouthsLedsArrays.push(getColoredPattern(­255/9*i, 255/9*i, 255/9*i, i*9, i*9+9)); // push 9/45 of leds to our array ( uses buff internally )
      }
    }
    
    
    // -- TIMING --
    // TODO: get final timings ( absolute or relative )
    // R: we have generated 5 mouths for our debug, each with 9 leds
    var absTimeMouthsIdxsArray = [
      //[<ms_from_start>, <mouth_idx>]
      [37,    0],
      [38,    1],
      [40,    2],
      [45,    3],
      [45.2,  4],
      [45.5,  3],
      [45.7,  2],
      [45.8,  1],
      [45.9,  0],
      [45.95, 1],
      [45.99, 2],
      [46,    3],
      [50,    4]
    ];
    // R: to map abolute times to relative timing in ms: relTime = (absTime * 1000) - (1stAbsTime * 1000)
    var reTimeMouthsIdxsArray = [];
    for(var i=0; i< absTimeMouthsIdxsArray.length; i++){
      var relTime = (i === 0) ? ((absTimeMouthsIdxsArray[i][0] * 1000) - (absTimeMouthsIdxsArray[i][0] * 1000)) :
                                 (absTimeMouthsIdxsArray[i][0] * 1000) - (absTimeMouthsIdxsArray[i-1][0] * 1000);
      reTimeMouthsIdxsArray[i] = [relTime, absTimeMouthsIdxsArray[i][1]];
    }
    
    
    // -- ANIMATION --
    // transition between mouths
    function nxtMouth(){
      if(currMouthAnimIdx+1 < reTimeMouthsIdxsArray.length){ // didn't reach end of array yet
        currMouthAnimIdx = currMouthAnimIdx+1;
        timr = setTimeout(function(){
          currMouth = mouthsLedsArrays[reTimeMouthsIdxsArray[c­urrMouthAnimIdx][1]];
          // useful for generated dummies
          console.log('currMouthIdx: ' +currMouthAnimIdx);
          //dotStar.write(getPattern(currMouth, 4));// update leds - we pass an array of paletted idx, rgb values or BrRGB values & a 'step' to indicate format
          getColoredPattern(0, 0, 0, 0, ledsCount); // clear buffer 
          dotStar.write(getColoredPattern(0, 0, 100, 0, currMouthAnimIdx*4, true)); // debuuuuug
          // for final impl
          //dotStar.write(getPattern(currMouth, 1));// update leds - we pass an array of paletted idx, rgb values or BrRGB values & a 'step' to indicate format
          nxtMouth(); // schedule next call
        }, reTimeMouthsIdxsArray[currMouthAnimIdx][­0]);
      } else {
        timr = -1;
        console.log('end of mouth timed array reached -> animation complete !');
        resetState();
      }
    }
    
    
    // -- BUTTON PRESS HANDLER: START/RESET --
    function handleBtnPress(){
      if(animating){ // currently animating: reset
        resetState();
      }
      else { // currently stopped: animate
        animating = true;
        console.log('animating !');
        nxtMouth(); // TODO: uncomment once we have final mouths arrays or generated dummys
      }
    }
    
    function resetState(){
      console.log('resetting !');
      if(timr !== -1){
        clearTimeout(timr);
        timr = -1;
      }
      currMouthAnimIdx = 0;
      currMouth = mouthsLedsArrays[reTimeMouthsIdxsArray[c­urrMouthAnimIdx][1]];
      dotStar.write(getColoredPattern(0, 0, 0, 0, ledsCount)); // clear
      animating = false;
    }
    
    
    // -- SETUP --
    // - modules -
    var spi;
    var dotStar;
    // - pins -
    var btn = BTN1;
    var dotStarSck = B3;
    var dotStarMosi = B5;
    // - watches -
    var btnW;
    // - vars -
    var ledsCount = 45;
    var animating = false;
    var timr = -1;
    var currMouthAnimIdx = 0; // where we're at in the 'reTimeMouthsIdxsArray'
    //var currMouthIdx = 0;
    var currMouth = mouthsLedsArrays[reTimeMouthsIdxsArray[c­urrMouthAnimIdx][1]];
    
    
    function onInit(){
      // setup modules
      spi = SPI1;
      spi.setup({miso:B4, mosi:dotStarMosi, sck:dotStarSck, mode:0,order:"msb", baud: 4000000});
      //spi.setup({mosi:dotStarMosi, sck:dotStarSck, mode:0,order:"msb", baud: 4000000});
      dotStar = exports(spi);
      dotStar.write(getColoredPattern(0, 0, 0, 0, ledsCount)); // start with all leds fully off
    
      // setup button
      //pinMode(btn, 'input_pullup');
      btnW = setWatch(function(e) { handleBtnPress(); }, btn, { repeat:true, edge:'rising', debounce: 100 });
      
      // debug logs
      console.log('currMouthAnimIdx : ' + currMouthAnimIdx);
      console.log('currMouth : ' + currMouth);
      console.log('reTimeMouthsIdxsArray : ' + reTimeMouthsIdxsArray);
      console.log('reTimeMouthsIdxsArray.lengt­h : ' + reTimeMouthsIdxsArray.length);
      
      // generate dummies to test until we have final mouths
      generateDummies(5); // we pass how many we want
    
      // quick leds feedback
      checkLeds(1000); // we pass the delay between color change
      
      // feedback - fully booted indication
      digitalWrite(LED3, 1);
    }
    
About

Avatar for stephaneAG @stephaneAG started