Compare commits

..

3 Commits

2 changed files with 201 additions and 181 deletions

View File

@ -8,17 +8,37 @@
; Please visit documentation for the other options and examples ; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html ; https://docs.platformio.org/page/projectconf.html
[env:esp32dev] [basic]
platform = espressif32 platform = espressif32
board = esp32dev board = esp32dev
framework = arduino framework = arduino
lib_deps = https://github.com/adafruit/Adafruit_NeoPixel lib_deps = https://github.com/adafruit/Adafruit_NeoPixel
https://github.com/knolleary/pubsubclient https://github.com/knolleary/pubsubclient
build_flags = build_flags =
upload_port = 10.0.0.116
upload_protocol = espota
;upload_port = /dev/ttyUSB0
;upload_speed = 921600
monitor_port = /dev/ttyUSB0 monitor_port = /dev/ttyUSB0
monitor_speed = 115200 monitor_speed = 115200
monitor_filters = esp32_exception_decoder monitor_filters = esp32_exception_decoder
[env:RGBMatrixDisplay_USB]
platform = ${basic.platform}
board = ${basic.board}
framework = ${basic.framework}
lib_deps = ${basic.lib_deps}
build_flags = ${basic.build_flags}
monitor_port = ${basic.monitor_port}
monitor_speed = ${basic.monitor_speed}
monitor_filters = ${basic.monitor_filters}
upload_port = /dev/ttyUSB0
upload_speed = 921600
[env:RGBMatrixDisplay_OTA]
platform = ${basic.platform}
board = ${basic.board}
framework = ${basic.framework}
lib_deps = ${basic.lib_deps}
build_flags = ${basic.build_flags}
monitor_port = ${basic.monitor_port}
monitor_speed = ${basic.monitor_speed}
monitor_filters = ${basic.monitor_filters}
upload_port = 10.0.0.116
upload_protocol = espota

View File

@ -24,226 +24,226 @@ class Display {
public: public:
const uint8_t width; const uint8_t width;
const uint8_t height; const uint8_t height;
const size_t pixelCount; const size_t pixelCount;
const size_t pixelByteCount; const size_t pixelByteCount;
bool fpsShow = false; bool fpsShow = false;
private: private:
Adafruit_NeoPixel leds; Adafruit_NeoPixel leds;
milliseconds_t fpsLastMillis = 0; milliseconds_t fpsLastMillis = 0;
int fps = 0; int fps = 0;
Color *buffer = nullptr; Color *buffer = nullptr;
uint8_t brightness = 10; uint8_t brightness = 10;
public: public:
Display(uint8_t width, uint8_t height) : Display(uint8_t width, uint8_t height) :
width(width), height(height), width(width), height(height),
pixelCount(width * height), pixelCount(width * height),
pixelByteCount(pixelCount * sizeof(Color)), pixelByteCount(pixelCount * sizeof(Color)),
leds(pixelCount, GPIO_NUM_13) { leds(pixelCount, GPIO_NUM_13) {
buffer = (Color *) malloc(pixelByteCount); buffer = (Color *) malloc(pixelByteCount);
if (buffer == nullptr) { if (buffer == nullptr) {
Serial.print("+-----------------------------------------------+\n"); Serial.print("+-----------------------------------------------+\n");
Serial.print("| OUT OF MEMORY: Cannot allocate double-buffer! |\n"); Serial.print("| OUT OF MEMORY: Cannot allocate double-buffer! |\n");
Serial.print("+-----------------------------------------------+\n"); Serial.print("+-----------------------------------------------+\n");
}
} }
}
~Display() { ~Display() {
if (buffer == nullptr) { if (buffer == nullptr) {
return; return;
}
free(buffer);
buffer = nullptr;
} }
free(buffer);
buffer = nullptr;
}
void setup() { void setup() {
leds.begin(); leds.begin();
clear(); clear();
flush();
}
void loop() {
calculateFPS();
drawFpsBorder();
if (isDirty()) {
flush(); flush();
} }
}
void loop() { void setBrightness(uint8_t value) {
calculateFPS(); brightness = value;
drawFpsBorder(); }
if (isDirty()) {
flush(); uint8_t getBrightness() const {
} return brightness;
}
void clear() {
if (buffer == nullptr) {
return;
} }
memset(buffer, 0, pixelByteCount);
}
void setBrightness(uint8_t value) { enum ALIGN {
brightness = value; LEFT, RIGHT
} };
uint8_t getBrightness() const { uint8_t print2(int x, int y, double valueDbl, Color colorPositive, Color colorZero, Color colorNegative, ALIGN align = RIGHT) {
return brightness; const Color color = valueDbl == 0 ? colorZero : (valueDbl < 0 ? colorNegative : colorPositive);
} return print2(x, y, valueDbl, color, align);
}
void clear() {
if (buffer == nullptr) {
return;
}
memset(buffer, 0, pixelByteCount);
}
enum ALIGN {
LEFT, RIGHT
};
uint8_t print2(int x, int y, double valueDbl, Color colorPositive, Color colorZero, Color colorNegative, ALIGN align = RIGHT) {
const Color color = valueDbl == 0 ? colorZero : (valueDbl < 0 ? colorNegative : colorPositive);
return print2(x, y, valueDbl, color, align);
}
uint8_t print2(int x, int y, double valueDbl, Color color, ALIGN align = RIGHT) {
if (isnan(valueDbl)) {
x -= 3 * (DISPLAY_CHAR_WIDTH + 1) - 1;
x += print(x, y, SYMBOL_DASH, color, true) + 1;
x += print(x, y, SYMBOL_DASH, color, true) + 1;
x += print(x, y, SYMBOL_DASH, color, true) + 1;
return x;
}
const int value = (int) round(abs(valueDbl));
const bool negative = valueDbl < 0;
const int digitCount = (int) max(1.0, ceil(log10(value))); // log10 is -inf for value==0, hence the max(1.0, ...)
if (align == RIGHT) {
x -= ((negative ? 1 : 0) + digitCount) * (DISPLAY_CHAR_WIDTH + 1) - 1;
}
int divider = (int) pow(10, digitCount - 1);
if (negative) {
x += print(x, y, SYMBOL_DASH, color, true) + 1;
}
bool showIfZero = false;
// Serial.printf("x=%d, y=%d, value=%d, align=%s, digitCount=%d, divider=%d\n", x, y, value, align == LEFT ? "LEFT" : "RIGHT", digitCount, divider);
for (int digitPos = 0; digitPos < digitCount; ++digitPos) {
const int digitVal = value / divider % 10;
showIfZero |= digitVal != 0 || (digitPos == digitCount - 1);
x += print(x, y, digitVal, color, showIfZero) + 1;
// Serial.printf(" digitPos=%d, x=%d, y=%d, digitVal=%d, showIfZero=%s, divider=%d\n", digitPos, x, y, digitVal, showIfZero ? "true" : "false", divider);
divider /= 10;
}
// Serial.println();
uint8_t print2(int x, int y, double valueDbl, Color color, ALIGN align = RIGHT) {
if (isnan(valueDbl)) {
x -= 3 * (DISPLAY_CHAR_WIDTH + 1) - 1;
x += print(x, y, SYMBOL_DASH, color, true) + 1;
x += print(x, y, SYMBOL_DASH, color, true) + 1;
x += print(x, y, SYMBOL_DASH, color, true) + 1;
return x; return x;
} }
uint8_t print(uint8_t xPos, uint8_t yPos, uint8_t index, Color color, bool showIfZero) { const int value = (int) round(abs(valueDbl));
if (index == 0 && !showIfZero) { const bool negative = valueDbl < 0;
return DISPLAY_CHAR_WIDTH;
} const int digitCount = (int) max(1.0, floor(log10(value)) + 1); // log10 is -inf for value==0, hence the max(1.0, ...)
if (index >= SYMBOL_COUNT) { if (align == RIGHT) {
Serial.printf("Cannot print2 symbol #%u.\n", index); x -= ((negative ? 1 : 0) + digitCount) * (DISPLAY_CHAR_WIDTH + 1) - 1;
index = SYMBOL_COUNT - 1; }
}
bool *symbolBit = SYMBOLS[index]; int divider = (int) pow(10, digitCount - 1);
for (uint8_t y = 0; y < DISPLAY_CHAR_HEIGHT; ++y) { if (negative) {
for (uint8_t x = 0; x < DISPLAY_CHAR_WIDTH; ++x) { x += print(x, y, SYMBOL_DASH, color, true) + 1;
if (*(symbolBit++)) { }
set(xPos + x, yPos + y, color);
} else { bool showIfZero = false;
set(xPos + x, yPos + y, BLACK); // Serial.printf("x=%d, y=%d, value=%d, align=%s, digitCount=%d, divider=%d\n", x, y, value, align == LEFT ? "LEFT" : "RIGHT", digitCount, divider);
} for (int digitPos = 0; digitPos < digitCount; ++digitPos) {
} const int digitVal = value / divider % 10;
} showIfZero |= digitVal != 0 || (digitPos == digitCount - 1);
x += print(x, y, digitVal, color, showIfZero) + 1;
// Serial.printf(" digitPos=%d, x=%d, y=%d, digitVal=%d, showIfZero=%s, divider=%d\n", digitPos, x, y, digitVal, showIfZero ? "true" : "false", divider);
divider /= 10;
}
// Serial.println();
return x;
}
uint8_t print(uint8_t xPos, uint8_t yPos, uint8_t index, Color color, bool showIfZero) {
if (index == 0 && !showIfZero) {
return DISPLAY_CHAR_WIDTH; return DISPLAY_CHAR_WIDTH;
} }
if (index >= SYMBOL_COUNT) {
void set(Vector pos, Color color) { Serial.printf("Cannot print2 symbol #%u.\n", index);
set((uint8_t) round(pos.x), (uint8_t) round(pos.y), color); index = SYMBOL_COUNT - 1;
} }
bool *symbolBit = SYMBOLS[index];
void set(uint8_t x, uint8_t y, Color color) { for (uint8_t y = 0; y < DISPLAY_CHAR_HEIGHT; ++y) {
if (x >= width || y >= height) { for (uint8_t x = 0; x < DISPLAY_CHAR_WIDTH; ++x) {
return; if (*(symbolBit++)) {
set(xPos + x, yPos + y, color);
} else {
set(xPos + x, yPos + y, BLACK);
}
} }
if ((y % 2) != 0) {
x = width - x - 1;
}
set(y * width + x, color);
} }
return DISPLAY_CHAR_WIDTH;
}
void set(uint16_t index, Color color) { void set(Vector pos, Color color) {
if (buffer == nullptr) { set((uint8_t) round(pos.x), (uint8_t) round(pos.y), color);
return; }
}
buffer[index] = { void set(uint8_t x, uint8_t y, Color color) {
// yes, correct order is GRB !!! if (x >= width || y >= height) {
(uint8_t) (color.g * brightness >> 8), return;
(uint8_t) (color.r * brightness >> 8),
(uint8_t) (color.b * brightness >> 8)
};
} }
if ((y % 2) != 0) {
x = width - x - 1;
}
set(y * width + x, color);
}
void set(uint16_t index, Color color) {
if (buffer == nullptr) {
return;
}
buffer[index] = {
// yes, correct order is GRB !!!
(uint8_t) (color.g * brightness >> 8),
(uint8_t) (color.r * brightness >> 8),
(uint8_t) (color.b * brightness >> 8)
};
}
private: private:
void flush() { void flush() {
if (buffer == nullptr) { if (buffer == nullptr) {
return; return;
} }
memcpy(leds.getPixels(), buffer, pixelByteCount); memcpy(leds.getPixels(), buffer, pixelByteCount);
leds.show(); leds.show();
}
bool isDirty() const {
if (buffer == nullptr) {
return false;
}
return memcmp(leds.getPixels(), buffer, pixelByteCount) != 0;
}
void calculateFPS() {
fps = (int) round(1000.0 / (millis() - fpsLastMillis));
fpsLastMillis = millis();
}
void drawFpsBorder() {
if (!fpsShow) {
return;
} }
bool isDirty() const { int frames = fps;
if (buffer == nullptr) {
return false; Color color = RED;
} if (frames > 3 * 76) {
return memcmp(leds.getPixels(), buffer, pixelByteCount) != 0; frames -= 3 * 76;
color = WHITE;
} else if (frames > 2 * 76) {
frames -= 2 * 76;
color = BLUE;
} else if (frames > 76) {
frames -= 76;
color = GREEN;
} }
void calculateFPS() { for (int x = 0; x <= width - 1 && frames-- > 0; x++) {
fps = (int) round(1000.0 / (millis() - fpsLastMillis)); set(x, 0, color);
fpsLastMillis = millis();
} }
for (int y = 0; y <= height - 1 && frames-- > 0; y++) {
void drawFpsBorder() { set(width - 1, y, color);
if (!fpsShow) {
return;
}
int frames = fps;
Color color = RED;
if (frames > 3 * 76) {
frames -= 3 * 76;
color = WHITE;
} else if (frames > 2 * 76) {
frames -= 2 * 76;
color = BLUE;
} else if (frames > 76) {
frames -= 76;
color = GREEN;
}
for (int x = 0; x <= width - 1 && frames-- > 0; x++) {
set(x, 0, color);
}
for (int y = 0; y <= height - 1 && frames-- > 0; y++) {
set(width - 1, y, color);
}
for (int x = width - 1; x >= 0 && frames-- > 0; x--) {
set(x, height - 1, color);
}
for (int y = height - 1; y >= 0 && frames-- > 0; y--) {
set(0, y, color);
}
} }
for (int x = width - 1; x >= 0 && frames-- > 0; x--) {
set(x, height - 1, color);
}
for (int y = height - 1; y >= 0 && frames-- > 0; y--) {
set(0, y, color);
}
}
}; };