M changelog.md => changelog.md +1 -0
@@ 49,6 49,7 @@
* `[doc]` Application manager documentation added.
* `[audio]` Improve synchronization during calls.
* `[system]` Application manager refactoring and improvements.
+* `[cellular]` URC handling refactor.
## [0.43.1 2020-10-23]
M module-cellular/CMakeLists.txt => module-cellular/CMakeLists.txt +10 -5
@@ 23,11 23,16 @@ set(SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/Modem/TS0710/TS0710_START.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Modem/TS0710/TS0710_TEST.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Modem/TS0710/TS0710_WAKEUP.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/at/src/URC_Any.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/at/src/URC_QIND.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/at/src/URC_CUSD.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/at/src/URC_CTZE.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/at/src/URC_CREG.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/at/src/Urc.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/at/src/UrcQind.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/at/src/UrcCusd.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/at/src/UrcCtze.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/at/src/UrcCreg.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/at/src/UrcCmti.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/at/src/UrcClip.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/at/src/UrcPoweredDown.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
${CMAKE_CURRENT_SOURCE_DIR}/at/response.cpp
)
M module-cellular/Modem/TS0710/TS0710.cpp => module-cellular/Modem/TS0710/TS0710.cpp +0 -1
@@ 8,7 8,6 @@
#include "service-cellular/SignalStrength.hpp"
#include "service-cellular/messages/CellularMessage.hpp"
#include <Service/Bus.hpp>
-#include <at/URC_QIND.hpp>
#include <cassert>
#include <memory>
#include <module-os/RTOSWrapper/include/ticks.hpp>
D module-cellular/at/URC_Any.hpp => module-cellular/at/URC_Any.hpp +0 -36
@@ 1,36 0,0 @@
-// 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 "Utils.hpp"
-#include <log/log.hpp>
-#include <string>
-#include <vector>
-
-namespace at::urc
-{
-
- /// generally URC are like that: re'*([+^][A-Z]): (([A-Z],)+)' where first group is `head` and rest is tokens
- /// i.e. in:
- /// +QIND: "csq",15,99
- /// '+QIND' - head
- /// '"csq", 15, 99' are three tokens
- class Any
- {
- public:
- Any(const std::string &str, char tokenDelimiter = ',');
- virtual ~Any() = default;
- virtual auto what() const noexcept -> std::string = 0;
- /// check if urc parsed is of proper type - i.e. QIND
- virtual auto is() const -> bool final;
-
- auto getTokens() const -> std::vector<std::string>;
-
- protected:
- std::string head;
- std::vector<std::string> tokens;
- /// split urc into: head and tokenized data (as in class descripiton)
- virtual void split(const std::string &str, char tokenDelimiter = ',') final;
- };
-}; // namespace at::urc
A module-cellular/at/Urc.hpp => module-cellular/at/Urc.hpp +88 -0
@@ 0,0 1,88 @@
+// 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 <module-utils/Utils.hpp>
+#include "UrcHandler.hpp"
+
+namespace at::urc
+
+{
+ class Urc
+ {
+ public:
+ /**
+ * Parses Urc body and constructs an instance.
+ * @param urcBody - Urc message body without the header
+ * @param urcHead - Urc message head
+ * @param tokenDelimiter - sign that separates parameters in Urc message
+ */
+ Urc(const std::string &urcBody, const std::string &urcHead = std::string(), char tokenDelimiter = ',');
+
+ virtual ~Urc() = default;
+
+ /**
+ * Checks weather Urc message is valid. Should be overridden in derived class of concrete Urc.
+ * @return true if valid, false otherwise
+ */
+ virtual auto isValid() const noexcept -> bool
+ {
+ return !urcBody.empty() || !urcHead.empty();
+ }
+
+ /**
+ * Gets vector of strings that represent Urc parameters.
+ * @return vector or parameters in order of appearance in message
+ */
+ auto getTokens() const -> std::vector<std::string>;
+
+ /**
+ * Gets Urc body stripped of urc header.
+ * @return Urc body string
+ */
+ auto getUrcBody() const -> std::string
+ {
+ return urcBody;
+ }
+
+ /**
+ * Call for dispatching handling to UrcHandler
+ * @param h - implementation of UrcHandler
+ */
+ virtual void Handle(UrcHandler &h)
+ {}
+
+ /**
+ * Flag Urc handled/unhandled
+ * @param state - true for handled, false for unhandled
+ */
+ void setHandled(bool state)
+ {
+ isUrcHandled = state;
+ }
+
+ /**
+ * @return true if Urc has been flagged as handled, false otherwise
+ */
+ bool isHandled()
+ {
+ return isUrcHandled;
+ }
+
+ protected:
+ std::vector<std::string> tokens;
+ std::string urcBody;
+ std::string urcHead;
+
+ bool isUrcHandled = false;
+
+ /**
+ * Splits Urc into head and tokenized data, cleans tokens from whitespaces and quotes
+ * @param str - string to be split
+ * @param tokenDelimiter - sign that separates parameters in Urc message
+ */
+ void split(const std::string &str, char tokenDelimiter = ',');
+ };
+
+} // namespace at::urc
A module-cellular/at/UrcClip.hpp => module-cellular/at/UrcClip.hpp +55 -0
@@ 0,0 1,55 @@
+// 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"
+
+namespace at::urc
+{
+ class Clip : public Urc
+ {
+ enum class Tokens
+ {
+ Number,
+ Type,
+ Subaddr,
+ Satype,
+ Alpha,
+ CLIValidity,
+ };
+
+ const size_t minParametersCount = magic_enum::enum_integer(Tokens::Type) + 1;
+
+ public:
+ enum class AddressType
+ {
+ UnknownType = 129,
+ InternationalNumber = 145,
+ NationalNumber = 161,
+ };
+
+ static constexpr std::string_view head = "+CLIP";
+ static bool isURC(const std::string uHead)
+ {
+ return uHead.find(Clip::head) != std::string::npos;
+ }
+
+ using Urc::Urc;
+
+ [[nodiscard]] auto isValid() const noexcept -> bool override;
+
+ [[nodiscard]] auto getNumber() const -> std::string;
+ [[nodiscard]] auto getType() const -> std::optional<Clip::AddressType>;
+ [[nodiscard]] auto getSubaddr() const -> std::optional<std::string>;
+ [[nodiscard]] auto getSatype() const -> std::optional<std::string>;
+ [[nodiscard]] auto getAlpha() const -> std::optional<std::string>;
+ [[nodiscard]] auto getCLIValidity() const -> std::optional<std::string>;
+
+ void Handle(UrcHandler &h) final
+ {
+ h.Handle(*this);
+ }
+ };
+} // namespace at::urc
A module-cellular/at/UrcCmti.hpp => module-cellular/at/UrcCmti.hpp +37 -0
@@ 0,0 1,37 @@
+// 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"
+
+namespace at::urc
+{
+ class Cmti : public Urc
+ {
+ enum Tokens
+ {
+ Mem,
+ Index
+ };
+
+ public:
+ static constexpr std::string_view head = "+CMTI";
+ static auto isURC(const std::string uHead) -> bool
+ {
+ return uHead.find(Cmti::head) != std::string::npos;
+ }
+
+ using Urc::Urc;
+
+ [[nodiscard]] auto isValid() const noexcept -> bool override;
+
+ [[nodiscard]] auto getMemory() const -> std::string;
+ [[nodiscard]] auto getIndex() const -> std::string;
+
+ void Handle(UrcHandler &h) final
+ {
+ h.Handle(*this);
+ }
+ };
+} // namespace at::urc
R module-cellular/at/URC_CREG.hpp => module-cellular/at/UrcCreg.hpp +15 -8
@@ 3,7 3,7 @@
#pragma once
-#include "URC_Any.hpp"
+#include "Urc.hpp"
#include <common_data/EventStore.hpp>
@@ 11,9 11,8 @@ namespace at::urc
{
/// +CREG: <stat> - Indicate network registration status of the ME
/// +CREG: <stat>[,<lac>,<ci>[,<Act>]] - Indicate network registration and location information of the ME
- class CREG : public Any
+ class Creg : public Urc
{
- const std::string urc_name = "+CREG";
enum Tokens
{
Stat,
@@ 24,12 23,15 @@ namespace at::urc
};
public:
- explicit CREG(const std::string &val);
- ~CREG() override = default;
+ static constexpr std::string_view head = "+CREG";
+ static bool isURC(const std::string uHead)
+ {
+ return uHead.find(Creg::head) != std::string::npos;
+ }
- [[nodiscard]] auto what() const noexcept -> std::string final;
+ using Urc::Urc;
- [[nodiscard]] auto isValid() const noexcept -> bool;
+ [[nodiscard]] auto isValid() const noexcept -> bool override;
[[nodiscard]] auto isExtended() const noexcept -> bool;
[[nodiscard]] auto isShort() const noexcept -> bool;
@@ 37,5 39,10 @@ namespace at::urc
[[nodiscard]] auto getLocation() const noexcept -> std::optional<std::string>;
[[nodiscard]] auto getCellId() const noexcept -> std::optional<std::string>;
[[nodiscard]] auto getAccessTechnology() const noexcept -> Store::Network::AccessTechnology;
+
+ void Handle(UrcHandler &h) final
+ {
+ h.Handle(*this);
+ }
};
-}; // namespace at::urc
+} // namespace at::urc
R module-cellular/at/URC_CTZE.hpp => module-cellular/at/UrcCtze.hpp +20 -12
@@ 3,14 3,13 @@
#pragma once
-#include "URC_Any.hpp"
+#include "Urc.hpp"
#include <ctime>
namespace at::urc
{
- class CTZE : public Any
+ class Ctze : public Urc
{
- const std::string urc_name = "+CTZE";
enum Tokens
{
GMTDifference,
@@ 20,18 19,27 @@ namespace at::urc
};
public:
- explicit CTZE(const std::string &val);
+ static constexpr std::string_view head = "+CTZE";
+ static auto isURC(const std::string uHead) -> bool
+ {
+ return uHead.find(Ctze::head) != std::string::npos;
+ }
+
+ using Urc::Urc;
constexpr static int maxTimezoneOffset = 56;
constexpr static int minTimezoneOffset = -48;
- ~CTZE() override = default;
- [[nodiscard]] auto what() const noexcept -> std::string final;
- [[nodiscard]] auto isValid() const noexcept -> bool;
- [[nodiscard]] auto getTimeInfo(void) const noexcept -> tm;
+ [[nodiscard]] auto isValid() const noexcept -> bool override;
+ [[nodiscard]] auto getTimeInfo() const noexcept -> tm;
- auto getTimeZoneOffset() const -> int;
- auto getTimeZoneString() const -> std::string;
- auto getGMTTime(void) const -> const struct tm;
+ [[nodiscard]] auto getTimeZoneOffset() const -> int;
+ [[nodiscard]] auto getTimeZoneString() const -> std::string;
+ [[nodiscard]] auto getGMTTime() const -> const struct tm;
+
+ void Handle(UrcHandler &h) final
+ {
+ h.Handle(*this);
+ }
};
-}; // namespace at::urc
+} // namespace at::urc
R module-cellular/at/URC_CUSD.hpp => module-cellular/at/UrcCusd.hpp +16 -7
@@ 3,17 3,16 @@
#pragma once
-#include "URC_Any.hpp"
+#include "Urc.hpp"
#include <optional>
namespace at::urc
{
- class CUSD : public Any
+ class Cusd : public Urc
{
- const std::string urc_name = "+CUSD";
enum Tokens
{
Status,
@@ 32,14 31,24 @@ namespace at::urc
NetworkTimeOut
};
- explicit CUSD(const std::string &val);
- ~CUSD() override = default;
+ static constexpr std::string_view head = "+CUSD";
+ static auto isURC(const std::string uHead) -> bool
+ {
+ return uHead.find(Cusd::head) != std::string::npos;
+ }
+
+ using Urc::Urc;
+
+ [[nodiscard]] auto isValid() const noexcept -> bool override;
- [[nodiscard]] auto what() const noexcept -> std::string final;
- [[nodiscard]] auto isValid() const noexcept -> bool;
[[nodiscard]] auto isActionNeeded() const noexcept -> bool;
[[nodiscard]] auto getMessage() const noexcept -> std::optional<std::string>;
[[nodiscard]] auto getStatus() const noexcept -> std::optional<StatusType>;
[[nodiscard]] auto getDCS() const noexcept -> std::optional<int>;
+
+ void Handle(UrcHandler &h) final
+ {
+ h.Handle(*this);
+ }
};
} // namespace at::urc
A module-cellular/at/UrcFactory.hpp => module-cellular/at/UrcFactory.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
+
+#include "Urc.hpp"
+
+namespace at::urc
+{
+ class UrcFactory
+ {
+ public:
+ /**
+ * Instantiates concrete Urc class on a base of Urc message body.
+ * @param urcMessage - Urc message to be parsed
+ * @return pointer to Urc
+ */
+ static std::unique_ptr<Urc> Create(const std::string &urcMessage);
+ };
+} // namespace at::urc
A module-cellular/at/UrcHandler.hpp => module-cellular/at/UrcHandler.hpp +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
+
+#pragma once
+
+namespace at::urc
+{
+ class Clip;
+ class Creg;
+ class Cmti;
+ class Cusd;
+ class Ctze;
+ class Qind;
+ class PoweredDown;
+ class UrcResponse;
+
+ class UrcHandler
+ {
+ public:
+ virtual void Handle(Clip &urc) = 0;
+ virtual void Handle(Creg &urc) = 0;
+ virtual void Handle(Cmti &urc) = 0;
+ virtual void Handle(Cusd &urc) = 0;
+ virtual void Handle(Ctze &urc) = 0;
+ virtual void Handle(Qind &urc) = 0;
+ virtual void Handle(PoweredDown &urc) = 0;
+ virtual void Handle(UrcResponse &urc) = 0;
+ };
+} // namespace at::urc
A module-cellular/at/UrcPoweredDown.hpp => module-cellular/at/UrcPoweredDown.hpp +36 -0
@@ 0,0 1,36 @@
+// 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"
+
+namespace at::urc
+{
+ class PoweredDown : public Urc
+ {
+ public:
+ static constexpr std::string_view head_immediate = "POWERED DOWN";
+ static constexpr std::string_view head_normal = "NORMAL POWER DOWN";
+ static auto isURC(const std::string uHead) -> bool
+ {
+ auto isImmediatePowerDown = uHead.find(PoweredDown::head_immediate) != std::string::npos;
+ auto isNormalPowerDown = uHead.find(PoweredDown::head_normal) != std::string::npos;
+ return isImmediatePowerDown || isNormalPowerDown;
+ }
+
+ using Urc::Urc;
+
+ [[nodiscard]] auto isValid() const noexcept -> bool override;
+ [[nodiscard]] auto isNormalPowerDown() const noexcept -> bool;
+ [[nodiscard]] auto isImmediatePowerDown() const noexcept -> bool;
+
+ void Handle(UrcHandler &h) final
+ {
+ h.Handle(*this);
+ }
+
+ private:
+ bool isNormal = false;
+ };
+} // namespace at::urc
R module-cellular/at/URC_QIND.hpp => module-cellular/at/UrcQind.hpp +41 -9
@@ 3,14 3,15 @@
#pragma once
-#include "URC_Any.hpp"
+#include "Urc.hpp"
namespace at::urc
{
- class QIND : public Any
+ class Qind : public Urc
{
- const std::string urc_name = "+QIND";
- const std::string type_csq = "\"csq\"";
+
+ const std::string type_csq = "csq";
+ const std::string type_fota = "FOTA";
static const auto invalid_rssi_low = 99;
static const auto invalid_rssi_high = 199;
@@ 23,17 24,48 @@ namespace at::urc
BER
};
+ enum FOTA
+ {
+ Fota,
+ Stage,
+ Param
+ };
+
+ const size_t fotaMinTokenSize = 2;
+
/// by docs invalid csq: RSSI: 99, 199, and ber: 99
[[nodiscard]] auto validate(enum CSQ) const noexcept -> bool;
public:
- explicit QIND(const std::string &val);
- ~QIND() override = default;
- [[nodiscard]] auto what() const noexcept -> std::string final;
+ enum class FotaStage
+ {
+ HTTPSTART,
+ HTTPEND,
+ START,
+ UPDATING,
+ END,
+ };
- [[nodiscard]] auto isCsq() const noexcept -> bool;
+ static constexpr std::string_view head = "+QIND";
+ static auto isURC(const std::string uHead) -> bool
+ {
+ return uHead.find(Qind::head) != std::string::npos;
+ }
+ using Urc::Urc;
+
+ [[nodiscard]] auto isCsq() const noexcept -> bool;
[[nodiscard]] auto getRSSI() const noexcept -> std::optional<int>;
[[nodiscard]] auto getBER() const noexcept -> std::optional<int>;
+
+ [[nodiscard]] auto isFota() const noexcept -> bool;
+ [[nodiscard]] auto isFotaValid() const noexcept -> bool;
+ [[nodiscard]] auto getFotaStage() const noexcept -> std::optional<FotaStage>;
+ [[nodiscard]] auto getFotaParameter() const noexcept -> std::string;
+
+ void Handle(UrcHandler &h) final
+ {
+ h.Handle(*this);
+ }
};
-}; // namespace at::urc
+} // namespace at::urc
A module-cellular/at/UrcResponse.hpp => module-cellular/at/UrcResponse.hpp +59 -0
@@ 0,0 1,59 @@
+// 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"
+
+namespace at::urc
+{
+ class UrcResponse : public Urc
+ {
+ public:
+ // this table has to be aligned with responseBodies
+ enum class URCResponseType
+ {
+ Ok,
+ Connect,
+ Ring,
+ NoCarrier,
+ Error,
+ NoDialtone,
+ Busy,
+ NoAnswer
+ };
+
+ static auto isURC(const std::string uHead) -> std::optional<URCResponseType>
+ {
+ for (auto &resp : urcResponses) {
+ if (uHead.find(resp.second) != std::string::npos) {
+ return resp.first;
+ }
+ }
+ return std::nullopt;
+ }
+
+ explicit UrcResponse(URCResponseType type) : Urc(std::string()), type(type){};
+
+ auto getURCResponseType() const noexcept -> URCResponseType;
+
+ void Handle(UrcHandler &h) final
+ {
+ h.Handle(*this);
+ }
+
+ private:
+ URCResponseType type;
+
+ static constexpr std::array<std::pair<URCResponseType, std::string_view>, 8> urcResponses = {{
+ {URCResponseType::Ok, "OK"},
+ {URCResponseType::Connect, "CONNECT"},
+ {URCResponseType::Ring, "RING"},
+ {URCResponseType::NoCarrier, "NO CARRIER"},
+ {URCResponseType::Error, "ERROR"},
+ {URCResponseType::NoDialtone, "NO DIALTONE"},
+ {URCResponseType::Busy, "BUSY"},
+ {URCResponseType::NoAnswer, "NO ANSWER"},
+ }};
+ };
+} // namespace at::urc
M module-cellular/at/response.cpp => module-cellular/at/response.cpp +1 -1
@@ 45,7 45,7 @@ namespace at
bool isRegistered(uint32_t commandData)
{
- // CREG command returns 1 when registered in home network, 5 when registered in roaming
+ // Creg command returns 1 when registered in home network, 5 when registered in roaming
constexpr uint32_t registeredHome = 1;
constexpr uint32_t registeredRoaming = 5;
D module-cellular/at/src/URC_Any.cpp => module-cellular/at/src/URC_Any.cpp +0 -34
@@ 1,34 0,0 @@
-// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
-// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
-
-#include <URC_Any.hpp>
-
-namespace at::urc
-{
-
- Any::Any(const std::string &str, char tokenDelimiter)
- {
- split(str, tokenDelimiter);
- }
-
- void Any::split(const std::string &str, char tokenDelimiter)
- {
- const std::string delim = ":";
- auto pos = str.find(delim);
- head = std::string(str, 0, pos);
- if (pos != std::string::npos) {
- tokens = utils::split(std::string(str.begin() + pos + delim.size(), str.end()), tokenDelimiter);
- } // else - everyting went to head
- }
-
- auto Any::is() const -> bool
- {
- return head.find(what()) != std::string::npos;
- }
-
- auto Any::getTokens() const -> std::vector<std::string>
- {
- return tokens;
- }
-
-} // namespace at::urc
A module-cellular/at/src/Urc.cpp => module-cellular/at/src/Urc.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 <Urc.hpp>
+#include <algorithm>
+
+namespace at::urc
+{
+ Urc::Urc(const std::string &urcBody, const std::string &urcHead, char tokenDelimiter)
+ : urcBody(urcBody), urcHead(urcHead)
+ {
+ split(urcBody, tokenDelimiter);
+ }
+
+ void Urc::split(const std::string &str, char tokenDelimiter)
+ {
+ tokens = utils::split(str, tokenDelimiter);
+ constexpr auto urcStringDelimiter = "\"";
+ for (auto &t : tokens) {
+ utils::findAndReplaceAll(t, urcStringDelimiter, "");
+ t = utils::trim(t);
+ }
+ }
+
+ auto Urc::getTokens() const -> std::vector<std::string>
+ {
+ return tokens;
+ }
+} // namespace at::urc
A module-cellular/at/src/UrcClip.cpp => module-cellular/at/src/UrcClip.cpp +88 -0
@@ 0,0 1,88 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include "UrcClip.hpp"
+
+using namespace at::urc;
+
+auto Clip::isValid() const noexcept -> bool
+{
+ return tokens.size() >= minParametersCount;
+}
+
+std::string Clip::getNumber() const
+{
+ if (!isValid()) {
+ return std::string();
+ }
+ return tokens[magic_enum::enum_integer(Tokens::Number)];
+};
+
+std::optional<Clip::AddressType> Clip::getType() const
+{
+ if (!isValid()) {
+ return std::nullopt;
+ }
+
+ int addressType;
+ if (!utils::toNumeric(tokens[magic_enum::enum_integer(Tokens::Type)], addressType)) {
+ return std::nullopt;
+ }
+
+ constexpr auto addressTypes = magic_enum::enum_values<Clip::AddressType>();
+ for (const auto &type : addressTypes) {
+ if (magic_enum::enum_integer(type) == addressType) {
+ return type;
+ }
+ }
+
+ return std::nullopt;
+};
+
+std::optional<std::string> Clip::getSubaddr() const
+{
+ size_t minNumOfParams = magic_enum::enum_integer(Tokens::Subaddr) + 1;
+ if (tokens.size() < minNumOfParams) {
+ return std::nullopt;
+ }
+ if (tokens[magic_enum::enum_integer(Tokens::Subaddr)].empty()) {
+ return std::nullopt;
+ }
+ return tokens[magic_enum::enum_integer(Tokens::Subaddr)];
+};
+
+std::optional<std::string> Clip::getSatype() const
+{
+ size_t minNumOfParams = magic_enum::enum_integer(Tokens::Satype) + 1;
+ if (tokens.size() < minNumOfParams) {
+ return std::nullopt;
+ }
+ if (tokens[magic_enum::enum_integer(Tokens::Satype)].empty()) {
+ return std::nullopt;
+ }
+ return tokens[magic_enum::enum_integer(Tokens::Satype)];
+};
+
+std::optional<std::string> Clip::getAlpha() const
+{
+ size_t minNumOfParams = magic_enum::enum_integer(Tokens::Alpha) + 1;
+ if (tokens.size() < minNumOfParams) {
+ return std::nullopt;
+ }
+ if (tokens[magic_enum::enum_integer(Tokens::Alpha)].empty()) {
+ return std::nullopt;
+ }
+ return tokens[magic_enum::enum_integer(Tokens::Alpha)];
+};
+
+std::optional<std::string> Clip::getCLIValidity() const
+{
+ size_t minNumOfParams = magic_enum::enum_integer(Tokens::CLIValidity) + 1;
+ if (tokens.size() < minNumOfParams) {
+ return std::nullopt;
+ }
+ if (tokens[magic_enum::enum_integer(Tokens::CLIValidity)].empty()) {
+ return std::nullopt;
+ }
+ return tokens[magic_enum::enum_integer(Tokens::CLIValidity)];
+};
A module-cellular/at/src/UrcCmti.cpp => module-cellular/at/src/UrcCmti.cpp +27 -0
@@ 0,0 1,27 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include "UrcCmti.hpp"
+
+using namespace at::urc;
+
+auto Cmti::isValid() const noexcept -> bool
+{
+ return tokens.size() == magic_enum::enum_count<Tokens>();
+}
+
+std::string Cmti::getMemory() const
+{
+ if (!isValid()) {
+ return std::string();
+ }
+ return tokens[Tokens::Mem];
+}
+
+std::string Cmti::getIndex() const
+{
+ if (!isValid()) {
+ return std::string();
+ }
+ return tokens[Tokens::Index];
+}
R module-cellular/at/src/URC_CREG.cpp => module-cellular/at/src/UrcCreg.cpp +9 -17
@@ 1,35 1,27 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
-#include <URC_CREG.hpp>
+#include <UrcCreg.hpp>
#include <magic_enum.hpp>
using namespace at::urc;
-CREG::CREG(const std::string &val) : Any(val)
-{}
-
-auto CREG::what() const noexcept -> std::string
-{
- return urc_name;
-}
-
-auto CREG::isValid() const noexcept -> bool
+auto Creg::isValid() const noexcept -> bool
{
- return is() && (isExtended() || isShort());
+ return isExtended() || isShort();
}
-auto CREG::isExtended() const noexcept -> bool
+auto Creg::isExtended() const noexcept -> bool
{
return tokens.size() == magic_enum::enum_count<Tokens>();
}
-auto CREG::isShort() const noexcept -> bool
+auto Creg::isShort() const noexcept -> bool
{
return tokens.size() == NumOfShortTokens;
}
-auto CREG::getStatus() const noexcept -> Store::Network::Status
+auto Creg::getStatus() const noexcept -> Store::Network::Status
{
if (isValid()) {
int statusInt;
@@ 48,7 40,7 @@ auto CREG::getStatus() const noexcept -> Store::Network::Status
return Store::Network::Status::Unknown;
}
-auto CREG::getLocation() const noexcept -> std::optional<std::string>
+auto Creg::getLocation() const noexcept -> std::optional<std::string>
{
if (isValid() && isExtended()) {
auto location = tokens[Tokens::Lac];
@@ 59,7 51,7 @@ auto CREG::getLocation() const noexcept -> std::optional<std::string>
return std::nullopt;
}
-auto CREG::getCellId() const noexcept -> std::optional<std::string>
+auto Creg::getCellId() const noexcept -> std::optional<std::string>
{
if (isValid() && isExtended()) {
auto cellId = tokens[Tokens::Ci];
@@ 70,7 62,7 @@ auto CREG::getCellId() const noexcept -> std::optional<std::string>
return std::nullopt;
}
-auto CREG::getAccessTechnology() const noexcept -> Store::Network::AccessTechnology
+auto Creg::getAccessTechnology() const noexcept -> Store::Network::AccessTechnology
{
if (isValid() && isExtended()) {
int accessTechnologyInt;
R module-cellular/at/src/URC_CTZE.cpp => module-cellular/at/src/UrcCtze.cpp +8 -23
@@ 1,7 1,7 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
-#include "../URC_CTZE.hpp"
+#include "../UrcCtze.hpp"
#include <log/debug.hpp>
#include <module-utils/time/time_conversion.hpp>
@@ 9,27 9,12 @@
using namespace at::urc;
-CTZE::CTZE(const std::string &val) : Any(val)
-{
- if (!is()) {
- return;
- }
- for (auto &t : tokens) {
- utils::findAndReplaceAll(t, "\"", "");
- }
-}
-
-auto CTZE::what() const noexcept -> std::string
-{
- return urc_name;
-}
-
-auto CTZE::isValid() const noexcept -> bool
+auto Ctze::isValid() const noexcept -> bool
{
return tokens.size() == magic_enum::enum_count<Tokens>();
}
-int CTZE::getTimeZoneOffset() const
+int Ctze::getTimeZoneOffset() const
{
const std::string &tzOffsetToken = tokens[static_cast<uint32_t>(Tokens::GMTDifference)];
@@ 42,7 27,7 @@ int CTZE::getTimeZoneOffset() const
}
if (failed) {
- LOG_ERROR("Failed to parse CTZE time zone offset: %s", tzOffsetToken.c_str());
+ LOG_ERROR("Failed to parse Ctze time zone offset: %s", tzOffsetToken.c_str());
}
int offsetInSeconds = offsetInQuartersOfHour * utils::time::minutesInQuarterOfHour * utils::time::secondsInMinute;
@@ 50,7 35,7 @@ int CTZE::getTimeZoneOffset() const
return offsetInSeconds;
}
-std::string CTZE::getTimeZoneString() const
+std::string Ctze::getTimeZoneString() const
{
std::string timeZoneStr = tokens[static_cast<uint32_t>(Tokens::GMTDifference)] + "," +
tokens[static_cast<uint32_t>(Tokens::DaylightSavingsAdjustment)];
@@ 58,19 43,19 @@ std::string CTZE::getTimeZoneString() const
return timeZoneStr;
}
-const struct tm CTZE::getGMTTime(void) const
+const struct tm Ctze::getGMTTime(void) const
{
struct tm timeinfo = {};
std::stringstream stream(tokens[static_cast<uint32_t>(Tokens::Date)] + "," +
tokens[static_cast<uint32_t>(Tokens::Time)]);
stream >> std::get_time(&timeinfo, "%Y/%m/%d,%H:%M:%S");
if (stream.fail()) {
- LOG_ERROR("Failed to parse CTZE time");
+ LOG_ERROR("Failed to parse Ctze time");
}
return timeinfo;
}
-auto CTZE::getTimeInfo() const noexcept -> tm
+auto Ctze::getTimeInfo() const noexcept -> tm
{
using namespace std::chrono;
R module-cellular/at/src/URC_CUSD.cpp => module-cellular/at/src/UrcCusd.cpp +7 -15
@@ 1,26 1,18 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
-#include <URC_CUSD.hpp>
+#include <UrcCusd.hpp>
#include <Utils.hpp>
#include <magic_enum.hpp>
using namespace at::urc;
-CUSD::CUSD(const std::string &val) : Any(val)
-{}
-
-auto CUSD::what() const noexcept -> std::string
-{
- return urc_name;
-}
-
-auto CUSD::isValid() const noexcept -> bool
+auto Cusd::isValid() const noexcept -> bool
{
- return is() && tokens.size() == magic_enum::enum_count<Tokens>();
+ return tokens.size() == magic_enum::enum_count<Tokens>();
}
-auto CUSD::isActionNeeded() const noexcept -> bool
+auto Cusd::isActionNeeded() const noexcept -> bool
{
if (isValid()) {
auto status = getStatus();
@@ 31,7 23,7 @@ auto CUSD::isActionNeeded() const noexcept -> bool
return false;
}
-auto CUSD::getMessage() const noexcept -> std::optional<std::string>
+auto Cusd::getMessage() const noexcept -> std::optional<std::string>
{
if (!isValid()) {
return std::nullopt;
@@ 43,7 35,7 @@ auto CUSD::getMessage() const noexcept -> std::optional<std::string>
return utils::trim(message);
}
-auto CUSD::getStatus() const noexcept -> std::optional<StatusType>
+auto Cusd::getStatus() const noexcept -> std::optional<StatusType>
{
if (isValid()) {
int statusInt;
@@ 63,7 55,7 @@ auto CUSD::getStatus() const noexcept -> std::optional<StatusType>
return std::nullopt;
}
-auto CUSD::getDCS() const noexcept -> std::optional<int>
+auto Cusd::getDCS() const noexcept -> std::optional<int>
{
if (!isValid()) {
return std::nullopt;
A module-cellular/at/src/UrcFactory.cpp => module-cellular/at/src/UrcFactory.cpp +54 -0
@@ 0,0 1,54 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include <UrcFactory.hpp>
+
+#include <UrcCreg.hpp>
+#include <UrcCtze.hpp>
+#include <UrcCusd.hpp>
+#include <UrcQind.hpp>
+#include <UrcCmti.hpp>
+#include <UrcClip.hpp>
+#include <UrcPoweredDown.hpp>
+#include <UrcResponse.hpp>
+
+using namespace at::urc;
+
+std::unique_ptr<Urc> UrcFactory::Create(const std::string &urcMessage)
+{
+ if (urcMessage.empty()) {
+ return std::make_unique<Urc>(std::string());
+ }
+
+ const char headDelimiter = ':';
+ auto it = std::find(urcMessage.begin(), urcMessage.end(), headDelimiter);
+ std::string head = std::string(urcMessage.begin(), it);
+ std::string body = std::string(it == urcMessage.end() ? urcMessage.begin() : it + 1, urcMessage.end());
+
+ if (Ctze::isURC(head)) {
+ return std::make_unique<Ctze>(body);
+ }
+ else if (Creg::isURC(head)) {
+ return std::make_unique<Creg>(body);
+ }
+ else if (Qind::isURC(head)) {
+ return std::make_unique<Qind>(body);
+ }
+ else if (Cusd::isURC(head)) {
+ return std::make_unique<Cusd>(body);
+ }
+ else if (Cmti::isURC(head)) {
+ return std::make_unique<Cmti>(body);
+ }
+ else if (Clip::isURC(head)) {
+ return std::make_unique<Clip>(body);
+ }
+ else if (PoweredDown::isURC(head)) {
+ return std::make_unique<PoweredDown>(body);
+ }
+ else if (auto type = UrcResponse::isURC(head)) {
+ return std::make_unique<UrcResponse>(type.value());
+ }
+
+ return std::make_unique<Urc>(body, head);
+}
A module-cellular/at/src/UrcPoweredDown.cpp => module-cellular/at/src/UrcPoweredDown.cpp +22 -0
@@ 0,0 1,22 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include <UrcPoweredDown.hpp>
+#include <module-utils/Utils.hpp>
+
+using namespace at::urc;
+
+bool PoweredDown::isValid() const noexcept
+{
+ return isNormalPowerDown() || isImmediatePowerDown();
+}
+
+bool PoweredDown::isNormalPowerDown() const noexcept
+{
+ return urcBody.find(PoweredDown::head_normal) != std::string::npos;
+}
+
+bool PoweredDown::isImmediatePowerDown() const noexcept
+{
+ return urcBody.find(PoweredDown::head_immediate) != std::string::npos;
+}
R module-cellular/at/src/URC_QIND.cpp => module-cellular/at/src/UrcQind.cpp +34 -12
@@ 1,28 1,50 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
-#include <URC_QIND.hpp>
+#include <UrcQind.hpp>
#include <log/debug.hpp>
using namespace at::urc;
-QIND::QIND(const std::string &val) : Any(val)
-{}
+auto Qind::isCsq() const noexcept -> bool
+{
+ if (tokens.size() == magic_enum::enum_count<enum CSQ>()) {
+ return tokens[CSQ].find(type_csq) != std::string::npos;
+ }
+ return false;
+}
-auto QIND::what() const noexcept -> std::string
+auto Qind::isFota() const noexcept -> bool
{
- return urc_name;
+ return tokens.size() > 0 && tokens[Fota] == type_fota;
}
-auto QIND::isCsq() const noexcept -> bool
+auto Qind::isFotaValid() const noexcept -> bool
{
- if (tokens.size() == magic_enum::enum_count<enum CSQ>()) {
- return tokens[CSQ].find(type_csq) != std::string::npos;
+ return isFota() && tokens.size() >= fotaMinTokenSize;
+}
+
+auto Qind::getFotaStage() const noexcept -> std::optional<FotaStage>
+{
+ if (isFotaValid()) {
+ for (auto &stage : magic_enum::enum_values<FotaStage>()) {
+ if (tokens[Stage] == magic_enum::enum_name(stage)) {
+ return stage;
+ }
+ }
}
- return false;
+ return std::nullopt;
+}
+
+auto Qind::getFotaParameter() const noexcept -> std::string
+{
+ if (isFotaValid() && tokens.size() >= fotaMinTokenSize) {
+ return tokens[Param];
+ }
+ return std::string();
}
-auto QIND::validate(enum CSQ check) const noexcept -> bool
+auto Qind::validate(enum CSQ check) const noexcept -> bool
{
try {
if (isCsq()) {
@@ 45,7 67,7 @@ auto QIND::validate(enum CSQ check) const noexcept -> bool
return false;
}
-auto QIND::getRSSI() const noexcept -> std::optional<int>
+auto Qind::getRSSI() const noexcept -> std::optional<int>
{
if (isCsq()) {
int rssi;
@@ 64,7 86,7 @@ auto QIND::getRSSI() const noexcept -> std::optional<int>
return std::nullopt;
}
-auto QIND::getBER() const noexcept -> std::optional<int>
+auto Qind::getBER() const noexcept -> std::optional<int>
{
if (isCsq()) {
int ber;
A module-cellular/at/src/UrcResponse.cpp => module-cellular/at/src/UrcResponse.cpp +12 -0
@@ 0,0 1,12 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include <UrcResponse.hpp>
+#include <module-utils/Utils.hpp>
+
+using namespace at::urc;
+
+UrcResponse::URCResponseType UrcResponse::getURCResponseType() const noexcept
+{
+ return type;
+}
M module-cellular/test/unittest_URC.cpp => module-cellular/test/unittest_URC.cpp +607 -224
@@ 10,81 10,99 @@
#include <catch2/catch.hpp>
#include <module-utils/time/time_conversion.hpp>
-#include "URC_QIND.hpp"
-#include "URC_CUSD.hpp"
-#include "URC_CTZE.hpp"
-#include "URC_CREG.hpp"
-
-TEST_CASE("+QIND: csq")
+#include "UrcQind.hpp"
+#include "UrcCusd.hpp"
+#include "UrcCtze.hpp"
+#include "UrcCreg.hpp"
+#include "UrcCmti.hpp"
+#include "UrcClip.hpp"
+#include "UrcPoweredDown.hpp"
+#include "UrcResponse.hpp"
+#include "UrcFactory.hpp"
+
+template <typename urcType> static auto getURC(std::unique_ptr<at::urc::Urc> &urc) -> std::shared_ptr<urcType>
{
- SECTION("Not valid data")
- {
- auto qind = at::urc::QIND("Not valid");
- REQUIRE_FALSE(qind.is());
+ if (urc) {
+ auto &rawUrc = *urc.get();
+ if (typeid(rawUrc) == typeid(urcType)) {
+ return std::unique_ptr<urcType>{static_cast<urcType *>(urc.release())};
+ }
}
+ return nullptr;
+}
+
+TEST_CASE("+Qind: csq")
+{
SECTION("CSQ")
{
- auto qind = at::urc::QIND("+QIND:\"csq\",100,50");
- REQUIRE(qind.is());
- REQUIRE(qind.isCsq());
- REQUIRE(*qind.getRSSI() == 100);
- REQUIRE(*qind.getBER() == 50);
+ auto urc = at::urc::UrcFactory::Create("+QIND:\"csq\",100,50");
+ auto qind = getURC<at::urc::Qind>(urc);
+ REQUIRE(qind);
+ REQUIRE(qind->isCsq());
+ REQUIRE(*qind->getRSSI() == 100);
+ REQUIRE(*qind->getBER() == 50);
}
SECTION("CSQ with white spaces")
{
- auto qind = at::urc::QIND("+QIND: \"csq\" , 100 , 50 ");
- REQUIRE(qind.is());
- REQUIRE(qind.isCsq());
- REQUIRE(*qind.getRSSI() == 100);
- REQUIRE(*qind.getBER() == 50);
+ auto urc = at::urc::UrcFactory::Create("+QIND: \"csq\" , 100 , 50 ");
+ auto qind = getURC<at::urc::Qind>(urc);
+ REQUIRE(qind);
+ REQUIRE(qind->isCsq());
+ REQUIRE(*qind->getRSSI() == 100);
+ REQUIRE(*qind->getBER() == 50);
}
SECTION("too short")
{
- auto qind = at::urc::QIND("+QIND:\"csq\",100");
- REQUIRE(qind.is());
- REQUIRE_FALSE(qind.isCsq());
- REQUIRE_FALSE(qind.getRSSI());
- REQUIRE_FALSE(qind.getBER());
+ auto urc = at::urc::UrcFactory::Create("+QIND:\"csq\",100");
+ auto qind = getURC<at::urc::Qind>(urc);
+ REQUIRE(qind);
+ REQUIRE_FALSE(qind->isCsq());
+ REQUIRE_FALSE(qind->getRSSI());
+ REQUIRE_FALSE(qind->getBER());
}
SECTION("too long")
{
- auto qind = at::urc::QIND("+QIND:\"csq\",100,50,25");
- REQUIRE(qind.is());
- REQUIRE_FALSE(qind.isCsq());
- REQUIRE_FALSE(qind.getRSSI());
- REQUIRE_FALSE(qind.getBER());
+ auto urc = at::urc::UrcFactory::Create("+QIND:\"csq\",100,50,25");
+ auto qind = getURC<at::urc::Qind>(urc);
+ REQUIRE(qind);
+ REQUIRE_FALSE(qind->isCsq());
+ REQUIRE_FALSE(qind->getRSSI());
+ REQUIRE_FALSE(qind->getBER());
}
SECTION("no integer values")
{
- auto qind = at::urc::QIND("+QIND:\"csq\",abc,def");
- REQUIRE(qind.is());
- REQUIRE(qind.isCsq());
- REQUIRE_FALSE(qind.getRSSI());
- REQUIRE_FALSE(qind.getBER());
+ auto urc = at::urc::UrcFactory::Create("+QIND:\"csq\",abc,def");
+ auto qind = getURC<at::urc::Qind>(urc);
+ REQUIRE(qind);
+ REQUIRE(qind->isCsq());
+ REQUIRE_FALSE(qind->getRSSI());
+ REQUIRE_FALSE(qind->getBER());
}
SECTION("not CSQ")
{
- auto qind = at::urc::QIND("+QIND:\"qsc\",100,50");
- REQUIRE(qind.is());
- REQUIRE_FALSE(qind.isCsq());
- REQUIRE_FALSE(qind.getRSSI());
- REQUIRE_FALSE(qind.getBER());
+ auto urc = at::urc::UrcFactory::Create("+QIND:\"qsc\",100,50");
+ auto qind = getURC<at::urc::Qind>(urc);
+ REQUIRE(qind);
+ REQUIRE_FALSE(qind->isCsq());
+ REQUIRE_FALSE(qind->getRSSI());
+ REQUIRE_FALSE(qind->getBER());
}
SECTION("valid CSQ")
{
std::vector<int> vec = {0, 1, 2, 98, 100, 101, 198, 200};
for (auto a : vec) {
- auto qind = at::urc::QIND("+QIND:\"csq\"," + std::to_string(a) + ",50");
- REQUIRE(qind.is());
- REQUIRE(qind.isCsq());
- REQUIRE(*qind.getRSSI() == a);
+ auto urc = at::urc::UrcFactory::Create("+QIND:\"csq\"," + std::to_string(a) + ",50");
+ auto qind = getURC<at::urc::Qind>(urc);
+ REQUIRE(qind);
+ REQUIRE(qind->isCsq());
+ REQUIRE(*qind->getRSSI() == a);
}
}
@@ 92,297 110,662 @@ TEST_CASE("+QIND: csq")
{
std::vector<std::uint32_t> vec = {99, 199};
for (auto a : vec) {
- auto qind = at::urc::QIND("+QIND:\"csq\"," + std::to_string(a) + ",50");
- REQUIRE(qind.is());
- REQUIRE(qind.isCsq());
- REQUIRE_FALSE(qind.getRSSI());
+ auto urc = at::urc::UrcFactory::Create("+QIND:\"csq\"," + std::to_string(a) + ",50");
+ auto qind = getURC<at::urc::Qind>(urc);
+ REQUIRE(qind);
+ REQUIRE(qind->isCsq());
+ REQUIRE_FALSE(qind->getRSSI());
}
}
SECTION("not valid BER")
{
int ber = 99;
- auto qind = at::urc::QIND("+QIND:\"csq\",50," + std::to_string(ber));
- REQUIRE(qind.is());
- REQUIRE(qind.isCsq());
- REQUIRE(*qind.getRSSI() == 50);
- REQUIRE_FALSE(qind.getBER());
+ auto urc = at::urc::UrcFactory::Create("+QIND:\"csq\",50," + std::to_string(ber));
+ auto qind = getURC<at::urc::Qind>(urc);
+ REQUIRE(qind);
+ REQUIRE(qind->isCsq());
+ REQUIRE(*qind->getRSSI() == 50);
+ REQUIRE_FALSE(qind->getBER());
}
}
-TEST_CASE("+CUSD")
+TEST_CASE("+Qind: FOTA")
{
- SECTION("Not valid data")
- {
- auto cusd = at::urc::CUSD("Not valid");
- REQUIRE_FALSE(cusd.is());
+ SECTION("FOTA")
+ {
+ // fota normal
+ auto urc = at::urc::UrcFactory::Create("+QIND:\"FOTA\",\"HTTPEND\",50");
+ auto qind = getURC<at::urc::Qind>(urc);
+ REQUIRE(qind);
+ REQUIRE(qind->isFotaValid());
+ // fota dirty
+ urc = at::urc::UrcFactory::Create("\r\r\n\n+QIND: \r\n\"FOTA\",\"HTTPEND\",50\n\n\r\r");
+ qind = getURC<at::urc::Qind>(urc);
+ REQUIRE(qind);
+ REQUIRE(qind->isFotaValid());
+ }
+
+ SECTION("FOTA malformed")
+ {
+ auto urc = at::urc::UrcFactory::Create("+QIND:\"FOTA\"");
+ auto qind = getURC<at::urc::Qind>(urc);
+ REQUIRE(qind);
+ REQUIRE(qind->isFota());
+ REQUIRE_FALSE(qind->isFotaValid());
+ }
+
+ SECTION("FOTA stage and parameter")
+ {
+ auto urc = at::urc::UrcFactory::Create("+QIND: \"FOTA\",\"HTTPSTART\"");
+ auto qind = getURC<at::urc::Qind>(urc);
+ REQUIRE(qind);
+ REQUIRE(qind->isFota());
+ REQUIRE(qind->isFotaValid());
+ REQUIRE(qind->getFotaStage() == at::urc::Qind::FotaStage::HTTPSTART);
+ REQUIRE(qind->getFotaParameter().empty());
+
+ urc = at::urc::UrcFactory::Create("+QIND: \"FOTA\",\"HTTPEND\", 22");
+ qind = getURC<at::urc::Qind>(urc);
+ REQUIRE(qind);
+ REQUIRE(qind->isFota());
+ REQUIRE(qind->isFotaValid());
+ REQUIRE(qind->getFotaStage() == at::urc::Qind::FotaStage::HTTPEND);
+ REQUIRE(qind->getFotaParameter() == "22");
+
+ urc = at::urc::UrcFactory::Create("+QIND: \"FOTA\",\"START\"");
+ qind = getURC<at::urc::Qind>(urc);
+ REQUIRE(qind);
+ REQUIRE(qind->isFota());
+ REQUIRE(qind->isFotaValid());
+ REQUIRE(qind->getFotaStage() == at::urc::Qind::FotaStage::START);
+ REQUIRE(qind->getFotaParameter().empty());
+
+ urc = at::urc::UrcFactory::Create("+QIND: \"FOTA\",\"UPDATING\", 99");
+ qind = getURC<at::urc::Qind>(urc);
+ REQUIRE(qind);
+ REQUIRE(qind->isFota());
+ REQUIRE(qind->isFotaValid());
+ REQUIRE(qind->getFotaStage() == at::urc::Qind::FotaStage::UPDATING);
+ REQUIRE(qind->getFotaParameter() == "99");
+
+ urc = at::urc::UrcFactory::Create("+QIND: \"FOTA\",\"END\", 2");
+ qind = getURC<at::urc::Qind>(urc);
+ REQUIRE(qind);
+ REQUIRE(qind->isFota());
+ REQUIRE(qind->isFotaValid());
+ REQUIRE(qind->getFotaStage() == at::urc::Qind::FotaStage::END);
+ REQUIRE(qind->getFotaParameter() == "2");
+
+ urc = at::urc::UrcFactory::Create("+QIND: \"FOTA\",\"TEST\", 3");
+ qind = getURC<at::urc::Qind>(urc);
+ REQUIRE(qind);
+ REQUIRE(qind->isFota());
+ REQUIRE(qind->isFotaValid());
+ REQUIRE_FALSE(qind->getFotaStage());
+ REQUIRE(qind->getFotaParameter() == "3");
+ }
+
+ SECTION("FOTA dirty")
+ {
+ auto urc =
+ at::urc::UrcFactory::Create("\n\r+QIND: \n\r\r \"FOTA\" ,\r \n \"HTTPEND\", \n\r test test \r\n");
+ auto qind = getURC<at::urc::Qind>(urc);
+ REQUIRE(qind);
+ REQUIRE(qind->isFota());
+ REQUIRE(qind->isFotaValid());
+ REQUIRE(qind->getFotaStage() == at::urc::Qind::FotaStage::HTTPEND);
+ REQUIRE(qind->getFotaParameter() == "test test");
}
+}
- SECTION("CUSD action needed")
+TEST_CASE("+Cusd")
+{
+ SECTION("Cusd action needed")
{
- auto cusd = at::urc::CUSD("+CUSD:1,\"test msg\",14");
- REQUIRE(cusd.is());
- REQUIRE(cusd.isValid());
- REQUIRE(cusd.isActionNeeded());
- REQUIRE(*cusd.getMessage() == "test msg");
- REQUIRE(*cusd.getStatus() == at::urc::CUSD::StatusType::FurtherUserActionRequired);
- REQUIRE(*cusd.getDCS() == 14);
+ auto urc = at::urc::UrcFactory::Create("+CUSD:1,\"test msg\",14");
+ auto cusd = getURC<at::urc::Cusd>(urc);
+
+ REQUIRE(cusd);
+ REQUIRE(cusd->isValid());
+ REQUIRE(cusd->isActionNeeded());
+ REQUIRE(*cusd->getMessage() == "test msg");
+ REQUIRE(*cusd->getStatus() == at::urc::Cusd::StatusType::FurtherUserActionRequired);
+ REQUIRE(*cusd->getDCS() == 14);
}
- SECTION("CUSD action needed with white spaces")
+ SECTION("Cusd action needed with white spaces")
{
- auto cusd = at::urc::CUSD("+CUSD: 0 , \"test msg\" , 15 ");
- REQUIRE(cusd.is());
- REQUIRE(cusd.isValid());
- REQUIRE_FALSE(cusd.isActionNeeded());
- REQUIRE(*cusd.getMessage() == "test msg");
- REQUIRE(*cusd.getStatus() == at::urc::CUSD::StatusType::NoFurtherUserActionRequired);
- REQUIRE(*cusd.getDCS() == 15);
+ auto urc = at::urc::UrcFactory::Create("+CUSD: 0 , \"test msg\" , 15 ");
+ auto cusd = getURC<at::urc::Cusd>(urc);
+ REQUIRE(cusd);
+ REQUIRE(cusd->isValid());
+ REQUIRE_FALSE(cusd->isActionNeeded());
+ REQUIRE(*cusd->getMessage() == "test msg");
+ REQUIRE(*cusd->getStatus() == at::urc::Cusd::StatusType::NoFurtherUserActionRequired);
+ REQUIRE(*cusd->getDCS() == 15);
}
- SECTION("CUSD wrong status and DCS")
+ SECTION("Cusd wrong status and DCS")
{
- auto cusd = at::urc::CUSD("+CUSD:100,\"test msg\", abc");
- REQUIRE(cusd.is());
- REQUIRE(cusd.isValid());
- REQUIRE_FALSE(cusd.isActionNeeded());
- REQUIRE(*cusd.getMessage() == "test msg");
- REQUIRE_FALSE(cusd.getStatus());
- REQUIRE_FALSE(cusd.getDCS());
+ auto urc = at::urc::UrcFactory::Create("+CUSD:100,\"test msg\", abc");
+ auto cusd = getURC<at::urc::Cusd>(urc);
+ REQUIRE(cusd);
+ REQUIRE(cusd->isValid());
+ REQUIRE_FALSE(cusd->isActionNeeded());
+ REQUIRE(*cusd->getMessage() == "test msg");
+ REQUIRE_FALSE(cusd->getStatus());
+ REQUIRE_FALSE(cusd->getDCS());
}
- SECTION("CUSD action not needed")
+ SECTION("Cusd action not needed")
{
- auto cusd = at::urc::CUSD("+CUSD:2,\"test msg\",15");
- REQUIRE(cusd.is());
- REQUIRE(cusd.isValid());
- REQUIRE_FALSE(cusd.isActionNeeded());
+ auto urc = at::urc::UrcFactory::Create("+CUSD:2,\"test msg\",15");
+ auto cusd = getURC<at::urc::Cusd>(urc);
+ REQUIRE(cusd);
+ REQUIRE(cusd->isValid());
+ REQUIRE_FALSE(cusd->isActionNeeded());
}
- SECTION("no CUSD")
+ SECTION("no Cusd")
{
- auto cusd = at::urc::CUSD("+CSUD:1,\"test msg\",15");
- REQUIRE_FALSE(cusd.is());
+ auto urc = at::urc::UrcFactory::Create("+CSUD:1,\"test msg\",15");
+ auto cusd = getURC<at::urc::Cusd>(urc);
+ REQUIRE_FALSE(cusd);
}
SECTION("too short")
{
- auto cusd = at::urc::CUSD("+CUSD:1,\"test msg\"");
- REQUIRE(cusd.is());
- REQUIRE_FALSE(cusd.isValid());
+ auto urc = at::urc::UrcFactory::Create("+CUSD:1,\"test msg\"");
+ auto cusd = getURC<at::urc::Cusd>(urc);
+ REQUIRE(cusd);
+ REQUIRE_FALSE(cusd->isValid());
}
SECTION("too long")
{
- auto cusd = at::urc::CUSD("+CUSD:1,\"test msg\",15,15");
- REQUIRE(cusd.is());
- REQUIRE_FALSE(cusd.isValid());
+ auto urc = at::urc::UrcFactory::Create("+CUSD:1,\"test msg\",15,15");
+ auto cusd = getURC<at::urc::Cusd>(urc);
+ REQUIRE(cusd);
+ REQUIRE_FALSE(cusd->isValid());
}
}
-TEST_CASE("+CTZE")
+TEST_CASE("+Ctze")
{
SECTION("Not valid data")
{
- auto ctze = at::urc::CTZE("Not valid");
- REQUIRE_FALSE(ctze.is());
- REQUIRE_FALSE(ctze.isValid());
+ auto urc = at::urc::UrcFactory::Create("+QIND:\"csq\"");
+ auto ctze = getURC<at::urc::Ctze>(urc);
+ REQUIRE_FALSE(ctze);
}
SECTION("ctze +08")
{
- auto ctze = at::urc::CTZE("+CTZE: \"+08\",1,\"2020/10/21,13:49:57\"");
- REQUIRE(ctze.is());
- REQUIRE(ctze.isValid());
- auto timeInfo = ctze.getTimeInfo();
+ auto urc = at::urc::UrcFactory::Create("+CTZE: \"+08\",1,\"2020/10/21,13:49:57\"");
+ auto ctze = getURC<at::urc::Ctze>(urc);
+ REQUIRE(ctze);
+ REQUIRE(ctze->isValid());
+ auto timeInfo = ctze->getTimeInfo();
std::stringstream ss;
ss << std::put_time(&timeInfo, "%Y/%m/%d,%H:%M:%S");
REQUIRE(ss.str() == "2020/10/21,15:49:57");
- REQUIRE(ctze.getTimeZoneOffset() == 8 * utils::time::minutesInQuarterOfHour * utils::time::secondsInMinute);
- REQUIRE(ctze.getTimeZoneString() == "+08,1");
+ REQUIRE(ctze->getTimeZoneOffset() == 8 * utils::time::minutesInQuarterOfHour * utils::time::secondsInMinute);
+ REQUIRE(ctze->getTimeZoneString() == "+08,1");
ss.str(std::string());
- timeInfo = ctze.getGMTTime();
+ timeInfo = ctze->getGMTTime();
ss << std::put_time(&timeInfo, "%Y/%m/%d,%H:%M:%S");
REQUIRE(ss.str() == "2020/10/21,13:49:57");
}
SECTION("ctze -08")
{
- auto ctze = at::urc::CTZE("+CTZE: \"-08\",1,\"2020/10/21,13:49:57\"");
- REQUIRE(ctze.is());
- REQUIRE(ctze.isValid());
- auto timeInfo = ctze.getTimeInfo();
+ auto urc = at::urc::UrcFactory::Create("+CTZE: \"-08\",1,\"2020/10/21,13:49:57\"");
+ auto ctze = getURC<at::urc::Ctze>(urc);
+ REQUIRE(ctze);
+ REQUIRE(ctze->isValid());
+ auto timeInfo = ctze->getTimeInfo();
std::ostringstream ss;
ss << std::put_time(&timeInfo, "%Y/%m/%d,%H:%M:%S");
REQUIRE(ss.str() == "2020/10/21,11:49:57");
- REQUIRE(ctze.getTimeZoneOffset() == -8 * utils::time::minutesInQuarterOfHour * utils::time::secondsInMinute);
- REQUIRE(ctze.getTimeZoneString() == "-08,1");
+ REQUIRE(ctze->getTimeZoneOffset() == -8 * utils::time::minutesInQuarterOfHour * utils::time::secondsInMinute);
+ REQUIRE(ctze->getTimeZoneString() == "-08,1");
ss.str(std::string());
- timeInfo = ctze.getGMTTime();
+ timeInfo = ctze->getGMTTime();
ss << std::put_time(&timeInfo, "%Y/%m/%d,%H:%M:%S");
REQUIRE(ss.str() == "2020/10/21,13:49:57");
}
SECTION("ctze -00")
{
- auto ctze = at::urc::CTZE("+CTZE: \"-00\",0,\"2020/10/21,13:49:57\"");
- REQUIRE(ctze.is());
- REQUIRE(ctze.isValid());
- auto timeInfo = ctze.getTimeInfo();
+ auto urc = at::urc::UrcFactory::Create("+CTZE: \"-00\",0,\"2020/10/21,13:49:57\"");
+ auto ctze = getURC<at::urc::Ctze>(urc);
+ REQUIRE(ctze);
+ REQUIRE(ctze->isValid());
+ auto timeInfo = ctze->getTimeInfo();
std::ostringstream ss;
ss << std::put_time(&timeInfo, "%Y/%m/%d,%H:%M:%S");
REQUIRE(ss.str() == "2020/10/21,13:49:57");
- REQUIRE(ctze.getTimeZoneOffset() == 0);
- REQUIRE(ctze.getTimeZoneString() == "-00,0");
+ REQUIRE(ctze->getTimeZoneOffset() == 0);
+ REQUIRE(ctze->getTimeZoneString() == "-00,0");
ss.str(std::string());
- timeInfo = ctze.getGMTTime();
+ timeInfo = ctze->getGMTTime();
ss << std::put_time(&timeInfo, "%Y/%m/%d,%H:%M:%S");
REQUIRE(ss.str() == "2020/10/21,13:49:57");
}
SECTION("too short")
{
- auto ctze = at::urc::CTZE("+CTZE: \"-08\",\"2020/10/21,13:49:57\"");
- REQUIRE(ctze.is());
- REQUIRE_FALSE(ctze.isValid());
- // auto timeInfo = ctze.getTimeInfo();
+ auto urc = at::urc::UrcFactory::Create("+CTZE: \"-08\",\"2020/10/21,13:49:57\"");
+ auto ctze = getURC<at::urc::Ctze>(urc);
+ REQUIRE(ctze);
+ REQUIRE_FALSE(ctze->isValid());
+ // auto timeInfo = ctze->getTimeInfo();
}
}
-TEST_CASE("+CREG")
+TEST_CASE("+Creg")
{
- SECTION("Not valid data")
+ SECTION("Creg short")
{
- auto creg = at::urc::CUSD("Not valid");
- REQUIRE_FALSE(creg.is());
+ auto urc = at::urc::UrcFactory::Create("+CREG: 0");
+ auto creg = getURC<at::urc::Creg>(urc);
+ REQUIRE(creg);
+ REQUIRE(creg->isValid());
+ REQUIRE(creg->isShort());
+ REQUIRE_FALSE(creg->isExtended());
+ REQUIRE(creg->getStatus() == Store::Network::Status::NotRegistered);
+ REQUIRE_FALSE(creg->getLocation());
+ REQUIRE_FALSE(creg->getCellId());
+ REQUIRE(creg->getAccessTechnology() == Store::Network::AccessTechnology::Unknown);
}
- SECTION("CREG short")
+ SECTION("Creg extended")
{
- auto creg = at::urc::CREG("+CREG: 0");
- REQUIRE(creg.is());
- REQUIRE(creg.isValid());
- REQUIRE(creg.isShort());
- REQUIRE_FALSE(creg.isExtended());
- REQUIRE(creg.getStatus() == Store::Network::Status::NotRegistered);
- REQUIRE_FALSE(creg.getLocation());
- REQUIRE_FALSE(creg.getCellId());
- REQUIRE(creg.getAccessTechnology() == Store::Network::AccessTechnology::Unknown);
+ auto urc = at::urc::UrcFactory::Create("+CREG: 1,\"D509\",\"80D413D\",7");
+ auto creg = getURC<at::urc::Creg>(urc);
+ REQUIRE(creg);
+ REQUIRE(creg->isValid());
+ REQUIRE_FALSE(creg->isShort());
+ REQUIRE(creg->isExtended());
+ REQUIRE(creg->getStatus() == Store::Network::Status::RegisteredHomeNetwork);
+ REQUIRE(*creg->getLocation() == "D509");
+ REQUIRE(*creg->getCellId() == "80D413D");
+ REQUIRE(creg->getAccessTechnology() == Store::Network::AccessTechnology::EUtran);
}
- SECTION("CREG extended")
- {
- auto creg = at::urc::CREG("+CREG: 1,\"D509\",\"80D413D\",7");
- REQUIRE(creg.is());
- REQUIRE(creg.isValid());
- REQUIRE_FALSE(creg.isShort());
- REQUIRE(creg.isExtended());
- REQUIRE(creg.getStatus() == Store::Network::Status::RegisteredHomeNetwork);
- REQUIRE(*creg.getLocation() == "D509");
- REQUIRE(*creg.getCellId() == "80D413D");
- REQUIRE(creg.getAccessTechnology() == Store::Network::AccessTechnology::EUtran);
- }
-
- SECTION("CREG extended access technology")
+ SECTION("Creg extended access technology")
{
{
- auto creg = at::urc::CREG("+CREG: 1,\"D509\",\"80D413D\",0");
- REQUIRE(creg.getAccessTechnology() == Store::Network::AccessTechnology::Gsm);
+ auto urc = at::urc::UrcFactory::Create("+CREG: 1,\"D509\",\"80D413D\",0");
+ auto creg = getURC<at::urc::Creg>(urc);
+ REQUIRE(creg->getAccessTechnology() == Store::Network::AccessTechnology::Gsm);
}
{
- auto creg = at::urc::CREG("+CREG: 1,\"D509\",\"80D413D\",1");
- REQUIRE(creg.getAccessTechnology() == Store::Network::AccessTechnology::Unknown);
+ auto urc = at::urc::UrcFactory::Create("+CREG: 1,\"D509\",\"80D413D\",1");
+ auto creg = getURC<at::urc::Creg>(urc);
+ REQUIRE(creg->getAccessTechnology() == Store::Network::AccessTechnology::Unknown);
}
{
- auto creg = at::urc::CREG("+CREG: 1,\"D509\",\"80D413D\",7");
- REQUIRE(creg.getAccessTechnology() == Store::Network::AccessTechnology::EUtran);
+ auto urc = at::urc::UrcFactory::Create("+CREG: 1,\"D509\",\"80D413D\",7");
+ auto creg = getURC<at::urc::Creg>(urc);
+ REQUIRE(creg->getAccessTechnology() == Store::Network::AccessTechnology::EUtran);
}
{
- auto creg = at::urc::CREG("+CREG: 1,\"D509\",\"80D413D\",8");
- REQUIRE(creg.getAccessTechnology() == Store::Network::AccessTechnology::Unknown);
+ auto urc = at::urc::UrcFactory::Create("+CREG: 1,\"D509\",\"80D413D\",8");
+ auto creg = getURC<at::urc::Creg>(urc);
+ REQUIRE(creg->getAccessTechnology() == Store::Network::AccessTechnology::Unknown);
}
{
- auto creg = at::urc::CREG("+CREG: 1,\"D509\",\"80D413D\",ABX");
- REQUIRE(creg.getAccessTechnology() == Store::Network::AccessTechnology::Unknown);
+ auto urc = at::urc::UrcFactory::Create("+CREG: 1,\"D509\",\"80D413D\",ABX");
+ auto creg = getURC<at::urc::Creg>(urc);
+ REQUIRE(creg->getAccessTechnology() == Store::Network::AccessTechnology::Unknown);
}
}
- SECTION("CREG status")
+ SECTION("Creg status")
{
{
- auto creg = at::urc::CREG("+CREG: 0,\"D509\",\"80D413D\",0");
- REQUIRE(creg.getStatus() == Store::Network::Status::NotRegistered);
+ auto urc = at::urc::UrcFactory::Create("+CREG: 0,\"D509\",\"80D413D\",0");
+ auto creg = getURC<at::urc::Creg>(urc);
+ REQUIRE(creg->getStatus() == Store::Network::Status::NotRegistered);
}
{
- auto creg = at::urc::CREG("+CREG: 5,\"D509\",\"80D413D\",0");
- REQUIRE(creg.getStatus() == Store::Network::Status::RegisteredRoaming);
+ auto urc = at::urc::UrcFactory::Create("+CREG: 5,\"D509\",\"80D413D\",0");
+ auto creg = getURC<at::urc::Creg>(urc);
+ REQUIRE(creg->getStatus() == Store::Network::Status::RegisteredRoaming);
}
{
- auto creg = at::urc::CREG("+CREG: 4,\"D509\",\"80D413D\",0");
- REQUIRE(creg.getStatus() == Store::Network::Status::Unknown);
+ auto urc = at::urc::UrcFactory::Create("+CREG: 4,\"D509\",\"80D413D\",0");
+ auto creg = getURC<at::urc::Creg>(urc);
+ REQUIRE(creg->getStatus() == Store::Network::Status::Unknown);
}
{
- auto creg = at::urc::CREG("+CREG: 6,\"D509\",\"80D413D\",0");
- REQUIRE(creg.getStatus() == Store::Network::Status::Unknown);
+ auto urc = at::urc::UrcFactory::Create("+CREG: 6,\"D509\",\"80D413D\",0");
+ auto creg = getURC<at::urc::Creg>(urc);
+ REQUIRE(creg->getStatus() == Store::Network::Status::Unknown);
}
{
- auto creg = at::urc::CREG("+CREG: A,\"D509\",\"80D413D\",0");
- REQUIRE(creg.getStatus() == Store::Network::Status::Unknown);
+ auto urc = at::urc::UrcFactory::Create("+CREG: A,\"D509\",\"80D413D\",0");
+ auto creg = getURC<at::urc::Creg>(urc);
+ REQUIRE(creg->getStatus() == Store::Network::Status::Unknown);
}
}
- SECTION("CREG no CREG")
- {
- auto creg = at::urc::CREG("+CEGR: 0");
- REQUIRE_FALSE(creg.is());
- REQUIRE_FALSE(creg.isValid());
- REQUIRE(creg.isShort());
- REQUIRE_FALSE(creg.isExtended());
- REQUIRE(creg.getStatus() == Store::Network::Status::Unknown);
- REQUIRE_FALSE(creg.getLocation());
- REQUIRE_FALSE(creg.getCellId());
- REQUIRE(creg.getAccessTechnology() == Store::Network::AccessTechnology::Unknown);
- }
-
- SECTION("CREG too short")
- {
- auto creg = at::urc::CREG("+CREG:");
- REQUIRE(creg.is());
- REQUIRE_FALSE(creg.isValid());
- REQUIRE_FALSE(creg.isShort());
- REQUIRE_FALSE(creg.isExtended());
- REQUIRE(creg.getStatus() == Store::Network::Status::Unknown);
- REQUIRE_FALSE(creg.getLocation());
- REQUIRE_FALSE(creg.getCellId());
- REQUIRE(creg.getAccessTechnology() == Store::Network::AccessTechnology::Unknown);
- }
-
- SECTION("CREG too long")
- {
- auto creg = at::urc::CREG("+CREG: 0,\"D509\",\"80D413D\",0,1");
- REQUIRE(creg.is());
- REQUIRE_FALSE(creg.isValid());
- REQUIRE_FALSE(creg.isShort());
- REQUIRE_FALSE(creg.isExtended());
- REQUIRE(creg.getStatus() == Store::Network::Status::Unknown);
- REQUIRE_FALSE(creg.getLocation());
- REQUIRE_FALSE(creg.getCellId());
- REQUIRE(creg.getAccessTechnology() == Store::Network::AccessTechnology::Unknown);
- }
-
- SECTION("CREG wrong length")
- {
- auto creg = at::urc::CREG("+CREG: 0,\"D509\"");
- REQUIRE(creg.is());
- REQUIRE_FALSE(creg.isValid());
- REQUIRE_FALSE(creg.isShort());
- REQUIRE_FALSE(creg.isExtended());
- REQUIRE(creg.getStatus() == Store::Network::Status::Unknown);
- REQUIRE_FALSE(creg.getLocation());
- REQUIRE_FALSE(creg.getCellId());
- REQUIRE(creg.getAccessTechnology() == Store::Network::AccessTechnology::Unknown);
+ SECTION("Creg no Creg")
+ {
+ auto urc = at::urc::UrcFactory::Create("+CEGR: 0");
+ auto creg = getURC<at::urc::Creg>(urc);
+ REQUIRE_FALSE(creg);
+ }
+
+ SECTION("Creg too short")
+ {
+ auto urc = at::urc::UrcFactory::Create("+CREG:");
+ auto creg = getURC<at::urc::Creg>(urc);
+ REQUIRE(creg);
+ REQUIRE_FALSE(creg->isValid());
+ }
+
+ SECTION("Creg too long")
+ {
+ auto urc = at::urc::UrcFactory::Create("+CREG: 0,\"D509\",\"80D413D\",0,1");
+ auto creg = getURC<at::urc::Creg>(urc);
+ REQUIRE(creg);
+ REQUIRE_FALSE(creg->isValid());
+ }
+
+ SECTION("Creg wrong length")
+ {
+ auto urc = at::urc::UrcFactory::Create("+CREG 0,\"D509\"");
+ auto creg = getURC<at::urc::Creg>(urc);
+ REQUIRE(creg);
+ REQUIRE_FALSE(creg->isValid());
+ }
+}
+
+TEST_CASE("+Cmti")
+{
+ SECTION("Cmti too short")
+ {
+ auto urc = at::urc::UrcFactory::Create("+CMTI: \"ME\"");
+ auto cmti = getURC<at::urc::Cmti>(urc);
+ REQUIRE(cmti);
+ REQUIRE_FALSE(cmti->isValid());
+ }
+
+ SECTION("Cmti too long")
+ {
+ auto urc = at::urc::UrcFactory::Create("+CMTI: \"ME\",1,1");
+ auto cmti = getURC<at::urc::Cmti>(urc);
+ REQUIRE(cmti);
+ REQUIRE_FALSE(cmti->isValid());
+ }
+
+ SECTION("Cmti valid")
+ {
+ auto urc = at::urc::UrcFactory::Create("+CMTI: \"ME\",1");
+ auto cmti = getURC<at::urc::Cmti>(urc);
+ REQUIRE(cmti);
+ REQUIRE(cmti->isValid());
+ REQUIRE(cmti->getIndex() == "1");
+ REQUIRE(cmti->getMemory() == "ME");
+ }
+}
+
+TEST_CASE("+CLIP")
+{
+ SECTION("CLIP too short")
+ {
+ auto urc = at::urc::UrcFactory::Create("+CLIP: \"+48123456789\"");
+ auto clip = getURC<at::urc::Clip>(urc);
+ REQUIRE(clip);
+ REQUIRE_FALSE(clip->isValid());
+ }
+
+ SECTION("CLIP valid")
+ {
+ // two parameters
+ auto urc = at::urc::UrcFactory::Create("+CLIP: \"+48123456789\",145");
+ auto clip = getURC<at::urc::Clip>(urc);
+ REQUIRE(clip);
+ REQUIRE(clip->isValid());
+
+ // three parameters
+ urc = at::urc::UrcFactory::Create("+CLIP: \"+48123456789\",145,");
+ clip = getURC<at::urc::Clip>(urc);
+ REQUIRE(clip);
+ REQUIRE(clip->isValid());
+ REQUIRE_FALSE(clip->getSubaddr());
+ REQUIRE_FALSE(clip->getAlpha());
+ REQUIRE_FALSE(clip->getSatype());
+ REQUIRE_FALSE(clip->getCLIValidity());
+
+ // four parameters
+ urc = at::urc::UrcFactory::Create("+CLIP: \"+48123456789\",145,,");
+ clip = getURC<at::urc::Clip>(urc);
+ REQUIRE(clip);
+ REQUIRE(clip->isValid());
+ REQUIRE_FALSE(clip->getSubaddr());
+ REQUIRE_FALSE(clip->getAlpha());
+ REQUIRE_FALSE(clip->getSatype());
+ REQUIRE_FALSE(clip->getCLIValidity());
+
+ // six parameters
+ urc = at::urc::UrcFactory::Create("+CLIP: \"+48123456789\",145,,,");
+ clip = getURC<at::urc::Clip>(urc);
+ REQUIRE(clip);
+ REQUIRE(clip->isValid());
+ REQUIRE_FALSE(clip->getSubaddr());
+ REQUIRE_FALSE(clip->getAlpha());
+ REQUIRE_FALSE(clip->getSatype());
+ REQUIRE_FALSE(clip->getCLIValidity());
+
+ // seven parameters
+ urc = at::urc::UrcFactory::Create("+CLIP: \"+48123456789\",145,,,,");
+ clip = getURC<at::urc::Clip>(urc);
+ REQUIRE(clip);
+ REQUIRE(clip->isValid());
+ REQUIRE_FALSE(clip->getSubaddr());
+ REQUIRE_FALSE(clip->getAlpha());
+ REQUIRE_FALSE(clip->getSatype());
+ REQUIRE_FALSE(clip->getCLIValidity());
+
+ // two parameters with validation not empty
+ urc = at::urc::UrcFactory::Create("+CLIP: \"+48123456789\",145,,,,0");
+ clip = getURC<at::urc::Clip>(urc);
+ REQUIRE(clip);
+ REQUIRE(clip->isValid());
+ REQUIRE_FALSE(clip->getSubaddr());
+ REQUIRE_FALSE(clip->getAlpha());
+ REQUIRE_FALSE(clip->getSatype());
+ REQUIRE(clip->getCLIValidity() == "0");
+ }
+
+ SECTION("CLIP phone number")
+ {
+ auto urc = at::urc::UrcFactory::Create("+CLIP: \"+48123456789\",145,,,,0");
+ auto clip = getURC<at::urc::Clip>(urc);
+ REQUIRE(clip);
+ REQUIRE(clip->isValid());
+ REQUIRE(clip->getNumber() == "+48123456789");
+
+ urc = at::urc::UrcFactory::Create("+CLIP: \"\",145,,,,0");
+ clip = getURC<at::urc::Clip>(urc);
+ REQUIRE(clip);
+ REQUIRE(clip->isValid());
+ REQUIRE(clip->getNumber() == "");
+
+ urc = at::urc::UrcFactory::Create("+CLIP: ,145,,,,0");
+ clip = getURC<at::urc::Clip>(urc);
+ REQUIRE(clip);
+ REQUIRE(clip->isValid());
+ REQUIRE(clip->getNumber() == "");
+ }
+
+ SECTION("CLIP address type")
+ {
+ auto urc = at::urc::UrcFactory::Create("+CLIP: \"+48123456789\",,,,,0");
+ auto clip = getURC<at::urc::Clip>(urc);
+ REQUIRE(clip);
+ REQUIRE(clip->isValid());
+ REQUIRE_FALSE(clip->getType());
+
+ urc = at::urc::UrcFactory::Create("+CLIP: \"+48123456789\",577,,,,0");
+ clip = getURC<at::urc::Clip>(urc);
+ REQUIRE(clip);
+ REQUIRE(clip->isValid());
+ REQUIRE_FALSE(clip->getType());
+
+ urc = at::urc::UrcFactory::Create("+CLIP: \"+48123456789\",\"test\",,,,0");
+ clip = getURC<at::urc::Clip>(urc);
+ REQUIRE(clip);
+ REQUIRE(clip->isValid());
+ REQUIRE_FALSE(clip->getType());
+
+ urc = at::urc::UrcFactory::Create("+CLIP: \"+48123456789\",test,,,,0");
+ clip = getURC<at::urc::Clip>(urc);
+ REQUIRE(clip);
+ REQUIRE(clip->isValid());
+ REQUIRE_FALSE(clip->getType());
+
+ urc = at::urc::UrcFactory::Create("+CLIP: \"+48123456789\",129,,,,0");
+ clip = getURC<at::urc::Clip>(urc);
+ REQUIRE(clip);
+ REQUIRE(clip->isValid());
+ REQUIRE(clip->getType() == at::urc::Clip::AddressType::UnknownType);
+
+ urc = at::urc::UrcFactory::Create("+CLIP: \"+48123456789\",145,,,,0");
+ clip = getURC<at::urc::Clip>(urc);
+ REQUIRE(clip);
+ REQUIRE(clip->isValid());
+ REQUIRE(clip->getType() == at::urc::Clip::AddressType::InternationalNumber);
+
+ urc = at::urc::UrcFactory::Create("+CLIP: \"+48123456789\",161,,,,0");
+ clip = getURC<at::urc::Clip>(urc);
+ REQUIRE(clip);
+ REQUIRE(clip->isValid());
+ REQUIRE(clip->getType() == at::urc::Clip::AddressType::NationalNumber);
+ }
+
+ SECTION("CLIP optional parameters")
+ {
+ auto urc = at::urc::UrcFactory::Create("+CLIP: \"+48123456789\",145,,,,");
+ auto clip = getURC<at::urc::Clip>(urc);
+ REQUIRE(clip);
+ REQUIRE(clip->isValid());
+ REQUIRE_FALSE(clip->getAlpha());
+ REQUIRE_FALSE(clip->getSatype());
+ REQUIRE_FALSE(clip->getSubaddr());
+ REQUIRE_FALSE(clip->getCLIValidity());
+
+ urc = at::urc::UrcFactory::Create("+CLIP: \"+48123456789\",145,1,2,3,0");
+ clip = getURC<at::urc::Clip>(urc);
+ REQUIRE(clip);
+ REQUIRE(clip->isValid());
+ REQUIRE(clip->getAlpha() == "3");
+ REQUIRE(clip->getSatype() == "2");
+ REQUIRE(clip->getSubaddr() == "1");
+ REQUIRE(clip->getCLIValidity() == "0");
+ }
+}
+
+TEST_CASE("POWERED DOWN")
+{
+ SECTION("POWERED DOWN valid")
+ {
+ auto urc = at::urc::UrcFactory::Create("POWERED DOWN");
+ auto pwd = getURC<at::urc::PoweredDown>(urc);
+ REQUIRE(pwd);
+ REQUIRE(pwd->isValid());
+ REQUIRE(pwd->isImmediatePowerDown());
+ REQUIRE_FALSE(pwd->isNormalPowerDown());
+
+ urc = at::urc::UrcFactory::Create("NORMAL POWER DOWN");
+ pwd = getURC<at::urc::PoweredDown>(urc);
+ REQUIRE(pwd);
+ REQUIRE(pwd->isValid());
+ REQUIRE_FALSE(pwd->isImmediatePowerDown());
+ REQUIRE(pwd->isNormalPowerDown());
+
+ // dirty
+ urc = at::urc::UrcFactory::Create("\n\r POWERED DOWN\n\r ");
+ pwd = getURC<at::urc::PoweredDown>(urc);
+ REQUIRE(pwd);
+ REQUIRE(pwd->isValid());
+ REQUIRE(pwd->isImmediatePowerDown());
+ REQUIRE_FALSE(pwd->isNormalPowerDown());
+
+ urc = at::urc::UrcFactory::Create(" \n\r NORMAL POWER DOWN \n\r ");
+ pwd = getURC<at::urc::PoweredDown>(urc);
+ REQUIRE(pwd);
+ REQUIRE(pwd->isValid());
+ REQUIRE_FALSE(pwd->isImmediatePowerDown());
+ REQUIRE(pwd->isNormalPowerDown());
+ }
+
+ SECTION("POWERED DOWN invalid")
+ {
+ auto pwd = at::urc::PoweredDown("TEST");
+ REQUIRE_FALSE(pwd.isValid());
+ REQUIRE_FALSE(pwd.isImmediatePowerDown());
+ REQUIRE_FALSE(pwd.isNormalPowerDown());
+ }
+}
+
+TEST_CASE("Urc RESPONSE")
+{
+ SECTION("Urc RESPONSE valid")
+ {
+ auto urc = at::urc::UrcFactory::Create("OK");
+ auto rsp = getURC<at::urc::UrcResponse>(urc);
+ REQUIRE(rsp);
+ REQUIRE(rsp->getURCResponseType() == at::urc::UrcResponse::URCResponseType::Ok);
+
+ urc = at::urc::UrcFactory::Create("CONNECT");
+ rsp = getURC<at::urc::UrcResponse>(urc);
+ REQUIRE(rsp);
+ REQUIRE(rsp->getURCResponseType() == at::urc::UrcResponse::URCResponseType::Connect);
+
+ urc = at::urc::UrcFactory::Create("RING");
+ rsp = getURC<at::urc::UrcResponse>(urc);
+ REQUIRE(rsp);
+ REQUIRE(rsp->getURCResponseType() == at::urc::UrcResponse::URCResponseType::Ring);
+
+ urc = at::urc::UrcFactory::Create("NO CARRIER");
+ rsp = getURC<at::urc::UrcResponse>(urc);
+ REQUIRE(rsp);
+ REQUIRE(rsp->getURCResponseType() == at::urc::UrcResponse::URCResponseType::NoCarrier);
+
+ urc = at::urc::UrcFactory::Create("ERROR");
+ rsp = getURC<at::urc::UrcResponse>(urc);
+ REQUIRE(rsp);
+ REQUIRE(rsp->getURCResponseType() == at::urc::UrcResponse::URCResponseType::Error);
+
+ urc = at::urc::UrcFactory::Create("NO DIALTONE");
+ rsp = getURC<at::urc::UrcResponse>(urc);
+ REQUIRE(rsp);
+ REQUIRE(rsp->getURCResponseType() == at::urc::UrcResponse::URCResponseType::NoDialtone);
+
+ urc = at::urc::UrcFactory::Create("BUSY");
+ rsp = getURC<at::urc::UrcResponse>(urc);
+ REQUIRE(rsp);
+ REQUIRE(rsp->getURCResponseType() == at::urc::UrcResponse::URCResponseType::Busy);
+
+ urc = at::urc::UrcFactory::Create("NO ANSWER");
+ rsp = getURC<at::urc::UrcResponse>(urc);
+ REQUIRE(rsp);
+ REQUIRE(rsp->getURCResponseType() == at::urc::UrcResponse::URCResponseType::NoAnswer);
+ }
+
+ SECTION("Urc RESPONSE dirty")
+ {
+ auto urc = at::urc::UrcFactory::Create("\n\n \rNO ANSWER\n\r\n");
+ auto rsp = getURC<at::urc::UrcResponse>(urc);
+ REQUIRE(rsp);
+ REQUIRE(rsp->getURCResponseType() == at::urc::UrcResponse::URCResponseType::NoAnswer);
}
}
M module-services/service-cellular/CMakeLists.txt => module-services/service-cellular/CMakeLists.txt +1 -0
@@ 16,6 16,7 @@ target_sources( ${PROJECT_NAME}
PRIVATE
"${CMAKE_CURRENT_LIST_DIR}/ServiceCellular.cpp"
+ "${CMAKE_CURRENT_LIST_DIR}/CellularUrcHandler.cpp"
"${CMAKE_CURRENT_LIST_DIR}/api/CellularServiceAPI.cpp"
"${CMAKE_CURRENT_LIST_DIR}/CellularCall.cpp"
"${CMAKE_CURRENT_LIST_DIR}/SignalStrength.cpp"
A module-services/service-cellular/CellularUrcHandler.cpp => module-services/service-cellular/CellularUrcHandler.cpp +160 -0
@@ 0,0 1,160 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include "CellularUrcHandler.hpp"
+
+#include "messages/CellularMessage.hpp"
+#include "api/CellularServiceAPI.hpp"
+
+#include <service-evtmgr/Constants.hpp> // for evt_manager service name
+#include <module-sys/Service/Bus.hpp> // for sys::Bus
+#include <module-services/service-antenna/api/AntennaServiceAPI.hpp> // for AntennaServiceAPI
+
+// this static function will be replaced by Settings API
+static bool isSettingsAutomaticTimeSyncEnabled()
+{
+ return true;
+}
+
+void CellularUrcHandler::Handle(Clip &urc)
+{
+ LOG_TRACE("incoming call...");
+ std::string phoneNumber;
+ if (urc.isValid()) {
+ phoneNumber = urc.getNumber();
+ }
+ // continue without number
+ response = std::make_unique<CellularCallMessage>(CellularCallMessage::Type::IncomingCall, phoneNumber);
+ urc.setHandled(true);
+}
+
+void CellularUrcHandler::Handle(Creg &urc)
+{
+ if (urc.isValid()) {
+ auto accessTechnology = urc.getAccessTechnology();
+ auto status = urc.getStatus();
+
+ LOG_INFO("Network status - %s, access technology %s",
+ utils::enumToString(status).c_str(),
+ utils::enumToString(accessTechnology).c_str());
+
+ Store::Network network{status, accessTechnology};
+
+ Store::GSM::get()->setNetwork(network);
+ response =
+ std::make_unique<CellularNotificationMessage>(CellularNotificationMessage::Type::NetworkStatusUpdate);
+ urc.setHandled(true);
+ }
+ else {
+ LOG_WARN("Network status - not valid");
+ }
+}
+
+void CellularUrcHandler::Handle(Cmti &urc)
+{
+ LOG_TRACE("received new SMS notification");
+ if (urc.isValid()) {
+ response = std::make_unique<CellularNotificationMessage>(CellularNotificationMessage::Type::NewIncomingSMS,
+ urc.getIndex());
+ urc.setHandled(true);
+ }
+ else {
+ LOG_ERROR("Could not parse Cmti message");
+ }
+}
+
+void CellularUrcHandler::Handle(Cusd &urc)
+{
+ if (urc.isActionNeeded()) {
+ if (cellularService.ussdState == ussd::State::pullRequestSent) {
+ cellularService.ussdState = ussd::State::pullResponseReceived;
+ cellularService.setUSSDTimer();
+ }
+ }
+ else {
+ CellularServiceAPI::USSDRequest(&cellularService, CellularUSSDMessage::RequestType::abortSesion);
+ cellularService.ussdState = ussd::State::sesionAborted;
+ cellularService.setUSSDTimer();
+ }
+
+ auto message = urc.getMessage();
+ if (!message) {
+ response = std::nullopt;
+ return;
+ }
+
+ response =
+ std::make_unique<CellularNotificationMessage>(CellularNotificationMessage::Type::NewIncomingUSSD, *message);
+ urc.setHandled(true);
+}
+
+void CellularUrcHandler::Handle(Ctze &urc)
+{
+ if (!urc.isValid()) {
+ return;
+ }
+
+ if (isSettingsAutomaticTimeSyncEnabled()) {
+ auto msg = std::make_shared<CellularTimeNotificationMessage>(
+ urc.getGMTTime(), urc.getTimeZoneOffset(), urc.getTimeZoneString());
+ sys::Bus::SendUnicast(msg, service::name::evt_manager, &cellularService);
+ }
+ else {
+ LOG_DEBUG("Timezone sync disabled.");
+ }
+ urc.setHandled(true);
+}
+
+void CellularUrcHandler::Handle(Qind &urc)
+{
+ if (urc.isCsq()) {
+ // Received signal strength change
+ AntennaServiceAPI::CSQChange(&cellularService);
+ auto rssi = urc.getRSSI();
+ if (!rssi) {
+ LOG_INFO("Invalid csq - ignore");
+ }
+ else {
+ SignalStrength signalStrength(*rssi);
+
+ Store::GSM::get()->setSignalStrength(signalStrength.data);
+ response = std::make_unique<CellularNotificationMessage>(
+ CellularNotificationMessage::Type::SignalStrengthUpdate, urc.getUrcBody());
+ }
+ urc.setHandled(true);
+ }
+ else if (urc.isFota()) {
+ std::string httpSuccess = "0";
+ if (urc.getFotaStage() == Qind::FotaStage::HTTPEND && urc.getFotaParameter() == httpSuccess) {
+ LOG_DEBUG("Fota UPDATE, switching to AT mode");
+ cellularService.cmux->setMode(TS0710::Mode::AT);
+ urc.setHandled(true);
+ }
+ }
+}
+
+void CellularUrcHandler::Handle(PoweredDown &urc)
+{
+ if (urc.isValid()) {
+ response =
+ std::make_unique<CellularNotificationMessage>(CellularNotificationMessage::Type::PowerDownDeregistering);
+ urc.setHandled(true);
+ }
+}
+
+void CellularUrcHandler::Handle(UrcResponse &urc)
+{
+ std::vector<UrcResponse::URCResponseType> typesToHandle = {
+ UrcResponse::URCResponseType::NoCarrier,
+ UrcResponse::URCResponseType::Busy,
+ UrcResponse::URCResponseType::NoAnswer,
+ };
+
+ for (auto &t : typesToHandle) {
+ if (t == urc.getURCResponseType()) {
+ LOG_TRACE("call aborted");
+ response = std::make_unique<CellularNotificationMessage>(CellularNotificationMessage::Type::CallAborted);
+ urc.setHandled(true);
+ }
+ }
+}
A module-services/service-cellular/CellularUrcHandler.hpp => module-services/service-cellular/CellularUrcHandler.hpp +53 -0
@@ 0,0 1,53 @@
+// 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 <module-cellular/at/UrcHandler.hpp>
+
+#include <module-cellular/at/UrcClip.hpp>
+#include <module-cellular/at/UrcCreg.hpp>
+#include <module-cellular/at/UrcCmti.hpp>
+#include <module-cellular/at/UrcCusd.hpp>
+#include <module-cellular/at/UrcCtze.hpp>
+#include <module-cellular/at/UrcQind.hpp>
+#include <module-cellular/at/UrcPoweredDown.hpp>
+#include <module-cellular/at/UrcResponse.hpp>
+
+using namespace at::urc;
+
+#include "messages/CellularMessage.hpp"
+#include "api/CellularServiceAPI.hpp"
+#include "ServiceCellular.hpp"
+
+/**
+ * ServiceCellular helper for handling Urc messages
+ */
+class CellularUrcHandler : public UrcHandler
+{
+ public:
+ CellularUrcHandler(ServiceCellular &cellularService) : cellularService(cellularService)
+ {}
+
+ void Handle(Clip &urc) final;
+ void Handle(Creg &urc) final;
+ void Handle(Cmti &urc) final;
+ void Handle(Cusd &urc) final;
+ void Handle(Ctze &urc) final;
+ void Handle(Qind &urc) final;
+ void Handle(PoweredDown &urc) final;
+ void Handle(UrcResponse &urc) final;
+
+ /**
+ * Gets the response that should be returned after handling Urc
+ * @return
+ */
+ std::optional<std::shared_ptr<CellularMessage>> getResponse()
+ {
+ return std::move(response);
+ };
+
+ private:
+ ServiceCellular &cellularService;
+ std::optional<std::unique_ptr<CellularMessage>> response;
+};
M module-services/service-cellular/ServiceCellular.cpp => module-services/service-cellular/ServiceCellular.cpp +17 -140
@@ 2,10 2,12 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#include <Utils.hpp> // for removeNewLines, enumToString, split, to_string
-#include <at/URC_QIND.hpp> // for QIND
-#include <at/URC_CUSD.hpp> // for CUSD
-#include <at/URC_CTZE.hpp> // for CTZE
-#include <at/URC_CREG.hpp> // for CREG
+#include <at/UrcQind.hpp> // for Qind
+#include <at/UrcCusd.hpp> // for Cusd
+#include <at/UrcCtze.hpp> // for Ctze
+#include <at/UrcCreg.hpp> // for Creg
+#include <at/UrcCmti.hpp> // for Cmti
+#include <at/UrcClip.hpp> // for CLIP
#include <at/response.hpp> // for parseQNWINFO
#include <common_data/EventStore.hpp> // for GSM, GSM::SIM, GSM::SIM::SIM1, GSM::SIM::SIM_FAIL, GSM::SIM::SIM2, GSM::Tray, GSM::Tray::IN, Network
#include <service-evtmgr/Constants.hpp> // for evt_manager
@@ 13,6 15,7 @@
#include <PhoneNumber.hpp> // for PhoneNumber::View, PhoneNumber
#include <module-db/queries/notifications/QueryNotificationsIncrement.hpp> // for Increment
#include <module-db/queries/messages/sms/QuerySMSSearchByType.hpp> // for SMSSearchByType, SMSSearchByTypeResult
+#include <module-cellular/at/UrcFactory.hpp> // for UrcFactory
#include <log/log.hpp> // for LOG_DEBUG, LOG_ERROR, LOG_INFO, LOG_FATAL, LOG_WARN, LOG_TRACE
#include <bits/exception.h> // for exception
#include <algorithm> // for remove, max
@@ 28,6 31,7 @@
#include "Service/Service.hpp" // for Service
#include "Service/Timer.hpp" // for Timer
#include "ServiceCellular.hpp"
+#include "CellularUrcHandler.hpp" // for CellularUrcHandler
#include "MessageType.hpp" // for MessageType, MessageType::CellularGetAntenna, MessageType::CellularListCurrentCalls, MessageType::CellularAnswerIncomingCall, MessageType::CellularCall, MessageType::CellularCallRequest, MessageType::CellularGetCREG, MessageType::CellularGetCSQ, MessageType::CellularGetFirmwareVersion, MessageType::CellularGetIMSI, MessageType::CellularGetNWINFO, MessageType::CellularGetNetworkInfo, MessageType::CellularGetOwnNumber, MessageType::CellularGetScanMode, MessageType::CellularGetScanModeResult, MessageType::CellularHangupCall, MessageType::CellularNetworkInfoResult, MessageType::CellularNotification, MessageType::CellularOperatorsScanResult, MessageType::CellularSelectAntenna, MessageType::CellularSetScanMode, MessageType::CellularSimProcedure, MessageType::CellularStartOperatorsScan, MessageType::CellularStateRequest, MessageType::CellularTransmitDtmfTones, MessageType::CellularUSSDRequest, MessageType::DBServiceNotification, MessageType::EVMModemStatus, MessageType::EVMTimeUpdated
#include "messages/CellularMessage.hpp" // for CellularResponseMessage, CellularNotificationMessage, CellularNotificationMessage::Type, CellularCallMessage, CellularUSSDMessage, RawCommandRespAsync, RawCommandResp, CellularUSSDMessage::RequestType, CellularRequestMessage, StateChange, CellularGetChannelMessage, CellularGetChannelResponseMessage, CellularAntennaResponseMessage, CellularCallMessage::Type, CellularTimeNotificationMessage, CellularUSSDMessage::RequestType::abortSesion, CellularAntennaRequestMessage, CellularCallRequestMessage, CellularNotificationMessage::Type::CallActive, RawCommand, CellularCallMessage::Type::IncomingCall, CellularCallMessage::Type::Ringing, CellularDtmfRequestMessage, CellularNotificationMessage::Type::CallAborted, CellularNotificationMessage::Type::NetworkStatusUpdate, CellularNotificationMessage::Type::NewIncomingSMS, CellularNotificationMessage::Type::NewIncomingUSSD, CellularNotificationMessage::Type::PowerDownDeregistered, CellularNotificationMessage::Type::PowerDownDeregistering, CellularNotificationMessage::Type::SIM, CellularNotificationMessage::Type::SignalStrengthUpdate, CellularUSSDMessage::RequestType::pushSesionRequest, CellularNotificationMessage::Type::PowerUpProcedureComplete, CellularNotificationMessage::Type::RawCommand, CellularUSSDMessage::RequestType::pullSesionRequest
#include "SignalStrength.hpp" // for SignalStrength
@@ 994,38 998,18 @@ sys::Message_t ServiceCellular::DataReceivedHandler(sys::DataMessage *msgl, sys:
return std::make_shared<sys::ResponseMessage>();
}
}
-namespace
-{
- bool isAbortCallNotification(const std::string &str)
- {
- return ((str.find(at::Chanel::NO_CARRIER) != std::string::npos) ||
- (str.find(at::Chanel::BUSY) != std::string::npos) ||
- (str.find(at::Chanel::NO_ANSWER) != std::string::npos));
- }
- namespace powerdown
- {
- static const std::string powerDownNormal = "NORMAL POWER DOWN";
- static const std::string poweredDown = "POWERED DOWN";
-
- bool isNormalPowerDown(const std::string str)
- {
- std::string stripped = utils::removeNewLines(str);
- return stripped.find(powerDownNormal) == 0;
- }
- bool isPoweredDown(const std::string str)
- {
- std::string stripped = utils::removeNewLines(str);
- return stripped.find(poweredDown) == 0;
- }
- } // namespace powerdown
-} // namespace
std::optional<std::shared_ptr<CellularMessage>> ServiceCellular::identifyNotification(const std::string &data)
{
- std::string str(data.begin(), data.end());
+ CellularUrcHandler urcHandler(*this);
+ std::string str(data.begin(), data.end());
std::string logStr = utils::removeNewLines(str);
LOG_DEBUG("Notification:: %s", logStr.c_str());
+
+ auto urc = at::urc::UrcFactory::Create(str);
+ urc->Handle(urcHandler);
+
if (auto ret = str.find("+CPIN: ") != std::string::npos) {
/// TODO handle different sim statuses - i.e. no sim, sim error, sim puk, sim pin etc.
if (str.find("NOT READY", ret) == std::string::npos) {
@@ 1055,118 1039,11 @@ std::optional<std::shared_ptr<CellularMessage>> ServiceCellular::identifyNotific
return std::nullopt;
}
- // Incoming call
- if (auto ret = str.find("+CLIP: ") != std::string::npos) {
- LOG_TRACE("incoming call...");
-
- auto beg = str.find("\"", ret);
- auto end = str.find("\"", ret + beg + 1);
- auto message = str.substr(beg + 1, end - beg - 1);
-
- return std::make_shared<CellularCallMessage>(CellularCallMessage::Type::IncomingCall, message);
- }
-
- // Call aborted/failed
- if (isAbortCallNotification(str)) {
- LOG_TRACE("call aborted");
- return std::make_shared<CellularNotificationMessage>(CellularNotificationMessage::Type::CallAborted);
- }
-
- // Received new SMS
- if (str.find("+CMTI: ") != std::string::npos) {
- LOG_TRACE("received new SMS notification");
- // find message number
- auto tokens = utils::split(str, ',');
- if (tokens.size() == 2) {
- return std::make_shared<CellularNotificationMessage>(CellularNotificationMessage::Type::NewIncomingSMS,
- tokens[1]);
- }
- }
-
- // Received signal strength change
- auto qind = at::urc::QIND(str);
- if (qind.is() && qind.isCsq()) {
- AntennaServiceAPI::CSQChange(this);
- auto rssi = qind.getRSSI();
- if (!rssi) {
- LOG_INFO("Invalid csq - ignore");
- }
- else {
- SignalStrength signalStrength(*rssi);
-
- Store::GSM::get()->setSignalStrength(signalStrength.data);
- return std::make_shared<CellularNotificationMessage>(
- CellularNotificationMessage::Type::SignalStrengthUpdate, str);
- }
- }
-
- if (str.find("\"FOTA\",\"HTTPEND\",0") != std::string::npos) {
- LOG_DEBUG("Fota UPDATE, switching to AT mode");
- cmux->setMode(TS0710::Mode::AT);
- }
-
- auto cusd = at::urc::CUSD(str);
- if (cusd.is()) {
- if (cusd.isActionNeeded()) {
- if (ussdState == ussd::State::pullRequestSent) {
- ussdState = ussd::State::pullResponseReceived;
- setUSSDTimer();
- }
- }
- else {
- CellularServiceAPI::USSDRequest(this, CellularUSSDMessage::RequestType::abortSesion);
- ussdState = ussd::State::sesionAborted;
- setUSSDTimer();
- }
-
- auto message = cusd.getMessage();
- if (!message) {
- return std::nullopt;
- }
-
- return std::make_shared<CellularNotificationMessage>(CellularNotificationMessage::Type::NewIncomingUSSD,
- *message);
- }
- auto ctze = at::urc::CTZE(str);
- if (ctze.is() && isSettingsAutomaticTimeSyncEnabled()) {
- auto msg = std::make_shared<CellularTimeNotificationMessage>(
- ctze.getGMTTime(), ctze.getTimeZoneOffset(), ctze.getTimeZoneString());
- sys::Bus::SendUnicast(msg, service::name::evt_manager, this);
- return std::nullopt;
- }
-
- auto creg = at::urc::CREG(str);
- if (creg.is()) {
- if (creg.isValid()) {
- auto accessTechnology = creg.getAccessTechnology();
- auto status = creg.getStatus();
-
- LOG_INFO("Network status - %s, access technology %s",
- utils::enumToString(status).c_str(),
- utils::enumToString(accessTechnology).c_str());
-
- Store::Network network{status, accessTechnology};
-
- Store::GSM::get()->setNetwork(network);
- return std::make_shared<CellularNotificationMessage>(
- CellularNotificationMessage::Type::NetworkStatusUpdate);
- }
-
- LOG_WARN("Network status - not valid");
-
- return std::nullopt;
- }
-
- // Power Down
- if (powerdown::isNormalPowerDown(str)) {
- return std::make_shared<CellularNotificationMessage>(CellularNotificationMessage::Type::PowerDownDeregistering);
- }
- if (powerdown::isPoweredDown(str)) {
- return std::make_shared<CellularNotificationMessage>(CellularNotificationMessage::Type::PowerDownDeregistered);
+ if (!urc->isHandled()) {
+ LOG_WARN("Unhandled notification: %s", logStr.c_str());
}
- LOG_WARN("Unhandled notification: %s", logStr.c_str());
- return std::nullopt;
+ return urcHandler.getResponse();
}
bool ServiceCellular::sendSMS(SMSRecord record)
M module-services/service-cellular/ServiceCellular.hpp => module-services/service-cellular/ServiceCellular.hpp +2 -0
@@ 171,6 171,8 @@ class ServiceCellular : public sys::Service
bool handleUSSDRequest(CellularUSSDMessage::RequestType requestType, const std::string &request = "");
bool handleUSSDURC(void);
void handleUSSDTimer(void);
+
+ friend class CellularUrcHandler;
};
#endif // PUREPHONE_SERVICECELLULAR_HPP
M module-services/service-fota/CMakeLists.txt => module-services/service-fota/CMakeLists.txt +1 -0
@@ 13,6 13,7 @@ message( "${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}" )
target_sources( ${PROJECT_NAME}
PRIVATE
ServiceFota.cpp
+ FotaUrcHandler.cpp
api/FotaServiceAPI.cpp
PUBLIC
messages/FotaMessages.hpp
A module-services/service-fota/FotaUrcHandler.cpp => module-services/service-fota/FotaUrcHandler.cpp +36 -0
@@ 0,0 1,36 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include "FotaUrcHandler.hpp"
+
+void FotaUrcHandler::Handle(Qind &urc)
+{
+ if (urc.isFotaValid()) {
+ if (urc.getFotaStage() == Qind::FotaStage::START) {
+ LOG_DEBUG("FOTA UPDATING");
+ }
+ else if (urc.getFotaStage() == Qind::FotaStage::HTTPEND) {
+ LOG_DEBUG("Downloading finished: %s", urc.getFotaParameter().c_str());
+ }
+ else if (urc.getFotaStage() == Qind::FotaStage::END) {
+ LOG_DEBUG("FOTA FINISHED -> reboot (%s)", fotaService.receiverServiceName.c_str());
+ fotaService.sendFotaFinshed(fotaService.receiverServiceName);
+ }
+ else if (urc.getFotaStage() == Qind::FotaStage::UPDATING) {
+ auto token_val = 0;
+ try {
+ token_val = std::stoi(urc.getFotaParameter());
+ }
+ catch (const std::exception &e) {
+ LOG_ERROR("Conversion error of %s, taking default value %d", urc.getFotaParameter().c_str(), token_val);
+ }
+
+ unsigned char progress = static_cast<unsigned char>(token_val);
+ LOG_DEBUG("FOTA UPDATING: %d", progress);
+ fotaService.sendProgress(progress, fotaService.receiverServiceName);
+ }
+ else if (urc.getFotaStage() == Qind::FotaStage::HTTPSTART) {
+ LOG_DEBUG("Start downloading DELTA");
+ }
+ }
+}
A module-services/service-fota/FotaUrcHandler.hpp => module-services/service-fota/FotaUrcHandler.hpp +32 -0
@@ 0,0 1,32 @@
+// 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 <module-cellular/at/UrcHandler.hpp>
+#include <module-cellular/at/UrcQind.hpp>
+#include "ServiceFota.hpp"
+
+using namespace at::urc;
+
+/**
+ * ServiceFota helper for handling Urc messages
+ */
+class FotaUrcHandler : public UrcHandler
+{
+ public:
+ FotaUrcHandler(FotaService::Service &fotaService) : fotaService(fotaService)
+ {}
+
+ void Handle(Qind &urc) final;
+ virtual void Handle(Clip &urc){};
+ virtual void Handle(Creg &urc){};
+ virtual void Handle(Cmti &urc){};
+ virtual void Handle(Cusd &urc){};
+ virtual void Handle(Ctze &urc){};
+ virtual void Handle(PoweredDown &urc){};
+ virtual void Handle(UrcResponse &urc){};
+
+ private:
+ FotaService::Service &fotaService;
+};
M module-services/service-fota/ServiceFota.cpp => module-services/service-fota/ServiceFota.cpp +5 -35
@@ 3,8 3,8 @@
#include <Service/Bus.hpp> // for Bus
#include <module-cellular/at/Result.hpp> // for Result, Result::Code, Result::Code::OK
-#include <module-cellular/at/URC_QIND.hpp> // for QIND
#include <service-cellular/api/CellularServiceAPI.hpp> // for GetDataChannel
+#include <module-cellular/at/UrcFactory.hpp> // for UrcFactory
#include <bits/exception.h> // for exception
#include <algorithm> // for find_if, remove, transform
#include <cctype> // for tolower
@@ 19,6 19,7 @@
#include "Service/Timer.hpp" // for Timer
#include "api/FotaServiceAPI.hpp" // for Config, ContextMap, ContextType, HTTPMethod, ContextPair, HTTPMethod::GET, AuthMethod, HTTPErrors, HTTPErrors::OK, HTTPMethod::POST
#include "ServiceFota.hpp"
+#include "FotaUrcHandler.hpp" // FotaUrcHandler
#include "Service/Service.hpp" // for Service
#include "Service/Message.hpp" // for Message_t, DataMessage, ResponseMessage
#include "MessageType.hpp" // for MessageType, MessageType::CellularListCurrentCalls
@@ 579,40 580,9 @@ namespace FotaService
void Service::parseQIND(const std::string &message)
{
- auto qind = at::urc::QIND(message);
- if (qind.is()) {
- const unsigned char fotaPrefixTagPosition = 0;
- const unsigned char fotaStatusTagPosition = 1;
- auto tokens = qind.getTokens();
- if (tokens[fotaPrefixTagPosition].find("FOTA") != std::string::npos) {
- if (tokens[1].find("START") != std::string::npos) {
- LOG_DEBUG("FOTA UPDATING");
- }
- else if (tokens[fotaStatusTagPosition].find("HTTPEND") != std::string::npos) {
- LOG_DEBUG("Downloading finished: %s", tokens[2].c_str());
- }
- else if (tokens[fotaStatusTagPosition].find("END") != std::string::npos) {
- LOG_DEBUG("FOTA FINISHED -> reboot (%s)", receiverServiceName.c_str());
- sendFotaFinshed(receiverServiceName);
- }
- else if (tokens[fotaStatusTagPosition].find("UPDATING") != std::string::npos) {
- auto token_val = 0;
- try {
- token_val = std::stoi(tokens[2]);
- }
- catch (const std::exception &e) {
- LOG_ERROR("Conversion error of %s, taking default value %d", tokens[2].c_str(), token_val);
- }
-
- unsigned char progress = static_cast<unsigned char>(token_val);
- LOG_DEBUG("FOTA UPDATING: %d", progress);
- sendProgress(progress, receiverServiceName);
- }
- else if (tokens[fotaStatusTagPosition].find("HTTPSTART") != std::string::npos) {
- LOG_DEBUG("Start downloading DELTA");
- }
- }
- }
+ auto urc = at::urc::UrcFactory::Create(message);
+ auto urcHandler = FotaUrcHandler(*this);
+ urc->Handle(urcHandler);
}
void Service::sendProgress(unsigned int progress, const std::string &receiver)
M module-services/service-fota/ServiceFota.hpp => module-services/service-fota/ServiceFota.hpp +4 -0
@@ 18,6 18,8 @@
#include "Service/Common.hpp" // for ReturnCodes, ReturnCodes::Success, ServicePowerMode
class DLC_channel;
+class FotaUrcHandler;
+
namespace sys
{
class Timer;
@@ 113,6 115,8 @@ namespace FotaService
std::string file;
std::string receiverServiceName;
unsigned char currentApnContext = 0;
+
+ friend FotaUrcHandler;
};
} // namespace FotaService