M module-apps/Application.cpp => module-apps/Application.cpp +5 -2
@@ 708,13 708,16 @@ namespace app
void Application::handlePhoneModeChanged(sys::phone_modes::PhoneMode mode)
{
+ auto flightModeSetting = settings->getValue(settings::Cellular::offlineMode, settings::SettingsScope::Global);
+ bool flightMode = flightModeSetting == "1" ? true : false;
+
using namespace gui::popup;
const auto &popupName = resolveWindowName(gui::popup::ID::PhoneModes);
if (const auto currentWindowName = getCurrentWindow()->getName(); currentWindowName == popupName) {
- updateWindow(popupName, std::make_unique<gui::ModesPopupData>(mode));
+ updateWindow(popupName, std::make_unique<gui::ModesPopupData>(mode, flightMode));
}
else {
- switchWindow(popupName, std::make_unique<gui::ModesPopupData>(mode));
+ switchWindow(popupName, std::make_unique<gui::ModesPopupData>(mode, flightMode));
}
}
M module-apps/application-settings-new/ApplicationSettings.cpp => module-apps/application-settings-new/ApplicationSettings.cpp +1 -2
@@ 740,7 740,6 @@ namespace app
void ApplicationSettingsNew::setConnectionFrequency(uint8_t val) noexcept
{
connectionFrequency = val;
- settings->setValue(
- ::settings::Offline::connectionFrequency, std::to_string(val), ::settings::SettingsScope::Global);
+ CellularServiceAPI::SetConnectionFrequency(this, val);
}
} /* namespace app */
M => +2 -1
@@ 35,7 35,8 @@ namespace gui
const auto popupData = dynamic_cast<ModesPopupData *>(data);
if (popupData != nullptr) {
const auto currentMode = popupData->getPhoneMode();
modesBox->update(currentMode);
const auto currentFlightMode = popupData->getFlightMode();
modesBox->update(currentMode, currentFlightMode);
}
}
M => +8 -1
@@ 35,7 35,8 @@ namespace gui
class ModesPopupData : public SwitchData
{
public:
explicit ModesPopupData(const sys::phone_modes::PhoneMode phoneMode) : SwitchData(), phoneMode{phoneMode}
explicit ModesPopupData(sys::phone_modes::PhoneMode phoneMode, bool flightMode)
: SwitchData(), phoneMode{phoneMode}, isFlightModeEnabled(flightMode)
{}
[[nodiscard]] auto getPhoneMode() const noexcept -> sys::phone_modes::PhoneMode
@@ 43,7 44,13 @@ namespace gui
return phoneMode;
}
[[nodiscard]] auto getFlightMode() const noexcept -> bool
{
return isFlightModeEnabled;
}
private:
const sys::phone_modes::PhoneMode phoneMode;
const bool isFlightModeEnabled;
};
} // namespace gui
M module-apps/widgets/ModesBox.cpp => module-apps/widgets/ModesBox.cpp +2 -2
@@ 24,7 24,7 @@ namespace gui
addOffline();
}
- void ModesBox::update(const sys::phone_modes::PhoneMode &phoneMode)
+ void ModesBox::update(const sys::phone_modes::PhoneMode &phoneMode, const bool flightMode)
{
using PhoneMode = sys::phone_modes::PhoneMode;
auto getUpdateValues = [&phoneMode](const PhoneMode &compare) -> std::pair<std::string, const bool> {
@@ 34,7 34,7 @@ namespace gui
connected->update(getUpdateValues(PhoneMode::Connected));
notDisturb->update(getUpdateValues(PhoneMode::DoNotDisturb));
offline->update(getUpdateValues(PhoneMode::Offline));
- if (phoneMode == PhoneMode::Offline) {
+ if (phoneMode == PhoneMode::Offline && !flightMode) {
messageOnly->setVisible(true);
}
else {
M module-apps/widgets/ModesBox.hpp => module-apps/widgets/ModesBox.hpp +1 -1
@@ 82,6 82,6 @@ namespace gui
public:
ModesBox(Item *parent = nullptr, uint32_t x = 0, uint32_t y = 0);
- void update(const sys::phone_modes::PhoneMode &phoneMode);
+ void update(const sys::phone_modes::PhoneMode &phoneMode, const bool flightMode);
};
} // namespace gui
M module-services/service-antenna/ServiceAntenna.cpp => module-services/service-antenna/ServiceAntenna.cpp +5 -1
@@ 244,7 244,6 @@ bool ServiceAntenna::HandleStateChange(antenna::State state)
switch (state) {
case antenna::State::none:
ret = noneStateHandler();
- ;
break;
case antenna::State::init:
ret = initStateHandler();
@@ 282,6 281,11 @@ bool ServiceAntenna::initStateHandler(void)
{
LOG_INFO("State Init");
bsp::cellular::antenna antenna;
+ if (phoneModeObserver->isInMode(sys::phone_modes::PhoneMode::Offline)) {
+ AntennaServiceAPI::LockRequest(this, antenna::lockState::locked);
+ return true;
+ }
+
if (CellularServiceAPI::GetAntenna(this, antenna)) {
currentAntenna = antenna;
state->enableStateTimeout(cpp_freertos::Ticks::GetTicks(),
M module-services/service-cellular/CMakeLists.txt => module-services/service-cellular/CMakeLists.txt +2 -0
@@ 14,6 14,8 @@ set(SOURCES
QMBNManager.cpp
RequestFactory.cpp
CellularRequestHandler.cpp
+ connection-manager/ConnectionManager.cpp
+ connection-manager/ConnectionManagerCellularCommands.cpp
requests/Request.cpp
requests/CallRequest.cpp
requests/SupplementaryServicesRequest.cpp
M module-services/service-cellular/CellularServiceAPI.cpp => module-services/service-cellular/CellularServiceAPI.cpp +6 -0
@@ 352,3 352,9 @@ bool CellularServiceAPI::SetFlightMode(sys::Service *serv, bool flightModeOn)
return serv->bus.sendUnicast(std::make_shared<CellularSetFlightModeMessage>(flightModeOn),
ServiceCellular::serviceName);
}
+
+bool CellularServiceAPI::SetConnectionFrequency(sys::Service *serv, uint8_t connectionFrequency)
+{
+ return serv->bus.sendUnicast(std::make_shared<CellularSetConnectionFrequencyMessage>(connectionFrequency),
+ ServiceCellular::serviceName);
+}
M module-services/service-cellular/ServiceCellular.cpp => module-services/service-cellular/ServiceCellular.cpp +70 -142
@@ 12,7 12,7 @@
#include "service-cellular/State.hpp"
#include "service-cellular/USSD.hpp"
#include "service-cellular/MessageConstants.hpp"
-
+#include <service-cellular/connection-manager/ConnectionManagerCellularCommands.hpp>
#include "SimCard.hpp"
#include "NetworkSettings.hpp"
#include "service-cellular/RequestFactory.hpp"
@@ 182,6 182,15 @@ ServiceCellular::ServiceCellular()
bus.channels.push_back(sys::BusChannel::ServiceEvtmgrNotifications);
bus.channels.push_back(sys::BusChannel::PhoneModeChanges);
+ settings = std::make_unique<settings::Settings>(this);
+
+ connectionManager = std::make_unique<ConnectionManager>(
+ utils::getNumericValue<bool>(
+ settings->getValue(settings::Cellular::offlineMode, settings::SettingsScope::Global)),
+ static_cast<std::chrono::minutes>(utils::getNumericValue<int>(settings->getValue(
+ settings->getValue(settings::Offline::connectionFrequency, settings::SettingsScope::Global)))),
+ std::make_shared<ConnectionManagerCellularCommands>(*this));
+
callStateTimer = sys::TimerFactory::createPeriodicTimer(
this, "call_state", std::chrono::milliseconds{1000}, [this](sys::Timer &) { CallStateTimerHandler(); });
stateTimer = sys::TimerFactory::createPeriodicTimer(
@@ 190,6 199,12 @@ ServiceCellular::ServiceCellular()
this, "ussd", std::chrono::milliseconds{1000}, [this](sys::Timer &) { handleUSSDTimer(); });
sleepTimer = sys::TimerFactory::createPeriodicTimer(
this, "sleep", constants::sleepTimerInterval, [this](sys::Timer &) { SleepTimerHandler(); });
+ connectionTimer =
+ sys::TimerFactory::createPeriodicTimer(this, "connection", std::chrono::seconds{60}, [this](sys::Timer &) {
+ utility::conditionally_invoke(
+ [this]() { return phoneModeObserver->isInMode(sys::phone_modes::PhoneMode::Offline); },
+ [this]() { connectionManager->onTimerTick(); });
+ });
ongoingCall.setStartCallAction([=](const CalllogRecord &rec) {
auto call = DBServiceAPI::CalllogAdd(this, rec);
@@ 326,16 341,8 @@ void handleCellularSimNewPinDataMessage(CellularSimNewPinDataMessage *msg)
void ServiceCellular::registerMessageHandlers()
{
phoneModeObserver->connect(this);
- phoneModeObserver->subscribe([this](sys::phone_modes::PhoneMode mode) {
- if (mode == sys::phone_modes::PhoneMode::Offline) {
- this->switchToOffline();
- }
- else {
- if (!this->isModemRadioModuleOn()) {
- this->turnOnRadioModule();
- }
- }
- });
+ phoneModeObserver->subscribe(
+ [this](sys::phone_modes::PhoneMode mode) { connectionManager->onPhoneModeChange(mode); });
phoneModeObserver->subscribe([](sys::phone_modes::Tethering tethering) {
using bsp::cellular::USB::setPassthrough;
using bsp::cellular::USB::PassthroughState;
@@ 524,18 531,10 @@ void ServiceCellular::registerMessageHandlers()
return handleCellularRingingMessage(msg);
});
- connect(typeid(CellularIncominCallMessage), [&](sys::Message *request) -> sys::MessagePointer {
- if (doNotDisturbCondition()) {
- return std::make_shared<CellularResponseMessage>(hangUpCall());
- }
- auto msg = static_cast<CellularIncominCallMessage *>(request);
- return handleCellularIncominCallMessage(msg);
- });
+ connect(typeid(CellularIncominCallMessage),
+ [&](sys::Message *request) -> sys::MessagePointer { return handleCellularIncominCallMessage(request); });
connect(typeid(CellularCallerIdMessage), [&](sys::Message *request) -> sys::MessagePointer {
- if (doNotDisturbCondition()) {
- return std::make_shared<CellularResponseMessage>(true);
- }
auto msg = static_cast<CellularCallerIdMessage *>(request);
return handleCellularCallerIdMessage(msg);
});
@@ 639,9 638,6 @@ void ServiceCellular::registerMessageHandlers()
connect(typeid(CellularUrcIncomingNotification),
[&](sys::Message *request) -> sys::MessagePointer { return handleUrcIncomingNotification(request); });
- connect(typeid(CellularSetRadioOnOffMessage),
- [&](sys::Message *request) -> sys::MessagePointer { return handleCellularSetRadioOnOffMessage(request); });
-
connect(typeid(CellularSendSMSMessage),
[&](sys::Message *request) -> sys::MessagePointer { return handleCellularSendSMSMessage(request); });
@@ 651,6 647,10 @@ void ServiceCellular::registerMessageHandlers()
connect(typeid(CellularCallerIdNotification),
[&](sys::Message *request) -> sys::MessagePointer { return handleCellularCallerIdNotification(request); });
+ connect(typeid(CellularSetConnectionFrequencyMessage), [&](sys::Message *request) -> sys::MessagePointer {
+ return handleCellularSetConnectionFrequencyMessage(request);
+ });
+
handle_CellularGetChannelMessage();
}
@@ 950,23 950,22 @@ bool ServiceCellular::handle_audio_conf_procedure()
LOG_DEBUG("Setting up notifications callback");
notificationsChannel->setCallback(notificationCallback);
}
- auto mode = phoneModeObserver->getCurrentPhoneMode();
- if (mode == sys::phone_modes::PhoneMode::Offline) {
- if (!turnOffRadioModule()) {
- LOG_ERROR("Disabling RF modeule failed");
- state.set(this, State::ST::Failed);
- return false;
- }
+ auto flightMode =
+ settings->getValue(settings::Cellular::offlineMode, settings::SettingsScope::Global) == "1" ? true
+ : false;
+ connectionManager->setFlightMode(flightMode);
+ auto interval = 0;
+ if (utils::toNumeric(
+ settings->getValue(settings::Offline::connectionFrequency, settings::SettingsScope::Global),
+ interval)) {
+ connectionManager->setInterval(std::chrono::minutes{interval});
}
- else {
- if (!isModemRadioModuleOn()) {
- if (turnOnRadioModule()) {
- LOG_ERROR("Enabling RF modeule failed");
- state.set(this, State::ST::Failed);
- return false;
- }
- }
+ if (!connectionManager->onPhoneModeChange(phoneModeObserver->getCurrentPhoneMode())) {
+ state.set(this, State::ST::Failed);
+ LOG_ERROR("Failed to handle phone mode");
+ return false;
}
+
state.set(this, State::ST::APNConfProcedure);
return true;
}
@@ 2376,20 2375,20 @@ auto ServiceCellular::handleCellularRingingMessage(CellularRingingMessage *msg)
return std::make_shared<CellularResponseMessage>(ongoingCall.startCall(msg->number, CallType::CT_OUTGOING));
}
-auto ServiceCellular::handleCellularIncominCallMessage(CellularIncominCallMessage *msg)
- -> std::shared_ptr<sys::ResponseMessage>
+auto ServiceCellular::handleCellularIncominCallMessage(sys::Message *msg) -> std::shared_ptr<sys::ResponseMessage>
{
- auto ret = true;
+ auto ret = true;
+ auto message = static_cast<CellularIncominCallMessage *>(msg);
if (!ongoingCall.isValid()) {
- ret = ongoingCall.startCall(msg->number, CallType::CT_INCOMING);
+ ret = ongoingCall.startCall(message->number, CallType::CT_INCOMING);
}
return std::make_shared<CellularResponseMessage>(ret);
}
-auto ServiceCellular::handleCellularCallerIdMessage(CellularCallerIdMessage *msg)
- -> std::shared_ptr<sys::ResponseMessage>
+auto ServiceCellular::handleCellularCallerIdMessage(sys::Message *msg) -> std::shared_ptr<sys::ResponseMessage>
{
- ongoingCall.setNumber(msg->number);
+ auto message = static_cast<CellularCallerIdMessage *>(msg);
+ ongoingCall.setNumber(message->number);
return sys::MessageNone{};
}
@@ 2643,18 2642,11 @@ auto ServiceCellular::handleCellularSetFlightModeMessage(sys::Message *msg) -> s
auto setMsg = static_cast<CellularSetFlightModeMessage *>(msg);
settings->setValue(
settings::Cellular::offlineMode, std::to_string(setMsg->flightModeOn), settings::SettingsScope::Global);
+ connectionManager->setFlightMode(setMsg->flightModeOn);
+ connectionManager->onPhoneModeChange(phoneModeObserver->getCurrentPhoneMode());
return std::make_shared<CellularResponseMessage>(true);
}
-auto ServiceCellular::handleCellularSetRadioOnOffMessage(sys::Message *msg) -> std::shared_ptr<sys::ResponseMessage>
-{
- auto message = static_cast<CellularSetRadioOnOffMessage *>(msg);
- if (message->getRadioOnOf()) {
- return std::make_shared<CellularResponseMessage>(turnOnRadioModule());
- }
- return std::make_shared<CellularResponseMessage>(turnOffRadioModule());
-}
-
auto ServiceCellular::handleCellularSendSMSMessage(sys::Message *msg) -> std::shared_ptr<sys::ResponseMessage>
{
auto message = static_cast<CellularSendSMSMessage *>(msg);
@@ 2674,106 2666,42 @@ auto ServiceCellular::handleCellularSendSMSMessage(sys::Message *msg) -> std::sh
auto ServiceCellular::handleCellularRingNotification(sys::Message *msg) -> std::shared_ptr<sys::ResponseMessage>
{
- auto message = static_cast<CellularRingNotification *>(msg);
-
- if (doNotDisturbCondition()) {
- return std::make_shared<CellularResponseMessage>(this->hangUpCall());
+ if (isIncommingCallAllowed()) {
+ auto message = static_cast<CellularRingNotification *>(msg);
+ bus.sendMulticast(std::make_shared<CellularIncominCallMessage>(message->getNubmer()),
+ sys::BusChannel::ServiceCellularNotifications);
+ return std::make_shared<CellularResponseMessage>(true);
}
- bus.sendMulticast(std::make_shared<CellularIncominCallMessage>(message->getNubmer()),
- sys::BusChannel::ServiceCellularNotifications);
- return std::make_shared<CellularResponseMessage>(true);
+ return std::make_shared<CellularResponseMessage>(this->hangUpCall());
}
auto ServiceCellular::handleCellularCallerIdNotification(sys::Message *msg) -> std::shared_ptr<sys::ResponseMessage>
{
- auto message = static_cast<CellularCallerIdNotification *>(msg);
-
- if (doNotDisturbCondition()) {
- return std::make_shared<CellularResponseMessage>(this->hangUpCall());
- }
-
- bus.sendMulticast(std::make_shared<CellularCallerIdMessage>(message->getNubmer()),
- sys::BusChannel::ServiceCellularNotifications);
- return std::make_shared<CellularResponseMessage>(true);
-}
-
-auto ServiceCellular::isModemRadioModuleOn() -> bool
-{
- using at::cfun::Functionality;
- auto channel = cmux->get(TS0710::Channel::Commands);
- if (channel) {
- auto cmd = at::cmd::CFUN(at::cmd::Modifier::Get);
- auto response = channel->cmd(cmd);
- if (response.code == at::Result::Code::OK) {
- auto result = cmd.parse(response);
- if (result.code == at::Result::Code::OK) {
- return result.functionality == Functionality::Full;
- }
- }
- }
- return false;
-}
-auto ServiceCellular::turnOnRadioModule() -> bool
-{
- using at::cfun::Functionality;
- auto channel = cmux->get(TS0710::Channel::Commands);
- if (channel) {
- auto cmd = at::cmd::CFUN(at::cmd::Modifier::Set);
- cmd.set(Functionality::Full);
- auto resp = channel->cmd(cmd);
- return resp.code == at::Result::Code::OK;
- }
- return false;
-}
-
-auto ServiceCellular::turnOffRadioModule() -> bool
-{
- using at::cfun::Functionality;
- auto channel = cmux->get(TS0710::Channel::Commands);
- if (channel) {
- auto cmd = at::cmd::CFUN(at::cmd::Modifier::Set);
- cmd.set(Functionality::DisableRF);
- auto resp = channel->cmd(cmd);
- return resp.code == at::Result::Code::OK;
+ if (isIncommingCallAllowed()) {
+ auto message = static_cast<CellularCallerIdNotification *>(msg);
+ bus.sendMulticast(std::make_shared<CellularCallerIdMessage>(message->getNubmer()),
+ sys::BusChannel::ServiceCellularNotifications);
+ return std::make_shared<CellularResponseMessage>(true);
}
- return false;
+ return std::make_shared<CellularResponseMessage>(this->hangUpCall());
}
-auto ServiceCellular::switchToOffline() -> bool
+auto ServiceCellular::handleCellularSetConnectionFrequencyMessage(sys::Message *msg)
+ -> std::shared_ptr<sys::ResponseMessage>
{
- if (ongoingCall.isActive()) {
- auto channel = cmux->get(TS0710::Channel::Commands);
- if (channel) {
- if (channel->cmd(at::factory(at::AT::ATH))) {
- callStateTimer.stop();
- if (!ongoingCall.endCall(CellularCall::Forced::True)) {
- LOG_ERROR("Failed to end ongoing call");
- return false;
- }
- auto msg = std::make_shared<CellularCallAbortedNotification>();
- bus.sendMulticast(msg, sys::BusChannel::ServiceCellularNotifications);
- }
- }
- }
-
- if (!turnOffRadioModule()) {
- LOG_ERROR("Failed to disable RF module");
- return false;
- }
-
- // force clear signal indicator
- auto rssi = 0;
- SignalStrength signalStrength(rssi);
- Store::GSM::get()->setSignalStrength(signalStrength.data);
- auto msg = std::make_shared<CellularSignalStrengthUpdateNotification>();
- bus.sendMulticast(msg, sys::BusChannel::ServiceCellularNotifications);
+ auto setMsg = static_cast<CellularSetConnectionFrequencyMessage *>(msg);
+ settings->setValue(settings::Offline::connectionFrequency,
+ std::to_string(setMsg->getConnectionFrequency()),
+ settings::SettingsScope::Global);
- return true;
+ connectionManager->setInterval(std::chrono::minutes{setMsg->getConnectionFrequency()});
+ connectionManager->onPhoneModeChange(phoneModeObserver->getCurrentPhoneMode());
+ return std::make_shared<CellularResponseMessage>(true);
}
-auto ServiceCellular::doNotDisturbCondition() -> bool
+auto ServiceCellular::isIncommingCallAllowed() -> bool
{
- return phoneModeObserver->isInMode(sys::phone_modes::PhoneMode::DoNotDisturb);
+ return phoneModeObserver->isInMode(sys::phone_modes::PhoneMode::Connected);
}
auto ServiceCellular::hangUpCall() -> bool
A module-services/service-cellular/connection-manager/ConnectionManager.cpp => module-services/service-cellular/connection-manager/ConnectionManager.cpp +107 -0
@@ 0,0 1,107 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include <module-services/service-cellular/service-cellular/connection-manager/ConnectionManager.hpp>
+#include <module-services/service-cellular/service-cellular/CellularMessage.hpp>
+#include <module-cellular/at/Cmd.hpp>
+
+auto ConnectionManager::onPhoneModeChange(sys::phone_modes::PhoneMode mode) -> bool
+{
+ if (mode == sys::phone_modes::PhoneMode::Offline) {
+ return handleModeChangeToCommonOffline();
+ }
+ return handleModeChangeToConnected();
+}
+
+void ConnectionManager::onTimerTick()
+{
+ if (connectionInterval.count() == 0 || isFlightMode) {
+ return;
+ }
+
+ minutesOfflineElapsed++;
+ if (minutesOfflineElapsed.count() >= connectionInterval.count()) {
+ minutesOfflineElapsed = static_cast<std::chrono::minutes>(0);
+ ;
+ onlinePeriod = true;
+ cellular->connectToNetwork();
+ return;
+ }
+ if (onlinePeriod) {
+ minutesOnlineElapsed++;
+ if (minutesOnlineElapsed.count() >= connectedPeriod.count()) {
+ minutesOnlineElapsed = static_cast<std::chrono::minutes>(0);
+ onlinePeriod = false;
+ cellular->disconnectFromNetwork();
+ }
+ }
+}
+
+void ConnectionManager::setInterval(const std::chrono::minutes interval)
+{
+ connectionInterval = interval;
+ minutesOnlineElapsed = static_cast<std::chrono::minutes>(0);
+ ;
+ minutesOfflineElapsed = static_cast<std::chrono::minutes>(0);
+ ;
+}
+
+void ConnectionManager::setFlightMode(const bool mode)
+{
+ isFlightMode = mode;
+}
+
+auto ConnectionManager::isMessagesOnlyMode() -> bool
+{
+ return !isFlightMode && connectionInterval.count() != 0;
+}
+
+auto ConnectionManager::handleModeChangeToCommonOffline() -> bool
+{
+ if (cellular->isConnectedToNetwork()) {
+ cellular->hangUpOngoingCall();
+ cellular->disconnectFromNetwork();
+ cellular->clearNetworkIndicator();
+ }
+
+ minutesOfflineElapsed = static_cast<std::chrono::minutes>(0);
+ ;
+ minutesOnlineElapsed = static_cast<std::chrono::minutes>(0);
+ ;
+
+ if (isMessagesOnlyMode()) {
+ handleModeChangeToMessageOnlyMode();
+ return true;
+ }
+ else {
+ handleModeChangeToOfflineMode();
+ return true;
+ }
+}
+
+void ConnectionManager::handleModeChangeToOfflineMode()
+{
+ if (cellular->isConnectionTimerActive()) {
+ cellular->stopConnectionTimer();
+ onlinePeriod = false;
+ }
+}
+
+void ConnectionManager::handleModeChangeToMessageOnlyMode()
+{
+ if (!cellular->isConnectionTimerActive()) {
+ cellular->startConnectionTimer();
+ }
+}
+
+auto ConnectionManager::handleModeChangeToConnected() -> bool
+{
+ if (cellular->isConnectionTimerActive()) {
+ cellular->stopConnectionTimer();
+ onlinePeriod = false;
+ }
+ if (!cellular->isConnectedToNetwork()) {
+ cellular->connectToNetwork();
+ }
+ return true;
+}
A module-services/service-cellular/connection-manager/ConnectionManagerCellularCommands.cpp => module-services/service-cellular/connection-manager/ConnectionManagerCellularCommands.cpp +99 -0
@@ 0,0 1,99 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include <service-cellular/service-cellular/connection-manager/ConnectionManagerCellularCommands.hpp>
+
+#include <module-cellular/at/cmd/CFUN.hpp>
+#include <module-cellular/at/Cmd.hpp>
+#include <module-cellular/at/ATFactory.hpp>
+
+auto ConnectionManagerCellularCommands::disconnectFromNetwork() -> bool
+{
+ using at::cfun::Functionality;
+ auto channel = cellular.cmux->get(TS0710::Channel::Commands);
+ if (channel) {
+ auto cmd = at::cmd::CFUN(at::cmd::Modifier::Set);
+ cmd.set(Functionality::DisableRF);
+ auto resp = channel->cmd(cmd);
+ return resp.code == at::Result::Code::OK;
+ }
+ return false;
+}
+
+auto ConnectionManagerCellularCommands::connectToNetwork() -> bool
+{
+ using at::cfun::Functionality;
+ auto channel = cellular.cmux->get(TS0710::Channel::Commands);
+ if (channel) {
+ auto cmd = at::cmd::CFUN(at::cmd::Modifier::Set);
+ cmd.set(Functionality::Full);
+ auto resp = channel->cmd(cmd);
+ return resp.code == at::Result::Code::OK;
+ }
+ return false;
+}
+
+auto ConnectionManagerCellularCommands::isConnectedToNetwork() -> bool
+{
+
+ using at::cfun::Functionality;
+ auto channel = cellular.cmux->get(TS0710::Channel::Commands);
+ if (channel) {
+ auto cmd = at::cmd::CFUN(at::cmd::Modifier::Get);
+ auto response = channel->cmd(cmd);
+ if (response.code == at::Result::Code::OK) {
+ auto result = cmd.parse(response);
+ if (result.code == at::Result::Code::OK) {
+ return result.functionality == Functionality::Full;
+ }
+ }
+ }
+ return false;
+}
+
+auto ConnectionManagerCellularCommands::clearNetworkIndicator() -> bool
+{
+
+ // force clear signal indicator
+ constexpr auto rssi = 0;
+ SignalStrength signalStrength(rssi);
+ Store::GSM::get()->setSignalStrength(signalStrength.data);
+ auto msg = std::make_shared<CellularSignalStrengthUpdateNotification>();
+ cellular.bus.sendMulticast(msg, sys::BusChannel::ServiceCellularNotifications);
+
+ return true;
+}
+
+auto ConnectionManagerCellularCommands::hangUpOngoingCall() -> bool
+{
+ if (cellular.ongoingCall.isActive()) {
+ auto channel = cellular.cmux->get(TS0710::Channel::Commands);
+ if (channel) {
+ if (channel->cmd(at::factory(at::AT::ATH))) {
+ cellular.callStateTimer.stop();
+ if (!cellular.ongoingCall.endCall(CellularCall::Forced::True)) {
+ LOG_ERROR("Failed to end ongoing call");
+ return false;
+ }
+ auto msg = std::make_shared<CellularCallAbortedNotification>();
+ cellular.bus.sendMulticast(msg, sys::BusChannel::ServiceCellularNotifications);
+ }
+ }
+ }
+ return true;
+}
+
+auto ConnectionManagerCellularCommands::isConnectionTimerActive() -> bool
+{
+ return cellular.connectionTimer.isActive();
+}
+
+void ConnectionManagerCellularCommands::startConnectionTimer()
+{
+ cellular.connectionTimer.start();
+}
+
+void ConnectionManagerCellularCommands::stopConnectionTimer()
+{
+ cellular.connectionTimer.stop();
+}
M module-services/service-cellular/doc/README.md => module-services/service-cellular/doc/README.md +14 -8
@@ 64,11 64,17 @@ Do not Disturb
Offline mode
* modem is disconnected from the GSM network, both calls and messages are rejected
-| | Connected | Do not Disturb | Offline |
-| ----------- | --------- | -------------- | ------- |
-|Incoming calls| Allowed | Rejected | Not allowed |
-|Outgoing calls| Allowed | Allowed | Not allowed |
-|Incoming messages| Allowed | Allowed | Not allowed |
-|Outgoing messages| Allowed | Allowed | Not allowed |
-
->
\ No newline at end of file
+Messages only mode
+* modem is disconnected from the GSM network, calls are rejected, sending messages is rejected
+* phone is connecting to the GSM network in selected by settings period to fetch incoming messages
+
+| | Connected | Do not Disturb | Offline | Message only |
+| ----------- | --------- | -------------- | ------- | ------- |
+|Incoming calls| Allowed | Rejected | Not allowed | Rejected |
+|Outgoing calls| Allowed | Allowed | Not allowed | Rejected |
+|Incoming messages| Allowed | Allowed | Not allowed | Rejected |
+|Outgoing messages| Allowed | Allowed | Not allowed | Partially allowed |
+
+
+
+<
\ No newline at end of file
A module-services/service-cellular/doc/connection_manager.puml => module-services/service-cellular/doc/connection_manager.puml +59 -0
@@ 0,0 1,59 @@
+@startuml
+
+participant "Connection manager " as manager
+participant "Service cellular" as cellular
+participant "Phone mode observer " as mode
+
+== Phone is connected to the GSM network==
+
+mode ->cellular : Phone mode change to Connected/ Do not Disturb
+cellular -> manager : onPhoneMode()
+manager -> cellular :isConnectedToTheNetwork() AT+CFUN?
+cellular -> manager : +CFUN: 1
+
+mode ->cellular : Phone mode change to Offline / Message only
+cellular -> manager : onPhoneMode()
+manager -> cellular :isConnectedToTheNetwork() AT+CFUN?
+cellular -> manager : +CFUN: 1
+manager -> cellular :hangUpOngoingCall()
+manager -> cellular :disconnectFromNetwork() AT+CFUN=4
+manager -> cellular :clearNetworkIndicator()
+manager->manager : handle switch to selected oflline mode
+
+== Phone is not connected to the GSM network==
+
+mode ->cellular : Phone mode change to CConnected/ Do not Disturb
+cellular -> manager : onPhoneMode()
+manager -> cellular :isConnectedToTheNetwork() AT+CFUN?
+cellular -> manager : +CFUN: 4
+manager -> cellular :connectToTheNetwork() AT+CFUN=1
+
+mode ->cellular : Phone mode change to Offline / Message only
+cellular -> manager : onPhoneMode()
+manager -> cellular :isConnectedToTheNetwork() AT+CFUN?
+cellular -> manager : +CFUN: 4
+manager->manager : handle switch to selected oflline mode
+
+==handle switch to selected oflline mode==
+
+==handleModeChangeToOfflineMode()==
+manager -> cellular : isConnectionTimerActive()
+cellular -> manager : timer is active
+manager -> cellular : stopConnectionTimer()
+
+==handleModeChangeToOfflineMode()==
+manager -> cellular : isConnectionTimerActive()
+cellular -> manager : timer is not active
+manager -> cellular : startonnectionTimer()
+
+==Connection manager in Messages only mode==
+cellular -> manager : service timer tick (60 seconds)
+manager -> manager : offline period not expired, online period not expired
+
+manager -> manager : offline period expired onTimTick()
+manager -> cellular : connectToNetwork()
+
+manager -> manager : online period expired onTimTick()
+manager -> cellular : disconnectFromNetwork()
+manager -> cellular :clearNetworkIndicator()
+@enduml
A module-services/service-cellular/doc/connection_manager.svg => module-services/service-cellular/doc/connection_manager.svg +69 -0
@@ 0,0 1,69 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentScriptType="application/ecmascript" contentStyleType="text/css" height="1447px" preserveAspectRatio="none" style="width:899px;height:1447px;" version="1.1" viewBox="0 0 899 1447" width="899px" zoomAndPan="magnify"><defs><filter height="300%" id="fatert3ea1apr" 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><line style="stroke:#A80036;stroke-width:1.0;stroke-dasharray:5.0,5.0;" x1="91" x2="91" y1="40.2969" y2="1403.7422"/><line style="stroke:#A80036;stroke-width:1.0;stroke-dasharray:5.0,5.0;" x1="441" x2="441" y1="40.2969" y2="1403.7422"/><line style="stroke:#A80036;stroke-width:1.0;stroke-dasharray:5.0,5.0;" x1="798" x2="798" y1="40.2969" y2="1403.7422"/><rect fill="#FEFECE" filter="url(#fatert3ea1apr)" height="30.2969" style="stroke:#A80036;stroke-width:1.5;" width="168" x="5" y="5"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="150" x="12" y="24.9951">Connection manager</text><rect fill="#FEFECE" filter="url(#fatert3ea1apr)" height="30.2969" style="stroke:#A80036;stroke-width:1.5;" width="168" x="5" y="1402.7422"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="150" x="12" y="1422.7373">Connection manager</text><rect fill="#FEFECE" filter="url(#fatert3ea1apr)" height="30.2969" style="stroke:#A80036;stroke-width:1.5;" width="124" x="377" y="5"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="110" x="384" y="24.9951">Service cellular</text><rect fill="#FEFECE" filter="url(#fatert3ea1apr)" height="30.2969" style="stroke:#A80036;stroke-width:1.5;" width="124" x="377" y="1402.7422"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="110" x="384" y="1422.7373">Service cellular</text><rect fill="#FEFECE" filter="url(#fatert3ea1apr)" height="30.2969" style="stroke:#A80036;stroke-width:1.5;" width="174" x="709" y="5"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="156" x="716" y="24.9951">Phone mode observer</text><rect fill="#FEFECE" filter="url(#fatert3ea1apr)" height="30.2969" style="stroke:#A80036;stroke-width:1.5;" width="174" x="709" y="1402.7422"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="156" x="716" y="1422.7373">Phone mode observer</text><rect fill="#EEEEEE" filter="url(#fatert3ea1apr)" height="3" style="stroke:#EEEEEE;stroke-width:1.0;" width="892" x="0" y="70.8633"/><line style="stroke:#000000;stroke-width:1.0;" x1="0" x2="892" y1="70.8633" y2="70.8633"/><line style="stroke:#000000;stroke-width:1.0;" x1="0" x2="892" y1="73.8633" y2="73.8633"/><rect fill="#EEEEEE" filter="url(#fatert3ea1apr)" height="23.1328" style="stroke:#000000;stroke-width:2.0;" width="310" x="291" y="60.2969"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacing" textLength="296" x="297" y="76.3638">Phone is connected to the GSM network</text><polygon fill="#A80036" points="452,110.5625,442,114.5625,452,118.5625,448,114.5625" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="446" x2="797" y1="114.5625" y2="114.5625"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="324" x="458" y="109.4966">Phone mode change to Connected/ Do not Disturb</text><polygon fill="#A80036" points="102,139.6953,92,143.6953,102,147.6953,98,143.6953" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="96" x2="440" y1="143.6953" y2="143.6953"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="101" x="108" y="138.6294">onPhoneMode()</text><polygon fill="#A80036" points="429,168.8281,439,172.8281,429,176.8281,433,172.8281" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="91" x2="435" y1="172.8281" y2="172.8281"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="260" x="98" y="167.7622">isConnectedToTheNetwork() AT+CFUN?</text><polygon fill="#A80036" points="102,197.9609,92,201.9609,102,205.9609,98,201.9609" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="96" x2="440" y1="201.9609" y2="201.9609"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="63" x="108" y="196.895">+CFUN: 1</text><polygon fill="#A80036" points="452,227.0938,442,231.0938,452,235.0938,448,231.0938" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="446" x2="797" y1="231.0938" y2="231.0938"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="298" x="458" y="226.0278">Phone mode change to Offline / Message only</text><polygon fill="#A80036" points="102,256.2266,92,260.2266,102,264.2266,98,260.2266" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="96" x2="440" y1="260.2266" y2="260.2266"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="101" x="108" y="255.1606">onPhoneMode()</text><polygon fill="#A80036" points="429,285.3594,439,289.3594,429,293.3594,433,289.3594" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="91" x2="435" y1="289.3594" y2="289.3594"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="260" x="98" y="284.2935">isConnectedToTheNetwork() AT+CFUN?</text><polygon fill="#A80036" points="102,314.4922,92,318.4922,102,322.4922,98,318.4922" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="96" x2="440" y1="318.4922" y2="318.4922"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="63" x="108" y="313.4263">+CFUN: 1</text><polygon fill="#A80036" points="429,343.625,439,347.625,429,351.625,433,347.625" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="91" x2="435" y1="347.625" y2="347.625"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="139" x="98" y="342.5591">hangUpOngoingCall()</text><polygon fill="#A80036" points="429,372.7578,439,376.7578,429,380.7578,433,376.7578" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="91" x2="435" y1="376.7578" y2="376.7578"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="255" x="98" y="371.6919">disconnectFromNetwork() AT+CFUN=4</text><polygon fill="#A80036" points="429,401.8906,439,405.8906,429,409.8906,433,405.8906" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="91" x2="435" y1="405.8906" y2="405.8906"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="154" x="98" y="400.8247">clearNetworkIndicator()</text><line style="stroke:#A80036;stroke-width:1.0;" x1="91" x2="133" y1="435.0234" y2="435.0234"/><line style="stroke:#A80036;stroke-width:1.0;" x1="133" x2="133" y1="435.0234" y2="448.0234"/><line style="stroke:#A80036;stroke-width:1.0;" x1="92" x2="133" y1="448.0234" y2="448.0234"/><polygon fill="#A80036" points="102,444.0234,92,448.0234,102,452.0234,98,448.0234" style="stroke:#A80036;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="252" x="98" y="429.9575">handle switch to selected oflline mode</text><rect fill="#EEEEEE" filter="url(#fatert3ea1apr)" height="3" style="stroke:#EEEEEE;stroke-width:1.0;" width="892" x="0" y="476.5898"/><line style="stroke:#000000;stroke-width:1.0;" x1="0" x2="892" y1="476.5898" y2="476.5898"/><line style="stroke:#000000;stroke-width:1.0;" x1="0" x2="892" y1="479.5898" y2="479.5898"/><rect fill="#EEEEEE" filter="url(#fatert3ea1apr)" height="23.1328" style="stroke:#000000;stroke-width:2.0;" width="339" x="276.5" y="466.0234"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacing" textLength="325" x="282.5" y="482.0903">Phone is not connected to the GSM network</text><polygon fill="#A80036" points="452,516.2891,442,520.2891,452,524.2891,448,520.2891" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="446" x2="797" y1="520.2891" y2="520.2891"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="333" x="458" y="515.2231">Phone mode change to CConnected/ Do not Disturb</text><polygon fill="#A80036" points="102,545.4219,92,549.4219,102,553.4219,98,549.4219" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="96" x2="440" y1="549.4219" y2="549.4219"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="101" x="108" y="544.356">onPhoneMode()</text><polygon fill="#A80036" points="429,574.5547,439,578.5547,429,582.5547,433,578.5547" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="91" x2="435" y1="578.5547" y2="578.5547"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="260" x="98" y="573.4888">isConnectedToTheNetwork() AT+CFUN?</text><polygon fill="#A80036" points="102,603.6875,92,607.6875,102,611.6875,98,607.6875" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="96" x2="440" y1="607.6875" y2="607.6875"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="63" x="108" y="602.6216">+CFUN: 4</text><polygon fill="#A80036" points="429,632.8203,439,636.8203,429,640.8203,433,636.8203" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="91" x2="435" y1="636.8203" y2="636.8203"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="243" x="98" y="631.7544">connectToTheNetwork() AT+CFUN=1</text><polygon fill="#A80036" points="452,661.9531,442,665.9531,452,669.9531,448,665.9531" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="446" x2="797" y1="665.9531" y2="665.9531"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="298" x="458" y="660.8872">Phone mode change to Offline / Message only</text><polygon fill="#A80036" points="102,691.0859,92,695.0859,102,699.0859,98,695.0859" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="96" x2="440" y1="695.0859" y2="695.0859"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="101" x="108" y="690.02">onPhoneMode()</text><polygon fill="#A80036" points="429,720.2188,439,724.2188,429,728.2188,433,724.2188" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="91" x2="435" y1="724.2188" y2="724.2188"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="260" x="98" y="719.1528">isConnectedToTheNetwork() AT+CFUN?</text><polygon fill="#A80036" points="102,749.3516,92,753.3516,102,757.3516,98,753.3516" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="96" x2="440" y1="753.3516" y2="753.3516"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="63" x="108" y="748.2856">+CFUN: 4</text><line style="stroke:#A80036;stroke-width:1.0;" x1="91" x2="133" y1="782.4844" y2="782.4844"/><line style="stroke:#A80036;stroke-width:1.0;" x1="133" x2="133" y1="782.4844" y2="795.4844"/><line style="stroke:#A80036;stroke-width:1.0;" x1="92" x2="133" y1="795.4844" y2="795.4844"/><polygon fill="#A80036" points="102,791.4844,92,795.4844,102,799.4844,98,795.4844" style="stroke:#A80036;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="252" x="98" y="777.4185">handle switch to selected oflline mode</text><rect fill="#EEEEEE" filter="url(#fatert3ea1apr)" height="3" style="stroke:#EEEEEE;stroke-width:1.0;" width="892" x="0" y="824.0508"/><line style="stroke:#000000;stroke-width:1.0;" x1="0" x2="892" y1="824.0508" y2="824.0508"/><line style="stroke:#000000;stroke-width:1.0;" x1="0" x2="892" y1="827.0508" y2="827.0508"/><rect fill="#EEEEEE" filter="url(#fatert3ea1apr)" height="23.1328" style="stroke:#000000;stroke-width:2.0;" width="298" x="297" y="813.4844"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacing" textLength="284" x="303" y="829.5513">handle switch to selected oflline mode</text><rect fill="#EEEEEE" filter="url(#fatert3ea1apr)" height="3" style="stroke:#EEEEEE;stroke-width:1.0;" width="892" x="0" y="867.1836"/><line style="stroke:#000000;stroke-width:1.0;" x1="0" x2="892" y1="867.1836" y2="867.1836"/><line style="stroke:#000000;stroke-width:1.0;" x1="0" x2="892" y1="870.1836" y2="870.1836"/><rect fill="#EEEEEE" filter="url(#fatert3ea1apr)" height="23.1328" style="stroke:#000000;stroke-width:2.0;" width="277" x="307.5" y="856.6172"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacing" textLength="263" x="313.5" y="872.6841">handleModeChangeToOfflineMode()</text><polygon fill="#A80036" points="429,906.8828,439,910.8828,429,914.8828,433,910.8828" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="91" x2="435" y1="910.8828" y2="910.8828"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="173" x="98" y="905.8169">isConnectionTimerActive()</text><polygon fill="#A80036" points="102,936.0156,92,940.0156,102,944.0156,98,940.0156" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="96" x2="440" y1="940.0156" y2="940.0156"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="94" x="108" y="934.9497">timer is active</text><polygon fill="#A80036" points="429,965.1484,439,969.1484,429,973.1484,433,969.1484" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="91" x2="435" y1="969.1484" y2="969.1484"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="149" x="98" y="964.0825">stopConnectionTimer()</text><rect fill="#EEEEEE" filter="url(#fatert3ea1apr)" height="3" style="stroke:#EEEEEE;stroke-width:1.0;" width="892" x="0" y="997.7148"/><line style="stroke:#000000;stroke-width:1.0;" x1="0" x2="892" y1="997.7148" y2="997.7148"/><line style="stroke:#000000;stroke-width:1.0;" x1="0" x2="892" y1="1000.7148" y2="1000.7148"/><rect fill="#EEEEEE" filter="url(#fatert3ea1apr)" height="23.1328" style="stroke:#000000;stroke-width:2.0;" width="277" x="307.5" y="987.1484"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacing" textLength="263" x="313.5" y="1003.2153">handleModeChangeToOfflineMode()</text><polygon fill="#A80036" points="429,1037.4141,439,1041.4141,429,1045.4141,433,1041.4141" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="91" x2="435" y1="1041.4141" y2="1041.4141"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="173" x="98" y="1036.3481">isConnectionTimerActive()</text><polygon fill="#A80036" points="102,1066.5469,92,1070.5469,102,1074.5469,98,1070.5469" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="96" x2="440" y1="1070.5469" y2="1070.5469"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="119" x="108" y="1065.481">timer is not active</text><polygon fill="#A80036" points="429,1095.6797,439,1099.6797,429,1103.6797,433,1099.6797" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="91" x2="435" y1="1099.6797" y2="1099.6797"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="142" x="98" y="1094.6138">startonnectionTimer()</text><rect fill="#EEEEEE" filter="url(#fatert3ea1apr)" height="3" style="stroke:#EEEEEE;stroke-width:1.0;" width="892" x="0" y="1128.2461"/><line style="stroke:#000000;stroke-width:1.0;" x1="0" x2="892" y1="1128.2461" y2="1128.2461"/><line style="stroke:#000000;stroke-width:1.0;" x1="0" x2="892" y1="1131.2461" y2="1131.2461"/><rect fill="#EEEEEE" filter="url(#fatert3ea1apr)" height="23.1328" style="stroke:#000000;stroke-width:2.0;" width="343" x="274.5" y="1117.6797"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacing" textLength="329" x="280.5" y="1133.7466">Connection manager in Messages only mode</text><polygon fill="#A80036" points="102,1167.9453,92,1171.9453,102,1175.9453,98,1171.9453" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="96" x2="440" y1="1171.9453" y2="1171.9453"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="201" x="108" y="1166.8794">service timer tick (60 seconds)</text><line style="stroke:#A80036;stroke-width:1.0;" x1="91" x2="133" y1="1201.0781" y2="1201.0781"/><line style="stroke:#A80036;stroke-width:1.0;" x1="133" x2="133" y1="1201.0781" y2="1214.0781"/><line style="stroke:#A80036;stroke-width:1.0;" x1="92" x2="133" y1="1214.0781" y2="1214.0781"/><polygon fill="#A80036" points="102,1210.0781,92,1214.0781,102,1218.0781,98,1214.0781" style="stroke:#A80036;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="336" x="98" y="1196.0122">offline period not expired, online period not expired</text><line style="stroke:#A80036;stroke-width:1.0;" x1="91" x2="133" y1="1243.2109" y2="1243.2109"/><line style="stroke:#A80036;stroke-width:1.0;" x1="133" x2="133" y1="1243.2109" y2="1256.2109"/><line style="stroke:#A80036;stroke-width:1.0;" x1="92" x2="133" y1="1256.2109" y2="1256.2109"/><polygon fill="#A80036" points="102,1252.2109,92,1256.2109,102,1260.2109,98,1256.2109" style="stroke:#A80036;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="222" x="98" y="1238.145">offline period expired onTimTick()</text><polygon fill="#A80036" points="429,1281.3438,439,1285.3438,429,1289.3438,433,1285.3438" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="91" x2="435" y1="1285.3438" y2="1285.3438"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="132" x="98" y="1280.2778">connectToNetwork()</text><line style="stroke:#A80036;stroke-width:1.0;" x1="91" x2="133" y1="1314.4766" y2="1314.4766"/><line style="stroke:#A80036;stroke-width:1.0;" x1="133" x2="133" y1="1314.4766" y2="1327.4766"/><line style="stroke:#A80036;stroke-width:1.0;" x1="92" x2="133" y1="1327.4766" y2="1327.4766"/><polygon fill="#A80036" points="102,1323.4766,92,1327.4766,102,1331.4766,98,1327.4766" style="stroke:#A80036;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="220" x="98" y="1309.4106">online period expired onTimTick()</text><polygon fill="#A80036" points="429,1352.6094,439,1356.6094,429,1360.6094,433,1356.6094" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="91" x2="435" y1="1356.6094" y2="1356.6094"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="168" x="98" y="1351.5435">disconnectFromNetwork()</text><polygon fill="#A80036" points="429,1381.7422,439,1385.7422,429,1389.7422,433,1385.7422" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="91" x2="435" y1="1385.7422" y2="1385.7422"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="154" x="98" y="1380.6763">clearNetworkIndicator()</text><!--MD5=[e46c5ad7b3b5a2a99eecdfa0cfb63c20]
+@startuml
+
+participant "Connection manager " as manager
+participant "Service cellular" as cellular
+participant "Phone mode observer " as mode
+
+== Phone is connected to the GSM network==
+
+mode ->cellular : Phone mode change to Connected/ Do not Disturb
+cellular -> manager : onPhoneMode()
+manager -> cellular :isConnectedToTheNetwork() AT+CFUN?
+cellular -> manager : +CFUN: 1
+
+mode ->cellular : Phone mode change to Offline / Message only
+cellular -> manager : onPhoneMode()
+manager -> cellular :isConnectedToTheNetwork() AT+CFUN?
+cellular -> manager : +CFUN: 1
+manager -> cellular :hangUpOngoingCall()
+manager -> cellular :disconnectFromNetwork() AT+CFUN=4
+manager -> cellular :clearNetworkIndicator()
+manager->manager : handle switch to selected oflline mode
+
+== Phone is not connected to the GSM network==
+
+mode ->cellular : Phone mode change to CConnected/ Do not Disturb
+cellular -> manager : onPhoneMode()
+manager -> cellular :isConnectedToTheNetwork() AT+CFUN?
+cellular -> manager : +CFUN: 4
+manager -> cellular :connectToTheNetwork() AT+CFUN=1
+
+mode ->cellular : Phone mode change to Offline / Message only
+cellular -> manager : onPhoneMode()
+manager -> cellular :isConnectedToTheNetwork() AT+CFUN?
+cellular -> manager : +CFUN: 4
+manager->manager : handle switch to selected oflline mode
+
+==handle switch to selected oflline mode==
+
+==handleModeChangeToOfflineMode()==
+manager -> cellular : isConnectionTimerActive()
+cellular -> manager : timer is active
+manager -> cellular : stopConnectionTimer()
+
+==handleModeChangeToOfflineMode()==
+manager -> cellular : isConnectionTimerActive()
+cellular -> manager : timer is not active
+manager -> cellular : startonnectionTimer()
+
+==Connection manager in Messages only mode==
+cellular -> manager : service timer tick (60 seconds)
+manager -> manager : offline period not expired, online period not expired
+
+manager -> manager : offline period expired onTimTick()
+manager -> cellular : connectToNetwork()
+
+manager -> manager : online period expired onTimTick()
+manager -> cellular : disconnectFromNetwork()
+manager -> cellular :clearNetworkIndicator()
+@enduml
+
+PlantUML version 1.2021.2(Sun Mar 07 12:10:27 CET 2021)
+(GPL source distribution)
+Java Runtime: OpenJDK Runtime Environment
+JVM: OpenJDK 64-Bit Server VM
+Default Encoding: UTF-8
+Language: pl
+Country: PL
+--></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 +17 -1
@@ 74,7 74,8 @@ class CellularMessage : public sys::DataMessage
MMIData,
NewIncomingSMS,
RadioOnOff,
- SendSMS
+ SendSMS,
+ CellularSetConnectionFrequency
};
explicit CellularMessage(Type type) : sys::DataMessage(), type(type)
{}
@@ 976,6 977,21 @@ class CellularSetFlightModeMessage : public CellularMessage
bool flightModeOn;
};
+class CellularSetConnectionFrequencyMessage : public CellularMessage
+{
+ public:
+ explicit CellularSetConnectionFrequencyMessage(const uint8_t &connectionFrequency)
+ : CellularMessage(Type::CellularSetConnectionFrequency), connectionFrequency(connectionFrequency)
+ {}
+ auto getConnectionFrequency() const noexcept -> uint8_t
+ {
+ return connectionFrequency;
+ }
+
+ private:
+ uint8_t connectionFrequency;
+};
+
class CellularCallActiveNotification : public CellularNotificationMessage
{
public:
M module-services/service-cellular/service-cellular/CellularServiceAPI.hpp => module-services/service-cellular/service-cellular/CellularServiceAPI.hpp +2 -0
@@ 148,4 148,6 @@ namespace CellularServiceAPI
bool SetFlightMode(sys::Service *serv, bool flightModeOn);
+ bool SetConnectionFrequency(sys::Service *serv, uint8_t connectionFrequency);
+
}; // namespace CellularServiceAPI
M module-services/service-cellular/service-cellular/ServiceCellular.hpp => module-services/service-cellular/service-cellular/ServiceCellular.hpp +14 -10
@@ 11,6 11,7 @@
#include "USSD.hpp"
#include "PacketData.hpp"
#include "PacketDataCellularMessage.hpp"
+#include <service-cellular/connection-manager/ConnectionManager.hpp>
#include <module-cellular/Modem/ATURCStream.hpp>
#include <Modem/TS0710/DLC_channel.h>
@@ 63,6 64,8 @@ namespace constants
inline constexpr std::chrono::milliseconds enterSleepModeTime{5s};
} // namespace constants
+class ConnectionManager;
+
class ServiceCellular : public sys::Service
{
@@ 188,13 191,18 @@ class ServiceCellular : public sys::Service
// used to enter modem sleep mode
sys::TimerHandle sleepTimer;
+ // used to manage network connection in Messages only mode
+ sys::TimerHandle connectionTimer;
+
+ std::unique_ptr<settings::Settings> settings;
+
void SleepTimerHandler();
void CallStateTimerHandler();
DLC_channel::Callback_t notificationCallback = nullptr;
std::unique_ptr<packet_data::PacketData> packetData;
std::unique_ptr<sys::phone_modes::Observer> phoneModeObserver;
-
+ std::unique_ptr<ConnectionManager> connectionManager;
cellular::State state;
bsp::Board board = bsp::Board::none;
@@ 268,7 276,6 @@ class ServiceCellular : public sys::Service
/// Process change of power state
void handle_power_state_change();
- std::unique_ptr<settings::Settings> settings = std::make_unique<settings::Settings>(this);
bool handle_apn_conf_procedure();
bool handleTextMessagesInit();
@@ 334,6 341,7 @@ class ServiceCellular : public sys::Service
friend class NetworkSettings;
friend class packet_data::PDPContext;
friend class packet_data::PacketData;
+ friend class ConnectionManagerCellularCommands;
void volteChanged(const std::string &value);
void apnListChanged(const std::string &value);
@@ 346,8 354,8 @@ class ServiceCellular : public sys::Service
auto handleCellularListCallsMessage(CellularMessage *msg) -> std::shared_ptr<sys::ResponseMessage>;
auto handleDBNotificatioMessage(db::NotificationMessage *msg) -> std::shared_ptr<sys::ResponseMessage>;
auto handleCellularRingingMessage(CellularRingingMessage *msg) -> std::shared_ptr<sys::ResponseMessage>;
- auto handleCellularIncominCallMessage(CellularIncominCallMessage *msg) -> std::shared_ptr<sys::ResponseMessage>;
- auto handleCellularCallerIdMessage(CellularCallerIdMessage *msg) -> std::shared_ptr<sys::ResponseMessage>;
+ auto handleCellularIncominCallMessage(sys::Message *msg) -> std::shared_ptr<sys::ResponseMessage>;
+ auto handleCellularCallerIdMessage(sys::Message *msg) -> std::shared_ptr<sys::ResponseMessage>;
auto handleCellularSimProcedureMessage(sys::Message *msg) -> std::shared_ptr<sys::ResponseMessage>;
auto handleCellularGetIMSIMessage(sys::Message *msg) -> std::shared_ptr<sys::ResponseMessage>;
auto handleCellularGetOwnNumberMessage(sys::Message *msg) -> std::shared_ptr<sys::ResponseMessage>;
@@ 384,13 392,9 @@ class ServiceCellular : public sys::Service
auto handleCellularSendSMSMessage(sys::Message *msg) -> std::shared_ptr<sys::ResponseMessage>;
auto handleCellularRingNotification(sys::Message *msg) -> std::shared_ptr<sys::ResponseMessage>;
auto handleCellularCallerIdNotification(sys::Message *msg) -> std::shared_ptr<sys::ResponseMessage>;
+ auto handleCellularSetConnectionFrequencyMessage(sys::Message *msg) -> std::shared_ptr<sys::ResponseMessage>;
- auto isModemRadioModuleOn() -> bool;
- auto turnOnRadioModule() -> bool;
- auto turnOffRadioModule() -> bool;
-
- auto switchToOffline() -> bool;
- auto doNotDisturbCondition() -> bool;
+ auto isIncommingCallAllowed() -> bool;
auto hangUpCall() -> bool;
};
A module-services/service-cellular/service-cellular/connection-manager/ConnectionManager.hpp => module-services/service-cellular/service-cellular/connection-manager/ConnectionManager.hpp +87 -0
@@ 0,0 1,87 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+#include "ConnectionManagerCellularCommandsInterface.hpp"
+#include "module-services/service-cellular/service-cellular/ServiceCellular.hpp"
+#include <module-sys/PhoneModes/Observer.hpp>
+#include <functional>
+
+// connection timer period is 1 minute, connect to network for 5 minutes
+constexpr std::chrono::minutes connectedPeriod{5};
+
+/**
+ * @brief Intended for GSM network connection management depending on the selected phone mode.
+ * Switching modes takes place at Phone Modes Observer event.
+ */
+class ConnectionManager
+{
+ public:
+ /**
+ * @brief Constructor
+ * @param flightMode current setting for flight mode
+ * @param interval current setting for connection interval in Message only mode
+ * @param serviceCellular pointer to service cellular methods provider
+ */
+ explicit ConnectionManager(const bool flightMode,
+ const std::chrono::minutes interval,
+ std::shared_ptr<ConnectionManagerCellularCommandsInterface> serviceCellular)
+ : isFlightMode(flightMode), connectionInterval(interval), cellular(serviceCellular)
+ {}
+ /**
+ * @brief Handles Phone mode change. Called on event provided by Phone mode observer or settinhs change.
+ * @param mode current Phone mode
+ * @return true on success, false on fail
+ */
+ auto onPhoneModeChange(sys::phone_modes::PhoneMode mode) -> bool;
+ /**
+ * @brief Sets interval of connecting to the GSM network in Offline Message only mode
+ * @param interval connection interval in minutes
+ */
+ void setInterval(const std::chrono::minutes interval);
+ /**
+ * @biref Sets flight mode.
+ * @param mode flight mode enabled/disabled
+ */
+ void setFlightMode(const bool mode);
+ /**
+ * @brief Handles cyclic connecting/disconnecting from the GSM network in Offline Message only mode. Called in
+ * service timer handler.
+ */
+ void onTimerTick();
+
+ private:
+ bool isFlightMode;
+ std::chrono::minutes connectionInterval{0};
+ std::chrono::minutes minutesOfflineElapsed{0};
+ std::chrono::minutes minutesOnlineElapsed{0};
+ std::shared_ptr<ConnectionManagerCellularCommandsInterface> cellular;
+ bool onlinePeriod = false;
+
+ /**
+ * @brief Checks if flightMode and connection interval are set as Messages only mode
+ * @return true when Messages only is configured, false when not
+ */
+ auto isMessagesOnlyMode() -> bool;
+ /**
+ * It's handling change Phone mode to common offline modes
+ * @return true on success, false on fail
+ */
+ auto handleModeChangeToCommonOffline() -> bool;
+ /**
+ * It's handling change Phone mode to Offline mode
+ * @return true on success, false on fail
+ */
+ void handleModeChangeToOfflineMode();
+ /**
+ * It's handling change Phone mode to Messages only mode
+ * @return true on success, false on fail
+ */
+ void handleModeChangeToMessageOnlyMode();
+ /**
+ * It's handling change Phone mode to Connected / Do not disturb mode
+ * @return true on success, false on fail
+ */
+ auto handleModeChangeToConnected() -> bool;
+};
A module-services/service-cellular/service-cellular/connection-manager/ConnectionManagerCellularCommands.hpp => module-services/service-cellular/service-cellular/connection-manager/ConnectionManagerCellularCommands.hpp +26 -0
@@ 0,0 1,26 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+#include "ConnectionManagerCellularCommandsInterface.hpp"
+
+#include <module-services/service-cellular/service-cellular/ServiceCellular.hpp>
+
+class ConnectionManagerCellularCommands : public ConnectionManagerCellularCommandsInterface
+{
+ public:
+ explicit ConnectionManagerCellularCommands(ServiceCellular &serviceCellular) : cellular(serviceCellular)
+ {}
+ auto disconnectFromNetwork() -> bool final;
+ auto connectToNetwork() -> bool final;
+ auto isConnectedToNetwork() -> bool final;
+ auto clearNetworkIndicator() -> bool final;
+ auto hangUpOngoingCall() -> bool final;
+ auto isConnectionTimerActive() -> bool final;
+ void startConnectionTimer() final;
+ void stopConnectionTimer() final;
+
+ private:
+ ServiceCellular &cellular;
+};
A module-services/service-cellular/service-cellular/connection-manager/ConnectionManagerCellularCommandsInterface.hpp => module-services/service-cellular/service-cellular/connection-manager/ConnectionManagerCellularCommandsInterface.hpp +52 -0
@@ 0,0 1,52 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+class ConnectionManagerCellularCommandsInterface
+{
+ public:
+ /**
+ * Destructor
+ */
+ virtual ~ConnectionManagerCellularCommandsInterface()
+ {}
+ /**
+ * It's enabling modem radio module, so it can connect to the GSM network
+ * @return true on success, false on fail
+ */
+ virtual auto disconnectFromNetwork() -> bool = 0;
+ /**
+ * It's enabling modem radio module, so it can connect to the GSM network
+ * @return true on success, false on fail
+ */
+ virtual auto connectToNetwork() -> bool = 0;
+ /**
+ * * Checks current state of modem radio module
+ * @return true when modem radio module is enabled, false when modem radio module is disabled
+ */
+ virtual auto isConnectedToNetwork() -> bool = 0;
+ /**
+ * * It's disabling modem radio module, so it can't connect to the GSM network
+ * @return true on success, false on fail
+ */
+ virtual auto clearNetworkIndicator() -> bool = 0;
+ /**
+ * @brief Checks if there is ongoing call and terminates it
+ * @return true on success, false on fail
+ */
+ virtual auto hangUpOngoingCall() -> bool = 0;
+ /**
+ * @brief Checks if connection Timer is active
+ * @return true when timer is active, false when not
+ */
+ virtual auto isConnectionTimerActive() -> bool = 0;
+ /**
+ * @brief Stats connectionTimer
+ */
+ virtual void startConnectionTimer() = 0;
+ /**
+ * @brief Stops connectionTimer
+ */
+ virtual void stopConnectionTimer() = 0;
+};
M module-services/service-cellular/tests/CMakeLists.txt => module-services/service-cellular/tests/CMakeLists.txt +8 -0
@@ 37,3 37,11 @@ add_catch2_executable(
module-cellular
)
+add_gtest_executable(
+ NAME
+ connection-manager
+ SRCS
+ unittest_connection-manager.cpp
+ LIBS
+ module-cellular
+)
A module-services/service-cellular/tests/unittest_connection-manager.cpp => module-services/service-cellular/tests/unittest_connection-manager.cpp +113 -0
@@ 0,0 1,113 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include <gtest/gtest.h>
+#include <gmock/gmock.h>
+
+#include <service-cellular/connection-manager/ConnectionManager.hpp>
+#include <service-cellular/connection-manager/ConnectionManagerCellularCommandsInterface.hpp>
+
+using namespace testing;
+
+class MockCellular : public ConnectionManagerCellularCommandsInterface
+{
+ public:
+ MOCK_METHOD(bool, disconnectFromNetwork, ());
+ MOCK_METHOD(bool, connectToNetwork, (), (override));
+ MOCK_METHOD(bool, isConnectedToNetwork, (), (override));
+ MOCK_METHOD(bool, clearNetworkIndicator, (), (override));
+ MOCK_METHOD(bool, hangUpOngoingCall, (), (override));
+ MOCK_METHOD(bool, isConnectionTimerActive, (), (override));
+ MOCK_METHOD(void, startConnectionTimer, (), (override));
+ MOCK_METHOD(void, stopConnectionTimer, (), (override));
+};
+
+TEST(ConnectionManager, onPhoneModeChange)
+{
+ std::shared_ptr<MockCellular> mock = std::make_shared<MockCellular>();
+ ConnectionManager tested(true, std::chrono::minutes{5}, mock);
+
+ // Connected / Do not disturb to Offline
+ EXPECT_CALL(*mock, isConnectedToNetwork()).Times(1).WillOnce(Return(true));
+ EXPECT_CALL(*mock, hangUpOngoingCall()).Times(1).WillOnce(Return(true));
+ EXPECT_CALL(*mock, disconnectFromNetwork()).Times(1).WillOnce(Return(true));
+ EXPECT_CALL(*mock, clearNetworkIndicator()).Times(1).WillOnce(Return(true));
+ EXPECT_CALL(*mock, isConnectionTimerActive()).Times(1).WillOnce(Return(true));
+ EXPECT_CALL(*mock, stopConnectionTimer()).Times(1);
+
+ EXPECT_CALL(*mock, startConnectionTimer()).Times(0);
+ EXPECT_CALL(*mock, connectToNetwork()).Times(0);
+ tested.onPhoneModeChange(sys::phone_modes::PhoneMode::Offline);
+
+ // Connected / Do not disturb to Messages only
+ EXPECT_CALL(*mock, isConnectedToNetwork()).Times(1).WillOnce(Return(true));
+ EXPECT_CALL(*mock, hangUpOngoingCall()).Times(1).WillOnce(Return(true));
+ EXPECT_CALL(*mock, disconnectFromNetwork()).Times(1).WillOnce(Return(true));
+ EXPECT_CALL(*mock, clearNetworkIndicator()).Times(1).WillOnce(Return(true));
+ EXPECT_CALL(*mock, isConnectionTimerActive()).Times(1).WillOnce(Return(false));
+ EXPECT_CALL(*mock, startConnectionTimer()).Times(1);
+
+ EXPECT_CALL(*mock, stopConnectionTimer()).Times(0);
+ EXPECT_CALL(*mock, connectToNetwork()).Times(0);
+ tested.setFlightMode(false);
+ tested.onPhoneModeChange(sys::phone_modes::PhoneMode::Offline);
+
+ // Offline to Connected / Do not disturb
+ EXPECT_CALL(*mock, isConnectionTimerActive()).Times(1).WillOnce(Return(false));
+ EXPECT_CALL(*mock, isConnectedToNetwork()).Times(1).WillOnce(Return(false));
+ EXPECT_CALL(*mock, connectToNetwork()).Times(1).WillOnce(Return(true));
+
+ EXPECT_CALL(*mock, disconnectFromNetwork()).Times(0);
+ tested.setFlightMode(true);
+ tested.onPhoneModeChange(sys::phone_modes::PhoneMode::Connected);
+
+ // Messages only to Connected / Do not disturb
+ EXPECT_CALL(*mock, isConnectionTimerActive()).Times(1).WillOnce(Return(true));
+ EXPECT_CALL(*mock, stopConnectionTimer()).Times(1);
+ EXPECT_CALL(*mock, isConnectedToNetwork()).Times(1).WillOnce(Return(false));
+ EXPECT_CALL(*mock, connectToNetwork()).Times(1).WillOnce(Return(true));
+
+ EXPECT_CALL(*mock, disconnectFromNetwork()).Times(0);
+ tested.onPhoneModeChange(sys::phone_modes::PhoneMode::Connected);
+}
+
+TEST(ConnectionManager, onTimerTick_Messages_only)
+{
+ std::shared_ptr<MockCellular> mock = std::make_shared<MockCellular>();
+ ConnectionManager tested(false, std::chrono::minutes{15}, mock);
+
+ // Messages only, interval 15 min
+ EXPECT_CALL(*mock, isConnectedToNetwork()).Times(1).WillOnce(Return(false));
+ EXPECT_CALL(*mock, isConnectionTimerActive()).Times(1).WillOnce(Return(false));
+ EXPECT_CALL(*mock, startConnectionTimer()).Times(1);
+ tested.onPhoneModeChange(sys::phone_modes::PhoneMode::Offline);
+
+ EXPECT_CALL(*mock, connectToNetwork()).Times(1).WillOnce(Return(true));
+ for (auto i = 0; i < 15; i++) {
+ tested.onTimerTick();
+ }
+
+ EXPECT_CALL(*mock, disconnectFromNetwork()).Times(1).WillOnce(Return(true));
+ for (auto i = 0; i < 5; i++) {
+ tested.onTimerTick();
+ }
+}
+
+TEST(ConnectionManager, onTimerTick_Offline)
+{
+ std::shared_ptr<MockCellular> mock = std::make_shared<MockCellular>();
+ ConnectionManager tested(true, std::chrono::minutes{15}, mock);
+
+ // Offline, timer was active
+ EXPECT_CALL(*mock, isConnectedToNetwork()).Times(1).WillOnce(Return(false));
+ EXPECT_CALL(*mock, isConnectionTimerActive()).Times(1).WillOnce(Return(true));
+ EXPECT_CALL(*mock, stopConnectionTimer()).Times(1);
+
+ tested.onPhoneModeChange(sys::phone_modes::PhoneMode::Offline);
+
+ EXPECT_CALL(*mock, connectToNetwork()).Times(0);
+ EXPECT_CALL(*mock, disconnectFromNetwork()).Times(0);
+ for (auto i = 0; i < 20; i++) {
+ tested.onTimerTick();
+ }
+}<
\ No newline at end of file