diff --git a/data/index.htm b/data/index.htm deleted file mode 100644 index 1a8f1482dd7a819c37485b377186858a431ee729..0000000000000000000000000000000000000000 --- a/data/index.htm +++ /dev/null @@ -1,64 +0,0 @@ -<!DOCTYPE html> -<html> - <head> - <meta http-equiv="Content-type" content="text/html; charset=utf-8"> - <title>Events Log</title> - <style type="text/css" media="screen"> - body { - margin:0; - padding:0; - background-color: black; - } - - #dbg { - font-family: monaco; - font-size: 12px; - line-height: 13px; - color: #AAA; - margin:0; - padding:0; - padding-left:4px; - } - </style> - <script type="text/javascript"> - function ge(s){ return document.getElementById(s);} - function ce(s){ return document.createElement(s);} - function stb(){ window.scrollTo(0, document.body.scrollHeight || document.documentElement.scrollHeight); } - function addMessage(m){ - var msg = ce("div"); - msg.innerText = m; - ge("dbg").appendChild(msg); - stb(); - } - function startEvents(){ - var es = new EventSource('/events'); - es.onopen = function(e) { - addMessage("Events Opened"); - }; - es.onerror = function(e) { - if (e.target.readyState != EventSource.OPEN) { - addMessage("Events Closed"); - } - }; - es.onmessage = function(e) { - addMessage("Event: " + e.data); - }; - es.addEventListener('ota', function(e) { - addMessage("[OTA] " + e.data); - }, false); - es.addEventListener('game', function(e) { - addMessage("[GAME] " + e.data); - }, false); - es.addEventListener('display', function(e) { - addMessage("[DISPLAY] " + e.data); - }, false); - } - function onBodyLoad(){ - startEvents(); - } - </script> - </head> - <body id="body" onload="onBodyLoad()"> - <pre id="dbg"></pre> - </body> -</html> diff --git a/data/index.html b/data/index.html new file mode 100644 index 0000000000000000000000000000000000000000..f167d3a3847638315026c4c4dce29a8a5f8c1ac9 --- /dev/null +++ b/data/index.html @@ -0,0 +1,81 @@ +<!DOCTYPE html> +<html> + <head> + <meta http-equiv="Content-type" content="text/html; charset=utf-8"> + <title>WebSocketTester</title> + <style type="text/css" media="screen"> + body { + margin:0; + padding:0; + background-color: black; + } + + #dbg, #input_div, #input_el { + font-family: monaco; + font-size: 12px; + line-height: 13px; + color: #AAA; + } + + #dbg, #input_div { + margin:0; + padding:0; + padding-left:4px; + } + + #input_el { + width:98%; + background-color: rgba(0,0,0,0); + border: 0px; + } + #input_el:focus { + outline: none; + } + </style> + <script type="text/javascript"> + var ws = null; + function ge(s){ return document.getElementById(s);} + function ce(s){ return document.createElement(s);} + function stb(){ window.scrollTo(0, document.body.scrollHeight || document.documentElement.scrollHeight); } + function addMessage(m){ + var msg = ce("div"); + msg.innerText = m; + ge("dbg").appendChild(msg); + stb(); + } + function startSocket(){ + ws = new WebSocket('ws://'+document.location.host+'/ws',['arduino']); + ws.onopen = function(e){ + addMessage("Connected"); + }; + ws.onclose = function(e){ + addMessage("Disconnected"); + }; + ws.onerror = function(e){ + console.log("ws error", e); + addMessage("Error"); + }; + ws.onmessage = function(e){ + var msg = "> "+e.data; + addMessage(msg); + }; + ge("input_el").onkeydown = function(e){ + stb(); + if(e.keyCode == 13 && ge("input_el").value != ""){ + ws.send(ge("input_el").value); + ge("input_el").value = ""; + } + } + } + function onBodyLoad(){ + startSocket(); + } + </script> + </head> + <body id="body" onload="onBodyLoad()"> + <pre id="dbg"></pre> + <div id="input_div"> + $<input type="text" value="" id="input_el"> + </div> + </body> +</html> diff --git a/platformio.ini b/platformio.ini index b8f71df7a07e842b90e3e9a222fc647f0e6225d9..e97b462c0d37ba3970e1bb3434f7f4d879538650 100644 --- a/platformio.ini +++ b/platformio.ini @@ -17,12 +17,14 @@ monitor_port = COM8 monitor_speed = 115200 monitor_filters = esp32_exception_decoder board_build.filesystem = littlefs +platform_packages = framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#2.0.9 +board_build.arduino.upstream_packages = no lib_deps = https://github.com/ayushsharma82/ESPConnect.git + https://github.com/bblanchon/ArduinoJson.git https://github.com/me-no-dev/AsyncTCP.git https://github.com/me-no-dev/ESPAsyncWebServer.git https://github.com/PlummersSoftwareLLC/SmartMatrix.git - https://github.com/sstaub/TickTwo.git https://github.com/LennartHennigs/ESPTelnet.git [env:esp32dev_ota] diff --git a/src/display.cpp b/src/display.cpp index 6aaf3009d4b4f4dd2b0765ca2d3587e514f0abea..a523205677b09278cc35280bb890b5aea00eeff5 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -14,7 +14,7 @@ const uint8_t kMatrixOptions = (SMARTMATRIX_OPTIONS_NONE); // see http://docs const uint8_t kBackgroundLayerOptions = (SM_BACKGROUND_OPTIONS_NONE); const uint8_t kIndexedLayerOptions = (SM_INDEXED_OPTIONS_NONE); -const int defaultBrightness = (brightnessPercent * 255) / 100; +int defaultBrightness = (brightnessPercent * 255) / 100; rgb24 colorWhite = {0xff, 0xff, 0xff}; @@ -71,9 +71,16 @@ void showEndScreen(int ticks) indexedLayer.swapBuffers(false); } +void displayBrightness(int brightness) +{ + //logLine("Display Brightness: " + (String)brightness); + // brightness = lightPowerMap8bit[brightness]; + matrix.setBrightness(brightness); +} + void gameBrightness(int brightness) { - logLine("Game Brightness: " + (String)brightness); + //logLine("Game Brightness: " + (String)brightness); // brightness = lightPowerMap8bit[brightness]; backgroundLayer.setBrightness(brightness); } diff --git a/src/display.h b/src/display.h index e550e2171e544f69c7213ee01475dd98ad14f3e4..be4764cd0121af833f5f89c617f126236b14e788 100644 --- a/src/display.h +++ b/src/display.h @@ -13,6 +13,7 @@ void setupDisplay(); void displayLoop(); void showEndScreen(int ticks); void showMessage(char* msg); +void displayBrightness(int brightness); void gameBrightness(int brightness); void clearDisplay(); diff --git a/src/gameoflife.cpp b/src/gameoflife.cpp index 3c45507e0ed5d1d7fd66430aacd886cbdb773923..421183832c6c487205d1e405c7512af1171de494 100644 --- a/src/gameoflife.cpp +++ b/src/gameoflife.cpp @@ -135,9 +135,9 @@ void gameLoop() if (currentTick % 2) { - char msg[80]; - sprintf(msg, "Tick: %4d, Cells now: %4d, before: %4d - No evolution since: %3d", currentTick, cellsAliveNow, cellsAliveBefore, noEvolutionTicks); - logLine(msg); + // char msg[80]; + // sprintf(msg, "Tick: %4d, Cells now: %4d, before: %4d - No evolution since: %3d", currentTick, cellsAliveNow, cellsAliveBefore, noEvolutionTicks); + // logLine(msg); cellsAliveBefore = cellsAliveNow; } diff --git a/src/gameoflife.h b/src/gameoflife.h index ab91666736ff1df1ebaf557ea269cd1d90b9edd7..2e0e14c8412616beb080b0df1d464b641bf36f1c 100644 --- a/src/gameoflife.h +++ b/src/gameoflife.h @@ -11,7 +11,7 @@ extern int arrayCopy[SCREEN_HEIGHT][SCREEN_WIDTH]; extern bool runGame; extern int noEvolutionTicksLimit; -extern const int defaultBrightness; +extern int defaultBrightness; void setupGameOfLife(); void createRandomMatrix(int (&a)[SCREEN_HEIGHT][SCREEN_WIDTH]); diff --git a/src/main.cpp b/src/main.cpp index 5b7b1aab3bc9f3b06fe981b0e2a3b93fba77daf1..5c4edae84458d2641f5b9a64bc7772f891659eb9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,5 +1,5 @@ +#define CONFIG_HEAP_CORRUPTION_DETECTION HEAP_POISONING_LIGHT #include <Arduino.h> -#include "TickTwo.h" #include "utils.h" #include "network.h" #include "display.h" @@ -7,32 +7,34 @@ int noEvolutionTicksLimit = 100; int brightnessPercent = 20; -int gameInterval = 10; +int gameInterval = 100; -TickTwo gameTimer(gameLoop, gameInterval); -TickTwo displayTimer(displayLoop, gameInterval); +unsigned long lastTick; -String titleMsg = "Game of Life"; +void showTitle() { + char msg[13]; + String titleMsg = "Game of Life"; + titleMsg.toCharArray(msg, 13); + showMessage(msg); +} void setup() { Serial.begin(115200); logLine("", true); - setupNetwork(); setupDisplay(); - char msg[13]; - titleMsg.toCharArray(msg, 13); - showMessage(msg); - delay(3000); + showTitle(); + setupNetwork(); clearDisplay(); setupGameOfLife(); - gameTimer.start(); - displayTimer.start(); } void loop() { networkLoop(); - gameTimer.update(); - displayTimer.update(); + if ((millis() - lastTick) >= gameInterval) { + gameLoop(); + displayLoop(); + lastTick += gameInterval; + } } diff --git a/src/network.cpp b/src/network.cpp index df71d8f3de4c293ac0490e4d4fc10bc3059827e8..c080dba5f38ed6e7cb96d79df201534c9775037c 100644 --- a/src/network.cpp +++ b/src/network.cpp @@ -7,11 +7,10 @@ MDNSResponder mdns; AsyncWebServer server(80); +AsyncWebSocket ws("/ws"); ESPTelnet telnet; IPAddress ip; -uint16_t telnetPort = 23; - void setupNetwork() { setupWifi(); @@ -53,7 +52,13 @@ void setupOTA() { ArduinoOTA.onStart([]() { - runGame = false; + runGame = false; + if (ArduinoOTA.getCommand() != U_FLASH) { + LittleFS.end(); + } + ws.enable(false); + ws.textAll("OTA Update Started"); + ws.closeAll(); logLine("Update Start"); clearDisplay(); }); ArduinoOTA.onEnd([]() @@ -66,9 +71,9 @@ void setupOTA() char msg[10]; sprintf(msg, "OTA:%3d%%", (progress/(total/100))); showMessage(msg); - char p[32]; - sprintf(p, "Progress: %u%%\n", (progress/(total/100))); - logLine(p); }); + logLine("OTA: ", false); + logLine((String)(progress/(total/100)), false); + logLine("%"); }); ArduinoOTA.onError([](ota_error_t error) { if(error == OTA_AUTH_ERROR) logLine("OTA Auth Failed"); @@ -91,7 +96,7 @@ void setupTelnet() telnet.onInputReceived(onTelnetInput); Serial.print("- Telnet: "); - if (telnet.begin(telnetPort)) + if (telnet.begin()) { Serial.println("running"); } @@ -104,9 +109,13 @@ void setupTelnet() void setupWebserver() { LittleFS.begin(); - server.serveStatic("/", LittleFS, "/"); + ws.onEvent(onEvent); + server.addHandler(&ws); + server.on("/heap", HTTP_GET, [](AsyncWebServerRequest *request) + { request->send(200, "text/plain", String(ESP.getFreeHeap())); }); server.onNotFound([](AsyncWebServerRequest *request) { request->send(404); }); + server.serveStatic("/", LittleFS, "/").setDefaultFile("index.html"); server.begin(); } @@ -114,9 +123,7 @@ void networkLoop() { ArduinoOTA.handle(); if (runGame) - { telnet.loop(); - } } void onTelnetConnect(String ip) @@ -165,3 +172,61 @@ void onTelnetInput(String str) telnet.disconnectClient(); } } + +DynamicJsonDocument getConfigJson() +{ + DynamicJsonDocument doc(1024); + doc["brightness"] = defaultBrightness; + doc["interval"] = gameInterval; + return doc; +} + +void onEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) +{ + if (type == WS_EVT_CONNECT) + { + // client connected + logLine("WS: connect"); + client->ping(); + DynamicJsonDocument doc = getConfigJson(); + size_t strsize = measureJson(doc) + 1; + char json[strsize]; + serializeJson(doc, json, strsize); + logLine("WS>> ", false); + logLine(json); + ws.text(client->id(), json); + } + else if (type == WS_EVT_DISCONNECT) + { + logLine("WS: disconnect"); + } + else if (type == WS_EVT_ERROR) + { + // error was received from the other end + char msg[64]; + snprintf_P(msg, sizeof(msg), PSTR("WS[%u] error(%u): %s"), client->id(), *((uint16_t *)arg), (char *)data); + logLine(msg); + } + else if (type == WS_EVT_PONG) + { + // pong message was received (in response to a ping request maybe) + logLine("WS: pong"); + } + else if (type == WS_EVT_DATA) + { + // data packet + data[len] = 0; + logLine("WS<< ", false); + logLine((char *)data); + updateConfig(data); + } +} + +void updateConfig(uint8_t *data) +{ + StaticJsonDocument<200> doc; + deserializeJson(doc, (char *)data); + defaultBrightness = (int)doc["brightness"]; + displayBrightness(defaultBrightness); + gameInterval = (int)doc["interval"]; +} diff --git a/src/network.h b/src/network.h index ae38bd386f77a11a75c8e2b1afcd61755e9a24c0..2177f8228d2c462ad69ef6d8ceb904fc9bf094a3 100644 --- a/src/network.h +++ b/src/network.h @@ -10,8 +10,11 @@ #include <ESPmDNS.h> #include <AsyncTCP.h> #include <ESPAsyncWebServer.h> +#include <ArduinoJson.h> extern bool runGame; +extern int defaultBrightness; +extern int gameInterval; void setupNetwork(); void setupMDNS(); @@ -25,5 +28,7 @@ void onTelnetDisconnect(String ip); void onTelnetReconnect(String ip); void onTelnetConnectionAttempt(String ip); void onTelnetInput(String str); +void onEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len); +void updateConfig (uint8_t* data); #endif