From 19a691beac7b015ae6aae429445eeb3950d60bd1 Mon Sep 17 00:00:00 2001 From: Tim Hendriks Date: Sat, 13 Jan 2024 11:27:22 +0100 Subject: [PATCH] re-add live mode --- .vscode/settings.json | 7 ++- examples/MultiplePCA9685/MultiplePCA9685.ino | 2 +- .../SwitchModeButton/SwitchModeButton.ino | 3 + src/internal/Animation.cpp | 40 +++++++----- src/internal/Animation.h | 10 ++- src/internal/Scene.cpp | 43 ++++++------- src/internal/Scene.h | 12 ++-- src/internal/ServoManager.cpp | 20 ++++++ src/internal/ServoManager.h | 3 +- test/test_scene/test_scene.cpp | 61 +++++-------------- .../test_servo_manager/test_servo_manager.cpp | 33 ++++++---- 11 files changed, 128 insertions(+), 106 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 0296f77..6bfc61c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -32,6 +32,11 @@ "__locale": "cpp", "iterator": "cpp", "locale": "cpp", - "thread": "cpp" + "thread": "cpp", + "memory": "cpp", + "random": "cpp", + "mutex": "cpp", + "optional": "cpp", + "__tree": "cpp" } } \ No newline at end of file diff --git a/examples/MultiplePCA9685/MultiplePCA9685.ino b/examples/MultiplePCA9685/MultiplePCA9685.ino index 679bcd8..4b03691 100644 --- a/examples/MultiplePCA9685/MultiplePCA9685.ino +++ b/examples/MultiplePCA9685/MultiplePCA9685.ino @@ -37,7 +37,7 @@ servoMapping servoMappings[] = { }; // Calculate the amount of servos so that we can easily extend the array -const byte servoAmount = sizeof(servoMaps) / sizeof(servoMaps[0]); +const byte servoAmount = sizeof(servoMappings) / sizeof(servoMappings[0]); // Callback function which is called whenever a servo needs to be moved void setPWM(byte servoID, int position) { diff --git a/examples/SwitchModeButton/SwitchModeButton.ino b/examples/SwitchModeButton/SwitchModeButton.ino index 3d7de7a..c4e1a69 100644 --- a/examples/SwitchModeButton/SwitchModeButton.ino +++ b/examples/SwitchModeButton/SwitchModeButton.ino @@ -106,6 +106,9 @@ void setup() { // Add a scene based on PROGMEM data animation.addScene(ANIMATION_DATA, LENGTH, FPS, FRAMES); + // Add a scene based on (live) Serial data + animation.addScene(Serial); + // Register the mode change callback function animation.onModeChange(modeChanged); } diff --git a/src/internal/Animation.cpp b/src/internal/Animation.cpp index 3c27537..13abd1f 100644 --- a/src/internal/Animation.cpp +++ b/src/internal/Animation.cpp @@ -28,15 +28,21 @@ bool Animation::hasScene(byte index) { return this->scenes[index] != nullptr; } -void Animation::addScene(const byte *data, int dataLength, byte fps, - int frames) { - ProgmemStream *stream = new ProgmemStream(data, dataLength); - this->addScene(*stream, fps, frames); +void Animation::addScene(const byte *data, int size, byte fps, int frames) { + ProgmemStream *stream = new ProgmemStream(data, size); + Scene *scene = new Scene(this->servoManager, fps, frames); + scene->setProgmemData(stream); + this->registerScene(scene); } void Animation::addScene(Stream &data, byte fps, int frames) { - this->scenes[this->addIndex] = - new Scene(this->servoManager, data, fps, frames); + Scene *scene = new Scene(this->servoManager, fps, frames); + scene->setData(&data); + this->registerScene(scene); +} + +void Animation::registerScene(Scene *scene) { + this->scenes[this->addIndex] = scene; this->addIndex++; } @@ -112,8 +118,7 @@ void Animation::loop() { } void Animation::pause() { - if (!this->scene || !this->modeIsIn(4, MODE_PLAY, MODE_PLAY_SINGLE, - MODE_PLAY_RANDOM, MODE_LOOP)) { + if (!this->scene || this->modeIsIn(4, MODE_DEFAULT, MODE_PAUSE, MODE_STOP)) { return; } @@ -128,13 +133,13 @@ void Animation::stop() { this->changeMode(MODE_STOP); } -void Animation::reset() { - this->addIndex = 0; - this->playIndex = 0; - - for (int i = 0; i < this->addIndex; i++) { - this->scenes[i] = nullptr; +void Animation::live(Stream &stream) { + if (this->mode != MODE_DEFAULT) { + return; } + + this->liveStream = &stream; + this->changeMode(MODE_LIVE); } byte Animation::getMode() { @@ -156,6 +161,9 @@ void Animation::run(unsigned long currentMicros) { case MODE_STOP: this->handleStopMode(currentMicros); break; + case MODE_LIVE: + this->handleLiveMode(); + break; } } @@ -217,6 +225,10 @@ void Animation::handleStopMode(unsigned long currentMicros) { } } +void Animation::handleLiveMode() { + this->servoManager.parseStream(this->liveStream); +} + Scene *Animation::getCurrentScene() { return this->scene; } diff --git a/src/internal/Animation.h b/src/internal/Animation.h index 11e2933..bce5de2 100644 --- a/src/internal/Animation.h +++ b/src/internal/Animation.h @@ -19,6 +19,7 @@ class Animation { static const byte MODE_PAUSE = 4; static const byte MODE_LOOP = 5; static const byte MODE_STOP = 6; + static const byte MODE_LIVE = 7; ~Animation(); @@ -39,14 +40,13 @@ class Animation { void loop(); void pause(); void stop(); - void reset(); + void live(Stream &stream); void setDefaultServoThreshold(byte value); void setServoThreshold(byte id, byte value); bool hasFinished(); bool hasScenes(); bool hasScene(byte index); - bool modeIsIn(byte modeAmount, ...); Scene *getCurrentScene(); @@ -58,6 +58,8 @@ class Animation { Scene *scenes[MAX_SCENE_COUNT] = {nullptr}; Scene *scene = nullptr; + Stream *liveStream; + mcb modeCallback = nullptr; scb sceneCallback = nullptr; @@ -66,10 +68,14 @@ class Animation { int addIndex = 0; int playIndex = 0; + void registerScene(Scene *scene); void changeMode(byte mode); void handlePlayMode(unsigned long currentMicros); void handleStopMode(unsigned long currentMicros); + void handleLiveMode(); void setRandomScene(); + + bool modeIsIn(byte modeAmount, ...); }; } // namespace BlenderServoAnimation diff --git a/src/internal/Scene.cpp b/src/internal/Scene.cpp index 5b1b29f..9f78506 100644 --- a/src/internal/Scene.cpp +++ b/src/internal/Scene.cpp @@ -6,26 +6,33 @@ using namespace BlenderServoAnimation; -Scene::Scene(ServoManager &servoManager, Stream &data, byte fps, int frames, - bool hasProgmemStream) { +Scene::Scene(ServoManager &servoManager, byte fps, int frames) { this->servoManager = &servoManager; - this->data = &data; this->fps = fps; this->frames = frames; this->frameMicros = round((float)Scene::SECOND_IN_MICROS / (float)fps); this->diffPerSecond = Scene::SECOND_IN_MICROS - (this->frameMicros * fps); - this->hasProgmemStream = hasProgmemStream; } Scene::~Scene() { - if (this->hasProgmemStream) { - delete this->data; + if (this->progmemData) { + delete this->progmemData; } } +void Scene::setData(Stream *data) { + this->data = data; +} + +void Scene::setProgmemData(ProgmemStream *data) { + this->progmemData = data; +} + void Scene::play(unsigned long currentMicros) { + Stream *data = this->getAnimationData(); + if (this->frames == 0) { - this->parseCommands(); + this->servoManager->parseStream(data); return; } @@ -45,7 +52,7 @@ void Scene::play(unsigned long currentMicros) { this->lastMicros += this->diffPerSecond; } - this->parseCommands(); + this->servoManager->parseStream(data); } void Scene::stop(unsigned long currentMicros) { @@ -90,22 +97,10 @@ int Scene::getFrames() { return this->frames; } -void Scene::parseCommands() { - if (!this->servoManager->hasPositionCallback()) { - return; +Stream* Scene::getAnimationData() { + if (this->progmemData) { + return this->progmemData; } - Command command; - - while (this->data->available() > 0) { - byte value = this->data->read(); - - if (this->frames > 0 && value == Command::LINE_BREAK) { - break; - } - - command.write(value); - - this->servoManager->handleCommand(command); - } + return this->data; } diff --git a/src/internal/Scene.h b/src/internal/Scene.h index 9b93e92..4d6d15e 100644 --- a/src/internal/Scene.h +++ b/src/internal/Scene.h @@ -1,4 +1,5 @@ #include "ServoManager.h" +#include "ProgmemStream.h" #include #ifndef BlenderServoAnimation_Scene_H @@ -9,10 +10,11 @@ namespace BlenderServoAnimation { class Scene { public: - Scene(ServoManager &servoManager, Stream &data, byte fps = 0, int frames = 0, - bool hasProgmemStream = false); + Scene(ServoManager &servoManager, byte fps, int frames); ~Scene(); + void setData(Stream *data); + void setProgmemData(ProgmemStream *data); void play(unsigned long currentMicros); void stop(unsigned long currentMicros); @@ -38,17 +40,17 @@ class Scene { unsigned long lastMicros = 0; - bool hasProgmemStream = false; - ServoManager *servoManager; Stream *data = nullptr; - void parseCommands(); + ProgmemStream *progmemData = nullptr; bool isNewFrame(unsigned long currentMicros); unsigned int getMicrosDiff(unsigned long currentMicros); + + Stream* getAnimationData(); }; } // namespace BlenderServoAnimation diff --git a/src/internal/ServoManager.cpp b/src/internal/ServoManager.cpp index 980b685..b0ba10c 100644 --- a/src/internal/ServoManager.cpp +++ b/src/internal/ServoManager.cpp @@ -34,6 +34,26 @@ void ServoManager::setThreshold(byte servoId, byte value) { } } +void ServoManager::parseStream(Stream *stream, bool considerLineBreaks) { + if (!stream || !this->hasPositionCallback()) { + return; + } + + Command command; + + while (stream->available() > 0) { + byte value = stream->read(); + + if (considerLineBreaks && value == Command::LINE_BREAK) { + break; + } + + command.write(value); + + this->handleCommand(command); + } +} + void ServoManager::handleCommand(Command command) { if (!command.isValid()) { return; diff --git a/src/internal/ServoManager.h b/src/internal/ServoManager.h index ac597fc..10f7fb1 100644 --- a/src/internal/ServoManager.h +++ b/src/internal/ServoManager.h @@ -16,7 +16,7 @@ class ServoManager { void setPositionCallback(pcb positionCallback); void setDefaultThreshold(byte value); void setThreshold(byte servoId, byte value); - void handleCommand(Command command); + void parseStream(Stream *stream, bool considerLineBreaks = true); void moveAllServosToNeutral(); bool hasPositionCallback(); @@ -33,6 +33,7 @@ class ServoManager { byte thresholds[MAX_SERVO_COUNT] = {0}; void addServo(byte id); + void handleCommand(Command command); }; } // namespace BlenderServoAnimation diff --git a/test/test_scene/test_scene.cpp b/test/test_scene/test_scene.cpp index cf41195..201baa0 100644 --- a/test/test_scene/test_scene.cpp +++ b/test/test_scene/test_scene.cpp @@ -12,8 +12,9 @@ void setUp(void) { void test_play_with_frames(void) { ServoManager servoManager; servoManager.setPositionCallback(move); - ProgmemStream stream(PROGMEM_DATA, DATA_SIZE); - Scene scene(servoManager, stream, FPS, FRAMES); + ProgmemStream *stream = new ProgmemStream(PROGMEM_DATA, DATA_SIZE); + Scene scene(servoManager, FPS, FRAMES); + scene.setProgmemData(stream); positionLog exp[10] = { {0, 375}, {1, 375}, {0, 376}, {1, 376}, {0, 377}, @@ -32,51 +33,18 @@ void test_play_with_frames(void) { } } -void test_play_without_frames(void) { - ServoManager servoManager; - servoManager.setPositionCallback(move); - ProgmemStream stream(PROGMEM_DATA, DATA_SIZE); - Scene scene(servoManager, stream); - - positionLog exp[10] = { - {0, 375}, {1, 375}, {0, 376}, {1, 376}, {0, 377}, - {1, 379}, {0, 380}, {1, 383}, {0, 384}, {1, 388}, - }; - - scene.play(0); - - TEST_ASSERT_EQUAL(10, logIndex); - - for (byte i = 0; i < 10; i++) { - TEST_ASSERT_EQUAL(exp[i].servoId, positions[i].servoId); - TEST_ASSERT_EQUAL(exp[i].position, positions[i].position); - } -} - void test_stop(void) { ServoManager servoManager; servoManager.setPositionCallback(move); servoManager.setDefaultThreshold(20); - ProgmemStream stream(PROGMEM_DATA, DATA_SIZE); - Scene scene(servoManager, stream, FPS, FRAMES); + ProgmemStream *stream = new ProgmemStream(PROGMEM_DATA, DATA_SIZE); + Scene scene(servoManager, FPS, FRAMES); + scene.setProgmemData(stream); positionLog exp[15] = { - {0, 375}, - {1, 375}, - {0, 376}, - {1, 376}, - {0, 377}, - {1, 379}, - {0, 380}, - {1, 383}, - // stop - {0, 378}, - {1, 381}, - {0, 376}, - {1, 379}, - {0, 375}, - {1, 377}, - {1, 375}, + {0, 375}, {1, 375}, {0, 376}, {1, 376}, {0, 377}, + {1, 379}, {0, 380}, {1, 383}, {0, 378}, {1, 381}, + {0, 376}, {1, 379}, {0, 375}, {1, 377}, {1, 375}, }; for (int i = 0; i < FRAME_MICROS * 4; i += FRAME_MICROS) { @@ -102,8 +70,9 @@ void test_stop(void) { void test_has_finished(void) { ServoManager servoManager; - ProgmemStream stream(PROGMEM_DATA, DATA_SIZE); - Scene scene(servoManager, stream, FPS, FRAMES); + ProgmemStream *stream = new ProgmemStream(PROGMEM_DATA, DATA_SIZE); + Scene scene(servoManager, FPS, FRAMES); + scene.setProgmemData(stream); TEST_ASSERT_FALSE(scene.hasFinished()); @@ -120,8 +89,9 @@ void test_has_finished(void) { void test_get_frame(void) { ServoManager servoManager; - ProgmemStream stream(PROGMEM_DATA, DATA_SIZE); - Scene scene(servoManager, stream, FPS, FRAMES); + ProgmemStream *stream = new ProgmemStream(PROGMEM_DATA, DATA_SIZE); + Scene scene(servoManager, FPS, FRAMES); + scene.setProgmemData(stream); TEST_ASSERT_EQUAL(0, scene.getFrame()); @@ -135,7 +105,6 @@ void test_get_frame(void) { int main(int argc, char **argv) { UNITY_BEGIN(); RUN_TEST(test_play_with_frames); - RUN_TEST(test_play_without_frames); RUN_TEST(test_stop); RUN_TEST(test_has_finished); RUN_TEST(test_get_frame); diff --git a/test/test_servo_manager/test_servo_manager.cpp b/test/test_servo_manager/test_servo_manager.cpp index e1fd2f4..e1d8e4b 100644 --- a/test/test_servo_manager/test_servo_manager.cpp +++ b/test/test_servo_manager/test_servo_manager.cpp @@ -1,5 +1,6 @@ #include "../test/helper.h" #include "internal/ServoManager.h" +#include "internal/ProgmemStream.h" #include using namespace BlenderServoAnimation; @@ -8,29 +9,37 @@ void setUp(void) { resetPositionLog(); } -void test_handle_command(void) { - Command command; +void test_parse_stream(void) { + ProgmemStream stream(PROGMEM_DATA, DATA_SIZE); ServoManager servoManager; servoManager.setPositionCallback(move); - for (byte i = 0; i < 4; i++) { - command.write(PROGMEM_DATA[i]); - } - - servoManager.handleCommand(command); - TEST_ASSERT_EQUAL(0, logIndex); - command.write(PROGMEM_DATA[4]); - servoManager.handleCommand(command); + servoManager.parseStream(&stream); - TEST_ASSERT_EQUAL(1, logIndex); + TEST_ASSERT_EQUAL(2, logIndex); TEST_ASSERT_EQUAL(0, positions[0].servoId); TEST_ASSERT_EQUAL(375, positions[0].position); + TEST_ASSERT_EQUAL(1, positions[1].servoId); + TEST_ASSERT_EQUAL(375, positions[1].position); +} + +void test_parse_stream_without_line_breaks(void) { + ProgmemStream stream(PROGMEM_DATA, DATA_SIZE); + ServoManager servoManager; + servoManager.setPositionCallback(move); + + TEST_ASSERT_EQUAL(0, logIndex); + + servoManager.parseStream(&stream, false); + + TEST_ASSERT_EQUAL(10, logIndex); } int main(int argc, char **argv) { UNITY_BEGIN(); - RUN_TEST(test_handle_command); + RUN_TEST(test_parse_stream); + RUN_TEST(test_parse_stream_without_line_breaks); UNITY_END(); } \ No newline at end of file