增加了语音抽签控制屏幕显示
增加了校准和财位控制电机旋转
This commit is contained in:
@@ -10,6 +10,7 @@ set(platform_srcs
|
||||
"src/runtime/platform_lcd_runtime.c"
|
||||
"src/platform_stepper_driver.c"
|
||||
"src/platform_digital_input_driver.c"
|
||||
"src/platform_io_effects.c"
|
||||
"src/lcd_direct.c"
|
||||
"src/lcd_direct_assets.c"
|
||||
"src/multimodal/audio_pipeline.c"
|
||||
@@ -27,6 +28,7 @@ set(platform_priv_requires
|
||||
esp_driver_gpio
|
||||
esp_driver_i2c
|
||||
esp_driver_i2s
|
||||
esp_driver_rmt
|
||||
esp_driver_spi
|
||||
esp_event
|
||||
esp_app_format
|
||||
|
||||
@@ -16,5 +16,6 @@ esp_err_t platform_stepper_driver_rotate_angle_with_accel(float angle,
|
||||
int timeout_ms);
|
||||
void platform_stepper_driver_power_off(void);
|
||||
void platform_power_hold_init(void);
|
||||
esp_err_t platform_io_effects_init(void);
|
||||
esp_err_t platform_digital_input_driver_configure(const platform_digital_input_config_t *config);
|
||||
bool platform_digital_input_driver_is_active(const platform_digital_input_config_t *config);
|
||||
|
||||
@@ -0,0 +1,313 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "platform_internal.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/rmt_tx.h"
|
||||
#include "esp_log.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#ifndef CONFIG_TQ_LOCAL_TASK_CORE
|
||||
#define CONFIG_TQ_LOCAL_TASK_CORE 1
|
||||
#endif
|
||||
|
||||
#if CONFIG_TQ_LOCAL_TASK_CORE < 0
|
||||
#define PLATFORM_IO_EFFECTS_TASK_CORE tskNO_AFFINITY
|
||||
#else
|
||||
#define PLATFORM_IO_EFFECTS_TASK_CORE ((BaseType_t)CONFIG_TQ_LOCAL_TASK_CORE)
|
||||
#endif
|
||||
|
||||
#define PLATFORM_RMT_GPIO GPIO_NUM_4
|
||||
#define PLATFORM_PULSE_GPIO GPIO_NUM_5
|
||||
|
||||
#define PLATFORM_PULSE_HIGH_MS 500
|
||||
#define PLATFORM_PULSE_LOW_MS 200
|
||||
|
||||
#define PLATFORM_RMT_LED_COUNT 22
|
||||
#define PLATFORM_RMT_LED_BYTES_PER_PIXEL 3
|
||||
#define PLATFORM_RMT_RESOLUTION_HZ 10000000
|
||||
#define PLATFORM_RMT_FRAME_MS 30
|
||||
#define PLATFORM_RMT_WAIT_DONE_MS 100
|
||||
#define PLATFORM_RMT_BRIGHTNESS_MIN 8
|
||||
#define PLATFORM_RMT_BRIGHTNESS_MAX 180
|
||||
|
||||
static const char *TAG = "platform_io_effects";
|
||||
|
||||
static TaskHandle_t s_pulse_task;
|
||||
static TaskHandle_t s_rmt_task;
|
||||
|
||||
static const rmt_symbol_word_t s_ws2812_zero = {
|
||||
.level0 = 1,
|
||||
.duration0 = PLATFORM_RMT_RESOLUTION_HZ / 10000000 * 3,
|
||||
.level1 = 0,
|
||||
.duration1 = PLATFORM_RMT_RESOLUTION_HZ / 10000000 * 9,
|
||||
};
|
||||
|
||||
static const rmt_symbol_word_t s_ws2812_one = {
|
||||
.level0 = 1,
|
||||
.duration0 = PLATFORM_RMT_RESOLUTION_HZ / 10000000 * 9,
|
||||
.level1 = 0,
|
||||
.duration1 = PLATFORM_RMT_RESOLUTION_HZ / 10000000 * 3,
|
||||
};
|
||||
|
||||
static const rmt_symbol_word_t s_ws2812_reset = {
|
||||
.level0 = 0,
|
||||
.duration0 = PLATFORM_RMT_RESOLUTION_HZ / 1000000 * 25,
|
||||
.level1 = 0,
|
||||
.duration1 = PLATFORM_RMT_RESOLUTION_HZ / 1000000 * 25,
|
||||
};
|
||||
|
||||
static size_t platform_ws2812_encoder_callback(const void *data,
|
||||
size_t data_size,
|
||||
size_t symbols_written,
|
||||
size_t symbols_free,
|
||||
rmt_symbol_word_t *symbols,
|
||||
bool *done,
|
||||
void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
|
||||
if (symbols_free < 8U) {
|
||||
return 0U;
|
||||
}
|
||||
|
||||
size_t data_pos = symbols_written / 8U;
|
||||
const uint8_t *data_bytes = (const uint8_t *)data;
|
||||
if (data_pos < data_size) {
|
||||
size_t symbol_pos = 0U;
|
||||
for (uint8_t bitmask = 0x80U; bitmask != 0U; bitmask >>= 1U) {
|
||||
symbols[symbol_pos++] =
|
||||
(data_bytes[data_pos] & bitmask) ? s_ws2812_one : s_ws2812_zero;
|
||||
}
|
||||
return symbol_pos;
|
||||
}
|
||||
|
||||
symbols[0] = s_ws2812_reset;
|
||||
*done = true;
|
||||
return 1U;
|
||||
}
|
||||
|
||||
static uint8_t scale_u8(uint8_t value, uint8_t scale)
|
||||
{
|
||||
return (uint8_t)(((uint16_t)value * (uint16_t)scale) / 255U);
|
||||
}
|
||||
|
||||
static void hsv_to_rgb(uint8_t hue, uint8_t value, uint8_t *red, uint8_t *green, uint8_t *blue)
|
||||
{
|
||||
uint8_t region = hue / 43U;
|
||||
uint8_t remainder = (uint8_t)((hue - (region * 43U)) * 6U);
|
||||
uint8_t p = 0U;
|
||||
uint8_t q = (uint8_t)(((uint16_t)value * (255U - remainder)) / 255U);
|
||||
uint8_t t = (uint8_t)(((uint16_t)value * remainder) / 255U);
|
||||
|
||||
switch (region) {
|
||||
case 0:
|
||||
*red = value;
|
||||
*green = t;
|
||||
*blue = p;
|
||||
break;
|
||||
case 1:
|
||||
*red = q;
|
||||
*green = value;
|
||||
*blue = p;
|
||||
break;
|
||||
case 2:
|
||||
*red = p;
|
||||
*green = value;
|
||||
*blue = t;
|
||||
break;
|
||||
case 3:
|
||||
*red = p;
|
||||
*green = q;
|
||||
*blue = value;
|
||||
break;
|
||||
case 4:
|
||||
*red = t;
|
||||
*green = p;
|
||||
*blue = value;
|
||||
break;
|
||||
default:
|
||||
*red = value;
|
||||
*green = p;
|
||||
*blue = q;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t breathing_brightness(uint16_t phase)
|
||||
{
|
||||
uint16_t wave = phase & 0x01FFU;
|
||||
if (wave > 255U) {
|
||||
wave = 511U - wave;
|
||||
}
|
||||
|
||||
return (uint8_t)(PLATFORM_RMT_BRIGHTNESS_MIN +
|
||||
((wave * (PLATFORM_RMT_BRIGHTNESS_MAX - PLATFORM_RMT_BRIGHTNESS_MIN)) / 255U));
|
||||
}
|
||||
|
||||
static void fill_breathing_pixels(uint8_t *pixels, size_t pixel_len, uint8_t hue_base, uint8_t brightness)
|
||||
{
|
||||
if (pixel_len < (PLATFORM_RMT_LED_COUNT * PLATFORM_RMT_LED_BYTES_PER_PIXEL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t led = 0; led < PLATFORM_RMT_LED_COUNT; ++led) {
|
||||
uint8_t red = 0U;
|
||||
uint8_t green = 0U;
|
||||
uint8_t blue = 0U;
|
||||
uint8_t hue = (uint8_t)(hue_base + ((led * 256U) / PLATFORM_RMT_LED_COUNT));
|
||||
hsv_to_rgb(hue, 255U, &red, &green, &blue);
|
||||
|
||||
pixels[(led * 3U) + 0U] = scale_u8(green, brightness);
|
||||
pixels[(led * 3U) + 1U] = scale_u8(red, brightness);
|
||||
pixels[(led * 3U) + 2U] = scale_u8(blue, brightness);
|
||||
}
|
||||
}
|
||||
|
||||
static void platform_pulse_task(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
|
||||
while (true) {
|
||||
gpio_set_level(PLATFORM_PULSE_GPIO, 1);
|
||||
vTaskDelay(pdMS_TO_TICKS(PLATFORM_PULSE_HIGH_MS));
|
||||
gpio_set_level(PLATFORM_PULSE_GPIO, 0);
|
||||
vTaskDelay(pdMS_TO_TICKS(PLATFORM_PULSE_LOW_MS));
|
||||
}
|
||||
}
|
||||
|
||||
static void platform_rmt_led_task(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
|
||||
uint8_t pixels[PLATFORM_RMT_LED_COUNT * PLATFORM_RMT_LED_BYTES_PER_PIXEL] = {0};
|
||||
rmt_channel_handle_t led_channel = NULL;
|
||||
rmt_encoder_handle_t led_encoder = NULL;
|
||||
|
||||
rmt_tx_channel_config_t tx_channel_config = {
|
||||
.gpio_num = PLATFORM_RMT_GPIO,
|
||||
.clk_src = RMT_CLK_SRC_DEFAULT,
|
||||
.resolution_hz = PLATFORM_RMT_RESOLUTION_HZ,
|
||||
.mem_block_symbols = 64,
|
||||
.trans_queue_depth = 4,
|
||||
.flags = {
|
||||
.invert_out = false,
|
||||
.with_dma = false,
|
||||
.io_loop_back = false,
|
||||
.io_od_mode = false,
|
||||
},
|
||||
};
|
||||
|
||||
esp_err_t err = rmt_new_tx_channel(&tx_channel_config, &led_channel);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Create RMT TX channel failed: %s", esp_err_to_name(err));
|
||||
s_rmt_task = NULL;
|
||||
vTaskDelete(NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
rmt_simple_encoder_config_t encoder_config = {
|
||||
.callback = platform_ws2812_encoder_callback,
|
||||
.min_chunk_size = 64,
|
||||
};
|
||||
err = rmt_new_simple_encoder(&encoder_config, &led_encoder);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Create RMT encoder failed: %s", esp_err_to_name(err));
|
||||
rmt_del_channel(led_channel);
|
||||
s_rmt_task = NULL;
|
||||
vTaskDelete(NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
err = rmt_enable(led_channel);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Enable RMT channel failed: %s", esp_err_to_name(err));
|
||||
rmt_del_encoder(led_encoder);
|
||||
rmt_del_channel(led_channel);
|
||||
s_rmt_task = NULL;
|
||||
vTaskDelete(NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "GPIO4 RMT breathing effect started for %u LEDs", (unsigned)PLATFORM_RMT_LED_COUNT);
|
||||
|
||||
rmt_transmit_config_t tx_config = {
|
||||
.loop_count = 0,
|
||||
};
|
||||
uint8_t hue_base = 0U;
|
||||
uint16_t phase = 0U;
|
||||
while (true) {
|
||||
fill_breathing_pixels(pixels, sizeof(pixels), hue_base, breathing_brightness(phase));
|
||||
|
||||
err = rmt_transmit(led_channel, led_encoder, pixels, sizeof(pixels), &tx_config);
|
||||
if (err == ESP_OK) {
|
||||
err = rmt_tx_wait_all_done(led_channel, pdMS_TO_TICKS(PLATFORM_RMT_WAIT_DONE_MS));
|
||||
}
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGW(TAG, "RMT LED frame failed: %s", esp_err_to_name(err));
|
||||
}
|
||||
|
||||
hue_base++;
|
||||
phase += 4U;
|
||||
vTaskDelay(pdMS_TO_TICKS(PLATFORM_RMT_FRAME_MS));
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t platform_io_effects_init(void)
|
||||
{
|
||||
gpio_config_t pulse_config = {
|
||||
.pin_bit_mask = BIT64(PLATFORM_PULSE_GPIO),
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
.pull_up_en = GPIO_PULLUP_DISABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE,
|
||||
};
|
||||
esp_err_t err = gpio_config(&pulse_config);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
gpio_set_level(PLATFORM_PULSE_GPIO, 0);
|
||||
|
||||
if (s_pulse_task == NULL) {
|
||||
BaseType_t created = xTaskCreatePinnedToCore(platform_pulse_task,
|
||||
"platform_pulse",
|
||||
2048,
|
||||
NULL,
|
||||
2,
|
||||
&s_pulse_task,
|
||||
PLATFORM_IO_EFFECTS_TASK_CORE);
|
||||
if (created != pdPASS) {
|
||||
s_pulse_task = NULL;
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
}
|
||||
|
||||
if (s_rmt_task == NULL) {
|
||||
BaseType_t created = xTaskCreatePinnedToCore(platform_rmt_led_task,
|
||||
"platform_rmt_led",
|
||||
4096,
|
||||
NULL,
|
||||
2,
|
||||
&s_rmt_task,
|
||||
PLATFORM_IO_EFFECTS_TASK_CORE);
|
||||
if (created != pdPASS) {
|
||||
s_rmt_task = NULL;
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG,
|
||||
"GPIO5 pulse output started (%ums high, %ums low); GPIO4 RMT task starting",
|
||||
(unsigned)PLATFORM_PULSE_HIGH_MS,
|
||||
(unsigned)PLATFORM_PULSE_LOW_MS);
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -118,6 +118,11 @@ esp_err_t platform_init(void)
|
||||
|
||||
platform_power_hold_init();
|
||||
|
||||
esp_err_t io_effects_err = platform_io_effects_init();
|
||||
if (io_effects_err != ESP_OK) {
|
||||
ESP_LOGW(TAG, "IO effects init failed: %s", esp_err_to_name(io_effects_err));
|
||||
}
|
||||
|
||||
#if CONFIG_TQ_STEPPER_ENABLE
|
||||
esp_err_t err = platform_stepper_driver_init();
|
||||
if (err != ESP_OK) {
|
||||
|
||||
Reference in New Issue
Block a user