scene_msf.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614
  1. #include "scene_msf.h"
  2. #include "app_state.h"
  3. #include "furi_hal_rtc.h"
  4. #include "longwave_clock_app.h"
  5. #include "module_date.h"
  6. #include "module_lights.h"
  7. #include "module_rollbits.h"
  8. #include "module_time.h"
  9. #define TOP_BAR 0
  10. #define TOP_TIME 30
  11. #define TOP_DATE 53
  12. #define DURATION_DIFF(x, y) (((x) < (y)) ? ((y) - (x)) : ((x) - (y)))
  13. /** main menu events */
  14. static bool lwc_msf_scene_input(InputEvent* input_event, void* context) {
  15. UNUSED(input_event);
  16. UNUSED(context);
  17. return false;
  18. }
  19. static void lwc_msf_scene_draw(Canvas* canvas, void* context) {
  20. LWCViewModel* model = context;
  21. canvas_clear(canvas);
  22. draw_decoded_bits(
  23. canvas,
  24. MSF,
  25. TOP_BAR,
  26. model->buffer,
  27. BUFFER,
  28. model->received_count,
  29. model->last_received,
  30. model->received_interrupt < MIN_INTERRUPT,
  31. model->decoding == DecodingUnknown);
  32. draw_decoded_time(
  33. canvas,
  34. TOP_TIME,
  35. model->decoding_time,
  36. model->hours_10s,
  37. model->hours_1s,
  38. model->minutes_10s,
  39. model->minutes_1s,
  40. model->seconds,
  41. model->timezone,
  42. model->seconds > 51);
  43. draw_decoded_date(
  44. canvas,
  45. TOP_DATE,
  46. model->decoding_date,
  47. 20,
  48. model->year_10s,
  49. model->year_1s,
  50. model->month_10s,
  51. model->month_1s,
  52. model->day_of_month_10s,
  53. model->day_of_month_1s,
  54. model->day_of_week);
  55. }
  56. static void msf_add_gui_bit(LWCViewModel* model, Bit bit) {
  57. if(model->last_received == BUFFER - 1) {
  58. model->last_received = 0;
  59. } else {
  60. model->last_received++;
  61. }
  62. if(model->received_count < BUFFER) {
  63. model->received_count++;
  64. }
  65. model->buffer[model->last_received] = bit;
  66. }
  67. static void msf_process_time_bit(LWCViewModel* model) {
  68. DecodingTimePhase old_decoding_time = model->decoding_time;
  69. DecodingTimePhase new_decoding_time = msf_get_decoding_time_phase(model->minute_data);
  70. if(model->decoding_time != new_decoding_time) {
  71. switch(old_decoding_time) {
  72. case DecodingTimeHours10s:
  73. model->hours_10s = msf_decode_hours_10s(model->minute_data);
  74. break;
  75. case DecodingTimeHours1s:
  76. model->hours_1s = msf_decode_hours_1s(model->minute_data);
  77. break;
  78. case DecodingTimeMinutes10s:
  79. model->minutes_10s = msf_decode_minutes_10s(model->minute_data);
  80. break;
  81. case DecodingTimeMinutes1s:
  82. model->minutes_1s = msf_decode_minutes_1s(model->minute_data);
  83. break;
  84. case DecodingTimeTimezone:
  85. model->timezone = msf_decode_timezone(model->minute_data);
  86. break;
  87. default:
  88. }
  89. switch(new_decoding_time) {
  90. case DecodingTimeTimezone:
  91. msf_add_gui_bit(model, BitStartTimezone);
  92. break;
  93. case DecodingTimeMinutes10s:
  94. msf_add_gui_bit(model, BitStartMinute);
  95. break;
  96. case DecodingTimeMinutes1s:
  97. msf_add_gui_bit(model, BitStartEmpty);
  98. break;
  99. case DecodingTimeHours10s:
  100. msf_add_gui_bit(model, BitStartHour);
  101. break;
  102. case DecodingTimeHours1s:
  103. msf_add_gui_bit(model, BitStartEmpty);
  104. break;
  105. case DecodingTimeConstant:
  106. msf_add_gui_bit(model, BitConstant);
  107. break;
  108. case DecodingTimeChecksum:
  109. msf_add_gui_bit(model, BitStartEmpty);
  110. break;
  111. default:
  112. }
  113. model->decoding_time = new_decoding_time;
  114. } else if(new_decoding_time == DecodingTimeChecksum) {
  115. if(msf_get_time_checksum(model->minute_data) != 1) {
  116. model->minutes_1s = -1;
  117. model->minutes_10s = -1;
  118. model->hours_1s = -1;
  119. model->hours_10s = -1;
  120. msf_add_gui_bit(model, BitChecksumError);
  121. } else {
  122. msf_add_gui_bit(model, BitChecksum);
  123. }
  124. }
  125. }
  126. static void msf_process_date_bit(LWCViewModel* model, DecodingPhase current_phase) {
  127. DecodingDatePhase new_decoding_date;
  128. if(current_phase == DecodingDate) {
  129. new_decoding_date = msf_get_decoding_date_phase(model->minute_data);
  130. } else {
  131. new_decoding_date = DecodingNoDate;
  132. }
  133. if(model->decoding_date != new_decoding_date) {
  134. switch(new_decoding_date) {
  135. case DecodingDateDayOfMonth10s:
  136. model->month_1s = msf_decode_month_1s(model->minute_data);
  137. msf_add_gui_bit(model, BitStartDayOfMonth);
  138. break;
  139. case DecodingDateDayOfMonth1s:
  140. model->day_of_month_10s = msf_decode_day_of_month_10s(model->minute_data);
  141. msf_add_gui_bit(model, BitStartEmpty);
  142. break;
  143. case DecodingDateDayOfWeek:
  144. model->day_of_month_1s = msf_decode_day_of_month_1s(model->minute_data);
  145. msf_add_gui_bit(model, BitStartDayOfWeek);
  146. break;
  147. case DecodingDateMonth10s:
  148. model->year_1s = msf_decode_year_1s(model->minute_data);
  149. msf_add_gui_bit(model, BitStartMonth);
  150. break;
  151. case DecodingDateMonth1s:
  152. model->month_10s = msf_decode_month_10s(model->minute_data);
  153. msf_add_gui_bit(model, BitStartEmpty);
  154. break;
  155. case DecodingDateYear10s:
  156. msf_add_gui_bit(model, BitStartYear);
  157. break;
  158. case DecodingDateYear1s:
  159. model->year_10s = msf_decode_year_10s(model->minute_data);
  160. msf_add_gui_bit(model, BitStartEmpty);
  161. break;
  162. case DecodingDateYearChecksum:
  163. msf_add_gui_bit(model, BitStartEmpty);
  164. break;
  165. case DecodingDateInYearChecksum:
  166. msf_add_gui_bit(model, BitStartEmpty);
  167. break;
  168. case DecodingDateDayOfWeekChecksum:
  169. msf_add_gui_bit(model, BitStartEmpty);
  170. break;
  171. default:
  172. }
  173. model->decoding_date = new_decoding_date;
  174. } else {
  175. switch(new_decoding_date) {
  176. case DecodingDateYearChecksum:
  177. if(msf_get_year_checksum(model->minute_data) != 1) {
  178. model->year_10s = -1;
  179. model->year_1s = -1;
  180. msf_add_gui_bit(model, BitChecksumError);
  181. } else {
  182. msf_add_gui_bit(model, BitChecksum);
  183. }
  184. break;
  185. case DecodingDateInYearChecksum:
  186. if(msf_get_inyear_checksum(model->minute_data) != 1) {
  187. model->month_10s = -1;
  188. model->month_1s = -1;
  189. model->day_of_month_1s = -1;
  190. model->day_of_month_10s = -1;
  191. msf_add_gui_bit(model, BitChecksumError);
  192. } else {
  193. msf_add_gui_bit(model, BitChecksum);
  194. }
  195. break;
  196. case DecodingDateDayOfWeekChecksum:
  197. if(msf_get_dow_checksum(model->minute_data) != 1) {
  198. model->day_of_week = -1;
  199. msf_add_gui_bit(model, BitChecksumError);
  200. } else {
  201. msf_add_gui_bit(model, BitChecksum);
  202. }
  203. break;
  204. default:
  205. }
  206. }
  207. }
  208. static void msf_process_finish_time_phase(LWCViewModel* model, DecodingTimePhase last_time_phase) {
  209. UNUSED(last_time_phase);
  210. model->decoding_time = DecodingNoTime;
  211. }
  212. static void msf_process_finish_date_phase(LWCViewModel* model, DecodingDatePhase last_date_phase) {
  213. if(last_date_phase == DecodingDateDayOfWeek) {
  214. model->day_of_week = msf_decode_day_of_week(model->minute_data);
  215. }
  216. model->decoding_date = DecodingNoDate;
  217. }
  218. static void msf_receive_bit(void* context, bool is_b, int8_t received_bit) {
  219. View* view = context;
  220. FURI_LOG_D(TAG, "Received a %d", received_bit);
  221. with_view_model(
  222. view,
  223. LWCViewModel * model,
  224. {
  225. model->received_interrupt = MIN_INTERRUPT;
  226. minute_data_add_bit(model->minute_data, received_bit);
  227. if(!is_b) {
  228. int8_t seconds = minute_data_get_length(model->minute_data) / 2;
  229. if(seconds > 0) {
  230. model->seconds = seconds;
  231. }
  232. }
  233. DecodingPhase old_phase = model->decoding;
  234. model->decoding = msf_get_decoding_phase(model->minute_data);
  235. bool change_phase = model->decoding != old_phase;
  236. if(change_phase) {
  237. switch(old_phase) {
  238. case DecodingTime:
  239. msf_process_finish_time_phase(model, model->decoding_time);
  240. break;
  241. case DecodingDate:
  242. msf_process_finish_date_phase(model, model->decoding_date);
  243. break;
  244. case DecodingUnknown:
  245. model->decoding_time = DecodingNoTime;
  246. model->decoding_date = DecodingNoDate;
  247. break;
  248. case DecodingMeta:
  249. model->decoding_time = DecodingNoTime;
  250. model->decoding_date = DecodingNoDate;
  251. msf_add_gui_bit(model, BitConstant);
  252. break;
  253. default:
  254. break;
  255. }
  256. switch(model->decoding) {
  257. case DecodingMeta:
  258. msf_add_gui_bit(model, BitConstant);
  259. break;
  260. case DecodingDUT:
  261. model->decoding_time = DecodingNoTime;
  262. model->decoding_date = DecodingNoDate;
  263. msf_add_gui_bit(model, BitStartDUT);
  264. break;
  265. default:
  266. break;
  267. }
  268. }
  269. switch(model->decoding) {
  270. case DecodingTime:
  271. msf_process_time_bit(model);
  272. break;
  273. case DecodingDate:
  274. msf_process_date_bit(model, model->decoding);
  275. break;
  276. default:
  277. break;
  278. }
  279. msf_add_gui_bit(model, (Bit)received_bit % 2);
  280. },
  281. true);
  282. }
  283. static void msf_receive_start_of_minute(void* context) {
  284. View* view = context;
  285. FURI_LOG_I(TAG, "Found the MSF synchronization, starting a new minute!");
  286. with_view_model(
  287. view,
  288. LWCViewModel * model,
  289. {
  290. model->received_interrupt = MIN_INTERRUPT;
  291. msf_add_gui_bit(model, BitEndMinute);
  292. minute_data_start_minute(model->minute_data);
  293. minute_data_add_bit(model->minute_data, 1);
  294. msf_add_gui_bit(model, BitOne);
  295. minute_data_add_bit(model->minute_data, 1);
  296. msf_add_gui_bit(model, BitOne);
  297. model->seconds = 0;
  298. },
  299. true);
  300. }
  301. static void msf_receive_desync(void* context) {
  302. View* view = context;
  303. FURI_LOG_I(TAG, "Got a DESYNC error, resetting all!");
  304. with_view_model(
  305. view,
  306. LWCViewModel * model,
  307. {
  308. model->decoding = DecodingUnknown;
  309. model->decoding_time = DecodingNoTime;
  310. model->decoding_date = DecodingNoDate;
  311. msf_add_gui_bit(model, BitEndSync);
  312. },
  313. true);
  314. }
  315. static void msf_receive_unknown(void* context) {
  316. View* view = context;
  317. FURI_LOG_I(TAG, "Not received any bit, assuming a missing receipt!");
  318. with_view_model(
  319. view,
  320. LWCViewModel * model,
  321. {
  322. minute_data_add_bit(model->minute_data, -1);
  323. msf_add_gui_bit(model, BitUnknown);
  324. },
  325. true);
  326. }
  327. static void msf_receive_interrupt(void* context) {
  328. View* view = context;
  329. with_view_model(view, LWCViewModel * model, { model->received_interrupt++; }, true);
  330. }
  331. static void msf_receive_gpio(GPIOEvent event, void* context) {
  332. App* app = context;
  333. if(!event.shift_up) {
  334. if(event.time_passed_down > 400) { // Decode A after the second marker
  335. if(DURATION_DIFF(event.time_passed_up, 100) < 50) { // A0
  336. scene_manager_handle_custom_event(app->scene_manager, LCWMSFEventReceiveA0);
  337. } else if(DURATION_DIFF(event.time_passed_up, 250) < 100) { //A1B0 or A1B1
  338. scene_manager_handle_custom_event(app->scene_manager, LCWMSFEventReceiveA1);
  339. }
  340. } else {
  341. scene_manager_handle_custom_event(app->scene_manager, LCWMSFEventReceiveInterrupt);
  342. }
  343. } else if(event.time_passed_down > 750) {
  344. scene_manager_handle_custom_event(app->scene_manager, LCWMSFEventReceiveB0);
  345. } else if(
  346. DURATION_DIFF(event.time_passed_down, 500) < 50 &&
  347. DURATION_DIFF(event.time_passed_up, 500) < 50) {
  348. scene_manager_handle_custom_event(app->scene_manager, LCWMSFEventReceiveSync);
  349. } else if(DURATION_DIFF(event.time_passed_down, 600) < 150) {
  350. scene_manager_handle_custom_event(app->scene_manager, LCWMSFEventReceiveB1);
  351. } else {
  352. scene_manager_handle_custom_event(app->scene_manager, LCWMSFEventReceiveInterrupt);
  353. FURI_LOG_E(
  354. TAG,
  355. "DOWN up for %lu, last down for %lu",
  356. event.time_passed_up,
  357. event.time_passed_down);
  358. }
  359. }
  360. bool lwc_msf_scene_on_event(void* context, SceneManagerEvent event) {
  361. App* app = context;
  362. bool consumed = false;
  363. switch(event.type) {
  364. case SceneManagerEventTypeCustom:
  365. LWCMSFEvent msf_event = event.event;
  366. switch(msf_event) {
  367. case LCWMSFEventReceiveA0:
  368. lwc_app_led_on_receive_clear(app);
  369. msf_receive_bit(app->msf_view, false, 0);
  370. consumed = true;
  371. break;
  372. case LCWMSFEventReceiveA1:
  373. lwc_app_led_on_receive_clear(app);
  374. msf_receive_bit(app->msf_view, false, 1);
  375. consumed = true;
  376. break;
  377. case LCWMSFEventReceiveB0:
  378. lwc_app_led_on_receive_clear(app);
  379. msf_receive_bit(app->msf_view, true, 0);
  380. consumed = true;
  381. break;
  382. case LCWMSFEventReceiveB1:
  383. lwc_app_led_on_receive_clear(app);
  384. msf_receive_bit(app->msf_view, true, 1);
  385. consumed = true;
  386. break;
  387. case LCWMSFEventReceiveSync:
  388. lwc_app_led_on_sync(app);
  389. msf_receive_start_of_minute(app->msf_view);
  390. consumed = true;
  391. break;
  392. case LCWMSFEventReceiveDesync:
  393. lwc_app_led_on_desync(app);
  394. msf_receive_desync(app->msf_view);
  395. consumed = true;
  396. break;
  397. case LCWMSFEventReceiveUnknown:
  398. msf_receive_unknown(app->msf_view);
  399. lwc_app_led_on_receive_unknown(app);
  400. consumed = true;
  401. break;
  402. case LCWMSFEventReceiveInterrupt:
  403. msf_receive_interrupt(app->msf_view);
  404. consumed = true;
  405. break;
  406. default:
  407. }
  408. break;
  409. case SceneManagerEventTypeTick:
  410. if(app->state->gpio != NULL) {
  411. for(int i = 10; i > 0 && gpio_callback_with_event(app->state->gpio, msf_receive_gpio);
  412. i--) {
  413. }
  414. }
  415. consumed = true;
  416. break;
  417. default:
  418. consumed = false;
  419. break;
  420. }
  421. return consumed;
  422. }
  423. static void msf_refresh_simulated_data(MinuteData* simulation_data, DateTime datetime) {
  424. FURI_LOG_I(TAG, "Setting simulated data for minute %d", datetime.minute);
  425. msf_set_simulated_minute_data(
  426. simulation_data,
  427. datetime.second,
  428. datetime.minute,
  429. datetime.hour,
  430. datetime.weekday,
  431. datetime.day,
  432. datetime.month,
  433. datetime.year % 100);
  434. }
  435. static void msf_500ms_callback(void* context) {
  436. App* app = context;
  437. if(lwc_get_protocol_config(app->state)->run_mode == Demo) {
  438. MinuteData* simulation = app->state->simulation_data;
  439. DateTime now;
  440. furi_hal_rtc_get_datetime(&now);
  441. if(now.second < MINUTE && simulation->index != now.second * 2) {
  442. simulation->index += 2;
  443. if(now.second == 0) {
  444. msf_refresh_simulated_data(app->state->simulation_data, now);
  445. scene_manager_handle_custom_event(app->scene_manager, LCWMSFEventReceiveSync);
  446. } else {
  447. if(minute_data_get_bit(app->state->simulation_data, now.second * 2) == 0) {
  448. scene_manager_handle_custom_event(app->scene_manager, LCWMSFEventReceiveA0);
  449. } else {
  450. scene_manager_handle_custom_event(app->scene_manager, LCWMSFEventReceiveA1);
  451. }
  452. if(minute_data_get_bit(app->state->simulation_data, now.second * 2 + 1) == 0) {
  453. scene_manager_handle_custom_event(app->scene_manager, LCWMSFEventReceiveB0);
  454. } else {
  455. scene_manager_handle_custom_event(app->scene_manager, LCWMSFEventReceiveB1);
  456. }
  457. }
  458. }
  459. }
  460. MinuteDataError result;
  461. with_view_model(
  462. app->msf_view,
  463. LWCViewModel * model,
  464. { result = minute_data_500ms_passed(model->minute_data); },
  465. false);
  466. switch(result) {
  467. case MinuteDataErrorNone:
  468. break;
  469. case MinuteDataErrorUnknownBit:
  470. scene_manager_handle_custom_event(app->scene_manager, LCWMSFEventReceiveUnknown);
  471. break;
  472. case MinuteDataErrorDesync:
  473. scene_manager_handle_custom_event(app->scene_manager, LCWMSFEventReceiveDesync);
  474. break;
  475. }
  476. }
  477. void lwc_msf_scene_on_enter(void* context) {
  478. App* app = context;
  479. ProtoConfig* config = lwc_get_protocol_config(app->state);
  480. with_view_model(
  481. app->msf_view,
  482. LWCViewModel * model,
  483. {
  484. model->decoding = DecodingUnknown;
  485. model->decoding_time = DecodingNoTime;
  486. model->decoding_date = DecodingNoDate;
  487. model->year_10s = -1;
  488. model->year_1s = -1;
  489. model->month_10s = -1;
  490. model->month_1s = -1;
  491. model->day_of_month_1s = -1;
  492. model->day_of_month_10s = -1;
  493. model->day_of_week = -1;
  494. model->hours_10s = -1;
  495. model->hours_1s = -1;
  496. model->minutes_10s = -1;
  497. model->minutes_1s = -1;
  498. model->seconds = -1;
  499. model->timezone = UnknownTimezone;
  500. model->last_received = BUFFER - 1;
  501. model->received_interrupt = config->run_mode == Demo ? MIN_INTERRUPT : 0;
  502. model->received_count = 0;
  503. minute_data_reset(model->minute_data);
  504. },
  505. true);
  506. switch(config->run_mode) {
  507. case Demo:
  508. app->state->simulation_data = minute_data_alloc(120);
  509. DateTime now;
  510. furi_hal_rtc_get_datetime(&now);
  511. msf_refresh_simulated_data(app->state->simulation_data, now);
  512. break;
  513. case GPIO:
  514. app->state->gpio =
  515. gpio_start_listening(config->data_pin, config->data_mode == Inverted, app);
  516. break;
  517. default:
  518. break;
  519. }
  520. app->state->seconds_timer = furi_timer_alloc(msf_500ms_callback, FuriTimerTypePeriodic, app);
  521. furi_timer_start(app->state->seconds_timer, furi_kernel_get_tick_frequency() / 2);
  522. view_dispatcher_switch_to_view(app->view_dispatcher, LWCMSFView);
  523. }
  524. void lwc_msf_scene_on_exit(void* context) {
  525. App* app = context;
  526. notification_message_block(app->notifications, &sequence_display_backlight_enforce_auto);
  527. furi_timer_stop(app->state->seconds_timer);
  528. furi_timer_free(app->state->seconds_timer);
  529. switch(lwc_get_protocol_config(app->state)->run_mode) {
  530. case Demo:
  531. minute_data_free(app->state->simulation_data);
  532. break;
  533. case GPIO:
  534. gpio_stop_listening(app->state->gpio);
  535. break;
  536. default:
  537. break;
  538. }
  539. }
  540. View* lwc_msf_scene_alloc() {
  541. View* view = view_alloc();
  542. view_allocate_model(view, ViewModelTypeLocking, sizeof(LWCViewModel));
  543. with_view_model(
  544. view, LWCViewModel * model, { model->minute_data = minute_data_alloc(120); }, true);
  545. view_set_context(view, view);
  546. view_set_input_callback(view, lwc_msf_scene_input);
  547. view_set_draw_callback(view, lwc_msf_scene_draw);
  548. return view;
  549. }
  550. void lwc_msf_scene_free(View* view) {
  551. furi_assert(view);
  552. with_view_model(view, LWCViewModel * model, { minute_data_free(model->minute_data); }, false);
  553. view_free(view);
  554. }