From aaefda4467cf45a3da8903faabd0f9890341eeae Mon Sep 17 00:00:00 2001 From: "Scruff.R" Date: Tue, 27 Jun 2017 14:41:06 +0200 Subject: [PATCH 1/2] Alternative I2C port, special chars, functional logic --- beam.cpp | 1758 ++++++++++++++++-------------------------------- beam.h | 174 ++--- charactermap.h | 154 +++-- frames.h | 227 +++---- 4 files changed, 875 insertions(+), 1438 deletions(-) diff --git a/beam.cpp b/beam.cpp index 600686e..ca5c6cd 100644 --- a/beam.cpp +++ b/beam.cpp @@ -1,947 +1,538 @@ -/* -=========================================================================== - This is the library for Beam. - - Beam is a beautiful LED matrix — features 120 LEDs that displays scrolling text, animations, or custom lighting effects. - Beam can be purchased here: http://www.hoverlabs.co - - Written by Emran Mahbub and Jonathan Li for Hover Labs. - BSD license, all text above must be included in any redistribution - +/* =========================================================================== -*/ +This is the library for Beam. + +Beam is a beautiful LED matrix — features 120 LEDs that displays scrolling +text, animations, or custom lighting effects. +Beam can be purchased here: http://www.hoverlabs.co + +Written by Emran Mahbub and Jonathan Li for Hover Labs. +BSD license, all text above must be included in any redistribution + +--------------------------------------------------------------------------- +Edit by ScruffR 2017-06-25: +Adapted to support alternative I2C interfaces +Added support for special characters (e.g. German Umlauts Ä, Ö, Ü) with the + framework to add any other +Replaced "copy-paste" logic with functional blocks by use of arrays and loops -#include "application.h" +=========================================================================== +*/ +#include #include "beam.h" #include "charactermap.h" #include "frames.h" - - /* ================= PUBLIC FUNCTIONS ================= */ -/* - This constructor used when multiple Beams behave like one long Beam +/* +This constructor used when multiple Beams behave like one long Beam */ -Beam::Beam ( int rstpin, int irqpin, int numberOfBeams){ - _rst = rstpin; - _irq = irqpin; - _beamCount = numberOfBeams; - activeBeams = numberOfBeams; - _gblMode = 1; +Beam::Beam(int rstpin, int irqpin, int numberOfBeams) { + Log.trace("Beam::Beam(int rstpin, int irqpin, int numberOfBeams)"); + _rst = rstpin; + _irq = irqpin; + + if (numberOfBeams <= 0 || 4 <= numberOfBeams) { + Log.warn("Number of Beams must be between 1 and 4 and not %d (default to 1 BEAMA)", numberOfBeams); + numberOfBeams = 1; + } + BEAM = &BEAM_ADDRESS[0]; + activeBeams = + _beamCount = numberOfBeams; + _gblMode = 1; } -/* - This constructor used when multiple Beams behave like single Beam units +/* +This constructor used when multiple Beams behave like single Beam units */ -Beam::Beam ( int rstpin, int irqpin, uint8_t syncMode, uint8_t beamAddress){ - _rst = rstpin; - _irq = irqpin; - _syncMode = 0; - activeBeams = 1; - _currBeam = beamAddress; - _gblMode = 0; -} - -bool Beam::begin(void){ - - //resets beam - will clear all beams - pinMode(_rst, OUTPUT); - digitalWrite(_rst, LOW); - delay(100); - digitalWrite(_rst, HIGH); - delay(250); - - //reset cs[] - int c = 0; - for (c=0; c<12; c++){ - cs[c] = 0x00; +Beam::Beam(int rstpin, int irqpin, uint8_t syncMode, uint8_t beamAddress) { + Log.trace("Beam::Beam(int rstpin, int irqpin, uint8_t syncMode, uint8_t beamAddress)"); + _rst = rstpin; + _irq = irqpin; + _syncMode = 0; + _beamCount = + activeBeams = 1; + BEAM = NULL; + for (unsigned int b = 0; b < sizeof(BEAM_ADDRESS); b++) { + if (BEAM_ADDRESS[b] == beamAddress) { + BEAM = &BEAM_ADDRESS[b]; + break; } - - //reset segmentmask[] - uint8_t val = 0x80; - int s = 0; - for (s=0; s<8; s++){ - segmentmask[s] = val; - val = val/2; - } - - return true; - -} - + } + if (!BEAM) { + BEAM = &BEAM_ADDRESS[0]; + Log.warn("%02x is not a valid Beam address (default to BEAMA %02x)", beamAddress, BEAM_ADDRESS[0]); + } -void Beam::initBeam(){ - - //initialize Beam - if (_gblMode == 1 ){ - if (_beamCount == 1) { - Serial.println("clearing BEAMA"); - initializeBeam(BEAMA); - } else if (_beamCount == 2){ - Serial.println("clearing BEAMA"); - initializeBeam(BEAMA); - Serial.println("clearing BEAMB"); - initializeBeam(BEAMB); - } else if (_beamCount == 3){ - Serial.println("clearing BEAMA"); - initializeBeam(BEAMA); - Serial.println("clearing BEAMB"); - initializeBeam(BEAMB); - Serial.println("clearing BEAMC"); - initializeBeam(BEAMC); - } else if (_beamCount == 4){ - Serial.println("clearing BEAMA"); - initializeBeam(BEAMA); - Serial.println("clearing BEAMB"); - initializeBeam(BEAMB); - Serial.println("clearing BEAMC"); - initializeBeam(BEAMC); - Serial.println("clearing BEAMD"); - initializeBeam(BEAMD); - } else { - Serial.println("beamCount should be between 1 and 4"); - } - } else { - initializeBeam(_currBeam); - } - + _gblMode = 0; } +bool Beam::begin(TwoWire& wire) { + Log.trace("bool Beam::begin(TwoWire& wire)"); + _wire = &wire; -void Beam::print(const char* text){ - - //resets beam - will clear all beams - pinMode(_rst, OUTPUT); - digitalWrite(_rst, LOW); - delay(100); - digitalWrite(_rst, HIGH); - delay(250); + //resets beam - will clear all beams + pinMode(_rst, OUTPUT); + digitalWrite(_rst, LOW); + delay(100); + digitalWrite(_rst, HIGH); + delay(250); - Serial.print("Text to print:"); - Serial.println(text); - - initBeam(); + //reset cs[] + memset((uint8_t*)cs, 0x00, sizeof(cs)); - // Clear all frames - for (int z=0; z<12; z++){ - cs[z] = 0x00; - } - if (_gblMode == 1 ){ - if (_beamCount == 1) { - for (int i=0;i<36;i++){ - writeFrame(BEAMA, i); - } - } else if (_beamCount == 2){ - for (int i=0;i<36;i++){ - writeFrame(BEAMA, i); - writeFrame(BEAMB, i); - } - } else if (_beamCount == 3){ - for (int i=0;i<36;i++){ - writeFrame(BEAMA, i); - writeFrame(BEAMB, i); - writeFrame(BEAMC, i); - } - } else if (_beamCount == 4){ - for (int i=0;i<36;i++){ - writeFrame(BEAMA, i); - writeFrame(BEAMB, i); - writeFrame(BEAMC, i); - writeFrame(BEAMD, i); - } - } - } else { - #if DEBUG - Serial.print("printing BEAM: "); - Serial.println(_currBeam, HEX); - #endif - for (int i=0;i<36;i++){ - writeFrame(_currBeam, i); - } - } + //reset segmentmask[] + for (int s = 0; s < 8; s++) { + segmentmask[s] = 0x0001 << (7 - s); + } - int i = 0; - int j = 0; - uint8_t * fontptr; - int frame = 0; - - int asciiVal; - int cscount = 0; - int stringLen = strlen(text); - - #if DEBUG - Serial.println(strlen(text)-1); - Serial.println(" "); - #endif - - while ( (i23) { - // if end of grid is reached in current frame, - // then start writing to the Beam registers - #if DEBUG - Serial.println("- end of frame reached"); - Serial.print("writing cs[] = "); - #endif - for (j=0; j<=11; j++){ - cs[j] = (cscolumn[j*2]) | (cscolumn[j*2+1] << 5); - #if DEBUG - Serial.print(cs[j], HEX); - Serial.print(" "); - #endif - } - #if DEBUG - Serial.println("done cs"); - #endif - - if (_gblMode == 1){ - if(_beamCount == 1){ - writeFrame(BEAMA,frame+1); - _lastFrameWrite = frame + 1; - } - else if (_beamCount == 2){ - writeFrame(BEAMA,frame+1+1); - writeFrame(BEAMB,frame+1); - _lastFrameWrite = frame + 1 + 1; - } - else if (_beamCount == 3){ - writeFrame(BEAMA,frame+1+1+1); - writeFrame(BEAMB,frame+1+1); - writeFrame(BEAMC,frame+1); - _lastFrameWrite = frame + 1 + 1 + 1; - } - else if (_beamCount == 4){ - writeFrame(BEAMA,frame+1+1+1+1); - writeFrame(BEAMB,frame+1+1+1); - writeFrame(BEAMC,frame+1+1); - writeFrame(BEAMD,frame+1); - _lastFrameWrite = frame + 1 + 1 + 1 + 1; - } - } else { - #if DEBUG - Serial.print("printing last frame BEAM: "); - Serial.println(_currBeam, HEX); - #endif - writeFrame(_currBeam,frame+1); - _lastFrameWrite = frame + 1; - - } - - int x; - for (x=0;x<12;x++){ - cs[x] = 0x00; - cscolumn[x*2] = 0x00; - cscolumn[x*2+1] = 0x00; - } - #if DEBUG - Serial.println(" "); - #endif - frame = frame + 1; // go to next frame - cscount = 0; // reset cscount - //_lastFrameWrite = 8; - - // if a specific frame is specified, then return if that frame is done. - - //ADD THIS LATER - //if (frameNum!=0 && frame > frameNum){ - // return; - //} - - if (*fontptr!=0xFF){ - //special case if current character needs to wrap to next frame - #if DEBUG - Serial.print("Continuing prev char "); - Serial.print("cscolumn[] = "); - #endif - while (cscount <24 && *fontptr!=0xFF){ - cscolumn[cscount] = *fontptr; - #if DEBUG - Serial.print(cscolumn[cscount], HEX); - Serial.print(" "); - #endif - fontptr++; - cscount++; - } - #if DEBUG - Serial.println(""); - #endif - } - } +void Beam::initBeam() { + Log.trace("void Beam::initBeam()"); + //initialize Beam + for (unsigned int b = 0; b < _beamCount; b++) { + Log.trace("clearing BEAM[%d]", b); + initializeBeam(BEAM[b]); + } +} - if (stringLen == i) { - // if end of string is reached in current frame, - // then start writing to Beam registers - #if DEBUG - Serial.println("- end of string reached"); - Serial.print("writing cs[] = "); - #endif - for (j=0; j<=11; j++){ - cs[j] = (cscolumn[j*2]) | (cscolumn[j*2+1] << 5); - #if DEBUG - Serial.print(cs[j], HEX); - Serial.print(" "); - #endif - } - #if DEBUG - Serial.println("done cs print"); - #endif - - if (_gblMode == 1){ - - if(_beamCount == 1){ - writeFrame(BEAMA,frame+1); - _lastFrameWrite = frame + 1; - } - else if (_beamCount == 2){ - writeFrame(BEAMA,frame+1+1); - writeFrame(BEAMB,frame+1); - _lastFrameWrite = frame + 1 + 1; - } - else if (_beamCount == 3){ - writeFrame(BEAMA,frame+1+1+1); - writeFrame(BEAMB,frame+1+1); - writeFrame(BEAMC,frame+1); - _lastFrameWrite = frame + 1 + 1 + 1; - } - else if (_beamCount == 4){ - writeFrame(BEAMA,frame+1+1+1+1); - writeFrame(BEAMB,frame+1+1+1); - writeFrame(BEAMC,frame+1+1); - writeFrame(BEAMD,frame+1); - _lastFrameWrite = frame + 1 + 1 + 1 + 1; - } - } else { - #if DEBUG - Serial.print("printing last last BEAM: "); - Serial.println(_currBeam, HEX); - #endif - writeFrame(_currBeam,frame+1); - _lastFrameWrite = frame + 1; - - } - - int x; - for (x=0;x<12;x++){ - cs[x] = 0x00; - cscolumn[x*2] = 0x00; - cscolumn[x*2+1] = 0x00; - } - #if DEBUG - Serial.println(" "); - #endif - } - } +void Beam::print(const char* text) { + Log.trace("void Beam::print(const char* text)"); + //resets beam - will clear all beams + pinMode(_rst, OUTPUT); + digitalWrite(_rst, LOW); + delay(100); + digitalWrite(_rst, HIGH); + delay(250); - //defaults Beam to basic settings - setPrintDefaults(SCROLL, 0, 6, 7, 5, 1, 0); + Log.info("Text to print: %s", text); -} + initBeam(); + // Clear all frames + memset((uint8_t*)cs, 0x00, sizeof(cs)); -void Beam::printFrame(uint8_t frameToPrint, const char * text){ + for (int i = 0; i < 36; i++) { + for (unsigned int b = 0; b < _beamCount; b++) { + writeFrame(BEAM[b], i); + } + } - Serial.print("Text to print:"); - Serial.println(text); + int i = 0; + const uint8_t *fontptr; + int frame = 0; + + int asciiVal; + int cscount = 0; + int stringLen = strlen(text); + + while ((i < stringLen) && frame < 36) { + // pick a character to print to Beam + asciiVal = toupper(text[i]); + if (32 <= asciiVal && asciiVal <= 96) { + fontptr = &charactermap[(asciiVal - 32)][0]; //set fontptr to matching font + } + else { + switch (text[i]) { + case 0xC3: // two byte character prefix to be ignored + i++; + continue; + break; + case 0x84: // (0xC3 0x84) 'Ä' + case 0xA4: // (0xC3 0xA4) 'ä' + fontptr = &charactermap[65][0]; + break; + case 0x96: // (0xC3 0x96) 'Ö' + case 0xB6: // (0xC3 0x86) 'ö' + fontptr = &charactermap[66][0]; + break; + case 0x9C: // (0xC3 0x9C) 'Ü' + case 0xBC: // (0xC3 0xBC) 'ü' + fontptr = &charactermap[67][0]; + break; + case 0x9F: // (0xC3 0xDF) 'ß' + fontptr = &charactermap[68][0]; + break; + default: + fontptr = &charactermap[0][0]; + break; + } + } + // loop through the Beam grid and place characters + // from the character map + Log.trace("%c = %d (0x%02x)\r\ncscolumn[] = ", text[i], asciiVal, asciiVal); + while (cscount < 24 && *fontptr != 0xFF) { + cscolumn[cscount] = *fontptr; + Log.trace("0x%02x", cscolumn[cscount]); + fontptr++; + cscount++; + } + i++; // go to next character + + if (cscount > 23) { + // if end of grid is reached in current frame, + // then start writing to the Beam registers + Log.trace("--- end of frame reached ---\r\nwriting cs[]"); + for (int j = 0; j < 12; j++) { + cs[j] = (cscolumn[j * 2]) | (cscolumn[j * 2 + 1] << 5); + Log.trace("0x%02x", cs[j]); + } + Log.trace("--- end of cs[] ---"); - int i = 0; - int j = 0; - uint8_t * fontptr; - int frame = frameToPrint; + for (unsigned int b = 0; b < _beamCount; b++) { + writeFrame(BEAM[b], frame + (_beamCount - b)); + } + _lastFrameWrite = frame + _beamCount; - int asciiVal; - int cscount = 0; - int stringLen = strlen(text); + for (int x = 0; x < 12; x++) { + cs[x] = 0x00; + cscolumn[x * 2] = 0x00; + cscolumn[x * 2 + 1] = 0x00; + } + frame++; // go to next frame + cscount = 0; // reset cscount - Serial.println(strlen(text)-1); - Serial.println(" "); + // if a specific frame is specified, then return if that frame is done. + //ADD THIS LATER + //if (frameNum!=0 && frame > frameNum){ + // return; + //} - while ( (i23) { - // if end of grid is reached in current frame, - // then start writing to the Beam registers - - Serial.println("- end of frame reached"); - Serial.print("writing cs[] = "); - for (j=0; j<=11; j++){ - cs[j] = (cscolumn[j*2]) | (cscolumn[j*2+1] << 5); - Serial.print(cs[j], HEX); - Serial.print(" "); - } - Serial.println("done cs"); - - //write cs[0-11] to as1130 with current frame number. - /*if(_beamCount >= 1){ - writeFrame(BEAMA,frame+1+1+1); - } - if (_beamCount >= 2){ - writeFrame(BEAMB,frame+1+1); - } - if (_beamCount >= 3){ - writeFrame(BEAMC,frame+1); - } - if (_beamCount >= 4){ - writeFrame(BEAMD,frame+1); - }*/ - - - if(_gblMode == 0){ - writeFrame(_currBeam,frame); - _lastFrameWrite = frame; - } - /*else if (_beamCount == 2){ - writeFrame(BEAMA,frame+1+1); - writeFrame(BEAMB,frame+1); - _lastFrameWrite = frame + 1 + 1; - } - else if (_beamCount == 3){ - writeFrame(BEAMA,frame+1+1+1); - writeFrame(BEAMB,frame+1+1); - writeFrame(BEAMC,frame+1); - _lastFrameWrite = frame + 1 + 1 + 1; - } - else if (_beamCount == 4){ - writeFrame(BEAMA,frame+1+1+1+1); - writeFrame(BEAMB,frame+1+1+1); - writeFrame(BEAMC,frame+1+1); - writeFrame(BEAMD,frame+1); - _lastFrameWrite = frame + 1 + 1 + 1 + 1; - } */ - - int x; - for (x=0;x<12;x++){ - cs[x] = 0x00; - cscolumn[x*2] = 0x00; - cscolumn[x*2+1] = 0x00; - } - - Serial.println(" "); - - frame = frame + 1; // go to next frame - cscount = 0; // reset cscount - _lastFrameWrite = frame; - - // if a specific frame is specified, then return if that frame is done. - if (frameToPrint!=0 && frame > frameToPrint){ - //defaults Beam to basic settings - setPrintDefaults(SCROLL, 0, _lastFrameWrite, 7, 15, 1, 1); - return; - } + Log.trace("--- done cs print ---"); + for (unsigned int b = 0; b < _beamCount; b++) { + writeFrame(BEAM[b], frame + (_beamCount - b)); } + _lastFrameWrite = frame + _beamCount; + for (int x = 0; x < 12; x++) { + cs[x] = 0x00; + cscolumn[x * 2] = 0x00; + cscolumn[x * 2 + 1] = 0x00; + } } + } + //defaults Beam to basic settings + setPrintDefaults(SCROLL, 0, 6, 7, 5, 1, 0); } - - - - -void Beam::play(){ - - Serial.println("play() called"); - - if (_gblMode == 1){ - - //start playing beams depending on scroll direction - if (_scrollDir == LEFT){ - if (_beamCount == 1){ - sendWriteCmd(BEAMA, CTRL, SHDN, 0x03); - } else if (_beamCount == 2){ - sendWriteCmd(BEAMB, CTRL, SHDN, 0x03); - } else if (_beamCount == 3){ - sendWriteCmd(BEAMC, CTRL, SHDN, 0x03); - } else if (_beamCount == 4) { - sendWriteCmd(BEAMD, CTRL, SHDN, 0x03); - } - } else if (_scrollDir == RIGHT) { - if (_beamCount ==1){ - sendWriteCmd(BEAMA, CTRL, SHDN, 0x03); - } else if (_beamCount == 2){ - sendWriteCmd(BEAMA, CTRL, SHDN, 0x03); - } else if (_beamCount == 3){ - sendWriteCmd(BEAMA, CTRL, SHDN, 0x03); - } else if (_beamCount == 4) { - sendWriteCmd(BEAMA, CTRL, SHDN, 0x03); - } - } - - if (_beamCount > 1) { - while (checkStatus() != 1){ - delay(10); - } - } - - } else { - //start playing current beam - sendWriteCmd(_currBeam, CTRL, SHDN, 0x03); +void Beam::printFrame(uint8_t frameToPrint, const char * text) { + Log.trace("void Beam::printFrame(uint8_t frameToPrint, const char * text)"); + Log.info("Text to print: %s", text); + + int i = 0; + const uint8_t * fontptr; + int frame = frameToPrint; + + int asciiVal; + int cscount = 0; + int stringLen = strlen(text); + + while ((i < stringLen) && frame < 36) { + // pick a character to print to Beam + asciiVal = toupper(text[i]); + if (32 <= asciiVal && asciiVal <= 96) { + fontptr = &charactermap[(asciiVal - 32)][0]; //set fontptr to matching font + } + else { + switch (text[i]) { + case 0xC3: // two byte character prefix to be ignored + i++; + continue; + break; + case 0x84: // (0xC3 0x84) 'Ä' + case 0xA4: // (0xC3 0xA4) 'ä' + fontptr = &charactermap[65][0]; + break; + case 0x96: // (0xC3 0x96) 'Ö' + case 0xB6: // (0xC3 0x86) 'ö' + fontptr = &charactermap[66][0]; + break; + case 0x9C: // (0xC3 0x9C) 'Ü' + case 0xBC: // (0xC3 0xBC) 'ü' + fontptr = &charactermap[67][0]; + break; + case 0x9F: // (0xC3 0xDF) 'ß' + fontptr = &charactermap[68][0]; + break; + default: + fontptr = &charactermap[0][0]; + break; + } } - Serial.println("play() done"); - -} -void Beam::startNextBeam(){ + Log.trace("%c = %d (0x%02x)\r\ncscolumn[] = ", text[i], asciiVal, asciiVal); + // loop through the Beam grid and place characters + // from the character map + while (cscount < 24 && *fontptr != 0xFF) { + cscolumn[cscount] = *fontptr; + Log.trace("0x%02x", cscolumn[cscount]); + fontptr++; + cscount++; + } + i++; // go to next character - Serial.println(_scrollDir); - Serial.println(_beamCount); - Serial.println(beamNumber); + if (cscount > 23) { + // if end of grid is reached in current frame, + // then start writing to the Beam registers - /*start playing beams depending on scroll direction*/ - if (_scrollDir == LEFT){ - if (_beamCount == 2){ - sendWriteCmd(BEAMA, CTRL, SHDN, 0x03); - } - } + Log.trace("--- end of frame reached ---\r\nwriting cs[]"); + for (int j = 0; j < 12; j++) { + cs[j] = (cscolumn[j * 2]) | (cscolumn[j * 2 + 1] << 5); + Log.trace("0x%02x", cs[j]); + } + Log.trace("--- end of cs[] ---"); -} + for (unsigned int b = 0; b < _beamCount; b++) { + writeFrame(BEAM[b], frame); + //_lastFrameWrite = frame; + } + for (int x = 0; x < 12; x++) { + cs[x] = 0x00; + cscolumn[x * 2] = 0x00; + cscolumn[x * 2 + 1] = 0x00; + } -void Beam::setScroll(uint8_t direction, uint8_t fade){ + frame++; // go to next frame + cscount = 0; // reset cscount + _lastFrameWrite = frame; - if (!(direction == RIGHT || direction == LEFT)){ - Serial.println("Select either LEFT or RIGHT for direction"); + // if a specific frame is specified, then return if that frame is done. + if (frameToPrint != 0 && frame > frameToPrint) { + //defaults Beam to basic settings + setPrintDefaults(SCROLL, 0, _lastFrameWrite, 7, 15, 1, 1); return; + } } + } +} - _scrollDir = direction; - _fadeMode = fade; - _scrollMode = 1; +void Beam::play() { + Log.trace("void Beam::play()"); + //start playing beams depending on scroll direction + if (_scrollDir == LEFT) { + sendWriteCmd(BEAM[_beamCount - 1], CTRL, SHDN, 0x03); + } + else { + sendWriteCmd(BEAM[0], CTRL, SHDN, 0x03); + } - uint8_t frameData = _fadeMode << 7 | _scrollDir << 6 | 0 << 5 | _scrollMode << 4 | _frameDelay; - - if (_gblMode == 1){ - if(_beamCount >= 1){ - sendWriteCmd(BEAMA, CTRL, FRAMETIME, frameData); - } - if (_beamCount >= 2){ - sendWriteCmd(BEAMB, CTRL, FRAMETIME, frameData); - } - if (_beamCount >= 3){ - sendWriteCmd(BEAMC, CTRL, FRAMETIME, frameData); - } - if (_beamCount >= 4){ - sendWriteCmd(BEAMD, CTRL, FRAMETIME, frameData); - } - - } else { - sendWriteCmd(_currBeam, CTRL, FRAMETIME, frameData); + if (_beamCount > 1) { + while (checkStatus() != 1) { + delay(10); } + } +} + +void Beam::startNextBeam() { + Log.trace("void Beam::startNextBeam()"); + Log.trace("_scrollDir: %d, _beamCount: %d, beamNumber: %d", _scrollDir, _beamCount, beamNumber); + // since the original logic didn't make much sense, I assumed similar behaviour to Beam::play() might make more sense + // see https://github.com/hoverlabs/beam_particle/issues/4 + //start playing beams depending on scroll direction + if (_scrollDir == LEFT) { + sendWriteCmd(BEAM[_beamCount - 1], CTRL, SHDN, 0x03); + } + else { + sendWriteCmd(BEAM[0], CTRL, SHDN, 0x03); + } } -void Beam::setSpeed (uint8_t speed){ - - if (!(speed >= 1 && speed <= 15)){ - Serial.println("Enter a speed between 1 and 15"); - return; - } - - if (_beamMode == MOVIE){ - _scrollMode = 0; - } else { - _scrollMode = 1; - } - - _frameDelay = speed; +void Beam::setScroll(uint8_t direction, uint8_t fade) { + Log.trace("void Beam::setScroll(uint8_t direction, uint8_t fade)"); + if (direction != RIGHT && direction != LEFT) { + Log.warn("Select either LEFT or RIGHT for direction"); + return; + } - uint8_t frameData = _fadeMode << 7 | _scrollDir << 6 | 0 << 5 | _scrollMode << 4 | _frameDelay; + _scrollDir = direction; + _fadeMode = fade; + _scrollMode = 1; - if (_gblMode == 1){ - if(_beamCount >= 1){ - sendWriteCmd(BEAMA, CTRL, FRAMETIME, frameData); - } - if (_beamCount >= 2){ - sendWriteCmd(BEAMB, CTRL, FRAMETIME, frameData); - } - if (_beamCount >= 3){ - sendWriteCmd(BEAMC, CTRL, FRAMETIME, frameData); - } - if (_beamCount >= 4){ - sendWriteCmd(BEAMD, CTRL, FRAMETIME, frameData); - } - - } else { - sendWriteCmd(_currBeam, CTRL, FRAMETIME, frameData); - } + uint8_t frameData = _fadeMode << 7 | _scrollDir << 6 | 0 << 5 | _scrollMode << 4 | _frameDelay; + for (unsigned int b = 0; b < _beamCount; b++) { + sendWriteCmd(BEAM[b], CTRL, FRAMETIME, frameData); + } } -void Beam::setLoops (uint8_t loops){ +void Beam::setSpeed(uint8_t speed) { + Log.trace("void Beam::setSpeed(uint8_t speed)"); + if (speed < 1 || 15 < speed) { + Log.trace("Enter a speed between 1 and 15"); + return; + } - if (!(loops >= 1 && loops <= 7)){ - Serial.println("Enter a speed between 1 and 7"); - return; - } - - _numLoops = loops; - uint8_t displayData = _numLoops << 5 | 0 << 4 | 0x0B; - - if (_gblMode == 1){ - - if(_beamCount >= 1){ - sendWriteCmd(BEAMA, CTRL, DISPLAYO, displayData); - } - if (_beamCount >= 2){ - sendWriteCmd(BEAMB, CTRL, DISPLAYO, displayData); - } - if (_beamCount >= 3){ - sendWriteCmd(BEAMC, CTRL, DISPLAYO, displayData); - } - if (_beamCount >= 4){ - sendWriteCmd(BEAMD, CTRL, DISPLAYO, displayData); - } - - } else { - - sendWriteCmd(_currBeam, CTRL, DISPLAYO, displayData); + _scrollMode = (_beamMode == MOVIE) ? 0 : 1; - } + _frameDelay = speed; + uint8_t frameData = _fadeMode << 7 | _scrollDir << 6 | 0 << 5 | _scrollMode << 4 | _frameDelay; + for (unsigned int b = 0; b < _beamCount; b++) { + sendWriteCmd(BEAM[b], CTRL, FRAMETIME, frameData); + } } +void Beam::setLoops(uint8_t loops) { + Log.trace("void Beam::setLoops(uint8_t loops)"); + if (loops < 1 || 7 < loops) { + Log.warn("Enter a speed between 1 and 7"); + return; + } -void Beam::setMode (uint8_t mode){ + _numLoops = loops; + uint8_t displayData = _numLoops << 5 | 0 << 4 | 0x0B; - if (!(mode == MOVIE || mode == SCROLL)){ - Serial.println("Select either SCROLL or MOVIE for mode"); - return; - } + for (unsigned int b = 0; b < _beamCount; b++) { + sendWriteCmd(BEAM[b], CTRL, DISPLAYO, displayData); + } +} - _beamMode = mode; - uint8_t frameData = 0; - - if (mode == MOVIE){ - frameData = 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | _frameDelay; - } else if (mode == SCROLL){ - frameData = _fadeMode << 7 | _scrollDir << 6 | 0 << 5 | _scrollMode << 4 | _frameDelay; - } - - if (_gblMode == 1){ - - if(_beamCount >= 1){ - sendWriteCmd(BEAMA, CTRL, FRAMETIME, frameData); - } - if (_beamCount >= 2){ - sendWriteCmd(BEAMB, CTRL, FRAMETIME, frameData); - } - if (_beamCount >= 3){ - sendWriteCmd(BEAMC, CTRL, FRAMETIME, frameData); - } - if (_beamCount >= 4){ - sendWriteCmd(BEAMD, CTRL, FRAMETIME, frameData); - } - - } else { - - sendWriteCmd(_currBeam, CTRL, FRAMETIME, frameData); - - } +void Beam::setMode(uint8_t mode) { + Log.trace("void Beam::setMode(uint8_t mode)"); + if (mode != MOVIE && mode != SCROLL) { + Log.warn("Select either SCROLL or MOVIE for mode"); + return; + } -} + _beamMode = mode; + uint8_t frameData = 0; + + if (mode == MOVIE) { + frameData = 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | _frameDelay; + } + else if (mode == SCROLL) { + frameData = _fadeMode << 7 | _scrollDir << 6 | 0 << 5 | _scrollMode << 4 | _frameDelay; + } + for (unsigned int b = 0; b < _beamCount; b++) { + sendWriteCmd(BEAM[b], CTRL, FRAMETIME, frameData); + } +} /* - Used by global mode to check when daisy chained Beams - should be activated depending on the scroll direction. +Used by global mode to check when daisy chained Beams +should be activated depending on the scroll direction. */ -int Beam::checkStatus(){ - - int frameDone = 0; - - if (_beamCount == 4){ - if (activeBeams == 4){ - frameDone = (sendReadCmd(BEAMD, CTRL, 0x0F)>>2); - if (frameDone == 1){ - sendWriteCmd(BEAMC, CTRL, SHDN, 0x03); - activeBeams--; - return 0; - } - } - - if (activeBeams == 3){ - frameDone = (sendReadCmd(BEAMC, CTRL, 0x0F)>>2); - if (frameDone == 2){ - sendWriteCmd(BEAMB, CTRL, SHDN, 0x03); - activeBeams--; - return 0; - } - } - - if (activeBeams == 2){ - frameDone = (sendReadCmd(BEAMB, CTRL, 0x0F)>>2); - if (frameDone == 3){ - sendWriteCmd(BEAMA, CTRL, SHDN, 0x03); - activeBeams--; - delay(10); - activeBeams = _beamCount; - return 1; - } - } - - } else if (_beamCount == 3){ - - if (activeBeams == 3){ - frameDone = (sendReadCmd(BEAMC, CTRL, 0x0F)>>2); - if (frameDone == 1){ - sendWriteCmd(BEAMB, CTRL, SHDN, 0x03); - activeBeams--; - return 0; - } - - } - - if (activeBeams == 2){ - frameDone = (sendReadCmd(BEAMB, CTRL, 0x0F)>>2); - if (frameDone == 2){ - sendWriteCmd(BEAMA, CTRL, SHDN, 0x03); - activeBeams--; - delay(10); - activeBeams = _beamCount; - return 1; - } - - } - - } else if (_beamCount == 2) { - - if (activeBeams == 2){ - frameDone = (sendReadCmd(BEAMB, CTRL, 0x0F)>>2); - if (frameDone == 1){ - sendWriteCmd(BEAMA, CTRL, SHDN, 0x03); - activeBeams--; - activeBeams = _beamCount; - return 1; - } - - } - +int Beam::checkStatus() { + Log.trace("int Beam::checkStatus()"); + if ((sendReadCmd(BEAM[activeBeams - 1], CTRL, 0x0F) >> 2) == (_beamCount - activeBeams + 1)) { + sendWriteCmd(BEAM[--activeBeams - 1], CTRL, SHDN, 0x03); + if (activeBeams <= 1) { + delay(10); + activeBeams = _beamCount; + return 1; } - - return 0; - + } + + return 0; } +void Beam::draw() { + Log.trace("void Beam::draw()"); + //resets beam - will clear all beams + pinMode(_rst, OUTPUT); + digitalWrite(_rst, LOW); + delay(100); + digitalWrite(_rst, HIGH); + delay(250); + + initBeam(); -void Beam::draw(){ - - //resets beam - will clear all beams - pinMode(_rst, OUTPUT); - digitalWrite(_rst, LOW); - delay(100); - digitalWrite(_rst, HIGH); - delay(250); - - initBeam(); - - for (int i=0; i<36; ++i){ - + for (int i = 0; i < 36; ++i) { convertFrame(frameList[i]); - - if (_gblMode == 1){ - if(_beamCount == 1){ - writeFrame(BEAMA,i); - _lastFrameWrite = i; - } - else if (_beamCount == 2){ - writeFrame(BEAMA,i+1+1); - writeFrame(BEAMB,i+1); - _lastFrameWrite = i + 1 + 1; - } - else if (_beamCount == 3){ - writeFrame(BEAMA,i+1+1+1); - writeFrame(BEAMB,i+1+1); - writeFrame(BEAMC,i+1); - _lastFrameWrite = i + 1 + 1 + 1; - } - else if (_beamCount == 4){ - writeFrame(BEAMA,i+1+1+1+1); - writeFrame(BEAMB,i+1+1+1); - writeFrame(BEAMC,i+1+1); - writeFrame(BEAMD,i+1); - _lastFrameWrite = i + 1 + 1 + 1 + 1; - } - } else { - - writeFrame(_currBeam,i); - _lastFrameWrite = i; - + // altered original frame counting logic: see https://github.com/hoverlabs/beam_particle/issues/6 + for (unsigned int b = 0; b < _beamCount; b++) { + writeFrame(BEAM[b], i + (_beamCount - 1 - b)); } - - // reset cs[] - for (int d=0; d<12; ++d){ - cs[d] = 0x00; - } - - } - - setPrintDefaults(MOVIE, 1, 20, 7, 2, 1, 0); + _lastFrameWrite = i + _beamCount - 1; + + // reset cs[] + memset((uint8_t*)cs, 0x00, sizeof(cs)); + } + setPrintDefaults(MOVIE, 1, 20, 7, 2, 1, 0); } +void Beam::display() { + uint8_t pictureData = 0 << 7 | 1 << 6 | _beamCount; + uint8_t displayData = 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0x0B; + uint8_t currsrcData = 0; -void Beam::display(){ - - uint8_t pictureData = 0 << 7 | 1 << 6 | _beamCount; - uint8_t displayData = 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | 0x0B; - uint8_t currsrcData = 0; - - // change led current based on number of connected beams - if (_beamCount == 4){ - currsrcData = 0x08; - sendWriteCmd(BEAMA, CTRL, PIC, pictureData); - sendWriteCmd(BEAMA, CTRL, CURSRC, currsrcData); - sendWriteCmd(BEAMA, CTRL, DISPLAYO, displayData); - - sendWriteCmd(BEAMB, CTRL, PIC, pictureData); - sendWriteCmd(BEAMB, CTRL, CURSRC, currsrcData); - sendWriteCmd(BEAMB, CTRL, DISPLAYO, displayData); - - sendWriteCmd(BEAMC, CTRL, PIC, pictureData); - sendWriteCmd(BEAMC, CTRL, CURSRC, currsrcData); - sendWriteCmd(BEAMC, CTRL, DISPLAYO, displayData); - - sendWriteCmd(BEAMD, CTRL, PIC, pictureData); - sendWriteCmd(BEAMD, CTRL, CURSRC, currsrcData); - sendWriteCmd(BEAMD, CTRL, DISPLAYO, displayData); - - sendWriteCmd(BEAMA, CTRL, SHDN, 0x03); - sendWriteCmd(BEAMB, CTRL, SHDN, 0x03); - sendWriteCmd(BEAMC, CTRL, SHDN, 0x03); - sendWriteCmd(BEAMD, CTRL, SHDN, 0x03); - - } else if (_beamCount == 3){ - currsrcData = 0x10; - - sendWriteCmd(BEAMA, CTRL, PIC, pictureData); - sendWriteCmd(BEAMA, CTRL, CURSRC, currsrcData); - sendWriteCmd(BEAMA, CTRL, DISPLAYO, displayData); - - sendWriteCmd(BEAMB, CTRL, PIC, pictureData); - sendWriteCmd(BEAMB, CTRL, CURSRC, currsrcData); - sendWriteCmd(BEAMB, CTRL, DISPLAYO, displayData); - - sendWriteCmd(BEAMC, CTRL, PIC, pictureData); - sendWriteCmd(BEAMC, CTRL, CURSRC, currsrcData); - sendWriteCmd(BEAMC, CTRL, DISPLAYO, displayData); - - sendWriteCmd(BEAMA, CTRL, SHDN, 0x03); - sendWriteCmd(BEAMB, CTRL, SHDN, 0x03); - sendWriteCmd(BEAMC, CTRL, SHDN, 0x03); - - } else if (_beamCount == 2){ - currsrcData = 0x15; - - sendWriteCmd(BEAMA, CTRL, PIC, pictureData); - sendWriteCmd(BEAMA, CTRL, CURSRC, currsrcData); - sendWriteCmd(BEAMA, CTRL, DISPLAYO, displayData); - - sendWriteCmd(BEAMB, CTRL, PIC, pictureData); - sendWriteCmd(BEAMB, CTRL, CURSRC, currsrcData); - sendWriteCmd(BEAMB, CTRL, DISPLAYO, displayData); - - sendWriteCmd(BEAMA, CTRL, SHDN, 0x03); - sendWriteCmd(BEAMB, CTRL, SHDN, 0x03); - - } else if (_beamCount == 1){ - currsrcData = 0x20; - - sendWriteCmd(BEAMA, CTRL, PIC, pictureData); - sendWriteCmd(BEAMA, CTRL, CURSRC, currsrcData); - sendWriteCmd(BEAMA, CTRL, DISPLAYO, displayData); - - sendWriteCmd(BEAMA, CTRL, SHDN, 0x03); - - } - - + // change led current based on number of connected beams + switch (_beamCount) { + case 1: + currsrcData = 0x20; + break; + case 2: + // unexpected value: see https://github.com/hoverlabs/beam_particle/issues/5 + currsrcData = 0x15; + break; + case 3: + currsrcData = 0x10; + break; + case 4: + currsrcData = 0x08; + break; + default: + currsrcData = 0x00; + break; + } + for (unsigned int b = 0; b < _beamCount; b++) { + sendWriteCmd(BEAM[b], CTRL, PIC, pictureData); + sendWriteCmd(BEAM[b], CTRL, CURSRC, currsrcData); + sendWriteCmd(BEAM[b], CTRL, DISPLAYO, displayData); + } + for (unsigned int b = 0; b < _beamCount; b++) { + sendWriteCmd(BEAM[b], CTRL, SHDN, 0x03); + } } -int Beam::status(){ - - int frameDone = 0; - - if (_gblMode == 0){ - frameDone = (sendReadCmd(_currBeam, CTRL, 0x0F)>>2); - - //if (frameDone == (_beamCount + 1)){ - Serial.println(frameDone); - return frameDone; - //} - } - -} +int Beam::status() { + int frameDone = 0; + if (_gblMode == 0) { + frameDone = (sendReadCmd(BEAM[0], CTRL, 0x0F) >> 2); + Log.trace("Frame done (%d)", frameDone); + } + return frameDone; +} /* ================= @@ -949,53 +540,46 @@ PRIVATE FUNCTIONS ================= */ -void Beam::initializeBeam(uint8_t baddr){ - - //set basic config on each defined beam unit - sendWriteCmd(baddr, CTRL, CFG, 0x01); +void Beam::initializeBeam(uint8_t baddr) { + Log.trace("void Beam::initializeBeam(uint8_t baddr)"); + //set basic config on each defined beam unit + sendWriteCmd(baddr, CTRL, CFG, 0x01); - //set each frame to off since cs[] is reset by default - for (int i=0;i<36;i++){ - writeFrame(baddr, i); + //set each frame to off since cs[] is reset by default + for (int i = 0; i < 36; i++) { + writeFrame(baddr, i); + } + + //set basic blink + pwm registers for each defined beam + for (int i = 0x40; i <= 0x45; i++) { + for (int j = 0x00; j <= 0x17; j++) { + sendWriteCmd(baddr, i, j, 0x00); } - - //set basic blink + pwm registers for each defined beam - for (int i=0x40; i<=0x45; i++) - { - for (int j=0x00; j<=0x17; j++) - { - sendWriteCmd(baddr, i, j, 0x00); - } - for (int k=0x18; k<=0x9b; k++) - { - sendWriteCmd(baddr, i, k, 0xFF); - } + for (int k = 0x18; k <= 0x9b; k++) { + sendWriteCmd(baddr, i, k, 0xFF); } - + } } - - -void Beam::setPrintDefaults (uint8_t mode, uint8_t startFrame, uint8_t numFrames, uint8_t numLoops, uint8_t frameDelay, uint8_t scrollDir, uint8_t fadeMode){ - +void Beam::setPrintDefaults(uint8_t mode, uint8_t startFrame, uint8_t numFrames, uint8_t numLoops, uint8_t frameDelay, uint8_t scrollDir, uint8_t fadeMode) { + Log.trace("void Beam::setPrintDefaults(uint8_t mode, uint8_t startFrame, uint8_t numFrames, uint8_t numLoops, uint8_t frameDelay, uint8_t scrollDir, uint8_t fadeMode)"); _scrollMode = 1; _scrollDir = scrollDir; _fadeMode = fadeMode; _frameDelay = frameDelay; _beamMode = mode; _numLoops = numLoops; - - if (mode == MOVIE || mode == SCROLL) { + if (mode == MOVIE || mode == SCROLL) { //make sure startFrame between 0 and 35 //make sure numFrames between 2 and 36 //make sure frameDelay between 0 and 1111 //make sure numLoops between 000 and 111 - uint8_t movieData = 0 << 7 | 1 << 6 | startFrame; + uint8_t movieData = 0 << 7 | 1 << 6 | startFrame; uint8_t moviemodeData = 0 << 7 | 0 << 6 | _lastFrameWrite; uint8_t frameData = 0; - uint8_t syncData = 0; + //uint8_t syncData = 0; switch (mode) { case MOVIE: @@ -1007,328 +591,168 @@ void Beam::setPrintDefaults (uint8_t mode, uint8_t startFrame, uint8_t numFrames } uint8_t displayData = _numLoops << 5 | 0 << 4 | 0x0B; - uint8_t irqmaskData = 0xFF; - uint8_t irqframedefData = 0x03; + //uint8_t irqmaskData = 0xFF; + //uint8_t irqframedefData = 0x03; uint8_t currsrcData = 0; - + // change led current based on number of connected beams - if (_beamCount == 4){ - currsrcData = 0x08; - } else if (_beamCount == 3){ - currsrcData = 0x10; - } else if (_beamCount == 2){ - currsrcData = 0x20; - } else if (_beamCount == 1){ - currsrcData = 0x20; - } else { - currsrcData = 0x15; + if (_beamCount == 4) { + currsrcData = 0x08; } - - - if (_gblMode == 1){ - - if (_scrollDir == LEFT){ - if(_beamCount >= 1){ - sendWriteCmd(BEAMA, CTRL, MOV, movieData ); - sendWriteCmd(BEAMA, CTRL, MOVMODE, moviemodeData); - sendWriteCmd(BEAMA, CTRL, CURSRC, currsrcData); - sendWriteCmd(BEAMA, CTRL, FRAMETIME, frameData); - sendWriteCmd(BEAMA, CTRL, DISPLAYO, displayData); - sendWriteCmd(BEAMA, CTRL, SHDN, 0x02); - } - - if(_beamCount >= 2){ - sendWriteCmd(BEAMB, CTRL, MOV, movieData); - sendWriteCmd(BEAMB, CTRL, MOVMODE, moviemodeData); - sendWriteCmd(BEAMB, CTRL, CURSRC, currsrcData); - sendWriteCmd(BEAMB, CTRL, FRAMETIME, frameData); - sendWriteCmd(BEAMB, CTRL, DISPLAYO, displayData); - sendWriteCmd(BEAMB, CTRL, SHDN, 0x02); - } - - if(_beamCount >= 3){ - sendWriteCmd(BEAMC, CTRL, MOV, movieData); - sendWriteCmd(BEAMC, CTRL, MOVMODE, moviemodeData); - sendWriteCmd(BEAMC, CTRL, CURSRC, currsrcData); - sendWriteCmd(BEAMC, CTRL, FRAMETIME, frameData); - sendWriteCmd(BEAMC, CTRL, DISPLAYO, displayData); - sendWriteCmd(BEAMC, CTRL, SHDN, 0x02); - } - - if(_beamCount >= 4){ - sendWriteCmd(BEAMD, CTRL, MOV, movieData); - sendWriteCmd(BEAMD, CTRL, MOVMODE, moviemodeData); - sendWriteCmd(BEAMD, CTRL, CURSRC, currsrcData); - sendWriteCmd(BEAMD, CTRL, FRAMETIME, frameData); - sendWriteCmd(BEAMD, CTRL, DISPLAYO, displayData); - } - - } else if (_scrollDir == RIGHT) { - //NEED TO MODIFY FOR RIGHT OR LEFT SCROLL// - } - - } else { - sendWriteCmd(_currBeam, CTRL, MOV, movieData ); - sendWriteCmd(_currBeam, CTRL, MOVMODE, moviemodeData); - sendWriteCmd(_currBeam, CTRL, CURSRC, currsrcData); - sendWriteCmd(_currBeam, CTRL, FRAMETIME, frameData); - sendWriteCmd(_currBeam, CTRL, DISPLAYO, displayData); - sendWriteCmd(_currBeam, CTRL, SHDN, 0x02); + else if (_beamCount == 3) { + currsrcData = 0x10; + } + else if (_beamCount == 2) { + currsrcData = 0x20; + } + else if (_beamCount == 1) { + currsrcData = 0x20; + } + else { + currsrcData = 0x15; } + if (_scrollDir == LEFT) { + for (unsigned int b = 0; b < _beamCount; b++) { + + sendWriteCmd(BEAM[b], CTRL, MOV, movieData); + sendWriteCmd(BEAM[b], CTRL, MOVMODE, moviemodeData); + sendWriteCmd(BEAM[b], CTRL, CURSRC, currsrcData); + sendWriteCmd(BEAM[b], CTRL, FRAMETIME, frameData); + sendWriteCmd(BEAM[b], CTRL, DISPLAYO, displayData); + if (b != 3) // for some reason not for BEAMD (???) + sendWriteCmd(BEAM[b], CTRL, SHDN, 0x02); + } + } + else { + //NEED TO MODIFY FOR RIGHT OR LEFT SCROLL// + } - - if (_gblMode == 1){ - - /* define clk sync in/out settings based on left/right scrolling direction */ - if (_scrollDir == LEFT){ - if (_beamCount == 2){ - sendWriteCmd(BEAMB, CTRL, CLKSYNC, 0x02); - sendWriteCmd(BEAMA, CTRL, CLKSYNC, 0x01); - } else if (_beamCount == 3){ - sendWriteCmd(BEAMC, CTRL, CLKSYNC, 0x02); - sendWriteCmd(BEAMB, CTRL, CLKSYNC, 0x01); - sendWriteCmd(BEAMA, CTRL, CLKSYNC, 0x01); - } else if (_beamCount == 4) { - sendWriteCmd(BEAMD, CTRL, CLKSYNC, 0x02); - sendWriteCmd(BEAMC, CTRL, CLKSYNC, 0x01); - sendWriteCmd(BEAMB, CTRL, CLKSYNC, 0x01); - sendWriteCmd(BEAMA, CTRL, CLKSYNC, 0x01); - } - - } else if (_scrollDir == RIGHT) { - if (_beamCount == 2){ - sendWriteCmd(BEAMA, CTRL, CLKSYNC, 0x02); - sendWriteCmd(BEAMB, CTRL, CLKSYNC, 0x01); - } else if (_beamCount == 3){ - sendWriteCmd(BEAMA, CTRL, CLKSYNC, 0x02); - sendWriteCmd(BEAMB, CTRL, CLKSYNC, 0x01); - sendWriteCmd(BEAMC, CTRL, CLKSYNC, 0x01); - } else if (_beamCount == 4) { - sendWriteCmd(BEAMA, CTRL, CLKSYNC, 0x02); - sendWriteCmd(BEAMB, CTRL, CLKSYNC, 0x01); - sendWriteCmd(BEAMC, CTRL, CLKSYNC, 0x01); - sendWriteCmd(BEAMD, CTRL, CLKSYNC, 0x01); - } + if (_gblMode == 1 && _beamCount > 1) { + /* define clk sync in/out settings based on left/right scrolling direction */ + if (_scrollDir == LEFT) { + sendWriteCmd(BEAM[_beamCount - 1], CTRL, CLKSYNC, 0x02); + for (int b = 0; b < _beamCount - 1; b++) { + sendWriteCmd(BEAM[b], CTRL, CLKSYNC, 0x01); } - } else { - - - + } + else { + sendWriteCmd(BEAM[0], CTRL, CLKSYNC, 0x02); + for (unsigned int b = 1; b < _beamCount; b++) { + sendWriteCmd(BEAM[b], CTRL, CLKSYNC, 0x01); + } + } + } + else { + // ToDo } - - - - } - - - - - } +unsigned int Beam::setSyncTimer() { + Log.trace("unsigned int Beam::setSyncTimer()"); + if (1 <= _frameDelay && _frameDelay <= 15) + return _frameDelay * 32.5; -unsigned int Beam::setSyncTimer(){ - - unsigned int timeDelay = 0; - - switch (_frameDelay){ - case 1: - timeDelay = 32.5; - break; - case 2: - timeDelay = 65; - break; - case 3: - timeDelay = 97.5; - break; - case 4: - timeDelay = 130; - break; - case 5: - timeDelay = 162.5; - break; - case 6: - timeDelay = 195; - break; - case 7: - timeDelay = 227.5; - break; - case 8: - timeDelay = 260; - break; - case 9: - timeDelay = 292.5; - break; - case 10: - timeDelay = 325; - break; - case 11: - timeDelay = 357.5; - break; - case 12: - timeDelay = 390; - break; - case 13: - timeDelay = 422.5; - break; - case 14: - timeDelay = 455; - break; - case 15: - timeDelay = 487.5; - break; - default: - timeDelay = 10000; - break; - } - return timeDelay; - + return 1000; } - - -void Beam::writeFrame(uint8_t addr, uint8_t f){ - - uint8_t p = f; - #if DEBUG - Serial.print("writing frame "); - Serial.print(p); - Serial.print(" = "); - #endif - int data = 0; - - for (int j=0x00; j<=0x0B; j++) - { - sendWriteCmd(addr, p+1, 2*j, cs[data]&0xFF); // i = frame address, 2*j = frame register address (even numbers) then first data byte - sendWriteCmd(addr, p+1, 2*j+1, (cs[data]&0x300)>>8); // i = frame address, 2*j+1 = frame register address (odd numbers) then second data byte - - //Serial.print(cs[data]&0xFF, HEX); - //Serial.print(" "); - //Serial.print((cs[data]&0x300)>>8, HEX); - //Serial.print(" "); - - data++; - } - #if DEBUG - Serial.println("Done writing frame"); - #endif +void Beam::writeFrame(uint8_t addr, uint8_t f) { + Log.trace("void Beam::writeFrame(uint8_t addr, uint8_t f)"); + uint8_t p = f; + Log.trace("writing frame %c (0x%02x)", p, p); + int data = 0; + for (int j = 0x00; j <= 0x0B; j++) { + sendWriteCmd(addr, p + 1, 2 * j, cs[data] & 0xFF); // i = frame address, 2*j = frame register address (even numbers) then first data byte + sendWriteCmd(addr, p + 1, 2 * j + 1, (cs[data] & 0x300) >> 8); // i = frame address, 2*j+1 = frame register address (odd numbers) then second data byte + data++; + } + Log.trace("Done writing frame"); } +void Beam::convertFrame(const uint8_t * currentFrame) { + Log.trace("void Beam::convertFrame(const uint8_t * currentFrame)"); + int i = 0; + //CS0 to CS3 + int n = 0; + for (int y = 10; y > 0; --y) { + i = (y < 6) ? 1 : 0; + cs[0] |= (((uint16_t)(*(currentFrame + n) & segmentmask[0 + i]) << (3 + i)) >> y); + cs[1] |= (((uint16_t)(*(currentFrame + n) & segmentmask[2 + i]) << (5 + i)) >> y); + cs[2] |= (((uint16_t)(*(currentFrame + n) & segmentmask[4 + i]) << (7 + i)) >> y); + cs[3] |= (((uint16_t)(*(currentFrame + n) & segmentmask[6 + i]) << (9 + i)) >> y); + n += 3; -void Beam::convertFrame(int * currentFrame){ - - int i=0; - - //CS0 to CS3 - int n=0; - for (int y=10; y>0; --y){ - - if (y < 6){ - i=1; - } else { - i=0; - } - cs[0] = cs[0] | (((*(currentFrame+n) & segmentmask[0+i]) <<(3+i)) >> y); - cs[1] = cs[1] | (((*(currentFrame+n) & segmentmask[2+i]) <<(5+i)) >> y); - cs[2] = cs[2] | (((*(currentFrame+n) & segmentmask[4+i]) <<(7+i)) >> y); - cs[3] = cs[3] | (((*(currentFrame+n) & segmentmask[6+i]) <<(9+i)) >> y); - n=n+3; - - if (n>12){ - n = 0; - } - - } - - //CS4 to CS7 - n = 1; - for (int y=10; y>0; --y){ - - if (y < 6){ - i=1; - } else { - i=0; - } - cs[4] = cs[4] | (((*(currentFrame+n) & segmentmask[0+i]) <<(3+i)) >> y); - cs[5] = cs[5] | (((*(currentFrame+n) & segmentmask[2+i]) <<(5+i)) >> y); - cs[6] = cs[6] | (((*(currentFrame+n) & segmentmask[4+i]) <<(7+i)) >> y); - cs[7] = cs[7] | (((*(currentFrame+n) & segmentmask[6+i]) <<(9+i)) >> y); - n=n+3; - - if (n>13){ - n = 1; - } + if (n > 12) { + n = 0; } - - //CS8 - CS11 - n = 2; - for (int y=10; y>0; --y){ - - if (y < 6){ - i=1; - } else { - i=0; - } - cs[8] = cs[8] | (((*(currentFrame+n) & segmentmask[0+i]) <<(3+i)) >> y); - cs[9] = cs[9] | (((*(currentFrame+n) & segmentmask[2+i]) <<(5+i)) >> y); - cs[10] = cs[10] | (((*(currentFrame+n) & segmentmask[4+i]) <<(7+i)) >> y); - cs[11] = cs[11] | (((*(currentFrame+n) & segmentmask[6+i]) <<(9+i)) >> y); - n=n+3; - - if (n>14){ - n = 2; - } - } -} - + } + //CS4 to CS7 + n = 1; + for (int y = 10; y > 0; --y) { + i = (y < 6) ? 1 : 0; + cs[4] |= (((uint16_t)(*(currentFrame + n) & segmentmask[0 + i]) << (3 + i)) >> y); + cs[5] |= (((uint16_t)(*(currentFrame + n) & segmentmask[2 + i]) << (5 + i)) >> y); + cs[6] |= (((uint16_t)(*(currentFrame + n) & segmentmask[4 + i]) << (7 + i)) >> y); + cs[7] |= (((uint16_t)(*(currentFrame + n) & segmentmask[6 + i]) << (9 + i)) >> y); + n += 3; + if (n > 13) { + n = 1; + } + } -void Beam::sendWriteCmd(uint8_t addr, uint8_t ramsection, uint8_t subreg, uint8_t subregdata){ + //CS8 - CS11 + n = 2; + for (int y = 10; y > 0; --y) { + i = (y < 6) ? 1 : 0; + cs[8] |= (((uint16_t)(*(currentFrame + n) & segmentmask[0 + i]) << (3 + i)) >> y); + cs[9] |= (((uint16_t)(*(currentFrame + n) & segmentmask[2 + i]) << (5 + i)) >> y); + cs[10] |= (((uint16_t)(*(currentFrame + n) & segmentmask[4 + i]) << (7 + i)) >> y); + cs[11] |= (((uint16_t)(*(currentFrame + n) & segmentmask[6 + i]) << (9 + i)) >> y); + n += 3; - int stat; - stat = i2cwrite(addr, REGSEL, ramsection); - if (stat == 0) { - i2cwrite(addr, subreg, subregdata); + if (n > 14) { + n = 2; } - else - { - Serial.print("Beam not found: "); - Serial.print(addr); - Serial.println(""); - } - + } } -uint8_t Beam::sendReadCmd(uint8_t addr, uint8_t ramsection, uint8_t subreg){ +void Beam::sendWriteCmd(uint8_t addr, uint8_t ramsection, uint8_t subreg, uint8_t subregdata) { + //Log.trace("void Beam::sendWriteCmd(uint8_t addr, uint8_t ramsection, uint8_t subreg, uint8_t subregdata)"); + static int errCount = 0; + if (!i2cwrite(addr, REGSEL, ramsection)) { + i2cwrite(addr, subreg, subregdata); + errCount = 0; + } + else { + Log.warn("Beam not found: 0x%02x (%d)", addr, _beamCount); + if (errCount++ > 50) _wire->reset(); + } +} - uint8_t c; +uint8_t Beam::sendReadCmd(uint8_t addr, uint8_t ramsection, uint8_t subreg) { + //Log.trace("uint8_t Beam::sendReadCmd(uint8_t addr, uint8_t ramsection, uint8_t subreg)"); i2cwrite(addr, REGSEL, ramsection); - Wire.beginTransmission(addr); - Wire.write(subreg); - Wire.endTransmission(); + _wire->beginTransmission(addr); + _wire->write(subreg); + _wire->endTransmission(); - Wire.requestFrom(addr, 1); - while(Wire.available()) - { - c = Wire.read(); - //Serial.println(c, HEX); - return c; - } - + _wire->requestFrom(addr, (uint8_t)1); + // wait up to 250ms for data + for (uint32_t _ms = millis(); !_wire->available() && millis() - _ms < 250; Particle.process()); + if (_wire->available()) return _wire->read(); + else _wire->reset(); + return 0; } - - -uint8_t Beam::i2cwrite(uint8_t address, uint8_t cmdbyte, uint8_t databyte) { - - Wire.beginTransmission(address); - Wire.write(cmdbyte); - Wire.write(databyte); - return (Wire.endTransmission()); - -} \ No newline at end of file +uint8_t Beam::i2cwrite(uint8_t address, uint8_t cmdbyte, uint8_t databyte) { + //Log.trace("uint8_t Beam::i2cwrite(uint8_t address, uint8_t cmdbyte, uint8_t databyte)"); + _wire->beginTransmission(address); + _wire->write(cmdbyte); + _wire->write(databyte); + return (_wire->endTransmission()); +} diff --git a/beam.h b/beam.h index acdce6e..0af24f6 100644 --- a/beam.h +++ b/beam.h @@ -1,93 +1,115 @@ +#pragma once /* -=========================================================================== - This is the library for Beam. - - Beam is a beautiful LED matrix — features 120 LEDs that displays scrolling text, animations, or custom lighting effects. - Beam can be purchased here: http://www.hoverlabs.co - - Written by Emran Mahbub and Jonathan Li for Hover Labs. - BSD license, all text above must be included in any redistribution - =========================================================================== -*/ - -#ifndef _BEAM -#define _BEAM +This is the library for Beam. -#define BEAMA 0x36 -#define BEAMB 0x34 -#define BEAMC 0x30 -#define BEAMD 0x37 +Beam is a beautiful LED matrix — features 120 LEDs that displays scrolling text, animations, or custom lighting effects. +Beam can be purchased here: http://www.hoverlabs.co +Written by Emran Mahbub and Jonathan Li for Hover Labs. +BSD license, all text above must be included in any redistribution + +--------------------------------------------------------------------------- + +Edit by ScruffR 2017-06-25: +Adapted to support alternative I2C interfaces +Added support for special characters (e.g. German Umlauts Ä, Ö, Ü) with the + framework to add any other +Replaced "copy-paste" logic with functional blocks by use of arrays and loops + +=========================================================================== +*/ #define MAXFRAME 36 -#define SPACE 3 -#define KERNING 1 +#define SPACE 3 +#define KERNING 1 -#define REGSEL 0xFD -//RAM section address -#define CTRL 0xC0 +const uint8_t BEAM_ADDRESS[] = {0x36, 0x34, 0x30, 0x37}; +#define BEAMA BEAM_ADDRESS[0] +#define BEAMB BEAM_ADDRESS[1] +#define BEAMC BEAM_ADDRESS[2] +#define BEAMD BEAM_ADDRESS[3] //Sub Register address -#define PIC 0x00 -#define MOV 0x01 -#define MOVMODE 0x02 -#define FRAMETIME 0x03 -#define DISPLAYO 0x04 -#define CURSRC 0x05 -#define CFG 0x06 -#define IRQMASK 0x07 -#define IRQFRAME 0x08 -#define SHDN 0x09 -#define CLKSYNC 0x0B +enum BEAM_REGISTER { + PIC = 0x00, + MOV = 0x01, + MOVMODE = 0x02, + FRAMETIME = 0x03, + DISPLAYO = 0x04, + CURSRC = 0x05, + CFG = 0x06, + IRQMASK = 0x07, + IRQFRAME = 0x08, + SHDN = 0x09, + CLKSYNC = 0x0B, + //RAM section address + CTRL = 0xC0, + REGSEL = 0xFD, +}; //User modes -#define PICTURE 0x01 -#define MOVIE 0x02 -#define SCROLL 0x03 - -#define RIGHT 0 -#define LEFT 1 -#define FADEON 1 -#define FADEOFF 0 +enum BEAM_MODE { + PICTURE = 0x01, + MOVIE = 0x02, + SCROLL = 0x03, + FADEOFF = 0x00, + FADEON = 0x01, +}; +enum BEAM_ORIENTATION { + RIGHT = 0, + LEFT = 1, +}; class Beam { - public: - Beam(int rstpin, int irqpin, int numberOfBeams); - Beam(int rstpin, int irqpin, uint8_t syncMode, uint8_t beamAddress); - bool begin(void); - void initBeam(); - void print(const char* text); - void printFrame(uint8_t frameToPrint, const char * text); - void play(); - void draw(); - void display(); - void setScroll(uint8_t direction, uint8_t fade); - void setSpeed(uint8_t speed); - void setLoops (uint8_t loops); - void setMode (uint8_t mode); - volatile int beamNumber; - int checkStatus(); - int status(); +public: + Beam(int rstpin, int irqpin, int numberOfBeams); + Beam(int rstpin, int irqpin, uint8_t syncMode, uint8_t beamAddress); + bool begin(TwoWire& wire = Wire); + void initBeam(); + void print(const char* text); + void printFrame(uint8_t frameToPrint, const char * text); + void play(); + void display(); + void draw(); + void setScroll(uint8_t direction, uint8_t fade); + void setSpeed(uint8_t speed); + void setLoops(uint8_t loops); + void setMode(uint8_t mode); + volatile int beamNumber; + int checkStatus(); + int status(); - private: - uint16_t cs[12], segmentmask[8]; - uint8_t cscolumn[25]; - uint8_t _gblMode, _currBeam, _syncMode, _lastFrameWrite, _scrollMode, _scrollDir, _fadeMode, _frameDelay, _beamMode, _numLoops; - int _rst, _irq, _beamCount, activeBeams; - Timer* _syncTimer; - - void startNextBeam(); - void initializeBeam(uint8_t b); - void setPrintDefaults(uint8_t mode, uint8_t startFrame, uint8_t numFrames, uint8_t numLoops, uint8_t frameDelay, uint8_t scrollDir, uint8_t fadeMode); - void writeFrame(uint8_t addr, uint8_t f); - void convertFrame(int * currentFrame); - unsigned int setSyncTimer(); - void sendWriteCmd(uint8_t addr, uint8_t ramsection, uint8_t subreg, uint8_t subregdata); - uint8_t sendReadCmd(uint8_t addr, uint8_t ramsection, uint8_t subreg); - uint8_t i2cwrite(uint8_t address, uint8_t cmdbyte, uint8_t databyte); -}; +private: + const uint8_t *BEAM; + uint16_t cs[12]; + uint16_t segmentmask[8]; + uint8_t cscolumn[25]; + uint8_t activeBeams; + uint8_t _gblMode; + uint8_t _syncMode; + uint8_t _lastFrameWrite; + uint8_t _scrollMode; + uint8_t _scrollDir; + uint8_t _fadeMode; + uint8_t _frameDelay; + uint8_t _beamMode; + uint8_t _numLoops; + uint8_t _beamCount; + int _rst; + int _irq; + TwoWire *_wire; + Timer *_syncTimer; + void startNextBeam(); + void initializeBeam(uint8_t b); + void setPrintDefaults(uint8_t mode, uint8_t startFrame, uint8_t numFrames, uint8_t numLoops, uint8_t frameDelay, uint8_t scrollDir, uint8_t fadeMode); + void writeFrame(uint8_t addr, uint8_t f); + void convertFrame(const uint8_t * currentFrame); + unsigned int setSyncTimer(); + void sendWriteCmd(uint8_t addr, uint8_t ramsection, uint8_t subreg, uint8_t subregdata); + uint8_t sendReadCmd(uint8_t addr, uint8_t ramsection, uint8_t subreg); + uint8_t i2cwrite(uint8_t address, uint8_t cmdbyte, uint8_t databyte); +}; -#endif \ No newline at end of file diff --git a/charactermap.h b/charactermap.h index 5d8548c..ff8f83b 100644 --- a/charactermap.h +++ b/charactermap.h @@ -1,3 +1,4 @@ +#pragma once /* =========================================================================== @@ -9,76 +10,95 @@ Written by Emran Mahbub and Jonathan Li for Hover Labs. BSD license, all text above must be included in any redistribution +--------------------------------------------------------------------------- + +Edit by ScruffR 2017-06-25: +Adapted to support alternative I2C interfaces +Added support for special characters (e.g. German Umlauts Ä, Ö, Ü) with the + framework to add any other +Replaced "copy-paste" logic with functional blocks by use of arrays and loops + =========================================================================== */ +#include -uint8_t charactermap[66][7] = { -{0x00,0x00,0xFF,0xFF,0xFF,0xFF}, // SPACE -{0x17,0x0,0xFF,0xFF,0xFF,0xFF,0xFF}, // ! -{0x3,0x0,0x3,0x0,0xFF,0x0,0xFF}, // " -{0xA,0x1F,0xA,0x1F,0xA,0x0,0xFF}, // # -{0x17,0x15,0x1F,0x15,0x1D,0x0,0xFF}, // $ -{0x12,0x8,0x4,0x12,0x0,0xFF,0xFF}, // % -{0xA,0x15,0xE,0x10,0x0,0xFF,0xFF}, // & -{0x3,0x0,0xFF,0xFF,0xFF,0xFF,0xFF}, // ' -{0xE,0x11,0x0,0xFF,0xFF,0xFF,0xFF}, // ( -{0x11,0xE,0x0,0xFF,0xFF,0xFF,0xFF}, // ) -{0x5,0x2,0x5,0x0,0xFF,0xFF,0xFF}, // * -{0x8,0x1C,0x8,0x0,0xFF,0xFF,0xFF}, // + -{0x10,0x8,0x0,0xFF,0xFF,0xFF,0xFF}, // , -{0x4,0x4,0x0,0xFF,0xFF,0xFF,0xFF}, // - -{0x10,0x0,0xFF,0xFF,0xFF,0xFF,0xFF}, // . -{0x18,0xE,0x3,0x0,0xFF,0xFF,0xFF}, // / -{0x1F,0x11,0x1F,0x0,0xFF,0xFF,0xFF}, // 0 -{0x2,0x1F,0x0,0xFF,0xFF,0xFF,0xFF}, // 1 -{0x1D,0x15,0x17,0x0,0xFF,0xFF,0xFF}, // 2 -{0x15,0x15,0x1F,0x0,0xFF,0xFF,0xFF}, // 3 -{0x7,0x4,0x1F,0x0,0xFF,0xFF,0xFF}, // 4 -{0x17,0x15,0x1D,0x0,0xFF,0xFF,0xFF}, // 5 -{0x1F,0x15,0x1D,0x0,0xFF,0xFF,0xFF}, // 6 -{0x1,0x1,0x1F,0x0,0xFF,0xFF,0xFF}, // 7 -{0x1F,0x15,0x1F,0x0,0xFF,0xFF,0xFF}, // 8 -{0x17,0x15,0x1F,0x0,0xFF,0xFF,0xFF}, // 9 -{0xA,0x0,0xFF,0xFF,0xFF,0xFF,0xFF}, // : -{0xA,0x0,0xFF,0xFF,0xFF,0xFF,0xFF}, // ; -{0x4,0xA,0x11,0x0,0xFF,0xFF,0xFF}, // < -{0xA,0xA,0xA,0x0,0xFF,0xFF,0xFF}, // = -{0x11,0xA,0x4,0x0,0xFF,0xFF,0xFF}, // > -{0x1,0x15,0x7,0x0,0xFF,0xFF,0xFF}, // ? -{0x1F,0x11,0x1D,0x15,0x1F,0x0,0xFF}, // @ -{0x1F,0x05,0x05,0x1F,0x00,0xFF,0xFF}, // A -{0x1F,0x15,0x15,0x0A,0x00,0xFF,0xFF}, // B -{0x0E,0x11,0x11,0x0A,0x00,0xFF,0xFF}, // C -{0x1F,0x11,0x11,0x0E,0x00,0xFF,0xFF}, // D -{0x1F,0x15,0x15,0x15,0x00,0xFF,0xFF}, // E -{0x1F,0x5,0x5,0x0,0xFF,0xFF,0xFF}, // F -{0x1F,0x11,0x15,0x1D,0x0,0xFF,0xFF}, // G -{0x1F,0x4,0x4,0x1F,0x0,0xFF,0xFF}, // H -{0x11,0x1F,0x11,0x0,0xFF,0xFF,0xFF}, // I -{0x18,0x10,0x1F,0x0,0xFF,0xFF,0xFF}, // J -{0x1F,0x4,0x1B,0x0,0xFF,0xFF,0xFF}, // K -{0x1F,0x10,0x10,0x0,0xFF,0xFF,0xFF}, // L -{0x1F,0x2,0x4,0x2,0x1F,0x00,0xFF}, // M -{0x1F,0x2,0x4,0x8,0x1F,0x00,0xFF}, // N -{0xE,0x11,0x11,0x11,0xE,0x00,0xFF}, // O -{0x1F,0x5,0x7,0x0,0xFF,0xFF,0xFF}, // P -{0x1F,0x11,0x15,0x19,0x1F,0x00,0xFF}, // Q -{0x1F,0x5,0xD,0x17,0x0,0xFF,0xFF}, // R -{0x17,0x15,0x15,0x1D,0x0,0xFF,0xFF}, // S -{0x1,0x1F,0x1,0x0,0xFF,0xFF,0xFF}, // T -{0x1F,0x10,0x10,0x1F,0x0,0xFF,0xFF}, // U -{0x7,0x8,0x10,0x8,0x7,0x00,0xFF}, // V -{0xF,0x10,0xC,0x10,0xF,0x00,0xFF}, // W -{0x11,0xA,0x4,0xA,0x11,0x00,0xFF}, // X -{0x1,0x2,0x1C,0x2,0x1,0x00,0xFF}, // Y -{0x11,0x19,0x15,0x13,0x0,0xFF,0xFF}, // Z +const uint8_t charactermap[69][7] = { +{0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF}, // 0 SPACE +{0x17,0x00,0xFF,0xFF,0xFF,0xFF,0xFF}, // 1 ! +{0x03,0x00,0x03,0x00,0xFF,0x00,0xFF}, // 2 " +{0x0A,0x1F,0x0A,0x1F,0x0A,0x00,0xFF}, // 3 # +{0x17,0x15,0x1F,0x15,0x1D,0x00,0xFF}, // 4 $ +{0x12,0x08,0x04,0x12,0x00,0xFF,0xFF}, // 5 % +{0x0A,0x15,0x0E,0x10,0x00,0xFF,0xFF}, // 6 & +{0x03,0x00,0xFF,0xFF,0xFF,0xFF,0xFF}, // 7 ' +{0x0E,0x11,0x00,0xFF,0xFF,0xFF,0xFF}, // 8 ( +{0x11,0x0E,0x00,0xFF,0xFF,0xFF,0xFF}, // 9 ) +{0x05,0x02,0x05,0x00,0xFF,0xFF,0xFF}, // 10 * +{0x08,0x1C,0x08,0x00,0xFF,0xFF,0xFF}, // 11 + +{0x10,0x08,0x00,0xFF,0xFF,0xFF,0xFF}, // 12 , +{0x04,0x04,0x00,0xFF,0xFF,0xFF,0xFF}, // 13 - +{0x10,0x00,0xFF,0xFF,0xFF,0xFF,0xFF}, // 14 . +{0x18,0x0E,0x03,0x00,0xFF,0xFF,0xFF}, // 15 / +{0x1F,0x11,0x1F,0x00,0xFF,0xFF,0xFF}, // 16 0 +{0x02,0x1F,0x00,0xFF,0xFF,0xFF,0xFF}, // 17 1 +{0x1D,0x15,0x17,0x00,0xFF,0xFF,0xFF}, // 18 2 +{0x11,0x15,0x1F,0x00,0xFF,0xFF,0xFF}, // 19 3 +{0x07,0x04,0x1F,0x00,0xFF,0xFF,0xFF}, // 20 4 +{0x17,0x15,0x1D,0x00,0xFF,0xFF,0xFF}, // 21 5 +{0x1F,0x15,0x1D,0x00,0xFF,0xFF,0xFF}, // 22 6 +{0x01,0x1D,0x03,0x00,0xFF,0xFF,0xFF}, // 23 7 +{0x1F,0x15,0x1F,0x00,0xFF,0xFF,0xFF}, // 24 8 +{0x17,0x15,0x1F,0x00,0xFF,0xFF,0xFF}, // 25 9 +{0x0A,0x00,0xFF,0xFF,0xFF,0xFF,0xFF}, // 26 : +{0x0A,0x00,0xFF,0xFF,0xFF,0xFF,0xFF}, // 27 ; +{0x04,0x0A,0x11,0x00,0xFF,0xFF,0xFF}, // 28 < +{0x0A,0x0A,0x0A,0x00,0xFF,0xFF,0xFF}, // 29 = +{0x11,0x0A,0x04,0x00,0xFF,0xFF,0xFF}, // 30 > +{0x01,0x15,0x07,0x00,0xFF,0xFF,0xFF}, // 31 ? +{0x1F,0x11,0x1D,0x15,0x1F,0x00,0xFF}, // 32 @ +{0x1E,0x05,0x05,0x1E,0x00,0xFF,0xFF}, // 33 A +{0x1F,0x15,0x15,0x0A,0x00,0xFF,0xFF}, // 34 B +{0x0E,0x11,0x11,0x0A,0x00,0xFF,0xFF}, // 35 C +{0x1F,0x11,0x11,0x0E,0x00,0xFF,0xFF}, // 36 D +{0x1F,0x15,0x15,0x11,0x00,0xFF,0xFF}, // 37 E +//{0x1F,0x15,0x15,0x00,0xFF,0xFF,0xFF}, // 37 E narrow +{0x1F,0x05,0x05,0x00,0xFF,0xFF,0xFF}, // 38 F +{0x0E,0x11,0x15,0x1D,0x00,0xFF,0xFF}, // 39 G +{0x1F,0x04,0x04,0x1F,0x00,0xFF,0xFF}, // 40 H +{0x11,0x1F,0x11,0x00,0xFF,0xFF,0xFF}, // 41 I +{0x18,0x10,0x1F,0x00,0xFF,0xFF,0xFF}, // 42 J +{0x1F,0x04,0x1B,0x00,0xFF,0xFF,0xFF}, // 43 K +{0x1F,0x10,0x10,0x00,0xFF,0xFF,0xFF}, // 44 L +{0x1F,0x02,0x04,0x02,0x1F,0x00,0xFF}, // 45 M +{0x1F,0x02,0x04,0x08,0x1F,0x00,0xFF}, // 46 N +{0x0E,0x11,0x11,0x11,0x0E,0x00,0xFF}, // 47 O +{0x1F,0x05,0x05,0x02,0x00,0xFF,0xFF}, // 48 P +{0x0E,0x11,0x15,0x09,0x16,0x00,0xFF}, // 49 Q +{0x1F,0x05,0x0D,0x12,0x00,0xFF,0xFF}, // 50 R +{0x12,0x15,0x15,0x09,0x00,0xFF,0xFF}, // 51 S +{0x01,0x1F,0x01,0x00,0xFF,0xFF,0xFF}, // 52 T +{0x0F,0x10,0x10,0x0F,0x00,0xFF,0xFF}, // 53 U +{0x07,0x08,0x10,0x08,0x07,0x00,0xFF}, // 54 V +{0x0F,0x10,0x0C,0x10,0x0F,0x00,0xFF}, // 55 W +{0x11,0x0A,0x04,0x0A,0x11,0x00,0xFF}, // 56 X +{0x01,0x02,0x1C,0x02,0x01,0x00,0xFF}, // 57 Y +{0x11,0x19,0x15,0x13,0x11,0x00,0xFF}, // 58 Z +{0x1F,0x11,0x00,0xFF,0xFF,0xFF,0xFF}, // 59 [ +{0x03,0x0E,0x18,0x00,0xFF,0xFF,0xFF}, // 60 / +{0x11,0x1F,0x00,0x00,0xFF,0xFF,0xFF}, // 61 ] +{0x06,0x0E,0x1C,0x0E,0x06,0x00,0xFF}, // 62 ^ +{0x10,0x10,0x10,0x00,0xFF,0xFF,0xFF}, // 63 _ +{0x01,0x02,0x00,0xFF,0xFF,0xFF,0xFF}, // 64 ' +//{0x1F,0x05,0x05,0x1F,0x00,0xFF,0xFF}, // 65 A -> Ä +{0x1D,0x0A,0x0A,0x1D,0x00,0xFF,0xFF}, // 65 Ä added +//{0x0E,0x11,0x11,0x11,0x0E,0x00,0xFF}, // 66 O -> Ö +{0x0D,0x12,0x12,0x0D,0x00,0xFF,0xFF}, // 66 Ö added +//{0x1F,0x10,0x10,0x1F,0x00,0xFF,0xFF}, // 67 U -> Ü +{0x0D,0x10,0x10,0x0D,0x00,0xFF,0xFF}, // 67 Ü added +//{0x17,0x15,0x15,0x1D,0x00,0xFF,0xFF}, // 68 S -> ß +{0x1E,0x15,0x17,0x0D,0x00,0xFF,0xFF}, // 68 ß added +}; -{0x1F,0x11,0x0,0xFF,0xFF,0xFF,0xFF}, //[ -{0x3,0xE,0x18,0x0,0xFF,0xFF,0xFF}, /// -{0x11,0x1F,0x0,0x0,0xFF,0xFF,0xFF}, //] -{0x6,0xE,0x1C,0xE,0x6,0x0,0xFF}, //^ -{0x10,0x10,0x10,0x0,0xFF,0xFF,0xFF}, //_ -{0x1,0x2,0x0,0xFF,0xFF,0xFF,0xFF}, //' + -}; diff --git a/frames.h b/frames.h index 6703802..7eb449f 100644 --- a/frames.h +++ b/frames.h @@ -1,6 +1,6 @@ +#pragma once /* =========================================================================== - This is the library for Beam. Beam is a beautiful LED matrix — features 120 LEDs that displays scrolling text, animations, or custom lighting effects. @@ -9,297 +9,268 @@ Written by Emran Mahbub and Jonathan Li for Hover Labs. BSD license, all text above must be included in any redistribution +--------------------------------------------------------------------------- + +Edit by ScruffR 2017-06-25: +Adapted to support alternative I2C interfaces +Added support for special characters (e.g. German Umlauts Ä, Ö, Ü) with the + framework to add any other +Replaced "copy-paste" logic with functional blocks by use of arrays and loops + =========================================================================== */ -int frame0[0x0F] = { //Frame 0 +const uint8_t frameList[MAXFRAME][15] = { +{ //Frame 0 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, -}; -int frame1[0x0F] = { //Frame 0 +}, +{ //Frame 1 0b10000000, 0b00000000, 0b00000001, 0b10000000, 0b00000000, 0b00000001, 0b10000000, 0b00000000, 0b00000001, 0b10000000, 0b00000000, 0b00000001, 0b10000000, 0b00000000, 0b00000001, -}; -int frame2[0x0F] = { //Frame 0 +}, +{ //Frame 2 0b11000000, 0b00000000, 0b00000011, 0b11000000, 0b00000000, 0b00000011, 0b11000000, 0b00000000, 0b00000011, 0b11000000, 0b00000000, 0b00000011, 0b11000000, 0b00000000, 0b00000011, -}; -int frame3[0x0F] = { //Frame 0 +}, +{ //Frame 3 0b01100000, 0b00000000, 0b00000110, 0b01100000, 0b00000000, 0b00000110, 0b01100000, 0b00000000, 0b00000110, 0b01100000, 0b00000000, 0b00000110, 0b01100000, 0b00000000, 0b00000110, -}; -int frame4[0x0F] = { //Frame 0 +}, +{ //Frame 4 0b00110000, 0b00000000, 0b00001100, 0b00110000, 0b00000000, 0b00001100, 0b00110000, 0b00000000, 0b00001100, 0b00110000, 0b00000000, 0b00001100, 0b00110000, 0b00000000, 0b00001100, -}; -int frame5[0x0F] = { //Frame 0 +}, +{ //Frame 5 0b00011000, 0b00000000, 0b00011000, 0b00011000, 0b00000000, 0b00011000, 0b00011000, 0b00000000, 0b00011000, 0b00011000, 0b00000000, 0b00011000, 0b00011000, 0b00000000, 0b00011000, -}; -int frame6[0x0F] = { //Frame 0 +}, +{ //Frame 6 0b00001100, 0b00000000, 0b00110000, 0b00001100, 0b00000000, 0b00110000, 0b00001100, 0b00000000, 0b00110000, 0b00001100, 0b00000000, 0b00110000, 0b00001100, 0b00000000, 0b00110000, -}; -int frame7[0x0F] = { //Frame 0 +}, +{ //Frame 7 0b00000110, 0b00000000, 0b01100000, 0b00000110, 0b00000000, 0b01100000, 0b00000110, 0b00000000, 0b01100000, 0b00000110, 0b00000000, 0b01100000, 0b00000110, 0b00000000, 0b01100000, -}; -int frame8[0x0F] = { //Frame 0 +}, +{ //Frame 8 0b00000011, 0b00000000, 0b11000000, 0b00000011, 0b00000000, 0b11000000, 0b00000011, 0b00000000, 0b11000000, 0b00000011, 0b00000000, 0b11000000, 0b00000011, 0b00000000, 0b11000000, -}; -int frame9[0x0F] = { - 0b00000011, 0b11000011, 0b11000000, //Frame 9 +}, +{ //Frame 9 0b00000011, 0b11000011, 0b11000000, 0b00000011, 0b11000011, 0b11000000, 0b00000011, 0b11000011, 0b11000000, 0b00000011, 0b11000011, 0b11000000, -}; -int frame10[0x0F] = { - 0b00000000, 0b00111100, 0b00000000, //Frame 10 + 0b00000011, 0b11000011, 0b11000000, +}, +{ //Frame 10 + 0b00000000, 0b00111100, 0b00000000, 0b00000000, 0b00111100, 0b00000000, 0b00000000, 0b00111100, 0b00000000, 0b00000000, 0b00111100, 0b00000000, 0b00000000, 0b00111100, 0b00000000, -}; -int frame11[0x0F] = { - 0b00000000, 0b00011000, 0b00000000, //Frame 11 +}, +{ //Frame 11 + 0b00000000, 0b00011000, 0b00000000, 0b00000000, 0b00011000, 0b00000000, 0b00000000, 0b00011000, 0b00000000, 0b00000000, 0b00011000, 0b00000000, 0b00000000, 0b00011000, 0b00000000, -}; -int frame12[0x0F] = { +}, +{ //Frame 12 0b00000000, 0b00010000, 0b00000000, 0b00000000, 0b00101000, 0b00000000, 0b00000000, 0b01000100, 0b00000000, 0b00000000, 0b00101000, 0b00000000, 0b00000000, 0b00010000, 0b00000000, -}; -int frame13[0x0F] = { +}, +{ //Frame 13 0b00000000, 0b00101000, 0b00000000, 0b00000000, 0b01000100, 0b00000000, 0b00000000, 0b10000010, 0b00000000, 0b00000000, 0b01000100, 0b00000000, 0b00000000, 0b00101000, 0b00000000, -}; -int frame14[0x0F] = { +}, +{ //Frame 14 0b00000000, 0b01000010, 0b00000000, 0b00000000, 0b10000001, 0b00000000, 0b00000001, 0b00000000, 0b10000000, 0b00000000, 0b10000001, 0b00000000, 0b00000000, 0b01000010, 0b00000000, -}; -int frame15[0x0F] = { +}, +{ //Frame 15 0b00000000, 0b01000010, 0b00000000, 0b00000000, 0b10000001, 0b00000000, 0b00000001, 0b00000000, 0b10000000, 0b00000000, 0b10000001, 0b00000000, 0b00000000, 0b01000010, 0b00000000, -}; -int frame16[0x0F] = { +}, +{ //Frame 16 0b00000000, 0b11000011, 0b00000000, 0b00000001, 0b10000001, 0b10000000, 0b00000011, 0b00000000, 0b11000000, 0b00000001, 0b10000001, 0b10000000, 0b00000000, 0b11000011, 0b00000000, -}; -int frame17[0x0F] = { +}, +{ //Frame 17 0b00000011, 0b00000000, 0b11000000, 0b00000110, 0b00000000, 0b01100000, 0b00001100, 0b00000000, 0b00110000, 0b00000110, 0b00000000, 0b01100000, 0b00000011, 0b00000000, 0b11000000, -}; -int frame18[0x0F] = { +}, +{ //Frame 18 0b00000110, 0b00000000, 0b01100000, 0b00001100, 0b00000000, 0b00110000, 0b00011000, 0b00000000, 0b00011000, 0b00001100, 0b00000000, 0b00110000, 0b00000110, 0b00000000, 0b01100000, -}; -int frame19[0x0F] = { +}, +{ //Frame 19 0b00001100, 0b00000000, 0b00110000, 0b00011000, 0b00000000, 0b00011000, 0b00110000, 0b00000000, 0b00001100, 0b00011000, 0b00000000, 0b00011000, 0b00001100, 0b00000000, 0b00110000, -}; -int frame20[0x0F] = { +}, +{ //Frame 20 0b00011000, 0b00000000, 0b00011000, 0b00110000, 0b00000000, 0b00001100, 0b01100000, 0b00000000, 0b00000110, 0b00110000, 0b00000000, 0b00001100, 0b00011000, 0b00000000, 0b00011000, -}; -int frame21[0x0F] = { +}, +{ //Frame 21 0b00110000, 0b00000000, 0b00001100, 0b01100000, 0b00000000, 0b00000110, 0b11000000, 0b00000000, 0b00000011, 0b01100000, 0b00000000, 0b00000110, 0b00110000, 0b00000000, 0b00001100, -}; -int frame22[0x0F] = { - 0b11100111, 0b10111101, 0b00010000, //Frame 22 +}, +{ //Frame 22 + 0b11100111, 0b10111101, 0b00010000, 0b10010100, 0b00100101, 0b10110000, 0b11100111, 0b10111101, 0b01010000, 0b10010100, 0b00100101, 0b00010000, 0b11100111, 0b10100101, 0b00010000, -}; -int frame23[0x0F] = { - 0b00011000, 0b01000010, 0b11101111, //Frame 22 +}, +{ //Frame 23 + 0b00011000, 0b01000010, 0b11101111, 0b01101011, 0b11011010, 0b01001111, 0b00011000, 0b01000010, 0b10101111, 0b01101011, 0b11011010, 0b11101111, 0b00011000, 0b01011010, 0b11101111, -}; -int frame24[0x0F] = { - 0b11100111, 0b10111101, 0b00010000, //Frame 22 +}, +{ //Frame 24 + 0b11100111, 0b10111101, 0b00010000, 0b10010100, 0b10100101, 0b10110000, 0b11100111, 0b10111101, 0b01010000, 0b10010100, 0b10100101, 0b00010000, 0b11100111, 0b10100101, 0b00010000, -}; -int frame25[0x0F] = { - 0b00011000, 0b01000010, 0b11101111, //Frame 22 +}, +{ //Frame 25 + 0b00011000, 0b01000010, 0b11101111, 0b01101011, 0b11011010, 0b01001111, 0b00011000, 0b01000010, 0b10101111, 0b01101011, 0b11011010, 0b11101111, 0b00011000, 0b01011010, 0b11101111, -}; -int frame26[0x0F] = { - 0b11100111, 0b10111101, 0b00010000, //Frame 22 +}, +{ //Frame 26 + 0b11100111, 0b10111101, 0b00010000, 0b10010100, 0b10100101, 0b10110000, 0b11100111, 0b10111101, 0b01010000, 0b10010100, 0b10100101, 0b00010000, 0b11100111, 0b10100101, 0b00010000, -}; -int frame27[0x0F] = { - 0b00011000, 0b01000010, 0b11101111, //Frame 22 +}, +{ //Frame 27 + 0b00011000, 0b01000010, 0b11101111, 0b01101011, 0b11011010, 0b01001111, 0b00011000, 0b01000010, 0b10101111, 0b01101011, 0b11011010, 0b11101111, 0b00011000, 0b01011010, 0b11101111, -}; -int frame28[0x0F] = { - 0b11100111, 0b10111101, 0b00010000, //Frame 22 +}, +{ //Frame 28 + 0b11100111, 0b10111101, 0b00010000, 0b10010100, 0b10100101, 0b10110000, 0b11100111, 0b10111101, 0b01010000, 0b10010100, 0b10100101, 0b00010000, 0b11100111, 0b10100101, 0b00010000, -}; -int frame29[0x0F] = { - 0b00011000, 0b01000010, 0b11101111, //Frame 22 +}, +{ //Frame 29 + 0b00011000, 0b01000010, 0b11101111, 0b01101011, 0b11011010, 0b01001111, 0b00011000, 0b01000010, 0b10101111, 0b01101011, 0b11011010, 0b11101111, 0b00011000, 0b01011010, 0b11101111, -}; -int frame30[0x0F] = { - 0b11100111, 0b10111101, 0b00010000, //Frame 22 +}, +{ //Frame 30 + 0b11100111, 0b10111101, 0b00010000, 0b10010100, 0b10100101, 0b10110000, 0b11100111, 0b10111101, 0b01010000, 0b10010100, 0b10100101, 0b00010000, 0b11100111, 0b10100101, 0b00010000, -}; -int frame31[0x0F] = { - 0b11111111, 0b11111111, 0b11111111, //Frame 31 +}, +{ //Frame 31 + 0b11111111, 0b11111111, 0b11111111, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b11111111, 0b11111111, 0b11111111, -}; -int frame32[0x0F] = { - 0b00000000, 0b00000000, 0b00000000, //Frame 32 +}, +{ //Frame 32 + 0b00000000, 0b00000000, 0b00000000, 0b11111111, 0b11111111, 0b11111111, 0b00000000, 0b00000000, 0b00000000, 0b11111111, 0b11111111, 0b11111111, 0b00000000, 0b00000000, 0b00000000, -}; -int frame33[0x0F] = { - 0b00000000, 0b00000000, 0b00000000, //Frame 33 +}, +{ //Frame 33 + 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b11111111, 0b11111111, 0b11111111, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, -}; -int frame34[0x0F] = { - 0b00000000, 0b00000000, 0b00000000, //Frame 34 +}, +{ //Frame 34 + 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00011111, 0b11111111, 0b11111000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, -}; -int frame35[0x0F] = { - 0b00000000, 0b00000000, 0b00000000, //Frame 35 +}, +{ //Frame 35 + 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, +}, }; - - -int * frameList[36]= {&frame0[0], - &frame1[0], - &frame2[0], - &frame3[0], - &frame4[0], - &frame5[0], - &frame6[0], - &frame7[0], - &frame8[0], - &frame9[0], - &frame10[0], - &frame11[0], - &frame12[0], - &frame13[0], - &frame14[0], - &frame15[0], - &frame16[0], - &frame17[0], - &frame18[0], - &frame19[0], - &frame20[0], - &frame21[0], - &frame22[0], - &frame23[0], - &frame24[0], - &frame25[0], - &frame26[0], - &frame27[0], - &frame28[0], - &frame29[0], - &frame30[0], - &frame31[0], - &frame32[0], - &frame33[0], - &frame34[0], - &frame35[0] - }; \ No newline at end of file From 186478d250fde8ebe16e8404c063e3c92da08886 Mon Sep 17 00:00:00 2001 From: "Scruff.R" Date: Tue, 27 Jun 2017 14:50:41 +0200 Subject: [PATCH 2/2] include Particle.h in header --- beam.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/beam.h b/beam.h index 0af24f6..2143507 100644 --- a/beam.h +++ b/beam.h @@ -19,6 +19,8 @@ Replaced "copy-paste" logic with functional blocks by use of arrays and loops =========================================================================== */ +#include + #define MAXFRAME 36 #define SPACE 3 #define KERNING 1