Adding environment setup and instructions

This commit is contained in:
Brent Perteet
2025-07-22 14:04:27 -05:00
parent 311981ceb4
commit dc2885e02e
23 changed files with 3741 additions and 114 deletions

View File

@@ -1,5 +1,5 @@
idf_component_register(SRCS "system.c" "bubble.c" "keypad.c" "main.c"
"bt_app_core.c"
idf_component_register(SRCS "bt_app.c" "system.c" "bubble.c" "keypad.c" "main.c"
"gui.c"
"lsm6dsv.c"
INCLUDE_DIRS "."

View File

@@ -12,9 +12,11 @@
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/task.h"
#include "freertos/stream_buffer.h"
#include "esp_log.h"
#include "bt_app_core.h"
#include "bt_app.h"
#include "system.h"
#include "esp_bt.h"
#include "esp_bt_main.h"
@@ -368,18 +370,215 @@ static void bt_app_a2d_cb(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param)
bt_app_work_dispatch(bt_app_av_sm_hdlr, event, param, sizeof(esp_a2d_cb_param_t), NULL);
}
static uint8_t btData[512];
static void fillBuffer(uint8_t *data, int32_t len)
{
#define SAMPLE_RATE 44100
#define TONE_FREQ 440.0f // A4
#define FADE_FREQ 1.0f // 1 Hz fade L->R
#define STREAM_BUF_SIZE (8192)
#define CHUNK_SIZE (512)
StreamBufferHandle_t audio_stream_buf;
void generate_synth_pcm(uint8_t *buf, int len) {
static float phase = 0.0f;
static float fade_phase = 0.0f;
int16_t *samples = (int16_t *)buf;
int samples_needed = len / 4; // 4 bytes per stereo frame (2 bytes L, 2 bytes R)
for (int i = 0; i < samples_needed; i++) {
// Fade L/R amplitude: 0..1 for L, inverted for R
float fade = (sinf(2 * M_PI * fade_phase) + 1.0f) * 0.5f;
// Sine wave sample
float sample = sinf(2 * M_PI * phase);
int16_t left = (int16_t)(sample * fade * 32767);
int16_t right = (int16_t)(sample * (1.0f - fade) * 32767);
samples[i * 2 + 0] = left;
samples[i * 2 + 1] = right;
// Advance phases
phase += TONE_FREQ / SAMPLE_RATE;
if (phase >= 1.0f) phase -= 1.0f;
fade_phase += FADE_FREQ / SAMPLE_RATE;
if (fade_phase >= 1.0f) fade_phase -= 1.0f;
}
}
#define MIN_RATE_HZ 1.0f
#define MAX_RATE_HZ 440.0f
#define CLICK_AMPLITUDE 32000 // 16-bit
static float click_timer = 0.0f;
void generate_synth_clicks(uint8_t *buf, int len, float balance) {
int16_t *samples = (int16_t *)buf;
int samples_needed = len / 4;
float abs_balance = fabsf(balance);
float rate_hz = MIN_RATE_HZ * powf(MAX_RATE_HZ / MIN_RATE_HZ, abs_balance);
float samples_per_click = SAMPLE_RATE / rate_hz;
for (int i = 0; i < samples_needed; i++) {
int16_t left = 0;
int16_t right = 0;
if (click_timer <= 0.0f) {
// Insert a short pulse: single sample spike
if (balance < 0) {
left = CLICK_AMPLITUDE;
} else if (balance > 0) {
right = CLICK_AMPLITUDE;
}
click_timer += samples_per_click;
}
click_timer -= 1.0f;
samples[i * 2 + 0] = left;
samples[i * 2 + 1] = right;
}
}
void audio_producer_task(void *pvParameters) {
uint8_t chunk[CHUNK_SIZE];
int core_id = xPortGetCoreID();
ESP_LOGI("Producer", "Running on core %d", core_id);
system_subscribe(xTaskGetCurrentTaskHandle());
#if 0
while (1) {
generate_synth_pcm(chunk, sizeof(chunk));
size_t sent = xStreamBufferSend(audio_stream_buf, chunk, sizeof(chunk), portMAX_DELAY);
if (sent < sizeof(chunk)) {
ESP_LOGW(BT_APP_CORE_TAG, "Dropped %d bytes", sizeof(chunk) - sent);
}
}
#endif
static float phase = 0.0f;
float balance = 0.0f; // -1.0 = left, +1.0 = right
uint32_t raw_value;
uint32_t notifiedBits = 0;
while (1) {
// Non-blocking check for new notification:
// clear on entry (first param), wait for any bit, block forever
xTaskNotifyWait(
0, // clear any old bits on entry
0, // clear bits on exit
&notifiedBits,
0);
if (notifiedBits & EM_EVENT_NEW_DATA)
{
ImuData_t d = system_getImuData();
if (fabs(d.raw[system_getPrimaryAxis()]) > 45.0f)
{
balance = 0.0f;
}
else
{
balance = -d.angle / MAX_INDICATION_ANGLE;
}
}
if (balance > 1.0f)
{
balance = 1.0f;
}
else
if (balance < -1.0f)
{
balance = -1.0f;
}
generate_synth_clicks(chunk, sizeof(chunk), balance);
#if 0
// Synthesize audio using latest balance
int16_t *samples = (int16_t *)chunk;
int samples_needed = CHUNK_SIZE / 4;
for (int i = 0; i < samples_needed; i++) {
float sample = sinf(2 * M_PI * phase);
float left_gain = 0.5f * (1.0f - balance);
float right_gain = 0.5f * (1.0f + balance);
int16_t left = (int16_t)(sample * left_gain * 32767);
int16_t right = (int16_t)(sample * right_gain * 32767);
samples[i * 2 + 0] = left;
samples[i * 2 + 1] = right;
phase += TONE_FREQ / SAMPLE_RATE;
if (phase >= 1.0f) phase -= 1.0f;
}
#endif
// Push chunk to FIFO
xStreamBufferSend(audio_stream_buf, chunk, sizeof(chunk), portMAX_DELAY);
}
}
/* generate some random noise to simulate source audio */
static int32_t bt_app_a2d_data_cb(uint8_t *data, int32_t len)
{
size_t bytes_read = xStreamBufferReceive(audio_stream_buf, data, len, 0);
if (bytes_read < len) {
memset(data + bytes_read, 0, len - bytes_read); // fill silence
}
return len;
#if 0
if (data == NULL || len < 0) {
return 0;
}
int16_t *p_buf = (int16_t *)data;
for (int i = 0; i < (len >> 1); i++) {
p_buf[i] = rand() % (1 << 16);
}
return len;
#endif
}
#if 0
/* Generate a continuous 440Hz sine wave */
static int32_t bt_app_a2d_data_cb(uint8_t *data, int32_t len)
{
static double phase = 0.0;
if (data == NULL || len < 0) {
return 0;
}
int16_t *p_buf = (int16_t *)data;
for (int i = 0; i < (len >> 1); i++) {
p_buf[i] = rand() % (1 << 16);
}
return len;
#if 0
static double phase = 0.0;
const double frequency = 440.0; // A4 tone (440 Hz)
const double sample_rate = 44100.0; // 44.1 kHz sample rate
const double phase_increment = 2.0 * M_PI * frequency / sample_rate;
@@ -406,7 +605,9 @@ static int32_t bt_app_a2d_data_cb(uint8_t *data, int32_t len)
}
}
return len;
#endif
}
#endif
static void bt_app_a2d_heart_beat(TimerHandle_t arg)
{
@@ -551,6 +752,7 @@ static void bt_app_av_media_proc(uint16_t event, void *param)
}
case APP_AV_MEDIA_STATE_STARTED: {
if (event == BT_APP_HEART_BEAT_EVT) {
#if 0
/* stop media after 10 heart beat intervals */
if (++s_intv_cnt >= 10) {
ESP_LOGI(BT_AV_TAG, "a2dp media suspending...");
@@ -558,6 +760,7 @@ static void bt_app_av_media_proc(uint16_t event, void *param)
s_media_state = APP_AV_MEDIA_STATE_STOPPING;
s_intv_cnt = 0;
}
#endif
}
break;
}
@@ -791,6 +994,10 @@ static void bt_app_task_handler(void *arg)
{
bt_app_msg_t msg;
int core_id = xPortGetCoreID();
ESP_LOGI("MY_TASK", "Running on core %d", core_id);
for (;;) {
/* receive message from work queue and handle it */
if (pdTRUE == xQueueReceive(s_bt_app_task_queue, &msg, (TickType_t)portMAX_DELAY)) {
@@ -846,7 +1053,9 @@ bool bt_app_work_dispatch(bt_app_cb_t p_cback, uint16_t event, void *p_params, i
void bt_app_task_start_up(void)
{
s_bt_app_task_queue = xQueueCreate(10, sizeof(bt_app_msg_t));
xTaskCreate(bt_app_task_handler, "BtAppTask", 4096, NULL, 10, &s_bt_app_task_handle);
//xTaskCreate(bt_app_task_handler, "BtAppTask", 8192, NULL, 10, &s_bt_app_task_handle);
xTaskCreatePinnedToCore(bt_app_task_handler, "BtAppTask", 8192, NULL, 10, NULL, 1);
}
void bt_app_task_shut_down(void)
@@ -867,7 +1076,27 @@ void bt_app_init(void)
esp_err_t ret;
char bda_str[18] = {0};
fillBuffer(btData, 512);
//esp_err_t esp_bredr_tx_power_get(esp_power_level_t *min_power_level, esp_power_level_t *max_power_level)
esp_power_level_t pmin;
esp_power_level_t pmax;
esp_bredr_tx_power_get(&pmin, &pmax);
ESP_LOGI(BT_APP_CORE_TAG, "BT Power min = %d\nBT Power max = %d", pmin, pmax);
//pmin = ESP_PWR_LVL_P6;
//pmax = ESP_PWR_LVL_P7;
pmin = ESP_PWR_LVL_N12;
pmax = ESP_PWR_LVL_N9;
esp_err_t err = esp_bredr_tx_power_set(pmin, pmax);
if (err != ESP_OK) {
ESP_LOGE(BT_APP_CORE_TAG, "Failed to set TX power: %s", esp_err_to_name(err));
}
esp_bredr_tx_power_get(&pmin, &pmax);
ESP_LOGI(BT_APP_CORE_TAG, "BT Power min = %d\nBT Power max = %d", pmin, pmax);
/*
* This example only uses the functions of Classical Bluetooth.
@@ -885,6 +1114,10 @@ void bt_app_init(void)
return;
}
err = esp_bredr_tx_power_set(pmin, pmax);
if (err != ESP_OK) {
ESP_LOGE(BT_APP_CORE_TAG, "Failed to set TX power: %s", esp_err_to_name(err));
}
esp_bluedroid_config_t bluedroid_cfg = BT_BLUEDROID_INIT_CONFIG_DEFAULT();
#if (CONFIG_EXAMPLE_SSP_ENABLED == false)
bluedroid_cfg.ssp_en = false;
@@ -918,4 +1151,19 @@ void bt_app_init(void)
bt_app_task_start_up();
/* Bluetooth device name, connection mode and profile set up */
bt_app_work_dispatch(bt_av_hdl_stack_evt, BT_APP_STACK_UP_EVT, NULL, 0, NULL);
audio_stream_buf = xStreamBufferCreate(STREAM_BUF_SIZE, 1);
assert(audio_stream_buf != NULL);
//xTaskCreate(audio_producer_task, "audio_producer", 4096, NULL, 5, NULL);
xTaskCreatePinnedToCore(audio_producer_task, "audio_producer", 4096, NULL, 5, NULL, 1);
ESP_LOGI(BT_APP_CORE_TAG, "Audio synth producer started");
vTaskDelay(pdMS_TO_TICKS(1000));
}

View File

@@ -5,6 +5,7 @@
#define PIN_NUM_BUTTON_0 36
#define PIN_NUM_BUTTON_1 39
#define PIN_NUM_LED_1 32
#define PIN_NUM_LED_2 33
#define PIN_NUM_nON 26

View File

@@ -105,9 +105,9 @@ static void create_lvgl_demo(void)
lvgl_port_lock(0);
// Create a screen with black background
lv_obj_t *scr = lv_scr_act();
//create_menu(scr);
createBubble(scr);
build_scrollable_menu();
//build_scrollable_menu();
lvgl_port_unlock();
@@ -167,8 +167,8 @@ static void lvgl_init(void)
#if 1
const lvgl_port_cfg_t lvgl_cfg = {
.task_priority = 4, // LVGL task priority
.task_stack = 32768, // LVGL task stack size
.task_affinity = -1, // LVGL task can run on any core
.task_stack = 16384, // LVGL task stack size
.task_affinity = 0, // LVGL task can run on any core
.task_max_sleep_ms = 500, // Maximum sleep in LVGL task
.timer_period_ms = 5 // LVGL timer period
};
@@ -180,7 +180,7 @@ static void lvgl_init(void)
.io_handle = io_handle,
.panel_handle = panel_handle,
.buffer_size = LCD_H_RES * LCD_V_RES * 2,
.double_buffer = true,
.double_buffer = false,
.hres = LCD_H_RES,
.vres = LCD_V_RES,
.monochrome = false,
@@ -219,15 +219,10 @@ static void createBubble(lv_obj_t * scr)
_bubble = level;
}
void ui_test()
{
lv_obj_t *label = lv_label_create(lv_screen_active());
lv_label_set_text(label, "Hello, LVGL 9.2!");
lv_obj_center(label);
}
void gui_start(void)
{
// Initialize LCD
lcd_init();
@@ -236,7 +231,6 @@ void gui_start(void)
// Create UI
create_lvgl_demo();
keypad_start();
@@ -333,21 +327,9 @@ static void refresh_highlight(void) {
next = lv_obj_get_child(page, index);
}
// for(int i = 0; i < ITEM_COUNT; i++) {
// if(i == selected_idx) {
// lv_obj_set_style_bg_color(btn_array[i], lv_color_hex(0xFF8800), 0);
// lv_obj_set_style_text_color(lv_obj_get_child(btn_array[i],0),
// lv_color_white(), 0);
// } else {
// lv_obj_set_style_bg_color(btn_array[i], lv_color_white(), 0);
// lv_obj_set_style_text_color(lv_obj_get_child(btn_array[i],0),
// lv_color_black(), 0);
// }
// }
if (selected)
{
lv_obj_scroll_to_view(selected, LV_ANIM_ON);
lv_obj_scroll_to_view(selected, LV_ANIM_ON);
}
lvgl_port_unlock();
@@ -521,40 +503,7 @@ static void build_scrollable_menu(void) {
addMenuItem(calMenu, "Exit");
_currentPage = main;
#if 0
for(int i = 0; i < ITEM_COUNT; i++) {
// create a full-width button in that section
lv_obj_t * btn = lv_btn_create(main);
lv_obj_set_size(btn, LV_PCT(100), ROW_H);
// style it just like your old list
lv_obj_set_style_bg_color(btn, lv_color_white(), 0);
lv_obj_set_style_radius(btn, 0, LV_PART_MAIN);
lv_obj_set_style_border_width(btn, 0, LV_PART_MAIN);
lv_obj_clear_flag(btn, LV_OBJ_FLAG_SCROLLABLE);
// label & center
lv_obj_t * lbl = lv_label_create(btn);
lv_label_set_text(lbl, items[i]);
lv_obj_set_style_radius(lbl, 0, LV_PART_MAIN | LV_STATE_ANY);
lv_obj_set_style_border_width(lbl, 0, LV_PART_MAIN | LV_STATE_ANY);
//lv_obj_center(lbl);
// click callback
lv_obj_add_event_cb(btn, btn_click_cb, LV_EVENT_CLICKED, NULL);
// save for highlight/scroll
btn_array[i] = btn;
}
// lv_obj_t * content = lv_obj_get_child(page, 0);
// lv_obj_set_style_radius(content, 0, LV_PART_MAIN | LV_STATE_ANY);
// lv_obj_set_style_border_width(content, 0, LV_PART_MAIN | LV_STATE_ANY);
#endif
// 6) Initial highlight
selected_idx = 0;
refresh_highlight();
@@ -563,6 +512,7 @@ static void build_scrollable_menu(void) {
}
static void gui_task(void)
{
system_subscribe(xTaskGetCurrentTaskHandle());
@@ -571,8 +521,12 @@ static void gui_task(void)
QueueHandle_t q = keypad_getQueue();
uint32_t ev = 0;
LOCK();
// _mode = GUI_MENU;
// lv_obj_remove_flag(_menu, LV_OBJ_FLAG_HIDDEN);
lv_obj_remove_flag(_bubble, LV_OBJ_FLAG_HIDDEN);
lv_obj_add_flag(_menu, LV_OBJ_FLAG_HIDDEN);
//lv_obj_add_flag(_menu, LV_OBJ_FLAG_HIDDEN);
UNLOCK();
while (1)
{
@@ -581,6 +535,19 @@ static void gui_task(void)
if (xQueueReceive(q, &ev, pdMS_TO_TICKS(10)) == pdTRUE)
{
switch (ev) {
case (KEY_UP << KEY_LONG_PRESS):
{
system_setZeroAngle();
break;
}
case (KEY_DOWN << KEY_LONG_PRESS):
{
system_clearZeroAngle();
break;
}
#if 0
case (KEY0 << KEY_SHORT_PRESS):
if (_mode == GUI_MENU)
@@ -590,7 +557,9 @@ static void gui_task(void)
ESP_LOGI(TAG, "MAIN: Button 1 SHORT");
break;
case (KEY0 << KEY_LONG_PRESS):
{
if (_mode != GUI_MENU)
{
_mode = GUI_MENU;
@@ -605,8 +574,8 @@ static void gui_task(void)
// lv_obj_remove_flag(_bubble, LV_OBJ_FLAG_HIDDEN);
// lv_obj_add_flag(_menu, LV_OBJ_FLAG_HIDDEN);
}
break;
}
case (KEY1 << KEY_SHORT_PRESS):
{
if (_mode == GUI_MENU)
@@ -619,6 +588,7 @@ static void gui_task(void)
ESP_LOGI(TAG, "MAIN: Button 2 LONG");
gpio_set_level(PIN_NUM_nON, 0);
break;
#endif
default:
break;
}
@@ -633,7 +603,7 @@ static void gui_task(void)
0xFFFFFFFF, // clear any old bits on entry
0xFFFFFFFF, // clear bits on exit
&notifiedBits,
pdMS_TO_TICKS(10));
pdMS_TO_TICKS(100));
if (notifiedBits & EM_EVENT_NEW_DATA)
{

View File

@@ -14,7 +14,8 @@ typedef enum
#define KEY_SHORT_PRESS 0
#define KEY_LONG_PRESS 4
#define KEY_UP KEY0
#define KEY_DOWN KEY1
void keypad_start(void);
QueueHandle_t keypad_getQueue(void);

View File

@@ -21,7 +21,7 @@
#include "nvs_flash.h"
#include "bt_app_core.h"
#include "bt_app.h"
#include "lsm6dsv.h"
#include "gui.h"
#include "gpio.h"
@@ -71,8 +71,9 @@ static void init_gpio(void)
// Configure output GPIO
io_conf.pin_bit_mask = (1ULL << PIN_NUM_LED_1);
io_conf.pin_bit_mask = (1ULL << PIN_NUM_LED_1) | (1ULL << PIN_NUM_LED_2);
io_conf.mode = GPIO_MODE_OUTPUT;
io_conf.intr_type = GPIO_INTR_DISABLE;
io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
gpio_config(&io_conf);
@@ -86,7 +87,8 @@ static void init_gpio(void)
io_conf.pin_bit_mask = (1ULL << PIN_NUM_nON);
io_conf.mode = GPIO_MODE_OUTPUT;
io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
io_conf.intr_type = GPIO_INTR_DISABLE;
io_conf.pull_up_en = GPIO_PULLUP_ENABLE;
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
gpio_config(&io_conf);
#endif
@@ -95,8 +97,8 @@ static void init_gpio(void)
// Configure LCD Backlight GPIO
io_conf.pin_bit_mask = (1ULL << PIN_NUM_BK_LIGHT);
io_conf.mode = GPIO_MODE_OUTPUT;
io_conf.intr_type = GPIO_INTR_DISABLE;
io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
gpio_config(&io_conf);
@@ -116,7 +118,7 @@ static void imu_task(void *pvParameters) {
ImuData_t imu;
LowPassFilter lpf;
LPF_Init(&lpf, 0.2, 0);
LPF_Init(&lpf, FILTER_COEFF, 0);
while (1) {
@@ -170,20 +172,20 @@ static void imu_task(void *pvParameters) {
float angle;
if (imu.raw[ANGLE_XY] > MAX_INDICATION_ANGLE)
angle = system_getAngle();
if (angle > MAX_INDICATION_ANGLE)
{
angle = MAX_INDICATION_ANGLE;
}
else
if (imu.raw[ANGLE_XY] > MAX_INDICATION_ANGLE)
if (angle < -MAX_INDICATION_ANGLE)
{
angle = -MAX_INDICATION_ANGLE;
}
else
{
angle = imu.raw[ANGLE_XY];
}
// low pass filter the angle measurement
imu.angle = LPF_Update(&lpf, angle);
//imu.filtered[ANGLE_XY] = LPF_Update(&lpf, imu.raw[ANGLE_XY]);
@@ -197,7 +199,7 @@ static void imu_task(void *pvParameters) {
#if 0
snprintf(data_str, sizeof(data_str),
"(%.1f, %.1f, %.1f) (%.2f, %.2f, %.2f)",
xz, yz, xy,
imu.raw[ANGLE_XZ], imu.raw[ANGLE_YZ], imu.raw[ANGLE_XY],
(float)imu_data.acc_x, (float)imu_data.acc_y, (float)imu_data.acc_z);
ESP_LOGI(TAG, "%s", data_str);
#endif
@@ -218,12 +220,12 @@ void app_main(void)
{
/* initialize NVS — it is used to store PHY calibration data */
// esp_err_t ret = nvs_flash_init();
// if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
// ESP_ERROR_CHECK(nvs_flash_erase());
// ret = nvs_flash_init();
// }
// ESP_ERROR_CHECK(ret);
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
init_gpio();
@@ -241,26 +243,49 @@ void app_main(void)
bt_app_init();
gui_start();
gpio_set_level(PIN_NUM_LED_2, 1);
//bt_app_init();
#if 0
keypad_start();
QueueHandle_t q = keypad_getQueue();
uint32_t ev = 0;
//gpio_set_level(PIN_NUM_LED_1, 1);
gpio_set_level(PIN_NUM_LED_2, 1);
// Main loop - LVGL task will run automatically
while (1) {
// int level = gpio_get_level(PIN_NUM_BUTTON_1); // Read input GPIO
// gpio_set_level(PIN_NUM_LED_1, level);
if (xQueueReceive(q, &ev, pdMS_TO_TICKS(10)) == pdTRUE)
{
switch (ev)
{
case (KEY_UP << KEY_LONG_PRESS):
{
system_setZeroAngle();
break;
}
//gpio_set_level(PIN_NUM_nON, (level ? 0 : 1));
vTaskDelay(pdMS_TO_TICKS(100));
//gui_service();
case (KEY_DOWN << KEY_LONG_PRESS):
{
system_clearZeroAngle();
break;
}
}
}
}
#else
while (1)
{
vTaskDelay(pdMS_TO_TICKS(1000));
}
#endif
}

View File

@@ -8,12 +8,77 @@ static EventManager_t _eventManager;
void system_init(void)
{
_systemState.zeroAngle = 0.0f;
_systemState.primaryAxis = PRIMARY_AXIS;
EventGroupHandle_t evt = xEventGroupCreate();
_eventManager.count = 0;
_eventManager.mutex = xSemaphoreCreateMutex();
}
int system_getPrimaryAxis(void)
{
int axis;
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
axis = _systemState.primaryAxis;
xSemaphoreGive(_eventManager.mutex);
return axis;
}
float system_getAngle(void)
{
float angle;
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
angle = _systemState.imu.raw[_systemState.primaryAxis] - _systemState.zeroAngle;
xSemaphoreGive(_eventManager.mutex);
return angle;
}
void system_setZeroAngle(void)
{
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
_systemState.zeroAngle = _systemState.imu.raw[_systemState.primaryAxis];
ESP_LOGI("system", "Zero: %.1f", _systemState.zeroAngle);
xSemaphoreGive(_eventManager.mutex);
}
void system_clearZeroAngle(void)
{
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
_systemState.zeroAngle = 0.0f;
ESP_LOGI("system", "Zero: %.1f", _systemState.zeroAngle);
xSemaphoreGive(_eventManager.mutex);
}
float system_getZeroAngle(void)
{
float angle;
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
angle = _systemState.zeroAngle;
xSemaphoreGive(_eventManager.mutex);
return angle;
}
void system_setImuData(ImuData_t imu)
{
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);

View File

@@ -5,6 +5,8 @@
#include "freertos/task.h"
#include "freertos/semphr.h"
#define DISABLE_GUI
enum
{
ANGLE_XY = 0,
@@ -27,11 +29,15 @@ typedef struct SystemState_s
EventGroupHandle_t event;
float zeroAngle;
int primaryAxis;
} SystemState_t;
#define MAX_INDICATION_ANGLE 10.0f
#define MAX_INDICATION_ANGLE 5.0f
#define FILTER_COEFF 0.2f // 0 to 1 Smaller number is heavier filter
#define PRIMARY_AXIS ANGLE_YZ
#define EM_MAX_SUBSCRIBERS 8 // tweak as needed
#define EM_EVENT_NEW_DATA (1UL<<0)
@@ -49,6 +55,13 @@ void system_setImuData(ImuData_t imu);
ImuData_t system_getImuData(void);
int system_getPrimaryAxis(void);
float system_getAngle(void);
void system_setZeroAngle(void);
void system_clearZeroAngle(void);
float system_getZeroAngle(void);
// Subscribe (register) current task to receive events
BaseType_t system_subscribe(TaskHandle_t task);