diff --git a/lib/application/maincontroller.cpp b/lib/application/maincontroller.cpp index 8f82718..ab4025e 100644 --- a/lib/application/maincontroller.cpp +++ b/lib/application/maincontroller.cpp @@ -260,6 +260,11 @@ void mainController::handleEventsStateNetworking(applicationEvent theEvent) { LoRaWAN::handleEvents(theEvent); break; + case applicationEvent::downlinkApplicationPayloadReceived: + handleDownLink(LoRaWAN::getPort(), LoRaWAN::getPayloadPtr(), LoRaWAN::getPayloadLength()); + LoRaWAN::getReceivedDownlinkMessage(); + break; + default: break; } @@ -389,7 +394,7 @@ void mainController::showLoRaWanStatus() { snprintf(tmpString, screen::maxConsoleTextLength, "Gateways : %u", static_cast(LoRaWAN::gatewayCount)); screen::setText(5, tmpString); time_t rtcTime = realTimeClock::get(); - const struct tm* rtcTime2 = localtime(&rtcTime); + const struct tm* rtcTime2 = gmtime(&rtcTime); strftime(tmpString, screen::maxConsoleTextLength, "Date : %Y-%b-%d", rtcTime2); screen::setText(6, tmpString); strftime(tmpString, screen::maxConsoleTextLength, "Time : %H:%M:%S", rtcTime2); @@ -590,7 +595,7 @@ void mainController::showPrompt() { } void mainController::showHelp() { - cli::sendResponse(" :show build info and license\n"); + cli::sendResponse(" : show build info and license\n"); cli::sendResponse("? : show help\n"); cli::sendResponse("gds : show device status\n"); cli::sendResponse("gms : show recorded measurements status\n"); @@ -613,12 +618,14 @@ void mainController::showHelp() { } void mainController::showDeviceStatus() { - cli::sendResponse("UID : %s\n", uniqueId::asHexString()); - cli::sendResponse("name : %s\n", name); - cli::sendResponse("display : %s\n", display::isPresent() ? "present" : "not present"); - cli::sendResponse("EEPROM : %d * 64K present\n", nonVolatileStorage::getNmbr64KBanks()); - cli::sendResponse("battery : %s (%d)\n", toString(battery::getType()), static_cast(battery::getType())); - cli::sendResponse("radioType: %s (%d)\n", toString(sx126x::getType()), static_cast(sx126x::getType())); + cli::sendResponse("UID : %s\n", uniqueId::asHexString()); + cli::sendResponse("name : %s\n", name); + cli::sendResponse("display : %s\n", display::isPresent() ? "present" : "not present"); + cli::sendResponse("EEPROM : %d * 64K present\n", nonVolatileStorage::getNmbr64KBanks()); + cli::sendResponse("battery : %s (%d)\n", toString(battery::getType()), static_cast(battery::getType())); + cli::sendResponse("radio : %s (%d)\n", toString(sx126x::getType()), static_cast(sx126x::getType())); + time_t rtcTime = realTimeClock::get(); + cli::sendResponse("RTC : %s", ctime(&rtcTime)); for (uint32_t sensorDeviceIndex = 0; sensorDeviceIndex < static_cast(sensorDeviceType::nmbrOfKnownDevices); sensorDeviceIndex++) { if (sensorDeviceCollection::isPresent(sensorDeviceIndex)) { @@ -780,6 +787,7 @@ void mainController::setDisplay(const cliCommand& theCommand) { displayChannelIndex[tmpLineIndex] = tmpChannelIndex; cli::sendResponse("display line %u set to %s - %s\n", tmpLineIndex, sensorDeviceCollection::name(tmpDeviceIndex), sensorDeviceCollection::name(tmpDeviceIndex, tmpChannelIndex)); + showMain(); } void mainController::setSensor(const cliCommand& theCommand) { @@ -938,4 +946,71 @@ void mainController::showMeasurementsCsv() { nmbrOfGroups++; offset += measurementGroup::lengthInBytes(tmpGroup.getNumberOfMeasurements()); } +} + +void mainController::setDisplay(const uint8_t* payload, const uint32_t payloadLength) { + if (payload == nullptr) { + return; + } + if (payloadLength != 3) { + return; + } + uint32_t tmpLineIndex = payload[0]; + if (tmpLineIndex >= screen::nmbrOfMeasurementTextLines) { + return; + } + uint32_t tmpDeviceIndex = payload[1]; + uint32_t tmpChannelIndex = payload[2]; + if (!sensorDeviceCollection::isValid(tmpDeviceIndex, tmpChannelIndex)) { + return; + } + uint8_t tmpDeviceAndChannel = sensorChannel::compressDeviceAndChannelIndex(static_cast(tmpDeviceIndex), static_cast(tmpChannelIndex)); + settingsCollection::save(tmpDeviceAndChannel, settingsCollection::settingIndex::displaySettings, tmpLineIndex); + displayDeviceIndex[tmpLineIndex] = tmpDeviceIndex; + displayChannelIndex[tmpLineIndex] = tmpChannelIndex; + showMain(); +} + +void mainController::setSensor(const uint8_t* payload, const uint32_t payloadLength) { + if (payload == nullptr) { + return; + } + if (payloadLength != 4) { + return; + } + uint32_t tmpDeviceIndex = payload[0]; + uint32_t tmpChannelIndex = payload[1]; + if (!sensorDeviceCollection::isValid(tmpDeviceIndex, tmpChannelIndex)) { + return; + } + uint32_t tmpOversamplingIndex = payload[2]; + ; + uint32_t tmpPrescalerIndex = payload[3]; + ; + if (tmpPrescalerIndex > sensorChannel::maxPrescalerIndex) { + tmpPrescalerIndex = sensorChannel::maxPrescalerIndex; + } + if (tmpOversamplingIndex > sensorChannel::maxOversamplingIndex) { + tmpOversamplingIndex = sensorChannel::maxOversamplingIndex; + } + if (tmpOversamplingIndex > tmpPrescalerIndex) { + tmpOversamplingIndex = tmpPrescalerIndex; + } + uint8_t tmpCombined = sensorChannel::compressOversamplingAndPrescalerIndex(tmpOversamplingIndex, tmpPrescalerIndex); + uint8_t tmpDeviceAndChannel = sensorChannel::compressDeviceAndChannelIndex(static_cast(tmpDeviceIndex), static_cast(tmpChannelIndex)); + settingsCollection::save(tmpCombined, settingsCollection::settingIndex::sensorSettings, tmpDeviceAndChannel); + sensorDeviceCollection::channel(tmpDeviceIndex, tmpChannelIndex).setIndex(tmpOversamplingIndex, tmpPrescalerIndex); +} + +void mainController::handleDownLink(const uint8_t port, const uint8_t* payload, const uint32_t payloadLength) { + switch (port) { + case 1: + setDisplay(payload, payloadLength); + break; + case 2: + setSensor(payload, payloadLength); + break; + default: + break; + } } \ No newline at end of file diff --git a/lib/application/maincontroller.hpp b/lib/application/maincontroller.hpp index c4468a1..97660ca 100644 --- a/lib/application/maincontroller.hpp +++ b/lib/application/maincontroller.hpp @@ -37,11 +37,11 @@ class mainController { static constexpr uint32_t minNmbrAnswers{2}; static constexpr uint32_t maxNmbrRequests{12}; - - #ifndef unitTesting - - // private: - #endif + +#ifndef unitTesting + +// private: +#endif static char name[maxNameLength + 1]; static uint32_t displayDeviceIndex[screen::nmbrOfMeasurementTextLines]; static uint32_t displayChannelIndex[screen::nmbrOfMeasurementTextLines]; @@ -80,4 +80,8 @@ class mainController { static void setRadioType(const cliCommand& aCommand); static void setDisplay(const cliCommand& aCommand); static void setSensor(const cliCommand& aCommand); + + static void setSensor(const uint8_t* payload, const uint32_t payloadLength); + static void setDisplay(const uint8_t* payload, const uint32_t payloadLength); + static void handleDownLink(const uint8_t port, const uint8_t* payload, const uint32_t payloadLength); }; diff --git a/lib/logging/logging.cpp b/lib/logging/logging.cpp index 0f3c129..683fa14 100644 --- a/lib/logging/logging.cpp +++ b/lib/logging/logging.cpp @@ -27,6 +27,9 @@ char logging::buffer[bufferLength]{}; void logging::initialize() { enable(logging::destination::uart1); + + enable(logging::source::lorawanData); + enable(logging::source::error); enable(logging::source::criticalError); } diff --git a/lib/lorawan/deviceaddress.hpp b/lib/lorawan/deviceaddress.hpp index 9ba71c7..4179690 100644 --- a/lib/lorawan/deviceaddress.hpp +++ b/lib/lorawan/deviceaddress.hpp @@ -10,6 +10,12 @@ class deviceAddress { public: + deviceAddress() = default; + deviceAddress(const deviceAddress&) = delete; + deviceAddress& operator=(const deviceAddress&) = delete; + deviceAddress(deviceAddress&&) = delete; + deviceAddress& operator=(deviceAddress&&) = delete; + static constexpr uint32_t lengthInBytes{4}; static constexpr uint32_t lengthAsHexAscii{8}; diff --git a/lib/lorawan/framecount.hpp b/lib/lorawan/framecount.hpp index 4da798b..fcdc560 100644 --- a/lib/lorawan/framecount.hpp +++ b/lib/lorawan/framecount.hpp @@ -9,6 +9,11 @@ class frameCount { public: + frameCount() = default; + frameCount(const frameCount&) = delete; + frameCount& operator=(const frameCount&) = delete; + frameCount& operator=(frameCount&&) = delete; + static constexpr uint32_t lengthInBytes{4}; static constexpr uint32_t lengthInWords{1}; void guessFromUint16(uint16_t frameCount16Lsb); diff --git a/lib/lorawan/lorawan.cpp b/lib/lorawan/lorawan.cpp index d3beabf..35df600 100644 --- a/lib/lorawan/lorawan.cpp +++ b/lib/lorawan/lorawan.cpp @@ -386,7 +386,7 @@ void LoRaWAN::encryptDecryptPayload(const aesKey& theKey, linkDirection theLinkD } void LoRaWAN::generateKeysK1K2() { - for (uint32_t byteIndex=0; byteIndex < aesKey::lengthInBytes; byteIndex++) { + for (uint32_t byteIndex = 0; byteIndex < aesKey::lengthInBytes; byteIndex++) { K1.setByte(byteIndex, 0); K2.setByte(byteIndex, 0); } @@ -627,15 +627,15 @@ void LoRaWAN::handleEvents(applicationEvent theEvent) { case messageType::application: lptim::stop(); processMacContents(); - applicationEventBuffer.push(applicationEvent::downlinkApplicationPayloadReceived); goTo(txRxCycleState::waitForRxMessageReadout); + applicationEventBuffer.push(applicationEvent::downlinkApplicationPayloadReceived); return; break; case messageType::lorawanMac: lptim::stop(); processMacContents(); - applicationEventBuffer.push(applicationEvent::downlinkMacCommandReceived); goTo(txRxCycleState::idle); + applicationEventBuffer.push(applicationEvent::downlinkMacCommandReceived); return; break; case messageType::invalid: // intentional fallthrough @@ -676,12 +676,14 @@ void LoRaWAN::handleEvents(applicationEvent theEvent) { messageType receivedMessageType = decodeMessage(); switch (receivedMessageType) { case messageType::application: + lptim::stop(); processMacContents(); applicationEventBuffer.push(applicationEvent::downlinkApplicationPayloadReceived); goTo(txRxCycleState::waitForRxMessageReadout); return; break; case messageType::lorawanMac: + lptim::stop(); processMacContents(); applicationEventBuffer.push(applicationEvent::downlinkMacCommandReceived); goTo(txRxCycleState::idle); @@ -1099,6 +1101,7 @@ void LoRaWAN::sendUplink(uint8_t theFramePort, const uint8_t applicationData[], void LoRaWAN::getReceivedDownlinkMessage() { // sx126x::getReceivedMessage(); // downlinkMessage.processDownlinkMessage(applicationPayloadReceived); + goTo(txRxCycleState::idle); } messageType LoRaWAN::decodeMessage() { @@ -1113,7 +1116,7 @@ messageType LoRaWAN::decodeMessage() { // 2. Extract & guess the downLinkFrameCount, as we need this to check the MIC uint16_t receivedDownlinkFramecount = receivedFramecount(); frameCount guessedDownlinkFramecount; - guessedDownlinkFramecount = downlinkFrameCount; + guessedDownlinkFramecount.setFromWord(downlinkFrameCount.getAsWord()); guessedDownlinkFramecount.guessFromUint16(receivedDownlinkFramecount); logging::snprintf(logging::source::lorawanMac, "receivedFramecount = %u, lastFramecount = %u, guessedFramecount = %u\n", receivedDownlinkFramecount, downlinkFrameCount.getAsWord(), guessedDownlinkFramecount.getAsWord()); @@ -1141,13 +1144,13 @@ messageType LoRaWAN::decodeMessage() { } // 5. check if the frameCount is valid - if (!isValidDownlinkFrameCount(guessedDownlinkFramecount)) { + if (!isValidDownlinkFrameCount(guessedDownlinkFramecount.getAsWord())) { logging::snprintf(logging::source::error, "Error : invalid downlinkFrameCount : received %u, current %u\n", guessedDownlinkFramecount.getAsWord(), downlinkFrameCount.getAsWord()); return messageType::invalid; } // 6. Seems a valid message, so update the downlinkFrameCount to what we've received (not just incrementing it, as there could be gaps in the sequence due to lost packets) - downlinkFrameCount = guessedDownlinkFramecount; + downlinkFrameCount.setFromWord(guessedDownlinkFramecount.getAsWord()); settingsCollection::save(downlinkFrameCount.getAsWord(), settingsCollection::settingIndex::downlinkFrameCounter); // 6.5 If we had sticky macOut stuff, we can clear that now, as we did receive a valid downlink @@ -1195,11 +1198,11 @@ uint32_t LoRaWAN::getReceiveTimeout(spreadingFactor aSpreadingFactor) { } } -bool LoRaWAN::isValidDownlinkFrameCount(frameCount testFrameCount) { +bool LoRaWAN::isValidDownlinkFrameCount(uint32_t testValue) { if (downlinkFrameCount.getAsWord() == 0) { return true; // no downlink received yet, so any frameCount is valid } else { - return (testFrameCount.getAsWord() > downlinkFrameCount.getAsWord()); + return (testValue > downlinkFrameCount.getAsWord()); } } @@ -1341,3 +1344,27 @@ void LoRaWAN::resetMacLayer() { resetChannels(); saveChannels(); } + +uint8_t LoRaWAN::getPort() { + if (framePortLength > 0) { + return rawMessage[framePortOffset]; + } else { + return 0; + } +} + +uint32_t LoRaWAN::getPayloadLength() { + return framePayloadLength; +} + +void LoRaWAN::getPayload(uint8_t* destination, uint32_t length) { + memcpy(destination, rawMessage + framePayloadOffset, length); +} + +const uint8_t* LoRaWAN::getPayloadPtr() { + if (framePayloadLength > 0) { + return rawMessage + framePayloadOffset; + } else { + return nullptr; + } +} \ No newline at end of file diff --git a/lib/lorawan/lorawan.hpp b/lib/lorawan/lorawan.hpp index 64940ef..6719886 100644 --- a/lib/lorawan/lorawan.hpp +++ b/lib/lorawan/lorawan.hpp @@ -58,9 +58,16 @@ class LoRaWAN { static void handleEvents(applicationEvent theEvent); static uint32_t getMaxApplicationPayloadLength(); + static void sendUplink(uint8_t framePort, const uint8_t payload[], uint32_t payloadLength); static void sendUplink(const measurementGroup &aMeasurementGroup); + static uint8_t getPort(); + static uint32_t getPayloadLength(); + static void getPayload(uint8_t* destination, uint32_t length); + static const uint8_t * getPayloadPtr(); + + static void appendMacCommand(macCommand theMacCommand); static void getReceivedDownlinkMessage(); static txRxCycleState getState(); @@ -186,9 +193,11 @@ class LoRaWAN { static uint16_t receivedFramecount(); static uint32_t receivedDeviceAddress(); static uint32_t receivedMic(); - static bool isValidDownlinkFrameCount(frameCount testFrameCount); + static bool isValidDownlinkFrameCount(uint32_t testFrameCount); static messageType decodeMessage(); + + // ############################################################# // ### Other Helper functions ### // ############################################################# diff --git a/platformio.ini b/platformio.ini index 73f8546..a3fe8bc 100644 --- a/platformio.ini +++ b/platformio.ini @@ -120,7 +120,7 @@ test_filter = ;generic/test_logging ;generic/test_gpio ;generic/test_power - generic/test_display + ;generic/test_display ;generic/test_battery ;generic/test_bme68x ;generic/test_tsl2591 @@ -131,8 +131,8 @@ test_filter = ;generic/test_applicationevent ;generic/test_graphics ;generic/test_lorawan_deviceaddress - ;generic/test_framecount - ;generic/test_lorawan_0_general + generic/test_framecount + generic/test_lorawan_0_general ;generic/test_lorawan_1_rawmessage ;generic/test_lorawan_2_crypto ;generic/test_lorawan_3_txrxcycle diff --git a/test/generic/test_framecount/test.cpp b/test/generic/test_framecount/test.cpp index bd6ec61..74e1373 100644 --- a/test/generic/test_framecount/test.cpp +++ b/test/generic/test_framecount/test.cpp @@ -21,25 +21,6 @@ void test_initialize() { } } -void test_operatorAssign() { - frameCount testFrameCount1; - frameCount testFrameCount2; - TEST_ASSERT_EQUAL(0, testFrameCount1.getAsWord()); - TEST_ASSERT_EQUAL(0, testFrameCount2.getAsWord()); - testFrameCount1.setFromWord(0x12345678); - TEST_ASSERT_EQUAL(0x12345678, testFrameCount1.getAsWord()); - uint8_t expectedBytes1[frameCount::lengthInBytes]{0x78, 0x56, 0x34, 0x12}; - for (uint32_t index = 0; index < frameCount::lengthInBytes; index++) { - TEST_ASSERT_EQUAL(expectedBytes1[index], testFrameCount1.getAsByte(index)); - } - testFrameCount2 = testFrameCount1; - TEST_ASSERT_EQUAL(0x12345678, testFrameCount2.getAsWord()); - uint8_t expectedBytes2[frameCount::lengthInBytes]{0x78, 0x56, 0x34, 0x12}; - for (uint32_t index = 0; index < frameCount::lengthInBytes; index++) { - TEST_ASSERT_EQUAL(expectedBytes2[index], testFrameCount2.getAsByte(index)); - } -} - void test_setFromByteArray() { frameCount testFrameCount; uint8_t testBytes[frameCount::lengthInBytes]{0x78, 0x56, 0x34, 0x12}; @@ -106,8 +87,7 @@ int main(int argc, char **argv) { #endif UNITY_BEGIN(); RUN_TEST(test_initialize); - RUN_TEST(test_operatorAssign); - RUN_TEST(test_setFromByteArray); + RUN_TEST(test_setFromByteArray); RUN_TEST(test_SetFromWord); RUN_TEST(test_operatorIncrement); RUN_TEST(test_guessFromUint16); diff --git a/test/generic/test_lorawan_0_general/test.cpp b/test/generic/test_lorawan_0_general/test.cpp index 22deac4..639016b 100644 --- a/test/generic/test_lorawan_0_general/test.cpp +++ b/test/generic/test_lorawan_0_general/test.cpp @@ -112,13 +112,13 @@ void test_isValidDownlinkFrameCount() { LoRaWAN::downlinkFrameCount.setFromWord(0); frameCount testFrameCount; testFrameCount.setFromWord(10); - TEST_ASSERT_TRUE(LoRaWAN::isValidDownlinkFrameCount(testFrameCount)); + TEST_ASSERT_TRUE(LoRaWAN::isValidDownlinkFrameCount(testFrameCount.getAsWord())); LoRaWAN::downlinkFrameCount.setFromWord(9); - TEST_ASSERT_TRUE(LoRaWAN::isValidDownlinkFrameCount(testFrameCount)); + TEST_ASSERT_TRUE(LoRaWAN::isValidDownlinkFrameCount(testFrameCount.getAsWord())); LoRaWAN::downlinkFrameCount.setFromWord(10); - TEST_ASSERT_FALSE(LoRaWAN::isValidDownlinkFrameCount(testFrameCount)); + TEST_ASSERT_FALSE(LoRaWAN::isValidDownlinkFrameCount(testFrameCount.getAsWord())); LoRaWAN::downlinkFrameCount.setFromWord(11); - TEST_ASSERT_FALSE(LoRaWAN::isValidDownlinkFrameCount(testFrameCount)); + TEST_ASSERT_FALSE(LoRaWAN::isValidDownlinkFrameCount(testFrameCount.getAsWord())); } void test_dump() { @@ -136,44 +136,6 @@ void test_dump() { TEST_MESSAGE("For Coverage only"); } -// void test_saveContext() { -// memset(mockEepromMemory, 0x00, 512); - -// LoRaWAN::DevAddr = 0x44657641; // reads as DevA in memory -// LoRaWAN::uplinkFrameCount = 0x554C4643; // reads as ULFC in memory -// LoRaWAN::downlinkFrameCount = 0x444C4643; // reads as DLFC in memory -// LoRaWAN::rx1DelayInSeconds = 7; -// LoRaWAN::currentDataRateIndex = 3; -// LoRaWAN::applicationKey.setFromHexString("000102030405060708090A0B0C0D0E0F"); -// LoRaWAN::networkKey.setFromHexString("101112131415161718191A1B1C1D1E1F"); - -// LoRaWAN::saveConfig(); -// LoRaWAN::saveState(); -// LoRaWAN::saveChannels(); - -// LoRaWAN::DevAddr = 0; -// LoRaWAN::uplinkFrameCount = 0; -// LoRaWAN::downlinkFrameCount = 0; -// LoRaWAN::rx1DelayInSeconds = 0; -// LoRaWAN::currentDataRateIndex = 0; -// LoRaWAN::applicationKey.setFromHexString("00000000000000000000000000000000"); -// LoRaWAN::networkKey.setFromHexString("00000000000000000000000000000000"); - -// LoRaWAN::restoreConfig(); -// LoRaWAN::restoreState(); -// LoRaWAN::restoreChannels(); - -// TEST_ASSERT_EQUAL_UINT32(0x44657641, LoRaWAN::DevAddr.asUint32); -// TEST_ASSERT_EQUAL_UINT32(0x554C4643, LoRaWAN::uplinkFrameCount.toUint32()); -// TEST_ASSERT_EQUAL_UINT32(0x444C4643, LoRaWAN::downlinkFrameCount.toUint32()); -// TEST_ASSERT_EQUAL_UINT32(7, LoRaWAN::rx1DelayInSeconds); -// TEST_ASSERT_EQUAL_UINT32(3, LoRaWAN::currentDataRateIndex); -// char tmpKeyAsHexString[33]; -// hexAscii::byteArrayToHexString(tmpKeyAsHexString, LoRaWAN::applicationKey.asBytes(), 16); -// TEST_ASSERT_EQUAL_STRING("000102030405060708090A0B0C0D0E0F", tmpKeyAsHexString); -// hexAscii::byteArrayToHexString(tmpKeyAsHexString, LoRaWAN::networkKey.asBytes(), 16); -// TEST_ASSERT_EQUAL_STRING("101112131415161718191A1B1C1D1E1F", tmpKeyAsHexString); -// } int main(int argc, char **argv) { UNITY_BEGIN(); @@ -187,7 +149,6 @@ int main(int argc, char **argv) { RUN_TEST(test_save_restore_channels); RUN_TEST(test_isValidDownlinkFrameCount); RUN_TEST(test_dump); - // RUN_TEST(test_saveContext); UNITY_END(); } \ No newline at end of file