| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614 |
- #include "scene_msf.h"
- #include "app_state.h"
- #include "furi_hal_rtc.h"
- #include "longwave_clock_app.h"
- #include "module_date.h"
- #include "module_lights.h"
- #include "module_rollbits.h"
- #include "module_time.h"
- #define TOP_BAR 0
- #define TOP_TIME 30
- #define TOP_DATE 53
- #define DURATION_DIFF(x, y) (((x) < (y)) ? ((y) - (x)) : ((x) - (y)))
- /** main menu events */
- static bool lwc_msf_scene_input(InputEvent* input_event, void* context) {
- UNUSED(input_event);
- UNUSED(context);
- return false;
- }
- static void lwc_msf_scene_draw(Canvas* canvas, void* context) {
- LWCViewModel* model = context;
- canvas_clear(canvas);
- draw_decoded_bits(
- canvas,
- MSF,
- TOP_BAR,
- model->buffer,
- BUFFER,
- model->received_count,
- model->last_received,
- model->received_interrupt < MIN_INTERRUPT,
- model->decoding == DecodingUnknown);
- draw_decoded_time(
- canvas,
- TOP_TIME,
- model->decoding_time,
- model->hours_10s,
- model->hours_1s,
- model->minutes_10s,
- model->minutes_1s,
- model->seconds,
- model->timezone,
- model->seconds > 51);
- draw_decoded_date(
- canvas,
- TOP_DATE,
- model->decoding_date,
- 20,
- model->year_10s,
- model->year_1s,
- model->month_10s,
- model->month_1s,
- model->day_of_month_10s,
- model->day_of_month_1s,
- model->day_of_week);
- }
- static void msf_add_gui_bit(LWCViewModel* model, Bit bit) {
- if(model->last_received == BUFFER - 1) {
- model->last_received = 0;
- } else {
- model->last_received++;
- }
- if(model->received_count < BUFFER) {
- model->received_count++;
- }
- model->buffer[model->last_received] = bit;
- }
- static void msf_process_time_bit(LWCViewModel* model) {
- DecodingTimePhase old_decoding_time = model->decoding_time;
- DecodingTimePhase new_decoding_time = msf_get_decoding_time_phase(model->minute_data);
- if(model->decoding_time != new_decoding_time) {
- switch(old_decoding_time) {
- case DecodingTimeHours10s:
- model->hours_10s = msf_decode_hours_10s(model->minute_data);
- break;
- case DecodingTimeHours1s:
- model->hours_1s = msf_decode_hours_1s(model->minute_data);
- break;
- case DecodingTimeMinutes10s:
- model->minutes_10s = msf_decode_minutes_10s(model->minute_data);
- break;
- case DecodingTimeMinutes1s:
- model->minutes_1s = msf_decode_minutes_1s(model->minute_data);
- break;
- case DecodingTimeTimezone:
- model->timezone = msf_decode_timezone(model->minute_data);
- break;
- default:
- }
- switch(new_decoding_time) {
- case DecodingTimeTimezone:
- msf_add_gui_bit(model, BitStartTimezone);
- break;
- case DecodingTimeMinutes10s:
- msf_add_gui_bit(model, BitStartMinute);
- break;
- case DecodingTimeMinutes1s:
- msf_add_gui_bit(model, BitStartEmpty);
- break;
- case DecodingTimeHours10s:
- msf_add_gui_bit(model, BitStartHour);
- break;
- case DecodingTimeHours1s:
- msf_add_gui_bit(model, BitStartEmpty);
- break;
- case DecodingTimeConstant:
- msf_add_gui_bit(model, BitConstant);
- break;
- case DecodingTimeChecksum:
- msf_add_gui_bit(model, BitStartEmpty);
- break;
- default:
- }
- model->decoding_time = new_decoding_time;
- } else if(new_decoding_time == DecodingTimeChecksum) {
- if(msf_get_time_checksum(model->minute_data) != 1) {
- model->minutes_1s = -1;
- model->minutes_10s = -1;
- model->hours_1s = -1;
- model->hours_10s = -1;
- msf_add_gui_bit(model, BitChecksumError);
- } else {
- msf_add_gui_bit(model, BitChecksum);
- }
- }
- }
- static void msf_process_date_bit(LWCViewModel* model, DecodingPhase current_phase) {
- DecodingDatePhase new_decoding_date;
- if(current_phase == DecodingDate) {
- new_decoding_date = msf_get_decoding_date_phase(model->minute_data);
- } else {
- new_decoding_date = DecodingNoDate;
- }
- if(model->decoding_date != new_decoding_date) {
- switch(new_decoding_date) {
- case DecodingDateDayOfMonth10s:
- model->month_1s = msf_decode_month_1s(model->minute_data);
- msf_add_gui_bit(model, BitStartDayOfMonth);
- break;
- case DecodingDateDayOfMonth1s:
- model->day_of_month_10s = msf_decode_day_of_month_10s(model->minute_data);
- msf_add_gui_bit(model, BitStartEmpty);
- break;
- case DecodingDateDayOfWeek:
- model->day_of_month_1s = msf_decode_day_of_month_1s(model->minute_data);
- msf_add_gui_bit(model, BitStartDayOfWeek);
- break;
- case DecodingDateMonth10s:
- model->year_1s = msf_decode_year_1s(model->minute_data);
- msf_add_gui_bit(model, BitStartMonth);
- break;
- case DecodingDateMonth1s:
- model->month_10s = msf_decode_month_10s(model->minute_data);
- msf_add_gui_bit(model, BitStartEmpty);
- break;
- case DecodingDateYear10s:
- msf_add_gui_bit(model, BitStartYear);
- break;
- case DecodingDateYear1s:
- model->year_10s = msf_decode_year_10s(model->minute_data);
- msf_add_gui_bit(model, BitStartEmpty);
- break;
- case DecodingDateYearChecksum:
- msf_add_gui_bit(model, BitStartEmpty);
- break;
- case DecodingDateInYearChecksum:
- msf_add_gui_bit(model, BitStartEmpty);
- break;
- case DecodingDateDayOfWeekChecksum:
- msf_add_gui_bit(model, BitStartEmpty);
- break;
- default:
- }
- model->decoding_date = new_decoding_date;
- } else {
- switch(new_decoding_date) {
- case DecodingDateYearChecksum:
- if(msf_get_year_checksum(model->minute_data) != 1) {
- model->year_10s = -1;
- model->year_1s = -1;
- msf_add_gui_bit(model, BitChecksumError);
- } else {
- msf_add_gui_bit(model, BitChecksum);
- }
- break;
- case DecodingDateInYearChecksum:
- if(msf_get_inyear_checksum(model->minute_data) != 1) {
- model->month_10s = -1;
- model->month_1s = -1;
- model->day_of_month_1s = -1;
- model->day_of_month_10s = -1;
- msf_add_gui_bit(model, BitChecksumError);
- } else {
- msf_add_gui_bit(model, BitChecksum);
- }
- break;
- case DecodingDateDayOfWeekChecksum:
- if(msf_get_dow_checksum(model->minute_data) != 1) {
- model->day_of_week = -1;
- msf_add_gui_bit(model, BitChecksumError);
- } else {
- msf_add_gui_bit(model, BitChecksum);
- }
- break;
- default:
- }
- }
- }
- static void msf_process_finish_time_phase(LWCViewModel* model, DecodingTimePhase last_time_phase) {
- UNUSED(last_time_phase);
- model->decoding_time = DecodingNoTime;
- }
- static void msf_process_finish_date_phase(LWCViewModel* model, DecodingDatePhase last_date_phase) {
- if(last_date_phase == DecodingDateDayOfWeek) {
- model->day_of_week = msf_decode_day_of_week(model->minute_data);
- }
- model->decoding_date = DecodingNoDate;
- }
- static void msf_receive_bit(void* context, bool is_b, int8_t received_bit) {
- View* view = context;
- FURI_LOG_D(TAG, "Received a %d", received_bit);
- with_view_model(
- view,
- LWCViewModel * model,
- {
- model->received_interrupt = MIN_INTERRUPT;
- minute_data_add_bit(model->minute_data, received_bit);
- if(!is_b) {
- int8_t seconds = minute_data_get_length(model->minute_data) / 2;
- if(seconds > 0) {
- model->seconds = seconds;
- }
- }
- DecodingPhase old_phase = model->decoding;
- model->decoding = msf_get_decoding_phase(model->minute_data);
- bool change_phase = model->decoding != old_phase;
- if(change_phase) {
- switch(old_phase) {
- case DecodingTime:
- msf_process_finish_time_phase(model, model->decoding_time);
- break;
- case DecodingDate:
- msf_process_finish_date_phase(model, model->decoding_date);
- break;
- case DecodingUnknown:
- model->decoding_time = DecodingNoTime;
- model->decoding_date = DecodingNoDate;
- break;
- case DecodingMeta:
- model->decoding_time = DecodingNoTime;
- model->decoding_date = DecodingNoDate;
- msf_add_gui_bit(model, BitConstant);
- break;
- default:
- break;
- }
- switch(model->decoding) {
- case DecodingMeta:
- msf_add_gui_bit(model, BitConstant);
- break;
- case DecodingDUT:
- model->decoding_time = DecodingNoTime;
- model->decoding_date = DecodingNoDate;
- msf_add_gui_bit(model, BitStartDUT);
- break;
- default:
- break;
- }
- }
- switch(model->decoding) {
- case DecodingTime:
- msf_process_time_bit(model);
- break;
- case DecodingDate:
- msf_process_date_bit(model, model->decoding);
- break;
- default:
- break;
- }
- msf_add_gui_bit(model, (Bit)received_bit % 2);
- },
- true);
- }
- static void msf_receive_start_of_minute(void* context) {
- View* view = context;
- FURI_LOG_I(TAG, "Found the MSF synchronization, starting a new minute!");
- with_view_model(
- view,
- LWCViewModel * model,
- {
- model->received_interrupt = MIN_INTERRUPT;
- msf_add_gui_bit(model, BitEndMinute);
- minute_data_start_minute(model->minute_data);
- minute_data_add_bit(model->minute_data, 1);
- msf_add_gui_bit(model, BitOne);
- minute_data_add_bit(model->minute_data, 1);
- msf_add_gui_bit(model, BitOne);
- model->seconds = 0;
- },
- true);
- }
- static void msf_receive_desync(void* context) {
- View* view = context;
- FURI_LOG_I(TAG, "Got a DESYNC error, resetting all!");
- with_view_model(
- view,
- LWCViewModel * model,
- {
- model->decoding = DecodingUnknown;
- model->decoding_time = DecodingNoTime;
- model->decoding_date = DecodingNoDate;
- msf_add_gui_bit(model, BitEndSync);
- },
- true);
- }
- static void msf_receive_unknown(void* context) {
- View* view = context;
- FURI_LOG_I(TAG, "Not received any bit, assuming a missing receipt!");
- with_view_model(
- view,
- LWCViewModel * model,
- {
- minute_data_add_bit(model->minute_data, -1);
- msf_add_gui_bit(model, BitUnknown);
- },
- true);
- }
- static void msf_receive_interrupt(void* context) {
- View* view = context;
- with_view_model(view, LWCViewModel * model, { model->received_interrupt++; }, true);
- }
- static void msf_receive_gpio(GPIOEvent event, void* context) {
- App* app = context;
- if(!event.shift_up) {
- if(event.time_passed_down > 400) { // Decode A after the second marker
- if(DURATION_DIFF(event.time_passed_up, 100) < 50) { // A0
- scene_manager_handle_custom_event(app->scene_manager, LCWMSFEventReceiveA0);
- } else if(DURATION_DIFF(event.time_passed_up, 250) < 100) { //A1B0 or A1B1
- scene_manager_handle_custom_event(app->scene_manager, LCWMSFEventReceiveA1);
- }
- } else {
- scene_manager_handle_custom_event(app->scene_manager, LCWMSFEventReceiveInterrupt);
- }
- } else if(event.time_passed_down > 750) {
- scene_manager_handle_custom_event(app->scene_manager, LCWMSFEventReceiveB0);
- } else if(
- DURATION_DIFF(event.time_passed_down, 500) < 50 &&
- DURATION_DIFF(event.time_passed_up, 500) < 50) {
- scene_manager_handle_custom_event(app->scene_manager, LCWMSFEventReceiveSync);
- } else if(DURATION_DIFF(event.time_passed_down, 600) < 150) {
- scene_manager_handle_custom_event(app->scene_manager, LCWMSFEventReceiveB1);
- } else {
- scene_manager_handle_custom_event(app->scene_manager, LCWMSFEventReceiveInterrupt);
- FURI_LOG_E(
- TAG,
- "DOWN up for %lu, last down for %lu",
- event.time_passed_up,
- event.time_passed_down);
- }
- }
- bool lwc_msf_scene_on_event(void* context, SceneManagerEvent event) {
- App* app = context;
- bool consumed = false;
- switch(event.type) {
- case SceneManagerEventTypeCustom:
- LWCMSFEvent msf_event = event.event;
- switch(msf_event) {
- case LCWMSFEventReceiveA0:
- lwc_app_led_on_receive_clear(app);
- msf_receive_bit(app->msf_view, false, 0);
- consumed = true;
- break;
- case LCWMSFEventReceiveA1:
- lwc_app_led_on_receive_clear(app);
- msf_receive_bit(app->msf_view, false, 1);
- consumed = true;
- break;
- case LCWMSFEventReceiveB0:
- lwc_app_led_on_receive_clear(app);
- msf_receive_bit(app->msf_view, true, 0);
- consumed = true;
- break;
- case LCWMSFEventReceiveB1:
- lwc_app_led_on_receive_clear(app);
- msf_receive_bit(app->msf_view, true, 1);
- consumed = true;
- break;
- case LCWMSFEventReceiveSync:
- lwc_app_led_on_sync(app);
- msf_receive_start_of_minute(app->msf_view);
- consumed = true;
- break;
- case LCWMSFEventReceiveDesync:
- lwc_app_led_on_desync(app);
- msf_receive_desync(app->msf_view);
- consumed = true;
- break;
- case LCWMSFEventReceiveUnknown:
- msf_receive_unknown(app->msf_view);
- lwc_app_led_on_receive_unknown(app);
- consumed = true;
- break;
- case LCWMSFEventReceiveInterrupt:
- msf_receive_interrupt(app->msf_view);
- consumed = true;
- break;
- default:
- }
- break;
- case SceneManagerEventTypeTick:
- if(app->state->gpio != NULL) {
- for(int i = 10; i > 0 && gpio_callback_with_event(app->state->gpio, msf_receive_gpio);
- i--) {
- }
- }
- consumed = true;
- break;
- default:
- consumed = false;
- break;
- }
- return consumed;
- }
- static void msf_refresh_simulated_data(MinuteData* simulation_data, DateTime datetime) {
- FURI_LOG_I(TAG, "Setting simulated data for minute %d", datetime.minute);
- msf_set_simulated_minute_data(
- simulation_data,
- datetime.second,
- datetime.minute,
- datetime.hour,
- datetime.weekday,
- datetime.day,
- datetime.month,
- datetime.year % 100);
- }
- static void msf_500ms_callback(void* context) {
- App* app = context;
- if(lwc_get_protocol_config(app->state)->run_mode == Demo) {
- MinuteData* simulation = app->state->simulation_data;
- DateTime now;
- furi_hal_rtc_get_datetime(&now);
- if(now.second < MINUTE && simulation->index != now.second * 2) {
- simulation->index += 2;
- if(now.second == 0) {
- msf_refresh_simulated_data(app->state->simulation_data, now);
- scene_manager_handle_custom_event(app->scene_manager, LCWMSFEventReceiveSync);
- } else {
- if(minute_data_get_bit(app->state->simulation_data, now.second * 2) == 0) {
- scene_manager_handle_custom_event(app->scene_manager, LCWMSFEventReceiveA0);
- } else {
- scene_manager_handle_custom_event(app->scene_manager, LCWMSFEventReceiveA1);
- }
- if(minute_data_get_bit(app->state->simulation_data, now.second * 2 + 1) == 0) {
- scene_manager_handle_custom_event(app->scene_manager, LCWMSFEventReceiveB0);
- } else {
- scene_manager_handle_custom_event(app->scene_manager, LCWMSFEventReceiveB1);
- }
- }
- }
- }
- MinuteDataError result;
- with_view_model(
- app->msf_view,
- LWCViewModel * model,
- { result = minute_data_500ms_passed(model->minute_data); },
- false);
- switch(result) {
- case MinuteDataErrorNone:
- break;
- case MinuteDataErrorUnknownBit:
- scene_manager_handle_custom_event(app->scene_manager, LCWMSFEventReceiveUnknown);
- break;
- case MinuteDataErrorDesync:
- scene_manager_handle_custom_event(app->scene_manager, LCWMSFEventReceiveDesync);
- break;
- }
- }
- void lwc_msf_scene_on_enter(void* context) {
- App* app = context;
- ProtoConfig* config = lwc_get_protocol_config(app->state);
- with_view_model(
- app->msf_view,
- LWCViewModel * model,
- {
- model->decoding = DecodingUnknown;
- model->decoding_time = DecodingNoTime;
- model->decoding_date = DecodingNoDate;
- model->year_10s = -1;
- model->year_1s = -1;
- model->month_10s = -1;
- model->month_1s = -1;
- model->day_of_month_1s = -1;
- model->day_of_month_10s = -1;
- model->day_of_week = -1;
- model->hours_10s = -1;
- model->hours_1s = -1;
- model->minutes_10s = -1;
- model->minutes_1s = -1;
- model->seconds = -1;
- model->timezone = UnknownTimezone;
- model->last_received = BUFFER - 1;
- model->received_interrupt = config->run_mode == Demo ? MIN_INTERRUPT : 0;
- model->received_count = 0;
- minute_data_reset(model->minute_data);
- },
- true);
- switch(config->run_mode) {
- case Demo:
- app->state->simulation_data = minute_data_alloc(120);
- DateTime now;
- furi_hal_rtc_get_datetime(&now);
- msf_refresh_simulated_data(app->state->simulation_data, now);
- break;
- case GPIO:
- app->state->gpio =
- gpio_start_listening(config->data_pin, config->data_mode == Inverted, app);
- break;
- default:
- break;
- }
- app->state->seconds_timer = furi_timer_alloc(msf_500ms_callback, FuriTimerTypePeriodic, app);
- furi_timer_start(app->state->seconds_timer, furi_kernel_get_tick_frequency() / 2);
- view_dispatcher_switch_to_view(app->view_dispatcher, LWCMSFView);
- }
- void lwc_msf_scene_on_exit(void* context) {
- App* app = context;
- notification_message_block(app->notifications, &sequence_display_backlight_enforce_auto);
- furi_timer_stop(app->state->seconds_timer);
- furi_timer_free(app->state->seconds_timer);
- switch(lwc_get_protocol_config(app->state)->run_mode) {
- case Demo:
- minute_data_free(app->state->simulation_data);
- break;
- case GPIO:
- gpio_stop_listening(app->state->gpio);
- break;
- default:
- break;
- }
- }
- View* lwc_msf_scene_alloc() {
- View* view = view_alloc();
- view_allocate_model(view, ViewModelTypeLocking, sizeof(LWCViewModel));
- with_view_model(
- view, LWCViewModel * model, { model->minute_data = minute_data_alloc(120); }, true);
- view_set_context(view, view);
- view_set_input_callback(view, lwc_msf_scene_input);
- view_set_draw_callback(view, lwc_msf_scene_draw);
- return view;
- }
- void lwc_msf_scene_free(View* view) {
- furi_assert(view);
- with_view_model(view, LWCViewModel * model, { minute_data_free(model->minute_data); }, false);
- view_free(view);
- }
|