From 59ca9f57e6261dc8008a44db5888c13ed6d3f79b Mon Sep 17 00:00:00 2001 From: brocci Date: Sat, 13 Jun 2026 19:08:27 +0200 Subject: [PATCH 1/5] Use Stream abstraction for serial services --- docs/Examples.md | 8 ++ .../VLCB_SerialGC_SerialUI_SoftwareSerial.ino | 131 ++++++++++++++++++ src/SerialGC.cpp | 1 - src/SerialGC.h | 5 +- src/SerialUserInterface.cpp | 60 ++++---- src/SerialUserInterface.h | 7 + 6 files changed, 179 insertions(+), 33 deletions(-) create mode 100644 examples/VLCB_SerialGC_SerialUI_SoftwareSerial/VLCB_SerialGC_SerialUI_SoftwareSerial.ino diff --git a/docs/Examples.md b/docs/Examples.md index 17f1022b..53f7f97d 100644 --- a/docs/Examples.md +++ b/docs/Examples.md @@ -107,3 +107,11 @@ use for programming the Arduino. You can then start FCU (or any other configuration utility) and connect through this serial port. The FCU will then communicate with your Arduino module as a CBUS module. + +## [VLCB_SerialGC_SerialUI_SoftwareSerial](../examples/VLCB_SerialGC_SerialUI_SoftwareSerial/VLCB_SerialGC_SerialUI_SoftwareSerial.ino) +This example demonstrates split serial usage on a single node. +The hardware serial port is dedicated to [SerialGC](../docs/CanTransport.md) for VLCB/GridConnect traffic, +while a separate SoftwareSerial port is used for [SerialUserInterface](SerialUserInterface.md) commands and status output. + +This layout is useful when you want to keep the transport channel and the user console separate. +It also shows the intended use of the Stream-based serial refactor for either HardwareSerial or SoftwareSerial. diff --git a/examples/VLCB_SerialGC_SerialUI_SoftwareSerial/VLCB_SerialGC_SerialUI_SoftwareSerial.ino b/examples/VLCB_SerialGC_SerialUI_SoftwareSerial/VLCB_SerialGC_SerialUI_SoftwareSerial.ino new file mode 100644 index 00000000..f791abd3 --- /dev/null +++ b/examples/VLCB_SerialGC_SerialUI_SoftwareSerial/VLCB_SerialGC_SerialUI_SoftwareSerial.ino @@ -0,0 +1,131 @@ +// Copyright (C) Sven Rosvall (sven@rosvall.ie) +// This file is part of VLCB-Arduino project on https://github.com/SvenRosvall/VLCB-Arduino +// Licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +// The full licence can be found at: http://creativecommons.org/licenses/by-nc-sa/4.0 + +/* + 3rd party libraries needed for compilation: (not for binary-only distributions) + + Streaming -- C++ stream style output, v5, (http://arduiniana.org/libraries/streaming/) + SoftwareSerial -- Arduino software serial library +*/ + +// +// This example demonstrates split serial usage: +// - SerialGC uses the hardware Serial port for GridConnect transport +// - SerialUserInterface uses SoftwareSerial for user commands and status output +// +// This is useful on boards where the USB serial port is already committed to +// the VLCB/GridConnect transport, but a separate command console is still wanted. +// + + +// 3rd party libraries +#include +#include + +// VLCB library header files +#include +#include +#include + +// forward function declarations +void printConfig(); + +// constants +const byte VER_MAJ = 1; // code major version +const char VER_MIN = 'a'; // code minor version +const byte VER_BETA = 0; // code beta sub-version +const byte MANUFACTURER = MANU_DEV; // for boards in development. +const byte MODULE_ID = 98; // VLCB module type + +// module name, must be at most 7 characters +char mname[] = "SPLIT"; + +const byte LED_GRN = 4; // VLCB green Unitialised LED pin +const byte LED_YLW = 7; // VLCB yellow Normal LED pin +const byte SWITCH0 = 8; // VLCB push button switch pin + +// SoftwareSerial pins: RX, TX +// Wire the external serial terminal or adapter to these pins. +const byte UI_RX_PIN = 10; +const byte UI_TX_PIN = 11; +SoftwareSerial serialUserPort(UI_RX_PIN, UI_TX_PIN); + +// module objects +VLCB::SerialGC serialGC(Serial); // CAN transport object using hardware serial +VLCB::SerialUserInterface serialUserInterface(serialUserPort); + +// Service objects +VLCB::LEDUserInterface ledUserInterface(LED_GRN, LED_YLW, SWITCH0); +VLCB::MinimumNodeServiceWithDiagnostics mnService; +VLCB::CanService serialCanService(&serialGC); + +// +/// setup VLCB - runs once at power on from setup() +// +void setupVLCB() +{ + VLCB::checkStartupAction(LED_GRN, LED_YLW, SWITCH0); + + VLCB::setServices({ + &mnService, &ledUserInterface, &serialUserInterface, &serialCanService}); + + // set module parameters + VLCB::setVersion(VER_MAJ, VER_MIN, VER_BETA); + VLCB::setModuleId(MANUFACTURER, MODULE_ID); + + // set module name + VLCB::setName(mname); + + // initialise and load configuration + VLCB::begin(); + + // show code version and copyright notice on the UI console + serialUserPort << F("> mode = ") << VLCB::Configuration::modeString(VLCB::getCurrentMode()); + serialUserPort << F(", CANID = ") << VLCB::getCANID(); + serialUserPort << F(", NN = ") << VLCB::getNodeNum() << endl; + + printConfig(); +} + +// +/// setup - runs once at power on +// +void setup() +{ + Serial.begin(115200); + serialUserPort.begin(9600); + + serialUserPort << F("> ** VLCB split SerialGC + SoftwareSerial UI example ** ") << __FILE__ << endl; + + setupVLCB(); + + serialUserPort << F("> ready") << endl << endl; +} + +// +/// loop - runs forever +// +void loop() +{ + // + /// do VLCB message, switch and LED processing + // + VLCB::process(); + + // bottom of loop() +} + +// +/// print code version config details and copyright notice +// +void printConfig() +{ + // code version + serialUserPort << F("> code version = ") << VER_MAJ << VER_MIN << F(" beta ") << VER_BETA << endl; + serialUserPort << F("> compiled on ") << __DATE__ << F(" at ") << __TIME__ << F(", compiler ver = ") << __cplusplus << endl; + + // copyright + serialUserPort << F("> © Sven Rosvall (MERG 3777) 2026") << endl; +} diff --git a/src/SerialGC.cpp b/src/SerialGC.cpp index 4484e58c..8e875719 100644 --- a/src/SerialGC.cpp +++ b/src/SerialGC.cpp @@ -19,7 +19,6 @@ namespace VLCB bool SerialGC::begin() { - Serial << F("> ** GridConnect over serial ** ") << endl; receivedCount = 0; transmitCount = 0; return true; diff --git a/src/SerialGC.h b/src/SerialGC.h index 67ebd1b0..5ebf3329 100644 --- a/src/SerialGC.h +++ b/src/SerialGC.h @@ -7,6 +7,7 @@ // header files #include +#include #include #include #include @@ -24,7 +25,7 @@ namespace VLCB class SerialGC : public CanTransport { public: - SerialGC(typeof(Serial)& _serial = Serial) : serial(_serial) {} + SerialGC(Stream& _serial = Serial) : serial(_serial) {} /// @cond LIBRARY bool begin(); @@ -48,7 +49,7 @@ namespace VLCB /// @endcond private: - typeof(Serial)& serial; + Stream& serial; char rxBuffer[RXBUFFERSIZE]; // Define a byte array to store the incoming data char txBuffer[RXBUFFERSIZE]; // Define a byte array to store the outgoing data diff --git a/src/SerialUserInterface.cpp b/src/SerialUserInterface.cpp index 65798f57..80bff3a0 100644 --- a/src/SerialUserInterface.cpp +++ b/src/SerialUserInterface.cpp @@ -24,10 +24,10 @@ void SerialUserInterface::processAction(const Action &action) void SerialUserInterface::processSerialInput() { - if (Serial.available()) + if (serial.available()) { Configuration *modconfig = controller->getModuleConfig(); - char c = Serial.read(); + char c = serial.read(); switch (c) { @@ -36,78 +36,78 @@ void SerialUserInterface::processSerialInput() printConfig(); // node identity - Serial << F("> VLCB node configuration") << endl; - Serial << F("> mode = ") << Configuration::modeString(modconfig->currentMode) + serial << F("> VLCB node configuration") << endl; + serial << F("> mode = ") << Configuration::modeString(modconfig->currentMode) << F(", CANID = ") << modconfig->CANID << F(", node number = ") << modconfig->nodeNum << endl; - Serial << endl; + serial << endl; break; case 'e': // EEPROM learned event data table - Serial << F("> stored events ") << endl; - Serial << F(" max events = ") << modconfig->getNumEvents() + serial << F("> stored events ") << endl; + serial << F(" max events = ") << modconfig->getNumEvents() << F(" EVs per event = ") << modconfig->getNumEVs() << F(" bytes per event = ") << modconfig->EE_BYTES_PER_EVENT << endl; { byte uev = modconfig->numEvents(); - Serial << F(" stored events = ") << uev << F(", free = ") << (modconfig->getNumEvents() - uev) << endl; - Serial << F(" using ") << (uev * modconfig->EE_BYTES_PER_EVENT) << F(" of ") + serial << F(" stored events = ") << uev << F(", free = ") << (modconfig->getNumEvents() - uev) << endl; + serial << F(" using ") << (uev * modconfig->EE_BYTES_PER_EVENT) << F(" of ") << (modconfig->getNumEvents() * modconfig->EE_BYTES_PER_EVENT) << F(" bytes") << endl << endl; } - Serial << F(" Ev# | NNhi | NNlo | ENhi | ENlo | "); + serial << F(" Ev# | NNhi | NNlo | ENhi | ENlo | "); for (byte j = 0; j < (modconfig->getNumEVs()); j++) { - Serial << _FMT(F("EV% | "), _WIDTHZ(j + 1, 3)); + serial << _FMT(F("EV% | "), _WIDTHZ(j + 1, 3)); } - Serial << F("Hash |") << endl; - Serial << F(" --------------------------------------------------------------") << endl; + serial << F("Hash |") << endl; + serial << F(" --------------------------------------------------------------") << endl; // for each event data line for (byte j = 0; j < modconfig->getNumEvents(); j++) { if (modconfig->getEvTableEntry(j) != 0) { - Serial << _FMT(F(" % | "), _WIDTHZ(j, 3)); + serial << _FMT(F(" % | "), _WIDTHZ(j, 3)); // for each data byte of this event byte evarray[EE_HASH_BYTES]; modconfig->readEvent(j, evarray); for (byte e = 0; e < 4; e++) { - Serial << _FMT(F(" 0x% | "), _WIDTHZ(_HEX(evarray[e]), 2)); + serial << _FMT(F(" 0x% | "), _WIDTHZ(_HEX(evarray[e]), 2)); } for (byte ev = 1; ev <= modconfig->getNumEVs(); ev++) { - Serial << _FMT(F(" 0x% | "), _WIDTHZ(_HEX(modconfig->getEventEVval(j, ev)), 2)); + serial << _FMT(F(" 0x% | "), _WIDTHZ(_HEX(modconfig->getEventEVval(j, ev)), 2)); } - Serial << _FMT("%", _WIDTH(modconfig->getEvTableEntry(j), 4)) << endl; + serial << _FMT("%", _WIDTH(modconfig->getEvTableEntry(j), 4)) << endl; } } - Serial << endl; + serial << endl; break; // NVs case 'v': // note NVs number from 1, not 0 - Serial << F("> Node variables") << endl; - Serial << F(" NV Val") << endl; - Serial << F(" --------------------") << endl; + serial << F("> Node variables") << endl; + serial << F(" NV Val") << endl; + serial << F(" --------------------") << endl; for (byte j = 1; j <= modconfig->getNumNodeVariables(); j++) { byte v = modconfig->readNV(j); - Serial << _FMT(F(" - % : % | 0x%"), _WIDTHZ(j, 2), _WIDTH(v, 3), _HEX(v)) << endl; + serial << _FMT(F(" - % : % | 0x%"), _WIDTHZ(j, 2), _WIDTH(v, 3), _HEX(v)) << endl; } - Serial << endl << endl; + serial << endl << endl; break; @@ -123,12 +123,12 @@ void SerialUserInterface::processSerialInput() case 'm': // free memory - Serial << F("Free SRAM = ") << modconfig->freeSRAM() << F(" bytes") << endl; + serial << F("Free SRAM = ") << modconfig->freeSRAM() << F(" bytes") << endl; break; case 'a': // Action queue info - Serial << F("Action Queue Size=") << controller->getActionQueue().bufUse() + serial << F("Action Queue Size=") << controller->getActionQueue().bufUse() << F(" High Water Mark=") << controller->getActionQueue().getHighWaterMark() << F(" Overflows=") << controller->getActionQueue().getOverflows() << endl; break; @@ -140,11 +140,11 @@ void SerialUserInterface::processSerialInput() case '\r': case '\n': - Serial << endl; + serial << endl; break; default: - Serial << F("> unknown command ") << c << endl; + serial << F("> unknown command ") << c << endl; break; } } @@ -176,15 +176,15 @@ void SerialUserInterface::indicateMode(VlcbModeParams mode) switch (mode) { case MODE_NORMAL: - Serial << F("Module in NORMAL mode") << endl; + serial << F("Module in NORMAL mode") << endl; break; case MODE_UNINITIALISED: - Serial << F("Module in UNINITIALISED mode") << endl; + serial << F("Module in UNINITIALISED mode") << endl; break; case MODE_SETUP: - Serial << F("Module in SETUP mode") << endl; + serial << F("Module in SETUP mode") << endl; break; default: diff --git a/src/SerialUserInterface.h b/src/SerialUserInterface.h index 134b4305..8727b86c 100644 --- a/src/SerialUserInterface.h +++ b/src/SerialUserInterface.h @@ -5,6 +5,9 @@ #pragma once +#include +#include + #include "Service.h" #include "Configuration.h" #include "Transport.h" @@ -20,6 +23,8 @@ class SerialUserInterface : public Service { public: /// @cond LIBRARY + SerialUserInterface(Stream& _serial = Serial) : serial(_serial) {} + virtual VlcbServiceTypes getServiceID() const override { return SERVICE_ID_NONE; }; virtual byte getServiceVersionID() const override { return 1; }; @@ -28,6 +33,8 @@ class SerialUserInterface : public Service /// @endcond private: + Stream& serial; + void handleAction(const Action &action); void processSerialInput(); void indicateMode(VlcbModeParams i); From ad582f62d20a82f762a08ede60be298b60a84c8b Mon Sep 17 00:00:00 2001 From: brocci Date: Mon, 15 Jun 2026 00:15:04 +0200 Subject: [PATCH 2/5] Fix CMake desktop build: add Stream.h mock, remove Serial_T indirection --- .gitignore | 3 +++ Arduino/Arduino.h | 14 ++--------- Arduino/Stream.h | 24 ++++++++++++++++++ Arduino/Streaming.h | 14 ++++++----- CMakeLists.txt | 1 + test/ArduinoMock.cpp | 58 +------------------------------------------- 6 files changed, 39 insertions(+), 75 deletions(-) create mode 100644 Arduino/Stream.h diff --git a/.gitignore b/.gitignore index 5acf4242..80eddb15 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,6 @@ .idea build +# Local working notes +notes/ + diff --git a/Arduino/Arduino.h b/Arduino/Arduino.h index 3f90b4e7..18325d64 100644 --- a/Arduino/Arduino.h +++ b/Arduino/Arduino.h @@ -4,6 +4,7 @@ #include #include #include +#include #define F(s) s @@ -28,15 +29,4 @@ void pinMode(int, PinMode); void digitalWrite(int, PinState); byte digitalRead(int); -struct Serial_T -{ - void begin(int baudrate); - - bool available(); - char read(); - void flush(); - unsigned char readBytesUntil(int termChar, char *string, int length); - void print(const char *); - void println(const char *); -}; -extern struct Serial_T Serial; \ No newline at end of file +extern Stream Serial; \ No newline at end of file diff --git a/Arduino/Stream.h b/Arduino/Stream.h new file mode 100644 index 00000000..535c1057 --- /dev/null +++ b/Arduino/Stream.h @@ -0,0 +1,24 @@ +#pragma once + +struct ENDL_T; + +class Stream +{ +public: + Stream() = default; + virtual ~Stream() = default; + + virtual bool available() { return false; } + virtual char read() { return 0; } + virtual void print(const char *) {} + virtual void println(const char *) {} + virtual void flush() {} +}; + +// Operator overloads for Stream to work with Streaming library +inline Stream & operator<<(Stream & s, int) { return s; } +inline Stream & operator<<(Stream & s, unsigned int) { return s; } +inline Stream & operator<<(Stream & s, long) { return s; } +inline Stream & operator<<(Stream & s, unsigned long) { return s; } +inline Stream & operator<<(Stream & s, const char *) { return s; } +inline Stream & operator<<(Stream & s, const ENDL_T &) { return s; } diff --git a/Arduino/Streaming.h b/Arduino/Streaming.h index 2a477db7..5e657635 100644 --- a/Arduino/Streaming.h +++ b/Arduino/Streaming.h @@ -1,15 +1,17 @@ #pragma once #include +#include struct ENDL_T {}; -Serial_T & operator<<(Serial_T &, int); -Serial_T & operator<<(Serial_T &, unsigned int); -Serial_T & operator<<(Serial_T &, long); -Serial_T & operator<<(Serial_T &, unsigned long); -Serial_T & operator<<(Serial_T &, const char *); -Serial_T & operator<<(Serial_T & s, const ENDL_T & e); +Stream & operator<<(Stream &, int); +Stream & operator<<(Stream &, unsigned int); +Stream & operator<<(Stream &, long); +Stream & operator<<(Stream &, unsigned long); +Stream & operator<<(Stream &, const char *); +Stream & operator<<(Stream & s, const ENDL_T & e); + extern ENDL_T endl; template T _HEX(T v) { return v;} template T _WIDTH(T v, int width) { return v;} diff --git a/CMakeLists.txt b/CMakeLists.txt index 43ea24fd..181e1c5f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -112,6 +112,7 @@ add_executable(VLCB_Arduino examples/VLCB_SerialGC_4in4out/VLCB_SerialGC_4in4out.ino examples/VLCB_SerialGC_4in4out_slot/VLCB_SerialGC_4in4out_slot.ino examples/VLCB_SerialGC_empty/VLCB_SerialGC_empty.ino + examples/VLCB_SerialGC_SerialUI_SoftwareSerial/VLCB_SerialGC_SerialUI_SoftwareSerial.ino ) add_executable(testAll diff --git a/test/ArduinoMock.cpp b/test/ArduinoMock.cpp index 6706771c..9f0153d4 100644 --- a/test/ArduinoMock.cpp +++ b/test/ArduinoMock.cpp @@ -99,64 +99,8 @@ byte lowByte(unsigned int i) return i & 0xFF; } -void Serial_T::begin(int baudRate) -{ -} - -bool Serial_T::available() -{ - return true; -} - -char Serial_T::read() -{ - return ' '; -} - -void Serial_T::print(const char *) -{ -} - -void Serial_T::println(const char *) -{ -} - -void Serial_T::flush() -{ -} - -Serial_T & operator<<(Serial_T & s, int i) -{ - std::cout << i; - return s; -} -Serial_T & operator<<(Serial_T & s, unsigned int i) -{ - std::cout << i; - return s; -} -Serial_T & operator<<(Serial_T & s, long i) -{ - std::cout << i; - return s; -} -Serial_T & operator<<(Serial_T & s, unsigned long i) -{ - std::cout << i; - return s; -} -Serial_T & operator<<(Serial_T & s, const char * i) -{ - std::cout << i; - return s; -} -Serial_T & operator<<(Serial_T & s, const ENDL_T & e) -{ - std::cout << std::endl; - return s; -} ENDL_T endl; -Serial_T Serial; +Stream Serial; //template T _HEX(T); // Hardware values used by ADC free running mode. From 7ab020839a91a27bada2948ddf5433e1041162e4 Mon Sep 17 00:00:00 2001 From: brocci Date: Tue, 16 Jun 2026 11:13:45 +0200 Subject: [PATCH 3/5] Add Serial1 option for the SerialUserInterface to split SerialGC/UI example --- .gitignore | 29 +++++++++- .../VLCB_SerialGC_SerialUI_SoftwareSerial.ino | 55 ++++++++++++------- 2 files changed, 61 insertions(+), 23 deletions(-) diff --git a/.gitignore b/.gitignore index 80eddb15..fb617e20 100644 --- a/.gitignore +++ b/.gitignore @@ -3,10 +3,35 @@ *.exe *.out -.DS_Store .idea build +# +# MacOS +# +.DS_Store +.localized +__MACOSX/ +.AppleDouble +._* + +# +# Visual Studio Code +# +.vscode/ +!.vscode/settings.json +!.vscode/extensions.json +!.vscode/*.code-snippets +!*.code-workspace +# Built Visual Studio Code Extensions +*.vsix + +# +# PlatformIO +# +.pio +.pioenvs +.piolibdeps + # Local working notes notes/ - diff --git a/examples/VLCB_SerialGC_SerialUI_SoftwareSerial/VLCB_SerialGC_SerialUI_SoftwareSerial.ino b/examples/VLCB_SerialGC_SerialUI_SoftwareSerial/VLCB_SerialGC_SerialUI_SoftwareSerial.ino index f791abd3..4cc859ec 100644 --- a/examples/VLCB_SerialGC_SerialUI_SoftwareSerial/VLCB_SerialGC_SerialUI_SoftwareSerial.ino +++ b/examples/VLCB_SerialGC_SerialUI_SoftwareSerial/VLCB_SerialGC_SerialUI_SoftwareSerial.ino @@ -7,22 +7,26 @@ 3rd party libraries needed for compilation: (not for binary-only distributions) Streaming -- C++ stream style output, v5, (http://arduiniana.org/libraries/streaming/) - SoftwareSerial -- Arduino software serial library + SoftwareSerial -- Arduino software serial library (not needed when USE_MEGA_SERIAL1 is set) */ -// // This example demonstrates split serial usage: -// - SerialGC uses the hardware Serial port for GridConnect transport +// +// - SerialGC uses the default hardware Serial port for GridConnect transport // - SerialUserInterface uses SoftwareSerial for user commands and status output +// - Optionally, hardware Serial1 can be used for the SerialUserInterface on Mega2560 by setting the USE_MEGA_SERIAL1 build flag in platformio.ini // // This is useful on boards where the USB serial port is already committed to // the VLCB/GridConnect transport, but a separate command console is still wanted. // +// Based on VLCB_SerialGC_empty example, modified by Bruno Rocci (MERG 9690). // 3rd party libraries #include +#ifndef USE_MEGA_SERIAL1 #include +#endif // VLCB library header files #include @@ -46,11 +50,15 @@ const byte LED_GRN = 4; // VLCB green Unitialised LED pin const byte LED_YLW = 7; // VLCB yellow Normal LED pin const byte SWITCH0 = 8; // VLCB push button switch pin -// SoftwareSerial pins: RX, TX -// Wire the external serial terminal or adapter to these pins. -const byte UI_RX_PIN = 10; -const byte UI_TX_PIN = 11; +#ifdef USE_MEGA_SERIAL1 +// Use hardware Serial1 on pins 18 (TX1) and 19 (RX1) +#define serialUserPort Serial1 +#else +// Use SoftwareSerial on pins 2 (RX) and 3 (TX) +const byte UI_RX_PIN = 2; +const byte UI_TX_PIN = 3; SoftwareSerial serialUserPort(UI_RX_PIN, UI_TX_PIN); +#endif // module objects VLCB::SerialGC serialGC(Serial); // CAN transport object using hardware serial @@ -89,6 +97,19 @@ void setupVLCB() printConfig(); } +// +/// print code version config details and copyright notice +// +void printConfig() +{ + // code version + serialUserPort << F("> code version = ") << VER_MAJ << VER_MIN << F(" beta ") << VER_BETA << endl; + serialUserPort << F("> compiled on ") << __DATE__ << F(" at ") << __TIME__ << F(", compiler ver = ") << __cplusplus << endl; + + // copyright + serialUserPort << F("> © Sven Rosvall (MERG 3777) 2026") << endl; +} + // /// setup - runs once at power on // @@ -96,8 +117,13 @@ void setup() { Serial.begin(115200); serialUserPort.begin(9600); + delay(2000); // Give some time to PIO to open the serial monitor before printing anything - serialUserPort << F("> ** VLCB split SerialGC + SoftwareSerial UI example ** ") << __FILE__ << endl; +#ifdef USE_MEGA_SERIAL1 + serialUserPort << F("> ** VLCB split: SerialGC + Serial1 UI example ** ") << __FILE__ << endl; +#else + serialUserPort << F("> ** VLCB split: SerialGC + SoftwareSerial UI example ** ") << __FILE__ << endl; +#endif setupVLCB(); @@ -116,16 +142,3 @@ void loop() // bottom of loop() } - -// -/// print code version config details and copyright notice -// -void printConfig() -{ - // code version - serialUserPort << F("> code version = ") << VER_MAJ << VER_MIN << F(" beta ") << VER_BETA << endl; - serialUserPort << F("> compiled on ") << __DATE__ << F(" at ") << __TIME__ << F(", compiler ver = ") << __cplusplus << endl; - - // copyright - serialUserPort << F("> © Sven Rosvall (MERG 3777) 2026") << endl; -} From 53097703e5a546911e402efe0ccf68bbbddc7648 Mon Sep 17 00:00:00 2001 From: brocci Date: Fri, 19 Jun 2026 17:25:03 +0200 Subject: [PATCH 4/5] Rename VLCB_SerialGC_SerialUI_SoftwareSerial example to VLCB_SerialGC_SerialUI_empty --- CMakeLists.txt | 2 +- docs/Examples.md | 2 +- .../VLCB_SerialGC_SerialUI_empty.ino} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename examples/{VLCB_SerialGC_SerialUI_SoftwareSerial/VLCB_SerialGC_SerialUI_SoftwareSerial.ino => VLCB_SerialGC_SerialUI_empty/VLCB_SerialGC_SerialUI_empty.ino} (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 181e1c5f..8788edd8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -112,7 +112,7 @@ add_executable(VLCB_Arduino examples/VLCB_SerialGC_4in4out/VLCB_SerialGC_4in4out.ino examples/VLCB_SerialGC_4in4out_slot/VLCB_SerialGC_4in4out_slot.ino examples/VLCB_SerialGC_empty/VLCB_SerialGC_empty.ino - examples/VLCB_SerialGC_SerialUI_SoftwareSerial/VLCB_SerialGC_SerialUI_SoftwareSerial.ino + examples/VLCB_SerialGC_SerialUI_empty/VLCB_SerialGC_SerialUI_empty.ino ) add_executable(testAll diff --git a/docs/Examples.md b/docs/Examples.md index 53f7f97d..c9f1a50f 100644 --- a/docs/Examples.md +++ b/docs/Examples.md @@ -108,7 +108,7 @@ You can then start FCU (or any other configuration utility) and connect through this serial port. The FCU will then communicate with your Arduino module as a CBUS module. -## [VLCB_SerialGC_SerialUI_SoftwareSerial](../examples/VLCB_SerialGC_SerialUI_SoftwareSerial/VLCB_SerialGC_SerialUI_SoftwareSerial.ino) +## [VLCB_SerialGC_SerialUI_empty](../examples/VLCB_SerialGC_SerialUI_empty/VLCB_SerialGC_SerialUI_empty.ino) This example demonstrates split serial usage on a single node. The hardware serial port is dedicated to [SerialGC](../docs/CanTransport.md) for VLCB/GridConnect traffic, while a separate SoftwareSerial port is used for [SerialUserInterface](SerialUserInterface.md) commands and status output. diff --git a/examples/VLCB_SerialGC_SerialUI_SoftwareSerial/VLCB_SerialGC_SerialUI_SoftwareSerial.ino b/examples/VLCB_SerialGC_SerialUI_empty/VLCB_SerialGC_SerialUI_empty.ino similarity index 100% rename from examples/VLCB_SerialGC_SerialUI_SoftwareSerial/VLCB_SerialGC_SerialUI_SoftwareSerial.ino rename to examples/VLCB_SerialGC_SerialUI_empty/VLCB_SerialGC_SerialUI_empty.ino From fff3c9b73aabd0cf1865b14cd9973cb7d79888ae Mon Sep 17 00:00:00 2001 From: brocci Date: Sat, 20 Jun 2026 00:03:42 +0200 Subject: [PATCH 5/5] Fix Mockup for Stream. Update copyrights in example. --- Arduino/Stream.h | 19 ++---- README.md | 2 +- .../VLCB_SerialGC_SerialUI_empty.ino | 35 +++++------ src/SerialUserInterface.h | 2 +- test/ArduinoMock.cpp | 62 +++++++++++++++++++ 5 files changed, 87 insertions(+), 33 deletions(-) diff --git a/Arduino/Stream.h b/Arduino/Stream.h index 535c1057..40a3ed8a 100644 --- a/Arduino/Stream.h +++ b/Arduino/Stream.h @@ -8,17 +8,10 @@ class Stream Stream() = default; virtual ~Stream() = default; - virtual bool available() { return false; } - virtual char read() { return 0; } - virtual void print(const char *) {} - virtual void println(const char *) {} - virtual void flush() {} + virtual void begin(int); + virtual bool available(); + virtual char read(); + virtual void print(const char *); + virtual void println(const char *); + virtual void flush(); }; - -// Operator overloads for Stream to work with Streaming library -inline Stream & operator<<(Stream & s, int) { return s; } -inline Stream & operator<<(Stream & s, unsigned int) { return s; } -inline Stream & operator<<(Stream & s, long) { return s; } -inline Stream & operator<<(Stream & s, unsigned long) { return s; } -inline Stream & operator<<(Stream & s, const char *) { return s; } -inline Stream & operator<<(Stream & s, const ENDL_T &) { return s; } diff --git a/README.md b/README.md index abe3a7e8..26a42c54 100644 --- a/README.md +++ b/README.md @@ -93,7 +93,7 @@ by email to vlcb@rosvall.ie or create an [issue in GitHub](https://github.com/Sv * John Fletcher - Contributor * Chris Andrews - Contributor * David Ellis - Contributor -* brocci - Contributor to the CBUS library +* Bruno Rocci - Contributor to the CBUS library ## License diff --git a/examples/VLCB_SerialGC_SerialUI_empty/VLCB_SerialGC_SerialUI_empty.ino b/examples/VLCB_SerialGC_SerialUI_empty/VLCB_SerialGC_SerialUI_empty.ino index 4cc859ec..5265c59c 100644 --- a/examples/VLCB_SerialGC_SerialUI_empty/VLCB_SerialGC_SerialUI_empty.ino +++ b/examples/VLCB_SerialGC_SerialUI_empty/VLCB_SerialGC_SerialUI_empty.ino @@ -1,4 +1,4 @@ -// Copyright (C) Sven Rosvall (sven@rosvall.ie) +// Copyright (C) Bruno Rocci (bruno_rocci@hotmail.com) // This file is part of VLCB-Arduino project on https://github.com/SvenRosvall/VLCB-Arduino // Licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. // The full licence can be found at: http://creativecommons.org/licenses/by-nc-sa/4.0 @@ -19,8 +19,7 @@ // This is useful on boards where the USB serial port is already committed to // the VLCB/GridConnect transport, but a separate command console is still wanted. // -// Based on VLCB_SerialGC_empty example, modified by Bruno Rocci (MERG 9690). - +// Based on VLCB_SerialGC_empty example from Sven Rosvall (MERG 3777) // 3rd party libraries #include @@ -39,7 +38,7 @@ void printConfig(); // constants const byte VER_MAJ = 1; // code major version const char VER_MIN = 'a'; // code minor version -const byte VER_BETA = 0; // code beta sub-version +const byte VER_BUILD = 0; // code build number const byte MANUFACTURER = MANU_DEV; // for boards in development. const byte MODULE_ID = 98; // VLCB module type @@ -80,7 +79,7 @@ void setupVLCB() &mnService, &ledUserInterface, &serialUserInterface, &serialCanService}); // set module parameters - VLCB::setVersion(VER_MAJ, VER_MIN, VER_BETA); + VLCB::setVersion(VER_MAJ, VER_MIN, VER_BUILD); VLCB::setModuleId(MANUFACTURER, MODULE_ID); // set module name @@ -97,19 +96,6 @@ void setupVLCB() printConfig(); } -// -/// print code version config details and copyright notice -// -void printConfig() -{ - // code version - serialUserPort << F("> code version = ") << VER_MAJ << VER_MIN << F(" beta ") << VER_BETA << endl; - serialUserPort << F("> compiled on ") << __DATE__ << F(" at ") << __TIME__ << F(", compiler ver = ") << __cplusplus << endl; - - // copyright - serialUserPort << F("> © Sven Rosvall (MERG 3777) 2026") << endl; -} - // /// setup - runs once at power on // @@ -142,3 +128,16 @@ void loop() // bottom of loop() } + +// +/// print code version config details and copyright notice +// +void printConfig() +{ + // code version + serialUserPort << F("> code version = ") << VER_MAJ << VER_MIN << F(" build ") << VER_BUILD << endl; + serialUserPort << F("> compiled on ") << __DATE__ << F(" at ") << __TIME__ << F(", compiler ver = ") << __cplusplus << endl; + + // copyright + serialUserPort << F("> Copyright © 2026 Bruno Rocci (MERG 9690)") << endl; +} diff --git a/src/SerialUserInterface.h b/src/SerialUserInterface.h index 8727b86c..397e7259 100644 --- a/src/SerialUserInterface.h +++ b/src/SerialUserInterface.h @@ -22,9 +22,9 @@ namespace VLCB class SerialUserInterface : public Service { public: - /// @cond LIBRARY SerialUserInterface(Stream& _serial = Serial) : serial(_serial) {} + /// @cond LIBRARY virtual VlcbServiceTypes getServiceID() const override { return SERVICE_ID_NONE; }; virtual byte getServiceVersionID() const override { return 1; }; diff --git a/test/ArduinoMock.cpp b/test/ArduinoMock.cpp index 9f0153d4..c8b9f284 100644 --- a/test/ArduinoMock.cpp +++ b/test/ArduinoMock.cpp @@ -99,6 +99,68 @@ byte lowByte(unsigned int i) return i & 0xFF; } +void Stream::begin(int baudRate) +{ +} + +bool Stream::available() +{ + return true; +} + +char Stream::read() +{ + return ' '; +} + +void Stream::print(const char *) +{ +} + +void Stream::println(const char *) +{ +} + +void Stream::flush() +{ +} + +Stream & operator<<(Stream & s, int i) +{ + std::cout << i; + return s; +} + +Stream & operator<<(Stream & s, unsigned int i) +{ + std::cout << i; + return s; +} + +Stream & operator<<(Stream & s, long i) +{ + std::cout << i; + return s; +} + +Stream & operator<<(Stream & s, unsigned long i) +{ + std::cout << i; + return s; +} + +Stream & operator<<(Stream & s, const char * i) +{ + std::cout << i; + return s; +} + +Stream & operator<<(Stream & s, const ENDL_T & e) +{ + std::cout << std::endl; + return s; +} + ENDL_T endl; Stream Serial; //template T _HEX(T);