FuriHalRtc refactor: new datetime lib (#3386)

* datetimelib created
* datetimelib unit tests added
* firmware fixes to new datetimelib
* typo fix
* merge artifacts fixed, datetimelib renamed to datetime

Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
Leptopt1los 2024-02-15 12:44:41 +09:00 committed by GitHub
parent dd988ba449
commit feb45f6645
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
28 changed files with 456 additions and 275 deletions

View file

@ -30,7 +30,7 @@ static void locale_test_view_draw_callback(Canvas* canvas, void* _model) {
} }
canvas_draw_str(canvas, 0, 10, furi_string_get_cstr(tmp_string)); canvas_draw_str(canvas, 0, 10, furi_string_get_cstr(tmp_string));
FuriHalRtcDateTime datetime; DateTime datetime;
furi_hal_rtc_get_datetime(&datetime); furi_hal_rtc_get_datetime(&datetime);
locale_format_time(tmp_string, &datetime, locale_get_time_format(), false); locale_format_time(tmp_string, &datetime, locale_get_time_format(), false);

View file

@ -0,0 +1,175 @@
#include <furi.h>
#include "../minunit.h"
#include <datetime/datetime.h>
MU_TEST(test_datetime_validate_datetime_correct_min) {
DateTime correct_min = {0, 0, 0, 1, 1, 2000, 1};
bool result = datetime_validate_datetime(&correct_min);
mu_assert_int_eq(true, result);
}
MU_TEST(test_datetime_validate_datetime_correct_max) {
DateTime correct_max = {23, 59, 59, 31, 12, 2099, 7};
bool result = datetime_validate_datetime(&correct_max);
mu_assert_int_eq(true, result);
}
MU_TEST(test_datetime_validate_datetime_incorrect_second) {
DateTime incorrect_sec = {0, 0, 60, 1, 1, 2000, 1};
bool result = datetime_validate_datetime(&incorrect_sec);
mu_assert_int_eq(false, result);
}
MU_TEST(test_datetime_validate_datetime_incorrect_minute) {
DateTime incorrect_min = {0, 60, 0, 1, 1, 2000, 1};
bool result = datetime_validate_datetime(&incorrect_min);
mu_assert_int_eq(false, result);
}
MU_TEST(test_datetime_validate_datetime_incorrect_hour) {
DateTime incorrect_hour = {24, 0, 0, 1, 1, 2000, 1};
bool result = datetime_validate_datetime(&incorrect_hour);
mu_assert_int_eq(false, result);
}
MU_TEST(test_datetime_validate_datetime_incorrect_day_min) {
DateTime incorrect_day_min = {0, 0, 0, 0, 1, 2000, 1};
bool result = datetime_validate_datetime(&incorrect_day_min);
mu_assert_int_eq(false, result);
}
MU_TEST(test_datetime_validate_datetime_incorrect_day_max) {
DateTime incorrect_day_max = {0, 0, 0, 32, 1, 2000, 1};
bool result = datetime_validate_datetime(&incorrect_day_max);
mu_assert_int_eq(false, result);
}
MU_TEST(test_datetime_validate_datetime_incorrect_month_min) {
DateTime incorrect_month_min = {0, 0, 0, 1, 0, 2000, 1};
bool result = datetime_validate_datetime(&incorrect_month_min);
mu_assert_int_eq(false, result);
}
MU_TEST(test_datetime_validate_datetime_incorrect_month_max) {
DateTime incorrect_month_max = {0, 0, 0, 1, 13, 2000, 1};
bool result = datetime_validate_datetime(&incorrect_month_max);
mu_assert_int_eq(false, result);
}
MU_TEST(test_datetime_validate_datetime_incorrect_year_min) {
DateTime incorrect_year_min = {0, 0, 0, 1, 1, 1999, 1};
bool result = datetime_validate_datetime(&incorrect_year_min);
mu_assert_int_eq(false, result);
}
MU_TEST(test_datetime_validate_datetime_incorrect_year_max) {
DateTime incorrect_year_max = {0, 0, 0, 1, 1, 2100, 1};
bool result = datetime_validate_datetime(&incorrect_year_max);
mu_assert_int_eq(false, result);
}
MU_TEST(test_datetime_validate_datetime_incorrect_weekday_min) {
DateTime incorrect_weekday_min = {0, 0, 0, 1, 1, 2000, 0};
bool result = datetime_validate_datetime(&incorrect_weekday_min);
mu_assert_int_eq(false, result);
}
MU_TEST(test_datetime_validate_datetime_incorrect_weekday_max) {
DateTime incorrect_weekday_max = {0, 0, 0, 1, 1, 2000, 8};
bool result = datetime_validate_datetime(&incorrect_weekday_max);
mu_assert_int_eq(false, result);
}
MU_TEST_SUITE(test_datetime_validate_datetime) {
MU_RUN_TEST(test_datetime_validate_datetime_correct_min);
MU_RUN_TEST(test_datetime_validate_datetime_correct_max);
MU_RUN_TEST(test_datetime_validate_datetime_incorrect_second);
MU_RUN_TEST(test_datetime_validate_datetime_incorrect_minute);
MU_RUN_TEST(test_datetime_validate_datetime_incorrect_hour);
MU_RUN_TEST(test_datetime_validate_datetime_incorrect_day_min);
MU_RUN_TEST(test_datetime_validate_datetime_incorrect_day_max);
MU_RUN_TEST(test_datetime_validate_datetime_incorrect_month_min);
MU_RUN_TEST(test_datetime_validate_datetime_incorrect_month_max);
MU_RUN_TEST(test_datetime_validate_datetime_incorrect_year_min);
MU_RUN_TEST(test_datetime_validate_datetime_incorrect_year_max);
MU_RUN_TEST(test_datetime_validate_datetime_incorrect_weekday_min);
MU_RUN_TEST(test_datetime_validate_datetime_incorrect_weekday_max);
}
MU_TEST(test_datetime_timestamp_to_datetime_min) {
uint32_t test_value = 0;
DateTime min_datetime_expected = {0, 0, 0, 1, 1, 1970, 0};
DateTime result = {0};
datetime_timestamp_to_datetime(test_value, &result);
mu_assert_mem_eq(&min_datetime_expected, &result, sizeof(result));
}
MU_TEST(test_datetime_timestamp_to_datetime_max) {
uint32_t test_value = UINT32_MAX;
DateTime max_datetime_expected = {6, 28, 15, 7, 2, 2106, 0};
DateTime result = {0};
datetime_timestamp_to_datetime(test_value, &result);
mu_assert_mem_eq(&max_datetime_expected, &result, sizeof(result));
}
MU_TEST(test_datetime_timestamp_to_datetime_to_timestamp) {
uint32_t test_value = random();
DateTime datetime = {0};
datetime_timestamp_to_datetime(test_value, &datetime);
uint32_t result = datetime_datetime_to_timestamp(&datetime);
mu_assert_int_eq(test_value, result);
}
MU_TEST_SUITE(test_datetime_timestamp_to_datetime_suite) {
MU_RUN_TEST(test_datetime_timestamp_to_datetime_min);
MU_RUN_TEST(test_datetime_timestamp_to_datetime_max);
MU_RUN_TEST(test_datetime_timestamp_to_datetime_to_timestamp);
}
MU_TEST(test_datetime_datetime_to_timestamp_min) {
DateTime min_datetime = {0, 0, 0, 1, 1, 1970, 0};
uint32_t result = datetime_datetime_to_timestamp(&min_datetime);
mu_assert_int_eq(0, result);
}
MU_TEST(test_datetime_datetime_to_timestamp_max) {
DateTime max_datetime = {6, 28, 15, 7, 2, 2106, 0};
uint32_t result = datetime_datetime_to_timestamp(&max_datetime);
mu_assert_int_eq(UINT32_MAX, result);
}
MU_TEST_SUITE(test_datetime_datetime_to_timestamp_suite) {
MU_RUN_TEST(test_datetime_datetime_to_timestamp_min);
MU_RUN_TEST(test_datetime_datetime_to_timestamp_max);
}
int run_minunit_test_datetime() {
MU_RUN_SUITE(test_datetime_timestamp_to_datetime_suite);
MU_RUN_SUITE(test_datetime_datetime_to_timestamp_suite);
MU_RUN_SUITE(test_datetime_validate_datetime);
return MU_EXIT_CODE;
}

View file

@ -214,37 +214,6 @@ MU_TEST(furi_hal_i2c_ext_eeprom) {
} }
} }
MU_TEST(furi_hal_rtc_timestamp2datetime_min) {
uint32_t test_value = 0;
FuriHalRtcDateTime min_datetime_expected = {0, 0, 0, 1, 1, 1970, 0};
FuriHalRtcDateTime result = {0};
furi_hal_rtc_timestamp_to_datetime(test_value, &result);
mu_assert_mem_eq(&min_datetime_expected, &result, sizeof(result));
}
MU_TEST(furi_hal_rtc_timestamp2datetime_max) {
uint32_t test_value = UINT32_MAX;
FuriHalRtcDateTime max_datetime_expected = {6, 28, 15, 7, 2, 2106, 0};
FuriHalRtcDateTime result = {0};
furi_hal_rtc_timestamp_to_datetime(test_value, &result);
mu_assert_mem_eq(&max_datetime_expected, &result, sizeof(result));
}
MU_TEST(furi_hal_rtc_timestamp2datetime2timestamp) {
uint32_t test_value = random();
FuriHalRtcDateTime datetime = {0};
furi_hal_rtc_timestamp_to_datetime(test_value, &datetime);
uint32_t result = furi_hal_rtc_datetime_to_timestamp(&datetime);
mu_assert_int_eq(test_value, result);
}
MU_TEST_SUITE(furi_hal_i2c_int_suite) { MU_TEST_SUITE(furi_hal_i2c_int_suite) {
MU_SUITE_CONFIGURE(&furi_hal_i2c_int_setup, &furi_hal_i2c_int_teardown); MU_SUITE_CONFIGURE(&furi_hal_i2c_int_setup, &furi_hal_i2c_int_teardown);
MU_RUN_TEST(furi_hal_i2c_int_1b); MU_RUN_TEST(furi_hal_i2c_int_1b);
@ -258,15 +227,8 @@ MU_TEST_SUITE(furi_hal_i2c_ext_suite) {
MU_RUN_TEST(furi_hal_i2c_ext_eeprom); MU_RUN_TEST(furi_hal_i2c_ext_eeprom);
} }
MU_TEST_SUITE(furi_hal_rtc_datetime_suite) {
MU_RUN_TEST(furi_hal_rtc_timestamp2datetime_min);
MU_RUN_TEST(furi_hal_rtc_timestamp2datetime_max);
MU_RUN_TEST(furi_hal_rtc_timestamp2datetime2timestamp);
}
int run_minunit_test_furi_hal() { int run_minunit_test_furi_hal() {
MU_RUN_SUITE(furi_hal_i2c_int_suite); MU_RUN_SUITE(furi_hal_i2c_int_suite);
MU_RUN_SUITE(furi_hal_i2c_ext_suite); MU_RUN_SUITE(furi_hal_i2c_ext_suite);
MU_RUN_SUITE(furi_hal_rtc_datetime_suite);
return MU_EXIT_CODE; return MU_EXIT_CODE;
} }

View file

@ -26,6 +26,7 @@ int run_minunit_test_protocol_dict();
int run_minunit_test_lfrfid_protocols(); int run_minunit_test_lfrfid_protocols();
int run_minunit_test_nfc(); int run_minunit_test_nfc();
int run_minunit_test_bit_lib(); int run_minunit_test_bit_lib();
int run_minunit_test_datetime();
int run_minunit_test_float_tools(); int run_minunit_test_float_tools();
int run_minunit_test_bt(); int run_minunit_test_bt();
int run_minunit_test_dialogs_file_browser_options(); int run_minunit_test_dialogs_file_browser_options();
@ -57,6 +58,7 @@ const UnitTest unit_tests[] = {
{.name = "protocol_dict", .entry = run_minunit_test_protocol_dict}, {.name = "protocol_dict", .entry = run_minunit_test_protocol_dict},
{.name = "lfrfid", .entry = run_minunit_test_lfrfid_protocols}, {.name = "lfrfid", .entry = run_minunit_test_lfrfid_protocols},
{.name = "bit_lib", .entry = run_minunit_test_bit_lib}, {.name = "bit_lib", .entry = run_minunit_test_bit_lib},
{.name = "datetime", .entry = run_minunit_test_datetime},
{.name = "float_tools", .entry = run_minunit_test_float_tools}, {.name = "float_tools", .entry = run_minunit_test_float_tools},
{.name = "bt", .entry = run_minunit_test_bt}, {.name = "bt", .entry = run_minunit_test_bt},
{.name = "dialogs_file_browser_options", {.name = "dialogs_file_browser_options",

View file

@ -24,7 +24,7 @@
#include <lib/nfc/protocols/mf_desfire/mf_desfire.h> #include <lib/nfc/protocols/mf_desfire/mf_desfire.h>
#include <bit_lib/bit_lib.h> #include <bit_lib/bit_lib.h>
#include <applications/services/locale/locale.h> #include <applications/services/locale/locale.h>
#include <furi_hal_rtc.h> #include <datetime/datetime.h>
#include <inttypes.h> #include <inttypes.h>
// //
@ -172,7 +172,7 @@ static void furi_string_cat_timestamp(
const char* date_hdr, const char* date_hdr,
const char* time_hdr, const char* time_hdr,
uint32_t tmst_1900); uint32_t tmst_1900);
static void epoch_1900_datetime_to_furi(uint32_t seconds, FuriHalRtcDateTime* out); static void epoch_1900_datetime_to_furi(uint32_t seconds, DateTime* out);
static bool get_file_contents( static bool get_file_contents(
const MfDesfireApplication* app, const MfDesfireApplication* app,
const MfDesfireFileId* id, const MfDesfireFileId* id,
@ -527,7 +527,7 @@ static void furi_string_cat_timestamp(
const char* date_hdr, const char* date_hdr,
const char* time_hdr, const char* time_hdr,
uint32_t tmst_1900) { uint32_t tmst_1900) {
FuriHalRtcDateTime tm; DateTime tm;
epoch_1900_datetime_to_furi(tmst_1900, &tm); epoch_1900_datetime_to_furi(tmst_1900, &tm);
@ -550,7 +550,7 @@ static void furi_string_cat_timestamp(
} }
// Convert a "1900"-based timestamp to Furi time, assuming a UTC/GMT timezone. // Convert a "1900"-based timestamp to Furi time, assuming a UTC/GMT timezone.
static void epoch_1900_datetime_to_furi(uint32_t seconds, FuriHalRtcDateTime* out) { static void epoch_1900_datetime_to_furi(uint32_t seconds, DateTime* out) {
uint16_t year, month, day, hour, minute, second; uint16_t year, month, day, hour, minute, second;
// Calculate absolute number of days elapsed since the 1900 epoch // Calculate absolute number of days elapsed since the 1900 epoch
@ -568,17 +568,17 @@ static void epoch_1900_datetime_to_furi(uint32_t seconds, FuriHalRtcDateTime* ou
// //
for(year = 1900;; year++) { for(year = 1900;; year++) {
uint16_t year_days = furi_hal_rtc_get_days_per_year(year); uint16_t year_days = datetime_get_days_per_year(year);
if(absolute_days >= year_days) if(absolute_days >= year_days)
absolute_days -= year_days; absolute_days -= year_days;
else else
break; break;
} }
bool is_leap = furi_hal_rtc_is_leap_year(year); bool is_leap = datetime_is_leap_year(year);
for(month = 1;; month++) { for(month = 1;; month++) {
uint8_t days_in_month = furi_hal_rtc_get_days_per_month(is_leap, month); uint8_t days_in_month = datetime_get_days_per_month(is_leap, month);
if(absolute_days >= days_in_month) if(absolute_days >= days_in_month)
absolute_days -= days_in_month; absolute_days -= days_in_month;
else else

View file

@ -5,7 +5,7 @@
#include <lib/nfc/protocols/mf_desfire/mf_desfire.h> #include <lib/nfc/protocols/mf_desfire/mf_desfire.h>
#include <applications/services/locale/locale.h> #include <applications/services/locale/locale.h>
#include <furi_hal_rtc.h> #include <datetime/datetime.h>
static const MfDesfireApplicationId itso_app_id = {.data = {0x16, 0x02, 0xa0}}; static const MfDesfireApplicationId itso_app_id = {.data = {0x16, 0x02, 0xa0}};
static const MfDesfireFileId itso_file_id = 0x0f; static const MfDesfireFileId itso_file_id = 0x0f;
@ -87,8 +87,8 @@ static bool itso_parse(const NfcDevice* device, FuriString* parsed_data) {
furi_string_push_back(parsed_data, ' '); furi_string_push_back(parsed_data, ' ');
} }
FuriHalRtcDateTime timestamp = {0}; DateTime timestamp = {0};
furi_hal_rtc_timestamp_to_datetime(unixTimestamp, &timestamp); datetime_timestamp_to_datetime(unixTimestamp, &timestamp);
FuriString* timestamp_str = furi_string_alloc(); FuriString* timestamp_str = furi_string_alloc();
locale_format_date(timestamp_str, &timestamp, locale_get_date_format(), "-"); locale_format_date(timestamp_str, &timestamp, locale_get_date_format(), "-");

View file

@ -32,7 +32,7 @@
#include <flipper_application/flipper_application.h> #include <flipper_application/flipper_application.h>
#include <applications/services/locale/locale.h> #include <applications/services/locale/locale.h>
#include <furi_hal_rtc.h> #include <datetime/datetime.h>
#include <lib/nfc/protocols/mf_desfire/mf_desfire.h> #include <lib/nfc/protocols/mf_desfire/mf_desfire.h>
@ -78,11 +78,11 @@ typedef struct __attribute__((__packed__)) {
static_assert(sizeof(OpalFile) == 16, "OpalFile"); static_assert(sizeof(OpalFile) == 16, "OpalFile");
// Converts an Opal timestamp to FuriHalRtcDateTime. // Converts an Opal timestamp to DateTime.
// //
// Opal measures days since 1980-01-01 and minutes since midnight, and presumes // Opal measures days since 1980-01-01 and minutes since midnight, and presumes
// all days are 1440 minutes. // all days are 1440 minutes.
static void opal_date_time_to_furi(uint16_t days, uint16_t minutes, FuriHalRtcDateTime* out) { static void opal_date_time_to_furi(uint16_t days, uint16_t minutes, DateTime* out) {
out->year = 1980; out->year = 1980;
out->month = 1; out->month = 1;
// 1980-01-01 is a Tuesday // 1980-01-01 is a Tuesday
@ -93,7 +93,7 @@ static void opal_date_time_to_furi(uint16_t days, uint16_t minutes, FuriHalRtcDa
// What year is it? // What year is it?
for(;;) { for(;;) {
const uint16_t num_days_in_year = furi_hal_rtc_get_days_per_year(out->year); const uint16_t num_days_in_year = datetime_get_days_per_year(out->year);
if(days < num_days_in_year) break; if(days < num_days_in_year) break;
days -= num_days_in_year; days -= num_days_in_year;
out->year++; out->year++;
@ -104,8 +104,8 @@ static void opal_date_time_to_furi(uint16_t days, uint16_t minutes, FuriHalRtcDa
for(;;) { for(;;) {
// What month is it? // What month is it?
const bool is_leap = furi_hal_rtc_is_leap_year(out->year); const bool is_leap = datetime_is_leap_year(out->year);
const uint8_t num_days_in_month = furi_hal_rtc_get_days_per_month(is_leap, out->month); const uint8_t num_days_in_month = datetime_get_days_per_month(is_leap, out->month);
if(days <= num_days_in_month) break; if(days <= num_days_in_month) break;
days -= num_days_in_month; days -= num_days_in_month;
out->month++; out->month++;
@ -154,7 +154,7 @@ static bool opal_parse(const NfcDevice* device, FuriString* parsed_data) {
const uint8_t balance_cents = balance % 100; const uint8_t balance_cents = balance % 100;
const int32_t balance_dollars = balance / 100; const int32_t balance_dollars = balance / 100;
FuriHalRtcDateTime timestamp; DateTime timestamp;
opal_date_time_to_furi(opal_file->days, opal_file->minutes, &timestamp); opal_date_time_to_furi(opal_file->days, opal_file->minutes, &timestamp);
// Usages 4..6 associated with the Manly Ferry, which correspond to // Usages 4..6 associated with the Manly Ferry, which correspond to

View file

@ -33,11 +33,11 @@
#include <bit_lib/bit_lib.h> #include <bit_lib/bit_lib.h>
#include <nfc/protocols/mf_classic/mf_classic_poller_sync.h> #include <nfc/protocols/mf_classic/mf_classic_poller_sync.h>
#include <furi_hal_rtc.h> #include <datetime/datetime.h>
#define TAG "Umarsh" #define TAG "Umarsh"
bool parse_datetime(uint16_t date, FuriHalRtcDateTime* result) { bool parse_datetime(uint16_t date, DateTime* result) {
result->year = 2000 + (date >> 9); result->year = 2000 + (date >> 9);
result->month = date >> 5 & 0x0F; result->month = date >> 5 & 0x0F;
result->day = date & 0x1F; result->day = date & 0x1F;
@ -85,13 +85,13 @@ static bool umarsh_parse(const NfcDevice* device, FuriString* parsed_data) {
const uint16_t balance_rub = (bit_lib_bytes_to_num_be(block_start_ptr + 8, 2)) & 0x7FFF; const uint16_t balance_rub = (bit_lib_bytes_to_num_be(block_start_ptr + 8, 2)) & 0x7FFF;
const uint8_t balance_kop = bit_lib_bytes_to_num_be(block_start_ptr + 10, 1) & 0x7F; const uint8_t balance_kop = bit_lib_bytes_to_num_be(block_start_ptr + 10, 1) & 0x7F;
FuriHalRtcDateTime expiry_datetime; DateTime expiry_datetime;
bool is_expiry_datetime_valid = parse_datetime(expiry_date, &expiry_datetime); bool is_expiry_datetime_valid = parse_datetime(expiry_date, &expiry_datetime);
FuriHalRtcDateTime valid_to_datetime; DateTime valid_to_datetime;
bool is_valid_to_datetime_valid = parse_datetime(valid_to, &valid_to_datetime); bool is_valid_to_datetime_valid = parse_datetime(valid_to, &valid_to_datetime);
FuriHalRtcDateTime last_refill_datetime; DateTime last_refill_datetime;
bool is_last_refill_datetime_valid = bool is_last_refill_datetime_valid =
parse_datetime(last_refill_date, &last_refill_datetime); parse_datetime(last_refill_date, &last_refill_datetime);

View file

@ -15,7 +15,7 @@ void subghz_scene_save_name_text_input_callback(void* context) {
} }
void subghz_scene_save_name_get_timefilename(FuriString* name) { void subghz_scene_save_name_get_timefilename(FuriString* name) {
FuriHalRtcDateTime datetime = {0}; DateTime datetime = {0};
furi_hal_rtc_get_datetime(&datetime); furi_hal_rtc_get_datetime(&datetime);
furi_string_printf( furi_string_printf(
name, name,

View file

@ -101,7 +101,7 @@ void cli_command_date(Cli* cli, FuriString* args, void* context) {
UNUSED(cli); UNUSED(cli);
UNUSED(context); UNUSED(context);
FuriHalRtcDateTime datetime = {0}; DateTime datetime = {0};
if(furi_string_size(args) > 0) { if(furi_string_size(args) > 0) {
uint16_t hours, minutes, seconds, month, day, year, weekday; uint16_t hours, minutes, seconds, month, day, year, weekday;
@ -135,7 +135,7 @@ void cli_command_date(Cli* cli, FuriString* args, void* context) {
return; return;
} }
if(!furi_hal_rtc_validate_datetime(&datetime)) { if(!datetime_validate_datetime(&datetime)) {
printf("Invalid datetime data"); printf("Invalid datetime data");
return; return;
} }

View file

@ -53,7 +53,7 @@ static void desktop_dummy_mode_icon_draw_callback(Canvas* canvas, void* context)
static void desktop_clock_update(Desktop* desktop) { static void desktop_clock_update(Desktop* desktop) {
furi_assert(desktop); furi_assert(desktop);
FuriHalRtcDateTime curr_dt; DateTime curr_dt;
furi_hal_rtc_get_datetime(&curr_dt); furi_hal_rtc_get_datetime(&curr_dt);
bool time_format_12 = locale_get_time_format() == LocaleTimeFormat12h; bool time_format_12 = locale_get_time_format() == LocaleTimeFormat12h;

View file

@ -128,7 +128,7 @@ static void dolphin_update_clear_limits_timer_period(Dolphin* dolphin) {
uint32_t timer_expires_at = furi_timer_get_expire_time(dolphin->clear_limits_timer); uint32_t timer_expires_at = furi_timer_get_expire_time(dolphin->clear_limits_timer);
if((timer_expires_at - now_ticks) > HOURS_IN_TICKS(0.1)) { if((timer_expires_at - now_ticks) > HOURS_IN_TICKS(0.1)) {
FuriHalRtcDateTime date; DateTime date;
furi_hal_rtc_get_datetime(&date); furi_hal_rtc_get_datetime(&date);
uint32_t now_time_in_ms = ((date.hour * 60 + date.minute) * 60 + date.second) * 1000; uint32_t now_time_in_ms = ((date.hour * 60 + date.minute) * 60 + date.second) * 1000;
uint32_t time_to_clear_limits = 0; uint32_t time_to_clear_limits = 0;

View file

@ -74,9 +74,9 @@ bool dolphin_state_load(DolphinState* dolphin_state) {
} }
uint64_t dolphin_state_timestamp() { uint64_t dolphin_state_timestamp() {
FuriHalRtcDateTime datetime; DateTime datetime;
furi_hal_rtc_get_datetime(&datetime); furi_hal_rtc_get_datetime(&datetime);
return furi_hal_rtc_datetime_to_timestamp(&datetime); return datetime_datetime_to_timestamp(&datetime);
} }
bool dolphin_state_is_levelup(uint32_t icounter) { bool dolphin_state_is_levelup(uint32_t icounter) {

View file

@ -36,7 +36,7 @@ float locale_celsius_to_fahrenheit(float temp_c) {
void locale_format_time( void locale_format_time(
FuriString* out_str, FuriString* out_str,
const FuriHalRtcDateTime* datetime, const DateTime* datetime,
const LocaleTimeFormat format, const LocaleTimeFormat format,
const bool show_seconds) { const bool show_seconds) {
furi_assert(out_str); furi_assert(out_str);
@ -69,7 +69,7 @@ void locale_format_time(
void locale_format_date( void locale_format_date(
FuriString* out_str, FuriString* out_str,
const FuriHalRtcDateTime* datetime, const DateTime* datetime,
const LocaleDateFormat format, const LocaleDateFormat format,
const char* separator) { const char* separator) {
furi_assert(out_str); furi_assert(out_str);

View file

@ -73,7 +73,7 @@ void locale_set_time_format(LocaleTimeFormat format);
*/ */
void locale_format_time( void locale_format_time(
FuriString* out_str, FuriString* out_str,
const FuriHalRtcDateTime* datetime, const DateTime* datetime,
const LocaleTimeFormat format, const LocaleTimeFormat format,
const bool show_seconds); const bool show_seconds);
@ -98,7 +98,7 @@ void locale_set_date_format(LocaleDateFormat format);
*/ */
void locale_format_date( void locale_format_date(
FuriString* out_str, FuriString* out_str,
const FuriHalRtcDateTime* datetime, const DateTime* datetime,
const LocaleDateFormat format, const LocaleDateFormat format,
const char* separator); const char* separator);

View file

@ -122,7 +122,7 @@ static void rpc_system_system_get_datetime_process(const PB_Main* request, void*
RpcSession* session = (RpcSession*)context; RpcSession* session = (RpcSession*)context;
furi_assert(session); furi_assert(session);
FuriHalRtcDateTime datetime; DateTime datetime;
furi_hal_rtc_get_datetime(&datetime); furi_hal_rtc_get_datetime(&datetime);
PB_Main* response = malloc(sizeof(PB_Main)); PB_Main* response = malloc(sizeof(PB_Main));
@ -157,7 +157,7 @@ static void rpc_system_system_set_datetime_process(const PB_Main* request, void*
return; return;
} }
FuriHalRtcDateTime datetime; DateTime datetime;
datetime.hour = request->content.system_set_datetime_request.datetime.hour; datetime.hour = request->content.system_set_datetime_request.datetime.hour;
datetime.minute = request->content.system_set_datetime_request.datetime.minute; datetime.minute = request->content.system_set_datetime_request.datetime.minute;
datetime.second = request->content.system_set_datetime_request.datetime.second; datetime.second = request->content.system_set_datetime_request.datetime.second;

View file

@ -43,6 +43,7 @@ libs = env.BuildModules(
"update_util", "update_util",
"heatshrink", "heatshrink",
"bit_lib", "bit_lib",
"datetime",
], ],
) )

22
lib/datetime/SConscript Normal file
View file

@ -0,0 +1,22 @@
Import("env")
env.Append(
LINT_SOURCES=[
Dir("."),
],
CPPPATH=[
"#/lib/datetime",
],
SDK_HEADERS=[
File("datetime.h"),
],
)
libenv = env.Clone(FW_LIB_NAME="datetime")
libenv.ApplyLibFlags()
sources = libenv.GlobRecursive("*.c*")
lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources)
libenv.Install("${LIB_DIST_DIR}", lib)
Return("lib")

104
lib/datetime/datetime.c Normal file
View file

@ -0,0 +1,104 @@
#include "datetime.h"
#define TAG "DateTime"
#define SECONDS_PER_MINUTE 60
#define SECONDS_PER_HOUR (SECONDS_PER_MINUTE * 60)
#define SECONDS_PER_DAY (SECONDS_PER_HOUR * 24)
#define MONTHS_COUNT 12
#define EPOCH_START_YEAR 1970
static const uint8_t datetime_days_per_month[2][MONTHS_COUNT] = {
{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}};
static const uint16_t datetime_days_per_year[] = {365, 366};
bool datetime_validate_datetime(DateTime* datetime) {
bool invalid = false;
invalid |= (datetime->second > 59);
invalid |= (datetime->minute > 59);
invalid |= (datetime->hour > 23);
invalid |= (datetime->year < 2000);
invalid |= (datetime->year > 2099);
invalid |= (datetime->month == 0);
invalid |= (datetime->month > 12);
invalid |= (datetime->day == 0);
invalid |= (datetime->day > 31);
invalid |= (datetime->weekday == 0);
invalid |= (datetime->weekday > 7);
return !invalid;
}
uint32_t datetime_datetime_to_timestamp(DateTime* datetime) {
uint32_t timestamp = 0;
uint8_t years = 0;
uint8_t leap_years = 0;
for(uint16_t y = EPOCH_START_YEAR; y < datetime->year; y++) {
if(datetime_is_leap_year(y)) {
leap_years++;
} else {
years++;
}
}
timestamp += ((years * datetime_days_per_year[0]) + (leap_years * datetime_days_per_year[1])) *
SECONDS_PER_DAY;
bool leap_year = datetime_is_leap_year(datetime->year);
for(uint8_t m = 1; m < datetime->month; m++) {
timestamp += datetime_get_days_per_month(leap_year, m) * SECONDS_PER_DAY;
}
timestamp += (datetime->day - 1) * SECONDS_PER_DAY;
timestamp += datetime->hour * SECONDS_PER_HOUR;
timestamp += datetime->minute * SECONDS_PER_MINUTE;
timestamp += datetime->second;
return timestamp;
}
void datetime_timestamp_to_datetime(uint32_t timestamp, DateTime* datetime) {
uint32_t days = timestamp / SECONDS_PER_DAY;
uint32_t seconds_in_day = timestamp % SECONDS_PER_DAY;
datetime->year = EPOCH_START_YEAR;
while(days >= datetime_get_days_per_year(datetime->year)) {
days -= datetime_get_days_per_year(datetime->year);
(datetime->year)++;
}
datetime->month = 1;
while(days >=
datetime_get_days_per_month(datetime_is_leap_year(datetime->year), datetime->month)) {
days -=
datetime_get_days_per_month(datetime_is_leap_year(datetime->year), datetime->month);
(datetime->month)++;
}
datetime->day = days + 1;
datetime->hour = seconds_in_day / SECONDS_PER_HOUR;
datetime->minute = (seconds_in_day % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE;
datetime->second = seconds_in_day % SECONDS_PER_MINUTE;
}
uint16_t datetime_get_days_per_year(uint16_t year) {
return datetime_days_per_year[datetime_is_leap_year(year) ? 1 : 0];
}
bool datetime_is_leap_year(uint16_t year) {
return (((year) % 4 == 0) && ((year) % 100 != 0)) || ((year) % 400 == 0);
}
uint8_t datetime_get_days_per_month(bool leap_year, uint8_t month) {
return datetime_days_per_month[leap_year ? 1 : 0][month - 1];
}

75
lib/datetime/datetime.h Normal file
View file

@ -0,0 +1,75 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
// Time
uint8_t hour; /**< Hour in 24H format: 0-23 */
uint8_t minute; /**< Minute: 0-59 */
uint8_t second; /**< Second: 0-59 */
// Date
uint8_t day; /**< Current day: 1-31 */
uint8_t month; /**< Current month: 1-12 */
uint16_t year; /**< Current year: 2000-2099 */
uint8_t weekday; /**< Current weekday: 1-7 */
} DateTime;
/** Validate Date Time
*
* @param datetime The datetime to validate
*
* @return { description_of_the_return_value }
*/
bool datetime_validate_datetime(DateTime* datetime);
/** Convert DateTime to UNIX timestamp
*
* @warning Mind timezone when perform conversion
*
* @param datetime The datetime (UTC)
*
* @return UNIX Timestamp in seconds from UNIX epoch start
*/
uint32_t datetime_datetime_to_timestamp(DateTime* datetime);
/** Convert UNIX timestamp to DateTime
*
* @warning Mind timezone when perform conversion
*
* @param[in] timestamp UNIX Timestamp in seconds from UNIX epoch start
* @param[out] datetime The datetime (UTC)
*/
void datetime_timestamp_to_datetime(uint32_t timestamp, DateTime* datetime);
/** Gets the number of days in the year according to the Gregorian calendar.
*
* @param year Input year.
*
* @return number of days in `year`.
*/
uint16_t datetime_get_days_per_year(uint16_t year);
/** Check if a year a leap year in the Gregorian calendar.
*
* @param year Input year.
*
* @return true if `year` is a leap year.
*/
bool datetime_is_leap_year(uint16_t year);
/** Get the number of days in the month.
*
* @param leap_year true to calculate based on leap years
* @param month month to check, where 1 = January
* @return the number of days in the month
*/
uint8_t datetime_get_days_per_month(bool leap_year, uint8_t month);
#ifdef __cplusplus
}
#endif

View file

@ -59,7 +59,7 @@ void name_generator_make_detailed(char* name, size_t max_name_size, const char*
furi_assert(max_name_size); furi_assert(max_name_size);
furi_assert(prefix); furi_assert(prefix);
FuriHalRtcDateTime dateTime; DateTime dateTime;
furi_hal_rtc_get_datetime(&dateTime); furi_hal_rtc_get_datetime(&dateTime);
snprintf( snprintf(

View file

@ -1,5 +1,5 @@
entry,status,name,type,params entry,status,name,type,params
Version,+,56.0,, Version,+,57.0,,
Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli.h,,
Header,+,applications/services/cli/cli_vcp.h,, Header,+,applications/services/cli/cli_vcp.h,,
@ -38,6 +38,7 @@ Header,+,applications/services/power/power_service/power.h,,
Header,+,applications/services/rpc/rpc_app.h,, Header,+,applications/services/rpc/rpc_app.h,,
Header,+,applications/services/storage/storage.h,, Header,+,applications/services/storage/storage.h,,
Header,+,lib/bit_lib/bit_lib.h,, Header,+,lib/bit_lib/bit_lib.h,,
Header,+,lib/datetime/datetime.h,,
Header,+,lib/digital_signal/digital_sequence.h,, Header,+,lib/digital_signal/digital_sequence.h,,
Header,+,lib/digital_signal/digital_signal.h,, Header,+,lib/digital_signal/digital_signal.h,,
Header,+,lib/drivers/cc1101_regs.h,, Header,+,lib/drivers/cc1101_regs.h,,
@ -730,6 +731,12 @@ Function,+,crc32_calc_buffer,uint32_t,"uint32_t, const void*, size_t"
Function,+,crc32_calc_file,uint32_t,"File*, const FileCrcProgressCb, void*" Function,+,crc32_calc_file,uint32_t,"File*, const FileCrcProgressCb, void*"
Function,-,ctermid,char*,char* Function,-,ctermid,char*,char*
Function,-,cuserid,char*,char* Function,-,cuserid,char*,char*
Function,+,datetime_datetime_to_timestamp,uint32_t,DateTime*
Function,+,datetime_get_days_per_month,uint8_t,"_Bool, uint8_t"
Function,+,datetime_get_days_per_year,uint16_t,uint16_t
Function,+,datetime_is_leap_year,_Bool,uint16_t
Function,+,datetime_timestamp_to_datetime,void,"uint32_t, DateTime*"
Function,+,datetime_validate_datetime,_Bool,DateTime*
Function,+,dialog_ex_alloc,DialogEx*, Function,+,dialog_ex_alloc,DialogEx*,
Function,+,dialog_ex_disable_extended_events,void,DialogEx* Function,+,dialog_ex_disable_extended_events,void,DialogEx*
Function,+,dialog_ex_enable_extended_events,void,DialogEx* Function,+,dialog_ex_enable_extended_events,void,DialogEx*
@ -1263,12 +1270,9 @@ Function,-,furi_hal_resources_deinit_early,void,
Function,+,furi_hal_resources_get_ext_pin_number,int32_t,const GpioPin* Function,+,furi_hal_resources_get_ext_pin_number,int32_t,const GpioPin*
Function,-,furi_hal_resources_init,void, Function,-,furi_hal_resources_init,void,
Function,-,furi_hal_resources_init_early,void, Function,-,furi_hal_resources_init_early,void,
Function,+,furi_hal_rtc_datetime_to_timestamp,uint32_t,FuriHalRtcDateTime*
Function,-,furi_hal_rtc_deinit_early,void, Function,-,furi_hal_rtc_deinit_early,void,
Function,+,furi_hal_rtc_get_boot_mode,FuriHalRtcBootMode, Function,+,furi_hal_rtc_get_boot_mode,FuriHalRtcBootMode,
Function,+,furi_hal_rtc_get_datetime,void,FuriHalRtcDateTime* Function,+,furi_hal_rtc_get_datetime,void,DateTime*
Function,+,furi_hal_rtc_get_days_per_month,uint8_t,"_Bool, uint8_t"
Function,+,furi_hal_rtc_get_days_per_year,uint16_t,uint16_t
Function,+,furi_hal_rtc_get_fault_data,uint32_t, Function,+,furi_hal_rtc_get_fault_data,uint32_t,
Function,+,furi_hal_rtc_get_heap_track_mode,FuriHalRtcHeapTrackMode, Function,+,furi_hal_rtc_get_heap_track_mode,FuriHalRtcHeapTrackMode,
Function,+,furi_hal_rtc_get_locale_dateformat,FuriHalRtcLocaleDateFormat, Function,+,furi_hal_rtc_get_locale_dateformat,FuriHalRtcLocaleDateFormat,
@ -1283,11 +1287,10 @@ Function,+,furi_hal_rtc_get_timestamp,uint32_t,
Function,-,furi_hal_rtc_init,void, Function,-,furi_hal_rtc_init,void,
Function,-,furi_hal_rtc_init_early,void, Function,-,furi_hal_rtc_init_early,void,
Function,+,furi_hal_rtc_is_flag_set,_Bool,FuriHalRtcFlag Function,+,furi_hal_rtc_is_flag_set,_Bool,FuriHalRtcFlag
Function,+,furi_hal_rtc_is_leap_year,_Bool,uint16_t
Function,+,furi_hal_rtc_reset_flag,void,FuriHalRtcFlag Function,+,furi_hal_rtc_reset_flag,void,FuriHalRtcFlag
Function,+,furi_hal_rtc_reset_registers,void, Function,+,furi_hal_rtc_reset_registers,void,
Function,+,furi_hal_rtc_set_boot_mode,void,FuriHalRtcBootMode Function,+,furi_hal_rtc_set_boot_mode,void,FuriHalRtcBootMode
Function,+,furi_hal_rtc_set_datetime,void,FuriHalRtcDateTime* Function,+,furi_hal_rtc_set_datetime,void,DateTime*
Function,+,furi_hal_rtc_set_fault_data,void,uint32_t Function,+,furi_hal_rtc_set_fault_data,void,uint32_t
Function,+,furi_hal_rtc_set_flag,void,FuriHalRtcFlag Function,+,furi_hal_rtc_set_flag,void,FuriHalRtcFlag
Function,+,furi_hal_rtc_set_heap_track_mode,void,FuriHalRtcHeapTrackMode Function,+,furi_hal_rtc_set_heap_track_mode,void,FuriHalRtcHeapTrackMode
@ -1300,8 +1303,6 @@ Function,+,furi_hal_rtc_set_log_level,void,uint8_t
Function,+,furi_hal_rtc_set_pin_fails,void,uint32_t Function,+,furi_hal_rtc_set_pin_fails,void,uint32_t
Function,+,furi_hal_rtc_set_register,void,"FuriHalRtcRegister, uint32_t" Function,+,furi_hal_rtc_set_register,void,"FuriHalRtcRegister, uint32_t"
Function,+,furi_hal_rtc_sync_shadow,void, Function,+,furi_hal_rtc_sync_shadow,void,
Function,+,furi_hal_rtc_timestamp_to_datetime,void,"uint32_t, FuriHalRtcDateTime*"
Function,+,furi_hal_rtc_validate_datetime,_Bool,FuriHalRtcDateTime*
Function,+,furi_hal_sd_get_card_state,FuriStatus, Function,+,furi_hal_sd_get_card_state,FuriStatus,
Function,+,furi_hal_sd_info,FuriStatus,FuriHalSdInfo* Function,+,furi_hal_sd_info,FuriStatus,FuriHalSdInfo*
Function,+,furi_hal_sd_init,FuriStatus,_Bool Function,+,furi_hal_sd_init,FuriStatus,_Bool
@ -1698,8 +1699,8 @@ Function,+,loading_free,void,Loading*
Function,+,loading_get_view,View*,Loading* Function,+,loading_get_view,View*,Loading*
Function,+,locale_celsius_to_fahrenheit,float,float Function,+,locale_celsius_to_fahrenheit,float,float
Function,+,locale_fahrenheit_to_celsius,float,float Function,+,locale_fahrenheit_to_celsius,float,float
Function,+,locale_format_date,void,"FuriString*, const FuriHalRtcDateTime*, const LocaleDateFormat, const char*" Function,+,locale_format_date,void,"FuriString*, const DateTime*, const LocaleDateFormat, const char*"
Function,+,locale_format_time,void,"FuriString*, const FuriHalRtcDateTime*, const LocaleTimeFormat, const _Bool" Function,+,locale_format_time,void,"FuriString*, const DateTime*, const LocaleTimeFormat, const _Bool"
Function,+,locale_get_date_format,LocaleDateFormat, Function,+,locale_get_date_format,LocaleDateFormat,
Function,+,locale_get_measurement_unit,LocaleMeasurementUnits, Function,+,locale_get_measurement_unit,LocaleMeasurementUnits,
Function,+,locale_get_time_format,LocaleTimeFormat, Function,+,locale_get_time_format,LocaleTimeFormat,

1 entry status name type params
2 Version + 56.0 57.0
3 Header + applications/services/bt/bt_service/bt.h
4 Header + applications/services/cli/cli.h
5 Header + applications/services/cli/cli_vcp.h
38 Header + applications/services/rpc/rpc_app.h
39 Header + applications/services/storage/storage.h
40 Header + lib/bit_lib/bit_lib.h
41 Header + lib/datetime/datetime.h
42 Header + lib/digital_signal/digital_sequence.h
43 Header + lib/digital_signal/digital_signal.h
44 Header + lib/drivers/cc1101_regs.h
731 Function + crc32_calc_file uint32_t File*, const FileCrcProgressCb, void*
732 Function - ctermid char* char*
733 Function - cuserid char* char*
734 Function + datetime_datetime_to_timestamp uint32_t DateTime*
735 Function + datetime_get_days_per_month uint8_t _Bool, uint8_t
736 Function + datetime_get_days_per_year uint16_t uint16_t
737 Function + datetime_is_leap_year _Bool uint16_t
738 Function + datetime_timestamp_to_datetime void uint32_t, DateTime*
739 Function + datetime_validate_datetime _Bool DateTime*
740 Function + dialog_ex_alloc DialogEx*
741 Function + dialog_ex_disable_extended_events void DialogEx*
742 Function + dialog_ex_enable_extended_events void DialogEx*
1270 Function + furi_hal_resources_get_ext_pin_number int32_t const GpioPin*
1271 Function - furi_hal_resources_init void
1272 Function - furi_hal_resources_init_early void
Function + furi_hal_rtc_datetime_to_timestamp uint32_t FuriHalRtcDateTime*
1273 Function - furi_hal_rtc_deinit_early void
1274 Function + furi_hal_rtc_get_boot_mode FuriHalRtcBootMode
1275 Function + furi_hal_rtc_get_datetime void FuriHalRtcDateTime* DateTime*
Function + furi_hal_rtc_get_days_per_month uint8_t _Bool, uint8_t
Function + furi_hal_rtc_get_days_per_year uint16_t uint16_t
1276 Function + furi_hal_rtc_get_fault_data uint32_t
1277 Function + furi_hal_rtc_get_heap_track_mode FuriHalRtcHeapTrackMode
1278 Function + furi_hal_rtc_get_locale_dateformat FuriHalRtcLocaleDateFormat
1287 Function - furi_hal_rtc_init void
1288 Function - furi_hal_rtc_init_early void
1289 Function + furi_hal_rtc_is_flag_set _Bool FuriHalRtcFlag
Function + furi_hal_rtc_is_leap_year _Bool uint16_t
1290 Function + furi_hal_rtc_reset_flag void FuriHalRtcFlag
1291 Function + furi_hal_rtc_reset_registers void
1292 Function + furi_hal_rtc_set_boot_mode void FuriHalRtcBootMode
1293 Function + furi_hal_rtc_set_datetime void FuriHalRtcDateTime* DateTime*
1294 Function + furi_hal_rtc_set_fault_data void uint32_t
1295 Function + furi_hal_rtc_set_flag void FuriHalRtcFlag
1296 Function + furi_hal_rtc_set_heap_track_mode void FuriHalRtcHeapTrackMode
1303 Function + furi_hal_rtc_set_pin_fails void uint32_t
1304 Function + furi_hal_rtc_set_register void FuriHalRtcRegister, uint32_t
1305 Function + furi_hal_rtc_sync_shadow void
Function + furi_hal_rtc_timestamp_to_datetime void uint32_t, FuriHalRtcDateTime*
Function + furi_hal_rtc_validate_datetime _Bool FuriHalRtcDateTime*
1306 Function + furi_hal_sd_get_card_state FuriStatus
1307 Function + furi_hal_sd_info FuriStatus FuriHalSdInfo*
1308 Function + furi_hal_sd_init FuriStatus _Bool
1699 Function + loading_get_view View* Loading*
1700 Function + locale_celsius_to_fahrenheit float float
1701 Function + locale_fahrenheit_to_celsius float float
1702 Function + locale_format_date void FuriString*, const FuriHalRtcDateTime*, const LocaleDateFormat, const char* FuriString*, const DateTime*, const LocaleDateFormat, const char*
1703 Function + locale_format_time void FuriString*, const FuriHalRtcDateTime*, const LocaleTimeFormat, const _Bool FuriString*, const DateTime*, const LocaleTimeFormat, const _Bool
1704 Function + locale_get_date_format LocaleDateFormat
1705 Function + locale_get_measurement_unit LocaleMeasurementUnits
1706 Function + locale_get_time_format LocaleTimeFormat

View file

@ -37,7 +37,8 @@
"heatshrink", "heatshrink",
"flipperformat", "flipperformat",
"flipper18", "flipper18",
"bit_lib" "bit_lib",
"datetime"
], ],
"excluded_sources": [ "excluded_sources": [
"furi_hal_infrared.c", "furi_hal_infrared.c",
@ -67,4 +68,4 @@
"ibutton", "ibutton",
"infrared" "infrared"
] ]
} }

View file

@ -1,5 +1,5 @@
entry,status,name,type,params entry,status,name,type,params
Version,+,56.0,, Version,+,57.0,,
Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,,
Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli.h,,
@ -39,6 +39,7 @@ Header,+,applications/services/power/power_service/power.h,,
Header,+,applications/services/rpc/rpc_app.h,, Header,+,applications/services/rpc/rpc_app.h,,
Header,+,applications/services/storage/storage.h,, Header,+,applications/services/storage/storage.h,,
Header,+,lib/bit_lib/bit_lib.h,, Header,+,lib/bit_lib/bit_lib.h,,
Header,+,lib/datetime/datetime.h,,
Header,+,lib/digital_signal/digital_sequence.h,, Header,+,lib/digital_signal/digital_sequence.h,,
Header,+,lib/digital_signal/digital_signal.h,, Header,+,lib/digital_signal/digital_signal.h,,
Header,+,lib/drivers/cc1101_regs.h,, Header,+,lib/drivers/cc1101_regs.h,,
@ -798,6 +799,12 @@ Function,+,crc32_calc_buffer,uint32_t,"uint32_t, const void*, size_t"
Function,+,crc32_calc_file,uint32_t,"File*, const FileCrcProgressCb, void*" Function,+,crc32_calc_file,uint32_t,"File*, const FileCrcProgressCb, void*"
Function,-,ctermid,char*,char* Function,-,ctermid,char*,char*
Function,-,cuserid,char*,char* Function,-,cuserid,char*,char*
Function,+,datetime_datetime_to_timestamp,uint32_t,DateTime*
Function,+,datetime_get_days_per_month,uint8_t,"_Bool, uint8_t"
Function,+,datetime_get_days_per_year,uint16_t,uint16_t
Function,+,datetime_is_leap_year,_Bool,uint16_t
Function,+,datetime_timestamp_to_datetime,void,"uint32_t, DateTime*"
Function,+,datetime_validate_datetime,_Bool,DateTime*
Function,+,dialog_ex_alloc,DialogEx*, Function,+,dialog_ex_alloc,DialogEx*,
Function,+,dialog_ex_disable_extended_events,void,DialogEx* Function,+,dialog_ex_disable_extended_events,void,DialogEx*
Function,+,dialog_ex_enable_extended_events,void,DialogEx* Function,+,dialog_ex_enable_extended_events,void,DialogEx*
@ -1408,12 +1415,9 @@ Function,+,furi_hal_rfid_tim_read_continue,void,
Function,+,furi_hal_rfid_tim_read_pause,void, Function,+,furi_hal_rfid_tim_read_pause,void,
Function,+,furi_hal_rfid_tim_read_start,void,"float, float" Function,+,furi_hal_rfid_tim_read_start,void,"float, float"
Function,+,furi_hal_rfid_tim_read_stop,void, Function,+,furi_hal_rfid_tim_read_stop,void,
Function,+,furi_hal_rtc_datetime_to_timestamp,uint32_t,FuriHalRtcDateTime*
Function,-,furi_hal_rtc_deinit_early,void, Function,-,furi_hal_rtc_deinit_early,void,
Function,+,furi_hal_rtc_get_boot_mode,FuriHalRtcBootMode, Function,+,furi_hal_rtc_get_boot_mode,FuriHalRtcBootMode,
Function,+,furi_hal_rtc_get_datetime,void,FuriHalRtcDateTime* Function,+,furi_hal_rtc_get_datetime,void,DateTime*
Function,+,furi_hal_rtc_get_days_per_month,uint8_t,"_Bool, uint8_t"
Function,+,furi_hal_rtc_get_days_per_year,uint16_t,uint16_t
Function,+,furi_hal_rtc_get_fault_data,uint32_t, Function,+,furi_hal_rtc_get_fault_data,uint32_t,
Function,+,furi_hal_rtc_get_heap_track_mode,FuriHalRtcHeapTrackMode, Function,+,furi_hal_rtc_get_heap_track_mode,FuriHalRtcHeapTrackMode,
Function,+,furi_hal_rtc_get_locale_dateformat,FuriHalRtcLocaleDateFormat, Function,+,furi_hal_rtc_get_locale_dateformat,FuriHalRtcLocaleDateFormat,
@ -1428,11 +1432,10 @@ Function,+,furi_hal_rtc_get_timestamp,uint32_t,
Function,-,furi_hal_rtc_init,void, Function,-,furi_hal_rtc_init,void,
Function,-,furi_hal_rtc_init_early,void, Function,-,furi_hal_rtc_init_early,void,
Function,+,furi_hal_rtc_is_flag_set,_Bool,FuriHalRtcFlag Function,+,furi_hal_rtc_is_flag_set,_Bool,FuriHalRtcFlag
Function,+,furi_hal_rtc_is_leap_year,_Bool,uint16_t
Function,+,furi_hal_rtc_reset_flag,void,FuriHalRtcFlag Function,+,furi_hal_rtc_reset_flag,void,FuriHalRtcFlag
Function,+,furi_hal_rtc_reset_registers,void, Function,+,furi_hal_rtc_reset_registers,void,
Function,+,furi_hal_rtc_set_boot_mode,void,FuriHalRtcBootMode Function,+,furi_hal_rtc_set_boot_mode,void,FuriHalRtcBootMode
Function,+,furi_hal_rtc_set_datetime,void,FuriHalRtcDateTime* Function,+,furi_hal_rtc_set_datetime,void,DateTime*
Function,+,furi_hal_rtc_set_fault_data,void,uint32_t Function,+,furi_hal_rtc_set_fault_data,void,uint32_t
Function,+,furi_hal_rtc_set_flag,void,FuriHalRtcFlag Function,+,furi_hal_rtc_set_flag,void,FuriHalRtcFlag
Function,+,furi_hal_rtc_set_heap_track_mode,void,FuriHalRtcHeapTrackMode Function,+,furi_hal_rtc_set_heap_track_mode,void,FuriHalRtcHeapTrackMode
@ -1445,8 +1448,6 @@ Function,+,furi_hal_rtc_set_log_level,void,uint8_t
Function,+,furi_hal_rtc_set_pin_fails,void,uint32_t Function,+,furi_hal_rtc_set_pin_fails,void,uint32_t
Function,+,furi_hal_rtc_set_register,void,"FuriHalRtcRegister, uint32_t" Function,+,furi_hal_rtc_set_register,void,"FuriHalRtcRegister, uint32_t"
Function,+,furi_hal_rtc_sync_shadow,void, Function,+,furi_hal_rtc_sync_shadow,void,
Function,+,furi_hal_rtc_timestamp_to_datetime,void,"uint32_t, FuriHalRtcDateTime*"
Function,+,furi_hal_rtc_validate_datetime,_Bool,FuriHalRtcDateTime*
Function,+,furi_hal_sd_get_card_state,FuriStatus, Function,+,furi_hal_sd_get_card_state,FuriStatus,
Function,+,furi_hal_sd_info,FuriStatus,FuriHalSdInfo* Function,+,furi_hal_sd_info,FuriStatus,FuriHalSdInfo*
Function,+,furi_hal_sd_init,FuriStatus,_Bool Function,+,furi_hal_sd_init,FuriStatus,_Bool
@ -2076,8 +2077,8 @@ Function,+,loading_free,void,Loading*
Function,+,loading_get_view,View*,Loading* Function,+,loading_get_view,View*,Loading*
Function,+,locale_celsius_to_fahrenheit,float,float Function,+,locale_celsius_to_fahrenheit,float,float
Function,+,locale_fahrenheit_to_celsius,float,float Function,+,locale_fahrenheit_to_celsius,float,float
Function,+,locale_format_date,void,"FuriString*, const FuriHalRtcDateTime*, const LocaleDateFormat, const char*" Function,+,locale_format_date,void,"FuriString*, const DateTime*, const LocaleDateFormat, const char*"
Function,+,locale_format_time,void,"FuriString*, const FuriHalRtcDateTime*, const LocaleTimeFormat, const _Bool" Function,+,locale_format_time,void,"FuriString*, const DateTime*, const LocaleTimeFormat, const _Bool"
Function,+,locale_get_date_format,LocaleDateFormat, Function,+,locale_get_date_format,LocaleDateFormat,
Function,+,locale_get_measurement_unit,LocaleMeasurementUnits, Function,+,locale_get_measurement_unit,LocaleMeasurementUnits,
Function,+,locale_get_time_format,LocaleTimeFormat, Function,+,locale_get_time_format,LocaleTimeFormat,

1 entry status name type params
2 Version + 56.0 57.0
3 Header + applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h
4 Header + applications/services/bt/bt_service/bt.h
5 Header + applications/services/cli/cli.h
39 Header + applications/services/rpc/rpc_app.h
40 Header + applications/services/storage/storage.h
41 Header + lib/bit_lib/bit_lib.h
42 Header + lib/datetime/datetime.h
43 Header + lib/digital_signal/digital_sequence.h
44 Header + lib/digital_signal/digital_signal.h
45 Header + lib/drivers/cc1101_regs.h
799 Function + crc32_calc_file uint32_t File*, const FileCrcProgressCb, void*
800 Function - ctermid char* char*
801 Function - cuserid char* char*
802 Function + datetime_datetime_to_timestamp uint32_t DateTime*
803 Function + datetime_get_days_per_month uint8_t _Bool, uint8_t
804 Function + datetime_get_days_per_year uint16_t uint16_t
805 Function + datetime_is_leap_year _Bool uint16_t
806 Function + datetime_timestamp_to_datetime void uint32_t, DateTime*
807 Function + datetime_validate_datetime _Bool DateTime*
808 Function + dialog_ex_alloc DialogEx*
809 Function + dialog_ex_disable_extended_events void DialogEx*
810 Function + dialog_ex_enable_extended_events void DialogEx*
1415 Function + furi_hal_rfid_tim_read_pause void
1416 Function + furi_hal_rfid_tim_read_start void float, float
1417 Function + furi_hal_rfid_tim_read_stop void
Function + furi_hal_rtc_datetime_to_timestamp uint32_t FuriHalRtcDateTime*
1418 Function - furi_hal_rtc_deinit_early void
1419 Function + furi_hal_rtc_get_boot_mode FuriHalRtcBootMode
1420 Function + furi_hal_rtc_get_datetime void FuriHalRtcDateTime* DateTime*
Function + furi_hal_rtc_get_days_per_month uint8_t _Bool, uint8_t
Function + furi_hal_rtc_get_days_per_year uint16_t uint16_t
1421 Function + furi_hal_rtc_get_fault_data uint32_t
1422 Function + furi_hal_rtc_get_heap_track_mode FuriHalRtcHeapTrackMode
1423 Function + furi_hal_rtc_get_locale_dateformat FuriHalRtcLocaleDateFormat
1432 Function - furi_hal_rtc_init void
1433 Function - furi_hal_rtc_init_early void
1434 Function + furi_hal_rtc_is_flag_set _Bool FuriHalRtcFlag
Function + furi_hal_rtc_is_leap_year _Bool uint16_t
1435 Function + furi_hal_rtc_reset_flag void FuriHalRtcFlag
1436 Function + furi_hal_rtc_reset_registers void
1437 Function + furi_hal_rtc_set_boot_mode void FuriHalRtcBootMode
1438 Function + furi_hal_rtc_set_datetime void FuriHalRtcDateTime* DateTime*
1439 Function + furi_hal_rtc_set_fault_data void uint32_t
1440 Function + furi_hal_rtc_set_flag void FuriHalRtcFlag
1441 Function + furi_hal_rtc_set_heap_track_mode void FuriHalRtcHeapTrackMode
1448 Function + furi_hal_rtc_set_pin_fails void uint32_t
1449 Function + furi_hal_rtc_set_register void FuriHalRtcRegister, uint32_t
1450 Function + furi_hal_rtc_sync_shadow void
Function + furi_hal_rtc_timestamp_to_datetime void uint32_t, FuriHalRtcDateTime*
Function + furi_hal_rtc_validate_datetime _Bool FuriHalRtcDateTime*
1451 Function + furi_hal_sd_get_card_state FuriStatus
1452 Function + furi_hal_sd_info FuriStatus FuriHalSdInfo*
1453 Function + furi_hal_sd_init FuriStatus _Bool
2077 Function + loading_get_view View* Loading*
2078 Function + locale_celsius_to_fahrenheit float float
2079 Function + locale_fahrenheit_to_celsius float float
2080 Function + locale_format_date void FuriString*, const FuriHalRtcDateTime*, const LocaleDateFormat, const char* FuriString*, const DateTime*, const LocaleDateFormat, const char*
2081 Function + locale_format_time void FuriString*, const FuriHalRtcDateTime*, const LocaleTimeFormat, const _Bool FuriString*, const DateTime*, const LocaleTimeFormat, const _Bool
2082 Function + locale_get_date_format LocaleDateFormat
2083 Function + locale_get_measurement_unit LocaleMeasurementUnits
2084 Function + locale_get_time_format LocaleTimeFormat

View file

@ -15,7 +15,7 @@ void fatfs_init(void) {
* @return Time in DWORD (toasters per square washing machine) * @return Time in DWORD (toasters per square washing machine)
*/ */
DWORD get_fattime() { DWORD get_fattime() {
FuriHalRtcDateTime furi_time; DateTime furi_time;
furi_hal_rtc_get_datetime(&furi_time); furi_hal_rtc_get_datetime(&furi_time);
return ((uint32_t)(furi_time.year - 1980) << 25) | furi_time.month << 21 | return ((uint32_t)(furi_time.year - 1980) << 25) | furi_time.month << 21 |

View file

@ -42,18 +42,6 @@ typedef struct {
_Static_assert(sizeof(SystemReg) == 4, "SystemReg size mismatch"); _Static_assert(sizeof(SystemReg) == 4, "SystemReg size mismatch");
#define FURI_HAL_RTC_SECONDS_PER_MINUTE 60
#define FURI_HAL_RTC_SECONDS_PER_HOUR (FURI_HAL_RTC_SECONDS_PER_MINUTE * 60)
#define FURI_HAL_RTC_SECONDS_PER_DAY (FURI_HAL_RTC_SECONDS_PER_HOUR * 24)
#define FURI_HAL_RTC_MONTHS_COUNT 12
#define FURI_HAL_RTC_EPOCH_START_YEAR 1970
static const uint8_t furi_hal_rtc_days_per_month[2][FURI_HAL_RTC_MONTHS_COUNT] = {
{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}};
static const uint16_t furi_hal_rtc_days_per_year[] = {365, 366};
static const FuriHalSerialId furi_hal_rtc_log_devices[] = { static const FuriHalSerialId furi_hal_rtc_log_devices[] = {
[FuriHalRtcLogDeviceUsart] = FuriHalSerialIdUsart, [FuriHalRtcLogDeviceUsart] = FuriHalSerialIdUsart,
[FuriHalRtcLogDeviceLpuart] = FuriHalSerialIdLpuart, [FuriHalRtcLogDeviceLpuart] = FuriHalSerialIdLpuart,
@ -103,7 +91,7 @@ static bool furi_hal_rtc_start_clock_and_switch() {
} }
static void furi_hal_rtc_recover() { static void furi_hal_rtc_recover() {
FuriHalRtcDateTime datetime = {0}; DateTime datetime = {0};
// Handle fixable LSE failure // Handle fixable LSE failure
if(LL_RCC_LSE_IsCSSDetected()) { if(LL_RCC_LSE_IsCSSDetected()) {
@ -350,7 +338,7 @@ FuriHalRtcLocaleDateFormat furi_hal_rtc_get_locale_dateformat() {
return data->locale_dateformat; return data->locale_dateformat;
} }
void furi_hal_rtc_set_datetime(FuriHalRtcDateTime* datetime) { void furi_hal_rtc_set_datetime(DateTime* datetime) {
furi_check(!FURI_IS_IRQ_MODE()); furi_check(!FURI_IS_IRQ_MODE());
furi_assert(datetime); furi_assert(datetime);
@ -389,7 +377,7 @@ void furi_hal_rtc_set_datetime(FuriHalRtcDateTime* datetime) {
FURI_CRITICAL_EXIT(); FURI_CRITICAL_EXIT();
} }
void furi_hal_rtc_get_datetime(FuriHalRtcDateTime* datetime) { void furi_hal_rtc_get_datetime(DateTime* datetime) {
furi_check(!FURI_IS_IRQ_MODE()); furi_check(!FURI_IS_IRQ_MODE());
furi_assert(datetime); furi_assert(datetime);
@ -407,28 +395,6 @@ void furi_hal_rtc_get_datetime(FuriHalRtcDateTime* datetime) {
datetime->weekday = __LL_RTC_CONVERT_BCD2BIN((date >> 24) & 0xFF); datetime->weekday = __LL_RTC_CONVERT_BCD2BIN((date >> 24) & 0xFF);
} }
bool furi_hal_rtc_validate_datetime(FuriHalRtcDateTime* datetime) {
bool invalid = false;
invalid |= (datetime->second > 59);
invalid |= (datetime->minute > 59);
invalid |= (datetime->hour > 23);
invalid |= (datetime->year < 2000);
invalid |= (datetime->year > 2099);
invalid |= (datetime->month == 0);
invalid |= (datetime->month > 12);
invalid |= (datetime->day == 0);
invalid |= (datetime->day > 31);
invalid |= (datetime->weekday == 0);
invalid |= (datetime->weekday > 7);
return !invalid;
}
void furi_hal_rtc_set_fault_data(uint32_t value) { void furi_hal_rtc_set_fault_data(uint32_t value) {
furi_hal_rtc_set_register(FuriHalRtcRegisterFaultData, value); furi_hal_rtc_set_register(FuriHalRtcRegisterFaultData, value);
} }
@ -446,76 +412,7 @@ uint32_t furi_hal_rtc_get_pin_fails() {
} }
uint32_t furi_hal_rtc_get_timestamp() { uint32_t furi_hal_rtc_get_timestamp() {
FuriHalRtcDateTime datetime = {0}; DateTime datetime = {0};
furi_hal_rtc_get_datetime(&datetime); furi_hal_rtc_get_datetime(&datetime);
return furi_hal_rtc_datetime_to_timestamp(&datetime); return datetime_datetime_to_timestamp(&datetime);
}
uint32_t furi_hal_rtc_datetime_to_timestamp(FuriHalRtcDateTime* datetime) {
uint32_t timestamp = 0;
uint8_t years = 0;
uint8_t leap_years = 0;
for(uint16_t y = FURI_HAL_RTC_EPOCH_START_YEAR; y < datetime->year; y++) {
if(furi_hal_rtc_is_leap_year(y)) {
leap_years++;
} else {
years++;
}
}
timestamp +=
((years * furi_hal_rtc_days_per_year[0]) + (leap_years * furi_hal_rtc_days_per_year[1])) *
FURI_HAL_RTC_SECONDS_PER_DAY;
bool leap_year = furi_hal_rtc_is_leap_year(datetime->year);
for(uint8_t m = 1; m < datetime->month; m++) {
timestamp += furi_hal_rtc_get_days_per_month(leap_year, m) * FURI_HAL_RTC_SECONDS_PER_DAY;
}
timestamp += (datetime->day - 1) * FURI_HAL_RTC_SECONDS_PER_DAY;
timestamp += datetime->hour * FURI_HAL_RTC_SECONDS_PER_HOUR;
timestamp += datetime->minute * FURI_HAL_RTC_SECONDS_PER_MINUTE;
timestamp += datetime->second;
return timestamp;
}
void furi_hal_rtc_timestamp_to_datetime(uint32_t timestamp, FuriHalRtcDateTime* datetime) {
uint32_t days = timestamp / FURI_HAL_RTC_SECONDS_PER_DAY;
uint32_t seconds_in_day = timestamp % FURI_HAL_RTC_SECONDS_PER_DAY;
datetime->year = FURI_HAL_RTC_EPOCH_START_YEAR;
while(days >= furi_hal_rtc_get_days_per_year(datetime->year)) {
days -= furi_hal_rtc_get_days_per_year(datetime->year);
(datetime->year)++;
}
datetime->month = 1;
while(days >= furi_hal_rtc_get_days_per_month(
furi_hal_rtc_is_leap_year(datetime->year), datetime->month)) {
days -= furi_hal_rtc_get_days_per_month(
furi_hal_rtc_is_leap_year(datetime->year), datetime->month);
(datetime->month)++;
}
datetime->day = days + 1;
datetime->hour = seconds_in_day / FURI_HAL_RTC_SECONDS_PER_HOUR;
datetime->minute =
(seconds_in_day % FURI_HAL_RTC_SECONDS_PER_HOUR) / FURI_HAL_RTC_SECONDS_PER_MINUTE;
datetime->second = seconds_in_day % FURI_HAL_RTC_SECONDS_PER_MINUTE;
}
uint16_t furi_hal_rtc_get_days_per_year(uint16_t year) {
return furi_hal_rtc_days_per_year[furi_hal_rtc_is_leap_year(year) ? 1 : 0];
}
bool furi_hal_rtc_is_leap_year(uint16_t year) {
return (((year) % 4 == 0) && ((year) % 100 != 0)) || ((year) % 400 == 0);
}
uint8_t furi_hal_rtc_get_days_per_month(bool leap_year, uint8_t month) {
return furi_hal_rtc_days_per_month[leap_year ? 1 : 0][month - 1];
} }

View file

@ -8,22 +8,12 @@
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <datetime/datetime.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
typedef struct {
// Time
uint8_t hour; /**< Hour in 24H format: 0-23 */
uint8_t minute; /**< Minute: 0-59 */
uint8_t second; /**< Second: 0-59 */
// Date
uint8_t day; /**< Current day: 1-31 */
uint8_t month; /**< Current month: 1-12 */
uint16_t year; /**< Current year: 2000-2099 */
uint8_t weekday; /**< Current weekday: 1-7 */
} FuriHalRtcDateTime;
typedef enum { typedef enum {
FuriHalRtcFlagDebug = (1 << 0), FuriHalRtcFlagDebug = (1 << 0),
FuriHalRtcFlagStorageFormatInternal = (1 << 1), FuriHalRtcFlagStorageFormatInternal = (1 << 1),
@ -247,21 +237,13 @@ FuriHalRtcLocaleDateFormat furi_hal_rtc_get_locale_dateformat(void);
* *
* @param datetime The date time to set * @param datetime The date time to set
*/ */
void furi_hal_rtc_set_datetime(FuriHalRtcDateTime* datetime); void furi_hal_rtc_set_datetime(DateTime* datetime);
/** Get RTC Date Time /** Get RTC Date Time
* *
* @param datetime The datetime * @param datetime The datetime
*/ */
void furi_hal_rtc_get_datetime(FuriHalRtcDateTime* datetime); void furi_hal_rtc_get_datetime(DateTime* datetime);
/** Validate Date Time
*
* @param datetime The datetime to validate
*
* @return { description_of_the_return_value }
*/
bool furi_hal_rtc_validate_datetime(FuriHalRtcDateTime* datetime);
/** Set RTC Fault Data /** Set RTC Fault Data
* *
@ -293,49 +275,6 @@ uint32_t furi_hal_rtc_get_pin_fails(void);
*/ */
uint32_t furi_hal_rtc_get_timestamp(void); uint32_t furi_hal_rtc_get_timestamp(void);
/** Convert DateTime to UNIX timestamp
*
* @warning Mind timezone when perform conversion
*
* @param datetime The datetime (UTC)
*
* @return UNIX Timestamp in seconds from UNIX epoch start
*/
uint32_t furi_hal_rtc_datetime_to_timestamp(FuriHalRtcDateTime* datetime);
/** Convert UNIX timestamp to DateTime
*
* @warning Mind timezone when perform conversion
*
* @param[in] timestamp UNIX Timestamp in seconds from UNIX epoch start
* @param[out] datetime The datetime (UTC)
*/
void furi_hal_rtc_timestamp_to_datetime(uint32_t timestamp, FuriHalRtcDateTime* datetime);
/** Gets the number of days in the year according to the Gregorian calendar.
*
* @param year Input year.
*
* @return number of days in `year`.
*/
uint16_t furi_hal_rtc_get_days_per_year(uint16_t year);
/** Check if a year a leap year in the Gregorian calendar.
*
* @param year Input year.
*
* @return true if `year` is a leap year.
*/
bool furi_hal_rtc_is_leap_year(uint16_t year);
/** Get the number of days in the month.
*
* @param leap_year true to calculate based on leap years
* @param month month to check, where 1 = January
* @return the number of days in the month
*/
uint8_t furi_hal_rtc_get_days_per_month(bool leap_year, uint8_t month);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View file

@ -49,6 +49,7 @@
"heatshrink", "heatshrink",
"flipperformat", "flipperformat",
"flipper7", "flipper7",
"bit_lib" "bit_lib",
"datetime"
] ]
} }