blob: 60924cea47edb5ed19356f6f70af17f81ddcb7a6 [file] [log] [blame]
/*
*
* Copyright (c) 2021 Project CHIP Authors
* Copyright (c) 2019 Google LLC.
* Copyright 2021, Cypress Semiconductor Corporation (an Infineon company)
* 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 "cybsp.h"
#include "cyhal.h"
#include <platform/CHIPDeviceLayer.h>
/*******************************************************************************
* 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 (1u)
#define PWM_LED_FREQ_HZ (1000000u) /* 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 CY_RGB_LED_PWM_PERIOD_US (255u)
// Clock instance
static cyhal_clock_t clk_pwm;
void LEDWidget::Init(int ledNum)
{
mLastChangeTimeMS = 0;
mBlinkOnTimeMS = 0;
mBlinkOffTimeMS = 0;
mLedNum = ledNum;
mState = 0;
mbrightness = LED_MAX_BRIGHTNESS;
if (CY_RSLT_SUCCESS != cyhal_pwm_init(&pwm_led, (cyhal_gpio_t) ledNum, NULL))
{
printf("LED PWM Init failed!");
}
if (CY_RSLT_SUCCESS != cyhal_pwm_set_duty_cycle(&pwm_led, GET_DUTY_CYCLE(LED_MAX_BRIGHTNESS), PWM_LED_FREQ_HZ))
{
printf("PWM failed to set dutycycle!");
}
}
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)
{
(state) ? PWM_start() : PWM_stop();
}
mState = state;
}
void LEDWidget::RGB_init()
{
cy_rslt_t result = CY_RSLT_SUCCESS;
// Allocate and assign the clock for TCPWMs for RGB LED control
result = cyhal_clock_allocate(&clk_pwm, CYHAL_CLOCK_BLOCK_PERIPHERAL_16BIT);
if (result == CY_RSLT_SUCCESS)
{
result = cyhal_clock_set_frequency(&clk_pwm, PWM_LED_FREQ_HZ, NULL);
}
if (result == CY_RSLT_SUCCESS)
{
result = cyhal_clock_set_enabled(&clk_pwm, true, true);
}
if (CY_RSLT_SUCCESS != cyhal_pwm_init(&pwm_red, CYBSP_LED_RGB_RED, &clk_pwm))
{
printf("PWM Init failed for RBG Red LED!");
}
if (CY_RSLT_SUCCESS != cyhal_pwm_init(&pwm_green, CYBSP_LED_RGB_GREEN, &clk_pwm))
{
printf("PWM Init failed for RBG Green LED!");
}
if (CY_RSLT_SUCCESS != cyhal_pwm_init(&pwm_blue, CYBSP_LED_RGB_BLUE, &clk_pwm))
{
printf("PWM Init failed for RBG blue LED!");
}
if (CY_RSLT_SUCCESS != cyhal_pwm_set_duty_cycle(&pwm_red, GET_DUTY_CYCLE(LED_MAX_BRIGHTNESS), PWM_LED_FREQ_HZ))
{
printf("PWM failed to set dutycycle for RBG Red LED!");
}
if (CY_RSLT_SUCCESS != cyhal_pwm_set_duty_cycle(&pwm_green, GET_DUTY_CYCLE(LED_MAX_BRIGHTNESS), PWM_LED_FREQ_HZ))
{
printf("PWM failed to set dutycycle for RBG Green LED!");
}
if (CY_RSLT_SUCCESS != cyhal_pwm_set_duty_cycle(&pwm_blue, GET_DUTY_CYCLE(LED_MAX_BRIGHTNESS), PWM_LED_FREQ_HZ))
{
printf("PWM failed to set dutycycle for RBG Blue LED!");
}
mState = 0;
mbrightness = LED_MAX_BRIGHTNESS;
mHue = 0;
mSaturation = 0;
}
void LEDWidget::PWM_start()
{
if (!mState)
{
/* Start PWM to turn the LED on */
if (CY_RSLT_SUCCESS != cyhal_pwm_start(&pwm_led))
{
printf("PWM failed to start!");
}
mState = 1;
}
}
void LEDWidget::PWM_stop()
{
if (mState)
{
/* Stop PWM to turn the LED off */
if (CY_RSLT_SUCCESS != cyhal_pwm_stop(&pwm_led))
{
printf("PWM failed to stop!");
}
mState = 0;
}
}
void LEDWidget::RGB_set(bool state)
{
if (mState != state)
{
if (state)
{
if (CY_RSLT_SUCCESS != cyhal_pwm_start(&pwm_red))
{
printf("PWM failed to start!");
}
if (CY_RSLT_SUCCESS != cyhal_pwm_start(&pwm_green))
{
printf("PWM failed to start!");
}
if (CY_RSLT_SUCCESS != cyhal_pwm_start(&pwm_blue))
{
printf("PWM failed to start!");
}
mState = 1;
}
else
{
if (CY_RSLT_SUCCESS != cyhal_pwm_stop(&pwm_red))
{
printf("PWM failed to start!");
}
if (CY_RSLT_SUCCESS != cyhal_pwm_stop(&pwm_green))
{
printf("PWM failed to start!");
}
if (CY_RSLT_SUCCESS != cyhal_pwm_stop(&pwm_blue))
{
printf("PWM failed to start!");
}
mState = 0;
}
}
}
void LEDWidget::SetBrightness(uint32_t led_brightness)
{
mbrightness = (led_brightness < LED_MIN_BRIGHTNESS) ? LED_MIN_BRIGHTNESS
: static_cast<uint16_t>(led_brightness) * 100 / CY_RGB_LED_PWM_PERIOD_US;
/* Set Brightness for RGB LED */
if (pwm_red.pin)
{
HSB2rgb(mHue, mSaturation, mbrightness);
}
else
{
/* Drive the LED with brightness */
if (CY_RSLT_SUCCESS != cyhal_pwm_set_duty_cycle(&pwm_led, GET_DUTY_CYCLE(mbrightness), PWM_LED_FREQ_HZ))
{
printf("PWM failed to set dutycycle!");
}
}
}
void LEDWidget::SetColor(uint8_t Hue, uint8_t Saturation)
{
uint8_t brightness = (mState) ? mbrightness : 0;
mHue = static_cast<uint16_t>(Hue) * 360 / 254; // mHue [0, 360]
mSaturation = static_cast<uint16_t>(Saturation) * 100 / 254; // mSaturation [0 , 100]
HSB2rgb(mHue, mSaturation, brightness);
}
void LEDWidget::HSB2rgb(uint16_t Hue, uint8_t Saturation, uint8_t brightness)
{
uint8_t red, green, blue;
uint16_t i = Hue / 60;
brightness = static_cast<uint16_t>(brightness) * CY_RGB_LED_PWM_PERIOD_US / 100;
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;
}
/* LED is configured as ACTIVE LOW */
red = CY_RGB_LED_PWM_PERIOD_US - red;
green = CY_RGB_LED_PWM_PERIOD_US - green;
blue = CY_RGB_LED_PWM_PERIOD_US - blue;
/* Set Period to control color setting */
cyhal_pwm_set_period(&pwm_red, CY_RGB_LED_PWM_PERIOD_US, red);
cyhal_pwm_set_period(&pwm_green, CY_RGB_LED_PWM_PERIOD_US, green);
cyhal_pwm_set_period(&pwm_blue, CY_RGB_LED_PWM_PERIOD_US, blue);
}