IO Task
The IO task manages buttons, LEDS, and the LED strip. It is also the home of several miscellaneous utility tasks.
to do all of this the task uses a scheduler to call tick functions for each task at regular configurable intervals.
the registered tasks are:
- wdt_reset
- kicks the watchdog timer (task needs to do this to prevent the watchdog from resetting the device)
- called every 1 second
- button_tick
- reads the button state and calls the button callback
- called every 5 milliseconds
- state_machine_tick
- updates the state machine
- called every 5 milliseconds
- battery_status_tick
- querys the PSOC for if an OHM battery is connected
- called every 500 milliseconds
- resistance_update
- updates the resistance value on the PSOC if the resistance has changed
- called every 500 milliseconds
- print_heap
- miscellanious task that prints the heap size
- called every 10 seconds
- retreive_debug_meta
- retreives the debug meta data from the PSOC
- called every 500 milliseconds
- retreive_debug_info
- uses the debug meta data to retreive specific debug information from the PSOC
- called every 1 second
Configuration
IO_TASK_VERBOSE_LOGGING
if set to 1 the IO task will print debug information to the console
RESISTANCE_STEP
the amount to change the resistance by for each button press
RESISTANCE_MAX
the maximum resistance value
RESISTANCE_MIN
the minimum resistance value
RESISTANCE_START
the initial resistance value
// resistance settings
#define RESISTANCE_STEP (5U)
#define RESISTANCE_MAX (100U)
#define RESISTANCE_MIN (0U)
#define RESISTANCE_START (0U)
led_ticks
how long the LED should remain in a temporary state for before reverting to the default state in state machine ticks
#define led_ticks (1000U)
NUM_LEDS
the number of LEDs in the LED strip
#define NUM_LEDS (3)
Public Variables
resistance_count_global
the current resistance value
uint16_t resistance_count_global = RESISTANCE_START;
battery_present
a flag indicating if an OHM battery is connected
bool battery_present = true;
Public Functions
io_task_init
initializes the IO task initializes the state machine initializes the button module initializes the LED initializes the LED strip set up button callbacks for the inc and dec buttons
void io_task_init(void)
{
state = STATE_IDLE;
resistance_count_global = 0;
last_time = xTaskGetTickCount();
button_init();
led_init();
strip.gpio = CRADEL_LED;
strip.led_strip_buf_1 = buf_1;
strip.led_strip_buf_2 = buf_2;
strip.led_strip_length = NUM_LEDS;
strip.rgb_led_type = RGB_LED_TYPE_WTF101;
strip.rmt_channel = RMT_CHANNEL_0;
strip.rmt_interrupt_num = 19;
strip.showing_buf_1 = true;
strip.access_semaphore = xSemaphoreCreateBinary();
led_strip_init(&strip);
led_strip_set_pixel_rgb(&strip, 0, 255, 0, 0);
led_strip_set_pixel_rgb(&strip, 1, 255, 0, 0);
led_strip_set_pixel_rgb(&strip, 2, 255, 0, 0);
led_strip_show(&strip);
button_setup(BUTTON_DEC, GPIO_INTR_POSEDGE, button_pressed_callback, (void*)&button_dec);
button_setup(BUTTON_INC, GPIO_INTR_POSEDGE, button_pressed_callback, (void*)&button_inc);
}
io_task
main FreeRTOS task function, task is currently registered by external code. runs in loop executing the registered tasks at regular intervals.
void io_task(void* arg)
{
while (true)
{
tick++;
for (int i = 0; i < sizeof(schedule) / sizeof(schedule_entry_t); i++)
{
if (tick % schedule[i].ticks == 0)
{
schedule[i].callback();
}
}
vTaskDelay(5 / portTICK_PERIOD_MS);
gpio_set_level(GPIO_NUM_12, true);
};
}
Private Types
State
an enum defining the possible states of the state machine
typedef enum State
{
STATE_IDLE = 0,
STATE_BUTTON_DEC_PRESSED = 1,
STATE_BUTTON_INC_PRESSED = 2,
} State;
Button
a struct representing a button
typedef struct Button
{
uint32_t id;
} Button;
Private Variables
buf_1 and buf_2
buffers used to store the LED strip state, their are two buffers so that the LED strip can be updated in the background while the current state is being displayed (double buffering)
static led_strip_color_t buf_1[NUM_LEDS] = {0};
static led_strip_color_t buf_2[NUM_LEDS] = {0};
led_strip
the LED strip object used by the led_strip library
static led_strip_t strip = {0};
button_inc and button_dec
buttons used to increase and decrease the resistance passed as user_data to the button callback
static const Button button_dec = {.id = BUTTON_DEC};
static const Button button_inc = {.id = BUTTON_INC};
state
the current state of the state machine
volatile static State state = STATE_IDLE;
last_time
the last time the state machine state changed, used to timeout temporary states back to the default state
volatile static uint32_t last_time = 0;
strip_state
the current state of the LED strip tracked seperatley from the main state machine to allow optimisation where we only update the LED strip when it needs to change
volatile static int strip_state = 0;
Private Functions
button_pressed_callback
callback function for the button module, user_arg is used to identify whether it is the inc or dec button so that same callback can be used for both buttons, in retrospect this didnt actually save any code space.
updates state machine state based on the button pressed updates the resistance value based on the button pressed
static void button_pressed_callback(void* args)
{
Button* button = (Button*)args;
switch (button->id)
{
case BUTTON_DEC:
state = STATE_BUTTON_DEC_PRESSED;
last_time = xTaskGetTickCountFromISR();
if ((resistance_count_global - RESISTANCE_STEP) <= RESISTANCE_MAX)
{
resistance_count_global = resistance_count_global - RESISTANCE_STEP;
}
break;
case BUTTON_INC:
state = STATE_BUTTON_INC_PRESSED;
last_time = xTaskGetTickCountFromISR();
if ((resistance_count_global + RESISTANCE_STEP) <= RESISTANCE_MAX)
{
resistance_count_global = resistance_count_global + RESISTANCE_STEP;
}
break;
}
}
state_machine_tick
updates the state machine, sets LEDS based on the current state, handles timeouts for temporary states, updates the LED strip when the state changes
static void state_machine_tick(void)
{
int last_strip_state = strip_state;
uint32_t time = xTaskGetTickCount();
switch (state)
{
case STATE_IDLE:
led_set_color(LED_COLOR_GREEN);
if (battery_present)
{
if (strip_state != 0)
{
strip_state = 0;
led_strip_set_pixel_rgb(&strip, 0, 0, 255, 0);
led_strip_set_pixel_rgb(&strip, 1, 0, 255, 0);
led_strip_set_pixel_rgb(&strip, 2, 0, 255, 0);
}
}
else
{
if (strip_state != 1)
{
strip_state = 1;
led_strip_set_pixel_rgb(&strip, 0, 0, 0, 0);
led_strip_set_pixel_rgb(&strip, 1, 0, 255, 0);
led_strip_set_pixel_rgb(&strip, 2, 0, 0, 0);
}
}
break;
case STATE_BUTTON_DEC_PRESSED:
led_set_color(LED_COLOR_RED);
if (strip_state != 2)
{
strip_state = 2;
led_strip_set_pixel_rgb(&strip, 0, 255, 0, 0);
led_strip_set_pixel_rgb(&strip, 1, 0, 255, 0);
led_strip_set_pixel_rgb(&strip, 2, 0, 0, 0);
}
if (time > (last_time + led_ticks))
{
state = STATE_IDLE;
last_time = time;
}
break;
case STATE_BUTTON_INC_PRESSED:
led_set_color(LED_COLOR_BLUE);
if (strip_state != 3)
{
strip_state = 3;
led_strip_set_pixel_rgb(&strip, 0, 0, 0, 0);
led_strip_set_pixel_rgb(&strip, 1, 0, 255, 0);
led_strip_set_pixel_rgb(&strip, 2, 0, 0, 255);
}
if (time > (last_time + led_ticks))
{
state = STATE_IDLE;
last_time = time;
}
break;
}
if (last_strip_state != strip_state)
{
led_strip_show(&strip);
}
}
wdt_reset
kicks the watchdog timer
static void wdt_reset()
{
esp_task_wdt_reset();
}
battery_status_check
queries the PSOC for if an OHM battery is connected
static void battery_status_check()
{
get_battery_present(UART_CHANNEL_PSOC);
}
resistance_update
updates the resistance value on the PSOC if the resistance has changed, does the same for the FTP for now, this is a temporary hack, should probably be rolled into its own function
static void resistance_update()
{
if(last_ftp != global_ftp || metrics.resistance != resistance_count_global)
{
last_ftp = global_ftp;
set_resistance(UART_CHANNEL_PSOC, resistance_count_global);
}
}