From 9319221fa0e1039857817138d7dcbfdf44d7112c Mon Sep 17 00:00:00 2001
From: Jan Grewe <jan@faked.org>
Date: Mon, 29 May 2023 23:23:47 +0200
Subject: [PATCH] split code OTA working GoL working

---
 platformio.ini       | 12 ++------
 platformio_upload.py | 53 ----------------------------------
 src/display.cpp      | 35 ++++++++++++-----------
 src/display.h        |  3 ++
 src/gameoflife.cpp   | 68 ++++++++++++++++++++++++++++++++++++++++++++
 src/gameoflife.h     | 17 +++++++++++
 src/main.cpp         |  5 ++++
 src/network.cpp      | 36 +++++++++++++++++------
 src/network.h        |  6 +++-
 9 files changed, 147 insertions(+), 88 deletions(-)
 delete mode 100644 platformio_upload.py
 create mode 100644 src/gameoflife.cpp
 create mode 100644 src/gameoflife.h

diff --git a/platformio.ini b/platformio.ini
index 94002fa..97270c2 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -19,17 +19,9 @@ lib_deps =
     https://github.com/ayushsharma82/ESPConnect.git
 	https://github.com/me-no-dev/AsyncTCP.git
 	https://github.com/me-no-dev/ESPAsyncWebServer.git
-    https://github.com/ayushsharma82/AsyncElegantOTA.git
     https://github.com/PlummersSoftwareLLC/SmartMatrix.git
-    https://github.com/adafruit/Adafruit-GFX-Library.git
-    https://github.com/marcmerlin/Framebuffer_GFX.git
-    https://github.com/FastLED/FastLED.git
-    https://github.com/marcmerlin/SmartMatrix_GFX.git
 
 [env:esp32dev_ota]
 extends = env:esp32dev
-#upload_port = matrixoflife.local
-#upload_protocol = espota
-upload_protocol = custom
-upload_url = http://matrixoflife.local/update
-extra_scripts = platformio_upload.py
+upload_port = matrixoflife.local
+upload_protocol = espota
diff --git a/platformio_upload.py b/platformio_upload.py
deleted file mode 100644
index 1c5f0a6..0000000
--- a/platformio_upload.py
+++ /dev/null
@@ -1,53 +0,0 @@
-# Allows PlatformIO to upload directly to AsyncElegantOTA
-#
-# To use:
-# - copy this script into the same folder as your platformio.ini
-# - set the following for your project in platformio.ini:
-#
-# extra_scripts = platformio_upload.py
-# upload_protocol = custom
-# upload_url = <your upload URL>
-# 
-# An example of an upload URL:
-# upload_URL = http://192.168.1.123/update
-
-import requests
-import hashlib
-Import('env')
-
-try:
-    from requests_toolbelt import MultipartEncoder, MultipartEncoderMonitor
-    from tqdm import tqdm
-except ImportError:
-    env.Execute("$PYTHONEXE -m pip install requests_toolbelt")
-    env.Execute("$PYTHONEXE -m pip install tqdm")
-    from requests_toolbelt import MultipartEncoder, MultipartEncoderMonitor
-    from tqdm import tqdm
-
-def on_upload(source, target, env):
-    firmware_path = str(source[0])
-    upload_url = env.GetProjectOption('upload_url')
-
-    with open(firmware_path, 'rb') as firmware:
-        md5 = hashlib.md5(firmware.read()).hexdigest()
-        firmware.seek(0)
-        encoder = MultipartEncoder(fields={
-            'MD5': md5, 
-            'firmware': ('firmware', firmware, 'application/octet-stream')}
-        )
-
-        bar = tqdm(desc='Upload Progress',
-              total=encoder.len,
-              dynamic_ncols=True,
-              unit='B',
-              unit_scale=True,
-              unit_divisor=1024
-              )
-
-        monitor = MultipartEncoderMonitor(encoder, lambda monitor: bar.update(monitor.bytes_read - bar.n))
-
-        response = requests.post(upload_url, data=monitor, headers={'Content-Type': monitor.content_type})
-        bar.close()
-        print(response,response.text)
-            
-env.Replace(UPLOADCMD=on_upload)
diff --git a/src/display.cpp b/src/display.cpp
index d78aaf8..fac11d2 100644
--- a/src/display.cpp
+++ b/src/display.cpp
@@ -1,4 +1,5 @@
 #include <Arduino.h>
+#include "gameoflife.h"
 #include "display.h"
 
 #define COLOR_DEPTH 24                  // known working: 24, 48 - If the sketch uses type `rgb24` directly, COLOR_DEPTH must be 24
@@ -9,33 +10,35 @@ const uint8_t kDmaBufferRows = 2;       // known working: 2-4, use 2 to save mem
 const uint8_t kPanelType = SMARTMATRIX_HUB75_64ROW_MOD32SCAN;   // use SMARTMATRIX_HUB75_16ROW_MOD8SCAN for common 16x32 panels
 const uint8_t kMatrixOptions = (SMARTMATRIX_OPTIONS_NONE);      // see http://docs.pixelmatix.com/SmartMatrix for options
 const uint8_t kBackgroundLayerOptions = (SM_BACKGROUND_OPTIONS_NONE);
-const uint8_t kScrollingLayerOptions = (SM_SCROLLING_OPTIONS_NONE);
-const uint8_t kIndexedLayerOptions = (SM_INDEXED_OPTIONS_NONE);
 
-const int defaultBrightness = (25*255)/100;        // (10%) brightness
-const int defaultScrollOffset = 6;
-const rgb24 defaultBackgroundColor = {0x40, 0, 0};
+const int defaultBrightness = (10*255)/100;
+
+rgb24 colorWhite = {0xff, 0xff, 0xff};
+rgb24 colorBlack = {0x00, 0x00, 0x00};
 
 SMARTMATRIX_ALLOCATE_BUFFERS(matrix, kMatrixWidth, kMatrixHeight, kRefreshDepth, kDmaBufferRows, kPanelType, kMatrixOptions);
 SMARTMATRIX_ALLOCATE_BACKGROUND_LAYER(backgroundLayer, kMatrixWidth, kMatrixHeight, COLOR_DEPTH, kBackgroundLayerOptions);
-SMARTMATRIX_ALLOCATE_SCROLLING_LAYER(scrollingLayer, kMatrixWidth, kMatrixHeight, COLOR_DEPTH, kScrollingLayerOptions);
-SMARTMATRIX_ALLOCATE_INDEXED_LAYER(indexedLayer, kMatrixWidth, kMatrixHeight, COLOR_DEPTH, kIndexedLayerOptions);
 
 void setupDisplay() {
   matrix.addLayer(&backgroundLayer); 
-  matrix.addLayer(&scrollingLayer); 
-  matrix.addLayer(&indexedLayer); 
   matrix.begin();
   matrix.setBrightness(defaultBrightness);
-  scrollingLayer.setOffsetFromTop(defaultScrollOffset);
   backgroundLayer.enableColorCorrection(true);
 }
 
 void displayLoop() {
-    scrollingLayer.setColor({0xff, 0xff, 0xff});
-    scrollingLayer.setMode(wrapForward);
-    scrollingLayer.setSpeed(40);
-    scrollingLayer.setFont(font6x10);
-    scrollingLayer.start("SmartMatrix Demo", 1);
-    delay(5000);
+  if (runGame) {
+    gameOfLife(g);
+    for (int i = 0; i < SCREEN_HEIGHT; i++) {
+      for (int j = 0; j < SCREEN_WIDTH; j++) {
+        backgroundLayer.drawPixel(j, i, g[i][j] ? colorWhite : colorBlack);
+      }
+    }
+    backgroundLayer.swapBuffers();
+  }
+}
+
+void clearDisplay() {
+  backgroundLayer.fillScreen({0,0,0});
+  backgroundLayer.swapBuffers();
 }
diff --git a/src/display.h b/src/display.h
index 803d624..9bfdd38 100644
--- a/src/display.h
+++ b/src/display.h
@@ -5,7 +5,10 @@
     #include <MatrixHardware_ESP32_V0.h>
     #include <SmartMatrix.h>
 
+    extern bool runGame;
+
     void setupDisplay();
     void displayLoop();
+    void clearDisplay();
 
 #endif
diff --git a/src/gameoflife.cpp b/src/gameoflife.cpp
new file mode 100644
index 0000000..acb23ef
--- /dev/null
+++ b/src/gameoflife.cpp
@@ -0,0 +1,68 @@
+#include <Arduino.h>
+#include "display.h"
+#include "gameoflife.h"
+
+// https://github.com/Stavrosfil/game-of-life-esp32
+
+int g[SCREEN_HEIGHT][SCREEN_WIDTH];
+int arrayCopy[SCREEN_HEIGHT][SCREEN_WIDTH];
+
+void setupGameOfLife() {
+    randomSeed(analogRead(34));
+    createRandomMatrix(g);
+    for (int i = 0; i < 10; i++)
+        addGlider(random(SCREEN_HEIGHT), random(SCREEN_WIDTH), g);
+    clearDisplay();
+}
+
+void createRandomMatrix(int (&a)[SCREEN_HEIGHT][SCREEN_WIDTH]) {
+    for (int i = 0; i < SCREEN_HEIGHT; i++) {
+        for (int j = 0; j < SCREEN_WIDTH; j++) {
+            a[i][j] = random(100) < 25 ? 1 : 0;
+        }
+    }
+}
+
+void gameOfLife(int (&a)[SCREEN_HEIGHT][SCREEN_WIDTH]) {
+    for (int i = 0; i < SCREEN_HEIGHT; i++) {
+        for (int j = 0; j < SCREEN_WIDTH; j++) {
+            arrayCopy[i][j] = a[i][j];
+        }
+    }
+
+    for (int i = 0; i < SCREEN_HEIGHT; i++) {
+        for (int j = 0; j < SCREEN_WIDTH; j++) {
+            int total = (a[i][(j - 1) % SCREEN_WIDTH] + a[i][(j + 1) % SCREEN_WIDTH] + a[(i - 1) % SCREEN_HEIGHT][j] +
+                         a[(i + 1) % SCREEN_HEIGHT][j] + a[(i - 1) % SCREEN_HEIGHT][(j - 1) % SCREEN_WIDTH] +
+                         a[(i - 1) % SCREEN_HEIGHT][(j + 1) % SCREEN_WIDTH] +
+                         a[(i + 1) % SCREEN_HEIGHT][(j - 1) % SCREEN_WIDTH] +
+                         a[(i + 1) % SCREEN_HEIGHT][(j + 1) % SCREEN_WIDTH]);
+
+            if (a[i][j] == 1) {
+                if (total < 2 || total > 3) {
+                    arrayCopy[i][j] = 0;
+                }
+            } else if (total == 3) {
+                arrayCopy[i][j] = 1;
+            }
+        }
+    }
+
+    for (int i = 0; i < SCREEN_HEIGHT; i++) {
+        for (int j = 0; j < SCREEN_WIDTH; j++) {
+            a[i][j] = arrayCopy[i][j];
+        }
+    }
+}
+
+void addGlider(int i1, int j1, int (&a)[SCREEN_HEIGHT][SCREEN_WIDTH]) {
+    // 010
+    // 001
+    // 111
+    int glider[3][3] = {{0, 0, 1}, {1, 0, 1}, {0, 1, 1}};
+    for (int i = 0; i < 3; i++) {
+        for (int j = 0; j < 3; j++) {
+            a[i1 + i][j1 + j] = glider[i][j];
+        }
+    }
+}
diff --git a/src/gameoflife.h b/src/gameoflife.h
new file mode 100644
index 0000000..af7a0dd
--- /dev/null
+++ b/src/gameoflife.h
@@ -0,0 +1,17 @@
+#ifndef GAMEOFLIFE_H
+    #define GAMEOFLIFE_H
+
+    #include <Arduino.h>
+
+    #define SCREEN_WIDTH  64
+    #define SCREEN_HEIGHT 64
+
+    extern int g[SCREEN_HEIGHT][SCREEN_WIDTH];
+    extern int arrayCopy[SCREEN_HEIGHT][SCREEN_WIDTH];
+    
+    void setupGameOfLife();
+    void createRandomMatrix(int (&a)[SCREEN_HEIGHT][SCREEN_WIDTH]);
+    void gameOfLife(int (&a)[SCREEN_HEIGHT][SCREEN_WIDTH]);
+    void addGlider(int i1, int j1, int (&a)[SCREEN_HEIGHT][SCREEN_WIDTH]);
+
+#endif
diff --git a/src/main.cpp b/src/main.cpp
index 0478caa..f54fa70 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,15 +1,20 @@
 #include <Arduino.h>
 #include "utils.h"
 #include "network.h"
+#include "gameoflife.h"
 #include "display.h"
 
+bool runGame = true;
+
 void setup() {
   Serial.begin(115200);
   logLine("", true);  
   setupNetwork();
   setupDisplay();
+  setupGameOfLife();
 }
 
 void loop() {
+  networkLoop();
   displayLoop();
 }
diff --git a/src/network.cpp b/src/network.cpp
index ad2a339..1ac9cd0 100644
--- a/src/network.cpp
+++ b/src/network.cpp
@@ -9,7 +9,7 @@ MDNSResponder mdns;
 void setupNetwork() {
     setupWifi();
     setupMDNS();
-    setupWebserver();
+    setupOTA();
 }
 
 void setupWifi() {
@@ -32,12 +32,32 @@ void setupMDNS() {
   }
 }
 
-void setupWebserver() {
-    server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
-        request->send(200, "text/plain", "Hi! I am ESP32.");
-    });
+void setupOTA() {
+  ArduinoOTA.onStart([]() { 
+    runGame = false;
+    logLine("OTA Update Start"); 
+  });
+  ArduinoOTA.onEnd([]() { 
+    logLine("OTA Update End"); 
+    runGame = true;
+  });
+  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
+    char p[32];
+    sprintf(p, "Progress: %u%%\n", (progress/(total/100)));
+    logLine(p, false);
+  });
+  ArduinoOTA.onError([](ota_error_t error) {
+    if(error == OTA_AUTH_ERROR) logLine("OTA Auth Failed");
+    else if(error == OTA_BEGIN_ERROR) logLine("OTA Begin Failed");
+    else if(error == OTA_CONNECT_ERROR) logLine("OTA Connect Failed");
+    else if(error == OTA_RECEIVE_ERROR) logLine("OTA Receive Failed");
+    else if(error == OTA_END_ERROR) logLine("OTA End Failed");
+    runGame = true;
+  });
+  ArduinoOTA.setHostname(HOSTNAME);
+  ArduinoOTA.begin();
+}
 
-    AsyncElegantOTA.begin(&server);
-    server.begin();
-    Serial.println("HTTP server started");
+void networkLoop() {
+  ArduinoOTA.handle();
 }
diff --git a/src/network.h b/src/network.h
index 54c6ffd..a760da4 100644
--- a/src/network.h
+++ b/src/network.h
@@ -2,16 +2,20 @@
     #define NETWORK_H
 
     #include <Arduino.h>
+    #include <ArduinoOTA.h>
     #include <ESPConnect.h>
     #include <Wifi.h>
     #include <ESPmDNS.h>
     #include <AsyncTCP.h>
     #include <ESPAsyncWebServer.h>
-    #include <AsyncElegantOTA.h>
+
+    extern bool runGame;
 
     void setupNetwork();
     void setupMDNS();
     void setupWifi();
     void setupWebserver();
+    void setupOTA();
+    void networkLoop();
 
 #endif
-- 
GitLab