console #2

Merged
chris merged 3 commits from console into main 2024-07-29 19:04:34 -05:00
10 changed files with 4997 additions and 29 deletions
Showing only changes of commit 853e4333c3 - Show all commits

93
Core/Inc/cir_buf.h Normal file
View File

@ -0,0 +1,93 @@
/**
*********************************************************************
*
* @file cir_buf.h
* @brief Circular buffer header file
*
* @date 2024-04-21 18:36:52
* @author CT
*
* @details Provides an interface for creating and interacting with circular
* buffers.
*
*************************************************************************
**/
#ifndef _CIR_BUF_H_
#define _CIR_BUF_H_
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
/// Opaque circular buffer structure
typedef struct circular_buf_t circular_buf_t;
/// Handle type, the way users interact with the API
typedef circular_buf_t* cbuf_handle_t;
/// Pass in a storage buffer and size, returns a circular buffer handle
/// Requires: buffer is not NULL, size > 0 (size > 1 for the threadsafe
// version, because it holds size - 1 elements)
/// Ensures: me has been created and is returned in an empty state
cbuf_handle_t circular_buf_init(uint8_t* buffer, size_t size);
/// Free a circular buffer structure
/// Requires: me is valid and created by circular_buf_init
/// Does not free data buffer; owner is responsible for that
void circular_buf_free(cbuf_handle_t me);
/// Reset the circular buffer to empty, head == tail. Data not cleared
/// Requires: me is valid and created by circular_buf_init
void circular_buf_reset(cbuf_handle_t me);
/// Put that continues to add data if the buffer is full
/// Old data is overwritten
/// Note: if you are using the threadsafe version, this API cannot be used, because
/// it modifies the tail pointer in some cases. Use circular_buf_try_put instead.
/// Requires: me is valid and created by circular_buf_init
void circular_buf_put(cbuf_handle_t me, uint8_t data);
/// Put that rejects new data if the buffer is full
/// Note: if you are using the threadsafe version, *this* is the put you should use
/// Requires: me is valid and created by circular_buf_init
/// Returns 0 on success, -1 if buffer is full
int circular_buf_try_put(cbuf_handle_t me, uint8_t data);
/// Retrieve a value from the buffer
/// Requires: me is valid and created by circular_buf_init
/// Returns 0 on success, -1 if the buffer is empty
int circular_buf_get(cbuf_handle_t me, uint8_t* data);
/// Checks if the buffer is empty
/// Requires: me is valid and created by circular_buf_init
/// Returns true if the buffer is empty
bool circular_buf_empty(cbuf_handle_t me);
/// Checks if the buffer is full
/// Requires: me is valid and created by circular_buf_init
/// Returns true if the buffer is full
bool circular_buf_full(cbuf_handle_t me);
/// Check the capacity of the buffer
/// Requires: me is valid and created by circular_buf_init
/// Returns the maximum capacity of the buffer
size_t circular_buf_capacity(cbuf_handle_t me);
/// Check the number of elements stored in the buffer
/// Requires: me is valid and created by circular_buf_init
/// Returns the current number of elements in the buffer
size_t circular_buf_size(cbuf_handle_t me);
/// Look ahead at values stored in the circular buffer without removing the data
/// Requires:
/// - me is valid and created by circular_buf_init
/// - look_ahead_counter is less than or equal to the value returned by circular_buf_size()
/// Returns 0 if successful, -1 if data is not available
int circular_buf_peek(cbuf_handle_t me, uint8_t* data, unsigned int look_ahead_counter);
// TODO: int circular_buf_get_range(circular_buf_t me, uint8_t *data, size_t len);
// TODO: int circular_buf_put_range(circular_buf_t me, uint8_t * data, size_t len);
#endif /* _CIR_BUF_H_ */

26
Core/Inc/console.h Normal file
View File

@ -0,0 +1,26 @@
/**
*********************************************************************
*
* @file console.h
* @brief
*
* @date 2024-04-14 19:12:40
* @author CT
*
* @details
*
*************************************************************************
**/
#ifndef _CONSOLE_H_
#define _CONSOLE_H_
#include "main.h"
#include "cir_buf.h"
void console_init(config_data_u_t* config_data);
void console_service(void);
int console_push(uint8_t data);
#endif // _CONOSLE_H_

View File

@ -36,7 +36,20 @@ extern "C" {
/* Exported types ------------------------------------------------------------*/
/* USER CODE BEGIN ET */
typedef struct config_data
{
int32_t slider_1;
int32_t slider_2;
int32_t slider_3;
int32_t slider_4;
int32_t slider_5;
} config_data_t;
typedef union config_data_u
{
config_data_t config;
uint8_t data[sizeof(config_data_t)];
} config_data_u_t;
/* USER CODE END ET */
/* Exported constants --------------------------------------------------------*/

View File

@ -2,8 +2,8 @@
#define _VERSION_H
#define VERSION_MAJOR (1)
#define VERSION_MINOR (0)
#define VERSION_PATCH (5)
#define VERSION_STR "V1.0.5"
#define VERSION_MINOR (1)
#define VERSION_PATCH (0)
#define VERSION_STR "V1.1.0"
#endif

190
Core/Src/cir_buf.c Normal file
View File

@ -0,0 +1,190 @@
/**
*********************************************************************
*
* @file cir_buf.c
* @brief Circular buffer header file
*
* @date 2024-04-21 18:36:52
* @author CT
*
* @details Provides an interface for creating and interacting with circular
* buffers.
*
*************************************************************************
**/
#include <stdlib.h>
#include <stdint.h>
#include <stddef.h>
#include <assert.h>
#include "cir_buf.h"
// The definition of our circular buffer structure is hidden from the user
struct circular_buf_t
{
uint8_t* buffer;
size_t head;
size_t tail;
size_t max; // of the buffer
bool full;
};
/* PRIVATE FUNCTIONS */
static inline size_t advance_headtail_value(size_t value, size_t max)
{
return (value + 1) % max;
}
static void advance_head_pointer(cbuf_handle_t me)
{
assert(me);
if(circular_buf_full(me))
{
me->tail = advance_headtail_value(me->tail, me->max);
}
me->head = advance_headtail_value(me->head, me->max);
me->full = (me->head == me->tail);
}
/* API FUNCTIONS */
cbuf_handle_t circular_buf_init(uint8_t* buffer, size_t size)
{
assert(buffer && size);
cbuf_handle_t cbuf = malloc(sizeof(circular_buf_t));
assert(cbuf);
cbuf->buffer = buffer;
cbuf->max = size;
circular_buf_reset(cbuf);
assert(circular_buf_empty(cbuf));
return cbuf;
}
void circular_buf_free(cbuf_handle_t me)
{
assert(me);
free(me);
}
void circular_buf_reset(cbuf_handle_t me)
{
assert(me);
me->head = 0;
me->tail = 0;
me->full = false;
}
size_t circular_buf_size(cbuf_handle_t me)
{
assert(me);
size_t size = me->max;
if(!circular_buf_full(me))
{
if(me->head >= me->tail)
{
size = (me->head - me->tail);
}
else
{
size = (me->max + me->head - me->tail);
}
}
return size;
}
size_t circular_buf_capacity(cbuf_handle_t me)
{
assert(me);
return me->max;
}
void circular_buf_put(cbuf_handle_t me, uint8_t data)
{
assert(me && me->buffer);
me->buffer[me->head] = data;
advance_head_pointer(me);
}
int circular_buf_try_put(cbuf_handle_t me, uint8_t data)
{
int r = -1;
assert(me && me->buffer);
if(!circular_buf_full(me))
{
me->buffer[me->head] = data;
advance_head_pointer(me);
r = 0;
}
return r;
}
int circular_buf_get(cbuf_handle_t me, uint8_t* data)
{
assert(me && data && me->buffer);
int r = -1;
if(!circular_buf_empty(me))
{
*data = me->buffer[me->tail];
me->tail = advance_headtail_value(me->tail, me->max);
me->full = false;
r = 0;
}
return r;
}
bool circular_buf_empty(cbuf_handle_t me)
{
assert(me);
return (!circular_buf_full(me) && (me->head == me->tail));
}
bool circular_buf_full(cbuf_handle_t me)
{
assert(me);
return me->full;
}
int circular_buf_peek(cbuf_handle_t me, uint8_t* data, unsigned int look_ahead_counter)
{
int r = -1;
size_t pos;
assert(me && data && me->buffer);
// We can't look beyond the current buffer size
if(circular_buf_empty(me) || look_ahead_counter > circular_buf_size(me))
{
return r;
}
pos = me->tail;
for(unsigned int i = 0; i < look_ahead_counter; i++)
{
data[i] = me->buffer[pos];
pos = advance_headtail_value(pos, me->max);
}
return 0;
}

422
Core/Src/console.c Normal file
View File

@ -0,0 +1,422 @@
/**
*********************************************************************
*
* @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);
}

View File

@ -29,6 +29,8 @@
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdbool.h>
#include "console.h"
#include "usbd_cdc_if.h"
#include "version.h"
/* USER CODE END Includes */
@ -52,7 +54,6 @@ typedef struct EMA_Filter
#define PWM_LIMIT (0.5f)
#define BTN_POLL_TIME (100u)
#define UART_LOOP_TIME (1000u)
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
@ -74,7 +75,9 @@ float m_sliders[NUM_SLIDERS];
uint8_t m_buttons = 0;
char buf[512] = {0};
// char buf[512] = {0};
config_data_u_t config_data;
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
@ -107,7 +110,6 @@ int main(void)
{
/* USER CODE BEGIN 1 */
uint32_t prev_uart_tick = UART_LOOP_TIME;
uint32_t prev_btn_time = BTN_POLL_TIME;
/* USER CODE END 1 */
@ -140,8 +142,11 @@ int main(void)
MX_USB_Device_Init();
/* USER CODE BEGIN 2 */
// int len = snprintf(buf, 128, "Version: %s\r\n", VERSION_STR);
// CDC_Transmit_FS((uint8_t *)buf, len);
// TODO Load configuration data from NV-memory
// Initialize the console and pass a pointer to our configuration data location
console_init(&config_data);
// Initialize EMA filters
for (uint32_t i = 0; i < NUM_SLIDERS; i++)
@ -183,6 +188,12 @@ int main(void)
/* USER CODE BEGIN WHILE */
while (1)
{
// Service the console, not interrupt based
console_service();
// TODO Service the NVmem module
if ((m_adc1_filtered_ready) == true && (m_adc2_filtered_ready == true))
{
// Map ADC value to PWM value
@ -203,20 +214,6 @@ int main(void)
m_adc2_filtered_ready = false;
}
// if ((HAL_GetTick() - prev_uart_tick) >= UART_LOOP_TIME)
// {
// prev_uart_tick = HAL_GetTick();
// int len = snprintf(buf, 512, "Master\tCh1\tCh2\tCh3\tCh4\t\r\n");
// len += snprintf((buf + len), (512 - len), "%03.1f\t%03.1f\t%03.1f\t%03.1f\t%03.1f\t\r\n",
// m_sliders[0], m_sliders[1], m_sliders[2], m_sliders[3], m_sliders[4]);
// len += snprintf((buf + len), (512 - len), "Version: %s\r\n", VERSION_STR);
// CDC_Transmit_FS((uint8_t *)buf, len);
// }
if ((HAL_GetTick() - prev_btn_time) >= BTN_POLL_TIME)
{
prev_btn_time = HAL_GetTick();
@ -332,10 +329,10 @@ void filter_adc2(void)
*/
void set_pwm_outputs(void)
{
float ch1 = map_clamp(m_sliders[1], 0.0f, 100.0f, 0, (MAX_PWM_VALUE * PWM_LIMIT));
float ch2 = map_clamp(m_sliders[2], 0.0f, 100.0f, 0, (MAX_PWM_VALUE * PWM_LIMIT));
float ch3 = map_clamp(m_sliders[3], 0.0f, 100.0f, 0, (MAX_PWM_VALUE * PWM_LIMIT));
float ch4 = map_clamp(m_sliders[4], 0.0f, 100.0f, 0, (MAX_PWM_VALUE * PWM_LIMIT));
float ch1 = map_clamp(m_sliders[1], 0.0f, 100.0f, 0, ((MAX_PWM_VALUE * config_data.config.slider_1) / 100.0f));
float ch2 = map_clamp(m_sliders[2], 0.0f, 100.0f, 0, ((MAX_PWM_VALUE * config_data.config.slider_2) / 100.0f));
float ch3 = map_clamp(m_sliders[3], 0.0f, 100.0f, 0, ((MAX_PWM_VALUE * config_data.config.slider_3) / 100.0f));
float ch4 = map_clamp(m_sliders[4], 0.0f, 100.0f, 0, ((MAX_PWM_VALUE * config_data.config.slider_4) / 100.0f));
htim1.Instance->CCR1 = (uint32_t)(ch1);
htim1.Instance->CCR2 = (uint32_t)(ch2);

4219
Releases/FW_1-1-0.hex Normal file

File diff suppressed because it is too large Load Diff

View File

@ -22,7 +22,7 @@
#include "usbd_cdc_if.h"
/* USER CODE BEGIN INCLUDE */
#include "console.h"
/* USER CODE END INCLUDE */
/* Private typedef -----------------------------------------------------------*/
@ -263,6 +263,12 @@ static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
/* USER CODE BEGIN 6 */
USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
USBD_CDC_ReceivePacket(&hUsbDeviceFS);
for (uint32_t i = 0; i < *Len; i++)
{
console_push(Buf[i]);
}
return (USBD_OK);
/* USER CODE END 6 */
}

View File

@ -6,8 +6,8 @@ add_library(stm32cubemx INTERFACE)
# Enable CMake support for ASM and C languages
enable_language(C ASM)
target_compile_definitions(stm32cubemx INTERFACE
USE_HAL_DRIVER
target_compile_definitions(stm32cubemx INTERFACE
USE_HAL_DRIVER
STM32G473xx
$<$<CONFIG:Debug>:DEBUG>
)
@ -32,6 +32,8 @@ target_sources(stm32cubemx INTERFACE
../../Core/Src/i2c.c
../../Core/Src/tim.c
../../Core/Src/usart.c
../../Core/Src/cir_buf.c
../../Core/Src/console.c
../../Core/Src/stm32g4xx_it.c
../../Core/Src/stm32g4xx_hal_msp.c
../../USB_Device/Target/usbd_conf.c