251 lines
6.3 KiB
C++
251 lines
6.3 KiB
C++
#ifndef DISPLAY_H
|
|
#define DISPLAY_H
|
|
|
|
// #include <Adafruit_NeoPixel.h>
|
|
|
|
#include <AsyncWebSocket.h>
|
|
#include <cstdint>
|
|
|
|
#include "Color.h"
|
|
#include "font.h"
|
|
#include "core/http.h"
|
|
|
|
#define PIXELS_PER_SEGMENT 3
|
|
#define SEGMENTS_PER_DIGIT 7
|
|
#define PIXELS_PER_DOT 1
|
|
#define DOT_COUNT 4
|
|
#define DIGIT_COUNT 4
|
|
|
|
#define PIXELS_PER_DIGIT (PIXELS_PER_SEGMENT * SEGMENTS_PER_DIGIT)
|
|
#define TOTAL_DOT_PIXEL_COUNT (PIXELS_PER_DOT * DOT_COUNT)
|
|
#define TOTAL_SEGMENT_PIXEL_COUNT (DIGIT_COUNT * PIXELS_PER_DIGIT)
|
|
#define TOTAL_PIXEL_COUNT (TOTAL_SEGMENT_PIXEL_COUNT + TOTAL_DOT_PIXEL_COUNT)
|
|
#define TOTAL_PIXEL_BYTE_COUNT (TOTAL_PIXEL_COUNT * sizeof(Color))
|
|
#define HEX_BUFFER_SIZE (TOTAL_PIXEL_BYTE_COUNT + 1)
|
|
|
|
#define DISPLAY_VIRTUAL_WIDTH 25
|
|
#define DISPLAY_VIRTUAL_HEIGHT 9
|
|
|
|
#define HEX_BUFFER_MIN_WAIT_MS 500
|
|
|
|
class Display {
|
|
|
|
// Adafruit_NeoPixel leds;
|
|
|
|
Color pixels[TOTAL_PIXEL_COUNT] = {};
|
|
|
|
Color color = WHITE;
|
|
|
|
char hexBuffer[HEX_BUFFER_SIZE] = "";
|
|
|
|
struct Mapping {
|
|
uint8_t x;
|
|
uint8_t y;
|
|
};
|
|
|
|
public:
|
|
|
|
Display() /* : leds(PIXEL_COUNT, GPIO_NUM_13) */ {
|
|
// leds.begin();
|
|
setBrightness(6);
|
|
clear();
|
|
flush();
|
|
}
|
|
|
|
void setColor(const Color newColor) {
|
|
this->color = newColor;
|
|
}
|
|
|
|
void setBrightness(const int brightness) {
|
|
// leds.setBrightness(brightness);
|
|
}
|
|
|
|
void clear() {
|
|
memset(pixels, 0, TOTAL_PIXEL_BYTE_COUNT);
|
|
}
|
|
|
|
void flush(const bool forceNextHexBuffer = false) {
|
|
// memcpy(leds.getPixels(), buffer, PIXEL_BYTE_COUNT);
|
|
// leds.show();
|
|
|
|
const auto now = millis() - HEX_BUFFER_MIN_WAIT_MS;
|
|
static auto last = now;
|
|
if (now - last >= HEX_BUFFER_MIN_WAIT_MS || forceNextHexBuffer) {
|
|
last = now;
|
|
fillHexBuffer();
|
|
websocketSendAll(hexBuffer);
|
|
}
|
|
}
|
|
|
|
void printf(const char *format, ...) {
|
|
char buffer[64];
|
|
|
|
va_list args;
|
|
va_start(args, format);
|
|
vsnprintf(buffer, sizeof buffer, format, args);
|
|
va_end(args);
|
|
|
|
print(buffer);
|
|
}
|
|
|
|
void print(const char *str) {
|
|
auto digit = 0;
|
|
for (auto c = str; *c != 0 && digit < 4; c++) {
|
|
switch (*c) {
|
|
case '\'':
|
|
case '"':
|
|
case '`':
|
|
case '.':
|
|
printDots(false, false, false, true);
|
|
digit = 2;
|
|
break;
|
|
case ',':
|
|
printDots(false, false, true, true);
|
|
digit = 2;
|
|
break;
|
|
case ':':
|
|
printDots(false, true, true, false);
|
|
digit = 2;
|
|
break;
|
|
case ';':
|
|
printDots(false, true, true, true);
|
|
digit = 2;
|
|
break;
|
|
case '|':
|
|
printDots(true, true, true, true);
|
|
digit = 2;
|
|
break;
|
|
default:
|
|
printCharacter(digit++, *c);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void printDots(const bool dot0, const bool dot1, const bool dot2, const bool dot3) {
|
|
auto pixel = PIXELS_PER_DIGIT * 2;
|
|
if (dot0) {
|
|
pixels[pixel] = color;
|
|
}
|
|
pixel++;
|
|
if (dot1) {
|
|
pixels[pixel] = color;
|
|
}
|
|
pixel++;
|
|
if (dot2) {
|
|
pixels[pixel] = color;
|
|
}
|
|
pixel++;
|
|
if (dot3) {
|
|
pixels[pixel] = color;
|
|
}
|
|
}
|
|
|
|
void printCharacter(int digit, const char character) {
|
|
auto pixel = digit * PIXELS_PER_DIGIT + (digit >= 2 ? TOTAL_DOT_PIXEL_COUNT : 0);
|
|
const auto symbol = getSymbol(character);
|
|
for (auto s = *symbol; s < *symbol + SYMBOL_SIZE; s++) {
|
|
if (*s) {
|
|
pixels[pixel++] = color;
|
|
pixels[pixel++] = color;
|
|
pixels[pixel++] = color;
|
|
} else {
|
|
pixel += 3;
|
|
}
|
|
}
|
|
}
|
|
|
|
void sendHexBuffer(AsyncWebSocketClient *client) {
|
|
client->text(hexBuffer);
|
|
}
|
|
|
|
void fillRect(const uint8_t x, uint8_t y, uint8_t w, uint8_t h) {
|
|
for (int dx = 0; dx < w; ++dx) {
|
|
for (int dy = 0; dy < h; ++dy) {
|
|
drawVirtualPixel(x + dx, y + dy);
|
|
}
|
|
}
|
|
}
|
|
|
|
void strokeRect(const uint8_t x, uint8_t y, uint8_t w, uint8_t h) {
|
|
for (int dx = 0; dx < w; ++dx) {
|
|
drawVirtualPixel(x + dx, y);
|
|
drawVirtualPixel(x + dx, y + h);
|
|
}
|
|
for (int dy = 0; dy < h; ++dy) {
|
|
drawVirtualPixel(x, y + dy);
|
|
drawVirtualPixel(x + w, y + dy);
|
|
}
|
|
}
|
|
|
|
void drawVirtualPixel(const uint8_t x, const uint8_t y) {
|
|
const auto index = findIndexForVirtualCoordinates(x, y);
|
|
if (index >= 0) {
|
|
pixels[index] = color;
|
|
}
|
|
}
|
|
|
|
private:
|
|
|
|
Mapping digitMapping[32] = {
|
|
// @formatter:off
|
|
{0, 3}, {0, 2}, {0, 1}, // top left
|
|
{1, 0}, {2, 0}, {3, 0}, // top
|
|
{4, 1}, {4, 2}, {4, 3}, // top right
|
|
{4, 5}, {4, 6}, {4, 7}, // bottom right
|
|
{3, 8}, {2, 8}, {1, 8}, // bottom
|
|
{0, 7}, {0, 6}, {0, 5}, // bottom left
|
|
{1, 4}, {2, 4}, {3, 4}, // middle
|
|
// @formatter:on
|
|
};
|
|
|
|
uint8_t dotMapping[4] = {0, 2, 6, 8};
|
|
|
|
uint8_t findIndexForVirtualCoordinates(const uint8_t x, const uint8_t y) {
|
|
if (x < 0 || x > 24 || y < 0 || y > 8) {
|
|
return -1;
|
|
} else if (x >= 20) {
|
|
return _findIndexForVirtualCoordinates_digitRelative(x - 20, y) + 3 * PIXELS_PER_DIGIT + TOTAL_DOT_PIXEL_COUNT;
|
|
} else if (x >= 14) {
|
|
return _findIndexForVirtualCoordinates_digitRelative(x - 14, y) + 2 * PIXELS_PER_DIGIT + TOTAL_DOT_PIXEL_COUNT;
|
|
} else if (x == 12) {
|
|
return _findIndexForVirtualCoordinates_dotRelative(y) + 2 * PIXELS_PER_DIGIT;
|
|
} else if (x >= 6) {
|
|
return _findIndexForVirtualCoordinates_digitRelative(x - 6, y) + 1 * PIXELS_PER_DIGIT;
|
|
} else {
|
|
return _findIndexForVirtualCoordinates_digitRelative(x, y) + 0 * PIXELS_PER_DIGIT;;
|
|
}
|
|
}
|
|
|
|
uint8_t _findIndexForVirtualCoordinates_digitRelative(const uint8_t x, const uint8_t y) {
|
|
for (auto index = 0; index < PIXELS_PER_DIGIT; index++) {
|
|
auto item = digitMapping[index];
|
|
if (item.x == x && item.y == y) {
|
|
return index;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
uint8_t _findIndexForVirtualCoordinates_dotRelative(const uint8_t y) {
|
|
for (auto index = 0; index < DOT_COUNT; index++) {
|
|
auto dotY = dotMapping[index];
|
|
if (dotY == y) {
|
|
return index;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
void fillHexBuffer() {
|
|
auto b = hexBuffer;
|
|
for (const auto& pixel: pixels) {
|
|
b += snprintf(b, sizeof hexBuffer - (b - hexBuffer), "%X%X%X", pixel.r / 16, pixel.g / 16, pixel.b / 16);
|
|
}
|
|
}
|
|
};
|
|
|
|
extern Display display;
|
|
|
|
#endif
|