M changelog.md => changelog.md +1 -0
@@ 7,6 7,7 @@
* `[settings][bluetooth]` Add "Phone name" window.
* `[gui]` Add "ButtonOnOff" widget.
* `[cellular]` Add support for modem reset
+* `[cellular]` Obtain time zone through network
### Changed
M module-cellular/at/URC_CTZE.hpp => module-cellular/at/URC_CTZE.hpp +8 -1
@@ 21,10 21,17 @@ namespace at::urc
public:
explicit CTZE(const std::string &val);
+
+ 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;
+
+ auto getTimeZoneOffset() const -> int;
+ auto getTimeZoneString() const -> std::string;
+ auto getGMTTime(void) const -> const struct tm;
};
}; // namespace at::urc
M module-cellular/at/response.cpp => module-cellular/at/response.cpp +15 -5
@@ 32,7 32,11 @@ namespace at
if (pos != std::string::npos) {
LOG_INFO("%s", CSQstring.c_str());
CSQstring = CSQstring.substr(0, pos);
- return utils::toNumeric(CSQstring, result);
+ int parsedVal = 0;
+ if (utils::toNumeric(CSQstring, parsedVal) && parsedVal >= 0) {
+ result = parsedVal;
+ return true;
+ }
}
}
return false;
@@ 59,7 63,11 @@ namespace at
if (pos != std::string::npos) {
auto constexpr digitLength = 1;
resp = resp.substr(pos + digitLength, digitLength);
- return utils::toNumeric(resp, result);
+ int parsedVal = 0;
+ if (utils::toNumeric(resp, parsedVal) && parsedVal >= 0) {
+ result = parsedVal;
+ return true;
+ }
}
return false;
}
@@ 127,7 135,7 @@ namespace at
utils::findAndReplaceAll(string, " ", "");
utils::findAndReplaceAll(string, "\"", "");
- uint32_t freq = 0;
+ int freq = 0;
utils::toNumeric(string, freq);
return freq;
}
@@ 158,8 166,10 @@ namespace at
utils::findAndReplaceAll(string, "\"", emptyString);
utils::findAndReplaceAll(string, toRemove, emptyString);
- uint32_t band;
- utils::toNumeric(string, band);
+ int band = 0;
+ if (utils::toNumeric(string, band) && band < 0) {
+ return 0;
+ }
auto freq = lteFreqs.find(band);
if (freq != lteFreqs.end()) {
M module-cellular/at/src/URC_CTZE.cpp => module-cellular/at/src/URC_CTZE.cpp +54 -8
@@ 3,13 3,21 @@
#include "../URC_CTZE.hpp"
#include <log/debug.hpp>
+#include <module-utils/time/time_conversion.hpp>
#include <module-utils/date/include/date/date.h>
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
{
@@ 21,6 29,47 @@ auto CTZE::isValid() const noexcept -> bool
return tokens.size() == magic_enum::enum_count<Tokens>();
}
+int CTZE::getTimeZoneOffset() const
+{
+ const std::string &tzOffsetToken = tokens[static_cast<uint32_t>(Tokens::GMTDifference)];
+
+ int offsetInQuartersOfHour = 0;
+ bool failed = !utils::toNumeric(tzOffsetToken, offsetInQuartersOfHour);
+
+ if (offsetInQuartersOfHour != std::clamp(offsetInQuartersOfHour, minTimezoneOffset, maxTimezoneOffset)) {
+ offsetInQuartersOfHour = 0;
+ failed = true;
+ }
+
+ if (failed) {
+ LOG_ERROR("Failed to parse CTZE time zone offset: %s", tzOffsetToken.c_str());
+ }
+
+ int offsetInSeconds = offsetInQuartersOfHour * utils::time::minutesInQuarterOfHour * utils::time::secondsInMinute;
+
+ return offsetInSeconds;
+}
+
+std::string CTZE::getTimeZoneString() const
+{
+ std::string timeZoneStr = tokens[static_cast<uint32_t>(Tokens::GMTDifference)] + "," +
+ tokens[static_cast<uint32_t>(Tokens::DaylightSavingsAdjustment)];
+ timeZoneStr.erase(remove_if(timeZoneStr.begin(), timeZoneStr.end(), isspace), timeZoneStr.end());
+ return timeZoneStr;
+}
+
+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");
+ }
+ return timeinfo;
+}
+
auto CTZE::getTimeInfo() const noexcept -> tm
{
using namespace std::chrono;
@@ 28,20 77,17 @@ auto CTZE::getTimeInfo() const noexcept -> tm
std::tm timeinfo{};
if (isValid()) {
std::string dateTimeStr(tokens[Tokens::Date] + "," + tokens[Tokens::Time]);
- utils::findAndReplaceAll(dateTimeStr, "\"", "");
std::stringstream stream(dateTimeStr);
date::sys_seconds tp;
stream >> date::parse("%Y/%m/%d,%H:%M:%S", tp);
auto gmtDifferenceStr = tokens[Tokens::GMTDifference];
- utils::findAndReplaceAll(gmtDifferenceStr, "\"", "");
- int gmtDifference = utils::getValue<int>(gmtDifferenceStr);
- constexpr auto minutesInQuartersOfHour = 15;
- constexpr auto secondsInMinutes = 60;
- auto time = system_clock::to_time_t(tp) + gmtDifference * minutesInQuartersOfHour * secondsInMinutes;
- timeinfo = *gmtime(&time);
+ int gmtDifference = utils::getValue<int>(gmtDifferenceStr);
+ auto time = system_clock::to_time_t(tp) +
+ gmtDifference * utils::time::minutesInQuarterOfHour * utils::time::secondsInMinute;
+ timeinfo = *gmtime(&time);
}
return timeinfo;
}
M module-cellular/test/unittest_URC.cpp => module-cellular/test/unittest_URC.cpp +33 -0
@@ 8,6 8,7 @@
#define CATCH_CONFIG_MAIN
#include <catch2/catch.hpp>
+#include <module-utils/time/time_conversion.hpp>
#include "URC_QIND.hpp"
#include "URC_CUSD.hpp"
@@ 197,6 198,13 @@ TEST_CASE("+CTZE")
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");
+ ss.str(std::string());
+ 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")
@@ 208,6 216,31 @@ TEST_CASE("+CTZE")
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");
+ ss.str(std::string());
+ 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();
+ 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");
+ ss.str(std::string());
+ 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")
M module-services/service-cellular/ServiceCellular.cpp => module-services/service-cellular/ServiceCellular.cpp +13 -6
@@ 187,6 187,12 @@ ServiceCellular::~ServiceCellular()
LOG_INFO("[ServiceCellular] Cleaning resources");
}
+// this static function will be replaced by Settings API
+static bool isSettingsAutomaticTimeSyncEnabled()
+{
+ return true;
+}
+
void ServiceCellular::CallStateTimerHandler()
{
std::shared_ptr<CellularRequestMessage> msg =
@@ 977,8 983,6 @@ std::optional<std::shared_ptr<CellularMessage>> ServiceCellular::identifyNotific
std::string str(data.begin(), data.end());
std::string logStr = utils::removeNewLines(str);
- LOG_DEBUG("Notification:: %s", logStr.c_str());
-
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) {
@@ 1075,8 1079,9 @@ std::optional<std::shared_ptr<CellularMessage>> ServiceCellular::identifyNotific
*message);
}
auto ctze = at::urc::CTZE(str);
- if (ctze.is()) {
- auto msg = std::make_shared<CellularTimeNotificationMessage>(ctze.getTimeInfo());
+ 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;
}
@@ 1594,8 1599,10 @@ bool ServiceCellular::handle_modem_on()
bool ServiceCellular::handle_URCReady()
{
auto channel = cmux->get(TS0710::Channel::Commands);
- channel->cmd(at::AT::ENABLE_TIME_ZONE_UPDATE);
- channel->cmd(at::AT::SET_TIME_ZONE_REPORTING);
+ if (isSettingsAutomaticTimeSyncEnabled()) {
+ channel->cmd(at::AT::ENABLE_TIME_ZONE_UPDATE);
+ channel->cmd(at::AT::SET_TIME_ZONE_REPORTING);
+ }
channel->cmd(at::AT::ENABLE_NETWORK_REGISTRATION_URC);
LOG_DEBUG("%s", state.c_str());
return true;
M module-services/service-cellular/messages/CellularMessage.hpp => module-services/service-cellular/messages/CellularMessage.hpp +25 -2
@@ 83,17 83,40 @@ class CellularNotificationMessage : public CellularMessage
class CellularTimeNotificationMessage : public CellularMessage
{
private:
- struct tm time;
+ std::optional<struct tm> time;
+ std::optional<int> timeZoneGmtOff;
+ std::optional<std::string> timeZoneString;
public:
CellularTimeNotificationMessage() = delete;
+ explicit CellularTimeNotificationMessage(struct tm time, long int timeZoneGmtOff, std::string timeZoneString)
+ : CellularMessage(MessageType::CellularTimeUpdated), time(time), timeZoneGmtOff(timeZoneGmtOff),
+ timeZoneString(timeZoneString)
+ {}
+
+ explicit CellularTimeNotificationMessage(long int timeZoneGmtOff, std::string timeZoneString)
+ : CellularMessage(MessageType::CellularTimeUpdated), timeZoneGmtOff(timeZoneGmtOff),
+ timeZoneString(timeZoneString)
+ {}
+
explicit CellularTimeNotificationMessage(struct tm time)
: CellularMessage(MessageType::CellularTimeUpdated), time(time)
{}
- struct tm getTime(void)
+
+ std::optional<struct tm> getTime(void)
{
return time;
}
+
+ std::optional<long int> getTimeZoneOffset(void)
+ {
+ return timeZoneGmtOff;
+ }
+
+ std::optional<const std::string> getTimeZoneString(void)
+ {
+ return timeZoneString;
+ }
};
class CellularUSSDMessage : public CellularMessage
{
M module-services/service-db/test/CMakeLists.txt => module-services/service-db/test/CMakeLists.txt +1 -0
@@ 9,4 9,5 @@ add_catch2_executable(
test-service-db-settings-api.cpp
LIBS
module-services
+ module-utils
)
M module-services/service-evtmgr/EventManager.cpp => module-services/service-evtmgr/EventManager.cpp +20 -3
@@ 41,6 41,7 @@
#include "service-audio/messages/AudioMessage.hpp" // for AudioEventRequest
#include "service-evtmgr/messages/BatteryMessages.hpp" // for BatteryLevelMessage, BatteryPlugMessage
#include "service-evtmgr/messages/KbdMessage.hpp" // for KbdMessage
+#include "module-utils/time/time_conversion.hpp" // for Time Zone handling
EventManager::EventManager(const std::string &name) : sys::Service(name)
{
@@ 57,6 58,17 @@ EventManager::~EventManager()
}
}
+// those static functions and variables will be replaced by Settings API
+static std::string tzSet;
+static void setSettingsTimeZone(const std::string &timeZone)
+{
+ tzSet = timeZone;
+}
+std::string getSettingsTimeZone()
+{
+ return tzSet;
+}
+
// Invoked upon receiving data message
sys::Message_t EventManager::DataReceivedHandler(sys::DataMessage *msgl, sys::ResponseMessage *resp)
{
@@ 211,9 223,14 @@ sys::Message_t EventManager::DataReceivedHandler(sys::DataMessage *msgl, sys::Re
else if (msgl->messageType == MessageType::CellularTimeUpdated) {
auto msg = dynamic_cast<CellularTimeNotificationMessage *>(msgl);
if (msg != nullptr) {
- auto time = msg->getTime();
- bsp::rtc_SetDateTime(&time);
- LOG_INFO("RTC set by network time.");
+ if (auto time = msg->getTime(); time) {
+ LOG_INFO("RTC set by network time.");
+ bsp::rtc_SetDateTime(&time.value());
+ }
+ if (auto timeZoneOffset = msg->getTimeZoneOffset(); timeZoneOffset) {
+ setSettingsTimeZone(msg->getTimeZoneString().value());
+ utils::time::Time::setTimeZoneOffset(msg->getTimeZoneOffset().value());
+ }
auto notification = std::make_shared<sys::DataMessage>(MessageType::EVMTimeUpdated);
sys::Bus::SendMulticast(notification, sys::BusChannels::ServiceEvtmgrNotifications, this);
}
M module-utils/Utils.hpp => module-utils/Utils.hpp +2 -4
@@ 169,18 169,16 @@ namespace utils
findAndReplaceAll(data, {{toSearch, replaceStr}});
}
- static inline bool toNumeric(const std::string &text, uint32_t &value)
+ static inline bool toNumeric(const std::string &text, int &value)
{
try {
value = std::stoi(text);
- return true;
}
catch (const std::exception &e) {
LOG_ERROR("toNumeric exception %s", e.what());
return false;
}
-
- return false;
+ return true;
}
static inline uint32_t swapBytes(uint32_t toSwap)
M module-utils/test/unittest_utils.cpp => module-utils/test/unittest_utils.cpp +1 -1
@@ 71,7 71,7 @@ TEST_CASE("Split tests")
TEST_CASE("toNumeric tests")
{
std::string inputStr1 = "2";
- uint32_t value;
+ int value;
auto ret = utils::toNumeric(inputStr1, value);
REQUIRE(ret == true);
M module-utils/time/time_conversion.cpp => module-utils/time/time_conversion.cpp +21 -0
@@ 25,6 25,7 @@ namespace utils
{
Locale tlocale;
+ static int msTimeGmtOff = 4 * utils::time::minutesInQuarterOfHour * utils::time::secondsInMinute;
UTF8 Localer::get_replacement(Replacements val, const struct tm &timeinfo)
{
@@ 48,6 49,16 @@ namespace utils
return retval;
}
+ Timestamp::Timestamp()
+ {
+ auto err = bsp::rtc_GetCurrentTimestamp(&time);
+ auto curTime = time + utils::time::Time::getTimeZoneOffset();
+ if (err) {
+ LOG_ERROR("rtc_GetCurrentTimestamp failure!");
+ }
+ timeinfo = *localtime(&curTime);
+ }
+
void Timestamp::set_time(time_t newtime)
{
time = newtime;
@@ 225,6 236,16 @@ namespace utils
}
}
+ void Time::setTimeZoneOffset(int tzOffset)
+ {
+ msTimeGmtOff = tzOffset;
+ }
+
+ int Time::getTimeZoneOffset()
+ {
+ return msTimeGmtOff;
+ };
+
Duration::Duration(time_t duration) : duration(duration)
{
calculate();
M module-utils/time/time_conversion.hpp => module-utils/time/time_conversion.hpp +10 -11
@@ 16,9 16,10 @@ namespace utils
{
namespace time
{
- constexpr auto secondsInMinute = 60;
- constexpr auto minutesInHour = 60;
- constexpr auto hoursInday = 24;
+ constexpr auto secondsInMinute = 60;
+ constexpr auto minutesInHour = 60;
+ constexpr auto hoursInday = 24;
+ constexpr auto minutesInQuarterOfHour = 15;
constexpr auto secondsInHour = minutesInHour * secondsInMinute;
constexpr auto secondsInDay = hoursInday * secondsInHour;
constexpr auto milisecondsInSecond = 1000;
@@ 70,14 71,7 @@ namespace utils
}
public:
- Timestamp()
- {
- auto err = bsp::rtc_GetCurrentTimestamp(&time);
- if (err) {
- LOG_ERROR("rtc_GetCurrentTimestamp failure!");
- }
- timeinfo = *localtime(&time);
- }
+ Timestamp();
Timestamp(time_t newtime) : time(newtime)
{
timeinfo = *localtime(&time);
@@ 195,6 189,11 @@ namespace utils
public:
Time(time_t val = 0, bool date_format_long = true) : DateTime(val, date_format_long){};
virtual UTF8 str(std::string format = "") final;
+
+ /// set time zone offset including adjustment for daylight saving
+ static void setTimeZoneOffset(int tzOffset);
+ // get time zone offset including adjustment for daylight saving
+ static int getTimeZoneOffset();
};
class Duration