[
  {
    "path": "FrekvensPanel/FrekvensPanel.cpp",
    "content": "// By /u/frumperino\n// goodwires.org\n\n#include \"FrekvensPanel.h\"\n\nvoid init(int p_latch, int p_clock, int p_data, int p_enable);\n\nFrekvensPanel::FrekvensPanel(int p_latch, int p_clock, int p_data, int bitDepth,\n                             int numPanels) : Adafruit_GFX(16, numPanels * 16)\n{\n    init(p_latch, p_clock, p_data, bitDepth, numPanels);\n}\n\nFrekvensPanel::FrekvensPanel(int p_latch, int p_clock, int p_data) :\nFrekvensPanel(p_latch, p_clock, p_data, 0, 1) { }\n\nvoid FrekvensPanel::init(int p_latch, int p_clock, int p_data, int bitDepth, int numPanels)\n{\n    _pLatch = p_latch;\n    _pClock = p_clock;\n    _pData = p_data;\n    pinMode(_pLatch, OUTPUT);\n    pinMode(_pClock, OUTPUT);\n    pinMode(_pData, OUTPUT);\n    _bitDepth = bitDepth;\n    _numPages = (1 << bitDepth);\n    _pageMask = _numPages - 1;\n    _numPanels = numPanels;\n    _pageStride = 16 * numPanels;\n    _numWords = _numPages * _pageStride;\n    _numPixels = 16 * 16 * numPanels;\n    _addressMask = _numPixels-1;\n    _width = 16;\n    _height = 16 * _numPanels;\n    buf = (unsigned short*) malloc(_numWords * sizeof(unsigned short));\n}\n\nvoid FrekvensPanel::clear()\n{\n    for (int i=0;i<_numWords;i++)\n    {\n        buf[i] = 0;\n    }\n}\n\nvoid FrekvensPanel::writeDeepPixel(unsigned short x, unsigned short y, unsigned short value)\n{\n    if (x > 7) { y += 0x10; x &= 0x07; }\n    unsigned int address = (x + (y << 3)) & _addressMask;\n    unsigned short ba = address >> 4;\n    unsigned short br = address & 0x0F;\n    unsigned short ms = (1 << br);\n    unsigned short mc = 0xFFFF ^ ms;\n    unsigned short* wp = &buf[ba];\n    unsigned short ofs = (x+y) & _pageMask;\n    for (unsigned int i=0;i<_numPages;i++)\n    {\n        ofs++;\n        ofs &= _pageMask;\n        char b = ((value >> ofs) & 0x01);\n        if (b)\n        {\n            *wp |= ms;\n        }\n        else\n        {\n            *wp &= mc;\n        }\n        wp+=_pageStride;\n    }\n}\n\nvoid FrekvensPanel::scan()\n{\n    if (_numPages == 1)\n    {\n        // single bit plane\n        unsigned short* p = &buf[0];\n        for (int i=0;i<_pageStride;i++)\n        {\n            unsigned short w = *p++;\n            for (int j=0;j<16;j++)\n            {\n                digitalWrite(_pData, w & 0x01);\n                w >>= 1;\n                digitalWrite(_pClock, HIGH);\n                delayMicroseconds(1);\n                digitalWrite(_pClock, LOW);\n            }\n        }\n        digitalWrite(_pLatch,HIGH);\n        delayMicroseconds(1);\n        digitalWrite(_pLatch,LOW);\n    }\n    else\n    {\n        // multiple bit planes\n        unsigned short* p = &buf[_pageStride * _activePage];\n        for (int i=0;i<_pageStride;i++)\n        {\n            unsigned short w = *p++;\n            for (int j=0;j<16;j++)\n            {\n                digitalWrite(_pData, w & 0x01);\n                w >>= 1;\n                digitalWrite(_pClock, HIGH);\n                delayMicroseconds(1);\n                digitalWrite(_pClock, LOW);\n            }\n        }\n        digitalWrite(_pLatch,HIGH);\n        delayMicroseconds(1);\n        digitalWrite(_pLatch,LOW);\n        _activePage++;\n        _activePage %= _numPages;\n    }\n}\n\nunsigned short FrekvensPanel::width()\n{\n    return this->_width;\n}\n\nunsigned short FrekvensPanel::height()\n{\n    return this->_height;\n}\n\nboolean FrekvensPanel::getPixel(int16_t x, int16_t y)\n{\n    if (x > 7) { y += 0x10; x &= 0x07; }\n    unsigned short address = (x + (y << 3)) & _addressMask;\n    unsigned short ba = address >> 4;\n    unsigned short br = address & 0x0F;\n    unsigned short* wp = &buf[ba];\n    return ((*wp) >> br) & 0x01;\n}\n\nvoid FrekvensPanel::drawPixel(int16_t x, int16_t y, uint16_t color)\n{\n    if ((x >= 0) && (y >= 0) && (x < _width) && ( y < _height))\n    {\n        if (x > 7) { y += 0x10; x &= 0x07; }\n        unsigned short address = (x + (y << 3)) & _addressMask;\n        unsigned short ba = address >> 4;\n        unsigned short br = address & 0x0F;\n        unsigned short ms = (1 << br);\n        unsigned short* wp = &buf[ba];\n        if (color & 0x01)\n        {\n            *wp |= ms;\n        }\n        else\n        {\n            *wp &= (0xFFFF ^ ms);\n        }\n    }\n}\n\nvoid FrekvensPanel::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color)\n{\n    for (int i=0;i<h;i++)\n    {\n        drawPixel(x,y+i,color);\n    }\n\n}\n\nvoid FrekvensPanel::drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color)\n{\n    for (int i=0;i<w;i++)\n    {\n        drawPixel(x+i,y,color);\n    }\n}\n\nvoid FrekvensPanel::fillScreen(uint16_t color)\n{\n    for (int i=0;i<_numPages;i++)\n    {\n        unsigned short w = color & 0x01 ? 0xFFFF : 0x0000;\n        color >>= 1;\n        unsigned short* p = &buf[i * _pageStride];\n        for (int j=0;j<_pageStride;j++)\n        {\n            *p++ = w;\n        }\n    }\n}\n\n\n\n\n\n"
  },
  {
    "path": "FrekvensPanel/FrekvensPanel.h",
    "content": "// by /u/frumperino\n// goodwires.org\n\n#ifndef __FREKVENSPANEL_H\n#define __FREKVENSPANEL_H\n\n#include <Arduino.h>\n#include <Adafruit_GFX.h>\n\nclass FrekvensPanel : public Adafruit_GFX\n{\nprivate:\n    unsigned short _numPanels : 4;\n    unsigned short _numPages : 4;\n    unsigned short _activePage : 4;\n    unsigned short _bitDepth : 4;\n    unsigned short _pLatch;\n    unsigned short _pClock;\n    unsigned short _pData;\n    unsigned short* buf;\n    unsigned short _pageMask;\n    unsigned short _addressMask;\n    unsigned short _numWords;\n    unsigned short _pageStride;\n    unsigned short _numPixels;\n    unsigned short _width;\n    unsigned short _height;\n\npublic:\n    FrekvensPanel(int p_latch, int p_clock, int p_data, int bitDepth,\n                  int numPanels);\n    FrekvensPanel(int p_latch, int p_clock, int p_data);\n\n    void init(int p_latch, int p_clock, int p_data, int bitDepth, int numPanels);\n    void clear();\n    void scan();\n    void writeDeepPixel(unsigned short x, unsigned short y, unsigned short value);\n\n    boolean getPixel(int16_t x, int16_t y);\n\n    unsigned short width();\n    unsigned short height();\n\n    void drawPixel(int16_t x, int16_t y, uint16_t color) override;\n    void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) override;\n    void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) override;\n    void fillScreen(uint16_t color) override;\n\nprivate:\n\n};\n\n\n#endif //__FREKVENSPANEL_H\n"
  },
  {
    "path": "FrekvensPanel/examples/buttons/button.h",
    "content": "//\n// Created by /u/frumperino\n//\n\n#include <Arduino.h>\n\n#ifndef __simplebutton_h\n#define __simplebutton_h\n\ntypedef void (*ButtonEH) (int, int); // id, state\n\nclass SimpleButton\n{\nprivate:\n    unsigned short pin      : 8;\n    unsigned short state    : 1;\n    unsigned short invert   : 1;\n    unsigned short changing : 1;\n    unsigned short attached : 1;\n    char id;\n    ButtonEH handler = nullptr;\n    unsigned short debounceMS;\n    unsigned long tChange = 0;\npublic:\n    SimpleButton(char id, char pin, char invert, unsigned short debounceMS)\n    {\n        this->id = id;\n        this->invert = invert;\n        this->pin = pin;\n        this->changing = false;\n        this->debounceMS = debounceMS;\n        this->state = digitalRead(pin);\n        this->attached = false;\n    }\n\n    void attachHandler(ButtonEH handler)\n    {\n        this->handler = handler;\n        this->attached = true;\n    }\n\n    char getState()\n    {\n        return this->state;\n    }\n\n    void scan()\n    {\n        char newState = digitalRead(pin);\n        if (newState == state)\n        {\n          changing = false;          \n        }\n        else\n        {\n            unsigned long tNow = millis();\n            if (!changing)\n            {\n                changing = true;\n                tChange = tNow;\n            }\n            else\n            {\n                unsigned long tD = tNow - tChange;\n                if (tD >= debounceMS)\n                {\n                    state = newState;\n                    changing = false;\n                    if (attached)\n                    {\n                        handler(id, state ^ invert);\n                    }\n                }\n            }\n        }\n    }\n\n};\n\n#endif //__simplebutton_h\n"
  },
  {
    "path": "FrekvensPanel/examples/buttons/buttons.ino",
    "content": "#include <FrekvensPanel.h>\n// see readme.md for wiring instructions\n\n#include \"button.h\"\n\n#define buttonCOM_VCC // comment out this line if button COM is wired to GND.  \n\n#define p_ena 5 \n#define p_data 6\n#define p_clock 9\n#define p_latch 10\n\n#define p_btn1 14 // A0 (Adafruit Feather M0) - RED button (black wire)\n#define p_btn2 15 // A1 (Adafruit Feather M0) - YELLOW button (white wire)\n\nFrekvensPanel panel(p_latch, p_clock, p_data);\n\nchar activeProgram = 1;\nchar activeBrightMode = 1;\n\n#ifdef buttonCOM_VCC\n// the red wire (COM) for the buttons is connected to (MCU board) VCC, \n// so the button signal is positive and the button input pins must be set to INPUT_PULLDOWN\nSimpleButton button1(1,p_btn1,0,20);\nSimpleButton button2(2,p_btn2,0,20);\n#else\n// the red wire (COM) for the buttons is connected to GND, so the button signal is inverted\nSimpleButton button1(1,p_btn1,1,20);\nSimpleButton button2(2,p_btn2,1,20);\n#endif\n\nvoid setBrightMode(int brightMode)\n{\n  activeBrightMode = brightMode % 4;\n  switch(activeBrightMode)\n  {\n    case 0: { pinMode(p_ena, OUTPUT); digitalWrite(p_ena, 1); } break; // off\n    case 1: analogWrite(p_ena, 254); break; // very dim\n    case 2: analogWrite(p_ena, 240); break; // dim\n    case 3: { pinMode(p_ena, OUTPUT); digitalWrite(p_ena, 0); } break; // on 100%\n  }\n}\n\nvoid setProgram(int program)\n{\n  activeProgram = (program % 3);\n}\n\nvoid buttonHandler(int id, int state)\n{\n  if (state) // button pressed\n  {\n    switch(id)\n    {\n      case 1: setBrightMode(activeBrightMode+1); break;\n      case 2: setProgram(activeProgram+1); break;\n    }\n  }  \n}\n\nvoid program0()\n{\n  for (int i=0;i<20;i++)\n  {\n    panel.drawPixel(random(16),random(16),random(10) == 0);\n  }\n}\n\nint p1_i = 0;\nvoid program1()\n{\n  float pi23 = PI*2/3;\n  float p = 0.02 * p1_i++;\n  int x0 = 7.98 + 7.98 * cos(p);\n  int y0 = 7.98 + 7.98 * sin(p);\n  p += pi23;\n  int x1 = 7.98 + 7.98 * cos(p);\n  int y1 = 7.98 + 7.98 * sin(p);\n  p += pi23;\n  int x2 = 7.98 + 7.98 * cos(p);\n  int y2 = 7.98 + 7.98 * sin(p);\n  panel.clear();\n  panel.drawLine(x0,y0,x1,y1,1);  \n  panel.drawLine(x1,y1,x2,y2,1);  \n  panel.drawLine(x2,y2,x0,y0,1);  \n}\n\n\nvoid program2()\n{\n  int x = random(16);\n  int y = random(16);\n  panel.drawRect(x,y,random(16-x),random(16-y),random(6)==0);\n}\n\nvoid setup() \n{\n#ifdef buttonCOM_VCC\n  pinMode(p_btn1, INPUT_PULLDOWN); \n  pinMode(p_btn2, INPUT_PULLDOWN); \n#else\n  pinMode(p_btn1, INPUT_PULLUP); \n  pinMode(p_btn2, INPUT_PULLUP); \n#endif\n  panel.clear();\n  pinMode(p_ena, OUTPUT); \n  analogWrite(p_ena, 0); // full brightness\n  button1.attachHandler(buttonHandler);\n  button2.attachHandler(buttonHandler);\n  panel.scan();\n}\n\nvoid loop() \n{\n  switch(activeProgram)\n  {\n    case 0: program0(); break;\n    case 1: program1(); break;\n    case 2: program2(); break;\n  }\n  panel.scan();\n  button1.scan();\n  button2.scan();\n  delay(2);\n}\n"
  },
  {
    "path": "FrekvensPanel/examples/pika/bm_pika.h",
    "content": "//\n// Created by /u/fumperino on 2020-02-15.\n//\n\n#ifndef __bm_pika_h\n#define __bm_pika_h\n\nstatic const unsigned short bm_pika_width = 56;\nstatic const unsigned short bm_pika_height = 56;\nstatic const unsigned char bm_pika[] =\n{\n        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,  // row 00\n        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,  // row 01\n        0xFF, 0xBF, 0x60, 0xDF, 0xBF, 0xC7, 0xFF,  // row 02\n        0xFF, 0xBF, 0x6F, 0xDF, 0xBF, 0xB9, 0xFF,  // row 03\n        0xFF, 0xBF, 0x6F, 0xDF, 0xBF, 0x7D, 0xFF,  // row 04\n        0xFF, 0xBF, 0x6F, 0xDF, 0xBE, 0xFE, 0xFF,  // row 05\n        0xFF, 0xBF, 0x6F, 0xDF, 0xBE, 0xFE, 0xFF,  // row 06\n        0xFF, 0x80, 0x60, 0xDF, 0xBE, 0xFE, 0xFF,  // row 07\n        0xFF, 0xBF, 0x6F, 0xDF, 0xBE, 0xFE, 0xFF,  // row 08\n        0xFF, 0xBF, 0x6F, 0xDF, 0xBE, 0xFE, 0xFF,  // row 09\n        0xFF, 0xBF, 0x6F, 0xDF, 0xBF, 0x7D, 0xFF,  // row 10\n        0xFF, 0xBF, 0x6F, 0xDF, 0xBF, 0x3B, 0xFF,  // row 11\n        0xFF, 0xBF, 0x60, 0x40, 0x81, 0xC7, 0xFF,  // row 12\n        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,  // row 13\n        0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF,  // row 14\n        0xFF, 0xFF, 0xFC, 0x7F, 0xFF, 0xFF, 0xFF,  // row 15\n        0xFF, 0xFF, 0xFC, 0x7F, 0xFF, 0xFF, 0xFF,  // row 16\n        0xFF, 0xFF, 0xF8, 0x7F, 0xFF, 0xFF, 0xFF,  // row 17\n        0xF8, 0x7F, 0xF8, 0xBF, 0xFF, 0x83, 0xFF,  // row 18\n        0xF7, 0xBF, 0xFB, 0xBF, 0xFC, 0x43, 0xFF,  // row 19\n        0xEF, 0xDF, 0xF3, 0xBF, 0xF3, 0xC7, 0xFF,  // row 20\n        0xEF, 0xDF, 0xF7, 0xC1, 0xCF, 0xCF, 0xFF,  // row 21\n        0xEF, 0xDF, 0xF7, 0x3E, 0x3F, 0x9F, 0xFF,  // row 22\n        0xE0, 0x1F, 0xF5, 0xFF, 0xFF, 0xBE, 0x7F,  // row 23\n        0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0x7D, 0xBF,  // row 24\n        0xFF, 0xDF, 0xEF, 0xFF, 0xFE, 0xFD, 0xCF,  // row 25\n        0xFF, 0xDF, 0xE7, 0xF9, 0xFD, 0xFB, 0xF7,  // row 26\n        0xFF, 0xDF, 0xD7, 0xF4, 0xF3, 0xFB, 0xFB,  // row 27\n        0xE0, 0x1F, 0xC7, 0xF0, 0xFB, 0xF7, 0xFB,  // row 28\n        0xFF, 0xFF, 0xAD, 0xF9, 0xFB, 0xF7, 0xFB,  // row 29\n        0xF1, 0x9F, 0xBF, 0xFF, 0x3D, 0xEF, 0xF7,  // row 30\n        0xEE, 0x7F, 0x9A, 0x6E, 0x1D, 0xEF, 0xEF,  // row 31\n        0xEE, 0xFF, 0x9C, 0x1E, 0x1E, 0xDF, 0xDF,  // row 32\n        0xEE, 0xFF, 0x9E, 0x3F, 0x1E, 0xDF, 0xBF,  // row 33\n        0xE0, 0x1E, 0x5E, 0x7F, 0xAE, 0x5F, 0x7F,  // row 34\n        0xFF, 0xFD, 0xEF, 0xFE, 0x74, 0x6F, 0x3F,  // row 35\n        0xFF, 0xFD, 0xF7, 0xFF, 0xF6, 0x77, 0xDF,  // row 36\n        0xF8, 0x7E, 0xFF, 0xFF, 0xEF, 0xB7, 0x9F,  // row 37\n        0xF7, 0xBF, 0x7F, 0xFF, 0xFF, 0xAF, 0x7F,  // row 38\n        0xEF, 0xDF, 0x9F, 0xFF, 0x8E, 0x9C, 0xFF,  // row 39\n        0xEF, 0xDF, 0xEF, 0xFD, 0x74, 0x2D, 0xFF,  // row 40\n        0xEF, 0xDF, 0xE7, 0xFA, 0xBE, 0x0E, 0xFF,  // row 41\n        0xF7, 0xBF, 0xF7, 0xFB, 0xBF, 0x89, 0xFF,  // row 42\n        0xF8, 0x7F, 0xF7, 0xFB, 0xDF, 0x47, 0xFF,  // row 43\n        0xE7, 0xFF, 0xF7, 0xFD, 0xDF, 0x1F, 0xFF,  // row 44\n        0xF8, 0x7F, 0xFB, 0xFD, 0xDE, 0x7F, 0xFF,  // row 45\n        0xFF, 0x9F, 0xFB, 0xFD, 0xBD, 0xFF, 0xFF,  // row 46\n        0xF8, 0x3F, 0xFD, 0xFE, 0x7B, 0xFF, 0xFF,  // row 47\n        0xE7, 0xFF, 0xFE, 0x7F, 0xC7, 0xFF, 0xFF,  // row 48\n        0xF8, 0x7F, 0xFF, 0x9F, 0x3F, 0xFF, 0xFF,  // row 49\n        0xFF, 0x9F, 0xFF, 0xE4, 0x7F, 0xFF, 0xFF,  // row 50\n        0xF8, 0x3F, 0xFF, 0xF7, 0x7F, 0xFF, 0xFF,  // row 51\n        0xE7, 0xFF, 0xFF, 0xF5, 0x7F, 0xFF, 0xFF,  // row 52\n        0xFF, 0xFF, 0xFF, 0xFA, 0xFF, 0xFF, 0xFF,  // row 53\n        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,  // row 54\n        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,  // row 55\n};\n\n#endif // __bm_pika_h\n"
  },
  {
    "path": "FrekvensPanel/examples/pika/pika.ino",
    "content": "#include <FrekvensPanel.h>\n// see readme.md for wiring instructions\n\n#include \"bm_pika.h\"\n\n#define p_ena 5 \n#define p_data 6\n#define p_clock 9\n#define p_latch 10\n\n#define p_btn1 14 // A0 (Adafruit Feather M0) - RED button (black wire)\n#define p_btn2 15 // A1 (Adafruit Feather M0) - YELLOW button (white wire)\n\nFrekvensPanel panel(p_latch, p_clock, p_data);\n\nint i = 0;\n\nvoid setup() \n{\n  panel.clear();\n  panel.scan();\n  pinMode(p_ena, OUTPUT); \n  analogWrite(p_ena, 0); // full brightness\n}\n\nvoid loop() \n{\n  panel.fillScreen(1);\n  int pw = panel.width();\n  int ph = panel.height();\n  int bw = bm_pika_width;\n  int bh = bm_pika_height;\n\n  float p = (0.002 * i++);\n  float bw2 = (float) (bw - pw) / 2;\n  float bh2 = (float) (bh - ph) / 2;\n  int x = (int) (bw2 + bw2 * cos(p * 3)) - bw + pw;\n  int y = (int) (bh2 + bh2 * sin(p * 4)) - bh + ph;\n  panel.drawBitmap(x,y,&bm_pika[0],bw,bh,0);\n  panel.scan();\n}\n"
  },
  {
    "path": "FrekvensPanel/examples/sparkles/sparkles.ino",
    "content": "#include <FrekvensPanel.h>\n// see readme.md for wiring instructions\n\n#define p_ena 5 \n#define p_data 6\n#define p_clock 9\n#define p_latch 10\n\n#define p_btn1 14 // A0 (Adafruit Feather M0) - RED button (black wire)\n#define p_btn2 15 // A1 (Adafruit Feather M0) - YELLOW button (white wire)\n\nFrekvensPanel panel(p_latch, p_clock, p_data);\n\nvoid setup() \n{\n  panel.clear();\n  panel.scan();\n  pinMode(p_ena, OUTPUT); \n  analogWrite(p_ena, 0); // full brightness\n}\n\nvoid loop() \n{\n  for (int i=0;i<20;i++)\n  {\n    panel.drawPixel(random(16),random(16),random(10) == 0);\n  }\n  panel.scan(); // refreshes display\n  delay(5);\n}\n"
  },
  {
    "path": "FrekvensPanel/library.properties",
    "content": "name=FrekvensPanel\nversion=0.0.1\nauthor=/u/frumperino\nmaintainer=/u/frumperino\nsentence=Frekvens LED panel driver\nparagraph=Use an Arduino to drive the IKEA Frekvens LED panel. \ncategory=Display\nincludes=FrekvensPanel.h\narchitectures=*\nurl=https://github.com/frumperino/FrekvensPanel"
  },
  {
    "path": "FrekvensPanel/readme.md",
    "content": "This is a first rough cut of an Arduino library for the IKEA FREKVENS LED panels developed jointly with Teenage Engineering.\n\nContributions welcome.\n\nArduino requirements: Must be type with 3.3V logic levels. If you want to try hooking this up through 8-bit 5V AVR antiques like an Arduino Uno, then you must use level shifters. \n\nRecommendation: Use Teensy 3+, Adafruit Feather M0 or Sparkfun SAMD21 mini breakouts. Should also work with 32U4 based boards as well, so\nlong as they're 3.3V. Haven't tried with ESP8266 yet. \n\nLibrary dependencies:\n- Adafruit GFX library must be installed.\n\nSoldering instructions:\n- Open & disassemble the LED cube. \n\n- Extract the mainboard.\n\n- Desolder the original controller daughterboard (green color).\n  * Use flux and solder wick. \n\n- Attach wires to the six solder points.\n  * The outermost solder points are marked VCC and GND. \n  * Let GND be (1) and VCC be (6). The middle four are as follows:\n  * (2) LATCH - connect to a digital output pin. \n  * (3) CLOCK - connect to a digital output pin.\n  * (4) DATA - connect to a digital output pin.\n  * (5) !ENABLE. This one is optional. \n        If you DON'T need to be able to control brightness\n        of the display, then just solder a wire from this pin\n        to GND. \n        If you DO want to control brightness, then connect this\n        pin to a PWM (\"analog\") output pin on your Arduino.\n\n  * Solder the GND wire to a GND pin on the Arduino.\n\n  * Leave the VCC wire unconnected until you're done programming\n  * The VCC wire has 4 volts on it coming from the isolated power\n  * supply of the Frekvens cube.\n  * While programming, the Arduino should be powered through USB.\n  * After programming, disconnect USB cable and attach VCC wire\n  * from Frekvens panel to battery input or \"USB\" voltage pin on\n  * the Arduino. The Frekvens panel will now supply the Arduino\n  * board voltages.\n\n- Optionally - hook up the red and yellow buttons on the back.\n  * RED wire is common so connect this to GND or VCC of the\n  * Arduino. BLACK wire is RED button, WHITE wire is YELLOW button. \n\n- Put the whole thing back together.\n\n- To use the library, add #include \"Frekvenspanel.h\" statement, and instantiate a FrekvensPanel object. See examples.\n\n- Library has several un-documented experimental modes, including\n  multiple bit planes (intensity dithering) and support for daisy-\n  chaining several modules. Needs more work. At the moment the daisy-\n  chain is mapped vertically which seems wrong. \n\n- Happy hacking\n\n"
  },
  {
    "path": "readme.md",
    "content": "This is a first rough cut of an Arduino library for the IKEA FREKVENS LED panels developed jointly with Teenage Engineering.\n\nContributions welcome.\n\nArduino requirements: Must be type with 3.3V logic levels. If you want to try hooking this up through 8-bit 5V AVR antiques like an Arduino Uno, then you must use level shifters. \n\nRecommendation: Use Teensy 3+, Adafruit Feather M0 or Sparkfun SAMD21 mini breakouts. Should also work with 32U4 based boards as well, so\nlong as they're 3.3V. Haven't tried with ESP8266 yet. \n\nLibrary dependencies:\n- Adafruit GFX library must be installed.\n\nSoldering instructions:\n- Open & disassemble the LED cube. \n\n- Extract the mainboard.\n\n- Desolder the original controller daughterboard (green color).\n  * Use flux and solder wick. \n\n- Attach wires to the six solder points.\n  * The outermost solder points are marked VCC and GND. \n  * Let GND be (1) and VCC be (6). The middle four are as follows:\n  * (2) LATCH - connect to a digital output pin. \n  * (3) CLOCK - connect to a digital output pin.\n  * (4) DATA - connect to a digital output pin.\n  * (5) !ENABLE. This one is optional. \n        If you DON'T need to be able to control brightness\n        of the display, then just solder a wire from this pin\n        to GND. \n        If you DO want to control brightness, then connect this\n        pin to a PWM (\"analog\") output pin on your Arduino.\n\n  * Solder the GND wire to a GND pin on the Arduino.\n\n  * Leave the VCC wire unconnected until you're done programming\n  * The VCC wire has 4 volts on it coming from the isolated power\n  * supply of the Frekvens cube.\n  * While programming, the Arduino should be powered through USB.\n  * After programming, disconnect USB cable and attach VCC wire\n  * from Frekvens panel to battery input or \"USB\" voltage pin on\n  * the Arduino. The Frekvens panel will now supply the Arduino\n  * board voltages.\n\n- Optionally - hook up the red and yellow buttons on the back.\n  * RED wire is common so connect this to GND or VCC of the\n  * Arduino. BLACK wire is RED button, WHITE wire is YELLOW button. \n\n- Put the whole thing back together.\n\n- To use the library, add #include \"Frekvenspanel.h\" statement, and instantiate a FrekvensPanel object. See examples.\n\n- Library has several un-documented experimental modes, including\n  multiple bit planes (intensity dithering) and support for daisy-\n  chaining several modules. Needs more work. At the moment the daisy-\n  chain is mapped vertically which seems wrong. \n\n- Happy hacking\n\n"
  }
]