/* * * Copyright (c) 2022 Project CHIP Authors * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "LEDWidget.h" #include "AppConfig.h" #include /******************************************************************************* * Macro Definitions *******************************************************************************/ /* Allowed TCPWM compare value for maximum brightness */ #define LED_MAX_BRIGHTNESS (100u) /* Allowed TCPWM compare value for minimum brightness*/ #define LED_MIN_BRIGHTNESS (0u) #define PWM_LED_FREQ_HZ (1000u) /* in Hz */ /* subtracting from 100 since the LED is connected in active low configuration */ #define GET_DUTY_CYCLE(x) (100 - x) // PWM period in micro seconds #define LED_PWM_PERIOD_US (255u) #ifdef LIGHT_SELECT_RGB static void show_pwm(duet_pwm_dev_t * pwm_dev, uint8_t val) { duet_pwm_config_t pwm_cfg; if (val < LED_MIN_BRIGHTNESS) val = LED_MIN_BRIGHTNESS; pwm_cfg.duty_cycle = (float) (val) / LED_PWM_PERIOD_US; pwm_cfg.freq = PWM_LED_FREQ_HZ; duet_pwm_para_chg(pwm_dev, pwm_cfg); } static void init_pwm(duet_pwm_dev_t * pwm_dev, uint8_t ledNum, uint8_t val) { pwm_dev->port = ledNum; pwm_dev->config.duty_cycle = val; pwm_dev->config.freq = PWM_LED_FREQ_HZ; pwm_dev->priv = NULL; duet_pwm_init(pwm_dev); } #endif void LEDWidget::Init(uint8_t ledNum) { mLastChangeTimeMS = 0; mBlinkOnTimeMS = 0; mBlinkOffTimeMS = 0; mState = 0; mbrightness = LED_MIN_BRIGHTNESS; mHue = 0; mSaturation = 0; #ifdef LIGHT_SELECT_RGB if (ledNum == LIGHT_RGB_GREEN) { #ifdef CFG_PLF_RV32 asr_pinmux_config(LIGHT_RGB_RED_PAD, PF_PWM); #endif init_pwm(&pwm_led_g, ledNum, LED_MIN_BRIGHTNESS); } else if (ledNum == LIGHT_RGB_BLUE) { #ifdef CFG_PLF_RV32 asr_pinmux_config(LIGHT_RGB_BLUE_PAD, PF_PWM); #endif init_pwm(&pwm_led_b, ledNum, LED_MIN_BRIGHTNESS); } else { #ifdef CFG_PLF_RV32 asr_pinmux_config(LIGHT_RGB_GREEN_PAD, PF_PWM); #endif init_pwm(&pwm_led, ledNum, LED_MIN_BRIGHTNESS); } #else gpio.port = ledNum; gpio.config = DUET_OUTPUT_PUSH_PULL; duet_gpio_init(&gpio); #endif } void LEDWidget::Invert(void) { Set(!mState); } void LEDWidget::Set(bool state) { mLastChangeTimeMS = mBlinkOnTimeMS = mBlinkOffTimeMS = 0; DoSet(state); } bool LEDWidget::Get() { return mState; } void LEDWidget::Blink(uint32_t changeRateMS) { Blink(changeRateMS, changeRateMS); } void LEDWidget::Blink(uint32_t onTimeMS, uint32_t offTimeMS) { mBlinkOnTimeMS = onTimeMS; mBlinkOffTimeMS = offTimeMS; Animate(); } void LEDWidget::Animate() { if (mBlinkOnTimeMS != 0 && mBlinkOffTimeMS != 0) { uint64_t nowMS = chip::System::SystemClock().GetMonotonicMilliseconds64().count(); uint64_t stateDurMS = ((mState) ? mBlinkOnTimeMS : mBlinkOffTimeMS); uint64_t nextChangeTimeMS = mLastChangeTimeMS + stateDurMS; if (nextChangeTimeMS < nowMS) { DoSet(!mState); mLastChangeTimeMS = nowMS; } } } void LEDWidget::DoSet(bool state) { if (mState != state) { #ifdef LIGHT_SELECT_RGB (state) ? PWM_start() : PWM_stop(); #else (state) ? duet_gpio_output_low(&gpio) : duet_gpio_output_high(&gpio); #endif } mState = state; } #ifdef LIGHT_SELECT_RGB void LEDWidget::RGB_init() { Init(LIGHT_RGB_RED); // red light of RGB Init(LIGHT_RGB_GREEN); // green light of RGB Init(LIGHT_RGB_BLUE); // blue light of RGB } void LEDWidget::PWM_start() { if (!mState) { /* Start PWM to turn the LED on */ if (0 != duet_pwm_start(&pwm_led)) { ASR_LOG("PWM failed to start!"); } /* Start PWM to turn the LED on */ if (0 != duet_pwm_start(&pwm_led_g)) { ASR_LOG("PWM failed to start!"); } /* Start PWM to turn the LED on */ if (0 != duet_pwm_start(&pwm_led_b)) { ASR_LOG("PWM failed to start!"); } mState = 1; } } void LEDWidget::PWM_stop() { SetBrightness(LED_MIN_BRIGHTNESS); mbrightness = LED_MIN_BRIGHTNESS; mState = 0; } void LEDWidget::SetBrightness(uint8_t brightness) { mbrightness = brightness; SetColor(mHue, mSaturation); } void LEDWidget::SetColor(uint8_t Hue, uint8_t Saturation) { uint8_t red, green, blue; uint8_t sSaturation, sbrightness; uint16_t sHue; sbrightness = (mState) ? mbrightness : 0; sHue = static_cast(Hue) * 360 / 254; // sHue [0, 360] sSaturation = static_cast(Saturation) * 100 / 254; // sSaturation [0 , 100] HSB2rgb(sHue, sSaturation, sbrightness, red, green, blue); ASR_LOG("brightness: %d, red: %d, green: %d, blue: %d", sbrightness, red, green, blue); mHue = Hue; mSaturation = Saturation; showRGB(red, green, blue); } void LEDWidget::HSB2rgb(uint16_t Hue, uint8_t Saturation, uint8_t brightness, uint8_t & red, uint8_t & green, uint8_t & blue) { uint16_t i = Hue / 60; uint16_t rgb_max = brightness; uint16_t rgb_min = rgb_max * (100 - Saturation) / 100; uint16_t diff = Hue % 60; uint16_t rgb_adj = (rgb_max - rgb_min) * diff / 60; switch (i) { case 0: red = rgb_max; green = rgb_min + rgb_adj; blue = rgb_min; break; case 1: red = rgb_max - rgb_adj; green = rgb_max; blue = rgb_min; break; case 2: red = rgb_min; green = rgb_max; blue = rgb_min + rgb_adj; break; case 3: red = rgb_min; green = rgb_max - rgb_adj; blue = rgb_max; break; case 4: red = rgb_min + rgb_adj; green = rgb_min; blue = rgb_max; break; default: red = rgb_max; green = rgb_min; blue = rgb_max - rgb_adj; break; } } void LEDWidget::showRGB(uint8_t red, uint8_t green, uint8_t blue) { show_pwm(&pwm_led, red); show_pwm(&pwm_led_g, green); show_pwm(&pwm_led_b, blue); } #endif