Protocol running.
This commit is contained in:
@@ -114,5 +114,8 @@ String buildConfigJson();
|
||||
bool applyConfigJson(const String &payload, String &errorMessage);
|
||||
void startWebInterface();
|
||||
void handleWebInterface();
|
||||
void Log(const String &message);
|
||||
void Log(const char *message);
|
||||
String buildLogsJson(uint32_t sinceSeq);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
platform = platformio/espressif32
|
||||
board = esp32dev
|
||||
framework = arduino
|
||||
monitor_speed = 115200
|
||||
monitor_speed = 9600
|
||||
upload_speed = 576000
|
||||
upload_port = /dev/ttyUSB*
|
||||
lib_deps =
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
#include "EggDuino.h"
|
||||
#include <ArduinoJson.h>
|
||||
#include <DNSServer.h>
|
||||
|
||||
namespace {
|
||||
const char *kConfigPath = "/config.json";
|
||||
const char *kApSsid = "EggDuino";
|
||||
const uint16_t kDnsPort = 53;
|
||||
const IPAddress kApIp(192, 168, 4, 1);
|
||||
const IPAddress kApSubnet(255, 255, 255, 0);
|
||||
const char *kWifiSsid = "Sternenlabor";
|
||||
const char *kWifiPassword = "!Sternenlabor99!";
|
||||
|
||||
WebServer server(80);
|
||||
DNSServer dnsServer;
|
||||
bool configStoreReady = false;
|
||||
|
||||
ConfigParameter *findParameter(const String &key) {
|
||||
@@ -38,12 +34,14 @@ void handleRoot() {
|
||||
<title>EggDuino Konfiguration</title>
|
||||
<style>
|
||||
body { font-family: "Segoe UI", sans-serif; margin: 20px; background: #f3f6fb; color: #1a1a1a; }
|
||||
main { max-width: 560px; margin: 0 auto; background: #fff; border-radius: 12px; padding: 20px; box-shadow: 0 8px 24px rgba(0,0,0,0.08); }
|
||||
main { max-width: 760px; margin: 0 auto; background: #fff; border-radius: 12px; padding: 20px; box-shadow: 0 8px 24px rgba(0,0,0,0.08); }
|
||||
h1 { margin-top: 0; font-size: 1.35rem; }
|
||||
label { display: block; margin: 14px 0 6px; font-weight: 600; }
|
||||
input[type='number'] { width: 100%; padding: 10px; border: 1px solid #c7d2e5; border-radius: 8px; box-sizing: border-box; }
|
||||
button { margin-top: 18px; border: 0; background: #0b5ed7; color: white; padding: 10px 14px; border-radius: 8px; cursor: pointer; }
|
||||
#status { margin-top: 12px; min-height: 1.2em; }
|
||||
#log { margin-top: 20px; border: 1px solid #d6dfef; border-radius: 8px; background: #0f172a; color: #d2e3ff; padding: 10px; height: 220px; overflow-y: auto; white-space: pre-wrap; font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; font-size: 0.9rem; }
|
||||
#logTitle { margin-top: 24px; margin-bottom: 8px; font-weight: 700; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -52,8 +50,12 @@ button { margin-top: 18px; border: 0; background: #0b5ed7; color: white; padding
|
||||
<form id="cfgForm"></form>
|
||||
<button id="saveBtn" type="button">Speichern</button>
|
||||
<div id="status"></div>
|
||||
<div id="logTitle">Logs</div>
|
||||
<div id="log"></div>
|
||||
</main>
|
||||
<script>
|
||||
let lastSeq = 0;
|
||||
|
||||
async function loadConfig() {
|
||||
const resp = await fetch('/api/config');
|
||||
if (!resp.ok) throw new Error('Konfiguration konnte nicht geladen werden');
|
||||
@@ -93,6 +95,22 @@ async function saveConfig() {
|
||||
status.textContent = 'Gespeichert';
|
||||
}
|
||||
|
||||
async function pollLogs() {
|
||||
const box = document.getElementById('log');
|
||||
const resp = await fetch('/api/logs?since=' + lastSeq);
|
||||
if (!resp.ok) {
|
||||
return;
|
||||
}
|
||||
const payload = await resp.json();
|
||||
(payload.logs || []).forEach(entry => {
|
||||
box.textContent += entry.text + '\n';
|
||||
});
|
||||
if (typeof payload.lastSeq === 'number') {
|
||||
lastSeq = payload.lastSeq;
|
||||
}
|
||||
box.scrollTop = box.scrollHeight;
|
||||
}
|
||||
|
||||
(async function init() {
|
||||
const status = document.getElementById('status');
|
||||
try {
|
||||
@@ -109,6 +127,8 @@ async function saveConfig() {
|
||||
status.textContent = e.message;
|
||||
}
|
||||
});
|
||||
pollLogs();
|
||||
setInterval(pollLogs, 800);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
@@ -118,14 +138,6 @@ async function saveConfig() {
|
||||
server.send(200, "text/html", kPage);
|
||||
}
|
||||
|
||||
void redirectToPortal() {
|
||||
server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
|
||||
server.sendHeader("Pragma", "no-cache");
|
||||
server.sendHeader("Expires", "-1");
|
||||
server.sendHeader("Location", String("http://") + WiFi.softAPIP().toString() + "/", true);
|
||||
server.send(302, "text/plain", "");
|
||||
}
|
||||
|
||||
void handleGetConfig() {
|
||||
if (!configStoreReady && !initConfigStore()) {
|
||||
server.send(500, "text/plain", "Config storage not available");
|
||||
@@ -160,6 +172,14 @@ void handlePostConfig() {
|
||||
// penServo.write(penState);
|
||||
server.send(200, "application/json", buildConfigJson());
|
||||
}
|
||||
|
||||
void handleGetLogs() {
|
||||
uint32_t since = 0;
|
||||
if (server.hasArg("since")) {
|
||||
since = static_cast<uint32_t>(server.arg("since").toInt());
|
||||
}
|
||||
server.send(200, "application/json", buildLogsJson(since));
|
||||
}
|
||||
} // namespace
|
||||
|
||||
ConfigParameter configParameters[] = {
|
||||
@@ -284,28 +304,30 @@ bool applyConfigJson(const String &payload, String &errorMessage) {
|
||||
}
|
||||
|
||||
void startWebInterface() {
|
||||
WiFi.mode(WIFI_AP);
|
||||
WiFi.softAPConfig(kApIp, kApIp, kApSubnet);
|
||||
WiFi.softAP(kApSsid);
|
||||
dnsServer.start(kDnsPort, "*", WiFi.softAPIP());
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.begin(kWifiSsid, kWifiPassword);
|
||||
|
||||
const unsigned long connectStart = millis();
|
||||
const unsigned long connectTimeoutMs = 20000;
|
||||
while (WiFi.status() != WL_CONNECTED && millis() - connectStart < connectTimeoutMs) {
|
||||
delay(250);
|
||||
}
|
||||
|
||||
initConfigStore();
|
||||
Serial.print("Config AP IP: ");
|
||||
Serial.println(WiFi.softAPIP());
|
||||
if (WiFi.status() == WL_CONNECTED) {
|
||||
Serial.println(String("WLAN verbunden, IP: ") + WiFi.localIP().toString());
|
||||
} else {
|
||||
Serial.println("WLAN Verbindung fehlgeschlagen");
|
||||
}
|
||||
|
||||
server.on("/", HTTP_GET, handleRoot);
|
||||
server.on("/api/config", HTTP_GET, handleGetConfig);
|
||||
server.on("/api/config", HTTP_POST, handlePostConfig);
|
||||
server.on("/generate_204", HTTP_GET, redirectToPortal);
|
||||
server.on("/gen_204", HTTP_GET, redirectToPortal);
|
||||
server.on("/hotspot-detect.html", HTTP_GET, redirectToPortal);
|
||||
server.on("/library/test/success.html", HTTP_GET, redirectToPortal);
|
||||
server.on("/ncsi.txt", HTTP_GET, redirectToPortal);
|
||||
server.on("/connecttest.txt", HTTP_GET, redirectToPortal);
|
||||
server.onNotFound(redirectToPortal);
|
||||
server.on("/api/logs", HTTP_GET, handleGetLogs);
|
||||
server.onNotFound(handleRoot);
|
||||
server.begin();
|
||||
}
|
||||
|
||||
void handleWebInterface() {
|
||||
dnsServer.processNextRequest();
|
||||
server.handleClient();
|
||||
}
|
||||
|
||||
@@ -121,6 +121,22 @@ void prepareMove(uint16_t duration, int penStepsEBB, int rotStepsEBB)
|
||||
{
|
||||
motorsOn();
|
||||
}
|
||||
|
||||
if (duration == 0)
|
||||
{
|
||||
duration = 1;
|
||||
}
|
||||
|
||||
if (penStepCorrection == 0)
|
||||
{
|
||||
penStepCorrection = 1;
|
||||
}
|
||||
|
||||
if (rotStepCorrection == 0)
|
||||
{
|
||||
rotStepCorrection = 1;
|
||||
}
|
||||
|
||||
if ((1 == rotStepCorrection) && (1 == penStepCorrection))
|
||||
{ // if coordinatessystems are identical
|
||||
// set Coordinates and Speed
|
||||
@@ -128,11 +144,11 @@ void prepareMove(uint16_t duration, int penStepsEBB, int rotStepsEBB)
|
||||
// rotMotor.setSpeed(abs((float)rotStepsEBB * (float)1000 / (float)duration));
|
||||
g_pStepperRotate->move(rotStepsEBB);
|
||||
g_pStepperRotate->setSpeedInTicks(abs((float)rotStepsEBB * (float)1000 / (float)duration));
|
||||
|
||||
|
||||
// penMotor.move(penStepsEBB);
|
||||
// penMotor.setSpeed(abs((float)penStepsEBB * (float)1000 / (float)duration));
|
||||
g_pStepperPen->move(penStepsEBB);
|
||||
g_pStepperRotate->setSpeedInTicks(abs((float)penStepsEBB * (float)1000 / (float)duration));
|
||||
g_pStepperPen->setSpeedInTicks(abs((float)penStepsEBB * (float)1000 / (float)duration));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -162,12 +178,14 @@ void prepareMove(uint16_t duration, int penStepsEBB, int rotStepsEBB)
|
||||
// penMotor.move(penStepsToGo);
|
||||
// penMotor.setSpeed(penSpeed);
|
||||
g_pStepperPen->move(penStepsToGo);
|
||||
g_pStepperRotate->setSpeedInTicks(penSpeed);
|
||||
g_pStepperPen->setSpeedInTicks(penSpeed);
|
||||
}
|
||||
}
|
||||
|
||||
void moveOneStep()
|
||||
{
|
||||
while (g_pStepperPen->isRunning() || g_pStepperRotate->isRunning())
|
||||
;
|
||||
// if (penMotor.distanceToGo() || rotMotor.distanceToGo())
|
||||
// {
|
||||
// penMotor.runSpeedToPosition(); // Moving.... moving... moving....
|
||||
@@ -177,6 +195,8 @@ void moveOneStep()
|
||||
|
||||
void moveToDestination()
|
||||
{
|
||||
while (g_pStepperPen->isRunning() || g_pStepperRotate->isRunning())
|
||||
;
|
||||
// while (penMotor.distanceToGo() || rotMotor.distanceToGo())
|
||||
// {
|
||||
// penMotor.runSpeedToPosition(); // Moving.... moving... moving....
|
||||
|
||||
86
src/Logging.cpp
Normal file
86
src/Logging.cpp
Normal file
@@ -0,0 +1,86 @@
|
||||
#include "EggDuino.h"
|
||||
|
||||
namespace {
|
||||
constexpr size_t kLogCapacity = 80;
|
||||
constexpr size_t kLogLineLength = 160;
|
||||
|
||||
char g_logLines[kLogCapacity][kLogLineLength];
|
||||
uint32_t g_logSeq[kLogCapacity];
|
||||
size_t g_logWritePos = 0;
|
||||
uint32_t g_nextLogSeq = 1;
|
||||
|
||||
void appendJsonEscaped(String &out, const char *text) {
|
||||
out += "\"";
|
||||
for (size_t i = 0; text[i] != '\0'; ++i) {
|
||||
const char c = text[i];
|
||||
switch (c) {
|
||||
case '\\':
|
||||
out += "\\\\";
|
||||
break;
|
||||
case '"':
|
||||
out += "\\\"";
|
||||
break;
|
||||
case '\n':
|
||||
out += "\\n";
|
||||
break;
|
||||
case '\r':
|
||||
out += "\\r";
|
||||
break;
|
||||
case '\t':
|
||||
out += "\\t";
|
||||
break;
|
||||
default:
|
||||
if (static_cast<unsigned char>(c) < 0x20) {
|
||||
out += '?';
|
||||
} else {
|
||||
out += c;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
out += "\"";
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void Log(const String &message) {
|
||||
const String trimmed = message.substring(0, kLogLineLength - 1);
|
||||
trimmed.toCharArray(g_logLines[g_logWritePos], kLogLineLength);
|
||||
g_logSeq[g_logWritePos] = g_nextLogSeq++;
|
||||
g_logWritePos = (g_logWritePos + 1) % kLogCapacity;
|
||||
}
|
||||
|
||||
void Log(const char *message) {
|
||||
Log(String(message));
|
||||
}
|
||||
|
||||
String buildLogsJson(uint32_t sinceSeq) {
|
||||
String output;
|
||||
output.reserve(2048);
|
||||
output += "{\"logs\":[";
|
||||
uint32_t lastSeq = sinceSeq;
|
||||
bool first = true;
|
||||
|
||||
for (size_t i = 0; i < kLogCapacity; ++i) {
|
||||
const size_t idx = (g_logWritePos + i) % kLogCapacity;
|
||||
const uint32_t seq = g_logSeq[idx];
|
||||
if (seq == 0 || seq <= sinceSeq) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!first) {
|
||||
output += ",";
|
||||
}
|
||||
first = false;
|
||||
output += "{\"seq\":";
|
||||
output += String(seq);
|
||||
output += ",\"text\":";
|
||||
appendJsonEscaped(output, g_logLines[idx]);
|
||||
output += "}";
|
||||
lastSeq = seq;
|
||||
}
|
||||
|
||||
output += "],\"lastSeq\":";
|
||||
output += String(lastSeq);
|
||||
output += "}";
|
||||
return output;
|
||||
}
|
||||
17
src/main.cpp
17
src/main.cpp
@@ -77,10 +77,10 @@ void setup()
|
||||
{
|
||||
Serial.begin(9600);
|
||||
Serial.println("Starting...");
|
||||
Log("Starting...");
|
||||
makeComInterface();
|
||||
initHardware();
|
||||
startWebInterface();
|
||||
|
||||
}
|
||||
|
||||
uint8_t g_uiState = 0;
|
||||
@@ -88,18 +88,18 @@ unsigned long g_uiLastTim = millis();
|
||||
|
||||
void loop()
|
||||
{
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
unsigned long uiNow = millis();
|
||||
motorsOn();
|
||||
|
||||
if (uiNow - g_uiLastTim > 500)
|
||||
if (uiNow - g_uiLastTim > 5000)
|
||||
{
|
||||
g_uiLastTim = uiNow;
|
||||
switch (g_uiState)
|
||||
{
|
||||
case 0:
|
||||
Serial.println(g_uiState);
|
||||
Log(String(g_uiState));
|
||||
g_pStepperRotate->setSpeedInUs(10); // the parameter is us/step !!!
|
||||
g_pStepperRotate->setAcceleration(10000);
|
||||
g_pStepperRotate->move(1000);
|
||||
@@ -107,7 +107,7 @@ void loop()
|
||||
break;
|
||||
|
||||
case 1:
|
||||
Serial.println(g_uiState);
|
||||
Log(String(g_uiState));
|
||||
g_pStepperRotate->setSpeedInUs(10); // the parameter is us/step !!!
|
||||
g_pStepperRotate->setAcceleration(10000);
|
||||
g_pStepperRotate->move(-1000);
|
||||
@@ -115,7 +115,7 @@ void loop()
|
||||
break;
|
||||
|
||||
case 2:
|
||||
Serial.println(g_uiState);
|
||||
Log(String(g_uiState));
|
||||
g_pStepperPen->setSpeedInUs(10); // the parameter is us/step !!!
|
||||
g_pStepperPen->setAcceleration(10000);
|
||||
g_pStepperPen->move(1000);
|
||||
@@ -123,7 +123,7 @@ void loop()
|
||||
break;
|
||||
|
||||
case 3:
|
||||
Serial.println(g_uiState);
|
||||
Log(String(g_uiState));
|
||||
g_pStepperPen->setSpeedInUs(10); // the parameter is us/step !!!
|
||||
g_pStepperPen->setAcceleration(10000);
|
||||
g_pStepperPen->move(-1000);
|
||||
@@ -133,9 +133,10 @@ void loop()
|
||||
default:
|
||||
break;
|
||||
}
|
||||
Log("Alive");
|
||||
}
|
||||
#endif
|
||||
//moveOneStep();
|
||||
// moveOneStep();
|
||||
SCmd.readSerial();
|
||||
handleWebInterface();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user