merged AppMatch.State.MINUTES/SECONDS to RUNNING + web-control for configMillis + re-implemented websocketEvent + configWrite delay
This commit is contained in:
parent
66a8474fca
commit
b7c2899f3f
@ -131,7 +131,7 @@
|
|||||||
segment.setAttribute("y", y + "vw");
|
segment.setAttribute("y", y + "vw");
|
||||||
segment.setAttribute("width", S + "vw");
|
segment.setAttribute("width", S + "vw");
|
||||||
segment.setAttribute("height", S + "vw");
|
segment.setAttribute("height", S + "vw");
|
||||||
segment.setAttribute("stroke", "magenta");
|
segment.setAttribute("stroke", "white");
|
||||||
segment.setAttribute("fill", "none");
|
segment.setAttribute("fill", "none");
|
||||||
segment.setAttribute("id", "segment" + segments.length);
|
segment.setAttribute("id", "segment" + segments.length);
|
||||||
display.appendChild(segment);
|
display.appendChild(segment);
|
||||||
@ -155,9 +155,7 @@
|
|||||||
|
|
||||||
function connect() {
|
function connect() {
|
||||||
console.log("connecting websocket...");
|
console.log("connecting websocket...");
|
||||||
const url2 = url("ws", "/ws");
|
const socket = new WebSocket(url("ws", "/ws"));
|
||||||
console.log(url2);
|
|
||||||
const socket = new WebSocket(url2);
|
|
||||||
socket.timeout = 1;
|
socket.timeout = 1;
|
||||||
socket.addEventListener('open', _ => {
|
socket.addEventListener('open', _ => {
|
||||||
console.log('websocket connected');
|
console.log('websocket connected');
|
||||||
@ -183,14 +181,14 @@
|
|||||||
console.log('websocket disconnected');
|
console.log('websocket disconnected');
|
||||||
segments.forEach(segment => {
|
segments.forEach(segment => {
|
||||||
segment.setAttribute("fill", "none");
|
segment.setAttribute("fill", "none");
|
||||||
segment.setAttribute("stroke", "magenta");
|
segment.setAttribute("stroke", "white");
|
||||||
});
|
});
|
||||||
connect();
|
setTimeout(connect, 1000);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
drawDisplay(1, 1);
|
drawDisplay(1, 1);
|
||||||
connect();
|
setTimeout(connect, 1000);
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@ -6,6 +6,8 @@
|
|||||||
#include <core/log.h>
|
#include <core/log.h>
|
||||||
#include <display/Display.h>
|
#include <display/Display.h>
|
||||||
|
|
||||||
|
#define CONFIG_WRITE_DELAY_MILLIS (30 * 1000)
|
||||||
|
|
||||||
class App {
|
class App {
|
||||||
|
|
||||||
const char *name;
|
const char *name;
|
||||||
@ -16,6 +18,8 @@ class App {
|
|||||||
|
|
||||||
JsonObject config = configJsonDoc.to<JsonObject>();
|
JsonObject config = configJsonDoc.to<JsonObject>();
|
||||||
|
|
||||||
|
unsigned long configDirty = 0;
|
||||||
|
|
||||||
bool dirty = true;
|
bool dirty = true;
|
||||||
|
|
||||||
bool doForceNextHexBuffer = true;
|
bool doForceNextHexBuffer = true;
|
||||||
@ -36,7 +40,6 @@ public:
|
|||||||
void start() {
|
void start() {
|
||||||
configRead();
|
configRead();
|
||||||
_start();
|
_start();
|
||||||
markDirty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
@ -45,6 +48,10 @@ public:
|
|||||||
const auto dtMillis = now - lastMillis;
|
const auto dtMillis = now - lastMillis;
|
||||||
lastMillis = now;
|
lastMillis = now;
|
||||||
_loop(dtMillis);
|
_loop(dtMillis);
|
||||||
|
if (configDirty != 0 && millis() - configDirty > CONFIG_WRITE_DELAY_MILLIS) {
|
||||||
|
configDirty = 0;
|
||||||
|
configWrite();
|
||||||
|
}
|
||||||
if (dirty) {
|
if (dirty) {
|
||||||
dirty = false;
|
dirty = false;
|
||||||
draw();
|
draw();
|
||||||
@ -98,6 +105,7 @@ protected:
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
void configSet(const char *key, T value) {
|
void configSet(const char *key, T value) {
|
||||||
config[key] = value;
|
config[key] = value;
|
||||||
|
configDirty = max(1UL, millis());
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void _start() {
|
virtual void _start() {
|
||||||
@ -116,7 +124,7 @@ protected:
|
|||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
void markDirty(const bool forceNextHexBuffer = false) {
|
void markDirty(const bool forceNextHexBuffer) {
|
||||||
dirty = true;
|
dirty = true;
|
||||||
doForceNextHexBuffer = forceNextHexBuffer;
|
doForceNextHexBuffer = forceNextHexBuffer;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,13 +5,23 @@
|
|||||||
|
|
||||||
#include "App.h"
|
#include "App.h"
|
||||||
|
|
||||||
|
#define MS_PER_SEC (1000L)
|
||||||
|
|
||||||
#define APP_MATCH_NAME "match"
|
#define APP_MATCH_NAME "match"
|
||||||
|
#define MILLIS_STEP_UP_DOWN (60 * MS_PER_SEC)
|
||||||
|
#define MILLIS_STEP_LEFT_RIGHT (MS_PER_SEC)
|
||||||
|
#define MILLIS_MIN (MS_PER_SEC)
|
||||||
|
#define MILLIS_MAX ((99 * 60 + 59) * MS_PER_SEC)
|
||||||
|
|
||||||
#define CONFIG_SECONDS_KEY "seconds"
|
#define CONFIG_SECONDS_KEY "seconds"
|
||||||
#define CONFIG_SECONDS_DEFAULT (6 * 60)
|
#define CONFIG_SECONDS_DEFAULT (6 * 60)
|
||||||
|
|
||||||
#define CONFIG_CENTIS_KEY "centis"
|
#define CONFIG_CENTIS_KEY "centis"
|
||||||
#define CONFIG_CENTIS_DEFAULT (6 * 60)
|
#define CONFIG_CENTIS_DEFAULT false
|
||||||
|
|
||||||
|
enum State {
|
||||||
|
INITIAL, RUNNING, PAUSE, END
|
||||||
|
};
|
||||||
|
|
||||||
class AppMatch final : public App {
|
class AppMatch final : public App {
|
||||||
|
|
||||||
@ -39,11 +49,7 @@ class AppMatch final : public App {
|
|||||||
|
|
||||||
unsigned long updateSeconds = totalSeconds;
|
unsigned long updateSeconds = totalSeconds;
|
||||||
|
|
||||||
enum State {
|
State state = INITIAL;
|
||||||
PAUSE, MINUTES, SECONDS, END
|
|
||||||
};
|
|
||||||
|
|
||||||
State state = PAUSE;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@ -55,11 +61,10 @@ public:
|
|||||||
bool setConfig(const String& key, const String& valueStr) override {
|
bool setConfig(const String& key, const String& valueStr) override {
|
||||||
if (key.equals(CONFIG_SECONDS_KEY)) {
|
if (key.equals(CONFIG_SECONDS_KEY)) {
|
||||||
const auto seconds = valueStr.toInt();
|
const auto seconds = valueStr.toInt();
|
||||||
const auto newMillis = seconds * 1000;
|
const auto newMillis = seconds * MS_PER_SEC;
|
||||||
if (seconds > 0 && configMillis != newMillis) {
|
if (seconds > 0 && configMillis != newMillis) {
|
||||||
configMillis = newMillis;
|
configMillis = newMillis;
|
||||||
configSet(CONFIG_SECONDS_KEY, seconds);
|
configSet(CONFIG_SECONDS_KEY, seconds);
|
||||||
configWrite();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else if (key.equals(CONFIG_CENTIS_KEY)) {
|
} else if (key.equals(CONFIG_CENTIS_KEY)) {
|
||||||
@ -67,50 +72,71 @@ public:
|
|||||||
if (configCentis != newCentis) {
|
if (configCentis != newCentis) {
|
||||||
configCentis = newCentis;
|
configCentis = newCentis;
|
||||||
configSet(CONFIG_CENTIS_KEY, newCentis);
|
configSet(CONFIG_CENTIS_KEY, newCentis);
|
||||||
configWrite();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void up() override {
|
||||||
|
addConfigMillis(MILLIS_STEP_UP_DOWN);
|
||||||
|
}
|
||||||
|
|
||||||
|
void down() override {
|
||||||
|
addConfigMillis(-MILLIS_STEP_UP_DOWN);
|
||||||
|
}
|
||||||
|
|
||||||
|
void right() override {
|
||||||
|
addConfigMillis(MILLIS_STEP_LEFT_RIGHT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void left() override {
|
||||||
|
addConfigMillis(-MILLIS_STEP_LEFT_RIGHT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void confirm() override {
|
||||||
|
if (state == END) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (state) {
|
||||||
|
case INITIAL:
|
||||||
|
case PAUSE:
|
||||||
|
setState(RUNNING);
|
||||||
|
break;
|
||||||
|
case RUNNING:
|
||||||
|
setState(PAUSE);
|
||||||
|
break;
|
||||||
|
case END:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cancel() override {
|
||||||
|
if (state == PAUSE || state == END) {
|
||||||
|
_start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
void _start() override {
|
void _start() override {
|
||||||
configMillis = configGet<unsigned long>(CONFIG_SECONDS_KEY, CONFIG_SECONDS_DEFAULT) * 1000;
|
configMillis = configGet<unsigned long>(CONFIG_SECONDS_KEY, CONFIG_SECONDS_DEFAULT) * MS_PER_SEC;
|
||||||
configCentis = configGet<bool>(CONFIG_CENTIS_KEY, CONFIG_CENTIS_DEFAULT);
|
configCentis = configGet<bool>(CONFIG_CENTIS_KEY, CONFIG_CENTIS_DEFAULT);
|
||||||
|
|
||||||
info("config:");
|
info("config:");
|
||||||
info(" seconds = %ld", configMillis / 1000);
|
info(" seconds = %ld", configMillis / MS_PER_SEC);
|
||||||
info(" centis = %s", configCentis ? "true" : "false");
|
info(" centis = %s", configCentis ? "true" : "false");
|
||||||
|
|
||||||
totalMillis = configMillis;
|
setTotalMillis(configMillis);
|
||||||
setState(PAUSE, true);
|
setState(INITIAL, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _loop(const unsigned long dtMillis) override {
|
void _loop(const unsigned long dtMillis) override {
|
||||||
if (state != PAUSE) {
|
if (state == RUNNING) {
|
||||||
if (totalMillis <= dtMillis) {
|
if (totalMillis <= dtMillis) {
|
||||||
totalMillis = 0;
|
setTotalMillis(0);
|
||||||
} else {
|
} else {
|
||||||
totalMillis -= dtMillis;
|
setTotalMillis(totalMillis - dtMillis);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
totalCentis = totalMillis / 10;
|
|
||||||
totalSeconds = totalCentis / 100;
|
|
||||||
totalMinutes = totalSeconds / 60;
|
|
||||||
|
|
||||||
partCentis = totalCentis % 100;
|
|
||||||
partSeconds = totalSeconds % 60;
|
|
||||||
|
|
||||||
if (state != PAUSE) {
|
|
||||||
if (totalMinutes > 0) {
|
|
||||||
setState(MINUTES);
|
|
||||||
} else if (totalMillis > 0) {
|
|
||||||
setState(SECONDS);
|
|
||||||
} else {
|
|
||||||
setState(END);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,25 +145,31 @@ protected:
|
|||||||
if (now - blinkMillis > blinkIntervalMillis) {
|
if (now - blinkMillis > blinkIntervalMillis) {
|
||||||
blinkMillis = now;
|
blinkMillis = now;
|
||||||
blinkState = !blinkState;
|
blinkState = !blinkState;
|
||||||
markDirty();
|
markDirty(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (updateSeconds != totalSeconds) {
|
if (state == RUNNING) {
|
||||||
updateSeconds = totalSeconds;
|
if (totalMinutes > 0 || !configCentis) {
|
||||||
markDirty();
|
if (updateSeconds != totalSeconds) {
|
||||||
} else if (state == SECONDS && configCentis) {
|
updateSeconds = totalSeconds;
|
||||||
markDirty();
|
markDirty(false);
|
||||||
|
}
|
||||||
|
} else if (configCentis) {
|
||||||
|
markDirty(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw() override {
|
void draw() override {
|
||||||
display.clear();
|
display.clear();
|
||||||
if (state == PAUSE) {
|
if (state == INITIAL) {
|
||||||
|
display.setColor(WHITE);
|
||||||
|
} else if (state == PAUSE) {
|
||||||
display.setColor(BLUE);
|
display.setColor(BLUE);
|
||||||
} else if (totalMillis * 2 >= configMillis) {
|
} else if (totalMillis * 2 >= configMillis) {
|
||||||
display.setColor(GREEN);
|
display.setColor(GREEN);
|
||||||
} else if (totalMillis >= 10 * 1000) {
|
} else if (totalMillis > 0) {
|
||||||
display.setColor(YELLOW);
|
display.setColor(YELLOW);
|
||||||
} else {
|
} else {
|
||||||
display.setColor(RED);
|
display.setColor(RED);
|
||||||
@ -145,7 +177,6 @@ protected:
|
|||||||
if (blinkIntervalMillis == 0 || blinkState) {
|
if (blinkIntervalMillis == 0 || blinkState) {
|
||||||
if (totalMinutes > 0) {
|
if (totalMinutes > 0) {
|
||||||
display.printf("%2d:%02d", totalMinutes, partSeconds);
|
display.printf("%2d:%02d", totalMinutes, partSeconds);
|
||||||
info("%2d:%02d", totalMinutes, partSeconds);
|
|
||||||
} else if (totalMillis > 0) {
|
} else if (totalMillis > 0) {
|
||||||
if (configCentis) {
|
if (configCentis) {
|
||||||
display.printf("%2d.%02d", partSeconds, partCentis);
|
display.printf("%2d.%02d", partSeconds, partCentis);
|
||||||
@ -158,60 +189,32 @@ protected:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void confirm() override {
|
|
||||||
if (state == END) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (state == PAUSE) {
|
|
||||||
setState(MINUTES);
|
|
||||||
} else {
|
|
||||||
setState(PAUSE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void cancel() override {
|
|
||||||
_start();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void blinkEnable(const unsigned long intervalMillis) {
|
|
||||||
blinkState = false;
|
|
||||||
blinkIntervalMillis = intervalMillis;
|
|
||||||
blinkMillis = millis();
|
|
||||||
}
|
|
||||||
|
|
||||||
void setState(const State newState, const bool force = false) {
|
void setState(const State newState, const bool force = false) {
|
||||||
if (state == newState && !force) {
|
if (state == newState && !force) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
state = newState;
|
state = newState;
|
||||||
switch (state) {
|
updateSeconds = totalSeconds;
|
||||||
case PAUSE:
|
blinkEnable(0);
|
||||||
blinkEnable(0);
|
if (state == END) {
|
||||||
break;
|
blinkEnable(500);
|
||||||
case MINUTES:
|
|
||||||
updateSeconds = totalSeconds;
|
|
||||||
blinkEnable(0);
|
|
||||||
case SECONDS:
|
|
||||||
blinkEnable(0);
|
|
||||||
break;
|
|
||||||
case END:
|
|
||||||
blinkEnable(500);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
info("state changed to %s", getStateName());
|
|
||||||
markDirty();
|
info("state = %s", getStateName());
|
||||||
|
markDirty(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *getStateName() const {
|
const char *getStateName() const {
|
||||||
switch (state) {
|
switch (state) {
|
||||||
|
case INITIAL:
|
||||||
|
return "INITIAL";
|
||||||
case PAUSE:
|
case PAUSE:
|
||||||
return "PAUSE";
|
return "PAUSE";
|
||||||
case MINUTES:
|
case RUNNING:
|
||||||
return "MINUTES";
|
return "RUNNING";
|
||||||
case SECONDS:
|
|
||||||
return "SECONDS";
|
|
||||||
case END:
|
case END:
|
||||||
return "END";
|
return "END";
|
||||||
default:
|
default:
|
||||||
@ -219,6 +222,44 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void blinkEnable(const unsigned long intervalMillis) {
|
||||||
|
blinkState = false;
|
||||||
|
blinkIntervalMillis = intervalMillis;
|
||||||
|
blinkMillis = millis();
|
||||||
|
}
|
||||||
|
|
||||||
|
void addConfigMillis(const long change) {
|
||||||
|
if (state != INITIAL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto newConfigMillis = max(MILLIS_MIN, min(static_cast<long>(configMillis) + change, MILLIS_MAX));
|
||||||
|
if (configMillis != newConfigMillis) {
|
||||||
|
configMillis = newConfigMillis;
|
||||||
|
configSet(CONFIG_SECONDS_KEY, configMillis / 1000);
|
||||||
|
setTotalMillis(configMillis);
|
||||||
|
markDirty(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setTotalMillis(const unsigned long newTotalMillis) {
|
||||||
|
if (totalMillis == newTotalMillis) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
totalMillis = newTotalMillis;
|
||||||
|
|
||||||
|
if (totalMillis == 0) {
|
||||||
|
setState(END);
|
||||||
|
}
|
||||||
|
|
||||||
|
totalCentis = totalMillis / 10;
|
||||||
|
totalSeconds = totalCentis / 100;
|
||||||
|
totalMinutes = totalSeconds / 60;
|
||||||
|
|
||||||
|
partCentis = totalCentis % 100;
|
||||||
|
partSeconds = totalSeconds % 60;
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -81,24 +81,16 @@ void httpNotFound(AsyncWebServerRequest *request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *getWebsocketTypeName(AwsEventType type) {
|
void websocketEvent(AsyncWebSocket *socket, AsyncWebSocketClient *client, const AwsEventType type, void *arg, unsigned char *message, const unsigned length) {
|
||||||
switch (type) {
|
if (type == WS_EVT_CONNECT) {
|
||||||
case WS_EVT_CONNECT:
|
display.sendHexBuffer(client);
|
||||||
return "CONNECT";
|
|
||||||
case WS_EVT_DISCONNECT:
|
|
||||||
return "DISCONNECT";
|
|
||||||
case WS_EVT_PONG:
|
|
||||||
return "PONG";
|
|
||||||
case WS_EVT_ERROR:
|
|
||||||
return "ERROR";
|
|
||||||
case WS_EVT_DATA:
|
|
||||||
return "DATA";
|
|
||||||
default:
|
|
||||||
return "[???]";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void httpSetup() {
|
void httpSetup() {
|
||||||
|
ws.onEvent(websocketEvent);
|
||||||
|
server.addHandler(&ws);
|
||||||
|
|
||||||
server.on("/action/left", HTTP_GET, httpActionLeft);
|
server.on("/action/left", HTTP_GET, httpActionLeft);
|
||||||
server.on("/action/up", HTTP_GET, httpActionUp);
|
server.on("/action/up", HTTP_GET, httpActionUp);
|
||||||
server.on("/action/down", HTTP_GET, httpActionDown);
|
server.on("/action/down", HTTP_GET, httpActionDown);
|
||||||
@ -108,7 +100,6 @@ void httpSetup() {
|
|||||||
server.on("/app/config", HTTP_GET, httpAppConfig);
|
server.on("/app/config", HTTP_GET, httpAppConfig);
|
||||||
server.serveStatic("/", LittleFS, "/http/", "max-age=86400").setDefaultFile("index.html");
|
server.serveStatic("/", LittleFS, "/http/", "max-age=86400").setDefaultFile("index.html");
|
||||||
server.onNotFound(httpNotFound);
|
server.onNotFound(httpNotFound);
|
||||||
server.addHandler(&ws);
|
|
||||||
server.begin();
|
server.begin();
|
||||||
|
|
||||||
DefaultHeaders::Instance().addHeader("Access-Control-Allow-Origin", "*");
|
DefaultHeaders::Instance().addHeader("Access-Control-Allow-Origin", "*");
|
||||||
|
|||||||
@ -32,6 +32,8 @@ class Display {
|
|||||||
|
|
||||||
Color color = WHITE;
|
Color color = WHITE;
|
||||||
|
|
||||||
|
char hexBuffer[HEX_BUFFER_SIZE] = "";
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Display() /* : leds(PIXEL_COUNT, GPIO_NUM_13) */ {
|
Display() /* : leds(PIXEL_COUNT, GPIO_NUM_13) */ {
|
||||||
@ -61,7 +63,8 @@ public:
|
|||||||
static auto last = now;
|
static auto last = now;
|
||||||
if (now - last >= HEX_BUFFER_MIN_WAIT_MS || forceNextHexBuffer) {
|
if (now - last >= HEX_BUFFER_MIN_WAIT_MS || forceNextHexBuffer) {
|
||||||
last = now;
|
last = now;
|
||||||
sendHexBuffer();
|
fillHexBuffer();
|
||||||
|
websocketSendAll(hexBuffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,15 +146,17 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sendHexBuffer(AsyncWebSocketClient *client) {
|
||||||
|
client->text(hexBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void sendHexBuffer() {
|
void fillHexBuffer() {
|
||||||
char hexBuffer[HEX_BUFFER_SIZE] = "";
|
|
||||||
auto b = hexBuffer;
|
auto b = hexBuffer;
|
||||||
for (const auto& pixel: pixels) {
|
for (const auto& pixel: pixels) {
|
||||||
b += snprintf(b, sizeof hexBuffer - (b - hexBuffer), "%X%X%X", pixel.r / 16, pixel.g / 16, pixel.b / 16);
|
b += snprintf(b, sizeof hexBuffer - (b - hexBuffer), "%X%X%X", pixel.r / 16, pixel.g / 16, pixel.b / 16);
|
||||||
}
|
}
|
||||||
websocketSendAll(hexBuffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user