Skip to content

Commit

Permalink
Repeat() and Forever() for sequences
Browse files Browse the repository at this point in the history
Update multiled example to use Repeat on sequence
  • Loading branch information
jandelgado committed Jan 24, 2021
1 parent db5d48f commit 540d607
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 31 deletions.
6 changes: 4 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# JLed changelog
# JLed changelog (github.com/jandelgado/jled)

## [tbd] 4.5.3
## [2021-01-24] 4.6.0

* new: JLedSequence can be configured to play the sequence multiple times
using the `Repeat()` and `Forever()` methods
* drop travis-ci, use github actions

## [2020-10-24] 4.5.2
Expand Down
11 changes: 7 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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() {
}
Expand All @@ -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
Expand Down
14 changes: 7 additions & 7 deletions examples/multiled/multiled.ino
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
// JLed multi LED demo. control multiple LEDs in-sync.
// Copyright 2017 by Jan Delgado. All rights reserved.
// Copyright (c) 2017-2021 by Jan Delgado. All rights reserved.
// https://github.com/jandelgado/jled
#include <jled.h>

JLed leds[] = {
JLed(4).Blink(750, 250).Forever(),
JLed(3).Breathe(2000).Forever(),
JLed(5).FadeOff(1000).Forever(),
JLed(6).FadeOn(1000).Forever(),
JLed(LED_BUILTIN).Blink(500, 500).Forever()
JLed(4).Blink(750, 250).Repeat(2),
JLed(3).Breathe(2000),
JLed(5).FadeOff(1000).Repeat(2),
JLed(6).FadeOn(1000).Repeat(2),
JLed(LED_BUILTIN).Blink(500, 500).Repeat(2)
};

JLedSequence sequence(JLedSequence::eMode::PARALLEL, leds);
auto sequence = JLedSequence(JLedSequence::eMode::PARALLEL, leds).Repeat(5);

void setup() { }

Expand Down
2 changes: 1 addition & 1 deletion library.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name=JLed
version=4.5.2
version=4.6.0
author=Jan Delgado <jdelgado[at]gmx.net>
maintainer=Jan Delgado <jdelgado[at]gmx.net>
sentence=An Arduino library to control LEDs
Expand Down
49 changes: 43 additions & 6 deletions src/jled_base.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2017 Jan Delgado <jdelgado[at]gmx.net>
// Copyright (c) 2017-2021 Jan Delgado <jdelgado[at]gmx.net>
// https://github.com/jandelgado/jled
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
Expand Down Expand Up @@ -475,6 +475,13 @@ class TJLedSequence {
return true;
}

void ResetLeds() {
for (auto i = 0u; i < n_; i++) {
leds_[i].Reset();
}
}


public:
enum eMode { SEQUENCE, PARALLEL };
TJLedSequence() = delete;
Expand All @@ -486,15 +493,31 @@ class TJLedSequence {
: mode_{mode}, leds_{leds}, cur_{0}, n_{n} {}

bool Update() {
return mode_ == eMode::PARALLEL ? UpdateParallel()
: UpdateSequentially();
if (!is_running_) {
return false;
}

const auto led_running = (mode_ == eMode::PARALLEL) ? UpdateParallel()
: UpdateSequentially();
if (led_running) {
return true;
}

// start next iteration of sequence
cur_ = 0;
ResetLeds();

is_running_ = ++iteration_ < num_repetitions_ &&
num_repetitions_ != kRepeatForever;

return is_running_;
}

void Reset() {
for (auto i = 0u; i < n_; i++) {
leds_[i].Reset();
}
ResetLeds();
cur_ = 0;
iteration_ = 0;
is_running_ = true;
}

void Stop() {
Expand All @@ -503,11 +526,25 @@ class TJLedSequence {
}
}

// set number of repetitions for the sequence
TJLedSequence<T> Repeat(uint16_t num_repetitions) {
num_repetitions_ = num_repetitions;
return *this;
}

// repeat Forever
TJLedSequence<T> 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
Expand Down
57 changes: 46 additions & 11 deletions test/test_jled_sequence.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// JLed Unit tests (run on host).
// Copyright 2017 Jan Delgado jdelgado@gmx.net
// Copyright 2017-2021 Jan Delgado jdelgado@gmx.net
#include "catch.hpp"

#include <jled_base.h> // NOLINT
Expand Down Expand Up @@ -88,26 +88,61 @@ TEST_CASE("stop on sequence stops alle JLeds and turns them off",
REQUIRE(!leds[1].IsRunning());
}

TEST_CASE("repeat 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),
TestJLed(HalMock(2)).Blink(1, 1)};
TestJLedSequence seq(TestJLedSequence::eMode::PARALLEL, leds);

constexpr uint8_t expected[]{/* 1ms on */ 255,
/* 1ms off */ 0,
255,
0,
/* finally off */ 0};
uint32_t time = 0;
for (const auto val : expected) {
seq.Update();

for (auto runs = 0; runs < 2; runs++) {
for (const auto val : expected) {
seq.Update();
REQUIRE(val == leds[0].Hal().Value());
REQUIRE(val == leds[1].Hal().Value());
leds[0].Hal().SetMillis(++time);
leds[1].Hal().SetMillis(++time);
REQUIRE(val == leds[0].Hal().Value());
REQUIRE(val == leds[1].Hal().Value());

++time;
leds[0].Hal().SetMillis(time);
leds[1].Hal().SetMillis(time);

if (time == 2) {
// expect sequence to stop after 2ms
REQUIRE(!seq.Update());
seq.Reset();
}
REQUIRE(!seq.Update());
seq.Reset(); // expected to start over in second iteration
}
}

0 comments on commit 540d607

Please sign in to comment.