Skip to content

Commit ef52585

Browse files
committed
update dcf77 sync
1 parent 26fcf9d commit ef52585

File tree

4 files changed

+88
-101
lines changed

4 files changed

+88
-101
lines changed

non_catalog_apps/dcf77_clock_sync/application.fam

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ App(
88
order=10,
99
fap_icon="icons/app_10x10.png",
1010
fap_category="Tools",
11-
fap_author="@mdaskalov",
12-
fap_weburl="https://github.com/mdaskalov/dcf77-clock-sync.git",
13-
fap_version="1.1",
14-
fap_description="Emulate DCF77 time signal on the RFID antena and the A4 GPIO pin",
15-
)
11+
fap_author="mdaskalov",
12+
fap_weburl="https://github.com/mdaskalov/dcf77-clock-sync",
13+
fap_version="1.3",
14+
fap_description="Emulate DCF77 time signal on the RFID antenna and the A4 GPIO pin",
15+
)

non_catalog_apps/dcf77_clock_sync/dcf77.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#include <furi_hal.h>
1+
#include "dcf77.h"
22

33
#define DST_BIT 17
44
#define MIN_BIT 21
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
#pragma once
22

3-
#include <furi_hal.h>
3+
#include <datetime/datetime.h>
4+
#include <furi.h>
45

56
void set_dcf77_time(DateTime* dt, bool is_dst);
6-
int get_dcf77_bit(int sec);
7+
bool get_dcf77_bit(int sec);
78
char* get_dcf77_data(int sec);

non_catalog_apps/dcf77_clock_sync/dcf77_clock_sync.c

Lines changed: 79 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -4,63 +4,69 @@
44
#include <notification/notification.h>
55
#include <notification/notification_messages.h>
66

7+
#include <datetime/datetime.h>
8+
#include <locale/locale.h>
9+
710
#include "dcf77.h"
811

912
#define SCREEN_SIZE_X 128
1013
#define SCREEN_SIZE_Y 64
1114
#define DCF77_FREQ 77500
1215
#define DCF77_OFFSET 60
1316
#define SYNC_DELAY 50
14-
#define UPDATES 8
15-
16-
#define SECONDS_PER_MINUTE 60
17-
#define SECONDS_PER_HOUR (SECONDS_PER_MINUTE * 60)
18-
#define SECONDS_PER_DAY (SECONDS_PER_HOUR * 24)
19-
#define MONTHS_COUNT 12
20-
#define EPOCH_START_YEAR 1970
2117

2218
char* WEEKDAYS[] = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
2319

2420
typedef struct {
2521
DateTime dt;
26-
DateTime dcf_dt;
2722
bool is_dst;
23+
FuriString* str;
24+
LocaleTimeFormat tim_fmt;
25+
LocaleDateFormat dat_fmt;
2826
} AppData;
2927

3028
static void app_draw_callback(Canvas* canvas, void* context) {
31-
AppData* app_data = (AppData*)context;
32-
33-
char buffer[64];
29+
AppData* app = (AppData*)context;
30+
furi_assert(app->str);
31+
32+
uint8_t hour = app->dt.hour;
33+
bool fmt_12h = false;
34+
if(app->tim_fmt == LocaleTimeFormat12h) {
35+
hour = hour == 0 ? 12 : hour % 12;
36+
fmt_12h = true;
37+
}
3438

35-
snprintf(
36-
buffer,
37-
sizeof(buffer),
38-
"%02u:%02u:%02u",
39-
app_data->dt.hour,
40-
app_data->dt.minute,
41-
app_data->dt.second);
39+
furi_string_printf(app->str, "%2u:%02u:%02u", hour, app->dt.minute, app->dt.second);
40+
const char* tim_cstr = furi_string_get_cstr(app->str);
4241

4342
canvas_set_font(canvas, FontBigNumbers);
4443
canvas_draw_str_aligned(
45-
canvas, SCREEN_SIZE_X / 2, SCREEN_SIZE_Y / 2, AlignCenter, AlignCenter, buffer);
46-
47-
const char* dow_str = WEEKDAYS[(app_data->dt.weekday - 1) % 7];
48-
const char* dst_str = app_data->is_dst ? "CEST" : "CET";
49-
snprintf(
50-
buffer,
51-
sizeof(buffer),
52-
"%s %02u-%02u-%04u %s",
53-
dow_str,
54-
app_data->dt.day,
55-
app_data->dt.month,
56-
app_data->dt.year,
57-
dst_str);
44+
canvas, SCREEN_SIZE_X / 2, SCREEN_SIZE_Y / 2, AlignCenter, AlignCenter, tim_cstr);
45+
46+
if(fmt_12h) {
47+
canvas_set_font(canvas, FontSecondary);
48+
canvas_draw_str_aligned(
49+
canvas,
50+
0,
51+
(SCREEN_SIZE_Y / 2) - 7,
52+
AlignLeft,
53+
AlignTop,
54+
(app->dt.hour >= 12 ? "PM" : "AM"));
55+
}
56+
57+
FuriString* dat = furi_string_alloc();
58+
locale_format_date(dat, &app->dt, app->dat_fmt, "-");
59+
const char* dow_str = WEEKDAYS[(app->dt.weekday - 1) % 7];
60+
const char* dst_str = app->is_dst ? "CEST" : "CET";
61+
furi_string_printf(app->str, "%s %s %s", dow_str, furi_string_get_cstr(dat), dst_str);
62+
furi_string_free(dat);
5863

5964
canvas_set_font(canvas, FontSecondary);
60-
canvas_draw_str_aligned(canvas, SCREEN_SIZE_X / 2, 0, AlignCenter, AlignTop, buffer);
65+
canvas_draw_str_aligned(
66+
canvas, SCREEN_SIZE_X / 2, 0, AlignCenter, AlignTop, furi_string_get_cstr(app->str));
6167

62-
if(app_data->dt.second < 59) {
63-
char* data = get_dcf77_data(app_data->dt.second);
68+
if(app->dt.second < 59) {
69+
char* data = get_dcf77_data(app->dt.second);
6470
canvas_draw_str_aligned(
6571
canvas, SCREEN_SIZE_X, SCREEN_SIZE_Y, AlignRight, AlignBottom, data);
6672
}
@@ -72,48 +78,29 @@ static void app_input_callback(InputEvent* input_event, void* ctx) {
7278
furi_message_queue_put(event_queue, input_event, FuriWaitForever);
7379
}
7480

75-
void time_add(DateTime* from, DateTime* to, int add) {
76-
uint32_t timestamp = datetime_datetime_to_timestamp(from) + add;
77-
78-
uint32_t days = timestamp / SECONDS_PER_DAY;
79-
uint32_t seconds_in_day = timestamp % SECONDS_PER_DAY;
80-
81-
to->year = EPOCH_START_YEAR;
82-
83-
while(days >= datetime_get_days_per_year(to->year)) {
84-
days -= datetime_get_days_per_year(to->year);
85-
(to->year)++;
86-
}
87-
88-
to->month = 1;
89-
while(days >= datetime_get_days_per_month(datetime_is_leap_year(to->year), to->month)) {
90-
days -= datetime_get_days_per_month(datetime_is_leap_year(to->year), to->month);
91-
(to->month)++;
92-
}
93-
94-
to->weekday = ((days + 4) % 7) + 1;
95-
96-
to->day = days + 1;
97-
to->hour = seconds_in_day / SECONDS_PER_HOUR;
98-
to->minute = (seconds_in_day % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE;
99-
to->second = seconds_in_day % SECONDS_PER_MINUTE;
81+
void set_time(AppData* app, int offset) {
82+
DateTime dcf_dt;
83+
uint32_t timestamp = datetime_datetime_to_timestamp(&app->dt) + offset;
84+
datetime_timestamp_to_datetime(timestamp, &dcf_dt);
85+
set_dcf77_time(&dcf_dt, app->is_dst);
10086
}
10187

10288
int dcf77_clock_sync_app_main(void* p) {
10389
UNUSED(p);
10490

105-
AppData app_data;
106-
InputEvent event;
91+
AppData* app = malloc(sizeof(AppData));
92+
furi_hal_rtc_get_datetime(&app->dt);
93+
app->is_dst = false;
94+
app->str = furi_string_alloc();
95+
app->tim_fmt = locale_get_time_format();
96+
app->dat_fmt = locale_get_date_format();
10797

108-
app_data.is_dst = false;
109-
furi_hal_rtc_get_datetime(&app_data.dt);
110-
time_add(&app_data.dt, &app_data.dcf_dt, DCF77_OFFSET);
111-
set_dcf77_time(&app_data.dcf_dt, app_data.is_dst);
98+
set_time(app, DCF77_OFFSET);
11299

113100
ViewPort* view_port = view_port_alloc();
114101
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(InputEvent));
115102

116-
view_port_draw_callback_set(view_port, app_draw_callback, &app_data);
103+
view_port_draw_callback_set(view_port, app_draw_callback, app);
117104
view_port_input_callback_set(view_port, app_input_callback, event_queue);
118105

119106
Gui* gui = furi_record_open(RECORD_GUI);
@@ -122,52 +109,48 @@ int dcf77_clock_sync_app_main(void* p) {
122109
NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
123110
notification_message_block(notification, &sequence_display_backlight_enforce_on);
124111

112+
InputEvent event;
125113
bool running = false;
126114
bool exit = false;
127-
int sec = app_data.dt.second;
115+
int sec = app->dt.second;
128116
while(!exit) {
129117
int silence_ms = 0;
130118
// wait next second
131-
while(app_data.dt.second == sec) furi_hal_rtc_get_datetime(&app_data.dt);
119+
while(app->dt.second == sec) furi_hal_rtc_get_datetime(&app->dt);
132120

133-
if(app_data.dt.second < 59) {
134-
furi_hal_light_set(LightRed | LightGreen | LightBlue, 0);
121+
if(app->dt.second < 59) {
135122
if(running) {
123+
furi_hal_light_set(LightRed | LightGreen | LightBlue, 0);
136124
furi_hal_rfid_tim_read_stop();
137125
furi_hal_pwm_stop(FuriHalPwmOutputIdLptim2PA4);
138126
furi_hal_gpio_init(
139127
&gpio_ext_pa4, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
140128
}
141-
silence_ms = get_dcf77_bit(app_data.dt.second) ? 200 : 100;
129+
silence_ms = get_dcf77_bit(app->dt.second) ? 200 : 100;
142130
furi_delay_ms(silence_ms);
143131
furi_hal_rfid_tim_read_start(DCF77_FREQ, 0.5);
144132
furi_hal_pwm_start(FuriHalPwmOutputIdLptim2PA4, DCF77_FREQ, 50);
145-
running = true;
146133
furi_hal_light_set(LightBlue, 0xFF);
147-
} else {
148-
time_add(&app_data.dt, &app_data.dcf_dt, DCF77_OFFSET + 1);
149-
set_dcf77_time(&app_data.dcf_dt, app_data.is_dst);
150-
}
151-
152-
sec = app_data.dt.second;
153-
int wait_ms = (1000 - silence_ms - SYNC_DELAY) / UPDATES;
154-
for(int i = 0; i < UPDATES; i++) {
155-
if(furi_message_queue_get(event_queue, &event, wait_ms) == FuriStatusOk) {
156-
if((event.type == InputTypePress) || (event.type == InputTypeRepeat)) {
157-
switch(event.key) {
158-
case InputKeyOk:
159-
app_data.is_dst = !app_data.is_dst;
160-
break;
161-
case InputKeyBack:
162-
exit = true;
163-
break;
164-
default:
165-
break;
166-
}
134+
running = true;
135+
} else
136+
set_time(app, DCF77_OFFSET + 1);
137+
138+
sec = app->dt.second;
139+
int wait_ms = 1000 - silence_ms - SYNC_DELAY;
140+
uint32_t tick_start = furi_get_tick();
141+
while(wait_ms > 0) {
142+
FuriStatus status = furi_message_queue_get(event_queue, &event, wait_ms);
143+
if((status == FuriStatusOk) && (event.type == InputTypePress)) {
144+
if(event.key == InputKeyOk)
145+
app->is_dst = !app->is_dst;
146+
else if(event.key == InputKeyBack) {
147+
exit = true;
148+
break;
167149
}
168150
}
169151
view_port_update(view_port);
170-
if(exit) break;
152+
if(status == FuriStatusErrorTimeout) break;
153+
wait_ms -= furi_get_tick() - tick_start;
171154
}
172155
}
173156

@@ -186,5 +169,8 @@ int dcf77_clock_sync_app_main(void* p) {
186169
furi_message_queue_free(event_queue);
187170
view_port_free(view_port);
188171

172+
furi_string_free(app->str);
173+
free(app);
174+
189175
return 0;
190176
}

0 commit comments

Comments
 (0)