Files
fastbee/sdk/ESP-IDF/esp_fastbee_aliyun/components/lightbulb/lightbulb.c
2024-08-05 15:46:10 +08:00

328 lines
7.9 KiB
C

/*
* ESPRESSIF MIT License
*
* Copyright (c) 2019 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case,
* it is free of charge, to any person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include <stdio.h>
#include <sdkconfig.h>
#ifdef CONFIG_IDF_TARGET_ESP8266
#include "driver/pwm.h"
#else
#include "driver/ledc.h"
#endif
#include "esp_log.h"
typedef struct rgb {
uint8_t r; // 0-100 %
uint8_t g; // 0-100 %
uint8_t b; // 0-100 %
} rgb_t;
typedef struct hsp {
uint16_t h; // 0-360
uint16_t s; // 0-100
uint16_t b; // 0-100
} hsp_t;
/* LED numbers below are for ESP-WROVER-KIT */
/* Red LED */
#define LEDC_IO_0 (0)
/* Green LED */
#define LEDC_IO_1 (2)
/* Blued LED */
#define LEDC_IO_2 (4)
#define PWM_DEPTH (1023)
#define PWM_TARGET_DUTY 8192
static hsp_t s_hsb_val;
static uint16_t s_brightness;
static bool s_on = false;
static const char *TAG = "lightbulb";
#ifdef CONFIG_IDF_TARGET_ESP8266
#define PWM_PERIOD (500)
#define PWM_IO_NUM 3
// pwm pin number
const uint32_t pin_num[PWM_IO_NUM] = {
LEDC_IO_0,
LEDC_IO_1,
LEDC_IO_2
};
// dutys table, (duty/PERIOD)*depth
uint32_t duties[PWM_IO_NUM] = {
250, 250, 250,
};
// phase table, (phase/180)*depth
int16_t phase[PWM_IO_NUM] = {
0, 0, 50,
};
#define LEDC_CHANNEL_0 0
#define LEDC_CHANNEL_1 1
#define LEDC_CHANNEL_2 2
#endif
/**
* @brief transform lightbulb's "RGB" and other parameter
*/
static void lightbulb_set_aim(uint32_t r, uint32_t g, uint32_t b, uint32_t cw, uint32_t ww, uint32_t period)
{
#ifdef CONFIG_IDF_TARGET_ESP8266
pwm_stop(0x3);
pwm_set_duty(LEDC_CHANNEL_0, r);
pwm_set_duty(LEDC_CHANNEL_1, g);
pwm_set_duty(LEDC_CHANNEL_2, b);
pwm_start();
#else
ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, r);
ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1, g);
ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_2, b);
ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0);
ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1);
ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_2);
#endif
}
/**
* @brief transform lightbulb's "HSV" to "RGB"
*/
static bool lightbulb_set_hsb2rgb(uint16_t h, uint16_t s, uint16_t v, rgb_t *rgb)
{
bool res = true;
uint16_t hi, F, P, Q, T;
if (!rgb)
return false;
if (h > 360) return false;
if (s > 100) return false;
if (v > 100) return false;
hi = (h / 60) % 6;
F = 100 * h / 60 - 100 * hi;
P = v * (100 - s) / 100;
Q = v * (10000 - F * s) / 10000;
T = v * (10000 - s * (100 - F)) / 10000;
switch (hi) {
case 0:
rgb->r = v;
rgb->g = T;
rgb->b = P;
break;
case 1:
rgb->r = Q;
rgb->g = v;
rgb->b = P;
break;
case 2:
rgb->r = P;
rgb->g = v;
rgb->b = T;
break;
case 3:
rgb->r = P;
rgb->g = Q;
rgb->b = v;
break;
case 4:
rgb->r = T;
rgb->g = P;
rgb->b = v;
break;
case 5:
rgb->r = v;
rgb->g = P;
rgb->b = Q;
break;
default:
return false;
}
return res;
}
/**
* @brief set the lightbulb's "HSV"
*/
static bool lightbulb_set_aim_hsv(uint16_t h, uint16_t s, uint16_t v)
{
rgb_t rgb_tmp;
bool ret = lightbulb_set_hsb2rgb(h, s, v, &rgb_tmp);
if (ret == false)
return false;
lightbulb_set_aim(rgb_tmp.r * PWM_TARGET_DUTY / 100, rgb_tmp.g * PWM_TARGET_DUTY / 100,
rgb_tmp.b * PWM_TARGET_DUTY / 100, (100 - s) * 5000 / 100, v * 2000 / 100, 1000);
return true;
}
/**
* @brief update the lightbulb's state
*/
static void lightbulb_update()
{
lightbulb_set_aim_hsv(s_hsb_val.h, s_hsb_val.s, s_hsb_val.b);
}
/**
* @brief initialize the lightbulb lowlevel module
*/
void lightbulb_init(void)
{
#ifdef CONFIG_IDF_TARGET_ESP8266
pwm_init(PWM_PERIOD, duties, PWM_IO_NUM, pin_num);
pwm_set_channel_invert(0x1 << 0);
pwm_set_phases(phase);
pwm_start();
#else
// enable ledc module
periph_module_enable(PERIPH_LEDC_MODULE);
// config the timer
ledc_timer_config_t ledc_timer = {
//set timer counter bit number
.bit_num = LEDC_TIMER_13_BIT,
//set frequency of pwm
.freq_hz = 5000,
//timer mode,
.speed_mode = LEDC_LOW_SPEED_MODE,
//timer index
.timer_num = LEDC_TIMER_0
};
ledc_timer_config(&ledc_timer);
//config the channel
ledc_channel_config_t ledc_channel = {
//set LEDC channel 0
.channel = LEDC_CHANNEL_0,
//set the duty for initialization.(duty range is 0 ~ ((2**bit_num)-1)
.duty = 100,
//GPIO number
.gpio_num = LEDC_IO_0,
//GPIO INTR TYPE, as an example, we enable fade_end interrupt here.
.intr_type = LEDC_INTR_FADE_END,
//set LEDC mode, from ledc_mode_t
.speed_mode = LEDC_LOW_SPEED_MODE,
//set LEDC timer source, if different channel use one timer,
//the frequency and bit_num of these channels should be the same
.timer_sel = LEDC_TIMER_0
};
//set the configuration
ledc_channel_config(&ledc_channel);
//config ledc channel1
ledc_channel.channel = LEDC_CHANNEL_1;
ledc_channel.gpio_num = LEDC_IO_1;
ledc_channel_config(&ledc_channel);
//config ledc channel2
ledc_channel.channel = LEDC_CHANNEL_2;
ledc_channel.gpio_num = LEDC_IO_2;
ledc_channel_config(&ledc_channel);
#endif
}
/**
* @brief deinitialize the lightbulb's lowlevel module
*/
void lightbulb_deinit(void)
{
#ifdef CONFIG_IDF_TARGET_ESP8266
#else
ledc_stop(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, 0);
ledc_stop(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1, 0);
ledc_stop(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_2, 0);
#endif
}
/**
* @brief turn on/off the lowlevel lightbulb
*/
int lightbulb_set_on(bool value)
{
ESP_LOGI(TAG, "lightbulb_set_on : %s", value == true ? "true" : "false");
if (value == true) {
s_hsb_val.b = s_brightness;
s_on = true;
} else {
s_brightness = s_hsb_val.b;
s_hsb_val.b = 0;
s_on = false;
}
lightbulb_update();
return 0;
}
/**
* @brief set the saturation of the lowlevel lightbulb
*/
int lightbulb_set_saturation(float value)
{
ESP_LOGI(TAG, "lightbulb_set_saturation : %f", value);
s_hsb_val.s = value;
if (true == s_on)
lightbulb_update();
return 0;
}
/**
* @brief set the hue of the lowlevel lightbulb
*/
int lightbulb_set_hue(float value)
{
ESP_LOGI(TAG, "lightbulb_set_hue : %f", value);
s_hsb_val.h = value;
if (true == s_on)
lightbulb_update();
return 0;
}
/**
* @brief set the brightness of the lowlevel lightbulb
*/
int lightbulb_set_brightness(int value)
{
ESP_LOGI(TAG, "lightbulb_set_brightness : %d", value);
s_hsb_val.b = value;
s_brightness = s_hsb_val.b;
if (true == s_on)
lightbulb_update();
return 0;
}