added tweaks to filter
This commit is contained in:
16
.vscode/c_cpp_properties.json
vendored
Normal file
16
.vscode/c_cpp_properties.json
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Linux",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**"
|
||||
],
|
||||
"defines": [],
|
||||
"compilerPath": "/usr/bin/gcc",
|
||||
"cStandard": "c17",
|
||||
"cppStandard": "gnu++17",
|
||||
"intelliSenseMode": "linux-gcc-x64"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
7
.vscode/settings.json
vendored
7
.vscode/settings.json
vendored
@@ -35,7 +35,10 @@
|
||||
"semphr.h": "c",
|
||||
"lv_spinbox.h": "c",
|
||||
"lv_slider.h": "c",
|
||||
"lv_menu.h": "c"
|
||||
"lv_menu.h": "c",
|
||||
"stdint.h": "c",
|
||||
"random": "c"
|
||||
},
|
||||
"git.ignoreLimitWarning": true
|
||||
"git.ignoreLimitWarning": true,
|
||||
"idf.pythonInstallPath": "/usr/bin/python"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,21 @@
|
||||
# The following lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
# The following lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
configure_file(${CMAKE_SOURCE_DIR}/settings.json ${CMAKE_BINARY_DIR}/settings.json COPYONLY)
|
||||
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} -E echo "Parsing settings.json..."
|
||||
)
|
||||
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} -E env python ${CMAKE_SOURCE_DIR}/prepare_config.py
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(level-shot)
|
||||
include("${CMAKE_SOURCE_DIR}/project_settings.cmake")
|
||||
project(${PROJECT_NAME})
|
||||
51
bt_test/bt_test.ino
Normal file
51
bt_test/bt_test.ino
Normal file
@@ -0,0 +1,51 @@
|
||||
#include <BluetoothSerial.h>
|
||||
#include "esp_bt.h"
|
||||
#include "esp_bt_main.h"
|
||||
#include "esp_bt_device.h"
|
||||
|
||||
BluetoothSerial SerialBT;
|
||||
|
||||
void setBluetoothTxPower(esp_power_level_t powerLevel) {
|
||||
esp_err_t err = esp_bredr_tx_power_set(powerLevel, powerLevel);
|
||||
if (err != ESP_OK) {
|
||||
Serial.printf("Failed to set TX Power: %s\n", esp_err_to_name(err));
|
||||
} else {
|
||||
Serial.printf("TX Power set to level %d\n", powerLevel);
|
||||
}
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
delay(1000);
|
||||
|
||||
Serial.println("Initializing Bluetooth...");
|
||||
|
||||
if (!btStart()) {
|
||||
Serial.println("Failed to start BT controller");
|
||||
return;
|
||||
}
|
||||
|
||||
// Disable and re-enable the classic BT stack to safely set TX power
|
||||
esp_bluedroid_disable();
|
||||
esp_bluedroid_deinit();
|
||||
|
||||
// Set Classic BT TX power (e.g., ESP_PWR_LVL_P9 = highest)
|
||||
//setBluetoothTxPower(ESP_PWR_LVL_P9);
|
||||
setBluetoothTxPower(ESP_PWR_LVL_N12);
|
||||
|
||||
|
||||
esp_bluedroid_init();
|
||||
esp_bluedroid_enable();
|
||||
|
||||
if (!SerialBT.begin("ESP32-TXPowerTest")) {
|
||||
Serial.println("Bluetooth Serial failed to start");
|
||||
return;
|
||||
}
|
||||
|
||||
Serial.println("Bluetooth initialized and ready!");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
SerialBT.println("Hello from ESP32 with boosted TX power!");
|
||||
delay(1);
|
||||
}
|
||||
@@ -27,8 +27,10 @@ def main():
|
||||
# Define binaries and offsets
|
||||
bootloader = root / "build" / "bootloader" / "bootloader.bin"
|
||||
firmware = root / "build" / f"{project}.bin"
|
||||
ota_intitial = root / "build" / "ota_data_initial.bin"
|
||||
partition = root / "build" / "partition_table" / "partition-table.bin"
|
||||
|
||||
|
||||
# Verify binaries exist
|
||||
for f in [bootloader, firmware, partition]:
|
||||
if not f.exists():
|
||||
@@ -47,8 +49,9 @@ def main():
|
||||
"--flash-mode", flash_mode, # ✅ hyphenated flags
|
||||
"--flash-freq", flash_freq,
|
||||
"--flash-size", flash_size,
|
||||
"0x0", str(bootloader),
|
||||
"0x10000", str(firmware),
|
||||
"0x1000", str(bootloader),
|
||||
"0x20000", str(firmware),
|
||||
"0x11000", str(ota_intitial),
|
||||
"0x8000", str(partition)
|
||||
]
|
||||
|
||||
|
||||
@@ -3,11 +3,7 @@ import serial
|
||||
import sys
|
||||
import time
|
||||
from pathlib import Path
|
||||
# import colorama
|
||||
# colorama.just_fix_windows_console()
|
||||
|
||||
print("\x1b[0;32mThis should be green\x1b[0m")
|
||||
print("\x1b[0;31mThis should be red\x1b[0m")
|
||||
|
||||
def main():
|
||||
# Load config
|
||||
@@ -27,6 +23,10 @@ def main():
|
||||
|
||||
try:
|
||||
with serial.Serial(port, baud, timeout=0.5) as ser:
|
||||
# 🔧 Clear DTR and RTS lines (common for ESP32 reset handling)
|
||||
ser.dtr = False
|
||||
ser.rts = False
|
||||
|
||||
print("[Serial Monitor] Press Ctrl+C to exit.\n")
|
||||
while True:
|
||||
if ser.in_waiting:
|
||||
|
||||
@@ -1,19 +1,4 @@
|
||||
<<<<<<< HEAD
|
||||
idf_component_register(SRCS "system.c.LOCAL.c" "bt_app.c" "system.c" "bubble.c" "keypad.c" "main.c"
|
||||
|
||||
"gui.c"
|
||||
"lsm6dsv.c"
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES "driver"
|
||||
"esp_lcd"
|
||||
"lvgl"
|
||||
"esp_lvgl_port"
|
||||
"esp_timer"
|
||||
"nvs_flash"
|
||||
"bt")
|
||||
=======
|
||||
idf_component_register(SRCS "bt_app.c" "system.c" "bubble.c" "keypad.c" "main.c"
|
||||
|
||||
"gui.c"
|
||||
"lsm6dsv.c"
|
||||
INCLUDE_DIRS "."
|
||||
@@ -24,5 +9,4 @@ idf_component_register(SRCS "bt_app.c" "system.c" "bubble.c" "keypad.c" "main.c"
|
||||
"esp_timer"
|
||||
"nvs_flash"
|
||||
"bt")
|
||||
>>>>>>> 4feb4c0a98bddb1f2a172ea4b195ce31ba18d442
|
||||
|
||||
|
||||
1259
main/bt_app.c
1259
main/bt_app.c
File diff suppressed because it is too large
Load Diff
31
main/gpio.h
31
main/gpio.h
@@ -1,4 +1,3 @@
|
||||
<<<<<<< HEAD
|
||||
#ifndef GPIO_H
|
||||
#define GPIO_H
|
||||
|
||||
@@ -27,34 +26,4 @@
|
||||
#define PIN_NUM_BK_LIGHT 5 // Backlight control pin, -1 if not used
|
||||
#endif
|
||||
|
||||
=======
|
||||
#ifndef GPIO_H
|
||||
#define GPIO_H
|
||||
|
||||
// Define keypad buttons
|
||||
#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
|
||||
|
||||
|
||||
// Define GPIO pins
|
||||
#ifdef DEVKIT
|
||||
#define PIN_NUM_MOSI 23 // SDA pin for LCD
|
||||
#define PIN_NUM_CLK 18 // SCL pin for LCD
|
||||
#define PIN_NUM_CS 2 // CS pin
|
||||
#define PIN_NUM_DC 12 // Data/Command pin (RS)
|
||||
#define PIN_NUM_RST 13 // Reset pin
|
||||
#define PIN_NUM_BK_LIGHT -1 // Backlight control pin, -1 if not used
|
||||
#else
|
||||
#define PIN_NUM_MOSI 23 // SDA pin for LCD
|
||||
#define PIN_NUM_CLK 18 // SCL pin for LCD
|
||||
#define PIN_NUM_CS 12 // CS pin
|
||||
#define PIN_NUM_DC 15 // Data/Command pin (RS)
|
||||
#define PIN_NUM_RST 13 // Reset pin
|
||||
#define PIN_NUM_BK_LIGHT 5 // Backlight control pin, -1 if not used
|
||||
#endif
|
||||
|
||||
>>>>>>> 4feb4c0a98bddb1f2a172ea4b195ce31ba18d442
|
||||
#endif
|
||||
621
main/gui.c
621
main/gui.c
@@ -1,4 +1,3 @@
|
||||
<<<<<<< HEAD
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
@@ -617,624 +616,4 @@ static void gui_task(void)
|
||||
|
||||
|
||||
|
||||
=======
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#include "esp_lcd_panel_io.h"
|
||||
#include "esp_lcd_panel_vendor.h"
|
||||
#include "esp_lcd_panel_ops.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/spi_master.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_timer.h"
|
||||
#include "lvgl.h"
|
||||
#include "esp_lvgl_port.h"
|
||||
|
||||
#include "gui.h"
|
||||
#include "gpio.h"
|
||||
#include "keypad.h"
|
||||
#include "bubble.h"
|
||||
#include "system.h"
|
||||
|
||||
#define DEVKIT
|
||||
#undef DEVKIT
|
||||
|
||||
static const char *TAG = "gui";
|
||||
|
||||
#define UNLOCK() lvgl_port_unlock()
|
||||
#define LOCK() lvgl_port_lock(0)
|
||||
|
||||
// LCD Pin Configuration
|
||||
#define LCD_PIXEL_CLOCK_HZ (5 * 1000 * 1000)
|
||||
#define LCD_SPI_HOST SPI2_HOST
|
||||
|
||||
#define PIN_NUM_nON 26
|
||||
|
||||
|
||||
|
||||
// ST7735S properties
|
||||
#define LCD_H_RES 160
|
||||
#define LCD_V_RES 80
|
||||
#define LCD_CMD_BITS 8
|
||||
#define LCD_PARAM_BITS 8
|
||||
#define LCD_COLOR_SPACE ESP_LCD_COLOR_SPACE_RGB
|
||||
#define LCD_BITS_PER_PIXEL 16
|
||||
|
||||
static esp_lcd_panel_handle_t panel_handle = NULL;
|
||||
esp_lcd_panel_io_handle_t io_handle = NULL;
|
||||
static lv_disp_t *disp = NULL;
|
||||
static lv_obj_t *imu_label = NULL; // Label for IMU data
|
||||
|
||||
static lv_style_t style_mono8;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int selected;
|
||||
int count;
|
||||
lv_obj_t *obj;
|
||||
} menu_context_t;
|
||||
|
||||
static void gui_task(void);
|
||||
static void createBubble(lv_obj_t * scr);
|
||||
static void build_scrollable_menu(void);
|
||||
static void currentFocusIndex(menu_context_t *ctx);
|
||||
|
||||
#define MAX_ITEMS 10
|
||||
#define VISIBLE_ITEMS 3
|
||||
#define MENU_MAX_STRING_LENGTH 30
|
||||
|
||||
static const char *menu_items[MAX_ITEMS] = {
|
||||
"V-Moda Crossfade", "Item 2", "Item 3", "Item 4",
|
||||
"Item 5", "Item 6", "Item 7", "Item 8",
|
||||
"Item 9", "Item 10"
|
||||
};
|
||||
|
||||
static lv_obj_t *list;
|
||||
static lv_obj_t *buttons[MAX_ITEMS];
|
||||
static int selected_index = 0;
|
||||
static lv_obj_t *_bubble = NULL;
|
||||
static lv_obj_t * _menu = NULL;
|
||||
static lv_obj_t *_currentPage = NULL;
|
||||
|
||||
static GuiMode_t _mode = GUI_BUBBLE;
|
||||
|
||||
/* 1. Prepare a default (unfocused) style */
|
||||
static lv_style_t _styleUnfocusedBtn;
|
||||
|
||||
|
||||
/* 2. Prepare a focus style */
|
||||
static lv_style_t _styleFocusedBtn;
|
||||
|
||||
static menu_context_t _menuContext;
|
||||
|
||||
static bool notify_lvgl_flush_ready(void *user_ctx) {
|
||||
if (disp) {
|
||||
lv_display_flush_ready(disp);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static void create_lvgl_demo(void)
|
||||
{
|
||||
|
||||
lvgl_port_lock(0);
|
||||
// Create a screen with black background
|
||||
lv_obj_t *scr = lv_scr_act();
|
||||
|
||||
createBubble(scr);
|
||||
//build_scrollable_menu();
|
||||
|
||||
lvgl_port_unlock();
|
||||
|
||||
|
||||
}
|
||||
|
||||
static void lcd_init(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "Initialize SPI bus");
|
||||
spi_bus_config_t buscfg = {
|
||||
.sclk_io_num = PIN_NUM_CLK,
|
||||
.mosi_io_num = PIN_NUM_MOSI,
|
||||
.miso_io_num = -1,
|
||||
.quadwp_io_num = -1,
|
||||
.quadhd_io_num = -1,
|
||||
.max_transfer_sz = LCD_H_RES * LCD_V_RES * 2
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(LCD_SPI_HOST, &buscfg, SPI_DMA_CH_AUTO));
|
||||
|
||||
ESP_LOGI(TAG, "Install panel IO");
|
||||
|
||||
esp_lcd_panel_io_spi_config_t io_config = {
|
||||
.dc_gpio_num = PIN_NUM_DC,
|
||||
.cs_gpio_num = PIN_NUM_CS,
|
||||
.pclk_hz = LCD_PIXEL_CLOCK_HZ,
|
||||
.lcd_cmd_bits = LCD_CMD_BITS,
|
||||
.lcd_param_bits = LCD_PARAM_BITS,
|
||||
.spi_mode = 3,
|
||||
.trans_queue_depth = 10,
|
||||
.user_ctx = NULL,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)LCD_SPI_HOST, &io_config, &io_handle));
|
||||
|
||||
esp_lcd_panel_dev_config_t panel_config = {
|
||||
.reset_gpio_num = PIN_NUM_RST,
|
||||
.rgb_endian = LCD_RGB_ENDIAN_BGR,
|
||||
.bits_per_pixel = LCD_BITS_PER_PIXEL,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(io_handle, &panel_config, &panel_handle));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_invert_color(panel_handle, true));
|
||||
|
||||
|
||||
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_set_gap(panel_handle, 1, 26)); // ST7735S typically needs these offsets
|
||||
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true));
|
||||
}
|
||||
|
||||
static void lvgl_init(void)
|
||||
{
|
||||
lv_init();
|
||||
|
||||
|
||||
#if 1
|
||||
const lvgl_port_cfg_t lvgl_cfg = {
|
||||
.task_priority = 4, // LVGL task priority
|
||||
.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
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK(lvgl_port_init(&lvgl_cfg));
|
||||
#endif
|
||||
|
||||
const lvgl_port_display_cfg_t disp_cfg = {
|
||||
.io_handle = io_handle,
|
||||
.panel_handle = panel_handle,
|
||||
.buffer_size = LCD_H_RES * LCD_V_RES * 2,
|
||||
.double_buffer = false,
|
||||
.hres = LCD_H_RES,
|
||||
.vres = LCD_V_RES,
|
||||
.monochrome = false,
|
||||
.rotation = {
|
||||
.swap_xy = true,
|
||||
.mirror_x = true,
|
||||
.mirror_y = false,
|
||||
},
|
||||
.flags = {
|
||||
//.buff_dma = true,
|
||||
.swap_bytes = true,
|
||||
}
|
||||
};
|
||||
|
||||
disp = lvgl_port_add_disp(&disp_cfg);
|
||||
//lv_display_set_color_format(disp, LV_COLOR_FORMAT_RGB565);
|
||||
|
||||
|
||||
}
|
||||
|
||||
static void createBubble(lv_obj_t * scr)
|
||||
{
|
||||
|
||||
// 2) Create a bubble level of size 200×60, with range [−30°, +30°], initial 0°:
|
||||
lv_obj_t * level = bubble_create(scr, 150, 40, -10.0f, +10.0f, 0.0f);
|
||||
lv_obj_align(level, LV_ALIGN_CENTER, 0, 0);
|
||||
|
||||
// 3) … Later, when you read your accelerometer or keypad‐derived angle …
|
||||
float new_angle = 10.0f;
|
||||
bubble_setValue(level, new_angle);
|
||||
|
||||
// 4) You can call bubble_level_set_value(level, …) as often as you like.
|
||||
// Each call invalidates the object and LVGL will call the draw callback
|
||||
// (usually on the next tick, or immediately if LVGL is idle).
|
||||
|
||||
_bubble = level;
|
||||
}
|
||||
|
||||
|
||||
void gui_start(void)
|
||||
{
|
||||
|
||||
// Initialize LCD
|
||||
lcd_init();
|
||||
|
||||
// Initialize LVGL
|
||||
lvgl_init();
|
||||
|
||||
// Create UI
|
||||
create_lvgl_demo();
|
||||
|
||||
keypad_start();
|
||||
|
||||
gpio_set_level(PIN_NUM_BK_LIGHT, 1);
|
||||
|
||||
xTaskCreate(gui_task, "gui_task", 4096, NULL, 5, NULL);
|
||||
|
||||
}
|
||||
|
||||
static uint32_t waitForKeyPress(void)
|
||||
{
|
||||
QueueHandle_t q = keypad_getQueue();
|
||||
uint32_t ev = 0;
|
||||
|
||||
if (xQueueReceive(q, &ev, portMAX_DELAY) == pdTRUE)
|
||||
{
|
||||
return ev;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void handleMainMenu(void)
|
||||
{
|
||||
lvgl_port_lock(0);
|
||||
// Create a screen with black background
|
||||
lv_obj_t *scr = lv_scr_act();
|
||||
|
||||
//create_menu(scr);
|
||||
|
||||
lvgl_port_unlock();
|
||||
}
|
||||
|
||||
|
||||
// ───── MENU CONFIG ─────
|
||||
#define ROW_H 20 // height of each row
|
||||
static const char * items[] = { // your menu entries
|
||||
"VMode Crossmade",
|
||||
"Second Choice",
|
||||
"Another Option",
|
||||
"Yet Another",
|
||||
"Yet Another",
|
||||
"Last One"
|
||||
};
|
||||
#define ITEM_COUNT (sizeof(items)/sizeof(items[0]))
|
||||
|
||||
// ───── STATE & HELPERS ─────
|
||||
static lv_obj_t * btn_array[ITEM_COUNT];
|
||||
static int selected_idx = 0;
|
||||
|
||||
// Called whenever a button is “activated” (Enter/Click)
|
||||
static void btn_click_cb(lv_event_t * e) {
|
||||
lv_obj_t * btn = lv_event_get_target(e);
|
||||
const char * txt = lv_label_get_text(lv_obj_get_child(btn, 0));
|
||||
ESP_LOGI(TAG, "Activated: %s\n", txt);
|
||||
}
|
||||
|
||||
// Repaint all rows so only btn_array[selected_idx] is highlighted
|
||||
static void refresh_highlight(void) {
|
||||
|
||||
return;
|
||||
lvgl_port_lock(0);
|
||||
|
||||
int index = 0;
|
||||
|
||||
lv_obj_t *page = _currentPage;
|
||||
|
||||
lv_obj_t * child = NULL;
|
||||
lv_obj_t * next = lv_obj_get_child(page, index);
|
||||
lv_obj_t * selected = NULL;
|
||||
while(next) {
|
||||
child = next;
|
||||
|
||||
ESP_LOGI(TAG, "Child: %p", child);
|
||||
|
||||
|
||||
if (lv_obj_has_flag(child, LV_OBJ_FLAG_USER_1))
|
||||
{
|
||||
lv_obj_set_style_bg_color(child, lv_color_hex(0xFF8800), 0);
|
||||
lv_obj_set_style_text_color(lv_obj_get_child(child,0),
|
||||
lv_color_white(), 0);
|
||||
|
||||
selected = child;
|
||||
ESP_LOGI(TAG, "Selected");
|
||||
}
|
||||
else
|
||||
{
|
||||
lv_obj_set_style_bg_color(child, lv_color_white(), 0);
|
||||
lv_obj_set_style_text_color(lv_obj_get_child(child,0),
|
||||
lv_color_black(), 0);
|
||||
}
|
||||
|
||||
index++;
|
||||
next = lv_obj_get_child(page, index);
|
||||
}
|
||||
|
||||
if (selected)
|
||||
{
|
||||
lv_obj_scroll_to_view(selected, LV_ANIM_ON);
|
||||
}
|
||||
|
||||
lvgl_port_unlock();
|
||||
}
|
||||
|
||||
|
||||
static void menuInc(int inc)
|
||||
{
|
||||
LOCK();
|
||||
|
||||
currentFocusIndex(&_menuContext);
|
||||
|
||||
ESP_LOGI(TAG, "Current Index: %d", _menuContext.selected);
|
||||
|
||||
lv_obj_t *next = NULL;
|
||||
|
||||
// check if we are at the first or last in the page
|
||||
lv_obj_t *test = lv_obj_get_child(_currentPage, (inc > 0 ? -1 : 0));
|
||||
|
||||
if (_menuContext.obj != test)
|
||||
{
|
||||
next = lv_obj_get_child(_currentPage, _menuContext.selected + inc);
|
||||
lv_obj_add_state(next, LV_STATE_FOCUSED);
|
||||
lv_obj_clear_state(_menuContext.obj, LV_STATE_FOCUSED);
|
||||
lv_obj_scroll_to_view(next, LV_ANIM_ON);
|
||||
|
||||
_menuContext.obj = next;
|
||||
_menuContext.selected += inc;
|
||||
}
|
||||
|
||||
UNLOCK();
|
||||
}
|
||||
|
||||
static void menuNext(void)
|
||||
{
|
||||
menuInc(1);
|
||||
}
|
||||
|
||||
|
||||
static void menuPrevious(void)
|
||||
{
|
||||
menuInc(-1);
|
||||
}
|
||||
|
||||
// Fire the “clicked” event on the selected row
|
||||
static void activate_selected(void)
|
||||
{
|
||||
LOCK();
|
||||
lv_obj_send_event(_menuContext.obj, LV_EVENT_CLICKED, NULL);
|
||||
UNLOCK();
|
||||
}
|
||||
|
||||
static lv_obj_t * addMenuItem(lv_obj_t *page, const char *text)
|
||||
{
|
||||
lv_obj_t * btn = lv_btn_create(page);
|
||||
lv_obj_set_size(btn, LV_PCT(100), ROW_H);
|
||||
|
||||
|
||||
lv_obj_add_style(btn, &_styleUnfocusedBtn, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||
lv_obj_add_style(btn, &_styleFocusedBtn, LV_PART_MAIN | LV_STATE_FOCUSED);
|
||||
|
||||
lv_obj_add_state(btn, LV_STATE_DEFAULT);
|
||||
|
||||
|
||||
// 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, text);
|
||||
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);
|
||||
|
||||
// click callback
|
||||
lv_obj_add_event_cb(btn, btn_click_cb, LV_EVENT_CLICKED, NULL);
|
||||
|
||||
return btn;
|
||||
}
|
||||
|
||||
static int getSelectedIndex(lv_obj_t *page)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void currentFocusIndex(menu_context_t *ctx)
|
||||
{
|
||||
ctx->count = lv_obj_get_child_cnt(_currentPage);
|
||||
ctx->obj = NULL;
|
||||
ctx->selected = -1;
|
||||
|
||||
// return the index of the currently focused object
|
||||
for(int i = 0; i < ctx->count; i++) {
|
||||
lv_obj_t * child = lv_obj_get_child(_currentPage, i);
|
||||
|
||||
if (lv_obj_has_state(child, LV_STATE_FOCUSED))
|
||||
{
|
||||
ctx->obj = child;
|
||||
ctx->selected = i;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
// ───── BUILD THE MENU ─────
|
||||
static void build_scrollable_menu(void) {
|
||||
|
||||
|
||||
lv_style_init(&_styleFocusedBtn);
|
||||
lv_style_init(&_styleUnfocusedBtn);
|
||||
|
||||
lv_style_set_bg_color(&_styleUnfocusedBtn, lv_color_make(0xff,0xff,0xff)); // gray bg
|
||||
lv_style_set_text_color(&_styleUnfocusedBtn, lv_color_hex(0xFF8800));
|
||||
|
||||
lv_style_set_bg_color(&_styleFocusedBtn, lv_color_make(0x33,0x99,0xFF)); // blue bg
|
||||
lv_style_set_text_color(&_styleUnfocusedBtn,lv_color_black());
|
||||
|
||||
|
||||
// 2) Inside it, create the lv_menu and hide its sidebar/header
|
||||
lv_obj_t *menu = lv_menu_create(lv_scr_act());
|
||||
_menu = menu;
|
||||
|
||||
lv_obj_set_style_radius(menu, 0, LV_PART_MAIN | LV_STATE_ANY);
|
||||
lv_obj_set_style_border_width(menu, 0, LV_PART_MAIN | LV_STATE_ANY);
|
||||
lv_obj_set_size(menu, lv_pct(100), lv_pct(100));
|
||||
lv_obj_center(menu);
|
||||
|
||||
lv_obj_set_scrollbar_mode(menu, LV_SCROLLBAR_MODE_AUTO);
|
||||
|
||||
|
||||
lv_obj_t * main = lv_menu_page_create(menu, NULL);
|
||||
lv_obj_set_style_radius(main, 0, LV_PART_MAIN | LV_STATE_ANY);
|
||||
lv_obj_set_style_border_width(main, 0, LV_PART_MAIN | LV_STATE_ANY);
|
||||
lv_obj_set_scrollbar_mode(main, LV_SCROLLBAR_MODE_AUTO);
|
||||
lv_obj_set_size(main, lv_pct(100), lv_pct(100));
|
||||
|
||||
lv_menu_set_page(menu, main);
|
||||
|
||||
lv_obj_t * tmpObj;
|
||||
|
||||
|
||||
|
||||
lv_obj_t * calMenu = lv_menu_page_create(menu, NULL);
|
||||
lv_obj_set_style_radius(calMenu, 0, LV_PART_MAIN | LV_STATE_ANY);
|
||||
lv_obj_set_style_border_width(calMenu, 0, LV_PART_MAIN | LV_STATE_ANY);
|
||||
lv_obj_set_scrollbar_mode(calMenu, LV_SCROLLBAR_MODE_AUTO);
|
||||
|
||||
tmpObj = addMenuItem(main, "Bluetooth");
|
||||
lv_obj_add_state(tmpObj, LV_STATE_FOCUSED);
|
||||
//lv_obj_add_flag(tmpObj, LV_OBJ_FLAG_USER_1);
|
||||
|
||||
tmpObj = addMenuItem(main, "Calibration");
|
||||
lv_menu_set_load_page_event(menu, tmpObj, calMenu);
|
||||
|
||||
|
||||
tmpObj = addMenuItem(main, "Volume");
|
||||
|
||||
addMenuItem(main, "About");
|
||||
addMenuItem(main, "Exit");
|
||||
|
||||
|
||||
addMenuItem(calMenu, "Calibrate Level");
|
||||
addMenuItem(calMenu, "Reset Calibration");
|
||||
addMenuItem(calMenu, "Exit");
|
||||
|
||||
_currentPage = main;
|
||||
|
||||
// 6) Initial highlight
|
||||
selected_idx = 0;
|
||||
refresh_highlight();
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void gui_task(void)
|
||||
{
|
||||
system_subscribe(xTaskGetCurrentTaskHandle());
|
||||
|
||||
// Grab queue handle
|
||||
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);
|
||||
UNLOCK();
|
||||
|
||||
while (1)
|
||||
{
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
menuNext();
|
||||
}
|
||||
ESP_LOGI(TAG, "MAIN: Button 1 SHORT");
|
||||
break;
|
||||
case (KEY0 << KEY_LONG_PRESS):
|
||||
{
|
||||
|
||||
|
||||
if (_mode != GUI_MENU)
|
||||
{
|
||||
_mode = GUI_MENU;
|
||||
lv_obj_remove_flag(_menu, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_add_flag(_bubble, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
else
|
||||
if (_mode == GUI_MENU)
|
||||
{
|
||||
activate_selected();
|
||||
_mode = GUI_BUBBLE;
|
||||
// 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)
|
||||
{
|
||||
menuPrevious();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case (KEY1 << KEY_LONG_PRESS):
|
||||
ESP_LOGI(TAG, "MAIN: Button 2 LONG");
|
||||
gpio_set_level(PIN_NUM_nON, 0);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (_mode == GUI_BUBBLE)
|
||||
{
|
||||
uint32_t notifiedBits = 0;
|
||||
// clear on entry (first param), wait for any bit, block forever
|
||||
xTaskNotifyWait(
|
||||
0xFFFFFFFF, // clear any old bits on entry
|
||||
0xFFFFFFFF, // clear bits on exit
|
||||
¬ifiedBits,
|
||||
pdMS_TO_TICKS(100));
|
||||
|
||||
if (notifiedBits & EM_EVENT_NEW_DATA)
|
||||
{
|
||||
ImuData_t d = system_getImuData();
|
||||
bubble_setValue(_bubble, -d.angle);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
>>>>>>> 4feb4c0a98bddb1f2a172ea4b195ce31ba18d442
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
<<<<<<< HEAD
|
||||
#ifndef _KEYPAD_H
|
||||
#define _KEYPAD_H
|
||||
|
||||
@@ -21,28 +20,4 @@ typedef enum
|
||||
void keypad_start(void);
|
||||
QueueHandle_t keypad_getQueue(void);
|
||||
|
||||
=======
|
||||
#ifndef _KEYPAD_H
|
||||
#define _KEYPAD_H
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/queue.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
KEY0 = (1 << 0),
|
||||
KEY1 = (1 << 1),
|
||||
} keycode_t;
|
||||
|
||||
|
||||
#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);
|
||||
|
||||
>>>>>>> 4feb4c0a98bddb1f2a172ea4b195ce31ba18d442
|
||||
#endif
|
||||
325
main/main.c
325
main/main.c
@@ -1,4 +1,3 @@
|
||||
<<<<<<< HEAD
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
@@ -40,6 +39,31 @@ typedef struct {
|
||||
float prev_output; // y[n-1]
|
||||
} LowPassFilter;
|
||||
|
||||
#define ALPHA_MIN 0.2f
|
||||
#define ALPHA_MAX 0.4f
|
||||
|
||||
// Clamp function to bound value between min and max
|
||||
double clamp(double value, double min, double max) {
|
||||
if (value < min) return min;
|
||||
if (value > max) return max;
|
||||
return value;
|
||||
}
|
||||
|
||||
// Compute alpha using linear ramp
|
||||
float compute_alpha_linear(double x, float alpha_min, float alpha_max, float threshold) {
|
||||
float abs_x = fabs(x);
|
||||
float t = clamp(abs_x / threshold, 0.0, 1.0); // Normalize |x| to [0,1]
|
||||
return alpha_min + (alpha_max - alpha_min) * t;
|
||||
}
|
||||
|
||||
// Compute sigmoid-based dynamic alpha
|
||||
float compute_alpha_sigmoid(float x, float alpha_min, float alpha_max, float k, float midpoint) {
|
||||
float abs_x = fabs(x);
|
||||
float exponent = -k * (abs_x - midpoint);
|
||||
float sigmoid = 1.0 / (1.0 + exp(exponent));
|
||||
return alpha_min + (alpha_max - alpha_min) * sigmoid;
|
||||
}
|
||||
|
||||
// Initialize the filter. alpha = smoothing factor.
|
||||
// e.g. alpha = dt/(RC+dt) if you derive from cutoff freq & sample time.
|
||||
// init_output can be 0 or your first sample to avoid startup glitch.
|
||||
@@ -51,7 +75,11 @@ static inline void LPF_Init(LowPassFilter *f, float alpha, float init_output) {
|
||||
// Run one input sample through the filter.
|
||||
// Returns y[n] = alpha * x[n] + (1-alpha) * y[n-1].
|
||||
static inline float LPF_Update(LowPassFilter *f, float input) {
|
||||
float out = f->alpha * input + (1.0f - f->alpha) * f->prev_output;
|
||||
|
||||
//float alpha = compute_alpha_sigmoid(input, ALPHA_MIN, ALPHA_MAX, 1.0f, 0.0f);
|
||||
float alpha = compute_alpha_linear(input, ALPHA_MIN, ALPHA_MAX, 2.0f);
|
||||
float out = alpha * input + (1.0f - alpha) * f->prev_output;
|
||||
//float out = f->alpha * input + (1.0f - f->alpha) * f->prev_output;
|
||||
f->prev_output = out;
|
||||
return out;
|
||||
}
|
||||
@@ -290,296 +318,3 @@ void app_main(void)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
=======
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include "math.h"
|
||||
|
||||
#include "esp_system.h"
|
||||
#include "esp_log.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/timers.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "nvs.h"
|
||||
#include "nvs_flash.h"
|
||||
|
||||
|
||||
#include "bt_app.h"
|
||||
#include "lsm6dsv.h"
|
||||
#include "gui.h"
|
||||
#include "gpio.h"
|
||||
#include "keypad.h"
|
||||
#include "system.h"
|
||||
|
||||
|
||||
|
||||
|
||||
/*********************************
|
||||
* STATIC FUNCTION DECLARATIONS
|
||||
********************************/
|
||||
typedef struct {
|
||||
float alpha; // smoothing factor, 0<alpha<1
|
||||
float prev_output; // y[n-1]
|
||||
} LowPassFilter;
|
||||
|
||||
// Initialize the filter. alpha = smoothing factor.
|
||||
// e.g. alpha = dt/(RC+dt) if you derive from cutoff freq & sample time.
|
||||
// init_output can be 0 or your first sample to avoid startup glitch.
|
||||
static inline void LPF_Init(LowPassFilter *f, float alpha, float init_output) {
|
||||
f->alpha = alpha;
|
||||
f->prev_output = init_output;
|
||||
}
|
||||
|
||||
// Run one input sample through the filter.
|
||||
// Returns y[n] = alpha * x[n] + (1-alpha) * y[n-1].
|
||||
static inline float LPF_Update(LowPassFilter *f, float input) {
|
||||
float out = f->alpha * input + (1.0f - f->alpha) * f->prev_output;
|
||||
f->prev_output = out;
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
/*********************************
|
||||
* STATIC VARIABLE DEFINITIONS
|
||||
********************************/
|
||||
static const char *TAG = "main";
|
||||
|
||||
/*********************************
|
||||
* STATIC FUNCTION DEFINITIONS
|
||||
********************************/
|
||||
|
||||
static void init_gpio(void)
|
||||
{
|
||||
gpio_config_t io_conf;
|
||||
|
||||
|
||||
// Configure output GPIO
|
||||
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);
|
||||
|
||||
|
||||
|
||||
|
||||
#if 1
|
||||
// Configure output power signal
|
||||
gpio_set_level(PIN_NUM_nON, 1);
|
||||
|
||||
io_conf.pin_bit_mask = (1ULL << PIN_NUM_nON);
|
||||
io_conf.mode = GPIO_MODE_OUTPUT;
|
||||
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
|
||||
|
||||
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// IMU task to read sensor data
|
||||
static void imu_task(void *pvParameters) {
|
||||
lsm6dsv_data_t imu_data;
|
||||
char data_str[128];
|
||||
|
||||
float roll, pitch, yaw;
|
||||
lsm6dsv_fifo_t fifo;
|
||||
|
||||
ImuData_t imu;
|
||||
|
||||
LowPassFilter lpf;
|
||||
LPF_Init(&lpf, FILTER_COEFF, 0);
|
||||
|
||||
while (1) {
|
||||
|
||||
// uint8_t samples = lsm6dsv_fifo_ready();
|
||||
|
||||
//ESP_LOGI(TAG, "Samples: %d", samples);
|
||||
// while (samples)
|
||||
// {
|
||||
// lsm6dsv_fifo_read(&fifo);
|
||||
|
||||
|
||||
|
||||
// // snprintf(data_str, sizeof(data_str),
|
||||
// // "tag: %d, count: %d, (%d, %d, %d)",
|
||||
// // fifo.tag, fifo.count, x, y, z);
|
||||
|
||||
// // ESP_LOGI(TAG, "%s", data_str);
|
||||
|
||||
// samples--;
|
||||
// }
|
||||
|
||||
// lsm6dsv_getAttitude(&fifo, &roll, &pitch, &yaw);
|
||||
|
||||
// snprintf(data_str, sizeof(data_str),
|
||||
// "r: %0.3f, p: %0.3f, y: %0.3f",
|
||||
// roll, pitch, yaw);
|
||||
|
||||
// ESP_LOGI(TAG, "%s", data_str);
|
||||
|
||||
float xz;
|
||||
float yz;
|
||||
float xy;
|
||||
|
||||
#if 1
|
||||
if (lsm6dsv_read_data(&imu_data) == ESP_OK)
|
||||
{
|
||||
// snprintf(data_str, sizeof(data_str),
|
||||
// "Acc: %.2f, %.2f, %.2f; "
|
||||
// "Gyro: %.2f, %.2f, %.2f (%d)\n",
|
||||
// imu_data.acc_x, imu_data.acc_y, imu_data.acc_z,
|
||||
// imu_data.gyro_x, imu_data.gyro_y, imu_data.gyro_z, lsm6dsv_fifo_ready());
|
||||
|
||||
|
||||
|
||||
|
||||
#if 1
|
||||
imu.raw[ANGLE_XZ] = atan2f((float)imu_data.acc_z, (float)imu_data.acc_x) * 180 / M_PI;
|
||||
imu.raw[ANGLE_YZ] = atan2f((float)imu_data.acc_z, (float)imu_data.acc_y) * 180 / M_PI;
|
||||
imu.raw[ANGLE_XY] = atan2f((float)imu_data.acc_x, (float)imu_data.acc_y) * 180 / M_PI;
|
||||
|
||||
|
||||
float angle;
|
||||
|
||||
|
||||
angle = system_getAngle();
|
||||
|
||||
if (angle > MAX_INDICATION_ANGLE)
|
||||
{
|
||||
angle = MAX_INDICATION_ANGLE;
|
||||
}
|
||||
else
|
||||
if (angle < -MAX_INDICATION_ANGLE)
|
||||
{
|
||||
angle = -MAX_INDICATION_ANGLE;
|
||||
}
|
||||
|
||||
// low pass filter the angle measurement
|
||||
imu.angle = LPF_Update(&lpf, angle);
|
||||
|
||||
//imu.filtered[ANGLE_XY] = LPF_Update(&lpf, imu.raw[ANGLE_XY]);
|
||||
|
||||
system_setImuData(imu);
|
||||
|
||||
// snprintf(data_str, sizeof(data_str),
|
||||
// "(%.2f, %.2f, %.2f)", xy, yz, xy);
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
snprintf(data_str, sizeof(data_str),
|
||||
"(%.1f, %.1f, %.1f) (%.2f, %.2f, %.2f)",
|
||||
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
|
||||
// Update label text in LVGL task
|
||||
//lv_label_set_text(imu_label, data_str);
|
||||
|
||||
}
|
||||
#endif
|
||||
vTaskDelay(pdMS_TO_TICKS(100)); // Update every 100ms
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************
|
||||
* MAIN ENTRY POINT
|
||||
********************************/
|
||||
|
||||
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);
|
||||
|
||||
init_gpio();
|
||||
|
||||
system_init();
|
||||
|
||||
|
||||
|
||||
// Initialize IMU
|
||||
ESP_ERROR_CHECK(lsm6dsv_init(22, 21)); // SCL = IO14, SDA = IO15
|
||||
|
||||
|
||||
|
||||
// Create IMU task
|
||||
TaskHandle_t h = xTaskCreate(imu_task, "imu_task", 4096, NULL, 5, NULL);
|
||||
|
||||
|
||||
|
||||
bt_app_init();
|
||||
|
||||
gui_start();
|
||||
|
||||
gpio_set_level(PIN_NUM_LED_2, 1);
|
||||
|
||||
|
||||
#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) {
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
#else
|
||||
while (1)
|
||||
{
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
>>>>>>> 4feb4c0a98bddb1f2a172ea4b195ce31ba18d442
|
||||
|
||||
171
main/system.c
171
main/system.c
@@ -1,4 +1,3 @@
|
||||
<<<<<<< HEAD
|
||||
#include "system.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
@@ -167,174 +166,4 @@ void system_notifyAll(uint32_t eventBits) {
|
||||
}
|
||||
xSemaphoreGive(em->mutex);
|
||||
}
|
||||
=======
|
||||
#include "system.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
static SystemState_t _systemState;
|
||||
|
||||
static EventGroupHandle_t _systemEvent;
|
||||
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);
|
||||
|
||||
_systemState.imu = imu;
|
||||
|
||||
xSemaphoreGive(_eventManager.mutex);
|
||||
|
||||
//ESP_LOGI("g", "New IMU Data: %.2f", xy);
|
||||
|
||||
system_notifyAll(EM_EVENT_NEW_DATA);
|
||||
}
|
||||
|
||||
ImuData_t system_getImuData(void)
|
||||
{
|
||||
ImuData_t imu;
|
||||
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
|
||||
|
||||
imu = _systemState.imu;
|
||||
|
||||
xSemaphoreGive(_eventManager.mutex);
|
||||
|
||||
return imu;
|
||||
}
|
||||
|
||||
void system_waitForEvent(void)
|
||||
{
|
||||
}
|
||||
|
||||
SystemState_t *system_getState(void)
|
||||
{
|
||||
return &_systemState;
|
||||
}
|
||||
|
||||
|
||||
BaseType_t system_subscribe(TaskHandle_t task) {
|
||||
|
||||
EventManager_t *em = &_eventManager;
|
||||
|
||||
ESP_LOGI("g", "Subscribe: %p", task);
|
||||
if (xSemaphoreTake(em->mutex, portMAX_DELAY) == pdFALSE) {
|
||||
return pdFAIL;
|
||||
}
|
||||
if (em->count < EM_MAX_SUBSCRIBERS) {
|
||||
// avoid duplicates?
|
||||
ESP_LOGI("g", "PASS");
|
||||
em->subscribers[em->count++] = task;
|
||||
xSemaphoreGive(em->mutex);
|
||||
return pdPASS;
|
||||
}
|
||||
xSemaphoreGive(em->mutex);
|
||||
return pdFAIL; // full
|
||||
}
|
||||
|
||||
BaseType_t system_unsubscribe(TaskHandle_t task) {
|
||||
|
||||
EventManager_t *em = &_eventManager;
|
||||
|
||||
BaseType_t removed = pdFAIL;
|
||||
if (xSemaphoreTake(em->mutex, portMAX_DELAY) == pdTRUE) {
|
||||
for (size_t i = 0; i < em->count; ++i) {
|
||||
if (em->subscribers[i] == task) {
|
||||
// shift down
|
||||
for (size_t j = i; j + 1 < em->count; ++j)
|
||||
em->subscribers[j] = em->subscribers[j+1];
|
||||
em->count--;
|
||||
removed = pdPASS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
xSemaphoreGive(em->mutex);
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
void system_notifyAll(uint32_t eventBits) {
|
||||
EventManager_t *em = &_eventManager;
|
||||
if (xSemaphoreTake(em->mutex, portMAX_DELAY) == pdTRUE) {
|
||||
for (size_t i = 0; i < em->count; ++i) {
|
||||
// set the bits in each task's notification value
|
||||
//ESP_LOGI("g", "Notify: %p", em->subscribers[i]);
|
||||
xTaskNotify(em->subscribers[i],
|
||||
eventBits,
|
||||
eSetBits);
|
||||
}
|
||||
xSemaphoreGive(em->mutex);
|
||||
}
|
||||
>>>>>>> 4feb4c0a98bddb1f2a172ea4b195ce31ba18d442
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
<<<<<<< HEAD
|
||||
#ifndef SYSTEM_H
|
||||
#define SYSTEM_H
|
||||
|
||||
@@ -37,8 +36,9 @@ typedef struct SystemState_s
|
||||
|
||||
|
||||
#define MAX_INDICATION_ANGLE 5.0f
|
||||
#define FILTER_COEFF 0.2f // 0 to 1 Smaller number is heavier filter
|
||||
#define FILTER_COEFF 0.4f // 0 to 1 Smaller number is heavier filter
|
||||
#define PRIMARY_AXIS ANGLE_YZ
|
||||
#define RIFLE_AXIS Y
|
||||
|
||||
#define EM_MAX_SUBSCRIBERS 8 // tweak as needed
|
||||
#define EM_EVENT_NEW_DATA (1UL<<0)
|
||||
@@ -73,80 +73,4 @@ BaseType_t system_unsubscribe(TaskHandle_t task);
|
||||
void system_notifyAll(uint32_t eventBits);
|
||||
|
||||
|
||||
=======
|
||||
#ifndef SYSTEM_H
|
||||
#define SYSTEM_H
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
|
||||
#define DISABLE_GUI
|
||||
|
||||
enum
|
||||
{
|
||||
ANGLE_XY = 0,
|
||||
ANGLE_XZ,
|
||||
ANGLE_YZ,
|
||||
};
|
||||
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float raw[3];
|
||||
float filtered[3];
|
||||
float angle;
|
||||
} ImuData_t;
|
||||
|
||||
typedef struct SystemState_s
|
||||
{
|
||||
ImuData_t imu;
|
||||
|
||||
EventGroupHandle_t event;
|
||||
|
||||
float zeroAngle;
|
||||
int primaryAxis;
|
||||
|
||||
} SystemState_t;
|
||||
|
||||
|
||||
#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)
|
||||
#define EM_EVENT_ERROR (1UL<<1)
|
||||
// …add more event bit-masks here…
|
||||
|
||||
typedef struct {
|
||||
TaskHandle_t subscribers[EM_MAX_SUBSCRIBERS];
|
||||
size_t count;
|
||||
SemaphoreHandle_t mutex;
|
||||
} EventManager_t;
|
||||
|
||||
void system_init(void);
|
||||
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);
|
||||
|
||||
// Unsubscribe if you ever need
|
||||
BaseType_t system_unsubscribe(TaskHandle_t task);
|
||||
|
||||
// Notify all subscribers of one or more event bits
|
||||
void system_notifyAll(uint32_t eventBits);
|
||||
|
||||
|
||||
>>>>>>> 4feb4c0a98bddb1f2a172ea4b195ce31ba18d442
|
||||
#endif
|
||||
@@ -7,4 +7,4 @@ with open("project_settings.cmake", "w") as out:
|
||||
out.write(f'set(PROJECT_NAME "{cfg["project_name"]}")\n')
|
||||
out.write(f'set(CHIP "{cfg["chip"]}")\n')
|
||||
out.write(f'set(PORT "{cfg["port"]}")\n')
|
||||
out.write(f'set(BAUD "{cfg["baud"]}")\n')
|
||||
out.write(f'set(BAUD "{cfg["flash_baud"]}")\n')
|
||||
|
||||
4
project_settings.cmake
Normal file
4
project_settings.cmake
Normal file
@@ -0,0 +1,4 @@
|
||||
set(PROJECT_NAME "soundshot")
|
||||
set(CHIP "esp32")
|
||||
set(PORT "COM3")
|
||||
set(BAUD "460800")
|
||||
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"project_name": "soundshot",
|
||||
"chip": "esp32h2",
|
||||
"port": "COM8",
|
||||
"chip": "esp32",
|
||||
"port": "COM3",
|
||||
"monitor_baud": 115200,
|
||||
"flash_baud": 460800,
|
||||
"flash_mode": "dio",
|
||||
"flash_freq": "48m",
|
||||
"flash_freq": "40m",
|
||||
"flash_size": "2MB",
|
||||
"before": "default-reset",
|
||||
"after": "hard-reset"
|
||||
|
||||
Reference in New Issue
Block a user