From 5d25f97913357845015e7328b08d5b170c818073 Mon Sep 17 00:00:00 2001 From: Pascal Roobrouck Date: Wed, 16 Jul 2025 17:36:51 +0200 Subject: [PATCH 1/2] extend downlink you can now send multiple commands in one downlink, updating several display lines or several sensors --- lib/application/maincontroller.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/application/maincontroller.cpp b/lib/application/maincontroller.cpp index ab4025e..776909b 100644 --- a/lib/application/maincontroller.cpp +++ b/lib/application/maincontroller.cpp @@ -1003,12 +1003,19 @@ void mainController::setSensor(const uint8_t* payload, const uint32_t payloadLen } void mainController::handleDownLink(const uint8_t port, const uint8_t* payload, const uint32_t payloadLength) { + if (payload == nullptr || payloadLength == 0) { + return; + } switch (port) { case 1: - setDisplay(payload, payloadLength); + for (uint32_t offset = 0; offset < payloadLength; offset += 3) { + setDisplay(payload + offset, 3); + } break; case 2: - setSensor(payload, payloadLength); + for (uint32_t offset = 0; offset < payloadLength; offset += 4) { + setSensor(payload + offset, 4); + } break; default: break; From 25f8da39edd4bd2b90f6eed8e865789ede6f6c80 Mon Sep 17 00:00:00 2001 From: Pascal Roobrouck Date: Sun, 20 Jul 2025 21:15:52 +0200 Subject: [PATCH 2/2] refactor * split functions with too many levels of nesting * remove TODO comments --- lib/application/maincontroller.cpp | 223 +++++++++++++------------ lib/application/maincontroller.hpp | 1 + lib/lorawan/lorawan.cpp | 7 +- lib/lorawan/lorawan.md | 7 + lib/sensors/sensordevicecollection.cpp | 99 +++++------ lib/sensors/sensordevicecollection.hpp | 2 + 6 files changed, 169 insertions(+), 170 deletions(-) diff --git a/lib/application/maincontroller.cpp b/lib/application/maincontroller.cpp index 776909b..0dc073e 100644 --- a/lib/application/maincontroller.cpp +++ b/lib/application/maincontroller.cpp @@ -459,118 +459,120 @@ void mainController::runCli() { break; default: - if (power::hasUsbPower()) { - if (cli::hasCommand()) { - cliCommand theCommand; - cli::getCommand(theCommand); - switch (theCommand.commandHash) { - case cliCommand::prompt: - showPrompt(); - break; - - case cliCommand::help: - showHelp(); - break; - - case cliCommand::enableLogging: - cli::sendResponse("logging enabled\n"); - logging::enable(logging::destination::uart2); - break; - - case cliCommand::disableLogging: - cli::sendResponse("logging disabled\n"); - logging::disable(logging::destination::uart2); - break; - - case cliCommand::enableRadio: - LoRaWAN::setEnableRadio(true); - cli::sendResponse("radio enabled\n"); - break; - - case cliCommand::disableRadio: - LoRaWAN::setEnableRadio(false); - cli::sendResponse("radio disabled\n"); - break; - - case cliCommand::getDeviceStatus: - showDeviceStatus(); - break; - - case cliCommand::getMeasurementsStatus: - showMeasurementsStatus(); - break; - - case cliCommand::getMeasurements: - if (theCommand.nmbrOfArguments == 0) { - showMeasurements(); - } - if (theCommand.nmbrOfArguments == 1) { - if (strncmp(theCommand.arguments[0], "csv", 3) == 0) { - showMeasurementsCsv(); - break; - } else { - cli::sendResponse("invalid argument\n"); - break; - } - } else { - cli::sendResponse("invalid number of arguments\n"); - } - break; - - case cliCommand::getLoRaWANStatus: - showNetworkStatus(); - break; - - case cliCommand::resetMacLayer: - LoRaWAN::resetMacLayer(); - cli::sendResponse("mac layer reset\n"); - break; - - case cliCommand::setDeviceAddress: - setDeviceAddress(theCommand); - break; - - case cliCommand::setNetworkKey: - setNetworkKey(theCommand); - break; - - case cliCommand::setApplicationKey: - setApplicationKey(theCommand); - break; - - case cliCommand::setName: - setName(theCommand); - break; - - case cliCommand::setBattery: - setBatteryType(theCommand); - break; - - case cliCommand::setRadio: - setRadioType(theCommand); - break; - - case cliCommand::setSensor: - setSensor(theCommand); - break; - - case cliCommand::setDisplay: - setDisplay(theCommand); - break; - - case cliCommand::softwareReset: - initialize(); - break; - - default: - cli::sendResponse("unknown command : "); - cli::sendResponse(theCommand.commandAsString); - cli::sendResponse("\n"); - break; - } + if (power::hasUsbPower() && cli::hasCommand()) { + cliCommand theCommand; + cli::getCommand(theCommand); + runCli(theCommand); + } + break; + } +} + +void mainController::runCli(const cliCommand& theCommand) { + switch (theCommand.commandHash) { + case cliCommand::prompt: + showPrompt(); + break; + + case cliCommand::help: + showHelp(); + break; + + case cliCommand::enableLogging: + cli::sendResponse("logging enabled\n"); + logging::enable(logging::destination::uart2); + break; + + case cliCommand::disableLogging: + cli::sendResponse("logging disabled\n"); + logging::disable(logging::destination::uart2); + break; + + case cliCommand::enableRadio: + LoRaWAN::setEnableRadio(true); + cli::sendResponse("radio enabled\n"); + break; + + case cliCommand::disableRadio: + LoRaWAN::setEnableRadio(false); + cli::sendResponse("radio disabled\n"); + break; + + case cliCommand::getDeviceStatus: + showDeviceStatus(); + break; + + case cliCommand::getMeasurementsStatus: + showMeasurementsStatus(); + break; + + case cliCommand::getMeasurements: + if (theCommand.nmbrOfArguments == 0) { + showMeasurements(); + } + if (theCommand.nmbrOfArguments == 1) { + if (strncmp(theCommand.arguments[0], "csv", 3) == 0) { + showMeasurementsCsv(); + break; + } else { + cli::sendResponse("invalid argument\n"); + break; } + } else { + cli::sendResponse("invalid number of arguments\n"); } break; + + case cliCommand::getLoRaWANStatus: + showNetworkStatus(); + break; + + case cliCommand::resetMacLayer: + LoRaWAN::resetMacLayer(); + cli::sendResponse("mac layer reset\n"); + break; + + case cliCommand::setDeviceAddress: + setDeviceAddress(theCommand); + break; + + case cliCommand::setNetworkKey: + setNetworkKey(theCommand); + break; + + case cliCommand::setApplicationKey: + setApplicationKey(theCommand); + break; + + case cliCommand::setName: + setName(theCommand); + break; + + case cliCommand::setBattery: + setBatteryType(theCommand); + break; + + case cliCommand::setRadio: + setRadioType(theCommand); + break; + + case cliCommand::setSensor: + setSensor(theCommand); + break; + + case cliCommand::setDisplay: + setDisplay(theCommand); + break; + + case cliCommand::softwareReset: + initialize(); + break; + + default: + cli::sendResponse("unknown command : "); + cli::sendResponse(theCommand.commandAsString); + cli::sendResponse("\n"); + break; } } @@ -984,9 +986,8 @@ void mainController::setSensor(const uint8_t* payload, const uint32_t payloadLen return; } uint32_t tmpOversamplingIndex = payload[2]; - ; uint32_t tmpPrescalerIndex = payload[3]; - ; + if (tmpPrescalerIndex > sensorChannel::maxPrescalerIndex) { tmpPrescalerIndex = sensorChannel::maxPrescalerIndex; } diff --git a/lib/application/maincontroller.hpp b/lib/application/maincontroller.hpp index 97660ca..e99dfe3 100644 --- a/lib/application/maincontroller.hpp +++ b/lib/application/maincontroller.hpp @@ -32,6 +32,7 @@ class mainController { static void runStateMachine(); static void handleEvents(); static void runCli(); + static void runCli(const cliCommand& aCommand); static void runDisplayUpdate(); static void runSleep(); diff --git a/lib/lorawan/lorawan.cpp b/lib/lorawan/lorawan.cpp index 35df600..40b2b60 100644 --- a/lib/lorawan/lorawan.cpp +++ b/lib/lorawan/lorawan.cpp @@ -892,7 +892,6 @@ void LoRaWAN::removeNonStickyMacStuff() { macOut.initialize(); macOut.append(tmpMacOut.asUint8Ptr(), tmpMacOut.getLevel()); - // TODO : if we have sticky MACstuff, we could append a linkcheckrequest and thus force the LNS to send us a downlink, which confirms the sticky MAC stuff... } void LoRaWAN::processLinkCheckAnswer() { @@ -901,7 +900,7 @@ void LoRaWAN::processLinkCheckAnswer() { gatewayCount = macIn[2]; // GwCnt : number of gateways that successfully received the last uplink macIn.consume(linkCheckAnswerLength); // consume all bytes - logging::snprintf(logging::source::lorawanMac, "LinkCheckAnswer : margin = %d, gatewayCount = %d \n", margin, gatewayCount); // TODO : For the time being, we just show this info in the logging. Later we could use it to show the quality of the link on the display + logging::snprintf(logging::source::lorawanMac, "LinkCheckAnswer : margin = %d, gatewayCount = %d \n", margin, gatewayCount); } void LoRaWAN::processLinkAdaptiveDataRateRequest() { @@ -912,12 +911,11 @@ void LoRaWAN::processLinkAdaptiveDataRateRequest() { macIn.consume(linkAdaptiveDataRateRequestLength); logging::snprintf(logging::source::lorawanMac, "LinkAdaptiveDataRateRequest : 0x%02X, 0x%04X, 0x%02X \n", dataRateTxPower, chMask, redundancy); - // TODO : currently I don't understand the purpose of this mac command, so I just ignore it. Maybe it's more useful in US-915 than EU-868 constexpr uint32_t linkAdaptiveDataRateAnswerLength{2}; // commandId, status uint8_t answer[linkAdaptiveDataRateAnswerLength]; answer[0] = static_cast(macCommand::linkAdaptiveDataRateAnswer); - answer[1] = static_cast(0); // TODO : For the time being we just reject this stupid mac command + answer[1] = static_cast(0); macOut.append(answer, linkAdaptiveDataRateAnswerLength); logging::snprintf(logging::source::lorawanMac, "linkAdaptiveDataRateAnswer : 0x%02X \n", answer[1]); } @@ -928,7 +926,6 @@ void LoRaWAN::processDutyCycleRequest() { macIn.consume(dutyCycleRequestLength); logging::snprintf(logging::source::lorawanMac, "DutyCycleRequest : 0x%02X \n", dutyCycle); - // TODO : until we implement dutyCycle management, we ignore this command constexpr uint32_t dutyCycleAnswerLength{1}; uint8_t answer[dutyCycleAnswerLength]; diff --git a/lib/lorawan/lorawan.md b/lib/lorawan/lorawan.md index 1666634..b302d75 100644 --- a/lib/lorawan/lorawan.md +++ b/lib/lorawan/lorawan.md @@ -69,3 +69,10 @@ If the application wants to send certain MAC commands, or needs to respond to re When a received LoRaWAN message contains MAC commands, they are stored in **macIn**, and processed afterwards. Some MAC commands are 'sticky', ie. they need to be repeated on every transmission until confirmed by a received message. + + +# Could Do +// TODO : if we have sticky MACstuff, we could append a linkcheckrequest and thus force the LNS to send us a downlink, which confirms the sticky MAC stuff... +processLinkAdaptiveDataRateRequest // TODO : currently I don't understand the purpose of this mac command, so I just ignore it. Maybe it's more useful in US-915 than EU-868 +processDutyCycleRequest // TODO : until we implement dutyCycle management, we ignore this command + processLinkCheckAnswer// TODO : For the time being, we just show this info in the logging. Later we could use it to show the quality of the link on the display \ No newline at end of file diff --git a/lib/sensors/sensordevicecollection.cpp b/lib/sensors/sensordevicecollection.cpp index 02c38ba..a69cf87 100644 --- a/lib/sensors/sensordevicecollection.cpp +++ b/lib/sensors/sensordevicecollection.cpp @@ -59,33 +59,35 @@ void sensorDeviceCollection::set(uint32_t deviceIndex, uint32_t channelIndex, ui void sensorDeviceCollection::startSampling() { for (auto index = 0U; index < static_cast(sensorDeviceType::nmbrOfKnownDevices); index++) { - if (isValid(index)) { - if (needsSampling(index)) { - switch (static_cast(index)) { - case sensorDeviceType::battery: - battery::startSampling(); - break; - case sensorDeviceType::bme680: - bme680::startSampling(); - break; - case sensorDeviceType::sht40: - sht40::startSampling(); - break; - case sensorDeviceType::tsl2591: - tsl2591::startSampling(); - break; - case sensorDeviceType::scd40: - scd40::startSampling(); - break; - // Add more types of sensors here - default: - break; - } - } + if (isValid(index) && needsSampling(index)) { + startSampling(static_cast(index)); } } } +void sensorDeviceCollection::startSampling(sensorDeviceType aDeviceType) { + switch (aDeviceType) { + case sensorDeviceType::battery: + battery::startSampling(); + break; + case sensorDeviceType::bme680: + bme680::startSampling(); + break; + case sensorDeviceType::sht40: + sht40::startSampling(); + break; + case sensorDeviceType::tsl2591: + tsl2591::startSampling(); + break; + case sensorDeviceType::scd40: + scd40::startSampling(); + break; + // Add more types of sensors here + default: + break; + } +} + void sensorDeviceCollection::run() { for (auto index = 0U; index < static_cast(sensorDeviceType::nmbrOfKnownDevices); index++) { if (present[index]) { @@ -113,39 +115,28 @@ void sensorDeviceCollection::run() { } } +bool sensorDeviceCollection::isSamplingReady(sensorDeviceType aDeviceType) { + switch (aDeviceType) { + case sensorDeviceType::battery: + return (battery::getState() == sensorDeviceState::sleeping); + case sensorDeviceType::bme680: + return (bme680::getState() == sensorDeviceState::sleeping); + case sensorDeviceType::sht40: + return (sht40::getState() == sensorDeviceState::sleeping); + case sensorDeviceType::tsl2591: + return (tsl2591::getState() == sensorDeviceState::sleeping); + case sensorDeviceType::scd40: + return (scd40::getState() == sensorDeviceState::sleeping); + // Add more types of sensors here + default: + return true; + } +} + bool sensorDeviceCollection::isSamplingReady() { for (auto index = 0U; index < static_cast(sensorDeviceType::nmbrOfKnownDevices); index++) { - if (present[index]) { - switch (static_cast(index)) { - case sensorDeviceType::battery: - if (battery::getState() != sensorDeviceState::sleeping) { - return false; - } - break; - case sensorDeviceType::bme680: - if (bme680::getState() != sensorDeviceState::sleeping) { - return false; - } - break; - case sensorDeviceType::sht40: - if (sht40::getState() != sensorDeviceState::sleeping) { - return false; - } - break; - case sensorDeviceType::tsl2591: - if (tsl2591::getState() != sensorDeviceState::sleeping) { - return false; - } - break; - case sensorDeviceType::scd40: - if (scd40::getState() != sensorDeviceState::sleeping) { - return false; - } - break; - // Add more types of sensors here - default: - break; - } + if ((present[index]) && (!isSamplingReady(static_cast(index)))) { + return false; } } return true; diff --git a/lib/sensors/sensordevicecollection.hpp b/lib/sensors/sensordevicecollection.hpp index 1c0eb89..407ef28 100644 --- a/lib/sensors/sensordevicecollection.hpp +++ b/lib/sensors/sensordevicecollection.hpp @@ -34,8 +34,10 @@ class sensorDeviceCollection { static bool needsSampling(uint32_t deviceIndex, uint32_t channelIndex); static void startSampling(); + static void startSampling(sensorDeviceType aDeviceType); static bool isSamplingReady(); + static bool isSamplingReady(sensorDeviceType aDeviceType); static bool hasNewMeasurements(); static bool hasNewMeasurements(uint32_t deviceIndex);