diff --git a/firmware/lib/cw-cf-0x01 b/firmware/lib/cw-cf-0x01
new file mode 160000
index 0000000..a56389f
--- /dev/null
+++ b/firmware/lib/cw-cf-0x01
@@ -0,0 +1 @@
+Subproject commit a56389f4efb2fb1c531e17ef8a2fde382a32c9a0
diff --git a/firmware/lib/cw-commons/CWPreferences.h b/firmware/lib/cw-commons/CWPreferences.h
index 6a464ff..e085ebc 100644
--- a/firmware/lib/cw-commons/CWPreferences.h
+++ b/firmware/lib/cw-commons/CWPreferences.h
@@ -13,6 +13,7 @@ struct ClockwiseParams
const char* const PREF_SWAP_BLUE_GREEN = "swapBlueGreen";
const char* const PREF_USE_24H_FORMAT = "use24hFormat";
+ const char* const CHAIN = "chain";
const char* const PREF_DISPLAY_BRIGHT = "displayBright";
const char* const PREF_DISPLAY_ABC_MIN = "autoBrightMin";
const char* const PREF_DISPLAY_ABC_MAX = "autoBrightMax";
@@ -28,6 +29,7 @@ struct ClockwiseParams
bool swapBlueGreen;
bool use24hFormat;
+ bool chain;
uint8_t displayBright;
uint16_t autoBrightMin;
uint16_t autoBrightMax;
@@ -57,6 +59,7 @@ struct ClockwiseParams
{
preferences.putBool(PREF_SWAP_BLUE_GREEN, swapBlueGreen);
preferences.putBool(PREF_USE_24H_FORMAT, use24hFormat);
+ preferences.putBool(CHAIN, chain);
preferences.putUInt(PREF_DISPLAY_BRIGHT, displayBright);
preferences.putUInt(PREF_DISPLAY_ABC_MIN, autoBrightMin);
preferences.putUInt(PREF_DISPLAY_ABC_MAX, autoBrightMax);
@@ -75,6 +78,7 @@ struct ClockwiseParams
{
swapBlueGreen = preferences.getBool(PREF_SWAP_BLUE_GREEN, false);
use24hFormat = preferences.getBool(PREF_USE_24H_FORMAT, true);
+ chain = preferences.getBool(CHAIN, false);
displayBright = preferences.getUInt(PREF_DISPLAY_BRIGHT, 32);
autoBrightMin = preferences.getUInt(PREF_DISPLAY_ABC_MIN, 0);
autoBrightMax = preferences.getUInt(PREF_DISPLAY_ABC_MAX, 0);
diff --git a/firmware/lib/cw-commons/CWWebServer.h b/firmware/lib/cw-commons/CWWebServer.h
index 8eebdee..555804f 100644
--- a/firmware/lib/cw-commons/CWWebServer.h
+++ b/firmware/lib/cw-commons/CWWebServer.h
@@ -17,7 +17,7 @@ struct ClockwiseWebServer
bool force_restart;
const char* HEADER_TEMPLATE_D = "X-%s: %d\r\n";
const char* HEADER_TEMPLATE_S = "X-%s: %s\r\n";
-
+
static ClockwiseWebServer *getInstance()
{
static ClockwiseWebServer base;
@@ -40,7 +40,6 @@ struct ClockwiseWebServer
if (force_restart)
StatusController::getInstance()->forceRestart();
-
WiFiClient client = server.available();
if (client)
{
@@ -83,49 +82,88 @@ struct ClockwiseWebServer
void processRequest(WiFiClient client, String method, String path, String key, String value)
{
- if (method == "GET" && path == "/") {
+ if (method == "GET" && path == "/")
+ {
client.println("HTTP/1.0 200 OK");
client.println("Content-Type: text/html");
client.println();
client.println(SETTINGS_PAGE);
- } else if (method == "GET" && path == "/get") {
+ }
+ else if (method == "GET" && path == "/get")
+ {
getCurrentSettings(client);
- } else if (method == "GET" && path == "/read") {
- if (key == "pin") {
+ }
+ else if (method == "GET" && path == "/read")
+ {
+ if (key == "pin")
+ {
readPin(client, key, value.toInt());
}
- } else if (method == "POST" && path == "/restart") {
+ }
+ else if (method == "POST" && path == "/restart")
+ {
client.println("HTTP/1.0 204 No Content");
force_restart = true;
- } else if (method == "POST" && path == "/set") {
+ }
+ else if (method == "POST" && path == "/set")
+ {
ClockwiseParams::getInstance()->load();
- //a baby seal has died due this ifs
- if (key == ClockwiseParams::getInstance()->PREF_DISPLAY_BRIGHT) {
+ // a baby seal has died due this ifs
+ if (key == ClockwiseParams::getInstance()->PREF_DISPLAY_BRIGHT)
+ {
ClockwiseParams::getInstance()->displayBright = value.toInt();
- } else if (key == ClockwiseParams::getInstance()->PREF_WIFI_SSID) {
+ }
+ else if (key == ClockwiseParams::getInstance()->PREF_WIFI_SSID)
+ {
ClockwiseParams::getInstance()->wifiSsid = value;
- } else if (key == ClockwiseParams::getInstance()->PREF_WIFI_PASSWORD) {
+ }
+ else if (key == ClockwiseParams::getInstance()->PREF_WIFI_PASSWORD)
+ {
ClockwiseParams::getInstance()->wifiPwd = value;
- } else if (key == "autoBright") { //autoBright=0010,0800
- ClockwiseParams::getInstance()->autoBrightMin = value.substring(0,4).toInt();
- ClockwiseParams::getInstance()->autoBrightMax = value.substring(5,9).toInt();
- } else if (key == ClockwiseParams::getInstance()->PREF_SWAP_BLUE_GREEN) {
+ }
+ else if (key == "autoBright")
+ { // autoBright=0010,0800
+ ClockwiseParams::getInstance()->autoBrightMin = value.substring(0, 4).toInt();
+ ClockwiseParams::getInstance()->autoBrightMax = value.substring(5, 9).toInt();
+ }
+ else if (key == ClockwiseParams::getInstance()->PREF_SWAP_BLUE_GREEN)
+ {
ClockwiseParams::getInstance()->swapBlueGreen = (value == "1");
- } else if (key == ClockwiseParams::getInstance()->PREF_USE_24H_FORMAT) {
+ }
+ else if (key == ClockwiseParams::getInstance()->PREF_USE_24H_FORMAT)
+ {
ClockwiseParams::getInstance()->use24hFormat = (value == "1");
- } else if (key == ClockwiseParams::getInstance()->PREF_LDR_PIN) {
+ }
+ else if (key == ClockwiseParams::getInstance()->CHAIN)
+ {
+ ClockwiseParams::getInstance()->chain = (value == "1");
+ }
+ else if (key == ClockwiseParams::getInstance()->PREF_LDR_PIN)
+ {
ClockwiseParams::getInstance()->ldrPin = value.toInt();
- } else if (key == ClockwiseParams::getInstance()->PREF_TIME_ZONE) {
+ }
+ else if (key == ClockwiseParams::getInstance()->PREF_TIME_ZONE)
+ {
ClockwiseParams::getInstance()->timeZone = value;
- } else if (key == ClockwiseParams::getInstance()->PREF_NTP_SERVER) {
+ }
+ else if (key == ClockwiseParams::getInstance()->PREF_NTP_SERVER)
+ {
ClockwiseParams::getInstance()->ntpServer = value;
- } else if (key == ClockwiseParams::getInstance()->PREF_CANVAS_FILE) {
+ }
+ else if (key == ClockwiseParams::getInstance()->PREF_CANVAS_FILE)
+ {
ClockwiseParams::getInstance()->canvasFile = value;
- } else if (key == ClockwiseParams::getInstance()->PREF_CANVAS_SERVER) {
+ }
+ else if (key == ClockwiseParams::getInstance()->PREF_CANVAS_SERVER)
+ {
ClockwiseParams::getInstance()->canvasServer = value;
- } else if (key == ClockwiseParams::getInstance()->PREF_MANUAL_POSIX) {
+ }
+ else if (key == ClockwiseParams::getInstance()->PREF_MANUAL_POSIX)
+ {
ClockwiseParams::getInstance()->manualPosix = value;
- } else if (key == ClockwiseParams::getInstance()->PREF_DISPLAY_ROTATION) {
+ }
+ else if (key == ClockwiseParams::getInstance()->PREF_DISPLAY_ROTATION)
+ {
ClockwiseParams::getInstance()->displayRotation = value.toInt();
}
ClockwiseParams::getInstance()->save();
@@ -133,19 +171,18 @@ struct ClockwiseWebServer
}
}
-
-
- void readPin(WiFiClient client, String key, uint16_t pin) {
+ void readPin(WiFiClient client, String key, uint16_t pin)
+ {
ClockwiseParams::getInstance()->load();
client.println("HTTP/1.0 204 No Content");
client.printf(HEADER_TEMPLATE_D, key, analogRead(pin));
-
+
client.println();
}
-
- void getCurrentSettings(WiFiClient client) {
+ void getCurrentSettings(WiFiClient client)
+ {
ClockwiseParams::getInstance()->load();
client.println("HTTP/1.0 204 No Content");
@@ -155,7 +192,8 @@ struct ClockwiseWebServer
client.printf(HEADER_TEMPLATE_D, ClockwiseParams::getInstance()->PREF_DISPLAY_ABC_MAX, ClockwiseParams::getInstance()->autoBrightMax);
client.printf(HEADER_TEMPLATE_D, ClockwiseParams::getInstance()->PREF_SWAP_BLUE_GREEN, ClockwiseParams::getInstance()->swapBlueGreen);
client.printf(HEADER_TEMPLATE_D, ClockwiseParams::getInstance()->PREF_USE_24H_FORMAT, ClockwiseParams::getInstance()->use24hFormat);
- client.printf(HEADER_TEMPLATE_D, ClockwiseParams::getInstance()->PREF_LDR_PIN, ClockwiseParams::getInstance()->ldrPin);
+ client.printf(HEADER_TEMPLATE_D, ClockwiseParams::getInstance()->CHAIN, ClockwiseParams::getInstance()->chain);
+ client.printf(HEADER_TEMPLATE_D, ClockwiseParams::getInstance()->PREF_LDR_PIN, ClockwiseParams::getInstance()->ldrPin);
client.printf(HEADER_TEMPLATE_S, ClockwiseParams::getInstance()->PREF_TIME_ZONE, ClockwiseParams::getInstance()->timeZone.c_str());
client.printf(HEADER_TEMPLATE_S, ClockwiseParams::getInstance()->PREF_WIFI_SSID, ClockwiseParams::getInstance()->wifiSsid.c_str());
client.printf(HEADER_TEMPLATE_S, ClockwiseParams::getInstance()->PREF_NTP_SERVER, ClockwiseParams::getInstance()->ntpServer.c_str());
@@ -169,5 +207,4 @@ struct ClockwiseWebServer
client.printf(HEADER_TEMPLATE_S, "CLOCKFACE_NAME", CLOCKFACE_NAME);
client.println();
}
-
};
diff --git a/firmware/lib/cw-commons/SettingsWebPage.h b/firmware/lib/cw-commons/SettingsWebPage.h
index 7a42c3f..3e73d92 100644
--- a/firmware/lib/cw-commons/SettingsWebPage.h
+++ b/firmware/lib/cw-commons/SettingsWebPage.h
@@ -69,6 +69,14 @@ const char SETTINGS_PAGE[] PROGMEM = R""""(
save: "updatePreference('use24hFormat', Number(use24h.checked))",
property: "use24hFormat"
},
+ {
+ title: "Chain 64x32 panels",
+ description: "Use two 64x32 LED Panels instead of one single 64x64",
+ formInput: "",
+ icon: "fa-clock-o",
+ save: "updatePreference('chain', Number(chain.checked))",
+ property: "chain"
+ },
{
title: "Swap Blue/Green pins?",
description: "Swap Blue and Green pins because the panel is RBG instead of RGB",
@@ -229,7 +237,7 @@ const char SETTINGS_PAGE[] PROGMEM = R""""(
}
//Local
- //createCards({ "displayBright": 30, "swapBlueGreen": 1, "use24hFormat": 0, "timeZone": "Europe/Lisbon", "ntpServer": "pool.ntp.org", "wifiSsid": "test", "autoBrightMin":0, "autoBrightMax":800, "ldrPin":35, "cw_fw_version":"1.2.2", "clockface_name":"cw-cf-0x07", "canvasServer":"raw.githubusercontent.com", "canvasFile":"star-wars.json" });
+ //createCards({ "displayBright": 30, "swapBlueGreen": 1, "use24hFormat": 0, , "chain" : 0, "timeZone": "Europe/Lisbon", "ntpServer": "pool.ntp.org", "wifiSsid": "test", "autoBrightMin":0, "autoBrightMax":800, "ldrPin":35, "cw_fw_version":"1.2.2", "clockface_name":"cw-cf-0x07", "canvasServer":"raw.githubusercontent.com", "canvasFile":"star-wars.json" });
//Embedded
begin();
diff --git a/firmware/src/main.cpp b/firmware/src/main.cpp
index 61ca80d..a64ffc3 100644
--- a/firmware/src/main.cpp
+++ b/firmware/src/main.cpp
@@ -1,5 +1,5 @@
#include
-#include
+#include
// Clockface
#include
@@ -15,7 +15,22 @@
#define ESP32_LED_BUILTIN 2
+// Single 64x64 LED panel use case
+#define PANEL_RES_X 64
+#define PANEL_RES_Y 64
+#define NUM_COLS 1
+#define NUM_ROWS 1
+
+// Chained 64x32 panels use case
+// #define CHAINED_PANEL_RES_X 64
+#define CHAINED_PANEL_RES_Y 32
+#define CHAINED_NUM_ROWS 2
+// #define CHAINED_NUM_COLS 1
+
+#define VIRTUAL_MATRIX_CHAIN_TYPE CHAIN_BOTTOM_LEFT_UP
+
MatrixPanel_I2S_DMA *dma_display = nullptr;
+VirtualMatrixPanel *virtualDisp = nullptr;
Clockface *clockface;
@@ -28,7 +43,11 @@ uint8_t currentBrightSlot = -1;
void displaySetup(bool swapBlueGreen, uint8_t displayBright, uint8_t displayRotation)
{
- HUB75_I2S_CFG mxconfig(64, 64, 1);
+ HUB75_I2S_CFG mxconfig(
+ PANEL_RES_X,
+ ClockwiseParams::getInstance()->chain ? CHAINED_PANEL_RES_Y : PANEL_RES_Y,
+ ClockwiseParams::getInstance()->chain ? (CHAINED_NUM_ROWS * NUM_COLS) : (NUM_ROWS * NUM_COLS)
+ );
if (swapBlueGreen)
{
@@ -46,8 +65,10 @@ void displaySetup(bool swapBlueGreen, uint8_t displayBright, uint8_t displayRota
dma_display = new MatrixPanel_I2S_DMA(mxconfig);
dma_display->begin();
dma_display->setBrightness8(displayBright);
- dma_display->clearScreen();
- dma_display->setRotation(displayRotation);
+
+ virtualDisp = new VirtualMatrixPanel((*dma_display), NUM_ROWS, NUM_COLS, PANEL_RES_X, PANEL_RES_Y, VIRTUAL_MATRIX_CHAIN_TYPE);
+ virtualDisp->clearScreen();
+ virtualDisp->setRotation(displayRotation);
}
void automaticBrightControl()
@@ -90,7 +111,7 @@ void setup()
pinMode(ClockwiseParams::getInstance()->ldrPin, INPUT);
displaySetup(ClockwiseParams::getInstance()->swapBlueGreen, ClockwiseParams::getInstance()->displayBright, ClockwiseParams::getInstance()->displayRotation);
- clockface = new Clockface(dma_display);
+ clockface = new Clockface(virtualDisp);
autoBrightEnabled = (ClockwiseParams::getInstance()->autoBrightMax > 0);