Skip to content

Add support for scrolling text asynchronously #312

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// To use ArduinoGraphics APIs, please include BEFORE Arduino_LED_Matrix and TextAnimation
#include "ArduinoGraphics.h"
#include "Arduino_LED_Matrix.h"
#include "TextAnimation.h"

ArduinoLEDMatrix matrix;

// 100 frames maximum. Compute as maximum length of text you want to print (eg. 20 chars)
// multiplied by font width (eg. 5 for Font_5x7), so 20 chars * 5 px = 100. If you enter lower
// value (or your text get unexpectedly long), animation will be cut and end soon.
TEXT_ANIMATION_DEFINE(anim, 100)

int counter;
bool requestNext = false;

void setup() {
pinMode(LED_BUILTIN, OUTPUT);

matrix.begin();
matrix.beginDraw();

matrix.stroke(0xFFFFFFFF);
matrix.textFont(Font_5x7);
matrix.textScrollSpeed(60);
matrix.setCallback(matrixCallback);

const char text[] = " UNO r4 ";
matrix.beginText(0, 1, 0xFFFFFF);
matrix.println(text);
matrix.endTextAnimation(SCROLL_LEFT, anim);

matrix.loadTextAnimationSequence(anim);
matrix.play();

// now animation play asynchronously. Will call matrixCallback once completed.
}

void matrixCallback() {
// callback is executed in IRQ and should run as fast as possible
requestNext = true;
}

void loop() {
if (requestNext) {
requestNext = false;

matrix.beginText(0, 1, 0xFFFFFF);
matrix.print(" ");
matrix.println(counter);
matrix.endTextAnimation(SCROLL_RIGHT, anim);

if (counter++ >= 20) {
counter = 0;
}

matrix.loadTextAnimationSequence(anim);
matrix.play();
}

delay(500);
digitalWrite(LED_BUILTIN, 0);
delay(500);
digitalWrite(LED_BUILTIN, 1);
}
56 changes: 47 additions & 9 deletions libraries/Arduino_LED_Matrix/src/Arduino_LED_Matrix.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,10 @@ static uint32_t reverse(uint32_t x)
}

// TODO: this is dangerous, use with care
#define loadSequence(frames) loadWrapper(frames, sizeof(frames))
#define renderBitmap(bitmap, rows, columns) loadPixels(&bitmap[0][0], rows*columns)
#define loadSequence(frames) loadWrapper(frames, sizeof(frames))
#define renderBitmap(bitmap, rows, columns) loadPixels(&bitmap[0][0], rows*columns)
#define endTextAnimation(scrollDirection, anim) endTextToAnimationBuffer(scrollDirection, anim ## _buf, sizeof(anim ## _buf), anim ## _buf_used)
#define loadTextAnimationSequence(anim) loadWrapper(anim ## _buf, anim ## _buf_used)

static uint8_t __attribute__((aligned)) framebuffer[NUM_LEDS / 8];

Expand Down Expand Up @@ -227,11 +229,11 @@ class ArduinoLEDMatrix
return false;
}

void loadPixels(uint8_t *arr, size_t size){
static void loadPixelsToBuffer(uint8_t* arr, size_t size, uint32_t* dst) {
uint32_t partialBuffer = 0;
uint8_t pixelIndex = 0;
uint8_t *frameP = arr;
uint32_t *frameHolderP = _frameHolder;
uint32_t *frameHolderP = dst;
while (pixelIndex < size) {
partialBuffer |= *frameP++;
if ((pixelIndex + 1) % 32 == 0) {
Expand All @@ -240,6 +242,10 @@ class ArduinoLEDMatrix
partialBuffer = partialBuffer << 1;
pixelIndex++;
}
}

void loadPixels(uint8_t *arr, size_t size){
loadPixelsToBuffer(arr, size, _frameHolder);
loadFrame(_frameHolder);
};

Expand All @@ -255,9 +261,9 @@ class ArduinoLEDMatrix

void clear() {
const uint32_t fullOff[] = {
0x00000000,
0x00000000,
0x00000000
0x00000000,
0x00000000,
0x00000000
};
loadFrame(fullOff);
}
Expand All @@ -277,16 +283,48 @@ class ArduinoLEDMatrix
renderBitmap(_canvasBuffer, canvasHeight, canvasWidth);
}

// display the drawing
// display the drawing or capture it to buffer when rendering dynamic anymation
void endDraw() {
ArduinoGraphics::endDraw();
renderBitmap(_canvasBuffer, canvasHeight, canvasWidth);

if (!captureAnimation) {
renderBitmap(_canvasBuffer, canvasHeight, canvasWidth);
} else {
if (captureAnimationHowManyRemains >= 4) {
loadPixelsToBuffer(&_canvasBuffer[0][0], sizeof(_canvasBuffer), captureAnimationFrame);
captureAnimationFrame[3] = _textScrollSpeed;
captureAnimationFrame += 4;
captureAnimationHowManyRemains -= 16;
}
}
}

void endTextToAnimationBuffer(int scrollDirection, uint32_t frames[][4], uint32_t howManyMax, uint32_t& howManyUsed) {
captureAnimationFrame = &frames[0][0];
captureAnimationHowManyRemains = howManyMax;

captureAnimation = true;
ArduinoGraphics::textScrollSpeed(0);
ArduinoGraphics::endText(scrollDirection);
ArduinoGraphics::textScrollSpeed(_textScrollSpeed);
captureAnimation = false;

howManyUsed = howManyMax - captureAnimationHowManyRemains;
}

void textScrollSpeed(unsigned long speed) {
ArduinoGraphics::textScrollSpeed(speed);
_textScrollSpeed = speed;
}

private:
uint32_t* captureAnimationFrame = nullptr;
uint32_t captureAnimationHowManyRemains = 0;
bool captureAnimation = false;
static const byte canvasWidth = 12;
static const byte canvasHeight = 8;
uint8_t _canvasBuffer[canvasHeight][canvasWidth] = {{0}};
unsigned long _textScrollSpeed = 100;
#endif

private:
Expand Down
15 changes: 15 additions & 0 deletions libraries/Arduino_LED_Matrix/src/TextAnimation.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#pragma once

#include "Arduino.h"

#if not __has_include("ArduinoGraphics.h")
#error "TextAnimation work only when ArduinoGraphics is installed and used. Include ArduinoGraphics first."
#endif

#define TEXT_ANIMATION_DECLARE(NAME, MAX_CHARS) \
extern uint32_t NAME ## _buf[MAX_CHARS][4]; \
extern uint32_t NAME ## _buf_used;

#define TEXT_ANIMATION_DEFINE(NAME, MAX_CHARS) \
uint32_t NAME ## _buf[MAX_CHARS][4]; \
uint32_t NAME ## _buf_used = 0;
Loading