diff --git a/CHANGELOG.md b/CHANGELOG.md index 05ab59e..201c03d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # JLed changelog +## [tbd] 4.6.0 + +* new: JLedSequence can be configured to play the sequence multiple times + using the `Repeat()` and `Forever()` methods + ## [tbd] 4.5.3 * drop travis-ci, use github actions diff --git a/README.md b/README.md index e1a8a89..ad37f2f 100644 --- a/README.md +++ b/README.md @@ -324,7 +324,7 @@ an effect. The default value is 0 ms. ##### Repetitions -Use the `Repeat()` method to specify the number of repetition. The default +Use the `Repeat()` method to specify the number of repetitions. The default value is 1 repetition. The `Forever()` methods sets to repeat the effect forever. Each repetition includes a full period of the effect and the time specified by `DelayAfter()` method. @@ -382,11 +382,11 @@ effect when the previous finished. The constructor takes the mode (`PARALLEL`, ```c++ JLed leds[] = { - JLed(4).Blink(750, 250).Forever(), - JLed(3).Breathe(2000).Forever() + JLed(4).Blink(750, 250).Repeat(10), + JLed(3).Breathe(2000).Repeat(5); }; -JLedSequence sequence(JLedSequence::eMode::PARALLEL, leds); +auto sequence = JLedSequence(JLedSequence::eMode::PARALLEL, leds).Repeat(2); void setup() { } @@ -405,6 +405,9 @@ The `JLedSequence` provides the following methods: * `Update()` - updates the active `JLed` objects controlled by the sequence. Like the `JLed::Update()` method, it returns `true` if an effect is running, else `false`. +* Use the `Repeat(n)` method to specify the number of repetitions. The default + value is 1 repetition. The `Forever()` methods sets to repeat the sequence + forever. * `Stop()` - turns off all `JLed` objects controlled by the sequence and stops the sequence. Further calls to `Update()` will have no effect. * `Reset()` - Resets all `JLed` objects controlled by the sequence and diff --git a/library.properties b/library.properties index 5928117..30dfe62 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=JLed -version=4.5.2 +version=4.6.0 author=Jan Delgado maintainer=Jan Delgado sentence=An Arduino library to control LEDs diff --git a/src/jled_base.h b/src/jled_base.h index 8fb9c24..6332aee 100644 --- a/src/jled_base.h +++ b/src/jled_base.h @@ -486,8 +486,23 @@ class TJLedSequence { : mode_{mode}, leds_{leds}, cur_{0}, n_{n} {} bool Update() { - return mode_ == eMode::PARALLEL ? UpdateParallel() - : UpdateSequentially(); + if (!is_running_) { + return false; + } + + auto led_running = (mode_ == eMode::PARALLEL) ? UpdateParallel() + : UpdateSequentially(); + if (led_running) { + return true; + } + + for (auto i = 0u; i < n_; i++) { + leds_[i].Reset(); + } + + is_running_ = ++iteration_ < num_repetitions_ && + num_repetitions_ != kRepeatForever; + return is_running_; } void Reset() { @@ -495,6 +510,8 @@ class TJLedSequence { leds_[i].Reset(); } cur_ = 0; + iteration_ = 0; + is_running_ = true; } void Stop() { @@ -503,11 +520,25 @@ class TJLedSequence { } } + // set number of repetitions for the sequence + TJLedSequence Repeat(uint16_t num_repetitions) { + num_repetitions_ = num_repetitions; + return *this; + } + + // repeat Forever + TJLedSequence Forever() { return Repeat(kRepeatForever); } + bool IsForever() const { return num_repetitions_ == kRepeatForever; } + private: const eMode mode_; T* leds_; size_t cur_; const size_t n_; + static constexpr uint16_t kRepeatForever = 65535; + uint16_t num_repetitions_ = 1; + uint16_t iteration_ = 0; + bool is_running_ = true; }; }; // namespace jled diff --git a/test/test_jled_sequence.cpp b/test/test_jled_sequence.cpp index 47d937d..f920348 100644 --- a/test/test_jled_sequence.cpp +++ b/test/test_jled_sequence.cpp @@ -88,6 +88,36 @@ TEST_CASE("stop on sequence stops alle JLeds and turns them off", REQUIRE(!leds[1].IsRunning()); } +TEST_CASE("reapeat plays the sequence N times", "[jled_sequence]") { + // 1 ms on, 1 ms off = 2ms off in total per iteration + TestJLed leds[] = {TestJLed(HalMock(1)).Blink(1, 1)}; + auto seq = TestJLedSequence(TestJLedSequence::eMode::PARALLEL, leds) + .Repeat(2); + + constexpr uint8_t expected[]{255, 0, 255, 0, 0}; + uint32_t time = 0; + + for (const auto val : expected) { + seq.Update(); + REQUIRE(val == leds[0].Hal().Value()); + leds[0].Hal().SetMillis(++time); + } + REQUIRE(!seq.Update()); +} + +TEST_CASE("Forever flag is initially set to false", "[jled_sequence]") { + TestJLed leds[] = {TestJLed(HalMock(1)).Blink(1, 1)}; + auto seq = TestJLedSequence(TestJLedSequence::eMode::PARALLEL, leds); + REQUIRE_FALSE(seq.IsForever()); +} + +TEST_CASE("Forever flag is set by call to Forever()", "[jled_sequence]") { + TestJLed leds[] = {TestJLed(HalMock(1)).Blink(1, 1)}; + auto seq = TestJLedSequence(TestJLedSequence::eMode::PARALLEL, leds) + .Forever(); + REQUIRE(seq.IsForever()); +} + TEST_CASE("reset on sequence resets all JLeds", "[jled_sequence]") { // 1 ms on, 2 ms off + 2 ms delay = 3ms off in total per iteration TestJLed leds[] = {TestJLed(HalMock(1)).Blink(1, 1),