From 180bfbadcd2e5eaa4ec949ffa3afce086ad808ef Mon Sep 17 00:00:00 2001 From: Hubert Chrzaniuk Date: Thu, 29 Oct 2020 08:36:41 +0100 Subject: [PATCH] [EGD-4170] Cellular - modem reset (#929) --- changelog.md | 2 + module-cellular/at/Commands.hpp | 13 ++++- .../service-cellular/ServiceCellular.cpp | 52 +++++++++++++++++-- .../service-cellular/ServiceCellular.hpp | 9 ++++ 4 files changed, 71 insertions(+), 5 deletions(-) diff --git a/changelog.md b/changelog.md index e8b7f53b0..a5d1f9182 100644 --- a/changelog.md +++ b/changelog.md @@ -3,8 +3,10 @@ ## Current release ### Added + * `[settings][bluetooth]` Add "Phone name" window. * `[gui]` Add "ButtonOnOff" widget. +* `[cellular]` Add support for modem reset ### Changed diff --git a/module-cellular/at/Commands.hpp b/module-cellular/at/Commands.hpp index 319598a48..0dc7240bf 100644 --- a/module-cellular/at/Commands.hpp +++ b/module-cellular/at/Commands.hpp @@ -96,6 +96,7 @@ namespace at ATD, /// setup call IPR, /// set baudrate CMUX, /// setup cmux params + CFUN, /// set phone functionality CMGS, /// sms QCMGS, CREG, /// network registration status @@ -122,9 +123,14 @@ namespace at DISABLE_TIME_ZONE_UPDATE, DISABLE_TIME_ZONE_REPORTING, ENABLE_NETWORK_REGISTRATION_URC, - SET_SMS_TEXT_MODE_UCS2 + SET_SMS_TEXT_MODE_UCS2, + CFUN_RESET, + CFUN_MIN_FUNCTIONALITY, /// Set minimum functionality + CFUN_FULL_FUNCTIONALITY, /// Full functionality + CFUN_DISABLE_TRANSMITTING, /// Disable the ME from both transmitting and receiving RF signals }; + // below timeouts are defined in Quectel_EC25&EC21_AT_Commands_Manual_V1.3.pdf inline auto factory(AT at) -> const Cmd & { static const std::map fact{ @@ -164,6 +170,11 @@ namespace at {AT::ATD, {"ATD"}}, {AT::IPR, {"AT+IPR="}}, {AT::CMUX, {"AT+CMUX="}}, + {AT::CFUN, {"AT+CFUN=", 15000}}, + {AT::CFUN_RESET, {"AT+CFUN=1,1", 15000}}, + {AT::CFUN_MIN_FUNCTIONALITY, {"AT+CFUN=0", 15000}}, + {AT::CFUN_FULL_FUNCTIONALITY, {"AT+CFUN=1", 15000}}, + {AT::CFUN_DISABLE_TRANSMITTING, {"AT+CFUN=4", 15000}}, {AT::CMGS, {"AT+CMGS=\""}}, {AT::QCMGS, {"AT+QCMGS=\""}}, {AT::CREG, {"AT+CREG?", default_doc_timeout}}, diff --git a/module-services/service-cellular/ServiceCellular.cpp b/module-services/service-cellular/ServiceCellular.cpp index 8bb8fd46a..2eed5b25c 100644 --- a/module-services/service-cellular/ServiceCellular.cpp +++ b/module-services/service-cellular/ServiceCellular.cpp @@ -243,6 +243,36 @@ void ServiceCellular::registerMessageHandlers() handle_CellularGetChannelMessage(); } +bool ServiceCellular::resetCellularModule(ResetType type) +{ + LOG_DEBUG("Cellular modem reset. Type %d", static_cast(type)); + + auto channel = cmux->get(TS0710::Channel::Commands); + if (!channel) { + LOG_ERROR("Bad channel"); + return false; + } + + switch (type) { + case ResetType::SoftReset: + if (auto response = channel->cmd(at::AT::CFUN_RESET); response.code == at::Result::Code::OK) { + return true; + } + LOG_ERROR("Cellular modem reset failed."); + return false; + case ResetType::PowerCycle: + cmux->TurnOffModem(); + cmux->TurnOnModem(); + isAfterForceReboot = true; + return true; + case ResetType::HardReset: + cmux->ResetModem(); + isAfterForceReboot = true; + return true; + } + return false; +} + void ServiceCellular::change_state(cellular::StateChange *msg) { assert(msg); @@ -367,6 +397,11 @@ bool ServiceCellular::handle_power_up_procedure() bool ServiceCellular::handle_power_up_in_progress_procedure(void) { + if (isAfterForceReboot) { + constexpr auto msModemUartInitTime = 12000; + vTaskDelay(pdMS_TO_TICKS(msModemUartInitTime)); + isAfterForceReboot = false; + } auto ret = cmux->BaudDetectProcedure(); if (ret == TS0710::ConfState::Success) { state.set(this, cellular::State::ST::CellularConfProcedure); @@ -406,6 +441,7 @@ bool ServiceCellular::handle_power_down_waiting() bool ServiceCellular::handle_power_down() { LOG_DEBUG("Powered Down"); + isAfterForceReboot = true; cmux.reset(); cmux = std::make_unique(PortSpeed_e::PS460800, this); InitHandler(); @@ -801,11 +837,19 @@ sys::Message_t ServiceCellular::DataReceivedHandler(sys::DataMessage *msgl, sys: if (msg != nullptr) { if (board == bsp::Board::T4) { auto status_pin = msg->state; - if (status_pin == value::ACTIVE && state.get() == State::ST::PowerUpProcedure) { - state.set(this, State::ST::PowerUpInProgress); // and go to baud detect as usual + if (status_pin == value::ACTIVE) { + if (state.get() == State::ST::PowerUpProcedure) { + state.set(this, State::ST::PowerUpInProgress); // and go to baud detect as usual + } + else { + // asynchronous power toggle should fall back to PowerDown regardless the state + state.set(this, State::ST::PowerDown); + } } - else if (status_pin == value::INACTIVE && state.get() == State::ST::PowerDownWaiting) { - state.set(this, State::ST::PowerDown); + else if (status_pin == value::INACTIVE) { + if (isAfterForceReboot == true || state.get() == State::ST::PowerDownWaiting) { + state.set(this, State::ST::PowerDown); + } } } } diff --git a/module-services/service-cellular/ServiceCellular.hpp b/module-services/service-cellular/ServiceCellular.hpp index 2398ba1f4..6ba3a333c 100644 --- a/module-services/service-cellular/ServiceCellular.hpp +++ b/module-services/service-cellular/ServiceCellular.hpp @@ -98,6 +98,15 @@ class ServiceCellular : public sys::Service ussd::State ussdState = ussd::State::none; + enum class ResetType + { + SoftReset, //