Hello everyone,
I am new to FreeRTOS, and RTOSes in general, and was hoping to get some advice on the proper way to manage the power state of external hardware (e.g. radios, modems, industrial equipment, etc.). If my system interfaces with an external device that has a warm-up time, interaction with that external device should be blocked until that warm-up time has elapsed, even if that external device is free (i.e. not being used by another task).
For simplicity, let’s make some assumptions:
- I have a system that does some timekeeping with an RTC, measures some ADC inputs, logs data to external memory, and when the external memory is full, transmits a payload via a radio.
- I have two tasks: Task A, a master task that contains the main loop and does most everything; and Task B, a task that monitors the power state of the radio.
- The radio takes 3 minutes to “warm up”.
Taking these assumptions, I have created what I think Task B could look like. Task B uses a state machine and a FreeRTOS one-shot timer to keep track of the power state of the radio. The intention would be for Task A to call “radio_start(…)” and then wait until “radio_get_state(…)” returns RADIO_STATE_READY.
I have pasted the code below.
Could anybody take a look at my code and give me some feedback? Is there a better way to approach this?
Thanks.
#include <stddef.h>
#include <FreeRTOS.h>
#include <task.h>
#include <timers.h>
#include "gpio_driver_name.h"
#include "radio_module_header.h"
////////////////////////////////////////////////////////////////////////////////
/////////// RADIO MODULE "HEADER" START ////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
typedef struct
{
RADIO_STATE_OFF = 0,
RADIO_STATE_START,
RADIO_STATE_STARTING,
RADIO_STATE_READY,
} RADIO_STATE;
void radio_start(void);
void radio_stop(void);
RADIO_STATE radio_get_state(void);
////////////////////////////////////////////////////////////////////////////////
/////////// RADIO MODULE "HEADER" END //////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/* ======== PRIVATE FUNCTIONS: PROTOTYPES =================================== */
static void timer_callback(TimerHandle_t xTimer);
static void create_or_reset_timer(void);
/* ======== PRIVATE VARIABLES =============================================== */
static TimerHandle_t xRadioTimer = NULL;
static const int g_radio_warmup_time_ms = 1000*60*3;
static RADIO_STATE g_radio_state = RADIO_STATE_OFF;
/* ======== PUBLIC FUNCTIONS: IMPLEMENTATION ================================ */
void radio_start(void)
{
g_radio_state = RADIO_STATE_STARTUP;
GPIO_set(MY_RADIO_LOADSWITCH);
return;
}
void radio_stop(void)
{
g_radio_state = RADIO_STATE_OFF;
GPIO_clear(MY_RADIO_LOADSWITCH);
return;
}
RADIO_STATE radio_get_state(void)
{
return g_radio_state;
}
/* ======== PRIVATE FUNCTIONS: IMPLEMENTATION =============================== */
void task_radio_power_manager(void *pvParameters)
{
for (;;)
{
switch(g_radio_state)
{
case (RADIO_STATE_OFF):
//wait for radio_start(...) function call
break;
case (RADIO_STATE_START):
//start the timer
create_or_reset_timer();
g_radio_state = RADIO_STATE_STARTING;
break;
case (RADIO_STATE_STARTING):
//wait for the timer callback
break;
case (RADIO_STATE_READY):
//wait for radio_stop(...) function call
break;
}
}
vTaskDelete(NULL);
}
static void timer_callback(TimerHandle_t xTimer);
{
if (RADIO_STATE_STARTING != g_radio_state)
{
while (1); //TODO: handle error case
}
g_radio_state = RADIO_STATE_READY;
return;
}
static void create_or_reset_timer(void)
{
if (NULL == xRadioTimer)
{
xRadioTimer = xTimerCreate(NULL, pdMS_TO_TICKS(g_radio_warmup_time_ms), pdFALSE, 0, handle_timer_callback);
if (NULL == xRadioTimer)
{
while (1); //TODO: handle error state
}
}
else
{
ret = xTimerReset(xRadioTimer, pdMS_TO_TICKS(g_radio_warmup_time_ms));
if (pdFAIL == ret)
{
while (1); //TODO: handle error state
}
}
}