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
commit a7e832df87102107bc7285404c0af909db9ad576
parent 40319f6c5dd6565e603076c398b6808c93cececb
Author: Martin Kloeckner <mjkloeckner@gmail.com>
Date:   Sun, 12 Apr 2026 21:42:25 -0300

Implementar parte de las respuestas a peticiones del modulo remoto

Diffstat:
Mfirmware-nucleo/.cproject | 26+-------------------------
Mfirmware-nucleo/App/Inc/ds18b20.h | 3+++
Mfirmware-nucleo/App/Inc/task_remote.h | 14++++++++++++++
Mfirmware-nucleo/App/Inc/task_system_attribute.h | 2++
Mfirmware-nucleo/App/Inc/task_temp_sensor.h | 2++
Mfirmware-nucleo/App/Src/app.c | 39+++++++++++++++++++++++++++++++++++++++
Mfirmware-nucleo/App/Src/ds18b20.c | 39+++------------------------------------
Mfirmware-nucleo/App/Src/task_remote.c | 232+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Mfirmware-nucleo/App/Src/task_system.c | 1+
Mfirmware-nucleo/Core/Inc/stm32f1xx_it.h | 1+
Mfirmware-nucleo/Core/Src/stm32f1xx_hal_msp.c | 5+++++
Mfirmware-nucleo/Core/Src/stm32f1xx_it.c | 15+++++++++++++++
Mfirmware-nucleo/tdse-tf_3-02.ioc | 3++-
13 files changed, 317 insertions(+), 65 deletions(-)
diff --git a/firmware-nucleo/.cproject b/firmware-nucleo/.cproject
@@ -83,33 +83,9 @@
                             <tool id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.objcopy.symbolsrec.596597920" name="MCU Output Converter Motorola S-rec with symbols" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.objcopy.symbolsrec"/>
                         </toolChain>
                     </folderInfo>
-                    <folderInfo id="com.st.stm32cube.ide.mcu.gnu.managedbuild.config.exe.debug.1668476548.1752752668" name="/" resourcePath="App">
-                        <toolChain id="com.st.stm32cube.ide.mcu.gnu.managedbuild.toolchain.exe.debug.989770405" name="MCU ARM GCC" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.toolchain.exe.debug" unusedChildren="">
-                            <option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.target_mcu.196613539.1648478559" name="MCU" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.target_mcu.196613539"/>
-                            <option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.target_cpuid.25261614.632056902" name="CPU" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.target_cpuid.25261614"/>
-                            <option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.target_coreid.1047645605.1894433030" name="Core" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.target_coreid.1047645605"/>
-                            <option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.target_board.1578684016.180907388" name="Board" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.target_board.1578684016"/>
-                            <option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.defaults.137200207.284673786" name="Defaults" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.defaults.137200207"/>
-                            <option id="com.st.stm32cube.ide.mcu.debug.option.cpuclock.718213595.1522586226" name="Cpu clock frequence" superClass="com.st.stm32cube.ide.mcu.debug.option.cpuclock.718213595"/>
-                            <option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.nanoprintffloat.1243536684.1592562187" name="Use float with printf from newlib-nano (-u _printf_float)" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.nanoprintffloat.1243536684"/>
-                            <tool id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.assembler.566746985" name="MCU/MPU GCC Assembler" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.assembler.1808103261"/>
-                            <tool id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.c.compiler.1993253250" name="MCU/MPU GCC Compiler" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.c.compiler.2136520025"/>
-                            <tool id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.cpp.compiler.703870765" name="MCU/MPU G++ Compiler" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.cpp.compiler.1502319755"/>
-                            <tool id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.c.linker.1307794806" name="MCU/MPU GCC Linker" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.c.linker.624237716"/>
-                            <tool id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.cpp.linker.1852067064" name="MCU/MPU G++ Linker" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.cpp.linker.1928646338"/>
-                            <tool id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.archiver.303859826" name="MCU/MPU GCC Archiver" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.archiver.2052663982"/>
-                            <tool id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.size.610374140" name="MCU Size" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.size.1032694119"/>
-                            <tool id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.objdump.listfile.735123117" name="MCU Output Converter list file" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.objdump.listfile.1873210802"/>
-                            <tool id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.objcopy.hex.1188725902" name="MCU Output Converter Hex" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.objcopy.hex.800696083"/>
-                            <tool id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.objcopy.binary.159045717" name="MCU Output Converter Binary" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.objcopy.binary.1497183090"/>
-                            <tool id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.objcopy.verilog.669813261" name="MCU Output Converter Verilog" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.objcopy.verilog.186810712"/>
-                            <tool id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.objcopy.srec.1266821805" name="MCU Output Converter Motorola S-rec" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.objcopy.srec.1871623811"/>
-                            <tool id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.objcopy.symbolsrec.1949485034" name="MCU Output Converter Motorola S-rec with symbols" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.objcopy.symbolsrec.596597920"/>
-                        </toolChain>
-                    </folderInfo>
                     <sourceEntries>
-                        <entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="App"/>
                         <entry excluding="Src/syscalls.c" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="Core"/>
+                        <entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="App"/>
                         <entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="Drivers"/>
                     </sourceEntries>
                 </configuration>
diff --git a/firmware-nucleo/App/Inc/ds18b20.h b/firmware-nucleo/App/Inc/ds18b20.h
@@ -11,6 +11,9 @@
 extern "C" {
 #endif
 
+extern bool b_ds18b20_dma_tx_done;
+extern bool b_ds18b20_dma_rx_done;
+
 void ds18b20_init(void);
 void ds18b20_async_tick(void);
 void ds18b20_async_read_temp(void);
diff --git a/firmware-nucleo/App/Inc/task_remote.h b/firmware-nucleo/App/Inc/task_remote.h
@@ -11,12 +11,26 @@
 extern "C" {
 #endif
 
+#define G_TASK_REMOTE_QUEUE_LEN 255
+
+typedef struct {
+    uint8_t head;
+    uint8_t tail;
+    uint8_t count;
+    uint8_t data[G_TASK_REMOTE_QUEUE_LEN];
+} queue_t;
+
 extern uint32_t g_task_remote_cnt;
 extern volatile uint32_t g_task_remote_tick_cnt;
 
+extern uint8_t task_remote_uart_rx_byte;
+extern queue_t task_remote_rx_queue;
+
 void task_remote_init(void *parameters);
 void task_remote_update(void *parameters);
 
+void task_remote_queue_enqueue(queue_t *queue, uint8_t value);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/firmware-nucleo/App/Inc/task_system_attribute.h b/firmware-nucleo/App/Inc/task_system_attribute.h
@@ -36,6 +36,8 @@ typedef enum task_system_ev {
     EV_SYS_BTN_C_ACTIVE,
     EV_SYS_BTN_D_IDLE,
     EV_SYS_BTN_D_ACTIVE,
+
+    EV_SYS_REM_TEMP_CTRL_ENABLED,
 } task_system_ev_t;
 
 typedef enum task_system_st {
diff --git a/firmware-nucleo/App/Inc/task_temp_sensor.h b/firmware-nucleo/App/Inc/task_temp_sensor.h
@@ -11,6 +11,8 @@
 extern "C" {
 #endif
 
+#include "ds18b20.h"
+
 extern uint32_t g_task_temp_sensor_cnt;
 extern volatile uint32_t g_task_temp_sensor_tick_cnt;
 
diff --git a/firmware-nucleo/App/Src/app.c b/firmware-nucleo/App/Src/app.c
@@ -163,6 +163,8 @@ void app_update(void)
     }
 }
 
+// Callbacks definition
+
 // This is called every ms
 void HAL_SYSTICK_Callback(void)
 {
@@ -177,3 +179,40 @@ void HAL_SYSTICK_Callback(void)
     g_task_temp_sensor_tick_cnt++;
     g_task_remote_tick_cnt++;
 }
+
+void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
+{
+    if (huart->Instance == USART1)
+    {
+        b_ds18b20_dma_tx_done = true;
+    }
+}
+
+void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
+{
+    if (huart->Instance == USART1)
+    {
+        b_ds18b20_dma_rx_done = true;
+    }
+    if (huart->Instance == USART3)
+    {
+        task_remote_queue_enqueue(&task_remote_rx_queue, task_remote_uart_rx_byte);
+        HAL_UART_Receive_IT(&huart3, &task_remote_uart_rx_byte, 1);
+    }
+}
+
+void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t size)
+{
+    if (huart->Instance == USART1)
+    {
+        b_ds18b20_dma_rx_done = true;
+    }
+}
+
+void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
+{
+    if(huart->Instance == USART1)
+    {
+        ;
+    }
+}
diff --git a/firmware-nucleo/App/Src/ds18b20.c b/firmware-nucleo/App/Src/ds18b20.c
@@ -55,12 +55,14 @@ static struct {
     ds18b20_data_t queue[G_DS18B20_ASYNC_QUEUE_LEN];
 } ds18b20_async_queue;
 
+// Public variables
+bool b_ds18b20_dma_tx_done, b_ds18b20_dma_rx_done;
+
 // Private global variables
 static uint32_t g_ds18b20_tick;
 static uint16_t g_ds18b20_temp, g_ds18b20_update_count;
 static uint8_t g_temp_lsb, g_temp_msb;
 static uint8_t g_ds18b20_tx_buffer[8], g_ds18b20_rx_buffer[8];
-static bool b_ds18b20_dma_tx_done, b_ds18b20_dma_rx_done;
 static bool b_ds18b20_rx_data_processed, b_ds18b20_async_temp_ready;
 
 // Private functions declaration
@@ -340,38 +342,3 @@ static ds18b20_data_t ds18b20_async_queue_tail(void)
 {
     return ds18b20_async_queue.queue[(ds18b20_async_queue.tail) - 1];
 }
-
-// Callbacks definition
-void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
-{
-    if (huart->Instance == USART1)
-    {
-        b_ds18b20_dma_tx_done = true;
-    }
-}
-
-void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
-{
-    if (huart->Instance == USART1)
-    {
-        b_ds18b20_dma_rx_done = true;
-    }
-}
-
-void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t size)
-{
-    if (huart->Instance == USART1)
-    {
-        b_ds18b20_dma_rx_done = true;
-    }
-}
-
-void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
-{
-    if(huart->Instance == USART1)
-    {
-        ;
-    }
-}
-
-
diff --git a/firmware-nucleo/App/Src/task_remote.c b/firmware-nucleo/App/Src/task_remote.c
@@ -8,27 +8,71 @@
 #include <stdint.h>
 #include <stdbool.h>
 #include <string.h>
+#include <time.h>
 
 #include "main.h"
 #include "app.h"
 
 #include "task_remote.h"
+#include "task_system_attribute.h"
+#include "task_system_interface.h"
 #include "logger.h"
 
 #define G_TASK_REMOTE_TICK_INI            0ul
 #define G_TASK_REMOTE_TEMP_UPDATE_RATE_MS 1000ul
 
 uint32_t g_task_remote_tick;
-uint8_t data = 69;
 
-// this variable is incremented by 1 on every ms by HAL_SysTick
+// Public variables
+//// this variable is incremented by 1 on every ms by HAL_SysTick
 volatile uint32_t g_task_remote_tick_cnt;
+queue_t task_remote_rx_queue;
+uint8_t task_remote_uart_rx_byte;
 
+queue_t task_remote_tx_queue;
+// uint8_t task_remote_uart_tx_byte;
+
+
+// Private variables definition
+typedef enum {
+    TX_DATA_STATUS_OK             = 'A',
+    TX_DATA_MAIN_OUTPUT_TOGGLE_OK = 'B',
+    TX_DATA_TIMER_TOGGLE_OK       = 'C',
+    TX_DATA_TIMER_SET_VALUES_OK   = 'D',
+    TX_DATA_TEMP_STATUS_OK        = 'E',
+    TX_DATA_TEMP_SET_OK           = 'F'
+} uart_tx_data_e;
+
+typedef enum {
+    RX_DATA_STATUS             = 'A',
+    RX_DATA_MAIN_OUTPUT_TOGGLE = 'B',
+    RX_DATA_TIMER_TOGGLE       = 'C',
+    RX_DATA_TIMER_SET_VALUES   = 'D',
+    RX_DATA_TEMP_STATUS        = 'E',
+    RX_DATA_TEMP_SET           = 'F'
+} uart_rx_data_e;
+
+// Public functions declaration
+void task_remote_queue_enqueue(queue_t *queue, uint8_t value);
+
+// Private functions declaration
+static void task_remote_rx_data_handler(void *parameters);
+static void task_remote_queue_init(queue_t *queue);
+static uint8_t task_remote_queue_dequeue(queue_t *queue);
+static uint8_t task_remote_queue_peek(queue_t *queue);
+static uint8_t task_remote_queue_count(queue_t *queue);
+static uint8_t task_remote_queue_is_empty(queue_t *queue);
+
+// Public funtions implementation
 void task_remote_init(void *parameters)
 {
     LOGGER_INFO("Initializing `task_remote`...");
 
+    task_remote_queue_init(&task_remote_tx_queue);
+    task_remote_queue_init(&task_remote_rx_queue);
+
     g_task_remote_tick = G_TASK_REMOTE_TICK_INI;
+    HAL_UART_Receive_IT(&huart3, &task_remote_uart_rx_byte, 1);
 
     LOGGER_INFO("Done initializing `task_remote`");
 }
@@ -60,10 +104,21 @@ void task_remote_update(void *parameters)
         }
         __asm("CPSIE i");
 
+        if (!task_remote_queue_is_empty(&task_remote_rx_queue))
+        {
+            task_remote_rx_data_handler(parameters);
+        }
+
+        // TODO: Send bytes on tx_queue asynchronously
+        while (!task_remote_queue_is_empty(&task_remote_tx_queue))
+        {
+            uint8_t byte = task_remote_queue_dequeue(&task_remote_tx_queue);
+            HAL_UART_Transmit(&huart3, &byte, 1, 100);
+        }
+
         if (0 == g_task_remote_tick)
         {
             g_task_remote_tick = G_TASK_REMOTE_TEMP_UPDATE_RATE_MS;
-            HAL_UART_Transmit(&huart3, &data, 1, 100);
         }
         else
         {
@@ -71,3 +126,174 @@ void task_remote_update(void *parameters)
         }
     }
 }
+
+void task_remote_queue_enqueue(queue_t *queue, uint8_t value)
+{
+    queue->count++;
+    queue->data[queue->head++] = value;
+}
+
+// Private function implementation
+
+static void task_remote_rx_data_handler(void *parameters)
+{
+    uint8_t query_type = task_remote_queue_peek(&task_remote_rx_queue);
+    shared_data_type *p_shared_data = (shared_data_type *)parameters;
+
+    switch(query_type)
+    {
+        case RX_DATA_STATUS:
+            task_remote_queue_dequeue(&task_remote_rx_queue); // skip query type
+
+            task_remote_queue_enqueue(&task_remote_tx_queue, TX_DATA_STATUS_OK);
+            task_remote_queue_enqueue(&task_remote_tx_queue,
+                    p_shared_data->temp_ctrl_enabled);
+
+            HAL_RTC_GetTime(&hrtc, &s_time, RTC_FORMAT_BIN);
+            HAL_RTC_GetDate(&hrtc, &s_date, RTC_FORMAT_BIN);
+
+            struct tm t = {
+                .tm_year = s_date.Year + 100,
+                .tm_mon  = s_date.Month - 1,
+                .tm_mday = s_date.Date,
+                .tm_hour = s_time.Hours,
+                .tm_min  = s_time.Minutes,
+                .tm_sec  = s_time.Seconds,
+            };
+
+            uint32_t system_time = (uint32_t)mktime(&t);
+
+            // LSB first
+            task_remote_queue_enqueue(&task_remote_tx_queue,
+                    (uint8_t)(system_time & 0xFF));
+            task_remote_queue_enqueue(&task_remote_tx_queue,
+                    (uint8_t)((system_time >> 8) & 0xFF));
+            task_remote_queue_enqueue(&task_remote_tx_queue,
+                    (uint8_t)((system_time >> 16) & 0xFF));
+            task_remote_queue_enqueue(&task_remote_tx_queue,
+                    (uint8_t)((system_time >> 24) & 0xFF));
+
+            task_remote_queue_enqueue(&task_remote_tx_queue, p_shared_data->timer->enabled);
+            task_remote_queue_enqueue(&task_remote_tx_queue, p_shared_data->timer->start_hour);
+            task_remote_queue_enqueue(&task_remote_tx_queue, p_shared_data->timer->start_min);
+            task_remote_queue_enqueue(&task_remote_tx_queue, p_shared_data->timer->end_hour);
+            task_remote_queue_enqueue(&task_remote_tx_queue, p_shared_data->timer->end_min);
+
+            task_remote_queue_enqueue(&task_remote_tx_queue,
+                    p_shared_data->temp_sensor);
+            task_remote_queue_enqueue(&task_remote_tx_queue,
+                    p_shared_data->temp_set_point);
+
+        break;
+
+        case RX_DATA_MAIN_OUTPUT_TOGGLE:
+
+            task_remote_queue_dequeue(&task_remote_rx_queue); // skip query type
+            task_system_interface_put_event(EV_SYS_REM_TEMP_CTRL_ENABLED);
+            task_remote_queue_enqueue(&task_remote_tx_queue,
+                    TX_DATA_MAIN_OUTPUT_TOGGLE_OK);
+
+        break;
+
+        case RX_DATA_TIMER_TOGGLE:
+            task_remote_queue_dequeue(&task_remote_rx_queue); // skip query type
+
+            // TODO: Do something...
+
+            task_remote_queue_enqueue(&task_remote_tx_queue,
+                    TX_DATA_TIMER_TOGGLE_OK);
+
+        break;
+
+        case RX_DATA_TIMER_SET_VALUES:
+
+            if (task_remote_queue_count(&task_remote_rx_queue) < 5)
+            {
+                // wait for additional data
+                break;
+            }
+
+            task_remote_queue_dequeue(&task_remote_rx_queue); // skip query type
+
+            // TODO: Do something...
+            // timer.from_hour   = task_remote_queue_dequeue(&task_remote_rx_queue);
+            // timer.from_minute = task_remote_queue_dequeue(&task_remote_rx_queue);
+            // timer.to_hour     = task_remote_queue_dequeue(&task_remote_rx_queue);
+            // timer.to_minute   = task_remote_queue_dequeue(&task_remote_rx_queue);
+
+            task_remote_queue_dequeue(&task_remote_rx_queue);
+            task_remote_queue_dequeue(&task_remote_rx_queue);
+            task_remote_queue_dequeue(&task_remote_rx_queue);
+            task_remote_queue_dequeue(&task_remote_rx_queue);
+            task_remote_queue_enqueue(&task_remote_tx_queue,
+                    TX_DATA_TIMER_SET_VALUES_OK);
+
+        break;
+
+        case RX_DATA_TEMP_STATUS:
+
+            task_remote_queue_dequeue(&task_remote_rx_queue); // skip query type
+
+            task_remote_queue_enqueue(&task_remote_tx_queue, TX_DATA_TEMP_STATUS_OK);
+            task_remote_queue_enqueue(&task_remote_tx_queue, p_shared_data->temp_sensor);
+            task_remote_queue_enqueue(&task_remote_tx_queue, p_shared_data->temp_set_point);
+
+        break;
+
+        case RX_DATA_TEMP_SET:
+
+            if (task_remote_queue_count(&task_remote_rx_queue) < 2)
+            {
+                // wait for additional data
+                break;
+            }
+
+            task_remote_queue_dequeue(&task_remote_rx_queue); // skip query type
+            p_shared_data->temp_set_point = task_remote_queue_dequeue(&task_remote_rx_queue);
+            task_remote_queue_enqueue(&task_remote_tx_queue, TX_DATA_TEMP_SET_OK);
+
+        break;
+
+        default: 
+            task_remote_queue_dequeue(&task_remote_rx_queue);
+        break;
+    }
+}
+
+static void task_remote_queue_init(queue_t *queue)
+{
+    queue->head = 0;
+    queue->tail = 0;
+    queue->count = 0;
+
+    for (uint8_t i = 0; i < G_TASK_REMOTE_QUEUE_LEN; ++i)
+    {
+        queue->data[i] = 0;
+    }
+}
+
+static uint8_t task_remote_queue_dequeue(queue_t *queue)
+{
+    if(task_remote_queue_is_empty(queue))
+    {
+        return task_remote_queue_peek(queue);
+    }
+
+    queue->count--;
+    return queue->data[queue->tail++];
+}
+
+static uint8_t task_remote_queue_peek(queue_t *queue)
+{
+    return queue->data[queue->tail];
+}
+
+static uint8_t task_remote_queue_count(queue_t *queue)
+{
+    return queue->count;
+}
+
+static uint8_t task_remote_queue_is_empty(queue_t *queue)
+{
+    return (queue->count == 0);
+}
diff --git a/firmware-nucleo/App/Src/task_system.c b/firmware-nucleo/App/Src/task_system.c
@@ -275,6 +275,7 @@ static void task_system_statechart(void *parameters)
                     break;
 
                     case EV_SYS_BTN_C_ACTIVE:
+                    case EV_SYS_REM_TEMP_CTRL_ENABLED:
                         p_shared_data->temp_ctrl_enabled = !p_shared_data->temp_ctrl_enabled;
                         task_menu_interface_put_event(EV_MEN_DISPLAY_UPDATE);
                         task_buzzer_interface_put_event(EV_BUZ_XX_LONG_BEEP, ID_BUZ_A);
diff --git a/firmware-nucleo/Core/Inc/stm32f1xx_it.h b/firmware-nucleo/Core/Inc/stm32f1xx_it.h
@@ -61,6 +61,7 @@ void DMA1_Channel6_IRQHandler(void);
 void I2C1_EV_IRQHandler(void);
 void I2C1_ER_IRQHandler(void);
 void USART1_IRQHandler(void);
+void USART3_IRQHandler(void);
 void EXTI15_10_IRQHandler(void);
 /* USER CODE BEGIN EFP */
 
diff --git a/firmware-nucleo/Core/Src/stm32f1xx_hal_msp.c b/firmware-nucleo/Core/Src/stm32f1xx_hal_msp.c
@@ -432,6 +432,9 @@ void HAL_UART_MspInit(UART_HandleTypeDef* huart)
 
     __HAL_AFIO_REMAP_USART3_PARTIAL();
 
+    /* USART3 interrupt Init */
+    HAL_NVIC_SetPriority(USART3_IRQn, 0, 0);
+    HAL_NVIC_EnableIRQ(USART3_IRQn);
     /* USER CODE BEGIN USART3_MspInit 1 */
 
     /* USER CODE END USART3_MspInit 1 */
@@ -484,6 +487,8 @@ void HAL_UART_MspDeInit(UART_HandleTypeDef* huart)
     */
     HAL_GPIO_DeInit(GPIOC, GPIO_PIN_10|GPIO_PIN_11);
 
+    /* USART3 interrupt DeInit */
+    HAL_NVIC_DisableIRQ(USART3_IRQn);
     /* USER CODE BEGIN USART3_MspDeInit 1 */
 
     /* USER CODE END USART3_MspDeInit 1 */
diff --git a/firmware-nucleo/Core/Src/stm32f1xx_it.c b/firmware-nucleo/Core/Src/stm32f1xx_it.c
@@ -60,6 +60,7 @@ extern I2C_HandleTypeDef hi2c1;
 extern DMA_HandleTypeDef hdma_usart1_tx;
 extern DMA_HandleTypeDef hdma_usart1_rx;
 extern UART_HandleTypeDef huart1;
+extern UART_HandleTypeDef huart3;
 /* USER CODE BEGIN EV */
 
 /* USER CODE END EV */
@@ -289,6 +290,20 @@ void USART1_IRQHandler(void)
 }
 
 /**
+  * @brief This function handles USART3 global interrupt.
+  */
+void USART3_IRQHandler(void)
+{
+  /* USER CODE BEGIN USART3_IRQn 0 */
+
+  /* USER CODE END USART3_IRQn 0 */
+  HAL_UART_IRQHandler(&huart3);
+  /* USER CODE BEGIN USART3_IRQn 1 */
+
+  /* USER CODE END USART3_IRQn 1 */
+}
+
+/**
   * @brief This function handles EXTI line[15:10] interrupts.
   */
 void EXTI15_10_IRQHandler(void)
diff --git a/firmware-nucleo/tdse-tf_3-02.ioc b/firmware-nucleo/tdse-tf_3-02.ioc
@@ -102,6 +102,7 @@ NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4
 NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
 NVIC.SysTick_IRQn=true\:15\:0\:false\:false\:true\:false\:true\:false
 NVIC.USART1_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:true
+NVIC.USART3_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:true
 NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
 PA10.GPIOParameters=GPIO_Label
 PA10.GPIO_Label=LD3
@@ -221,7 +222,7 @@ ProjectManager.ToolChainLocation=
 ProjectManager.UAScriptAfterPath=
 ProjectManager.UAScriptBeforePath=
 ProjectManager.UnderRoot=true
-ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-false-HAL-true,3-MX_DMA_Init-DMA-false-HAL-true,4-MX_RTC_Init-RTC-false-HAL-true,5-MX_I2C1_Init-I2C1-false-HAL-true,6-MX_TIM1_Init-TIM1-false-HAL-true,7-MX_USART1_UART_Init-USART1-false-HAL-true,8-MX_TIM3_Init-TIM3-false-HAL-true,9-MX_USART2_UART_Init-USART2-false-HAL-true
+ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-false-HAL-true,3-MX_DMA_Init-DMA-false-HAL-true,4-MX_RTC_Init-RTC-false-HAL-true,5-MX_I2C1_Init-I2C1-false-HAL-true,6-MX_TIM1_Init-TIM1-false-HAL-true,7-MX_USART1_UART_Init-USART1-false-HAL-true,8-MX_TIM3_Init-TIM3-false-HAL-true,9-MX_USART3_UART_Init-USART3-false-HAL-true
 RCC.ADCFreqValue=32000000
 RCC.AHBFreq_Value=64000000
 RCC.APB1CLKDivider=RCC_HCLK_DIV2