M module-apps/application-settings-new/models/QuotesRepository.hpp => module-apps/application-settings-new/models/QuotesRepository.hpp +2 -1
@@ 1,7 1,7 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
-// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#pragma once
@@ 11,6 11,7 @@
#include <list>
#include <functional>
#include <module-apps/Application.hpp>
+#include <vfs.hpp>
namespace app
{
M module-cellular/CMakeLists.txt => module-cellular/CMakeLists.txt +2 -0
@@ 36,7 36,9 @@ set(SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/at/src/UrcResponse.cpp
${CMAKE_CURRENT_SOURCE_DIR}/at/src/UrcFactory.cpp
${CMAKE_CURRENT_SOURCE_DIR}/at/src/Commands.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/at/src/Cmd.cpp
${CMAKE_CURRENT_SOURCE_DIR}/at/response.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/at/cmd/src/CSCA.cpp
)
if(NOT ${PROJECT_TARGET} STREQUAL "TARGET_Linux")
M module-cellular/Modem/ATCommon.cpp => module-cellular/Modem/ATCommon.cpp +26 -27
@@ 2,6 2,7 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#include "ATCommon.hpp"
+#include "time/ScopedTime.hpp"
#include <functional>
#include <log/log.hpp>
#include <string>
@@ 12,18 13,18 @@
using namespace at;
-const std::string Chanel::OK = "OK";
-const std::string Chanel::ERROR = "ERROR";
-const std::string Chanel::NO_CARRIER = "NO CARRIER";
-const std::string Chanel::BUSY = "BUSY";
-const std::string Chanel::NO_ANSWER = "NO ANSWER";
-const std::string Chanel::CME_ERROR = "+CME ERROR:";
-const std::string Chanel::CMS_ERROR = "+CMS ERROR:";
-// const std::string Chanel::CONNECT = "CONNECT";
-// const std::string Chanel::RING = "RING";
-// const std::string Chanel::NO_DIALTONE = "NO DIALTONE";
-
-Result::Code Chanel::at_check(const std::vector<std::string> &arr)
+const std::string Channel::OK = "OK";
+const std::string Channel::ERROR = "ERROR";
+const std::string Channel::NO_CARRIER = "NO CARRIER";
+const std::string Channel::BUSY = "BUSY";
+const std::string Channel::NO_ANSWER = "NO ANSWER";
+const std::string Channel::CME_ERROR = "+CME ERROR:";
+const std::string Channel::CMS_ERROR = "+CMS ERROR:";
+// const std::string Channel::CONNECT = "CONNECT";
+// const std::string Channel::RING = "RING";
+// const std::string Channel::NO_DIALTONE = "NO DIALTONE";
+
+Result::Code Channel::at_check(const std::vector<std::string> &arr)
{
if (arr.size()) {
for (auto el : arr) {
@@ 38,7 39,7 @@ Result::Code Chanel::at_check(const std::vector<std::string> &arr)
return Result::Code::NONE;
}
-bool Chanel::at_check_cmx_error(const std::string &CMX, const std::vector<std::string> &arr, uint32_t &errcode)
+bool Channel::at_check_cmx_error(const std::string &CMX, const std::vector<std::string> &arr, uint32_t &errcode)
{
if (arr.size()) {
for (auto cmxerr : arr) {
@@ 54,7 55,7 @@ bool Chanel::at_check_cmx_error(const std::string &CMX, const std::vector<std::s
return false;
}
-void Chanel::cmd_log(std::string cmd, const Result &result, uint32_t timeout)
+void Channel::cmd_log(std::string cmd, const Result &result, uint32_t timeout)
{
cmd.erase(std::remove(cmd.begin(), cmd.end(), '\r'), cmd.end());
cmd.erase(std::remove(cmd.begin(), cmd.end(), '\n'), cmd.end());
@@ 80,7 81,7 @@ void Chanel::cmd_log(std::string cmd, const Result &result, uint32_t timeout)
#endif
}
-std::string Chanel::formatCommand(const std::string &cmd) const
+std::string Channel::formatCommand(const std::string &cmd) const
{
bool isTerminatorValid = std::find(validTerm.begin(), validTerm.end(), cmd.back()) != validTerm.end();
if (isTerminatorValid) {
@@ 89,7 90,7 @@ std::string Chanel::formatCommand(const std::string &cmd) const
return cmd + cmdSeparator;
}
-class Result Chanel::cmd(const std::string cmd, uint32_t timeout, size_t rxCount)
+Result Channel::cmd(const std::string &cmd, std::chrono::milliseconds timeout, size_t rxCount)
{
Result result;
blockedTaskHandle = xTaskGetCurrentTaskHandle();
@@ 99,10 100,10 @@ class Result Chanel::cmd(const std::string cmd, uint32_t timeout, size_t rxCount
cmd_send(cmdFixed);
uint32_t currentTime = cpp_freertos::Ticks::GetTicks();
- uint32_t timeoutNeeded = ((timeout == UINT32_MAX) ? UINT32_MAX : currentTime + timeout);
+ uint32_t timeoutNeeded = ((timeout.count() == UINT32_MAX) ? UINT32_MAX : currentTime + timeout.count());
uint32_t timeElapsed = currentTime;
- while (1) {
+ while (true) {
if (timeoutNeeded != UINT32_MAX && timeElapsed >= timeoutNeeded) {
result.code = Result::Code::TIMEOUT;
break;
@@ 110,7 111,7 @@ class Result Chanel::cmd(const std::string cmd, uint32_t timeout, size_t rxCount
auto ret = ulTaskNotifyTake(pdTRUE, timeoutNeeded - timeElapsed);
timeElapsed = cpp_freertos::Ticks::GetTicks();
- if (ret) {
+ if (ret != 0u) {
std::vector<std::string> ret = cmd_receive();
result.response.insert(std::end(result.response), std::begin(ret), std::end(ret));
@@ 161,22 162,20 @@ class Result Chanel::cmd(const std::string cmd, uint32_t timeout, size_t rxCount
blockedTaskHandle = nullptr;
cmd_post();
- cmd_log(cmdFixed, result, timeout);
+ cmd_log(cmdFixed, result, timeout.count());
return result;
}
-auto Chanel::cmd(at::Cmd &at) -> Result
+auto Channel::cmd(const at::Cmd &at) -> Result
{
- at.last.requested = cpp_freertos::Ticks::GetTicks();
- Result result = this->cmd(at.cmd, at.timeout);
- at.last.response = cpp_freertos::Ticks::GetTicks();
- at.last.status = result.code;
- return result;
+ auto time = utils::time::Scoped("Time to run at command" + at.getCmd());
+ return cmd(at.getCmd(), at.getTimeout());
}
-auto Chanel::cmd(const at::AT at) -> Result
+auto Channel::cmd(const at::AT &at) -> Result
{
auto cmd = at::factory(at);
+ auto time = utils::time::Scoped("Time to run at command" + cmd.getCmd());
return this->cmd(cmd);
}
M module-cellular/Modem/ATCommon.hpp => module-cellular/Modem/ATCommon.hpp +22 -21
@@ 3,24 3,25 @@
#pragma once
-#include <string>
-#include <vector>
-
#include <FreeRTOS.h>
#include <at/ErrorCode.hpp>
-#include <at/Commands.hpp>
-#include <at/Result.hpp>
#include <mutex.hpp>
#include <task.h>
+#include "BaseChannel.hpp"
+
+namespace sys
+{
+ class Service;
+}
namespace at
{
- class Chanel
+ class Channel : public BaseChannel
{
protected:
constexpr static char cmdSeparator = '\r';
const std::array<char, 3> validTerm = {cmdSeparator, ',', '='};
- std::string formatCommand(const std::string &cmd) const;
+ [[nodiscard]] auto formatCommand(const std::string &cmd) const -> std::string;
cpp_freertos::MutexStandard mutex;
TaskHandle_t blockedTaskHandle = nullptr;
@@ 33,26 34,26 @@ namespace at
static const std::string NO_ANSWER;
static const std::string CME_ERROR;
static const std::string CMS_ERROR;
- // /// other codes unused right now: Please see quectel QuectelEC2526EC21ATCommandsManualV1.3 page 21
- // const std::string Chanel::CONNECT = "CONNECT";
- // const std::string Chanel::RING = "RING";
- // const std::string Chanel::NO_DIALTONE = "NO DIALTONE";
+ // other codes unused right now: Please see quectel QuectelEC2526EC21ATCommandsManualV1.3 page 21
+ // const std::string Channel::CONNECT = "CONNECT";
+ // const std::string Channel::RING = "RING";
+ // const std::string Channel::NO_DIALTONE = "NO DIALTONE";
/// waits till ok or timeout
- virtual auto cmd(const std::string cmd, uint32_t timeout = at::default_timeout, size_t rxCount = 0)
- -> Result final;
- virtual auto cmd(const at::AT at) -> Result final;
- virtual auto cmd(at::Cmd &at) -> Result final;
+ virtual auto cmd(const std::string &cmd,
+ std::chrono::milliseconds timeout = at::default_timeout,
+ size_t rxCount = 0) -> Result final;
+ virtual auto cmd(const at::AT &at) -> Result final;
+ virtual auto cmd(const at::Cmd &at) -> Result final;
/// check for OK, ERROR in string in last token
virtual Result::Code at_check(const std::vector<std::string> &arr);
/// check for +CME ERROR: errors if exists in last token
virtual bool at_check_cmx_error(const std::string &CMX, const std::vector<std::string> &arr, uint32_t &errcode);
- /// log result
virtual void cmd_log(std::string cmd, const Result &result, uint32_t timeout) final;
-
- virtual void cmd_init() = 0;
- virtual void cmd_send(std::string cmd) = 0;
- virtual std::vector<std::string> cmd_receive() = 0;
- virtual void cmd_post() = 0;
+ virtual auto ProcessNewData(sys::Service *service) -> int
+ {
+ return 0;
+ }
};
+
}; // namespace at
M module-cellular/Modem/ATParser.hpp => module-cellular/Modem/ATParser.hpp +1 -1
@@ 17,7 17,7 @@ namespace bsp
class Cellular;
}
-class ATParser : public at::Chanel
+class ATParser : public at::Channel
{
public:
enum class Urc
A module-cellular/Modem/BaseChannel.hpp => module-cellular/Modem/BaseChannel.hpp +37 -0
@@ 0,0 1,37 @@
+// 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 <string>
+#include <vector>
+#include <at/Commands.hpp>
+#include <at/Result.hpp>
+
+namespace at
+{
+ class BaseChannel
+ {
+ public:
+ /// @defgroup Channel OS dependent methods
+ /// {
+
+ /// waits till ok or timeout
+ virtual auto cmd(const std::string &cmd,
+ std::chrono::milliseconds timeout = at::default_timeout,
+ size_t rxCount = 0) -> Result = 0;
+ virtual auto cmd(const at::AT &at) -> Result = 0;
+ virtual auto cmd(const at::Cmd &at) -> Result = 0;
+ /// }
+
+ /// @defgroup Channel Platform independent methods
+ /// {
+ virtual void cmd_log(std::string cmd, const Result &result, uint32_t timeout)
+ {}
+ virtual void cmd_init() = 0;
+ virtual void cmd_send(std::string cmd) = 0;
+ virtual std::vector<std::string> cmd_receive() = 0;
+ virtual void cmd_post() = 0;
+ /// }
+ };
+} // namespace at
M module-cellular/Modem/TS0710/DLC_channel.h => module-cellular/Modem/TS0710/DLC_channel.h +1 -1
@@ 17,7 17,7 @@
#include <FreeRTOS.h>
#include <task.h>
-class DLC_channel : public at::Chanel
+class DLC_channel : public at::Channel
{
public:
using Callback_t = std::function<void(std::string &data)>;
A module-cellular/at/Cmd.hpp => module-cellular/at/Cmd.hpp +90 -0
@@ 0,0 1,90 @@
+// 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 <string>
+#include <Result.hpp>
+#include <chrono>
+
+namespace at
+{
+ using namespace std::chrono_literals;
+
+ struct Cmd;
+
+ /// if you've checked it's ok - or it was at least 300 in code somewhere, take this
+ const auto default_timeout = 300ms;
+
+ namespace cmd
+ {
+ enum class Modifier
+ {
+ None,
+ Get,
+ Set
+ };
+ }
+
+ /// at::Cmd structure with command, it's timeout and some runtime data
+ /// { command, timeout, last : {sent, response, status } }
+ struct Cmd
+ {
+ private:
+ std::string cmd; /// command head to run (AT, CLCC etc...)
+ std::chrono::milliseconds timeout = default_timeout; /// timeout for this command
+ protected:
+ std::unique_ptr<Result> result; /// lifetime result storage to be able to return reference to it
+ cmd::Modifier mod = cmd::Modifier::None; /// modifier responsible to define action we want to perform
+ std::string body; /// part after command name
+ public:
+ Cmd() = delete;
+ Cmd(std::string cmd, cmd::Modifier mod, std::chrono::milliseconds timeout = default_timeout) noexcept;
+ Cmd(std::string cmd, std::chrono::milliseconds timeout = default_timeout) noexcept;
+ Cmd(const Cmd &p) noexcept;
+ Cmd(Cmd &&) noexcept;
+ auto operator =(const Cmd &) noexcept -> Cmd &;
+ auto operator =(Cmd &&) noexcept -> Cmd &;
+ virtual ~Cmd() = default;
+
+ auto setModifier(cmd::Modifier mod) noexcept
+ {
+ this->mod = mod;
+ }
+
+ [[nodiscard]] auto getCmd() const
+ {
+ switch (mod) {
+ case cmd::Modifier::Get:
+ return cmd + "?";
+ case cmd::Modifier::Set:
+ return cmd + "=" + body;
+ case cmd::Modifier::None:
+ return cmd;
+ }
+ return cmd;
+ }
+
+ [[nodiscard]] auto getTimeout() const noexcept
+ {
+ return timeout;
+ }
+
+ /// not the prettiest, for now it's ok - for commands which modify strings to execute - return copy of command
+ /// str
+ [[nodiscard]] operator std::string() const
+ {
+ return getCmd();
+ }
+
+ auto operator+(const std::string &val) const -> Cmd
+ {
+ Cmd tmp = *this;
+ tmp.cmd += val;
+ return tmp;
+ }
+
+ /// would have used optional but it doesn't work with references
+ [[nodiscard]] virtual auto parse(Result &base_result) -> Result &;
+ };
+}; // namespace at
M module-cellular/at/Commands.hpp => module-cellular/at/Commands.hpp +29 -53
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#pragma once
@@ 10,46 10,19 @@
#include <map>
#include <memory>
#include <string>
+#include "Cmd.hpp"
+#include "cmd/CSCA.hpp"
+#include <chrono>
namespace at
{
- inline const uint32_t default_timeout = 5000; /// if unsure - take this
- inline const uint32_t default_doc_timeout =
- 300; /// if you've checked it's ok - or it was at least 300 in code somewhere, take this
- inline const uint32_t default_long_doc_timeout = 15000;
+
+ using namespace std::chrono_literals;
+ const auto default_doc_timeout = 5000ms; /// if unsure - take this
+ const auto default_long_doc_timeout = 15000ms;
/// at::Cmd structure with command, it's timeout and some runtime data
/// { command, timeout, last : {sent, response, status } }
- struct Cmd
- {
- std::string cmd; /// command to run
- uint32_t timeout = default_timeout; /// timeout for this command
- struct
- {
- Result::Code status = Result::Code::NONE; /// last response for that command
- time_t requested = 0; /// last time comand was requested
- time_t response = 0; /// last time command was received
- auto request_time() -> time_t
- {
- return response - requested;
- } /// time it took to send command and get response
- } last; /// last status of command execution
-
- Cmd(std::string cmd, uint32_t timeout = default_timeout) : cmd(std::move(cmd)), timeout(timeout)
- {}
- /// not the prettiest, for now it's ok - for commands which modify strings to execute - return copy of command
- /// str
- operator std::string() const
- {
- return cmd;
- }
- auto operator+(const std::string &val) const -> Cmd
- {
- Cmd tmp = *this;
- tmp.cmd += val;
- return tmp;
- }
- };
/// doc is: per Quectel_EC25&EC21_AT_Commands_Manual_V1.3.pdf
enum class AT
@@ 151,22 124,23 @@ namespace at
COLP_GET,
COLP_ENABLE,
COLP_DISABLE,
- CSSN, /// Supplementary Services - Supplementary Service Notifications
- QICSGP, /// Configure Parameters of a TCP/IP Context
- QIACT, /// Activate a PDP Context
- QIDEACT /// Deactivate a PDP Context
+ CSSN, /// Supplementary Services - Supplementary Service Notifications
+ QICSGP, /// Configure Parameters of a TCP/IP Context
+ QIACT, /// Activate a PDP Context
+ QIDEACT, /// Deactivate a PDP Context
+ CSCA, /// check SMS Center
};
// 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<AT, const Cmd> fact{
- {AT::AT, {"AT", 100}},
+ {AT::AT, {"AT", 100ms}},
{AT::ECHO_OFF, {"ATE0"}},
{AT::FACTORY_RESET, {"AT&F"}},
{AT::SW_INFO, {"ATI\r", default_doc_timeout}},
- {AT::FLOW_CTRL_ON, {"AT+IFC=2,2\r\n", 500}},
- {AT::FLOW_CTRL_OFF, {"AT+IFC=0,0", 500}},
+ {AT::FLOW_CTRL_ON, {"AT+IFC=2,2\r\n", 500ms}},
+ {AT::FLOW_CTRL_OFF, {"AT+IFC=0,0", 500ms}},
{AT::URC_NOTIF_CHANNEL, {"AT+QCFG=\"cmux/urcport\",1"}},
{AT::RI_PIN_AUTO_CALL, {"AT+QCFG=\"urc/ri/ring\",\"auto\""}},
{AT::RI_PIN_OFF_CALL, {"AT+QCFG=\"urc/ri/ring\",\"off\""}},
@@ 178,11 152,11 @@ namespace at
{AT::AT_PIN_READY_LOGIC, {"AT+QCFG=\"apready\",1,1,200"}},
{AT::URC_NOTIF_SIGNAL, {"AT+QINDCFG=\"csq\",1"}},
{AT::CRC_ON, {"AT+CRC=1"}},
- {AT::CALLER_NUMBER_PRESENTATION, {"AT+CLIP=1", 18000}},
+ {AT::CALLER_NUMBER_PRESENTATION, {"AT+CLIP=1", 18000ms}},
{AT::SMS_TEXT_FORMAT, {"AT+CMGF=1"}},
{AT::SMS_UCSC2, {"AT+CSCS=\"UCS2\""}},
{AT::SMS_GSM, {"AT+CSCS=\"GSM\""}},
- {AT::QSCLK_ON, {"AT+QSCLK=1", 3000}},
+ {AT::QSCLK_ON, {"AT+QSCLK=1", 3000ms}},
{AT::QDAI, {"AT+QDAI?"}},
{AT::QDAI_INIT, {"AT+QDAI=1,0,0,5,0,1"}},
{AT::SET_URC_CHANNEL, {"AT+QCFG=\"cmux/urcport\",2", default_doc_timeout}},
@@ 191,9 165,9 @@ namespace at
{AT::CMGD, {"AT+CMGD=", default_doc_timeout}},
{AT::CNUM, {"AT+CNUM"}},
{AT::CIMI, {"AT+CIMI"}},
- {AT::QCMGR, {"AT+QCMGR=", 2000}},
+ {AT::QCMGR, {"AT+QCMGR=", 2000ms}},
{AT::ATH, {"ATH"}},
- {AT::ATA, {"ATA", 90000}},
+ {AT::ATA, {"ATA", 90000ms}},
{AT::ATD, {"ATD"}},
{AT::IPR, {"AT+IPR="}},
{AT::CMUX, {"AT+CMUX="}},
@@ 202,11 176,11 @@ namespace at
{AT::CFUN_MIN_FUNCTIONALITY, {"AT+CFUN=0", default_long_doc_timeout}},
{AT::CFUN_FULL_FUNCTIONALITY, {"AT+CFUN=1", default_long_doc_timeout}},
{AT::CFUN_DISABLE_TRANSMITTING, {"AT+CFUN=4", default_long_doc_timeout}},
- {AT::CMGS, {"AT+CMGS=\""}},
- {AT::QCMGS, {"AT+QCMGS=\""}},
+ {AT::CMGS, {"AT+CMGS=\"", 120s}}, // verified in docs
+ {AT::QCMGS, {"AT+QCMGS=\"", 120s}}, // verified in docs
{AT::CREG, {"AT+CREG?", default_doc_timeout}},
{AT::QNWINFO, {"AT+QNWINFO"}},
- {AT::COPS, {"AT+COPS", 180000}},
+ {AT::COPS, {"AT+COPS", 180000ms}},
{AT::QSIMSTAT, {"AT+QSIMSTAT?"}},
{AT::SIM_DET, {"AT+QSIMDET?"}},
{AT::SIM_DET_ON, {"AT+QSIMDET=1,0"}},
@@ 222,7 196,7 @@ namespace at
{AT::CUSD_OPEN_SESSION, {"AT+CUSD=1"}},
{AT::CUSD_CLOSE_SESSION, {"AT+CUSD=2"}},
{AT::CUSD_SEND, {"AT+CUSD=1,"}},
- {AT::SET_SMS_STORAGE, {"AT+CPMS=\"SM\",\"SM\",\"SM\"", 300}},
+ {AT::SET_SMS_STORAGE, {"AT+CPMS=\"SM\",\"SM\",\"SM\"", 300ms}},
{AT::CPIN, {"AT+CPIN=", default_timeout}},
{AT::GET_CPIN, {"AT+CPIN?", default_timeout}},
{AT::QPINC, {"AT+QPINC=", default_timeout}},
@@ 253,20 227,22 @@ namespace at
{AT::COLP_DISABLE, {"AT+COLP=0", default_long_doc_timeout}},
{AT::CSSN, {"AT+CSSN=\"", default_doc_timeout}},
{AT::QICSGP, {"AT+QICSGP", default_timeout}},
- {AT::QIACT, {"AT+QIACT", 150000}},
- {AT::QIDEACT, {"AT+QIDEACT", 40000}}};
+ {AT::QIACT, {"AT+QIACT", 150000ms}},
+ {AT::QIDEACT, {"AT+QIDEACT", 40000ms}}};
- if (fact.count(at)) {
+ if (fact.count(at) != 0u) {
return fact.at(at);
}
LOG_ERROR("NO SUCH AT COMMAND DEFINED: %d", static_cast<int>(at));
return fact.at(AT::AT);
}
+
enum class commadsSet
{
modemInit,
simInit,
smsInit
};
+
std::vector<AT> getCommadsSet(commadsSet set);
}; // namespace at
M module-cellular/at/ErrorCode.hpp => module-cellular/at/ErrorCode.hpp +1 -1
@@ 127,4 127,4 @@ namespace magic_enum
static constexpr int max = at::MAX_AT_ERROR_VALUE + 2;
};
-} // namespace magic_enum>
\ No newline at end of file
+} // namespace magic_enum
M module-cellular/at/Result.hpp => module-cellular/at/Result.hpp +11 -7
@@ 16,12 16,14 @@ namespace at
/// result class for AT send -> receive command, could return promise :p
enum class Code
{
- OK, // at OK
- ERROR, // at ERROR
- TIMEOUT, // at Timeout
- TOKENS, // at numbers of tokens needed met
- NONE, // no code
- } code = Code::NONE;
+ OK, /// at OK
+ ERROR, /// at ERROR
+ TIMEOUT, /// at Timeout
+ TOKENS, /// at numbers of tokens needed met
+ NONE, /// no code
+ UNDEFINED, /// undefined result - usage of Undefined result, define and pin result to use it
+ PARSING_ERROR, /// parser error
+ } code = Code::UNDEFINED;
//! Information about Equipment or Network error as variant type
/*!
@@ 34,9 36,11 @@ namespace at
std::vector<std::string> response;
- explicit operator bool() const
+ virtual explicit operator bool() const
{
return code == Code::OK;
}
+
+ virtual ~Result() = default;
};
} // namespace at
A module-cellular/at/cmd/CSCA.hpp => module-cellular/at/cmd/CSCA.hpp +41 -0
@@ 0,0 1,41 @@
+// 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 <PhoneNumber.hpp>
+
+namespace at
+{
+ namespace result
+ {
+ /// please see documentation:
+ /// QuectelEC2526EC21ATCommandsManualV13.1100970659
+ /// page: 118 for more information
+ struct CSCA : public Result
+ {
+ std::string smsCenterAddress;
+ std::string smsTypeOfAddress;
+ explicit CSCA(const Result &);
+ operator bool() const override;
+ };
+ } // namespace result
+
+ namespace cmd
+ {
+
+ class PhoneView;
+
+ class CSCA : public Cmd
+ {
+ public:
+ CSCA() noexcept;
+ explicit CSCA(at::cmd::Modifier mod) noexcept;
+ [[nodiscard]] auto parse(Result &base_result) -> result::CSCA & final;
+ void set(const utils::PhoneNumber::View &smsCenterAddress, int smsTypeOfAddress);
+ };
+ } // namespace cmd
+} // namespace at
A module-cellular/at/cmd/src/CSCA.cpp => module-cellular/at/cmd/src/CSCA.cpp +71 -0
@@ 0,0 1,71 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include <log/log.hpp>
+#include <memory>
+#include <string>
+#include <type_traits>
+#include <at/cmd/CSCA.hpp>
+
+namespace at
+{
+ namespace cmd
+ {
+ CSCA::CSCA(at::cmd::Modifier mod) noexcept : Cmd("AT+CSCA", mod)
+ {}
+
+ CSCA::CSCA() noexcept : CSCA(at::cmd::Modifier::None)
+ {}
+
+ result::CSCA &CSCA::parse(Result &base_result)
+ {
+ auto *p = new result::CSCA(base_result);
+ result = std::unique_ptr<result::CSCA>(p);
+ // use parent operator bool
+ if (p->Result::operator bool()) {
+ if (p->response.empty()) {
+ LOG_ERROR("Can't parse - empty response");
+ p->code = result::CSCA::Code::PARSING_ERROR;
+ }
+ else {
+ auto str = p->response[0];
+ str.erase(std::remove(str.begin(), str.end(), ' '), str.end());
+ auto pos = str.find(":");
+ auto end = str.find(",");
+ p->smsCenterAddress = std::string(str, pos + 1, end - pos - 1);
+ p->smsTypeOfAddress = std::string(str, end + 1);
+ if (p->smsCenterAddress.empty() || p->smsTypeOfAddress.empty()) {
+ LOG_ERROR("Can't parse - bad value");
+ p->code = result::CSCA::Code::PARSING_ERROR;
+ }
+ }
+ }
+ return *p;
+ }
+
+ void CSCA::set(const utils::PhoneNumber::View &smsCenterAddress, int smsTypeOfAddress)
+ {
+ body += "\"" + smsCenterAddress.getE164() + "\"," + std::to_string(smsTypeOfAddress);
+ }
+ } // namespace cmd
+
+ namespace result
+ {
+ CSCA::CSCA(const Result &that) : Result(that)
+ {}
+
+ CSCA::operator bool() const
+ {
+ if (!Result::operator bool()) {
+ return false;
+ }
+ if (smsCenterAddress.empty() || smsCenterAddress == "\"\"") {
+ return false;
+ }
+ if (smsTypeOfAddress.empty() || smsTypeOfAddress == "\"\"") {
+ return false;
+ }
+ return true;
+ }
+ } // namespace result
+} // namespace at
A module-cellular/at/src/Cmd.cpp => module-cellular/at/src/Cmd.cpp +54 -0
@@ 0,0 1,54 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include <Cmd.hpp>
+
+namespace at
+{
+ Cmd::Cmd(std::string cmd, cmd::Modifier mod, std::chrono::milliseconds timeout) noexcept
+ : cmd(std::move(cmd)), timeout(timeout), mod(mod)
+ {}
+
+ Cmd::Cmd(std::string cmd, std::chrono::milliseconds timeout) noexcept : Cmd(cmd, cmd::Modifier::None, timeout)
+ {}
+
+ Cmd::Cmd(const Cmd &p) noexcept
+ {
+ *this = operator=(p);
+ }
+
+ Cmd::Cmd(Cmd &&p) noexcept
+ {
+ *this = operator=(p);
+ }
+
+ auto Cmd::operator=(const Cmd &p) noexcept -> Cmd &
+ {
+ if (&p == this) {
+ return *this;
+ }
+ this->cmd = p.cmd;
+ this->timeout = p.timeout;
+ this->mod = p.mod;
+ this->body = p.body;
+ return *this;
+ }
+
+ auto Cmd::operator=(Cmd &&p) noexcept -> Cmd &
+ {
+ if (&p == this) {
+ return *this;
+ }
+ this->cmd = std::move(p.cmd);
+ this->timeout = std::move(p.timeout);
+ this->mod = std::move(p.mod);
+ this->body = std::move(p.body);
+ return *this;
+ }
+
+ Result &Cmd::parse(Result &that)
+ {
+ result = std::unique_ptr<Result>();
+ return *result;
+ }
+} // namespace at
M module-cellular/test/CMakeLists.txt => module-cellular/test/CMakeLists.txt +9 -0
@@ 19,3 19,12 @@ add_catch2_executable(
module-cellular
)
+add_catch2_executable(
+ NAME
+ unittest_parse_CSCA
+ SRCS
+ unittest_parse_CSCA.cpp
+ LIBS
+ module-cellular
+)
+
A module-cellular/test/mock/AtCommon_channel.hpp => module-cellular/test/mock/AtCommon_channel.hpp +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
+
+#pragma once
+
+#include "Modem/BaseChannel.hpp"
+
+namespace at
+{
+
+ class ChannelMock : public BaseChannel
+ {
+ public:
+ virtual Result ResultMock()
+ {
+ return Result();
+ }
+
+ auto cmd(const std::string &cmd,
+ std::chrono::milliseconds timeout = at::default_timeout,
+ size_t rxCount = 0) noexcept -> Result override
+ {
+ return ResultMock();
+ }
+ auto cmd(const at::AT &at) noexcept -> Result override
+ {
+ return ResultMock();
+ }
+ auto cmd(const at::Cmd &at) -> Result override
+ {
+ return ResultMock();
+ }
+
+ void cmd_init() override
+ {}
+
+ void cmd_send(std::string cmd) override
+ {}
+
+ void cmd_post() override
+ {}
+
+ std::vector<std::string> cmd_receive() override
+ {
+ return {};
+ }
+ };
+
+ class FailingChannel : public ChannelMock
+ {
+ virtual Result ResultMock()
+ {
+ auto r = Result();
+ r.code = Result::Code::ERROR;
+ return r;
+ }
+ };
+
+ /// provides CSCS bad response
+ class CSCS_badChannel : public ChannelMock
+ {
+ virtual Result ResultMock()
+ {
+ auto r = Result();
+ r.code = Result::Code::ERROR;
+ r.response = {"LOL", "XD"};
+ return r;
+ }
+ };
+
+ /// standard bad CSCA values I get from modem (with result OK)
+ class CSCA_emptyData : public ChannelMock
+ {
+ virtual Result ResultMock()
+ {
+ auto r = Result();
+ r.code = Result::Code::OK;
+ r.response = {"+CSCA: \"\","};
+ return r;
+ }
+ };
+
+ /// provides proper CSCS reponse
+ class CSCS_successChannel : public ChannelMock
+ {
+ public:
+ std::string smsCenterAddress = "\"0700\"";
+ std::string smsTypeOfAddress = "124";
+
+ auto ResultMock() -> Result override
+ {
+ auto r = Result();
+ r.code = Result::Code::OK;
+ // space below side to CSCS matters
+ r.response = {"+CSCA: " + smsCenterAddress + "," + smsTypeOfAddress, "OK"};
+ return r;
+ }
+ };
+} // namespace at
A module-cellular/test/unittest_parse_CSCA.cpp => module-cellular/test/unittest_parse_CSCA.cpp +85 -0
@@ 0,0 1,85 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include <string>
+#define CATCH_CONFIG_MAIN
+
+#include <catch2/catch.hpp>
+#include <at/cmd/CSCA.hpp>
+#include "mock/AtCommon_channel.hpp"
+#include "PhoneNumber.hpp"
+#include "Result.hpp"
+
+TEST_CASE("CSCA parser test")
+{
+ SECTION("empty failed data")
+ {
+ at::cmd::CSCA cmd;
+ at::Result base_result; // normally returned from cmux->exec(), TODO getter for dumb result ala exe
+ auto &result = cmd.parse(base_result);
+ REQUIRE(!result);
+ REQUIRE(result.smsCenterAddress == "");
+ REQUIRE(result.smsTypeOfAddress == "");
+ }
+
+ SECTION("failing channel")
+ {
+ at::cmd::CSCA cmd;
+ at::CSCS_badChannel channel;
+ auto base = channel.cmd(cmd);
+ auto resp = cmd.parse(base);
+ REQUIRE(!resp);
+ REQUIRE(resp.code == at::Result::Code::ERROR);
+ }
+
+ SECTION("bad data")
+ {
+ at::cmd::CSCA cmd(at::cmd::Modifier::Get);
+ at::CSCA_emptyData channel;
+ auto base = channel.cmd(cmd);
+ auto resp = cmd.parse(base);
+ REQUIRE(!resp);
+ REQUIRE(resp.code == at::Result::Code::PARSING_ERROR);
+ }
+
+ SECTION("proper data")
+ {
+ at::cmd::CSCA cmd;
+ at::CSCS_successChannel channel;
+ auto base = channel.cmd(cmd);
+ auto resp = cmd.parse(base);
+ REQUIRE(resp);
+ REQUIRE(resp.smsCenterAddress == channel.smsCenterAddress);
+ REQUIRE(resp.smsTypeOfAddress == channel.smsTypeOfAddress);
+ }
+
+ SECTION("failing data")
+ {}
+}
+
+TEST_CASE("CSCA set data")
+{
+ SECTION("set proper data")
+ {
+ const std::string play_sms_center = "+48 790 998 250";
+ const int example_type_of_address = 145;
+ utils::PhoneNumber nr(play_sms_center);
+
+ const std::string expected_result =
+ "AT+CSCA=\"" + nr.getView().getE164() + "\"," + std::to_string(example_type_of_address);
+
+ at::cmd::CSCA cmd;
+ cmd.set(nr.getView(), example_type_of_address);
+ SECTION("We fail - `NONE` modifier set")
+ {
+ REQUIRE(cmd.getCmd() != expected_result);
+ }
+
+ cmd.setModifier(at::cmd::Modifier::Set);
+
+ SECTION("Success: proper modifier and data set")
+ {
+ REQUIRE(cmd.getCmd() == expected_result);
+ }
+ }
+}
M module-services/service-cellular/CMakeLists.txt => module-services/service-cellular/CMakeLists.txt +1 -0
@@ 5,6 5,7 @@ set(SOURCES
CellularCall.cpp
CellularServiceAPI.cpp
CellularUrcHandler.cpp
+ checkSmsCenter.cpp
ServiceCellular.cpp
SignalStrength.cpp
SimCard.cpp
M module-services/service-cellular/ServiceCellular.cpp => module-services/service-cellular/ServiceCellular.cpp +26 -15
@@ 82,6 82,7 @@
#include <string>
#include <utility>
#include <vector>
+#include "checkSmsCenter.hpp"
const char *ServiceCellular::serviceName = "ServiceCellular";
@@ 775,7 776,7 @@ sys::MessagePointer ServiceCellular::DataReceivedHandler(sys::DataMessage *msgl,
break;
}
auto respMsg = std::make_shared<cellular::RawCommandResp>(true);
- auto ret = channel->cmd(m->command.c_str(), m->timeout);
+ auto ret = channel->cmd(m->command, std::chrono::milliseconds(m->timeout));
respMsg->response = ret.response;
if (respMsg->response.size()) {
for (auto const &el : respMsg->response) {
@@ 1383,17 1384,18 @@ bool ServiceCellular::sendSMS(SMSRecord record)
constexpr uint32_t singleMessageLen = 30;
bool result = false;
auto channel = cmux->get(TS0710::Channel::Commands);
+ auto receiver = record.number.getEntered();
if (channel) {
channel->cmd(at::AT::SET_SMS_TEXT_MODE_UCS2);
channel->cmd(at::AT::SMS_UCSC2);
// if text fit in single message send
if (textLen < singleMessageLen) {
-
+ std::string command = std::string(at::factory(at::AT::CMGS));
+ std::string body = UCS2(UTF8(receiver)).str();
+ std::string suffix = "\"";
+ std::string command_data = command + body + suffix;
if (cmux->CheckATCommandPrompt(channel->SendCommandPrompt(
- (std::string(at::factory(at::AT::CMGS)) + UCS2(UTF8(record.number.getEntered())).str() + "\"")
- .c_str(),
- 1,
- commandTimeout))) {
+ command_data.c_str(), 1, at::factory(at::AT::CMGS).getTimeout().count()))) {
if (channel->cmd((UCS2(record.body).str() + "\032").c_str())) {
result = true;
@@ 1401,6 1403,8 @@ bool ServiceCellular::sendSMS(SMSRecord record)
else {
result = false;
}
+ if (!result)
+ LOG_ERROR("Message to: %s send failure", receiver.c_str());
}
}
// split text, and send concatenated messages
@@ 1426,21 1430,25 @@ bool ServiceCellular::sendSMS(SMSRecord record)
}
UTF8 messagePart = record.body.substr(i * singleMessageLen, partLength);
- std::string command(at::factory(at::AT::QCMGS) + UCS2(UTF8(record.number.getEntered())).str() +
- "\",120," + std::to_string(i + 1) + "," + std::to_string(messagePartsCount));
+ std::string command(at::factory(at::AT::QCMGS) + UCS2(UTF8(receiver)).str() + "\",120," +
+ std::to_string(i + 1) + "," + std::to_string(messagePartsCount));
if (cmux->CheckATCommandPrompt(channel->SendCommandPrompt(command.c_str(), 1, commandTimeout))) {
// prompt sign received, send data ended by "Ctrl+Z"
- if (channel->cmd((UCS2(messagePart).str() + "\032").c_str(), commandTimeout, 2)) {
+ if (channel->cmd(UCS2(messagePart).str() + "\032", std::chrono::milliseconds(commandTimeout), 2)) {
result = true;
}
else {
result = false;
+ if (!result)
+ LOG_ERROR("Message send failure");
break;
}
}
else {
result = false;
+ if (!result)
+ LOG_ERROR("Message send failure");
break;
}
}
@@ 1453,6 1461,9 @@ bool ServiceCellular::sendSMS(SMSRecord record)
else {
LOG_INFO("SMS sending failed.");
record.type = SMSType::FAILED;
+ if (checkSmsCenter(*channel)) {
+ LOG_ERROR("SMS center check");
+ }
}
DBServiceAPI::GetQuery(this, db::Interface::Name::SMS, std::make_unique<db::query::SMSUpdate>(record));
@@ 1470,7 1481,7 @@ bool ServiceCellular::receiveSMS(std::string messageNumber)
channel->cmd(at::AT::SMS_UCSC2);
auto cmd = at::factory(at::AT::QCMGR);
- auto ret = channel->cmd(cmd + messageNumber, cmd.timeout);
+ auto ret = channel->cmd(cmd + messageNumber, cmd.getTimeout());
bool messageParsed = false;
std::string messageRawBody;
@@ 1952,7 1963,7 @@ bool ServiceCellular::SetScanMode(std::string mode)
if (channel) {
auto command = at::factory(at::AT::SET_SCANMODE);
- auto resp = channel->cmd(command.cmd + mode + ",1", 300, 1);
+ auto resp = channel->cmd(command.getCmd() + mode + ",1", command.getTimeout(), 1);
if (resp.code == at::Result::Code::OK) {
return true;
}
@@ 1984,10 1995,10 @@ bool ServiceCellular::transmitDtmfTone(uint32_t digit)
if (channel) {
auto command = at::factory(at::AT::QLDTMF);
std::string dtmfString = "\"" + std::string(1, digit) + "\"";
- resp = channel->cmd(command.cmd + dtmfString);
+ resp = channel->cmd(command.getCmd() + dtmfString);
if (resp) {
command = at::factory(at::AT::VTS);
- resp = channel->cmd(command.cmd + dtmfString);
+ resp = channel->cmd(command.getCmd() + dtmfString);
}
}
return resp.code == at::Result::Code::OK;
@@ 2000,7 2011,7 @@ void ServiceCellular::handle_CellularGetChannelMessage()
LOG_DEBUG("Handle request for channel: %s", TS0710::name(getChannelMsg->dataChannel).c_str());
std::shared_ptr<CellularGetChannelResponseMessage> channelResponsMessage =
std::make_shared<CellularGetChannelResponseMessage>(cmux->get(getChannelMsg->dataChannel));
- LOG_DEBUG("chanel ptr: %p", channelResponsMessage->dataChannelPtr);
+ LOG_DEBUG("channel ptr: %p", channelResponsMessage->dataChannelPtr);
sys::Bus::SendUnicast(std::move(channelResponsMessage), req->sender, this);
return sys::MessageNone{};
});
@@ 2097,7 2108,7 @@ bool ServiceCellular::handleUSSDRequest(CellularUSSDMessage::RequestType request
if (requestType == CellularUSSDMessage::RequestType::pullSesionRequest) {
channel->cmd(at::AT::SMS_GSM);
std::string command = at::factory(at::AT::CUSD_SEND) + request + ",15";
- auto result = channel->cmd(command, commandTimeout, commandExpectedTokens);
+ auto result = channel->cmd(command, std::chrono::milliseconds(commandTimeout), commandExpectedTokens);
if (result.code == at::Result::Code::OK) {
ussdState = ussd::State::pullRequestSent;
setUSSDTimer();
A module-services/service-cellular/checkSmsCenter.cpp => module-services/service-cellular/checkSmsCenter.cpp +20 -0
@@ 0,0 1,20 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include "checkSmsCenter.hpp"
+#include "Modem/BaseChannel.hpp"
+
+[[nodiscard]] bool checkSmsCenter(at::BaseChannel &channel)
+{
+ auto success = true;
+ auto smsCenterCmd = at::cmd::CSCA(at::cmd::Modifier::Get);
+ auto resp = channel.cmd(smsCenterCmd);
+ auto centerResponse = smsCenterCmd.parse(resp);
+ if (!centerResponse) {
+ success = false;
+ if (centerResponse.code == at::Result::Code::PARSING_ERROR) {
+ LOG_FATAL("possibly unrecoverable SMS center value error!");
+ }
+ }
+ return success;
+}
A module-services/service-cellular/checkSmsCenter.hpp => module-services/service-cellular/checkSmsCenter.hpp +11 -0
@@ 0,0 1,11 @@
+// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+namespace at
+{
+ class BaseChannel;
+}
+
+[[nodiscard]] auto checkSmsCenter(at::BaseChannel &chanel) -> bool;
M module-services/service-fota/ServiceFota.cpp => module-services/service-fota/ServiceFota.cpp +1 -1
@@ 516,7 516,7 @@ namespace FotaService
at::Result Service::sendAndLogError(const std::string &msg, uint32_t timeout) const
{
- at::Result result = dataChannel->cmd(msg, timeout);
+ at::Result result = dataChannel->cmd(msg, std::chrono::milliseconds(timeout));
logIfError(result, msg);
return result;
}