blob: 8cd7e82294a57a693689d4a25a95fb70e950171c [file] [log] [blame]
/*
* Copyright 2018 - 2019 NXP
* All rights reserved.
*
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "fsl_common.h"
#include "gpio.h"
#include "timer_manager.h"
#include "led.h"
#if (defined(LED_DIMMING_ENABLEMENT) && (LED_DIMMING_ENABLEMENT > 0U))
#include "pwm.h"
#endif
/*******************************************************************************
* Definitions
******************************************************************************/
#define LED_ENTER_CRITICAL() uint32_t regPrimask = DisableGlobalIRQ();
#define LED_EXIT_CRITICAL() EnableGlobalIRQ(regPrimask);
/* LED control type enumeration */
typedef enum _led_control_type
{
kLED_TurnOffOn = 0x01U, /*!< Turn Off or on*/
kLED_Flash, /*!< Flash */
#if (defined(LED_COLOR_WHEEL_ENABLEMENT) && (LED_COLOR_WHEEL_ENABLEMENT > 0U))
kLED_TricolorCycleFlash, /*!< Tricolor Cycle Flash */
kLED_CycleFlash, /*!< Cycle Flash */
#endif /* (defined(LED_COLOR_WHEEL_ENABLEMENT) && (LED_COLOR_WHEEL_ENABLEMENT > 0U)) */
kLED_Dimming, /*!< Dimming */
} led_control_type_t;
/* LED Dimming state structure when dimming is enabled */
typedef struct _led_dimming
{
uint8_t increasement;
uint8_t powerDelta[sizeof(led_config_t) / sizeof(led_pin_config_t)];
} led_dimming_t;
/*! @brief The pin config struct of LED */
typedef struct _led_pin
{
union
{
struct
{
uint16_t type : 2U; /*!< LED type, 1 - RGB, 2 - Monochrome */
uint16_t dimmingEnable : 1U; /*!< dimming enable, 0 - disable, 1 - enable */
uint16_t : 13U;
} config;
struct
{
uint16_t : 3U;
uint16_t port : 3U; /*!< GPIO Port */
uint16_t : 1U;
uint16_t pin : 5U; /*!< GPIO Pin */
uint16_t pinStateDefault : 1U; /*!< GPIO Pin voltage when LED is off (0 - low level, 1 - high level)*/
uint16_t : 3U;
} gpio;
struct
{
uint16_t : 3U;
uint16_t instance : 3U; /*!< PWM instance of the pin */
uint16_t : 1U;
uint16_t channel : 5U; /*!< PWM channel of the pin */
uint16_t pinStateDefault : 1U; /*!< The Pin voltage when LED is off (0 - low level, 1 - high level)*/
uint16_t : 3U;
} dimming;
};
} led_pin_t;
/* LED state structure */
typedef struct _led_state
{
struct _led_state *next;
uint32_t gpioHandle[sizeof(led_config_t) / sizeof(led_pin_config_t)]
[((HAL_GPIO_HANDLE_SIZE + sizeof(uint32_t) - 1U) / sizeof(uint32_t))];
volatile uint32_t expiryPeriodCount;
#if (defined(LED_DIMMING_ENABLEMENT) && (LED_DIMMING_ENABLEMENT > 0U))
uint32_t pwmHandle[sizeof(led_config_t) / sizeof(led_pin_config_t)]
[((HAL_PWM_HANDLE_SIZE + sizeof(uint32_t) - 1U) / sizeof(uint32_t))];
#endif
uint32_t flashCycle;
led_color_t settingColor;
led_color_t currentColor;
led_color_t nextColor;
led_pin_t pins[sizeof(led_config_t) / sizeof(led_pin_config_t)];
uint16_t flashPeriod;
#if (defined(LED_DIMMING_ENABLEMENT) && (LED_DIMMING_ENABLEMENT > 0U))
led_dimming_t dimming;
#endif
struct
{
uint16_t controlType : 4U;
#if (defined(LED_COLOR_WHEEL_ENABLEMENT) && (LED_COLOR_WHEEL_ENABLEMENT > 0U))
uint16_t flashCount : 3U;
#endif
uint16_t : 1U;
uint16_t flashDuty : 7U;
uint16_t : 1U;
};
} led_state_t;
typedef struct _led_list
{
led_state_t *ledState;
volatile uint32_t periodCount;
TIMER_MANAGER_HANDLE_DEFINE(timerHandle);
} led_list_t;
/*******************************************************************************
* Prototypes
******************************************************************************/
/*******************************************************************************
* Variables
******************************************************************************/
static led_list_t s_ledList;
/*******************************************************************************
* Code
******************************************************************************/
static led_status_t LED_SetStatus(led_state_t *ledState, led_color_t color, uint32_t threshold)
{
led_pin_t *ledRgbPin;
led_status_t status = kStatus_LED_Success;
led_color_t colorSet;
uint8_t count;
ledState->expiryPeriodCount = s_ledList.periodCount + threshold;
ledRgbPin = (led_pin_t *)ledState->pins;
if ((uint16_t)kLED_TypeRgb == ledRgbPin->config.type)
{
count = sizeof(led_config_t) / sizeof(led_pin_config_t);
}
else
{
count = 1;
}
for (uint8_t i = 0; i < count; i++)
{
colorSet = ((color >> (i * 8U)) & (0xFFU));
#if (defined(LED_DIMMING_ENABLEMENT) && (LED_DIMMING_ENABLEMENT > 0U))
if (ledRgbPin[i].config.dimmingEnable)
{
HAL_PwmUpdateDutycycle(ledState->pwmHandle[i], ledRgbPin[i].dimming.channel, kHAL_EdgeAlignedPwm,
colorSet * 100 / 255);
}
else
#endif
{
if (kStatus_HAL_GpioSuccess !=
HAL_GpioSetOutput(ledState->gpioHandle[i], (colorSet != 0U) ?
(1U - (uint8_t)ledRgbPin[i].gpio.pinStateDefault) :
(uint8_t)ledRgbPin[i].gpio.pinStateDefault))
{
status = kStatus_LED_Error;
}
}
}
return status;
}
static void LED_TimerEvent(void *param)
{
led_state_t *ledState = (led_state_t *)s_ledList.ledState;
uint32_t threshold = 0;
led_color_t color;
#if (defined(LED_DIMMING_ENABLEMENT) && (LED_DIMMING_ENABLEMENT > 0U))
uint16_t power[sizeof(led_config_t) / sizeof(led_pin_config_t)];
uint8_t count = sizeof(led_config_t) / sizeof(led_pin_config_t);
#endif
s_ledList.periodCount += LED_TIMER_INTERVAL;
while (NULL != ledState)
{
if (s_ledList.periodCount >= ledState->expiryPeriodCount)
{
switch (ledState->controlType)
{
case (uint16_t)kLED_Flash: /*!< Flash */
#if (defined(LED_COLOR_WHEEL_ENABLEMENT) && (LED_COLOR_WHEEL_ENABLEMENT > 0U))
case (uint16_t)kLED_TricolorCycleFlash: /*!< Tricolor Cycle Flash */
case (uint16_t)kLED_CycleFlash: /*!< Cycle Flash */
#endif /* (defined(LED_COLOR_WHEEL_ENABLEMENT) && (LED_COLOR_WHEEL_ENABLEMENT > 0U)) */
if (LED_FLASH_CYCLE_FOREVER != ledState->flashCycle)
{
if ((0U != ledState->flashCycle))
{
if (((led_color_t)kLED_Black == ledState->currentColor) || (100U == ledState->flashDuty))
{
ledState->flashCycle--;
}
}
}
if (0U != ledState->flashCycle)
{
if ((100U > ledState->flashDuty))
{
color = ledState->nextColor;
ledState->nextColor = ledState->currentColor;
ledState->currentColor = color;
}
if (((led_color_t)kLED_Black == ledState->currentColor))
{
threshold = (uint32_t)ledState->flashPeriod * (100U - (uint32_t)ledState->flashDuty) / 100U;
}
else
{
#if (defined(LED_COLOR_WHEEL_ENABLEMENT) && (LED_COLOR_WHEEL_ENABLEMENT > 0U))
ledState->flashCount++;
if ((uint16_t)kLED_TricolorCycleFlash == ledState->controlType)
{
ledState->currentColor = (led_color_t)(0xFFUL << ((ledState->flashCount % 3U) * 8U));
}
else if ((uint16_t)kLED_CycleFlash == ledState->controlType)
{
color = 0;
if (0U == ((ledState->flashCount) & 0x07U))
{
(ledState->flashCount)++;
}
if (0U != ((ledState->flashCount) & 0x04U))
{
color = (led_color_t)0xFF0000;
}
if (0U != ((ledState->flashCount) & 0x02U))
{
color |= (led_color_t)0xFF00;
}
if (0U != ((ledState->flashCount) & 0x01U))
{
color |= (led_color_t)0xFF;
}
ledState->currentColor = color;
}
else
{
/*Misra Rule 15.7*/
}
#endif /* (defined(LED_COLOR_WHEEL_ENABLEMENT) && (LED_COLOR_WHEEL_ENABLEMENT > 0U)) */
threshold = (uint32_t)ledState->flashPeriod * (uint32_t)(ledState->flashDuty) / 100U;
}
(void)LED_SetStatus(ledState, ledState->currentColor, threshold);
}
break;
#if (defined(LED_DIMMING_ENABLEMENT) && (LED_DIMMING_ENABLEMENT > 0U))
case kLED_Dimming: /*!< Dimming */
for (int i = 0; i < count; i++)
{
int value = (ledState->currentColor >> (8 * i)) & 0xFF;
if ((ledState->dimming.increasement))
{
if ((value + ledState->dimming.powerDelta[i]) < 0xFF)
{
power[i] = value + ledState->dimming.powerDelta[i];
}
else
{
power[i] = 0xFF;
}
}
else
{
if (value > ledState->dimming.powerDelta[i])
{
power[i] = value - ledState->dimming.powerDelta[i];
}
else
{
power[i] = 0;
}
}
if (kLED_TypeMonochrome == ledState->pins[0].config.type)
{
break;
}
}
ledState->currentColor = LED_MAKE_COLOR(power[0], power[1], power[2]);
LED_SetStatus(ledState, ledState->currentColor, ledState->flashPeriod);
break;
#endif
default:
/* MISRA Rule 16.4*/
break;
}
}
ledState = ledState->next;
}
}
led_status_t LED_Init(led_handle_t ledHandle, led_config_t *ledConfig)
{
led_state_t *ledState;
led_pin_config_t *ledRgbConfigPin;
hal_gpio_pin_config_t controlPin;
uint32_t count;
uint32_t regPrimask;
int i;
#if (defined(LED_DIMMING_ENABLEMENT) && (LED_DIMMING_ENABLEMENT > 0U))
uint8_t rgbFlag = 0;
uint8_t rgbDimmingFlag = 0;
#endif
assert((NULL != ledHandle) && (NULL != ledConfig));
assert(LED_HANDLE_SIZE >= sizeof(led_state_t));
if (kLED_TypeRgb == ledConfig->type)
{
count = sizeof(led_config_t) / sizeof(led_pin_config_t);
}
else
{
count = 1;
}
ledState = (led_state_t *)ledHandle;
(void)memset(ledHandle, 0, sizeof(led_state_t));
regPrimask = DisableGlobalIRQ();
if (NULL == s_ledList.ledState)
{
do
{
if (kStatus_TimerSuccess != TM_Open((timer_handle_t)s_ledList.timerHandle))
{
break;
}
if (kStatus_TimerSuccess != TM_InstallCallback(s_ledList.timerHandle, LED_TimerEvent, &s_ledList))
{
break;
}
if (kStatus_TimerSuccess != TM_Start(s_ledList.timerHandle, (uint8_t)kTimerModeIntervalTimer, LED_TIMER_INTERVAL))
{
break;
}
s_ledList.ledState = ledState;
} while (false);
}
else
{
ledState->next = s_ledList.ledState;
s_ledList.ledState = ledState;
}
EnableGlobalIRQ(regPrimask);
if (NULL == s_ledList.ledState)
{
return kStatus_LED_Error;
}
ledState->settingColor = (led_color_t)kLED_White;
ledRgbConfigPin = (led_pin_config_t *)(void *)(&ledConfig->ledRgb);
controlPin.direction = kHAL_GpioDirectionOut;
#if (defined(LED_DIMMING_ENABLEMENT) && (LED_DIMMING_ENABLEMENT > 0U))
for (i = 0; i < (int)count; i++)
{
if (ledRgbConfigPin[i].dimmingEnable)
{
rgbDimmingFlag = 1;
}
else
{
rgbFlag = 1;
}
}
if (rgbDimmingFlag && rgbFlag)
{
return kStatus_LED_Error;
}
#endif
for (i = 0; i < (int)count; i++)
{
ledState->pins[i].config.type = (uint16_t)ledConfig->type;
#if (defined(LED_DIMMING_ENABLEMENT) && (LED_DIMMING_ENABLEMENT > 0U))
if (ledRgbConfigPin[i].dimmingEnable)
{
hal_pwm_setup_config_t setupConfig;
ledState->pins[i].config.dimmingEnable = ledRgbConfigPin[i].dimmingEnable;
ledState->pins[i].dimming.instance = ledRgbConfigPin[i].dimming.instance;
ledState->pins[i].dimming.channel = ledRgbConfigPin[i].dimming.channel;
ledState->pins[i].dimming.pinStateDefault = ledRgbConfigPin[i].dimming.pinStateDefault;
HAL_PwmInit((hal_pwm_handle_t)ledState->pwmHandle[i], ledRgbConfigPin[i].dimming.instance,
ledRgbConfigPin[i].dimming.sourceClock);
setupConfig.dutyCyclePercent = 0;
setupConfig.level = ledRgbConfigPin[i].dimming.pinStateDefault ? kHAL_PwmLowTrue : kHAL_PwmHighTrue;
setupConfig.mode = kHAL_EdgeAlignedPwm;
setupConfig.pwmFreq_Hz = 1000;
HAL_PwmSetupPwm(ledState->pwmHandle[i], ledRgbConfigPin[i].dimming.channel, &setupConfig);
}
else
#endif
{
ledState->pins[i].gpio.port = ledRgbConfigPin[i].gpio.port;
ledState->pins[i].gpio.pin = ledRgbConfigPin[i].gpio.pin;
ledState->pins[i].gpio.pinStateDefault = ledRgbConfigPin[i].gpio.pinStateDefault;
controlPin.port = ledRgbConfigPin[i].gpio.port;
controlPin.pin = ledRgbConfigPin[i].gpio.pin;
controlPin.level = ledRgbConfigPin[i].gpio.pinStateDefault;
if (kStatus_HAL_GpioSuccess != HAL_GpioInit((hal_gpio_handle_t)ledState->gpioHandle[i], &controlPin))
{
return kStatus_LED_Error;
}
}
}
return LED_TurnOnOff(ledState, 0);
}
led_status_t LED_Deinit(led_handle_t ledHandle)
{
led_state_t *ledState;
led_state_t *ledStatePre;
uint32_t regPrimask;
#if (defined(LED_DIMMING_ENABLEMENT) && (LED_DIMMING_ENABLEMENT > 0U))
led_pin_t *ledRgbPin;
#endif
assert(ledHandle);
ledState = (led_state_t *)ledHandle;
regPrimask = DisableGlobalIRQ();
ledStatePre = s_ledList.ledState;
if (ledStatePre != ledState)
{
while ((NULL != ledStatePre) && (ledStatePre->next != ledState))
{
ledStatePre = ledStatePre->next;
}
if (NULL != ledStatePre)
{
ledStatePre->next = ledState->next;
}
}
else
{
s_ledList.ledState = ledState->next;
}
if (NULL == s_ledList.ledState)
{
(void)TM_Close(s_ledList.timerHandle);
}
EnableGlobalIRQ(regPrimask);
#if (defined(LED_DIMMING_ENABLEMENT) && (LED_DIMMING_ENABLEMENT > 0U))
ledRgbPin = (led_pin_t *)(ledState->pins);
#endif
for (uint32_t i = 0; i < (sizeof(led_config_t) / sizeof(led_pin_config_t)); i++)
{
#if (defined(LED_DIMMING_ENABLEMENT) && (LED_DIMMING_ENABLEMENT > 0U))
if (ledRgbPin[i].config.dimmingEnable)
{
HAL_PwmDeinit(ledState->pwmHandle[i]);
}
else
#endif
{
(void)HAL_GpioDeinit(ledState->gpioHandle[i]);
}
if (((uint16_t)kLED_TypeRgb != ledState->pins[i].config.type))
{
break;
}
}
return kStatus_LED_Success;
}
led_status_t LED_TurnOnOff(led_handle_t ledHandle, uint8_t turnOnOff)
{
led_state_t *ledState;
led_status_t status;
assert(ledHandle);
ledState = (led_state_t *)ledHandle;
ledState->controlType = (uint16_t)kLED_TurnOffOn;
ledState->currentColor = (1U == turnOnOff) ? ledState->settingColor : (led_color_t)kLED_Black;
status = LED_SetStatus(ledState, ledState->currentColor, 0);
return status;
}
led_status_t LED_SetColor(led_handle_t ledHandle, led_color_t ledRgbColor)
{
led_state_t *ledState;
assert(ledHandle);
ledState = (led_state_t *)ledHandle;
if (((uint16_t)kLED_TypeRgb != ledState->pins[0].config.type))
{
return kStatus_LED_Error;
}
ledState->settingColor = ledRgbColor;
return kStatus_LED_Success;
}
led_status_t LED_Flash(led_handle_t ledHandle, led_flash_config_t *ledFlash)
{
led_state_t *ledState;
led_status_t status;
assert(ledHandle);
assert(ledFlash);
assert(ledFlash->times);
assert(ledFlash->duty <= 100U);
ledState = (led_state_t *)ledHandle;
ledState->flashPeriod = ledFlash->period;
ledState->flashDuty = ledFlash->duty;
ledState->currentColor = ledState->settingColor;
ledState->flashCycle = ledFlash->times;
ledState->nextColor = (led_color_t)kLED_Black;
#if (defined(LED_COLOR_WHEEL_ENABLEMENT) && (LED_COLOR_WHEEL_ENABLEMENT > 0U))
if (kLED_FlashOneColor == ledFlash->flashType)
{
ledState->controlType = (uint16_t)kLED_Flash;
}
else
{
if (((uint16_t)kLED_TypeRgb != ledState->pins[0].config.type))
{
return kStatus_LED_Error;
}
ledState->controlType = (uint16_t)kLED_CycleFlash;
}
#else
ledState->controlType = (uint16_t)kLED_Flash;
#endif /* (defined(LED_COLOR_WHEEL_ENABLEMENT) && (LED_COLOR_WHEEL_ENABLEMENT > 0U)) */
status = LED_SetStatus(ledState, ledState->currentColor,
((uint32_t)ledState->flashPeriod * (uint32_t)ledState->flashDuty) / 100U);
return status;
}
led_status_t LED_Blip(led_handle_t ledHandle)
{
led_flash_config_t ledFlash;
ledFlash.duty = 50;
ledFlash.flashType = kLED_FlashOneColor;
ledFlash.period = LED_BLIP_INTERVAL;
ledFlash.times = 1;
return LED_Flash(ledHandle, &ledFlash);
}
led_status_t LED_Dimming(led_handle_t ledHandle, uint16_t dimmingPeriod, uint8_t increasement)
{
#if (defined(LED_DIMMING_ENABLEMENT) && (LED_DIMMING_ENABLEMENT > 0U))
led_state_t *ledState;
led_status_t status;
int i;
uint16_t power[sizeof(led_config_t) / sizeof(led_pin_config_t)];
uint8_t value;
uint8_t count = sizeof(led_config_t) / sizeof(led_pin_config_t);
assert(ledHandle);
assert(dimmingPeriod);
ledState = (led_state_t *)ledHandle;
if (!ledState->pins[0].config.dimmingEnable)
{
return kStatus_LED_Error;
}
LED_ENTER_CRITICAL();
ledState->controlType = kLED_Dimming;
ledState->flashPeriod = LED_DIMMING_UPDATE_INTERVAL;
ledState->flashDuty = 100;
ledState->dimming.increasement = increasement;
if ((kLED_TypeRgb == ledState->pins[0].config.type))
{
ledState->currentColor = ledState->settingColor;
}
for (i = 0; i < count; i++)
{
ledState->dimming.powerDelta[i] = 0;
}
for (i = 0; i < count; i++)
{
value = (ledState->currentColor >> (8 * (i))) & 0xFF;
if (ledState->dimming.increasement)
{
ledState->dimming.powerDelta[i] = (0xFF - value) * LED_DIMMING_UPDATE_INTERVAL / (dimmingPeriod);
if ((value + ledState->dimming.powerDelta[i]) < 0xFF)
{
power[i] = value + ledState->dimming.powerDelta[i];
}
else
{
power[i] = 0xFF;
}
}
else
{
ledState->dimming.powerDelta[i] = (value)*LED_DIMMING_UPDATE_INTERVAL / (dimmingPeriod);
if (value > ledState->dimming.powerDelta[i])
{
power[i] = value - ledState->dimming.powerDelta[i];
}
else
{
power[i] = 0;
}
}
if (kLED_TypeMonochrome == ledState->pins[0].config.type)
{
break;
}
}
ledState->currentColor = LED_MAKE_COLOR(power[0], power[1], power[2]);
ledState->flashCycle = LED_FLASH_CYCLE_FOREVER;
LED_EXIT_CRITICAL();
status = LED_SetStatus(ledState, ledState->currentColor, ledState->flashPeriod);
return status;
#else
return kStatus_LED_Error;
#endif
}
led_status_t LED_EnterLowpower(led_handle_t ledHandle)
{
#if 0
led_state_t* ledState;
led_pin_config_t* ledRgbPin;
led_status_t status;
int count;
assert(ledHandle);
ledState = (led_state_t*)ledHandle;
ledRgbPin = (led_pin_config_t*)&ledState->config.ledRgb;
if (kLED_TypeRgb == ledState->config.type)
{
count = sizeof(led_config_t) / sizeof(led_pin_config_t);
}
else
{
count = 1;
}
for (int i = 0;i < count; i++)
{
#if (defined(LED_DIMMING_ENABLEMENT) && (LED_DIMMING_ENABLEMENT > 0U))
if (ledRgbPin[i].dimmingEnable)
{
HAL_PwmEnterLowpower(ledRgbPin[i].dimming.instance, ledRgbPin[i].dimming.channel);
}
else
#endif
{
HAL_GpioEnterLowpower(ledState->gpioHandle[i]);
}
}
#endif
return kStatus_LED_Success;
}
led_status_t LED_ExitLowpower(led_handle_t ledHandle)
{
#if 0
led_state_t* ledState;
led_pin_config_t* ledRgbPin;
led_status_t status;
int count;
assert(ledHandle);
ledState = (led_state_t*)ledHandle;
ledRgbPin = (led_pin_config_t*)&ledState->config.ledRgb;
if (kLED_TypeRgb == ledState->config.type)
{
count = sizeof(led_config_t) / sizeof(led_pin_config_t);
}
else
{
count = 1;
}
for (int i = 0;i < count; i++)
{
#if (defined(LED_DIMMING_ENABLEMENT) && (LED_DIMMING_ENABLEMENT > 0U))
if (ledRgbPin[i].dimmingEnable)
{
HAL_PwmExitLowpower(ledRgbPin[i].dimming.instance, ledRgbPin[i].dimming.channel);
}
else
#endif
{
HAL_GpioExitLowpower(ledState->gpioHandle[i]);
}
}
#endif
return kStatus_LED_Success;
}