tdse-tp3_04-interactive_menu

Index Commits Files Refs
app/gemini_02.txt (8061B)
   1 ### **Análisis y Explicación del Código Fuente**
   2 
   3 #### **1. `logger.c` y `logger.h` (Sistema de Registro/Log)** Estos archivos
   4 implementan un sistema de registro de mensajes (logging) para depuración.
   5 
   6 * **`logger.h`**:
   7     * Define las macros `LOGGER_LOG` y `LOGGER_INFO` para facilitar el envío de
   8       mensajes.
   9     * La configuración `LOGGER_CONFIG_USE_SEMIHOSTING` (activada) indica que la
  10       salida de los logs se realizará a través de "semihosting". Este es un
  11       mecanismo de depuración que permite al microcontrolador enviar datos (como
  12       texto) al computador anfitrión a través de la sonda de depuración (ej.
  13       ST-Link), mostrándolos en la consola del IDE.
  14     * **Crucialmente, la macro `LOGGER_LOG` deshabilita las interrupciones
  15       (`__asm("CPSID i")`) antes de preparar y enviar el mensaje, y las
  16       rehabilita después (`__asm("CPSIE i")`)**. Esto se hace para evitar que
  17       una interrupción ocurra a mitad de una operación de log y corrompa los
  18       datos, pero tiene importantes consecuencias en el rendimiento, como se
  19       verá más adelante.
  20 
  21 * **`logger.c`**:
  22     * Implementa la función `logger_log_print_` que, en este caso, utiliza
  23       `printf` para enviar el mensaje formateado a través de semihosting.
  24 
  25 #### **2. `app.c` (Planificador Principal)** Este archivo es el núcleo del
  26 sistema operativo simple, un planificador cooperativo basado en un "super-loop".
  27 
  28 * **`app_init()`**:
  29     * Se ejecuta una sola vez al inicio.
  30     * Imprime mensajes de bienvenida e inicialización usando `LOGGER_INFO`.
  31     * Recorre una lista de tareas (`task_cfg_list`) y llama a la función de
  32       inicialización de cada una (ej. `task_sensor_init`, `task_menu_init`).
  33     * Inicializa las variables de rendimiento, como el `WCET` (Worst-Case
  34       Execution Time) de cada tarea, en cero.
  35     * Inicializa los contadores de "ticks" que son la base de tiempo del
  36       sistema.
  37 
  38 * **`app_update()`**:
  39     * Se ejecuta continuamente dentro del bucle `while(1)` de `main.c`.
  40     * Es activado por un "tick" del sistema (la variable `g_app_tick_cnt` se
  41       vuelve mayor que cero).
  42     * Dentro de un bucle `while`, procesa todos los ticks pendientes. En cada
  43       pasada: 1.  Mide el tiempo de ejecución de la función `_update` de cada
  44       tarea (`task_sensor_update`, `task_menu_update`) utilizando un contador de
  45       ciclos de hardware (DWT). 2.  Suma estos tiempos para obtener el tiempo de
  46       ejecución total del ciclo (`g_app_runtime_us`). 3.  Compara el tiempo de
  47       ejecución de la tarea actual con el `WCET` almacenado y lo actualiza si el
  48       tiempo actual es mayor.
  49 
  50 * **`HAL_SYSTICK_Callback()`**:
  51     * Esta función es la rutina de servicio de interrupción (ISR) del `SysTick`.
  52       Se ejecuta automáticamente cada 1 milisegundo.
  53     * Incrementa los contadores de tick para la aplicación principal
  54       (`g_app_tick_cnt`) y para cada tarea específica (`g_task_sensor_tick_cnt`,
  55       `g_task_menu_tick_cnt`).
  56 
  57 #### **3. `task_sensor.c` (Tarea de Lectura de Botones)** Gestiona la lectura de
  58 los botones físicos, implementando un filtro antirrebote (debounce) por
  59 software.
  60 
  61 * **`task_sensor_init()`**: Inicializa las variables de la tarea y muestra
  62   mensajes de log.
  63 * **`task_sensor_update()`**: Se activa periódicamente gracias a
  64   `g_task_sensor_tick_cnt` y ejecuta la máquina de estados.
  65 * **`task_sensor_statechart()`**:
  66     * Implementa una máquina de estados de 4 etapas (`UP`, `FALLING`, `DOWN`,
  67       `RISING`) para cada botón.
  68     * Cuando se presiona un botón, no reacciona al instante. Entra en el estado
  69       `FALLING` y espera un tiempo (`tick_max`). Si el botón sigue presionado
  70       después de ese tiempo, se valida la pulsación y se genera un evento (ej.
  71       `EV_MEN_ENT_ACTIVE`).
  72     * Los eventos se envían a la tarea del menú mediante la función
  73       `put_event_task_menu()`.
  74 
  75 #### **4. `task_menu.c` (Tarea de Lógica de Menú)** Controla la lógica de la
  76 interfaz de usuario y actualiza la pantalla LCD.
  77 
  78 * **`task_menu_init()`**: Inicializa la pantalla LCD y muestra un mensaje de
  79   bienvenida. También inicializa sus propias variables y la cola de eventos.
  80 * **`task_menu_update()`**: Se activa periódicamente y ejecuta la máquina de
  81   estados del menú.
  82 * **`task_menu_statechart()`**:
  83     * Revisa si hay eventos pendientes en la cola (enviados por `task_sensor`).
  84     * Procesa los eventos para cambiar entre sus estados (`ST_MEN_XX_IDLE`,
  85       `ST_MEN_XX_ACTIVE`).
  86     * En el estado `ACTIVE`, decrementa un temporizador. Cuando este llega a
  87       cero, actualiza un contador en la pantalla LCD. Esto crea una
  88       actualización periódica en el display.
  89 
  90 ---
  91 
  92 ### **Impacto de `LOGGER_INFO()` en la Evolución de Variables**
  93 
  94 El uso de `LOGGER_INFO()` tiene un **impacto muy significativo y negativo** en
  95 el rendimiento del sistema y, por lo tanto, en las variables que lo miden. La
  96 razón principal es que la comunicación por semihosting es **extremadamente
  97 lenta** en comparación con la velocidad de ejecución normal del
  98 microcontrolador.
  99 
 100 #### **Nota sobre `g_task_test_tick_cnt`** Esta variable **no existe** en el
 101 código fuente proporcionado. Es probable que sea un error y se refiera a una de
 102 las variables de tick existentes: `g_app_tick_cnt`, `g_task_sensor_tick_cnt` o
 103 `g_task_menu_tick_cnt`. El impacto principal sobre estas es que la
 104 deshabilitación de interrupciones por parte de `LOGGER_INFO` puede introducir
 105 "jitter" (variabilidad en el tiempo de respuesta a la interrupción del
 106 `SysTick`), haciendo que el sistema sea menos predecible.
 107 
 108 #### **`g_app_runtime_us` (Tiempo de Ejecución del Ciclo)**
 109 * **Unidad de medida**: Microsegundos ($µs$).
 110 * **Evolución**:
 111     * **Sin `LOGGER_INFO()`**: En un ciclo normal de `app_update`,
 112       `g_app_runtime_us` mediría solo el tiempo de la lógica de las tareas (leer
 113       pines, actualizar máquinas de estado), que sería de unas pocas decenas de
 114       microsegundos.
 115     * **Con `LOGGER_INFO()`**: Cada vez que se llama a `LOGGER_INFO`
 116       (especialmente durante `app_init`), el tiempo de ejecución se dispara. La
 117       operación de `printf` sobre semihosting puede tardar **varios
 118       milisegundos**. Como `app.c` mide el tiempo de ejecución de las funciones
 119       `_init` y `_update` que contienen estos logs, el valor de
 120       `g_app_runtime_us` reflejará este enorme tiempo.
 121     * **Impacto**: `g_app_runtime_us` tendrá valores **extremadamente altos y
 122       variables**, del orden de **miles de microsegundos (milisegundos)** en
 123       lugar de decenas, cada vez que una tarea imprima un log. Esto falsea por
 124       completo la métrica de carga de la CPU.
 125 
 126 #### **`task_dta_list[index].WCET` (Tiempo de Ejecución de Peor Caso)**
 127 * **Unidad de medida**: Microsegundos ($µs$).
 128 * **Evolución**:
 129     * **Inicialización (`app_init`)**: Las funciones `task_sensor_init` y
 130       `task_menu_init` hacen un uso intensivo de `LOGGER_INFO`. Dado que el
 131       `WCET` se mide también durante la inicialización, este se establecerá
 132       inmediatamente en un valor **muy alto** (múltiples milisegundos) debido al
 133       tiempo que tarda la consola de depuración en procesar los mensajes.
 134     * **Ejecución (`app_update`)**: El `WCET` representa el tiempo máximo que ha
 135       tardado una tarea en ejecutarse. Debido a los logs en la inicialización,
 136       este valor ya será muy grande desde el principio. Durante la ejecución
 137       normal, la lógica de las tareas es rápida, por lo que el `WCET`
 138       probablemente no se actualizará, a menos que se llame a `LOGGER_INFO` de
 139       nuevo dentro de `app_update`.
 140     * **Impacto**: El `WCET` medido **no reflejará el tiempo de ejecución de la
 141       lógica real de la tarea, sino el tiempo de la operación de E/S de
 142       depuración**. Esto hace que la métrica `WCET` sea inútil para el análisis
 143       de tiempo real, ya que el código de depuración no estaría presente en una
 144       versión final del producto. El valor será del orden de **miles de
 145       microsegundos**.