422 lines
9.5 KiB
C
422 lines
9.5 KiB
C
|
/**
|
||
|
*********************************************************************
|
||
|
*
|
||
|
* @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);
|
||
|
|
||
|
// for this demonstratior, load example values from nvmem
|
||
|
// NVmem_read(configuration_data->data, 0, 12);
|
||
|
}
|
||
|
|
||
|
|
||
|
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, 12);
|
||
|
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)
|
||
|
{
|
||
|
// *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\n[3]Slider [3]: \"%li\"\r\n[3]Slider [4]: \"%li\"\r\n[3]Slider [5]: \"%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, 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: ", 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);
|
||
|
}
|