Skip to content

Commit

Permalink
Merge branch 'feat/lightbulb_enable_dimming_curve' into 'master'
Browse files Browse the repository at this point in the history
feat(lightbulb): Enable dimming curve

See merge request ae_group/esp-iot-solution!1139
  • Loading branch information
shixinke-orion committed Jan 9, 2025
2 parents f293523 + 13cb283 commit 6f1d8ad
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 86 deletions.
10 changes: 8 additions & 2 deletions components/led/lightbulb_driver/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# ChangeLog

## v1.5.0 - 2024-12-25

### Enhancements:

* Remove linear dimming, default to enabling curve dimming for all.

## v1.4.0 - 2024-11-15

### Enhancements:
Expand All @@ -16,7 +22,7 @@

### Enhancements:

* Added cct range check in precision mode
* Added CCT range check in precision mode

## v1.3.1 - 2024-08-28

Expand Down Expand Up @@ -75,7 +81,7 @@
### Enhancements:

* Added the conversion function of IIC current values to the enumeration values required by the driver.
* Added driver layer parameter checking macro and allowed to configure the detail level of the output log through menuconfig.
* Added driver layer parameter checking macro and allowed configuring the detail level of the output log through menuconfig.

## v1.0.0 - 2024-01-16

Expand Down
4 changes: 2 additions & 2 deletions components/led/lightbulb_driver/idf_component.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
version: "1.4.0"
version: "1.5.0"
description: Provide multiple dimming driver solutions to easily build lightbulb applications
url: https://github.com/espressif/esp-iot-solution/tree/master/components/led/lightbulb_driver
dependencies:
idf: ">=4.3.2"
espressif/cmake_utilities: "0.*"
espressif/cmake_utilities: "*"
examples:
- path: ../../../examples/lighting/lightbulb
sbom:
Expand Down
7 changes: 3 additions & 4 deletions components/led/lightbulb_driver/include/lightbulb.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
Expand Down Expand Up @@ -173,9 +173,8 @@ typedef struct {
float balance_coefficient[5]; /**< Array of float coefficients for adjusting the intensity of each color channel (R, G, B, C, W).
These coefficients help in achieving the desired color balance for the light output. */

float curve_coefficient; /**< Coefficient for gamma correction. This value is used to modify the luminance levels
to suit the non-linear characteristics of human vision, thus improving the overall
visual appearance of the light. */
float color_curve_coefficient; /**< Coefficient for gamma correction (RGB mode). The default value is 1.0, which is linear.*/
float white_curve_coefficient; /**< Coefficient for gamma correction (CCT mode). The default value is 1.0, which is linear.*/
} lightbulb_gamma_config_t;

/**
Expand Down
79 changes: 27 additions & 52 deletions components/led/lightbulb_driver/src/hal_driver.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
Expand Down Expand Up @@ -100,10 +100,7 @@ typedef struct {
hal_obj_t *interface;
int s_err_count;
bool use_hw_fade;
bool linear_use_curve_table;
// index 0: curve table
// index 1: linear table
uint16_t *table_group[2];
uint16_t *table_group;
// R G B C W
float balance_coefficient[5];
SemaphoreHandle_t fade_mutex;
Expand Down Expand Up @@ -252,7 +249,7 @@ static float final_processing(uint8_t channel, uint16_t src_value)
return s_hal_obj->balance_coefficient[channel] * src_value;
}

static esp_err_t gamma_table_create(uint16_t *output_gamma_table, uint16_t table_size, float gamma_curve_coefficient, int32_t grayscale_level)
esp_err_t hal_gamma_table_create(uint16_t *output_gamma_table, uint16_t table_size, float gamma_curve_coefficient, int32_t grayscale_level)
{
float value_tmp = 0;

Expand Down Expand Up @@ -290,13 +287,9 @@ static void force_stop_all_ch(void)

static void cleanup(void)
{
if (s_hal_obj->table_group[0]) {
free(s_hal_obj->table_group[0]);
s_hal_obj->table_group[0] = NULL;
}
if (s_hal_obj->table_group[1]) {
free(s_hal_obj->table_group[1]);
s_hal_obj->table_group[1] = NULL;
if (s_hal_obj->table_group) {
free(s_hal_obj->table_group);
s_hal_obj->table_group = NULL;
}
if (s_hal_obj->fade_mutex) {
vSemaphoreDelete(s_hal_obj->fade_mutex);
Expand Down Expand Up @@ -493,38 +486,34 @@ esp_err_t hal_output_init(hal_config_t *config, lightbulb_gamma_config_t *gamma,
err = s_hal_obj->interface->init(config->driver_data, driver_default_hook_func);
LIGHTBULB_CHECK(err == ESP_OK, "driver init fail", goto EXIT);

s_hal_obj->table_group[0] = calloc(s_hal_obj->interface->driver_grayscale_level, sizeof(uint16_t));
LIGHTBULB_CHECK(s_hal_obj->table_group[0], "curve table buffer alloc fail", goto EXIT);

float curve_coe = gamma ? gamma->curve_coefficient : DEFAULT_CURVE_COE;
float linear_coe = 1.0;

gamma_table_create(s_hal_obj->table_group[0], s_hal_obj->interface->driver_grayscale_level, curve_coe, s_hal_obj->interface->driver_grayscale_level);
s_hal_obj->table_group[0][s_hal_obj->interface->driver_grayscale_level - 1] = s_hal_obj->interface->hardware_allow_max_input_value;

if (linear_coe == curve_coe) {
s_hal_obj->linear_use_curve_table = true;
} else {
s_hal_obj->table_group[1] = calloc(s_hal_obj->interface->driver_grayscale_level, sizeof(uint16_t));
LIGHTBULB_CHECK(s_hal_obj->table_group[1], "linear table buffer alloc fail", goto EXIT);
gamma_table_create(s_hal_obj->table_group[1], s_hal_obj->interface->driver_grayscale_level, linear_coe, s_hal_obj->interface->driver_grayscale_level);
s_hal_obj->table_group[1][s_hal_obj->interface->driver_grayscale_level - 1] = s_hal_obj->interface->hardware_allow_max_input_value;
}

for (int i = 0; i < 5; i++) {
float balance = gamma ? gamma->balance_coefficient[i] : 1.0;
LIGHTBULB_CHECK(balance >= 0.0 && balance <= 1.0, "balance data error", goto EXIT);
s_hal_obj->balance_coefficient[i] = balance;
}

/**
* @brief Differential configuration for different chips
*
*/
int table_size = s_hal_obj->interface->driver_grayscale_level;
if (s_hal_obj->interface->type == DRIVER_ESP_PWM) {
#if CONFIG_PWM_ENABLE_HW_FADE
s_hal_obj->use_hw_fade = true;
#endif
// PWM
// 10bit: 0~1024, size: 1024 + 1
table_size += 1;

// I2C Chip
// 10bit: 0~1023, size: 1024
}

s_hal_obj->table_group = calloc(table_size, sizeof(uint16_t));
LIGHTBULB_CHECK(s_hal_obj->table_group, "curve table buffer alloc fail", goto EXIT);

//Currently only used as a mapping table, it will be used for fade to achieve curve sliding changes in the future
float curve_coe = DEFAULT_CURVE_COE;
hal_gamma_table_create(s_hal_obj->table_group, table_size, curve_coe, s_hal_obj->interface->hardware_allow_max_input_value);

for (int i = 0; i < 5; i++) {
float balance = gamma ? gamma->balance_coefficient[i] : 1.0;
LIGHTBULB_CHECK(balance >= 0.0 && balance <= 1.0, "balance data error", goto EXIT);
s_hal_obj->balance_coefficient[i] = balance;
}

#ifdef FADE_TICKS_FROM_GPTIMER
Expand Down Expand Up @@ -1052,21 +1041,7 @@ esp_err_t hal_get_curve_table_value(uint16_t input, uint16_t *output)
LIGHTBULB_CHECK(s_hal_obj, "init() must be called first", return ESP_ERR_INVALID_STATE);
LIGHTBULB_CHECK(output, "out_data is null", return ESP_ERR_INVALID_STATE);

*output = s_hal_obj->table_group[0][input];

return ESP_OK;
}

esp_err_t hal_get_linear_table_value(uint16_t input, uint16_t *output)
{
LIGHTBULB_CHECK(s_hal_obj, "init() must be called first", return ESP_ERR_INVALID_STATE);
LIGHTBULB_CHECK(output, "out_data is null", return ESP_ERR_INVALID_STATE);

if (s_hal_obj->linear_use_curve_table) {
*output = s_hal_obj->table_group[0][input];
} else {
*output = s_hal_obj->table_group[1][input];
}
*output = s_hal_obj->table_group[input];

return ESP_OK;
}
Expand Down
76 changes: 55 additions & 21 deletions components/led/lightbulb_driver/src/lightbulb.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
Expand Down Expand Up @@ -62,6 +62,12 @@ typedef struct {
TimerHandle_t effect_timer; // Timer handle related to the flashing, fading
SemaphoreHandle_t mutex; // For multi-thread protection

// Structure containing pointers to gamma correction tables for color and white
struct {
uint16_t *color_gamma_table; // Pointer to the color gamma correction table (for RGB)
uint16_t *white_gamma_table; // Pointer to the white gamma correction table (for CCT)
} gamma_correction;

// Structure containing flags related to effects
struct {
bool allow_interrupt : 1; // Flag indicating if the effect can be interrupted
Expand Down Expand Up @@ -304,23 +310,22 @@ static void cct_and_brightness_convert_and_power_limit(lightbulb_led_beads_comb_
hal_get_driver_feature(QUERY_MAX_INPUT_VALUE, &max_value);

if (led_beads == LED_BEADS_1CH_C || led_beads == LED_BEADS_4CH_RGBC || led_beads == LED_BEADS_4CH_RGBCC) {
uint16_t value = brightness / 100.0 * max_value;
hal_get_linear_table_value((uint8_t)value, &white_value[3]);
uint16_t value = brightness * max_value / 100;
hal_get_curve_table_value(value, &white_value[3]);
if (led_beads == LED_BEADS_4CH_RGBCC) {
hal_get_linear_table_value((uint8_t)value, &white_value[4]);
hal_get_curve_table_value(value, &white_value[4]);
}
} else if (led_beads == LED_BEADS_1CH_W || led_beads == LED_BEADS_4CH_RGBW || led_beads == LED_BEADS_4CH_RGBWW) {
uint16_t value = brightness / 100.0 * max_value;
hal_get_linear_table_value(value, &white_value[4]);

uint16_t value = brightness * max_value / 100;
hal_get_curve_table_value(value, &white_value[4]);
if (led_beads == LED_BEADS_4CH_RGBWW) {
hal_get_linear_table_value((uint8_t)value, &white_value[3]);
hal_get_curve_table_value(value, &white_value[3]);
}
} else if ((led_beads == LED_BEADS_2CH_CW || led_beads == LED_BEADS_5CH_RGBCW) && IS_WHITE_OUTPUT_HARDWARE_MIXED()) {
uint16_t value1 = cct / 100.0 * max_value;
uint16_t value2 = brightness / 100.0 * max_value;
hal_get_linear_table_value((uint8_t)value1, &white_value[3]);
hal_get_linear_table_value((uint8_t)value2, &white_value[4]);
uint16_t value1 = cct * max_value / 100;
uint16_t value2 = brightness * max_value / 100;
hal_get_curve_table_value(value1, &white_value[3]);
hal_get_curve_table_value(value2, &white_value[4]);
} else if (led_beads == LED_BEADS_2CH_CW || ((led_beads == LED_BEADS_5CH_RGBCW) && (s_lb_obj->cap.enable_precise_cct_control == false))) {
float max_power;
float _c = cct / 100.0;
Expand All @@ -330,8 +335,8 @@ static void cct_and_brightness_convert_and_power_limit(lightbulb_led_beads_comb_
max_power = MIN(max_value * multiple, max_value / baseline);
_c = max_power * _c * (brightness / 100.0);
_w = max_power * _w * (brightness / 100.0);
hal_get_linear_table_value((uint16_t)_c, &white_value[3]);
hal_get_linear_table_value((uint16_t)_w, &white_value[4]);
hal_get_curve_table_value(_c, &white_value[3]);
hal_get_curve_table_value(_w, &white_value[4]);
} else {
float max_power;
lightbulb_cct_mapping_data_t data = search_mapping_cct_data(cct);
Expand All @@ -344,7 +349,8 @@ static void cct_and_brightness_convert_and_power_limit(lightbulb_led_beads_comb_
max_power = MIN(max_value * multiple, max_value / baseline);
ESP_LOGD(TAG, "%f, %d, %f", max_power, max_value, baseline);
for (int i = 0; i < 5; i++) {
white_value[i] = round(max_power * data.rgbcw[i] * (brightness / 100.0));
float value = round(max_power * data.rgbcw[i] * (brightness / 100.0));
hal_get_curve_table_value((uint16_t)value, &white_value[i]);
}
}
}
Expand All @@ -371,7 +377,9 @@ static uint8_t process_color_value_limit(uint8_t value)
float percentage = value / 100.0;

uint8_t result = (s_lb_obj->power.color_max_value - s_lb_obj->power.color_min_value) * percentage + s_lb_obj->power.color_min_value;
result = s_lb_obj->gamma_correction.color_gamma_table[result];
ESP_LOGD(TAG, "color_value convert input:%d output:%d", value, result);

return result;
}

Expand All @@ -397,7 +405,9 @@ static uint8_t process_white_brightness_limit(uint8_t brightness)
float percentage = brightness / 100.0;

uint8_t result = (s_lb_obj->power.white_max_brightness - s_lb_obj->power.white_min_brightness) * percentage + s_lb_obj->power.white_min_brightness;
result = s_lb_obj->gamma_correction.white_gamma_table[result];
ESP_LOGD(TAG, "white_brightness_output input:%d output:%d", brightness, result);

return result;
}

Expand Down Expand Up @@ -428,7 +438,8 @@ static void process_color_power_limit(float multiple, float rgbcw[5], uint16_t v
max_power = MIN(max_power, max_value / baseline);
ESP_LOGD(TAG, "%f, %d, %f", max_power, max_value, baseline);
for (int i = 0; i < 5; i++) {
out[i] = round(max_power * rgbcw[i] * (value / 100.0));
float value = round(max_power * rgbcw[i]);
hal_get_curve_table_value((uint16_t)value, &out[i]);
}
}

Expand Down Expand Up @@ -911,6 +922,20 @@ esp_err_t lightbulb_init(lightbulb_config_t *config)
s_lb_obj->cap.fade_time_ms = MAX(MIN_FADE_MS, s_lb_obj->cap.fade_time_ms);
}

//Gamma table create
float color_coe = 1.0;
float white_coe = 1.0;
if (config->gamma_conf) {
color_coe = config->gamma_conf->color_curve_coefficient;
white_coe = config->gamma_conf->white_curve_coefficient;
}
s_lb_obj->gamma_correction.color_gamma_table = calloc(101, sizeof(uint16_t));
LIGHTBULB_CHECK(s_lb_obj->gamma_correction.color_gamma_table, "curve table buffer alloc fail", goto EXIT);
s_lb_obj->gamma_correction.white_gamma_table = calloc(101, sizeof(uint16_t));
LIGHTBULB_CHECK(s_lb_obj->gamma_correction.white_gamma_table, "curve table buffer alloc fail", goto EXIT);
hal_gamma_table_create(s_lb_obj->gamma_correction.color_gamma_table, 101, color_coe, 100);
hal_gamma_table_create(s_lb_obj->gamma_correction.white_gamma_table, 101, white_coe, 100);

// Low power check
if (config->capability.enable_lowpower) {
/* Make sure the fade is done and the flash operation is done, then enable light sleep */
Expand Down Expand Up @@ -991,6 +1016,15 @@ esp_err_t lightbulb_deinit(void)
s_lb_obj->color_manager.mix_table = NULL;
}

if (s_lb_obj->gamma_correction.color_gamma_table) {
free(s_lb_obj->gamma_correction.color_gamma_table);
s_lb_obj->gamma_correction.color_gamma_table = NULL;
}
if (s_lb_obj->gamma_correction.white_gamma_table) {
free(s_lb_obj->gamma_correction.white_gamma_table);
s_lb_obj->gamma_correction.white_gamma_table = NULL;
}

free(s_lb_obj);
s_lb_obj = NULL;

Expand Down Expand Up @@ -1196,11 +1230,11 @@ static esp_err_t lightbulb_hsv2rgb_adjusted(uint16_t hue, uint8_t saturation, ui
}
}

*red = interpolated_rgbcw[0];
*green = interpolated_rgbcw[1];
*blue = interpolated_rgbcw[2];
*cold = interpolated_rgbcw[3];
*warm = interpolated_rgbcw[4];
*red = interpolated_rgbcw[0] * value / 100.0;
*green = interpolated_rgbcw[1] * value / 100.0;
*blue = interpolated_rgbcw[2] * value / 100.0;
*cold = interpolated_rgbcw[3] * value / 100.0;
*warm = interpolated_rgbcw[4] * value / 100.0;

return ESP_OK;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,13 @@ esp_err_t hal_output_deinit(void);
esp_err_t hal_regist_channel(int channel, gpio_num_t gpio_num);
esp_err_t hal_get_driver_feature(hal_feature_query_list_t type, void *out_data);
esp_err_t hal_get_curve_table_value(uint16_t input, uint16_t *output);
esp_err_t hal_get_linear_table_value(uint16_t input, uint16_t *output);
esp_err_t hal_set_channel(int channel, uint16_t value, uint16_t fade_ms);
esp_err_t hal_set_channel_group(uint16_t value[], uint8_t channel_mask, uint16_t fade_ms);
esp_err_t hal_start_channel_action(int channel, uint16_t value_min, uint16_t value_max, uint16_t period_ms, bool fade_flag);
esp_err_t hal_start_channel_group_action(uint16_t value_min[], uint16_t value_max[], uint8_t channel_mask, uint16_t period_ms, bool fade_flag);
esp_err_t hal_stop_channel_action(uint8_t channel_mask);
esp_err_t hal_sleep_control(bool enable_sleep);
esp_err_t hal_gamma_table_create(uint16_t *output_gamma_table, uint16_t table_size, float gamma_curve_coefficient, int32_t grayscale_level);

/**
* @brief To resolve some compilation warning issues
Expand Down
Loading

0 comments on commit 6f1d8ad

Please sign in to comment.