This commit is contained in:
Clawdia
2026-08-11 22:33:36 +02:00
commit 6cf7455986
51 changed files with 50733 additions and 0 deletions
+6
View File
@@ -0,0 +1,6 @@
# This file was automatically generated for projects
# without default 'CMakeLists.txt' file.
FILE(GLOB_RECURSE app_sources ${CMAKE_SOURCE_DIR}/src/*.*)
idf_component_register(SRCS ${app_sources})
+126
View File
@@ -0,0 +1,126 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_check.h"
#include "led_strip_encoder.h"
static const char *TAG = "led_encoder";
typedef struct {
rmt_encoder_t base;
rmt_encoder_t *bytes_encoder;
rmt_encoder_t *copy_encoder;
int state;
rmt_symbol_word_t reset_code;
} rmt_led_strip_encoder_t;
RMT_ENCODER_FUNC_ATTR
static size_t rmt_encode_led_strip(rmt_encoder_t *encoder, rmt_channel_handle_t channel, const void *primary_data, size_t data_size, rmt_encode_state_t *ret_state)
{
rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base);
rmt_encoder_handle_t bytes_encoder = led_encoder->bytes_encoder;
rmt_encoder_handle_t copy_encoder = led_encoder->copy_encoder;
rmt_encode_state_t session_state = RMT_ENCODING_RESET;
rmt_encode_state_t state = RMT_ENCODING_RESET;
size_t encoded_symbols = 0;
switch (led_encoder->state) {
case 0: // send RGB data
encoded_symbols += bytes_encoder->encode(bytes_encoder, channel, primary_data, data_size, &session_state);
if (session_state & RMT_ENCODING_COMPLETE) {
led_encoder->state = 1; // switch to next state when current encoding session finished
}
if (session_state & RMT_ENCODING_MEM_FULL) {
state |= RMT_ENCODING_MEM_FULL;
goto out; // yield if there's no free space for encoding artifacts
}
// fall-through
case 1: // send reset code
encoded_symbols += copy_encoder->encode(copy_encoder, channel, &led_encoder->reset_code,
sizeof(led_encoder->reset_code), &session_state);
if (session_state & RMT_ENCODING_COMPLETE) {
led_encoder->state = RMT_ENCODING_RESET; // back to the initial encoding session
state |= RMT_ENCODING_COMPLETE;
}
if (session_state & RMT_ENCODING_MEM_FULL) {
state |= RMT_ENCODING_MEM_FULL;
goto out; // yield if there's no free space for encoding artifacts
}
}
out:
*ret_state = state;
return encoded_symbols;
}
static esp_err_t rmt_del_led_strip_encoder(rmt_encoder_t *encoder)
{
rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base);
rmt_del_encoder(led_encoder->bytes_encoder);
rmt_del_encoder(led_encoder->copy_encoder);
free(led_encoder);
return ESP_OK;
}
RMT_ENCODER_FUNC_ATTR
static esp_err_t rmt_led_strip_encoder_reset(rmt_encoder_t *encoder)
{
rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base);
rmt_encoder_reset(led_encoder->bytes_encoder);
rmt_encoder_reset(led_encoder->copy_encoder);
led_encoder->state = RMT_ENCODING_RESET;
return ESP_OK;
}
esp_err_t rmt_new_led_strip_encoder(const led_strip_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder)
{
esp_err_t ret = ESP_OK;
rmt_led_strip_encoder_t *led_encoder = NULL;
ESP_GOTO_ON_FALSE(config && ret_encoder, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
led_encoder = rmt_alloc_encoder_mem(sizeof(rmt_led_strip_encoder_t));
ESP_GOTO_ON_FALSE(led_encoder, ESP_ERR_NO_MEM, err, TAG, "no mem for led strip encoder");
led_encoder->base.encode = rmt_encode_led_strip;
led_encoder->base.del = rmt_del_led_strip_encoder;
led_encoder->base.reset = rmt_led_strip_encoder_reset;
// different led strip might have its own timing requirements, following parameter is for WS2812
rmt_bytes_encoder_config_t bytes_encoder_config = {
.bit0 = {
.level0 = 1,
.duration0 = 0.3 * config->resolution / 1000000, // T0H=0.3us
.level1 = 0,
.duration1 = 0.9 * config->resolution / 1000000, // T0L=0.9us
},
.bit1 = {
.level0 = 1,
.duration0 = 0.9 * config->resolution / 1000000, // T1H=0.9us
.level1 = 0,
.duration1 = 0.3 * config->resolution / 1000000, // T1L=0.3us
},
.flags.msb_first = 1 // WS2812 transfer bit order: G7...G0R7...R0B7...B0
};
ESP_GOTO_ON_ERROR(rmt_new_bytes_encoder(&bytes_encoder_config, &led_encoder->bytes_encoder), err, TAG, "create bytes encoder failed");
rmt_copy_encoder_config_t copy_encoder_config = {};
ESP_GOTO_ON_ERROR(rmt_new_copy_encoder(&copy_encoder_config, &led_encoder->copy_encoder), err, TAG, "create copy encoder failed");
uint32_t reset_ticks = config->resolution / 1000000 * 50 / 2; // reset code duration defaults to 50us
led_encoder->reset_code = (rmt_symbol_word_t) {
.level0 = 0,
.duration0 = reset_ticks,
.level1 = 0,
.duration1 = reset_ticks,
};
*ret_encoder = &led_encoder->base;
return ESP_OK;
err:
if (led_encoder) {
if (led_encoder->bytes_encoder) {
rmt_del_encoder(led_encoder->bytes_encoder);
}
if (led_encoder->copy_encoder) {
rmt_del_encoder(led_encoder->copy_encoder);
}
free(led_encoder);
}
return ret;
}
+36
View File
@@ -0,0 +1,36 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "driver/rmt_encoder.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Type of led strip encoder configuration
*/
typedef struct {
uint32_t resolution; /*!< Encoder resolution, in Hz */
} led_strip_encoder_config_t;
/**
* @brief Create RMT encoder for encoding LED strip pixels into RMT symbols
*
* @param[in] config Encoder configuration
* @param[out] ret_encoder Returned encoder handle
* @return
* - ESP_ERR_INVALID_ARG for any invalid arguments
* - ESP_ERR_NO_MEM out of memory when creating led strip encoder
* - ESP_OK if creating encoder successfully
*/
esp_err_t rmt_new_led_strip_encoder(const led_strip_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder);
#ifdef __cplusplus
}
#endif
+184
View File
@@ -0,0 +1,184 @@
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "driver/uart.h"
#include "driver/rmt_tx.h"
#include "led_strip_encoder.h"
#define RMT_LED_STRIP_RESOLUTION_HZ 10000000
#define LED_GPIO_NUM 6
#define LED_NUMBERS 30
static const char *TAG = "led-laser";
static uint8_t led_pixels[LED_NUMBERS * 3];
static rmt_channel_handle_t led_chan = NULL;
static rmt_encoder_handle_t led_encoder = NULL;
typedef struct {
const char *name;
int freq_hz;
int duration_min;
uint32_t hue;
} preset_t;
static const preset_t presets[] = {
{"Regeneration", 40, 60, 0},
{"Durchblutung", 60, 60, 15},
{"Tiefenwirkung",80,45, 5},
{"Gepulst Rot", 50, 60, 0},
{"Oberflächenlicht",30,45,20},
{"Muskeln/Gelenke",65,60,10},
{"Ganzkörper", 45, 90, 0}
};
#define PRESET_COUNT (sizeof(presets)/sizeof(presets[0]))
static int current_preset = -1;
static bool led_on = false;
static uint64_t last_toggle_ms = 0;
static void hsv2rgb(uint32_t h, uint32_t s, uint32_t v, uint32_t *r, uint32_t *g, uint32_t *b) {
h %= 360;
uint32_t rgb_max = v * 255 / 100;
uint32_t rgb_min = rgb_max * (100 - s) / 100;
uint32_t i = h / 60;
uint32_t diff = h % 60;
uint32_t adj = (rgb_max - rgb_min) * diff / 60;
switch(i){
case 0: *r=rgb_max; *g=rgb_min+adj; *b=rgb_min; break;
case 1: *r=rgb_max-adj; *g=rgb_max; *b=rgb_min; break;
case 2: *r=rgb_min; *g=rgb_max; *b=rgb_min+adj; break;
case 3: *r=rgb_min; *g=rgb_max-adj; *b=rgb_max; break;
case 4: *r=rgb_min+adj; *g=rgb_min; *b=rgb_max; break;
default:*r=rgb_max; *g=rgb_min; *b=rgb_max-adj; break;
}
}
static void set_all_pixels(uint32_t r, uint32_t g, uint32_t b) {
for(int i=0;i<LED_NUMBERS;i++){
led_pixels[i*3+0]= (uint8_t)g;
led_pixels[i*3+1]= (uint8_t)b;
led_pixels[i*3+2]= (uint8_t)r;
}
}
static void flush_leds(void){
rmt_transmit_config_t tx_cfg = { .loop_count = 0 };
ESP_ERROR_CHECK(rmt_transmit(led_chan, led_encoder, led_pixels, sizeof(led_pixels), &tx_cfg));
ESP_ERROR_CHECK(rmt_tx_wait_all_done(led_chan, portMAX_DELAY));
}
static void apply_preset(int idx){
if(idx<0 || idx>=PRESET_COUNT) return;
current_preset = idx;
const preset_t *p = &presets[idx];
uint32_t r,g,b;
hsv2rgb(p->hue, 100, 100, &r,&g,&b);
set_all_pixels(r,g,b);
led_on = true;
last_toggle_ms = esp_timer_get_time()/1000;
ESP_LOGI(TAG, "Preset %d %s %dHz", idx, p->name, p->freq_hz);
}
static void stop_leds(void){
current_preset = -1;
memset(led_pixels,0,sizeof(led_pixels));
flush_leds();
ESP_LOGI(TAG,"LEDs stopped");
}
static void list_presets(void){
printf("\n--- Presets ---\n");
for(int i=0;i<PRESET_COUNT;i++){
const preset_t *p=&presets[i];
printf("%d - %s %dHz %dmin\n", i, p->name, p->freq_hz, p->duration_min);
}
printf("Commands: 0-6 select, next, stop, list\n");
}
static void process_line(char *line){
if(strcmp(line,"stop")==0){ stop_leds(); return; }
if(strcmp(line,"next")==0){
int nxt = (current_preset+1)%PRESET_COUNT;
apply_preset(nxt);
return;
}
if(strcmp(line,"list")==0){ list_presets(); return; }
if(strlen(line)==1 && line[0]>='0' && line[0]<='6'){
int idx = line[0]-'0';
if(idx<PRESET_COUNT){ apply_preset(idx); return; }
}
printf("Unknown: %s\n", line);
}
void app_main(void){
ESP_LOGI(TAG,"LED Laser Frequenz start");
uart_config_t uart_cfg = {
.baud_rate = 115200,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE
};
ESP_ERROR_CHECK(uart_driver_install(UART_NUM_0, 1024,0,0,NULL,0));
ESP_ERROR_CHECK(uart_param_config(UART_NUM_0,&uart_cfg));
rmt_tx_channel_config_t tx_cfg = {
.clk_src = RMT_CLK_SRC_DEFAULT,
.gpio_num = LED_GPIO_NUM,
.mem_block_symbols = 64,
.resolution_hz = RMT_LED_STRIP_RESOLUTION_HZ,
.trans_queue_depth = 4
};
ESP_ERROR_CHECK(rmt_new_tx_channel(&tx_cfg,&led_chan));
led_strip_encoder_config_t enc_cfg = { .resolution = RMT_LED_STRIP_RESOLUTION_HZ };
ESP_ERROR_CHECK(rmt_new_led_strip_encoder(&enc_cfg,&led_encoder));
ESP_ERROR_CHECK(rmt_enable(led_chan));
memset(led_pixels,0,sizeof(led_pixels));
flush_leds();
char line_buf[64];
int line_pos=0;
while(1){
int ch;
while(uart_get_buffered_data_len(UART_NUM_0) > 0){
uint8_t c;
int len = uart_read_bytes(UART_NUM_0,&c,1,0);
if(len>0){
if(c=='\r' || c=='\n'){
line_buf[line_pos]='\0';
if(line_pos>0){ process_line(line_buf); }
line_pos=0;
}else{
if(line_pos < (int)sizeof(line_buf)-1){ line_buf[line_pos++]=c; }
}
}
}
if(current_preset>=0){
const preset_t *p=&presets[current_preset];
uint64_t now = esp_timer_get_time()/1000;
uint64_t period_ms = 1000 / p->freq_hz;
uint64_t half = period_ms/2;
if(half<1) half=1;
if(now - last_toggle_ms >= half){
led_on = !led_on;
last_toggle_ms = now;
if(led_on){
uint32_t r,g,b;
hsv2rgb(p->hue,100,100,&r,&g,&b);
set_all_pixels(r,g,b);
}else{
memset(led_pixels,0,sizeof(led_pixels));
}
flush_leds();
}
}
vTaskDelay(pdMS_TO_TICKS(5));
}
}