menu.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. /*
  2. * menu.c
  3. *
  4. * Created on: 1 февр. 2022 г.
  5. * Author: radioman
  6. */
  7. #include <stdlib.h>
  8. #include <stdio.h>
  9. #include <string.h>
  10. #include "menu.h"
  11. #include "ssd1306.h"
  12. #include "preferences.h"
  13. static const char *menu_template[] = {\
  14. "A, 0, 0, Dose rate",
  15. "A, 0, 0, Total dose",
  16. "A, 0, 0, Up time",
  17. "A, 0, 0, Debug",
  18. "D, 0, 0, Settings",
  19. "D, 0, 1, Sound",
  20. "P, 1, 2, Volume",
  21. "P, 2, 2, Tone",
  22. "P, 3, 2, Buttons",
  23. "B, 0, 2, Back",
  24. "D, 0, 1, Alarm",
  25. "D, 0, 2, Dose rate alarm",
  26. "R, 4, 3, OFF",
  27. "R, 4, 3, 0.5 uSv/h",
  28. "R, 4, 3, 1 uSv/h",
  29. "R, 4, 3, 10 uSv/h",
  30. "R, 4, 3, 100 uSv/h",
  31. "R, 4, 3, 1 mSv/h",
  32. "R, 4, 3, 10 mSv/h",
  33. "R, 4, 3, 100 mSv/h",
  34. "R, 4, 3, 1 Sv/h",
  35. "B, 0, 3, Back",
  36. "D, 0, 2, Total dose alarm",
  37. "R, 5, 3, OFF",
  38. "R, 5, 3, 1 uSv",
  39. "R, 5, 3, 10 uSv",
  40. "R, 5, 3, 100 uSv",
  41. "R, 5, 3, 1 mSv",
  42. "R, 5, 3, 10 uSv",
  43. "R, 5, 3, 100 uSv",
  44. "R, 5, 3, 1 Sv",
  45. "R, 5, 3, 10 Sv",
  46. "R, 5, 3, 100 Sv",
  47. "B, 0, 3, Back",
  48. "P, 6, 2, Sound type",
  49. "P, 7, 2, Volume",
  50. "B, 0, 2, Back",
  51. "D, 0, 1, Energy saving",
  52. "P, 8, 2, Brightness",
  53. "P, 9, 2, Disp.off min",
  54. "P, 10, 2, Shutdown min",
  55. "B, 0, 2, Back",
  56. "B, 0, 1, Back",
  57. "A, 0, 0, Info" };
  58. static menu_td menu_items[sizeof(menu_template) / sizeof(char*)];
  59. static menu_td *menu = &menu_items[0];
  60. static uint8_t scroll = 0;
  61. extern uint8_t screen;
  62. char * capstring(char *dest, const char *source)
  63. {
  64. while(*source)
  65. {
  66. unsigned char c = *source++;
  67. // ASCII & CP1251 Cyrillic
  68. if((c >= 'a' && c <= 'z') || (c >= 0xe0 && c <= 0xff))
  69. c -= 32;
  70. *dest++ = c;
  71. }
  72. *dest = 0;
  73. return dest;
  74. }
  75. void MenuInit()
  76. {
  77. uint8_t items_total = sizeof(menu_template) / sizeof(char*);
  78. char type;
  79. int max_level = 0;
  80. for(int i = 0; i < items_total; i++)
  81. {
  82. menu_items[i].id = i;
  83. sscanf(menu_template[i], "%c, %hhu, %hhu, %[^\n]",
  84. &type, &(menu_items[i].pref), &(menu_items[i].level), menu_items[i].title);
  85. menu_items[i].type = (entry_type)type;
  86. if(menu_items[i].level > max_level)
  87. max_level = menu_items[i].level;
  88. }
  89. /* Iterating through menu levels (complicated algorithm)*/
  90. for(int lvl = 0; lvl <= max_level; lvl++)
  91. {
  92. /* prev - previous entry ID on current level,
  93. * first - ID of first entry on current level */
  94. int prev = 0, first = -1;
  95. for(int i = 0; i < items_total; i++)
  96. {
  97. if(menu_items[i].level == lvl)
  98. {
  99. if(first < 0)
  100. {
  101. prev = first = i;
  102. }
  103. else
  104. {
  105. menu_items[prev].next = &menu_items[i];
  106. menu_items[i].prev = &menu_items[prev];
  107. prev = i;
  108. }
  109. /* At levels higher than 0 we assign parent and child pointers
  110. * All children have the same parent at one level
  111. * Parent always is the closest entry on lower level */
  112. if(lvl > 0)
  113. {
  114. menu_items[i].parent = &menu_items[first - 1];
  115. menu_items[first - 1].child = &menu_items[first];
  116. }
  117. }
  118. /* When we reaching entry that have lower level than our last entry
  119. * we need to close scroll loop by assigning 'next' pointer of last entry
  120. * to first entry on current level and reset 'first' variable
  121. * Also we need to do this if it is the last cycle of whole loop */
  122. if((first >= 0) && ((menu_items[i].level < menu_items[prev].level) || (i == (items_total - 1))))
  123. {
  124. menu_items[first].prev = &menu_items[prev];
  125. menu_items[prev].next = &menu_items[first];
  126. first = -1;
  127. }
  128. }
  129. }
  130. }
  131. void MenuScroll()
  132. {
  133. scroll = 1;
  134. menu = menu->next;
  135. }
  136. void MenuEnter()
  137. {
  138. switch(menu->type)
  139. {
  140. case ENTRY_DIR:
  141. menu = menu->child;
  142. break;
  143. case ENTRY_ACTION:
  144. screen = menu->id;
  145. //PrefSetValue(menu->pref, menu->id);
  146. //*(prefs[menu->pref].prefptr) = menu->id;
  147. break;
  148. case ENTRY_PREF:
  149. PrefIncValue(menu->pref);
  150. // *(prefs[menu->pref].prefptr) = (*(prefs[menu->pref].prefptr) +
  151. // prefs[menu->pref].step) % (prefs[menu->pref].max_val + 1);
  152. break;
  153. case ENTRY_BACK:
  154. menu = menu->parent;
  155. break;
  156. case ENTRY_CHECK:
  157. PrefSetValue(menu->pref, PrefGetValue(menu->pref) ^ 1);
  158. //*(prefs[menu->pref].prefptr) ^= 1;
  159. break;
  160. case ENTRY_RADIO:
  161. PrefSetValue(menu->pref, menu->id - menu->parent->child->id);
  162. //*(prefs[menu->pref].prefptr) = menu->id - menu->parent->child->id;
  163. break;
  164. }
  165. }
  166. void PrintMenuHeader()
  167. {
  168. char tempstr[30];
  169. if(menu->parent == NULL)
  170. strcpy(tempstr, "MAIN MENU");
  171. else
  172. capstring(tempstr, menu->parent->title);
  173. ssd1306_Line(0, 0, 127, 0, White);
  174. ssd1306_SetCursor(0, 1);
  175. ssd1306_WriteString(" ", Font_7x10, Black);
  176. ssd1306_SetCursor(64 - ((strlen(tempstr) * 7) / 2), 1);
  177. ssd1306_WriteString(tempstr, Font_7x10, Black);
  178. ssd1306_Line(0, 10, 127, 10, Black);
  179. }
  180. char * FormatEntryText(menu_td *mn, char * buf)
  181. {
  182. if(mn->type == ENTRY_PREF)
  183. {
  184. sprintf(buf, "%-12s -%.2d-", mn->title, PrefGetValue(mn->pref));
  185. }
  186. else if(mn->type == ENTRY_RADIO)
  187. {
  188. if(PrefGetValue(mn->pref) == (mn->id - mn->parent->child->id))
  189. sprintf(buf, "[%s]", mn->title);
  190. else
  191. sprintf(buf, "%s", mn->title);
  192. }
  193. else
  194. {
  195. strcpy(buf, mn->title);
  196. }
  197. return buf;
  198. }
  199. void MenuShow()
  200. {
  201. static int x = 0, y = 0, an_steps = 0;
  202. char tempstr[30];
  203. ssd1306_Fill(Black);
  204. /*
  205. ssd1306_SetCursor(1, 1);
  206. menu = &menu_items[1];
  207. sprintf(tempstr, "id: %s", menu->next->title);
  208. ssd1306_WriteString(tempstr, Font_7x10, White);
  209. */
  210. if(scroll)
  211. {
  212. y = 11;
  213. an_steps = 5;
  214. scroll = 0;
  215. }
  216. if(an_steps > 0)
  217. {
  218. an_steps--;
  219. y = (an_steps * 11) / 5;
  220. }
  221. ssd1306_SetCursor(x + 8, y + 1);
  222. ssd1306_WriteString(FormatEntryText(menu->prev, tempstr), Font_7x10, White);
  223. ssd1306_SetCursor(x + 8, y + 12);
  224. ssd1306_WriteString(FormatEntryText(menu, tempstr), Font_7x10, White);
  225. ssd1306_SetCursor(x + 8, y + 23);
  226. ssd1306_WriteString(FormatEntryText(menu->next, tempstr), Font_7x10, White);
  227. ssd1306_SetCursor(0, 12);
  228. if(menu->type == ENTRY_BACK)
  229. ssd1306_WriteChar('<', Font_7x10, White);
  230. else
  231. ssd1306_WriteChar('>', Font_7x10, White);
  232. PrintMenuHeader();
  233. ssd1306_UpdateScreen();
  234. }