Start of debug mode serial commands.

Still need to implement data transfer over serial, but at least you can see that Parchment is working on the device side now.
This commit is contained in:
2026-01-29 10:48:57 -06:00
parent c04516c0c8
commit 7350266246
3 changed files with 198 additions and 38 deletions
+125
View File
@@ -0,0 +1,125 @@
#include "SerialDebug.h"
enum State {
IDLE, READING_HEADER, READING_PAYLOAD
};
struct PacketHeader {
uint8_t command;
uint16_t length; // 2 bytes for length per protocol spec
uint8_t checksum;
};
bool debugMode = false;
State currentState = IDLE;
uint8_t rxBuffer[1024];
namespace SerialDebug {
int handleSerialInput() {
static PacketHeader currentHeader;
static uint16_t bytesRead = 0;
// Continue processing if we're in the middle of a packet, even if no bytes available
while (Serial.available() > 0 || currentState == READING_PAYLOAD) {
switch (currentState) {
case IDLE:
if (Serial.read() == 0xAA) {
Serial.println("Got magic byte 0xAA");
currentState = READING_HEADER;
bytesRead = 0;
}
break;
case READING_HEADER:
{
int avail = Serial.available();
if (avail < 4) {
Serial.print("Waiting for header bytes, have ");
Serial.print(avail);
Serial.println("/4");
break;
}
currentHeader.command = Serial.read();
// Read 2 bytes for length (little-endian)
uint8_t lengthLow = Serial.read();
uint8_t lengthHigh = Serial.read();
currentHeader.length = lengthLow | (lengthHigh << 8);
currentHeader.checksum = Serial.read();
Serial.print("Got header: cmd=0x");
Serial.print(currentHeader.command, HEX);
Serial.print(" len=");
Serial.print(currentHeader.length);
Serial.print(" checksum=0x");
Serial.println(currentHeader.checksum, HEX);
currentState = READING_PAYLOAD;
bytesRead = 0;
}
break;
case READING_PAYLOAD:
if (currentHeader.length == 0) {
Serial.println("No payload, processing immediately");
currentState = IDLE;
return processPacket(currentHeader, rxBuffer);
} else if (Serial.available() >= currentHeader.length) {
Serial.print("Reading ");
Serial.print(currentHeader.length);
Serial.println(" bytes of payload");
Serial.readBytes(rxBuffer, currentHeader.length);
currentState = IDLE;
return processPacket(currentHeader, rxBuffer);
} else {
Serial.print("Waiting for payload: have ");
Serial.print(Serial.available());
Serial.print("/");
Serial.println(currentHeader.length);
}
break;
}
}
return -1; // No data processed
}
int processPacket(PacketHeader& header, uint8_t* data) {
switch (header.command) {
case 0x01:
// Handle command 0x01
if (!debugMode) {
return 0x00;
}
break;
case 0x02:
// Handle command 0x02
if (!debugMode) {
return 0x00;
}
break;
case 0x03:
// Handle command 0x03
if (!debugMode) {
return 0x00;
}
break;
case 0x04:
debugMode = true;
Serial.println("DEBUG MODE SET TO TRUE");
return 0x04;
break;
case 0x05:
debugMode = false;
Serial.println("DEBUG MODE SET TO FALSE");
return 0x05;
break;
default:
return 0x00;
break;
}
}
bool getDebugMode() {
return debugMode;
}
} // namespace SerialDebug
+11
View File
@@ -0,0 +1,11 @@
#pragma once
#include <Arduino.h>
struct PacketHeader;
namespace SerialDebug {
int handleSerialInput();
int processPacket(PacketHeader& header, uint8_t* data);
bool getDebugMode();
}
+32 -8
View File
@@ -28,6 +28,7 @@ extern "C" {
#include "lua/bindings/lua_gfx.h" #include "lua/bindings/lua_gfx.h"
#include "lua/require_sd.h" #include "lua/require_sd.h"
#include "lua/bindings/lua_keyboard.h" #include "lua/bindings/lua_keyboard.h"
#include "debug/SerialDebug.h"
// ------------------------------- // -------------------------------
// Build-time configuration knobs // Build-time configuration knobs
@@ -64,6 +65,9 @@ struct LuaHost {
static LuaHost g_host; static LuaHost g_host;
// Sprite for double-buffered debug mode indicator
static LGFX_Sprite debug_sprite(&M5Cardputer.Display);
static void* host_from_lua(lua_State* L) { static void* host_from_lua(lua_State* L) {
// Store LuaHost* in the Lua "extra space" (Lua 5.4 feature). // Store LuaHost* in the Lua "extra space" (Lua 5.4 feature).
void** p = reinterpret_cast<void**>(lua_getextraspace(L)); void** p = reinterpret_cast<void**>(lua_getextraspace(L));
@@ -108,7 +112,7 @@ static bool read_entire_file_from_sd(const String& path, std::unique_ptr<uint8_t
const String normalized = (path.length() && path[0] == '/') ? path : (String("/") + path); const String normalized = (path.length() && path[0] == '/') ? path : (String("/") + path);
File f = SD.open(normalized.c_str(), FILE_READ); File f = SD.open(normalized.c_str(), FILE_READ);
if (!f) { if (!f) {
out_err = "SD.open failed: " + normalized; out_err = "SD.open failed: " + normalized + "\nMake sure your SD card is formatted correctly.";
return false; return false;
} }
@@ -300,17 +304,23 @@ static bool lua_boot_and_load(LuaHost& host, const String& script_path) {
} }
void setup() { void setup() {
Serial.setRxBufferSize(2048);
Serial.begin(115200); Serial.begin(115200);
delay(50); delay(50);
auto cfg = M5.config(); auto cfg = M5.config();
M5Cardputer.begin(cfg); M5Cardputer.begin(cfg);
M5Cardputer.Display.setRotation(1); M5Cardputer.Display.setRotation(1);
// Initialize debug mode sprite (width, height, color depth)
debug_sprite.createSprite(60, 12);
debug_sprite.setTextSize(1);
ui_status("cardstock", "booting..."); ui_status("cardstock", "booting...");
if (!init_sd_card()) { if (!init_sd_card()) {
ui_status("SD init failed", ui_status("SD init failed",
"Define CARDSTOCK_SD_* pins or check wiring"); "Check that the SD card is inserted, and that the system is installed correctly.");
log_line("SD init failed. If you're on Cardputer, define CARDSTOCK_SD_CS/SCK/MISO/MOSI in build_flags."); log_line("SD init failed. If you're on Cardputer, define CARDSTOCK_SD_CS/SCK/MISO/MOSI in build_flags.");
return; return;
} }
@@ -323,12 +333,7 @@ void setup() {
void loop() { void loop() {
M5Cardputer.update(); M5Cardputer.update();
// If SD failed in setup, nothing to do. if (g_host.L) { // If Lua is loaded, run the main loop
if (!g_host.L) {
delay(250);
return;
}
uint32_t now = millis(); uint32_t now = millis();
float dt = (now - g_host.last_ms) / 1000.0f; float dt = (now - g_host.last_ms) / 1000.0f;
g_host.last_ms = now; g_host.last_ms = now;
@@ -365,4 +370,23 @@ void loop() {
delay(1); delay(1);
} }
int serialResult = SerialDebug::handleSerialInput();
if (serialResult == 0x00) {
ui_status("Failed to process serial input", "Unknown command");
delay(1000); // Show error briefly before continuing
} else if (serialResult == 0x04) {
Serial.println("Debug mode ENABLED");
}
if (SerialDebug::getDebugMode()) {
// Draw to sprite buffer first (double-buffering to prevent flicker)
debug_sprite.fillSprite(BLACK);
debug_sprite.setTextColor(WHITE, BLACK);
debug_sprite.drawString("DEV MODE", 5, 2.5);
// Push sprite to display in one operation
debug_sprite.pushSprite(0, 0);
}
}