From 8cb880328e8e166f8257f892867d1b94ab767834 Mon Sep 17 00:00:00 2001 From: HRS Date: Tue, 10 Feb 2026 21:43:22 +0100 Subject: [PATCH 1/2] Fix wrong end of frame marker --- src/SlvCtrlArduinoSerialCommandsTransport.h | 8 ++--- src/SlvCtrlProtocol.h | 37 ++++++++++++--------- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/src/SlvCtrlArduinoSerialCommandsTransport.h b/src/SlvCtrlArduinoSerialCommandsTransport.h index 807bfc4..515bd77 100644 --- a/src/SlvCtrlArduinoSerialCommandsTransport.h +++ b/src/SlvCtrlArduinoSerialCommandsTransport.h @@ -14,6 +14,10 @@ class SlvCtrlArduinoOut final : public ISlvCtrlOut { s_.print(s ? s : ""); } + void print(char v) override { + s_.print(v); + } + void print(int32_t v) override { // Arduino Print uses long for signed integers s_.print((long)v); @@ -32,10 +36,6 @@ class SlvCtrlArduinoOut final : public ISlvCtrlOut { s_.print(v); } - void println(const char* s = "") override { - s_.println(s ? s : ""); - } - private: Stream& s_; }; diff --git a/src/SlvCtrlProtocol.h b/src/SlvCtrlProtocol.h index 80a5d2c..b495833 100644 --- a/src/SlvCtrlProtocol.h +++ b/src/SlvCtrlProtocol.h @@ -52,11 +52,11 @@ struct ISlvCtrlTransport { struct ISlvCtrlOut { virtual ~ISlvCtrlOut() = default; virtual void print(const char* s) = 0; + virtual void print(char c) = 0; virtual void print(uint32_t v) = 0; virtual void print(int32_t v) = 0; virtual void print(float v, uint8_t decimals = 3) = 0; virtual void print(bool v) = 0; - virtual void println(const char* s = "") = 0; }; // ---- Command context abstraction (no SerialCommands) ---- @@ -271,6 +271,7 @@ class StrAttribute : public BaseAttribute { class SlvCtrlProtocol { public: static constexpr uint32_t protocolVersion = 10000; + static constexpr const char ETX = '\n'; template SlvCtrlProtocol(const char* deviceType, uint32_t fwVersion, IAttribute* (&attrs)[N]) @@ -287,7 +288,8 @@ class SlvCtrlProtocol { o.print(fwVersion_); o.print(",protocol:"); o.print(protocolVersion); - o.println(";status:ok"); + o.print(";status:ok"); + o.print(ETX); } void cmdAttributes(ISlvCtrlCmdCtx& ctx) { @@ -307,7 +309,7 @@ class SlvCtrlProtocol { a->describe(o); } o.print(";status:ok"); - o.println(); + o.print(ETX); } void cmdStatus(ISlvCtrlCmdCtx& ctx) { @@ -327,23 +329,24 @@ class SlvCtrlProtocol { a->writeValue(o); } o.print(";status:ok"); - o.println(); + o.print(ETX); } void cmdGet(ISlvCtrlCmdCtx& ctx) { auto& o = ctx.out(); const char* name = ctx.next(); - if (!name) { o.println("get;;status:error,reason:missing_attribute_name_arg"); return; } + if (!name) { o.print("get;;status:error,reason:missing_attribute_name_arg"); o.print(ETX); return; } IAttribute* a = findAttr(name); - if (!a) { o.print("get "); o.print(name); o.println(";;status:error,reason:unknown_attribute"); return; } - if (!canRead(a->access())) { o.print("get "); o.print(name); o.println(";;status:error,reason:write_only_attribute"); return; } + if (!a) { o.print("get "); o.print(name); o.print(";;status:error,reason:unknown_attribute"); o.print(ETX); return; } + if (!canRead(a->access())) { o.print("get "); o.print(name); o.print(";;status:error,reason:write_only_attribute"); o.print(ETX); return; } o.print("get "); o.print(a->name()); o.print(";value:"); a->writeValue(o); - o.println(";status:ok"); + o.print(";status:ok"); + o.print(ETX); } void cmdSet(ISlvCtrlCmdCtx& ctx) { @@ -352,20 +355,22 @@ class SlvCtrlProtocol { const char* value = ctx.next(); if (!name) { - o.println("set;;status:error,reason:attribute_name_missing"); + o.print("set;;status:error,reason:attribute_name_missing"); + o.print(ETX); return; } if (!value) { o.print("set "); o.print(name); - o.println(";;status:error,reason:attribute_value_missing"); + o.print(";;status:error,reason:attribute_value_missing"); + o.print(ETX); return; } IAttribute* a = findAttr(name); - if (!a) { o.print("set "); o.print(name); o.println(";;status:error,reason:unknown_attribute"); return; } - if (!canWrite(a->access())) { o.print("set "); o.print(name); o.println(";;status:error,reason:read_only_attribute"); return; } + if (!a) { o.print("set "); o.print(name); o.print(";;status:error,reason:unknown_attribute"); o.print(ETX); return; } + if (!canWrite(a->access())) { o.print("set "); o.print(name); o.print(";;status:error,reason:read_only_attribute"); o.print(ETX); return; } SlvCtrlParseError err = a->setFromCString(value); @@ -376,18 +381,20 @@ class SlvCtrlProtocol { o.print(";;"); if (err == SlvCtrlParseError::Ok) { - o.println("status:ok"); + o.print("status:ok"); } else { o.print("status:error,reason:"); - o.println(slvCtrlParseErrorToString(err)); + o.print(slvCtrlParseErrorToString(err)); } + + o.print(ETX); } void cmdUnrecognized(ISlvCtrlCmdCtx& ctx, const char* cmd) { auto& o = ctx.out(); o.print(cmd ? cmd : ""); o.print(";;status:error,reason:unknown_command"); - o.println(); + o.print(ETX); } private: From 5d73c45c8146ce9c4d2f28b7cd367f5ce0aa1296 Mon Sep 17 00:00:00 2001 From: HRS Date: Tue, 10 Feb 2026 21:49:28 +0100 Subject: [PATCH 2/2] Rename print to send --- src/SlvCtrlArduinoSerialCommandsTransport.h | 12 +- src/SlvCtrlProtocol.h | 148 ++++++++++---------- 2 files changed, 80 insertions(+), 80 deletions(-) diff --git a/src/SlvCtrlArduinoSerialCommandsTransport.h b/src/SlvCtrlArduinoSerialCommandsTransport.h index 515bd77..e88b5c5 100644 --- a/src/SlvCtrlArduinoSerialCommandsTransport.h +++ b/src/SlvCtrlArduinoSerialCommandsTransport.h @@ -10,29 +10,29 @@ class SlvCtrlArduinoOut final : public ISlvCtrlOut { public: explicit SlvCtrlArduinoOut(Stream& s) : s_(s) {} - void print(const char* s) override { + void send(const char* s) override { s_.print(s ? s : ""); } - void print(char v) override { + void send(char v) override { s_.print(v); } - void print(int32_t v) override { + void send(int32_t v) override { // Arduino Print uses long for signed integers s_.print((long)v); } - void print(uint32_t v) override { + void send(uint32_t v) override { // Arduino Print uses unsigned long for unsigned integers s_.print((unsigned long)v); } - void print(float v, uint8_t decimals = 3) override { + void send(float v, uint8_t decimals = 3) override { s_.print(v, decimals); } - void print(bool v) override { + void send(bool v) override { s_.print(v); } diff --git a/src/SlvCtrlProtocol.h b/src/SlvCtrlProtocol.h index b495833..b68db36 100644 --- a/src/SlvCtrlProtocol.h +++ b/src/SlvCtrlProtocol.h @@ -51,12 +51,12 @@ struct ISlvCtrlTransport { // ---- Output abstraction (no Stream) ---- struct ISlvCtrlOut { virtual ~ISlvCtrlOut() = default; - virtual void print(const char* s) = 0; - virtual void print(char c) = 0; - virtual void print(uint32_t v) = 0; - virtual void print(int32_t v) = 0; - virtual void print(float v, uint8_t decimals = 3) = 0; - virtual void print(bool v) = 0; + virtual void send(const char* s) = 0; + virtual void send(char c) = 0; + virtual void send(uint32_t v) = 0; + virtual void send(int32_t v) = 0; + virtual void send(float v, uint8_t decimals = 3) = 0; + virtual void send(bool v) = 0; }; // ---- Command context abstraction (no SerialCommands) ---- @@ -107,7 +107,7 @@ class BaseAttribute : public IAttribute { } void writeValue(ISlvCtrlOut& out) const override { - out.print(this->getValue()); + out.send(this->getValue()); } private: @@ -132,8 +132,8 @@ class IntAttribute : public BaseAttribute { } void describe(ISlvCtrlOut& out) const override { - out.print(slvCtrlAccessToString(access())); - out.print("[int]"); + out.send(slvCtrlAccessToString(access())); + out.send("[int]"); } }; @@ -151,8 +151,8 @@ class FloatAttribute : public BaseAttribute { } void describe(ISlvCtrlOut& out) const override { - out.print(slvCtrlAccessToString(access())); - out.print("[float]"); + out.send(slvCtrlAccessToString(access())); + out.send("[float]"); } }; @@ -169,12 +169,12 @@ class BoolAttribute : public BaseAttribute { } void describe(ISlvCtrlOut& out) const override { - out.print(slvCtrlAccessToString(access())); - out.print("[bool]"); + out.send(slvCtrlAccessToString(access())); + out.send("[bool]"); } void writeValue(ISlvCtrlOut& out) const override { - out.print(this->getValue() ? "true" : "false"); + out.send(this->getValue() ? "true" : "false"); } }; @@ -216,21 +216,21 @@ class RangeAttribute : public BaseAttribute { } void describe(ISlvCtrlOut& out) const override { - out.print(slvCtrlAccessToString(this->access())); - out.print("["); + out.send(slvCtrlAccessToString(this->access())); + out.send("["); if constexpr (std::is_same_v) { - out.print("int("); + out.send("int("); } else if constexpr (std::is_same_v) { - out.print("float("); + out.send("float("); } else { - out.print("?("); + out.send("?("); } - out.print(min_); - out.print(".."); - out.print(max_); - out.print(")]"); + out.send(min_); + out.send(".."); + out.send(max_); + out.send(")]"); } private: @@ -249,13 +249,13 @@ class StrAttribute : public BaseAttribute { } void describe(ISlvCtrlOut& out) const override { - out.print(slvCtrlAccessToString(access())); - out.print("[str]"); + out.send(slvCtrlAccessToString(access())); + out.send("[str]"); } void writeValue(ISlvCtrlOut& out) const override { const char* s = this->getValue(); - out.print(s ? s : ""); + out.send(s ? s : ""); } }; @@ -282,71 +282,71 @@ class SlvCtrlProtocol { void cmdIntroduce(ISlvCtrlCmdCtx& ctx) { auto& o = ctx.out(); - o.print("introduce;type:"); - o.print(deviceType_); - o.print(",fw:"); - o.print(fwVersion_); - o.print(",protocol:"); - o.print(protocolVersion); - o.print(";status:ok"); - o.print(ETX); + o.send("introduce;type:"); + o.send(deviceType_); + o.send(",fw:"); + o.send(fwVersion_); + o.send(",protocol:"); + o.send(protocolVersion); + o.send(";status:ok"); + o.send(ETX); } void cmdAttributes(ISlvCtrlCmdCtx& ctx) { auto& o = ctx.out(); - o.print("attributes;"); + o.send("attributes;"); bool first = true; for (size_t i = 0; i < attrCount_; ++i) { IAttribute* a = attrs_[i]; if (!a) continue; - if (!first) o.print(","); + if (!first) o.send(","); first = false; - o.print(a->name()); - o.print(":"); + o.send(a->name()); + o.send(":"); a->describe(o); } - o.print(";status:ok"); - o.print(ETX); + o.send(";status:ok"); + o.send(ETX); } void cmdStatus(ISlvCtrlCmdCtx& ctx) { auto& o = ctx.out(); - o.print("status;"); + o.send("status;"); bool first = true; for (size_t i = 0; i < attrCount_; ++i) { IAttribute* a = attrs_[i]; if (!a || !canRead(a->access())) continue; - if (!first) o.print(","); + if (!first) o.send(","); first = false; - o.print(a->name()); - o.print(":"); + o.send(a->name()); + o.send(":"); a->writeValue(o); } - o.print(";status:ok"); - o.print(ETX); + o.send(";status:ok"); + o.send(ETX); } void cmdGet(ISlvCtrlCmdCtx& ctx) { auto& o = ctx.out(); const char* name = ctx.next(); - if (!name) { o.print("get;;status:error,reason:missing_attribute_name_arg"); o.print(ETX); return; } + if (!name) { o.send("get;;status:error,reason:missing_attribute_name_arg"); o.send(ETX); return; } IAttribute* a = findAttr(name); - if (!a) { o.print("get "); o.print(name); o.print(";;status:error,reason:unknown_attribute"); o.print(ETX); return; } - if (!canRead(a->access())) { o.print("get "); o.print(name); o.print(";;status:error,reason:write_only_attribute"); o.print(ETX); return; } + if (!a) { o.send("get "); o.send(name); o.send(";;status:error,reason:unknown_attribute"); o.send(ETX); return; } + if (!canRead(a->access())) { o.send("get "); o.send(name); o.send(";;status:error,reason:write_only_attribute"); o.send(ETX); return; } - o.print("get "); - o.print(a->name()); - o.print(";value:"); + o.send("get "); + o.send(a->name()); + o.send(";value:"); a->writeValue(o); - o.print(";status:ok"); - o.print(ETX); + o.send(";status:ok"); + o.send(ETX); } void cmdSet(ISlvCtrlCmdCtx& ctx) { @@ -355,46 +355,46 @@ class SlvCtrlProtocol { const char* value = ctx.next(); if (!name) { - o.print("set;;status:error,reason:attribute_name_missing"); - o.print(ETX); + o.send("set;;status:error,reason:attribute_name_missing"); + o.send(ETX); return; } if (!value) { - o.print("set "); - o.print(name); - o.print(";;status:error,reason:attribute_value_missing"); - o.print(ETX); + o.send("set "); + o.send(name); + o.send(";;status:error,reason:attribute_value_missing"); + o.send(ETX); return; } IAttribute* a = findAttr(name); - if (!a) { o.print("set "); o.print(name); o.print(";;status:error,reason:unknown_attribute"); o.print(ETX); return; } - if (!canWrite(a->access())) { o.print("set "); o.print(name); o.print(";;status:error,reason:read_only_attribute"); o.print(ETX); return; } + if (!a) { o.send("set "); o.send(name); o.send(";;status:error,reason:unknown_attribute"); o.send(ETX); return; } + if (!canWrite(a->access())) { o.send("set "); o.send(name); o.send(";;status:error,reason:read_only_attribute"); o.send(ETX); return; } SlvCtrlParseError err = a->setFromCString(value); - o.print("set "); - o.print(name); - o.print(" "); - o.print(value); - o.print(";;"); + o.send("set "); + o.send(name); + o.send(" "); + o.send(value); + o.send(";;"); if (err == SlvCtrlParseError::Ok) { - o.print("status:ok"); + o.send("status:ok"); } else { - o.print("status:error,reason:"); - o.print(slvCtrlParseErrorToString(err)); + o.send("status:error,reason:"); + o.send(slvCtrlParseErrorToString(err)); } - o.print(ETX); + o.send(ETX); } void cmdUnrecognized(ISlvCtrlCmdCtx& ctx, const char* cmd) { auto& o = ctx.out(); - o.print(cmd ? cmd : ""); - o.print(";;status:error,reason:unknown_command"); - o.print(ETX); + o.send(cmd ? cmd : ""); + o.send(";;status:error,reason:unknown_command"); + o.send(ETX); } private: