Skip to content

Commit

Permalink
chore: use led encoder from example, remove now unneeded esp-idf-lib
Browse files Browse the repository at this point in the history
  • Loading branch information
portasynthinca3 committed Jun 15, 2024
1 parent 67f7ad4 commit 14bdba5
Show file tree
Hide file tree
Showing 7 changed files with 197 additions and 115 deletions.
3 changes: 0 additions & 3 deletions .gitmodules

This file was deleted.

1 change: 0 additions & 1 deletion esp-idf-lib
Submodule esp-idf-lib deleted from c6da18
36 changes: 36 additions & 0 deletions main/include/led_strip_encoder.h
Original file line number Diff line number Diff line change
@@ -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
4 changes: 1 addition & 3 deletions main/include/led_task.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,12 @@

#include <esp_err.h>
#include <freertos/queue.h>
#include <rgb.h>
#include <stdbool.h>

#define LED_Q_SIZE 4
#define LED_PATTERN_LEN 4
extern QueueHandle_t led_queue;

#define LED_COLOR_HEX(hex) ((rgb_t){ .r = ((hex) >> 16) & 0xff, .g = ((hex) >> 8) & 0xff, .b = (hex) & 0xff })

typedef enum {
led_status_error = 0,
Expand All @@ -20,7 +18,7 @@ typedef enum {
} led_status_t;

typedef struct {
rgb_t color;
uint32_t color;
uint32_t time_ms;
bool final;
} led_pattern_step_t;
Expand Down
124 changes: 124 additions & 0 deletions main/led_strip_encoder.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/*
* 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;

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;
}

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;
}
56 changes: 36 additions & 20 deletions main/led_task.c
Original file line number Diff line number Diff line change
@@ -1,50 +1,61 @@
#include <esp_log.h>
#include <freertos/FreeRTOS.h>
#include <freertos/queue.h>
#include <esp_random.h>
#include <led_strip.h>
#include <rgb.h>
#include <driver/rmt.h>
#include <driver/rmt_tx.h>
#include <esp_timer.h>
#include <time.h>

#include "common.h"
#include "led_task.h"
#include "config.h"
#include "led_strip_encoder.h"

#define TAG "led_task"
#define RMT_LED_STRIP_RESOLUTION_HZ 10000000

static const led_pattern_step_t _led_patterns[][LED_PATTERN_LEN] = {
/* error */ {
{ LED_COLOR_HEX(0xff0000), 500, 0 },
{ LED_COLOR_HEX(0), 500, 1 }
{ 0xff0000, 500, 0 },
{ 0x000000, 500, 1 }
},
/* wait */ {
{ LED_COLOR_HEX(0xffff00), 10000, 1 }
{ 0xffff00, 10000, 1 }
},
/* idle */ {
{ LED_COLOR_HEX(0x00ffff), 20, 0 },
{ LED_COLOR_HEX(0), 1980, 1 }
{ 0x00ffff, 20, 0 },
{ 0x000000, 1980, 1 }
},
/* granted */ {
{ LED_COLOR_HEX(0x00ff00), 10000, 1}
{ 0x00ff00, 10000, 1}
},
/* refused */ {
{ LED_COLOR_HEX(0xff0000), 10000, 1}
{ 0xff0000, 10000, 1}
},
};

QueueHandle_t led_queue;

void led_task(void* _arg) {
// initialize LED strip
led_strip_t strip = {
.type = LED_STRIP_WS2812,
.brightness = 255,
.length = 1,
.gpio = LED_PIN,
.channel = RMT_CHANNEL_0,
rmt_channel_handle_t led_chan = NULL;
rmt_tx_channel_config_t tx_chan_config = {
.clk_src = RMT_CLK_SRC_DEFAULT,
.gpio_num = LED_PIN,
.mem_block_symbols = 64,
.resolution_hz = RMT_LED_STRIP_RESOLUTION_HZ,
.trans_queue_depth = 4,
};
ESP_ERROR_CHECK(rmt_new_tx_channel(&tx_chan_config, &led_chan));
rmt_encoder_handle_t led_encoder = NULL;
led_strip_encoder_config_t encoder_config = {
.resolution = RMT_LED_STRIP_RESOLUTION_HZ,
};
ESP_ERROR_CHECK(rmt_new_led_strip_encoder(&encoder_config, &led_encoder));
ESP_ERROR_CHECK(rmt_enable(led_chan));
rmt_transmit_config_t tx_config = {
.loop_count = 0,
};
ESP_ERROR_CHECK(led_strip_init(&strip));

// sequencer state
led_status_t status = led_status_wait;
Expand All @@ -59,11 +70,17 @@ void led_task(void* _arg) {
}

// refresh led according to next step
// discuss: does this macro trick improve or hurt readability?
#define step _led_patterns[status][step_idx]
if(step_idx < 0 || esp_timer_get_time() - step_started >= step.time_ms * 1000) {
step_idx = (step_idx < 0 || step.final) ? 0 : (step_idx + 1);
led_strip_set_pixel(&strip, 0, step.color);
led_strip_flush(&strip);
uint8_t grb[3] = {
(step.color & 0x00ff00) >> 8,
(step.color & 0xff0000) >> 16,
step.color & 0x0000ff
};
ESP_ERROR_CHECK(rmt_transmit(led_chan, led_encoder, grb, sizeof(grb), &tx_config));
ESP_ERROR_CHECK(rmt_tx_wait_all_done(led_chan, portMAX_DELAY));
step_started = esp_timer_get_time();
}
#undef step
Expand All @@ -72,7 +89,6 @@ void led_task(void* _arg) {

void led_init(void) {
led_queue = xQueueCreate(LED_Q_SIZE, sizeof(led_status_t));
led_strip_install();
}

void led_set_status(led_status_t status) {
Expand Down
88 changes: 0 additions & 88 deletions sdkconfig
Original file line number Diff line number Diff line change
Expand Up @@ -1718,94 +1718,6 @@ CONFIG_WIFI_PROV_AUTOSTOP_TIMEOUT=30
CONFIG_WIFI_PROV_STA_ALL_CHANNEL_SCAN=y
# CONFIG_WIFI_PROV_STA_FAST_SCAN is not set
# end of Wi-Fi Provisioning Manager

#
# Button
#
CONFIG_BUTTON_MAX=5
CONFIG_BUTTON_POLL_TIMEOUT=10
CONFIG_BUTTON_LONG_PRESS_TIMEOUT=1000
CONFIG_BUTTON_AUTOREPEAT_TIMEOUT=500
CONFIG_BUTTON_AUTOREPEAT_INTERVAL=250
# end of Button

#
# DPS310 driver
#
CONFIG_DPS310_PROTOCOL_USING_I2C=y
# end of DPS310 driver

#
# Rotary encoders
#
CONFIG_RE_MAX=1
CONFIG_RE_INTERVAL_US=1000
CONFIG_RE_BTN_DEAD_TIME_US=10000
CONFIG_RE_BTN_PRESSED_LEVEL_0=y
# CONFIG_RE_BTN_PRESSED_LEVEL_1 is not set
CONFIG_RE_BTN_LONG_PRESS_TIME_US=500000
# end of Rotary encoders

#
# Example
#
CONFIG_EXAMPLE_USING_FOO=y
# CONFIG_EXAMPLE_USING_BAR is not set
CONFIG_EXAMPLE_NUMBER=1
# end of Example

#
# HMC5883L
#
CONFIG_HMC5883L_MEAS_TIMEOUT=6000
# end of HMC5883L

#
# I2C
#
CONFIG_I2CDEV_TIMEOUT=1000
# CONFIG_I2CDEV_NOLOCK is not set
# end of I2C

#
# LED strip
#
CONFIG_LED_STRIP_FLUSH_TIMEOUT=1000
CONFIG_LED_STRIP_PAUSE_LENGTH=50
# end of LED strip

#
# LED strip SPI
#
CONFIG_LED_STRIP_SPI_USING_SK9822=y
CONFIG_LED_STRIP_SPI_MUTEX_TIMEOUT_MS=1
# end of LED strip SPI

#
# MAX1704X Battery Fuel Gauge
#
CONFIG_MAX1704X_MODEL_3_4=y
# CONFIG_MAX1704X_MODEL_8_9 is not set
# end of MAX1704X Battery Fuel Gauge

#
# MCP23x17
#
CONFIG_MCP23X17_IFACE_I2C=y
# CONFIG_MCP23X17_IFACE_SPI is not set
# end of MCP23x17

#
# MPU6050
#
# CONFIG_AUTO_CONFIG_ADDR is not set
# end of MPU6050

#
# OneWire
#
# CONFIG_ONEWIRE_CRC8_TABLE is not set
# end of OneWire
# end of Component config

# CONFIG_IDF_EXPERIMENTAL_FEATURES is not set
Expand Down

0 comments on commit 14bdba5

Please sign in to comment.