-
Notifications
You must be signed in to change notification settings - Fork 83
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #797 from SignalK/rgb_led
Rewrite LED blinking functionality
- Loading branch information
Showing
12 changed files
with
470 additions
and
316 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,154 +1,63 @@ | ||
|
||
#include "sensesp.h" | ||
|
||
#include "led_blinker.h" | ||
|
||
#include "sensesp_app.h" | ||
|
||
namespace sensesp { | ||
|
||
#define max(a, b) ((a) > (b) ? (a) : (b)) | ||
|
||
BaseBlinker::BaseBlinker(int pin) : pin_{pin} { | ||
pinMode(pin, OUTPUT); | ||
event_loop()->onDelay(1, [this]() { this->tick(); }); | ||
} | ||
LEDPatternFragment frag_solid_color(uint32_t duration_ms, const CRGB& color) { | ||
return LEDPatternFragment(duration_ms, | ||
[color](uint32_t, CRGB& crgb) { crgb = color; }); | ||
} | ||
|
||
LEDPatternFragment frag_linear_fade(uint32_t duration_ms, | ||
uint32_t fade_duration_ms, | ||
const CRGB& target_color) { | ||
LEDPatternFragment fragment(duration_ms, [target_color, fade_duration_ms]( | ||
uint32_t elapsed_ms, | ||
CRGB& crgb) { | ||
static CRGB from_color; | ||
static unsigned long last_elapsed_ms = 0; | ||
if (elapsed_ms < last_elapsed_ms) { | ||
from_color = crgb; | ||
} | ||
last_elapsed_ms = elapsed_ms; | ||
if (elapsed_ms >= fade_duration_ms) { | ||
crgb = target_color; | ||
return; | ||
} | ||
crgb = blend(from_color, target_color, elapsed_ms * 256 / fade_duration_ms); | ||
}); | ||
|
||
/** | ||
* Turn the LED on or off. | ||
*/ | ||
void BaseBlinker::set_state(bool state) { | ||
this->state_ = state; | ||
digitalWrite(pin_, state); | ||
update_counter_++; | ||
return fragment; | ||
} | ||
|
||
/** | ||
* Invert the current LED state. | ||
*/ | ||
void BaseBlinker::flip_state() { this->set_state(!this->state_); } | ||
|
||
/** | ||
* Flip the LED off and on for `duration` milliseconds. | ||
*/ | ||
void BaseBlinker::blip(int duration) { | ||
// indicator for a blip being in progress | ||
static bool blipping = false; | ||
|
||
// only allow one blip at a time | ||
if (blipping) { | ||
return; | ||
} | ||
blipping = true; | ||
|
||
bool const orig_state = this->state_; | ||
this->set_state(false); | ||
int const current_counter = this->update_counter_; | ||
event_loop()->onDelay( | ||
duration, [this, duration, orig_state, current_counter]() { | ||
// only update if no-one has touched the LED in the meanwhile | ||
if (this->update_counter_ == current_counter) { | ||
this->set_state(true); | ||
int const new_counter = this->update_counter_; | ||
event_loop()->onDelay( | ||
duration, [this, orig_state, new_counter]() { | ||
// again, only update if no-one has touched the LED | ||
if (this->update_counter_ == new_counter) { | ||
this->set_state(orig_state); | ||
} | ||
blipping = false; | ||
}); | ||
LEDPatternFragment frag_linear_invert(uint32_t duration_ms, bool reverse) { | ||
return LEDPatternFragment( | ||
duration_ms, [duration_ms, reverse](uint32_t elapsed_ms, CRGB& crgb) { | ||
// Blend the color from current color to inverted | ||
if (reverse) { | ||
crgb = blend(CRGB(255, 255, 255) - crgb, crgb, | ||
elapsed_ms * 256 / duration_ms); | ||
} else { | ||
blipping = false; | ||
crgb = blend(crgb, CRGB(255, 255, 255) - crgb, | ||
elapsed_ms * 256 / duration_ms); | ||
} | ||
}); | ||
} | ||
|
||
/** | ||
* Enable or disable the blinker. | ||
*/ | ||
void BaseBlinker::set_enabled(bool state) { | ||
bool const was_enabled = this->enabled_; | ||
this->enabled_ = state; | ||
if (this->enabled_) { | ||
this->tick(); | ||
} else { | ||
this->set_state(false); | ||
if (was_enabled) { | ||
event_->remove(event_loop()); | ||
LEDPatternFragment frag_blend(uint32_t duration_ms, const CRGB& target_color, | ||
bool reverse) { | ||
return LEDPatternFragment(duration_ms, [duration_ms, reverse, target_color]( | ||
uint32_t elapsed_ms, CRGB& crgb) { | ||
if (reverse) { | ||
crgb = blend(target_color, crgb, elapsed_ms * 255 / duration_ms); | ||
} else { | ||
crgb = blend(crgb, target_color, elapsed_ms * 255 / duration_ms); | ||
} | ||
} | ||
} | ||
|
||
PeriodicBlinker::PeriodicBlinker(int pin, unsigned int period) | ||
: BaseBlinker(pin), period_{period} {} | ||
|
||
EvenBlinker::EvenBlinker(int pin, unsigned int period) | ||
: PeriodicBlinker(pin, period) {} | ||
|
||
void EvenBlinker::tick() { | ||
if (!enabled_) { | ||
return; | ||
} | ||
this->flip_state(); | ||
event_ = event_loop()->onDelay( | ||
period_, [this]() { this->tick(); }); | ||
} | ||
|
||
RatioBlinker::RatioBlinker(int pin, unsigned int period, float ratio) | ||
: PeriodicBlinker(pin, period), ratio_{ratio} {} | ||
|
||
void RatioBlinker::tick() { | ||
if (!enabled_) { | ||
return; | ||
} | ||
this->flip_state(); | ||
int const on_duration = ratio_ * period_; | ||
int const off_duration = max(0, period_ - on_duration); | ||
unsigned int const ref_duration = | ||
state_ == false ? off_duration : on_duration; | ||
event_ = event_loop()->onDelay( | ||
ref_duration, [this]() { this->tick(); }); | ||
} | ||
|
||
PatternBlinker::PatternBlinker(int pin, int pattern[]) | ||
: BaseBlinker(pin), pattern_{pattern} {} | ||
|
||
/** | ||
* Set a new blink pattern. Patterns are arrays of ints, with | ||
* PATTERN_END as the last value. Each number in the pattern indicates | ||
* the length of that segment, in milliseconds. The first number indicates | ||
* an ON duration, the second an OFF duration, and so on. | ||
*/ | ||
void PatternBlinker::set_pattern(int pattern[]) { | ||
this->pattern_ = pattern; | ||
this->restart(); | ||
} | ||
|
||
void PatternBlinker::tick() { | ||
if (!enabled_) { | ||
return; | ||
} | ||
// When pattern[pattern_ptr] == PATTERN_END, that's the end of the pattern, | ||
// so start over at the beginning. | ||
if (pattern_[pattern_ptr_] == PATTERN_END) { | ||
pattern_ptr_ = 0; | ||
} | ||
// odd indices indicate times when LED should be OFF, even when ON | ||
bool const new_state = (pattern_ptr_ % 2) == 0; | ||
this->set_state(new_state); | ||
event_ = event_loop()->onDelay( | ||
pattern_[pattern_ptr_++], [this]() { this->tick(); }); | ||
}); | ||
} | ||
|
||
void PatternBlinker::restart() { | ||
state_ = false; | ||
pattern_ptr_ = 0; | ||
if (event_ != NULL) { | ||
event_->remove(event_loop()); | ||
event_ = NULL; | ||
this->tick(); | ||
} | ||
LEDPatternFragment frag_nop(uint32_t duration_ms) { | ||
// No operation | ||
return LEDPatternFragment(duration_ms, [](uint32_t, CRGB&) {}); | ||
} | ||
|
||
} // namespace sensesp |
Oops, something went wrong.