General_view.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688
  1. /*
  2. Unitemp - Universal temperature reader
  3. Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n)
  4. This program is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <https://www.gnu.org/licenses/>.
  14. */
  15. #include "UnitempViews.h"
  16. #include "unitemp_icons.h"
  17. #include <assets_icons.h>
  18. // extern const Icon I_ButtonRight_4x7;
  19. // extern const Icon I_ButtonLeft_4x7;
  20. // extern const Icon I_Ok_btn_9x9;
  21. static View* view;
  22. typedef enum general_views {
  23. G_NO_SENSORS_VIEW, //Нет датчиков
  24. G_LIST_VIEW, //Вид в ввиде списка
  25. G_CAROUSEL_VIEW, //Карусель
  26. } general_view;
  27. typedef enum carousel_info {
  28. CAROUSEL_VALUES, //Отображение значений датчиков
  29. CAROUSEL_INFO, //Отображение информации о датчике
  30. } carousel_info;
  31. static general_view current_view;
  32. carousel_info carousel_info_selector = CAROUSEL_VALUES;
  33. uint8_t generalview_sensor_index = 0;
  34. static void _draw_temperature(Canvas* canvas, Sensor* sensor, uint8_t x, uint8_t y, Color color) {
  35. //Рисование рамки
  36. canvas_draw_rframe(canvas, x, y, 54, 20, 3);
  37. if(color == ColorBlack) {
  38. canvas_draw_rbox(canvas, x, y, 54, 19, 3);
  39. canvas_invert_color(canvas);
  40. } else {
  41. canvas_draw_rframe(canvas, x, y, 54, 19, 3);
  42. }
  43. int8_t temp_dec = abs((int16_t)(sensor->temp * 10) % 10);
  44. //Рисование иконки
  45. canvas_draw_icon(
  46. canvas,
  47. x + 3,
  48. y + 3,
  49. (app->settings.temp_unit == UT_TEMP_CELSIUS ? &I_temp_C_11x14 : &I_temp_F_11x14));
  50. if((int16_t)sensor->temp == -128 || sensor->status == UT_SENSORSTATUS_TIMEOUT) {
  51. canvas_set_font(canvas, FontBigNumbers);
  52. canvas_draw_str_aligned(canvas, x + 27, y + 10, AlignCenter, AlignCenter, "--");
  53. canvas_set_font(canvas, FontPrimary);
  54. canvas_draw_str_aligned(canvas, x + 50, y + 10 + 3, AlignRight, AlignCenter, ". -");
  55. if(color == ColorBlack) canvas_invert_color(canvas);
  56. return;
  57. }
  58. //Целая часть температуры
  59. //Костыль для отображения знака числа меньше 0
  60. uint8_t offset = 0;
  61. if(sensor->temp < 0 && sensor->temp > -1) {
  62. app->buff[0] = '-';
  63. offset = 1;
  64. }
  65. snprintf((char*)(app->buff + offset), BUFF_SIZE, "%d", (int16_t)sensor->temp);
  66. canvas_set_font(canvas, FontBigNumbers);
  67. canvas_draw_str_aligned(
  68. canvas,
  69. x + 27 + ((sensor->temp <= -10 || sensor->temp > 99) ? 5 : 0),
  70. y + 10,
  71. AlignCenter,
  72. AlignCenter,
  73. app->buff);
  74. //Печать дробной части температуры в диапазоне от -9 до 99 (когда два знака в числе)
  75. if(sensor->temp > -10 && sensor->temp <= 99) {
  76. uint8_t int_len = canvas_string_width(canvas, app->buff);
  77. snprintf(app->buff, BUFF_SIZE, ".%d", temp_dec);
  78. canvas_set_font(canvas, FontPrimary);
  79. canvas_draw_str(canvas, x + 27 + int_len / 2 + 2, y + 10 + 7, app->buff);
  80. }
  81. if(color == ColorBlack) canvas_invert_color(canvas);
  82. }
  83. static void _draw_humidity(Canvas* canvas, Sensor* sensor, const uint8_t pos[2]) {
  84. //Рисование рамки
  85. canvas_draw_rframe(canvas, pos[0], pos[1], 54, 20, 3);
  86. canvas_draw_rframe(canvas, pos[0], pos[1], 54, 19, 3);
  87. //Рисование иконки
  88. canvas_draw_icon(canvas, pos[0] + 3, pos[1] + 2, &I_hum_9x15);
  89. //Целая часть влажности
  90. snprintf(app->buff, BUFF_SIZE, "%d", (uint8_t)sensor->hum);
  91. canvas_set_font(canvas, FontBigNumbers);
  92. canvas_draw_str_aligned(canvas, pos[0] + 27, pos[1] + 10, AlignCenter, AlignCenter, app->buff);
  93. uint8_t int_len = canvas_string_width(canvas, app->buff);
  94. //Единица измерения
  95. canvas_set_font(canvas, FontPrimary);
  96. canvas_draw_str(canvas, pos[0] + 27 + int_len / 2 + 4, pos[1] + 10 + 7, "%");
  97. }
  98. static void _draw_heat_index(Canvas* canvas, Sensor* sensor, const uint8_t pos[2]) {
  99. canvas_draw_rframe(canvas, pos[0], pos[1], 54, 20, 3);
  100. canvas_draw_rframe(canvas, pos[0], pos[1], 54, 19, 3);
  101. canvas_draw_icon(canvas, pos[0] + 3, pos[1] + 3, &I_heat_index_11x14);
  102. int16_t heat_index_int = sensor->heat_index;
  103. int8_t heat_index_dec = abs((int16_t)(sensor->heat_index * 10) % 10);
  104. snprintf(app->buff, BUFF_SIZE, "%d", heat_index_int);
  105. canvas_set_font(canvas, FontBigNumbers);
  106. canvas_draw_str_aligned(
  107. canvas,
  108. pos[0] + 27 + ((sensor->heat_index <= -10 || sensor->heat_index > 99) ? 5 : 0),
  109. pos[1] + 10,
  110. AlignCenter,
  111. AlignCenter,
  112. app->buff);
  113. if(heat_index_int <= 99) {
  114. uint8_t int_len = canvas_string_width(canvas, app->buff);
  115. snprintf(app->buff, BUFF_SIZE, ".%d", heat_index_dec);
  116. canvas_set_font(canvas, FontPrimary);
  117. canvas_draw_str(canvas, pos[0] + 27 + int_len / 2 + 2, pos[1] + 10 + 7, app->buff);
  118. }
  119. }
  120. static void _draw_pressure(Canvas* canvas, Sensor* sensor) {
  121. const uint8_t x = 29, y = 39;
  122. //Рисование рамки
  123. if(app->settings.pressure_unit == UT_PRESSURE_HPA) {
  124. canvas_draw_rframe(canvas, x, y, 84, 20, 3);
  125. canvas_draw_rframe(canvas, x, y, 84, 19, 3);
  126. } else {
  127. canvas_draw_rframe(canvas, x, y, 69, 20, 3);
  128. canvas_draw_rframe(canvas, x, y, 69, 19, 3);
  129. }
  130. //Рисование иконки
  131. canvas_draw_icon(canvas, x + 3, y + 4, &I_pressure_7x13);
  132. int16_t press_int = sensor->pressure;
  133. // Change Temp for Pressure
  134. int8_t press_dec = (int16_t)(sensor->pressure * 10) % 10;
  135. //Целая часть давления
  136. snprintf(app->buff, BUFF_SIZE, "%d", press_int);
  137. canvas_set_font(canvas, FontBigNumbers);
  138. canvas_draw_str_aligned(
  139. canvas, x + 27 + ((press_int > 99) ? 5 : 0), y + 10, AlignCenter, AlignCenter, app->buff);
  140. //Печать дробной части давления в диапазоне от 0 до 99 (когда два знака в числе)
  141. if(press_int <= 99) {
  142. uint8_t int_len = canvas_string_width(canvas, app->buff);
  143. snprintf(app->buff, BUFF_SIZE, ".%d", press_dec);
  144. canvas_set_font(canvas, FontPrimary);
  145. canvas_draw_str(canvas, x + 27 + int_len / 2 + 2, y + 10 + 7, app->buff);
  146. } else if(app->settings.pressure_unit == UT_PRESSURE_HPA) {
  147. uint8_t int_len = canvas_string_width(canvas, app->buff);
  148. snprintf(app->buff, BUFF_SIZE, ".%d", press_dec);
  149. canvas_set_font(canvas, FontPrimary);
  150. canvas_draw_str(canvas, x + 32 + int_len / 2 + 2, y + 10 + 7, app->buff);
  151. }
  152. canvas_set_font(canvas, FontSecondary);
  153. //Единица измерения
  154. if(app->settings.pressure_unit == UT_PRESSURE_MM_HG) {
  155. canvas_draw_icon(canvas, x + 50, y + 2, &I_mm_hg_15x15);
  156. } else if(app->settings.pressure_unit == UT_PRESSURE_IN_HG) {
  157. canvas_draw_icon(canvas, x + 50, y + 2, &I_in_hg_15x15);
  158. } else if(app->settings.pressure_unit == UT_PRESSURE_KPA) {
  159. canvas_draw_str(canvas, x + 52, y + 13, "kPa");
  160. } else if(app->settings.pressure_unit == UT_PRESSURE_HPA) {
  161. canvas_draw_str(canvas, x + 67, y + 13, "hPa");
  162. }
  163. }
  164. static void _draw_co2(Canvas* canvas, Sensor* sensor, Color color) {
  165. const uint8_t x = 29, y = 39;
  166. //Рисование рамки
  167. canvas_draw_rframe(canvas, x, y, 75, 20, 3);
  168. if(color == ColorBlack) {
  169. canvas_draw_rbox(canvas, x, y, 75, 19, 3);
  170. canvas_invert_color(canvas);
  171. } else {
  172. canvas_draw_rframe(canvas, x, y, 75, 19, 3);
  173. }
  174. //Рисование иконки
  175. canvas_draw_icon(canvas, x + 3, y + 3, &I_co2_11x14);
  176. int16_t concentration_int = sensor->co2;
  177. // int8_t concentration_dec = (int16_t)(sensor->co2 * 10) % 10;
  178. //Целая часть
  179. if(concentration_int > 9999) {
  180. snprintf(app->buff, BUFF_SIZE, "MAX ");
  181. canvas_set_font(canvas, FontPrimary);
  182. } else {
  183. snprintf(app->buff, BUFF_SIZE, "%d", concentration_int);
  184. canvas_set_font(canvas, FontBigNumbers);
  185. }
  186. canvas_draw_str_aligned(canvas, x + 70, y + 10, AlignRight, AlignCenter, app->buff);
  187. }
  188. static void _draw_singleSensor(Canvas* canvas, Sensor* sensor, const uint8_t pos[2], Color color) {
  189. canvas_set_font(canvas, FontPrimary);
  190. const uint8_t max_width = 56;
  191. char sensor_name[12] = {0};
  192. memcpy(sensor_name, sensor->name, 10);
  193. if(canvas_string_width(canvas, sensor_name) > max_width) {
  194. uint8_t i = 10;
  195. while((canvas_string_width(canvas, sensor_name) > max_width - 6) && (i != 0)) {
  196. sensor_name[i--] = '\0';
  197. }
  198. sensor_name[++i] = '.';
  199. sensor_name[++i] = '.';
  200. }
  201. canvas_draw_str_aligned(
  202. canvas, pos[0] + 27, pos[1] + 3, AlignCenter, AlignCenter, sensor_name);
  203. _draw_temperature(canvas, sensor, pos[0], pos[1] + 8, color);
  204. }
  205. static void _draw_view_noSensors(Canvas* canvas) {
  206. canvas_draw_icon(canvas, 7, 17, &I_sherlok_53x45);
  207. //Рисование рамки
  208. canvas_draw_rframe(canvas, 0, 0, 128, 63, 7);
  209. canvas_draw_rframe(canvas, 0, 0, 128, 64, 7);
  210. canvas_set_font(canvas, FontPrimary);
  211. canvas_draw_str_aligned(canvas, 63, 10, AlignCenter, AlignCenter, "No sensors found");
  212. canvas_set_font(canvas, FontSecondary);
  213. const uint8_t x = 65, y = 32;
  214. canvas_draw_rframe(canvas, x - 4, y - 11, 54, 33, 3);
  215. canvas_draw_rframe(canvas, x - 4, y - 11, 54, 34, 3);
  216. canvas_draw_str(canvas, x, y, "To add the");
  217. canvas_draw_str(canvas, x, y + 9, "new sensor");
  218. canvas_draw_str(canvas, x, y + 18, "press OK");
  219. canvas_draw_icon(canvas, x + 37, y + 10, &I_Ok_btn_9x9);
  220. }
  221. static void _draw_view_sensorsList(Canvas* canvas) {
  222. //Текущая страница
  223. uint8_t page = generalview_sensor_index / 4;
  224. //Количество датчиков, которые будут отображаться на странице
  225. uint8_t page_sensors_count;
  226. if((unitemp_sensors_getActiveCount() - page * 4) / 4) {
  227. page_sensors_count = 4;
  228. } else {
  229. page_sensors_count = (unitemp_sensors_getActiveCount() - page * 4) % 4;
  230. }
  231. //Количество страниц
  232. uint8_t pages =
  233. unitemp_sensors_getActiveCount() / 4 + (unitemp_sensors_getActiveCount() % 4 ? 1 : 0);
  234. //Стрелка влево
  235. if(page > 0) {
  236. canvas_draw_icon(canvas, 2, 32, &I_ButtonLeft_4x7);
  237. }
  238. //Стрелка вправо
  239. if(pages > 0 && page < pages - 1) {
  240. canvas_draw_icon(canvas, 122, 32, &I_ButtonRight_4x7);
  241. }
  242. const uint8_t value_positions[][4][2] = {
  243. {{36, 18}}, //1 датчик
  244. {{7, 18}, {67, 18}}, //2 датчика
  245. {{7, 3}, {67, 3}, {37, 33}}, //3 датчика
  246. {{7, 3}, {67, 3}, {7, 33}, {67, 33}}}; //4 датчика
  247. //Рисование рамки
  248. canvas_draw_rframe(canvas, 0, 0, 128, 63, 7);
  249. canvas_draw_rframe(canvas, 0, 0, 128, 64, 7);
  250. for(uint8_t i = 0; i < page_sensors_count; i++) {
  251. _draw_singleSensor(
  252. canvas,
  253. unitemp_sensor_getActive(page * 4 + i),
  254. value_positions[page_sensors_count - 1][i],
  255. ColorWhite);
  256. }
  257. }
  258. static void _draw_carousel_values(Canvas* canvas) {
  259. UnitempStatus sensor_status = unitemp_sensor_getActive(generalview_sensor_index)->status;
  260. if(sensor_status == UT_SENSORSTATUS_ERROR || sensor_status == UT_SENSORSTATUS_TIMEOUT) {
  261. const Icon* frames[] = {
  262. &I_flipper_happy_60x38, &I_flipper_happy_2_60x38, &I_flipper_sad_60x38};
  263. canvas_draw_icon(canvas, 34, 23, frames[furi_get_tick() % 2250 / 750]);
  264. canvas_set_font(canvas, FontSecondary);
  265. //TODO: Оптимизировать эту срань
  266. if(unitemp_sensor_getActive(generalview_sensor_index)->type->interface == &SINGLE_WIRE) {
  267. snprintf(
  268. app->buff,
  269. BUFF_SIZE,
  270. "Waiting for module on pin %d",
  271. ((SingleWireSensor*)unitemp_sensor_getActive(generalview_sensor_index)->instance)
  272. ->gpio->num);
  273. }
  274. if(unitemp_sensor_getActive(generalview_sensor_index)->type->interface == &ONE_WIRE) {
  275. snprintf(
  276. app->buff,
  277. BUFF_SIZE,
  278. "Waiting for module on pin %d",
  279. ((OneWireSensor*)unitemp_sensor_getActive(generalview_sensor_index)->instance)
  280. ->bus->gpio->num);
  281. }
  282. if(unitemp_sensor_getActive(generalview_sensor_index)->type->interface == &I2C) {
  283. snprintf(app->buff, BUFF_SIZE, "Waiting for module on I2C pins");
  284. }
  285. if(unitemp_sensor_getActive(generalview_sensor_index)->type->interface == &SPI) {
  286. snprintf(app->buff, BUFF_SIZE, "Waiting for module on SPI pins");
  287. }
  288. canvas_draw_str_aligned(canvas, 64, 19, AlignCenter, AlignCenter, app->buff);
  289. return;
  290. }
  291. static const uint8_t temp_positions[3][2] = {{37, 23}, {37, 16}, {9, 16}};
  292. static const uint8_t hum_positions[2][2] = {{37, 38}, {65, 16}};
  293. //Селектор значений для отображения
  294. switch(unitemp_sensor_getActive(generalview_sensor_index)->type->datatype) {
  295. case UT_DATA_TYPE_TEMP:
  296. _draw_temperature(
  297. canvas,
  298. unitemp_sensor_getActive(generalview_sensor_index),
  299. temp_positions[0][0],
  300. temp_positions[0][1],
  301. ColorWhite);
  302. break;
  303. case UT_DATA_TYPE_TEMP_HUM:
  304. if(!app->settings.heat_index) {
  305. _draw_temperature(
  306. canvas,
  307. unitemp_sensor_getActive(generalview_sensor_index),
  308. temp_positions[1][0],
  309. temp_positions[1][1],
  310. ColorWhite);
  311. } else {
  312. _draw_temperature(
  313. canvas,
  314. unitemp_sensor_getActive(generalview_sensor_index),
  315. temp_positions[2][0],
  316. temp_positions[2][1],
  317. ColorWhite);
  318. _draw_heat_index(
  319. canvas, unitemp_sensor_getActive(generalview_sensor_index), hum_positions[1]);
  320. }
  321. _draw_humidity(
  322. canvas, unitemp_sensor_getActive(generalview_sensor_index), hum_positions[0]);
  323. break;
  324. case UT_DATA_TYPE_TEMP_PRESS:
  325. _draw_temperature(
  326. canvas,
  327. unitemp_sensor_getActive(generalview_sensor_index),
  328. temp_positions[1][0],
  329. temp_positions[1][1],
  330. ColorWhite);
  331. _draw_pressure(canvas, unitemp_sensor_getActive(generalview_sensor_index));
  332. break;
  333. case UT_DATA_TYPE_TEMP_HUM_PRESS:
  334. _draw_temperature(
  335. canvas,
  336. unitemp_sensor_getActive(generalview_sensor_index),
  337. temp_positions[2][0],
  338. temp_positions[2][1],
  339. ColorWhite);
  340. _draw_humidity(
  341. canvas, unitemp_sensor_getActive(generalview_sensor_index), hum_positions[1]);
  342. _draw_pressure(canvas, unitemp_sensor_getActive(generalview_sensor_index));
  343. break;
  344. case UT_DATA_TYPE_TEMP_HUM_CO2:
  345. _draw_temperature(
  346. canvas,
  347. unitemp_sensor_getActive(generalview_sensor_index),
  348. temp_positions[2][0],
  349. temp_positions[2][1],
  350. ColorWhite);
  351. _draw_humidity(
  352. canvas, unitemp_sensor_getActive(generalview_sensor_index), hum_positions[1]);
  353. _draw_co2(canvas, unitemp_sensor_getActive(generalview_sensor_index), ColorWhite);
  354. break;
  355. }
  356. }
  357. //TODO: Оптимизировать вывод информации
  358. static void _draw_carousel_info(Canvas* canvas) {
  359. canvas_set_font(canvas, FontPrimary);
  360. canvas_draw_str(canvas, 10, 23, "Type:");
  361. if(unitemp_sensor_getActive(generalview_sensor_index)->type->interface == &ONE_WIRE) {
  362. OneWireSensor* s = unitemp_sensor_getActive(generalview_sensor_index)->instance;
  363. canvas_set_font(canvas, FontPrimary);
  364. canvas_draw_str(canvas, 10, 35, "GPIO:");
  365. canvas_draw_str(canvas, 10, 47, "ID:");
  366. canvas_set_font(canvas, FontSecondary);
  367. canvas_draw_str(
  368. canvas,
  369. 41,
  370. 23,
  371. unitemp_onewire_sensor_getModel(unitemp_sensor_getActive(generalview_sensor_index)));
  372. canvas_draw_str(canvas, 41, 35, s->bus->gpio->name);
  373. snprintf(
  374. app->buff,
  375. BUFF_SIZE,
  376. "%02X%02X%02X%02X%02X%02X%02X%02X",
  377. s->deviceID[0],
  378. s->deviceID[1],
  379. s->deviceID[2],
  380. s->deviceID[3],
  381. s->deviceID[4],
  382. s->deviceID[5],
  383. s->deviceID[6],
  384. s->deviceID[7]);
  385. canvas_draw_str(canvas, 24, 47, app->buff);
  386. }
  387. if(unitemp_sensor_getActive(generalview_sensor_index)->type->interface == &SINGLE_WIRE) {
  388. canvas_set_font(canvas, FontPrimary);
  389. canvas_draw_str(canvas, 10, 35, "GPIO:");
  390. canvas_set_font(canvas, FontSecondary);
  391. canvas_draw_str(
  392. canvas, 41, 23, unitemp_sensor_getActive(generalview_sensor_index)->type->typename);
  393. canvas_draw_str(
  394. canvas,
  395. 41,
  396. 35,
  397. ((SingleWireSensor*)unitemp_sensor_getActive(generalview_sensor_index)->instance)
  398. ->gpio->name);
  399. }
  400. if(unitemp_sensor_getActive(generalview_sensor_index)->type->interface == &SPI) {
  401. canvas_set_font(canvas, FontPrimary);
  402. canvas_draw_str(canvas, 10, 35, "MISO pin:");
  403. canvas_draw_str(canvas, 10, 46, "CS pin:");
  404. canvas_draw_str(canvas, 10, 58, "SCK pin:");
  405. canvas_set_font(canvas, FontSecondary);
  406. canvas_draw_str(
  407. canvas, 41, 23, unitemp_sensor_getActive(generalview_sensor_index)->type->typename);
  408. canvas_draw_str(canvas, 60, 35, unitemp_gpio_getFromInt(3)->name);
  409. canvas_draw_str(
  410. canvas,
  411. 47,
  412. 46,
  413. ((SPISensor*)unitemp_sensor_getActive(generalview_sensor_index)->instance)
  414. ->CS_pin->name);
  415. canvas_draw_str(canvas, 54, 58, unitemp_gpio_getFromInt(5)->name);
  416. }
  417. if(unitemp_sensor_getActive(generalview_sensor_index)->type->interface == &I2C) {
  418. canvas_set_font(canvas, FontPrimary);
  419. canvas_draw_str(canvas, 10, 35, "I2C addr:");
  420. canvas_draw_str(canvas, 10, 46, "SDA pin:");
  421. canvas_draw_str(canvas, 10, 58, "SCL pin:");
  422. canvas_set_font(canvas, FontSecondary);
  423. canvas_draw_str(
  424. canvas, 41, 23, unitemp_sensor_getActive(generalview_sensor_index)->type->typename);
  425. snprintf(
  426. app->buff,
  427. BUFF_SIZE,
  428. "0x%02X",
  429. ((I2CSensor*)unitemp_sensor_getActive(generalview_sensor_index)->instance)
  430. ->currentI2CAdr >>
  431. 1);
  432. canvas_draw_str(canvas, 57, 35, app->buff);
  433. canvas_draw_str(canvas, 54, 46, "15 (C1)");
  434. canvas_draw_str(canvas, 54, 58, "16 (C0)");
  435. }
  436. }
  437. static void _draw_view_sensorsCarousel(Canvas* canvas) {
  438. //Рисование рамки
  439. canvas_draw_rframe(canvas, 0, 0, 128, 63, 7);
  440. canvas_draw_rframe(canvas, 0, 0, 128, 64, 7);
  441. //Печать имени
  442. canvas_set_font(canvas, FontPrimary);
  443. canvas_draw_str_aligned(
  444. canvas,
  445. 64,
  446. 7,
  447. AlignCenter,
  448. AlignCenter,
  449. unitemp_sensor_getActive(generalview_sensor_index)->name);
  450. //Подчёркивание
  451. uint8_t line_len =
  452. canvas_string_width(canvas, unitemp_sensor_getActive(generalview_sensor_index)->name) + 2;
  453. canvas_draw_line(canvas, 64 - line_len / 2, 12, 64 + line_len / 2, 12);
  454. //Стрелка вправо
  455. if(unitemp_sensors_getTypesCount() > 0 &&
  456. generalview_sensor_index < unitemp_sensors_getActiveCount() - 1) {
  457. canvas_draw_icon(canvas, 122, 29, &I_ButtonRight_4x7);
  458. }
  459. //Стрелка влево
  460. if(generalview_sensor_index > 0) {
  461. canvas_draw_icon(canvas, 2, 29, &I_ButtonLeft_4x7);
  462. }
  463. switch(carousel_info_selector) {
  464. case CAROUSEL_VALUES:
  465. _draw_carousel_values(canvas);
  466. break;
  467. case CAROUSEL_INFO:
  468. _draw_carousel_info(canvas);
  469. break;
  470. }
  471. }
  472. static void _draw_callback(Canvas* canvas, void* _model) {
  473. UNUSED(_model);
  474. app->sensors_ready = true;
  475. uint8_t sensors_count = unitemp_sensors_getActiveCount();
  476. if(generalview_sensor_index + 1 > sensors_count) generalview_sensor_index = 0;
  477. if(sensors_count == 0) {
  478. current_view = G_NO_SENSORS_VIEW;
  479. _draw_view_noSensors(canvas);
  480. } else {
  481. if(sensors_count == 1) current_view = G_CAROUSEL_VIEW;
  482. if(current_view == G_NO_SENSORS_VIEW) current_view = G_CAROUSEL_VIEW;
  483. if(current_view == G_LIST_VIEW) _draw_view_sensorsList(canvas);
  484. if(current_view == G_CAROUSEL_VIEW) _draw_view_sensorsCarousel(canvas);
  485. }
  486. }
  487. static bool _input_callback(InputEvent* event, void* context) {
  488. UNUSED(context);
  489. //Обработка короткого нажатия "ок"
  490. if(event->key == InputKeyOk && event->type == InputTypeShort) {
  491. //Меню добавления датчика при их отсутствии
  492. if(current_view == G_NO_SENSORS_VIEW) {
  493. app->sensors_ready = false;
  494. unitemp_SensorsList_switch();
  495. } else if(current_view == G_LIST_VIEW) {
  496. //Переход в главное меню при выключенном селекторе
  497. app->sensors_ready = false;
  498. unitemp_MainMenu_switch();
  499. } else if(current_view == G_CAROUSEL_VIEW) {
  500. app->sensors_ready = false;
  501. unitemp_SensorActions_switch(unitemp_sensor_getActive(generalview_sensor_index));
  502. }
  503. }
  504. //Обработка короткого нажатия "вниз"
  505. if(event->key == InputKeyDown && event->type == InputTypeShort) {
  506. //Переход из значений в информацию в карусели
  507. if(current_view == G_CAROUSEL_VIEW && carousel_info_selector == CAROUSEL_VALUES) {
  508. carousel_info_selector = CAROUSEL_INFO;
  509. return true;
  510. }
  511. //Переход в карусель из списка
  512. if(current_view == G_LIST_VIEW) {
  513. current_view = G_CAROUSEL_VIEW;
  514. return true;
  515. }
  516. }
  517. //Обработка короткого нажатия "вверх"
  518. if(event->key == InputKeyUp && event->type == InputTypeShort) {
  519. //Переход из информации в значения в карусели
  520. if(current_view == G_CAROUSEL_VIEW && carousel_info_selector == CAROUSEL_INFO) {
  521. carousel_info_selector = CAROUSEL_VALUES;
  522. return true;
  523. }
  524. //Переход в список из карусели
  525. if(current_view == G_CAROUSEL_VIEW && carousel_info_selector == CAROUSEL_VALUES &&
  526. unitemp_sensors_getActiveCount() > 1) {
  527. current_view = G_LIST_VIEW;
  528. return true;
  529. }
  530. }
  531. //Обработка короткого нажатия "вправо"
  532. if(event->key == InputKeyRight && event->type == InputTypeShort) {
  533. //Пролистывание карусели вперёд
  534. if(current_view == G_CAROUSEL_VIEW) {
  535. if(++generalview_sensor_index >= unitemp_sensors_getActiveCount()) {
  536. generalview_sensor_index = 0;
  537. if(carousel_info_selector == CAROUSEL_VALUES) current_view = G_LIST_VIEW;
  538. }
  539. return true;
  540. }
  541. //Пролистывание списка вперёд
  542. if(current_view == G_LIST_VIEW) {
  543. generalview_sensor_index += 4;
  544. if(generalview_sensor_index >= unitemp_sensors_getActiveCount()) {
  545. generalview_sensor_index = 0;
  546. current_view = G_CAROUSEL_VIEW;
  547. }
  548. return true;
  549. }
  550. }
  551. //Обработка короткого нажатия "влево"
  552. if(event->key == InputKeyLeft && event->type == InputTypeShort) {
  553. //Пролистывание карусели назад
  554. if(current_view == G_CAROUSEL_VIEW) {
  555. if(--generalview_sensor_index >= unitemp_sensors_getActiveCount()) {
  556. generalview_sensor_index = unitemp_sensors_getActiveCount() - 1;
  557. if(carousel_info_selector == CAROUSEL_VALUES) current_view = G_LIST_VIEW;
  558. }
  559. return true;
  560. }
  561. //Пролистывание списка назад
  562. if(current_view == G_LIST_VIEW) {
  563. generalview_sensor_index -= 4;
  564. if(generalview_sensor_index >= unitemp_sensors_getActiveCount()) {
  565. generalview_sensor_index = unitemp_sensors_getActiveCount() - 1;
  566. current_view = G_CAROUSEL_VIEW;
  567. }
  568. return true;
  569. }
  570. }
  571. //Обработка короткого нажатия "назад"
  572. if(event->key == InputKeyBack && event->type == InputTypeShort) {
  573. //Выход из приложения при карусели или отсутствии датчиков
  574. if(current_view == G_NO_SENSORS_VIEW ||
  575. ((current_view == G_CAROUSEL_VIEW) && (carousel_info_selector == CAROUSEL_VALUES))) {
  576. app->processing = false;
  577. return true;
  578. }
  579. //Переключение селектора вида карусели
  580. if((current_view == G_CAROUSEL_VIEW) && (carousel_info_selector != CAROUSEL_VALUES)) {
  581. carousel_info_selector = CAROUSEL_VALUES;
  582. return true;
  583. }
  584. //Переход в карусель из списка
  585. if(current_view == G_LIST_VIEW) {
  586. current_view = G_CAROUSEL_VIEW;
  587. return true;
  588. }
  589. }
  590. //Обработка длинного нажатия "Ок"
  591. if(event->key == InputKeyOk && event->type == InputTypeLong) {
  592. app->settings.temp_unit = !app->settings.temp_unit;
  593. }
  594. return true;
  595. }
  596. void unitemp_General_alloc(void) {
  597. view = view_alloc();
  598. view_set_context(view, app);
  599. view_set_draw_callback(view, _draw_callback);
  600. view_set_input_callback(view, _input_callback);
  601. view_dispatcher_add_view(app->view_dispatcher, UnitempViewGeneral, view);
  602. }
  603. void unitemp_General_switch(void) {
  604. app->sensors_ready = true;
  605. view_dispatcher_switch_to_view(app->view_dispatcher, UnitempViewGeneral);
  606. }
  607. void unitemp_General_free(void) {
  608. view_dispatcher_remove_view(app->view_dispatcher, UnitempViewGeneral);
  609. view_free(view);
  610. }