// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #include "CSQHandler.hpp" #include #include #include #include namespace { constexpr auto urcThreshold = 4; constexpr auto pollModeDuration = std::chrono::minutes{60}; bool isRssiValid(std::uint32_t csq) { constexpr auto invalidRssiLow = 99; constexpr auto invalidRssiHigh = 199; return ((csq != invalidRssiLow) && (csq != invalidRssiHigh)); } } // namespace namespace cellular::service { void CSQHandler::handleTimerTick() { if (currentMode == CSQMode::HybridPolling) { if (isPollModeTimeElapsed()) { LOG_INFO("CSQ poll mode timer elapsed"); switchToHybridReportMode(); return; } getCSQ(); } } void CSQHandler::handleURCCounterMessage(std::uint32_t counter) { urcCounter = counter; if (isTooManyURCs() && (currentMode == CSQMode::HybridReporting)) { switchToHybridPollMode(); } } auto CSQHandler::isTooManyURCs() -> bool { return (urcCounter > urcThreshold); } auto CSQHandler::isPollModeTimeElapsed() -> bool { const auto currentTime = cpp_freertos::Ticks::TicksToMs(cpp_freertos::Ticks::GetTicks()); const auto timeSpentInPollMode = utils::computeIncrease(currentTime, switchToPollModeTimestamp); return (timeSpentInPollMode >= std::chrono::duration_cast(pollModeDuration).count()); } void CSQHandler::checkConditionToChangeMode() { if (currentMode != CSQMode::PermanentReporting) { if (!isPhoneLocked || isBluetoothCarKitConnected || (Store::Battery::get().state != Store::Battery::State::Discharging)) { switchToPermanentReportMode(); } } else { if (isPhoneLocked && !isBluetoothCarKitConnected && (Store::Battery::get().state == Store::Battery::State::Discharging)) { switchToHybridReportMode(); } } } bool CSQHandler::switchToPermanentReportMode() { if ((onEnableCsqReporting != nullptr) && onEnableCsqReporting()) { currentMode = CSQMode::PermanentReporting; LOG_INFO("Switch to permanent report mode"); return true; } LOG_ERROR("Failed to switch to CSQ permanent report mode, retrying"); if (onRetrySwitchMode != nullptr) { onRetrySwitchMode(CSQMode::PermanentReporting); } return false; } bool CSQHandler::switchToHybridReportMode() { if ((onEnableCsqReporting != nullptr) && onEnableCsqReporting()) { currentMode = CSQMode::HybridReporting; LOG_INFO("Switching to hybrid report mode"); return true; } LOG_ERROR("Failed to switch to CSQ hybrid report mode, retrying"); if (onRetrySwitchMode != nullptr) { onRetrySwitchMode(CSQMode::HybridReporting); } return false; } bool CSQHandler::switchToHybridPollMode() { if ((onDisableCsqReporting != nullptr) && onDisableCsqReporting()) { currentMode = CSQMode::HybridPolling; switchToPollModeTimestamp = cpp_freertos::Ticks::TicksToMs(cpp_freertos::Ticks::GetTicks()); LOG_INFO("Too many signal strength updates, switching to hybrid poll mode"); return true; } LOG_ERROR("Failed to switch to CSQ hybrid poll mode, retrying"); if (onRetrySwitchMode != nullptr) { onRetrySwitchMode(CSQMode::HybridPolling); } return false; } bool CSQHandler::getCSQ() { if (onGetCsq != nullptr) { if (const auto &result = onGetCsq(); result.has_value()) { const auto &csq = result.value(); if (isRssiValid(csq.csq)) { LOG_INFO("Propagating valid CSQ"); if (onPropagateCSQ != nullptr) { onPropagateCSQ(csq.csq); return true; } } else { LOG_INFO("Invalid CSQ, notifying service antenna"); if (onInvalidCSQ != nullptr) { onInvalidCSQ(); return true; } } } } LOG_ERROR("Failed to get CSQ, retrying"); if (onRetryGetCSQ != nullptr) { onRetryGetCSQ(); } return false; } void CSQHandler::handleLockPhone() { isPhoneLocked = true; } void CSQHandler::handleUnlockPhone() { isPhoneLocked = false; } void CSQHandler::handleBluetoothCarKitConnect() { isBluetoothCarKitConnected = true; } void CSQHandler::handleBluetoothCarKitDisconnect() { isBluetoothCarKitConnected = false; } } // namespace cellular::service