firmware-nucleo/App/Src/task_menu.c (10977B)
1 /* 2 * Copyright (c) 2023 Juan Manuel Cruz <jcruz@fi.uba.ar> <jcruz@frba.utn.edu.ar>. 3 * Copyright (c) 2026 Martin Javier Klöckner <mklockner@fi.uba.ar> 4 * 5 * All rights reserved 6 * 7 * See file `LICENSE` for full details 8 */ 9 10 #include "main.h" 11 12 #include "logger.h" 13 #include "dwt.h" 14 15 #include "app.h" 16 #include "task_menu_attribute.h" 17 #include "task_menu_interface.h" 18 #include "display_i2c.h" 19 20 #define G_TASK_MEN_TICK_INI 0ul 21 #define G_TASK_MEN_TICK_CNT_INI 0ul 22 #define G_TASK_MEN_DISPLAY_UPDATE_RATE_MS 1000ul 23 24 static task_menu_dta_t task_menu_dta = { 25 G_TASK_MEN_TICK_INI, ST_MEN_IDLE, EV_MEN_ST_IDLE, false 26 }; 27 28 // Private functions declaration 29 static void task_menu_statechart(void *parameters); 30 static void task_menu_set_state(task_menu_st_t new_state); 31 static uint8_t task_menu_count_digits(int16_t n); 32 33 // Private variables 34 static bool g_display_update; 35 static task_menu_st_t g_menu_prev_state; 36 static int16_t temp_sensor_prev; 37 static uint8_t temp_ctrl_pwm_dc_prev; 38 39 // Public variables 40 volatile uint32_t g_task_menu_tick_cnt; 41 42 // External variables 43 extern uint16_t g_ds18b20_temp; 44 extern uint16_t g_ds18b20_update_count; 45 extern uint16_t g_ds18b20_dma_error_count; 46 47 // Public functions 48 void task_menu_init(void *parameters) 49 { 50 task_menu_dta_t *p_task_menu_dta; 51 shared_data_type *p_shared_data = (shared_data_type *)parameters; 52 53 LOGGER_INFO("Initializing `task_menu`..."); 54 55 task_menu_interface_init_event_queue(); 56 57 g_menu_prev_state = ST_MEN_IDLE; 58 p_task_menu_dta = &task_menu_dta; 59 p_task_menu_dta->state = ST_MEN_IDLE; 60 p_task_menu_dta->event = EV_MEN_ST_IDLE; 61 p_task_menu_dta->event_flag = false; 62 temp_sensor_prev = p_shared_data->temp_sensor; 63 temp_ctrl_pwm_dc_prev = p_shared_data->temp_ctrl_pwm_dc; 64 65 display_i2c_init(); 66 display_i2c_set_cursor_pos(0, 0); 67 display_i2c_write_string("Initializing..."); 68 g_display_update = true; 69 70 LOGGER_INFO("Done initializing `task_menu`"); 71 } 72 73 void task_menu_update(void *parameters) 74 { 75 bool b_time_update_required = false; 76 77 __asm("CPSID i"); 78 if (G_TASK_MEN_TICK_CNT_INI < g_task_menu_tick_cnt) 79 { 80 /* Update Tick Counter */ 81 g_task_menu_tick_cnt--; 82 b_time_update_required = true; 83 } 84 __asm("CPSIE i"); 85 86 while (b_time_update_required) 87 { 88 display_i2c_async_tick(); 89 task_menu_statechart(parameters); 90 91 __asm("CPSID i"); 92 if (G_TASK_MEN_TICK_CNT_INI < g_task_menu_tick_cnt) 93 { 94 g_task_menu_tick_cnt--; 95 b_time_update_required = true; 96 } 97 else 98 { 99 b_time_update_required = false; 100 } 101 __asm("CPSIE i"); 102 } 103 } 104 105 static void task_menu_set_state(task_menu_st_t new_state) 106 { 107 task_menu_dta_t *p_task_menu_dta; 108 p_task_menu_dta = &task_menu_dta; 109 110 g_menu_prev_state = p_task_menu_dta->state; 111 p_task_menu_dta->state = new_state; 112 113 g_display_update = true; 114 115 switch(new_state) 116 { 117 case ST_MEN_CLOCK_SET: 118 p_task_menu_dta->tick = G_TASK_MEN_DISPLAY_UPDATE_RATE_MS; 119 break; 120 default: break; 121 } 122 } 123 124 static uint8_t task_menu_count_digits(int16_t n) 125 { 126 uint8_t count = 0; 127 128 if (n == 0) return 1; 129 if (n < 0) n = -n; 130 131 while (n > 0) { 132 n /= 10; 133 count++; 134 } 135 136 return count; 137 } 138 139 static void task_menu_statechart(void *parameters) 140 { 141 task_menu_dta_t *p_task_menu_dta; 142 shared_data_type *p_shared_data = (shared_data_type *)parameters; 143 char menu_row_str[32]; 144 145 p_task_menu_dta = &task_menu_dta; 146 147 if (true == task_menu_interface_any_event()) 148 { 149 p_task_menu_dta->event_flag = true; 150 p_task_menu_dta->event = task_menu_interface_get_event(); 151 } 152 153 if (true == p_task_menu_dta->event_flag) 154 { 155 p_task_menu_dta->event_flag = false; 156 switch (p_task_menu_dta->event) 157 { 158 case EV_MEN_ST_IDLE: 159 case EV_MEN_INACTIVE_TIMEOUT: 160 task_menu_set_state(ST_MEN_IDLE); 161 break; 162 163 case EV_MEN_DISPLAY_UPDATE: 164 g_display_update = true; 165 break; 166 167 case EV_MEN_ST_CLOCK_SET: 168 task_menu_set_state(ST_MEN_CLOCK_SET); 169 break; 170 171 case EV_MEN_ST_TEMP_SET: 172 task_menu_set_state(ST_MEN_TEMP_SET); 173 break; 174 175 case EV_MEN_ST_TIMER_SET_STATUS: 176 task_menu_set_state(ST_MEN_TIMER_SET_STATUS); 177 break; 178 179 case EV_MEN_ST_TIMER_SET_START: 180 task_menu_set_state(ST_MEN_TIMER_SET_START); 181 break; 182 183 case EV_MEN_ST_TIMER_SET_END: 184 task_menu_set_state(ST_MEN_TIMER_SET_END); 185 break; 186 187 default: break; 188 } 189 } 190 191 switch (p_task_menu_dta->state) 192 { 193 case ST_MEN_IDLE: 194 195 if (0 == p_task_menu_dta->tick) 196 { 197 if ((p_shared_data->temp_sensor != temp_sensor_prev) || 198 (p_shared_data->temp_ctrl_pwm_dc != temp_ctrl_pwm_dc_prev)) 199 { 200 g_display_update = true; 201 } 202 temp_sensor_prev = p_shared_data->temp_sensor; 203 temp_ctrl_pwm_dc_prev = p_shared_data->temp_ctrl_pwm_dc; 204 p_task_menu_dta->tick = G_TASK_MEN_DISPLAY_UPDATE_RATE_MS; 205 } 206 else 207 { 208 p_task_menu_dta->tick--; 209 } 210 211 if (g_display_update) 212 { 213 g_display_update = false; 214 display_i2c_async_clear(); 215 memset(menu_row_str, '\0', sizeof(menu_row_str)); 216 217 if (p_shared_data->temp_ctrl_enabled) 218 { 219 display_i2c_async_write_string("On"); 220 display_i2c_async_set_cursor_pos(10, 0); 221 sprintf(menu_row_str, "%5d%%", 222 p_shared_data->temp_ctrl_pwm_dc); 223 display_i2c_async_write_string(menu_row_str); 224 } 225 else 226 { 227 sprintf(menu_row_str, "Off"); 228 display_i2c_async_write_string(menu_row_str); 229 } 230 231 display_i2c_async_set_cursor_pos(0, 1); 232 memset(menu_row_str, '\0', sizeof(menu_row_str)); 233 uint8_t aux = (8 - task_menu_count_digits(p_shared_data->temp_set_point)); 234 aux = ((aux < 0) ? 0 : ((aux > 8) ? 8 : aux)); 235 sprintf(menu_row_str, "%s %*d(%d)%cC", 236 p_shared_data->timer->enabled ? "[P]" : " ", aux, 237 p_shared_data->temp_sensor, 238 p_shared_data->temp_set_point, 239 G_DISPLAY_CHAR_DEGREE_CODE); 240 display_i2c_async_write_string(menu_row_str); 241 } 242 243 break; 244 245 case ST_MEN_CLOCK_SET: 246 247 if (0 == p_task_menu_dta->tick) 248 { 249 g_display_update = true; 250 p_task_menu_dta->tick = G_TASK_MEN_DISPLAY_UPDATE_RATE_MS; 251 } 252 else 253 { 254 p_task_menu_dta->tick--; 255 } 256 257 if (g_display_update) 258 { 259 g_display_update = false; 260 display_i2c_async_clear(); 261 display_i2c_async_write_string("Clock>"); 262 display_i2c_async_set_cursor_pos(8, 0); 263 264 HAL_RTC_GetTime(&hrtc, &s_time, RTC_FORMAT_BIN); 265 HAL_RTC_GetDate(&hrtc, &s_date, RTC_FORMAT_BIN); 266 267 memset(menu_row_str, '\0', sizeof(menu_row_str)); 268 sprintf(menu_row_str, "%2d:%02d:%02d", 269 s_time.Hours, s_time.Minutes, s_time.Seconds); 270 display_i2c_async_write_string(menu_row_str); 271 } 272 273 break; 274 275 case ST_MEN_TEMP_SET: 276 277 if (g_display_update) 278 { 279 g_display_update = false; 280 display_i2c_async_clear(); 281 display_i2c_async_write_string("Temp>"); 282 memset(menu_row_str, '\0', sizeof(menu_row_str)); 283 sprintf(menu_row_str, "%9d%cC", 284 p_shared_data->temp_set_point, G_DISPLAY_CHAR_DEGREE_CODE); 285 display_i2c_async_write_string(menu_row_str); 286 } 287 288 break; 289 290 case ST_MEN_TIMER_SET_STATUS: 291 292 if (g_display_update) 293 { 294 g_display_update = false; 295 display_i2c_async_clear(); 296 display_i2c_async_write_string("Timer>"); 297 display_i2c_async_set_cursor_pos(13, 0); 298 memset(menu_row_str, '\0', sizeof(menu_row_str)); 299 sprintf(menu_row_str, "%3s", 300 p_shared_data->timer->enabled ? "On" : "Off"); 301 display_i2c_async_write_string(menu_row_str); 302 303 display_i2c_async_set_cursor_pos(3, 1); 304 memset(menu_row_str, '\0', sizeof(menu_row_str)); 305 sprintf(menu_row_str, "%s%2d:%02d - %d:%02d", 306 (p_shared_data->timer->end_hour >= 10) ? "" : " ", 307 p_shared_data->timer->start_hour, 308 p_shared_data->timer->start_min, 309 p_shared_data->timer->end_hour, 310 p_shared_data->timer->end_min); 311 display_i2c_async_write_string(menu_row_str); 312 } 313 314 break; 315 316 case ST_MEN_TIMER_SET_START: 317 318 if (g_display_update) 319 { 320 g_display_update = false; 321 display_i2c_async_clear(); 322 display_i2c_async_write_string("Timer>start>"); 323 display_i2c_async_set_cursor_pos(11, 1); 324 memset(menu_row_str, '\0', sizeof(menu_row_str)); 325 sprintf(menu_row_str, "%2d:%02d", 326 p_shared_data->timer->start_hour, 327 p_shared_data->timer->start_min); 328 display_i2c_async_write_string(menu_row_str); 329 } 330 331 break; 332 333 case ST_MEN_TIMER_SET_END: 334 335 if (g_display_update) 336 { 337 g_display_update = false; 338 display_i2c_async_clear(); 339 display_i2c_async_write_string("Timer>end>"); 340 display_i2c_async_set_cursor_pos(11, 1); 341 memset(menu_row_str, '\0', sizeof(menu_row_str)); 342 sprintf(menu_row_str, "%2d:%02d", 343 p_shared_data->timer->end_hour, 344 p_shared_data->timer->end_min); 345 display_i2c_async_write_string(menu_row_str); 346 } 347 348 break; 349 350 default: 351 352 p_task_menu_dta->tick = G_TASK_MEN_TICK_INI; 353 p_task_menu_dta->state = ST_MEN_IDLE; 354 p_task_menu_dta->event = EV_MEN_ST_IDLE; 355 p_task_menu_dta->event_flag = false; 356 g_display_update = false; 357 358 break; 359 } 360 }
