Browse Source

rpn: update to support 64bit time_t

- specialize ntp functions to split time_t into 32bit ints when time_t is larger than rpn_int
- rework 'tick' variable into an operator that can be triggered once
- make sure operators expect new time_t split via argc of 2
mcspr-patch-1
Maxim Prokhorov 3 years ago
parent
commit
14da395724
1 changed files with 128 additions and 36 deletions
  1. +128
    -36
      code/espurna/rpnrules.cpp

+ 128
- 36
code/espurna/rpnrules.cpp View File

@ -24,6 +24,7 @@ Copyright (C) 2019 by Xose Pérez <xose dot perez at gmail dot com>
#include "ws.h"
#include <list>
#include <type_traits>
#include <vector>
// -----------------------------------------------------------------------------
@ -170,23 +171,110 @@ void _rpnBrokerStatus(const String& topic, unsigned char id, unsigned int value)
#if NTP_SUPPORT
rpn_error _rpnNtpNow(rpn_context & ctxt) {
if (!ntpSynced()) return rpn_operator_error::CannotContinue;
rpn_value ts { static_cast<rpn_int>(now()) };
rpn_stack_push(ctxt, ts);
return 0;
}
namespace {
constexpr bool time_t_is_32bit { sizeof(time_t) == 4 };
constexpr bool time_t_is_64bit { sizeof(time_t) == 8 };
static_assert(time_t_is_32bit || time_t_is_64bit, "");
template <typename T>
using split_t = std::integral_constant<bool, sizeof(T) == 8>;
rpn_error _rpnNtpFunc(rpn_context & ctxt, rpn_int (*func)(time_t)) {
rpn_value value;
rpn_stack_pop(ctxt, value);
using RpnNtpFunc = rpn_int(*)(time_t);
value = rpn_value(func(value.toInt()));
rpn_error _rpnNtpPopTimestampPair(rpn_context& ctxt, RpnNtpFunc func) {
rpn_value rhs = rpn_stack_pop(ctxt);
rpn_value lhs = rpn_stack_pop(ctxt);
auto timestamp = (static_cast<long long>(lhs.toInt()) << 32ll)
| (static_cast<long long>(rhs.toInt()));
rpn_value value(func(timestamp));
rpn_stack_push(ctxt, value);
return 0;
}
rpn_error _rpnNtpPopTimestampSingle(rpn_context& ctxt, RpnNtpFunc func) {
rpn_value input = rpn_stack_pop(ctxt);
rpn_value result(func(input.toInt()));
rpn_stack_push(ctxt, result);
return 0;
}
void _rpnNtpPushTimestampPair(rpn_context& ctxt, time_t timestamp) {
rpn_value lhs(static_cast<rpn_int>((static_cast<long long>(timestamp) >> 32ll) & 0xffffffffll));
rpn_value rhs(static_cast<rpn_int>(static_cast<long long>(timestamp) & 0xffffffffll));
rpn_stack_push(ctxt, lhs);
rpn_stack_push(ctxt, rhs);
}
void _rpnNtpPushTimestampSingle(rpn_context& ctxt, time_t timestamp) {
rpn_value result(static_cast<rpn_int>(timestamp));
rpn_stack_push(ctxt, result);
}
inline rpn_error _rpnNtpPopTimestamp(const std::true_type&, rpn_context& ctxt, RpnNtpFunc func) {
return _rpnNtpPopTimestampPair(ctxt, func);
}
inline rpn_error _rpnNtpPopTimestamp(const std::false_type&, rpn_context& ctxt, RpnNtpFunc func) {
return _rpnNtpPopTimestampSingle(ctxt, func);
}
rpn_error _rpnNtpPopTimestamp(rpn_context& ctxt, RpnNtpFunc func) {
return _rpnNtpPopTimestamp(split_t<time_t>{}, ctxt, func);
}
inline void _rpnNtpPushTimestamp(const std::true_type&, rpn_context& ctxt, time_t timestamp) {
_rpnNtpPushTimestampPair(ctxt, timestamp);
}
inline void _rpnNtpPushTimestamp(const std::false_type&, rpn_context& ctxt, time_t timestamp) {
_rpnNtpPushTimestampSingle(ctxt, timestamp);
}
void _rpnNtpPushTimestamp(rpn_context& ctxt, time_t timestamp) {
_rpnNtpPushTimestamp(split_t<time_t>{}, ctxt, timestamp);
}
rpn_error _rpnNtpNow(rpn_context & ctxt) {
if (ntpSynced()) {
_rpnNtpPushTimestamp(ctxt, now());
return 0;
}
return rpn_operator_error::CannotContinue;
}
rpn_error _rpnNtpFunc(rpn_context & ctxt, RpnNtpFunc func) {
return _rpnNtpPopTimestamp(ctxt, func);
}
bool _rpn_ntp_tick_minute { false };
bool _rpn_ntp_tick_hour { false };
rpn_error _rpnNtpTickMinute(rpn_context& ctxt) {
if (_rpn_ntp_tick_minute) {
_rpn_ntp_tick_minute = false;
return 0;
}
return rpn_operator_error::CannotContinue;
}
rpn_error _rpnNtpTickHour(rpn_context& ctxt) {
if (_rpn_ntp_tick_hour) {
_rpn_ntp_tick_hour = false;
return 0;
}
return rpn_operator_error::CannotContinue;
}
} // namespace
#endif // NTP_SUPPORT
String _rpnValueToString(const rpn_value& value) {
@ -476,43 +564,50 @@ void _rpnInit() {
// TODO: since 1.15.0, timelib+ntpclientlib are no longer used with latest Cores
// `now` is always in UTC, `utc_...` functions to be used instead to convert time
#if NTP_SUPPORT && !NTP_LEGACY_SUPPORT
{
constexpr size_t time_t_argc { split_t<time_t>{} ? 2 : 1 };
rpn_operator_set(_rpn_ctxt, "tick_1h", 0, _rpnNtpTickHour);
rpn_operator_set(_rpn_ctxt, "tick_1m", 0, _rpnNtpTickMinute);
rpn_operator_set(_rpn_ctxt, "utc", 0, _rpnNtpNow);
rpn_operator_set(_rpn_ctxt, "now", 0, _rpnNtpNow);
rpn_operator_set(_rpn_ctxt, "utc_month", 1, [](rpn_context & ctxt) {
rpn_operator_set(_rpn_ctxt, "utc_month", time_t_argc, [](rpn_context & ctxt) {
return _rpnNtpFunc(ctxt, utc_month);
});
rpn_operator_set(_rpn_ctxt, "month", 1, [](rpn_context & ctxt) {
rpn_operator_set(_rpn_ctxt, "month", time_t_argc, [](rpn_context & ctxt) {
return _rpnNtpFunc(ctxt, month);
});
rpn_operator_set(_rpn_ctxt, "utc_day", 1, [](rpn_context & ctxt) {
rpn_operator_set(_rpn_ctxt, "utc_day", time_t_argc, [](rpn_context & ctxt) {
return _rpnNtpFunc(ctxt, utc_day);
});
rpn_operator_set(_rpn_ctxt, "day", 1, [](rpn_context & ctxt) {
rpn_operator_set(_rpn_ctxt, "day", time_t_argc, [](rpn_context & ctxt) {
return _rpnNtpFunc(ctxt, day);
});
rpn_operator_set(_rpn_ctxt, "utc_dow", 1, [](rpn_context & ctxt) {
rpn_operator_set(_rpn_ctxt, "utc_dow", time_t_argc, [](rpn_context & ctxt) {
return _rpnNtpFunc(ctxt, utc_weekday);
});
rpn_operator_set(_rpn_ctxt, "dow", 1, [](rpn_context & ctxt) {
rpn_operator_set(_rpn_ctxt, "dow", time_t_argc, [](rpn_context & ctxt) {
return _rpnNtpFunc(ctxt, weekday);
});
rpn_operator_set(_rpn_ctxt, "utc_hour", 1, [](rpn_context & ctxt) {
rpn_operator_set(_rpn_ctxt, "utc_hour", time_t_argc, [](rpn_context & ctxt) {
return _rpnNtpFunc(ctxt, utc_hour);
});
rpn_operator_set(_rpn_ctxt, "hour", 1, [](rpn_context & ctxt) {
rpn_operator_set(_rpn_ctxt, "hour", time_t_argc, [](rpn_context & ctxt) {
return _rpnNtpFunc(ctxt, hour);
});
rpn_operator_set(_rpn_ctxt, "utc_minute", 1, [](rpn_context & ctxt) {
rpn_operator_set(_rpn_ctxt, "utc_minute", time_t_argc, [](rpn_context & ctxt) {
return _rpnNtpFunc(ctxt, utc_minute);
});
rpn_operator_set(_rpn_ctxt, "minute", 1, [](rpn_context & ctxt) {
rpn_operator_set(_rpn_ctxt, "minute", time_t_argc, [](rpn_context & ctxt) {
return _rpnNtpFunc(ctxt, minute);
});
}
#endif
// TODO: 1.14.0 weekday(...) conversion seemed to have 0..6 range with Monday as 0
@ -896,22 +991,19 @@ void rpnSetup() {
mqttRegister(_rpnMQTTCallback);
#endif
#if NTP_SUPPORT
NtpBroker::Register([](NtpTick tick, time_t timestamp, const String& datetime) {
static const String tick_every_hour(F("tick1h"));
static const String tick_every_minute(F("tick1m"));
const char* ptr =
(tick == NtpTick::EveryMinute) ? tick_every_minute.c_str() :
(tick == NtpTick::EveryHour) ? tick_every_hour.c_str() : nullptr;
if (ptr != nullptr) {
rpn_value value { static_cast<rpn_int>(timestamp) };
rpn_variable_set(_rpn_ctxt, ptr, value);
_rpn_run = true;
}
});
#endif
#if NTP_SUPPORT
NtpBroker::Register([](NtpTick tick, time_t, const String&) {
switch (tick) {
case NtpTick::EveryMinute:
_rpn_ntp_tick_minute = true;
break;
case NtpTick::EveryHour:
_rpn_ntp_tick_hour = true;
break;
}
_rpn_run = true;
});
#endif
StatusBroker::Register(_rpnBrokerStatus);


Loading…
Cancel
Save