1 // Copyright 2020 Espressif Systems (Shanghai) PTE LTD
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <stdio.h>
16 #include <string.h>
17 #include <stdlib.h>
18 #include "errno.h"
19 
20 #include "freertos/FreeRTOS.h"
21 #include "freertos/queue.h"
22 #include "freertos/task.h"
23 #include "freertos/timers.h"
24 #include "freertos/event_groups.h"
25 
26 #include "esp_err.h"
27 #include "esp_log.h"
28 #include "esp_system.h"
29 #include "esp_partition.h"
30 
31 #include "lwip/sockets.h"
32 #include "lwip/netdb.h"
33 #include "lwip/sockets.h"
34 
35 #include "nvs.h"
36 #include "nvs_flash.h"
37 #include "driver/i2c.h"
38 #include "sys/param.h"
39 #include "driver/gpio.h"
40 
41 #include "light_driver.h"
42 #include "ble_mesh_example_nvs.h"
43 
44 /**
45  * @brief The state of the five-color light
46  */
47 typedef struct {
48     uint8_t mode;
49     uint8_t on;
50     uint16_t hue;
51     uint8_t saturation;
52     uint8_t value;
53     uint8_t lightness;
54     uint8_t color_temperature;
55     uint8_t brightness;
56     uint32_t fade_period_ms;
57     uint32_t blink_period_ms;
58 } light_status_t;
59 
60 /**
61  * @brief The channel of the five-color light
62  */
63 enum light_channel {
64     CHANNEL_ID_RED = 0,
65     CHANNEL_ID_GREEN,
66     CHANNEL_ID_BLUE,
67     CHANNEL_ID_WARM,
68     CHANNEL_ID_COLD,
69 };
70 
71 #define LIGHT_FADE_PERIOD_MAX_MS (3 * 1000)
72 
73 static const char *TAG               = "light_driver";
74 static light_status_t g_light_status = {0};
75 static bool g_light_blink_flag       = false;
76 static TimerHandle_t g_fade_timer    = NULL;
77 static int g_fade_mode               = MODE_NONE;
78 static uint16_t g_fade_hue           = 0;
79 extern nvs_handle_t NVS_HANDLE;
80 
light_driver_init(light_driver_config_t * config)81 esp_err_t light_driver_init(light_driver_config_t *config)
82 {
83     LIGHT_PARAM_CHECK(config);
84     bool exist = false;
85 
86     if (ble_mesh_nvs_restore(NVS_HANDLE, LIGHT_STATUS_STORE_KEY, &g_light_status, sizeof(light_status_t), &exist) != ESP_OK) {
87         memset(&g_light_status, 0, sizeof(light_status_t));
88         g_light_status.mode              = MODE_HSV;
89         g_light_status.on                = 1;
90         g_light_status.hue               = 360;
91         g_light_status.saturation        = 0;
92         g_light_status.value             = 100;
93         g_light_status.lightness         = 100;
94         g_light_status.color_temperature = 0;
95         g_light_status.brightness        = 30;
96     }
97 
98 #if CONFIG_IDF_TARGET_ESP32C3
99     iot_led_init(LEDC_TIMER_0, LEDC_LOW_SPEED_MODE, 1000);
100 #elif CONFIG_IDF_TARGET_ESP32
101     iot_led_init(LEDC_TIMER_0, LEDC_HIGH_SPEED_MODE, 1000);
102 #endif
103 
104     g_light_status.fade_period_ms  = config->fade_period_ms;
105     g_light_status.blink_period_ms = config->blink_period_ms;
106 
107     iot_led_regist_channel(CHANNEL_ID_RED, config->gpio_red);
108     iot_led_regist_channel(CHANNEL_ID_GREEN, config->gpio_green);
109     iot_led_regist_channel(CHANNEL_ID_BLUE, config->gpio_blue);
110     iot_led_regist_channel(CHANNEL_ID_WARM, config->gpio_warm);
111     iot_led_regist_channel(CHANNEL_ID_COLD, config->gpio_cold);
112 
113     ESP_LOGI(TAG, "hue: %d, saturation: %d, value: %d, lightness: %d",
114              g_light_status.hue, g_light_status.saturation, g_light_status.value, g_light_status.lightness);
115     ESP_LOGI(TAG, "brightness: %d, color_temperature: %d",
116              g_light_status.brightness, g_light_status.color_temperature);
117 
118     return ESP_OK;
119 }
120 
light_driver_deinit(void)121 esp_err_t light_driver_deinit(void)
122 {
123     esp_err_t ret = ESP_OK;
124 
125     iot_led_deinit();
126 
127     return ret;
128 }
129 
light_driver_config(uint32_t fade_period_ms,uint32_t blink_period_ms)130 esp_err_t light_driver_config(uint32_t fade_period_ms, uint32_t blink_period_ms)
131 {
132     g_light_status.fade_period_ms = fade_period_ms;
133     g_light_status.blink_period_ms = blink_period_ms;
134 
135     return ESP_OK;
136 }
137 
light_driver_set_rgb(uint8_t red,uint8_t green,uint8_t blue)138 esp_err_t light_driver_set_rgb(uint8_t red, uint8_t green, uint8_t blue)
139 {
140     esp_err_t ret = 0;
141 
142     ret = iot_led_set_channel(CHANNEL_ID_RED, red, 0);
143     LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
144 
145     ret = iot_led_set_channel(CHANNEL_ID_GREEN, green, 0);
146     LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
147 
148     ret = iot_led_set_channel(CHANNEL_ID_BLUE, blue, 0);
149     LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
150 
151     ret = iot_led_set_channel(CHANNEL_ID_WARM, 0, 0);
152     LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
153 
154     ret = iot_led_set_channel(CHANNEL_ID_COLD, 0, 0);
155     LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
156 
157     return ESP_OK;
158 }
159 
light_driver_hsv2rgb(uint16_t hue,uint8_t saturation,uint8_t value,uint8_t * red,uint8_t * green,uint8_t * blue)160 static esp_err_t light_driver_hsv2rgb(uint16_t hue, uint8_t saturation, uint8_t value,
161                                       uint8_t *red, uint8_t *green, uint8_t *blue)
162 {
163     uint16_t hi = (hue / 60) % 6;
164     uint16_t F = 100 * hue / 60 - 100 * hi;
165     uint16_t P = value * (100 - saturation) / 100;
166     uint16_t Q = value * (10000 - F * saturation) / 10000;
167     uint16_t T = value * (10000 - saturation * (100 - F)) / 10000;
168 
169     switch (hi) {
170         case 0:
171             *red   = value;
172             *green = T;
173             *blue  = P;
174             break;
175 
176         case 1:
177             *red   = Q;
178             *green = value;
179             *blue  = P;
180             break;
181 
182         case 2:
183             *red   = P;
184             *green = value;
185             *blue  = T;
186             break;
187 
188         case 3:
189             *red   = P;
190             *green = Q;
191             *blue  = value;
192             break;
193 
194         case 4:
195             *red   = T;
196             *green = P;
197             *blue  = value;
198             break;
199 
200         case 5:
201             *red   = value;
202             *green = P;
203             *blue  = Q;
204             break;
205 
206         default:
207             return ESP_FAIL;
208     }
209 
210     *red   = *red * 255 / 100;
211     *green = *green * 255 / 100;
212     *blue  = *blue * 255 / 100;
213 
214     return ESP_OK;
215 }
216 
light_driver_rgb2hsv(uint16_t red,uint16_t green,uint16_t blue,uint16_t * h,uint8_t * s,uint8_t * v)217 static void light_driver_rgb2hsv(uint16_t red, uint16_t green, uint16_t blue,
218                                  uint16_t *h, uint8_t *s, uint8_t *v)
219 {
220     double hue, saturation, value;
221     double m_max = MAX(red, MAX(green, blue));
222     double m_min = MIN(red, MIN(green, blue));
223     double m_delta = m_max - m_min;
224 
225     value = m_max / 255.0;
226 
227     if (m_delta == 0) {
228         hue = 0;
229         saturation = 0;
230     } else {
231         saturation = m_delta / m_max;
232 
233         if (red == m_max) {
234             hue = (green - blue) / m_delta;
235         } else if (green == m_max) {
236             hue = 2 + (blue - red) / m_delta;
237         } else {
238             hue = 4 + (red - green) / m_delta;
239         }
240 
241         hue = hue * 60;
242 
243         if (hue < 0) {
244             hue = hue + 360;
245         }
246     }
247 
248     *h = (int)(hue + 0.5);
249     *s = (int)(saturation * 100 + 0.5);
250     *v = (int)(value * 100 + 0.5);
251 }
252 
253 // refence: https://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c
light_driver_hsl2rgb(uint16_t hue,uint8_t saturation,uint8_t lightness,uint8_t * red,uint8_t * green,uint8_t * blue)254 static esp_err_t light_driver_hsl2rgb(uint16_t hue, uint8_t saturation, uint8_t lightness,
255                                       uint8_t *red, uint8_t *green, uint8_t *blue)
256 {
257     uint16_t hi = (hue / 60) % 6;
258     uint16_t C  = (100 - abs(2 * lightness - 100)) * saturation / 100;
259     uint16_t M  = 100 * (lightness - 0.5 * C) / 100;
260     uint16_t X  = C * (100 - abs((hue * 100 / 60 ) % 200 - 100)) / 100;
261 
262     switch (hi) {
263         case 0: /* hue 0~60 */
264             *red   = C + M;
265             *green = X + M;
266             *blue  = M;
267             break;
268 
269         case 1: /* hue 60~120 */
270             *red   = X + M;
271             *green = C + M;
272             *blue  = M;
273             break;
274 
275         case 2: /* hue 120~180 */
276             *red   = M;
277             *green = C + M;
278             *blue  = X + M;
279             break;
280 
281         case 3: /* hue 180~240 */
282             *red   = M;
283             *green = X + M;
284             *blue  = C + M;
285             break;
286 
287         case 4: /* hue 240~300 */
288             *red   = X + M;
289             *green = M;
290             *blue  = C + M;
291             break;
292 
293         case 5: /* hue 300~360 */
294             *red   = C + M;
295             *green = M;
296             *blue  = X + M;
297             break;
298 
299         default:
300             return ESP_FAIL;
301     }
302 
303     *red   = *red * 255 / 100;
304     *green = *green * 255 / 100;
305     *blue  = *blue * 255 / 100;
306 
307     return ESP_OK;
308 }
309 
light_driver_set_hsv(uint16_t hue,uint8_t saturation,uint8_t value)310 esp_err_t light_driver_set_hsv(uint16_t hue, uint8_t saturation, uint8_t value)
311 {
312     LIGHT_PARAM_CHECK(hue <= 360);
313     LIGHT_PARAM_CHECK(saturation <= 100);
314     LIGHT_PARAM_CHECK(value <= 100);
315 
316     esp_err_t ret = ESP_OK;
317     uint8_t red   = 0;
318     uint8_t green = 0;
319     uint8_t blue  = 0;
320 
321     ret = light_driver_hsv2rgb(hue, saturation, value, &red, &green, &blue);
322     LIGHT_ERROR_CHECK(ret < 0, ret, "light_driver_hsv2rgb, ret: %d", ret);
323 
324     ESP_LOGV(TAG, "red: %d, green: %d, blue: %d", red, green, blue);
325 
326     ret = iot_led_set_channel(CHANNEL_ID_RED, red, g_light_status.fade_period_ms);
327     LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
328 
329     ret = iot_led_set_channel(CHANNEL_ID_GREEN, green, g_light_status.fade_period_ms);
330     LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
331 
332     ret = iot_led_set_channel(CHANNEL_ID_BLUE, blue, g_light_status.fade_period_ms);
333     LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
334 
335     if (g_light_status.mode != MODE_HSV) {
336         ret = iot_led_set_channel(CHANNEL_ID_WARM, 0, g_light_status.fade_period_ms);
337         LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
338 
339         ret = iot_led_set_channel(CHANNEL_ID_COLD, 0, g_light_status.fade_period_ms);
340         LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
341     }
342 
343     g_light_status.mode       = MODE_HSV;
344     g_light_status.on         = 1;
345     g_light_status.hue        = hue;
346     g_light_status.value      = value;
347     g_light_status.saturation = saturation;
348 
349     ret = ble_mesh_nvs_store(NVS_HANDLE, LIGHT_STATUS_STORE_KEY, &g_light_status, sizeof(light_status_t));
350     LIGHT_ERROR_CHECK(ret < 0, ret, "ble_mesh_nvs_store, ret: %d", ret);
351 
352     return ESP_OK;
353 }
354 
light_driver_set_hue(uint16_t hue)355 esp_err_t light_driver_set_hue(uint16_t hue)
356 {
357     if (g_light_status.mode == MODE_HSV) {
358         return light_driver_set_hsv(hue, g_light_status.saturation, g_light_status.value);
359     } else if (g_light_status.mode == MODE_HSL) {
360         return light_driver_set_hsl(hue, g_light_status.saturation, g_light_status.lightness);
361     } else {
362         return ESP_FAIL;
363     }
364 }
365 
light_driver_set_saturation(uint8_t saturation)366 esp_err_t light_driver_set_saturation(uint8_t saturation)
367 {
368     if (g_light_status.mode == MODE_HSV) {
369         return light_driver_set_hsv(g_light_status.hue, saturation, g_light_status.value);
370     } else if (g_light_status.mode == MODE_HSL) {
371         return light_driver_set_hsl(g_light_status.hue, saturation, g_light_status.lightness);
372     } else {
373         return ESP_FAIL;
374     }
375 }
376 
light_driver_set_value(uint8_t value)377 esp_err_t light_driver_set_value(uint8_t value)
378 {
379     return light_driver_set_hsv(g_light_status.hue, g_light_status.saturation, value);
380 }
381 
light_driver_get_hsv(uint16_t * hue,uint8_t * saturation,uint8_t * value)382 esp_err_t light_driver_get_hsv(uint16_t *hue, uint8_t *saturation, uint8_t *value)
383 {
384     LIGHT_PARAM_CHECK(hue);
385     LIGHT_PARAM_CHECK(saturation);
386     LIGHT_PARAM_CHECK(value);
387 
388     *hue        = g_light_status.hue;
389     *saturation = g_light_status.saturation;
390     *value      = g_light_status.value;
391 
392     return ESP_OK;
393 }
394 
light_driver_get_hue(void)395 uint16_t light_driver_get_hue(void)
396 {
397     return g_light_status.hue;
398 }
399 
light_driver_get_saturation(void)400 uint8_t light_driver_get_saturation(void)
401 {
402     return g_light_status.saturation;
403 }
404 
light_driver_get_value(void)405 uint8_t light_driver_get_value(void)
406 {
407     return g_light_status.value;
408 }
409 
light_driver_get_mode(void)410 uint8_t light_driver_get_mode(void)
411 {
412     return g_light_status.mode;
413 }
414 
light_driver_set_ctb(uint8_t color_temperature,uint8_t brightness)415 esp_err_t light_driver_set_ctb(uint8_t color_temperature, uint8_t brightness)
416 {
417     LIGHT_PARAM_CHECK(brightness <= 100);
418     LIGHT_PARAM_CHECK(color_temperature <= 100);
419 
420     esp_err_t ret = ESP_OK;
421     uint8_t warm_tmp = color_temperature * brightness / 100;
422     uint8_t cold_tmp = (100 - color_temperature) * brightness / 100;
423     warm_tmp         = warm_tmp < 15 ? warm_tmp : 14 + warm_tmp * 86 / 100;
424     cold_tmp         = cold_tmp < 15 ? cold_tmp : 14 + cold_tmp * 86 / 100;
425 
426     ret = iot_led_set_channel(CHANNEL_ID_COLD,
427                               cold_tmp * 255 / 100, g_light_status.fade_period_ms);
428     LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
429 
430     ret = iot_led_set_channel(CHANNEL_ID_WARM,
431                               warm_tmp * 255 / 100, g_light_status.fade_period_ms);
432     LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
433 
434     if (g_light_status.mode != MODE_CTB) {
435         ret = iot_led_set_channel(CHANNEL_ID_RED, 0, g_light_status.fade_period_ms);
436         LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
437 
438         ret = iot_led_set_channel(CHANNEL_ID_GREEN, 0, g_light_status.fade_period_ms);
439         LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
440 
441         ret = iot_led_set_channel(CHANNEL_ID_BLUE, 0, g_light_status.fade_period_ms);
442         LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
443     }
444 
445     g_light_status.mode              = MODE_CTB;
446     g_light_status.on                = 1;
447     g_light_status.brightness        = brightness;
448     g_light_status.color_temperature = color_temperature;
449 
450     ret = ble_mesh_nvs_store(NVS_HANDLE, LIGHT_STATUS_STORE_KEY, &g_light_status, sizeof(light_status_t));
451     LIGHT_ERROR_CHECK(ret < 0, ret, "ble_mesh_nvs_store, ret: %d", ret);
452 
453     return ESP_OK;
454 }
455 
light_driver_set_color_temperature(uint8_t color_temperature)456 esp_err_t light_driver_set_color_temperature(uint8_t color_temperature)
457 {
458     return light_driver_set_ctb(color_temperature, g_light_status.brightness);
459 }
460 
light_driver_set_brightness(uint8_t brightness)461 esp_err_t light_driver_set_brightness(uint8_t brightness)
462 {
463     return light_driver_set_ctb(g_light_status.color_temperature, brightness);
464 }
465 
light_driver_get_ctb(uint8_t * color_temperature,uint8_t * brightness)466 esp_err_t light_driver_get_ctb(uint8_t *color_temperature, uint8_t *brightness)
467 {
468     LIGHT_PARAM_CHECK(color_temperature);
469     LIGHT_PARAM_CHECK(brightness);
470 
471     *brightness        = g_light_status.brightness;
472     *color_temperature = g_light_status.color_temperature;
473 
474     return ESP_OK;
475 }
476 
light_driver_get_color_temperature(void)477 uint8_t light_driver_get_color_temperature(void)
478 {
479     return g_light_status.color_temperature;
480 }
481 
light_driver_get_brightness(void)482 uint8_t light_driver_get_brightness(void)
483 {
484     return g_light_status.brightness;
485 }
486 
light_driver_set_hsl(uint16_t hue,uint8_t saturation,uint8_t lightness)487 esp_err_t light_driver_set_hsl(uint16_t hue, uint8_t saturation, uint8_t lightness)
488 {
489     LIGHT_PARAM_CHECK(hue <= 360);
490     LIGHT_PARAM_CHECK(saturation <= 100);
491     LIGHT_PARAM_CHECK(lightness <= 100);
492 
493     esp_err_t ret = ESP_OK;
494     uint8_t red   = 0;
495     uint8_t green = 0;
496     uint8_t blue  = 0;
497 
498     ret = light_driver_hsl2rgb(hue, saturation, lightness, &red, &green, &blue);
499     LIGHT_ERROR_CHECK(ret < 0, ret, "light_driver_hsl2rgb, ret: %d", ret);
500 
501     ESP_LOGV(TAG, "red: %d, green: %d, blue: %d", red, green, blue);
502 
503     ret = iot_led_set_channel(CHANNEL_ID_RED, red, g_light_status.fade_period_ms);
504     LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
505 
506     ret = iot_led_set_channel(CHANNEL_ID_GREEN, green, g_light_status.fade_period_ms);
507     LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
508 
509     ret = iot_led_set_channel(CHANNEL_ID_BLUE, blue, g_light_status.fade_period_ms);
510     LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
511 
512     if (g_light_status.mode != MODE_HSL) {
513         ret = iot_led_set_channel(CHANNEL_ID_WARM, 0, g_light_status.fade_period_ms);
514         LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
515 
516         ret = iot_led_set_channel(CHANNEL_ID_COLD, 0, g_light_status.fade_period_ms);
517         LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
518     }
519 
520     g_light_status.mode       = MODE_HSL;
521     g_light_status.on         = 1;
522     g_light_status.hue        = hue;
523     g_light_status.saturation = saturation;
524     g_light_status.lightness  = lightness;
525 
526     ret = ble_mesh_nvs_store(NVS_HANDLE, LIGHT_STATUS_STORE_KEY, &g_light_status, sizeof(light_status_t));
527     LIGHT_ERROR_CHECK(ret < 0, ret, "ble_mesh_nvs_store, ret: %d", ret);
528 
529     return ESP_OK;
530 }
531 
light_driver_set_lightness(uint8_t lightness)532 esp_err_t light_driver_set_lightness(uint8_t lightness)
533 {
534     return light_driver_set_hsl(g_light_status.hue, g_light_status.saturation, lightness);
535 }
536 
light_driver_get_lightness(void)537 uint8_t light_driver_get_lightness(void)
538 {
539     return g_light_status.lightness;
540 }
541 
light_driver_get_hsl(uint16_t * hue,uint8_t * saturation,uint8_t * lightness)542 esp_err_t light_driver_get_hsl(uint16_t *hue, uint8_t *saturation, uint8_t *lightness)
543 {
544     LIGHT_PARAM_CHECK(hue);
545     LIGHT_PARAM_CHECK(saturation);
546     LIGHT_PARAM_CHECK(lightness);
547 
548     *hue        = g_light_status.hue;
549     *saturation = g_light_status.saturation;
550     *lightness  = g_light_status.lightness;
551 
552     return ESP_OK;
553 }
554 
light_driver_set_switch(bool on)555 esp_err_t light_driver_set_switch(bool on)
556 {
557     esp_err_t ret     = ESP_OK;
558     g_light_status.on = on;
559 
560     if (!g_light_status.on) {
561         ret = iot_led_set_channel(CHANNEL_ID_RED, 0, g_light_status.fade_period_ms);
562         LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_set_channel, ret: %d", ret);
563 
564         ret = iot_led_set_channel(CHANNEL_ID_GREEN, 0, g_light_status.fade_period_ms);
565         LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_set_channel, ret: %d", ret);
566 
567         ret = iot_led_set_channel(CHANNEL_ID_BLUE, 0, g_light_status.fade_period_ms);
568         LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_set_channel, ret: %d", ret);
569 
570         ret = iot_led_set_channel(CHANNEL_ID_COLD, 0, g_light_status.fade_period_ms);
571         LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_set_channel, ret: %d", ret);
572 
573         ret = iot_led_set_channel(CHANNEL_ID_WARM, 0, g_light_status.fade_period_ms);
574         LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_set_channel, ret: %d", ret);
575 
576     } else {
577         switch (g_light_status.mode) {
578             case MODE_HSV:
579                 g_light_status.value = (g_light_status.value) ? g_light_status.value : 100;
580                 ret = light_driver_set_hsv(g_light_status.hue, g_light_status.saturation, g_light_status.value);
581                 LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "light_driver_set_hsv, ret: %d", ret);
582                 break;
583 
584             case MODE_HSL:
585                 g_light_status.lightness = (g_light_status.lightness) ? g_light_status.lightness : 100;
586                 ret = light_driver_set_hsl(g_light_status.hue, g_light_status.saturation, g_light_status.lightness);
587                 LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "light_driver_set_hsl, ret: %d", ret);
588                 break;
589 
590             case MODE_CTB:
591                 g_light_status.brightness = (g_light_status.brightness) ? g_light_status.brightness : 100;
592                 ret = light_driver_set_ctb(g_light_status.color_temperature, g_light_status.brightness);
593                 LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "light_driver_set_ctb, ret: %d", ret);
594                 break;
595 
596             default:
597                 ESP_LOGW(TAG, "This operation is not supported");
598                 break;
599         }
600     }
601 
602     ret = ble_mesh_nvs_store(NVS_HANDLE, LIGHT_STATUS_STORE_KEY, &g_light_status, sizeof(light_status_t));
603     LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "ble_mesh_nvs_store, ret: %d", ret);
604 
605     return ESP_OK;
606 }
607 
light_driver_set_mode(light_mode_t mode)608 esp_err_t light_driver_set_mode(light_mode_t mode)
609 {
610     g_light_status.mode = mode;
611 
612     return ESP_OK;
613 }
614 
light_driver_get_switch(void)615 bool light_driver_get_switch(void)
616 {
617     return g_light_status.on;
618 }
619 
light_driver_breath_start(uint8_t red,uint8_t green,uint8_t blue)620 esp_err_t light_driver_breath_start(uint8_t red, uint8_t green, uint8_t blue)
621 {
622     esp_err_t ret = ESP_OK;
623 
624     ret = iot_led_start_blink(CHANNEL_ID_RED,
625                               red, g_light_status.blink_period_ms, true);
626     LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_start_blink, ret: %d", ret);
627     ret = iot_led_start_blink(CHANNEL_ID_GREEN,
628                               green, g_light_status.blink_period_ms, true);
629     LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_start_blink, ret: %d", ret);
630     ret = iot_led_start_blink(CHANNEL_ID_BLUE,
631                               blue, g_light_status.blink_period_ms, true);
632     LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_start_blink, ret: %d", ret);
633 
634     g_light_blink_flag = true;
635 
636     return ESP_OK;
637 }
638 
light_driver_breath_stop(void)639 esp_err_t light_driver_breath_stop(void)
640 {
641     esp_err_t ret = ESP_OK;
642 
643     if (g_light_blink_flag == false) {
644         return ESP_OK;
645     }
646 
647     ret = iot_led_stop_blink(CHANNEL_ID_RED);
648     LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_stop_blink, ret: %d", ret);
649 
650     ret = iot_led_stop_blink(CHANNEL_ID_GREEN);
651     LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_stop_blink, ret: %d", ret);
652 
653     ret = iot_led_stop_blink(CHANNEL_ID_BLUE);
654     LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_stop_blink, ret: %d", ret);
655 
656     light_driver_set_switch(true);
657 
658     return ESP_OK;
659 }
660 
light_driver_fade_brightness(uint8_t brightness)661 esp_err_t light_driver_fade_brightness(uint8_t brightness)
662 {
663     esp_err_t ret = ESP_OK;
664     g_fade_mode   = MODE_ON;
665     uint32_t fade_period_ms = 0;
666 
667     if (g_light_status.mode == MODE_HSV) {
668         uint8_t red   = 0;
669         uint8_t green = 0;
670         uint8_t blue  = 0;
671 
672         ret = light_driver_hsv2rgb(g_light_status.hue, g_light_status.saturation, g_light_status.value, &red, &green, &blue);
673         LIGHT_ERROR_CHECK(ret < 0, ret, "light_driver_hsv2rgb, ret: %d", ret);
674 
675         if (brightness != 0) {
676             ret = iot_led_get_channel((ledc_channel_t)CHANNEL_ID_RED, &red);
677             LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_get_channel, ret: %d", ret);
678             ret = iot_led_get_channel((ledc_channel_t)CHANNEL_ID_GREEN, &green);
679             LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_get_channel, ret: %d", ret);
680             ret = iot_led_get_channel((ledc_channel_t)CHANNEL_ID_BLUE, &blue);
681             LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_get_channel, ret: %d", ret);
682 
683             uint8_t max_color       = MAX(MAX(red, green), blue);
684             uint8_t change_value    = brightness * 255 / 100 - max_color;
685             fade_period_ms = LIGHT_FADE_PERIOD_MAX_MS * change_value / 255;
686         } else {
687             fade_period_ms = LIGHT_FADE_PERIOD_MAX_MS * MAX(MAX(red, green), blue) / 255;
688             red   = 0;
689         }
690 
691         g_light_status.value = brightness;
692         light_driver_hsv2rgb(g_light_status.hue, g_light_status.saturation, g_light_status.value, &red, &green, &blue);
693 
694         ret = iot_led_set_channel(CHANNEL_ID_RED, red, fade_period_ms);
695         LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
696 
697         ret = iot_led_set_channel(CHANNEL_ID_GREEN, green, fade_period_ms);
698         LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
699 
700         ret = iot_led_set_channel(CHANNEL_ID_BLUE, blue, fade_period_ms);
701         LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
702 
703     } else if (g_light_status.mode == MODE_CTB) {
704         uint8_t warm_tmp = 0;
705         uint8_t cold_tmp = 0;
706         fade_period_ms = LIGHT_FADE_PERIOD_MAX_MS * g_light_status.brightness / 100;
707 
708         if (brightness != 0) {
709             uint8_t change_value = brightness - g_light_status.brightness;
710             warm_tmp = g_light_status.color_temperature;
711             cold_tmp = (brightness - g_light_status.color_temperature);
712             fade_period_ms = LIGHT_FADE_PERIOD_MAX_MS * change_value / 100;
713         }
714 
715         ret = iot_led_set_channel(CHANNEL_ID_COLD,
716                                   cold_tmp * 255 / 100, fade_period_ms);
717         LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
718 
719         ret = iot_led_set_channel(CHANNEL_ID_WARM,
720                                   warm_tmp * 255 / 100, fade_period_ms);
721         LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
722 
723         g_light_status.brightness = brightness;
724     }
725 
726     ret = ble_mesh_nvs_store(NVS_HANDLE, LIGHT_STATUS_STORE_KEY, &g_light_status, sizeof(light_status_t));
727     LIGHT_ERROR_CHECK(ret < 0, ret, "ble_mesh_nvs_store, ret: %d", ret);
728 
729     return ESP_OK;
730 }
731 
light_fade_timer_stop(void)732 static void light_fade_timer_stop(void)
733 {
734     if (!g_fade_timer) {
735         return ;
736     }
737 
738     if (!xTimerStop(g_fade_timer, portMAX_DELAY)) {
739         ESP_LOGW(TAG, "xTimerStop timer: %p", g_fade_timer);
740     }
741 
742     if (!xTimerDelete(g_fade_timer, portMAX_DELAY)) {
743         ESP_LOGW(TAG, "xTimerDelete timer: %p", g_fade_timer);
744     }
745 
746     g_fade_timer = NULL;
747 }
748 
light_fade_timer_cb(void * timer)749 static void light_fade_timer_cb(void *timer)
750 {
751     uint8_t red   = 0;
752     uint8_t green = 0;
753     uint8_t blue  = 0;
754     uint32_t fade_period_ms = LIGHT_FADE_PERIOD_MAX_MS * 2 / 6;
755     int variety = (g_fade_hue > 180) ? 60 : -60;
756 
757     if (g_light_status.hue >= 360 || g_light_status.hue <= 0) {
758         light_fade_timer_stop();
759     }
760 
761     g_light_status.hue = g_light_status.hue >= 360 ? 360 : g_light_status.hue + variety;
762     g_light_status.hue = g_light_status.hue <= 60 ? 0 : g_light_status.hue + variety;
763 
764     light_driver_hsv2rgb(g_light_status.hue, g_light_status.saturation, g_light_status.value, &red, &green, &blue);
765 
766     iot_led_set_channel(CHANNEL_ID_RED, red, fade_period_ms);
767     iot_led_set_channel(CHANNEL_ID_GREEN, green, fade_period_ms);
768     iot_led_set_channel(CHANNEL_ID_BLUE, blue, fade_period_ms);
769 }
770 
light_driver_fade_hue(uint16_t hue)771 esp_err_t light_driver_fade_hue(uint16_t hue)
772 {
773     esp_err_t ret = ESP_OK;
774     g_fade_mode   = MODE_HSV;
775     g_fade_hue    = hue;
776 
777     light_fade_timer_stop();
778 
779     if (g_light_status.mode != MODE_HSV) {
780         ret = iot_led_set_channel(CHANNEL_ID_WARM, 0, 0);
781         LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
782 
783         ret = iot_led_set_channel(CHANNEL_ID_COLD, 0, 0);
784         LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
785     }
786 
787     g_light_status.mode     = MODE_HSV;
788     g_light_status.value    = (g_light_status.value == 0) ? 100 : g_light_status.value;
789     uint32_t fade_period_ms = LIGHT_FADE_PERIOD_MAX_MS * 2 / 6;
790 
791     light_fade_timer_cb(NULL);
792 
793     g_fade_timer = xTimerCreate("light_timer", fade_period_ms,
794                                 true, NULL, light_fade_timer_cb);
795     xTimerStart(g_fade_timer, 0);
796 
797     return ESP_OK;
798 }
799 
light_driver_fade_warm(uint8_t color_temperature)800 esp_err_t light_driver_fade_warm(uint8_t color_temperature)
801 {
802     esp_err_t ret = ESP_OK;
803     g_fade_mode   = MODE_CTB;
804 
805     if (g_light_status.mode != MODE_CTB) {
806         ret = iot_led_set_channel(CHANNEL_ID_RED, 0, g_light_status.fade_period_ms);
807         LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
808 
809         ret = iot_led_set_channel(CHANNEL_ID_GREEN, 0, g_light_status.fade_period_ms);
810         LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
811 
812         ret = iot_led_set_channel(CHANNEL_ID_BLUE, 0, g_light_status.fade_period_ms);
813         LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
814     }
815 
816     uint8_t warm_tmp =  color_temperature * g_light_status.brightness / 100;
817     uint8_t cold_tmp = (100 - color_temperature) * g_light_status.brightness / 100;
818 
819     ret = iot_led_set_channel(CHANNEL_ID_COLD, cold_tmp * 255 / 100, LIGHT_FADE_PERIOD_MAX_MS);
820     LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
821 
822     ret = iot_led_set_channel(CHANNEL_ID_WARM, warm_tmp * 255 / 100, LIGHT_FADE_PERIOD_MAX_MS);
823     LIGHT_ERROR_CHECK(ret < 0, ret, "iot_led_set_channel, ret: %d", ret);
824 
825     g_light_status.mode              = MODE_CTB;
826     g_light_status.color_temperature = color_temperature;
827     ret = ble_mesh_nvs_store(NVS_HANDLE, LIGHT_STATUS_STORE_KEY, &g_light_status, sizeof(light_status_t));
828     LIGHT_ERROR_CHECK(ret < 0, ret, "ble_mesh_nvs_store, ret: %d", ret);
829 
830     return ESP_OK;
831 }
832 
light_driver_fade_stop(void)833 esp_err_t light_driver_fade_stop(void)
834 {
835     esp_err_t ret = ESP_OK;
836 
837     light_fade_timer_stop();
838 
839     if (g_light_status.mode != MODE_CTB) {
840         uint16_t hue       = 0;
841         uint8_t saturation = 0;
842         uint8_t value      = 0;
843 
844         ret = iot_led_stop_blink(CHANNEL_ID_RED);
845         LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_stop_blink, ret: %d", ret);
846 
847         ret = iot_led_stop_blink(CHANNEL_ID_GREEN);
848         LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_stop_blink, ret: %d", ret);
849 
850         ret = iot_led_stop_blink(CHANNEL_ID_BLUE);
851         LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_stop_blink, ret: %d", ret);
852 
853         uint8_t red, green, blue;
854 
855         ret = iot_led_get_channel(CHANNEL_ID_RED, &red);
856         LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_get_channel, ret: %d", ret);
857         ret = iot_led_get_channel(CHANNEL_ID_GREEN, &green);
858         LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_get_channel, ret: %d", ret);
859         ret = iot_led_get_channel(CHANNEL_ID_BLUE, &blue);
860         LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_get_channel, ret: %d", ret);
861 
862         light_driver_rgb2hsv(red, green, blue, &hue, &saturation, &value);
863 
864         g_light_status.hue   = (g_fade_mode == MODE_HSV) ? hue : g_light_status.hue;
865         g_light_status.value = (g_fade_mode == MODE_OFF || g_fade_mode == MODE_ON) ? value : g_light_status.value;
866     } else {
867         uint8_t color_temperature = 0;
868         uint8_t brightness        = 0;
869 
870         ret = iot_led_stop_blink(CHANNEL_ID_COLD);
871         LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_stop_blink, ret: %d", ret);
872 
873         ret = iot_led_stop_blink(CHANNEL_ID_WARM);
874         LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_stop_blink, ret: %d", ret);
875 
876         uint8_t warm_tmp, cold_tmp;
877         uint8_t tmp;
878 
879         ret = iot_led_get_channel(CHANNEL_ID_WARM, &tmp);
880         LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_get_channel, ret: %d", ret);
881         warm_tmp = (int32_t)tmp * 100 / 255;
882 
883         ret = iot_led_get_channel(CHANNEL_ID_COLD, &tmp);
884         LIGHT_ERROR_CHECK(ret < 0, ESP_FAIL, "iot_led_get_channel, ret: %d", ret);
885         cold_tmp = (int32_t)tmp * 100 / 255;
886 
887         color_temperature = (!warm_tmp) ? 0 : 100 / (cold_tmp / warm_tmp + 1);
888         brightness        = (!color_temperature) ? cold_tmp : warm_tmp * 100 / color_temperature;
889 
890         g_light_status.brightness        = (g_fade_mode == MODE_OFF || g_fade_mode == MODE_ON) ? brightness : g_light_status.brightness;
891         g_light_status.color_temperature = (g_fade_mode == MODE_CTB) ? color_temperature : g_light_status.color_temperature;
892     }
893 
894     ret = ble_mesh_nvs_store(NVS_HANDLE, LIGHT_STATUS_STORE_KEY, &g_light_status, sizeof(light_status_t));
895     LIGHT_ERROR_CHECK(ret < 0, ret, "ble_mesh_nvs_store, ret: %d", ret);
896 
897     g_fade_mode = MODE_NONE;
898     return ESP_OK;
899 }
900