diff --git a/src/cli.cpp b/src/cli.cpp index 5914944..45189ff 100644 --- a/src/cli.cpp +++ b/src/cli.cpp @@ -163,16 +163,7 @@ void process_command(const char* cmd) { if (valid_433 || valid_868) { if (lora_system != nullptr) { - // SX1276 formula: Frf = Ffreq * 2^19 / 32000000 - // Using double to prevent truncation during division before bit masking - double fraction = (static_cast(target_freq_hz) * 524288.0) / 32000000.0; - uint32_t frf = static_cast(fraction); - - uint8_t msb = static_cast((frf >> 16) & 0xFFU); - uint8_t mid = static_cast((frf >> 8) & 0xFFU); - uint8_t lsb = static_cast(frf & 0xFFU); - - lora_system->setFrequency(msb, mid, lsb); + lora_system->setFrequency(target_freq_hz); printf("Success: Frequency shifted to %lu Hz.\r\n", (unsigned long)target_freq_hz); } else { printf("Error: LoraController handle is uninitialized.\r\n"); diff --git a/src/config.hpp b/src/config.hpp index 5aed84d..b41b42b 100644 --- a/src/config.hpp +++ b/src/config.hpp @@ -22,7 +22,7 @@ namespace Config { // Compile-time constants with strict type enforcement constexpr const char* PROJECT_TITLE = "FoxMesh"; - constexpr const char* PROJECT_VERSION = "1.0.3"; + constexpr const char* PROJECT_VERSION = "1.0.4"; constexpr const char* PROJECT_AUTHORS = "Tom OE3TKT"; // CLI Mute Configuration diff --git a/src/lora.cpp b/src/lora.cpp index feb1b5d..fc403d0 100644 --- a/src/lora.cpp +++ b/src/lora.cpp @@ -108,11 +108,26 @@ void LoraController::setFrequency(uint32_t freq_hz) { if (xSemaphoreTake(m_stateMutex, portMAX_DELAY) == pdTRUE) { m_state.frequencyHz = freq_hz; - // Translate frequency configuration parameter layouts to register bytes... - // writeRegister(0x06, msb); etc. + // Force trx into Standby mode to update hardware frequency registers safely + uint8_t previousMode = readRegister(0x01); // RegOpMode + writeRegister(0x01, (previousMode & 0xF8U) | 0x01U); // Set to Standby (0x01) + vTaskDelay(pdMS_TO_TICKS(5)); + + // Calculate the 24-bit frequency word using 64-bit precision to avoid intermediate overflow + // Formula: FRF = (freq_hz * 2^19) / 32 000 000 + uint64_t frf = ((uint64_t)freq_hz << 19) / 32000000ULL; + + // Split the 24-bit tracking token across the three consecutive hardware registers + writeRegister(0x06, static_cast((frf >> 16) & 0xFFU)); // RegFrfMsb + writeRegister(0x07, static_cast((frf >> 8) & 0xFFU)); // RegFrfMid + writeRegister(0x08, static_cast(frf & 0xFFU)); // RegFrfLsb + + writeRegister(0x01, previousMode); xSemaphoreGive(m_stateMutex); - ESP_LOGI(TAG, "Frequency updated to %lu Hz", (unsigned long)freq_hz); + + // High-precision formatted terminal trace showing both decimal and uppercase 24-bit hex configurations + ESP_LOGI(TAG, "Frequency updated to %lu Hz (0x%06X)", (unsigned long)freq_hz, (unsigned int)frf); } } @@ -269,8 +284,8 @@ void LoraController::sortListChronologically() { * @brief Safely clones active database tracks within temporary storage allocations to protect ongoing engine execution. * @return A deep copy duplicate containing isolated copies of the tracked packet records database tracking array. */ -std::list LoraController::getPacketListCopy() { - std::list listCopy; +std::list LoraController::getPacketListCopy() { + std::list listCopy; if (xSemaphoreTake(m_stateMutex, portMAX_DELAY) == pdTRUE) { listCopy = m_state.packetList; xSemaphoreGive(m_stateMutex); @@ -347,7 +362,7 @@ esp_err_t LoraController::transmitFrame(const uint8_t* buffer, uint8_t length) { * @brief Core trampoline context function remapping FreeRTOS pointer entries back into our object instances. * @param pvParameters Object execution context tracking reference token. */ -void LoraController::taskTrampoline(void pvParameters) { +void LoraController::taskTrampoline(void* pvParameters) { auto* instance = static_cast(pvParameters); if (instance != nullptr) { instance->run(); diff --git a/src/lora.hpp b/src/lora.hpp index 6db686f..896b069 100644 --- a/src/lora.hpp +++ b/src/lora.hpp @@ -19,14 +19,10 @@ * @brief Simple internal abstraction layer mirroring the raw incoming packet payload. */ struct LoraPacket { - /** @brief High-precision calibrated received signal power in dBm. */ - float rssi; - /** @brief High-precision calibrated signal-to-noise ratio in dB. */ - float snr; - /** @brief Payload size explicitly specified in bytes. */ - uint8_t length; - /** @brief Fixed internal memory buffer capturing raw ingress bytes. Max SX1276 FIFO is 256. */ - uint8_t payload[256]; + float rssi; /**< High-precision calibrated received signal power in dBm. */ + float snr; /**< High-precision calibrated signal-to-noise ratio in dB. */ + uint8_t length; /**< Payload size explicitly specified in bytes. */ + uint8_t payload[256]; /**< Fixed internal memory buffer capturing raw ingress bytes. Max SX1276 FIFO is 256. */ }; /** @@ -179,4 +175,15 @@ public: * @return A standalone, thread-isolated linked list duplicate snapshot copy containing current history rows. */ std::list getPacketListCopy(); + + /** + * @brief Generates an atomic, high-performance runtime snapshot of configuration parameters and metrics. + * @details This routine performs a rapid, thread-safe memory copy of the volatile tracking state variables. + * Unlike getPacketListCopy(), this method explicitly excludes the heavy heap-allocated packet list data, + * making it exceptionally lightweight and highly suitable for high-frequency UI display refreshes, + * CLI updates, or periodic remote health diagnostics. + * @note Acquires the internal synchronization mutex lock momentarily to guarantee structural telemetry alignment. + * @return A self-contained snapshot structure mapping the current system hardware configurations and operational counts. + */ + LoraStateSnapshot getSnapshot(); };