guifn.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. /*
  2. guifn.c
  3. */
  4. #include "gui.h"
  5. #include "datecalc.h"
  6. #include <string.h>
  7. /*============================================*/
  8. gui_alarm_t gui_alarm_list[GUI_ALARM_CNT];
  9. char gui_alarm_str[GUI_ALARM_CNT][8];
  10. uint32_t gui_backup_array[5];
  11. gui_data_t gui_data;
  12. menu_t gui_menu;
  13. /*============================================*/
  14. /* local functions */
  15. uint32_t get_u32_by_alarm_data(gui_alarm_t *alarm);
  16. void set_alarm_data_by_u32(gui_alarm_t *alarm, uint32_t u);
  17. void gui_alarm_calc_next_wd_alarm(uint8_t idx, uint16_t current_week_time_in_minutes);
  18. void gui_alarm_calc_str_time(uint8_t idx) U8G2_NOINLINE;
  19. void gui_date_adjust(void) U8G2_NOINLINE;
  20. void gui_calc_week_time(void);
  21. void gui_calc_next_alarm(void);
  22. /*============================================*/
  23. uint32_t get_u32_by_alarm_data(gui_alarm_t *alarm)
  24. {
  25. uint32_t u;
  26. int i;
  27. u = 0;
  28. for( i = 0; i < 7; i++ )
  29. {
  30. if ( alarm->wd[i] )
  31. {
  32. u |= 1<<i;
  33. }
  34. }
  35. /* 17 Sep 2017: fixed 32 bit handling for the next statements */
  36. u |= ((uint32_t)alarm->m&63) << (7);
  37. u |= ((uint32_t)alarm->h&31) << (7+6);
  38. u |= ((uint32_t)alarm->skip_wd&7) << (7+6+5);
  39. u |= ((uint32_t)alarm->enable&1) << (7+6+5+3);
  40. u |= ((uint32_t)alarm->snooze_count&1) << (7+6+5+3+1);
  41. return u;
  42. }
  43. void set_alarm_data_by_u32(gui_alarm_t *alarm, uint32_t u)
  44. {
  45. int i;
  46. for( i = 0; i < 7; i++ )
  47. {
  48. if ( (u & (1<<i)) != 0 )
  49. alarm->wd[i] = 1;
  50. else
  51. alarm->wd[i] = 0;
  52. }
  53. u>>=7;
  54. alarm->m = u & 63;
  55. u>>=6;
  56. alarm->h = u & 31;
  57. u>>=5;
  58. alarm->skip_wd = u & 7;
  59. u>>=3;
  60. alarm->enable = u & 1;
  61. u>>=1;
  62. alarm->snooze_count = u & 1;
  63. }
  64. /*============================================*/
  65. void gui_alarm_calc_next_wd_alarm(uint8_t idx, uint16_t current_week_time_in_minutes)
  66. {
  67. uint8_t i;
  68. uint16_t week_time_abs;
  69. uint16_t week_time_diff; /* difference to current_week_time_in_minutes */
  70. uint16_t best_diff = 0x0ffff;
  71. gui_alarm_list[idx].na_week_time_in_minutes = 0x0ffff; /* not found */
  72. gui_alarm_list[idx].na_minutes_diff = 0x0ffff; /* not found */
  73. gui_alarm_list[idx].na_wd = 7; /* not found */
  74. //printf("gui_alarm_calc_next_wd_alarm: %d\n", idx);
  75. if ( gui_alarm_list[idx].enable != 0 )
  76. {
  77. //printf("gui_alarm_calc_next_wd_alarm: %d enabled\n", idx);
  78. for( i = 0; i < 7; i++ )
  79. {
  80. if ( gui_alarm_list[idx].wd[i] != 0 )
  81. {
  82. //printf("gui_alarm_calc_next_wd_alarm: %d i=%d gui_alarm_list[idx].skip_wd=%d \n", idx, i, gui_alarm_list[idx].skip_wd);
  83. if ( gui_alarm_list[idx].skip_wd != i+1 )
  84. {
  85. week_time_abs = i;
  86. week_time_abs *= 24;
  87. week_time_abs += gui_alarm_list[idx].h;
  88. week_time_abs *= 60;
  89. week_time_abs += gui_alarm_list[idx].m;
  90. week_time_abs += gui_alarm_list[idx].snooze_count*(uint16_t)SNOOZE_MINUTES;
  91. if ( current_week_time_in_minutes <= week_time_abs )
  92. week_time_diff = week_time_abs - current_week_time_in_minutes;
  93. else
  94. week_time_diff = week_time_abs + 7*24*60 - current_week_time_in_minutes;
  95. //printf("gui_alarm_calc_next_wd_alarm: %d week_time_abs=%d current_week_time_in_minutes=%d week_time_diff=%d\n", idx, week_time_abs, current_week_time_in_minutes,week_time_diff);
  96. if ( best_diff > week_time_diff )
  97. {
  98. best_diff = week_time_diff;
  99. /* found for this alarm */
  100. gui_alarm_list[idx].na_minutes_diff = week_time_diff;
  101. gui_alarm_list[idx].na_week_time_in_minutes = week_time_abs;
  102. gui_alarm_list[idx].na_h = gui_alarm_list[idx].h;
  103. gui_alarm_list[idx].na_m = gui_alarm_list[idx].m;
  104. gui_alarm_list[idx].na_wd = i;
  105. }
  106. }
  107. }
  108. }
  109. }
  110. //printf("gui_alarm_calc_next_wd_alarm: %d na_minutes_diff=%d\n", idx, gui_alarm_list[idx].na_minutes_diff);
  111. //printf("gui_alarm_calc_next_wd_alarm: %d na_wd=%d\n", idx, gui_alarm_list[idx].na_wd);
  112. }
  113. void gui_alarm_calc_str_time(uint8_t idx)
  114. {
  115. gui_alarm_str[idx][0] = ' ';
  116. strcpy(gui_alarm_str[idx]+1, u8x8_u8toa(gui_alarm_list[idx].h, 2));
  117. strcpy(gui_alarm_str[idx]+4, u8x8_u8toa(gui_alarm_list[idx].m, 2));
  118. gui_alarm_str[idx][3] = ':';
  119. if ( gui_alarm_list[idx].enable == 0 )
  120. {
  121. gui_alarm_str[idx][0] = '(';
  122. gui_alarm_str[idx][6] = ')';
  123. gui_alarm_str[idx][7] = '\0';
  124. }
  125. }
  126. /* adjust day/month and calculates the weekday */
  127. /* this function must be called after reading from RTC or after setting the input vars by the user */
  128. void gui_date_adjust(void)
  129. {
  130. uint16_t ydn;
  131. uint16_t year;
  132. //uint16_t cdn;
  133. //uint32_t minutes_since_2000;
  134. if ( gui_data.month == 0 )
  135. gui_data.month++;
  136. if ( gui_data.day == 0 )
  137. gui_data.day++;
  138. year = 2000+gui_data.year_t*10 + gui_data.year_o;
  139. ydn = get_year_day_number(year, gui_data.month, gui_data.day);
  140. //cdn = to_century_day_number(year, ydn);
  141. //minutes_since_2000 = to_minutes(cdn, gui_data.h, gui_data.mt*10+gui_data.mo);
  142. // maybe adjust time by +/- 1h based on argument given to gui_date_adjust... but then it should be renamed also
  143. gui_data.month = get_month_by_year_day_number(year, ydn);
  144. gui_data.day = get_day_by_year_day_number(year, ydn);
  145. gui_data.weekday = get_weekday_by_year_day_number(year, ydn); /* 0 = Sunday */
  146. /* adjust the weekday so that 0 will be Monday */
  147. gui_data.weekday += 6;
  148. if ( gui_data.weekday >= 7 )
  149. gui_data.weekday -= 7;
  150. if ( gui_data.day != gui_data.last_day )
  151. {
  152. gui_data.uptime++;
  153. gui_data.last_day = gui_data.day;
  154. }
  155. }
  156. /*
  157. calculate the minute within the week.
  158. this must be called after gui_date_adjust(), because the weekday is used here
  159. */
  160. void gui_calc_week_time(void)
  161. {
  162. gui_data.week_time = gui_data.weekday;
  163. gui_data.week_time *= 24;
  164. gui_data.week_time += gui_data.h;
  165. gui_data.week_time *= 60;
  166. gui_data.week_time += gui_data.mt * 10 + gui_data.mo;
  167. }
  168. /*
  169. calculate the next alarm.
  170. this must be called after gui_calc_week_time() because, we need week_time
  171. */
  172. void gui_calc_next_alarm(void)
  173. {
  174. uint8_t i;
  175. uint8_t lowest_i;
  176. uint16_t lowest_diff;
  177. uint8_t redo;
  178. do
  179. {
  180. redo = 0;
  181. /* step 1: Calculate the difference to current weektime for each alarm */
  182. /* result is stored in gui_alarm_list[i].na_minutes_diff */
  183. for( i = 0; i < GUI_ALARM_CNT; i++ )
  184. gui_alarm_calc_next_wd_alarm(i, gui_data.week_time+(uint16_t)gui_data.is_equal); /* is_equal flag is used as a offset */
  185. /* step 2: find the index with the lowest difference */
  186. lowest_diff = 0x0ffff;
  187. lowest_i = GUI_ALARM_CNT;
  188. for( i = 0; i < GUI_ALARM_CNT; i++ )
  189. {
  190. if ( lowest_diff > gui_alarm_list[i].na_minutes_diff )
  191. {
  192. lowest_diff = gui_alarm_list[i].na_minutes_diff;
  193. lowest_i = i;
  194. }
  195. }
  196. /* step 3: store the result */
  197. gui_data.next_alarm_index = lowest_i; /* this can be GUI_ALARM_CNT */
  198. //printf("gui_calc_next_alarm gui_data.next_alarm_index=%d\n", gui_data.next_alarm_index);
  199. /* calculate the is_skip_possible and the is_alarm flag */
  200. gui_data.is_skip_possible = 0;
  201. if ( lowest_i < GUI_ALARM_CNT )
  202. {
  203. if ( gui_alarm_list[lowest_i].na_minutes_diff == 0 )
  204. {
  205. if ( gui_data.is_equal == 0 )
  206. {
  207. gui_data.is_alarm = 1;
  208. gui_data.is_equal = 1;
  209. gui_data.active_alarm_idx = lowest_i;
  210. //gui_data.active_equal_idx = lowest_i;
  211. gui_data.equal_h = gui_data.h;
  212. gui_data.equal_mt = gui_data.mt;
  213. gui_data.equal_mo = gui_data.mo;
  214. redo = 1;
  215. }
  216. }
  217. else
  218. {
  219. /* valid next alarm time */
  220. if ( gui_alarm_list[lowest_i].skip_wd == 0 )
  221. {
  222. /* skip flag not yet set */
  223. if ( gui_alarm_list[lowest_i].na_minutes_diff <= (uint16_t)60*(uint16_t)ALLOW_SKIP_HOURS )
  224. {
  225. /* within the limit before alarm */
  226. gui_data.is_skip_possible = 1;
  227. }
  228. }
  229. }
  230. }
  231. } while( redo );
  232. /* reset the equal flag */
  233. if ( gui_data.is_equal != 0 )
  234. {
  235. if ( gui_data.equal_h != gui_data.h ||
  236. gui_data.equal_mt != gui_data.mt ||
  237. gui_data.equal_mo != gui_data.mo )
  238. {
  239. gui_data.is_equal = 0;
  240. }
  241. }
  242. }
  243. /*============================================*/
  244. void gui_LoadData(void)
  245. {
  246. uint32_t data[5];
  247. int i;
  248. //printf("Load Data\n");
  249. load_gui_data(data);
  250. for( i = 0; i < GUI_ALARM_CNT; i++ )
  251. {
  252. set_alarm_data_by_u32(gui_alarm_list+i, data[i]);
  253. }
  254. gui_data.uptime = data[4] & (uint32_t)0x03ff;
  255. gui_data.last_day = (data[4]>>10) & (uint32_t)31;
  256. gui_data.contrast = (data[4]>>15) & (uint32_t)7;
  257. gui_data.display_voltage = (data[4]>>16) & (uint32_t)1;
  258. }
  259. void gui_StoreData(void)
  260. {
  261. uint32_t data[5];
  262. int i;
  263. for( i = 0; i < GUI_ALARM_CNT; i++ )
  264. {
  265. data[i] = get_u32_by_alarm_data(gui_alarm_list+i);
  266. //printf("%d: %08lx\n", i, data[i]);
  267. }
  268. data[4] = 0;
  269. data[4] |= gui_data.uptime & (uint32_t)0x03ff; /* 0...1023 */
  270. data[4] |= (gui_data.last_day & (uint32_t)31)<<10;
  271. data[4] |= (gui_data.contrast & (uint32_t)7)<<15;
  272. data[4] |= (gui_data.display_voltage & (uint32_t)1)<<16;
  273. store_gui_data(data);
  274. }
  275. /* recalculate all internal data */
  276. void gui_Recalculate(void)
  277. {
  278. int i;
  279. gui_date_adjust();
  280. gui_calc_week_time();
  281. gui_calc_next_alarm();
  282. for ( i = 0; i < GUI_ALARM_CNT; i++ )
  283. {
  284. gui_alarm_calc_str_time(i);
  285. }
  286. gui_StoreData();
  287. }
  288. /* minute and/or hour has changed */
  289. /* additionally the active alarm menu might be set by this function */
  290. void gui_SignalTimeChange(void)
  291. {
  292. /* recalculate dependent values */
  293. gui_Recalculate();
  294. /* setup menu */
  295. menu_SetMEList(&gui_menu, melist_display_time, 0);
  296. /* enable alarm */
  297. if ( gui_data.is_alarm != 0 )
  298. {
  299. menu_SetMEList(&gui_menu, melist_active_alarm_menu, 0);
  300. enable_alarm();
  301. }
  302. }
  303. void gui_Init(u8g2_t *u8g2, uint8_t is_por)
  304. {
  305. if ( is_por == 0 )
  306. {
  307. /* not a POR reset, so load current values */
  308. gui_LoadData();
  309. /* do NOT init the display, otherwise there will be some flicker visible */
  310. /* however, the GPIO subsystem still has to be setup, so call the other init procedures */
  311. /* this acts like a warm start for the display */
  312. /* the display setup code for the display is NOT send */
  313. u8x8_gpio_Init(u8g2_GetU8x8(u8g2));
  314. u8x8_cad_Init(u8g2_GetU8x8(u8g2));
  315. u8x8_gpio_SetReset(u8g2_GetU8x8(u8g2), 1);
  316. //u8g2_InitDisplay(u8g2);
  317. //u8x8_d_helper_display_init(u8g2_GetU8x8(u8g2));
  318. // u8g2_SetPowerSave(u8g2, 0); // this will be done later
  319. }
  320. else
  321. {
  322. /* POR reset, so do NOT load any values (they will be 0 in the best case) */
  323. /* instead do a proper reset of the display */
  324. // u8x8_InitDisplay(u8g2_GetU8x8(&u8g2));
  325. u8g2_InitDisplay(u8g2);
  326. // u8x8_SetPowerSave(u8g2_GetU8x8(&u8g2), 0);
  327. u8g2_SetPowerSave(u8g2, 0);
  328. }
  329. menu_Init(&gui_menu, u8g2);
  330. gui_SignalTimeChange();
  331. }
  332. void gui_Draw(void)
  333. {
  334. menu_Draw(&gui_menu);
  335. }
  336. void gui_Next(void)
  337. {
  338. if ( gui_menu.me_list == melist_active_alarm_menu )
  339. {
  340. disable_alarm();
  341. if ( gui_alarm_list[gui_data.active_alarm_idx].snooze_count != 0 )
  342. {
  343. int i;
  344. /* this is already the snooze alarm, so clear all and behave like the normal alarm off */
  345. for( i = 0; i < GUI_ALARM_CNT; i++ )
  346. gui_alarm_list[i].snooze_count = 0;
  347. }
  348. else
  349. {
  350. /* enable snooze */
  351. gui_alarm_list[gui_data.active_alarm_idx].snooze_count = 1;
  352. }
  353. gui_data.is_alarm = 0;
  354. gui_Recalculate();
  355. menu_SetMEList(&gui_menu, melist_display_time, 0);
  356. }
  357. else
  358. {
  359. menu_NextFocus(&gui_menu);
  360. }
  361. }
  362. void gui_Select(void)
  363. {
  364. if ( gui_menu.me_list == melist_active_alarm_menu )
  365. {
  366. int i;
  367. disable_alarm();
  368. for( i = 0; i < GUI_ALARM_CNT; i++ )
  369. gui_alarm_list[i].snooze_count = 0;
  370. gui_data.is_alarm = 0;
  371. gui_Recalculate();
  372. menu_SetMEList(&gui_menu, melist_display_time, 0);
  373. }
  374. else
  375. {
  376. menu_Select(&gui_menu);
  377. }
  378. }