tdse-tp3_04-interactive_menu

Index Commits Files Refs
app/src/task_menu.c (17413B)
   1 /*
   2  * Copyright (c) 2023 Juan Manuel Cruz <jcruz@fi.uba.ar> <jcruz@frba.utn.edu.ar>.
   3  * All rights reserved.
   4  *
   5  * Redistribution and use in source and binary forms, with or without
   6  * modification, are permitted provided that the following conditions are met:
   7  *
   8  * 1. Redistributions of source code must retain the above copyright
   9  *    notice, this list of conditions and the following disclaimer.
  10  *
  11  * 2. Redistributions in binary form must reproduce the above copyright
  12  *    notice, this list of conditions and the following disclaimer in the
  13  *    documentation and/or other materials provided with the distribution.
  14  *
  15  * 3. Neither the name of the copyright holder nor the names of its
  16  *    contributors may be used to endorse or promote products derived from
  17  *    this software without specific prior written permission.
  18  *
  19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  23  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  25  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  26  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  28  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
  29  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  30  * POSSIBILITY OF SUCH DAMAGE.
  31  *
  32  * @file   : task_menu.c
  33  * @date   : Set 26, 2023
  34  * @author : Juan Manuel Cruz <jcruz@fi.uba.ar> <jcruz@frba.utn.edu.ar>
  35  * @version    v1.0.0
  36  */
  37 
  38 /********************** inclusions *******************************************/
  39 /* Project includes */
  40 #include "main.h"
  41 
  42 /* Demo includes */
  43 #include "logger.h"
  44 #include "dwt.h"
  45 
  46 /* Application & Tasks includes */
  47 #include "board.h"
  48 #include "app.h"
  49 #include "task_menu_attribute.h"
  50 #include "task_menu_interface.h"
  51 #include "display.h"
  52 
  53 /********************** macros and definitions *******************************/
  54 #define G_TASK_MEN_CNT_INI          0ul
  55 #define G_TASK_MEN_TICK_CNT_INI     0ul
  56 
  57 #define DEL_MEN_XX_MIN              0ul
  58 #define DEL_MEN_XX_MED             50ul
  59 #define DEL_MEN_XX_MAX            150ul
  60 
  61 /********************** internal data declaration ****************************/
  62 task_menu_dta_t task_menu_dta =
  63     {DEL_MEN_XX_MIN, ST_MEN_MOTOR_INFO, EV_MEN_ENT_IDLE, false};
  64 
  65 #define MENU_DTA_QTY    (sizeof(task_menu_dta)/sizeof(task_menu_dta_t))
  66 
  67 typedef struct {
  68     bool power, spin;
  69     uint8_t speed;
  70 } motor_data_t;
  71 
  72 /********************** internal functions declaration ***********************/
  73 void task_menu_statechart(void);
  74 
  75 /********************** internal data definition *****************************/
  76 const char *p_task_menu = "Task Menu (Interactive Menu)";
  77 const char *p_task_menu_ = "Non-Blocking & Update By Time Code";
  78 bool g_display_update = false;
  79 
  80 #define MOTOR_QTY 2
  81 
  82 motor_data_t g_motor_data[MOTOR_QTY];
  83 
  84 uint8_t g_selected_motor = 0;
  85 uint8_t g_new_sel_motor_spin;
  86 bool g_new_sel_motor_power;
  87 uint8_t g_new_sel_motor_speed;
  88 task_menu_st_t g_menu_prev_state;
  89 
  90 /********************** external data declaration ****************************/
  91 uint32_t g_task_menu_cnt;
  92 volatile uint32_t g_task_menu_tick_cnt;
  93 
  94 /********************** external functions definition ************************/
  95 void task_menu_init(void *parameters)
  96 {
  97     task_menu_dta_t *p_task_menu_dta;
  98     task_menu_st_t    state;
  99     task_menu_ev_t    event;
 100     bool b_event;
 101 
 102     /* Print out: Task Initialized */
 103     LOGGER_INFO(" ");
 104     LOGGER_INFO("  %s is running - %s", GET_NAME(task_menu_init), p_task_menu);
 105     LOGGER_INFO("  %s is a %s", GET_NAME(task_menu), p_task_menu_);
 106 
 107     /* Init & Print out: Task execution counter */
 108     g_task_menu_cnt = G_TASK_MEN_CNT_INI;
 109     LOGGER_INFO("   %s = %lu", GET_NAME(g_task_menu_cnt), g_task_menu_cnt);
 110 
 111     init_queue_event_task_menu();
 112 
 113     /* Update Task Actuator Configuration & Data Pointer */
 114     p_task_menu_dta = &task_menu_dta;
 115 
 116     /* Init & Print out: Task execution FSM */
 117     state = ST_MEN_MOTOR_INFO;
 118     p_task_menu_dta->state = state;
 119 
 120     g_menu_prev_state = state;
 121     g_selected_motor = 1;
 122 
 123     event = EV_MEN_ENT_IDLE;
 124     p_task_menu_dta->event = event;
 125 
 126     b_event = false;
 127     p_task_menu_dta->flag = b_event;
 128 
 129     /* Init & Print out: LCD Display */
 130     displayInit(DISPLAY_CONNECTION_GPIO_4BITS);
 131     g_display_update = true;
 132 }
 133 
 134 void task_menu_update(void *parameters)
 135 {
 136     bool b_time_update_required = false;
 137 
 138     /* Protect shared resource */
 139     __asm("CPSID i");    /* disable interrupts */
 140     if (G_TASK_MEN_TICK_CNT_INI < g_task_menu_tick_cnt)
 141     {
 142         /* Update Tick Counter */
 143         g_task_menu_tick_cnt--;
 144         b_time_update_required = true;
 145     }
 146     __asm("CPSIE i");    /* enable interrupts */
 147 
 148     while (b_time_update_required)
 149     {
 150         /* Update Task Counter */
 151         g_task_menu_cnt++;
 152 
 153         /* Run Task Menu Statechart */
 154         task_menu_statechart();
 155 
 156         /* Protect shared resource */
 157         __asm("CPSID i");    /* disable interrupts */
 158         if (G_TASK_MEN_TICK_CNT_INI < g_task_menu_tick_cnt)
 159         {
 160             /* Update Tick Counter */
 161             g_task_menu_tick_cnt--;
 162             b_time_update_required = true;
 163         }
 164         else
 165         {
 166             b_time_update_required = false;
 167         }
 168         __asm("CPSIE i");    /* enable interrupts */
 169     }
 170 }
 171 
 172 void menu_set_state(task_menu_st_t new_state)
 173 {
 174     task_menu_dta_t *p_task_menu_dta;
 175     p_task_menu_dta = &task_menu_dta;
 176 
 177     g_menu_prev_state = p_task_menu_dta->state;
 178     p_task_menu_dta->state = new_state;
 179 
 180     g_display_update = true;
 181 }
 182 
 183 char* motor_power_to_str(uint8_t motor_power)
 184 {
 185     return motor_power ? "On" : "Off";
 186 }
 187 
 188 char* motor_spin_to_str(uint8_t motor_spin)
 189 {
 190     return motor_spin ? "Right" : "Left";
 191 }
 192 
 193 void task_menu_statechart(void)
 194 {
 195     task_menu_dta_t *p_task_menu_dta;
 196     char menu_row_str[16 + 4];
 197 
 198     /* Update Task Menu Data Pointer */
 199     p_task_menu_dta = &task_menu_dta;
 200 
 201     if (true == any_event_task_menu())
 202     {
 203         p_task_menu_dta->flag = true;
 204         p_task_menu_dta->event = get_event_task_menu();
 205     }
 206 
 207 
 208     if ((true == p_task_menu_dta->flag)
 209         && (p_task_menu_dta->event == EV_MEN_INACTIVE_TIMEOUT)
 210         && (p_task_menu_dta->state != ST_MEN_MOTOR_INFO))
 211     {
 212         menu_set_state(ST_MEN_MOTOR_INFO);
 213     }
 214 
 215     switch (p_task_menu_dta->state)
 216     {
 217         case ST_MEN_MOTOR_INFO:
 218 
 219             if (g_display_update)
 220             {
 221                 g_display_update = false;
 222                 displayClear();
 223                 sprintf(menu_row_str, "1>%4s> %s>%5d%%",
 224                         motor_power_to_str(g_motor_data[0].power),
 225                         g_motor_data[0].spin ? "R" : "L",
 226                         g_motor_data[0].speed);
 227                 displayStringWrite(menu_row_str);
 228 
 229                 displayCharPositionWrite(0, 1);
 230                 sprintf(menu_row_str, "2>%4s> %s>%5d%%",
 231                         motor_power_to_str(g_motor_data[1].power),
 232                         g_motor_data[1].spin ? "R" : "L",
 233                         g_motor_data[1].speed);
 234                 displayStringWrite(menu_row_str);
 235             }
 236 
 237             if (true == p_task_menu_dta->flag)
 238             {
 239                 p_task_menu_dta->flag = false;
 240                 switch (p_task_menu_dta->event)
 241                 {
 242                     case EV_MEN_ENT_ACTIVE:
 243                     case EV_MEN_NEX_ACTIVE:
 244                     case EV_MEN_ESC_ACTIVE:
 245                         menu_set_state(ST_MEN_MOTOR_SELECT);
 246                         break;
 247                     default:
 248                     break;
 249                 }
 250             }
 251 
 252         break;
 253 
 254         case ST_MEN_MOTOR_SELECT:
 255 
 256             if (g_display_update)
 257             {
 258                 g_display_update = false;
 259                 displayClear();
 260                 sprintf(menu_row_str, "> Motor %d", g_selected_motor);
 261                 displayStringWrite(menu_row_str);
 262             }
 263 
 264             if (true == p_task_menu_dta->flag)
 265             {
 266                 p_task_menu_dta->flag = false;
 267                 switch (p_task_menu_dta->event)
 268                 {
 269                     case EV_MEN_ENT_ACTIVE:
 270                         menu_set_state(ST_MEN_MOTOR_POWER);
 271                     break;
 272                     case EV_MEN_NEX_ACTIVE:
 273                         g_selected_motor = (g_selected_motor % MOTOR_QTY) + 1;
 274                         g_display_update = true;
 275                     break;
 276                     case EV_MEN_ESC_ACTIVE:
 277                         menu_set_state(ST_MEN_MOTOR_INFO);
 278                     break;
 279                     default:
 280                     break;
 281                 }
 282             }
 283 
 284         break;
 285 
 286         case ST_MEN_MOTOR_POWER:
 287 
 288             if (g_menu_prev_state != p_task_menu_dta->state)
 289             {
 290                 g_menu_prev_state = p_task_menu_dta->state;
 291                 g_new_sel_motor_power = g_motor_data[g_selected_motor - 1].power;
 292             }
 293 
 294             if (g_display_update)
 295             {
 296                 g_display_update = false;
 297                 displayClear();
 298                 sprintf(menu_row_str, "%1d> Power", g_selected_motor);
 299                 displayStringWrite(menu_row_str);
 300                 displayCharPositionWrite(11, 1);
 301                 displayStringWrite(motor_power_to_str(g_motor_data[g_selected_motor-1].power));
 302             }
 303 
 304             if (true == p_task_menu_dta->flag)
 305             {
 306                 p_task_menu_dta->flag = false;
 307                 switch (p_task_menu_dta->event)
 308                 {
 309                     case EV_MEN_ENT_ACTIVE:
 310                         menu_set_state(ST_MEN_MOTOR_POWER_SEL);
 311                     break;
 312                     case EV_MEN_NEX_ACTIVE:
 313                         menu_set_state(ST_MEN_MOTOR_SPEED);
 314                     break;
 315                     case EV_MEN_ESC_ACTIVE:
 316                         menu_set_state(ST_MEN_MOTOR_SELECT);
 317                     break;
 318                     default:
 319                     break;
 320                 }
 321             }
 322 
 323         break;
 324 
 325         case ST_MEN_MOTOR_POWER_SEL:
 326 
 327             if (g_menu_prev_state != p_task_menu_dta->state)
 328             {
 329                 g_menu_prev_state = p_task_menu_dta->state;
 330                 g_new_sel_motor_power = g_motor_data[g_selected_motor - 1].power;
 331             }
 332 
 333             if (g_display_update)
 334             {
 335                 g_display_update = false;
 336                 displayClear();
 337                 displayCharPositionWrite(0, 0);
 338                 sprintf(menu_row_str, "%1d> Power set", g_selected_motor);
 339                 displayStringWrite(menu_row_str);
 340                 displayCharPositionWrite(11, 1);
 341                 displayStringWrite(motor_power_to_str(g_new_sel_motor_power));
 342             }
 343 
 344             if (true == p_task_menu_dta->flag)
 345             {
 346                 p_task_menu_dta->flag = false;
 347                 switch (p_task_menu_dta->event)
 348                 {
 349                     case EV_MEN_ENT_ACTIVE:
 350                         g_motor_data[g_selected_motor - 1].power = g_new_sel_motor_power;
 351                         menu_set_state(ST_MEN_MOTOR_POWER);
 352                     break;
 353                     case EV_MEN_NEX_ACTIVE:
 354                         g_new_sel_motor_power = !g_new_sel_motor_power;
 355                         g_display_update = true;
 356                     break;
 357                     case EV_MEN_ESC_ACTIVE:
 358                         menu_set_state(ST_MEN_MOTOR_POWER);
 359                     break;
 360                     default:
 361                     break;
 362                 }
 363             }
 364 
 365         break;
 366 
 367         case ST_MEN_MOTOR_SPEED:
 368 
 369             if (g_display_update)
 370             {
 371                 g_display_update = false;
 372                 displayClear();
 373                 sprintf(menu_row_str, "%1d> Speed", g_selected_motor);
 374                 displayStringWrite(menu_row_str);
 375 
 376                 displayCharPositionWrite(11, 1);
 377                 sprintf(menu_row_str, "%3d%%", g_motor_data[g_selected_motor-1].speed);
 378                 displayStringWrite(menu_row_str);
 379             }
 380 
 381             if (true == p_task_menu_dta->flag)
 382             {
 383                 p_task_menu_dta->flag = false;
 384                 switch (p_task_menu_dta->event)
 385                 {
 386                     case EV_MEN_NEX_ACTIVE:
 387                         menu_set_state(ST_MEN_MOTOR_SPIN);
 388                     break;
 389 
 390                     case EV_MEN_ESC_ACTIVE:
 391                         menu_set_state(ST_MEN_MOTOR_SELECT);
 392                     break;
 393 
 394                     case EV_MEN_ENT_ACTIVE:
 395                         menu_set_state(ST_MEN_MOTOR_SPEED_SEL);
 396                     break;
 397 
 398                     default:
 399                     break;
 400                 }
 401             }
 402 
 403         break;
 404 
 405         case ST_MEN_MOTOR_SPEED_SEL:
 406 
 407             if (g_menu_prev_state != p_task_menu_dta->state)
 408             {
 409                 g_menu_prev_state = p_task_menu_dta->state;
 410                 g_new_sel_motor_speed = g_motor_data[g_selected_motor-1].speed;
 411             }
 412 
 413             if (g_display_update)
 414             {
 415                 g_display_update = false;
 416                 displayClear();
 417                 sprintf(menu_row_str, "%1d> Speed set", g_selected_motor);
 418                 displayStringWrite(menu_row_str);
 419 
 420                 displayCharPositionWrite(11, 1);
 421                 sprintf(menu_row_str, "%3d%%", g_new_sel_motor_speed);
 422                 displayStringWrite(menu_row_str);
 423             }
 424 
 425             if (true == p_task_menu_dta->flag)
 426             {
 427                 p_task_menu_dta->flag = false;
 428                 switch (p_task_menu_dta->event)
 429                 {
 430                     case EV_MEN_NEX_ACTIVE:
 431                         g_new_sel_motor_speed = ((g_new_sel_motor_speed + 10) % 110);
 432                         g_display_update = true;
 433                     break;
 434 
 435                     case EV_MEN_ENT_ACTIVE:
 436                         g_motor_data[g_selected_motor-1].speed = g_new_sel_motor_speed;
 437                     case EV_MEN_ESC_ACTIVE:
 438                         menu_set_state(ST_MEN_MOTOR_SPEED);
 439                     break;
 440 
 441                     default:
 442                     break;
 443                 }
 444             }
 445 
 446         break;
 447 
 448         case ST_MEN_MOTOR_SPIN:
 449 
 450             if (g_display_update)
 451             {
 452                 g_display_update = false;
 453                 displayClear();
 454                 sprintf(menu_row_str, "%1d> Spin", g_selected_motor);
 455                 displayStringWrite(menu_row_str);
 456                 displayCharPositionWrite(0, 1);
 457                 sprintf(menu_row_str, "%15s",
 458                         motor_spin_to_str(g_motor_data[g_selected_motor-1].spin));
 459                 displayStringWrite(menu_row_str);
 460             }
 461 
 462             if (true == p_task_menu_dta->flag)
 463             {
 464                 p_task_menu_dta->flag = false;
 465                 switch (p_task_menu_dta->event)
 466                 {
 467                     case EV_MEN_NEX_ACTIVE:
 468                         menu_set_state(ST_MEN_MOTOR_POWER);
 469                     break;
 470 
 471                     case EV_MEN_ESC_ACTIVE:
 472                         menu_set_state(ST_MEN_MOTOR_SELECT);
 473                     break;
 474 
 475                     case EV_MEN_ENT_ACTIVE:
 476                         menu_set_state(ST_MEN_MOTOR_SPIN_SEL);
 477                     break;
 478                     default:
 479                     break;
 480                 }
 481             }
 482 
 483         break;
 484 
 485         case ST_MEN_MOTOR_SPIN_SEL:
 486 
 487             if (g_menu_prev_state != p_task_menu_dta->state)
 488             {
 489                 g_menu_prev_state = p_task_menu_dta->state;
 490                 g_new_sel_motor_spin = g_motor_data[g_selected_motor - 1].spin;
 491             }
 492 
 493             if (g_display_update)
 494             {
 495                 g_display_update = false;
 496                 displayClear();
 497                 sprintf(menu_row_str, "%1d> Spin set", g_selected_motor);
 498                 displayStringWrite(menu_row_str);
 499                 displayCharPositionWrite(0, 1);
 500                 sprintf(menu_row_str, "%15s", motor_spin_to_str(g_new_sel_motor_spin));
 501                 displayStringWrite(menu_row_str);
 502             }
 503 
 504             if (true == p_task_menu_dta->flag)
 505             {
 506                 p_task_menu_dta->flag = false;
 507                 switch (p_task_menu_dta->event)
 508                 {
 509                     case EV_MEN_NEX_ACTIVE:
 510                         g_new_sel_motor_spin = g_new_sel_motor_spin ? 0 : 1;
 511                         g_display_update = true;
 512                     break;
 513 
 514                     case EV_MEN_ENT_ACTIVE:
 515                         g_motor_data[g_selected_motor-1].spin = g_new_sel_motor_spin;
 516                     case EV_MEN_ESC_ACTIVE:
 517                         menu_set_state(ST_MEN_MOTOR_SPIN);
 518                     break;
 519 
 520                     default:
 521                     break;
 522                 }
 523             }
 524 
 525         break;
 526 
 527         default:
 528 
 529             p_task_menu_dta->tick  = DEL_MEN_XX_MIN;
 530             p_task_menu_dta->state = ST_MEN_MOTOR_SELECT;
 531             p_task_menu_dta->event = EV_MEN_ENT_IDLE;
 532             p_task_menu_dta->flag  = false;
 533             g_display_update = false;
 534 
 535             break;
 536     }
 537 }
 538 
 539 /********************** end of file ******************************************/