tdse-tf_3-02

Controlador PID para derretidor de miel con control local via botones y remoto via WiFi
Index Commits Files Refs Submodules README
firmware-nucleo/App/Src/task_system.c (17421B)
   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  * See file `LICENSE` for full details
   6  */
   7 
   8 #include "main.h"
   9 
  10 #include "logger.h"
  11 #include "dwt.h"
  12 
  13 #include "app.h"
  14 #include "task_system_attribute.h"
  15 #include "task_system_interface.h"
  16 #include "task_leds_attribute.h"
  17 #include "task_leds_interface.h"
  18 #include "task_menu_attribute.h"
  19 #include "task_menu_interface.h"
  20 #include "task_buzzer_attribute.h"
  21 #include "task_buzzer_interface.h"
  22 
  23 #define G_TASK_SYS_CNT_INI              0ul
  24 #define G_TASK_SYS_TICK_CNT_INI         0ul
  25 #define G_TASK_SYS_EEPROM_START_ADDR    0x0801FC00
  26 #define G_TASK_SYS_EEPROM_END_ADDR      0x0801FFF0
  27 #define G_TASK_SYS_TIMER_UPDATE_RATE_MS 1000ul
  28 
  29 #define DEL_SYS_MIN 0ul
  30 #define DEL_SYS_MED 50ul
  31 #define DEL_SYS_MAX 500ul
  32 
  33 // If persistent values are lost these are the timer default values
  34 #define TIMER_DEFAULT_START_HOUR 00ul
  35 #define TIMER_DEFAULT_START_MIN  00ul
  36 #define TIMER_DEFAULT_END_HOUR   12ul
  37 #define TIMER_DEFAULT_END_MIN    00ul
  38 #define TIMER_DEFAULT_STATUS     false
  39 
  40 // Exported variables
  41 volatile uint32_t g_task_system_tick_cnt; // Updated every ms by SysTick callback
  42 
  43 // Private variables
  44 static task_system_dta_t task_system_dta = {
  45     DEL_SYS_MIN, ST_SYS_IDLE, EV_SYS_IDLE, false
  46 };
  47 
  48 #define SYSTEM_DTA_QTY (sizeof(task_system_dta)/sizeof(task_system_dta_t))
  49 
  50 static uint32_t g_task_system_timer_tick;
  51 static task_system_timer_t task_system_timer = {
  52     TIMER_DEFAULT_START_HOUR, TIMER_DEFAULT_START_MIN,
  53     TIMER_DEFAULT_END_HOUR, TIMER_DEFAULT_END_MIN,
  54     TIMER_DEFAULT_STATUS
  55 };
  56 
  57 // Private function declaration
  58 static void task_system_statechart(void *parameters);
  59 static void task_system_temp_ctrl_enable(void *parameters);
  60 static void task_system_timer_update(void *parameters);
  61 static void task_system_rtc_init(void);
  62 static void task_system_rtc_increment_hour(void);
  63 static void task_system_rtc_increment_min(void);
  64 static void task_system_eeprom_read_param(void *parameters);
  65 static void task_system_eeprom_write_param(void *parameters);
  66 static uint32_t task_system_eeprom_get_current_addr(void);
  67 
  68 // Public function definition
  69 void task_system_init(void *parameters)
  70 {
  71     task_system_dta_t *p_task_system_dta;
  72     task_system_st_t state;
  73 
  74     LOGGER_INFO("Initializing `task_system`...");
  75 
  76     g_task_system_tick_cnt = G_TASK_SYS_TICK_CNT_INI;
  77     g_task_system_timer_tick = G_TASK_SYS_CNT_INI;
  78 
  79     task_system_interface_init_event_queue();
  80     task_system_rtc_init();
  81     task_system_eeprom_read_param(parameters);
  82 
  83     p_task_system_dta = &task_system_dta;
  84 
  85     state = ST_SYS_IDLE;
  86     p_task_system_dta->state = state;
  87 
  88     shared_data_type *p_shared_data = (shared_data_type *)parameters;
  89     p_shared_data->timer = &task_system_timer;
  90 
  91     LOGGER_INFO("Done initializing `task_system`");
  92 }
  93 
  94 void task_system_update(void *parameters)
  95 {
  96     bool b_time_update_required = false;
  97 
  98     __asm("CPSID i");
  99     if (G_TASK_SYS_TICK_CNT_INI < g_task_system_tick_cnt)
 100     {
 101         g_task_system_tick_cnt--;
 102         b_time_update_required = true;
 103     }
 104     __asm("CPSIE i");
 105 
 106     while (b_time_update_required)
 107     {
 108         if (0 == g_task_system_timer_tick)
 109         {
 110             g_task_system_timer_tick = G_TASK_SYS_TIMER_UPDATE_RATE_MS;
 111             task_system_timer_update(parameters);
 112         }
 113         else
 114         {
 115             g_task_system_timer_tick--;
 116         }
 117         task_system_statechart(parameters);
 118 
 119         __asm("CPSID i");
 120         if (G_TASK_SYS_TICK_CNT_INI < g_task_system_tick_cnt)
 121         {
 122             g_task_system_tick_cnt--;
 123             b_time_update_required = true;
 124         }
 125         else
 126         {
 127             b_time_update_required = false;
 128         }
 129         __asm("CPSIE i");
 130     }
 131 }
 132 
 133 // Private function definition
 134 static void task_system_rtc_init(void)
 135 {
 136     HAL_PWR_EnableBkUpAccess();
 137 
 138     // Set RTC Time only if RTC has been reset
 139     if (HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR1) != RTC_BACKUP_MAGIC_NUMBER)
 140     {
 141         s_time.Hours   = 16;
 142         s_time.Minutes = 41;
 143         s_time.Seconds = 20;
 144         HAL_RTC_SetTime(&hrtc, &s_time, RTC_FORMAT_BIN);
 145 
 146         s_date.WeekDay = RTC_WEEKDAY_FRIDAY;
 147         s_date.Month   = RTC_MONTH_MARCH;
 148         s_date.Date    = 20;
 149         s_date.Year    = 26; // 2026
 150         HAL_RTC_SetDate(&hrtc, &s_date, RTC_FORMAT_BIN);
 151         HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR1, RTC_BACKUP_MAGIC_NUMBER);
 152     }
 153 }
 154 
 155 static void task_system_rtc_increment_hour()
 156 {
 157     HAL_RTC_GetTime(&hrtc, &s_time, RTC_FORMAT_BIN);
 158     s_time.Hours = (s_time.Hours + 1) % 24;
 159     HAL_RTC_SetTime(&hrtc, &s_time, RTC_FORMAT_BIN);
 160 }
 161 
 162 static void task_system_rtc_increment_min()
 163 {
 164     HAL_RTC_GetTime(&hrtc, &s_time, RTC_FORMAT_BIN);
 165     s_time.Minutes = (s_time.Minutes + 1) % 60;
 166     HAL_RTC_SetTime(&hrtc, &s_time, RTC_FORMAT_BIN);
 167 }
 168 
 169 static uint32_t task_system_eeprom_get_current_addr(void)
 170 {
 171     uint32_t addr = G_TASK_SYS_EEPROM_START_ADDR;
 172 
 173     while (G_TASK_SYS_EEPROM_END_ADDR > addr)
 174     {
 175         if (0xFFFF == *(uint16_t*)addr)
 176         {
 177             // Empty value found
 178             return (addr - sizeof(uint16_t));
 179         }
 180         addr += sizeof(uint16_t);
 181     }
 182 
 183     // Page is full
 184     return 0;
 185 }
 186 
 187 static void task_system_eeprom_read_param(void *parameters)
 188 {
 189     shared_data_type *p_shared_data = (shared_data_type *)parameters;
 190 
 191     uint32_t addr = task_system_eeprom_get_current_addr();
 192     if (0 == addr)
 193     {
 194         addr = G_TASK_SYS_EEPROM_END_ADDR;
 195     }
 196 
 197     p_shared_data->temp_set_point = *(uint16_t*)addr;
 198 }
 199 
 200 // To reduce the wear of flash its better to write the new variables on the same
 201 // page but on contiguous addresses every time the variables are updated, this
 202 // also has the benefit that there is no need to erase the full page all the
 203 // time but only once the page fills which after 512 writes (2 bytes on a page
 204 // of 1024 bytes).
 205 static void task_system_eeprom_write_param(void *parameters)
 206 {
 207     uint32_t new_addr, curr_addr;
 208     shared_data_type *p_shared_data = (shared_data_type *)parameters;
 209 
 210     curr_addr = task_system_eeprom_get_current_addr();
 211 
 212     if(p_shared_data->temp_set_point == *(uint16_t *)curr_addr)
 213     {
 214         // No need to update if the value is the same
 215         return;
 216     }
 217 
 218     uint16_t data[] = {
 219         p_shared_data->temp_set_point
 220     };
 221 
 222     HAL_FLASH_Unlock();
 223 
 224     if (0 == curr_addr)
 225     {
 226         // Memory page is full
 227         LOGGER_INFO("Memory page is full. Erasing full page...");
 228 
 229         FLASH_EraseInitTypeDef erase = {0};
 230         uint32_t sector_error;
 231 
 232         erase.TypeErase   = FLASH_TYPEERASE_PAGES;
 233         erase.PageAddress = G_TASK_SYS_EEPROM_START_ADDR;
 234         erase.NbPages     = 1; // 1024 bytes
 235 
 236         if(HAL_FLASHEx_Erase(&erase, &sector_error) != HAL_OK)
 237         {
 238             HAL_FLASH_Lock();
 239             LOGGER_ERROR("Could erase flash at address %d",
 240                     G_TASK_SYS_EEPROM_START_ADDR);
 241             return;
 242         }
 243 
 244         new_addr = G_TASK_SYS_EEPROM_START_ADDR;
 245     }
 246     else
 247     {
 248         new_addr = (curr_addr + sizeof(uint16_t));
 249     }
 250 
 251     HAL_FLASH_Program(TYPEPROGRAM_HALFWORD, new_addr, *(uint16_t *)data);
 252     HAL_FLASH_Lock();
 253     return;
 254 }
 255 
 256 static void task_system_temp_ctrl_enable(void *parameters)
 257 {
 258     shared_data_type *p_shared_data = (shared_data_type *)parameters;
 259 
 260     p_shared_data->temp_ctrl_enabled = !p_shared_data->temp_ctrl_enabled;
 261     task_menu_interface_put_event(EV_MEN_DISPLAY_UPDATE);
 262     task_buzzer_interface_put_event(EV_BUZ_XX_LONG_BEEP, ID_BUZ_A);
 263 
 264     if (true == p_shared_data->temp_ctrl_enabled)
 265     {
 266         task_leds_interface_put_event(EV_LED_XX_BLINK, ID_LED_A);
 267         task_leds_interface_put_event(EV_LED_XX_BLINK, ID_LED_B);
 268     }
 269     else
 270     {
 271         task_leds_interface_put_event(EV_LED_XX_OFF, ID_LED_A);
 272         task_leds_interface_put_event(EV_LED_XX_OFF, ID_LED_B);
 273     }
 274 }
 275 
 276 static void task_system_statechart(void *parameters)
 277 {
 278     task_system_dta_t *p_task_system_dta = &task_system_dta;
 279     shared_data_type *p_shared_data = (shared_data_type *)parameters;
 280 
 281     if (true == task_system_interface_any_event())
 282     {
 283         p_task_system_dta->event_flag = true;
 284         p_task_system_dta->event = task_system_interface_get_event();
 285 
 286         // Events which are common to every state
 287         switch (p_task_system_dta->event)
 288         {
 289 
 290             case EV_SYS_REM_TIMER_TOGGLE:
 291                 p_task_system_dta->event_flag = false;
 292                 p_shared_data->timer->enabled = !p_shared_data->timer->enabled;
 293                 task_menu_interface_put_event(EV_MEN_DISPLAY_UPDATE);
 294             break;
 295 
 296             case EV_SYS_REM_TEMP_CTRL_ENABLED:
 297                 p_task_system_dta->event_flag = false;
 298                 task_system_temp_ctrl_enable(parameters);
 299                 task_menu_interface_put_event(EV_MEN_DISPLAY_UPDATE);
 300             break;
 301 
 302             case EV_SYS_REM_TEMP_SET:
 303                 p_task_system_dta->event_flag = false;
 304                 task_system_eeprom_write_param(parameters);
 305                 task_menu_interface_put_event(EV_MEN_DISPLAY_UPDATE);
 306             break;
 307 
 308             default:
 309             break;
 310         }
 311     }
 312 
 313     switch (p_task_system_dta->state)
 314     {
 315         case ST_SYS_IDLE:
 316             if (true == p_task_system_dta->event_flag)
 317             {
 318                 p_task_system_dta->event_flag = false;
 319                 switch (p_task_system_dta->event)
 320                 {
 321                     case EV_SYS_BTN_B_ACTIVE:
 322                     break;
 323 
 324                     case EV_SYS_BTN_C_ACTIVE:
 325                         task_system_temp_ctrl_enable(parameters);
 326                     break;
 327 
 328                     case EV_SYS_BTN_A_ACTIVE:
 329                     case EV_SYS_BTN_D_ACTIVE:
 330                         p_task_system_dta->state = ST_SYS_CLOCK_SET;
 331                         task_menu_interface_put_event(EV_MEN_ST_CLOCK_SET);
 332                     break;
 333 
 334                     default: break;
 335                 }
 336             }
 337         break;
 338 
 339         case ST_SYS_CLOCK_SET:
 340             if (true == p_task_system_dta->event_flag)
 341             {
 342                 p_task_system_dta->event_flag = false;
 343                 switch (p_task_system_dta->event)
 344                 {
 345                     case EV_SYS_BTN_A_ACTIVE:
 346                     case EV_SYS_BTN_D_ACTIVE:
 347                         p_task_system_dta->state = ST_SYS_TEMP_SET;
 348                         task_menu_interface_put_event(EV_MEN_ST_TEMP_SET);
 349                     break;
 350                     case EV_SYS_BTN_B_ACTIVE:
 351                         task_system_rtc_increment_hour();
 352                         task_menu_interface_put_event(EV_MEN_DISPLAY_UPDATE);
 353                     break;
 354                     case EV_SYS_BTN_C_ACTIVE:
 355                         task_system_rtc_increment_min();
 356                         task_menu_interface_put_event(EV_MEN_DISPLAY_UPDATE);
 357                     break;
 358                     default: break;
 359                 }
 360             }
 361         break;
 362 
 363         case ST_SYS_TEMP_SET:
 364             if (true == p_task_system_dta->event_flag)
 365             {
 366                 p_task_system_dta->event_flag = false;
 367                 switch (p_task_system_dta->event)
 368                 {
 369                     case EV_SYS_BTN_A_ACTIVE:
 370                     case EV_SYS_BTN_D_ACTIVE:
 371                         p_task_system_dta->state = ST_SYS_TIMER_SET_STATUS;
 372                         task_menu_interface_put_event(EV_MEN_ST_TIMER_SET_STATUS);
 373                         task_system_eeprom_write_param(parameters);
 374                     break;
 375 
 376                     case EV_SYS_BTN_B_ACTIVE:
 377                         p_shared_data->temp_set_point =
 378                             ((p_shared_data->temp_set_point - 5) % 85);
 379                         task_menu_interface_put_event(EV_MEN_DISPLAY_UPDATE);
 380                     break;
 381 
 382                     case EV_SYS_BTN_C_ACTIVE:
 383                         p_shared_data->temp_set_point =
 384                             ((p_shared_data->temp_set_point + 5) % 85);
 385 
 386                         task_menu_interface_put_event(EV_MEN_DISPLAY_UPDATE);
 387                     break;
 388 
 389                     default: break;
 390                 }
 391             }
 392         break;
 393 
 394         case ST_SYS_TIMER_SET_STATUS:
 395             if (true == p_task_system_dta->event_flag)
 396             {
 397                 p_task_system_dta->event_flag = false;
 398                 switch (p_task_system_dta->event)
 399                 {
 400 
 401                     case EV_SYS_BTN_C_ACTIVE:
 402                         p_shared_data->timer->enabled = !p_shared_data->timer->enabled;
 403                         task_menu_interface_put_event(EV_MEN_DISPLAY_UPDATE);
 404                     break;
 405 
 406                     case EV_SYS_BTN_A_ACTIVE:
 407                     case EV_SYS_BTN_B_ACTIVE:
 408                         p_task_system_dta->state = ST_SYS_IDLE;
 409                         task_menu_interface_put_event(EV_MEN_ST_IDLE);
 410                         break;
 411 
 412                     case EV_SYS_BTN_D_ACTIVE:
 413                         p_task_system_dta->state = ST_SYS_TIMER_SET_START;
 414                         task_menu_interface_put_event(EV_MEN_ST_TIMER_SET_START);
 415                     break;
 416 
 417                     default: break;
 418                 }
 419             }
 420         break;
 421 
 422         case ST_SYS_TIMER_SET_START:
 423             if (true == p_task_system_dta->event_flag)
 424             {
 425                 p_task_system_dta->event_flag = false;
 426                 switch (p_task_system_dta->event)
 427                 {
 428                     case EV_SYS_BTN_B_ACTIVE:
 429                         p_shared_data->timer->start_hour =
 430                             ((p_shared_data->timer->start_hour + 1) % 24);
 431                         task_menu_interface_put_event(EV_MEN_DISPLAY_UPDATE);
 432                     break;
 433 
 434                     case EV_SYS_BTN_C_ACTIVE:
 435                         p_shared_data->timer->start_min =
 436                             ((p_shared_data->timer->start_min + 1) % 60);
 437                         task_menu_interface_put_event(EV_MEN_DISPLAY_UPDATE);
 438                     break;
 439 
 440                     case EV_SYS_BTN_A_ACTIVE:
 441                     case EV_SYS_BTN_D_ACTIVE:
 442                         p_task_system_dta->state = ST_SYS_TIMER_SET_END;
 443                         task_menu_interface_put_event(EV_MEN_ST_TIMER_SET_END);
 444                     break;
 445 
 446                     default: break;
 447                 }
 448             }
 449         break;
 450 
 451         case ST_SYS_TIMER_SET_END:
 452             if (true == p_task_system_dta->event_flag)
 453             {
 454                 p_task_system_dta->event_flag = false;
 455                 switch (p_task_system_dta->event)
 456                 {
 457                     case EV_SYS_BTN_B_ACTIVE:
 458                         p_shared_data->timer->end_hour =
 459                             ((p_shared_data->timer->end_hour + 1) % 24);
 460                         task_menu_interface_put_event(EV_MEN_DISPLAY_UPDATE);
 461                     break;
 462 
 463                     case EV_SYS_BTN_C_ACTIVE:
 464                         p_shared_data->timer->end_min =
 465                             ((p_shared_data->timer->end_min + 1) % 60);
 466                         task_menu_interface_put_event(EV_MEN_DISPLAY_UPDATE);
 467                     break;
 468 
 469                     case EV_SYS_BTN_A_ACTIVE:
 470                     case EV_SYS_BTN_D_ACTIVE:
 471                         p_task_system_dta->state = ST_SYS_IDLE;
 472                         task_menu_interface_put_event(EV_MEN_ST_IDLE);
 473                     break;
 474 
 475                     default: break;
 476                 }
 477             }
 478         break;
 479 
 480         default: 
 481             p_task_system_dta->state = ST_SYS_IDLE;
 482             p_task_system_dta->event_flag = false;
 483             p_shared_data->temp_ctrl_enabled = false;
 484             task_menu_interface_put_event(EV_MEN_ST_IDLE);
 485             task_leds_interface_put_event(EV_LED_XX_OFF, ID_LED_A);
 486             task_leds_interface_put_event(EV_LED_XX_OFF, ID_LED_B);
 487         break;
 488     }
 489 }
 490 
 491 // TODO: Only check timer conditions every second (not on every tick)
 492 static void task_system_timer_update(void *parameters)
 493 {
 494     shared_data_type *p_shared_data = (shared_data_type *)parameters;
 495     uint16_t start_24, end_24, clock_24;
 496     bool new_temp_ctrl_state;
 497 
 498     if (false == p_shared_data->timer->enabled)
 499     {
 500         return;
 501     }
 502 
 503     HAL_RTC_GetTime(&hrtc, &s_time, RTC_FORMAT_BIN);
 504 
 505     clock_24 = (s_time.Hours*100) + s_time.Minutes;
 506     start_24 = (p_shared_data->timer->start_hour*100) +
 507                 p_shared_data->timer->start_min;
 508     end_24 = (p_shared_data->timer->end_hour*100) +
 509               p_shared_data->timer->end_min;
 510 
 511     new_temp_ctrl_state = ((end_24 > start_24)
 512                 ? ((clock_24 >= start_24) && (clock_24 < end_24))
 513                 : ((clock_24 >= start_24) || (clock_24 < end_24)));
 514 
 515     if (new_temp_ctrl_state != p_shared_data->temp_ctrl_enabled)
 516     {
 517         p_shared_data->temp_ctrl_enabled = new_temp_ctrl_state;
 518 
 519         task_menu_interface_put_event(EV_MEN_DISPLAY_UPDATE);
 520         task_buzzer_interface_put_event(EV_BUZ_XX_LONG_BEEP, ID_BUZ_A);
 521 
 522         if (true == p_shared_data->temp_ctrl_enabled)
 523         {
 524             task_leds_interface_put_event(EV_LED_XX_BLINK, ID_LED_A);
 525             task_leds_interface_put_event(EV_LED_XX_BLINK, ID_LED_B);
 526         }
 527         else
 528         {
 529             task_leds_interface_put_event(EV_LED_XX_OFF, ID_LED_A);
 530             task_leds_interface_put_event(EV_LED_XX_OFF, ID_LED_B);
 531         }
 532     }
 533 }