~aleteoryx/muditaos

e5114922d36952830fba3041cabeba7e98c60fc4 — Maciej Gibowicz 3 years ago ced8642
[MOS-138] Correction of URC poll mode parameters

In poll mode, the CSQ will be requested every 15 minutes
and another attempt to switch the mode will be after 1 hour.
If the keyboard is unlocked or the USB cable is connected
or the BT car kit is connected, the URCs will be operated
in the reporting mode.
M module-bluetooth/Bluetooth/Device.hpp => module-bluetooth/Bluetooth/Device.hpp +2 -2
@@ 88,9 88,9 @@ static inline std::string getListOfSupportedServicesInString(uint32_t cod)

enum class DeviceState
{
    ConnectedBoth,
    ConnectedAudio,
    ConnectedVoice,
    ConnectedAudio,
    ConnectedBoth,
    Connecting,
    Pairing,
    Paired,

M module-gui/gui/widgets/status-bar/BT.cpp => module-gui/gui/widgets/status-bar/BT.cpp +6 -2
@@ 1,4 1,4 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "BT.hpp"


@@ 23,7 23,11 @@ namespace gui::status_bar
        case sys::bluetooth::BluetoothMode::Enabled:
            set(bt_status, style::status_bar::imageTypeSpecifier);
            break;
        case sys::bluetooth::BluetoothMode::Connected:
        case sys::bluetooth::BluetoothMode::ConnectedVoice:
            [[fallthrough]];
        case sys::bluetooth::BluetoothMode::ConnectedAudio:
            [[fallthrough]];
        case sys::bluetooth::BluetoothMode::ConnectedBoth:
            set(bt_connected_status, style::status_bar::imageTypeSpecifier);
            break;
        }

M module-services/service-bluetooth/Constants.hpp => module-services/service-bluetooth/Constants.hpp +5 -3
@@ 1,4 1,4 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 12,8 12,10 @@ namespace sys::bluetooth
{
    enum class BluetoothMode
    {
        ConnectedVoice,
        ConnectedAudio,
        ConnectedBoth,
        Disabled,
        Enabled,
        Connected
        Enabled
    };
}

M module-services/service-bluetooth/ServiceBluetooth.cpp => module-services/service-bluetooth/ServiceBluetooth.cpp +16 -1
@@ 313,6 313,20 @@ auto ServiceBluetooth::handle(message::bluetooth::Connect *msg) -> std::shared_p
    return sys::MessageNone{};
}

auto convertDeviceStateIntoBluetoothState(const DeviceState &state) -> sys::bluetooth::BluetoothMode
{
    switch (state) {
    case DeviceState::ConnectedVoice:
        return sys::bluetooth::BluetoothMode::ConnectedVoice;
    case DeviceState::ConnectedAudio:
        return sys::bluetooth::BluetoothMode::ConnectedAudio;
    case DeviceState::ConnectedBoth:
        return sys::bluetooth::BluetoothMode::ConnectedBoth;
    default:
        return sys::bluetooth::BluetoothMode::Enabled;
    }
}

auto ServiceBluetooth::handle(message::bluetooth::ConnectResult *msg) -> std::shared_ptr<sys::Message>
{
    if (msg->isSucceed()) {


@@ 321,8 335,9 @@ auto ServiceBluetooth::handle(message::bluetooth::ConnectResult *msg) -> std::sh

        settingsHolder->setValue(bluetooth::Settings::ConnectedDevice, bd_addr_to_str(device.address));

        auto deviceState = bluetoothDevicesModel->getDeviceByAddress(device.address)->get().deviceState;
        bus.sendMulticast(
            std::make_shared<sys::bluetooth::BluetoothModeChanged>(sys::bluetooth::BluetoothMode::Connected),
            std::make_shared<sys::bluetooth::BluetoothModeChanged>(convertDeviceStateIntoBluetoothState(deviceState)),
            sys::BusChannel::BluetoothModeChanges);

        stopTimeoutTimer();

M module-services/service-cellular/ServiceCellular.cpp => module-services/service-cellular/ServiceCellular.cpp +1 -1
@@ 156,7 156,7 @@ ServiceCellular::ServiceCellular()
    simTimer = sys::TimerFactory::createSingleShotTimer(
        this, "simTimer", std::chrono::milliseconds{6000}, [this](sys::Timer &) { priv->simCard->handleSimTimer(); });

    csqTimer = sys::TimerFactory::createPeriodicTimer(this, "csqTimer", std::chrono::seconds{60}, [this](sys::Timer &) {
    csqTimer = sys::TimerFactory::createPeriodicTimer(this, "csqTimer", std::chrono::minutes{15}, [this](sys::Timer &) {
        auto message = std::make_shared<cellular::URCCounterMessage>(csqCounter.getCounter());
        csqCounter.clearCounter();
        bus.sendUnicast(std::move(message), serviceName);

M module-services/service-cellular/doc/README.md => module-services/service-cellular/doc/README.md +16 -0
@@ 15,6 15,22 @@ This way system voltage will not be dropped down when module is trying to acheiv

![](urc_handling.svg)

## CSQ handling flow

There are 3 modes of CSQ signal handling:
* Permanent Reporting

The host is constantly waiting to report data from the modem when the CSQ signal changes. This mode is active only when the user unlocks the keyboard or connects USB or connects the BT car kit.
![](csq_handling.svg)

* Hybrid Reporting

The host waits for data to be reported from the modem when the CSQ signal changes until the data is received more frequently than parameter 'cellular::service::urcThreshold'. When the threshold is exceeded, the mode changes to Hybrid Pooling.

* Hybrid Polling

Data reporting is disabled. The host queries the modem for the current CSQ value every 15 minutes. Every time specified by the 'cellular::service::pollTime' parameter, the system enters Hybrid Reporting mode again.

## Call Request handling flow

Call request represents the string written by te user in the input window.

A module-services/service-cellular/doc/csq_handling.puml => module-services/service-cellular/doc/csq_handling.puml +25 -0
@@ 0,0 1,25 @@
@startuml
skinparam BackgroundColor F0F0F0

start
fork
  :unlocks keyboard;
fork again
  :connects USB;
fork again
  :connects the BT car kit;
end fork {or}
: switch to Permanent Report Mode;
stop
start
fork
  :locks keyboard;
fork again
  :disconnects USB;
fork again
  :disconnects the BT car kit;
end fork {and}
: switch to Hybrid Report Mode;
stop

@enduml

A module-services/service-cellular/doc/csq_handling.svg => module-services/service-cellular/doc/csq_handling.svg +1 -0
@@ 0,0 1,1 @@
<?xml version='1.0' encoding='UTF-8' standalone='no'?><svg contentScriptType='application/ecmascript' contentStyleType='text/css' height='480px' preserveAspectRatio='none' style='width:569px;height:480px;background:#F0F0F0;' version='1.1' viewBox='0 0 569 480' width='569px' xmlns:xlink='http://www.w3.org/1999/xlink' xmlns='http://www.w3.org/2000/svg' zoomAndPan='magnify'><defs><filter height='300%' id='f1i28n6s4zieix' width='300%' x='-1' y='-1'><feGaussianBlur result='blurOut' stdDeviation='2.0'/><feColorMatrix in='blurOut' result='blurOut2' type='matrix' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .4 0'/><feOffset dx='4.0' dy='4.0' in='blurOut2' result='blurOut3'/><feBlend in='SourceGraphic' in2='blurOut3' mode='normal'/></filter></defs><g><ellipse cx='264' cy='20' fill='#000000' filter='url(#f1i28n6s4zieix)' rx='10' ry='10' style='stroke:none;stroke-width:1.0;'/><rect fill='#000000' filter='url(#f1i28n6s4zieix)' height='6' rx='2.5' ry='2.5' style='stroke:#000000;stroke-width:1.0;' width='486' x='21' y='50'/><rect fill='#FEFECE' filter='url(#f1i28n6s4zieix)' height='33.9688' rx='12.5' ry='12.5' style='stroke:#A80036;stroke-width:1.5;' width='130' x='35' y='76'/><text fill='#000000' font-family='sans-serif' font-size='12' lengthAdjust='spacing' textLength='110' x='45' y='97.1387'>unlocks keyboard</text><rect fill='#FEFECE' filter='url(#f1i28n6s4zieix)' height='33.9688' rx='12.5' ry='12.5' style='stroke:#A80036;stroke-width:1.5;' width='107' x='193' y='76'/><text fill='#000000' font-family='sans-serif' font-size='12' lengthAdjust='spacing' textLength='87' x='203' y='97.1387'>connects USB</text><rect fill='#FEFECE' filter='url(#f1i28n6s4zieix)' height='33.9688' rx='12.5' ry='12.5' style='stroke:#A80036;stroke-width:1.5;' width='165' x='328' y='76'/><text fill='#000000' font-family='sans-serif' font-size='12' lengthAdjust='spacing' textLength='145' x='338' y='97.1387'>connects the BT car kit</text><rect fill='#000000' filter='url(#f1i28n6s4zieix)' height='6' rx='2.5' ry='2.5' style='stroke:#000000;stroke-width:1.0;' width='486' x='21' y='129.9688'/><text fill='#000000' font-family='sans-serif' font-size='11' lengthAdjust='spacing' textLength='26' x='512' y='133.7769'>{or}</text><rect fill='#FEFECE' filter='url(#f1i28n6s4zieix)' height='33.9688' rx='12.5' ry='12.5' style='stroke:#A80036;stroke-width:1.5;' width='237' x='145.5' y='155.9688'/><text fill='#000000' font-family='sans-serif' font-size='12' lengthAdjust='spacing' textLength='213' x='159.5' y='177.1074'>switch to Permanent Report Mode</text><ellipse cx='264' cy='220.9375' fill='#F0F0F0' filter='url(#f1i28n6s4zieix)' rx='11' ry='11' style='stroke:#000000;stroke-width:1.0;'/><ellipse cx='264' cy='220.9375' fill='#000000' rx='6' ry='6' style='stroke:#787878;stroke-width:1.0;'/><ellipse cx='264' cy='251.9375' fill='#000000' filter='url(#f1i28n6s4zieix)' rx='10' ry='10' style='stroke:none;stroke-width:1.0;'/><rect fill='#000000' filter='url(#f1i28n6s4zieix)' height='6' rx='2.5' ry='2.5' style='stroke:#000000;stroke-width:1.0;' width='506' x='11' y='281.9375'/><rect fill='#FEFECE' filter='url(#f1i28n6s4zieix)' height='33.9688' rx='12.5' ry='12.5' style='stroke:#A80036;stroke-width:1.5;' width='114' x='25' y='307.9375'/><text fill='#000000' font-family='sans-serif' font-size='12' lengthAdjust='spacing' textLength='94' x='35' y='329.0762'>locks keyboard</text><rect fill='#FEFECE' filter='url(#f1i28n6s4zieix)' height='33.9688' rx='12.5' ry='12.5' style='stroke:#A80036;stroke-width:1.5;' width='125' x='167' y='307.9375'/><text fill='#000000' font-family='sans-serif' font-size='12' lengthAdjust='spacing' textLength='105' x='177' y='329.0762'>disconnects USB</text><rect fill='#FEFECE' filter='url(#f1i28n6s4zieix)' height='33.9688' rx='12.5' ry='12.5' style='stroke:#A80036;stroke-width:1.5;' width='183' x='320' y='307.9375'/><text fill='#000000' font-family='sans-serif' font-size='12' lengthAdjust='spacing' textLength='163' x='330' y='329.0762'>disconnects the BT car kit</text><rect fill='#000000' filter='url(#f1i28n6s4zieix)' height='6' rx='2.5' ry='2.5' style='stroke:#000000;stroke-width:1.0;' width='506' x='11' y='361.9063'/><text fill='#000000' font-family='sans-serif' font-size='11' lengthAdjust='spacing' textLength='35' x='522' y='365.7144'>{and}</text><rect fill='#FEFECE' filter='url(#f1i28n6s4zieix)' height='33.9688' rx='12.5' ry='12.5' style='stroke:#A80036;stroke-width:1.5;' width='207' x='160.5' y='387.9063'/><text fill='#000000' font-family='sans-serif' font-size='12' lengthAdjust='spacing' textLength='183' x='174.5' y='409.0449'>switch to Hybrid Report Mode</text><ellipse cx='264' cy='452.875' fill='#F0F0F0' filter='url(#f1i28n6s4zieix)' rx='11' ry='11' style='stroke:#000000;stroke-width:1.0;'/><ellipse cx='264' cy='452.875' fill='#000000' rx='6' ry='6' style='stroke:#787878;stroke-width:1.0;'/><line style='stroke:#A80036;stroke-width:1.5;' x1='100' x2='100' y1='56' y2='76'/><polygon fill='#A80036' points='96,66,100,76,104,66,100,70' style='stroke:#A80036;stroke-width:1.0;'/><line style='stroke:#A80036;stroke-width:1.5;' x1='246.5' x2='246.5' y1='56' y2='76'/><polygon fill='#A80036' points='242.5,66,246.5,76,250.5,66,246.5,70' style='stroke:#A80036;stroke-width:1.0;'/><line style='stroke:#A80036;stroke-width:1.5;' x1='410.5' x2='410.5' y1='56' y2='76'/><polygon fill='#A80036' points='406.5,66,410.5,76,414.5,66,410.5,70' style='stroke:#A80036;stroke-width:1.0;'/><line style='stroke:#A80036;stroke-width:1.5;' x1='100' x2='100' y1='109.9688' y2='129.9688'/><polygon fill='#A80036' points='96,119.9688,100,129.9688,104,119.9688,100,123.9688' style='stroke:#A80036;stroke-width:1.0;'/><line style='stroke:#A80036;stroke-width:1.5;' x1='246.5' x2='246.5' y1='109.9688' y2='129.9688'/><polygon fill='#A80036' points='242.5,119.9688,246.5,129.9688,250.5,119.9688,246.5,123.9688' style='stroke:#A80036;stroke-width:1.0;'/><line style='stroke:#A80036;stroke-width:1.5;' x1='410.5' x2='410.5' y1='109.9688' y2='129.9688'/><polygon fill='#A80036' points='406.5,119.9688,410.5,129.9688,414.5,119.9688,410.5,123.9688' style='stroke:#A80036;stroke-width:1.0;'/><line style='stroke:#A80036;stroke-width:1.5;' x1='264' x2='264' y1='30' y2='50'/><polygon fill='#A80036' points='260,40,264,50,268,40,264,44' style='stroke:#A80036;stroke-width:1.0;'/><line style='stroke:#A80036;stroke-width:1.5;' x1='264' x2='264' y1='135.9688' y2='155.9688'/><polygon fill='#A80036' points='260,145.9688,264,155.9688,268,145.9688,264,149.9688' style='stroke:#A80036;stroke-width:1.0;'/><line style='stroke:#A80036;stroke-width:1.5;' x1='264' x2='264' y1='189.9375' y2='209.9375'/><polygon fill='#A80036' points='260,199.9375,264,209.9375,268,199.9375,264,203.9375' style='stroke:#A80036;stroke-width:1.0;'/><line style='stroke:#A80036;stroke-width:1.5;' x1='82' x2='82' y1='287.9375' y2='307.9375'/><polygon fill='#A80036' points='78,297.9375,82,307.9375,86,297.9375,82,301.9375' style='stroke:#A80036;stroke-width:1.0;'/><line style='stroke:#A80036;stroke-width:1.5;' x1='229.5' x2='229.5' y1='287.9375' y2='307.9375'/><polygon fill='#A80036' points='225.5,297.9375,229.5,307.9375,233.5,297.9375,229.5,301.9375' style='stroke:#A80036;stroke-width:1.0;'/><line style='stroke:#A80036;stroke-width:1.5;' x1='411.5' x2='411.5' y1='287.9375' y2='307.9375'/><polygon fill='#A80036' points='407.5,297.9375,411.5,307.9375,415.5,297.9375,411.5,301.9375' style='stroke:#A80036;stroke-width:1.0;'/><line style='stroke:#A80036;stroke-width:1.5;' x1='82' x2='82' y1='341.9063' y2='361.9063'/><polygon fill='#A80036' points='78,351.9063,82,361.9063,86,351.9063,82,355.9063' style='stroke:#A80036;stroke-width:1.0;'/><line style='stroke:#A80036;stroke-width:1.5;' x1='229.5' x2='229.5' y1='341.9063' y2='361.9063'/><polygon fill='#A80036' points='225.5,351.9063,229.5,361.9063,233.5,351.9063,229.5,355.9063' style='stroke:#A80036;stroke-width:1.0;'/><line style='stroke:#A80036;stroke-width:1.5;' x1='411.5' x2='411.5' y1='341.9063' y2='361.9063'/><polygon fill='#A80036' points='407.5,351.9063,411.5,361.9063,415.5,351.9063,411.5,355.9063' style='stroke:#A80036;stroke-width:1.0;'/><line style='stroke:#A80036;stroke-width:1.5;' x1='264' x2='264' y1='261.9375' y2='281.9375'/><polygon fill='#A80036' points='260,271.9375,264,281.9375,268,271.9375,264,275.9375' style='stroke:#A80036;stroke-width:1.0;'/><line style='stroke:#A80036;stroke-width:1.5;' x1='264' x2='264' y1='367.9063' y2='387.9063'/><polygon fill='#A80036' points='260,377.9063,264,387.9063,268,377.9063,264,381.9063' style='stroke:#A80036;stroke-width:1.0;'/><line style='stroke:#A80036;stroke-width:1.5;' x1='264' x2='264' y1='421.875' y2='441.875'/><polygon fill='#A80036' points='260,431.875,264,441.875,268,431.875,264,435.875' style='stroke:#A80036;stroke-width:1.0;'/></g></svg>
\ No newline at end of file

M module-services/service-cellular/service-cellular/CellularMessage.hpp => module-services/service-cellular/service-cellular/CellularMessage.hpp +11 -5
@@ 1006,15 1006,21 @@ namespace cellular
    class RetrySwitchCSQMode : public sys::DataMessage
    {
      public:
        explicit RetrySwitchCSQMode(bool switchToPollMode)
            : sys::DataMessage(MessageType::MessageTypeUninitialized), switchToPollMode(switchToPollMode){};
        auto isSwitchToPollMode()
        enum class Mode
        {
            return switchToPollMode;
            PermanentReporting,
            HybridReporting,
            HybridPolling
        };
        explicit RetrySwitchCSQMode(Mode newMode)
            : sys::DataMessage(MessageType::MessageTypeUninitialized), mode(newMode){};
        auto getNewMode()
        {
            return mode;
        };

      private:
        bool switchToPollMode = false;
        Mode mode;
    };

    class RetryGetCSQ : public sys::DataMessage

M module-services/service-cellular/src/CSQHandler.cpp => module-services/service-cellular/src/CSQHandler.cpp +77 -22
@@ 4,16 4,19 @@
#include "CSQHandler.hpp"

#include <log/log.hpp>
#include <EventStore.hpp>
#include <ticks.hpp>
#include <chrono>

namespace cellular::service
{

    void CSQHandler::handleTimerTick()
    {
        if (isInPollMode()) {
            timeSpentInPollMode++;
        if (currentMode == CSQMode::HybridPolling) {
            if (isPollModeTimeElapsed()) {
                switchToReportMode();
                LOG_INFO("CSQ poll mode time elapsed.");
                switchToHybridReportMode();
                return;
            }



@@ 24,16 27,11 @@ namespace cellular::service
    void CSQHandler::handleURCCounterMessage(const uint32_t counter)
    {
        urcCounter = counter;
        if (isTooManyURC() && not isInPollMode()) {
            switchToPollMode();
        if (isTooManyURC() && currentMode == CSQMode::HybridReporting) {
            switchToHybridPollMode();
        }
    }

    auto CSQHandler::isInPollMode() -> bool
    {
        return currentMode == CSQMode::Polling;
    }

    auto CSQHandler::isTooManyURC() -> bool
    {
        return urcCounter > urcThreshold;


@@ 41,36 39,72 @@ namespace cellular::service

    auto CSQHandler::isPollModeTimeElapsed() -> bool
    {
        return timeSpentInPollMode > pollTime;
        auto currentTime = cpp_freertos::Ticks::TicksToMs(cpp_freertos::Ticks::GetTicks());
        auto timeSpentInPollMode =
            currentTime >= switchToPollModeTimestamp
                ? currentTime - switchToPollModeTimestamp
                : std::numeric_limits<TickType_t>::max() - switchToPollModeTimestamp + currentTime;
        return timeSpentInPollMode > std::chrono::duration_cast<std::chrono::milliseconds>(pollTime).count();
    }

    bool CSQHandler::switchToReportMode()
    void CSQHandler::checkConditionToChangeMode()
    {
        LOG_INFO("CSQ poll mode time elapsed, switch to report mode.");
        if (currentMode != CSQMode::PermanentReporting) {
            if (not isPhoneLocked || isBluetoothCarKitConnected ||
                Store::Battery::get().state != Store::Battery::State::Discharging) {
                switchToPermanentReportMode();
            }
        }
        else {
            if (isPhoneLocked && not isBluetoothCarKitConnected &&
                Store::Battery::get().state == Store::Battery::State::Discharging) {
                switchToHybridReportMode();
            }
        }
    }

    bool CSQHandler::switchToPermanentReportMode()
    {
        LOG_INFO("Switch to permanent report mode.");
        if (onEnableCsqReporting != nullptr && onEnableCsqReporting()) {
            timeSpentInPollMode = std::chrono::minutes{0};
            currentMode         = CSQMode::Reporting;
            currentMode = CSQMode::PermanentReporting;
            return true;
        }

        LOG_ERROR("Failed to switch to CSQ report mode! Retry!");
        LOG_ERROR("Failed to switch to CSQ permanent report mode! Retry!");
        if (onRetrySwitchMode != nullptr) {
            onRetrySwitchMode(false);
            onRetrySwitchMode(CSQMode::PermanentReporting);
        }
        return false;
    }

    bool CSQHandler::switchToPollMode()
    bool CSQHandler::switchToHybridReportMode()
    {
        LOG_INFO("Too many signal strength updates, switch to poll mode.");
        LOG_INFO("Switch to hybrid report mode.");
        if (onEnableCsqReporting != nullptr && onEnableCsqReporting()) {
            currentMode = CSQMode::HybridReporting;
            return true;
        }

        LOG_ERROR("Failed to switch to CSQ hybrid report mode! Retry!");
        if (onRetrySwitchMode != nullptr) {
            onRetrySwitchMode(CSQMode::HybridReporting);
        }
        return false;
    }

    bool CSQHandler::switchToHybridPollMode()
    {
        LOG_INFO("Too many signal strength updates, switch to hybrid poll mode.");
        if (onDisableCsqReporting != nullptr && onDisableCsqReporting()) {
            currentMode = CSQMode::Polling;
            currentMode               = CSQMode::HybridPolling;
            switchToPollModeTimestamp = cpp_freertos::Ticks::TicksToMs(cpp_freertos::Ticks::GetTicks());
            return true;
        }

        LOG_ERROR("Failed to switch to CSQ poll mode! Retry!");
        LOG_ERROR("Failed to switch to CSQ hybrid poll mode! Retry!");
        if (onRetrySwitchMode != nullptr) {
            onRetrySwitchMode(false);
            onRetrySwitchMode(CSQMode::HybridPolling);
        }
        return false;
    }


@@ 103,4 137,25 @@ namespace cellular::service
        }
        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

M module-services/service-cellular/src/CSQHandler.hpp => module-services/service-cellular/src/CSQHandler.hpp +20 -9
@@ 8,20 8,22 @@
#include <cstdint>
#include <chrono>
#include <functional>
#include <FreeRTOS.h>

namespace cellular::service
{

    constexpr auto urcThreshold = 4;
    constexpr auto pollTime     = std::chrono::minutes{15};
    constexpr auto pollTime     = std::chrono::minutes{60};

    static const auto invalid_rssi_low  = 99;
    static const auto invalid_rssi_high = 199;

    enum class CSQMode
    {
        Reporting,
        Polling
        PermanentReporting,
        HybridReporting,
        HybridPolling
    };

    class CSQHandler


@@ 36,19 38,28 @@ namespace cellular::service
        std::function<void(uint32_t)> onPropagateCSQ;
        std::function<void()> onInvalidCSQ;

        std::function<void(bool)> onRetrySwitchMode;
        std::function<void(CSQMode)> onRetrySwitchMode;
        std::function<void()> onRetryGetCSQ;

        bool switchToReportMode();
        bool switchToPollMode();
        void handleLockPhone();
        void handleUnlockPhone();
        void handleBluetoothCarKitConnect();
        void handleBluetoothCarKitDisconnect();
        void checkConditionToChangeMode();
        bool switchToPermanentReportMode();
        bool switchToHybridReportMode();
        bool switchToHybridPollMode();
        bool getCSQ();

      private:
        uint32_t urcCounter = 0;
        CSQMode currentMode = CSQMode::Reporting;
        std::chrono::minutes timeSpentInPollMode{};
        CSQMode currentMode = CSQMode::HybridReporting;
        TickType_t switchToPollModeTimestamp{0};

        // parameters needed to switch poll/report mode
        bool isPhoneLocked{true};
        bool isBluetoothCarKitConnected{false};

        auto isInPollMode() -> bool;
        auto isPollModeTimeElapsed() -> bool;
        auto isTooManyURC() -> bool;
    };

M module-services/service-cellular/src/ServiceCellularPriv.cpp => module-services/service-cellular/src/ServiceCellularPriv.cpp +68 -8
@@ 11,6 11,8 @@
#include <service-evtmgr/EVMessages.hpp>
#include <service-evtmgr/Constants.hpp>

#include <service-bluetooth/messages/BluetoothModeChanged.hpp>
#include <locks/data/PhoneLockMessages.hpp>
#include <service-time/service-time/TimeMessage.hpp>
#include <service-time/Constants.hpp>
#include <queries/messages/sms/QuerySMSUpdate.hpp>


@@ 399,7 401,7 @@ namespace cellular::internal
    {
        csqHandler->onEnableCsqReporting = [this]() {
            if (owner->cpuSentinel) {
                owner->cpuSentinel->HoldMinimumFrequency(bsp::CpuFrequencyMHz::Level_4);
                owner->cpuSentinel->HoldMinimumFrequency(bsp::CpuFrequencyMHz::Level_2);
            }

            auto channel = owner->cmux->get(CellularMux::Channel::Commands);


@@ 414,7 416,7 @@ namespace cellular::internal

        csqHandler->onDisableCsqReporting = [this]() {
            if (owner->cpuSentinel) {
                owner->cpuSentinel->HoldMinimumFrequency(bsp::CpuFrequencyMHz::Level_4);
                owner->cpuSentinel->HoldMinimumFrequency(bsp::CpuFrequencyMHz::Level_2);
            }

            auto channel = owner->cmux->get(CellularMux::Channel::Commands);


@@ 428,6 430,10 @@ namespace cellular::internal
        };

        csqHandler->onGetCsq = [this]() -> std::optional<at::result::CSQ> {
            if (owner->cpuSentinel) {
                owner->cpuSentinel->HoldMinimumFrequency(bsp::CpuFrequencyMHz::Level_2);
            }

            auto channel = owner->cmux->get(CellularMux::Channel::Commands);
            if (!channel) {
                return std::nullopt;


@@ 452,8 458,22 @@ namespace cellular::internal

        csqHandler->onInvalidCSQ = [this]() { AntennaServiceAPI::InvalidCSQNotification(owner); };

        csqHandler->onRetrySwitchMode = [this](bool isSwitchToPollMode) {
            owner->bus.sendUnicast(std::make_shared<RetrySwitchCSQMode>(isSwitchToPollMode), ::service::name::cellular);
        csqHandler->onRetrySwitchMode = [this](service::CSQMode newMode) {
            switch (newMode) {
            case service::CSQMode::PermanentReporting:
                owner->bus.sendUnicast(
                    std::make_shared<RetrySwitchCSQMode>(RetrySwitchCSQMode::Mode::PermanentReporting),
                    ::service::name::cellular);
                break;
            case service::CSQMode::HybridReporting:
                owner->bus.sendUnicast(std::make_shared<RetrySwitchCSQMode>(RetrySwitchCSQMode::Mode::HybridReporting),
                                       ::service::name::cellular);
                break;
            case service::CSQMode::HybridPolling:
                owner->bus.sendUnicast(std::make_shared<RetrySwitchCSQMode>(RetrySwitchCSQMode::Mode::HybridPolling),
                                       ::service::name::cellular);
                break;
            }
        };

        csqHandler->onRetryGetCSQ = [this]() {


@@ 465,6 485,9 @@ namespace cellular::internal

    void ServiceCellularPriv::connectCSQHandler()
    {
        owner->bus.channels.push_back(sys::BusChannel::PhoneLockChanges);
        owner->bus.channels.push_back(sys::BusChannel::BluetoothModeChanges);

        owner->connect(typeid(URCCounterMessage), [&](sys::Message *request) -> sys::MessagePointer {
            auto message = dynamic_cast<cellular::URCCounterMessage *>(request);
            csqHandler->handleURCCounterMessage(message->getCounter());


@@ 473,11 496,17 @@ namespace cellular::internal

        owner->connect(typeid(RetrySwitchCSQMode), [&](sys::Message *request) -> sys::MessagePointer {
            auto message = dynamic_cast<cellular::RetrySwitchCSQMode *>(request);
            if (message->isSwitchToPollMode()) {
                csqHandler->switchToPollMode();
                return sys::MessageNone{};
            switch (message->getNewMode()) {
            case cellular::RetrySwitchCSQMode::Mode::PermanentReporting:
                csqHandler->switchToPermanentReportMode();
                break;
            case cellular::RetrySwitchCSQMode::Mode::HybridReporting:
                csqHandler->switchToHybridReportMode();
                break;
            case cellular::RetrySwitchCSQMode::Mode::HybridPolling:
                csqHandler->switchToHybridPollMode();
                break;
            }
            csqHandler->switchToReportMode();
            return sys::MessageNone{};
        });



@@ 485,5 514,36 @@ namespace cellular::internal
            csqHandler->getCSQ();
            return sys::MessageNone{};
        });

        owner->connect(typeid(locks::UnlockedPhone), [&](sys::Message *request) -> sys::MessagePointer {
            csqHandler->handleUnlockPhone();
            csqHandler->checkConditionToChangeMode();
            return sys::MessageNone{};
        });

        owner->connect(typeid(locks::LockedPhone), [&](sys::Message *request) -> sys::MessagePointer {
            csqHandler->handleLockPhone();
            csqHandler->checkConditionToChangeMode();
            return sys::MessageNone{};
        });

        owner->connect(typeid(sys::bluetooth::BluetoothModeChanged), [&](sys::Message *request) -> sys::MessagePointer {
            auto data   = static_cast<sys::bluetooth::BluetoothModeChanged *>(request);
            auto btMode = data->getBluetoothMode();
            if (btMode == sys::bluetooth::BluetoothMode::ConnectedVoice ||
                btMode == sys::bluetooth::BluetoothMode::ConnectedBoth) {
                csqHandler->handleBluetoothCarKitConnect();
            }
            else {
                csqHandler->handleBluetoothCarKitDisconnect();
            }
            csqHandler->checkConditionToChangeMode();
            return sys::MessageNone{};
        });

        owner->connect(typeid(sevm::BatteryStatusChangeMessage), [&](sys::Message *request) -> sys::MessagePointer {
            csqHandler->checkConditionToChangeMode();
            return sys::MessageNone{};
        });
    }
} // namespace cellular::internal

M module-services/service-evtmgr/EventManager.cpp => module-services/service-evtmgr/EventManager.cpp +2 -0
@@ 29,6 29,7 @@
#include <service-time/Constants.hpp>
#include <service-time/service-time/TimeMessage.hpp>
#include <service-bluetooth/messages/Status.hpp>
#include <service-cellular/Constans.hpp>

#include <cassert>
#include <fstream>


@@ 157,6 158,7 @@ sys::ReturnCodes EventManagerCommon::InitHandler()
            }
            bus.sendUnicast(std::make_shared<sevm::BatteryStatusChangeMessage>(), service::name::service_desktop);
            bus.sendUnicast(std::make_shared<sevm::BatteryStatusChangeMessage>(), service::name::bluetooth);
            bus.sendUnicast(std::make_shared<sevm::BatteryStatusChangeMessage>(), service::name::cellular);
        }
        return sys::msgHandled();
    });