diff --git a/example.json b/example.json index 27a653e..3152010 100644 --- a/example.json +++ b/example.json @@ -27,6 +27,10 @@ { "name": "rollup_pattern", "repeat": 1, + "before": [ + {"color": "#000000", "led": 0, "time": 100}, + {"time": 100} + ], "lines": [ {"color": "#FFFFFF", "led": 0, "time": 500}, {"time": 500}, @@ -58,6 +62,10 @@ {"color": "#0000FF", "led": 1, "time": 250}, {"color": "#FF0000", "led": 2, "time": 250}, {"time": 250} + ], + "after": [ + {"color": "#000000", "led": 0, "time": 100}, + {"time": 100} ] } ] diff --git a/include/config/ConfigParser.hpp b/include/config/ConfigParser.hpp index 4e65a35..342f6da 100644 --- a/include/config/ConfigParser.hpp +++ b/include/config/ConfigParser.hpp @@ -34,6 +34,7 @@ namespace blink1_control::config { [[nodiscard]] static std::shared_ptr parseProcessMonitor(const Json& json); [[nodiscard]] static std::shared_ptr parseRollup(const Json& json); [[nodiscard]] static blink1_lib::RGBN parseRgb(const std::string& rgbString); + static void readPattern(const Json& json, std::vector>& commands); public: /** diff --git a/include/config/PatternConfig.hpp b/include/config/PatternConfig.hpp index 239b8de..7880eb2 100644 --- a/include/config/PatternConfig.hpp +++ b/include/config/PatternConfig.hpp @@ -24,6 +24,16 @@ namespace blink1_control::config { */ std::string name; + /** + * A list of pattern lines which get played before the pattern starts + */ + std::vector> before; + + /** + * A list of pattern lines which get played after the pattern is done + */ + std::vector> after; + /** * A list of pattern lines which make up the pattern */ diff --git a/src/config/ConfigParser.cpp b/src/config/ConfigParser.cpp index 556ef9a..7954a41 100644 --- a/src/config/ConfigParser.cpp +++ b/src/config/ConfigParser.cpp @@ -118,6 +118,26 @@ namespace blink1_control::config { return parseArray(json, config, PATTERNS_STRING, [](const Json& ljson, Config& lconfig){return parsePattern(ljson, lconfig);}); } + void ConfigParser::readPattern(const Json& json, std::vector>& commands) { + for (const Json& line : json) { + bool hasLed = line.contains("led"); + bool hasColor = line.contains("color"); + + if (hasLed && hasColor) { + blink1_lib::PatternLineN patternLine; + patternLine.rgbn = parseRgb(line.at("color")); + patternLine.rgbn.n = line.at("led"); + patternLine.fadeMillis = line.at("time"); + + commands.push_back(std::make_unique(patternLine)); + } else if (hasLed || hasColor) { + throw std::runtime_error("Pattern line must contain both 'led' and 'color' or neither of them"); + } else { + commands.push_back(std::make_unique(std::chrono::milliseconds(line.at("time")))); + } + } + } + bool ConfigParser::parsePattern(const Json& json, Config& config) { bool success = true; @@ -126,22 +146,12 @@ namespace blink1_control::config { pattern->name = json.at("name"); pattern->repeat = json.at("repeat"); - for (const Json& line : json.at("lines")) { - bool hasLed = line.contains("led"); - bool hasColor = line.contains("color"); - - if (hasLed && hasColor) { - blink1_lib::PatternLineN patternLine; - patternLine.rgbn = parseRgb(line.at("color")); - patternLine.rgbn.n = line.at("led"); - patternLine.fadeMillis = line.at("time"); - - pattern->pattern.push_back(std::make_unique(patternLine)); - } else if (hasLed || hasColor) { - throw std::runtime_error("Pattern line must contain both 'led' and 'color' or neither of them"); - } else { - pattern->pattern.push_back(std::make_unique(std::chrono::milliseconds(line.at("time")))); - } + readPattern(json.at("lines"), pattern->pattern); + if (json.contains("before")) { + readPattern(json.at("before"), pattern->before); + } + if (json.contains("after")) { + readPattern(json.at("after"), pattern->after); } config.patternConfigs.emplace(pattern->name, pattern); diff --git a/src/main.cpp b/src/main.cpp index 46d5b53..e342074 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -68,6 +68,12 @@ int main(int argc, const char* argv[]) { PatternConfig& pattern = *it->second; std::cout << "Playing " << pattern.name << "\n"; + std::cout << " Playing before pattern\n"; + for (auto& patternLine : pattern.before) { + std::cout << " Playing " << *patternLine << "\n"; + patternLine->execute(blinkDevice); + } + for (int i = 0; i < pattern.repeat && LOOPING; ++i) { std::cout << " Playing iteration " << i << "/" << pattern.repeat << "\n"; for (auto& patternLine : pattern.pattern) { @@ -75,6 +81,12 @@ int main(int argc, const char* argv[]) { patternLine->execute(blinkDevice); } } + + std::cout << " Playing after pattern\n"; + for (auto& patternLine : pattern.after) { + std::cout << " Playing " << *patternLine << "\n"; + patternLine->execute(blinkDevice); + } } } } diff --git a/test/config/ConfigParser_test.cpp b/test/config/ConfigParser_test.cpp index b816b89..8d8d730 100644 --- a/test/config/ConfigParser_test.cpp +++ b/test/config/ConfigParser_test.cpp @@ -83,6 +83,20 @@ TEST_F(SUITE_NAME, TestParseConfig) { { "time": 1234 } + ], + "before": [ + { + "color": "#ABCDEF", + "led": 5, + "time": 10 + } + ], + "after": [ + { + "color": "#FEDCBA", + "led": 6, + "time": 11 + } ] } ] @@ -155,6 +169,25 @@ TEST_F(SUITE_NAME, TestParseConfig) { EXPECT_EQ(typeid(WaitCommand&), typeid(patternLine3)); auto& waitCommand = dynamic_cast(patternLine3); EXPECT_EQ(std::chrono::milliseconds(1234), waitCommand.waitTime); + + auto& beforeLine = *rollupPatternConfig->before[0]; + auto& afterLine = *rollupPatternConfig->after[0]; + + EXPECT_EQ(typeid(FadeCommand&), typeid(beforeLine)); + auto& beforeCommand = dynamic_cast(beforeLine); + EXPECT_EQ(0xAB, beforeCommand.fadeParams.rgbn.r); + EXPECT_EQ(0xCD, beforeCommand.fadeParams.rgbn.g); + EXPECT_EQ(0xEF, beforeCommand.fadeParams.rgbn.b); + EXPECT_EQ(5, beforeCommand.fadeParams.rgbn.n); + EXPECT_EQ(10, beforeCommand.fadeParams.fadeMillis); + + EXPECT_EQ(typeid(FadeCommand&), typeid(afterLine)); + auto& afterCommand = dynamic_cast(afterLine); + EXPECT_EQ(0xFE, afterCommand.fadeParams.rgbn.r); + EXPECT_EQ(0xDC, afterCommand.fadeParams.rgbn.g); + EXPECT_EQ(0xBA, afterCommand.fadeParams.rgbn.b); + EXPECT_EQ(6, afterCommand.fadeParams.rgbn.n); + EXPECT_EQ(11, afterCommand.fadeParams.fadeMillis); } TEST_F(SUITE_NAME, TestBadStreams) {