main/task_user.c

changeset 21
043ae27633f8
child 22
cceb36fd3a2a
equal deleted inserted replaced
20:7c1dacafed03 21:043ae27633f8
1 /**
2 * @file task_user.c
3 * @brief co2meter project.
4 */
5
6 #include "config.h"
7
8 static const char *TAG = "task_user";
9
10
11 EventGroupHandle_t xEventGroupUser; ///< Events User task
12 esp_timer_handle_t timerHandle; ///< Seconds timer
13 uint32_t SecsCount = 0; ///< Seconds counter
14 uint32_t UserTimer = 0; ///< User inactive timeout
15 int Main_Loop2 = -1; ///< Effective menu
16 int New_Loop2 = ML2_INIT; ///< New menu
17 int SubMenu = 0; ///< Submenu number
18 u8g2_t u8g2; ///< A structure which will contain all the data for one display
19 rotary_encoder_info_t rinfo = { 0 }; ///< Rotary encoder record
20 rotary_encoder_event_t event = { 0 };
21 QueueHandle_t event_queue;
22 static int PushDuration = 0; ///< Duration of the pushed button
23
24 extern const esp_app_desc_t *app_desc;
25 extern unit_t units[3]; ///< Pressure test units
26 extern SemaphoreHandle_t xSemaphoreUnits; ///< Units lock semaphore
27 extern DS18B20_State *ds18b20_state; ///< DS18B20 state
28 extern SemaphoreHandle_t xSemaphoreDS18B20; ///< DS18B20 lock semaphore
29 extern ADC_State *adc_state; ///< ADC state
30 extern SemaphoreHandle_t xSemaphoreADC; ///< ADC lock semaphore
31 extern WIFI_State *wifi_state; ///< WiFi state
32 extern int count_pub; ///< Published MQTT messages in transit
33 static xQueueHandle gpio_evt_queue = NULL; ///< Rotary pushbutton queue
34 extern int Main_Loop1; ///< Main measure loop
35
36
37
38 const int TASK_USER_COLD = BIT0; ///< System cold start
39 const int TASK_USER_WAKEUP = BIT1; ///< System wakeup from deepsleep
40 const int TASK_USER_BUSY = BIT2; ///< User interface is busy doing something.
41 const int TASK_USER_REFRESH = BIT3; ///< Refresh measurement results
42
43
44
45 /**
46 * @brief Seconds timer callback.
47 */
48 void TimerCallback(void *arg);
49
50
51 /***************************************************************************/
52
53
54
55 void TimerCallback(void *arg)
56 {
57 SecsCount++;
58 if ((SecsCount % 60) == 0) {
59 if (Main_Loop1 == ML1_DONE)
60 Main_Loop1 = ML1_INIT;
61 }
62
63 if (UserTimer == 1) {
64 ESP_LOGI(TAG, "User inactivity timeout");
65 xEventGroupClearBits(xEventGroupUser, TASK_USER_BUSY);
66 u8g2_SetPowerSave(&u8g2, 1);
67 }
68 if (UserTimer) {
69 UserTimer--;
70 }
71 }
72
73
74
75 void user_cold()
76 {
77 xEventGroupSetBits(xEventGroupUser, TASK_USER_COLD);
78 }
79
80
81
82 void user_wakeup()
83 {
84 xEventGroupSetBits(xEventGroupUser, TASK_USER_WAKEUP);
85 }
86
87
88
89 void user_refresh()
90 {
91 xEventGroupSetBits(xEventGroupUser, TASK_USER_REFRESH);
92 }
93
94
95
96 bool user_busy(void)
97 {
98 if (xEventGroupGetBits(xEventGroupUser) & TASK_USER_BUSY)
99 return true;
100 return false;
101 }
102
103
104
105
106 /**
107 * @brief Get a keyboard character from the rotary encoder.
108 * @param curkey The referenced value if the key being edited. NOTE, start at 0 for a new char??
109 * @param type The edittype, all values, integer or float.
110 * @param x The x position on the screen.
111 * @param y The y position on the screen.
112 * @return 1 if short keypress, meaning enter key. 2 if long press, enter key and editing is ready.
113 */
114 int getkey(int *curkey, int type, int x, int y)
115 {
116 int key = *curkey;
117 int rc = 0;
118
119 u8g2_DrawHLine(&u8g2, x, y+3, 12);
120 u8g2_SendBuffer(&u8g2);
121
122 for (;;) {
123 if (xQueueReceive(event_queue, &event, 100 / portTICK_PERIOD_MS) == pdTRUE) {
124 UserTimer = INACTIVITY;
125 if (event.state.position != 0) {
126
127 u8g2_SetDrawColor(&u8g2, 0);
128 u8g2_DrawGlyph(&u8g2, x, y, key);
129 u8g2_SetDrawColor(&u8g2, 1);
130 u8g2_SendBuffer(&u8g2);
131
132 if (event.state.position > 0) {
133 if (key == 126)
134 key = 171;
135 else if (key < 126)
136 key++;
137 } else if (event.state.position < 0) {
138 if (key == 171)
139 key = 126;
140 else if (key > 32)
141 key--;
142 }
143
144 ESP_ERROR_CHECK(rotary_encoder_reset(&rinfo));
145 u8g2_DrawGlyph(&u8g2, x, y, key);
146 u8g2_SendBuffer(&u8g2);
147 }
148 } else {
149 if (PushDuration) {
150 if (PushDuration > 500)
151 rc = 2;
152 else
153 rc = 1;
154 PushDuration = 0;
155 break;
156 }
157 }
158 }
159 u8g2_SetDrawColor(&u8g2, 0);
160 u8g2_DrawHLine(&u8g2, x, y+3, 12);
161 u8g2_SetDrawColor(&u8g2, 1);
162 u8g2_SendBuffer(&u8g2);
163
164 *curkey = key;
165 return rc;
166 }
167
168
169
170 /**
171 * @brief Editor using the rotary switch.
172 * @param label The label of the edit field.
173 * @param txt The string to edit.
174 * @param errmsg The error message if needed.
175 * @param len The maximum length for the string.
176 * @param type The edit type.
177 */
178 void rotary_editer(char *label, char *txt, char *errmsg, int len, int type)
179 {
180 char buf[65];
181 int key, x, y, rc;
182
183 u8g2_ClearBuffer(&u8g2);
184 u8g2_DrawHLine(&u8g2, 0, 14, 128);
185 u8g2_DrawHLine(&u8g2, 0, 49, 128);
186 u8g2_SetFont(&u8g2, u8g2_font_t0_15_tf);
187 sprintf(buf, "Edit %s", label);
188 u8g2_DrawStr(&u8g2,0,12,buf);
189
190 if (strlen(errmsg)) {
191 u8g2_SetFont(&u8g2, u8g2_font_t0_12b_tf);
192 u8g2_DrawStr(&u8g2, 0, 61, errmsg);
193 }
194 u8g2_SetFont(&u8g2, u8g2_font_t0_12_tf);
195 y = 36;
196 u8g2_DrawStr(&u8g2, 0, y, txt);
197 u8g2_SendBuffer(&u8g2);
198
199 for (;;) {
200 x = u8g2_GetUTF8Width(&u8g2, txt);
201 key = 'a';
202 rc = getkey(&key, type, x, y);
203 if (rc == 1) {
204 if (key >= 32 && key <= 126 && strlen(txt) < len) {
205 txt[strlen(txt) + 1] = '\0';
206 txt[strlen(txt)] = key;
207 } else if (key == 171 && strlen(txt)) {
208 // delete key
209 txt[strlen(txt) - 1] = '\0';
210 }
211 printf("strlen %d x %d key %d\n", strlen(txt), x, key);
212 } else if (rc == 2) {
213 break;
214 }
215 }
216 }
217
218
219
220 /**
221 * @brief Write a menu line on the display.
222 * @param bright Display the line with a bold or normal font.
223 * @param x The horizontal start position of the line.
224 * @param y The vertical bottom of the line position.
225 * @param format The formatted data to display.
226 */
227 void menu_line(int bright, int x, int y, const char *format, ...)
228 {
229 char buf[65];
230 va_list va_ptr;
231
232 if (bright)
233 u8g2_SetFont(&u8g2, u8g2_font_t0_12b_tr);
234 else
235 u8g2_SetFont(&u8g2, u8g2_font_t0_12_tr);
236
237 va_start(va_ptr, format);
238 vsnprintf(buf, 65, format, va_ptr);
239 va_end(va_ptr);
240
241 u8g2_DrawStr(&u8g2, x, y, buf);
242 }
243
244
245
246 /**
247 * @brief Clear the display and prepare the top of the display.
248 * @format The formatted data to display at the top.
249 */
250 void screen_top(const char *format, ...)
251 {
252 char buf[65];
253 va_list va_ptr;
254
255 va_start(va_ptr, format);
256 vsnprintf(buf, 65, format, va_ptr);
257 va_end(va_ptr);
258
259 u8g2_ClearBuffer(&u8g2);
260 u8g2_DrawHLine(&u8g2, 0, 14, 128);
261
262 u8g2_SetFont(&u8g2, u8g2_font_t0_15_tr);
263 u8g2_uint_t w = u8g2_GetStrWidth(&u8g2, buf);
264 u8g2_DrawStr(&u8g2, (128 - w) / 2,12, buf);
265 }
266
267
268
269 /**
270 * @brief The splash screen shown during cold boot or user wakeup.
271 */
272 void screen_splash()
273 {
274 screen_top("CO2 meter %s", app_desc->version);
275
276 u8g2_SetFont(&u8g2, u8g2_font_t0_22b_tf);
277 u8g2_uint_t w = u8g2_GetUTF8Width(&u8g2, "START");
278 u8g2_DrawUTF8(&u8g2, (128 - w) / 2,50, "START");
279
280 u8g2_SendBuffer(&u8g2);
281 u8g2_SetPowerSave(&u8g2, 0); // wake up display
282 }
283
284
285
286 /**
287 * @brief The main overview screen.
288 */
289 void screen_main()
290 {
291 char buf[65];
292 int i;
293
294 screen_top("CO2 meter %s", app_desc->version);
295
296 if (xSemaphoreTake(xSemaphoreUnits, 25) == pdTRUE) {
297
298 u8g2_SetFont(&u8g2, u8g2_font_t0_22b_tf);
299 sprintf(buf, "%.1f °C", units[0].temperature / 1000.0);
300 u8g2_uint_t w = u8g2_GetUTF8Width(&u8g2, buf);
301 u8g2_DrawUTF8(&u8g2, (128 - w) / 2,40, buf);
302 u8g2_SetFont(&u8g2, u8g2_font_t0_18b_tf);
303
304 for (i = 0; i < 3; i++) {
305 sprintf(buf, "%.1f", units[i].pressure / 1000.0);
306 w = u8g2_GetUTF8Width(&u8g2, buf);
307 u8g2_DrawUTF8(&u8g2, ((42 - w) / 2) + i * 43,63, buf);
308 }
309 xSemaphoreGive(xSemaphoreUnits);
310 }
311 u8g2_SendBuffer(&u8g2);
312 u8g2_SetPowerSave(&u8g2, 0); // wake up display
313 }
314
315
316
317 /**
318 * @brief The unit display screen.
319 * @param no The unit index number.
320 */
321 void screen_unit(int no)
322 {
323 char buf[65];
324
325 if (xSemaphoreTake(xSemaphoreUnits, 25) == pdTRUE) {
326
327 screen_top("Unit %d %s", no + 1, units[no].mode ? "On":"Off");
328
329 u8g2_SetFont(&u8g2, u8g2_font_t0_22b_tf);
330 sprintf(buf, "%.1f °C", units[no].temperature / 1000.0);
331 u8g2_uint_t w = u8g2_GetUTF8Width(&u8g2, buf);
332 u8g2_DrawUTF8(&u8g2, (128 - w) / 2,40, buf);
333
334 sprintf(buf, "%.2f bar", units[no].pressure / 1000.0);
335 w = u8g2_GetUTF8Width(&u8g2, buf);
336 u8g2_DrawUTF8(&u8g2, (128 - w) / 2,63, buf);
337
338 xSemaphoreGive(xSemaphoreUnits);
339 }
340 u8g2_SendBuffer(&u8g2);
341 u8g2_SetPowerSave(&u8g2, 0); // wake up display
342 }
343
344
345
346 /**
347 * @brief The unit zero setup screen.
348 * @param no The unit index number.
349 * @param sub The submenu index number.
350 */
351 void screen_unit_zero(int no, int sub)
352 {
353 screen_top("Unit %d zero mV", no + 1);
354 menu_line( 0, 2, 25, "Current %d", units[no].pressure_zero);
355 menu_line(sub == 0, 2, 37, "New value %d", units[no].pressure_voltage / (adc_state->Batt_voltage / 1000));
356 menu_line(sub == 1, 2, 49, "Return");
357 printf("current %d p_voltage %d batt %d\n", units[no].pressure_zero, units[no].pressure_voltage, adc_state->Batt_voltage);
358 u8g2_SendBuffer(&u8g2);
359 u8g2_SetPowerSave(&u8g2, 0);
360 }
361
362
363
364 /**
365 * @brief The unit setup screen.
366 * @param no The unit index number.
367 * @param sub The submenu index number.
368 */
369 void screen_unit_setup(int no, int sub)
370 {
371 screen_top("Unit %d setup", no + 1);
372 menu_line(sub == 0, 2, 25, "Mode %s", units[no].mode ? "ON":"OFF");
373 menu_line(sub == 1, 2, 37, "Zero mV %d", units[no].pressure_zero);
374 menu_line(sub == 2, 2, 49, "DS18B20 %s", units[no].temperature_rom_code);
375 menu_line(sub == 3, 2, 61, "Return");
376 u8g2_SendBuffer(&u8g2);
377 u8g2_SetPowerSave(&u8g2, 0);
378 }
379
380
381
382 void screen_wifi()
383 {
384 char buf[65];
385
386 screen_top("WiFi Status");
387 snprintf(buf, 65, "SSID %s", wifi_state->STA_ssid);
388 u8g2_DrawStr(&u8g2, 1, 28, buf);
389 snprintf(buf, 65, "Online %s", wifi_state->STA_online ? "Yes":"No");
390 u8g2_DrawStr(&u8g2, 1, 43, buf);
391 snprintf(buf, 65, "RSSI %d", wifi_state->STA_rssi);
392 u8g2_DrawStr(&u8g2, 1, 59, buf);
393 u8g2_SendBuffer(&u8g2);
394 u8g2_SetPowerSave(&u8g2, 0);
395 }
396
397
398
399 void screen_wifi_setup(int sub)
400 {
401 screen_top("WiFi Setup");
402 menu_line(sub == 0, 2, 25, "Connect");
403 menu_line(sub == 1, 2, 37, "New");
404 menu_line(sub == 2, 2, 49, "Delete");
405 menu_line(sub == 3, 2, 61, "Return");
406 u8g2_SendBuffer(&u8g2);
407 u8g2_SetPowerSave(&u8g2, 0);
408 }
409
410
411
412 void screen_network()
413 {
414 screen_top("Network Status");
415 menu_line(0, 1, 25, "IP %s", wifi_state->STA_ip);
416 menu_line(0, 1, 37, "Mask %s", wifi_state->STA_nm);
417 menu_line(0, 1, 49, "GW %s", wifi_state->STA_gw);
418 menu_line(0, 1, 61, "Name %s", config.hostname);
419 u8g2_SendBuffer(&u8g2);
420 u8g2_SetPowerSave(&u8g2, 0);
421 }
422
423
424
425 void screen_mqtt()
426 {
427 screen_top("MQTT Status");
428 menu_line(0, 1, 25, "serv %s", config.mqtt_server);
429 menu_line(0, 1, 37, "port %d", config.mqtt_port);
430 menu_line(0, 1, 49, "user %s", config.mqtt_user);
431 u8g2_SendBuffer(&u8g2);
432 u8g2_SetPowerSave(&u8g2, 0);
433 }
434
435
436
437 void screen_update()
438 {
439 screen_top("Update firmware");
440 menu_line(0, 1, 43, "Push to update");
441 u8g2_SendBuffer(&u8g2);
442 u8g2_SetPowerSave(&u8g2, 0);
443 }
444
445
446
447 /**
448 * @brief Fatal messages on the screen.
449 * @param e1 The first line.
450 * @param e2 The second line.
451 */
452 void screen_fatal(char *e1, char *e2)
453 {
454 u8g2_SetFont(&u8g2, u8g2_font_t0_15_tr);
455 u8g2_DrawStr(&u8g2,2,12,e1);
456 u8g2_DrawStr(&u8g2,2,24,e2);
457 u8g2_SendBuffer(&u8g2);
458 u8g2_SetPowerSave(&u8g2, 0);
459 }
460
461
462
463 /**
464 * @brief Interrupt service routine for the rotary pushbutton.
465 */
466 static void IRAM_ATTR gpio_isr_handler(void* arg)
467 {
468 uint32_t gpio_num = (uint32_t) arg;
469 xQueueSendFromISR(gpio_evt_queue, &gpio_num, NULL);
470 }
471
472
473
474 /**
475 * @brief GPIO queue task. See if there is a rotary pushbutton event on the queue.
476 */
477 static void gpio_task(void* arg)
478 {
479 uint32_t io_num;
480 static int64_t pushed = 0;
481
482 for(;;) {
483 if (xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY)) {
484 if (io_num == ROT_ENC_SW_GPIO) {
485 if (gpio_get_level(io_num) == 0) {
486 pushed = esp_timer_get_time();
487 PushDuration = 0;
488 } else if (gpio_get_level(io_num) == 1) {
489 PushDuration = (esp_timer_get_time() - pushed) / 1000;
490 ESP_LOGI(TAG, "GPIO rotary button intr, val: %d time: %d", gpio_get_level(io_num), PushDuration);
491 }
492 } else {
493 ESP_LOGE(TAG, "GPIO[%d] unknown intr, val: %d", io_num, gpio_get_level(io_num));
494 }
495 UserTimer = INACTIVITY;
496 }
497 }
498 }
499
500
501
502 /**
503 * @brief Select new menu number on a postitive or negative rotary position.
504 * @param pos The new position, positive, negative or zero.
505 * @param next_menu The selected menu if rotated clockwise.
506 * @param prev_menu The selected menu if rotated counter-clockwise.
507 */
508 static void rotate_to_menu(rotary_encoder_position_t pos, int next_menu, int prev_menu)
509 {
510 if (pos > 0)
511 New_Loop2 = next_menu;
512 else if (pos < 0)
513 New_Loop2 = prev_menu;
514 ESP_ERROR_CHECK(rotary_encoder_reset(&rinfo));
515 }
516
517
518
519 /**
520 * @brief Rotate subscreens numbers.
521 * @param pos The new position, positive, negative or zero.
522 * @param min The lowest number. If already at the lowest, select the highest.
523 * @param max The highest number. If already at the highest, select the lowest.
524 * @param cursub The subscreen number by reference. This is updated with the new number.
525 * @return Returns true if a new number is selected, false if nothing changed.
526 */
527 bool rotate_to_sub(rotary_encoder_position_t pos, int min, int max, int *cursub)
528 {
529 int sub = *cursub;
530 bool rc = false;
531
532 if (pos > 0) {
533 if (sub < max)
534 sub++;
535 else
536 sub = min;
537 ESP_ERROR_CHECK(rotary_encoder_reset(&rinfo));
538 rc = true;
539 } else if (pos < 0) {
540 if (sub > min)
541 sub--;
542 else
543 sub = max;
544 ESP_ERROR_CHECK(rotary_encoder_reset(&rinfo));
545 rc = true;
546 }
547
548 *cursub = sub;
549 return rc;
550 }
551
552
553
554 void menu_change(void)
555 {
556 char txt[65];
557
558 if (New_Loop2 != Main_Loop2) {
559
560 Main_Loop2 = New_Loop2;
561
562 switch (Main_Loop2) {
563 case ML2_INIT:
564 ESP_LOGI(TAG, "Loop user: Init");
565 New_Loop2 = ML2_USER;
566 break;
567
568 case ML2_USER:
569 ESP_LOGI(TAG, "Loop user: User mainmenu");
570 screen_main();
571 break;
572
573 case ML2_UNIT1:
574 case ML2_UNIT2:
575 case ML2_UNIT3:
576 ESP_LOGI(TAG, "Loop user: Unit %d", Main_Loop2 - ML2_UNIT1);
577 screen_unit(Main_Loop2 - ML2_UNIT1);
578 break;
579
580 case ML2_WIFI:
581 ESP_LOGI(TAG, "Loop user: WiFi");
582 screen_wifi();
583 break;
584
585 case ML2_NETWORK:
586 ESP_LOGI(TAG, "Loop user: Network");
587 screen_network();
588 break;
589
590 case ML2_MQTT:
591 ESP_LOGI(TAG, "Loop user: MQTT");
592 screen_mqtt();
593 break;
594
595 case ML2_SETUP_MQTT:
596 ESP_LOGI(TAG, "Loop user: MQTT setup");
597 sprintf(txt, "EDtXt");
598 rotary_editer("MQTT demo", txt, "", 16, EDIT_TYPE_TEXT);
599 New_Loop2 = ML2_MQTT;
600 break;
601
602 case ML2_UPDATE:
603 ESP_LOGI(TAG, "Loop user: Update");
604 screen_update();
605 break;
606
607 case ML2_SETUP_UNIT1:
608 case ML2_SETUP_UNIT2:
609 case ML2_SETUP_UNIT3:
610 ESP_LOGI(TAG, "Loop user: Setup Unit %d", Main_Loop2 - ML2_SETUP_UNIT1);
611 SubMenu = 0;
612 screen_unit_setup(Main_Loop2 - ML2_SETUP_UNIT1, SubMenu);
613 break;
614
615 case ML2_ZERO_UNIT1:
616 case ML2_ZERO_UNIT2:
617 case ML2_ZERO_UNIT3:
618 ESP_LOGI(TAG, "Loop user: Zero Unit %d", Main_Loop2 - ML2_ZERO_UNIT1);
619 SubMenu = 0;
620 screen_unit_zero(Main_Loop2 - ML2_ZERO_UNIT1, SubMenu);
621 break;
622
623 case ML2_INACTIVE:
624 ESP_LOGI(TAG, "Loop user: Inactive");
625 u8g2_SetPowerSave(&u8g2, 1); // powersave display
626 New_Loop2 = ML2_DONE;
627 break;
628
629 default:
630 break;
631 }
632 }
633 }
634
635
636
637 void menu_rotary(void)
638 {
639 switch (Main_Loop2) {
640 case ML2_USER: rotate_to_menu(event.state.position, ML2_UNIT1, ML2_USER); break;
641 case ML2_UNIT1: rotate_to_menu(event.state.position, ML2_UNIT2, ML2_USER); break;
642 case ML2_UNIT2: rotate_to_menu(event.state.position, ML2_UNIT3, ML2_UNIT1); break;
643 case ML2_UNIT3: rotate_to_menu(event.state.position, ML2_WIFI, ML2_UNIT2); break;
644 case ML2_WIFI: rotate_to_menu(event.state.position, ML2_NETWORK, ML2_UNIT3); break;
645 case ML2_NETWORK: rotate_to_menu(event.state.position, ML2_MQTT, ML2_WIFI); break;
646 case ML2_MQTT: rotate_to_menu(event.state.position, ML2_UPDATE, ML2_NETWORK); break;
647 case ML2_UPDATE: rotate_to_menu(event.state.position, ML2_UPDATE, ML2_MQTT); break;
648 case ML2_SETUP_UNIT1:
649 case ML2_SETUP_UNIT2:
650 case ML2_SETUP_UNIT3: if (rotate_to_sub(event.state.position, 0, 3, &SubMenu))
651 screen_unit_setup(Main_Loop2 - ML2_SETUP_UNIT1, SubMenu);
652 break;
653 case ML2_ZERO_UNIT1:
654 case ML2_ZERO_UNIT2:
655 case ML2_ZERO_UNIT3: if (rotate_to_sub(event.state.position, 0, 1, &SubMenu))
656 screen_unit_zero(Main_Loop2 - ML2_ZERO_UNIT1, SubMenu);
657 break;
658 default:
659 ESP_LOGI(TAG, "Event: position %d, direction %s", event.state.position,
660 event.state.direction ? (event.state.direction == ROTARY_ENCODER_DIRECTION_CLOCKWISE ? "CW":"CCW"):"NOT_SET");
661 }
662 }
663
664
665
666 void menu_loop(void)
667 {
668 int idx = 0;
669
670 switch (Main_Loop2) {
671 case ML2_UNIT1:
672 case ML2_UNIT2:
673 case ML2_UNIT3:
674 New_Loop2 = ML2_SETUP_UNIT1 + (Main_Loop2 - ML2_UNIT1);
675 break;
676
677 case ML2_SETUP_UNIT1:
678 case ML2_SETUP_UNIT2:
679 case ML2_SETUP_UNIT3:
680 idx = Main_Loop2 - ML2_SETUP_UNIT1;
681 if (SubMenu == 0) {
682 if (xSemaphoreTake(xSemaphoreUnits, 25) == pdTRUE) {
683 if (units[idx].mode)
684 units[idx].mode = 0;
685 else
686 units[idx].mode = 1;
687 write_units();
688 xSemaphoreGive(xSemaphoreUnits);
689 }
690 screen_unit_setup(idx, SubMenu);
691 if (Main_Loop1 == ML1_DONE)
692 Main_Loop1 = ML1_INIT;
693 }
694 if (SubMenu == 1)
695 New_Loop2 = ML2_ZERO_UNIT1 + idx;
696 if (SubMenu == 3)
697 New_Loop2 = ML2_UNIT1 + idx;
698 printf("unit setup sub %d new %d idx %d\n", SubMenu, New_Loop2, idx);
699 break;
700
701 case ML2_ZERO_UNIT1:
702 case ML2_ZERO_UNIT2:
703 case ML2_ZERO_UNIT3:
704 idx = Main_Loop2 - ML2_ZERO_UNIT1;
705 if (SubMenu == 0) {
706 if (xSemaphoreTake(xSemaphoreUnits, 25) == pdTRUE &&
707 xSemaphoreTake(xSemaphoreADC, 10) == pdTRUE &&
708 adc_state->Pressure[idx].voltage > 165 &&
709 adc_state->Pressure[idx].voltage < 660) {
710 units[idx].pressure_zero = adc_state->Pressure[idx].voltage / (adc_state->Batt_voltage / 1000);
711 write_units();
712 xSemaphoreGive(xSemaphoreADC);
713 xSemaphoreGive(xSemaphoreUnits);
714 screen_unit_zero(idx, SubMenu);
715 if (Main_Loop1 == ML1_DONE)
716 Main_Loop1 = ML1_INIT;
717 }
718 }
719 if (SubMenu == 1) {
720 New_Loop2 = ML2_SETUP_UNIT1 + idx;
721 SubMenu = 1;
722 }
723 printf("unit zero sub %d new %d idx %d\n", SubMenu, New_Loop2, idx);
724 break;
725
726 case ML2_MQTT:
727 New_Loop2 = ML2_SETUP_MQTT;
728 break;
729
730 default:
731 break;
732 }
733 }
734
735
736
737 void task_user(void *pvParameter)
738 {
739 esp_err_t ret;
740
741 ESP_LOGI(TAG, "Starting User task");
742 Main_Loop2 = -1;
743
744 /*
745 * Setup the OLED display.
746 * See: https://github.com/nkolban/esp32-snippets/blob/master/hardware/displays/U8G2/
747 */
748 u8g2_esp32_hal_t u8g2_esp32_hal = U8G2_ESP32_HAL_DEFAULT;
749 u8g2_esp32_hal.sda = PIN_SDA;
750 u8g2_esp32_hal.scl = PIN_SCL;
751 u8g2_esp32_hal_init(u8g2_esp32_hal);
752
753 u8g2_Setup_sh1106_i2c_128x64_noname_f(&u8g2, U8G2_R0, u8g2_esp32_i2c_byte_cb, u8g2_esp32_gpio_and_delay_cb); // init u8g2 structure
754 u8x8_SetI2CAddress(&u8g2.u8x8, 0x78);
755 u8g2_InitDisplay(&u8g2); // send init sequence to the display, display is in sleep mode after this,
756
757 /*
758 * Setup the Rotary Encoder.
759 * esp32-rotary-encoder requires that the GPIO ISR service is
760 * installed before calling rotary_encoder_register()
761 */
762 ESP_ERROR_CHECK(gpio_install_isr_service(0));
763 ESP_ERROR_CHECK(rotary_encoder_init(&rinfo, ROT_ENC_A_GPIO, ROT_ENC_B_GPIO));
764 ESP_ERROR_CHECK(rotary_encoder_enable_half_steps(&rinfo, false));
765
766 gpio_config_t io_conf;
767 io_conf.intr_type = GPIO_PIN_INTR_ANYEDGE;
768 io_conf.pin_bit_mask = (1ULL << ROT_ENC_SW_GPIO);
769 io_conf.mode = GPIO_MODE_INPUT;
770 gpio_config(&io_conf);
771
772 gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t));
773 xTaskCreate(gpio_task, "gpio_task", 2048, NULL, 10, NULL);
774
775 gpio_isr_handler_add(ROT_ENC_SW_GPIO, gpio_isr_handler, (void*) ROT_ENC_SW_GPIO);
776
777 // Create a queue for events from the rotary encoder driver.
778 // Tasks can read from this queue to receive up to date position information.
779 event_queue = rotary_encoder_create_queue();
780 ESP_ERROR_CHECK(rotary_encoder_set_queue(&rinfo, event_queue));
781
782 esp_timer_create_args_t timerSecond = {
783 .callback = &TimerCallback,
784 .name = "SecondsTimer"
785 };
786
787 /*
788 * Create a one second periodic timer.
789 */
790 ESP_ERROR_CHECK(esp_timer_create(&timerSecond, &timerHandle));
791 ret = esp_timer_start_periodic(timerHandle, 1000000);
792 assert(ret == ESP_OK);
793
794 EventBits_t uxBits;
795 ESP_LOGI(TAG, "User task loop enter");
796
797 /*
798 * Task loop forever.
799 */
800 while (1) {
801
802 uxBits = xEventGroupWaitBits(xEventGroupUser, TASK_USER_COLD | TASK_USER_WAKEUP, pdFALSE, pdFALSE, portMAX_DELAY );
803
804 if (uxBits & TASK_USER_COLD) {
805 ESP_LOGI(TAG, "User task cold start");
806 screen_splash();
807 xEventGroupClearBits(xEventGroupUser, TASK_USER_COLD);
808 UserTimer = 10;
809 }
810
811 if (uxBits & TASK_USER_WAKEUP) {
812 ESP_LOGI(TAG, "User task wakeup");
813 xEventGroupSetBits(xEventGroupUser, TASK_USER_BUSY);
814 xEventGroupClearBits(xEventGroupUser, TASK_USER_REFRESH);
815 screen_main();
816 UserTimer = INACTIVITY;
817 New_Loop2 = ML2_INIT;
818 Main_Loop2 = -1;
819 SubMenu = 0;
820
821 while (UserTimer) {
822
823 menu_change();
824 if (xQueueReceive(event_queue, &event, 250 / portTICK_PERIOD_MS) == pdTRUE) {
825 UserTimer = INACTIVITY;
826 menu_rotary();
827 }
828
829 if (PushDuration) {
830 PushDuration = 0;
831 menu_loop();
832 }
833
834 if (xEventGroupGetBits(xEventGroupUser) & TASK_USER_REFRESH) {
835 ESP_LOGI(TAG, "User task refresh");
836 switch (Main_Loop2) {
837 case ML2_USER: screen_main(); break;
838 case ML2_UNIT1: screen_unit(0); break;
839 case ML2_UNIT2: screen_unit(1); break;
840 case ML2_UNIT3: screen_unit(2); break;
841 }
842 xEventGroupClearBits(xEventGroupUser, TASK_USER_REFRESH);
843 }
844
845 vTaskDelay(10 / portTICK_PERIOD_MS);
846 }
847
848 xEventGroupClearBits(xEventGroupUser, TASK_USER_WAKEUP);
849 }
850 vTaskDelay(10 / portTICK_PERIOD_MS);
851 }
852
853 // If not configured, start configure
854 // If configured select first unit
855 // Handle screen (first is show measured values)
856 // Display per unit. Temp + Pressure + state. Press is setup this sensor.
857 // Setup menu: Sensors
858 // WiFi
859 // MQTT
860 // System (timers etc)
861 // Update OTA
862 // Return
863
864 // Sensors menu: Assignments, turn to choose one.
865 // Sensors setup menu: DS18B20 addr Press is assign
866 // DS18B20 addr
867 }
868

mercurial