General_view.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512
  1. #include "UnitempViews.h"
  2. #include "unitemp_icons.h"
  3. #include <assets_icons.h>
  4. static View* view;
  5. typedef enum general_views {
  6. G_NO_SENSORS_VIEW, //Нет датчиков
  7. G_LIST_VIEW, //Вид в ввиде списка
  8. G_CAROUSEL_VIEW, //Карусель
  9. } general_view;
  10. typedef enum carousel_info {
  11. CAROUSEL_VALUES, //Отображение значений датчиков
  12. CAROUSEL_INFO, //Отображение информации о датчике
  13. } carousel_info;
  14. static general_view current_view;
  15. carousel_info carousel_info_selector = CAROUSEL_VALUES;
  16. uint8_t generalview_sensor_index = 0;
  17. static void _draw_temperature(Canvas* canvas, Sensor* sensor, uint8_t x, uint8_t y, Color color) {
  18. //Рисование рамки
  19. canvas_draw_rframe(canvas, x, y, 54, 20, 3);
  20. if(color == ColorBlack) {
  21. canvas_draw_rbox(canvas, x, y, 54, 19, 3);
  22. canvas_invert_color(canvas);
  23. } else {
  24. canvas_draw_rframe(canvas, x, y, 54, 19, 3);
  25. }
  26. int16_t temp_int = sensor->temp;
  27. int8_t temp_dec = abs((int16_t)(sensor->temp * 10) % 10);
  28. //Рисование иконки
  29. canvas_draw_icon(
  30. canvas, x + 3, y + 3, (app->settings.unit == CELSIUS ? &I_temp_C_11x14 : &I_temp_F_11x14));
  31. if((int16_t)sensor->temp == -128 || sensor->status == UT_TIMEOUT) {
  32. snprintf(app->buff, BUFF_SIZE, "--");
  33. canvas_set_font(canvas, FontBigNumbers);
  34. canvas_draw_str_aligned(canvas, x + 27, y + 10, AlignCenter, AlignCenter, app->buff);
  35. snprintf(app->buff, BUFF_SIZE, ". -");
  36. canvas_set_font(canvas, FontPrimary);
  37. canvas_draw_str_aligned(canvas, x + 50, y + 10 + 3, AlignRight, AlignCenter, app->buff);
  38. if(color == ColorBlack) canvas_invert_color(canvas);
  39. return;
  40. }
  41. //Целая часть температуры
  42. snprintf(app->buff, BUFF_SIZE, "%d", temp_int);
  43. canvas_set_font(canvas, FontBigNumbers);
  44. canvas_draw_str_aligned(
  45. canvas,
  46. x + 27 + ((temp_int <= -10 || temp_int > 99) ? 5 : 0),
  47. y + 10,
  48. AlignCenter,
  49. AlignCenter,
  50. app->buff);
  51. //Печать дробной части температуры в диапазоне от -9 до 99 (когда два знака в числе)
  52. if(temp_int > -10 && temp_int <= 99) {
  53. uint8_t int_len = canvas_string_width(canvas, app->buff);
  54. snprintf(app->buff, BUFF_SIZE, ".%d", temp_dec);
  55. canvas_set_font(canvas, FontPrimary);
  56. canvas_draw_str(canvas, x + 27 + int_len / 2 + 2, y + 10 + 7, app->buff);
  57. }
  58. if(color == ColorBlack) canvas_invert_color(canvas);
  59. }
  60. static void _draw_humidity(Canvas* canvas, Sensor* sensor, const uint8_t pos[2]) {
  61. //Рисование рамки
  62. canvas_draw_rframe(canvas, pos[0], pos[1], 54, 20, 3);
  63. canvas_draw_rframe(canvas, pos[0], pos[1], 54, 19, 3);
  64. //Рисование иконки
  65. canvas_draw_icon(canvas, pos[0] + 3, pos[1] + 2, &I_hum_9x15);
  66. if((int8_t)sensor->hum == -128 || sensor->status == UT_TIMEOUT) {
  67. snprintf(app->buff, BUFF_SIZE, "--");
  68. canvas_set_font(canvas, FontBigNumbers);
  69. canvas_draw_str_aligned(
  70. canvas, pos[0] + 27, pos[1] + 10, AlignCenter, AlignCenter, app->buff);
  71. snprintf(app->buff, BUFF_SIZE, ". -");
  72. canvas_set_font(canvas, FontPrimary);
  73. canvas_draw_str_aligned(
  74. canvas, pos[0] + 50, pos[1] + 10 + 3, AlignRight, AlignCenter, app->buff);
  75. return;
  76. }
  77. //Целая часть влажности
  78. snprintf(app->buff, BUFF_SIZE, "%d", (uint8_t)sensor->hum);
  79. canvas_set_font(canvas, FontBigNumbers);
  80. canvas_draw_str_aligned(canvas, pos[0] + 27, pos[1] + 10, AlignCenter, AlignCenter, app->buff);
  81. uint8_t int_len = canvas_string_width(canvas, app->buff);
  82. //Единица измерения
  83. canvas_set_font(canvas, FontPrimary);
  84. canvas_draw_str(canvas, pos[0] + 27 + int_len / 2 + 4, pos[1] + 10 + 7, "%");
  85. }
  86. static void _draw_pressure(Canvas* canvas, Sensor* sensor) {
  87. const uint8_t x = 29, y = 39;
  88. //Рисование рамки
  89. canvas_draw_rframe(canvas, x, y, 69, 20, 3);
  90. canvas_draw_rframe(canvas, x, y, 69, 19, 3);
  91. //Рисование иконки
  92. canvas_draw_icon(canvas, x + 3, y + 4, &I_pressure_7x13);
  93. //Давление
  94. snprintf(app->buff, BUFF_SIZE, "%d", (uint16_t)sensor->pressure);
  95. canvas_set_font(canvas, FontBigNumbers);
  96. canvas_draw_str_aligned(canvas, x + 30, y + 10, AlignCenter, AlignCenter, app->buff);
  97. //Единица измерения
  98. canvas_draw_icon(canvas, x + 50, y + 3, &I_mm_hg_17x15);
  99. }
  100. static void _draw_singleSensor(Canvas* canvas, Sensor* sensor, const uint8_t pos[2], Color color) {
  101. canvas_set_font(canvas, FontPrimary);
  102. const uint8_t max_width = 61;
  103. char sensor_name[12] = {0};
  104. memcpy(sensor_name, sensor->name, 10);
  105. if(canvas_string_width(canvas, sensor_name) > max_width) {
  106. uint8_t i = 10;
  107. while((canvas_string_width(canvas, sensor_name) > max_width - 6) && (i != 0)) {
  108. sensor_name[i--] = '\0';
  109. }
  110. sensor_name[++i] = '.';
  111. sensor_name[++i] = '.';
  112. }
  113. canvas_draw_str_aligned(
  114. canvas, pos[0] + 27, pos[1] + 3, AlignCenter, AlignCenter, sensor_name);
  115. _draw_temperature(canvas, sensor, pos[0], pos[1] + 8, color);
  116. }
  117. static void _draw_view_noSensors(Canvas* canvas) {
  118. canvas_draw_icon(canvas, 7, 17, &I_sherlok_53x55);
  119. //Рисование рамки
  120. canvas_draw_rframe(canvas, 0, 0, 128, 63, 7);
  121. canvas_draw_rframe(canvas, 0, 0, 128, 64, 7);
  122. canvas_set_font(canvas, FontPrimary);
  123. canvas_draw_str_aligned(canvas, 63, 10, AlignCenter, AlignCenter, "No sensors found");
  124. canvas_set_font(canvas, FontSecondary);
  125. const uint8_t x = 65, y = 32;
  126. canvas_draw_rframe(canvas, x - 4, y - 11, 54, 33, 3);
  127. canvas_draw_rframe(canvas, x - 4, y - 11, 54, 34, 3);
  128. canvas_draw_str(canvas, x, y, "To add the");
  129. canvas_draw_str(canvas, x, y + 9, "new sensor");
  130. canvas_draw_str(canvas, x, y + 18, "press OK");
  131. canvas_draw_icon(canvas, x + 37, y + 10, &I_Ok_btn_9x9);
  132. }
  133. static void _draw_view_sensorsList(Canvas* canvas) {
  134. //Текущая страница
  135. uint8_t page = generalview_sensor_index / 4;
  136. //Количество датчиков, которые будут отображаться на странице
  137. uint8_t page_sensors_count;
  138. if((unitemp_sensors_getActiveCount() - page * 4) / 4) {
  139. page_sensors_count = 4;
  140. } else {
  141. page_sensors_count = (unitemp_sensors_getActiveCount() - page * 4) % 4;
  142. }
  143. //Количество страниц
  144. uint8_t pages =
  145. unitemp_sensors_getActiveCount() / 4 + (unitemp_sensors_getActiveCount() % 4 ? 1 : 0);
  146. //Стрелка влево
  147. if(page > 0) {
  148. canvas_draw_icon(canvas, 2, 32, &I_ButtonLeft_4x7);
  149. }
  150. //Стрелка вправо
  151. if(pages > 0 && page < pages - 1) {
  152. canvas_draw_icon(canvas, 122, 32, &I_ButtonRight_4x7);
  153. }
  154. const uint8_t value_positions[][4][2] = {
  155. {{36, 18}}, //1 датчик
  156. {{7, 18}, {67, 18}}, //2 датчика
  157. {{7, 3}, {67, 3}, {37, 33}}, //3 датчика
  158. {{7, 3}, {67, 3}, {7, 33}, {67, 33}}}; //4 датчика
  159. //Рисование рамки
  160. canvas_draw_rframe(canvas, 0, 0, 128, 63, 7);
  161. canvas_draw_rframe(canvas, 0, 0, 128, 64, 7);
  162. for(uint8_t i = 0; i < page_sensors_count; i++) {
  163. _draw_singleSensor(
  164. canvas,
  165. unitemp_sensor_getActive(page * 4 + i),
  166. value_positions[page_sensors_count - 1][i],
  167. ColorWhite);
  168. }
  169. }
  170. static void _draw_carousel_values(Canvas* canvas) {
  171. if(unitemp_sensor_getActive(generalview_sensor_index)->status == UT_TIMEOUT) {
  172. const Icon* frames[] = {
  173. &I_flipper_happy_60x38, &I_flipper_happy_2_60x38, &I_flipper_sad_60x38};
  174. canvas_draw_icon(canvas, 34, 23, frames[furi_get_tick() % 2250 / 750]);
  175. canvas_set_font(canvas, FontSecondary);
  176. if(unitemp_sensor_getActive(generalview_sensor_index)->type->interface == &SINGLE_WIRE) {
  177. snprintf(
  178. app->buff,
  179. BUFF_SIZE,
  180. "Waiting for module on pin %d",
  181. ((SingleWireSensor*)unitemp_sensor_getActive(generalview_sensor_index)->instance)
  182. ->gpio->num);
  183. }
  184. if(unitemp_sensor_getActive(generalview_sensor_index)->type->interface == &ONE_WIRE) {
  185. snprintf(
  186. app->buff,
  187. BUFF_SIZE,
  188. "Waiting for module on pin %d",
  189. ((OneWireSensor*)unitemp_sensor_getActive(generalview_sensor_index)->instance)
  190. ->bus->gpio->num);
  191. }
  192. if(unitemp_sensor_getActive(generalview_sensor_index)->type->interface == &I2C) {
  193. snprintf(app->buff, BUFF_SIZE, "Waiting for module on I2C pins");
  194. }
  195. canvas_draw_str_aligned(canvas, 64, 19, AlignCenter, AlignCenter, app->buff);
  196. return;
  197. }
  198. static const uint8_t temp_positions[3][2] = {{37, 23}, {37, 16}, {9, 16}};
  199. static const uint8_t hum_positions[2][2] = {{37, 38}, {65, 16}};
  200. //Селектор значений для отображения
  201. switch(unitemp_sensor_getActive(generalview_sensor_index)->type->datatype) {
  202. case UT_DATA_TYPE_TEMP:
  203. _draw_temperature(
  204. canvas,
  205. unitemp_sensor_getActive(generalview_sensor_index),
  206. temp_positions[0][0],
  207. temp_positions[0][1],
  208. ColorWhite);
  209. break;
  210. case UT_DATA_TYPE_TEMP_HUM:
  211. _draw_temperature(
  212. canvas,
  213. unitemp_sensor_getActive(generalview_sensor_index),
  214. temp_positions[1][0],
  215. temp_positions[1][1],
  216. ColorWhite);
  217. _draw_humidity(
  218. canvas, unitemp_sensor_getActive(generalview_sensor_index), hum_positions[0]);
  219. break;
  220. case UT_DATA_TYPE_TEMP_PRESS:
  221. _draw_temperature(
  222. canvas,
  223. unitemp_sensor_getActive(generalview_sensor_index),
  224. temp_positions[1][0],
  225. temp_positions[1][1],
  226. ColorWhite);
  227. _draw_pressure(canvas, unitemp_sensor_getActive(generalview_sensor_index));
  228. break;
  229. case UT_DATA_TYPE_TEMP_HUM_PRESS:
  230. _draw_temperature(
  231. canvas,
  232. unitemp_sensor_getActive(generalview_sensor_index),
  233. temp_positions[2][0],
  234. temp_positions[2][1],
  235. ColorWhite);
  236. _draw_humidity(
  237. canvas, unitemp_sensor_getActive(generalview_sensor_index), hum_positions[1]);
  238. _draw_pressure(canvas, unitemp_sensor_getActive(generalview_sensor_index));
  239. break;
  240. }
  241. }
  242. static void _draw_carousel_info(Canvas* canvas) {
  243. canvas_set_font(canvas, FontPrimary);
  244. canvas_draw_str(canvas, 10, 23, "Type:");
  245. if(unitemp_sensor_getActive(generalview_sensor_index)->type->interface == &ONE_WIRE) {
  246. OneWireSensor* s = unitemp_sensor_getActive(generalview_sensor_index)->instance;
  247. canvas_set_font(canvas, FontPrimary);
  248. canvas_draw_str(canvas, 10, 35, "GPIO:");
  249. canvas_draw_str(canvas, 10, 47, "ID:");
  250. canvas_set_font(canvas, FontSecondary);
  251. canvas_draw_str(
  252. canvas,
  253. 41,
  254. 23,
  255. unitemp_onewire_sensor_getModel(unitemp_sensor_getActive(generalview_sensor_index)));
  256. canvas_draw_str(canvas, 41, 35, s->bus->gpio->name);
  257. snprintf(
  258. app->buff,
  259. BUFF_SIZE,
  260. "%02X%02X%02X%02X%02X%02X%02X%02X",
  261. s->deviceID[0],
  262. s->deviceID[1],
  263. s->deviceID[2],
  264. s->deviceID[3],
  265. s->deviceID[4],
  266. s->deviceID[5],
  267. s->deviceID[6],
  268. s->deviceID[7]);
  269. canvas_draw_str(canvas, 24, 47, app->buff);
  270. }
  271. if(unitemp_sensor_getActive(generalview_sensor_index)->type->interface == &SINGLE_WIRE) {
  272. canvas_set_font(canvas, FontPrimary);
  273. canvas_draw_str(canvas, 10, 35, "GPIO:");
  274. canvas_set_font(canvas, FontSecondary);
  275. canvas_draw_str(
  276. canvas, 41, 23, unitemp_sensor_getActive(generalview_sensor_index)->type->typename);
  277. canvas_draw_str(
  278. canvas,
  279. 41,
  280. 35,
  281. ((SingleWireSensor*)unitemp_sensor_getActive(generalview_sensor_index)->instance)
  282. ->gpio->name);
  283. }
  284. if(unitemp_sensor_getActive(generalview_sensor_index)->type->interface == &I2C) {
  285. canvas_set_font(canvas, FontPrimary);
  286. canvas_draw_str(canvas, 10, 35, "I2C addr:");
  287. canvas_set_font(canvas, FontSecondary);
  288. canvas_draw_str(
  289. canvas, 41, 23, unitemp_sensor_getActive(generalview_sensor_index)->type->typename);
  290. snprintf(
  291. app->buff,
  292. BUFF_SIZE,
  293. "0x%02X",
  294. ((I2CSensor*)unitemp_sensor_getActive(generalview_sensor_index)->instance)
  295. ->currentI2CAdr);
  296. canvas_draw_str(canvas, 57, 35, app->buff);
  297. }
  298. }
  299. static void _draw_view_sensorsCarousel(Canvas* canvas) {
  300. //Рисование рамки
  301. canvas_draw_rframe(canvas, 0, 0, 128, 63, 7);
  302. canvas_draw_rframe(canvas, 0, 0, 128, 64, 7);
  303. //Печать имени
  304. canvas_set_font(canvas, FontPrimary);
  305. canvas_draw_str_aligned(
  306. canvas,
  307. 64,
  308. 7,
  309. AlignCenter,
  310. AlignCenter,
  311. unitemp_sensor_getActive(generalview_sensor_index)->name);
  312. //Подчёркивание
  313. uint8_t line_len =
  314. canvas_string_width(canvas, unitemp_sensor_getActive(generalview_sensor_index)->name) + 2;
  315. canvas_draw_line(canvas, 64 - line_len / 2, 12, 64 + line_len / 2, 12);
  316. //Стрелка вправо
  317. if(unitemp_sensors_getTypesCount() > 0 &&
  318. generalview_sensor_index < unitemp_sensors_getActiveCount() - 1) {
  319. canvas_draw_icon(canvas, 122, 29, &I_ButtonRight_4x7);
  320. }
  321. //Стрелка влево
  322. if(generalview_sensor_index > 0) {
  323. canvas_draw_icon(canvas, 2, 29, &I_ButtonLeft_4x7);
  324. }
  325. switch(carousel_info_selector) {
  326. case CAROUSEL_VALUES:
  327. _draw_carousel_values(canvas);
  328. break;
  329. case CAROUSEL_INFO:
  330. _draw_carousel_info(canvas);
  331. break;
  332. }
  333. }
  334. static void _draw_callback(Canvas* canvas, void* _model) {
  335. UNUSED(_model);
  336. app->sensors_ready = true;
  337. uint8_t sensors_count = unitemp_sensors_getActiveCount();
  338. if(generalview_sensor_index + 1 > sensors_count) generalview_sensor_index = 0;
  339. if(sensors_count == 0) {
  340. current_view = G_NO_SENSORS_VIEW;
  341. _draw_view_noSensors(canvas);
  342. } else {
  343. if(sensors_count == 1) current_view = G_CAROUSEL_VIEW;
  344. if(current_view == G_NO_SENSORS_VIEW) current_view = G_CAROUSEL_VIEW;
  345. if(current_view == G_LIST_VIEW) _draw_view_sensorsList(canvas);
  346. if(current_view == G_CAROUSEL_VIEW) _draw_view_sensorsCarousel(canvas);
  347. }
  348. }
  349. static bool _input_callback(InputEvent* event, void* context) {
  350. Unitemp* app = context;
  351. //Обработка короткого нажатия "ок"
  352. if(event->key == InputKeyOk && event->type == InputTypeShort) {
  353. //Меню добавления датчика при их отсутствии
  354. if(current_view == G_NO_SENSORS_VIEW) {
  355. app->sensors_ready = false;
  356. unitemp_SensorsList_switch();
  357. } else if(current_view == G_LIST_VIEW) {
  358. //Переход в главное меню при выключенном селекторе
  359. app->sensors_ready = false;
  360. unitemp_MainMenu_switch();
  361. } else if(current_view == G_CAROUSEL_VIEW) {
  362. app->sensors_ready = false;
  363. unitemp_SensorActions_switch(unitemp_sensor_getActive(generalview_sensor_index));
  364. }
  365. }
  366. //Обработка короткого нажатия "вниз"
  367. if(event->key == InputKeyDown && event->type == InputTypeShort) {
  368. //Переход из значений в информацию в карусели
  369. if(current_view == G_CAROUSEL_VIEW && carousel_info_selector == CAROUSEL_VALUES) {
  370. carousel_info_selector = CAROUSEL_INFO;
  371. return true;
  372. }
  373. //Переход в карусель из списка
  374. if(current_view == G_LIST_VIEW) {
  375. current_view = G_CAROUSEL_VIEW;
  376. return true;
  377. }
  378. }
  379. //Обработка короткого нажатия "вверх"
  380. if(event->key == InputKeyUp && event->type == InputTypeShort) {
  381. //Переход из информации в значения в карусели
  382. if(current_view == G_CAROUSEL_VIEW && carousel_info_selector == CAROUSEL_INFO) {
  383. carousel_info_selector = CAROUSEL_VALUES;
  384. return true;
  385. }
  386. //Переход в список из карусели
  387. if(current_view == G_CAROUSEL_VIEW && carousel_info_selector == CAROUSEL_VALUES &&
  388. unitemp_sensors_getActiveCount() > 1) {
  389. current_view = G_LIST_VIEW;
  390. return true;
  391. }
  392. }
  393. //Обработка короткого нажатия "вправо"
  394. if(event->key == InputKeyRight && event->type == InputTypeShort) {
  395. //Пролистывание карусели вперёд
  396. if(current_view == G_CAROUSEL_VIEW) {
  397. if(++generalview_sensor_index >= unitemp_sensors_getActiveCount())
  398. generalview_sensor_index = 0;
  399. return true;
  400. }
  401. //Пролистывание списка вперёд
  402. if(current_view == G_LIST_VIEW) {
  403. generalview_sensor_index += 4;
  404. if(generalview_sensor_index >= unitemp_sensors_getActiveCount())
  405. generalview_sensor_index = 0;
  406. return true;
  407. }
  408. }
  409. //Обработка короткого нажатия "влево"
  410. if(event->key == InputKeyLeft && event->type == InputTypeShort) {
  411. //Пролистывание карусели назад
  412. if(current_view == G_CAROUSEL_VIEW) {
  413. if(--generalview_sensor_index >= unitemp_sensors_getActiveCount())
  414. generalview_sensor_index = unitemp_sensors_getActiveCount() - 1;
  415. return true;
  416. }
  417. //Пролистывание списка назад
  418. if(current_view == G_LIST_VIEW) {
  419. generalview_sensor_index -= 4;
  420. if(generalview_sensor_index >= unitemp_sensors_getActiveCount())
  421. generalview_sensor_index = unitemp_sensors_getActiveCount() - 1;
  422. return true;
  423. }
  424. }
  425. //Обработка короткого нажатия "назад"
  426. if(event->key == InputKeyBack && event->type == InputTypeShort) {
  427. //Выход из приложения при листе или отсутствии датчиков
  428. if(current_view == G_LIST_VIEW || current_view == G_NO_SENSORS_VIEW ||
  429. ((current_view == G_CAROUSEL_VIEW) && (carousel_info_selector == CAROUSEL_VALUES))) {
  430. app->processing = false;
  431. return true;
  432. }
  433. //Переключение селектора вида карусели
  434. if((current_view == G_CAROUSEL_VIEW) && (carousel_info_selector != CAROUSEL_VALUES)) {
  435. carousel_info_selector = CAROUSEL_VALUES;
  436. return true;
  437. }
  438. }
  439. return true;
  440. }
  441. void unitemp_General_alloc(void) {
  442. view = view_alloc();
  443. view_set_context(view, app);
  444. view_set_draw_callback(view, _draw_callback);
  445. view_set_input_callback(view, _input_callback);
  446. view_dispatcher_add_view(app->view_dispatcher, UnitempViewGeneral, view);
  447. }
  448. void unitemp_General_switch(void) {
  449. app->sensors_ready = true;
  450. view_dispatcher_switch_to_view(app->view_dispatcher, UnitempViewGeneral);
  451. }
  452. void unitemp_General_free(void) {
  453. view_free(view);
  454. }