M module-apps/apps-common/locks/handlers/SimLockHandler.cpp => module-apps/apps-common/locks/handlers/SimLockHandler.cpp +6 -10
@@ 17,17 17,11 @@ namespace locks
constexpr unsigned int default_attempts = 4;
constexpr unsigned int max_input_size = 8;
constexpr unsigned int min_input_size = 4;
- constexpr unsigned int sim_not_responding_timeout = 3;
SimLockHandler::SimLockHandler(sys::Service *owner)
: owner(owner), lock(Lock::LockState::Unlocked, default_attempts)
{
lock.setInputSizeBounds(min_input_size, max_input_size);
-
- simResponseTimer = sys::TimerFactory::createSingleShotTimer(
- owner, simResponseTimerName, std::chrono::seconds{sim_not_responding_timeout}, [this](sys::Timer &) {
- handleSimNotRespondingMessage();
- });
}
void SimLockHandler::clearStoredInputs()
@@ 38,8 32,6 @@ namespace locks
void SimLockHandler::setSimInputTypeAction(SimInputTypeAction _simInputTypeAction)
{
- simResponseTimer.stop();
-
if (simInputTypeAction != _simInputTypeAction) {
simInputTypeAction = _simInputTypeAction;
lock.lockState = Lock::LockState::Unlocked;
@@ 107,7 99,6 @@ namespace locks
void SimLockHandler::setSim(cellular::api::SimSlot simSlot)
{
if (simReady) {
- simResponseTimer.start();
Store::GSM::get()->selected = static_cast<Store::GSM::SIM>(simSlot);
owner->bus.sendUnicast<cellular::msg::request::sim::SetActiveSim>(simSlot);
}
@@ 271,10 262,15 @@ namespace locks
sys::MessagePointer SimLockHandler::handleSimReadyMessage()
{
- simResponseTimer.stop();
+ setSimReady();
return sys::msgHandled();
}
+ sys::MessagePointer SimLockHandler::handleSimNotInsertedMessage()
+ {
+ return handleSimNotRespondingMessage();
+ }
+
sys::MessagePointer SimLockHandler::handleSimNotRespondingMessage()
{
setSimInputTypeAction(SimInputTypeAction::Error);
M module-apps/apps-common/locks/handlers/SimLockHandler.hpp => module-apps/apps-common/locks/handlers/SimLockHandler.hpp +1 -3
@@ 13,7 13,6 @@
namespace locks
{
using StoredLockInput = std::vector<unsigned int>;
- constexpr auto simResponseTimerName = "SimResponseTimer";
class SimLockHandler
{
@@ 28,8 27,6 @@ namespace locks
StoredLockInput storedFirstInput;
StoredLockInput storedSecondInput;
- sys::TimerHandle simResponseTimer;
-
void clearStoredInputs();
void setSimInputTypeAction(SimInputTypeAction _simInputTypeAction);
@@ 70,6 67,7 @@ namespace locks
sys::MessagePointer handleSimPinChangedMessage();
sys::MessagePointer handleSimAvailabilityMessage();
sys::MessagePointer handleSimReadyMessage();
+ sys::MessagePointer handleSimNotInsertedMessage();
sys::MessagePointer handleSimNotRespondingMessage();
void getSettingsSimSelect(const std::string &settingsSim);
M module-cellular/CMakeLists.txt => module-cellular/CMakeLists.txt +2 -0
@@ 24,6 24,7 @@ set(SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/at/src/UrcQiurc.cpp
${CMAKE_CURRENT_SOURCE_DIR}/at/src/UrcPoweredDown.cpp
${CMAKE_CURRENT_SOURCE_DIR}/at/src/UrcRing.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/at/src/UrcQSimstat.cpp
${CMAKE_CURRENT_SOURCE_DIR}/at/src/UrcResponse.cpp
${CMAKE_CURRENT_SOURCE_DIR}/at/src/UrcFactory.cpp
${CMAKE_CURRENT_SOURCE_DIR}/at/src/Commands.cpp
@@ 37,6 38,7 @@ set(SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/at/cmd/src/CPBS.cpp
${CMAKE_CURRENT_SOURCE_DIR}/at/cmd/src/CPBR.cpp
${CMAKE_CURRENT_SOURCE_DIR}/at/cmd/src/QNWINFO.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/at/cmd/src/QSIMSTAT.cpp
)
add_library(${PROJECT_NAME} STATIC ${SOURCES})
A module-cellular/at/SimInsertedState.hpp => module-cellular/at/SimInsertedState.hpp +20 -0
@@ 0,0 1,20 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+namespace at
+{
+ enum class SimInsertedStatus
+ {
+ Removed,
+ Inserted,
+ Unknown
+ };
+
+ enum class SimInsertedStatusEnable
+ {
+ Disable,
+ Enable
+ };
+} // namespace at
M module-cellular/at/UrcHandler.hpp => module-cellular/at/UrcHandler.hpp +2 -0
@@ 16,6 16,7 @@ namespace at::urc
class Ring;
class PoweredDown;
class UrcResponse;
+ class QSimstat;
class UrcHandler
{
@@ 31,5 32,6 @@ namespace at::urc
virtual void Handle(Ring &urc) = 0;
virtual void Handle(PoweredDown &urc) = 0;
virtual void Handle(UrcResponse &urc) = 0;
+ virtual void Handle(QSimstat &urc) = 0;
};
} // namespace at::urc
A module-cellular/at/UrcQSimstat.hpp => module-cellular/at/UrcQSimstat.hpp +40 -0
@@ 0,0 1,40 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+#include "Urc.hpp"
+#include "UrcHandler.hpp"
+#include "SimInsertedState.hpp"
+
+namespace at::urc
+{
+ class QSimstat : public Urc
+ {
+ static constexpr std::string_view head = "+QSIMSTAT";
+ const size_t minParametersCount = 2;
+
+ enum class Tokens
+ {
+ Enable,
+ InsertedStatus
+ };
+
+ public:
+ static bool isURC(const std::string &uHead)
+ {
+ return uHead.find(QSimstat::head) != std::string::npos;
+ }
+
+ using Urc::Urc;
+
+ [[nodiscard]] auto isValid() const noexcept -> bool override;
+ [[nodiscard]] auto getInsertedStatus() const noexcept -> std::optional<at::SimInsertedStatus>;
+ [[nodiscard]] auto getEnabled() const noexcept -> std::optional<at::SimInsertedStatusEnable>;
+
+ void Handle(UrcHandler &h) final
+ {
+ h.Handle(*this);
+ }
+ };
+} // namespace at::urc
A module-cellular/at/cmd/QSIMSTAT.hpp => module-cellular/at/cmd/QSIMSTAT.hpp +43 -0
@@ 0,0 1,43 @@
+// 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 "Result.hpp"
+#include <at/Cmd.hpp>
+#include <functional>
+#include <SimInsertedState.hpp>
+
+namespace at
+{
+ namespace result
+ {
+ struct QSIMSTAT : public Result
+ {
+ at::SimInsertedStatusEnable enabled;
+ at::SimInsertedStatus status;
+ explicit QSIMSTAT(const Result &that);
+ };
+ } // namespace result
+
+ namespace cmd
+ {
+ class QSIMSTAT : public Cmd
+ {
+ public:
+ QSIMSTAT() noexcept;
+ explicit QSIMSTAT(at::cmd::Modifier mod) noexcept;
+
+ [[nodiscard]] auto parseQSIMSTAT(const Result &base_result) -> result::QSIMSTAT;
+
+ private:
+ enum class responseTokens
+ {
+ Enabled,
+ SimInserted
+ };
+ void parseTokens(const std::vector<std::string> &tokens, result::QSIMSTAT &parsed);
+ };
+ } // namespace cmd
+
+} // namespace at
A module-cellular/at/cmd/src/QSIMSTAT.cpp => module-cellular/at/cmd/src/QSIMSTAT.cpp +80 -0
@@ 0,0 1,80 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include <at/cmd/QSIMSTAT.hpp>
+
+#include <log.hpp>
+#include <memory>
+#include <string>
+
+namespace at
+{
+ namespace cmd
+ {
+ QSIMSTAT::QSIMSTAT(at::cmd::Modifier mod) noexcept : Cmd("AT+QSIMSTAT", mod, at::default_timeout)
+ {}
+
+ QSIMSTAT::QSIMSTAT() noexcept : QSIMSTAT(at::cmd::Modifier::None)
+ {}
+
+ auto QSIMSTAT::parseQSIMSTAT(const Result &base_result) -> result::QSIMSTAT
+ {
+
+ auto constexpr responseHeader = "+QSIMSTAT: ";
+ auto constexpr qsimstatTokensCount = 2;
+ result::QSIMSTAT parsed{base_result};
+
+ if (parsed) {
+ if (parsed.response.empty()) {
+ LOG_ERROR("Can't parse - empty response");
+ parsed.code = result::QSIMSTAT::Code::PARSING_ERROR;
+ }
+ else {
+ std::string str = parsed.response[0];
+ if (str.find(responseHeader) == std::string::npos) {
+ LOG_ERROR("Can't parse - bad header");
+ parsed.code = result::QSIMSTAT::Code::PARSING_ERROR;
+ return parsed;
+ }
+
+ utils::findAndReplaceAll(str, responseHeader, "");
+ utils::trim(str);
+
+ std::vector<std::string> tokens = utils::split(str, ',');
+
+ if (tokens.size() != qsimstatTokensCount) {
+ LOG_ERROR("Can't parse - invalid tokens count");
+ parsed.code = result::QSIMSTAT::Code::PARSING_ERROR;
+ return parsed;
+ }
+
+ parseTokens(tokens, parsed);
+ }
+ }
+ return parsed;
+ }
+
+ void QSIMSTAT::parseTokens(const std::vector<std::string> &tokens, result::QSIMSTAT &parsed)
+ {
+ auto status = 0, enabled = 0;
+ if (utils::toNumeric(tokens[magic_enum::enum_integer(responseTokens::SimInserted)], status) &&
+ utils::toNumeric(tokens[magic_enum::enum_integer(responseTokens::Enabled)], enabled)) {
+ if (magic_enum::enum_contains<SimInsertedStatus>(status) &&
+ magic_enum::enum_contains<at::SimInsertedStatusEnable>(enabled)) {
+ parsed.enabled = static_cast<at::SimInsertedStatusEnable>(enabled);
+ parsed.status = static_cast<SimInsertedStatus>(status);
+ return;
+ }
+ }
+
+ LOG_ERROR("Can't parse - bad value");
+ parsed.code = result::QSIMSTAT::Code::PARSING_ERROR;
+ }
+ } // namespace cmd
+ namespace result
+ {
+ QSIMSTAT::QSIMSTAT(const Result &that) : Result(that)
+ {}
+
+ } // namespace result
+} // namespace at
M module-cellular/at/src/UrcFactory.cpp => module-cellular/at/src/UrcFactory.cpp +4 -0
@@ 14,6 14,7 @@
#include <UrcCpin.hpp>
#include <UrcQiurc.hpp>
#include <UrcRing.hpp>
+#include <UrcQSimstat.hpp>
using namespace at::urc;
@@ 60,6 61,9 @@ std::unique_ptr<Urc> UrcFactory::Create(const std::string &urcMessage)
else if (Qiurc::isURC(head)) {
return std::make_unique<Qiurc>(body);
}
+ else if (QSimstat::isURC(head)) {
+ return std::make_unique<QSimstat>(body);
+ }
return std::make_unique<Urc>(body, head);
}
A module-cellular/at/src/UrcQSimstat.cpp => module-cellular/at/src/UrcQSimstat.cpp +29 -0
@@ 0,0 1,29 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include "UrcQSimstat.hpp"
+
+using namespace at::urc;
+
+auto QSimstat::isValid() const noexcept -> bool
+{
+ return tokens.size() >= minParametersCount;
+}
+auto QSimstat::getInsertedStatus() const noexcept -> std::optional<at::SimInsertedStatus>
+{
+ auto status = 0;
+ if (utils::toNumeric(tokens[magic_enum::enum_integer(Tokens::InsertedStatus)], status) &&
+ magic_enum::enum_contains<SimInsertedStatus>(status)) {
+ return static_cast<SimInsertedStatus>(status);
+ }
+ return std::nullopt;
+}
+auto QSimstat::getEnabled() const noexcept -> std::optional<at::SimInsertedStatusEnable>
+{
+ auto enabled = 0;
+ if (utils::toNumeric(tokens[magic_enum::enum_integer(Tokens::Enable)], enabled) &&
+ magic_enum::enum_contains<at::SimInsertedStatusEnable>(enabled)) {
+ return static_cast<at::SimInsertedStatusEnable>(enabled);
+ }
+ return std::nullopt;
+}
M module-cellular/test/mock/AtCommon_channel.hpp => module-cellular/test/mock/AtCommon_channel.hpp +80 -0
@@ 429,4 429,84 @@ namespace at
return result;
}
};
+
+ /// provides proper QSIMSTAT response
+ class QSIMSTAT_successChannel : public ChannelMock
+ {
+ public:
+ const std::string enabled = "1";
+ const std::string status = "1";
+
+ auto ResultMock() -> Result final
+ {
+ auto result = Result();
+ result.code = Result::Code::OK;
+ result.response = {"+QSIMSTAT: " + enabled + "," + status, "OK"};
+ return result;
+ }
+ };
+
+ /// provides invalid QSIMSTAT response
+ class QSIMSTAT_toLittleTokens : public ChannelMock
+ {
+ public:
+ const std::string enabled = "1";
+
+ auto ResultMock() -> Result final
+ {
+ auto result = Result();
+ result.code = Result::Code::OK;
+ result.response = {"+QSIMSTAT: " + enabled, "OK"};
+ return result;
+ }
+ };
+
+ /// provides invalid QSIMSTAT response
+ class QSIMSTAT_toManyTokens : public ChannelMock
+ {
+ public:
+ const std::string enabled = "1";
+ const std::string status = "1";
+ const std::string bad = "1";
+
+ auto ResultMock() -> Result final
+ {
+ auto result = Result();
+ result.code = Result::Code::OK;
+ result.response = {"+QSIMSTAT: " + enabled + "," + status + "," + bad, "OK"};
+ return result;
+ }
+ };
+
+ /// provides invalid QSIMSTAT response
+ class QSIMSTAT_invalidEnabled : public ChannelMock
+ {
+ public:
+ const std::string enabled = "78";
+ const std::string status = "1";
+
+ auto ResultMock() -> Result final
+ {
+ auto result = Result();
+ result.code = Result::Code::OK;
+ result.response = {"+QSIMSTAT: " + enabled + "," + status, "OK"};
+ return result;
+ }
+ };
+
+ /// provides invalid QSIMSTAT response
+ class QSIMSTAT_invalidStatus : public ChannelMock
+ {
+ public:
+ const std::string enabled = "1";
+ const std::string status = "98";
+
+ auto ResultMock() -> Result final
+ {
+ auto result = Result();
+ result.code = Result::Code::OK;
+ result.response = {"+QSIMSTAT: " + enabled + "," + status, "OK"};
+ return result;
+ }
+ };
} // namespace at
M module-cellular/test/unittest_URC.cpp => module-cellular/test/unittest_URC.cpp +55 -0
@@ 22,8 22,10 @@
#include "UrcRing.hpp"
#include "UrcPoweredDown.hpp"
#include "UrcResponse.hpp"
+#include <at/UrcQSimstat.hpp>
#include "UrcFactory.hpp"
#include "SimState.hpp"
+#include <at/SimInsertedState.hpp>
template <typename urcType> static auto getURC(std::unique_ptr<at::urc::Urc> &urc) -> std::shared_ptr<urcType>
{
@@ 925,3 927,56 @@ TEST_CASE("RING")
}
}
}
+
+TEST_CASE("QSimstat")
+{
+ SECTION("Valid parameter, inserted")
+ {
+ auto urc = at::urc::UrcFactory::Create("+QSIMSTAT: 1,1");
+ auto qsimstat = getURC<at::urc::QSimstat>(urc);
+
+ REQUIRE(qsimstat);
+ REQUIRE(qsimstat->getInsertedStatus() == at::SimInsertedStatus::Inserted);
+ REQUIRE(qsimstat->getEnabled() == at::SimInsertedStatusEnable::Enable);
+ }
+
+ SECTION("Valid parameter, removed")
+ {
+ auto urc = at::urc::UrcFactory::Create("+QSIMSTAT: 1,0");
+ auto qsimstat = getURC<at::urc::QSimstat>(urc);
+
+ REQUIRE(qsimstat);
+ REQUIRE(qsimstat->getInsertedStatus() == at::SimInsertedStatus::Removed);
+ REQUIRE(qsimstat->getEnabled() == at::SimInsertedStatusEnable::Enable);
+ }
+
+ SECTION("Valid parameter, unknown")
+ {
+ auto urc = at::urc::UrcFactory::Create("+QSIMSTAT: 0,2");
+ auto qsimstat = getURC<at::urc::QSimstat>(urc);
+
+ REQUIRE(qsimstat);
+ REQUIRE(qsimstat->getInsertedStatus() == at::SimInsertedStatus::Unknown);
+ REQUIRE(qsimstat->getEnabled() == at::SimInsertedStatusEnable::Disable);
+ }
+
+ SECTION("Invalid parameter, wrong Enable token")
+ {
+ auto urc = at::urc::UrcFactory::Create("+QSIMSTAT: 5,2");
+ auto qsimstat = getURC<at::urc::QSimstat>(urc);
+
+ REQUIRE(qsimstat);
+ REQUIRE(qsimstat->getInsertedStatus() == at::SimInsertedStatus::Unknown);
+ REQUIRE(qsimstat->getEnabled() == std::nullopt);
+ }
+
+ SECTION("Invalid parameter, wrong Inserted Status token")
+ {
+ auto urc = at::urc::UrcFactory::Create("+QSIMSTAT: 0,7");
+ auto qsimstat = getURC<at::urc::QSimstat>(urc);
+
+ REQUIRE(qsimstat);
+ REQUIRE(qsimstat->getInsertedStatus() == std::nullopt);
+ REQUIRE(qsimstat->getEnabled() == at::SimInsertedStatusEnable::Disable);
+ }
+}
M module-cellular/test/unittest_parse_result.cpp => module-cellular/test/unittest_parse_result.cpp +73 -0
@@ 13,6 13,7 @@
#include <at/cmd/CPBS.hpp>
#include <at/cmd/CPBR.hpp>
#include <at/cmd/QNWINFO.hpp>
+#include <at/cmd/QSIMSTAT.hpp>
#include "mock/AtCommon_channel.hpp"
#include "PhoneNumber.hpp"
@@ 681,3 682,75 @@ TEST_CASE("QNWINFO parser test")
REQUIRE(!resp);
}
}
+
+TEST_CASE("QSIMSTAT parser")
+{
+ SECTION("Empty data")
+ {
+ at::cmd::QSIMSTAT cmd;
+ at::Result result;
+ auto response = cmd.parseQSIMSTAT(result);
+ REQUIRE(!response);
+ }
+
+ SECTION("Failing channel")
+ {
+ at::cmd::QSIMSTAT cmd;
+ at::FailingChannel channel;
+ auto base = channel.cmd(cmd);
+ auto response = cmd.parseQSIMSTAT(base);
+ REQUIRE(!response);
+ REQUIRE(response.code == at::Result::Code::ERROR);
+ }
+
+ SECTION("Success - valid token")
+ {
+ at::cmd::QSIMSTAT cmd;
+ at::QSIMSTAT_successChannel channel;
+ auto base = channel.cmd(cmd);
+ auto response = cmd.parseQSIMSTAT(base);
+ REQUIRE(response);
+ REQUIRE(response.enabled == at::SimInsertedStatusEnable::Enable);
+ REQUIRE(response.status == at::SimInsertedStatus::Inserted);
+ }
+
+ SECTION("to little tokens")
+ {
+ at::cmd::QSIMSTAT cmd;
+ at::QSIMSTAT_toLittleTokens channel;
+ auto base = channel.cmd(cmd);
+ auto response = cmd.parseQSIMSTAT(base);
+ REQUIRE(!response);
+ REQUIRE(response.code == at::Result::Code::PARSING_ERROR);
+ }
+
+ SECTION("Failed - to many tokens")
+ {
+ at::cmd::QSIMSTAT cmd;
+ at::QSIMSTAT_toManyTokens channel;
+ auto base = channel.cmd(cmd);
+ auto response = cmd.parseQSIMSTAT(base);
+ REQUIRE(!response);
+ REQUIRE(response.code == at::Result::Code::PARSING_ERROR);
+ }
+
+ SECTION("Failed - invalid enabled oken")
+ {
+ at::cmd::QSIMSTAT cmd;
+ at::QSIMSTAT_invalidEnabled channel;
+ auto base = channel.cmd(cmd);
+ auto response = cmd.parseQSIMSTAT(base);
+ REQUIRE(!response);
+ REQUIRE(response.code == at::Result::Code::PARSING_ERROR);
+ }
+
+ SECTION("Failed - invalid status token")
+ {
+ at::cmd::QSIMSTAT cmd;
+ at::QSIMSTAT_invalidStatus channel;
+ auto base = channel.cmd(cmd);
+ auto response = cmd.parseQSIMSTAT(base);
+ REQUIRE(!response);
+ REQUIRE(response.code == at::Result::Code::PARSING_ERROR);
+ }
+}
M module-services/service-cellular/CellularUrcHandler.cpp => module-services/service-cellular/CellularUrcHandler.cpp +11 -0
@@ 210,3 210,14 @@ void CellularUrcHandler::Handle(UrcResponse &urc)
}
}
}
+
+void CellularUrcHandler::Handle(QSimstat &urc)
+{
+ if (urc.isValid()) {
+ auto inserted = urc.getInsertedStatus();
+ if (inserted.has_value()) {
+ response = std::make_unique<cellular::SimInsertedNotication>(inserted.value());
+ urc.setHandled(true);
+ }
+ }
+}
M module-services/service-cellular/CellularUrcHandler.hpp => module-services/service-cellular/CellularUrcHandler.hpp +2 -0
@@ 18,6 18,7 @@
#include <module-cellular/at/UrcResponse.hpp>
#include <module-cellular/at/UrcQiurc.hpp>
#include <module-cellular/at/UrcRing.hpp>
+#include <module-cellular/at/UrcQSimstat.hpp>
/**
* ServiceCellular helper for handling Urc messages
@@ 39,6 40,7 @@ class CellularUrcHandler : public at::urc::UrcHandler
void Handle(at::urc::Ring &urc) final;
void Handle(at::urc::PoweredDown &urc) final;
void Handle(at::urc::UrcResponse &urc) final;
+ void Handle(at::urc::QSimstat &urc) final;
/**
* Gets the response that should be returned after handling Urc
M module-services/service-cellular/ServiceCellular.cpp => module-services/service-cellular/ServiceCellular.cpp +2 -1
@@ 143,6 143,8 @@ ServiceCellular::ServiceCellular()
connectionManager->onTimerTick();
});
});
+ simTimer = sys::TimerFactory::createSingleShotTimer(
+ this, "simTimer", std::chrono::milliseconds{6000}, [this](sys::Timer &) { priv->simCard->handleSimTimer(); });
ongoingCall.setStartCallAction([=](const CalllogRecord &rec) {
auto call = DBServiceAPI::CalllogAdd(this, rec);
@@ 1267,7 1269,6 @@ bool ServiceCellular::handle_sim_sanity_check()
auto ret = sim_check_hot_swap(cmux->get(CellularMux::Channel::Commands));
if (ret) {
priv->state->set(State::ST::ModemOn);
- bsp::cellular::sim::simSelect();
}
else {
LOG_ERROR("Sanity check failure - user will be promped about full shutdown");
M module-services/service-cellular/include/service-cellular/api/notification/notification.hpp => module-services/service-cellular/include/service-cellular/api/notification/notification.hpp +3 -0
@@ 45,4 45,7 @@ namespace cellular::msg::notification
const api::ModemState state;
};
+ struct SimNotInserted : public msg::Notification
+ {};
+
} // namespace cellular::msg::notification
M module-services/service-cellular/service-cellular/CellularMessage.hpp => module-services/service-cellular/service-cellular/CellularMessage.hpp +16 -0
@@ 12,6 12,7 @@
#include <module-bsp/bsp/cellular/bsp_cellular.hpp>
#include <utf8/UTF8.hpp>
#include <SimState.hpp>
+#include <module-cellular/at/SimInsertedState.hpp>
#include <response.hpp>
@@ 960,4 961,19 @@ namespace cellular
std::shared_ptr<std::string> imei;
};
+ class SimInsertedNotication : public sys::DataMessage
+ {
+ public:
+ explicit SimInsertedNotication(at::SimInsertedStatus status)
+ : sys::DataMessage(MessageType::MessageTypeUninitialized), insertedStatus(status)
+ {}
+ auto getInsertedStatus() -> at::SimInsertedStatus
+ {
+ return insertedStatus;
+ }
+
+ private:
+ at::SimInsertedStatus insertedStatus;
+ };
+
} // namespace cellular
M module-services/service-cellular/service-cellular/ServiceCellular.hpp => module-services/service-cellular/service-cellular/ServiceCellular.hpp +1 -0
@@ 112,6 112,7 @@ class ServiceCellular : public sys::Service
sys::TimerHandle callEndedRecentlyTimer;
sys::TimerHandle stateTimer;
sys::TimerHandle ussdTimer;
+ sys::TimerHandle simTimer;
// used to enter modem sleep mode
sys::TimerHandle sleepTimer;
M module-services/service-cellular/src/ServiceCellularPriv.cpp => module-services/service-cellular/src/ServiceCellularPriv.cpp +33 -1
@@ 52,6 52,7 @@ namespace cellular::internal
simCard->onUnhandledCME = [this](unsigned int code) {
owner->bus.sendMulticast<notification::UnhandledCME>(code);
};
+ simCard->onSimNotPresent = [this]() { owner->bus.sendMulticast<notification::SimNotInserted>(); };
}
void ServiceCellularPriv::connectSimCard()
@@ 62,27 63,49 @@ namespace cellular::internal
*/
owner->connect(typeid(request::sim::SetActiveSim), [&](sys::Message *request) -> sys::MessagePointer {
auto msg = static_cast<request::sim::SetActiveSim *>(request);
- return std::make_shared<request::sim::SetActiveSim::Response>(simCard->handleSetActiveSim(msg->sim));
+ auto result = simCard->handleSetActiveSim(msg->sim);
+ owner->simTimer.start();
+ return std::make_shared<request::sim::SetActiveSim::Response>(result);
});
owner->connect(typeid(request::sim::GetLockState), [&](sys::Message *) -> sys::MessagePointer {
+ if (!simCard->isSimCardInserted()) {
+ owner->bus.sendMulticast<notification::SimNotInserted>();
+ return sys::MessageNone{};
+ }
return std::make_shared<request::sim::GetLockState::Response>(simCard->handleIsPinLocked());
});
owner->connect(typeid(request::sim::ChangePin), [&](sys::Message *request) -> sys::MessagePointer {
auto msg = static_cast<request::sim::ChangePin *>(request);
+ if (!simCard->isSimCardInserted()) {
+ owner->bus.sendMulticast<notification::SimNotInserted>();
+ return sys::MessageNone{};
+ }
return std::make_shared<request::sim::ChangePin::Response>(simCard->handleChangePin(msg->oldPin, msg->pin));
});
owner->connect(typeid(request::sim::UnblockWithPuk), [&](sys::Message *request) -> sys::MessagePointer {
auto msg = static_cast<request::sim::UnblockWithPuk *>(request);
+ if (!simCard->isSimCardInserted()) {
+ owner->bus.sendMulticast<notification::SimNotInserted>();
+ return sys::MessageNone{};
+ }
return std::make_shared<request::sim::UnblockWithPuk::Response>(
simCard->handleUnblockWithPuk(msg->puk, msg->pin));
});
owner->connect(typeid(request::sim::SetPinLock), [&](sys::Message *request) -> sys::MessagePointer {
auto msg = static_cast<request::sim::SetPinLock *>(request);
+ if (!simCard->isSimCardInserted()) {
+ owner->bus.sendMulticast<notification::SimNotInserted>();
+ return sys::MessageNone{};
+ }
return std::make_shared<request::sim::SetPinLock::Response>(simCard->handleSetPinLock(msg->pin, msg->lock),
msg->lock);
});
owner->connect(typeid(request::sim::PinUnlock), [&](sys::Message *request) -> sys::MessagePointer {
auto msg = static_cast<request::sim::PinUnlock *>(request);
+ if (!simCard->isSimCardInserted()) {
+ owner->bus.sendMulticast<notification::SimNotInserted>();
+ return sys::MessageNone{};
+ }
return std::make_shared<request::sim::PinUnlock::Response>(simCard->handlePinUnlock(msg->pin));
});
@@ 93,6 116,15 @@ namespace cellular::internal
simCard->handleTrayState();
return sys::MessageNone{};
});
+ owner->connect(typeid(cellular::SimInsertedNotication), [&](sys::Message *request) -> sys::MessagePointer {
+ auto message = static_cast<cellular::SimInsertedNotication *>(request);
+
+ if (simCard->isSimSelectInProgress()) {
+ return sys::MessageNone{};
+ }
+ simCard->handleSimInsertionNotification(message->getInsertedStatus());
+ return sys::MessageNone{};
+ });
/**
* Internal message handlers
M module-services/service-cellular/src/SimCard.cpp => module-services/service-cellular/src/SimCard.cpp +50 -0
@@ 9,6 9,7 @@
#include <at/ATFactory.hpp>
#include <at/UrcFactory.hpp>
#include <at/UrcCpin.hpp>
+#include <at/cmd/QSIMSTAT.hpp>
namespace cellular
{
@@ 63,6 64,8 @@ namespace cellular
Store::GSM::get()->selected = static_cast<Store::GSM::SIM>(sim);
bsp::cellular::sim::simSelect();
bsp::cellular::sim::hotSwapTrigger();
+ clearSimInsertedStatus();
+ simSelectInProgress = true;
return true;
}
@@ 302,5 305,52 @@ namespace cellular
return sim::Result::OK;
}
+
+ bool SimCard::isSimCardInserted()
+ {
+ if (simInserted == std::nullopt) {
+ if (simInserted = readSimCardInsertStatus(); !simInserted) {
+ return false;
+ }
+ }
+
+ if (simInserted == at::SimInsertedStatus::Inserted || simInserted == at::SimInsertedStatus::Unknown) {
+ return true;
+ }
+ return false;
+ }
+
+ std::optional<at::SimInsertedStatus> SimCard::readSimCardInsertStatus()
+ {
+ auto command = at::cmd::QSIMSTAT(at::cmd::Modifier::Get);
+ auto response = channel->cmd(command);
+ auto result = command.parseQSIMSTAT(response);
+
+ if (result.code != at::Result::Code::OK) {
+ LOG_ERROR("Can't read SIM insertion status.");
+ return std::nullopt;
+ }
+ return result.status;
+ }
+ void SimCard::handleSimTimer()
+ {
+ simSelectInProgress = false;
+ if (!isSimCardInserted()) {
+ if (onSimNotPresent) {
+ onSimNotPresent();
+ }
+ }
+ }
+ void SimCard::handleSimInsertionNotification(at::SimInsertedStatus status)
+ {
+ if (auto actual = getSimInsertedStatus(); actual.has_value() && actual != status) {
+ setSimInserted(status);
+ if (status == at::SimInsertedStatus::Removed) {
+ if (onSimNotPresent) {
+ onSimNotPresent();
+ }
+ }
+ }
+ }
} // namespace service
} // namespace cellular
M module-services/service-cellular/src/SimCard.hpp => module-services/service-cellular/src/SimCard.hpp +72 -0
@@ 7,6 7,8 @@
#include <at/SimState.hpp>
#include <service-cellular/api/common.hpp>
+#include <module-cellular/at/SimInsertedState.hpp>
+
namespace at
{
class Cmd;
@@ 99,6 101,67 @@ namespace cellular::service
void handleATSimStateChange(at::SimState state);
/**
+ * Check if sim card is present in slot
+ * @return true if sim card is present in slot
+ */
+ bool isSimCardInserted();
+
+ /**
+ * Set new sim inserted status
+ * @param newStatus
+ */
+ void setSimInserted(at::SimInsertedStatus newStatus)
+ {
+ simInserted = newStatus;
+ }
+
+ /**
+ * Gets sim inserted status
+ * @return actual value of sim inserted status
+ */
+ std::optional<at::SimInsertedStatus> getSimInsertedStatus()
+ {
+ return simInserted;
+ }
+
+ /**
+ * Clears sim inserted status
+ */
+ void clearSimInsertedStatus()
+ {
+ simInserted = std::nullopt;
+ }
+
+ /**
+ * Gets Sim Select progress state
+ * @return true if sim selecting is in progres
+ */
+ bool isSimSelectInProgress()
+ {
+ return simSelectInProgress;
+ }
+
+ /**
+ * Sets Sim Select progress state
+ * @param inProgress new progress state
+ */
+ void setSimSelectInProgress(bool inProgress)
+ {
+ simSelectInProgress = inProgress;
+ }
+
+ /**
+ * Sim timer event handler
+ */
+ void handleSimTimer();
+
+ /**
+ * Sim Inserted notification handler
+ * @param status new Sim Inserted status
+ */
+ void handleSimInsertionNotification(at::SimInsertedStatus status);
+
+ /**
* Notification events
*/
std::function<void()> onSimReady;
@@ 107,6 170,7 @@ namespace cellular::service
std::function<void()> onSimBlocked;
std::function<void()> onSimEvent;
std::function<void(unsigned int code)> onUnhandledCME;
+ std::function<void()> onSimNotPresent;
private:
/** SIM card initialization sequence
@@ 168,8 232,16 @@ namespace cellular::service
void handleSimState(at::SimState state);
+ /**
+ * Read sim card insert status
+ * @return sim card inserted status
+ */
+ std::optional<at::SimInsertedStatus> readSimCardInsertStatus();
+
at::BaseChannel *channel = nullptr;
std::optional<api::SimSlot> sim = std::nullopt;
+ std::optional<at::SimInsertedStatus> simInserted = std::nullopt;
+ bool simSelectInProgress = false;
};
} // namespace cellular::service
M module-services/service-fota/FotaUrcHandler.hpp => module-services/service-fota/FotaUrcHandler.hpp +1 -0
@@ 28,6 28,7 @@ class FotaUrcHandler : public at::urc::UrcHandler
virtual void Handle(at::urc::Ring &urc){};
virtual void Handle(at::urc::PoweredDown &urc){};
virtual void Handle(at::urc::UrcResponse &urc){};
+ virtual void Handle(at::urc::QSimstat &urc){};
private:
FotaService::Service &fotaService;
M products/PurePhone/services/appmgr/ApplicationManager.cpp => products/PurePhone/services/appmgr/ApplicationManager.cpp +3 -0
@@ 296,6 296,9 @@ namespace app::manager
}
return simLockHandler.handleCMEErrorRequest(data->code);
});
+ connect(typeid(cellular::msg::notification::SimNotInserted), [&](sys::Message *request) -> sys::MessagePointer {
+ return simLockHandler.handleSimNotInsertedMessage();
+ });
connect(typeid(locks::SetSim), [&](sys::Message *request) -> sys::MessagePointer {
auto data = static_cast<locks::SetSim *>(request);
simLockHandler.setSim(data->getSimSlot());