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 ******************************************/
