Просмотр исходного кода

[FL-3024] Locale settings (#2137)

* Locale settings
* Time/date format fix
* Locale: add docs, enums for HAL, cleanup.

Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
Nikolay Minaylov 3 лет назад
Родитель
Сommit
f10e82c64d

+ 11 - 0
applications/debug/locale_test/application.fam

@@ -0,0 +1,11 @@
+App(
+    appid="locale_test",
+    name="Locale Test",
+    apptype=FlipperAppType.DEBUG,
+    entry_point="locale_test_app",
+    cdefines=["APP_LOCALE"],
+    requires=["gui", "locale"],
+    stack_size=2 * 1024,
+    order=70,
+    fap_category="Debug",
+)

+ 102 - 0
applications/debug/locale_test/locale_test.c

@@ -0,0 +1,102 @@
+#include <furi.h>
+#include <gui/gui.h>
+#include <gui/elements.h>
+#include <gui/view_dispatcher.h>
+#include <gui/modules/dialog_ex.h>
+#include <locale/locale.h>
+
+typedef struct {
+    Gui* gui;
+    ViewDispatcher* view_dispatcher;
+    View* view;
+} LocaleTestApp;
+
+static void locale_test_view_draw_callback(Canvas* canvas, void* _model) {
+    UNUSED(_model);
+
+    // Prepare canvas
+    canvas_set_color(canvas, ColorBlack);
+    canvas_set_font(canvas, FontSecondary);
+
+    FuriString* tmp_string = furi_string_alloc();
+
+    float temp = 25.3f;
+    LocaleMeasurementUnits units = locale_get_measurement_unit();
+    if(units == LocaleMeasurementUnitsMetric) {
+        furi_string_printf(tmp_string, "Temp: %5.1fC", (double)temp);
+    } else {
+        temp = locale_celsius_to_fahrenheit(temp);
+        furi_string_printf(tmp_string, "Temp: %5.1fF", (double)temp);
+    }
+    canvas_draw_str(canvas, 0, 10, furi_string_get_cstr(tmp_string));
+
+    FuriHalRtcDateTime datetime;
+    furi_hal_rtc_get_datetime(&datetime);
+
+    locale_format_time(tmp_string, &datetime, locale_get_time_format(), false);
+    canvas_draw_str(canvas, 0, 25, furi_string_get_cstr(tmp_string));
+
+    locale_format_date(tmp_string, &datetime, locale_get_date_format(), "/");
+    canvas_draw_str(canvas, 0, 40, furi_string_get_cstr(tmp_string));
+
+    furi_string_free(tmp_string);
+}
+
+static bool locale_test_view_input_callback(InputEvent* event, void* context) {
+    UNUSED(event);
+    UNUSED(context);
+    return false;
+}
+
+static uint32_t locale_test_exit(void* context) {
+    UNUSED(context);
+    return VIEW_NONE;
+}
+
+static LocaleTestApp* locale_test_alloc() {
+    LocaleTestApp* app = malloc(sizeof(LocaleTestApp));
+
+    // Gui
+    app->gui = furi_record_open(RECORD_GUI);
+
+    // View dispatcher
+    app->view_dispatcher = view_dispatcher_alloc();
+    view_dispatcher_enable_queue(app->view_dispatcher);
+    view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
+
+    // Views
+    app->view = view_alloc();
+    view_set_draw_callback(app->view, locale_test_view_draw_callback);
+    view_set_input_callback(app->view, locale_test_view_input_callback);
+
+    view_set_previous_callback(app->view, locale_test_exit);
+    view_dispatcher_add_view(app->view_dispatcher, 0, app->view);
+    view_dispatcher_switch_to_view(app->view_dispatcher, 0);
+
+    return app;
+}
+
+static void locale_test_free(LocaleTestApp* app) {
+    furi_assert(app);
+
+    // Free views
+    view_dispatcher_remove_view(app->view_dispatcher, 0);
+
+    view_free(app->view);
+    view_dispatcher_free(app->view_dispatcher);
+
+    // Close gui record
+    furi_record_close(RECORD_GUI);
+    app->gui = NULL;
+
+    // Free rest
+    free(app);
+}
+
+int32_t locale_test_app(void* p) {
+    UNUSED(p);
+    LocaleTestApp* app = locale_test_alloc();
+    view_dispatcher_run(app->view_dispatcher);
+    locale_test_free(app);
+    return 0;
+}

+ 9 - 0
applications/services/locale/application.fam

@@ -0,0 +1,9 @@
+App(
+    appid="locale",
+    name="LocaleSrv",
+    apptype=FlipperAppType.STARTUP,
+    entry_point="locale_on_system_start",
+    cdefines=["SRV_LOCALE"],
+    order=90,
+    sdk_headers=["locale.h"],
+)

+ 109 - 0
applications/services/locale/locale.c

@@ -0,0 +1,109 @@
+#include "locale.h"
+
+#define TAG "LocaleSrv"
+
+LocaleMeasurementUnits locale_get_measurement_unit(void) {
+    return (LocaleMeasurementUnits)furi_hal_rtc_get_locale_units();
+}
+
+void locale_set_measurement_unit(LocaleMeasurementUnits format) {
+    furi_hal_rtc_set_locale_units((FuriHalRtcLocaleUnits)format);
+}
+
+LocaleTimeFormat locale_get_time_format(void) {
+    return (LocaleTimeFormat)furi_hal_rtc_get_locale_timeformat();
+}
+
+void locale_set_time_format(LocaleTimeFormat format) {
+    furi_hal_rtc_set_locale_timeformat((FuriHalRtcLocaleTimeFormat)format);
+}
+
+LocaleDateFormat locale_get_date_format(void) {
+    return (LocaleDateFormat)furi_hal_rtc_get_locale_dateformat();
+}
+
+void locale_set_date_format(LocaleDateFormat format) {
+    furi_hal_rtc_set_locale_dateformat((FuriHalRtcLocaleDateFormat)format);
+}
+
+float locale_fahrenheit_to_celsius(float temp_f) {
+    return (temp_f - 32.f) / 1.8f;
+}
+
+float locale_celsius_to_fahrenheit(float temp_c) {
+    return (temp_c * 1.8f + 32.f);
+}
+
+void locale_format_time(
+    FuriString* out_str,
+    const FuriHalRtcDateTime* datetime,
+    const LocaleTimeFormat format,
+    const bool show_seconds) {
+    furi_assert(out_str);
+    furi_assert(datetime);
+
+    uint8_t hours = datetime->hour;
+    uint8_t am_pm = 0;
+    if(format == LocaleTimeFormat12h) {
+        if(hours > 12) {
+            hours -= 12;
+            am_pm = 2;
+        } else {
+            am_pm = 1;
+        }
+    }
+
+    if(show_seconds) {
+        furi_string_printf(out_str, "%02u:%02u:%02u", hours, datetime->minute, datetime->second);
+    } else {
+        furi_string_printf(out_str, "%02u:%02u", hours, datetime->minute);
+    }
+
+    if(am_pm > 0) {
+        furi_string_cat_printf(out_str, " %s", (am_pm == 1) ? ("AM") : ("PM"));
+    }
+}
+
+void locale_format_date(
+    FuriString* out_str,
+    const FuriHalRtcDateTime* datetime,
+    const LocaleDateFormat format,
+    const char* separator) {
+    furi_assert(out_str);
+    furi_assert(datetime);
+    furi_assert(separator);
+
+    if(format == LocaleDateFormatDMY) {
+        furi_string_printf(
+            out_str,
+            "%02u%s%02u%s%04u",
+            datetime->day,
+            separator,
+            datetime->month,
+            separator,
+            datetime->year);
+    } else if(format == LocaleDateFormatMDY) {
+        furi_string_printf(
+            out_str,
+            "%02u%s%02u%s%04u",
+            datetime->month,
+            separator,
+            datetime->day,
+            separator,
+            datetime->year);
+    } else {
+        furi_string_printf(
+            out_str,
+            "%04u%s%02u%s%02u",
+            datetime->year,
+            separator,
+            datetime->month,
+            separator,
+            datetime->day);
+    }
+}
+
+int32_t locale_on_system_start(void* p) {
+    UNUSED(p);
+    return 0;
+}

+ 107 - 0
applications/services/locale/locale.h

@@ -0,0 +1,107 @@
+#pragma once
+
+#include <stdbool.h>
+#include <furi.h>
+#include <furi_hal.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+    LocaleMeasurementUnitsMetric = 0, /**< Metric measurement units */
+    LocaleMeasurementUnitsImperial = 1, /**< Imperial measurement units */
+} LocaleMeasurementUnits;
+
+typedef enum {
+    LocaleTimeFormat24h = 0, /**< 24-hour format */
+    LocaleTimeFormat12h = 1, /**< 12-hour format */
+} LocaleTimeFormat;
+
+typedef enum {
+    LocaleDateFormatDMY = 0, /**< Day/Month/Year */
+    LocaleDateFormatMDY = 1, /**< Month/Day/Year */
+    LocaleDateFormatYMD = 2, /**< Year/Month/Day */
+} LocaleDateFormat;
+
+/** Get Locale measurement units
+ *
+ * @return     The locale measurement units.
+ */
+LocaleMeasurementUnits locale_get_measurement_unit();
+
+/** Set locale measurement units
+ *
+ * @param[in]  format  The locale measurements units
+ */
+void locale_set_measurement_unit(LocaleMeasurementUnits format);
+
+/** Convert Fahrenheit to Celsius
+ *
+ * @param[in]  temp_f  The Temperature in Fahrenheit
+ *
+ * @return     The Temperature in Celsius 
+ */
+float locale_fahrenheit_to_celsius(float temp_f);
+
+/** Convert Celsius to Fahrenheit
+ *
+ * @param[in]  temp_c  The Temperature in Celsius 
+ *
+ * @return     The Temperature in Fahrenheit
+ */
+float locale_celsius_to_fahrenheit(float temp_c);
+
+/** Get Locale time format
+ *
+ * @return     The locale time format.
+ */
+LocaleTimeFormat locale_get_time_format();
+
+/** Set Locale Time Format
+ *
+ * @param[in]  format  The Locale Time Format
+ */
+void locale_set_time_format(LocaleTimeFormat format);
+
+/** Format time to furi string
+ *
+ * @param[out] out_str       The FuriString to store formatted time
+ * @param[in]  datetime      Pointer to the datetime
+ * @param[in]  format        The Locale Time Format
+ * @param[in]  show_seconds  The show seconds flag
+ */
+void locale_format_time(
+    FuriString* out_str,
+    const FuriHalRtcDateTime* datetime,
+    const LocaleTimeFormat format,
+    const bool show_seconds);
+
+/** Get Locale DateFormat
+ *
+ * @return     The Locale DateFormat.
+ */
+LocaleDateFormat locale_get_date_format();
+
+/** Set Locale DateFormat
+ *
+ * @param[in]  format  The Locale DateFormat
+ */
+void locale_set_date_format(LocaleDateFormat format);
+
+/** Format date to furi string
+ *
+ * @param[out] out_str    The FuriString to store formatted date
+ * @param[in]  datetime   Pointer to the datetime
+ * @param[in]  format     The format
+ * @param[in]  separator  The separator
+ */
+void locale_format_date(
+    FuriString* out_str,
+    const FuriHalRtcDateTime* datetime,
+    const LocaleDateFormat format,
+    const char* separator);
+
+#ifdef __cplusplus
+}
+#endif

+ 1 - 1
applications/settings/system/application.fam

@@ -3,7 +3,7 @@ App(
     name="System",
     name="System",
     apptype=FlipperAppType.SETTINGS,
     apptype=FlipperAppType.SETTINGS,
     entry_point="system_settings_app",
     entry_point="system_settings_app",
-    requires=["gui"],
+    requires=["gui", "locale"],
     stack_size=1 * 1024,
     stack_size=1 * 1024,
     order=70,
     order=70,
 )
 )

+ 79 - 0
applications/settings/system/system_settings.c

@@ -1,6 +1,7 @@
 #include "system_settings.h"
 #include "system_settings.h"
 #include <loader/loader.h>
 #include <loader/loader.h>
 #include <lib/toolbox/value_index.h>
 #include <lib/toolbox/value_index.h>
+#include <locale/locale.h>
 
 
 const char* const log_level_text[] = {
 const char* const log_level_text[] = {
     "Default",
     "Default",
@@ -70,6 +71,59 @@ static void heap_trace_mode_changed(VariableItem* item) {
     furi_hal_rtc_set_heap_track_mode(heap_trace_mode_value[index]);
     furi_hal_rtc_set_heap_track_mode(heap_trace_mode_value[index]);
 }
 }
 
 
+const char* const mesurement_units_text[] = {
+    "Metric",
+    "Imperial",
+};
+
+const uint32_t mesurement_units_value[] = {
+    LocaleMeasurementUnitsMetric,
+    LocaleMeasurementUnitsImperial,
+};
+
+static void mesurement_units_changed(VariableItem* item) {
+    // SystemSettings* app = variable_item_get_context(item);
+    uint8_t index = variable_item_get_current_value_index(item);
+    variable_item_set_current_value_text(item, mesurement_units_text[index]);
+    locale_set_measurement_unit(mesurement_units_value[index]);
+}
+
+const char* const time_format_text[] = {
+    "24h",
+    "12h",
+};
+
+const uint32_t time_format_value[] = {
+    LocaleTimeFormat24h,
+    LocaleTimeFormat12h,
+};
+
+static void time_format_changed(VariableItem* item) {
+    // SystemSettings* app = variable_item_get_context(item);
+    uint8_t index = variable_item_get_current_value_index(item);
+    variable_item_set_current_value_text(item, time_format_text[index]);
+    locale_set_time_format(time_format_value[index]);
+}
+
+const char* const date_format_text[] = {
+    "D/M/Y",
+    "M/D/Y",
+    "Y/M/D",
+};
+
+const uint32_t date_format_value[] = {
+    LocaleDateFormatDMY,
+    LocaleDateFormatMDY,
+    LocaleDateFormatYMD,
+};
+
+static void date_format_changed(VariableItem* item) {
+    // SystemSettings* app = variable_item_get_context(item);
+    uint8_t index = variable_item_get_current_value_index(item);
+    variable_item_set_current_value_text(item, date_format_text[index]);
+    locale_set_date_format(date_format_value[index]);
+}
+
 static uint32_t system_settings_exit(void* context) {
 static uint32_t system_settings_exit(void* context) {
     UNUSED(context);
     UNUSED(context);
     return VIEW_NONE;
     return VIEW_NONE;
@@ -91,6 +145,31 @@ SystemSettings* system_settings_alloc() {
     uint8_t value_index;
     uint8_t value_index;
     app->var_item_list = variable_item_list_alloc();
     app->var_item_list = variable_item_list_alloc();
 
 
+    item = variable_item_list_add(
+        app->var_item_list,
+        "Units",
+        COUNT_OF(mesurement_units_text),
+        mesurement_units_changed,
+        app);
+    value_index = value_index_uint32(
+        locale_get_measurement_unit(), mesurement_units_value, COUNT_OF(mesurement_units_value));
+    variable_item_set_current_value_index(item, value_index);
+    variable_item_set_current_value_text(item, mesurement_units_text[value_index]);
+
+    item = variable_item_list_add(
+        app->var_item_list, "Time Format", COUNT_OF(time_format_text), time_format_changed, app);
+    value_index = value_index_uint32(
+        locale_get_time_format(), time_format_value, COUNT_OF(time_format_value));
+    variable_item_set_current_value_index(item, value_index);
+    variable_item_set_current_value_text(item, time_format_text[value_index]);
+
+    item = variable_item_list_add(
+        app->var_item_list, "Date Format", COUNT_OF(date_format_text), date_format_changed, app);
+    value_index = value_index_uint32(
+        locale_get_date_format(), date_format_value, COUNT_OF(date_format_value));
+    variable_item_set_current_value_index(item, value_index);
+    variable_item_set_current_value_text(item, date_format_text[value_index]);
+
     item = variable_item_list_add(
     item = variable_item_list_add(
         app->var_item_list, "Log Level", COUNT_OF(log_level_text), log_level_changed, app);
         app->var_item_list, "Log Level", COUNT_OF(log_level_text), log_level_changed, app);
     value_index = value_index_uint32(
     value_index = value_index_uint32(

+ 18 - 1
firmware/targets/f7/api_symbols.csv

@@ -1,5 +1,5 @@
 entry,status,name,type,params
 entry,status,name,type,params
-Version,+,11.0,,
+Version,+,11.1,,
 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,,
@@ -29,6 +29,7 @@ Header,+,applications/services/gui/view_dispatcher.h,,
 Header,+,applications/services/gui/view_stack.h,,
 Header,+,applications/services/gui/view_stack.h,,
 Header,+,applications/services/input/input.h,,
 Header,+,applications/services/input/input.h,,
 Header,+,applications/services/loader/loader.h,,
 Header,+,applications/services/loader/loader.h,,
+Header,+,applications/services/locale/locale.h,,
 Header,+,applications/services/notification/notification.h,,
 Header,+,applications/services/notification/notification.h,,
 Header,+,applications/services/notification/notification_messages.h,,
 Header,+,applications/services/notification/notification_messages.h,,
 Header,+,applications/services/power/power_service/power.h,,
 Header,+,applications/services/power/power_service/power.h,,
@@ -1265,6 +1266,9 @@ Function,+,furi_hal_rtc_get_boot_mode,FuriHalRtcBootMode,
 Function,+,furi_hal_rtc_get_datetime,void,FuriHalRtcDateTime*
 Function,+,furi_hal_rtc_get_datetime,void,FuriHalRtcDateTime*
 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_timeformat,FuriHalRtcLocaleTimeFormat,
+Function,+,furi_hal_rtc_get_locale_units,FuriHalRtcLocaleUnits,
 Function,+,furi_hal_rtc_get_log_level,uint8_t,
 Function,+,furi_hal_rtc_get_log_level,uint8_t,
 Function,+,furi_hal_rtc_get_pin_fails,uint32_t,
 Function,+,furi_hal_rtc_get_pin_fails,uint32_t,
 Function,+,furi_hal_rtc_get_register,uint32_t,FuriHalRtcRegister
 Function,+,furi_hal_rtc_get_register,uint32_t,FuriHalRtcRegister
@@ -1278,6 +1282,9 @@ Function,+,furi_hal_rtc_set_datetime,void,FuriHalRtcDateTime*
 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
+Function,+,furi_hal_rtc_set_locale_dateformat,void,FuriHalRtcLocaleDateFormat
+Function,+,furi_hal_rtc_set_locale_timeformat,void,FuriHalRtcLocaleTimeFormat
+Function,+,furi_hal_rtc_set_locale_units,void,FuriHalRtcLocaleUnits
 Function,+,furi_hal_rtc_set_log_level,void,uint8_t
 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"
@@ -1736,6 +1743,16 @@ Function,+,loader_update_menu,void,
 Function,+,loading_alloc,Loading*,
 Function,+,loading_alloc,Loading*,
 Function,+,loading_free,void,Loading*
 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_fahrenheit_to_celsius,float,float
+Function,+,locale_format_date,void,"FuriString*, const FuriHalRtcDateTime*, const LocaleDateFormat, const char*"
+Function,+,locale_format_time,void,"FuriString*, const FuriHalRtcDateTime*, const LocaleTimeFormat, const _Bool"
+Function,+,locale_get_date_format,LocaleDateFormat,
+Function,+,locale_get_measurement_unit,LocaleMeasurementUnits,
+Function,+,locale_get_time_format,LocaleTimeFormat,
+Function,+,locale_set_date_format,void,LocaleDateFormat
+Function,+,locale_set_measurement_unit,void,LocaleMeasurementUnits
+Function,+,locale_set_time_format,void,LocaleTimeFormat
 Function,-,localtime,tm*,const time_t*
 Function,-,localtime,tm*,const time_t*
 Function,-,localtime_r,tm*,"const time_t*, tm*"
 Function,-,localtime_r,tm*,"const time_t*, tm*"
 Function,-,log,double,double
 Function,-,log,double,double

+ 58 - 16
firmware/targets/f7/furi_hal/furi_hal_rtc.c

@@ -29,12 +29,15 @@ typedef struct {
     uint8_t log_level : 4;
     uint8_t log_level : 4;
     uint8_t log_reserved : 4;
     uint8_t log_reserved : 4;
     uint8_t flags;
     uint8_t flags;
-    uint8_t boot_mode : 4;
-    uint8_t heap_track_mode : 2;
-    uint16_t reserved : 10;
-} DeveloperReg;
+    FuriHalRtcBootMode boot_mode : 4;
+    FuriHalRtcHeapTrackMode heap_track_mode : 2;
+    FuriHalRtcLocaleUnits locale_units : 1;
+    FuriHalRtcLocaleTimeFormat locale_timeformat : 1;
+    FuriHalRtcLocaleDateFormat locale_dateformat : 2;
+    uint8_t reserved : 6;
+} SystemReg;
 
 
-_Static_assert(sizeof(DeveloperReg) == 4, "DeveloperReg size mismatch");
+_Static_assert(sizeof(SystemReg) == 4, "SystemReg size mismatch");
 
 
 #define FURI_HAL_RTC_SECONDS_PER_MINUTE 60
 #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_HOUR (FURI_HAL_RTC_SECONDS_PER_MINUTE * 60)
@@ -172,7 +175,7 @@ void furi_hal_rtc_set_register(FuriHalRtcRegister reg, uint32_t value) {
 
 
 void furi_hal_rtc_set_log_level(uint8_t level) {
 void furi_hal_rtc_set_log_level(uint8_t level) {
     uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
     uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
-    DeveloperReg* data = (DeveloperReg*)&data_reg;
+    SystemReg* data = (SystemReg*)&data_reg;
     data->log_level = level;
     data->log_level = level;
     furi_hal_rtc_set_register(FuriHalRtcRegisterSystem, data_reg);
     furi_hal_rtc_set_register(FuriHalRtcRegisterSystem, data_reg);
     furi_log_set_level(level);
     furi_log_set_level(level);
@@ -180,13 +183,13 @@ void furi_hal_rtc_set_log_level(uint8_t level) {
 
 
 uint8_t furi_hal_rtc_get_log_level() {
 uint8_t furi_hal_rtc_get_log_level() {
     uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
     uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
-    DeveloperReg* data = (DeveloperReg*)&data_reg;
+    SystemReg* data = (SystemReg*)&data_reg;
     return data->log_level;
     return data->log_level;
 }
 }
 
 
 void furi_hal_rtc_set_flag(FuriHalRtcFlag flag) {
 void furi_hal_rtc_set_flag(FuriHalRtcFlag flag) {
     uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
     uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
-    DeveloperReg* data = (DeveloperReg*)&data_reg;
+    SystemReg* data = (SystemReg*)&data_reg;
     data->flags |= flag;
     data->flags |= flag;
     furi_hal_rtc_set_register(FuriHalRtcRegisterSystem, data_reg);
     furi_hal_rtc_set_register(FuriHalRtcRegisterSystem, data_reg);
 
 
@@ -197,7 +200,7 @@ void furi_hal_rtc_set_flag(FuriHalRtcFlag flag) {
 
 
 void furi_hal_rtc_reset_flag(FuriHalRtcFlag flag) {
 void furi_hal_rtc_reset_flag(FuriHalRtcFlag flag) {
     uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
     uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
-    DeveloperReg* data = (DeveloperReg*)&data_reg;
+    SystemReg* data = (SystemReg*)&data_reg;
     data->flags &= ~flag;
     data->flags &= ~flag;
     furi_hal_rtc_set_register(FuriHalRtcRegisterSystem, data_reg);
     furi_hal_rtc_set_register(FuriHalRtcRegisterSystem, data_reg);
 
 
@@ -208,34 +211,73 @@ void furi_hal_rtc_reset_flag(FuriHalRtcFlag flag) {
 
 
 bool furi_hal_rtc_is_flag_set(FuriHalRtcFlag flag) {
 bool furi_hal_rtc_is_flag_set(FuriHalRtcFlag flag) {
     uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
     uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
-    DeveloperReg* data = (DeveloperReg*)&data_reg;
+    SystemReg* data = (SystemReg*)&data_reg;
     return data->flags & flag;
     return data->flags & flag;
 }
 }
 
 
 void furi_hal_rtc_set_boot_mode(FuriHalRtcBootMode mode) {
 void furi_hal_rtc_set_boot_mode(FuriHalRtcBootMode mode) {
     uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
     uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
-    DeveloperReg* data = (DeveloperReg*)&data_reg;
+    SystemReg* data = (SystemReg*)&data_reg;
     data->boot_mode = mode;
     data->boot_mode = mode;
     furi_hal_rtc_set_register(FuriHalRtcRegisterSystem, data_reg);
     furi_hal_rtc_set_register(FuriHalRtcRegisterSystem, data_reg);
 }
 }
 
 
 FuriHalRtcBootMode furi_hal_rtc_get_boot_mode() {
 FuriHalRtcBootMode furi_hal_rtc_get_boot_mode() {
     uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
     uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
-    DeveloperReg* data = (DeveloperReg*)&data_reg;
-    return (FuriHalRtcBootMode)data->boot_mode;
+    SystemReg* data = (SystemReg*)&data_reg;
+    return data->boot_mode;
 }
 }
 
 
 void furi_hal_rtc_set_heap_track_mode(FuriHalRtcHeapTrackMode mode) {
 void furi_hal_rtc_set_heap_track_mode(FuriHalRtcHeapTrackMode mode) {
     uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
     uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
-    DeveloperReg* data = (DeveloperReg*)&data_reg;
+    SystemReg* data = (SystemReg*)&data_reg;
     data->heap_track_mode = mode;
     data->heap_track_mode = mode;
     furi_hal_rtc_set_register(FuriHalRtcRegisterSystem, data_reg);
     furi_hal_rtc_set_register(FuriHalRtcRegisterSystem, data_reg);
 }
 }
 
 
 FuriHalRtcHeapTrackMode furi_hal_rtc_get_heap_track_mode() {
 FuriHalRtcHeapTrackMode furi_hal_rtc_get_heap_track_mode() {
     uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
     uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
-    DeveloperReg* data = (DeveloperReg*)&data_reg;
-    return (FuriHalRtcHeapTrackMode)data->heap_track_mode;
+    SystemReg* data = (SystemReg*)&data_reg;
+    return data->heap_track_mode;
+}
+
+void furi_hal_rtc_set_locale_units(FuriHalRtcLocaleUnits value) {
+    uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
+    SystemReg* data = (SystemReg*)&data_reg;
+    data->locale_units = value;
+    furi_hal_rtc_set_register(FuriHalRtcRegisterSystem, data_reg);
+}
+
+FuriHalRtcLocaleUnits furi_hal_rtc_get_locale_units() {
+    uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
+    SystemReg* data = (SystemReg*)&data_reg;
+    return data->locale_units;
+}
+
+void furi_hal_rtc_set_locale_timeformat(FuriHalRtcLocaleTimeFormat value) {
+    uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
+    SystemReg* data = (SystemReg*)&data_reg;
+    data->locale_timeformat = value;
+    furi_hal_rtc_set_register(FuriHalRtcRegisterSystem, data_reg);
+}
+
+FuriHalRtcLocaleTimeFormat furi_hal_rtc_get_locale_timeformat() {
+    uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
+    SystemReg* data = (SystemReg*)&data_reg;
+    return data->locale_timeformat;
+}
+
+void furi_hal_rtc_set_locale_dateformat(FuriHalRtcLocaleDateFormat value) {
+    uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
+    SystemReg* data = (SystemReg*)&data_reg;
+    data->locale_dateformat = value;
+    furi_hal_rtc_set_register(FuriHalRtcRegisterSystem, data_reg);
+}
+
+FuriHalRtcLocaleDateFormat furi_hal_rtc_get_locale_dateformat() {
+    uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
+    SystemReg* data = (SystemReg*)&data_reg;
+    return data->locale_dateformat;
 }
 }
 
 
 void furi_hal_rtc_set_datetime(FuriHalRtcDateTime* datetime) {
 void furi_hal_rtc_set_datetime(FuriHalRtcDateTime* datetime) {

+ 142 - 1
firmware/targets/furi_hal_include/furi_hal_rtc.h

@@ -59,53 +59,194 @@ typedef enum {
     FuriHalRtcRegisterMAX, /**< Service value, do not use */
     FuriHalRtcRegisterMAX, /**< Service value, do not use */
 } FuriHalRtcRegister;
 } FuriHalRtcRegister;
 
 
+typedef enum {
+    FuriHalRtcLocaleUnitsMetric = 0, /**< Metric measurement units */
+    FuriHalRtcLocaleUnitsImperial = 1, /**< Imperial measurement units */
+} FuriHalRtcLocaleUnits;
+
+typedef enum {
+    FuriHalRtcLocaleTimeFormat24h = 0, /**< 24-hour format */
+    FuriHalRtcLocaleTimeFormat12h = 1, /**< 12-hour format */
+} FuriHalRtcLocaleTimeFormat;
+
+typedef enum {
+    FuriHalRtcLocaleDateFormatDMY = 0, /**< Day/Month/Year */
+    FuriHalRtcLocaleDateFormatMDY = 1, /**< Month/Day/Year */
+    FuriHalRtcLocaleDateFormatYMD = 2, /**< Year/Month/Day */
+} FuriHalRtcLocaleDateFormat;
+
 /** Early initialization */
 /** Early initialization */
 void furi_hal_rtc_init_early();
 void furi_hal_rtc_init_early();
 
 
-/** Early deinitialization */
+/** Early de-initialization */
 void furi_hal_rtc_deinit_early();
 void furi_hal_rtc_deinit_early();
 
 
 /** Initialize RTC subsystem */
 /** Initialize RTC subsystem */
 void furi_hal_rtc_init();
 void furi_hal_rtc_init();
 
 
+/** Get RTC register content
+ *
+ * @param[in]  reg   The register identifier
+ *
+ * @return     content of the register
+ */
 uint32_t furi_hal_rtc_get_register(FuriHalRtcRegister reg);
 uint32_t furi_hal_rtc_get_register(FuriHalRtcRegister reg);
 
 
+/** Set register content
+ *
+ * @param[in]  reg    The register identifier
+ * @param[in]  value  The value to store into register
+ */
 void furi_hal_rtc_set_register(FuriHalRtcRegister reg, uint32_t value);
 void furi_hal_rtc_set_register(FuriHalRtcRegister reg, uint32_t value);
 
 
+/** Set Log Level value
+ *
+ * @param[in]  level  The level to store
+ */
 void furi_hal_rtc_set_log_level(uint8_t level);
 void furi_hal_rtc_set_log_level(uint8_t level);
 
 
+/** Get Log Level value
+ *
+ * @return     The Log Level value
+ */
 uint8_t furi_hal_rtc_get_log_level();
 uint8_t furi_hal_rtc_get_log_level();
 
 
+/** Set RTC Flag
+ *
+ * @param[in]  flag  The flag to set
+ */
 void furi_hal_rtc_set_flag(FuriHalRtcFlag flag);
 void furi_hal_rtc_set_flag(FuriHalRtcFlag flag);
 
 
+/** Reset RTC Flag
+ *
+ * @param[in]  flag  The flag to reset
+ */
 void furi_hal_rtc_reset_flag(FuriHalRtcFlag flag);
 void furi_hal_rtc_reset_flag(FuriHalRtcFlag flag);
 
 
+/** Check if RTC Flag is set
+ *
+ * @param[in]  flag  The flag to check
+ *
+ * @return     true if set
+ */
 bool furi_hal_rtc_is_flag_set(FuriHalRtcFlag flag);
 bool furi_hal_rtc_is_flag_set(FuriHalRtcFlag flag);
 
 
+/** Set RTC boot mode
+ *
+ * @param[in]  mode  The mode to set
+ */
 void furi_hal_rtc_set_boot_mode(FuriHalRtcBootMode mode);
 void furi_hal_rtc_set_boot_mode(FuriHalRtcBootMode mode);
 
 
+/** Get RTC boot mode
+ *
+ * @return     The RTC boot mode.
+ */
 FuriHalRtcBootMode furi_hal_rtc_get_boot_mode();
 FuriHalRtcBootMode furi_hal_rtc_get_boot_mode();
 
 
+/** Set Heap Track mode
+ *
+ * @param[in]  mode  The mode to set
+ */
 void furi_hal_rtc_set_heap_track_mode(FuriHalRtcHeapTrackMode mode);
 void furi_hal_rtc_set_heap_track_mode(FuriHalRtcHeapTrackMode mode);
 
 
+/** Get RTC Heap Track mode
+ *
+ * @return     The RTC heap track mode.
+ */
 FuriHalRtcHeapTrackMode furi_hal_rtc_get_heap_track_mode();
 FuriHalRtcHeapTrackMode furi_hal_rtc_get_heap_track_mode();
 
 
+/** Set locale units
+ *
+ * @param[in]  mode  The RTC Locale Units
+ */
+void furi_hal_rtc_set_locale_units(FuriHalRtcLocaleUnits value);
+
+/** Get RTC Locale Units
+ *
+ * @return     The RTC Locale Units.
+ */
+FuriHalRtcLocaleUnits furi_hal_rtc_get_locale_units();
+
+/** Set RTC Locale Time Format
+ *
+ * @param[in]  value  The RTC Locale Time Format
+ */
+void furi_hal_rtc_set_locale_timeformat(FuriHalRtcLocaleTimeFormat value);
+
+/** Get RTC Locale Time Format
+ *
+ * @return     The RTC Locale Time Format.
+ */
+FuriHalRtcLocaleTimeFormat furi_hal_rtc_get_locale_timeformat();
+
+/** Set RTC Locale Date Format
+ *
+ * @param[in]  value  The RTC Locale Date Format
+ */
+void furi_hal_rtc_set_locale_dateformat(FuriHalRtcLocaleDateFormat value);
+
+/** Get RTC Locale Date Format
+ *
+ * @return     The RTC Locale Date Format
+ */
+FuriHalRtcLocaleDateFormat furi_hal_rtc_get_locale_dateformat();
+
+/** Set RTC Date Time
+ *
+ * @param      datetime  The date time to set
+ */
 void furi_hal_rtc_set_datetime(FuriHalRtcDateTime* datetime);
 void furi_hal_rtc_set_datetime(FuriHalRtcDateTime* datetime);
 
 
+/** Get RTC Date Time
+ *
+ * @param      datetime  The datetime
+ */
 void furi_hal_rtc_get_datetime(FuriHalRtcDateTime* datetime);
 void furi_hal_rtc_get_datetime(FuriHalRtcDateTime* datetime);
 
 
+/** Validate Date Time
+ *
+ * @param      datetime  The datetime to validate
+ *
+ * @return     { description_of_the_return_value }
+ */
 bool furi_hal_rtc_validate_datetime(FuriHalRtcDateTime* datetime);
 bool furi_hal_rtc_validate_datetime(FuriHalRtcDateTime* datetime);
 
 
+/** Set RTC Fault Data
+ *
+ * @param[in]  value  The value
+ */
 void furi_hal_rtc_set_fault_data(uint32_t value);
 void furi_hal_rtc_set_fault_data(uint32_t value);
 
 
+/** Get RTC Fault Data
+ *
+ * @return     RTC Fault Data value
+ */
 uint32_t furi_hal_rtc_get_fault_data();
 uint32_t furi_hal_rtc_get_fault_data();
 
 
+/** Set Pin Fails count
+ *
+ * @param[in]  value  The Pin Fails count
+ */
 void furi_hal_rtc_set_pin_fails(uint32_t value);
 void furi_hal_rtc_set_pin_fails(uint32_t value);
 
 
+/** Get Pin Fails count
+ *
+ * @return     Pin Fails Count
+ */
 uint32_t furi_hal_rtc_get_pin_fails();
 uint32_t furi_hal_rtc_get_pin_fails();
 
 
+/** Get UNIX Timestamp
+ *
+ * @return     Unix Timestamp in seconds from UNIX epoch start
+ */
 uint32_t furi_hal_rtc_get_timestamp();
 uint32_t furi_hal_rtc_get_timestamp();
 
 
+/** Convert DateTime to UNIX timestamp
+ *
+ * @param      datetime  The datetime
+ *
+ * @return     UNIX Timestamp in seconds from UNIX epoch start
+ */
 uint32_t furi_hal_rtc_datetime_to_timestamp(FuriHalRtcDateTime* datetime);
 uint32_t furi_hal_rtc_datetime_to_timestamp(FuriHalRtcDateTime* datetime);
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus