Skip to content

Commit 2de90a1

Browse files
authored
Add files via upload
1 parent 3531296 commit 2de90a1

2 files changed

Lines changed: 159 additions & 5 deletions

File tree

src/main.cpp

Lines changed: 138 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,22 @@ MyBLECharacteristicCallbacks* charCallbacks = nullptr;
100100

101101
void setup() {
102102
Serial.begin(115200);
103+
delay(100); // Give serial time to initialize
104+
writeSerial("=== FIRMWARE INFO ===");
105+
writeSerial("Firmware Version: " + String(getFirmwareMajor()) + "." + String(getFirmwareMinor()));
106+
// SHA_STRING is already a string literal from the macro, so we can use it directly
107+
const char* shaCStr = SHA_STRING;
108+
String shaStr = String(shaCStr);
109+
// Remove surrounding quotes if present (from stringification when SHA is empty string "")
110+
if (shaStr.length() >= 2 && shaStr.charAt(0) == '"' && shaStr.charAt(shaStr.length() - 1) == '"') {
111+
shaStr = shaStr.substring(1, shaStr.length() - 1);
112+
}
113+
if (shaStr.length() > 0 && shaStr != "\"\"" && shaStr != "") {
114+
writeSerial("Git SHA: " + shaStr);
115+
} else {
116+
writeSerial("Git SHA: (not set)");
117+
}
118+
writeSerial("=====================");
103119
writeSerial("Starting setup...");
104120
writeSerial("Initializing full config...");
105121
full_config_init();
@@ -209,6 +225,24 @@ void initio(){
209225
initSensors();
210226
}
211227

228+
uint8_t getFirmwareMajor(){
229+
String version = String(BUILD_VERSION);
230+
int dotIndex = version.indexOf('.');
231+
if (dotIndex > 0) {
232+
return version.substring(0, dotIndex).toInt();
233+
}
234+
return 0;
235+
}
236+
237+
uint8_t getFirmwareMinor(){
238+
String version = String(BUILD_VERSION);
239+
int dotIndex = version.indexOf('.');
240+
if (dotIndex > 0 && dotIndex < version.length() - 1) {
241+
return version.substring(dotIndex + 1).toInt();
242+
}
243+
return 0;
244+
}
245+
212246
void initDataBuses(){
213247
writeSerial("=== Initializing Data Buses ===");
214248
if(globalConfig.data_bus_count == 0){
@@ -917,6 +951,21 @@ void initDisplay(){
917951
epd.print("Name: OEPL"+ chipId);
918952
epd.setCursor(100, 300);
919953
epd.print("Epaper driver by Larry Bank https://github.com/bitbank2");
954+
epd.setCursor(100, 400);
955+
const char* shaCStr = SHA_STRING;
956+
String shaStr = String(shaCStr);
957+
// Remove surrounding quotes if present (from stringification when SHA is empty string "")
958+
if (shaStr.length() >= 2 && shaStr.charAt(0) == '"' && shaStr.charAt(shaStr.length() - 1) == '"') {
959+
shaStr = shaStr.substring(1, shaStr.length() - 1);
960+
}
961+
if (shaStr.length() == 0 || shaStr == "\"\"" || shaStr == "") {
962+
shaStr = "(not set)";
963+
}
964+
epd.print("Firmware: " + String(getFirmwareMajor()) + "." + String(getFirmwareMinor()) + " SHA: " + shaStr);
965+
if(globalConfig.displays[0].color_scheme == 0){
966+
writeSerial("2 color test");
967+
epd.fillRect(100,320,10,10,BBEP_BLACK);
968+
}
920969
if(globalConfig.displays[0].color_scheme == 4){
921970
writeSerial("6 color test");
922971
epd.fillRect(100,320,10,10,BBEP_RED);
@@ -1080,6 +1129,10 @@ void imageDataWritten(void* conn_hdl, void* chr, uint8_t* data, uint16_t len){
10801129
delay(100);
10811130
reboot();
10821131
break;
1132+
case 0x0043: // Firmware Version command
1133+
writeSerial("=== FIRMWARE VERSION COMMAND (0x0043) ===");
1134+
handleFirmwareVersion();
1135+
break;
10831136
default:
10841137
writeSerial("ERROR: Unknown command: 0x" + String(command, HEX));
10851138
writeSerial("Expected: 0x0011 (read config), 0x0064 (image info), 0x0065 (block data), or 0x0003 (finalize)");
@@ -1951,13 +2004,11 @@ bool decompressImageDataChunked(){
19512004
uint8_t invertedFirstPlane = ~firstPlaneByte;
19522005
uint16_t planeY = thirdPlaneIndex / (imgWidth / 8);
19532006
uint16_t planeX = (thirdPlaneIndex % (imgWidth / 8)) * 8;
1954-
19552007
for (int bit = 7; bit >= 0; bit--) {
19562008
if (planeY < ((imgHeight < displayWidth) ? imgHeight : displayWidth) && planeX + (7-bit) < ((imgWidth < displayHeight) ? imgWidth : displayHeight)) {
19572009
bool plane1 = (invertedFirstPlane >> bit) & 0x01; // B/W base
19582010
bool plane2 = (secondPlaneByte >> bit) & 0x01; // R/Y
19592011
bool plane3 = (byte >> bit) & 0x01; // G/B
1960-
19612012
// Decode 6 colors: BLACK=000, WHITE=100, RED=110, YELLOW=010, GREEN=101, BLUE=001
19622013
if (!plane1 && !plane2 && !plane3) {
19632014
epd.drawPixel(displayWidth - planeY, planeX + (7-bit), BBEP_BLACK);
@@ -1988,13 +2039,10 @@ bool decompressImageDataChunked(){
19882039
writeSerial("ERROR: uzlib data error");
19892040
break;
19902041
}
1991-
19922042
} while (res == TINF_OK && totalDecompressed < originalLength);
19932043
writeSerial("Chunked decompression complete: " + String(totalDecompressed) + " bytes");
19942044
writeSerial("Expected: " + String(originalLength) + " bytes");
19952045
writeSerial("Pixel bytes processed: " + String(pixelBytesProcessed));
1996-
1997-
// Cleanup allocated buffers
19982046
if (firstPlaneBuffer) {
19992047
free(firstPlaneBuffer);
20002048
writeSerial("Freed first plane buffer");
@@ -2252,6 +2300,34 @@ void handleReadConfig(){
22522300
writeSerial("handleReadConfig function completed successfully");
22532301
}
22542302

2303+
void handleFirmwareVersion(){
2304+
writeSerial("Building Firmware Version response...");
2305+
uint8_t major = getFirmwareMajor();
2306+
uint8_t minor = getFirmwareMinor();
2307+
const char* shaCStr = SHA_STRING;
2308+
String shaStr = String(shaCStr);
2309+
// Remove surrounding quotes if present (from stringification when SHA is empty string "")
2310+
if (shaStr.length() >= 2 && shaStr.charAt(0) == '"' && shaStr.charAt(shaStr.length() - 1) == '"') {
2311+
shaStr = shaStr.substring(1, shaStr.length() - 1);
2312+
}
2313+
writeSerial("Firmware version: " + String(major) + "." + String(minor));
2314+
writeSerial("SHA: " + shaStr);
2315+
uint8_t shaLen = shaStr.length();
2316+
if (shaLen > 40) shaLen = 40;
2317+
uint8_t response[2 + 1 + 1 + 1 + 40];
2318+
uint16_t offset = 0;
2319+
response[offset++] = 0x00;
2320+
response[offset++] = 0x43;
2321+
response[offset++] = major;
2322+
response[offset++] = minor;
2323+
response[offset++] = shaLen;
2324+
for (uint8_t i = 0; i < shaLen && i < 40; i++) {
2325+
response[offset++] = shaStr.charAt(i);
2326+
}
2327+
sendResponse(response, offset);
2328+
writeSerial("Firmware version response sent");
2329+
}
2330+
22552331
void handleWriteConfig(uint8_t* data, uint16_t len){
22562332
if (len == 0) {
22572333
writeSerial("ERROR: No config data received");
@@ -2354,6 +2430,11 @@ void handleWriteConfigChunk(uint8_t* data, uint16_t len){
23542430
bool loadGlobalConfig(){
23552431
writeSerial("Loading global configuration...");
23562432
memset(&globalConfig, 0, sizeof(globalConfig));
2433+
// Reset WiFi configuration flag
2434+
wifiConfigured = false;
2435+
wifiSsid[0] = '\0';
2436+
wifiPassword[0] = '\0';
2437+
wifiEncryptionType = 0;
23572438
static uint8_t configData[MAX_CONFIG_SIZE];
23582439
static uint32_t configLen = MAX_CONFIG_SIZE;
23592440
if (!loadConfig(configData, &configLen)) {
@@ -2496,6 +2577,58 @@ bool loadGlobalConfig(){
24962577
return false;
24972578
}
24982579
break;
2580+
case 0x26: // wifi_config
2581+
{
2582+
const uint16_t WIFI_CONFIG_SIZE = 162; // 32 (SSID) + 32 (password) + 1 (encryption) + 95 (reserved)
2583+
if (offset + WIFI_CONFIG_SIZE <= configLen) {
2584+
// Parse SSID (32 bytes, null-terminated)
2585+
memcpy(wifiSsid, &configData[offset], 32);
2586+
wifiSsid[32] = '\0'; // Ensure null termination
2587+
// Find actual string length (up to first null byte)
2588+
uint8_t ssidLen = 0;
2589+
while (ssidLen < 32 && wifiSsid[ssidLen] != '\0') ssidLen++;
2590+
offset += 32;
2591+
2592+
// Parse password (32 bytes, null-terminated)
2593+
memcpy(wifiPassword, &configData[offset], 32);
2594+
wifiPassword[32] = '\0'; // Ensure null termination
2595+
// Find actual string length (up to first null byte)
2596+
uint8_t passwordLen = 0;
2597+
while (passwordLen < 32 && wifiPassword[passwordLen] != '\0') passwordLen++;
2598+
offset += 32;
2599+
2600+
// Parse encryption type (1 byte)
2601+
wifiEncryptionType = configData[offset++];
2602+
2603+
// Skip reserved bytes (95 bytes)
2604+
offset += 95;
2605+
2606+
// Mark WiFi as configured
2607+
wifiConfigured = true;
2608+
2609+
// Print WiFi config to console
2610+
writeSerial("=== WiFi Configuration Loaded ===");
2611+
writeSerial("SSID: \"" + String(wifiSsid) + "\"");
2612+
writeSerial("Password: " + String(passwordLen > 0 ? "***" : "(empty)"));
2613+
String encTypeStr = "Unknown";
2614+
switch(wifiEncryptionType) {
2615+
case 0x00: encTypeStr = "None (Open)"; break;
2616+
case 0x01: encTypeStr = "WEP"; break;
2617+
case 0x02: encTypeStr = "WPA"; break;
2618+
case 0x03: encTypeStr = "WPA2"; break;
2619+
case 0x04: encTypeStr = "WPA3"; break;
2620+
}
2621+
writeSerial("Encryption Type: 0x" + String(wifiEncryptionType, HEX) + " (" + encTypeStr + ")");
2622+
writeSerial("SSID length: " + String(ssidLen) + " bytes");
2623+
writeSerial("Password length: " + String(passwordLen) + " bytes");
2624+
writeSerial("WiFi configured: true");
2625+
} else {
2626+
writeSerial("ERROR: Not enough data for wifi_config");
2627+
globalConfig.loaded = false;
2628+
return false;
2629+
}
2630+
}
2631+
break;
24992632
default:
25002633
writeSerial("WARNING: Unknown packet ID 0x" + String(packetId, HEX) + ", skipping");
25012634
// Skip unknown packet - we can't determine its size, so we'll stop parsing

src/main.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,18 @@
33
#include "uzlib.h"
44
#include <bb_epaper.h>
55

6+
// Firmware version - parsed from BUILD_VERSION at compile time
7+
#ifndef BUILD_VERSION
8+
#define BUILD_VERSION "0.0"
9+
#endif
10+
#ifndef SHA
11+
#define SHA ""
12+
#endif
13+
// Helper macros to properly stringify SHA (handles both quoted and unquoted defines)
14+
#define STRINGIFY(x) #x
15+
#define XSTRINGIFY(x) STRINGIFY(x)
16+
#define SHA_STRING XSTRINGIFY(SHA)
17+
618
#ifdef TARGET_NRF
719
#include <Adafruit_LittleFS.h>
820
#include <InternalFileSystem.h>
@@ -82,6 +94,12 @@ uint8_t dictionaryBuffer[MAX_DICT_SIZE];
8294
uint8_t headerBuffer[6];
8395
uint8_t bleResponseBuffer[94];
8496

97+
// WiFi configuration (from packet 0x26)
98+
char wifiSsid[33] = {0}; // 32 bytes + null terminator
99+
char wifiPassword[33] = {0}; // 32 bytes + null terminator
100+
uint8_t wifiEncryptionType = 0; // 0x00=none, 0x01=WEP, 0x02=WPA, 0x03=WPA2, 0x04=WPA3
101+
bool wifiConfigured = false; // True if WiFi config packet (0x26) was received and parsed
102+
85103
bool waitforrefresh(int timeout);
86104
void pwrmgm(bool onoff);
87105
void writeSerial(String message, bool newLine = true);
@@ -126,6 +144,7 @@ uint32_t calculateConfigCRC(uint8_t* data, uint32_t len);
126144
void handleReadConfig();
127145
void handleWriteConfig(uint8_t* data, uint16_t len);
128146
void handleWriteConfigChunk(uint8_t* data, uint16_t len);
147+
void handleFirmwareVersion();
129148
void printConfigSummary();
130149
void reboot();
131150
bool loadGlobalConfig();
@@ -145,6 +164,8 @@ struct BinaryInputs* getBinaryInput(uint8_t index);
145164
uint8_t getBinaryInputCount();
146165
void printConfigSummary();
147166
int mapEpd(int id);
167+
uint8_t getFirmwareMajor();
168+
uint8_t getFirmwareMinor();
148169

149170
typedef struct {
150171
bool active;

0 commit comments

Comments
 (0)