Sliders_McGee/Core/Src/console.c

420 lines
9.4 KiB
C
Raw Permalink Normal View History

/**
*********************************************************************
*
* @file console.c
* @brief
*
* @date 2024-04-14 19:12:40
* @author CT
*
* @details
*
*************************************************************************
**/
/*
Operational Concept:
Sending enter displays the current menu
Simple 1 char command interface
*/
#include <stdint.h>
#include <stdbool.h>
#include "main.h"
#include "console.h"
#include "NVmem.h"
#include "version.h"
#include "usbd_cdc_if.h"
#define CONSOLE_BUF_SIZE (256u)
static cbuf_handle_t m_console_input;
static cbuf_handle_t m_console_output;
static uint8_t m_console_input_buf[CONSOLE_BUF_SIZE] = {0};
static uint8_t m_console_output_buf[CONSOLE_BUF_SIZE] = {0};
static uint8_t tx_buf[CONSOLE_BUF_SIZE];
static uint8_t m_command_buf[16] = {0};
static uint8_t m_command_len = 0;
static bool m_command_ready = false;
static bool m_echo_console = false;
config_data_u_t* configuration_data;
enum console_menu_state{main_menu, slider_1_menu, slider_2_menu, slider_3_menu, slider_4_menu, save_menu, version_menu};
enum console_menu_state console_menu = main_menu;
static void process_incoming(void);
static void process_outgoing(void);
static void process_command(void);
static int console_send(uint8_t* buf, uint32_t len);
static void menu_state_machine(void);
static int parse_input(int32_t* data);
static int32_t read_line(uint8_t data);
// menus
static void print_main_menu(void);
static void print_slider_menu(uint32_t slider);
static void print_saved_menu(int32_t val);
// console control
static void set_console_reset(void);
static void set_console_red(void);
static void set_console_green(void);
static void reset_console(void);
/* PUBLIC FUNCTIONS */
void console_init(config_data_u_t* config_data)
{
configuration_data = config_data;
m_console_input = circular_buf_init(m_console_input_buf, CONSOLE_BUF_SIZE);
m_console_output = circular_buf_init(m_console_output_buf, CONSOLE_BUF_SIZE);
}
void console_service(void)
{
// if there is received data waiting
process_incoming();
// if there is data waiting to be transmitted
process_outgoing();
// Process command
process_command();
}
/// @brief Attempts to push one byte into the console input buffer
/// @param data byte to be pushed to input
/// @return 0 on success, -1 on failure
int console_push(uint8_t data)
{
int ret = 0;
ret = circular_buf_try_put(m_console_input, data);
return (ret);
}
/* PRIVATE FUNCTIONS */
void process_incoming(void)
{
if (!circular_buf_empty(m_console_input))
{
uint8_t data;
while (!circular_buf_empty(m_console_input))
{
circular_buf_get(m_console_input, &data);
m_command_ready = read_line(data);
if (m_echo_console)
{
circular_buf_try_put(m_console_output, data);
}
}
}
}
void process_outgoing(void)
{
if(!circular_buf_empty(m_console_output))
{
size_t tx_len = circular_buf_size(m_console_output);
for (uint32_t i = 0; i < tx_len; i++)
{
circular_buf_get(m_console_output, &tx_buf[i]);
}
// Note: directly interacts with interface
CDC_Transmit_FS(tx_buf, tx_len);
}
}
void process_command(void)
{
if(m_command_ready)
{
m_command_ready = false;
menu_state_machine();
}
}
int console_send(uint8_t* buf, uint32_t len)
{
int ret = 0;
for (uint32_t i = 0; i < len; i++)
{
ret |= circular_buf_try_put(m_console_output, buf[i]);
}
return (ret);
}
/// @brief Reads in a line terminated by \\n
/// @param data
/// @return 1 if EOL found, 0 otherwise
int32_t read_line(uint8_t data)
{
int32_t ret = 0;
static uint8_t m_command_buf_index = 0;
// if EOL, return on and set length
if((data == '\n') || (data == '\r'))
{
m_command_buf[m_command_buf_index++] = '\n';
// set length of command for use within rest of module
m_command_len = m_command_buf_index;
// reset index
m_command_buf_index = 0;
ret = 1;
}
else if (data == 0x1B) // ESCAPE
{
m_command_len = 1;
m_command_buf[0] = 0x1B;
// reset index
m_command_buf_index = 0;
ret = 1;
}
else
{
if (m_command_buf_index < 16)
{
m_command_buf[m_command_buf_index++] = data;
}
else
{
m_command_buf_index = 0;
}
}
return (ret);
}
// Called when a complete line has been received
void menu_state_machine(void)
{
int32_t success = 1;
switch (console_menu)
{
case main_menu:
if (m_command_buf[0] == '1')
{
print_slider_menu(1);
console_menu = slider_1_menu;
}
else if (m_command_buf[0] == '2')
{
print_slider_menu(2);
console_menu = slider_2_menu;
}
else if (m_command_buf[0] == '3')
{
print_slider_menu(3);
console_menu = slider_3_menu;
}
else if (m_command_buf[0] == '4')
{
print_slider_menu(4);
console_menu = slider_4_menu;
}
else if (m_command_buf[0] == 'S')
{
success = NVmem_write_immediate(configuration_data->data, 0, sizeof(config_data_t));
print_saved_menu(success);
// need to call service because we are blocking all normal execution here
process_outgoing();
// Delay for user to read result
HAL_Delay(3000);
console_menu = main_menu;
print_main_menu();
}
else
{
print_main_menu();
}
break;
case slider_1_menu:
if (m_command_buf[0] == 0x1B) // ESCAPE
{
console_menu = main_menu;
print_main_menu();
}
else
{
// Take input and immediately return to main menu
parse_input(&configuration_data->config.slider_1);
console_menu = main_menu;
print_main_menu();
}
break;
case slider_2_menu:
if (m_command_buf[0] == 0x1B) // ESCAPE
{
console_menu = main_menu;
print_main_menu();
}
else
{
// Take input and immediately return to main menu
parse_input(&configuration_data->config.slider_2);
console_menu = main_menu;
print_main_menu();
}
break;
case slider_3_menu:
if (m_command_buf[0] == 0x1B) // ESCAPE
{
console_menu = main_menu;
print_main_menu();
}
else
{
// Take input and immediately return to main menu
parse_input(&configuration_data->config.slider_3);
console_menu = main_menu;
print_main_menu();
}
break;
case slider_4_menu:
if (m_command_buf[0] == 0x1B) // ESCAPE
{
console_menu = main_menu;
print_main_menu();
}
else
{
// Take input and immediately return to main menu
parse_input(&configuration_data->config.slider_4);
console_menu = main_menu;
print_main_menu();
}
break;
case save_menu:
break;
default:
break;
}
}
/// @brief Parses line for integer
/// @param data parsed out integer
/// @return 1 on success, otherwise fail...kinda
int parse_input(int32_t* data)
{
// TODO check and limit input within bounds
// *data = atoi((char*)m_command_buf);
int ret = sscanf((char*)m_command_buf, "%ld", data);
return (ret);
}
// Also acts as initialization for state
void print_main_menu(void)
{
char buf[256];
m_echo_console = true;
reset_console();
set_console_red();
uint32_t len = snprintf(buf, 256, "Main Menu:\r\nSlider [1]: \"%li\"\r\nSlider [2]: \"%li\"\r\nSlider [3]: \"%li\"\r\nSlider [4]: \"%li\"\r\n[S]ave\r\nVersion: %s\r\nEnter Selection: ",
configuration_data->config.slider_1, configuration_data->config.slider_2, configuration_data->config.slider_3, configuration_data->config.slider_4, VERSION_STR);
console_send((uint8_t*)buf, len);
}
void print_slider_menu(uint32_t slider)
{
char buf[128];
m_echo_console = true;
reset_console();
set_console_reset();
uint32_t len = snprintf(buf, 128, "Slider %lu Max Value (0-100): ", slider);
console_send((uint8_t*)buf, len);
}
void print_saved_menu(int32_t val)
{
char buf[128];
uint32_t len;
reset_console();
set_console_green();
if (0 == val)
{
len = snprintf(buf, 128, "SAVED!!1!");
}
else
{
len = snprintf(buf, 128, "SAVE FAILED!");
}
console_send((uint8_t*)buf, len);
}
void set_console_reset(void)
{
char buf[16] = {0};
uint32_t len = snprintf(buf, 16, "\x1b[1;0m");
console_send((uint8_t*)buf, len);
}
void set_console_red(void)
{
char buf[16] = {0};
uint32_t len = snprintf(buf, 16, "\x1b[1;31m");
console_send((uint8_t*)buf, len);
}
void set_console_green(void)
{
char buf[16] = {0};
uint32_t len = snprintf(buf, 16, "\x1b[1;32m");
console_send((uint8_t*)buf, len);
}
void reset_console(void)
{
char buf[16] = {0};
uint32_t len = snprintf(buf, 16, "\x1b[2J\x1b[H");
console_send((uint8_t*)buf, len);
}