mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
feat: replace lightdriver, and support more chips in ble mesh examples
This commit is contained in:
parent
c05940a0fb
commit
fde5e93ab5
@ -1,5 +1,5 @@
|
||||
| Supported Targets | ESP32 |
|
||||
| ----------------- | ----- |
|
||||
| Supported Targets | ESP32 | ESP32-C3 | ESP32-S3 | ESP32-H2 | ESP32-C6 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- |
|
||||
|
||||
ESP BLE Mesh AliGenie Example
|
||||
=============================
|
||||
|
@ -23,6 +23,7 @@ menu "AliGenie Example Configuration"
|
||||
menu "light driver config"
|
||||
config LIGHT_GPIO_RED
|
||||
int "Light red pin GPIO number"
|
||||
range -1 48 if IDF_TARGET_ESP32S3
|
||||
range -1 33
|
||||
default 25
|
||||
help
|
||||
@ -33,6 +34,7 @@ menu "AliGenie Example Configuration"
|
||||
|
||||
config LIGHT_GPIO_GREEN
|
||||
int "Light green pin GPIO number"
|
||||
range -1 48 if IDF_TARGET_ESP32S3
|
||||
range -1 33
|
||||
default 26
|
||||
help
|
||||
@ -43,6 +45,7 @@ menu "AliGenie Example Configuration"
|
||||
|
||||
config LIGHT_GPIO_BLUE
|
||||
int "Light blue pin GPIO number"
|
||||
range -1 48 if IDF_TARGET_ESP32S3
|
||||
range -1 33
|
||||
default 27
|
||||
help
|
||||
@ -53,6 +56,7 @@ menu "AliGenie Example Configuration"
|
||||
|
||||
config LIGHT_GPIO_COLD
|
||||
int "Light cold colors pin GPIO number"
|
||||
range -1 48 if IDF_TARGET_ESP32S3
|
||||
range -1 33
|
||||
default -1
|
||||
help
|
||||
@ -63,6 +67,7 @@ menu "AliGenie Example Configuration"
|
||||
|
||||
config LIGHT_GPIO_WARM
|
||||
int "Light warm color pin GPIO number"
|
||||
range -1 48 if IDF_TARGET_ESP32S3
|
||||
range -1 33
|
||||
default -1
|
||||
help
|
||||
|
@ -37,6 +37,7 @@ static const char *TAG = "genie_demo";
|
||||
|
||||
#define MESH_ELEM_COUNT 1
|
||||
#define MESH_ELEM_STATE_COUNT MESH_ELEM_COUNT
|
||||
#define LIGHT_STATUS_STORE_KEY "light_status"
|
||||
|
||||
nvs_handle_t NVS_HANDLE;
|
||||
|
||||
@ -416,12 +417,34 @@ void user_genie_event_handle(genie_event_t event, void *p_arg)
|
||||
switch (event) {
|
||||
case GENIE_EVT_RESET_BY_REPEAT_NOTIFY:
|
||||
ESP_LOGI(TAG, "GENIE_EVT_RESET_BY_REPEAT_NOTIFY");
|
||||
light_driver_breath_start(0, 255, 0); /**< green blink */
|
||||
lightbulb_set_switch(false);
|
||||
lightbulb_effect_config_t effect1 = {
|
||||
.red = 0,
|
||||
.green = 255,
|
||||
.blue = 0,
|
||||
.max_brightness = 100,
|
||||
.min_brightness = 0,
|
||||
.effect_cycle_ms = CONFIG_LIGHT_BLINK_PERIOD_MS,
|
||||
.effect_type = EFFECT_BLINK,
|
||||
.mode = WORK_COLOR,
|
||||
};
|
||||
lightbulb_basic_effect_start(&effect1); /**< green blink */
|
||||
break;
|
||||
case GENIE_EVT_SW_RESET:
|
||||
case GENIE_EVT_HW_RESET_START:
|
||||
ESP_LOGI(TAG, "GENIE_EVT_HW_RESET_START");
|
||||
light_driver_breath_start(0, 255, 0); /**< green blink */
|
||||
lightbulb_set_switch(false);
|
||||
lightbulb_effect_config_t effect2 = {
|
||||
.red = 0,
|
||||
.green = 255,
|
||||
.blue = 0,
|
||||
.max_brightness = 100,
|
||||
.min_brightness = 0,
|
||||
.effect_cycle_ms = CONFIG_LIGHT_BLINK_PERIOD_MS,
|
||||
.effect_type = EFFECT_BLINK,
|
||||
.mode = WORK_COLOR,
|
||||
};
|
||||
lightbulb_basic_effect_start(&effect2); /**< green blink */
|
||||
ble_mesh_nvs_erase(NVS_HANDLE, LIGHT_STATUS_STORE_KEY); // erase led status
|
||||
reset_light_para();
|
||||
break;
|
||||
@ -442,7 +465,7 @@ void user_genie_event_handle(genie_event_t event, void *p_arg)
|
||||
g_indication_flag |= INDICATION_FLAG_CTL;
|
||||
#endif
|
||||
ESP_LOGI(TAG, "light_driver_breath_stop %s", __FUNCTION__);
|
||||
light_driver_breath_stop();
|
||||
lightbulb_basic_effect_stop();
|
||||
// update led status
|
||||
genie_event(GENIE_EVT_SDK_ANALYZE_MSG, &g_elem_state[0]);
|
||||
break;
|
||||
@ -1290,7 +1313,18 @@ static esp_err_t ble_mesh_init(void)
|
||||
ESP_LOGW(TAG, "node already provisioned");
|
||||
} else {
|
||||
ESP_LOGW(TAG, "node not provisioned");
|
||||
light_driver_breath_start(0, 255, 0); /**< green blink */
|
||||
lightbulb_set_switch(false);
|
||||
lightbulb_effect_config_t effect3 = {
|
||||
.red = 0,
|
||||
.green = 255,
|
||||
.blue = 0,
|
||||
.max_brightness = 100,
|
||||
.min_brightness = 0,
|
||||
.effect_cycle_ms = CONFIG_LIGHT_BLINK_PERIOD_MS,
|
||||
.effect_type = EFFECT_BLINK,
|
||||
.mode = WORK_COLOR,
|
||||
};
|
||||
lightbulb_basic_effect_start(&effect3); /**< green blink */
|
||||
}
|
||||
|
||||
return err;
|
||||
|
@ -13,11 +13,15 @@
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "iot_button.h"
|
||||
#include "light_driver.h"
|
||||
#include "lightbulb.h"
|
||||
|
||||
#include "genie_event.h"
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32C3
|
||||
#define BUTTON_ON_OFF 9 /* on/off button */
|
||||
#else
|
||||
#define BUTTON_ON_OFF 0 /* on/off button */
|
||||
#endif
|
||||
#define BUTTON_ACTIVE_LEVEL 0
|
||||
|
||||
static const char *TAG = "board";
|
||||
@ -38,22 +42,37 @@ static void board_led_init(void)
|
||||
* If the module has SPI flash, GPIOs 6-11 are connected to the module’s integrated SPI flash and PSRAM.
|
||||
* If the module has PSRAM, GPIOs 16 and 17 are connected to the module’s integrated PSRAM.
|
||||
*/
|
||||
light_driver_config_t driver_config = {
|
||||
.gpio_red = CONFIG_LIGHT_GPIO_RED,
|
||||
.gpio_green = CONFIG_LIGHT_GPIO_GREEN,
|
||||
.gpio_blue = CONFIG_LIGHT_GPIO_BLUE,
|
||||
.gpio_cold = CONFIG_LIGHT_GPIO_COLD,
|
||||
.gpio_warm = CONFIG_LIGHT_GPIO_WARM,
|
||||
.fade_period_ms = CONFIG_LIGHT_FADE_PERIOD_MS,
|
||||
.blink_period_ms = CONFIG_LIGHT_BLINK_PERIOD_MS,
|
||||
lightbulb_config_t config = {
|
||||
.type = DRIVER_ESP_PWM,
|
||||
.driver_conf.pwm.freq_hz = 4000,
|
||||
.capability.enable_fades = true,
|
||||
.capability.fades_ms = CONFIG_LIGHT_FADE_PERIOD_MS,
|
||||
.capability.enable_lowpower = false,
|
||||
.capability.enable_mix_cct = false,
|
||||
.capability.enable_status_storage = false,
|
||||
.capability.mode_mask = COLOR_MODE,
|
||||
.capability.storage_cb = NULL,
|
||||
.capability.sync_change_brightness_value = true,
|
||||
.io_conf.pwm_io.red = CONFIG_LIGHT_GPIO_RED,
|
||||
.io_conf.pwm_io.green = CONFIG_LIGHT_GPIO_GREEN,
|
||||
.io_conf.pwm_io.blue = CONFIG_LIGHT_GPIO_BLUE,
|
||||
.io_conf.pwm_io.cold_cct = CONFIG_LIGHT_GPIO_COLD,
|
||||
.io_conf.pwm_io.warm_brightness = CONFIG_LIGHT_GPIO_WARM,
|
||||
.external_limit = NULL,
|
||||
.gamma_conf = NULL,
|
||||
.init_status.mode = WORK_COLOR,
|
||||
.init_status.on = true,
|
||||
.init_status.hue = 0,
|
||||
.init_status.saturation = 100,
|
||||
.init_status.value = 100,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Light driver initialization
|
||||
*/
|
||||
ESP_ERROR_CHECK(light_driver_init(&driver_config));
|
||||
light_driver_set_mode(MODE_HSL);
|
||||
// light_driver_set_switch(true);
|
||||
ESP_ERROR_CHECK(lightbulb_init(&config));
|
||||
vTaskDelay(pdMS_TO_TICKS(1000) * 1);
|
||||
lightbulb_set_switch(true);
|
||||
|
||||
button_handle_t dev_on_off_btn = iot_button_create(BUTTON_ON_OFF, BUTTON_ACTIVE_LEVEL);
|
||||
iot_button_set_evt_cb(dev_on_off_btn, BUTTON_CB_TAP, button_tap_cb, &dev_on_btn_num);
|
||||
@ -64,6 +83,62 @@ void board_init(void)
|
||||
board_led_init();
|
||||
}
|
||||
|
||||
static esp_err_t board_led_hsl2rgb(uint16_t hue, uint8_t saturation, uint8_t lightness,
|
||||
uint8_t *red, uint8_t *green, uint8_t *blue)
|
||||
{
|
||||
uint16_t hi = (hue / 60) % 6;
|
||||
uint16_t C = (100 - abs(2 * lightness - 100)) * saturation / 100;
|
||||
uint16_t M = 100 * (lightness - 0.5 * C) / 100;
|
||||
uint16_t X = C * (100 - abs((hue * 100 / 60 ) % 200 - 100)) / 100;
|
||||
|
||||
switch (hi) {
|
||||
case 0: /* hue 0~60 */
|
||||
*red = C + M;
|
||||
*green = X + M;
|
||||
*blue = M;
|
||||
break;
|
||||
|
||||
case 1: /* hue 60~120 */
|
||||
*red = X + M;
|
||||
*green = C + M;
|
||||
*blue = M;
|
||||
break;
|
||||
|
||||
case 2: /* hue 120~180 */
|
||||
*red = M;
|
||||
*green = C + M;
|
||||
*blue = X + M;
|
||||
break;
|
||||
|
||||
case 3: /* hue 180~240 */
|
||||
*red = M;
|
||||
*green = X + M;
|
||||
*blue = C + M;
|
||||
break;
|
||||
|
||||
case 4: /* hue 240~300 */
|
||||
*red = X + M;
|
||||
*green = M;
|
||||
*blue = C + M;
|
||||
break;
|
||||
|
||||
case 5: /* hue 300~360 */
|
||||
*red = C + M;
|
||||
*green = M;
|
||||
*blue = X + M;
|
||||
break;
|
||||
|
||||
default:
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
*red = *red * 255 / 100;
|
||||
*green = *green * 255 / 100;
|
||||
*blue = *blue * 255 / 100;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* hsl
|
||||
*/
|
||||
@ -86,8 +161,14 @@ void board_led_hsl(uint8_t elem_index, uint16_t hue, uint16_t saturation, uint16
|
||||
uint8_t actual_saturation = (float)last_saturation / (UINT16_MAX / 100.0);
|
||||
uint8_t actual_lightness = (float)last_lightness / (UINT16_MAX / 100.0);
|
||||
|
||||
uint8_t r, g, b;
|
||||
uint16_t h;
|
||||
uint8_t s, v;
|
||||
|
||||
ESP_LOGD(TAG, "hsl: %d, %d, %d operation", actual_hue, actual_saturation, actual_lightness);
|
||||
light_driver_set_hsl(actual_hue, actual_saturation, actual_lightness);
|
||||
board_led_hsl2rgb(actual_hue, actual_saturation, actual_lightness, &r, &g, &b);
|
||||
lightbulb_rgb2hsv(r, g, b, &h, &s, &v);
|
||||
lightbulb_set_hsv(h, s, v);
|
||||
}
|
||||
}
|
||||
|
||||
@ -105,7 +186,7 @@ void board_led_temperature(uint8_t elem_index, uint16_t temperature)
|
||||
|
||||
uint16_t actual_temperature = (float)last_temperature / (UINT16_MAX / 100.0);
|
||||
ESP_LOGD(TAG, "temperature %d %%%d operation", last_temperature, actual_temperature);
|
||||
light_driver_set_color_temperature(actual_temperature);
|
||||
lightbulb_set_cct(actual_temperature);
|
||||
}
|
||||
}
|
||||
|
||||
@ -123,7 +204,7 @@ void board_led_lightness(uint8_t elem_index, uint16_t actual)
|
||||
|
||||
uint16_t actual_lightness = (float)last_acual / (UINT16_MAX / 100.0);
|
||||
ESP_LOGD(TAG, "lightness %d %%%d operation", last_acual, actual_lightness);
|
||||
light_driver_set_lightness(actual_lightness);
|
||||
lightbulb_set_brightness(actual_lightness);
|
||||
}
|
||||
}
|
||||
|
||||
@ -139,10 +220,10 @@ void board_led_switch(uint8_t elem_index, uint8_t onoff)
|
||||
last_onoff = onoff;
|
||||
if (last_onoff) {
|
||||
ESP_LOGD(TAG, "onoff %d operation", last_onoff);
|
||||
light_driver_set_switch(true);
|
||||
lightbulb_set_switch(true);
|
||||
} else {
|
||||
ESP_LOGD(TAG, "onoff %d operation", last_onoff);
|
||||
light_driver_set_switch(false);
|
||||
lightbulb_set_switch(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ extern "C" {
|
||||
#endif /**< __cplusplus */
|
||||
|
||||
#include "driver/gpio.h"
|
||||
#include "light_driver.h"
|
||||
#include "lightbulb.h"
|
||||
|
||||
#define LED_ON 1
|
||||
#define LED_OFF 0
|
||||
|
@ -35,3 +35,9 @@ CONFIG_BLE_MESH_MODEL_KEY_COUNT=5
|
||||
CONFIG_BLE_MESH_MODEL_GROUP_COUNT=5
|
||||
CONFIG_BLE_MESH_MSG_CACHE_SIZE=20
|
||||
CONFIG_BLE_MESH_ADV_BUF_COUNT=256
|
||||
|
||||
#
|
||||
# light driver config
|
||||
#
|
||||
CONFIG_PWM_ENABLE_HW_FADE=n
|
||||
# end of light driver config
|
||||
|
@ -1,15 +1,3 @@
|
||||
#
|
||||
# Partition Table
|
||||
#
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
||||
|
||||
#
|
||||
# Serial flasher config
|
||||
#
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
|
||||
|
||||
# Override some defaults so BT stack is enabled
|
||||
# by default in this example
|
||||
CONFIG_BT_ENABLED=y
|
||||
@ -18,20 +6,8 @@ CONFIG_BT_CTRL_BLE_MESH_SCAN_DUPL_EN=y
|
||||
CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MANUAL=y
|
||||
CONFIG_BT_BTU_TASK_STACK_SIZE=4512
|
||||
CONFIG_BT_BLE_42_FEATURES_SUPPORTED=y
|
||||
|
||||
# Override some defaults of ESP BLE Mesh
|
||||
CONFIG_BLE_MESH=y
|
||||
CONFIG_BLE_MESH_NODE=y
|
||||
CONFIG_BLE_MESH_PB_GATT=y
|
||||
CONFIG_BLE_MESH_TX_SEG_MSG_COUNT=10
|
||||
CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=10
|
||||
CONFIG_BLE_MESH_SETTINGS=y
|
||||
CONFIG_BLE_MESH_SUBNET_COUNT=5
|
||||
CONFIG_BLE_MESH_APP_KEY_COUNT=5
|
||||
CONFIG_BLE_MESH_MODEL_KEY_COUNT=5
|
||||
CONFIG_BLE_MESH_MODEL_GROUP_COUNT=5
|
||||
CONFIG_BLE_MESH_MSG_CACHE_SIZE=20
|
||||
CONFIG_BLE_MESH_ADV_BUF_COUNT=256
|
||||
CONFIG_BT_BLE_50_FEATURES_SUPPORTED=n
|
||||
CONFIG_BT_LE_50_FEATURE_SUPPORT=n
|
||||
|
||||
#
|
||||
# light driver config
|
||||
|
@ -0,0 +1,19 @@
|
||||
# Override some defaults so BT stack is enabled
|
||||
# by default in this example
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BT_LE_SCAN_DUPL_TYPE_DATA_DEVICE=y
|
||||
CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MANUAL=y
|
||||
CONFIG_BT_BTU_TASK_STACK_SIZE=4512
|
||||
CONFIG_BT_BLE_42_FEATURES_SUPPORTED=y
|
||||
CONFIG_BT_BLE_50_FEATURES_SUPPORTED=n
|
||||
CONFIG_BT_LE_50_FEATURE_SUPPORT=n
|
||||
|
||||
#
|
||||
# light driver config
|
||||
#
|
||||
CONFIG_LIGHT_GPIO_RED=4
|
||||
CONFIG_LIGHT_GPIO_GREEN=5
|
||||
CONFIG_LIGHT_GPIO_BLUE=6
|
||||
CONFIG_LIGHT_GPIO_COLD=7
|
||||
CONFIG_LIGHT_GPIO_WARM=10
|
||||
# end of light driver config
|
@ -0,0 +1,19 @@
|
||||
# Override some defaults so BT stack is enabled
|
||||
# by default in this example
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BT_LE_SCAN_DUPL_TYPE_DATA_DEVICE=y
|
||||
CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MANUAL=y
|
||||
CONFIG_BT_BTU_TASK_STACK_SIZE=4512
|
||||
CONFIG_BT_BLE_42_FEATURES_SUPPORTED=y
|
||||
CONFIG_BT_BLE_50_FEATURES_SUPPORTED=n
|
||||
CONFIG_BT_LE_50_FEATURE_SUPPORT=n
|
||||
|
||||
#
|
||||
# light driver config
|
||||
#
|
||||
CONFIG_LIGHT_GPIO_RED=4
|
||||
CONFIG_LIGHT_GPIO_GREEN=5
|
||||
CONFIG_LIGHT_GPIO_BLUE=11
|
||||
CONFIG_LIGHT_GPIO_COLD=12
|
||||
CONFIG_LIGHT_GPIO_WARM=10
|
||||
# end of light driver config
|
@ -0,0 +1,21 @@
|
||||
# Override some defaults so BT stack is enabled
|
||||
# by default in this example
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
|
||||
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n
|
||||
CONFIG_BTDM_CTRL_MODE_BTDM=n
|
||||
CONFIG_CTRL_BTDM_MODEM_SLEEP=n
|
||||
CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE=y
|
||||
CONFIG_BTDM_BLE_MESH_SCAN_DUPL_EN=y
|
||||
CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MANUAL=y
|
||||
CONFIG_BT_BTU_TASK_STACK_SIZE=4512
|
||||
|
||||
#
|
||||
# light driver config
|
||||
#
|
||||
CONFIG_LIGHT_GPIO_RED=14
|
||||
CONFIG_LIGHT_GPIO_GREEN=13
|
||||
CONFIG_LIGHT_GPIO_BLUE=12
|
||||
CONFIG_LIGHT_GPIO_COLD=11
|
||||
CONFIG_LIGHT_GPIO_WARM=10
|
||||
# end of light driver config
|
@ -1,12 +1,5 @@
|
||||
|
||||
set(COMPONENT_SRCS
|
||||
"light_driver.c"
|
||||
"iot_led.c"
|
||||
"led_strip_encoder.c")
|
||||
|
||||
set(COMPONENT_ADD_INCLUDEDIRS ". include")
|
||||
|
||||
# requirements can't depend on config
|
||||
set(COMPONENT_REQUIRES example_nvs driver)
|
||||
set(COMPONENT_REQUIRES example_nvs driver lightbulb_driver)
|
||||
|
||||
register_component()
|
||||
|
@ -1,22 +1,3 @@
|
||||
# Component: Light
|
||||
# Source
|
||||
|
||||
* This component defines a light as a well encapsulated object.
|
||||
* A light device is defined by:
|
||||
* ledc timer which is used to control the pwm channels of light
|
||||
* mode of the ledc timer
|
||||
* frequency of the ledc timer
|
||||
* pwm channel number of the light
|
||||
* bit number of the ledc timer
|
||||
* A light device can provide:
|
||||
* iot_light_channel_regist function to add channel to corresponding channel id
|
||||
* iot_light_duty_write function to set the duty of corresponding channel and it support setting duty directly or gradually
|
||||
* iot_light_breath_write function to set the corresponding channel to breath mode and breath period can be set
|
||||
* iot_light_blink_starte and iot_light_blink_stop function to make some of channels to blink in appointed period. Note that if any channel works in blink mode, all the other channels would be turned off.
|
||||
|
||||
* To use the light device, you need to:
|
||||
* create a light object returned by iot_light_create()
|
||||
* regist the light channels according the channel number by iot_light_channel_regist()
|
||||
* To free the object, you can call iot_light_delete to delete the button object and free the memory.
|
||||
|
||||
### NOTE:
|
||||
> If any channel(s) work(s) in blink mode, all the other channels would be turned off. iot_light_blink_stop() must be called before setting any channel to other mode(write duty or breath).
|
||||
The `light_driver` component is taken from https://github.com/espressif/esp-iot-solution/tree/master/components/led/lightbulb_driver via idf_component.yml
|
@ -0,0 +1,3 @@
|
||||
## IDF Component Manager Manifest File
|
||||
dependencies:
|
||||
espressif/lightbulb_driver: "==0.5.5"
|
@ -1,167 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __IOT_LED_H__
|
||||
#define __IOT_LED_H__
|
||||
|
||||
#include "driver/ledc.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define GAMMA_CORRECTION 0.8 /**< Gamma curve parameter */
|
||||
#define GAMMA_TABLE_SIZE 256 /**< Gamma table size, used for led fade*/
|
||||
#define DUTY_SET_CYCLE (20) /**< Set duty cycle */
|
||||
|
||||
/**
|
||||
* Macro which can be used to check the error code,
|
||||
* and terminate the program in case the code is not ESP_OK.
|
||||
* Prints the error code, error location, and the failed statement to serial output.
|
||||
*
|
||||
* Disabled if assertions are disabled.
|
||||
*/
|
||||
#define LIGHT_ERROR_CHECK(con, err, format, ...) do { \
|
||||
if (con) { \
|
||||
if(*format != '\0') \
|
||||
ESP_LOGW(TAG, "<%s> " format, esp_err_to_name(err), ##__VA_ARGS__); \
|
||||
return err; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define LIGHT_PARAM_CHECK(con) do { \
|
||||
if (!(con)) { \
|
||||
ESP_LOGE(TAG, "<ESP_ERR_INVALID_ARG> !(%s)", #con); \
|
||||
return ESP_ERR_INVALID_ARG; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
/**
|
||||
* @brief Initialize and set the ledc timer for the iot led
|
||||
*
|
||||
* @param timer_num The timer index of ledc timer group used for iot led
|
||||
* This parameter can be one of LEDC_TIMER_x where x can be (0 .. 3)
|
||||
*
|
||||
* @param speed_mode speed mode of ledc timer
|
||||
* This parameter can be one of LEDC_x_SPEED_MODE where x can be (LOW, HIGH)
|
||||
*
|
||||
* @param freq_hz frequency of ledc timer
|
||||
* This parameter must be less than 5000
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK if sucess
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_FAIL Can not find a proper pre-divider number base on the given frequency
|
||||
* and the current duty_resolution.
|
||||
*/
|
||||
esp_err_t iot_led_init(ledc_timer_t timer_num, ledc_mode_t speed_mode, uint32_t freq_hz);
|
||||
|
||||
/**
|
||||
* @brief DeInitializes the iot led and free resource
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK if sucess
|
||||
*/
|
||||
esp_err_t iot_led_deinit(void);
|
||||
|
||||
/**
|
||||
* @brief Set the ledc channel used by iot led and associate the gpio port used
|
||||
* for output
|
||||
*
|
||||
* @param channel The ledc channel
|
||||
* This parameter can be LEDC_CHANNEL_x where x can be (0 .. 15)
|
||||
* @param gpio_num the ledc output gpio_num
|
||||
* This parameter can be GPIO_NUM_x where x can be (0, 33)
|
||||
*
|
||||
* @note If the operation of esp32 depends on SPI FLASH or PSRAM, then these related
|
||||
* pins should not be set to output.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK if sucess
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t iot_led_regist_channel(ledc_channel_t channel, gpio_num_t gpio_num);
|
||||
|
||||
/**
|
||||
* @brief Returns the channel value
|
||||
* @note before calling this function, you need to call iot_led_regist_channel() to
|
||||
* set the channel
|
||||
*
|
||||
* @param channel The ledc channel
|
||||
* This parameter can be LEDC_CHANNEL_x where x can be (0 .. 15)
|
||||
* @param dst The address where the channel value is stored
|
||||
* @return
|
||||
* - ESP_OK if sucess
|
||||
* - ESP_ERR_INVALID_ARG if dst is NULL
|
||||
*/
|
||||
esp_err_t iot_led_get_channel(ledc_channel_t channel, uint8_t *dst);
|
||||
|
||||
/**
|
||||
* @brief Set the fade state for the specified channel
|
||||
* @note before calling this function, you need to call iot_led_regist_channel() to
|
||||
* set the channel
|
||||
*
|
||||
* @param channel The ledc channel
|
||||
* This parameter can be LEDC_CHANNEL_x where x can be (0 .. 15)
|
||||
* @param value The target output brightness of iot led
|
||||
* This parameter can be (0 .. 255)
|
||||
* @param fade_ms The time from the current value to the target value
|
||||
* @return
|
||||
* - ESP_OK if sucess
|
||||
*/
|
||||
esp_err_t iot_led_set_channel(ledc_channel_t channel, uint8_t value, uint32_t fade_ms);
|
||||
|
||||
/**
|
||||
* @brief Set the blink state or loop fade for the specified channel
|
||||
* @note before calling this function, you need to call iot_led_regist_channel() to
|
||||
* set the channel
|
||||
*
|
||||
* @param channel The ledc channel
|
||||
* This parameter can be LEDC_CHANNEL_x where x can be (0 .. 15)
|
||||
* @param value The output brightness of iot led
|
||||
* This parameter can be (0 .. 255)
|
||||
* @param period_ms Blink cycle
|
||||
* @param fade_flag select loop fade or blink
|
||||
* 1 for loop fade
|
||||
* 0 for blink
|
||||
* @return
|
||||
* - ESP_OK if sucess
|
||||
*/
|
||||
esp_err_t iot_led_start_blink(ledc_channel_t channel, uint8_t value, uint32_t period_ms, bool fade_flag);
|
||||
|
||||
/**
|
||||
* @brief Stop the blink state or loop fade for the specified channel
|
||||
*
|
||||
* @param channel The ledc channel
|
||||
* This parameter can be LEDC_CHANNEL_x where x can be (0 .. 15)
|
||||
* @return
|
||||
* - ESP_OK if sucess
|
||||
*/
|
||||
esp_err_t iot_led_stop_blink(ledc_channel_t channel);
|
||||
|
||||
/**
|
||||
* @brief Set the specified gamma_table to control the fade effect, usually
|
||||
* no need to set
|
||||
*
|
||||
* @param gamma_table[GAMMA_TABLE_SIZE] Expected gamma table value
|
||||
*
|
||||
* @note Gamma_table is the dimming curve used by the iot_led driver.
|
||||
* The element type is uint16_t. Each element is treated as a binary
|
||||
* fixed-point number. The decimal point is before the eighth bit
|
||||
* and after the ninth bit, so the range of expressions can be
|
||||
* 0x00.00 ~ 0xff.ff.
|
||||
* @note default gamma_table is created in iot_led_init()
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK if sucess
|
||||
*/
|
||||
esp_err_t iot_led_set_gamma_table(const uint16_t gamma_table[GAMMA_TABLE_SIZE]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /**< __IOT_LED_H__ */
|
@ -1,142 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __IOT_LIGHT_H__
|
||||
#define __IOT_LIGHT_H__
|
||||
|
||||
#include "driver/ledc.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void *light_handle_t;
|
||||
|
||||
#define DUTY_SET_CYCLE (20) /**< Set duty cycle */
|
||||
#define DUTY_SET_GAMMA (0.6) /**< Set the Gamma value for the fade curve, default value is 0.6 */
|
||||
|
||||
#define LIGHT_MAX_CHANNEL_NUM (5)
|
||||
|
||||
/**
|
||||
* @brief light initialize
|
||||
*
|
||||
* @param timer the LEDC timer used by light
|
||||
* @param speed_mode speed mode of LEDC timer
|
||||
* @param freq_hz frequency of LEDC timer
|
||||
* @param channel_num decide how many channels the light contains
|
||||
* @param timer_bit LEDC PWM duty resolution
|
||||
*
|
||||
* @return the handle of light
|
||||
*/
|
||||
light_handle_t iot_light_create(ledc_timer_t timer, ledc_mode_t speed_mode, uint32_t freq_hz, uint8_t channel_num, ledc_timer_bit_t timer_bit);
|
||||
|
||||
/**
|
||||
* @brief add an output channel to light
|
||||
*
|
||||
* @param light_handle light handle
|
||||
* @param channel_idx the id of channel (0 ~ channel_num-1)
|
||||
* @param io_num the IO number use to output LEDC PWM
|
||||
* @param channel the ledc channel you want to use
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - others: fail
|
||||
*/
|
||||
esp_err_t iot_light_channel_regist(light_handle_t light_handle, uint8_t channel_idx, gpio_num_t io_num, ledc_channel_t channel);
|
||||
|
||||
/**
|
||||
* @brief free the memory of light
|
||||
*
|
||||
* @param light_handle light handle
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - others: fail
|
||||
*/
|
||||
esp_err_t iot_light_delete(light_handle_t light_handle);
|
||||
|
||||
/**
|
||||
* @brief get channel duty
|
||||
*
|
||||
* @param light_handle light handle
|
||||
* @param channel_id the id of channel (0 ~ channel_num-1)
|
||||
*
|
||||
* @return
|
||||
* - LEDC_ERR_DUTY if parameter error
|
||||
* - Others Current LEDC duty
|
||||
*/
|
||||
uint32_t iot_light_duty_get(light_handle_t light_handle, uint8_t channel_id);
|
||||
|
||||
/**
|
||||
* @brief set light fade with time. if set fade_period_ms as 0, set the duty directly.
|
||||
*
|
||||
* @param light_handle light handle
|
||||
* @param channel_id the id of channel (0 ~ channel_num-1)
|
||||
* @param duty target duty
|
||||
* @param fade_period_ms fade time (uint: ms)
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - others: fail
|
||||
*/
|
||||
esp_err_t iot_light_fade_with_time(light_handle_t light_handle, uint8_t channel_id, uint32_t duty, uint32_t fade_period_ms);
|
||||
|
||||
/**
|
||||
* @brief set breath config of a light channel, call `iot_light_operate_start` to start breath operation
|
||||
*
|
||||
* @param light_handle light handle
|
||||
* @param channel_id the id of channel (0 ~ channel_num-1)
|
||||
* @param duty the maximum duty when breath
|
||||
* @param breath_period_ms breath period (uint: ms)
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - others: fail
|
||||
*/
|
||||
esp_err_t iot_light_breath_config(light_handle_t light_handle, uint8_t channel_id, uint32_t duty, uint32_t breath_period_ms);
|
||||
|
||||
/**
|
||||
* @brief set blink config of a light channel, call `iot_light_operate_start` to start blink operation
|
||||
*
|
||||
* @param light_handle light handle
|
||||
* @param channel_id the id of channel (0 ~ channel_num-1)
|
||||
* @param blink_period_ms blink period (uint: ms)
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - others: fail
|
||||
*/
|
||||
esp_err_t iot_light_blink_config(light_handle_t light_handle, uint8_t channel_id, uint32_t blink_period_ms);
|
||||
|
||||
/**
|
||||
* @brief start breath or blink operation, user need to set breath or blink config before call this API
|
||||
*
|
||||
* @param light_handle light handle
|
||||
* @param channel_id the id of channel (0 ~ channel_num-1)
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - others: fail
|
||||
*/
|
||||
esp_err_t iot_light_operate_start(light_handle_t light_handle, uint8_t channel_id);
|
||||
|
||||
/**
|
||||
* @brief stop breath or blink operation
|
||||
*
|
||||
* @param light_handle light handle
|
||||
* @param channel_id the id of channel (0 ~ channel_num-1)
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - others: fail
|
||||
*/
|
||||
esp_err_t iot_light_operate_stop(light_handle_t light_handle, uint8_t channel_id);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /**< __IOT_LIGHT_H__ */
|
@ -1,41 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
|
||||
|
||||
|
||||
void rmt_encoder_init(void);
|
||||
void rmt_led_set(uint8_t red, uint8_t green, uint8_t blue);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -1,158 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __LIGHT_DRIVER_H__
|
||||
#define __LIGHT_DRIVER_H__
|
||||
|
||||
#include "iot_led.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define LIGHT_STATUS_STORE_KEY "light_status"
|
||||
|
||||
/**
|
||||
* @brief The mode of the five-color light
|
||||
*/
|
||||
typedef enum light_mode {
|
||||
MODE_NONE = 0,
|
||||
MODE_RGB = 1,
|
||||
MODE_HSV = 2,
|
||||
MODE_CTB = 3,
|
||||
MODE_ON = 4,
|
||||
MODE_OFF = 5,
|
||||
MODE_HUE_INCREASE = 4,
|
||||
MODE_HUE_DECREASE = 5,
|
||||
MODE_WARM_INCREASE = 6,
|
||||
MODE_WARM_DECREASE = 7,
|
||||
MODE_BRIGHTNESS_INCREASE = 8,
|
||||
MODE_BRIGHTNESS_DECREASE = 9,
|
||||
MODE_HSL = 10,
|
||||
} light_mode_t;
|
||||
|
||||
/**
|
||||
* @brief Light driven configuration
|
||||
*/
|
||||
typedef struct {
|
||||
gpio_num_t gpio_red; /**< Red corresponds to GPIO */
|
||||
gpio_num_t gpio_green; /**< Green corresponds to GPIO */
|
||||
gpio_num_t gpio_blue; /**< Blue corresponds to GPIO */
|
||||
gpio_num_t gpio_cold; /**< Cool corresponds to GPIO */
|
||||
gpio_num_t gpio_warm; /**< Warm corresponds to GPIO */
|
||||
uint32_t fade_period_ms; /**< The time from the current color to the next color */
|
||||
uint32_t blink_period_ms; /**< Period of flashing lights */
|
||||
} light_driver_config_t;
|
||||
|
||||
/**
|
||||
* @brief Light initialize
|
||||
*
|
||||
* @param config [description]
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK
|
||||
* - ESP_ERR_INVALID_ARG
|
||||
*/
|
||||
esp_err_t light_driver_init(light_driver_config_t *config);
|
||||
|
||||
/**
|
||||
* @brief Light deinitialize
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK
|
||||
* - ESP_ERR_INVALID_ARG
|
||||
*/
|
||||
esp_err_t light_driver_deinit(void);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the fade time of the light
|
||||
*
|
||||
* @param fade_period_ms The time from the current color to the next color
|
||||
* @param blink_period_ms Light flashing frequency
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK
|
||||
* - ESP_FAIL
|
||||
*/
|
||||
esp_err_t light_driver_config(uint32_t fade_period_ms, uint32_t blink_period_ms);
|
||||
|
||||
/**@{*/
|
||||
/**
|
||||
* @brief Set the status of the light
|
||||
*
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK
|
||||
* - ESP_ERR_INVALID_ARG
|
||||
*/
|
||||
esp_err_t light_driver_set_hue(uint16_t hue);
|
||||
esp_err_t light_driver_set_saturation(uint8_t saturation);
|
||||
esp_err_t light_driver_set_value(uint8_t value);
|
||||
esp_err_t light_driver_set_color_temperature(uint8_t color_temperature);
|
||||
esp_err_t light_driver_set_brightness(uint8_t brightness);
|
||||
esp_err_t light_driver_set_hsv(uint16_t hue, uint8_t saturation, uint8_t value);
|
||||
esp_err_t light_driver_set_hsl(uint16_t hue, uint8_t saturation, uint8_t lightness);
|
||||
esp_err_t light_driver_set_lightness(uint8_t lightness);
|
||||
esp_err_t light_driver_set_ctb(uint8_t color_temperature, uint8_t brightness);
|
||||
esp_err_t light_driver_set_switch(bool status);
|
||||
esp_err_t light_driver_set_mode(light_mode_t mode);
|
||||
|
||||
/**@}*/
|
||||
|
||||
/**@{*/
|
||||
/**
|
||||
* @brief Set the status of the light
|
||||
*/
|
||||
uint16_t light_driver_get_hue(void);
|
||||
uint8_t light_driver_get_saturation(void);
|
||||
uint8_t light_driver_get_value(void);
|
||||
esp_err_t light_driver_get_hsv(uint16_t *hue, uint8_t *saturation, uint8_t *value);
|
||||
uint8_t light_driver_get_lightness(void);
|
||||
esp_err_t light_driver_get_hsl(uint16_t *hue, uint8_t *saturation, uint8_t *lightness);
|
||||
uint8_t light_driver_get_color_temperature(void);
|
||||
uint8_t light_driver_get_brightness(void);
|
||||
esp_err_t light_driver_get_ctb(uint8_t *color_temperature, uint8_t *brightness);
|
||||
bool light_driver_get_switch(void);
|
||||
uint8_t light_driver_get_mode(void);
|
||||
/**@}*/
|
||||
|
||||
/**@{*/
|
||||
/**
|
||||
* @brief Used to indicate the operating mode, such as configuring the network mode, upgrading mode
|
||||
*
|
||||
* @note The state of the light is not saved in nvs
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK
|
||||
* - ESP_ERR_INVALID_ARG
|
||||
*/
|
||||
esp_err_t light_driver_set_rgb(uint8_t red, uint8_t green, uint8_t blue);
|
||||
esp_err_t light_driver_breath_start(uint8_t red, uint8_t green, uint8_t blue);
|
||||
esp_err_t light_driver_breath_stop(void);
|
||||
esp_err_t light_driver_blink_start(uint8_t red, uint8_t green, uint8_t blue);
|
||||
esp_err_t light_driver_blink_stop(void);
|
||||
/**@}*/
|
||||
|
||||
/**@{*/
|
||||
/**
|
||||
* @brief Color gradient
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK
|
||||
* - ESP_ERR_INVALID_ARG
|
||||
*/
|
||||
esp_err_t light_driver_fade_brightness(uint8_t brightness);
|
||||
esp_err_t light_driver_fade_hue(uint16_t hue);
|
||||
esp_err_t light_driver_fade_warm(uint8_t color_temperature);
|
||||
esp_err_t light_driver_fade_stop(void);
|
||||
/**@}*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif/**< __LIGHT_DRIVER_H__ */
|
@ -1,481 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <math.h>
|
||||
#include "soc/ledc_reg.h"
|
||||
#include "soc/timer_group_struct.h"
|
||||
#include "soc/ledc_struct.h"
|
||||
#include "driver/gptimer.h"
|
||||
#include "driver/ledc.h"
|
||||
#include "esp_attr.h"
|
||||
#include "iot_led.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#define LEDC_FADE_MARGIN (10)
|
||||
#define LEDC_VALUE_TO_DUTY(value) (value * ((1 << LEDC_TIMER_13_BIT) - 1) / UINT16_MAX)
|
||||
#define LEDC_DUTY_TO_VALUE(value) (value * UINT16_MAX / ((1 << LEDC_TIMER_13_BIT) - 1) )
|
||||
#define LEDC_FIXED_Q (8)
|
||||
#define FLOATINT_2_FIXED(X, Q) ((int)((X)*(0x1U << Q)))
|
||||
#define FIXED_2_FLOATING(X, Q) ((int)((X)/(0x1U << Q)))
|
||||
#define GET_FIXED_INTEGER_PART(X, Q) (X >> Q)
|
||||
#define GET_FIXED_DECIMAL_PART(X, Q) (X & ((0x1U << Q) - 1))
|
||||
|
||||
#define GPTIMER_RESOLUTION_HZ 1000000 // 1MHz, 1 tick=1us
|
||||
|
||||
#if (CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S3)
|
||||
|
||||
typedef struct {
|
||||
int cur;
|
||||
int final;
|
||||
int step;
|
||||
int cycle;
|
||||
size_t num;
|
||||
} ledc_fade_data_t;
|
||||
|
||||
typedef struct {
|
||||
ledc_fade_data_t fade_data[LEDC_CHANNEL_MAX];
|
||||
ledc_mode_t speed_mode;
|
||||
ledc_timer_t timer_num;
|
||||
gptimer_handle_t gptimer;
|
||||
} iot_light_t;
|
||||
|
||||
static const char *TAG = "iot_light";
|
||||
static DRAM_ATTR iot_light_t *g_light_config = NULL;
|
||||
static DRAM_ATTR uint16_t *g_gamma_table = NULL;
|
||||
static DRAM_ATTR bool g_hw_timer_started = false;
|
||||
|
||||
static bool fade_timercb(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_ctx);
|
||||
|
||||
static void iot_timer_start(gptimer_handle_t gptimer)
|
||||
{
|
||||
gptimer_alarm_config_t alarm_config = {
|
||||
.reload_count = 0,
|
||||
.alarm_count = DUTY_SET_CYCLE / 1000 * GPTIMER_RESOLUTION_HZ,
|
||||
.flags.auto_reload_on_alarm = true,
|
||||
};
|
||||
gptimer_set_alarm_action(gptimer, &alarm_config);
|
||||
gptimer_start(gptimer);
|
||||
g_hw_timer_started = true;
|
||||
}
|
||||
|
||||
static IRAM_ATTR void iot_timer_stop(gptimer_handle_t gptimer)
|
||||
{
|
||||
gptimer_stop(gptimer);
|
||||
g_hw_timer_started = false;
|
||||
}
|
||||
|
||||
static IRAM_ATTR esp_err_t iot_ledc_duty_config(ledc_mode_t speed_mode, ledc_channel_t channel, int hpoint_val, int duty_val,
|
||||
uint32_t duty_direction, uint32_t duty_num, uint32_t duty_cycle, uint32_t duty_scale)
|
||||
{
|
||||
if (hpoint_val >= 0) {
|
||||
#if CONFIG_IDF_TARGET_ESP32C3
|
||||
LEDC.channel_group[speed_mode].channel[channel].hpoint.hpoint = hpoint_val & LEDC_HPOINT_LSCH1_V;
|
||||
#elif CONFIG_IDF_TARGET_ESP32
|
||||
LEDC.channel_group[speed_mode].channel[channel].hpoint.hpoint = hpoint_val & LEDC_HPOINT_HSCH1_V;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (duty_val >= 0) {
|
||||
LEDC.channel_group[speed_mode].channel[channel].duty.duty = duty_val;
|
||||
}
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32C3
|
||||
LEDC.channel_group[speed_mode].channel[channel].conf1.val = ((duty_direction & LEDC_DUTY_INC_LSCH0_V) << LEDC_DUTY_INC_LSCH0_S) |
|
||||
((duty_num & LEDC_DUTY_NUM_LSCH0_V) << LEDC_DUTY_NUM_LSCH0_S) |
|
||||
((duty_cycle & LEDC_DUTY_CYCLE_LSCH0_V) << LEDC_DUTY_CYCLE_LSCH0_S) |
|
||||
((duty_scale & LEDC_DUTY_SCALE_LSCH0_V) << LEDC_DUTY_SCALE_LSCH0_S);
|
||||
#elif CONFIG_IDF_TARGET_ESP32
|
||||
LEDC.channel_group[speed_mode].channel[channel].conf1.val = ((duty_direction & LEDC_DUTY_INC_HSCH0_V) << LEDC_DUTY_INC_HSCH0_S) |
|
||||
((duty_num & LEDC_DUTY_NUM_HSCH0_V) << LEDC_DUTY_NUM_HSCH0_S) |
|
||||
((duty_cycle & LEDC_DUTY_CYCLE_HSCH0_V) << LEDC_DUTY_CYCLE_HSCH0_S) |
|
||||
((duty_scale & LEDC_DUTY_SCALE_HSCH0_V) << LEDC_DUTY_SCALE_HSCH0_S);
|
||||
#endif
|
||||
|
||||
LEDC.channel_group[speed_mode].channel[channel].conf0.sig_out_en = 1;
|
||||
LEDC.channel_group[speed_mode].channel[channel].conf1.duty_start = 1;
|
||||
|
||||
if (speed_mode == LEDC_LOW_SPEED_MODE) {
|
||||
LEDC.channel_group[speed_mode].channel[channel].conf0.low_speed_update = 1;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static IRAM_ATTR esp_err_t _iot_set_fade_with_step(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t target_duty, int scale, int cycle_num)
|
||||
{
|
||||
uint32_t duty_cur = LEDC.channel_group[speed_mode].channel[channel].duty_rd.duty_read >> 4;
|
||||
int step_num = 0;
|
||||
int dir = LEDC_DUTY_DIR_DECREASE;
|
||||
|
||||
if (scale > 0) {
|
||||
if (duty_cur > target_duty) {
|
||||
step_num = (duty_cur - target_duty) / scale;
|
||||
step_num = step_num > 1023 ? 1023 : step_num;
|
||||
scale = (step_num == 1023) ? (duty_cur - target_duty) / step_num : scale;
|
||||
} else {
|
||||
dir = LEDC_DUTY_DIR_INCREASE;
|
||||
step_num = (target_duty - duty_cur) / scale;
|
||||
step_num = step_num > 1023 ? 1023 : step_num;
|
||||
scale = (step_num == 1023) ? (target_duty - duty_cur) / step_num : scale;
|
||||
}
|
||||
}
|
||||
|
||||
if (scale > 0 && step_num > 0) {
|
||||
iot_ledc_duty_config(speed_mode, channel, -1, duty_cur << 4, dir, step_num, cycle_num, scale);
|
||||
} else {
|
||||
iot_ledc_duty_config(speed_mode, channel, -1, target_duty << 4, dir, 0, 1, 0);
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static IRAM_ATTR esp_err_t _iot_set_fade_with_time(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t target_duty, int max_fade_time_ms)
|
||||
{
|
||||
uint32_t freq = 0;
|
||||
uint32_t duty_cur = LEDC.channel_group[speed_mode].channel[channel].duty_rd.duty_read >> 4;
|
||||
uint32_t duty_delta = target_duty > duty_cur ? target_duty - duty_cur : duty_cur - target_duty;
|
||||
|
||||
uint32_t timer_source_clk = LEDC.timer_group[speed_mode].timer[g_light_config->timer_num].conf.tick_sel;
|
||||
uint32_t duty_resolution = LEDC.timer_group[speed_mode].timer[g_light_config->timer_num].conf.duty_resolution;
|
||||
uint32_t clock_divider = LEDC.timer_group[speed_mode].timer[g_light_config->timer_num].conf.clock_divider;
|
||||
uint32_t precision = (0x1U << duty_resolution);
|
||||
|
||||
if (timer_source_clk == LEDC_APB_CLK) {
|
||||
freq = ((uint64_t)APB_CLK_FREQ << 8) / precision / clock_divider;
|
||||
} else {
|
||||
freq = ((uint64_t)REF_CLK_FREQ << 8) / precision / clock_divider;
|
||||
}
|
||||
|
||||
if (duty_delta == 0) {
|
||||
return _iot_set_fade_with_step(speed_mode, channel, target_duty, 0, 0);
|
||||
}
|
||||
|
||||
int total_cycles = max_fade_time_ms * freq / 1000;
|
||||
|
||||
if (total_cycles == 0) {
|
||||
return _iot_set_fade_with_step(speed_mode, channel, target_duty, 0, 0);
|
||||
}
|
||||
|
||||
int scale, cycle_num;
|
||||
|
||||
if (total_cycles > duty_delta) {
|
||||
scale = 1;
|
||||
cycle_num = total_cycles / duty_delta;
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32C3
|
||||
if (cycle_num > LEDC_DUTY_NUM_LSCH0_V) {
|
||||
cycle_num = LEDC_DUTY_NUM_LSCH0_V;
|
||||
}
|
||||
#elif CONFIG_IDF_TARGET_ESP32
|
||||
if (cycle_num > LEDC_DUTY_NUM_HSCH0_V) {
|
||||
cycle_num = LEDC_DUTY_NUM_HSCH0_V;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
cycle_num = 1;
|
||||
scale = duty_delta / total_cycles;
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32C3
|
||||
if (scale > LEDC_DUTY_SCALE_LSCH0_V) {
|
||||
scale = LEDC_DUTY_SCALE_LSCH0_V;
|
||||
}
|
||||
#elif CONFIG_IDF_TARGET_ESP32
|
||||
if (scale > LEDC_DUTY_SCALE_HSCH0_V) {
|
||||
scale = LEDC_DUTY_SCALE_HSCH0_V;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return _iot_set_fade_with_step(speed_mode, channel, target_duty, scale, cycle_num);
|
||||
}
|
||||
|
||||
static IRAM_ATTR esp_err_t _iot_update_duty(ledc_mode_t speed_mode, ledc_channel_t channel)
|
||||
{
|
||||
LEDC.channel_group[speed_mode].channel[channel].conf0.sig_out_en = 1;
|
||||
LEDC.channel_group[speed_mode].channel[channel].conf1.duty_start = 1;
|
||||
|
||||
if (speed_mode == LEDC_LOW_SPEED_MODE) {
|
||||
LEDC.channel_group[speed_mode].channel[channel].conf0.low_speed_update = 1;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static IRAM_ATTR esp_err_t iot_ledc_set_duty(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t duty)
|
||||
{
|
||||
return iot_ledc_duty_config(speed_mode,
|
||||
channel, // uint32_t chan_num,
|
||||
-1,
|
||||
duty << 4, // uint32_t duty_val,the least 4 bits are decimal part
|
||||
1, // uint32_t increase,
|
||||
1, // uint32_t duty_num,
|
||||
1, // uint32_t duty_cycle,
|
||||
0 // uint32_t duty_scale
|
||||
);
|
||||
}
|
||||
|
||||
static void gamma_table_create(uint16_t *gamma_table, float correction)
|
||||
{
|
||||
float value_tmp = 0;
|
||||
|
||||
/**
|
||||
* @brief gamma curve formula: y=a*x^(1/gm)
|
||||
* x ∈ (0,(GAMMA_TABLE_SIZE-1)/GAMMA_TABLE_SIZE)
|
||||
* a = GAMMA_TABLE_SIZE
|
||||
*/
|
||||
for (int i = 0; i < GAMMA_TABLE_SIZE; i++) {
|
||||
value_tmp = (float)(i) / GAMMA_TABLE_SIZE;
|
||||
value_tmp = powf(value_tmp, 1.0f / correction);
|
||||
gamma_table[i] = (uint16_t)FLOATINT_2_FIXED((value_tmp * GAMMA_TABLE_SIZE), LEDC_FIXED_Q);
|
||||
}
|
||||
}
|
||||
|
||||
static IRAM_ATTR uint32_t gamma_value_to_duty(int value)
|
||||
{
|
||||
uint32_t tmp_q = GET_FIXED_INTEGER_PART(value, LEDC_FIXED_Q);
|
||||
uint32_t tmp_r = GET_FIXED_DECIMAL_PART(value, LEDC_FIXED_Q);
|
||||
|
||||
uint16_t cur = LEDC_VALUE_TO_DUTY(g_gamma_table[tmp_q]);
|
||||
uint16_t next = LEDC_VALUE_TO_DUTY(g_gamma_table[tmp_q + 1]);
|
||||
return (cur + (next - cur) * tmp_r / (0x1U << LEDC_FIXED_Q));
|
||||
}
|
||||
|
||||
static IRAM_ATTR bool fade_timercb(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_ctx)
|
||||
{
|
||||
int idle_channel_num = 0;
|
||||
|
||||
for (int channel = 0; channel < LEDC_CHANNEL_MAX; channel++) {
|
||||
ledc_fade_data_t *fade_data = g_light_config->fade_data + channel;
|
||||
|
||||
if (fade_data->num > 0) {
|
||||
fade_data->num--;
|
||||
|
||||
if (fade_data->step) {
|
||||
fade_data->cur += fade_data->step;
|
||||
|
||||
if (fade_data->num != 0) {
|
||||
_iot_set_fade_with_time(g_light_config->speed_mode, channel,
|
||||
gamma_value_to_duty(fade_data->cur),
|
||||
DUTY_SET_CYCLE - LEDC_FADE_MARGIN);
|
||||
} else {
|
||||
iot_ledc_set_duty(g_light_config->speed_mode, channel, gamma_value_to_duty(fade_data->cur));
|
||||
}
|
||||
|
||||
_iot_update_duty(g_light_config->speed_mode, channel);
|
||||
} else {
|
||||
iot_ledc_set_duty(g_light_config->speed_mode, channel, gamma_value_to_duty(fade_data->cur));
|
||||
_iot_update_duty(g_light_config->speed_mode, channel);
|
||||
}
|
||||
} else if (fade_data->cycle) {
|
||||
fade_data->num = fade_data->cycle - 1;
|
||||
|
||||
if (fade_data->step) {
|
||||
fade_data->step *= -1;
|
||||
fade_data->cur += fade_data->step;
|
||||
} else {
|
||||
fade_data->cur = (fade_data->cur == fade_data->final) ? 0 : fade_data->final;
|
||||
}
|
||||
|
||||
_iot_set_fade_with_time(g_light_config->speed_mode, channel,
|
||||
gamma_value_to_duty(fade_data->cur),
|
||||
DUTY_SET_CYCLE - LEDC_FADE_MARGIN);
|
||||
_iot_update_duty(g_light_config->speed_mode, channel);
|
||||
|
||||
} else {
|
||||
idle_channel_num++;
|
||||
}
|
||||
}
|
||||
|
||||
if (idle_channel_num >= LEDC_CHANNEL_MAX) {
|
||||
iot_timer_stop(timer);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
esp_err_t iot_led_init(ledc_timer_t timer_num, ledc_mode_t speed_mode, uint32_t freq_hz)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
const ledc_timer_config_t ledc_time_config = {
|
||||
.speed_mode = speed_mode,
|
||||
.timer_num = timer_num,
|
||||
.freq_hz = freq_hz,
|
||||
.duty_resolution = LEDC_TIMER_13_BIT,
|
||||
};
|
||||
|
||||
ret = ledc_timer_config(&ledc_time_config);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGW(TAG, "LEDC timer configuration");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (g_gamma_table == NULL) {
|
||||
g_gamma_table = calloc(GAMMA_TABLE_SIZE, sizeof(uint16_t));
|
||||
gamma_table_create(g_gamma_table, GAMMA_CORRECTION);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "gamma_table has been initialized");
|
||||
}
|
||||
|
||||
if (g_light_config == NULL) {
|
||||
g_light_config = calloc(1, sizeof(iot_light_t));
|
||||
g_light_config->timer_num = timer_num;
|
||||
g_light_config->speed_mode = speed_mode;
|
||||
|
||||
gptimer_config_t timer_config = {
|
||||
.clk_src = GPTIMER_CLK_SRC_DEFAULT,
|
||||
.direction = GPTIMER_COUNT_UP,
|
||||
.resolution_hz = GPTIMER_RESOLUTION_HZ,
|
||||
};
|
||||
ESP_ERROR_CHECK(gptimer_new_timer(&timer_config, &g_light_config->gptimer));
|
||||
gptimer_event_callbacks_t cbs = {
|
||||
.on_alarm = fade_timercb,
|
||||
};
|
||||
ESP_ERROR_CHECK(gptimer_register_event_callbacks(g_light_config->gptimer, &cbs, NULL));
|
||||
ESP_ERROR_CHECK(gptimer_enable(g_light_config->gptimer));
|
||||
} else {
|
||||
ESP_LOGE(TAG, "g_light_config has been initialized");
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t iot_led_deinit(void)
|
||||
{
|
||||
if (g_gamma_table) {
|
||||
free(g_gamma_table);
|
||||
}
|
||||
|
||||
if (g_light_config) {
|
||||
gptimer_disable(g_light_config->gptimer);
|
||||
gptimer_del_timer(g_light_config->gptimer);
|
||||
free(g_light_config);
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t iot_led_regist_channel(ledc_channel_t channel, gpio_num_t gpio_num)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
if (g_light_config == NULL) {
|
||||
ESP_LOGW(TAG, "iot_led_init() must be called first");
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
#ifdef CONFIG_SPIRAM_SUPPORT
|
||||
if (gpio_num != GPIO_NUM_16 || gpio_num != GPIO_NUM_17) {
|
||||
ESP_LOGW(TAG, "gpio_num must not conflict to PSRAM(IO16 && IO17)");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
#endif
|
||||
const ledc_channel_config_t ledc_ch_config = {
|
||||
.gpio_num = gpio_num,
|
||||
.channel = channel,
|
||||
.intr_type = LEDC_INTR_DISABLE,
|
||||
.speed_mode = g_light_config->speed_mode,
|
||||
.timer_sel = g_light_config->timer_num,
|
||||
};
|
||||
|
||||
ret = ledc_channel_config(&ledc_ch_config);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGW(TAG, "LEDC channel configuration");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t iot_led_get_channel(ledc_channel_t channel, uint8_t *dst)
|
||||
{
|
||||
if (g_light_config == NULL || dst == NULL) {
|
||||
ESP_LOGW(TAG, "iot_led_init() must be called first or dst should not be NULL");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
int cur = g_light_config->fade_data[channel].cur;
|
||||
*dst = FIXED_2_FLOATING(cur, LEDC_FIXED_Q);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t iot_led_set_channel(ledc_channel_t channel, uint8_t value, uint32_t fade_ms)
|
||||
{
|
||||
if (g_light_config == NULL) {
|
||||
ESP_LOGW(TAG, "iot_led_init() must be called first");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
ledc_fade_data_t *fade_data = g_light_config->fade_data + channel;
|
||||
|
||||
fade_data->final = FLOATINT_2_FIXED(value, LEDC_FIXED_Q);
|
||||
|
||||
if (fade_ms < DUTY_SET_CYCLE) {
|
||||
fade_data->num = 1;
|
||||
} else {
|
||||
fade_data->num = fade_ms / DUTY_SET_CYCLE;
|
||||
}
|
||||
|
||||
fade_data->step = abs(fade_data->cur - fade_data->final) / fade_data->num;
|
||||
|
||||
if (fade_data->cur > fade_data->final) {
|
||||
fade_data->step *= -1;
|
||||
}
|
||||
|
||||
if (fade_data->cycle != 0) {
|
||||
fade_data->cycle = 0;
|
||||
}
|
||||
|
||||
if (g_hw_timer_started != true) {
|
||||
iot_timer_start(g_light_config->gptimer);
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t iot_led_start_blink(ledc_channel_t channel, uint8_t value, uint32_t period_ms, bool fade_flag)
|
||||
{
|
||||
if (g_light_config == NULL) {
|
||||
ESP_LOGW(TAG, "iot_led_init() must be called first");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
ledc_fade_data_t *fade_data = g_light_config->fade_data + channel;
|
||||
|
||||
fade_data->final = fade_data->cur = FLOATINT_2_FIXED(value, LEDC_FIXED_Q);
|
||||
fade_data->cycle = period_ms / 2 / DUTY_SET_CYCLE;
|
||||
fade_data->num = (fade_flag) ? period_ms / 2 / DUTY_SET_CYCLE : 0;
|
||||
fade_data->step = (fade_flag) ? fade_data->cur / fade_data->num * -1 : 0;
|
||||
|
||||
if (g_hw_timer_started != true) {
|
||||
iot_timer_start(g_light_config->gptimer);
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
|
||||
}
|
||||
|
||||
esp_err_t iot_led_stop_blink(ledc_channel_t channel)
|
||||
{
|
||||
if (g_light_config == NULL) {
|
||||
ESP_LOGW(TAG, "iot_led_init() must be called first");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
ledc_fade_data_t *fade_data = g_light_config->fade_data + channel;
|
||||
fade_data->cycle = fade_data->num = 0;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t iot_led_set_gamma_table(const uint16_t gamma_table[GAMMA_TABLE_SIZE])
|
||||
{
|
||||
if (g_gamma_table == NULL) {
|
||||
ESP_LOGW(TAG, "iot_led_init() must be called first");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
memcpy(g_gamma_table, gamma_table, GAMMA_TABLE_SIZE * sizeof(uint16_t));
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#endif /* (IDF_TARGET_ESP32 || IDF_TARGET_ESP32S3) */
|
@ -1,459 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <sys/time.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/timers.h"
|
||||
#include "esp_log.h"
|
||||
#include "soc/ledc_reg.h"
|
||||
#include "soc/timer_group_struct.h"
|
||||
#include "soc/ledc_struct.h"
|
||||
#include "driver/gptimer.h"
|
||||
#include "driver/ledc.h"
|
||||
#include "iot_light.h"
|
||||
|
||||
static const char *TAG = "light";
|
||||
|
||||
#define IOT_CHECK(tag, a, ret) if(!(a)) { \
|
||||
return (ret); \
|
||||
}
|
||||
#define ERR_ASSERT(tag, param, ret) IOT_CHECK(tag, (param) == ESP_OK, ret)
|
||||
#define POINT_ASSERT(tag, param) IOT_CHECK(tag, (param) != NULL, ESP_FAIL)
|
||||
#define LIGHT_NUM_MAX 4
|
||||
|
||||
#define GPTIMER_RESOLUTION_HZ 1000000 // 1MHz, 1 tick=1us
|
||||
|
||||
typedef enum {
|
||||
LIGHT_CH_NUM_1 = 1, /*!< Light channel number */
|
||||
LIGHT_CH_NUM_2 = 2, /*!< Light channel number */
|
||||
LIGHT_CH_NUM_3 = 3, /*!< Light channel number */
|
||||
LIGHT_CH_NUM_4 = 4, /*!< Light channel number */
|
||||
LIGHT_CH_NUM_5 = 5, /*!< Light channel number */
|
||||
LIGHT_CH_NUM_MAX, /*!< user shouldn't use this */
|
||||
} light_channel_num_t;
|
||||
|
||||
typedef struct {
|
||||
gpio_num_t io_num;
|
||||
ledc_mode_t mode;
|
||||
ledc_channel_t channel;
|
||||
int breath_period;
|
||||
int blink_period;
|
||||
uint32_t fade_step_num;
|
||||
uint32_t *fade_duty_step;
|
||||
int fade_duty_counter;
|
||||
bool fade_step_up;
|
||||
bool fade_once;
|
||||
bool fade_start;
|
||||
} light_channel_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t channel_num;
|
||||
ledc_mode_t mode;
|
||||
ledc_timer_t ledc_timer;
|
||||
uint32_t full_duty;
|
||||
uint32_t freq_hz;
|
||||
ledc_timer_bit_t timer_bit;
|
||||
gptimer_handle_t gptimer;
|
||||
light_channel_t *channel_group[];
|
||||
} light_t;
|
||||
|
||||
static bool g_fade_installed = false;
|
||||
static bool g_hw_timer_started = false;
|
||||
static light_t *g_light_group[LIGHT_NUM_MAX] = {NULL};
|
||||
static esp_err_t iot_light_duty_set(light_handle_t light_handle, uint8_t channel_id, uint32_t duty);
|
||||
|
||||
static IRAM_ATTR void iot_ledc_ls_channel_update(ledc_mode_t speed_mode, ledc_channel_t channel_num)
|
||||
{
|
||||
if (speed_mode == LEDC_LOW_SPEED_MODE) {
|
||||
LEDC.channel_group[speed_mode].channel[channel_num].conf0.low_speed_update = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static IRAM_ATTR esp_err_t iot_ledc_duty_config(ledc_mode_t speed_mode, ledc_channel_t channel_num, int hpoint_val, int duty_val,
|
||||
uint32_t duty_direction, uint32_t duty_num, uint32_t duty_cycle, uint32_t duty_scale)
|
||||
{
|
||||
if (hpoint_val >= 0) {
|
||||
LEDC.channel_group[speed_mode].channel[channel_num].hpoint.hpoint = hpoint_val & LEDC_HPOINT_HSCH1_V;
|
||||
}
|
||||
|
||||
if (duty_val >= 0) {
|
||||
LEDC.channel_group[speed_mode].channel[channel_num].duty.duty = duty_val;
|
||||
}
|
||||
|
||||
LEDC.channel_group[speed_mode].channel[channel_num].conf1.val = ((duty_direction & LEDC_DUTY_INC_HSCH0_V) << LEDC_DUTY_INC_HSCH0_S) |
|
||||
((duty_num & LEDC_DUTY_NUM_HSCH0_V) << LEDC_DUTY_NUM_HSCH0_S) |
|
||||
((duty_cycle & LEDC_DUTY_CYCLE_HSCH0_V) << LEDC_DUTY_CYCLE_HSCH0_S) |
|
||||
((duty_scale & LEDC_DUTY_SCALE_HSCH0_V) << LEDC_DUTY_SCALE_HSCH0_S);
|
||||
iot_ledc_ls_channel_update(speed_mode, channel_num);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static IRAM_ATTR esp_err_t iot_ledc_set_duty(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t duty)
|
||||
{
|
||||
return iot_ledc_duty_config(speed_mode,
|
||||
channel, //uint32_t chan_num,
|
||||
-1,
|
||||
duty << 4, //uint32_t duty_val,the least 4 bits are decimal part
|
||||
1, //uint32_t increase,
|
||||
1, //uint32_t duty_num,
|
||||
1, //uint32_t duty_cycle,
|
||||
0 //uint32_t duty_scale
|
||||
);
|
||||
}
|
||||
|
||||
static IRAM_ATTR esp_err_t iot_ledc_update_duty(ledc_mode_t speed_mode, ledc_channel_t channel)
|
||||
{
|
||||
LEDC.channel_group[speed_mode].channel[channel].conf0.sig_out_en = 1;
|
||||
LEDC.channel_group[speed_mode].channel[channel].conf1.duty_start = 1;
|
||||
iot_ledc_ls_channel_update(speed_mode, channel);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static IRAM_ATTR bool breath_timer_callback(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_ctx)
|
||||
{
|
||||
for (int i = 0; i < LIGHT_NUM_MAX; i++) {
|
||||
if (g_light_group[i] != NULL) {
|
||||
light_t *light = g_light_group[i];
|
||||
|
||||
for (int j = 0; j < light->channel_num; j++) {
|
||||
light_channel_t *l_chn = light->channel_group[j];
|
||||
|
||||
if (l_chn->fade_start == true) {
|
||||
if (l_chn->fade_step_up == true) {
|
||||
l_chn->fade_duty_counter++;
|
||||
} else {
|
||||
l_chn->fade_duty_counter--;
|
||||
}
|
||||
|
||||
if ((l_chn->fade_duty_counter >= 0) && (l_chn->fade_duty_counter < l_chn->fade_step_num)) {
|
||||
iot_ledc_set_duty(l_chn->mode, l_chn->channel, l_chn->fade_duty_step[l_chn->fade_duty_counter]);
|
||||
iot_ledc_update_duty(l_chn->mode, l_chn->channel);
|
||||
} else {
|
||||
if (l_chn->fade_once != true) {
|
||||
l_chn->fade_step_up = 1 - l_chn->fade_step_up;
|
||||
} else {
|
||||
l_chn->fade_start = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static light_channel_t *light_channel_create(gpio_num_t io_num, ledc_channel_t channel, ledc_mode_t mode, ledc_timer_t timer)
|
||||
{
|
||||
ledc_channel_config_t ledc_channel = {
|
||||
.channel = channel,
|
||||
.duty = 0,
|
||||
.gpio_num = io_num,
|
||||
.intr_type = LEDC_INTR_FADE_END,
|
||||
.speed_mode = mode,
|
||||
.timer_sel = timer
|
||||
};
|
||||
ERR_ASSERT(TAG, ledc_channel_config(&ledc_channel), NULL);
|
||||
light_channel_t *pwm = (light_channel_t *)calloc(1, sizeof(light_channel_t));
|
||||
pwm->io_num = io_num;
|
||||
pwm->channel = channel;
|
||||
pwm->mode = mode;
|
||||
pwm->breath_period = 0;
|
||||
pwm->blink_period = 0;
|
||||
pwm->fade_step_num = 0;
|
||||
pwm->fade_duty_step = NULL;
|
||||
pwm->fade_duty_counter = 0;
|
||||
pwm->fade_step_up = true;
|
||||
pwm->fade_once = false;
|
||||
pwm->fade_start = false;
|
||||
return pwm;
|
||||
}
|
||||
|
||||
static esp_err_t light_channel_delete(light_channel_t *light_channel)
|
||||
{
|
||||
POINT_ASSERT(TAG, light_channel);
|
||||
|
||||
if (light_channel->fade_duty_step != NULL) {
|
||||
heap_caps_free(light_channel->fade_duty_step);
|
||||
light_channel->fade_duty_step = NULL;
|
||||
}
|
||||
|
||||
free(light_channel);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t light_channel_fade_clear(light_channel_t *light_channel)
|
||||
{
|
||||
light_channel->fade_start = false;
|
||||
light_channel->fade_step_num = 0;
|
||||
light_channel->fade_duty_counter = 0;
|
||||
light_channel->fade_step_up = true;
|
||||
light_channel->fade_once = false;
|
||||
|
||||
if (light_channel->fade_duty_step != NULL) {
|
||||
heap_caps_free(light_channel->fade_duty_step);
|
||||
light_channel->fade_duty_step = NULL;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
light_handle_t iot_light_create(ledc_timer_t timer, ledc_mode_t speed_mode, uint32_t freq_hz, uint8_t channel_num, ledc_timer_bit_t timer_bit)
|
||||
{
|
||||
IOT_CHECK(TAG, channel_num != 0, NULL);
|
||||
ledc_timer_config_t timer_conf = {
|
||||
.timer_num = timer,
|
||||
.speed_mode = speed_mode,
|
||||
.freq_hz = freq_hz,
|
||||
.bit_num = timer_bit
|
||||
};
|
||||
ERR_ASSERT(TAG, ledc_timer_config(&timer_conf), NULL);
|
||||
light_t *light_ptr = (light_t *)calloc(1, sizeof(light_t) + sizeof(light_channel_t *) * channel_num);
|
||||
light_ptr->channel_num = channel_num;
|
||||
light_ptr->ledc_timer = timer;
|
||||
light_ptr->full_duty = (1 << timer_bit) - 1;
|
||||
light_ptr->freq_hz = freq_hz;
|
||||
light_ptr->mode = speed_mode;
|
||||
light_ptr->timer_bit = timer_bit;
|
||||
|
||||
if (g_hw_timer_started == false) {
|
||||
gptimer_config_t timer_config = {
|
||||
.clk_src = GPTIMER_CLK_SRC_DEFAULT,
|
||||
.direction = GPTIMER_COUNT_UP,
|
||||
.resolution_hz = GPTIMER_RESOLUTION_HZ,
|
||||
};
|
||||
ESP_ERROR_CHECK(gptimer_new_timer(&timer_config, &light_ptr->gptimer));
|
||||
gptimer_alarm_config_t alarm_config = {
|
||||
.alarm_count = DUTY_SET_CYCLE / 1000 * GPTIMER_RESOLUTION_HZ,
|
||||
.reload_count = 0,
|
||||
.flags.auto_reload_on_alarm = true,
|
||||
};
|
||||
gptimer_event_callbacks_t cbs = {
|
||||
.on_alarm = breath_timer_callback,
|
||||
};
|
||||
gptimer_register_event_callbacks(light_ptr->gptimer, &cbs, NULL);
|
||||
gptimer_set_alarm_action(light_ptr->gptimer, &alarm_config);
|
||||
gptimer_enable(light_ptr->gptimer);
|
||||
gptimer_start(light_ptr->gptimer);
|
||||
g_hw_timer_started = true;
|
||||
}
|
||||
|
||||
for (int i = 0; i < channel_num; i++) {
|
||||
light_ptr->channel_group[i] = NULL;
|
||||
}
|
||||
|
||||
for (int i = 0; i < LIGHT_NUM_MAX; i++) {
|
||||
if (g_light_group[i] == NULL) {
|
||||
g_light_group[i] = light_ptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (light_handle_t)light_ptr;
|
||||
}
|
||||
|
||||
esp_err_t iot_light_delete(light_handle_t light_handle)
|
||||
{
|
||||
light_t *light = (light_t *)light_handle;
|
||||
POINT_ASSERT(TAG, light_handle);
|
||||
|
||||
for (int i = 0; i < light->channel_num; i++) {
|
||||
if (light->channel_group[i] != NULL) {
|
||||
iot_light_duty_set(light, i, 0);
|
||||
light_channel_delete(light->channel_group[i]);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < LIGHT_NUM_MAX; i++) {
|
||||
if (g_light_group[i] == light) {
|
||||
g_light_group[i] = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < LIGHT_NUM_MAX; i++) {
|
||||
if (g_light_group[i] != NULL) {
|
||||
goto FREE_MEM;
|
||||
}
|
||||
}
|
||||
|
||||
ledc_fade_func_uninstall();
|
||||
g_fade_installed = false;
|
||||
g_hw_timer_started = false;
|
||||
gptimer_stop(light->gptimer);
|
||||
gptimer_disable(light->gptimer);
|
||||
gptimer_del_timer(light->gptimer);
|
||||
FREE_MEM:
|
||||
free(light_handle);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t iot_light_channel_regist(light_handle_t light_handle, uint8_t channel_idx, gpio_num_t io_num, ledc_channel_t channel)
|
||||
{
|
||||
light_t *light = (light_t *)light_handle;
|
||||
POINT_ASSERT(TAG, light_handle);
|
||||
IOT_CHECK(TAG, channel_idx < light->channel_num, FAIL);
|
||||
|
||||
if (light->channel_group[channel_idx] != NULL) {
|
||||
ESP_LOGE(TAG, "this channel index has been registered");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
light->channel_group[channel_idx] = light_channel_create(io_num, channel, light->mode, light->ledc_timer);
|
||||
|
||||
if (g_fade_installed == false) {
|
||||
ledc_fade_func_install(0);
|
||||
g_fade_installed = true;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t iot_light_duty_set(light_handle_t light_handle, uint8_t channel_id, uint32_t duty)
|
||||
{
|
||||
light_t *light = (light_t *)light_handle;
|
||||
POINT_ASSERT(TAG, light_handle);
|
||||
IOT_CHECK(TAG, channel_id < light->channel_num, ESP_FAIL);
|
||||
POINT_ASSERT(TAG, light->channel_group[channel_id]);
|
||||
light_channel_t *l_chn = light->channel_group[channel_id];
|
||||
|
||||
light_channel_fade_clear(l_chn);
|
||||
|
||||
iot_ledc_set_duty(l_chn->mode, l_chn->channel, duty);
|
||||
iot_ledc_update_duty(l_chn->mode, l_chn->channel);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
uint32_t iot_light_duty_get(light_handle_t light_handle, uint8_t channel_id)
|
||||
{
|
||||
light_t *light = (light_t *)light_handle;
|
||||
POINT_ASSERT(TAG, light_handle);
|
||||
IOT_CHECK(TAG, channel_id < light->channel_num, ESP_FAIL);
|
||||
POINT_ASSERT(TAG, light->channel_group[channel_id]);
|
||||
light_channel_t *l_chn = light->channel_group[channel_id];
|
||||
|
||||
return ledc_get_duty(l_chn->mode, l_chn->channel);
|
||||
}
|
||||
|
||||
esp_err_t iot_light_fade_with_time(light_handle_t light_handle, uint8_t channel_id, uint32_t duty, uint32_t fade_period_ms)
|
||||
{
|
||||
light_t *light = (light_t *)light_handle;
|
||||
POINT_ASSERT(TAG, light_handle);
|
||||
IOT_CHECK(TAG, channel_id < light->channel_num, ESP_FAIL);
|
||||
POINT_ASSERT(TAG, light->channel_group[channel_id]);
|
||||
light_channel_t *l_chn = light->channel_group[channel_id];
|
||||
|
||||
if (fade_period_ms == 0) {
|
||||
return iot_light_duty_set(light, channel_id, duty);
|
||||
}
|
||||
|
||||
light_channel_fade_clear(l_chn);
|
||||
|
||||
l_chn->fade_step_num = fade_period_ms / DUTY_SET_CYCLE + 1;
|
||||
l_chn->fade_duty_step = (uint32_t *)heap_caps_malloc(l_chn->fade_step_num * sizeof(uint32_t), MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
|
||||
|
||||
uint32_t duty_cur = iot_light_duty_get(light, channel_id);
|
||||
int duty_delta = duty - duty_cur;
|
||||
|
||||
if (duty_delta > 0) {
|
||||
float coe = (duty_delta / pow((double)l_chn->fade_step_num, (double)1 / DUTY_SET_GAMMA));
|
||||
|
||||
for (int i = 0; i < l_chn->fade_step_num; i++) {
|
||||
l_chn->fade_duty_step[i] = duty_cur + (int)(coe * pow((double)i, (double)1 / DUTY_SET_GAMMA));
|
||||
}
|
||||
|
||||
l_chn->fade_step_up = true;
|
||||
} else {
|
||||
duty_delta = 0 - duty_delta;
|
||||
float coe = (duty_delta / pow((double)l_chn->fade_step_num, (double)1 / DUTY_SET_GAMMA));
|
||||
|
||||
for (int i = 0; i < l_chn->fade_step_num; i++) {
|
||||
l_chn->fade_duty_step[i] = duty + (int)(coe * pow((double)i, (double)1 / DUTY_SET_GAMMA));
|
||||
}
|
||||
|
||||
l_chn->fade_duty_counter = l_chn->fade_step_num;
|
||||
l_chn->fade_step_up = false;
|
||||
}
|
||||
|
||||
l_chn->fade_once = true;
|
||||
l_chn->fade_start = true;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t iot_light_breath_config(light_handle_t light_handle, uint8_t channel_id, uint32_t duty, uint32_t breath_period_ms)
|
||||
{
|
||||
light_t *light = (light_t *)light_handle;
|
||||
POINT_ASSERT(TAG, light_handle);
|
||||
IOT_CHECK(TAG, channel_id < light->channel_num, ESP_FAIL);
|
||||
POINT_ASSERT(TAG, light->channel_group[channel_id]);
|
||||
light_channel_t *l_chn = light->channel_group[channel_id];
|
||||
|
||||
light_channel_fade_clear(l_chn);
|
||||
|
||||
/**
|
||||
* @brief control light with nonlinearity fade, the duty and the fade step
|
||||
* conform to gamma curve. gamma curve formula: y=a*x^(1/gm) firstly,
|
||||
* use the target duty and step number to calculate coefficient `a`,
|
||||
* secondly, calculate the duty for every step
|
||||
*/
|
||||
|
||||
l_chn->fade_step_num = (breath_period_ms / 2) / DUTY_SET_CYCLE + 1;
|
||||
float coe = (duty / pow((double)l_chn->fade_step_num, (double)1 / DUTY_SET_GAMMA));
|
||||
|
||||
l_chn->fade_duty_step = (uint32_t *)heap_caps_malloc(l_chn->fade_step_num * sizeof(uint32_t), MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
|
||||
|
||||
for (int i = 0; i < l_chn->fade_step_num; i++) {
|
||||
l_chn->fade_duty_step[i] = (int)(coe * pow((double)i, (double)1 / DUTY_SET_GAMMA));
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t iot_light_blink_config(light_handle_t light_handle, uint8_t channel_id, uint32_t blink_period_ms)
|
||||
{
|
||||
light_t *light = (light_t *)light_handle;
|
||||
POINT_ASSERT(TAG, light_handle);
|
||||
IOT_CHECK(TAG, channel_id < light->channel_num, ESP_FAIL);
|
||||
light_channel_t *l_chn = light->channel_group[channel_id];
|
||||
|
||||
light_channel_fade_clear(l_chn);
|
||||
|
||||
l_chn->fade_step_num = (blink_period_ms / 2) / DUTY_SET_CYCLE;
|
||||
l_chn->fade_duty_step = (uint32_t *)heap_caps_malloc(l_chn->fade_step_num * sizeof(uint32_t), MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < (l_chn->fade_step_num / 2); i++) {
|
||||
l_chn->fade_duty_step[i] = 0;
|
||||
}
|
||||
|
||||
for (; i < l_chn->fade_step_num; i++) {
|
||||
l_chn->fade_duty_step[i] = light->full_duty;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t iot_light_operate_start(light_handle_t light_handle, uint8_t channel_id)
|
||||
{
|
||||
light_t *light = (light_t *)light_handle;
|
||||
POINT_ASSERT(TAG, light_handle);
|
||||
IOT_CHECK(TAG, channel_id < light->channel_num, ESP_FAIL);
|
||||
light->channel_group[channel_id]->fade_start = true;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t iot_light_operate_stop(light_handle_t light_handle, uint8_t channel_id)
|
||||
{
|
||||
light_t *light = (light_t *)light_handle;
|
||||
POINT_ASSERT(TAG, light_handle);
|
||||
IOT_CHECK(TAG, channel_id < light->channel_num, ESP_FAIL);
|
||||
light->channel_group[channel_id]->fade_start = false;
|
||||
// iot_light_duty_set(light, channel_id, 0);
|
||||
return ESP_OK;
|
||||
}
|
@ -1,178 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "esp_check.h"
|
||||
#include "led_strip_encoder.h"
|
||||
#include "driver/rmt_tx.h"
|
||||
#include "portmacro.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 = calloc(1, 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(©_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;
|
||||
}
|
||||
|
||||
|
||||
#define RMT_LED_STRIP_RESOLUTION_HZ 10000000 // 10MHz resolution, 1 tick = 0.1us (led strip needs a high resolution)
|
||||
|
||||
#ifndef BLE_MESH_LED_STRIP_IO
|
||||
#define RMT_LED_STRIP_GPIO_NUM 8
|
||||
#else
|
||||
#define RMT_LED_STRIP_GPIO_NUM BLE_MESH_LED_STRIP_IO
|
||||
#endif
|
||||
|
||||
#define EXAMPLE_LED_NUMBERS 1
|
||||
#define EXAMPLE_CHASE_SPEED_MS 10
|
||||
|
||||
static uint8_t led_strip_pixels[EXAMPLE_LED_NUMBERS * 3];
|
||||
rmt_channel_handle_t led_chan = NULL;
|
||||
rmt_encoder_handle_t led_encoder = NULL;
|
||||
rmt_transmit_config_t tx_config;
|
||||
|
||||
void rmt_encoder_init()
|
||||
{
|
||||
led_chan = NULL;
|
||||
rmt_tx_channel_config_t tx_chan_config = {
|
||||
.clk_src = RMT_CLK_SRC_DEFAULT, // select source clock
|
||||
.gpio_num = RMT_LED_STRIP_GPIO_NUM,
|
||||
.mem_block_symbols = 64, // increase the block size can make the LED less flickering
|
||||
.resolution_hz = RMT_LED_STRIP_RESOLUTION_HZ,
|
||||
.trans_queue_depth = 4, // set the number of transactions that can be pending in the background
|
||||
};
|
||||
ESP_ERROR_CHECK(rmt_new_tx_channel(&tx_chan_config, &led_chan));
|
||||
|
||||
ESP_LOGI(TAG, "Install led strip encoder");
|
||||
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_LOGI(TAG, "Enable RMT TX channel");
|
||||
ESP_ERROR_CHECK(rmt_enable(led_chan));
|
||||
|
||||
tx_config.loop_count = 0; // no transfer loop
|
||||
}
|
||||
|
||||
void rmt_led_set(uint8_t red, uint8_t green, uint8_t blue)
|
||||
{
|
||||
led_strip_pixels[0] = green;
|
||||
led_strip_pixels[1] = red;
|
||||
led_strip_pixels[2] = blue;
|
||||
|
||||
ESP_ERROR_CHECK(rmt_transmit(led_chan, led_encoder, led_strip_pixels, sizeof(led_strip_pixels), &tx_config));
|
||||
ESP_ERROR_CHECK(rmt_tx_wait_all_done(led_chan, portMAX_DELAY));
|
||||
}
|
@ -1,891 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "errno.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/timers.h"
|
||||
#include "freertos/event_groups.h"
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_partition.h"
|
||||
|
||||
#include "lwip/sockets.h"
|
||||
#include "lwip/netdb.h"
|
||||
#include "lwip/sockets.h"
|
||||
|
||||
#include "nvs.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "driver/i2c.h"
|
||||
#include "sys/param.h"
|
||||
#include "driver/gpio.h"
|
||||
|
||||
#include "light_driver.h"
|
||||
#include "ble_mesh_example_nvs.h"
|
||||
|
||||
/**
|
||||
* @brief The state of the five-color light
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t mode;
|
||||
uint8_t on;
|
||||
uint16_t hue;
|
||||
uint8_t saturation;
|
||||
uint8_t value;
|
||||
uint8_t lightness;
|
||||
uint8_t color_temperature;
|
||||
uint8_t brightness;
|
||||
uint32_t fade_period_ms;
|
||||
uint32_t blink_period_ms;
|
||||
} light_status_t;
|
||||
|
||||
/**
|
||||
* @brief The channel of the five-color light
|
||||
*/
|
||||
enum light_channel {
|
||||
CHANNEL_ID_RED = 0,
|
||||
CHANNEL_ID_GREEN,
|
||||
CHANNEL_ID_BLUE,
|
||||
CHANNEL_ID_WARM,
|
||||
CHANNEL_ID_COLD,
|
||||
};
|
||||
|
||||
#define LIGHT_FADE_PERIOD_MAX_MS (3 * 1000)
|
||||
|
||||
static const char *TAG = "light_driver";
|
||||
static light_status_t g_light_status = {0};
|
||||
static bool g_light_blink_flag = false;
|
||||
static TimerHandle_t g_fade_timer = NULL;
|
||||
static int g_fade_mode = MODE_NONE;
|
||||
static uint16_t g_fade_hue = 0;
|
||||
extern nvs_handle_t NVS_HANDLE;
|
||||
|
||||
esp_err_t light_driver_init(light_driver_config_t *config)
|
||||
{
|
||||
LIGHT_PARAM_CHECK(config);
|
||||
bool exist = false;
|
||||
|
||||
if (ble_mesh_nvs_restore(NVS_HANDLE, LIGHT_STATUS_STORE_KEY, &g_light_status, sizeof(light_status_t), &exist) != ESP_OK) {
|
||||
memset(&g_light_status, 0, sizeof(light_status_t));
|
||||
g_light_status.mode = MODE_HSV;
|
||||
g_light_status.on = 1;
|
||||
g_light_status.hue = 360;
|
||||
g_light_status.saturation = 0;
|
||||
g_light_status.value = 100;
|
||||
g_light_status.lightness = 100;
|
||||
g_light_status.color_temperature = 0;
|
||||
g_light_status.brightness = 30;
|
||||
}
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32C3
|
||||
iot_led_init(LEDC_TIMER_0, LEDC_LOW_SPEED_MODE, 1000);
|
||||
#elif CONFIG_IDF_TARGET_ESP32
|
||||
iot_led_init(LEDC_TIMER_0, LEDC_HIGH_SPEED_MODE, 1000);
|
||||
#endif
|
||||
|
||||
g_light_status.fade_period_ms = config->fade_period_ms;
|
||||
g_light_status.blink_period_ms = config->blink_period_ms;
|
||||
|
||||
iot_led_regist_channel(CHANNEL_ID_RED, config->gpio_red);
|
||||
iot_led_regist_channel(CHANNEL_ID_GREEN, config->gpio_green);
|
||||
iot_led_regist_channel(CHANNEL_ID_BLUE, config->gpio_blue);
|
||||
iot_led_regist_channel(CHANNEL_ID_WARM, config->gpio_warm);
|
||||
iot_led_regist_channel(CHANNEL_ID_COLD, config->gpio_cold);
|
||||
|
||||
ESP_LOGI(TAG, "hue: %d, saturation: %d, value: %d, lightness: %d",
|
||||
g_light_status.hue, g_light_status.saturation, g_light_status.value, g_light_status.lightness);
|
||||
ESP_LOGI(TAG, "brightness: %d, color_temperature: %d",
|
||||
g_light_status.brightness, g_light_status.color_temperature);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t light_driver_deinit(void)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
iot_led_deinit();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t light_driver_config(uint32_t fade_period_ms, uint32_t blink_period_ms)
|
||||
{
|
||||
g_light_status.fade_period_ms = fade_period_ms;
|
||||
g_light_status.blink_period_ms = blink_period_ms;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t light_driver_set_rgb(uint8_t red, uint8_t green, uint8_t blue)
|
||||
{
|
||||
esp_err_t ret = 0;
|
||||
|
||||
ret = iot_led_set_channel(CHANNEL_ID_RED, red, 0);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
|
||||
|
||||
ret = iot_led_set_channel(CHANNEL_ID_GREEN, green, 0);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
|
||||
|
||||
ret = iot_led_set_channel(CHANNEL_ID_BLUE, blue, 0);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
|
||||
|
||||
ret = iot_led_set_channel(CHANNEL_ID_WARM, 0, 0);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
|
||||
|
||||
ret = iot_led_set_channel(CHANNEL_ID_COLD, 0, 0);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t light_driver_hsv2rgb(uint16_t hue, uint8_t saturation, uint8_t value,
|
||||
uint8_t *red, uint8_t *green, uint8_t *blue)
|
||||
{
|
||||
uint16_t hi = (hue / 60) % 6;
|
||||
uint16_t F = 100 * hue / 60 - 100 * hi;
|
||||
uint16_t P = value * (100 - saturation) / 100;
|
||||
uint16_t Q = value * (10000 - F * saturation) / 10000;
|
||||
uint16_t T = value * (10000 - saturation * (100 - F)) / 10000;
|
||||
|
||||
switch (hi) {
|
||||
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;
|
||||
|
||||
case 5:
|
||||
*red = value;
|
||||
*green = P;
|
||||
*blue = Q;
|
||||
break;
|
||||
|
||||
default:
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
*red = *red * 255 / 100;
|
||||
*green = *green * 255 / 100;
|
||||
*blue = *blue * 255 / 100;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void light_driver_rgb2hsv(uint16_t red, uint16_t green, uint16_t blue,
|
||||
uint16_t *h, uint8_t *s, uint8_t *v)
|
||||
{
|
||||
double hue, saturation, value;
|
||||
double m_max = MAX(red, MAX(green, blue));
|
||||
double m_min = MIN(red, MIN(green, blue));
|
||||
double m_delta = m_max - m_min;
|
||||
|
||||
value = m_max / 255.0;
|
||||
|
||||
if (m_delta == 0) {
|
||||
hue = 0;
|
||||
saturation = 0;
|
||||
} else {
|
||||
saturation = m_delta / m_max;
|
||||
|
||||
if (red == m_max) {
|
||||
hue = (green - blue) / m_delta;
|
||||
} else if (green == m_max) {
|
||||
hue = 2 + (blue - red) / m_delta;
|
||||
} else {
|
||||
hue = 4 + (red - green) / m_delta;
|
||||
}
|
||||
|
||||
hue = hue * 60;
|
||||
|
||||
if (hue < 0) {
|
||||
hue = hue + 360;
|
||||
}
|
||||
}
|
||||
|
||||
*h = (int)(hue + 0.5);
|
||||
*s = (int)(saturation * 100 + 0.5);
|
||||
*v = (int)(value * 100 + 0.5);
|
||||
}
|
||||
|
||||
// refence: https://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c
|
||||
static esp_err_t light_driver_hsl2rgb(uint16_t hue, uint8_t saturation, uint8_t lightness,
|
||||
uint8_t *red, uint8_t *green, uint8_t *blue)
|
||||
{
|
||||
uint16_t hi = (hue / 60) % 6;
|
||||
uint16_t C = (100 - abs(2 * lightness - 100)) * saturation / 100;
|
||||
uint16_t M = 100 * (lightness - 0.5 * C) / 100;
|
||||
uint16_t X = C * (100 - abs((hue * 100 / 60 ) % 200 - 100)) / 100;
|
||||
|
||||
switch (hi) {
|
||||
case 0: /* hue 0~60 */
|
||||
*red = C + M;
|
||||
*green = X + M;
|
||||
*blue = M;
|
||||
break;
|
||||
|
||||
case 1: /* hue 60~120 */
|
||||
*red = X + M;
|
||||
*green = C + M;
|
||||
*blue = M;
|
||||
break;
|
||||
|
||||
case 2: /* hue 120~180 */
|
||||
*red = M;
|
||||
*green = C + M;
|
||||
*blue = X + M;
|
||||
break;
|
||||
|
||||
case 3: /* hue 180~240 */
|
||||
*red = M;
|
||||
*green = X + M;
|
||||
*blue = C + M;
|
||||
break;
|
||||
|
||||
case 4: /* hue 240~300 */
|
||||
*red = X + M;
|
||||
*green = M;
|
||||
*blue = C + M;
|
||||
break;
|
||||
|
||||
case 5: /* hue 300~360 */
|
||||
*red = C + M;
|
||||
*green = M;
|
||||
*blue = X + M;
|
||||
break;
|
||||
|
||||
default:
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
*red = *red * 255 / 100;
|
||||
*green = *green * 255 / 100;
|
||||
*blue = *blue * 255 / 100;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t light_driver_set_hsv(uint16_t hue, uint8_t saturation, uint8_t value)
|
||||
{
|
||||
LIGHT_PARAM_CHECK(hue <= 360);
|
||||
LIGHT_PARAM_CHECK(saturation <= 100);
|
||||
LIGHT_PARAM_CHECK(value <= 100);
|
||||
|
||||
esp_err_t ret = ESP_OK;
|
||||
uint8_t red = 0;
|
||||
uint8_t green = 0;
|
||||
uint8_t blue = 0;
|
||||
|
||||
ret = light_driver_hsv2rgb(hue, saturation, value, &red, &green, &blue);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ret, "light_driver_hsv2rgb, ret: %d", ret);
|
||||
|
||||
ESP_LOGV(TAG, "red: %d, green: %d, blue: %d", red, green, blue);
|
||||
|
||||
ret = iot_led_set_channel(CHANNEL_ID_RED, red, g_light_status.fade_period_ms);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
|
||||
|
||||
ret = iot_led_set_channel(CHANNEL_ID_GREEN, green, g_light_status.fade_period_ms);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
|
||||
|
||||
ret = iot_led_set_channel(CHANNEL_ID_BLUE, blue, g_light_status.fade_period_ms);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
|
||||
|
||||
if (g_light_status.mode != MODE_HSV) {
|
||||
ret = iot_led_set_channel(CHANNEL_ID_WARM, 0, g_light_status.fade_period_ms);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
|
||||
|
||||
ret = iot_led_set_channel(CHANNEL_ID_COLD, 0, g_light_status.fade_period_ms);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
|
||||
}
|
||||
|
||||
g_light_status.mode = MODE_HSV;
|
||||
g_light_status.on = 1;
|
||||
g_light_status.hue = hue;
|
||||
g_light_status.value = value;
|
||||
g_light_status.saturation = saturation;
|
||||
|
||||
ret = ble_mesh_nvs_store(NVS_HANDLE, LIGHT_STATUS_STORE_KEY, &g_light_status, sizeof(light_status_t));
|
||||
LIGHT_ERROR_CHECK(ret < 0, ret, "ble_mesh_nvs_store, ret: %d", ret);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t light_driver_set_hue(uint16_t hue)
|
||||
{
|
||||
if (g_light_status.mode == MODE_HSV) {
|
||||
return light_driver_set_hsv(hue, g_light_status.saturation, g_light_status.value);
|
||||
} else if (g_light_status.mode == MODE_HSL) {
|
||||
return light_driver_set_hsl(hue, g_light_status.saturation, g_light_status.lightness);
|
||||
} else {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t light_driver_set_saturation(uint8_t saturation)
|
||||
{
|
||||
if (g_light_status.mode == MODE_HSV) {
|
||||
return light_driver_set_hsv(g_light_status.hue, saturation, g_light_status.value);
|
||||
} else if (g_light_status.mode == MODE_HSL) {
|
||||
return light_driver_set_hsl(g_light_status.hue, saturation, g_light_status.lightness);
|
||||
} else {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t light_driver_set_value(uint8_t value)
|
||||
{
|
||||
return light_driver_set_hsv(g_light_status.hue, g_light_status.saturation, value);
|
||||
}
|
||||
|
||||
esp_err_t light_driver_get_hsv(uint16_t *hue, uint8_t *saturation, uint8_t *value)
|
||||
{
|
||||
LIGHT_PARAM_CHECK(hue);
|
||||
LIGHT_PARAM_CHECK(saturation);
|
||||
LIGHT_PARAM_CHECK(value);
|
||||
|
||||
*hue = g_light_status.hue;
|
||||
*saturation = g_light_status.saturation;
|
||||
*value = g_light_status.value;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
uint16_t light_driver_get_hue(void)
|
||||
{
|
||||
return g_light_status.hue;
|
||||
}
|
||||
|
||||
uint8_t light_driver_get_saturation(void)
|
||||
{
|
||||
return g_light_status.saturation;
|
||||
}
|
||||
|
||||
uint8_t light_driver_get_value(void)
|
||||
{
|
||||
return g_light_status.value;
|
||||
}
|
||||
|
||||
uint8_t light_driver_get_mode(void)
|
||||
{
|
||||
return g_light_status.mode;
|
||||
}
|
||||
|
||||
esp_err_t light_driver_set_ctb(uint8_t color_temperature, uint8_t brightness)
|
||||
{
|
||||
LIGHT_PARAM_CHECK(brightness <= 100);
|
||||
LIGHT_PARAM_CHECK(color_temperature <= 100);
|
||||
|
||||
esp_err_t ret = ESP_OK;
|
||||
uint8_t warm_tmp = color_temperature * brightness / 100;
|
||||
uint8_t cold_tmp = (100 - color_temperature) * brightness / 100;
|
||||
warm_tmp = warm_tmp < 15 ? warm_tmp : 14 + warm_tmp * 86 / 100;
|
||||
cold_tmp = cold_tmp < 15 ? cold_tmp : 14 + cold_tmp * 86 / 100;
|
||||
|
||||
ret = iot_led_set_channel(CHANNEL_ID_COLD,
|
||||
cold_tmp * 255 / 100, g_light_status.fade_period_ms);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
|
||||
|
||||
ret = iot_led_set_channel(CHANNEL_ID_WARM,
|
||||
warm_tmp * 255 / 100, g_light_status.fade_period_ms);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
|
||||
|
||||
if (g_light_status.mode != MODE_CTB) {
|
||||
ret = iot_led_set_channel(CHANNEL_ID_RED, 0, g_light_status.fade_period_ms);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
|
||||
|
||||
ret = iot_led_set_channel(CHANNEL_ID_GREEN, 0, g_light_status.fade_period_ms);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
|
||||
|
||||
ret = iot_led_set_channel(CHANNEL_ID_BLUE, 0, g_light_status.fade_period_ms);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
|
||||
}
|
||||
|
||||
g_light_status.mode = MODE_CTB;
|
||||
g_light_status.on = 1;
|
||||
g_light_status.brightness = brightness;
|
||||
g_light_status.color_temperature = color_temperature;
|
||||
|
||||
ret = ble_mesh_nvs_store(NVS_HANDLE, LIGHT_STATUS_STORE_KEY, &g_light_status, sizeof(light_status_t));
|
||||
LIGHT_ERROR_CHECK(ret < 0, ret, "ble_mesh_nvs_store, ret: %d", ret);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t light_driver_set_color_temperature(uint8_t color_temperature)
|
||||
{
|
||||
return light_driver_set_ctb(color_temperature, g_light_status.brightness);
|
||||
}
|
||||
|
||||
esp_err_t light_driver_set_brightness(uint8_t brightness)
|
||||
{
|
||||
return light_driver_set_ctb(g_light_status.color_temperature, brightness);
|
||||
}
|
||||
|
||||
esp_err_t light_driver_get_ctb(uint8_t *color_temperature, uint8_t *brightness)
|
||||
{
|
||||
LIGHT_PARAM_CHECK(color_temperature);
|
||||
LIGHT_PARAM_CHECK(brightness);
|
||||
|
||||
*brightness = g_light_status.brightness;
|
||||
*color_temperature = g_light_status.color_temperature;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
uint8_t light_driver_get_color_temperature(void)
|
||||
{
|
||||
return g_light_status.color_temperature;
|
||||
}
|
||||
|
||||
uint8_t light_driver_get_brightness(void)
|
||||
{
|
||||
return g_light_status.brightness;
|
||||
}
|
||||
|
||||
esp_err_t light_driver_set_hsl(uint16_t hue, uint8_t saturation, uint8_t lightness)
|
||||
{
|
||||
LIGHT_PARAM_CHECK(hue <= 360);
|
||||
LIGHT_PARAM_CHECK(saturation <= 100);
|
||||
LIGHT_PARAM_CHECK(lightness <= 100);
|
||||
|
||||
esp_err_t ret = ESP_OK;
|
||||
uint8_t red = 0;
|
||||
uint8_t green = 0;
|
||||
uint8_t blue = 0;
|
||||
|
||||
ret = light_driver_hsl2rgb(hue, saturation, lightness, &red, &green, &blue);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ret, "light_driver_hsl2rgb, ret: %d", ret);
|
||||
|
||||
ESP_LOGV(TAG, "red: %d, green: %d, blue: %d", red, green, blue);
|
||||
|
||||
ret = iot_led_set_channel(CHANNEL_ID_RED, red, g_light_status.fade_period_ms);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
|
||||
|
||||
ret = iot_led_set_channel(CHANNEL_ID_GREEN, green, g_light_status.fade_period_ms);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
|
||||
|
||||
ret = iot_led_set_channel(CHANNEL_ID_BLUE, blue, g_light_status.fade_period_ms);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
|
||||
|
||||
if (g_light_status.mode != MODE_HSL) {
|
||||
ret = iot_led_set_channel(CHANNEL_ID_WARM, 0, g_light_status.fade_period_ms);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
|
||||
|
||||
ret = iot_led_set_channel(CHANNEL_ID_COLD, 0, g_light_status.fade_period_ms);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
|
||||
}
|
||||
|
||||
g_light_status.mode = MODE_HSL;
|
||||
g_light_status.on = 1;
|
||||
g_light_status.hue = hue;
|
||||
g_light_status.saturation = saturation;
|
||||
g_light_status.lightness = lightness;
|
||||
|
||||
ret = ble_mesh_nvs_store(NVS_HANDLE, LIGHT_STATUS_STORE_KEY, &g_light_status, sizeof(light_status_t));
|
||||
LIGHT_ERROR_CHECK(ret < 0, ret, "ble_mesh_nvs_store, ret: %d", ret);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t light_driver_set_lightness(uint8_t lightness)
|
||||
{
|
||||
return light_driver_set_hsl(g_light_status.hue, g_light_status.saturation, lightness);
|
||||
}
|
||||
|
||||
uint8_t light_driver_get_lightness(void)
|
||||
{
|
||||
return g_light_status.lightness;
|
||||
}
|
||||
|
||||
esp_err_t light_driver_get_hsl(uint16_t *hue, uint8_t *saturation, uint8_t *lightness)
|
||||
{
|
||||
LIGHT_PARAM_CHECK(hue);
|
||||
LIGHT_PARAM_CHECK(saturation);
|
||||
LIGHT_PARAM_CHECK(lightness);
|
||||
|
||||
*hue = g_light_status.hue;
|
||||
*saturation = g_light_status.saturation;
|
||||
*lightness = g_light_status.lightness;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t light_driver_set_switch(bool on)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
g_light_status.on = on;
|
||||
|
||||
if (!g_light_status.on) {
|
||||
ret = iot_led_set_channel(CHANNEL_ID_RED, 0, g_light_status.fade_period_ms);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_set_channel, ret: %d", ret);
|
||||
|
||||
ret = iot_led_set_channel(CHANNEL_ID_GREEN, 0, g_light_status.fade_period_ms);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_set_channel, ret: %d", ret);
|
||||
|
||||
ret = iot_led_set_channel(CHANNEL_ID_BLUE, 0, g_light_status.fade_period_ms);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_set_channel, ret: %d", ret);
|
||||
|
||||
ret = iot_led_set_channel(CHANNEL_ID_COLD, 0, g_light_status.fade_period_ms);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_set_channel, ret: %d", ret);
|
||||
|
||||
ret = iot_led_set_channel(CHANNEL_ID_WARM, 0, g_light_status.fade_period_ms);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_set_channel, ret: %d", ret);
|
||||
|
||||
} else {
|
||||
switch (g_light_status.mode) {
|
||||
case MODE_HSV:
|
||||
g_light_status.value = (g_light_status.value) ? g_light_status.value : 100;
|
||||
ret = light_driver_set_hsv(g_light_status.hue, g_light_status.saturation, g_light_status.value);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "light_driver_set_hsv, ret: %d", ret);
|
||||
break;
|
||||
|
||||
case MODE_HSL:
|
||||
g_light_status.lightness = (g_light_status.lightness) ? g_light_status.lightness : 100;
|
||||
ret = light_driver_set_hsl(g_light_status.hue, g_light_status.saturation, g_light_status.lightness);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "light_driver_set_hsl, ret: %d", ret);
|
||||
break;
|
||||
|
||||
case MODE_CTB:
|
||||
g_light_status.brightness = (g_light_status.brightness) ? g_light_status.brightness : 100;
|
||||
ret = light_driver_set_ctb(g_light_status.color_temperature, g_light_status.brightness);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "light_driver_set_ctb, ret: %d", ret);
|
||||
break;
|
||||
|
||||
default:
|
||||
ESP_LOGW(TAG, "This operation is not supported");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ret = ble_mesh_nvs_store(NVS_HANDLE, LIGHT_STATUS_STORE_KEY, &g_light_status, sizeof(light_status_t));
|
||||
LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "ble_mesh_nvs_store, ret: %d", ret);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t light_driver_set_mode(light_mode_t mode)
|
||||
{
|
||||
g_light_status.mode = mode;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
bool light_driver_get_switch(void)
|
||||
{
|
||||
return g_light_status.on;
|
||||
}
|
||||
|
||||
esp_err_t light_driver_breath_start(uint8_t red, uint8_t green, uint8_t blue)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
ret = iot_led_start_blink(CHANNEL_ID_RED,
|
||||
red, g_light_status.blink_period_ms, true);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_start_blink, ret: %d", ret);
|
||||
ret = iot_led_start_blink(CHANNEL_ID_GREEN,
|
||||
green, g_light_status.blink_period_ms, true);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_start_blink, ret: %d", ret);
|
||||
ret = iot_led_start_blink(CHANNEL_ID_BLUE,
|
||||
blue, g_light_status.blink_period_ms, true);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_start_blink, ret: %d", ret);
|
||||
|
||||
g_light_blink_flag = true;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t light_driver_breath_stop(void)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
if (g_light_blink_flag == false) {
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
ret = iot_led_stop_blink(CHANNEL_ID_RED);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_stop_blink, ret: %d", ret);
|
||||
|
||||
ret = iot_led_stop_blink(CHANNEL_ID_GREEN);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_stop_blink, ret: %d", ret);
|
||||
|
||||
ret = iot_led_stop_blink(CHANNEL_ID_BLUE);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_stop_blink, ret: %d", ret);
|
||||
|
||||
light_driver_set_switch(true);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t light_driver_fade_brightness(uint8_t brightness)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
g_fade_mode = MODE_ON;
|
||||
uint32_t fade_period_ms = 0;
|
||||
|
||||
if (g_light_status.mode == MODE_HSV) {
|
||||
uint8_t red = 0;
|
||||
uint8_t green = 0;
|
||||
uint8_t blue = 0;
|
||||
|
||||
ret = light_driver_hsv2rgb(g_light_status.hue, g_light_status.saturation, g_light_status.value, &red, &green, &blue);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ret, "light_driver_hsv2rgb, ret: %d", ret);
|
||||
|
||||
if (brightness != 0) {
|
||||
ret = iot_led_get_channel((ledc_channel_t)CHANNEL_ID_RED, &red);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_get_channel, ret: %d", ret);
|
||||
ret = iot_led_get_channel((ledc_channel_t)CHANNEL_ID_GREEN, &green);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_get_channel, ret: %d", ret);
|
||||
ret = iot_led_get_channel((ledc_channel_t)CHANNEL_ID_BLUE, &blue);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_get_channel, ret: %d", ret);
|
||||
|
||||
uint8_t max_color = MAX(MAX(red, green), blue);
|
||||
uint8_t change_value = brightness * 255 / 100 - max_color;
|
||||
fade_period_ms = LIGHT_FADE_PERIOD_MAX_MS * change_value / 255;
|
||||
} else {
|
||||
fade_period_ms = LIGHT_FADE_PERIOD_MAX_MS * MAX(MAX(red, green), blue) / 255;
|
||||
red = 0;
|
||||
}
|
||||
|
||||
g_light_status.value = brightness;
|
||||
light_driver_hsv2rgb(g_light_status.hue, g_light_status.saturation, g_light_status.value, &red, &green, &blue);
|
||||
|
||||
ret = iot_led_set_channel(CHANNEL_ID_RED, red, fade_period_ms);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
|
||||
|
||||
ret = iot_led_set_channel(CHANNEL_ID_GREEN, green, fade_period_ms);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
|
||||
|
||||
ret = iot_led_set_channel(CHANNEL_ID_BLUE, blue, fade_period_ms);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
|
||||
|
||||
} else if (g_light_status.mode == MODE_CTB) {
|
||||
uint8_t warm_tmp = 0;
|
||||
uint8_t cold_tmp = 0;
|
||||
fade_period_ms = LIGHT_FADE_PERIOD_MAX_MS * g_light_status.brightness / 100;
|
||||
|
||||
if (brightness != 0) {
|
||||
uint8_t change_value = brightness - g_light_status.brightness;
|
||||
warm_tmp = g_light_status.color_temperature;
|
||||
cold_tmp = (brightness - g_light_status.color_temperature);
|
||||
fade_period_ms = LIGHT_FADE_PERIOD_MAX_MS * change_value / 100;
|
||||
}
|
||||
|
||||
ret = iot_led_set_channel(CHANNEL_ID_COLD,
|
||||
cold_tmp * 255 / 100, fade_period_ms);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
|
||||
|
||||
ret = iot_led_set_channel(CHANNEL_ID_WARM,
|
||||
warm_tmp * 255 / 100, fade_period_ms);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
|
||||
|
||||
g_light_status.brightness = brightness;
|
||||
}
|
||||
|
||||
ret = ble_mesh_nvs_store(NVS_HANDLE, LIGHT_STATUS_STORE_KEY, &g_light_status, sizeof(light_status_t));
|
||||
LIGHT_ERROR_CHECK(ret < 0, ret, "ble_mesh_nvs_store, ret: %d", ret);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void light_fade_timer_stop(void)
|
||||
{
|
||||
if (!g_fade_timer) {
|
||||
return ;
|
||||
}
|
||||
|
||||
if (!xTimerStop(g_fade_timer, portMAX_DELAY)) {
|
||||
ESP_LOGW(TAG, "xTimerStop timer: %p", g_fade_timer);
|
||||
}
|
||||
|
||||
if (!xTimerDelete(g_fade_timer, portMAX_DELAY)) {
|
||||
ESP_LOGW(TAG, "xTimerDelete timer: %p", g_fade_timer);
|
||||
}
|
||||
|
||||
g_fade_timer = NULL;
|
||||
}
|
||||
|
||||
static void light_fade_timer_cb(TimerHandle_t timer)
|
||||
{
|
||||
uint8_t red = 0;
|
||||
uint8_t green = 0;
|
||||
uint8_t blue = 0;
|
||||
uint32_t fade_period_ms = LIGHT_FADE_PERIOD_MAX_MS * 2 / 6;
|
||||
int variety = (g_fade_hue > 180) ? 60 : -60;
|
||||
|
||||
if (g_light_status.hue >= 360 || g_light_status.hue <= 0) {
|
||||
light_fade_timer_stop();
|
||||
}
|
||||
|
||||
g_light_status.hue = g_light_status.hue >= 360 ? 360 : g_light_status.hue + variety;
|
||||
g_light_status.hue = g_light_status.hue <= 60 ? 0 : g_light_status.hue + variety;
|
||||
|
||||
light_driver_hsv2rgb(g_light_status.hue, g_light_status.saturation, g_light_status.value, &red, &green, &blue);
|
||||
|
||||
iot_led_set_channel(CHANNEL_ID_RED, red, fade_period_ms);
|
||||
iot_led_set_channel(CHANNEL_ID_GREEN, green, fade_period_ms);
|
||||
iot_led_set_channel(CHANNEL_ID_BLUE, blue, fade_period_ms);
|
||||
}
|
||||
|
||||
esp_err_t light_driver_fade_hue(uint16_t hue)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
g_fade_mode = MODE_HSV;
|
||||
g_fade_hue = hue;
|
||||
|
||||
light_fade_timer_stop();
|
||||
|
||||
if (g_light_status.mode != MODE_HSV) {
|
||||
ret = iot_led_set_channel(CHANNEL_ID_WARM, 0, 0);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
|
||||
|
||||
ret = iot_led_set_channel(CHANNEL_ID_COLD, 0, 0);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
|
||||
}
|
||||
|
||||
g_light_status.mode = MODE_HSV;
|
||||
g_light_status.value = (g_light_status.value == 0) ? 100 : g_light_status.value;
|
||||
uint32_t fade_period_ms = LIGHT_FADE_PERIOD_MAX_MS * 2 / 6;
|
||||
|
||||
light_fade_timer_cb(NULL);
|
||||
|
||||
g_fade_timer = xTimerCreate("light_timer", fade_period_ms,
|
||||
true, NULL, light_fade_timer_cb);
|
||||
xTimerStart(g_fade_timer, 0);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t light_driver_fade_warm(uint8_t color_temperature)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
g_fade_mode = MODE_CTB;
|
||||
|
||||
if (g_light_status.mode != MODE_CTB) {
|
||||
ret = iot_led_set_channel(CHANNEL_ID_RED, 0, g_light_status.fade_period_ms);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
|
||||
|
||||
ret = iot_led_set_channel(CHANNEL_ID_GREEN, 0, g_light_status.fade_period_ms);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
|
||||
|
||||
ret = iot_led_set_channel(CHANNEL_ID_BLUE, 0, g_light_status.fade_period_ms);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
|
||||
}
|
||||
|
||||
uint8_t warm_tmp = color_temperature * g_light_status.brightness / 100;
|
||||
uint8_t cold_tmp = (100 - color_temperature) * g_light_status.brightness / 100;
|
||||
|
||||
ret = iot_led_set_channel(CHANNEL_ID_COLD, cold_tmp * 255 / 100, LIGHT_FADE_PERIOD_MAX_MS);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
|
||||
|
||||
ret = iot_led_set_channel(CHANNEL_ID_WARM, warm_tmp * 255 / 100, LIGHT_FADE_PERIOD_MAX_MS);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
|
||||
|
||||
g_light_status.mode = MODE_CTB;
|
||||
g_light_status.color_temperature = color_temperature;
|
||||
ret = ble_mesh_nvs_store(NVS_HANDLE, LIGHT_STATUS_STORE_KEY, &g_light_status, sizeof(light_status_t));
|
||||
LIGHT_ERROR_CHECK(ret < 0, ret, "ble_mesh_nvs_store, ret: %d", ret);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t light_driver_fade_stop(void)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
light_fade_timer_stop();
|
||||
|
||||
if (g_light_status.mode != MODE_CTB) {
|
||||
uint16_t hue = 0;
|
||||
uint8_t saturation = 0;
|
||||
uint8_t value = 0;
|
||||
|
||||
ret = iot_led_stop_blink(CHANNEL_ID_RED);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_stop_blink, ret: %d", ret);
|
||||
|
||||
ret = iot_led_stop_blink(CHANNEL_ID_GREEN);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_stop_blink, ret: %d", ret);
|
||||
|
||||
ret = iot_led_stop_blink(CHANNEL_ID_BLUE);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_stop_blink, ret: %d", ret);
|
||||
|
||||
uint8_t red, green, blue;
|
||||
|
||||
ret = iot_led_get_channel(CHANNEL_ID_RED, &red);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_get_channel, ret: %d", ret);
|
||||
ret = iot_led_get_channel(CHANNEL_ID_GREEN, &green);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_get_channel, ret: %d", ret);
|
||||
ret = iot_led_get_channel(CHANNEL_ID_BLUE, &blue);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_get_channel, ret: %d", ret);
|
||||
|
||||
light_driver_rgb2hsv(red, green, blue, &hue, &saturation, &value);
|
||||
|
||||
g_light_status.hue = (g_fade_mode == MODE_HSV) ? hue : g_light_status.hue;
|
||||
g_light_status.value = (g_fade_mode == MODE_OFF || g_fade_mode == MODE_ON) ? value : g_light_status.value;
|
||||
} else {
|
||||
uint8_t color_temperature = 0;
|
||||
uint8_t brightness = 0;
|
||||
|
||||
ret = iot_led_stop_blink(CHANNEL_ID_COLD);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_stop_blink, ret: %d", ret);
|
||||
|
||||
ret = iot_led_stop_blink(CHANNEL_ID_WARM);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_stop_blink, ret: %d", ret);
|
||||
|
||||
uint8_t warm_tmp, cold_tmp;
|
||||
uint8_t tmp;
|
||||
|
||||
ret = iot_led_get_channel(CHANNEL_ID_WARM, &tmp);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_get_channel, ret: %d", ret);
|
||||
warm_tmp = (int32_t)tmp * 100 / 255;
|
||||
|
||||
ret = iot_led_get_channel(CHANNEL_ID_COLD, &tmp);
|
||||
LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_get_channel, ret: %d", ret);
|
||||
cold_tmp = (int32_t)tmp * 100 / 255;
|
||||
|
||||
color_temperature = (!warm_tmp) ? 0 : 100 / (cold_tmp / warm_tmp + 1);
|
||||
brightness = (!color_temperature) ? cold_tmp : warm_tmp * 100 / color_temperature;
|
||||
|
||||
g_light_status.brightness = (g_fade_mode == MODE_OFF || g_fade_mode == MODE_ON) ? brightness : g_light_status.brightness;
|
||||
g_light_status.color_temperature = (g_fade_mode == MODE_CTB) ? color_temperature : g_light_status.color_temperature;
|
||||
}
|
||||
|
||||
ret = ble_mesh_nvs_store(NVS_HANDLE, LIGHT_STATUS_STORE_KEY, &g_light_status, sizeof(light_status_t));
|
||||
LIGHT_ERROR_CHECK(ret < 0, ret, "ble_mesh_nvs_store, ret: %d", ret);
|
||||
|
||||
g_fade_mode = MODE_NONE;
|
||||
return ESP_OK;
|
||||
}
|
@ -15,7 +15,7 @@
|
||||
#include "iot_button.h"
|
||||
#include "board.h"
|
||||
#include "esp_timer.h"
|
||||
#include "led_strip_encoder.h"
|
||||
#include "lightbulb.h"
|
||||
|
||||
#define TAG "BOARD"
|
||||
|
||||
@ -28,7 +28,7 @@ esp_timer_handle_t led_timer_hdl;
|
||||
|
||||
void board_led_operation(uint8_t r, uint8_t g, uint8_t b)
|
||||
{
|
||||
rmt_led_set(r,g,b);
|
||||
ws2812_set_rgb_channel(r, g, b);
|
||||
}
|
||||
|
||||
static void led_timer_callback(void* arg)
|
||||
@ -57,7 +57,24 @@ void board_led_operation_auto_close(uint8_t r, uint8_t g, uint8_t b, uint32_t ms
|
||||
|
||||
static void board_led_init(void)
|
||||
{
|
||||
rmt_encoder_init();
|
||||
lightbulb_config_t config = {
|
||||
.type = DRIVER_WS2812,
|
||||
.driver_conf.ws2812.led_num = 3,
|
||||
.driver_conf.ws2812.ctrl_io = 8,
|
||||
.capability.enable_fades = true,
|
||||
.capability.fades_ms = 800,
|
||||
.capability.enable_status_storage = false,
|
||||
.capability.mode_mask = COLOR_MODE,
|
||||
.capability.storage_cb = NULL,
|
||||
.external_limit = NULL,
|
||||
.gamma_conf = NULL,
|
||||
.init_status.mode = WORK_COLOR,
|
||||
.init_status.on = false,
|
||||
.init_status.hue = 0,
|
||||
.init_status.saturation = 100,
|
||||
.init_status.value = 100,
|
||||
};
|
||||
lightbulb_init(&config);
|
||||
esp_led_timer_init();
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
||||
#include "esp_log.h"
|
||||
#include "board.h"
|
||||
#include "esp_timer.h"
|
||||
#include "led_strip_encoder.h"
|
||||
#include "lightbulb.h"
|
||||
#include "iot_button.h"
|
||||
|
||||
#include "mesh/adapter.h"
|
||||
@ -26,7 +26,7 @@ esp_timer_handle_t led_timer_hdl;
|
||||
|
||||
void board_led_operation(uint8_t r, uint8_t g, uint8_t b)
|
||||
{
|
||||
rmt_led_set(r,g,b);
|
||||
ws2812_set_rgb_channel(r, g, b);
|
||||
}
|
||||
|
||||
static void led_timer_callback(void* arg)
|
||||
@ -54,7 +54,24 @@ void board_led_operation_auto_close(uint8_t r, uint8_t g, uint8_t b, uint32_t ms
|
||||
|
||||
static void board_led_init(void)
|
||||
{
|
||||
rmt_encoder_init();
|
||||
lightbulb_config_t config = {
|
||||
.type = DRIVER_WS2812,
|
||||
.driver_conf.ws2812.led_num = 3,
|
||||
.driver_conf.ws2812.ctrl_io = 8,
|
||||
.capability.enable_fades = true,
|
||||
.capability.fades_ms = 800,
|
||||
.capability.enable_status_storage = false,
|
||||
.capability.mode_mask = COLOR_MODE,
|
||||
.capability.storage_cb = NULL,
|
||||
.external_limit = NULL,
|
||||
.gamma_conf = NULL,
|
||||
.init_status.mode = WORK_COLOR,
|
||||
.init_status.on = false,
|
||||
.init_status.hue = 0,
|
||||
.init_status.saturation = 100,
|
||||
.init_status.value = 100,
|
||||
};
|
||||
lightbulb_init(&config);
|
||||
esp_led_timer_init();
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
#include "iot_button.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "lightbulb.h"
|
||||
#include "esp_log.h"
|
||||
#include "board.h"
|
||||
|
||||
@ -25,7 +26,7 @@ extern void example_ble_mesh_send_remote_provisioning_scan_start(void);
|
||||
void board_led_operation(uint8_t r, uint8_t g, uint8_t b)
|
||||
{
|
||||
#ifdef BLE_MESH_LED_STRIP_IO
|
||||
rmt_led_set(r, g, b);
|
||||
ws2812_set_rgb_channel(r, g, b);
|
||||
#else
|
||||
gpio_set_level(LED_R, r);
|
||||
gpio_set_level(LED_G, g);
|
||||
@ -36,8 +37,25 @@ void board_led_operation(uint8_t r, uint8_t g, uint8_t b)
|
||||
static void board_led_init(void)
|
||||
{
|
||||
#ifdef BLE_MESH_LED_STRIP_IO
|
||||
rmt_encoder_init();
|
||||
rmt_led_set(LED_OFF,LED_OFF,LED_OFF);
|
||||
lightbulb_config_t config = {
|
||||
.type = DRIVER_WS2812,
|
||||
.driver_conf.ws2812.led_num = 3,
|
||||
.driver_conf.ws2812.ctrl_io = 8,
|
||||
.capability.enable_fades = true,
|
||||
.capability.fades_ms = 800,
|
||||
.capability.enable_status_storage = false,
|
||||
.capability.mode_mask = COLOR_MODE,
|
||||
.capability.storage_cb = NULL,
|
||||
.external_limit = NULL,
|
||||
.gamma_conf = NULL,
|
||||
.init_status.mode = WORK_COLOR,
|
||||
.init_status.on = false,
|
||||
.init_status.hue = 0,
|
||||
.init_status.saturation = 100,
|
||||
.init_status.value = 100,
|
||||
};
|
||||
lightbulb_init(&config);
|
||||
ws2812_set_rgb_channel(LED_OFF, LED_OFF, LED_OFF);
|
||||
#else
|
||||
gpio_set_level(LED_R, LED_OFF);
|
||||
gpio_set_level(LED_G, LED_OFF);
|
||||
|
@ -15,7 +15,6 @@ extern "C" {
|
||||
#endif /**< __cplusplus */
|
||||
|
||||
#include "driver/gpio.h"
|
||||
#include "led_strip_encoder.h"
|
||||
|
||||
#if defined(CONFIG_BLE_MESH_ESP_WROOM_32)
|
||||
#define LED_R GPIO_NUM_25
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "driver/gpio.h"
|
||||
#include "lightbulb.h"
|
||||
#include "esp_log.h"
|
||||
#include "board.h"
|
||||
|
||||
@ -18,7 +19,7 @@
|
||||
void board_led_operation(uint8_t r, uint8_t g, uint8_t b)
|
||||
{
|
||||
#ifdef BLE_MESH_LED_STRIP_IO
|
||||
rmt_led_set(r, g, b);
|
||||
ws2812_set_rgb_channel(r, g, b);
|
||||
#else
|
||||
gpio_set_level(LED_R, r);
|
||||
gpio_set_level(LED_G, g);
|
||||
@ -29,8 +30,25 @@ void board_led_operation(uint8_t r, uint8_t g, uint8_t b)
|
||||
static void board_led_init(void)
|
||||
{
|
||||
#ifdef BLE_MESH_LED_STRIP_IO
|
||||
rmt_encoder_init();
|
||||
rmt_led_set(LED_OFF,LED_OFF,LED_OFF);
|
||||
lightbulb_config_t config = {
|
||||
.type = DRIVER_WS2812,
|
||||
.driver_conf.ws2812.led_num = 3,
|
||||
.driver_conf.ws2812.ctrl_io = 8,
|
||||
.capability.enable_fades = true,
|
||||
.capability.fades_ms = 800,
|
||||
.capability.enable_status_storage = false,
|
||||
.capability.mode_mask = COLOR_MODE,
|
||||
.capability.storage_cb = NULL,
|
||||
.external_limit = NULL,
|
||||
.gamma_conf = NULL,
|
||||
.init_status.mode = WORK_COLOR,
|
||||
.init_status.on = false,
|
||||
.init_status.hue = 0,
|
||||
.init_status.saturation = 100,
|
||||
.init_status.value = 100,
|
||||
};
|
||||
lightbulb_init(&config);
|
||||
ws2812_set_rgb_channel(LED_OFF, LED_OFF, LED_OFF);
|
||||
#else
|
||||
gpio_set_level(LED_R, LED_OFF);
|
||||
gpio_set_level(LED_G, LED_OFF);
|
||||
|
@ -15,7 +15,6 @@ extern "C" {
|
||||
#endif /**< __cplusplus */
|
||||
|
||||
#include "driver/gpio.h"
|
||||
#include "led_strip_encoder.h"
|
||||
|
||||
#if defined(CONFIG_BLE_MESH_ESP_WROOM_32)
|
||||
#define LED_R GPIO_NUM_25
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "driver/gpio.h"
|
||||
#include "lightbulb.h"
|
||||
#include "esp_log.h"
|
||||
#include "board.h"
|
||||
|
||||
@ -18,7 +19,7 @@
|
||||
void board_led_operation(uint8_t r, uint8_t g, uint8_t b)
|
||||
{
|
||||
#ifdef BLE_MESH_LED_STRIP_IO
|
||||
rmt_led_set(r, g, b);
|
||||
ws2812_set_rgb_channel(r, g, b);
|
||||
#else
|
||||
gpio_set_level(LED_R, r);
|
||||
gpio_set_level(LED_G, g);
|
||||
@ -29,8 +30,25 @@ void board_led_operation(uint8_t r, uint8_t g, uint8_t b)
|
||||
static void board_led_init(void)
|
||||
{
|
||||
#ifdef BLE_MESH_LED_STRIP_IO
|
||||
rmt_encoder_init();
|
||||
rmt_led_set(LED_OFF,LED_OFF,LED_OFF);
|
||||
lightbulb_config_t config = {
|
||||
.type = DRIVER_WS2812,
|
||||
.driver_conf.ws2812.led_num = 3,
|
||||
.driver_conf.ws2812.ctrl_io = 8,
|
||||
.capability.enable_fades = true,
|
||||
.capability.fades_ms = 800,
|
||||
.capability.enable_status_storage = false,
|
||||
.capability.mode_mask = COLOR_MODE,
|
||||
.capability.storage_cb = NULL,
|
||||
.external_limit = NULL,
|
||||
.gamma_conf = NULL,
|
||||
.init_status.mode = WORK_COLOR,
|
||||
.init_status.on = false,
|
||||
.init_status.hue = 0,
|
||||
.init_status.saturation = 100,
|
||||
.init_status.value = 100,
|
||||
};
|
||||
lightbulb_init(&config);
|
||||
ws2812_set_rgb_channel(LED_OFF, LED_OFF, LED_OFF);
|
||||
#else
|
||||
gpio_set_level(LED_R, LED_OFF);
|
||||
gpio_set_level(LED_G, LED_OFF);
|
||||
|
@ -15,7 +15,6 @@ extern "C" {
|
||||
#endif /**< __cplusplus */
|
||||
|
||||
#include "driver/gpio.h"
|
||||
#include "led_strip_encoder.h"
|
||||
|
||||
#if defined(CONFIG_BLE_MESH_ESP_WROOM_32)
|
||||
#define LED_R GPIO_NUM_25
|
||||
|
Loading…
x
Reference in New Issue
Block a user