Skip to content

Commit

Permalink
Pull request project-chip#22: 🐛 Lighting bugfix.
Browse files Browse the repository at this point in the history
Merge in WMN_TOOLS/matter from minor_bugfix_BT to silabs

Squashed commit of the following:

commit 5f721726e1b9d5be71b8330009dbdfb2dc5b6fc2
Author: Elfelsoufi-SiLabs <moaminee@silabs.com>
Date:   Fri Aug 5 16:55:35 2022 -0400

    🔨 If value is greater than max level, set to max level.

commit cb8a4a27a7a5573413cf1b0ffe71024b58bc6a60
Author: Elfelsoufi-SiLabs <moaminee@silabs.com>
Date:   Fri Aug 5 16:52:40 2022 -0400

    🐛 Return if wrong level value is received.

commit c639c6b6f205763c4b97e5abf557ac3c86295f6c
Author: Elfelsoufi-SiLabs <moaminee@silabs.com>
Date:   Thu Aug 4 19:40:13 2022 -0400

    🎨 Remove color enum. Use color struct.

commit 1bd420a2d8786a9386bd70be1d22ec5d1fb776b4
Author: Elfelsoufi-SiLabs <moaminee@silabs.com>
Date:   Thu Aug 4 14:37:38 2022 -0400

    ⛳ Remove all endpoints from the code.

commit f45cf02c47e4508802fe0dcb6e764debe8a9e404
Author: Elfelsoufi-SiLabs <moaminee@silabs.com>
Date:   Wed Aug 3 19:01:32 2022 -0400

    ✨ Remove useless callback.

commit da69394d72f7febe170278fb5bbba652f8d2655b
Author: Elfelsoufi-SiLabs <moaminee@silabs.com>
Date:   Wed Aug 3 18:48:15 2022 -0400

    📬 Post Light Control event using PostEvent. Remove LightControl Callback.

commit 5b58d6ba1ddd6ce318e89dbf89669bc3181bc942
Author: Elfelsoufi-SiLabs <moaminee@silabs.com>
Date:   Wed Aug 3 14:43:48 2022 -0400

    🎨 Use current level as the parameter value in the HSV to RGB conversion.

commit 11e02cdd7b1312f8737817974989502d08d53c4e
Author: Elfelsoufi-SiLabs <moaminee@silabs.com>
Date:   Tue Aug 2 19:49:27 2022 -0400

    ✨ Code improvements.

commit 40e9fa1c8d37a18dfd5218307582c0d215e01021
Author: Elfelsoufi-SiLabs <moaminee@silabs.com>
Date:   Mon Jul 25 12:22:31 2022 -0400

    🎬 Change currentLevel attribute to 254 in ZAP generated files for New-Light.

commit 94fe176c33826d3b4dc7aac1faf2db9ca32228df
Author: Elfelsoufi-SiLabs <moaminee@silabs.com>
Date:   Sun Jul 24 19:20:07 2022 -0400

    🎨 Scale color with current level.

commit 2c7958ec31fe61e4a15d83c94159b38ad599a0d9
Author: Elfelsoufi-SiLabs <moaminee@silabs.com>
Date:   Sun Jul 24 19:18:59 2022 -0400

    🐛 Fix Hardfault in LightingManager.cpp.

commit 057fd61fdb35b98bd23936cdff4d833c99d04d7d
Author: Elfelsoufi-SiLabs <moaminee@silabs.com>
Date:   Wed Jul 20 14:29:51 2022 -0400

    🐛 Bugfix for Light Level.
  • Loading branch information
Mohamed Amine Elfelsoufi authored and jmartinez-silabs committed Aug 22, 2023
1 parent f79bbd2 commit 8f8b999
Show file tree
Hide file tree
Showing 11 changed files with 725 additions and 412 deletions.
6 changes: 6 additions & 0 deletions silabs_examples/sl-newLight/efr32/include/AppEvent.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ struct AppEvent
uint8_t Action;
int32_t Actor;
} LightEvent;
struct
{
uint8_t Action;
int32_t Actor;
uint8_t Value;
} LightControlEvent;
};

EventHandler Handler;
Expand Down
3 changes: 2 additions & 1 deletion silabs_examples/sl-newLight/efr32/include/AppTask.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class AppTask
static void AppTaskMain(void * pvParameter);

void PostLightActionRequest(int32_t aActor, LightingManager::Action_t aAction);
void PostLightControlActionRequest(int32_t aActor, LightingManager::Action_t aAction, uint8_t value);
void PostEvent(const AppEvent * event);

void ButtonEventHandler(const sl_button_t * buttonHandle, uint8_t btnAction);
Expand All @@ -58,7 +59,6 @@ class AppTask

static void ActionInitiated(LightingManager::Action_t aAction, int32_t aActor);
static void ActionCompleted(LightingManager::Action_t aAction);
static void ActionChangeLight(LightingManager::Action_t aAction, uint16_t endpoint, uint8_t value);

void CancelTimer(void);

Expand All @@ -67,6 +67,7 @@ class AppTask
static void FunctionTimerEventHandler(AppEvent * aEvent);
static void FunctionHandler(AppEvent * aEvent);
static void LightActionEventHandler(AppEvent * aEvent);
static void LightControlEventHandler(AppEvent * aEvent);
static void TimerEventHandler(TimerHandle_t xTimer);

static void UpdateClusterState(intptr_t context);
Expand Down
21 changes: 10 additions & 11 deletions silabs_examples/sl-newLight/efr32/light_modules/LightingManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,6 @@ void LightingManager::SetCallbacks(Callback_fn_initiated aActionInitiated_CB, Ca
mActionCompleted_CB = aActionCompleted_CB;
}

void LightingManager::SetLightCallbacks(Callback_fn_set_light aChangeLight_CB)
{
mChangeLight_CB = aChangeLight_CB;
}

bool LightingManager::IsActionInProgress()
{
return (mState == kState_OffInitiated || mState == kState_OnInitiated);
Expand Down Expand Up @@ -140,15 +135,19 @@ bool LightingManager::InitiateAction(int32_t aActor, Action_t aAction)
bool LightingManager::InitiateActionLight(int32_t aActor, Action_t aAction, uint16_t endpoint, uint8_t value)
{
bool action_initiated = false;
bool onoff_complete = (mState == kState_OnCompleted || mState == kState_OffCompleted);
bool led_action = ((aAction == MOVE_TO_LEVEL) || (aAction == MOVE_TO_HUE) || (aAction == MOVE_TO_SAT));

if (onoff_complete && led_action)
switch(aAction)
{
action_initiated = true;
mChangeLight_CB(aAction, endpoint, value);
case MOVE_TO_LEVEL:
case MOVE_TO_HUE:
case MOVE_TO_SAT:
action_initiated = true;
GetAppTask().PostLightControlActionRequest(aActor, aAction, value);
break;
default:
break;
}

return action_initiated;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,17 +61,14 @@ class LightingManager

typedef void (*Callback_fn_initiated)(Action_t, int32_t aActor);
typedef void (*Callback_fn_completed)(Action_t);
typedef void (*Callback_fn_set_light)(Action_t, uint16_t endpoint, uint8_t value);
void SetCallbacks(Callback_fn_initiated aActionInitiated_CB, Callback_fn_completed aActionCompleted_CB);
void SetLightCallbacks(Callback_fn_set_light aChangeLight_CB);

private:
friend LightingManager & LightMgr(void);
State_t mState;

Callback_fn_initiated mActionInitiated_CB;
Callback_fn_completed mActionCompleted_CB;
Callback_fn_set_light mChangeLight_CB;

bool mAutoTurnOff;
uint32_t mAutoTurnOffDuration;
Expand Down
224 changes: 101 additions & 123 deletions silabs_examples/sl-newLight/efr32/light_modules/led_widget_rgb.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,21 +145,17 @@ void LEDWidgetRGB::Init(const sl_led_rgb_pwm_t* led)
/* 1. Initialize the value of class variables. */
sl_simple_rgb_pwm_led_context_t* led_context;
led_context = reinterpret_cast<sl_simple_rgb_pwm_led_context_t*>(led->led_common.context);
this->level_resolution_ = led_context->resolution;
this->current_hue_ = INITIAL_HUE;
this->current_saturation_ = INITIAL_SATURATION;
this->led_rgb_ = led;

/* 2. Set the RGB values to INITIAL_RGB. This does not affect the driver. */
for (uint8_t i = 0; i < 3; i++)
{
this->current_rgb_[i] = INITIAL_RGB;
}
this->level_resolution_ = led_context->resolution;
this->current_hue_ = INITIAL_HUE;
this->current_level_ = INITIAL_RGB;
this->current_saturation_ = INITIAL_SATURATION;
this->led_rgb_ = led;

/* 3. Initialize the value of the base class member variables. */
/* 2. Initialize the value of the base class member variables. */
LEDWidget::Init(&(led->led_common));

/* 4. Turn on the RGB LED pins. */
/* 3. Turn on the RGB LED pins. */
GPIO_PinOutSet(gpioPortJ, 14);
GPIO_PinOutSet(gpioPortI, 0);
GPIO_PinOutSet(gpioPortI, 1);
Expand All @@ -168,167 +164,149 @@ void LEDWidgetRGB::Init(const sl_led_rgb_pwm_t* led)
}


void LEDWidgetRGB::Set(bool state)
{
this->Set(state, LED_ENDPOINT_DEFAULT);
}


void LEDWidgetRGB::Set(bool state, uint16_t led_endpoint)
void LEDWidgetRGB::SetLevel(uint8_t level)
{
uint8_t rgb[3] = {0, 0, 0};
bool save_values = false;

if (state == true)
/* 1. Check if the input value is correct. */
if (level > ATTRIBUTE_LEVEL_MAX)
{
EFR32_LOG(" Error in led_widget_rgb.cpp. The level received is too great.");
this->current_level_ = PWM_MAX_VALUE;
}
else
{
save_values = true;
bool turned_on = false;

for (int i = 0; i < 3; i++)
{
if (this->current_rgb_[i] > 1)
{
turned_on = true;
}
}

if (turned_on == true)
{
for (int i = 0; i < 3; i++)
{
rgb[i] = current_rgb_[i];
}
}
else
{
for (int i = 0; i < 3; i++)
{
rgb[i] = PWM_MAX_VALUE;
}
}
// The Levelcontrol cluster takes values from 0 to 254.
// However, the PWM driver is sensitive to values from 0 to 100.
// For more information, see "appclusters.pdf", section 1.6.6.1.
this->current_level_ = (level * PWM_MAX_VALUE) / ATTRIBUTE_LEVEL_MAX;
}

this->SetRGB(rgb, led_endpoint, save_values);
/* 2. Update the color. */
this->SetColor(this->current_hue_, this->current_saturation_, this->current_level_);
}


void LEDWidgetRGB::SetLevel(uint8_t level, uint16_t led_endpoint)
void LEDWidgetRGB::GetLevel(ColorElements* rgb)
{
if(led_endpoint == 1)
/* 1. Check if the argument struct is not null. */
if (rgb == nullptr)
{
/* 1. Adjust the color level. */
// The Levelcontrol cluster takes values from 0 to 254.
// However, the PWM driver accepts values from 0 to 100.
// See appclusters, section 1.6.6.1.
uint8_t adjusted_level = (level * PWM_MAX_VALUE) / ATTRIBUTE_LEVEL_MAX;

/* 2. Set the colors. */
uint8_t rgb[3] = {adjusted_level, adjusted_level, adjusted_level};
this->SetRGB(rgb, led_endpoint, true);
EFR32_LOG(" Error in led_widget_rgb.cpp. Argument struct is null.");
return;
}
}

/* 2. Get the current RGB value from the driver. */
uint16_t red = 0;
uint16_t green = 0;
uint16_t blue = 0;
this->led_rgb_->get_rgb_color(this->led_rgb_->led_common.context, &red, &green, &blue);

void LEDWidgetRGB::GetLevel(uint8_t* rgb, uint32_t size)
{
/* 1. Create a buffer and assign it to the pointer. */
if (rgb == nullptr || rgb == NULL || size < 3)
/* 3. Verify that the colors are in-bound. */
if (red > PWM_MAX_VALUE)
{
EFR32_LOG(" In led_widget_rgb.cpp. get_rgb_color() returned red value of %d.", red);
red = PWM_MAX_VALUE;
}
if(green > PWM_MAX_VALUE)
{
EFR32_LOG(" In led_widget_rgb.cpp. get_rgb_color() returned green value of %d.", green);
green = PWM_MAX_VALUE;
}
if(blue > PWM_MAX_VALUE)
{
EFR32_LOG(" Error in led_widget_rgb.cpp. Array refused.");
return;
}
EFR32_LOG(" In led_widget_rgb.cpp. get_rgb_color() returned blue value of %d.", blue);
blue = PWM_MAX_VALUE;
}

/* 2. Get the current RGB value from the driver. */
uint16_t red = 0;
uint16_t green = 0;
uint16_t blue = 0;
void* led_rgb_context = this->led_rgb_->led_common.context;
this->led_rgb_->get_rgb_color(led_rgb_context, &red, &green, &blue);

/* 3. Assign the colors in the array. */
rgb[0] = static_cast<uint8_t>(red);
rgb[1] = static_cast<uint8_t>(green);
rgb[2] = static_cast<uint8_t>(blue);
/* 4. Assign the colors to the argument struct. */
rgb->red_value = static_cast<uint8_t>(red);
rgb->green_value = static_cast<uint8_t>(green);
rgb->blue_value = static_cast<uint8_t>(blue);
}


void LEDWidgetRGB::SetHue(uint8_t hue, uint16_t led_endpoint)
void LEDWidgetRGB::SetHue(uint8_t hue)
{
// Hue takes a value [0, 360] and is expressed in degrees.
// See appclusters, section 3.2.7.1.
this->current_hue_ = static_cast<uint16_t>((hue * 360) / ATTRIBUTE_LEVEL_MAX);
this->SetColor(this->current_hue_, this->current_saturation_, led_endpoint);
this->SetColor(this->current_hue_, this->current_saturation_, this->current_level_);
}


void LEDWidgetRGB::SetSaturation(uint8_t sat, uint16_t led_endpoint)
void LEDWidgetRGB::SetSaturation(uint8_t sat)
{
// Saturation takes a value [0, 1] representing a percentage.
// The Color Control cluster accepts saturation values 0 to 254.
// See appclusters, section 3.2.7.2.
this->current_saturation_ = sat/254.0;
this->SetColor(this->current_hue_, this->current_saturation_, led_endpoint);
this->SetColor(this->current_hue_, this->current_saturation_, this->current_level_);
}


void LEDWidgetRGB::SetColor(uint8_t* rgb, uint16_t led_endpoint)
{
/* 1. Set the color values. */
this->SetRGB(rgb, led_endpoint, true);
}


void LEDWidgetRGB::SetColor(uint8_t hue, uint8_t saturation, uint16_t led_endpoint)
void LEDWidgetRGB::SetColor(uint8_t hue, float saturation, uint8_t level)
{
/* 1. Convert the hue and saturation input to RGB values. (HSV to RGB conversion) */
uint8_t rgb[3] = {0, 0, 0};
HueToRGB(this->current_hue_, this->current_saturation_, rgb, PWM_MAX_VALUE);
ColorElements rgb =
{
.red_value = 0,
.green_value = 0,
.blue_value = 0
};

/* 2. Update the LEDs RGB values. */
this->SetRGB(rgb, led_endpoint, true);
HueToRGB(hue, saturation, level, &rgb, PWM_MAX_VALUE);

/* 2. Set the color values. */
this->SetColorRGB(&rgb);
}


void LEDWidgetRGB::SetRGB(uint8_t* rgb, uint16_t led_endpoint, bool memorize)
void LEDWidgetRGB::SetColorRGB(ColorElements* rgb)
{
/* 1. Call the PWM driver to set the new values. */
void* led_rgb_context = this->led_rgb_->led_common.context;
this->led_rgb_->set_rgb_color(led_rgb_context, rgb[0], rgb[1], rgb[2]);

/* 2. Save the current RGB values. */
if (memorize == true)
/* 1. Verify that the struct argument is not null. */
if (rgb == nullptr)
{
memcpy(this->current_rgb_, rgb, sizeof(this->current_rgb_));
EFR32_LOG(" Error in led_widget_rgb.cpp. Argument struct is null.");
return;
}

/* 2. Call the PWM driver to set the new values. */
this->led_rgb_->set_rgb_color(this->led_rgb_->led_common.context, rgb->red_value, rgb->green_value, rgb->blue_value);
}


/**
* @note This code is based on the HSV to RGB mathematical formula
* which was retrieved from: https://en.wikipedia.org/wiki/HSL_and_HSV
* which was retrieved from: https://en.wikipedia.org/wiki/HSL_and_HSV
*/
void LEDWidgetRGB::HueToRGB(uint16_t hue, float saturation, uint8_t* rgb, uint8_t max_value)
void LEDWidgetRGB::HueToRGB(uint16_t hue, float saturation, uint8_t value, ColorElements* rgb, uint8_t max_value)
{
/* 1. Normalize the values. */
/* 1. Verify that the struct argument is not null. */
if (rgb == nullptr)
{
EFR32_LOG(" Error in led_widget_rgb.cpp. Struct argument is null.");
return;
}

/* 2. Normalize the values. */
uint16_t hue_degrees = hue;
float saturation_decimal = saturation;
float hsv_value = 1.0;
float hsv_value = static_cast<float>(value) / 100.0;

if (hue_degrees == 360)
{
hue_degrees = 0;
}

/* 2. Calculate the formula parameters. */
float chroma = hsv_value * saturation_decimal;
float hue_prime = hue_degrees / 60.0;
float hue_modulo = fmod(hue_prime, 2.0);
float hue_diff = hue_modulo - 1.0;
float hue_abs = fabs(hue_diff);
float median_value = chroma * (1.0 - hue_abs);
float m = hsv_value - chroma;

/* 3. Determine the points R', G' and B'. */
}

/* 3. Calculate the formula parameters. */
float chroma = hsv_value * saturation_decimal;
float hue_prime = hue_degrees / 60.0;
float hue_modulo = fmod(hue_prime, 2.0);
float hue_diff = hue_modulo - 1.0;
float hue_abs = fabs(hue_diff);
float median_value = chroma * (1.0 - hue_abs);
float m = hsv_value - chroma;

/* 4. Determine the points R', G' and B'. */
float r_prime, g_prime, b_prime = 0;

if ( hue_degrees < 60 )
Expand Down Expand Up @@ -368,8 +346,8 @@ void LEDWidgetRGB::HueToRGB(uint16_t hue, float saturation, uint8_t* rgb, uint8_
b_prime = median_value;
}

/* 4. Calculate the final values of RGB. */
rgb[0] = (uint8_t) ( (r_prime + m) * max_value );
rgb[1] = (uint8_t) ( (g_prime + m) * max_value );
rgb[2] = (uint8_t) ( (b_prime + m) * max_value );
}
/* 5. Calculate the final values of RGB. */
rgb->red_value = static_cast<uint8_t>( (r_prime + m) * max_value );
rgb->green_value = static_cast<uint8_t>( (g_prime + m) * max_value );
rgb->blue_value = static_cast<uint8_t>( (b_prime + m) * max_value );
}
Loading

0 comments on commit 8f8b999

Please sign in to comment.