Ingo LohsScruffR
Published © GPL3+

Die Losungen - Every Day a New Bible Verse

You love daily changing Bible verse? Then the "Die Losungen" are a concept: here they are represented with value added information.

IntermediateFull instructions provided2 hours889

Things used in this project

Hardware components

Photon
Particle Photon
×1
Hoverlabs Beam
you need 1-3 beams
×1
Breadboard (generic)
Breadboard (generic)
×1
Jumper wires (generic)
Jumper wires (generic)
you need 8 jumper wires
×1

Software apps and online services

Particle WebIDE
Blynk
Blynk
optional for transfer individual text to the beam grid

Story

Read more

Code

Die Losungen - Main

C/C++
Tab 1/5
// Die Losungen - every day a new bible verse
// ScruffR & Ingo Lohs
// v1.0, 24.07.2017
// works with Particle Photon v0.6.2 and Electron v0.6.1
// Display: Hoverlabs Beam

// Include LIBs from Particle ---------------------

#include <SparkJson.h> // v0.0.2
#include <blynk.h>     // v0.4.7

// Include LIBs via Tabs ---------------------

#include "application.h"
#include "beam.h"
#ifdef IGNORE 
#include "charactermap.h"
#include "frames.h"
#endif

SYSTEM_MODE(SEMI_AUTOMATIC)
SYSTEM_THREAD(ENABLED)

// USERs CONFIG AREA: WIFI & BLYNK ---------------------

#if ( PLATFORM_ID != PLATFORM_ELECTRON_PRODUCTION )
const char defaultSSID[] = "<YOUR SSID HERE>";
const char defaultPWD[]  = "<YOUR WiFi PASSWORD HERE>";
const int  defaultAUTH   = WPA2;
const int  defaultWCIPH  = WLAN_CIPHER_AES_TKIP;
#endif 

// You should get Auth Token in the Blynk App.
// Go to the Project Settings (nut icon).
const char auth[] = "<YOUR BLYNK TOKEN HERE>";

// DEFINITIONS ---------------------

// Attach virtual serial terminal to Virtual Pin V0
WidgetTerminal terminal(V0);

const int pinSYNC   = D7;
const int pinRESET  = D3;
const int pinIRQ    = D2; 
const int BEAMCOUNT =  1; // USERs CONFIG: set number of beams daisy chained together - works with 1, 2 or 3

const int loopCount             =   1;
const int msDelayPerCharPlay    = 460;

enum DISPLAY_METHOD {
    NONE,
    PLAY,
    DISPLAY
};

Beam b = Beam(pinRESET, pinIRQ, BEAMCOUNT);

/*
      "Datum": "2017-05-05T00:00:00",
      "Wtag": "Freitag", 
      "Sonntag": {},
      "Losungstext": "Du sollst dein Herz nicht verhärten und deine Hand nicht zuhalten gegenüber deinem armen Bruder.",
      "Losungsvers": "5.Mose 15,7",
      "Lehrtext": "Wenn jemand dieser Welt Güter hat und sieht seinen Bruder darben und verschließt sein Herz vor ihm, wie bleibt dann die Liebe Gottes in ihm?",
      "Lehrtextvers": "1.Johannes 3,17"
*/

// TESTING ---------------------

char datum[20];        //= "2017-01-01T00:00:00";
char wochentag[12];    //= "XXXXXXXXtag";
char sonntag[12];      //= "YYYYYYYYtag";
char losungstext[256]; //= "LosungsText: Das ist ein längerer Text ÄÖÜ";
char losungsvers[32];  //= "LosungVers ÄÖÜ";
char lehrtext[256];    //= "LehrText: Das ist ein längerer Text ÄÖÜ";
char lehrtextvers[32]; //= "LehrTextVers ÄÖÜ";
char customMessage[256] = "Meine Gemeinde: www.emf-bielefeld.de";

uint32_t msLastTime;
uint32_t msDelay;
int      lastDay = 0;

// SERIAL LOG ---------------------

SerialLogHandler myLogger(LOG_LEVEL_INFO);

// BLYNK Terminal Widget ---------------------

BLYNK_WRITE(V0)
{
  if (strlen((const char*)param.asStr())) {
    strncpy(customMessage, (const char*)param.asStr(), sizeof(customMessage));
    customMessage[sizeof(customMessage)-1] = '\0';    
    terminal.print(customMessage);
  } 
  else {
    terminal.print(customMessage);
    memset(customMessage, 0, sizeof(customMessage)); 
  }
  terminal.flush();
}

// FUNCTION ---------------------

volatile bool proceede = false;
void isrBeam() {
    proceede = true;
}

// SETUP ---------------------

void setup() {
  Wire.setSpeed(CLOCK_SPEED_400KHZ);
  Wire.begin();
  b.begin();
  b.setSpeed(1);
  b.print("Die Losungen");
  b.play();
  delay(3000);

  // setup a time zone, which is part of the ISO6801 format 
  Time.zone(isDST() ? +2.00 : +1.00);  

  // Subscribe to the integration response event
  Particle.subscribe("hook-response/tageslosung", myHandler, MY_DEVICES);

  #if ( PLATFORM_ID != PLATFORM_ELECTRON_PRODUCTION )
  WiFi.on();
  if (!WiFi.hasCredentials()) {
    WiFi.setCredentials(defaultSSID, defaultPWD, defaultAUTH, defaultWCIPH);
    for(uint32_t _ms = millis(); millis() - _ms < 500; Particle.process());
    WiFi.off();
  }
  #endif
  
  Particle.connect();
  waitUntil(Particle.connected);

  Blynk.begin(auth);
  terminal.println("Die Losungen");
  terminal.println("Thanks to Richard Klose");
  terminal.println("with special thanks to");
  terminal.println("ScruffR for Coding");
  terminal.println("https://community.particle.io");
  terminal.println("Ingo Lohs");
  
  while(Serial.read() >= 0) Particle.process(); // flush USB Serial RX buffer

  Particle.publish("tageslosung", "MyLosung", PRIVATE);
}

// LOOP ---------------------

void loop() {
  static uint32_t msPublish = millis();

  Blynk.run();

  if (lastDay != Time.day() && millis() - msPublish > 60000) {
    Particle.syncTime(); 
    waitFor(Particle.syncTimeDone, 5000); // works with v0.6.1 with Photon & Electron
    msPublish = millis();
    if (lastDay == Time.day()) return; // if sync brought us back before midnight, try a bit later again
    // request new day's data
    Particle.publish("tageslosung", "MyLosung", PRIVATE);
  }

  print_out_on_Beam();
    
}

// FUNCTION to DISPLAY DATA ---------------------

void print_out_on_Beam() {
  static int step = 0;
  char  dynText[32];
  const char* txt = NULL;
  DISPLAY_METHOD method = NONE; 

  // don't procede if we need to wait a bit
  if(msDelay && millis() - msLastTime < msDelay) return;
  msDelay = 0;
 
  switch (step++) {
    case 0:
      txt = customMessage;
      method = PLAY;
      break;

    case 1:
    case 5:
      Time.zone(isDST() ? +2.00 : +1.00);  
      snprintf(dynText, sizeof(dynText), "%s", (const char*)Time.format("%d.%m.%Y %H:%M"));
      //snprintf(dynText, sizeof(dynText), "%s", (const char*)Time.format("%H:%M"));
      txt = dynText;
      method = DISPLAY;
      break;

    case 2:
      txt = wochentag; 
      method = DISPLAY;
      break;
      
    case 3:
      txt = losungstext;
      method = PLAY;
      break;
      
    case 4:
      txt = losungsvers;
      msDelay = 10000;
      method = DISPLAY;
      break;
      
    case 6:
      txt =lehrtext;
      method = PLAY;
      break;
      
    case 7:
      txt = lehrtextvers;
      msDelay = 10000;
      method = DISPLAY;
      break;
      
    default:
      step = 0;
      break;
  }
  
  Blynk.virtualWrite(V0, txt);
  Blynk.virtualWrite(V0, "\n"); // Carriage Return - every text displays in a new line

  b.print(txt); 
  switch (method) {
    case PLAY:
      b.setLoops(loopCount);
      //b.setScroll(LEFT,4);
      //b.setSpeed(6);
      b.play();
      msDelay = BEAMCOUNT * 2000 + strlen(txt) * msDelayPerCharPlay * loopCount;
      break;
    case DISPLAY:
      if (!msDelay) msDelay = 5000;
      b.display();
      break;
    default:
      break;
  }
  msLastTime = millis();

  // Beam can begin scrolling text with just print() and play() > Beam using ONLY Strings to display  
  /*
  // methods like setSpeed(), setScroll() setLoops(), setMode() can be called 
  //on the fly to change the existing default settings
  b.setSpeed(2);      //increase speed
  b.setSpeed(1);      //increase speed again!
  b.setSpeed(15);     //reduce speed to lowest setting
  */
}

// WEBHOOK HANDLER TO GET DATA ---------------------

void myHandler(const char *event, const char *data)
{
  static int cntEvents = 0;
  char mutableCopy[strlen(data)+1];
  strcpy(mutableCopy, data);

  // Start SparkJSON Example	    
  Log.info("%d: %s, data: %s", ++cntEvents, event, data);
  if (data) {
    terminal.println(data);
    terminal.println("--------end--------");
    terminal.flush();
    /* JSON Source - https://losungen.klose.cloud/api/today
    {
      "Datum": "2017-05-05T00:00:00",
      "Wtag": "Freitag", 
      "Sonntag": {},
      "Losungstext": "Du sollst dein Herz nicht verhärten und deine Hand nicht zuhalten gegenüber deinem armen Bruder.",
      "Losungsvers": "5.Mose 15,7",
      "Lehrtext": "Wenn jemand dieser Welt Güter hat und sieht seinen Bruder darben und verschließt sein Herz vor ihm, wie bleibt dann die Liebe Gottes in ihm?",
      "Lehrtextvers": "1.Johannes 3,17"
    }
    */
    
    // https://bblanchon.github.io/ArduinoJson/faq/how-to-determine-the-buffer-size/
    // https://bblanchon.github.io/ArduinoJson/assistant/
    StaticJsonBuffer<256> jsonBuffer;
	JsonObject& root = jsonBuffer.parseObject(mutableCopy);

	
	if (!root.success()) {
      Log.warn("parseObject() failed");
      return;
    }
             
    strncpy(datum       , root["Datum"       ], sizeof(datum)       );
    strncpy(wochentag   , root["Wtag"        ], sizeof(wochentag)   );
    strncpy(sonntag     , root["Sonntag"     ], sizeof(sonntag)     );
	strncpy(losungstext , root["Losungstext" ], sizeof(losungstext) );
	strncpy(losungsvers , root["Losungsvers" ], sizeof(losungsvers) );
	strncpy(lehrtext    , root["Lehrtext"    ], sizeof(lehrtext)    );
	strncpy(lehrtextvers, root["Lehrtextvers"], sizeof(lehrtextvers));

    lastDay = Time.day();
  }
  else {
    terminal.println("no JSON Records available - check the Webhook under Particle Cloud - Console - Integrations!");
  }
}

// FUNCTION TO CHECK SUMMER/WINTER-TIME ---------------------

bool isDST()
{ // Central European Summer Timer calculation
  int dayOfMonth = Time.day();
  int month = Time.month();
  int dayOfWeek = Time.weekday() - 1; // make Sunday 0 .. Saturday 6

  if (month >= 4 && month <= 9)
  { // March to September definetly DST
    return true;
  }
  else if (month < 3 || month > 10)
  { // before March or after October is definetly normal time
    return false;
  }

  // March and October need deeper examination
  boolean lastSundayOrAfter = (dayOfMonth - dayOfWeek > 24);
  if (!lastSundayOrAfter)
  { // before switching Sunday
    return (month == 10); // October DST will be true, March not
  }

  if (dayOfWeek)
  { // AFTER the switching Sunday
    return (month == 3); // for March DST is true, for October not
  }

  int secSinceMidnightUTC = Time.now() % 86400;
  boolean dayStartedAs = (month == 10); // DST in October, in March not
                                        // on switching Sunday we need to consider the time
  if (secSinceMidnightUTC >= 1 * 3600)
  { // 1:00 UTC (=2:00 CET/3:00 CEST)
    return !dayStartedAs;
  }

  return dayStartedAs;
}

Die Losungen - beam.cpp

C/C++
Tab 2/5
/*
===========================================================================
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

===========================================================================
*/
#include <Particle.h>
#include "beam.h"
#include "charactermap.h"
#include "frames.h"

/*
=================
PUBLIC FUNCTIONS
=================
*/

/*
This constructor used when multiple Beams behave like one long Beam
*/
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
*/
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;
    }
  }
  if (!BEAM) {
    BEAM = &BEAM_ADDRESS[0];
    Log.warn("%02x is not a valid Beam address (default to BEAMA %02x)", beamAddress, BEAM_ADDRESS[0]);
  }

  _gblMode = 0;
}

bool Beam::begin(TwoWire& wire) {
  Log.trace("bool Beam::begin(TwoWire& wire)");
  _wire = &wire;

  //resets beam - will clear all beams
  pinMode(_rst, OUTPUT);
  digitalWrite(_rst, LOW);
  delay(100);
  digitalWrite(_rst, HIGH);
  delay(250);

  //reset cs[]
  memset((uint8_t*)cs, 0x00, sizeof(cs));

  //reset segmentmask[]
  for (int s = 0; s < 8; s++) {
    segmentmask[s] = 0x0001 << (7 - s);
  }

  return true;
}

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]);
  }
}

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);

  Log.info("Text to print: %s", text);

  initBeam();

  // Clear all frames
  memset((uint8_t*)cs, 0x00, sizeof(cs));

  for (int i = 0; i < 36; i++) {
    for (unsigned int b = 0; b < _beamCount; b++) {
      writeFrame(BEAM[b], i);
    }
  }

  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[] ---");

      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;
      }
      frame++;            // go to next frame
      cscount = 0;        // reset cscount

      // 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
        Log.trace("Continuing prev char cscolumn[] = ");

        while (cscount < 24 && *fontptr != 0xFF) {
          cscolumn[cscount] = *fontptr;
          Log.trace("0x%02x", cscolumn[cscount]);
          fontptr++;
          cscount++;
        }
      }
    }

    if (stringLen == i) {
      // if end of string is reached in current frame,
      // then start writing to Beam registers
      Log.trace("--- end of string 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("--- 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::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;
      }
    }

    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

    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[] ---");

      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;
      }

      frame++;            // 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;
      }
    }
  }
}

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);
  }

  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::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;
  }

  _scrollDir = direction;
  _fadeMode = fade;
  _scrollMode = 1;

  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::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;
  }

  _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;
  }

  _numLoops = loops;
  uint8_t displayData = _numLoops << 5 | 0 << 4 | 0x0B;

  for (unsigned int b = 0; b < _beamCount; b++) {
    sendWriteCmd(BEAM[b], CTRL, DISPLAYO, displayData);
  }
}

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.
*/
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;
}

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();

  for (int i = 0; i < 36; ++i) {
    convertFrame(frameList[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));
    }
    _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;

  // 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(BEAM[0], CTRL, 0x0F) >> 2);
    Log.trace("Frame done (%d)", frameDone);
  }
  return frameDone;
}

/*
=================
PRIVATE FUNCTIONS
=================
*/

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 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);
    }
  }
}

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) {
    //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 moviemodeData = 0 << 7 | 0 << 6 | _lastFrameWrite;
    uint8_t frameData = 0;
    //uint8_t syncData = 0;

    switch (mode) {
      case MOVIE:
        frameData = 0 << 7 | 0 << 6 | 0 << 5 | 0 << 4 | frameDelay;
        break;
      case SCROLL:
        frameData = fadeMode << 7 | scrollDir << 6 | 0 << 5 | _scrollMode << 4 | frameDelay;
        break;
    }

    uint8_t displayData = _numLoops << 5 | 0 << 4 | 0x0B;
    //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 (_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 && _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 {
        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;

  return 1000;
}

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;

    if (n > 12) {
      n = 0;
    }
  }

  //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;
    }
  }

  //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;

    if (n > 14) {
      n = 2;
    }
  }
}

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 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->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) { 
  //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());
}

Die Losungen - beam.h

C/C++
Tab 3/5
#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

===========================================================================
*/
#define MAXFRAME 36
#define SPACE     3
#define KERNING   1


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
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
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(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:
  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);
};

Die Losungen - charactermap.h

C/C++
Tab 4/5
#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
  
===========================================================================
*/ 
#include <Particle.h>

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
};

Die Losungen - frames.h

C/C++
Tab 5/5
#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
  
===========================================================================
*/ 

const uint8_t frameList[MAXFRAME][15] = {
{                    //Frame 0
  0b00000000, 0b00000000, 0b00000000,     
  0b00000000, 0b00000000, 0b00000000,
  0b00000000, 0b00000000, 0b00000000,
  0b00000000, 0b00000000, 0b00000000,
  0b00000000, 0b00000000, 0b00000000,
},
{                    //Frame 1
  0b10000000, 0b00000000, 0b00000001,     
  0b10000000, 0b00000000, 0b00000001,
  0b10000000, 0b00000000, 0b00000001,
  0b10000000, 0b00000000, 0b00000001,
  0b10000000, 0b00000000, 0b00000001,
},
{                    //Frame 2
  0b11000000, 0b00000000, 0b00000011,     
  0b11000000, 0b00000000, 0b00000011,
  0b11000000, 0b00000000, 0b00000011,
  0b11000000, 0b00000000, 0b00000011,
  0b11000000, 0b00000000, 0b00000011,
},
{                    //Frame 3
  0b01100000, 0b00000000, 0b00000110,     
  0b01100000, 0b00000000, 0b00000110,
  0b01100000, 0b00000000, 0b00000110,
  0b01100000, 0b00000000, 0b00000110,
  0b01100000, 0b00000000, 0b00000110,
},
{                    //Frame 4
  0b00110000, 0b00000000, 0b00001100,     
  0b00110000, 0b00000000, 0b00001100,
  0b00110000, 0b00000000, 0b00001100,
  0b00110000, 0b00000000, 0b00001100,
  0b00110000, 0b00000000, 0b00001100,
},
{                    //Frame 5
  0b00011000, 0b00000000, 0b00011000,     
  0b00011000, 0b00000000, 0b00011000,
  0b00011000, 0b00000000, 0b00011000,
  0b00011000, 0b00000000, 0b00011000,
  0b00011000, 0b00000000, 0b00011000,
},
{                    //Frame 6
  0b00001100, 0b00000000, 0b00110000,     
  0b00001100, 0b00000000, 0b00110000,
  0b00001100, 0b00000000, 0b00110000,
  0b00001100, 0b00000000, 0b00110000,
  0b00001100, 0b00000000, 0b00110000,
},
{                    //Frame 7
  0b00000110, 0b00000000, 0b01100000,     
  0b00000110, 0b00000000, 0b01100000,
  0b00000110, 0b00000000, 0b01100000,
  0b00000110, 0b00000000, 0b01100000,
  0b00000110, 0b00000000, 0b01100000,
},
{                    //Frame 8
  0b00000011, 0b00000000, 0b11000000,     
  0b00000011, 0b00000000, 0b11000000,
  0b00000011, 0b00000000, 0b11000000,
  0b00000011, 0b00000000, 0b11000000,
  0b00000011, 0b00000000, 0b11000000,
},
{                    //Frame 9
  0b00000011, 0b11000011, 0b11000000,
  0b00000011, 0b11000011, 0b11000000,
  0b00000011, 0b11000011, 0b11000000,
  0b00000011, 0b11000011, 0b11000000,
  0b00000011, 0b11000011, 0b11000000,
},
{                    //Frame 10
  0b00000000, 0b00111100, 0b00000000,   
  0b00000000, 0b00111100, 0b00000000,
  0b00000000, 0b00111100, 0b00000000,
  0b00000000, 0b00111100, 0b00000000,
  0b00000000, 0b00111100, 0b00000000,
},
{                    //Frame 11
  0b00000000, 0b00011000, 0b00000000,     
  0b00000000, 0b00011000, 0b00000000,
  0b00000000, 0b00011000, 0b00000000,
  0b00000000, 0b00011000, 0b00000000,
  0b00000000, 0b00011000, 0b00000000,
},
{                    //Frame 12
  0b00000000, 0b00010000, 0b00000000,     
  0b00000000, 0b00101000, 0b00000000,
  0b00000000, 0b01000100, 0b00000000,
  0b00000000, 0b00101000, 0b00000000,
  0b00000000, 0b00010000, 0b00000000,
},
{                    //Frame 13
  0b00000000, 0b00101000, 0b00000000,     
  0b00000000, 0b01000100, 0b00000000,
  0b00000000, 0b10000010, 0b00000000,
  0b00000000, 0b01000100, 0b00000000,
  0b00000000, 0b00101000, 0b00000000,
},
{                    //Frame 14
  0b00000000, 0b01000010, 0b00000000,     
  0b00000000, 0b10000001, 0b00000000,
  0b00000001, 0b00000000, 0b10000000,
  0b00000000, 0b10000001, 0b00000000,
  0b00000000, 0b01000010, 0b00000000,
},
{                    //Frame 15
  0b00000000, 0b01000010, 0b00000000,     
  0b00000000, 0b10000001, 0b00000000,
  0b00000001, 0b00000000, 0b10000000,
  0b00000000, 0b10000001, 0b00000000,
  0b00000000, 0b01000010, 0b00000000,
},
{                    //Frame 16
  0b00000000, 0b11000011, 0b00000000,     
  0b00000001, 0b10000001, 0b10000000,
  0b00000011, 0b00000000, 0b11000000,
  0b00000001, 0b10000001, 0b10000000,
  0b00000000, 0b11000011, 0b00000000,
},
{                    //Frame 17
  0b00000011, 0b00000000, 0b11000000,     
  0b00000110, 0b00000000, 0b01100000,
  0b00001100, 0b00000000, 0b00110000,
  0b00000110, 0b00000000, 0b01100000,
  0b00000011, 0b00000000, 0b11000000,
},
{                    //Frame 18
  0b00000110, 0b00000000, 0b01100000,     
  0b00001100, 0b00000000, 0b00110000,
  0b00011000, 0b00000000, 0b00011000,
  0b00001100, 0b00000000, 0b00110000,
  0b00000110, 0b00000000, 0b01100000,
},
{                    //Frame 19
  0b00001100, 0b00000000, 0b00110000,     
  0b00011000, 0b00000000, 0b00011000,
  0b00110000, 0b00000000, 0b00001100,
  0b00011000, 0b00000000, 0b00011000,
  0b00001100, 0b00000000, 0b00110000,
},
{                    //Frame 20
  0b00011000, 0b00000000, 0b00011000,     
  0b00110000, 0b00000000, 0b00001100,
  0b01100000, 0b00000000, 0b00000110,
  0b00110000, 0b00000000, 0b00001100,
  0b00011000, 0b00000000, 0b00011000,
},
{                    //Frame 21
  0b00110000, 0b00000000, 0b00001100,     
  0b01100000, 0b00000000, 0b00000110,
  0b11000000, 0b00000000, 0b00000011,
  0b01100000, 0b00000000, 0b00000110,
  0b00110000, 0b00000000, 0b00001100,
},
{                    //Frame 22
  0b11100111, 0b10111101, 0b00010000,     
  0b10010100, 0b00100101, 0b10110000,
  0b11100111, 0b10111101, 0b01010000,
  0b10010100, 0b00100101, 0b00010000,
  0b11100111, 0b10100101, 0b00010000,
},
{                    //Frame 23
  0b00011000, 0b01000010, 0b11101111,     
  0b01101011, 0b11011010, 0b01001111,
  0b00011000, 0b01000010, 0b10101111,
  0b01101011, 0b11011010, 0b11101111,
  0b00011000, 0b01011010, 0b11101111,
},
{                    //Frame 24
  0b11100111, 0b10111101, 0b00010000,    
  0b10010100, 0b10100101, 0b10110000,
  0b11100111, 0b10111101, 0b01010000,
  0b10010100, 0b10100101, 0b00010000,
  0b11100111, 0b10100101, 0b00010000,
},
{                    //Frame 25
  0b00011000, 0b01000010, 0b11101111,     
  0b01101011, 0b11011010, 0b01001111,
  0b00011000, 0b01000010, 0b10101111,
  0b01101011, 0b11011010, 0b11101111,
  0b00011000, 0b01011010, 0b11101111,
},
{                    //Frame 26
  0b11100111, 0b10111101, 0b00010000,     
  0b10010100, 0b10100101, 0b10110000,
  0b11100111, 0b10111101, 0b01010000,
  0b10010100, 0b10100101, 0b00010000,
  0b11100111, 0b10100101, 0b00010000,
},
{                    //Frame 27
  0b00011000, 0b01000010, 0b11101111,     
  0b01101011, 0b11011010, 0b01001111,
  0b00011000, 0b01000010, 0b10101111,
  0b01101011, 0b11011010, 0b11101111,
  0b00011000, 0b01011010, 0b11101111,
},
{                    //Frame 28
  0b11100111, 0b10111101, 0b00010000,     
  0b10010100, 0b10100101, 0b10110000,
  0b11100111, 0b10111101, 0b01010000,
  0b10010100, 0b10100101, 0b00010000,
  0b11100111, 0b10100101, 0b00010000,
},
{                    //Frame 29
  0b00011000, 0b01000010, 0b11101111,     
  0b01101011, 0b11011010, 0b01001111,
  0b00011000, 0b01000010, 0b10101111,
  0b01101011, 0b11011010, 0b11101111,
  0b00011000, 0b01011010, 0b11101111,
},
{                    //Frame 30
  0b11100111, 0b10111101, 0b00010000,     
  0b10010100, 0b10100101, 0b10110000,
  0b11100111, 0b10111101, 0b01010000,
  0b10010100, 0b10100101, 0b00010000,
  0b11100111, 0b10100101, 0b00010000,
},
{                    //Frame 31
  0b11111111, 0b11111111, 0b11111111,     
  0b00000000, 0b00000000, 0b00000000,
  0b00000000, 0b00000000, 0b00000000,
  0b00000000, 0b00000000, 0b00000000,
  0b11111111, 0b11111111, 0b11111111,
},
{                    //Frame 32
  0b00000000, 0b00000000, 0b00000000,     
  0b11111111, 0b11111111, 0b11111111,
  0b00000000, 0b00000000, 0b00000000,
  0b11111111, 0b11111111, 0b11111111,
  0b00000000, 0b00000000, 0b00000000,
},
{                    //Frame 33
  0b00000000, 0b00000000, 0b00000000,     
  0b00000000, 0b00000000, 0b00000000,
  0b11111111, 0b11111111, 0b11111111,
  0b00000000, 0b00000000, 0b00000000,
  0b00000000, 0b00000000, 0b00000000,
},
{                    //Frame 34
  0b00000000, 0b00000000, 0b00000000,     
  0b00000000, 0b00000000, 0b00000000,
  0b00011111, 0b11111111, 0b11111000,
  0b00000000, 0b00000000, 0b00000000,
  0b00000000, 0b00000000, 0b00000000,
},
{                    //Frame 35
  0b00000000, 0b00000000, 0b00000000,     
  0b00000000, 0b00000000, 0b00000000,
  0b00000000, 0b00000000, 0b00000000,
  0b00000000, 0b00000000, 0b00000000,
  0b00000000, 0b00000000, 0b00000000,
},
};

Die Losungen - every day a new bible verse

Credits

Ingo Lohs

Ingo Lohs

182 projects • 194 followers
I am well over 50 years and come from the middle of Germany.
ScruffR

ScruffR

2 projects • 3 followers

Comments