clock_app.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. #include <furi.h>
  2. #include <furi_hal.h>
  3. #include <gui/gui.h>
  4. #include <locale/locale.h>
  5. typedef enum {
  6. ClockEventTypeTick,
  7. ClockEventTypeKey,
  8. } ClockEventType;
  9. typedef struct {
  10. ClockEventType type;
  11. InputEvent input;
  12. } ClockEvent;
  13. typedef struct {
  14. FuriString* buffer;
  15. FuriHalRtcDateTime datetime;
  16. LocaleTimeFormat timeformat;
  17. LocaleDateFormat dateformat;
  18. } ClockData;
  19. typedef struct {
  20. FuriMutex* mutex;
  21. FuriMessageQueue* queue;
  22. ClockData* data;
  23. } Clock;
  24. static void clock_input_callback(InputEvent* input_event, FuriMessageQueue* queue) {
  25. furi_assert(queue);
  26. ClockEvent event = {.type = ClockEventTypeKey, .input = *input_event};
  27. furi_message_queue_put(queue, &event, FuriWaitForever);
  28. }
  29. static void clock_render_callback(Canvas* canvas, void* ctx) {
  30. Clock* clock = ctx;
  31. if(furi_mutex_acquire(clock->mutex, 200) != FuriStatusOk) {
  32. return;
  33. }
  34. ClockData* data = clock->data;
  35. canvas_set_font(canvas, FontBigNumbers);
  36. locale_format_time(data->buffer, &data->datetime, data->timeformat, true);
  37. canvas_draw_str_aligned(
  38. canvas, 64, 28, AlignCenter, AlignCenter, furi_string_get_cstr(data->buffer));
  39. // Special case to cover missing glyphs in FontBigNumbers
  40. if(data->timeformat == LocaleTimeFormat12h) {
  41. size_t time_width = canvas_string_width(canvas, furi_string_get_cstr(data->buffer));
  42. canvas_set_font(canvas, FontPrimary);
  43. canvas_draw_str_aligned(
  44. canvas,
  45. 64 + (time_width / 2) - 10,
  46. 31,
  47. AlignLeft,
  48. AlignCenter,
  49. (data->datetime.hour > 11) ? "PM" : "AM");
  50. }
  51. canvas_set_font(canvas, FontSecondary);
  52. locale_format_date(data->buffer, &data->datetime, data->dateformat, "/");
  53. canvas_draw_str_aligned(
  54. canvas, 64, 42, AlignCenter, AlignTop, furi_string_get_cstr(data->buffer));
  55. furi_mutex_release(clock->mutex);
  56. }
  57. static void clock_tick(void* ctx) {
  58. furi_assert(ctx);
  59. FuriMessageQueue* queue = ctx;
  60. ClockEvent event = {.type = ClockEventTypeTick};
  61. // It's OK to loose this event if system overloaded
  62. furi_message_queue_put(queue, &event, 0);
  63. }
  64. int32_t clock_app(void* p) {
  65. UNUSED(p);
  66. Clock* clock = malloc(sizeof(Clock));
  67. clock->data = malloc(sizeof(ClockData));
  68. clock->data->buffer = furi_string_alloc();
  69. clock->queue = furi_message_queue_alloc(8, sizeof(ClockEvent));
  70. clock->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
  71. furi_hal_rtc_get_datetime(&clock->data->datetime);
  72. clock->data->timeformat = locale_get_time_format();
  73. clock->data->dateformat = locale_get_date_format();
  74. // Set ViewPort callbacks
  75. ViewPort* view_port = view_port_alloc();
  76. view_port_draw_callback_set(view_port, clock_render_callback, clock);
  77. view_port_input_callback_set(view_port, clock_input_callback, clock->queue);
  78. FuriTimer* timer = furi_timer_alloc(clock_tick, FuriTimerTypePeriodic, clock->queue);
  79. // Open GUI and register view_port
  80. Gui* gui = furi_record_open(RECORD_GUI);
  81. gui_add_view_port(gui, view_port, GuiLayerFullscreen);
  82. furi_timer_start(timer, 100);
  83. // Main loop
  84. ClockEvent event;
  85. for(bool processing = true; processing;) {
  86. furi_check(furi_message_queue_get(clock->queue, &event, FuriWaitForever) == FuriStatusOk);
  87. furi_mutex_acquire(clock->mutex, FuriWaitForever);
  88. if(event.type == ClockEventTypeKey) {
  89. if(event.input.type == InputTypeShort && event.input.key == InputKeyBack) {
  90. processing = false;
  91. }
  92. } else if(event.type == ClockEventTypeTick) {
  93. furi_hal_rtc_get_datetime(&clock->data->datetime);
  94. }
  95. furi_mutex_release(clock->mutex);
  96. view_port_update(view_port);
  97. }
  98. furi_timer_free(timer);
  99. view_port_enabled_set(view_port, false);
  100. gui_remove_view_port(gui, view_port);
  101. view_port_free(view_port);
  102. furi_record_close(RECORD_GUI);
  103. furi_message_queue_free(clock->queue);
  104. furi_mutex_free(clock->mutex);
  105. furi_string_free(clock->data->buffer);
  106. free(clock->data);
  107. free(clock);
  108. return 0;
  109. }