From 4076e099706d0790268f88c65652b8dd176c4735 Mon Sep 17 00:00:00 2001 From: Tim Hendriks Date: Wed, 10 Jan 2024 23:22:27 +0100 Subject: [PATCH] introduce scene based library approach --- .vscode/settings.json | 37 +++ examples/AdafruitPCA9685/AdafruitPCA9685.ino | 14 +- examples/AdafruitPCA9685/ik.h | 34 ++- examples/MultiplePCA9685/MultiplePCA9685.ino | 36 ++- examples/MultiplePCA9685/ik.h | 34 ++- examples/MultipleScenes/MultipleScenes.ino | 54 ++++ examples/{Show => MultipleScenes}/README.md | 0 .../{Show => MultipleScenes}/platformio.ini | 0 examples/MultipleScenes/scene-a.h | 36 +++ examples/MultipleScenes/scene-b.h | 48 +++ .../MultipleScenesSD/MultipleScenesSD.ino | 66 +++++ examples/MultipleScenesSD/README.md | 7 + examples/MultipleScenesSD/platformio.ini | 31 ++ examples/SDAnimation/README.md | 7 + examples/SDAnimation/SDAnimation.ino | 50 ++++ examples/SDAnimation/platformio.ini | 31 ++ examples/SerialLiveMode/SerialLiveMode.ino | 17 +- examples/Show/Show.ino | 68 ----- examples/Show/scene-a.h | 26 -- examples/Show/scene-b.h | 28 -- .../StandardServoLib/StandardServoLib.ino | 12 +- examples/StandardServoLib/simple.h | 18 +- .../SwitchModeButton/SwitchModeButton.ino | 20 +- examples/SwitchModeButton/simple.h | 18 +- .../WebSocketLiveMode/WebSocketLiveMode.ino | 24 +- platformio.ini | 5 +- src/BlenderServoAnimation.h | 3 +- src/internal/Animation.cpp | 276 ++++++++++-------- src/internal/Animation.h | 94 +++--- src/internal/Command.cpp | 39 +++ src/internal/{LiveCommand.h => Command.h} | 31 +- src/internal/LiveCommand.cpp | 48 --- src/internal/LiveStream.cpp | 12 +- src/internal/LiveStream.h | 22 +- src/internal/ProgmemStream.cpp | 37 +++ src/internal/ProgmemStream.h | 31 ++ src/internal/Scene.cpp | 109 +++++++ src/internal/Scene.h | 56 ++++ src/internal/Servo.cpp | 77 +++-- src/internal/Servo.h | 34 +-- src/internal/ServoManager.cpp | 86 ++++++ src/internal/ServoManager.h | 41 +++ src/internal/Show.cpp | 254 ---------------- src/internal/Show.h | 67 ----- src/internal/typedefs.h | 5 + test/animation/helper.h | 36 --- test/animation/test_live/test_live.cpp | 119 -------- test/animation/test_loop/test_loop.cpp | 104 ++++--- .../test_mode_callback/test_mode_callback.cpp | 65 +++-- test/animation/test_pause/test_pause.cpp | 134 +++++---- test/animation/test_play/test_play.cpp | 110 +++---- .../test_play_random/test_play_random.cpp | 103 +++++++ .../test_play_single/test_play_single.cpp | 112 +++++++ test/animation/test_stop/test_stop.cpp | 142 +++++---- test/helper.h | 41 +++ test/show/test_live/test_live.cpp | 76 ----- test/show/test_loop/test_loop.cpp | 108 ------- .../test_mode_callback/test_mode_callback.cpp | 104 ------- test/show/test_pause/test_pause.cpp | 141 --------- test/show/test_play/test_play.cpp | 117 -------- .../test_play_random/test_play_random.cpp | 108 ------- .../test_play_single/test_play_single.cpp | 118 -------- test/show/test_stop/test_stop.cpp | 143 --------- .../test_command.cpp} | 39 +-- test/test_live_stream/test_live_stream.cpp | 48 +++ .../test_progmem_stream.cpp | 28 ++ test/test_scene/test_scene.cpp | 159 ++++++++++ test/test_servo/test_servo.cpp | 101 ++++--- .../test_servo_manager/test_servo_manager.cpp | 36 +++ 69 files changed, 2113 insertions(+), 2222 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 examples/MultipleScenes/MultipleScenes.ino rename examples/{Show => MultipleScenes}/README.md (100%) rename examples/{Show => MultipleScenes}/platformio.ini (100%) create mode 100644 examples/MultipleScenes/scene-a.h create mode 100644 examples/MultipleScenes/scene-b.h create mode 100644 examples/MultipleScenesSD/MultipleScenesSD.ino create mode 100644 examples/MultipleScenesSD/README.md create mode 100644 examples/MultipleScenesSD/platformio.ini create mode 100644 examples/SDAnimation/README.md create mode 100644 examples/SDAnimation/SDAnimation.ino create mode 100644 examples/SDAnimation/platformio.ini delete mode 100644 examples/Show/Show.ino delete mode 100644 examples/Show/scene-a.h delete mode 100644 examples/Show/scene-b.h create mode 100644 src/internal/Command.cpp rename src/internal/{LiveCommand.h => Command.h} (70%) delete mode 100644 src/internal/LiveCommand.cpp create mode 100644 src/internal/ProgmemStream.cpp create mode 100644 src/internal/ProgmemStream.h create mode 100644 src/internal/Scene.cpp create mode 100644 src/internal/Scene.h create mode 100644 src/internal/ServoManager.cpp create mode 100644 src/internal/ServoManager.h delete mode 100644 src/internal/Show.cpp delete mode 100644 src/internal/Show.h create mode 100644 src/internal/typedefs.h delete mode 100644 test/animation/helper.h delete mode 100644 test/animation/test_live/test_live.cpp create mode 100644 test/animation/test_play_random/test_play_random.cpp create mode 100644 test/animation/test_play_single/test_play_single.cpp create mode 100644 test/helper.h delete mode 100644 test/show/test_live/test_live.cpp delete mode 100644 test/show/test_loop/test_loop.cpp delete mode 100644 test/show/test_mode_callback/test_mode_callback.cpp delete mode 100644 test/show/test_pause/test_pause.cpp delete mode 100644 test/show/test_play/test_play.cpp delete mode 100644 test/show/test_play_random/test_play_random.cpp delete mode 100644 test/show/test_play_single/test_play_single.cpp delete mode 100644 test/show/test_stop/test_stop.cpp rename test/{test_live_command/test_live_command.cpp => test_command/test_command.cpp} (50%) create mode 100644 test/test_live_stream/test_live_stream.cpp create mode 100644 test/test_progmem_stream/test_progmem_stream.cpp create mode 100644 test/test_scene/test_scene.cpp create mode 100644 test/test_servo_manager/test_servo_manager.cpp diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..0296f77 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,37 @@ +{ + "files.associations": { + "*.tcc": "cpp", + "exception": "cpp", + "memory_resource": "cpp", + "iosfwd": "cpp", + "new": "cpp", + "ostream": "cpp", + "sstream": "cpp", + "stop_token": "cpp", + "streambuf": "cpp", + "__bit_reference": "cpp", + "__string": "cpp", + "algorithm": "cpp", + "deque": "cpp", + "ios": "cpp", + "string": "cpp", + "type_traits": "cpp", + "cstddef": "cpp", + "array": "cpp", + "bitset": "cpp", + "vector": "cpp", + "string_view": "cpp", + "functional": "cpp", + "iomanip": "cpp", + "istream": "cpp", + "limits": "cpp", + "ratio": "cpp", + "tuple": "cpp", + "__config": "cpp", + "__hash_table": "cpp", + "__locale": "cpp", + "iterator": "cpp", + "locale": "cpp", + "thread": "cpp" + } +} \ No newline at end of file diff --git a/examples/AdafruitPCA9685/AdafruitPCA9685.ino b/examples/AdafruitPCA9685/AdafruitPCA9685.ino index e06712c..f754b8a 100644 --- a/examples/AdafruitPCA9685/AdafruitPCA9685.ino +++ b/examples/AdafruitPCA9685/AdafruitPCA9685.ino @@ -23,16 +23,14 @@ void move(byte servoID, int position) { } // Animation object to represent the original Blender animation -Animation animation(FPS, FRAMES); - -// Servo objects to manage the positions -Servo neckLeftServo(0, NeckLeft, move); -Servo neckRightServo(1, NeckRight, move); +Animation animation; void setup() { - // Add the Blender servo objects to the animation - animation.addServo(neckLeftServo); - animation.addServo(neckRightServo); + // Set the position callback + animation.onPositionChange(move); + + // Add a scene based on PROGMEM data + animation.addScene(ANIMATION_DATA, LENGTH, FPS, FRAMES); // Trigger the animation loop mode animation.loop(); diff --git a/examples/AdafruitPCA9685/ik.h b/examples/AdafruitPCA9685/ik.h index a872655..3c3c0d3 100644 --- a/examples/AdafruitPCA9685/ik.h +++ b/examples/AdafruitPCA9685/ik.h @@ -14,15 +14,29 @@ const byte FPS = 30; const int FRAMES = 100; +const int LENGTH = 1100; -// Servo ID: 0 -const int NeckLeft[FRAMES] PROGMEM = { - 375, 376, 377, 380, 384, 387, 391, 396, 400, 403, 406, 408, 410, 410, 409, 406, 402, 396, 390, 382, 373, 364, 355, 346, 338, 330, 323, 318, 314, 311, 309, 307, 305, 305, 305, 305, 306, 307, 309, 311, 314, 317, 320, 323, 327, 331, 335, 339, 343, 347, - 351, 356, 360, 364, 369, 374, 380, 386, 392, 398, 404, 410, 415, 420, 425, 429, 432, 435, 436, 437, 437, 436, 435, 434, 432, 430, 428, 426, 423, 421, 418, 415, 412, 409, 406, 403, 400, 397, 394, 391, 388, 386, 384, 381, 380, 378, 377, 376, 375, 375, -}; - -// Servo ID: 1 -const int NeckRight[FRAMES] PROGMEM = { - 375, 376, 379, 383, 388, 394, 401, 409, 417, 426, 434, 443, 450, 457, 463, 468, 471, 472, 471, 469, 466, 462, 457, 452, 447, 441, 437, 432, 428, 424, 420, 416, 411, 407, 402, 398, 394, 389, 384, 380, 375, 370, 366, 361, 356, 352, 347, 342, 337, 333, - 328, 324, 319, 315, 312, 309, 308, 307, 306, 306, 306, 307, 308, 309, 310, 311, 312, 313, 313, 313, 313, 314, 315, 316, 318, 320, 322, 324, 327, 329, 332, 335, 338, 341, 344, 347, 350, 353, 356, 359, 362, 364, 366, 369, 370, 372, 373, 374, 375, 375, +const byte PROGMEM ANIMATION_DATA[LENGTH] = { + 60, 0, 1, 119, 62, 60, 1, 1, 119, 62, 10, 60, 0, 1, 120, 62, 60, 1, 1, 120, 62, 10, 60, 0, 1, 121, 62, 60, 1, 1, 123, 62, 10, 60, 0, 1, 124, 62, 60, 1, 1, 127, 62, 10, 60, 0, 1, 128, 62, 60, + 1, 1, 132, 62, 10, 60, 0, 1, 131, 62, 60, 1, 1, 138, 62, 10, 60, 0, 1, 135, 62, 60, 1, 1, 145, 62, 10, 60, 0, 1, 140, 62, 60, 1, 1, 153, 62, 10, 60, 0, 1, 144, 62, 60, 1, 1, 161, 62, 10, 60, + 0, 1, 147, 62, 60, 1, 1, 170, 62, 10, 60, 0, 1, 150, 62, 60, 1, 1, 178, 62, 10, 60, 0, 1, 152, 62, 60, 1, 1, 187, 62, 10, 60, 0, 1, 154, 62, 60, 1, 1, 194, 62, 10, 60, 0, 1, 154, 62, 60, 1, + 1, 201, 62, 10, 60, 0, 1, 153, 62, 60, 1, 1, 207, 62, 10, 60, 0, 1, 150, 62, 60, 1, 1, 212, 62, 10, 60, 0, 1, 146, 62, 60, 1, 1, 215, 62, 10, 60, 0, 1, 140, 62, 60, 1, 1, 216, 62, 10, 60, 0, + 1, 134, 62, 60, 1, 1, 215, 62, 10, 60, 0, 1, 126, 62, 60, 1, 1, 213, 62, 10, 60, 0, 1, 117, 62, 60, 1, 1, 210, 62, 10, 60, 0, 1, 108, 62, 60, 1, 1, 206, 62, 10, 60, 0, 1, 99, 62, 60, 1, 1, + 201, 62, 10, 60, 0, 1, 90, 62, 60, 1, 1, 196, 62, 10, 60, 0, 1, 82, 62, 60, 1, 1, 191, 62, 10, 60, 0, 1, 74, 62, 60, 1, 1, 185, 62, 10, 60, 0, 1, 67, 62, 60, 1, 1, 181, 62, 10, 60, 0, 1, + 62, 62, 60, 1, 1, 176, 62, 10, 60, 0, 1, 58, 62, 60, 1, 1, 172, 62, 10, 60, 0, 1, 55, 62, 60, 1, 1, 168, 62, 10, 60, 0, 1, 53, 62, 60, 1, 1, 164, 62, 10, 60, 0, 1, 51, 62, 60, 1, 1, 160, + 62, 10, 60, 0, 1, 49, 62, 60, 1, 1, 155, 62, 10, 60, 0, 1, 49, 62, 60, 1, 1, 151, 62, 10, 60, 0, 1, 49, 62, 60, 1, 1, 146, 62, 10, 60, 0, 1, 49, 62, 60, 1, 1, 142, 62, 10, 60, 0, 1, 50, + 62, 60, 1, 1, 138, 62, 10, 60, 0, 1, 51, 62, 60, 1, 1, 133, 62, 10, 60, 0, 1, 53, 62, 60, 1, 1, 128, 62, 10, 60, 0, 1, 55, 62, 60, 1, 1, 124, 62, 10, 60, 0, 1, 58, 62, 60, 1, 1, 119, 62, + 10, 60, 0, 1, 61, 62, 60, 1, 1, 114, 62, 10, 60, 0, 1, 64, 62, 60, 1, 1, 110, 62, 10, 60, 0, 1, 67, 62, 60, 1, 1, 105, 62, 10, 60, 0, 1, 71, 62, 60, 1, 1, 100, 62, 10, 60, 0, 1, 75, 62, + 60, 1, 1, 96, 62, 10, 60, 0, 1, 79, 62, 60, 1, 1, 91, 62, 10, 60, 0, 1, 83, 62, 60, 1, 1, 86, 62, 10, 60, 0, 1, 87, 62, 60, 1, 1, 81, 62, 10, 60, 0, 1, 91, 62, 60, 1, 1, 77, 62, 10, + 60, 0, 1, 95, 62, 60, 1, 1, 72, 62, 10, 60, 0, 1, 100, 62, 60, 1, 1, 68, 62, 10, 60, 0, 1, 104, 62, 60, 1, 1, 63, 62, 10, 60, 0, 1, 108, 62, 60, 1, 1, 59, 62, 10, 60, 0, 1, 113, 62, 60, + 1, 1, 56, 62, 10, 60, 0, 1, 118, 62, 60, 1, 1, 53, 62, 10, 60, 0, 1, 124, 62, 60, 1, 1, 52, 62, 10, 60, 0, 1, 130, 62, 60, 1, 1, 51, 62, 10, 60, 0, 1, 136, 62, 60, 1, 1, 50, 62, 10, 60, + 0, 1, 142, 62, 60, 1, 1, 50, 62, 10, 60, 0, 1, 148, 62, 60, 1, 1, 50, 62, 10, 60, 0, 1, 154, 62, 60, 1, 1, 51, 62, 10, 60, 0, 1, 159, 62, 60, 1, 1, 52, 62, 10, 60, 0, 1, 164, 62, 60, 1, + 1, 53, 62, 10, 60, 0, 1, 169, 62, 60, 1, 1, 54, 62, 10, 60, 0, 1, 173, 62, 60, 1, 1, 55, 62, 10, 60, 0, 1, 176, 62, 60, 1, 1, 56, 62, 10, 60, 0, 1, 179, 62, 60, 1, 1, 57, 62, 10, 60, 0, + 1, 180, 62, 60, 1, 1, 57, 62, 10, 60, 0, 1, 181, 62, 60, 1, 1, 57, 62, 10, 60, 0, 1, 181, 62, 60, 1, 1, 57, 62, 10, 60, 0, 1, 180, 62, 60, 1, 1, 58, 62, 10, 60, 0, 1, 179, 62, 60, 1, 1, + 59, 62, 10, 60, 0, 1, 178, 62, 60, 1, 1, 60, 62, 10, 60, 0, 1, 176, 62, 60, 1, 1, 62, 62, 10, 60, 0, 1, 174, 62, 60, 1, 1, 64, 62, 10, 60, 0, 1, 172, 62, 60, 1, 1, 66, 62, 10, 60, 0, 1, + 170, 62, 60, 1, 1, 68, 62, 10, 60, 0, 1, 167, 62, 60, 1, 1, 71, 62, 10, 60, 0, 1, 165, 62, 60, 1, 1, 73, 62, 10, 60, 0, 1, 162, 62, 60, 1, 1, 76, 62, 10, 60, 0, 1, 159, 62, 60, 1, 1, 79, + 62, 10, 60, 0, 1, 156, 62, 60, 1, 1, 82, 62, 10, 60, 0, 1, 153, 62, 60, 1, 1, 85, 62, 10, 60, 0, 1, 150, 62, 60, 1, 1, 88, 62, 10, 60, 0, 1, 147, 62, 60, 1, 1, 91, 62, 10, 60, 0, 1, 144, + 62, 60, 1, 1, 94, 62, 10, 60, 0, 1, 141, 62, 60, 1, 1, 97, 62, 10, 60, 0, 1, 138, 62, 60, 1, 1, 100, 62, 10, 60, 0, 1, 135, 62, 60, 1, 1, 103, 62, 10, 60, 0, 1, 132, 62, 60, 1, 1, 106, 62, + 10, 60, 0, 1, 130, 62, 60, 1, 1, 108, 62, 10, 60, 0, 1, 128, 62, 60, 1, 1, 110, 62, 10, 60, 0, 1, 125, 62, 60, 1, 1, 113, 62, 10, 60, 0, 1, 124, 62, 60, 1, 1, 114, 62, 10, 60, 0, 1, 122, 62, + 60, 1, 1, 116, 62, 10, 60, 0, 1, 121, 62, 60, 1, 1, 117, 62, 10, 60, 0, 1, 120, 62, 60, 1, 1, 118, 62, 10, 60, 0, 1, 119, 62, 60, 1, 1, 119, 62, 10, 60, 0, 1, 119, 62, 60, 1, 1, 119, 62, 10, }; diff --git a/examples/MultiplePCA9685/MultiplePCA9685.ino b/examples/MultiplePCA9685/MultiplePCA9685.ino index 3b4cb18..679bcd8 100644 --- a/examples/MultiplePCA9685/MultiplePCA9685.ino +++ b/examples/MultiplePCA9685/MultiplePCA9685.ino @@ -18,25 +18,22 @@ Adafruit_PWMServoDriver pwmA(0x40); Adafruit_PWMServoDriver pwmB(0x41); // Animation object to represent the original Blender animation -Animation animation(FPS, FRAMES); +Animation animation; // We use a struct to map a servo to a PCA9685 board and channel -struct servoMap { - Servo servo; +struct servoMapping { + byte id; Adafruit_PWMServoDriver pwm; byte channel; }; -// Forward declare the callback as it will be referenced in the following array -void setPWM(byte servoID, int position); - // Define an array of servo mapsf -servoMap servoMaps[] = { - // Servo attached to board A on channel 0 - {Servo(0, NeckLeft, setPWM), pwmA, 0}, +servoMapping servoMappings[] = { + // Servo 0 attached to board A on channel 0 + {0, pwmA, 0}, - // Servo attached to board B on channel 0 - {Servo(1, NeckRight, setPWM), pwmB, 0}, + // Servo 1 attached to board B on channel 0 + {1, pwmB, 0}, }; // Calculate the amount of servos so that we can easily extend the array @@ -47,25 +44,26 @@ void setPWM(byte servoID, int position) { // Iterate through the available servos for (int i = 0; i < servoAmount; i++) { // Check if the current servo ID matches the target servo ID - if (servoMaps[i].servo.getID() == servoID) { + if (servoMappings[i].id == servoID) { // Get the PWM driver instance and channel from the mapping - Adafruit_PWMServoDriver pwm = servoMaps[i].pwm; - byte channel = servoMaps[i].channel; + Adafruit_PWMServoDriver pwm = servoMappings[i].pwm; + byte channel = servoMappings[i].channel; // Set the current position as PWM output pwm.setPWM(channel, 0, position); - // Break the loop as we already handled the servo movement + // Break the for loop as we already handled the servo movement break; } } } void setup() { - // Dynamically add the Blender servo objects to the animation - for (int i = 0; i < servoAmount; i++) { - animation.addServo(servoMaps[i].servo); - } + // Set the position callback + animation.onPositionChange(setPWM); + + // Add a scene based on PROGMEM data + animation.addScene(ANIMATION_DATA, LENGTH, FPS, FRAMES); // Trigger the animation loop mode animation.loop(); diff --git a/examples/MultiplePCA9685/ik.h b/examples/MultiplePCA9685/ik.h index a872655..3c3c0d3 100644 --- a/examples/MultiplePCA9685/ik.h +++ b/examples/MultiplePCA9685/ik.h @@ -14,15 +14,29 @@ const byte FPS = 30; const int FRAMES = 100; +const int LENGTH = 1100; -// Servo ID: 0 -const int NeckLeft[FRAMES] PROGMEM = { - 375, 376, 377, 380, 384, 387, 391, 396, 400, 403, 406, 408, 410, 410, 409, 406, 402, 396, 390, 382, 373, 364, 355, 346, 338, 330, 323, 318, 314, 311, 309, 307, 305, 305, 305, 305, 306, 307, 309, 311, 314, 317, 320, 323, 327, 331, 335, 339, 343, 347, - 351, 356, 360, 364, 369, 374, 380, 386, 392, 398, 404, 410, 415, 420, 425, 429, 432, 435, 436, 437, 437, 436, 435, 434, 432, 430, 428, 426, 423, 421, 418, 415, 412, 409, 406, 403, 400, 397, 394, 391, 388, 386, 384, 381, 380, 378, 377, 376, 375, 375, -}; - -// Servo ID: 1 -const int NeckRight[FRAMES] PROGMEM = { - 375, 376, 379, 383, 388, 394, 401, 409, 417, 426, 434, 443, 450, 457, 463, 468, 471, 472, 471, 469, 466, 462, 457, 452, 447, 441, 437, 432, 428, 424, 420, 416, 411, 407, 402, 398, 394, 389, 384, 380, 375, 370, 366, 361, 356, 352, 347, 342, 337, 333, - 328, 324, 319, 315, 312, 309, 308, 307, 306, 306, 306, 307, 308, 309, 310, 311, 312, 313, 313, 313, 313, 314, 315, 316, 318, 320, 322, 324, 327, 329, 332, 335, 338, 341, 344, 347, 350, 353, 356, 359, 362, 364, 366, 369, 370, 372, 373, 374, 375, 375, +const byte PROGMEM ANIMATION_DATA[LENGTH] = { + 60, 0, 1, 119, 62, 60, 1, 1, 119, 62, 10, 60, 0, 1, 120, 62, 60, 1, 1, 120, 62, 10, 60, 0, 1, 121, 62, 60, 1, 1, 123, 62, 10, 60, 0, 1, 124, 62, 60, 1, 1, 127, 62, 10, 60, 0, 1, 128, 62, 60, + 1, 1, 132, 62, 10, 60, 0, 1, 131, 62, 60, 1, 1, 138, 62, 10, 60, 0, 1, 135, 62, 60, 1, 1, 145, 62, 10, 60, 0, 1, 140, 62, 60, 1, 1, 153, 62, 10, 60, 0, 1, 144, 62, 60, 1, 1, 161, 62, 10, 60, + 0, 1, 147, 62, 60, 1, 1, 170, 62, 10, 60, 0, 1, 150, 62, 60, 1, 1, 178, 62, 10, 60, 0, 1, 152, 62, 60, 1, 1, 187, 62, 10, 60, 0, 1, 154, 62, 60, 1, 1, 194, 62, 10, 60, 0, 1, 154, 62, 60, 1, + 1, 201, 62, 10, 60, 0, 1, 153, 62, 60, 1, 1, 207, 62, 10, 60, 0, 1, 150, 62, 60, 1, 1, 212, 62, 10, 60, 0, 1, 146, 62, 60, 1, 1, 215, 62, 10, 60, 0, 1, 140, 62, 60, 1, 1, 216, 62, 10, 60, 0, + 1, 134, 62, 60, 1, 1, 215, 62, 10, 60, 0, 1, 126, 62, 60, 1, 1, 213, 62, 10, 60, 0, 1, 117, 62, 60, 1, 1, 210, 62, 10, 60, 0, 1, 108, 62, 60, 1, 1, 206, 62, 10, 60, 0, 1, 99, 62, 60, 1, 1, + 201, 62, 10, 60, 0, 1, 90, 62, 60, 1, 1, 196, 62, 10, 60, 0, 1, 82, 62, 60, 1, 1, 191, 62, 10, 60, 0, 1, 74, 62, 60, 1, 1, 185, 62, 10, 60, 0, 1, 67, 62, 60, 1, 1, 181, 62, 10, 60, 0, 1, + 62, 62, 60, 1, 1, 176, 62, 10, 60, 0, 1, 58, 62, 60, 1, 1, 172, 62, 10, 60, 0, 1, 55, 62, 60, 1, 1, 168, 62, 10, 60, 0, 1, 53, 62, 60, 1, 1, 164, 62, 10, 60, 0, 1, 51, 62, 60, 1, 1, 160, + 62, 10, 60, 0, 1, 49, 62, 60, 1, 1, 155, 62, 10, 60, 0, 1, 49, 62, 60, 1, 1, 151, 62, 10, 60, 0, 1, 49, 62, 60, 1, 1, 146, 62, 10, 60, 0, 1, 49, 62, 60, 1, 1, 142, 62, 10, 60, 0, 1, 50, + 62, 60, 1, 1, 138, 62, 10, 60, 0, 1, 51, 62, 60, 1, 1, 133, 62, 10, 60, 0, 1, 53, 62, 60, 1, 1, 128, 62, 10, 60, 0, 1, 55, 62, 60, 1, 1, 124, 62, 10, 60, 0, 1, 58, 62, 60, 1, 1, 119, 62, + 10, 60, 0, 1, 61, 62, 60, 1, 1, 114, 62, 10, 60, 0, 1, 64, 62, 60, 1, 1, 110, 62, 10, 60, 0, 1, 67, 62, 60, 1, 1, 105, 62, 10, 60, 0, 1, 71, 62, 60, 1, 1, 100, 62, 10, 60, 0, 1, 75, 62, + 60, 1, 1, 96, 62, 10, 60, 0, 1, 79, 62, 60, 1, 1, 91, 62, 10, 60, 0, 1, 83, 62, 60, 1, 1, 86, 62, 10, 60, 0, 1, 87, 62, 60, 1, 1, 81, 62, 10, 60, 0, 1, 91, 62, 60, 1, 1, 77, 62, 10, + 60, 0, 1, 95, 62, 60, 1, 1, 72, 62, 10, 60, 0, 1, 100, 62, 60, 1, 1, 68, 62, 10, 60, 0, 1, 104, 62, 60, 1, 1, 63, 62, 10, 60, 0, 1, 108, 62, 60, 1, 1, 59, 62, 10, 60, 0, 1, 113, 62, 60, + 1, 1, 56, 62, 10, 60, 0, 1, 118, 62, 60, 1, 1, 53, 62, 10, 60, 0, 1, 124, 62, 60, 1, 1, 52, 62, 10, 60, 0, 1, 130, 62, 60, 1, 1, 51, 62, 10, 60, 0, 1, 136, 62, 60, 1, 1, 50, 62, 10, 60, + 0, 1, 142, 62, 60, 1, 1, 50, 62, 10, 60, 0, 1, 148, 62, 60, 1, 1, 50, 62, 10, 60, 0, 1, 154, 62, 60, 1, 1, 51, 62, 10, 60, 0, 1, 159, 62, 60, 1, 1, 52, 62, 10, 60, 0, 1, 164, 62, 60, 1, + 1, 53, 62, 10, 60, 0, 1, 169, 62, 60, 1, 1, 54, 62, 10, 60, 0, 1, 173, 62, 60, 1, 1, 55, 62, 10, 60, 0, 1, 176, 62, 60, 1, 1, 56, 62, 10, 60, 0, 1, 179, 62, 60, 1, 1, 57, 62, 10, 60, 0, + 1, 180, 62, 60, 1, 1, 57, 62, 10, 60, 0, 1, 181, 62, 60, 1, 1, 57, 62, 10, 60, 0, 1, 181, 62, 60, 1, 1, 57, 62, 10, 60, 0, 1, 180, 62, 60, 1, 1, 58, 62, 10, 60, 0, 1, 179, 62, 60, 1, 1, + 59, 62, 10, 60, 0, 1, 178, 62, 60, 1, 1, 60, 62, 10, 60, 0, 1, 176, 62, 60, 1, 1, 62, 62, 10, 60, 0, 1, 174, 62, 60, 1, 1, 64, 62, 10, 60, 0, 1, 172, 62, 60, 1, 1, 66, 62, 10, 60, 0, 1, + 170, 62, 60, 1, 1, 68, 62, 10, 60, 0, 1, 167, 62, 60, 1, 1, 71, 62, 10, 60, 0, 1, 165, 62, 60, 1, 1, 73, 62, 10, 60, 0, 1, 162, 62, 60, 1, 1, 76, 62, 10, 60, 0, 1, 159, 62, 60, 1, 1, 79, + 62, 10, 60, 0, 1, 156, 62, 60, 1, 1, 82, 62, 10, 60, 0, 1, 153, 62, 60, 1, 1, 85, 62, 10, 60, 0, 1, 150, 62, 60, 1, 1, 88, 62, 10, 60, 0, 1, 147, 62, 60, 1, 1, 91, 62, 10, 60, 0, 1, 144, + 62, 60, 1, 1, 94, 62, 10, 60, 0, 1, 141, 62, 60, 1, 1, 97, 62, 10, 60, 0, 1, 138, 62, 60, 1, 1, 100, 62, 10, 60, 0, 1, 135, 62, 60, 1, 1, 103, 62, 10, 60, 0, 1, 132, 62, 60, 1, 1, 106, 62, + 10, 60, 0, 1, 130, 62, 60, 1, 1, 108, 62, 10, 60, 0, 1, 128, 62, 60, 1, 1, 110, 62, 10, 60, 0, 1, 125, 62, 60, 1, 1, 113, 62, 10, 60, 0, 1, 124, 62, 60, 1, 1, 114, 62, 10, 60, 0, 1, 122, 62, + 60, 1, 1, 116, 62, 10, 60, 0, 1, 121, 62, 60, 1, 1, 117, 62, 10, 60, 0, 1, 120, 62, 60, 1, 1, 118, 62, 10, 60, 0, 1, 119, 62, 60, 1, 1, 119, 62, 10, 60, 0, 1, 119, 62, 60, 1, 1, 119, 62, 10, }; diff --git a/examples/MultipleScenes/MultipleScenes.ino b/examples/MultipleScenes/MultipleScenes.ino new file mode 100644 index 0000000..3db7b51 --- /dev/null +++ b/examples/MultipleScenes/MultipleScenes.ino @@ -0,0 +1,54 @@ +/* + Setting up a show consisting of 2 animations. + + Note the namespaces which are used to distinguish the positions + of one scene / animation from another. It's even possible to + have different playback rates (fps) and frames per animation. +*/ + +#include "scene-a.h" +#include "scene-b.h" +#include + +#ifdef ARDUINO_ARCH_ESP32 +#include +#else +#include +#endif + +// Servo object to send positions +Servo myServo; + +// Callback function which is called whenever a servo needs to be moved +void move(byte servoID, int position) { + // Ignore the servoID (there is only one servo) and write the current position + myServo.writeMicroseconds(position); +} + +// Animation object to represent the original Blender animation +BlenderServoAnimation::Animation animation; + +void setup() { + // Attach the servo to pin 12 + myServo.attach(12); + + // Set the position callback + animation.onPositionChange(move); + + // Add multiple scenes based on PROGMEM data + animation.addScene(SceneA::ANIMATION_DATA, SceneA::LENGTH, SceneA::FPS, SceneA::FRAMES); + animation.addScene(SceneB::ANIMATION_DATA, SceneB::LENGTH, SceneB::FPS, SceneB::FRAMES); + + // Trigger the show loop mode + animation.loop(); + + // There are also other playback options + // show.play(); // Plays all scenes once in the order they have been added + // show.playRandom(); // Randomly plays scenes in a loop + // show.playSingle(1); // Play the scene at the given index once +} + +void loop() { + // Update the animation state on each loop + animation.run(); +} diff --git a/examples/Show/README.md b/examples/MultipleScenes/README.md similarity index 100% rename from examples/Show/README.md rename to examples/MultipleScenes/README.md diff --git a/examples/Show/platformio.ini b/examples/MultipleScenes/platformio.ini similarity index 100% rename from examples/Show/platformio.ini rename to examples/MultipleScenes/platformio.ini diff --git a/examples/MultipleScenes/scene-a.h b/examples/MultipleScenes/scene-a.h new file mode 100644 index 0000000..38dbece --- /dev/null +++ b/examples/MultipleScenes/scene-a.h @@ -0,0 +1,36 @@ +/* + Blender Servo Animation Positions + + FPS: 30 + Frames: 100 + Seconds: 3 + Bones: 1 + Armature: Armature + Scene: SceneA + File: scenes.blend +*/ + +#include + +namespace SceneA { + +const byte FPS = 30; +const int FRAMES = 100; +const int LENGTH = 600; + +const byte PROGMEM ANIMATION_DATA[LENGTH] = { + 60, 0, 5, 192, 62, 10, 60, 0, 5, 193, 62, 10, 60, 0, 5, 197, 62, 10, 60, 0, 5, 203, 62, 10, 60, 0, 5, 212, 62, 10, 60, 0, 5, 222, 62, 10, 60, 0, 5, 235, 62, 10, 60, 0, 5, 249, 62, 10, 60, 0, + 6, 8, 62, 10, 60, 0, 6, 26, 62, 10, 60, 0, 6, 44, 62, 10, 60, 0, 6, 63, 62, 10, 60, 0, 6, 83, 62, 10, 60, 0, 6, 104, 62, 10, 60, 0, 6, 125, 62, 10, 60, 0, 6, 146, 62, 10, 60, 0, 6, 168, + 62, 10, 60, 0, 6, 190, 62, 10, 60, 0, 6, 211, 62, 10, 60, 0, 6, 232, 62, 10, 60, 0, 6, 253, 62, 10, 60, 0, 7, 17, 62, 10, 60, 0, 7, 36, 62, 10, 60, 0, 7, 54, 62, 10, 60, 0, 7, 72, 62, 10, + 60, 0, 7, 87, 62, 10, 60, 0, 7, 101, 62, 10, 60, 0, 7, 114, 62, 10, 60, 0, 7, 124, 62, 10, 60, 0, 7, 133, 62, 10, 60, 0, 7, 139, 62, 10, 60, 0, 7, 143, 62, 10, 60, 0, 7, 144, 62, 10, 60, 0, + 7, 142, 62, 10, 60, 0, 7, 134, 62, 10, 60, 0, 7, 122, 62, 10, 60, 0, 7, 106, 62, 10, 60, 0, 7, 87, 62, 10, 60, 0, 7, 63, 62, 10, 60, 0, 7, 36, 62, 10, 60, 0, 7, 7, 62, 10, 60, 0, 6, 231, + 62, 10, 60, 0, 6, 196, 62, 10, 60, 0, 6, 159, 62, 10, 60, 0, 6, 121, 62, 10, 60, 0, 6, 81, 62, 10, 60, 0, 6, 41, 62, 10, 60, 0, 5, 255, 62, 10, 60, 0, 5, 213, 62, 10, 60, 0, 5, 171, 62, 10, + 60, 0, 5, 129, 62, 10, 60, 0, 5, 87, 62, 10, 60, 0, 5, 47, 62, 10, 60, 0, 5, 7, 62, 10, 60, 0, 4, 225, 62, 10, 60, 0, 4, 188, 62, 10, 60, 0, 4, 153, 62, 10, 60, 0, 4, 121, 62, 10, 60, 0, + 4, 92, 62, 10, 60, 0, 4, 65, 62, 10, 60, 0, 4, 41, 62, 10, 60, 0, 4, 22, 62, 10, 60, 0, 4, 6, 62, 10, 60, 0, 3, 250, 62, 10, 60, 0, 3, 242, 62, 10, 60, 0, 3, 240, 62, 10, 60, 0, 3, 241, + 62, 10, 60, 0, 3, 245, 62, 10, 60, 0, 3, 250, 62, 10, 60, 0, 4, 2, 62, 10, 60, 0, 4, 11, 62, 10, 60, 0, 4, 22, 62, 10, 60, 0, 4, 35, 62, 10, 60, 0, 4, 49, 62, 10, 60, 0, 4, 64, 62, 10, + 60, 0, 4, 81, 62, 10, 60, 0, 4, 98, 62, 10, 60, 0, 4, 117, 62, 10, 60, 0, 4, 136, 62, 10, 60, 0, 4, 155, 62, 10, 60, 0, 4, 175, 62, 10, 60, 0, 4, 196, 62, 10, 60, 0, 4, 216, 62, 10, 60, 0, + 4, 236, 62, 10, 60, 0, 5, 1, 62, 10, 60, 0, 5, 21, 62, 10, 60, 0, 5, 40, 62, 10, 60, 0, 5, 59, 62, 10, 60, 0, 5, 78, 62, 10, 60, 0, 5, 95, 62, 10, 60, 0, 5, 112, 62, 10, 60, 0, 5, 127, + 62, 10, 60, 0, 5, 141, 62, 10, 60, 0, 5, 154, 62, 10, 60, 0, 5, 165, 62, 10, 60, 0, 5, 174, 62, 10, 60, 0, 5, 182, 62, 10, 60, 0, 5, 187, 62, 10, 60, 0, 5, 191, 62, 10, 60, 0, 5, 192, 62, 10, +}; + +} // namespace SceneA diff --git a/examples/MultipleScenes/scene-b.h b/examples/MultipleScenes/scene-b.h new file mode 100644 index 0000000..325c7bb --- /dev/null +++ b/examples/MultipleScenes/scene-b.h @@ -0,0 +1,48 @@ +/* + Blender Servo Animation Positions + + FPS: 60 + Frames: 200 + Seconds: 3 + Bones: 1 + Armature: Armature.001 + Scene: SceneB + File: scenes.blend +*/ + +#include + +namespace SceneB { + +const byte FPS = 60; +const int FRAMES = 200; +const int LENGTH = 1200; + +const byte PROGMEM ANIMATION_DATA[LENGTH] = { + 60, 0, 5, 192, 62, 10, 60, 0, 5, 192, 62, 10, 60, 0, 5, 193, 62, 10, 60, 0, 5, 193, 62, 10, 60, 0, 5, 194, 62, 10, 60, 0, 5, 195, 62, 10, 60, 0, 5, 197, 62, 10, 60, 0, 5, 199, 62, 10, 60, 0, + 5, 201, 62, 10, 60, 0, 5, 203, 62, 10, 60, 0, 5, 205, 62, 10, 60, 0, 5, 208, 62, 10, 60, 0, 5, 211, 62, 10, 60, 0, 5, 214, 62, 10, 60, 0, 5, 217, 62, 10, 60, 0, 5, 221, 62, 10, 60, 0, 5, 224, + 62, 10, 60, 0, 5, 228, 62, 10, 60, 0, 5, 232, 62, 10, 60, 0, 5, 237, 62, 10, 60, 0, 5, 241, 62, 10, 60, 0, 5, 246, 62, 10, 60, 0, 5, 251, 62, 10, 60, 0, 6, 0, 62, 10, 60, 0, 6, 5, 62, 10, + 60, 0, 6, 10, 62, 10, 60, 0, 6, 15, 62, 10, 60, 0, 6, 21, 62, 10, 60, 0, 6, 26, 62, 10, 60, 0, 6, 32, 62, 10, 60, 0, 6, 38, 62, 10, 60, 0, 6, 44, 62, 10, 60, 0, 6, 50, 62, 10, 60, 0, + 6, 56, 62, 10, 60, 0, 6, 63, 62, 10, 60, 0, 6, 69, 62, 10, 60, 0, 6, 75, 62, 10, 60, 0, 6, 82, 62, 10, 60, 0, 6, 89, 62, 10, 60, 0, 6, 95, 62, 10, 60, 0, 6, 102, 62, 10, 60, 0, 6, 109, + 62, 10, 60, 0, 6, 116, 62, 10, 60, 0, 6, 123, 62, 10, 60, 0, 6, 130, 62, 10, 60, 0, 6, 136, 62, 10, 60, 0, 6, 143, 62, 10, 60, 0, 6, 150, 62, 10, 60, 0, 6, 157, 62, 10, 60, 0, 6, 164, 62, 10, + 60, 0, 6, 172, 62, 10, 60, 0, 6, 179, 62, 10, 60, 0, 6, 186, 62, 10, 60, 0, 6, 193, 62, 10, 60, 0, 6, 200, 62, 10, 60, 0, 6, 206, 62, 10, 60, 0, 6, 213, 62, 10, 60, 0, 6, 220, 62, 10, 60, 0, + 6, 227, 62, 10, 60, 0, 6, 234, 62, 10, 60, 0, 6, 241, 62, 10, 60, 0, 6, 247, 62, 10, 60, 0, 6, 254, 62, 10, 60, 0, 7, 5, 62, 10, 60, 0, 7, 11, 62, 10, 60, 0, 7, 17, 62, 10, 60, 0, 7, 24, + 62, 10, 60, 0, 7, 30, 62, 10, 60, 0, 7, 36, 62, 10, 60, 0, 7, 42, 62, 10, 60, 0, 7, 48, 62, 10, 60, 0, 7, 54, 62, 10, 60, 0, 7, 59, 62, 10, 60, 0, 7, 65, 62, 10, 60, 0, 7, 70, 62, 10, + 60, 0, 7, 75, 62, 10, 60, 0, 7, 80, 62, 10, 60, 0, 7, 85, 62, 10, 60, 0, 7, 90, 62, 10, 60, 0, 7, 95, 62, 10, 60, 0, 7, 99, 62, 10, 60, 0, 7, 104, 62, 10, 60, 0, 7, 108, 62, 10, 60, 0, + 7, 112, 62, 10, 60, 0, 7, 115, 62, 10, 60, 0, 7, 119, 62, 10, 60, 0, 7, 122, 62, 10, 60, 0, 7, 125, 62, 10, 60, 0, 7, 128, 62, 10, 60, 0, 7, 131, 62, 10, 60, 0, 7, 133, 62, 10, 60, 0, 7, 135, + 62, 10, 60, 0, 7, 137, 62, 10, 60, 0, 7, 139, 62, 10, 60, 0, 7, 141, 62, 10, 60, 0, 7, 142, 62, 10, 60, 0, 7, 143, 62, 10, 60, 0, 7, 143, 62, 10, 60, 0, 7, 144, 62, 10, 60, 0, 7, 144, 62, 10, + 60, 0, 7, 144, 62, 10, 60, 0, 7, 143, 62, 10, 60, 0, 7, 143, 62, 10, 60, 0, 7, 142, 62, 10, 60, 0, 7, 141, 62, 10, 60, 0, 7, 139, 62, 10, 60, 0, 7, 138, 62, 10, 60, 0, 7, 136, 62, 10, 60, 0, + 7, 133, 62, 10, 60, 0, 7, 131, 62, 10, 60, 0, 7, 128, 62, 10, 60, 0, 7, 126, 62, 10, 60, 0, 7, 123, 62, 10, 60, 0, 7, 119, 62, 10, 60, 0, 7, 116, 62, 10, 60, 0, 7, 112, 62, 10, 60, 0, 7, 108, + 62, 10, 60, 0, 7, 104, 62, 10, 60, 0, 7, 100, 62, 10, 60, 0, 7, 96, 62, 10, 60, 0, 7, 91, 62, 10, 60, 0, 7, 86, 62, 10, 60, 0, 7, 82, 62, 10, 60, 0, 7, 77, 62, 10, 60, 0, 7, 72, 62, 10, + 60, 0, 7, 66, 62, 10, 60, 0, 7, 61, 62, 10, 60, 0, 7, 55, 62, 10, 60, 0, 7, 50, 62, 10, 60, 0, 7, 44, 62, 10, 60, 0, 7, 38, 62, 10, 60, 0, 7, 32, 62, 10, 60, 0, 7, 26, 62, 10, 60, 0, + 7, 20, 62, 10, 60, 0, 7, 13, 62, 10, 60, 0, 7, 7, 62, 10, 60, 0, 7, 0, 62, 10, 60, 0, 6, 250, 62, 10, 60, 0, 6, 243, 62, 10, 60, 0, 6, 237, 62, 10, 60, 0, 6, 230, 62, 10, 60, 0, 6, 223, + 62, 10, 60, 0, 6, 216, 62, 10, 60, 0, 6, 210, 62, 10, 60, 0, 6, 203, 62, 10, 60, 0, 6, 196, 62, 10, 60, 0, 6, 189, 62, 10, 60, 0, 6, 182, 62, 10, 60, 0, 6, 175, 62, 10, 60, 0, 6, 168, 62, 10, + 60, 0, 6, 161, 62, 10, 60, 0, 6, 154, 62, 10, 60, 0, 6, 147, 62, 10, 60, 0, 6, 140, 62, 10, 60, 0, 6, 133, 62, 10, 60, 0, 6, 126, 62, 10, 60, 0, 6, 120, 62, 10, 60, 0, 6, 113, 62, 10, 60, 0, + 6, 106, 62, 10, 60, 0, 6, 99, 62, 10, 60, 0, 6, 93, 62, 10, 60, 0, 6, 86, 62, 10, 60, 0, 6, 80, 62, 10, 60, 0, 6, 73, 62, 10, 60, 0, 6, 67, 62, 10, 60, 0, 6, 60, 62, 10, 60, 0, 6, 54, + 62, 10, 60, 0, 6, 48, 62, 10, 60, 0, 6, 42, 62, 10, 60, 0, 6, 36, 62, 10, 60, 0, 6, 30, 62, 10, 60, 0, 6, 25, 62, 10, 60, 0, 6, 19, 62, 10, 60, 0, 6, 14, 62, 10, 60, 0, 6, 8, 62, 10, + 60, 0, 6, 3, 62, 10, 60, 0, 5, 254, 62, 10, 60, 0, 5, 250, 62, 10, 60, 0, 5, 245, 62, 10, 60, 0, 5, 240, 62, 10, 60, 0, 5, 236, 62, 10, 60, 0, 5, 232, 62, 10, 60, 0, 5, 228, 62, 10, 60, 0, + 5, 224, 62, 10, 60, 0, 5, 220, 62, 10, 60, 0, 5, 217, 62, 10, 60, 0, 5, 213, 62, 10, 60, 0, 5, 210, 62, 10, 60, 0, 5, 208, 62, 10, 60, 0, 5, 205, 62, 10, 60, 0, 5, 203, 62, 10, 60, 0, 5, 200, + 62, 10, 60, 0, 5, 198, 62, 10, 60, 0, 5, 197, 62, 10, 60, 0, 5, 195, 62, 10, 60, 0, 5, 194, 62, 10, 60, 0, 5, 193, 62, 10, 60, 0, 5, 193, 62, 10, 60, 0, 5, 192, 62, 10, 60, 0, 5, 192, 62, 10, +}; + +} // namespace SceneB diff --git a/examples/MultipleScenesSD/MultipleScenesSD.ino b/examples/MultipleScenesSD/MultipleScenesSD.ino new file mode 100644 index 0000000..15c1851 --- /dev/null +++ b/examples/MultipleScenesSD/MultipleScenesSD.ino @@ -0,0 +1,66 @@ +/* + Setting up a show consisting of 2 animations. + + Note the namespaces which are used to distinguish the positions + of one scene / animation from another. It's even possible to + have different playback rates (fps) and frames per animation. +*/ + +#include +#include + +#ifdef ARDUINO_ARCH_ESP32 +#include +#else +#include +#endif + +// Servo object to send positions +Servo myServo; + +File animationFile; + +// Callback function which is called whenever a servo needs to be moved +void move(byte servoID, int position) { + // Ignore the servoID (there is only one servo) and write the current position + myServo.writeMicroseconds(position); +} + +void changeFile(byte prevSceneIndex, byte nextSceneIndex) { + String filename = "test"; + animationFile.close(); + animationFile = SD.open(filename, FILE_READ); +} + +// Animation object to represent the original Blender animation +BlenderServoAnimation::Animation animation; + +void setup() { + SD.begin(4); + + // Attach the servo to pin 12 + myServo.attach(12); + + // Set the position callback + animation.onPositionChange(move); + + // Set the scene callback + animation.onSceneChange(changeFile); + + // Add multiple scenes with the same File stream + animation.addScene(animationFile, 30, 100); + animation.addScene(animationFile, 60, 200); + + // Trigger the show loop mode + animation.loop(); + + // There are also other playback options + // show.play(); // Plays all scenes once in the order they have been added + // show.playRandom(); // Randomly plays scenes in a loop + // show.playSingle(1); // Play the scene at the given index once +} + +void loop() { + // Update the animation state on each loop + animation.run(); +} diff --git a/examples/MultipleScenesSD/README.md b/examples/MultipleScenesSD/README.md new file mode 100644 index 0000000..2619f9f --- /dev/null +++ b/examples/MultipleScenesSD/README.md @@ -0,0 +1,7 @@ +# Show + +Setting up a show consisting of 2 animations. + +By default, the 2 animations will be played synchronously in a loop. + +![Arduino Nano with servo](../../images/arduino-nano-with-servo.png) diff --git a/examples/MultipleScenesSD/platformio.ini b/examples/MultipleScenesSD/platformio.ini new file mode 100644 index 0000000..daaafbc --- /dev/null +++ b/examples/MultipleScenesSD/platformio.ini @@ -0,0 +1,31 @@ +[platformio] +src_dir = ./ + +[env] +framework = arduino + +[atmelavr_base] +platform = atmelavr +lib_deps = + arduino-libraries/Servo@^1.1.8 + arduino-libraries/SD@^1.2.4 + BlenderServoAnimation=symlink://../../ + +[env:uno] +extends = atmelavr_base +board = uno + +[env:ATmega2560] +extends = atmelavr_base +board = ATmega2560 + +[env:nanoatmega328] +extends = atmelavr_base +board = nanoatmega328 + +[env:esp32dev] +platform = espressif32 +board = esp32dev +lib_deps = + madhephaestus/ESP32Servo@^0.13.0 + BlenderServoAnimation=symlink://../../ diff --git a/examples/SDAnimation/README.md b/examples/SDAnimation/README.md new file mode 100644 index 0000000..bb47cc7 --- /dev/null +++ b/examples/SDAnimation/README.md @@ -0,0 +1,7 @@ +# Standard Servo Library + +Using the standard Arduino servo library to send servo positions. + +The setup requires nothing but a micro controller and a single servo. + +![Arduino Nano with servo](../../images/arduino-nano-with-servo.png) diff --git a/examples/SDAnimation/SDAnimation.ino b/examples/SDAnimation/SDAnimation.ino new file mode 100644 index 0000000..66408b7 --- /dev/null +++ b/examples/SDAnimation/SDAnimation.ino @@ -0,0 +1,50 @@ +/* + Using the standard Arduino servo library to send servo positions. + + Note the namespace BlenderServoAnimation which helps to distinguish + between the standard library servo class (Servo) and the servo + class of this library (BlenderServoAnimation::Servo). +*/ + +#include +#include + +#ifdef ARDUINO_ARCH_ESP32 +#include +#else +#include +#endif + +// Servo object to send positions +Servo myServo; + +// Callback function which is called whenever a servo needs to be moved +void move(byte servoID, int position) { + // Ignore the servoID (there is only one servo) and write the current position + myServo.writeMicroseconds(position); +} + +// Animation object to represent the original Blender animation +BlenderServoAnimation::Animation animation; + +void setup() { + SD.begin(4); + File myFile = SD.open("test.txt", FILE_READ); + + // Attach the servo to pin 12 + myServo.attach(12); + + // Set the position callback + animation.onPositionChange(move); + + // Add a scene with the File stream + animation.addScene(myFile, 30, 100); + + // Trigger the animation loop mode + animation.loop(); +} + +void loop() { + // Update the animation state on each loop + animation.run(); +} diff --git a/examples/SDAnimation/platformio.ini b/examples/SDAnimation/platformio.ini new file mode 100644 index 0000000..daaafbc --- /dev/null +++ b/examples/SDAnimation/platformio.ini @@ -0,0 +1,31 @@ +[platformio] +src_dir = ./ + +[env] +framework = arduino + +[atmelavr_base] +platform = atmelavr +lib_deps = + arduino-libraries/Servo@^1.1.8 + arduino-libraries/SD@^1.2.4 + BlenderServoAnimation=symlink://../../ + +[env:uno] +extends = atmelavr_base +board = uno + +[env:ATmega2560] +extends = atmelavr_base +board = ATmega2560 + +[env:nanoatmega328] +extends = atmelavr_base +board = nanoatmega328 + +[env:esp32dev] +platform = espressif32 +board = esp32dev +lib_deps = + madhephaestus/ESP32Servo@^0.13.0 + BlenderServoAnimation=symlink://../../ diff --git a/examples/SerialLiveMode/SerialLiveMode.ino b/examples/SerialLiveMode/SerialLiveMode.ino index 0c30629..972240d 100644 --- a/examples/SerialLiveMode/SerialLiveMode.ino +++ b/examples/SerialLiveMode/SerialLiveMode.ino @@ -23,24 +23,23 @@ void move(byte servoID, int position) { myServo.writeMicroseconds(position); } -// Animation object to manage the servos -// We skip providing fps or frames as we just want to use the live mode +// Animation object to represent the original Blender animation BlenderServoAnimation::Animation animation; -// Servo object to manage the positions -BlenderServoAnimation::Servo myBlenderServo(0, move); - void setup() { Serial.begin(115200); // Attach the servo to pin 12 myServo.attach(12); - // Add the Blender servo object to the animation - animation.addServo(myBlenderServo); + // Set the position callback + animation.onPositionChange(move); + + // Add a new scene with the Serial stream - we can omit fps and frames + animation.addScene(Serial); - // Trigger the animation live mode - animation.live(Serial); + // Trigger the animation play mode + animation.play(); } void loop() { diff --git a/examples/Show/Show.ino b/examples/Show/Show.ino deleted file mode 100644 index 5725a63..0000000 --- a/examples/Show/Show.ino +++ /dev/null @@ -1,68 +0,0 @@ -/* - Setting up a show consisting of 2 animations. - - Note the namespaces which are used to distinguish the positions - of one scene / animation from another. It's even possible to - have different playback rates (fps) and frames per animation. -*/ - -#include "scene-a.h" -#include "scene-b.h" -#include - -#ifdef ARDUINO_ARCH_ESP32 -#include -#else -#include -#endif - -// Servo object to send positions -Servo myServo; - -// Callback function which is called whenever a servo needs to be moved -void move(byte servoID, int position) { - // Ignore the servoID (there is only one servo) and write the current position - myServo.writeMicroseconds(position); -} - -// Show object to manage all Blender animations -BlenderServoAnimation::Show show; - -// Animation objects to represent the original Blender animations -BlenderServoAnimation::Animation animationA(SceneA::FPS, SceneA::FRAMES); -BlenderServoAnimation::Animation animationB(SceneB::FPS, SceneB::FRAMES); - -// Servo objects to manage the positions -BlenderServoAnimation::Servo myBlenderServoA(0, SceneA::Bone, move); -BlenderServoAnimation::Servo myBlenderServoB(0, SceneB::Bone, move); - -void setup() { - // Attach the servo to pin 12 - myServo.attach(12); - - // Add the Blender servo objects to the animations - animationA.addServo(myBlenderServoA); - animationB.addServo(myBlenderServoB); - - // Add the Blender animation objects to the show - show.addAnimation(animationA); - show.addAnimation(animationB); - - // Trigger the show loop mode - show.loop(); - - // There are also other playback options - // show.play(); // Plays all animations once in the order they have been added - // show.playRandom(); // Randomly plays animations in a loop - // show.playSingle(1); // Play the animation with the given ID once - - // Further controls are similar to what we can do on animation objects - // show.pause(); - // show.stop(); - // show.live(Serial); -} - -void loop() { - // Update the show state on each loop - show.run(); -} diff --git a/examples/Show/scene-a.h b/examples/Show/scene-a.h deleted file mode 100644 index 8c1e25e..0000000 --- a/examples/Show/scene-a.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - Blender Servo Animation Positions - - FPS: 30 - Frames: 100 - Seconds: 3 - Bones: 1 - Armature: Armature - Scene: SceneA - File: scenes.blend -*/ - -#include - -namespace SceneA { - -const byte FPS = 30; -const int FRAMES = 100; - -// Servo ID: 0 -const int Bone[FRAMES] PROGMEM = { - 1472, 1473, 1477, 1483, 1492, 1502, 1515, 1529, 1544, 1562, 1580, 1599, 1619, 1640, 1661, 1682, 1704, 1726, 1747, 1768, 1789, 1809, 1828, 1846, 1864, 1879, 1893, 1906, 1916, 1925, 1931, 1935, 1936, 1934, 1926, 1914, 1898, 1879, 1855, 1828, 1799, 1767, 1732, 1695, 1657, 1617, 1577, 1535, 1493, 1451, - 1409, 1367, 1327, 1287, 1249, 1212, 1177, 1145, 1116, 1089, 1065, 1046, 1030, 1018, 1010, 1008, 1009, 1013, 1018, 1026, 1035, 1046, 1059, 1073, 1088, 1105, 1122, 1141, 1160, 1179, 1199, 1220, 1240, 1260, 1281, 1301, 1320, 1339, 1358, 1375, 1392, 1407, 1421, 1434, 1445, 1454, 1462, 1467, 1471, 1472, -}; - -} // namespace SceneA diff --git a/examples/Show/scene-b.h b/examples/Show/scene-b.h deleted file mode 100644 index 9e1d07e..0000000 --- a/examples/Show/scene-b.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - Blender Servo Animation Positions - - FPS: 60 - Frames: 200 - Seconds: 3 - Bones: 1 - Armature: Armature.001 - Scene: SceneB - File: scenes.blend -*/ - -#include - -namespace SceneB { - -const byte FPS = 60; -const int FRAMES = 200; - -// Servo ID: 0 -const int Bone[FRAMES] PROGMEM = { - 1472, 1472, 1473, 1473, 1474, 1475, 1477, 1479, 1481, 1483, 1485, 1488, 1491, 1494, 1497, 1501, 1504, 1508, 1512, 1517, 1521, 1526, 1531, 1536, 1541, 1546, 1551, 1557, 1562, 1568, 1574, 1580, 1586, 1592, 1599, 1605, 1611, 1618, 1625, 1631, 1638, 1645, 1652, 1659, 1666, 1672, 1679, 1686, 1693, 1700, - 1708, 1715, 1722, 1729, 1736, 1742, 1749, 1756, 1763, 1770, 1777, 1783, 1790, 1797, 1803, 1809, 1816, 1822, 1828, 1834, 1840, 1846, 1851, 1857, 1862, 1867, 1872, 1877, 1882, 1887, 1891, 1896, 1900, 1904, 1907, 1911, 1914, 1917, 1920, 1923, 1925, 1927, 1929, 1931, 1933, 1934, 1935, 1935, 1936, 1936, - 1936, 1935, 1935, 1934, 1933, 1931, 1930, 1928, 1925, 1923, 1920, 1918, 1915, 1911, 1908, 1904, 1900, 1896, 1892, 1888, 1883, 1878, 1874, 1869, 1864, 1858, 1853, 1847, 1842, 1836, 1830, 1824, 1818, 1812, 1805, 1799, 1792, 1786, 1779, 1773, 1766, 1759, 1752, 1746, 1739, 1732, 1725, 1718, 1711, 1704, - 1697, 1690, 1683, 1676, 1669, 1662, 1656, 1649, 1642, 1635, 1629, 1622, 1616, 1609, 1603, 1596, 1590, 1584, 1578, 1572, 1566, 1561, 1555, 1550, 1544, 1539, 1534, 1530, 1525, 1520, 1516, 1512, 1508, 1504, 1500, 1497, 1493, 1490, 1488, 1485, 1483, 1480, 1478, 1477, 1475, 1474, 1473, 1473, 1472, 1472, -}; - -} // namespace SceneB diff --git a/examples/StandardServoLib/StandardServoLib.ino b/examples/StandardServoLib/StandardServoLib.ino index cad3195..70b6b82 100644 --- a/examples/StandardServoLib/StandardServoLib.ino +++ b/examples/StandardServoLib/StandardServoLib.ino @@ -25,17 +25,17 @@ void move(byte servoID, int position) { } // Animation object to represent the original Blender animation -BlenderServoAnimation::Animation animation(FPS, FRAMES); - -// Servo object to manage the positions -BlenderServoAnimation::Servo myBlenderServo(0, Bone, move); +BlenderServoAnimation::Animation animation; void setup() { // Attach the servo to pin 12 myServo.attach(12); - // Add the Blender servo object to the animation - animation.addServo(myBlenderServo); + // Set the position callback + animation.onPositionChange(move); + + // Add a scene based on PROGMEM data + animation.addScene(ANIMATION_DATA, LENGTH, FPS, FRAMES); // Trigger the animation loop mode animation.loop(); diff --git a/examples/StandardServoLib/simple.h b/examples/StandardServoLib/simple.h index 3ab17cb..23abb09 100644 --- a/examples/StandardServoLib/simple.h +++ b/examples/StandardServoLib/simple.h @@ -14,9 +14,19 @@ const byte FPS = 30; const int FRAMES = 100; +const int LENGTH = 600; -// Servo ID: 0 -const int Bone[FRAMES] PROGMEM = { - 1472, 1475, 1482, 1495, 1512, 1533, 1558, 1586, 1617, 1651, 1687, 1726, 1766, 1807, 1849, 1893, 1936, 1979, 2023, 2065, 2106, 2146, 2185, 2221, 2255, 2286, 2314, 2339, 2360, 2377, 2390, 2397, 2400, 2395, 2380, 2357, 2325, 2285, 2238, 2185, 2126, 2061, 1992, 1919, 1842, 1763, 1681, 1598, 1514, 1430, - 1346, 1263, 1181, 1102, 1025, 952, 883, 818, 759, 706, 659, 619, 587, 564, 549, 544, 546, 553, 564, 579, 598, 621, 646, 674, 705, 738, 773, 809, 847, 886, 927, 967, 1008, 1049, 1089, 1130, 1169, 1207, 1243, 1278, 1311, 1342, 1370, 1395, 1418, 1437, 1452, 1463, 1470, 1472, +const byte PROGMEM ANIMATION_DATA[LENGTH] = { + 60, 0, 5, 192, 62, 10, 60, 0, 5, 195, 62, 10, 60, 0, 5, 202, 62, 10, 60, 0, 5, 215, 62, 10, 60, 0, 5, 232, 62, 10, 60, 0, 5, 253, 62, 10, 60, 0, 6, 22, 62, 10, 60, 0, 6, 50, 62, 10, 60, 0, + 6, 81, 62, 10, 60, 0, 6, 115, 62, 10, 60, 0, 6, 151, 62, 10, 60, 0, 6, 190, 62, 10, 60, 0, 6, 230, 62, 10, 60, 0, 7, 15, 62, 10, 60, 0, 7, 57, 62, 10, 60, 0, 7, 101, 62, 10, 60, 0, 7, 144, + 62, 10, 60, 0, 7, 187, 62, 10, 60, 0, 7, 231, 62, 10, 60, 0, 8, 17, 62, 10, 60, 0, 8, 58, 62, 10, 60, 0, 8, 98, 62, 10, 60, 0, 8, 137, 62, 10, 60, 0, 8, 173, 62, 10, 60, 0, 8, 207, 62, 10, + 60, 0, 8, 238, 62, 10, 60, 0, 9, 10, 62, 10, 60, 0, 9, 35, 62, 10, 60, 0, 9, 56, 62, 10, 60, 0, 9, 73, 62, 10, 60, 0, 9, 86, 62, 10, 60, 0, 9, 93, 62, 10, 60, 0, 9, 96, 62, 10, 60, 0, + 9, 91, 62, 10, 60, 0, 9, 76, 62, 10, 60, 0, 9, 53, 62, 10, 60, 0, 9, 21, 62, 10, 60, 0, 8, 237, 62, 10, 60, 0, 8, 190, 62, 10, 60, 0, 8, 137, 62, 10, 60, 0, 8, 78, 62, 10, 60, 0, 8, 13, + 62, 10, 60, 0, 7, 200, 62, 10, 60, 0, 7, 127, 62, 10, 60, 0, 7, 50, 62, 10, 60, 0, 6, 227, 62, 10, 60, 0, 6, 145, 62, 10, 60, 0, 6, 62, 62, 10, 60, 0, 5, 234, 62, 10, 60, 0, 5, 150, 62, 10, + 60, 0, 5, 66, 62, 10, 60, 0, 4, 239, 62, 10, 60, 0, 4, 157, 62, 10, 60, 0, 4, 78, 62, 10, 60, 0, 4, 1, 62, 10, 60, 0, 3, 184, 62, 10, 60, 0, 3, 115, 62, 10, 60, 0, 3, 50, 62, 10, 60, 0, + 2, 247, 62, 10, 60, 0, 2, 194, 62, 10, 60, 0, 2, 147, 62, 10, 60, 0, 2, 107, 62, 10, 60, 0, 2, 75, 62, 10, 60, 0, 2, 52, 62, 10, 60, 0, 2, 37, 62, 10, 60, 0, 2, 32, 62, 10, 60, 0, 2, 34, + 62, 10, 60, 0, 2, 41, 62, 10, 60, 0, 2, 52, 62, 10, 60, 0, 2, 67, 62, 10, 60, 0, 2, 86, 62, 10, 60, 0, 2, 109, 62, 10, 60, 0, 2, 134, 62, 10, 60, 0, 2, 162, 62, 10, 60, 0, 2, 193, 62, 10, + 60, 0, 2, 226, 62, 10, 60, 0, 3, 5, 62, 10, 60, 0, 3, 41, 62, 10, 60, 0, 3, 79, 62, 10, 60, 0, 3, 118, 62, 10, 60, 0, 3, 159, 62, 10, 60, 0, 3, 199, 62, 10, 60, 0, 3, 240, 62, 10, 60, 0, + 4, 25, 62, 10, 60, 0, 4, 65, 62, 10, 60, 0, 4, 106, 62, 10, 60, 0, 4, 145, 62, 10, 60, 0, 4, 183, 62, 10, 60, 0, 4, 219, 62, 10, 60, 0, 4, 254, 62, 10, 60, 0, 5, 31, 62, 10, 60, 0, 5, 62, + 62, 10, 60, 0, 5, 90, 62, 10, 60, 0, 5, 115, 62, 10, 60, 0, 5, 138, 62, 10, 60, 0, 5, 157, 62, 10, 60, 0, 5, 172, 62, 10, 60, 0, 5, 183, 62, 10, 60, 0, 5, 190, 62, 10, 60, 0, 5, 192, 62, 10, }; diff --git a/examples/SwitchModeButton/SwitchModeButton.ino b/examples/SwitchModeButton/SwitchModeButton.ino index 594a331..52ce525 100644 --- a/examples/SwitchModeButton/SwitchModeButton.ino +++ b/examples/SwitchModeButton/SwitchModeButton.ino @@ -57,27 +57,21 @@ void modeChanged(byte prevMode, byte newMode) { } // Animation object to represent the original Blender animation -BlenderServoAnimation::Animation animation(FPS, FRAMES); - -// Servo object to manage the positions -BlenderServoAnimation::Servo myBlenderServo(0, Bone, move, 100); +BlenderServoAnimation::Animation animation; // Callback to be triggered on a short button press void onPressed() { // Get the current mode, act accordingly and trigger another mode switch (animation.getMode()) { - // On short press in default mode, we want to start the animation + // On short press in default or pause mode, we want to start or resume the animation case BlenderServoAnimation::Animation::MODE_DEFAULT: + case BlenderServoAnimation::Animation::MODE_PAUSE: animation.play(); break; // On short press in play mode, we want to pause the animation case BlenderServoAnimation::Animation::MODE_PLAY: animation.pause(); break; - // On short press in pause mode, we want to resume the animation - case BlenderServoAnimation::Animation::MODE_PAUSE: - animation.play(); - break; } } @@ -91,8 +85,10 @@ void onLongPressed() { break; // On long press in any other mode, we want to stop the animation case BlenderServoAnimation::Animation::MODE_PLAY: + case BlenderServoAnimation::Animation::MODE_PLAY_SINGLE: + case BlenderServoAnimation::Animation::MODE_PLAY_RANDOM: + case BlenderServoAnimation::Animation::MODE_LOOP: case BlenderServoAnimation::Animation::MODE_PAUSE: - case BlenderServoAnimation::Animation::MODE_LIVE: animation.stop(); break; } @@ -106,8 +102,8 @@ void setup() { modeButton.attachClick(onPressed); modeButton.attachLongPressStart(onLongPressed); - // Add the Blender servo object to the animation - animation.addServo(myBlenderServo); + // Add a scene based on PROGMEM data + animation.addScene(ANIMATION_DATA, LENGTH, FPS, FRAMES); // Register the mode change callback function animation.onModeChange(modeChanged); diff --git a/examples/SwitchModeButton/simple.h b/examples/SwitchModeButton/simple.h index 3ab17cb..23abb09 100644 --- a/examples/SwitchModeButton/simple.h +++ b/examples/SwitchModeButton/simple.h @@ -14,9 +14,19 @@ const byte FPS = 30; const int FRAMES = 100; +const int LENGTH = 600; -// Servo ID: 0 -const int Bone[FRAMES] PROGMEM = { - 1472, 1475, 1482, 1495, 1512, 1533, 1558, 1586, 1617, 1651, 1687, 1726, 1766, 1807, 1849, 1893, 1936, 1979, 2023, 2065, 2106, 2146, 2185, 2221, 2255, 2286, 2314, 2339, 2360, 2377, 2390, 2397, 2400, 2395, 2380, 2357, 2325, 2285, 2238, 2185, 2126, 2061, 1992, 1919, 1842, 1763, 1681, 1598, 1514, 1430, - 1346, 1263, 1181, 1102, 1025, 952, 883, 818, 759, 706, 659, 619, 587, 564, 549, 544, 546, 553, 564, 579, 598, 621, 646, 674, 705, 738, 773, 809, 847, 886, 927, 967, 1008, 1049, 1089, 1130, 1169, 1207, 1243, 1278, 1311, 1342, 1370, 1395, 1418, 1437, 1452, 1463, 1470, 1472, +const byte PROGMEM ANIMATION_DATA[LENGTH] = { + 60, 0, 5, 192, 62, 10, 60, 0, 5, 195, 62, 10, 60, 0, 5, 202, 62, 10, 60, 0, 5, 215, 62, 10, 60, 0, 5, 232, 62, 10, 60, 0, 5, 253, 62, 10, 60, 0, 6, 22, 62, 10, 60, 0, 6, 50, 62, 10, 60, 0, + 6, 81, 62, 10, 60, 0, 6, 115, 62, 10, 60, 0, 6, 151, 62, 10, 60, 0, 6, 190, 62, 10, 60, 0, 6, 230, 62, 10, 60, 0, 7, 15, 62, 10, 60, 0, 7, 57, 62, 10, 60, 0, 7, 101, 62, 10, 60, 0, 7, 144, + 62, 10, 60, 0, 7, 187, 62, 10, 60, 0, 7, 231, 62, 10, 60, 0, 8, 17, 62, 10, 60, 0, 8, 58, 62, 10, 60, 0, 8, 98, 62, 10, 60, 0, 8, 137, 62, 10, 60, 0, 8, 173, 62, 10, 60, 0, 8, 207, 62, 10, + 60, 0, 8, 238, 62, 10, 60, 0, 9, 10, 62, 10, 60, 0, 9, 35, 62, 10, 60, 0, 9, 56, 62, 10, 60, 0, 9, 73, 62, 10, 60, 0, 9, 86, 62, 10, 60, 0, 9, 93, 62, 10, 60, 0, 9, 96, 62, 10, 60, 0, + 9, 91, 62, 10, 60, 0, 9, 76, 62, 10, 60, 0, 9, 53, 62, 10, 60, 0, 9, 21, 62, 10, 60, 0, 8, 237, 62, 10, 60, 0, 8, 190, 62, 10, 60, 0, 8, 137, 62, 10, 60, 0, 8, 78, 62, 10, 60, 0, 8, 13, + 62, 10, 60, 0, 7, 200, 62, 10, 60, 0, 7, 127, 62, 10, 60, 0, 7, 50, 62, 10, 60, 0, 6, 227, 62, 10, 60, 0, 6, 145, 62, 10, 60, 0, 6, 62, 62, 10, 60, 0, 5, 234, 62, 10, 60, 0, 5, 150, 62, 10, + 60, 0, 5, 66, 62, 10, 60, 0, 4, 239, 62, 10, 60, 0, 4, 157, 62, 10, 60, 0, 4, 78, 62, 10, 60, 0, 4, 1, 62, 10, 60, 0, 3, 184, 62, 10, 60, 0, 3, 115, 62, 10, 60, 0, 3, 50, 62, 10, 60, 0, + 2, 247, 62, 10, 60, 0, 2, 194, 62, 10, 60, 0, 2, 147, 62, 10, 60, 0, 2, 107, 62, 10, 60, 0, 2, 75, 62, 10, 60, 0, 2, 52, 62, 10, 60, 0, 2, 37, 62, 10, 60, 0, 2, 32, 62, 10, 60, 0, 2, 34, + 62, 10, 60, 0, 2, 41, 62, 10, 60, 0, 2, 52, 62, 10, 60, 0, 2, 67, 62, 10, 60, 0, 2, 86, 62, 10, 60, 0, 2, 109, 62, 10, 60, 0, 2, 134, 62, 10, 60, 0, 2, 162, 62, 10, 60, 0, 2, 193, 62, 10, + 60, 0, 2, 226, 62, 10, 60, 0, 3, 5, 62, 10, 60, 0, 3, 41, 62, 10, 60, 0, 3, 79, 62, 10, 60, 0, 3, 118, 62, 10, 60, 0, 3, 159, 62, 10, 60, 0, 3, 199, 62, 10, 60, 0, 3, 240, 62, 10, 60, 0, + 4, 25, 62, 10, 60, 0, 4, 65, 62, 10, 60, 0, 4, 106, 62, 10, 60, 0, 4, 145, 62, 10, 60, 0, 4, 183, 62, 10, 60, 0, 4, 219, 62, 10, 60, 0, 4, 254, 62, 10, 60, 0, 5, 31, 62, 10, 60, 0, 5, 62, + 62, 10, 60, 0, 5, 90, 62, 10, 60, 0, 5, 115, 62, 10, 60, 0, 5, 138, 62, 10, 60, 0, 5, 157, 62, 10, 60, 0, 5, 172, 62, 10, 60, 0, 5, 183, 62, 10, 60, 0, 5, 190, 62, 10, 60, 0, 5, 192, 62, 10, }; diff --git a/examples/WebSocketLiveMode/WebSocketLiveMode.ino b/examples/WebSocketLiveMode/WebSocketLiveMode.ino index 0ebe8e4..3cf0528 100644 --- a/examples/WebSocketLiveMode/WebSocketLiveMode.ino +++ b/examples/WebSocketLiveMode/WebSocketLiveMode.ino @@ -24,23 +24,18 @@ AsyncWebSocket ws("/"); // Servo object to send positions Servo myServo; +// LiveStream instance acting as a middleware between web socket and animation instance +BlenderServoAnimation::LiveStream liveStream; + // Callback function which is called whenever a servo needs to be moved void move(byte servoID, int position) { // Ignore the servoID (there is only one servo) and write the current position myServo.writeMicroseconds(position); } -// Animation object to manage the servos -// We skip providing fps or frames as we just want to use the live mode +// Animation object to represent the original Blender animation BlenderServoAnimation::Animation animation; -// Servo object to manage the positions -BlenderServoAnimation::Servo myBlenderServo(0, move); - -// Live mode stream instance acting as a middleware between web socket and -// animation object -BlenderServoAnimation::LiveStream liveStream; - // Handler function writing data to the live stream instance when receiving data void onWebSocketEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) { @@ -72,11 +67,14 @@ void setup() { // Attach the servo to pin 12 myServo.attach(12); - // Add the Blender servo object to the animation - animation.addServo(myBlenderServo); + // Set the position callback + animation.onPositionChange(move); + + // Add a new scene with the LiveStream - we can omit fps and frames + animation.addScene(liveStream); - // Trigger the animation live mode - animation.live(liveStream); + // Trigger the animation play mode + animation.play(); } void loop() { diff --git a/platformio.ini b/platformio.ini index 3366b58..501ee34 100644 --- a/platformio.ini +++ b/platformio.ini @@ -1,7 +1,8 @@ [env:native] platform = native test_build_src = yes -build_flags = -Wno-deprecated-declarations -debug_test = test_servo +build_flags = + -Wno-deprecated-declarations +debug_test = test_scene lib_deps = ArduinoFake diff --git a/src/BlenderServoAnimation.h b/src/BlenderServoAnimation.h index 79f474d..2c2d964 100644 --- a/src/BlenderServoAnimation.h +++ b/src/BlenderServoAnimation.h @@ -1,5 +1,4 @@ #include "internal/Animation.h" #include "internal/LiveStream.h" -#include "internal/Servo.h" -#include "internal/Show.h" +#include "internal/Scene.h" #include diff --git a/src/internal/Animation.cpp b/src/internal/Animation.cpp index 4cb1976..3baef83 100644 --- a/src/internal/Animation.cpp +++ b/src/internal/Animation.cpp @@ -1,199 +1,243 @@ #include "Animation.h" -#include "Servo.h" +#include "ProgmemStream.h" #include using namespace BlenderServoAnimation; -Animation::Animation() { +Animation::~Animation() { + for (int i = 0; i < this->addIndex; i++) { + if (this->scenes[i]) { + delete this->scenes[i]; + } + } } -Animation::Animation(byte fps, int frames) { - this->fps = fps; - this->frames = frames; - this->frameMicros = round((float)Animation::SECOND_IN_MICROS / (float)fps); - this->diffPerSecond = Animation::SECOND_IN_MICROS - (this->frameMicros * fps); +int Animation::countScenes() { + return this->addIndex; } -void Animation::addServo(Servo &servo) { - byte id = servo.getID(); - this->servos[id] = &servo; +bool Animation::hasFinished() { + return this->playIndex + 1 >= this->addIndex; } -void Animation::addServos(Servo servos[], byte servoAmount) { - for (int i = 0; i < servoAmount; i++) { - this->addServo(servos[i]); - } +bool Animation::hasScenes() { + return this->countScenes() > 0; } -void Animation::onModeChange(mcb modeCallback) { - this->modeCallback = modeCallback; +bool Animation::hasScene(byte index) { + return this->scenes[index] != nullptr; } -void Animation::changeMode(byte mode) { - byte prevMode = this->mode; - this->mode = mode; +void Animation::addScene(const byte PROGMEM *data, int dataLength, byte fps, int frames) { + ProgmemStream* stream = new ProgmemStream(data, dataLength); + this->addScene(*stream, fps, frames); +} - if (this->modeCallback) { - this->modeCallback(prevMode, mode); - } +void Animation::addScene(Stream &data, byte fps, int frames) { + this->scenes[this->addIndex] = new Scene(this->servoManager, data, fps, frames); + this->addIndex++; } -void Animation::run(unsigned long currentMicros) { - switch (this->mode) { - case MODE_PLAY: - case MODE_LOOP: - this->handlePlayMode(currentMicros); - break; - case MODE_STOP: - this->handleStopMode(currentMicros); - break; - case MODE_LIVE: - this->handleLiveMode(); - break; - } +void Animation::setDefaultServoThreshold(byte value) { + this->servoManager.setDefaultThreshold(value); } -void Animation::handlePlayMode(unsigned long currentMicros) { - bool isNewFrame = currentMicros - this->lastMicros >= this->frameMicros; +void Animation::setServoThreshold(byte id, byte value) { + this->servoManager.setThreshold(id, value); +} - if (!isNewFrame || this->frames == 0) { - return; +void Animation::setRandomScene() { + byte randomIndex = 0; + + if (this->countScenes() > 1) { + randomIndex = random(this->addIndex); } - this->lastMicros = currentMicros; - this->frame++; + this->playIndex = randomIndex; + this->scene = this->scenes[this->playIndex]; +} - if (this->frame >= this->frames) { - this->frame = 0; +void Animation::play() { + if (!this->hasScenes() || !this->modeIsIn(2, MODE_DEFAULT, MODE_PAUSE)) { + return; } - if (this->frame % this->fps == 0) { - this->lastMicros += this->diffPerSecond; + if (!this->scene) { + this->scene = this->scenes[this->playIndex]; } - for (int i = 0; i < MAX_SERVO_COUNT; i++) { - Servo *servo = this->servos[i]; + this->changeMode(MODE_PLAY); +} - if (servo && servo->hasPositions()) { - servo->moveByFrame(this->frame); - } +void Animation::playSingle(byte index) { + Scene *scene = this->scenes[index]; + + if (scene == nullptr || !this->modeIsIn(2, MODE_DEFAULT, MODE_PAUSE) || + (this->mode == MODE_PAUSE && playIndex != index)) { + return; } - if (this->frame == 0) { - if (this->mode == MODE_LOOP) { - this->changeMode(MODE_LOOP); - } else { - this->changeMode(MODE_DEFAULT); - } + if (!this->scene || this->scene->getFrame() == 0) { + this->playIndex = index; + this->scene = scene; } + + this->changeMode(MODE_PLAY_SINGLE); } -void Animation::handleStopMode(unsigned long currentMicros) { - bool allNeutral = true; +void Animation::playRandom() { + if (!this->hasScenes() || !this->modeIsIn(2, MODE_DEFAULT, MODE_PAUSE)) { + return; + } - if (currentMicros - this->lastMicros < 10000) { + if (!this->scene || this->scene->getFrame() == 0) { + this->setRandomScene(); + } + + this->changeMode(MODE_PLAY_RANDOM); +} + +void Animation::loop() { + if (!this->hasScenes() || !this->modeIsIn(2, MODE_DEFAULT, MODE_PAUSE)) { return; } - this->lastMicros = currentMicros; + if (!this->scene) { + this->scene = this->scenes[this->playIndex]; + } - for (int i = 0; i < MAX_SERVO_COUNT; i++) { - Servo *servo = this->servos[i]; + this->changeMode(MODE_LOOP); +} - if (servo && servo->hasPositions() && !servo->isNeutral()) { - servo->moveTowardsNeutral(); - allNeutral = false; - } +void Animation::pause() { + if (!this->scene || !this->modeIsIn(4, MODE_PLAY, MODE_PLAY_SINGLE, + MODE_PLAY_RANDOM, MODE_LOOP)) { + return; } - if (!allNeutral) { + this->changeMode(MODE_PAUSE); +} + +void Animation::stop() { + if (!this->scene || this->modeIsIn(2, MODE_DEFAULT, MODE_STOP)) { return; } - this->changeMode(MODE_DEFAULT); + this->changeMode(MODE_STOP); } -void Animation::handleLiveMode() { - while (this->liveStream->available() > 0) { - this->liveCommand.read(this->liveStream); +void Animation::reset() { + this->addIndex = 0; + this->playIndex = 0; - if (!this->liveCommand.isComplete() || !this->liveCommand.isValid()) { - continue; - } + for (int i = 0; i < this->addIndex; i++) { + this->scenes[i] = nullptr; + } +} - byte id = this->liveCommand.getServoID(); - int position = this->liveCommand.getServoPosition(); +byte Animation::getMode() { + return this->mode; +} - for (int i = 0; i < MAX_SERVO_COUNT; i++) { - Servo *servo = this->servos[i]; +byte Animation::getPlayIndex() { + return this->playIndex; +} - if (servo && servo->getID() == id) { - servo->move(position); - break; - } - } +void Animation::run(unsigned long currentMicros) { + switch (this->mode) { + case MODE_PLAY: + case MODE_PLAY_SINGLE: + case MODE_PLAY_RANDOM: + case MODE_LOOP: + this->handlePlayMode(currentMicros); + break; + case MODE_STOP: + this->handleStopMode(currentMicros); + break; } } -void Animation::play(unsigned long currentMicros) { - if (!this->modeIsIn(2, MODE_DEFAULT, MODE_PAUSE)) { +void Animation::handlePlayMode(unsigned long currentMicros) { + if (!this->scene) { + this->changeMode(MODE_DEFAULT); return; } - this->lastMicros = currentMicros; - this->changeMode(MODE_PLAY); -} + this->scene->play(currentMicros); -void Animation::pause() { - if (!this->modeIsIn(2, MODE_PLAY, MODE_LOOP)) { + if (!this->scene->hasFinished()) { return; } - this->changeMode(MODE_PAUSE); -} + switch (this->mode) { + case MODE_PLAY: + if (this->hasFinished()) { + this->scene = nullptr; + } else { + this->playIndex++; + this->scene = this->scenes[this->playIndex]; + } + break; + case MODE_PLAY_SINGLE: + this->scene = nullptr; + break; + case MODE_PLAY_RANDOM: + this->setRandomScene(); + this->changeMode(MODE_PLAY_RANDOM); + break; + case MODE_LOOP: + if (this->hasFinished()) { + this->playIndex = 0; + } else { + this->playIndex++; + } + this->scene = this->scenes[this->playIndex]; + this->changeMode(MODE_LOOP); + break; + } -void Animation::loop(unsigned long currentMicros) { - if (!this->modeIsIn(2, MODE_DEFAULT, MODE_PAUSE)) { + if (!this->scene) { + this->changeMode(MODE_DEFAULT); return; } - - this->lastMicros = currentMicros; - this->changeMode(MODE_LOOP); } -void Animation::stop(unsigned long currentMicros) { - if (this->modeIsIn(2, MODE_DEFAULT, MODE_STOP)) { +void Animation::handleStopMode(unsigned long currentMicros) { + if (!this->scene) { + this->changeMode(MODE_DEFAULT); return; } - this->frame = 0; - this->lastMicros = currentMicros; - this->changeMode(MODE_STOP); -} + this->scene->stop(currentMicros); -void Animation::live(Stream &liveStream) { - if (this->mode != MODE_DEFAULT) { - return; + if (this->servoManager.servosAreAllNeutral()) { + this->changeMode(MODE_DEFAULT); } +} - this->liveStream = &liveStream; - this->changeMode(MODE_LIVE); +Scene* Animation::getCurrentScene() { + return this->scene; } -byte Animation::getFPS() { - return this->fps; +void Animation::onPositionChange(pcb positionCallback) { + this->servoManager.setPositionCallback(positionCallback); } -byte Animation::getMode() { - return this->mode; +void Animation::onModeChange(mcb modeCallback) { + this->modeCallback = modeCallback; } -int Animation::getFrame() { - return this->frame; +void Animation::onSceneChange(scb sceneCallback) { + this->sceneCallback = sceneCallback; } -int Animation::getFrames() { - return this->frames; +void Animation::changeMode(byte mode) { + byte prevMode = this->mode; + this->mode = mode; + + if (this->modeCallback) { + this->modeCallback(prevMode, mode); + } } bool Animation::modeIsIn(byte modeAmount, ...) { diff --git a/src/internal/Animation.h b/src/internal/Animation.h index 6a687b2..66bba68 100644 --- a/src/internal/Animation.h +++ b/src/internal/Animation.h @@ -1,5 +1,6 @@ -#include "LiveCommand.h" -#include "Servo.h" +#include "Scene.h" +#include "ServoManager.h" +#include "typedefs.h" #include #include @@ -10,61 +11,66 @@ namespace BlenderServoAnimation { class Animation { - typedef void (*mcb)(byte, byte); +public: + static const byte MODE_DEFAULT = 0; + static const byte MODE_PLAY = 1; + static const byte MODE_PLAY_SINGLE = 2; + static const byte MODE_PLAY_RANDOM = 3; + static const byte MODE_PAUSE = 4; + static const byte MODE_LOOP = 5; + static const byte MODE_STOP = 6; -private: - static const int MAX_SERVO_COUNT = 256; - static const long SECOND_IN_MICROS = 1000000; + ~Animation(); - byte fps = 0; - byte mode = MODE_DEFAULT; + byte getMode(); + byte getPlayIndex(); - int diffPerSecond = 0; + int countScenes(); - unsigned int frame = 0; - unsigned int frames = 0; - unsigned int frameMicros = 0; + void addScene(const byte PROGMEM *data, int dataLength, byte fps, int frames); + void addScene(Stream &data, byte fps = 0, int frames = 0); + void onPositionChange(pcb positionCallback); + void onModeChange(mcb modeCallback); + void onSceneChange(scb sceneCallback); + void run(unsigned long currentMicros = micros()); + void play(); + void playSingle(byte index); + void playRandom(); + void loop(); + void pause(); + void stop(); + void reset(); + void setDefaultServoThreshold(byte value); + void setServoThreshold(byte id, byte value); + + bool hasFinished(); + bool hasScenes(); + bool hasScene(byte index); + bool modeIsIn(byte modeAmount, ...); - unsigned long lastMicros; + Scene* getCurrentScene(); - Servo *servos[MAX_SERVO_COUNT] = {}; - Stream *liveStream; - LiveCommand liveCommand; - mcb modeCallback = nullptr; +private: + static const int MAX_SCENE_COUNT = 256; - void changeMode(byte mode); - void handlePlayMode(unsigned long currentMicros); - void handleStopMode(unsigned long currentMicros); - void handleLiveMode(); + ServoManager servoManager; -public: - static const byte MODE_DEFAULT = 0; - static const byte MODE_PLAY = 1; - static const byte MODE_PAUSE = 2; - static const byte MODE_LOOP = 3; - static const byte MODE_STOP = 4; - static const byte MODE_LIVE = 5; + Scene* scenes[MAX_SCENE_COUNT] = {nullptr}; + Scene* scene = nullptr; - Animation(); - Animation(byte fps, int frames); + mcb modeCallback = nullptr; + scb sceneCallback = nullptr; - void addServo(Servo &servo); - void addServos(Servo servos[], byte servoAmount); - void onModeChange(mcb modeCallback); - void run(unsigned long currentMicros = micros()); - void play(unsigned long currentMicros = micros()); - void pause(); - void loop(unsigned long currentMicros = micros()); - void stop(unsigned long currentMicros = micros()); - void live(Stream &liveStream); + byte mode = MODE_DEFAULT; - byte getFPS(); - byte getMode(); + int addIndex = 0; + int playIndex = 0; - int getFrame(); - int getFrames(); + void changeMode(byte mode); + void handlePlayMode(unsigned long currentMicros); + void handleStopMode(unsigned long currentMicros); + void setRandomScene(); - bool modeIsIn(byte modeAmount, ...); }; } // namespace BlenderServoAnimation diff --git a/src/internal/Command.cpp b/src/internal/Command.cpp new file mode 100644 index 0000000..e0b3d38 --- /dev/null +++ b/src/internal/Command.cpp @@ -0,0 +1,39 @@ +#include "Command.h" +#include + +using namespace BlenderServoAnimation; + +void Command::write(byte value) { + if (value == START_MARKER) { + this->reset(); + } + + if (this->index >= LENGTH) { + return; + } + + this->values[this->index] = value; + this->index++; +} + +bool Command::isValid() { + return this->values[INDEX_START_MARKER] == START_MARKER && + this->values[INDEX_END_MARKER] == END_MARKER; +} + +byte Command::getServoID() { + return this->values[INDEX_SERVO_ID]; +} + +int Command::getServoPosition() { + return this->values[INDEX_POSITION_BYTE] | + this->values[INDEX_POSITION_SIG_BYTE] << BITS; +} + +void Command::reset() { + for (byte i = 0; i < LENGTH; i++) { + this->values[i] = 0; + } + + this->index = 0; +} \ No newline at end of file diff --git a/src/internal/LiveCommand.h b/src/internal/Command.h similarity index 70% rename from src/internal/LiveCommand.h rename to src/internal/Command.h index a62e886..168982d 100644 --- a/src/internal/LiveCommand.h +++ b/src/internal/Command.h @@ -5,7 +5,18 @@ namespace BlenderServoAnimation { -class LiveCommand { +class Command { + +public: + static const byte LINE_BREAK = 0xA; + + void write(byte value); + + bool isValid(); + + byte getServoID(); + + int getServoPosition(); private: static const byte START_MARKER = 0x3C; @@ -14,25 +25,17 @@ class LiveCommand { static const byte LENGTH = 5; static const byte BITS = 8; + static const byte INDEX_START_MARKER = 0; static const byte INDEX_SERVO_ID = 1; static const byte INDEX_POSITION_SIG_BYTE = 2; static const byte INDEX_POSITION_BYTE = 3; + static const byte INDEX_END_MARKER = 4; - byte receivedBytes[LENGTH]; - byte receivedIndex = 0; - - bool receiving = false; - bool complete = false; - -public: - void read(Stream *liveStream); - - bool isValid(); - bool isComplete(); + byte values[LENGTH] = {0}; + byte index = 0; - byte getServoID(); + void reset(); - int getServoPosition(); }; } // namespace BlenderServoAnimation diff --git a/src/internal/LiveCommand.cpp b/src/internal/LiveCommand.cpp deleted file mode 100644 index 14eb308..0000000 --- a/src/internal/LiveCommand.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include "LiveCommand.h" -#include - -using namespace BlenderServoAnimation; - -void LiveCommand::read(Stream *liveStream) { - byte receivedByte = liveStream->read(); - - if (!this->receiving && receivedByte != START_MARKER) { - return; - } - - switch (this->receivedIndex) { - case 0: // Start marker - this->receiving = true; - this->complete = false; - break; - case LENGTH - 1: // End marker - this->receiving = false; - this->complete = true; - break; - } - - this->receivedBytes[receivedIndex] = receivedByte; - this->receivedIndex++; - - if (complete) { - this->receivedIndex = 0; - } -} - -bool LiveCommand::isValid() { - return this->receivedBytes[0] == START_MARKER && - this->receivedBytes[LENGTH - 1] == END_MARKER; -} - -bool LiveCommand::isComplete() { - return this->complete; -} - -byte LiveCommand::getServoID() { - return this->receivedBytes[INDEX_SERVO_ID]; -} - -int LiveCommand::getServoPosition() { - return this->receivedBytes[INDEX_POSITION_BYTE] | - this->receivedBytes[INDEX_POSITION_SIG_BYTE] << BITS; -} \ No newline at end of file diff --git a/src/internal/LiveStream.cpp b/src/internal/LiveStream.cpp index b0b07e6..bea53a7 100644 --- a/src/internal/LiveStream.cpp +++ b/src/internal/LiveStream.cpp @@ -4,11 +4,19 @@ using namespace BlenderServoAnimation; int LiveStream::available() { - return this->readIndex != this->writeIndex; + if (this->writeIndex >= this->readIndex) { + return this->writeIndex - this->readIndex; + } else { + return BUFFER_SIZE - this->readIndex + this->writeIndex; + } } int LiveStream::peek() { - return this->buffer[this->readIndex]; + if (this->available()) { + return this->buffer[this->readIndex]; + } else { + return -1; + } } int LiveStream::read() { diff --git a/src/internal/LiveStream.h b/src/internal/LiveStream.h index 2337a13..cd462f8 100644 --- a/src/internal/LiveStream.h +++ b/src/internal/LiveStream.h @@ -1,28 +1,28 @@ #include -#ifndef BlenderServoAnimation_Live_H -#define BlenderServoAnimation_Live_H +#ifndef BlenderServoAnimation_LiveStream_H +#define BlenderServoAnimation_LiveStream_H namespace BlenderServoAnimation { class LiveStream : public Stream { -private: - static const byte BUFFER_SIZE = 20; - - byte buffer[BUFFER_SIZE]; - byte writeIndex = 0; - byte readIndex = 0; public: int available(); - int read(); - int peek(); - + size_t write(uint8_t); void flush(); + +private: + static const byte BUFFER_SIZE = 64; + + byte buffer[BUFFER_SIZE] = {0}; + byte writeIndex = 0; + byte readIndex = 0; + }; } // namespace BlenderServoAnimation diff --git a/src/internal/ProgmemStream.cpp b/src/internal/ProgmemStream.cpp new file mode 100644 index 0000000..3f8d880 --- /dev/null +++ b/src/internal/ProgmemStream.cpp @@ -0,0 +1,37 @@ +#include "ProgmemStream.h" +#include + +using namespace BlenderServoAnimation; + +ProgmemStream::ProgmemStream(const byte PROGMEM *data, size_t size) { + this->data = data; + this->size = size; +} + +int ProgmemStream::read() { + if (this->position < this->size) { + return pgm_read_byte_far(this->data + this->position++); + } else { + return -1; + } +} + +int ProgmemStream::available() { + return size - position; +} + +int ProgmemStream::peek() { + if (position < size) { + return pgm_read_byte_far(this->data + this->position); + } else { + return -1; + } +} + +size_t ProgmemStream::write(uint8_t value) { + return 0; +} + +void ProgmemStream::flush() { + this->position = 0; +} diff --git a/src/internal/ProgmemStream.h b/src/internal/ProgmemStream.h new file mode 100644 index 0000000..49dc5cd --- /dev/null +++ b/src/internal/ProgmemStream.h @@ -0,0 +1,31 @@ +#include + +#ifndef BlenderServoAnimation_ProgmemStream_H +#define BlenderServoAnimation_ProgmemStream_H + +namespace BlenderServoAnimation { + +class ProgmemStream : public Stream { + +public: + ProgmemStream(const byte PROGMEM *data, size_t size); + + int available(); + int read(); + int peek(); + + size_t write(uint8_t); + + void flush(); + +private: + const byte PROGMEM *data = nullptr; + + size_t size = 0; + size_t position = 0; + +}; + +} // namespace BlenderServoAnimation + +#endif \ No newline at end of file diff --git a/src/internal/Scene.cpp b/src/internal/Scene.cpp new file mode 100644 index 0000000..4d148f6 --- /dev/null +++ b/src/internal/Scene.cpp @@ -0,0 +1,109 @@ +#include "Command.h" +#include "Scene.h" +#include "Servo.h" +#include "ProgmemStream.h" +#include + +using namespace BlenderServoAnimation; + +Scene::Scene(ServoManager &servoManager, Stream &data, byte fps, int frames, bool hasProgmemStream) { + 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; + } +} + +void Scene::play(unsigned long currentMicros) { + if (this->frames == 0) { + this->parseCommands(); + return; + } + + if (!this->isNewFrame(currentMicros)) { + return; + } + + this->lastMicros = currentMicros; + + if (this->frame >= this->frames) { + this->frame = 0; + } else { + this->frame++; + } + + if (this->frame % this->fps == 0) { + this->lastMicros += this->diffPerSecond; + } + + this->parseCommands(); +} + +void Scene::stop(unsigned long currentMicros) { + if (this->getMicrosDiff(currentMicros) < STOP_DELAY_IN_MICROS) { + return; + } + + this->lastMicros = currentMicros; + this->servoManager->moveAllServosToNeutral(); + + if (this->servoManager->servosAreAllNeutral()) { + this->frame = 0; + } +} + +int Scene::getMicrosDiff(unsigned long currentMicros) { + if (currentMicros >= this->lastMicros) { + return currentMicros - this->lastMicros; + } + + return MAX_MICROS - this->lastMicros + currentMicros; +} + +bool Scene::isNewFrame(unsigned long currentMicros) { + return this->lastMicros == 0 || this->getMicrosDiff(currentMicros) >= this->frameMicros; +} + +bool Scene::hasFinished() { + return this->frame == this->frames; +} + +byte Scene::getFPS() { + return this->fps; +} + +int Scene::getFrame() { + return this->frame; +} + +int Scene::getFrames() { + return this->frames; +} + +void Scene::parseCommands() { + if (!this->servoManager->hasPositionCallback()) { + return; + } + + 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); + } +} diff --git a/src/internal/Scene.h b/src/internal/Scene.h new file mode 100644 index 0000000..4c7078e --- /dev/null +++ b/src/internal/Scene.h @@ -0,0 +1,56 @@ +#include "ServoManager.h" +#include + +#ifndef BlenderServoAnimation_Scene_H +#define BlenderServoAnimation_Scene_H + +namespace BlenderServoAnimation { + +class Scene { + +public: + Scene(ServoManager &servoManager, Stream &data, byte fps = 0, int frames = 0, bool hasProgmemStream = false); + ~Scene(); + + void play(unsigned long currentMicros); + void stop(unsigned long currentMicros); + + bool hasFinished(); + + byte getFPS(); + + int getFrame(); + int getFrames(); + +private: + static const unsigned long MAX_MICROS = 4294967295; + static const unsigned long SECOND_IN_MICROS = 1000000; + static const unsigned int STOP_DELAY_IN_MICROS = 10000; + + byte fps = 0; + + int diffPerSecond = 0; + + unsigned int frame = 0; + unsigned int frames = 0; + unsigned int frameMicros = 0; + + unsigned long lastMicros = 0; + + bool hasProgmemStream = false; + + ServoManager* servoManager; + + Stream* data = nullptr; + + void parseCommands(); + + bool isNewFrame(unsigned long currentMicros); + + int getMicrosDiff(unsigned long currentMicros); + +}; + +} // namespace BlenderServoAnimation + +#endif \ No newline at end of file diff --git a/src/internal/Servo.cpp b/src/internal/Servo.cpp index 4d2a8fa..6690711 100644 --- a/src/internal/Servo.cpp +++ b/src/internal/Servo.cpp @@ -1,61 +1,45 @@ #include "Servo.h" +#include "typedefs.h" #include using namespace BlenderServoAnimation; -Servo::Servo(byte id, const int positions[], cb moveCallback, byte threshold) { +Servo::Servo(byte id, pcb positionCallback, byte threshold) { this->id = id; - this->positions = positions; - this->moveCallback = moveCallback; - this->threshold = threshold; - this->neutralPosition = pgm_read_word_near(positions + 0); - this->currentPosition = this->neutralPosition; + this->positionCallback = positionCallback; + this->setThreshold(threshold); } -Servo::Servo(byte id, cb moveCallback, byte threshold) { - this->id = id; - this->moveCallback = moveCallback; - this->threshold = threshold; -} - -void Servo::move(int position, bool force) { - if (position == this->currentPosition && force == false) { - return; - } - - int positionDiff = abs(position - this->currentPosition); - bool exceedsThreshold = this->threshold && positionDiff > this->threshold; - - if (this->currentPosition > 0 && exceedsThreshold) { +void Servo::move(int position) { + if (position == this->currentPosition || this->positionExceedsThreshold(position)) { return; } - this->moveCallback(this->id, position); + this->positionCallback(this->id, position); this->currentPosition = position; -} -void Servo::moveByFrame(int frame) { - int newPosition = pgm_read_word_near(this->positions + frame); - this->move(newPosition); + if (this->neutralPosition == -1) { + this->neutralPosition = this->currentPosition; + } } -void Servo::moveTowardsNeutral(bool inSteps) { - int step = round(this->threshold / 10); - int newPosition = this->currentPosition; - - if (inSteps == false) { - this->move(newPosition, true); +void Servo::moveTowardsNeutral() { + if (this->neutralPosition == -1) { return; } - if (this->currentPosition > this->neutralPosition) { - newPosition -= step; - } else if (this->currentPosition < this->neutralPosition) { - newPosition += step; + if (this->threshold == 0) { + return this->move(this->neutralPosition); } - if (abs(this->neutralPosition - newPosition) < step) { + int newPosition = this->currentPosition; + + if (abs(this->neutralPosition - newPosition) < this->step) { newPosition = this->neutralPosition; + } else if (this->currentPosition > this->neutralPosition) { + newPosition -= this->step; + } else if (this->currentPosition < this->neutralPosition) { + newPosition += this->step; } this->move(newPosition); @@ -65,10 +49,21 @@ bool Servo::isNeutral() { return this->currentPosition == this->neutralPosition; } -bool Servo::hasPositions() { - return this->positions != nullptr; +void Servo::setPositionCallback(pcb positionCallback) { + this->positionCallback = positionCallback; } -byte Servo::getID() { - return this->id; +void Servo::setThreshold(byte value) { + this->threshold = value; + this->step = round(value / STEP_DIVIDER); +} + +bool Servo::positionExceedsThreshold(int position) { + if (this->currentPosition == -1) { + return false; + } + + int positionDiff = abs(position - this->currentPosition); + + return this->threshold && positionDiff > this->threshold; } diff --git a/src/internal/Servo.h b/src/internal/Servo.h index 39a8e33..ea34084 100644 --- a/src/internal/Servo.h +++ b/src/internal/Servo.h @@ -1,3 +1,4 @@ +#include "typedefs.h" #include #ifndef BlenderServoAnimation_Servo_H @@ -7,31 +8,30 @@ namespace BlenderServoAnimation { class Servo { - typedef void (*cb)(byte, int); +public: + Servo(byte id, pcb positionCallback, byte threshold = 0); -private: - byte id; - byte threshold; + void move(int position); + void moveTowardsNeutral(); + void setThreshold(byte value); + void setPositionCallback(pcb positionCallback); - int neutralPosition = -1; - int currentPosition = -1; + bool isNeutral(); - const int *positions = nullptr; +private: + const byte STEP_DIVIDER = 10; - cb moveCallback; + byte id = 0; + byte threshold = 0; + byte step = 0; -public: - Servo(byte id, const int positions[], cb moveCallback, byte threshold = 0); - Servo(byte id, cb moveCallback, byte threshold = 0); + int neutralPosition = -1; + int currentPosition = -1; - void move(int position, bool force = false); - void moveByFrame(int frame); - void moveTowardsNeutral(bool inSteps = true); + pcb positionCallback = nullptr; - bool isNeutral(); - bool hasPositions(); + bool positionExceedsThreshold(int position); - byte getID(); }; } // namespace BlenderServoAnimation diff --git a/src/internal/ServoManager.cpp b/src/internal/ServoManager.cpp new file mode 100644 index 0000000..6d2361e --- /dev/null +++ b/src/internal/ServoManager.cpp @@ -0,0 +1,86 @@ +#include "ServoManager.h" +#include "Servo.h" +#include + +using namespace BlenderServoAnimation; + +ServoManager::~ServoManager() { + for (int i = 0; i < MAX_SERVO_COUNT; i++) { + if (this->servos[i]) { + delete this->servos[i]; + } + } +} + +void ServoManager::setPositionCallback(pcb positionCallback) { + this->positionCallback = positionCallback; + + for (int i = 0; i < MAX_SERVO_COUNT; i++) { + if (this->servos[i]) { + this->servos[i]->setPositionCallback(positionCallback); + } + } +} + +void ServoManager::setDefaultThreshold(byte value) { + this->defaultThreshold = value; +} + +void ServoManager::setThreshold(byte servoId, byte value) { + this->thresholds[servoId] = value; + + if (this->servos[servoId]) { + this->servos[servoId]->setThreshold(value); + } +} + +void ServoManager::handleCommand(Command command) { + if (!command.isValid()) { + return; + } + + byte id = command.getServoID(); + int position = command.getServoPosition(); + + if (!this->servos[id]) { + this->addServo(id); + } + + this->servos[id]->move(position); +} + +void ServoManager::moveAllServosToNeutral() { + for (int i = 0; i < MAX_SERVO_COUNT; i++) { + Servo* servo = this->servos[i]; + + if (servo && !servo->isNeutral()) { + servo->moveTowardsNeutral(); + } + } +} + +bool ServoManager::hasPositionCallback() { + return this->positionCallback != nullptr; +} + +bool ServoManager::servosAreAllNeutral() { + for (int i = 0; i < MAX_SERVO_COUNT; i++) { + Servo* servo = this->servos[i]; + + if (servo && !servo->isNeutral()) { + return false; + } + } + + return true; +} + +void ServoManager::addServo(byte id) { + byte threshold = this->defaultThreshold; + + if (this->thresholds[id]) { + threshold = this->thresholds[id]; + } + + this->servos[id] = new Servo(id, this->positionCallback, threshold); +} diff --git a/src/internal/ServoManager.h b/src/internal/ServoManager.h new file mode 100644 index 0000000..22e04a8 --- /dev/null +++ b/src/internal/ServoManager.h @@ -0,0 +1,41 @@ +#include "Command.h" +#include "Servo.h" +#include "typedefs.h" +#include + +#ifndef BlenderServoAnimation_ServoManager_H +#define BlenderServoAnimation_ServoManager_H + +namespace BlenderServoAnimation { + +class ServoManager { + +public: + ~ServoManager(); + + void setPositionCallback(pcb positionCallback); + void setDefaultThreshold(byte value); + void setThreshold(byte servoId, byte value); + void handleCommand(Command command); + void moveAllServosToNeutral(); + + bool hasPositionCallback(); + bool servosAreAllNeutral(); + +private: + static const int MAX_SERVO_COUNT = 256; + + Servo* servos[MAX_SERVO_COUNT] = {nullptr}; + + pcb positionCallback = nullptr; + + byte defaultThreshold = 0; + byte thresholds[MAX_SERVO_COUNT] = {0}; + + void addServo(byte id); + +}; + +} // namespace BlenderServoAnimation + +#endif diff --git a/src/internal/Show.cpp b/src/internal/Show.cpp deleted file mode 100644 index 96e2919..0000000 --- a/src/internal/Show.cpp +++ /dev/null @@ -1,254 +0,0 @@ -#include "Show.h" -#include "Animation.h" -#include - -using namespace BlenderServoAnimation; - -byte Show::countAnimations() { - return this->addIndex; -} - -bool Show::hasAnimations() { - return this->countAnimations() > 0; -} - -bool Show::hasAnimation(byte index) { - return this->animations[index] != nullptr; -} - -void Show::addAnimation(Animation &animation) { - this->animations[this->addIndex] = &animation; - this->addIndex++; -} - -void Show::addAnimations(Animation animations[], byte animationAmount) { - for (int i = 0; i < animationAmount; i++) { - this->addAnimation(animations[i]); - } -} - -void Show::setRandomAnimation() { - byte randomIndex = 0; - - if (this->countAnimations() > 1) { - randomIndex = random(this->addIndex); - } - - this->playIndex = randomIndex; - this->animation = this->animations[this->playIndex]; -} - -void Show::play(unsigned long currentMicros) { - if (!this->hasAnimations() || !this->modeIsIn(2, MODE_DEFAULT, MODE_PAUSE)) { - return; - } - - if (!this->animation) { - this->animation = this->animations[this->playIndex]; - } - - this->animation->play(currentMicros); - this->changeMode(MODE_PLAY); -} - -void Show::playSingle(byte index, unsigned long currentMicros) { - Animation *animation = this->animations[index]; - - if (animation == nullptr || !this->modeIsIn(2, MODE_DEFAULT, MODE_PAUSE) || - (this->mode == MODE_PAUSE && playIndex != index)) { - return; - } - - if (!this->animation || this->animation->getFrame() == 0) { - this->playIndex = index; - this->animation = animation; - } - - this->animation->play(currentMicros); - this->changeMode(MODE_PLAY_SINGLE); -} - -void Show::playRandom(unsigned long currentMicros) { - if (!this->hasAnimations() || !this->modeIsIn(2, MODE_DEFAULT, MODE_PAUSE)) { - return; - } - - if (!this->animation || this->animation->getFrame() == 0) { - this->setRandomAnimation(); - } - - this->animation->play(currentMicros); - this->changeMode(MODE_PLAY_RANDOM); -} - -void Show::loop(unsigned long currentMicros) { - if (!this->hasAnimations() || !this->modeIsIn(2, MODE_DEFAULT, MODE_PAUSE)) { - return; - } - - if (!this->animation) { - this->animation = this->animations[this->playIndex]; - } - - this->animation->play(currentMicros); - this->changeMode(MODE_LOOP); -} - -void Show::pause() { - if (!this->animation || !this->modeIsIn(4, MODE_PLAY, MODE_PLAY_SINGLE, - MODE_PLAY_RANDOM, MODE_LOOP)) { - return; - } - - this->animation->pause(); - this->changeMode(MODE_PAUSE); -} - -void Show::stop(unsigned long currentMicros) { - if (!this->animation || this->modeIsIn(2, MODE_DEFAULT, MODE_STOP)) { - return; - } - - this->animation->stop(currentMicros); - this->changeMode(MODE_STOP); -} - -void Show::live(Stream &liveStream) { - if (!this->hasAnimations() || this->mode != MODE_DEFAULT) { - return; - } - - if (!this->animation) { - this->animation = this->animations[this->playIndex]; - } - - this->animation->live(liveStream); - this->changeMode(MODE_LIVE); -} - -void Show::reset() { - this->addIndex = 0; - this->playIndex = 0; - - for (int i = 0; i < this->addIndex; i++) { - this->animations[i] = nullptr; - } -} - -byte Show::getMode() { - return this->mode; -} - -byte Show::getPlayIndex() { - return this->playIndex; -} - -void Show::run(unsigned long currentMicros) { - switch (this->mode) { - case MODE_PLAY: - case MODE_PLAY_SINGLE: - case MODE_PLAY_RANDOM: - case MODE_LOOP: - this->handlePlayMode(currentMicros); - break; - case MODE_STOP: - this->handleStopMode(currentMicros); - break; - } -} - -void Show::handlePlayMode(unsigned long currentMicros) { - if (!this->animation) { - this->changeMode(MODE_DEFAULT); - return; - } - - this->animation->run(currentMicros); - - if (this->animation->getMode() == Animation::MODE_PLAY) { - return; - } - - bool lastAnimation = this->playIndex + 1 >= this->addIndex; - - switch (this->mode) { - case MODE_PLAY: - if (lastAnimation) { - this->animation = nullptr; - } else { - this->playIndex++; - this->animation = this->animations[this->playIndex]; - } - break; - case MODE_PLAY_SINGLE: - this->animation = nullptr; - break; - case MODE_PLAY_RANDOM: - this->setRandomAnimation(); - this->changeMode(MODE_PLAY_RANDOM); - break; - case MODE_LOOP: - if (lastAnimation) { - this->playIndex = 0; - } else { - this->playIndex++; - } - this->animation = this->animations[this->playIndex]; - this->changeMode(MODE_LOOP); - break; - } - - if (!this->animation) { - this->changeMode(MODE_DEFAULT); - return; - } - - this->animation->play(currentMicros); -} - -void Show::handleStopMode(unsigned long currentMicros) { - if (!this->animation) { - this->changeMode(MODE_DEFAULT); - return; - } - - this->animation->run(currentMicros); - - if (this->animation->getMode() == Animation::MODE_DEFAULT) { - this->changeMode(MODE_DEFAULT); - } -} - -Animation *Show::getCurrentAnimation() { - return this->animation; -} - -void Show::onModeChange(mcb modeCallback) { - this->modeCallback = modeCallback; -} - -void Show::changeMode(byte mode) { - byte prevMode = this->mode; - this->mode = mode; - - if (this->modeCallback) { - this->modeCallback(prevMode, mode); - } -} - -bool Show::modeIsIn(byte modeAmount, ...) { - bool match = false; - - va_list modes; - va_start(modes, modeAmount); - - for (int i = 0; i < modeAmount; i++) { - if (this->mode == va_arg(modes, int)) { - match = true; - } - } - - va_end(modes); - - return match; -} diff --git a/src/internal/Show.h b/src/internal/Show.h deleted file mode 100644 index 705f9ab..0000000 --- a/src/internal/Show.h +++ /dev/null @@ -1,67 +0,0 @@ -#include "Animation.h" -#include -#include - -#ifndef BlenderServoAnimation_Show_H -#define BlenderServoAnimation_Show_H - -namespace BlenderServoAnimation { - -class Show { - - typedef void (*mcb)(byte, byte); - -private: - static const int MAX_ANIMATION_COUNT = 256; - - Animation *animations[MAX_ANIMATION_COUNT] = {}; - Animation *animation = nullptr; - - mcb modeCallback = nullptr; - - byte mode = MODE_DEFAULT; - byte addIndex = 0; - byte playIndex = 0; - - void changeMode(byte mode); - void handlePlayMode(unsigned long currentMicros); - void handleStopMode(unsigned long currentMicros); - void setRandomAnimation(); - -public: - static const byte MODE_DEFAULT = 0; - static const byte MODE_PLAY = 1; - static const byte MODE_PLAY_SINGLE = 2; - static const byte MODE_PLAY_RANDOM = 3; - static const byte MODE_PAUSE = 4; - static const byte MODE_LOOP = 5; - static const byte MODE_STOP = 6; - static const byte MODE_LIVE = 7; - - byte getMode(); - byte getPlayIndex(); - byte countAnimations(); - - void addAnimation(Animation &animation); - void addAnimations(Animation animations[], byte animationAmount); - void onModeChange(mcb modeCallback); - void run(unsigned long currentMicros = micros()); - void play(unsigned long currentMicros = micros()); - void playSingle(byte index, unsigned long currentMicros = micros()); - void playRandom(unsigned long currentMicros = micros()); - void loop(unsigned long currentMicros = micros()); - void pause(); - void stop(unsigned long currentMicros = micros()); - void live(Stream &liveStream); - void reset(); - - bool hasAnimations(); - bool hasAnimation(byte index); - bool modeIsIn(byte modeAmount, ...); - - Animation *getCurrentAnimation(); -}; - -} // namespace BlenderServoAnimation - -#endif \ No newline at end of file diff --git a/src/internal/typedefs.h b/src/internal/typedefs.h new file mode 100644 index 0000000..27b657b --- /dev/null +++ b/src/internal/typedefs.h @@ -0,0 +1,5 @@ +#include + +typedef void (*mcb)(byte, byte); // Mode callback +typedef void (*pcb)(byte, int); // Position callback +typedef void (*scb)(byte, byte); // Scene callback diff --git a/test/animation/helper.h b/test/animation/helper.h deleted file mode 100644 index 993deb3..0000000 --- a/test/animation/helper.h +++ /dev/null @@ -1,36 +0,0 @@ -#include - -#define FPS 60 -#define FRAMES 5 -#define FRAME_MICROS 16667 - -byte modeChangeCount = 0; - -struct positionLog { - int index; - int positions[20]; -}; - -positionLog lastPositions[16]; - -void setUpHelper(void) { - for (int id = 0; id < 16; id++) { - lastPositions[id].index = 0; - - for (int i = 0; i < 20; i++) { - lastPositions[id].positions[i] = 0; - } - } - - modeChangeCount = 0; -} - -void onModeChange(byte prevMode, byte newMode) { - modeChangeCount++; -} - -void move(byte servoID, int position) { - int index = lastPositions[servoID].index; - lastPositions[servoID].positions[index] = position; - lastPositions[servoID].index++; -} \ No newline at end of file diff --git a/test/animation/test_live/test_live.cpp b/test/animation/test_live/test_live.cpp deleted file mode 100644 index 327c083..0000000 --- a/test/animation/test_live/test_live.cpp +++ /dev/null @@ -1,119 +0,0 @@ -#include "../helper.h" -#include "BlenderServoAnimation.h" -#include - -using namespace BlenderServoAnimation; - -void setUp(void) { - setUpHelper(); -} - -const int positions[5] PROGMEM = {350, 340, 330, 340, 330}; - -void test_live(void) { - Animation animation; - LiveStream mock; - Servo servos[] = { - Servo(0, positions, move), - Servo(1, move), - }; - animation.addServos(servos, 2); - animation.live(mock); - TEST_ASSERT_EQUAL(Animation::MODE_LIVE, animation.getMode()); - - byte values[20] = {60, 0, 1, 94, 62, 60, 1, 1, 94, 62, - 60, 0, 1, 99, 62, 60, 1, 1, 99, 62}; - - for (int i = 0; i < 10; i++) { - mock.write(values[i]); - } - - animation.run(0); - - TEST_ASSERT_EQUAL(0, lastPositions[0].positions[0]); - TEST_ASSERT_EQUAL(350, lastPositions[1].positions[0]); - - for (int i = 10; i < 20; i++) { - mock.write(values[i]); - } - - animation.run(0); - - TEST_ASSERT_EQUAL(355, lastPositions[0].positions[0]); - TEST_ASSERT_EQUAL(355, lastPositions[1].positions[1]); -} - -void test_skip_incomplete_command(void) { - Animation animation; - LiveStream mock; - Servo servo(0, move); - animation.addServo(servo); - animation.live(mock); - TEST_ASSERT_EQUAL(Animation::MODE_LIVE, animation.getMode()); - - byte values[15] = {60, 0, 1, 94, 62, 60, 0, 1, 99, 0, 60, 0, 1, 104, 62}; - - for (int i = 0; i < 15; i++) { - mock.write(values[i]); - } - - animation.run(0); - - TEST_ASSERT_EQUAL(350, lastPositions[0].positions[0]); - TEST_ASSERT_EQUAL(360, lastPositions[0].positions[1]); -} - -void test_call_twice(void) { - Serial_ mock; - Animation animation(FPS, FRAMES); - animation.onModeChange(onModeChange); - - TEST_ASSERT_EQUAL(Animation::MODE_DEFAULT, animation.getMode()); - animation.live(mock); - TEST_ASSERT_EQUAL(Animation::MODE_LIVE, animation.getMode()); - animation.live(mock); - TEST_ASSERT_EQUAL(Animation::MODE_LIVE, animation.getMode()); - - TEST_ASSERT_EQUAL(1, modeChangeCount); -} - -void test_prevented(void) { - Serial_ mock; - Animation animation(FPS, FRAMES); - - animation.play(0); - TEST_ASSERT_EQUAL(Animation::MODE_PLAY, animation.getMode()); - animation.live(mock); - TEST_ASSERT_EQUAL(Animation::MODE_PLAY, animation.getMode()); - animation.pause(); - TEST_ASSERT_EQUAL(Animation::MODE_PAUSE, animation.getMode()); - animation.live(mock); - TEST_ASSERT_EQUAL(Animation::MODE_PAUSE, animation.getMode()); - animation.loop(0); - TEST_ASSERT_EQUAL(Animation::MODE_LOOP, animation.getMode()); - animation.live(mock); - TEST_ASSERT_EQUAL(Animation::MODE_LOOP, animation.getMode()); - animation.stop(0); - TEST_ASSERT_EQUAL(Animation::MODE_STOP, animation.getMode()); - animation.live(mock); - TEST_ASSERT_EQUAL(Animation::MODE_STOP, animation.getMode()); -} - -void test_allowed(void) { - Serial_ mock; - Animation animation(FPS, FRAMES); - - TEST_ASSERT_EQUAL(Animation::MODE_DEFAULT, animation.getMode()); - animation.live(mock); - TEST_ASSERT_EQUAL(Animation::MODE_LIVE, animation.getMode()); -} - -int main(int argc, char **argv) { - UNITY_BEGIN(); - RUN_TEST(test_live); - RUN_TEST(test_skip_incomplete_command); - RUN_TEST(test_call_twice); - RUN_TEST(test_prevented); - RUN_TEST(test_allowed); - UNITY_END(); -} diff --git a/test/animation/test_loop/test_loop.cpp b/test/animation/test_loop/test_loop.cpp index bec1a8d..e097397 100644 --- a/test/animation/test_loop/test_loop.cpp +++ b/test/animation/test_loop/test_loop.cpp @@ -1,92 +1,102 @@ -#include "../helper.h" -#include "BlenderServoAnimation.h" +#include "internal/Animation.h" +#include "internal/LiveStream.h" +#include "../test/helper.h" #include using namespace BlenderServoAnimation; +using namespace fakeit; void setUp(void) { - setUpHelper(); + ArduinoFakeReset(); + resetPositionLog(); } -const int positionsA[5] PROGMEM = {350, 340, 330, 340, 330}; -const int positionsB[5] PROGMEM = {250, 240, 230, 240, 230}; - void test_loop(void) { - Animation animation(FPS, FRAMES); - Servo servos[] = { - Servo(1, positionsA, move), - Servo(2, positionsB, move), - Servo(3, move), - }; - animation.addServos(servos, 3); + Animation animation; + animation.onPositionChange(move); + animation.addScene(PROGMEM_DATA, DATA_SIZE, FPS, FRAMES); + animation.addScene(PROGMEM_DATA, DATA_SIZE, FPS, FRAMES); + + TEST_ASSERT_TRUE(animation.hasScenes()); + TEST_ASSERT_EQUAL(2, animation.countScenes()); + TEST_ASSERT_EQUAL(Animation::MODE_DEFAULT, animation.getMode()); - animation.loop(0); - TEST_ASSERT_EQUAL(Animation::MODE_LOOP, animation.getMode()); - int expA[9] = {340, 330, 340, 330, 350, 340, 330, 340, 330}; - int expB[9] = {240, 230, 240, 230, 250, 240, 230, 240, 230}; + animation.loop(); - for (long i = 0; i < FRAME_MICROS * (long)10; i += FRAME_MICROS) { + TEST_ASSERT_EQUAL(Animation::MODE_LOOP, animation.getMode()); + TEST_ASSERT_EQUAL(0, animation.getPlayIndex()); + + for (int i = 0; i < FRAME_MICROS * 5; i += FRAME_MICROS) { animation.run(i); } - for (int i = 0; i < 9; i++) { - TEST_ASSERT_EQUAL(expA[i], lastPositions[1].positions[i]); - TEST_ASSERT_EQUAL(expB[i], lastPositions[2].positions[i]); - TEST_ASSERT_EQUAL(0, lastPositions[3].positions[i]); + TEST_ASSERT_EQUAL(Animation::MODE_LOOP, animation.getMode()); + TEST_ASSERT_EQUAL(1, animation.getPlayIndex()); + + for (int i = FRAME_MICROS * 5; i < FRAME_MICROS * 10; i += FRAME_MICROS) { + animation.run(i); } TEST_ASSERT_EQUAL(Animation::MODE_LOOP, animation.getMode()); + TEST_ASSERT_EQUAL(0, animation.getPlayIndex()); + TEST_ASSERT_EQUAL(20, logIndex); } -void test_call_twice(void) { - Animation animation(FPS, FRAMES); - animation.onModeChange(onModeChange); - +void test_without_scenes(void) { + Animation animation; + animation.onPositionChange(move); + animation.loop(); TEST_ASSERT_EQUAL(Animation::MODE_DEFAULT, animation.getMode()); - animation.loop(0); - TEST_ASSERT_EQUAL(Animation::MODE_LOOP, animation.getMode()); - animation.loop(0); - TEST_ASSERT_EQUAL(Animation::MODE_LOOP, animation.getMode()); - - TEST_ASSERT_EQUAL(1, modeChangeCount); } void test_prevented(void) { - Serial_ mock; - Animation animation(FPS, FRAMES); + LiveStream stream; + Animation animation; + animation.onPositionChange(move); + animation.addScene(stream, FPS, FRAMES); + + When(OverloadedMethod(ArduinoFake(), random, long(long))).Return(0); - animation.play(0); + animation.play(); TEST_ASSERT_EQUAL(Animation::MODE_PLAY, animation.getMode()); - animation.loop(0); + animation.loop(); TEST_ASSERT_EQUAL(Animation::MODE_PLAY, animation.getMode()); - animation.stop(0); + animation.pause(); + animation.playSingle(0); + TEST_ASSERT_EQUAL(Animation::MODE_PLAY_SINGLE, animation.getMode()); + animation.loop(); + TEST_ASSERT_EQUAL(Animation::MODE_PLAY_SINGLE, animation.getMode()); + animation.pause(); + animation.playRandom(); + TEST_ASSERT_EQUAL(Animation::MODE_PLAY_RANDOM, animation.getMode()); + animation.loop(); + TEST_ASSERT_EQUAL(Animation::MODE_PLAY_RANDOM, animation.getMode()); + animation.stop(); TEST_ASSERT_EQUAL(Animation::MODE_STOP, animation.getMode()); - animation.loop(0); + animation.loop(); TEST_ASSERT_EQUAL(Animation::MODE_STOP, animation.getMode()); - animation.run(10000); - animation.live(mock); - TEST_ASSERT_EQUAL(Animation::MODE_LIVE, animation.getMode()); - animation.loop(0); - TEST_ASSERT_EQUAL(Animation::MODE_LIVE, animation.getMode()); } void test_allowed(void) { - Animation animation(FPS, FRAMES); + LiveStream stream; + Animation animation; + animation.onPositionChange(move); + animation.addScene(stream, FPS, FRAMES); TEST_ASSERT_EQUAL(Animation::MODE_DEFAULT, animation.getMode()); - animation.loop(0); + animation.loop(); TEST_ASSERT_EQUAL(Animation::MODE_LOOP, animation.getMode()); animation.pause(); TEST_ASSERT_EQUAL(Animation::MODE_PAUSE, animation.getMode()); - animation.loop(0); + animation.loop(); TEST_ASSERT_EQUAL(Animation::MODE_LOOP, animation.getMode()); } int main(int argc, char **argv) { UNITY_BEGIN(); RUN_TEST(test_loop); - RUN_TEST(test_call_twice); + RUN_TEST(test_without_scenes); RUN_TEST(test_prevented); RUN_TEST(test_allowed); UNITY_END(); diff --git a/test/animation/test_mode_callback/test_mode_callback.cpp b/test/animation/test_mode_callback/test_mode_callback.cpp index 6353499..cace6ba 100644 --- a/test/animation/test_mode_callback/test_mode_callback.cpp +++ b/test/animation/test_mode_callback/test_mode_callback.cpp @@ -1,11 +1,11 @@ -#include "BlenderServoAnimation.h" +#include "internal/Animation.h" +#include "internal/LiveStream.h" +#include "../test/helper.h" + #include using namespace BlenderServoAnimation; -#define FPS 60 -#define FRAMES 5 - int prevMode = -1; int newMode = -1; @@ -20,53 +20,72 @@ void onModeChange(byte prevArg, byte newArg) { } void test_different_mode(void) { - Animation animation(FPS, FRAMES); + LiveStream stream; + Animation animation; + animation.onPositionChange(move); animation.onModeChange(onModeChange); + animation.addScene(stream, FPS, FRAMES); + animation.addScene(stream, FPS, FRAMES); - animation.play(0); + TEST_ASSERT_EQUAL(-1, prevMode); + TEST_ASSERT_EQUAL(-1, newMode); + animation.playSingle(1); TEST_ASSERT_EQUAL(Animation::MODE_DEFAULT, prevMode); - TEST_ASSERT_EQUAL(Animation::MODE_PLAY, newMode); + TEST_ASSERT_EQUAL(Animation::MODE_PLAY_SINGLE, newMode); + TEST_ASSERT_EQUAL(1, animation.getPlayIndex()); animation.pause(); - TEST_ASSERT_EQUAL(Animation::MODE_PLAY, prevMode); + TEST_ASSERT_EQUAL(Animation::MODE_PLAY_SINGLE, prevMode); TEST_ASSERT_EQUAL(Animation::MODE_PAUSE, newMode); } void test_same_mode(void) { - Animation animation(FPS, FRAMES); + LiveStream stream; + Animation animation; + animation.onPositionChange(move); animation.onModeChange(onModeChange); + animation.addScene(stream, FPS, FRAMES); - animation.loop(0); + animation.loop(); TEST_ASSERT_EQUAL(Animation::MODE_DEFAULT, prevMode); TEST_ASSERT_EQUAL(Animation::MODE_LOOP, newMode); - animation.loop(0); + animation.loop(); TEST_ASSERT_EQUAL(Animation::MODE_DEFAULT, prevMode); TEST_ASSERT_EQUAL(Animation::MODE_LOOP, newMode); } void test_all_modes(void) { - Serial_ mock; - Animation animation(FPS, FRAMES); - + LiveStream stream; + Animation animation; + animation.onPositionChange(move); animation.onModeChange(onModeChange); + animation.addScene(stream, FPS, FRAMES); - animation.play(0); + animation.play(); TEST_ASSERT_EQUAL(Animation::MODE_DEFAULT, prevMode); TEST_ASSERT_EQUAL(Animation::MODE_PLAY, newMode); + TEST_ASSERT_EQUAL(0, animation.getPlayIndex()); animation.pause(); TEST_ASSERT_EQUAL(Animation::MODE_PLAY, prevMode); TEST_ASSERT_EQUAL(Animation::MODE_PAUSE, newMode); - animation.loop(0); + TEST_ASSERT_EQUAL(0, animation.getPlayIndex()); + animation.playRandom(); + TEST_ASSERT_EQUAL(Animation::MODE_PAUSE, prevMode); + TEST_ASSERT_EQUAL(Animation::MODE_PLAY_RANDOM, newMode); + TEST_ASSERT_EQUAL(0, animation.getPlayIndex()); + animation.pause(); + animation.playSingle(0); + TEST_ASSERT_EQUAL(Animation::MODE_PAUSE, prevMode); + TEST_ASSERT_EQUAL(Animation::MODE_PLAY_SINGLE, newMode); + TEST_ASSERT_EQUAL(0, animation.getPlayIndex()); + animation.pause(); + animation.loop(); TEST_ASSERT_EQUAL(Animation::MODE_PAUSE, prevMode); TEST_ASSERT_EQUAL(Animation::MODE_LOOP, newMode); - animation.stop(0); + TEST_ASSERT_EQUAL(0, animation.getPlayIndex()); + animation.stop(); TEST_ASSERT_EQUAL(Animation::MODE_LOOP, prevMode); TEST_ASSERT_EQUAL(Animation::MODE_STOP, newMode); - animation.run(10000); - TEST_ASSERT_EQUAL(Animation::MODE_STOP, prevMode); - TEST_ASSERT_EQUAL(Animation::MODE_DEFAULT, newMode); - animation.live(mock); - TEST_ASSERT_EQUAL(Animation::MODE_DEFAULT, prevMode); - TEST_ASSERT_EQUAL(Animation::MODE_LIVE, newMode); + TEST_ASSERT_EQUAL(0, animation.getPlayIndex()); } int main(int argc, char **argv) { diff --git a/test/animation/test_pause/test_pause.cpp b/test/animation/test_pause/test_pause.cpp index a76eafd..f84b0c9 100644 --- a/test/animation/test_pause/test_pause.cpp +++ b/test/animation/test_pause/test_pause.cpp @@ -1,107 +1,122 @@ -#include "../helper.h" -#include "BlenderServoAnimation.h" +#include "internal/Animation.h" +#include "internal/LiveStream.h" +#include "../test/helper.h" #include using namespace BlenderServoAnimation; +using namespace fakeit; void setUp(void) { - setUpHelper(); + ArduinoFakeReset(); + resetPositionLog(); } -const int positions[5] PROGMEM = {350, 340, 330, 340, 330}; -const int positionsB[5] PROGMEM = {250, 240, 230, 240, 230}; +void test_pause(byte mode) { + Animation animation; + animation.onPositionChange(move); + animation.addScene(PROGMEM_DATA, DATA_SIZE, FPS, FRAMES); -void test_pause(bool loop) { - Animation animation(FPS, FRAMES); - Servo servo(2, positions, move); - animation.addServo(servo); + TEST_ASSERT_EQUAL(Animation::MODE_DEFAULT, animation.getMode()); - if (loop) { - animation.loop(0); - TEST_ASSERT_EQUAL(Animation::MODE_LOOP, animation.getMode()); - } else { - animation.play(0); - TEST_ASSERT_EQUAL(Animation::MODE_PLAY, animation.getMode()); + switch (mode) { + case Animation::MODE_PLAY: + animation.play(); + break; + case Animation::MODE_PLAY_SINGLE: + animation.playSingle(0); + break; + case Animation::MODE_PLAY_RANDOM: + animation.playRandom(); + break; + case Animation::MODE_LOOP: + animation.loop(); + break; } - int exp[5] = {340, 330, 340, 330, 350}; + TEST_ASSERT_EQUAL(mode, animation.getMode()); + TEST_ASSERT_EQUAL(0, animation.getCurrentScene()->getFrame()); - for (int i = 0; i < 2; i++) { - animation.run(FRAME_MICROS * (long)(i + 1)); - TEST_ASSERT_EQUAL(exp[i], lastPositions[2].positions[i]); + for (int i = 0; i < FRAME_MICROS * 3; i += FRAME_MICROS) { + animation.run(i); } + TEST_ASSERT_EQUAL(3, animation.getCurrentScene()->getFrame()); + animation.pause(); - TEST_ASSERT_EQUAL(Animation::MODE_PAUSE, animation.getMode()); - for (int i = 2; i < 5; i++) { - animation.run(FRAME_MICROS * (long)(i + 1)); - TEST_ASSERT_EQUAL(0, lastPositions[2].positions[i]); + for (int i = FRAME_MICROS * 3; i < FRAME_MICROS * 6; i += FRAME_MICROS) { + animation.run(i); } - if (loop) { - animation.loop(0); - TEST_ASSERT_EQUAL(Animation::MODE_LOOP, animation.getMode()); - } else { - animation.play(0); - TEST_ASSERT_EQUAL(Animation::MODE_PLAY, animation.getMode()); + TEST_ASSERT_EQUAL(Animation::MODE_PAUSE, animation.getMode()); + TEST_ASSERT_EQUAL(3, animation.getCurrentScene()->getFrame()); + + switch (mode) { + case Animation::MODE_PLAY: + animation.play(); + break; + case Animation::MODE_PLAY_SINGLE: + animation.playSingle(0); + break; + case Animation::MODE_PLAY_RANDOM: + animation.playRandom(); + break; + case Animation::MODE_LOOP: + animation.loop(); + break; } - for (int i = 5; i < 8; i++) { - animation.run(FRAME_MICROS * (long)(i + 1)); - TEST_ASSERT_EQUAL(exp[i - 3], lastPositions[2].positions[i - 3]); - } + animation.run(FRAME_MICROS * 7); + + TEST_ASSERT_EQUAL(mode, animation.getMode()); + TEST_ASSERT_EQUAL(4, animation.getCurrentScene()->getFrame()); + TEST_ASSERT_EQUAL(8, logIndex); } void test_pause_play(void) { - test_pause(false); + test_pause(Animation::MODE_PLAY); } void test_pause_loop(void) { - test_pause(true); + test_pause(Animation::MODE_LOOP); } -void test_call_twice(void) { - Animation animation(FPS, FRAMES); - animation.onModeChange(onModeChange); - - animation.play(0); - TEST_ASSERT_EQUAL(Animation::MODE_PLAY, animation.getMode()); - animation.pause(); - TEST_ASSERT_EQUAL(Animation::MODE_PAUSE, animation.getMode()); - animation.pause(); - TEST_ASSERT_EQUAL(Animation::MODE_PAUSE, animation.getMode()); +void test_pause_play_single(void) { + test_pause(Animation::MODE_PLAY_SINGLE); +} - TEST_ASSERT_EQUAL(2, modeChangeCount); +void test_pause_play_random(void) { + When(OverloadedMethod(ArduinoFake(), random, long(long))).Return(1, 0); + test_pause(Animation::MODE_PLAY_RANDOM); } void test_prevented(void) { - Serial_ mock; - Animation animation(FPS, FRAMES); + LiveStream stream; + Animation animation; + animation.onPositionChange(move); + animation.addScene(stream, FPS, FRAMES); TEST_ASSERT_EQUAL(Animation::MODE_DEFAULT, animation.getMode()); animation.pause(); TEST_ASSERT_EQUAL(Animation::MODE_DEFAULT, animation.getMode()); - animation.play(0); - animation.stop(0); + animation.play(); + animation.stop(); TEST_ASSERT_EQUAL(Animation::MODE_STOP, animation.getMode()); animation.pause(); TEST_ASSERT_EQUAL(Animation::MODE_STOP, animation.getMode()); - animation.run(10000); - animation.live(mock); - TEST_ASSERT_EQUAL(Animation::MODE_LIVE, animation.getMode()); - animation.pause(); - TEST_ASSERT_EQUAL(Animation::MODE_LIVE, animation.getMode()); } void test_allowed(void) { - Animation animation(FPS, FRAMES); + LiveStream stream; + Animation animation; + animation.onPositionChange(move); + animation.addScene(stream, FPS, FRAMES); - animation.play(0); + animation.play(); TEST_ASSERT_EQUAL(Animation::MODE_PLAY, animation.getMode()); animation.pause(); TEST_ASSERT_EQUAL(Animation::MODE_PAUSE, animation.getMode()); - animation.loop(0); + animation.loop(); TEST_ASSERT_EQUAL(Animation::MODE_LOOP, animation.getMode()); animation.pause(); TEST_ASSERT_EQUAL(Animation::MODE_PAUSE, animation.getMode()); @@ -111,7 +126,8 @@ int main(int argc, char **argv) { UNITY_BEGIN(); RUN_TEST(test_pause_play); RUN_TEST(test_pause_loop); - RUN_TEST(test_call_twice); + RUN_TEST(test_pause_play_single); + RUN_TEST(test_pause_play_random); RUN_TEST(test_prevented); RUN_TEST(test_allowed); UNITY_END(); diff --git a/test/animation/test_play/test_play.cpp b/test/animation/test_play/test_play.cpp index 63d3a3f..6962634 100644 --- a/test/animation/test_play/test_play.cpp +++ b/test/animation/test_play/test_play.cpp @@ -1,98 +1,98 @@ -#include "../helper.h" -#include "BlenderServoAnimation.h" +#include "internal/Animation.h" +#include "../test/helper.h" #include using namespace BlenderServoAnimation; +using namespace fakeit; void setUp(void) { - setUpHelper(); + ArduinoFakeReset(); + resetPositionLog(); } -const int positionsA[5] PROGMEM = {350, 340, 330, 340, 330}; -const int positionsB[5] PROGMEM = {250, 240, 230, 240, 230}; - void test_play(void) { - Animation animation(FPS, FRAMES); - Servo servos[] = { - Servo(1, positionsA, move), - Servo(2, positionsB, move), - Servo(3, move), - }; - animation.addServos(servos, 3); - TEST_ASSERT_EQUAL(Animation::MODE_DEFAULT, animation.getMode()); - animation.play(0); - TEST_ASSERT_EQUAL(Animation::MODE_PLAY, animation.getMode()); + Animation animation; + animation.onPositionChange(move); - int expA[5] = {340, 330, 340, 330, 350}; - int expB[5] = {240, 230, 240, 230, 250}; + TEST_ASSERT_FALSE(animation.hasScenes()); + TEST_ASSERT_EQUAL(0, animation.countScenes()); + TEST_ASSERT_FALSE(animation.hasScene(0)); + TEST_ASSERT_EQUAL(nullptr, animation.getCurrentScene()); - for (long i = 0; i < FRAME_MICROS * (long)9; i += FRAME_MICROS) { - animation.run(i); - } + animation.addScene(PROGMEM_DATA, DATA_SIZE, FPS, FRAMES); - for (int i = 0; i < 5; i++) { - TEST_ASSERT_EQUAL(expA[i], lastPositions[1].positions[i]); - TEST_ASSERT_EQUAL(expB[i], lastPositions[2].positions[i]); - TEST_ASSERT_EQUAL(0, lastPositions[3].positions[i]); - } + TEST_ASSERT_TRUE(animation.hasScenes()); + TEST_ASSERT_EQUAL(1, animation.countScenes()); + TEST_ASSERT_TRUE(animation.hasScene(0)); + + TEST_ASSERT_EQUAL(Animation::MODE_DEFAULT, animation.getMode()); - for (int i = 5; i < 9; i++) { - TEST_ASSERT_EQUAL(0, lastPositions[1].positions[i]); - TEST_ASSERT_EQUAL(0, lastPositions[2].positions[i]); - TEST_ASSERT_EQUAL(0, lastPositions[3].positions[i]); + animation.play(); + + TEST_ASSERT_EQUAL(Animation::MODE_PLAY, animation.getMode()); + TEST_ASSERT_NOT_EQUAL(nullptr, animation.getCurrentScene()); + TEST_ASSERT_EQUAL(5, animation.getCurrentScene()->getFrames()); + + for (int i = 0; i < ANIMATION_MICROS; i += FRAME_MICROS) { + animation.run(i); } TEST_ASSERT_EQUAL(Animation::MODE_DEFAULT, animation.getMode()); + TEST_ASSERT_EQUAL(10, logIndex); } -void test_call_twice(void) { - Animation animation(FPS, FRAMES); - animation.onModeChange(onModeChange); - +void test_without_scenes(void) { + Animation animation; + animation.onPositionChange(move); + animation.play(); TEST_ASSERT_EQUAL(Animation::MODE_DEFAULT, animation.getMode()); - animation.play(0); - TEST_ASSERT_EQUAL(Animation::MODE_PLAY, animation.getMode()); - animation.play(0); - TEST_ASSERT_EQUAL(Animation::MODE_PLAY, animation.getMode()); - - TEST_ASSERT_EQUAL(1, modeChangeCount); } void test_prevented(void) { - Serial_ mock; - Animation animation(FPS, FRAMES); + Animation animation; + animation.onPositionChange(move); + animation.addScene(PROGMEM_DATA, DATA_SIZE, FPS, FRAMES); + + When(OverloadedMethod(ArduinoFake(), random, long(long))).Return(0); - animation.loop(0); + animation.loop(); TEST_ASSERT_EQUAL(Animation::MODE_LOOP, animation.getMode()); - animation.play(0); + animation.play(); TEST_ASSERT_EQUAL(Animation::MODE_LOOP, animation.getMode()); - animation.stop(0); + animation.pause(); + animation.playSingle(0); + TEST_ASSERT_EQUAL(Animation::MODE_PLAY_SINGLE, animation.getMode()); + animation.play(); + TEST_ASSERT_EQUAL(Animation::MODE_PLAY_SINGLE, animation.getMode()); + animation.pause(); + animation.playRandom(); + TEST_ASSERT_EQUAL(Animation::MODE_PLAY_RANDOM, animation.getMode()); + animation.play(); + TEST_ASSERT_EQUAL(Animation::MODE_PLAY_RANDOM, animation.getMode()); + animation.stop(); TEST_ASSERT_EQUAL(Animation::MODE_STOP, animation.getMode()); - animation.play(0); + animation.play(); TEST_ASSERT_EQUAL(Animation::MODE_STOP, animation.getMode()); - animation.run(10000); - animation.live(mock); - TEST_ASSERT_EQUAL(Animation::MODE_LIVE, animation.getMode()); - animation.play(0); - TEST_ASSERT_EQUAL(Animation::MODE_LIVE, animation.getMode()); } void test_allowed(void) { - Animation animation(FPS, FRAMES); + Animation animation; + animation.onPositionChange(move); + animation.addScene(PROGMEM_DATA, DATA_SIZE, FPS, FRAMES); TEST_ASSERT_EQUAL(Animation::MODE_DEFAULT, animation.getMode()); - animation.play(0); + animation.play(); TEST_ASSERT_EQUAL(Animation::MODE_PLAY, animation.getMode()); animation.pause(); TEST_ASSERT_EQUAL(Animation::MODE_PAUSE, animation.getMode()); - animation.play(0); + animation.play(); TEST_ASSERT_EQUAL(Animation::MODE_PLAY, animation.getMode()); } int main(int argc, char **argv) { UNITY_BEGIN(); RUN_TEST(test_play); - RUN_TEST(test_call_twice); + RUN_TEST(test_without_scenes); RUN_TEST(test_prevented); RUN_TEST(test_allowed); UNITY_END(); diff --git a/test/animation/test_play_random/test_play_random.cpp b/test/animation/test_play_random/test_play_random.cpp new file mode 100644 index 0000000..a968b41 --- /dev/null +++ b/test/animation/test_play_random/test_play_random.cpp @@ -0,0 +1,103 @@ +#include "internal/Animation.h" +#include "internal/LiveStream.h" +#include "../test/helper.h" +#include + +using namespace BlenderServoAnimation; +using namespace fakeit; + +void setUp(void) { + ArduinoFakeReset(); + resetPositionLog(); +} + +void test_play_random(void) { + Animation animation; + animation.onPositionChange(move); + animation.addScene(PROGMEM_DATA, DATA_SIZE, FPS, FRAMES); + animation.addScene(PROGMEM_DATA, DATA_SIZE, FPS, FRAMES); + animation.addScene(PROGMEM_DATA, DATA_SIZE, FPS, FRAMES); + + TEST_ASSERT_EQUAL(3, animation.countScenes()); + TEST_ASSERT_EQUAL(Animation::MODE_DEFAULT, animation.getMode()); + + When(OverloadedMethod(ArduinoFake(), random, long(long))).Return(1, 0, 2); + + animation.playRandom(); + + TEST_ASSERT_EQUAL(Animation::MODE_PLAY_RANDOM, animation.getMode()); + TEST_ASSERT_NOT_EQUAL(nullptr, animation.getCurrentScene()); + TEST_ASSERT_EQUAL(1, animation.getPlayIndex()); + + for (int i = 0; i < ANIMATION_MICROS; i += FRAME_MICROS) { + animation.run(i); + } + + TEST_ASSERT_EQUAL(Animation::MODE_PLAY_RANDOM, animation.getMode()); + TEST_ASSERT_EQUAL(0, animation.getPlayIndex()); + + for (long i = 0; i < ANIMATION_MICROS; i += FRAME_MICROS) { + animation.run(i); + } + + TEST_ASSERT_EQUAL(Animation::MODE_PLAY_RANDOM, animation.getMode()); + TEST_ASSERT_EQUAL(2, animation.getPlayIndex()); + TEST_ASSERT_EQUAL(20, logIndex); +} + +void test_without_scenes(void) { + Animation animation; + animation.onPositionChange(move); + animation.playRandom(); + TEST_ASSERT_EQUAL(Animation::MODE_DEFAULT, animation.getMode()); +} + +void test_prevented(void) { + LiveStream stream; + Animation animation; + animation.onPositionChange(move); + animation.addScene(stream, FPS, FRAMES); + + animation.loop(); + TEST_ASSERT_EQUAL(Animation::MODE_LOOP, animation.getMode()); + animation.playRandom(); + TEST_ASSERT_EQUAL(Animation::MODE_LOOP, animation.getMode()); + animation.pause(); + animation.play(); + TEST_ASSERT_EQUAL(Animation::MODE_PLAY, animation.getMode()); + animation.playRandom(); + TEST_ASSERT_EQUAL(Animation::MODE_PLAY, animation.getMode()); + animation.pause(); + animation.playSingle(0); + TEST_ASSERT_EQUAL(Animation::MODE_PLAY_SINGLE, animation.getMode()); + animation.playRandom(); + TEST_ASSERT_EQUAL(Animation::MODE_PLAY_SINGLE, animation.getMode()); + animation.stop(); + TEST_ASSERT_EQUAL(Animation::MODE_STOP, animation.getMode()); + animation.playRandom(); + TEST_ASSERT_EQUAL(Animation::MODE_STOP, animation.getMode()); +} + +void test_allowed(void) { + LiveStream stream; + Animation animation; + animation.onPositionChange(move); + animation.addScene(stream, FPS, FRAMES); + + TEST_ASSERT_EQUAL(Animation::MODE_DEFAULT, animation.getMode()); + animation.playRandom(); + TEST_ASSERT_EQUAL(Animation::MODE_PLAY_RANDOM, animation.getMode()); + animation.pause(); + TEST_ASSERT_EQUAL(Animation::MODE_PAUSE, animation.getMode()); + animation.playRandom(); + TEST_ASSERT_EQUAL(Animation::MODE_PLAY_RANDOM, animation.getMode()); +} + +int main(int argc, char **argv) { + UNITY_BEGIN(); + RUN_TEST(test_play_random); + RUN_TEST(test_without_scenes); + RUN_TEST(test_prevented); + RUN_TEST(test_allowed); + UNITY_END(); +} diff --git a/test/animation/test_play_single/test_play_single.cpp b/test/animation/test_play_single/test_play_single.cpp new file mode 100644 index 0000000..0f32f4a --- /dev/null +++ b/test/animation/test_play_single/test_play_single.cpp @@ -0,0 +1,112 @@ +#include "internal/Animation.h" +#include "internal/LiveStream.h" +#include "../test/helper.h" +#include + +using namespace BlenderServoAnimation; +using namespace fakeit; + +void setUp(void) { + ArduinoFakeReset(); + resetPositionLog(); +} + +void test_play_single(void) { + LiveStream stream; + Animation animation; + animation.onPositionChange(move); + animation.addScene(PROGMEM_DATA, DATA_SIZE, FPS, FRAMES); + animation.addScene(PROGMEM_DATA, DATA_SIZE, FPS, FRAMES); + animation.addScene(PROGMEM_DATA, DATA_SIZE, FPS, FRAMES); + + TEST_ASSERT_EQUAL(3, animation.countScenes()); + TEST_ASSERT_EQUAL(Animation::MODE_DEFAULT, animation.getMode()); + + animation.playSingle(2); + + TEST_ASSERT_EQUAL(Animation::MODE_PLAY_SINGLE, animation.getMode()); + TEST_ASSERT_EQUAL(2, animation.getPlayIndex()); + + for (long i = 0; i < ANIMATION_MICROS; i += FRAME_MICROS) { + animation.run(i); + } + + TEST_ASSERT_EQUAL(Animation::MODE_DEFAULT, animation.getMode()); + TEST_ASSERT_EQUAL(10, logIndex); +} + +void test_without_scenes(void) { + Animation animation; + animation.onPositionChange(move); + animation.playSingle(0); + TEST_ASSERT_EQUAL(Animation::MODE_DEFAULT, animation.getMode()); +} + +void test_prevented(void) { + LiveStream stream; + Animation animation; + animation.onPositionChange(move); + animation.addScene(stream, FPS, FRAMES); + + When(OverloadedMethod(ArduinoFake(), random, long(long))).Return(0); + + animation.loop(); + TEST_ASSERT_EQUAL(Animation::MODE_LOOP, animation.getMode()); + animation.playSingle(0); + TEST_ASSERT_EQUAL(Animation::MODE_LOOP, animation.getMode()); + animation.pause(); + animation.play(); + TEST_ASSERT_EQUAL(Animation::MODE_PLAY, animation.getMode()); + animation.playSingle(0); + TEST_ASSERT_EQUAL(Animation::MODE_PLAY, animation.getMode()); + animation.pause(); + animation.playRandom(); + TEST_ASSERT_EQUAL(Animation::MODE_PLAY_RANDOM, animation.getMode()); + animation.playSingle(0); + TEST_ASSERT_EQUAL(Animation::MODE_PLAY_RANDOM, animation.getMode()); + animation.stop(); + TEST_ASSERT_EQUAL(Animation::MODE_STOP, animation.getMode()); + animation.playSingle(0); + TEST_ASSERT_EQUAL(Animation::MODE_STOP, animation.getMode()); +} + +void test_allowed(void) { + LiveStream stream; + Animation animation; + animation.onPositionChange(move); + animation.addScene(stream, FPS, FRAMES); + + TEST_ASSERT_EQUAL(Animation::MODE_DEFAULT, animation.getMode()); + animation.playSingle(0); + TEST_ASSERT_EQUAL(Animation::MODE_PLAY_SINGLE, animation.getMode()); + animation.pause(); + TEST_ASSERT_EQUAL(Animation::MODE_PAUSE, animation.getMode()); + animation.playSingle(0); + TEST_ASSERT_EQUAL(Animation::MODE_PLAY_SINGLE, animation.getMode()); +} + +void test_prevent_sudden_index_change(void) { + Animation animation; + animation.onPositionChange(move); + animation.addScene(PROGMEM_DATA, DATA_SIZE, FPS, FRAMES); + animation.addScene(PROGMEM_DATA, DATA_SIZE, FPS, FRAMES); + + animation.play(); + TEST_ASSERT_EQUAL(Animation::MODE_PLAY, animation.getMode()); + animation.run(FRAME_MICROS); + animation.pause(); + TEST_ASSERT_EQUAL(Animation::MODE_PAUSE, animation.getMode()); + animation.playSingle(1); + TEST_ASSERT_EQUAL(Animation::MODE_PAUSE, animation.getMode()); + TEST_ASSERT_EQUAL(2, logIndex); +} + +int main(int argc, char **argv) { + UNITY_BEGIN(); + RUN_TEST(test_play_single); + RUN_TEST(test_without_scenes); + RUN_TEST(test_prevented); + RUN_TEST(test_allowed); + RUN_TEST(test_prevent_sudden_index_change); + UNITY_END(); +} diff --git a/test/animation/test_stop/test_stop.cpp b/test/animation/test_stop/test_stop.cpp index f4513c0..c688e47 100644 --- a/test/animation/test_stop/test_stop.cpp +++ b/test/animation/test_stop/test_stop.cpp @@ -1,100 +1,120 @@ -#include "../helper.h" -#include "BlenderServoAnimation.h" +#include "internal/Animation.h" +#include "internal/Scene.h" +#include "internal/ProgmemStream.h" +#include "internal/LiveStream.h" +#include "../test/helper.h" #include using namespace BlenderServoAnimation; +using namespace fakeit; void setUp(void) { - setUpHelper(); + ArduinoFakeReset(); + resetPositionLog(); } -const int positions[5] PROGMEM = {350, 340, 330, 340, 330}; -const int positionsB[5] PROGMEM = {250, 240, 230, 240, 230}; - -void test_stop(void) { - Animation animation(FPS, FRAMES); - Servo servos[] = { - Servo(0, positions, move, 10), - Servo(1, positionsB, move, 10), - Servo(2, move, 10), - }; - animation.addServos(servos, 3); +void test_stop(byte mode) { + LiveStream stream; + Animation animation; + animation.onPositionChange(move); + animation.addScene(stream, FPS, FRAMES); + TEST_ASSERT_EQUAL(Animation::MODE_DEFAULT, animation.getMode()); - animation.play(0); - TEST_ASSERT_EQUAL(Animation::MODE_PLAY, animation.getMode()); - animation.run(FRAME_MICROS); - TEST_ASSERT_EQUAL(340, lastPositions[0].positions[0]); - TEST_ASSERT_EQUAL(240, lastPositions[1].positions[0]); - TEST_ASSERT_EQUAL(0, lastPositions[2].positions[0]); - TEST_ASSERT_EQUAL(1, animation.getFrame()); - animation.stop(0); - - for (int i = 0; i < 10; i++) { - animation.run(FRAME_MICROS * (long)(i + 2)); - TEST_ASSERT_EQUAL(341 + i, lastPositions[0].positions[i + 1]); - TEST_ASSERT_EQUAL(241 + i, lastPositions[1].positions[i + 1]); - TEST_ASSERT_EQUAL(0, lastPositions[2].positions[i + 1]); - TEST_ASSERT_EQUAL(Animation::MODE_STOP, animation.getMode()); + + switch (mode) { + case Animation::MODE_PLAY: + animation.play(); + break; + case Animation::MODE_PLAY_SINGLE: + animation.playSingle(0); + break; + case Animation::MODE_PLAY_RANDOM: + animation.playRandom(); + break; + case Animation::MODE_LOOP: + animation.loop(); + break; + } + + TEST_ASSERT_EQUAL(mode, animation.getMode()); + + for (int i = 0; i < FRAME_MICROS * 2; i += FRAME_MICROS) { + animation.run(i); + } + + animation.stop(); + + TEST_ASSERT_EQUAL(Animation::MODE_STOP, animation.getMode()); + + for (int i = FRAME_MICROS * 2; i < FRAME_MICROS * 4; i += FRAME_MICROS) { + animation.run(i); } - animation.run(FRAME_MICROS * (long)12); TEST_ASSERT_EQUAL(Animation::MODE_DEFAULT, animation.getMode()); - TEST_ASSERT_EQUAL(0, animation.getFrame()); } -void test_call_twice(void) { - Animation animation(FPS, FRAMES); - animation.onModeChange(onModeChange); +void test_stop_play(void) { + test_stop(Animation::MODE_PLAY); +} - animation.play(0); - TEST_ASSERT_EQUAL(Animation::MODE_PLAY, animation.getMode()); - animation.stop(0); - TEST_ASSERT_EQUAL(Animation::MODE_STOP, animation.getMode()); - animation.stop(0); - TEST_ASSERT_EQUAL(Animation::MODE_STOP, animation.getMode()); +void test_stop_loop(void) { + test_stop(Animation::MODE_LOOP); +} + +void test_stop_play_single(void) { + test_stop(Animation::MODE_PLAY_SINGLE); +} - TEST_ASSERT_EQUAL(2, modeChangeCount); +void test_stop_play_random(void) { + When(OverloadedMethod(ArduinoFake(), random, long(long))).Return(1); + test_stop(Animation::MODE_PLAY_RANDOM); } void test_prevented(void) { - Animation animation(FPS, FRAMES); + LiveStream stream; + Animation animation; + animation.onPositionChange(move); + animation.addScene(stream, FPS, FRAMES); TEST_ASSERT_EQUAL(Animation::MODE_DEFAULT, animation.getMode()); - animation.stop(0); + animation.stop(); TEST_ASSERT_EQUAL(Animation::MODE_DEFAULT, animation.getMode()); } void test_allowed(void) { - Serial_ mock; - Animation animation(FPS, FRAMES); + LiveStream stream; + Animation animation; + animation.onPositionChange(move); + animation.addScene(stream, FPS, FRAMES); - animation.play(0); + animation.play(); TEST_ASSERT_EQUAL(Animation::MODE_PLAY, animation.getMode()); - animation.stop(0); + animation.stop(); TEST_ASSERT_EQUAL(Animation::MODE_STOP, animation.getMode()); animation.run(10000); - animation.loop(0); - TEST_ASSERT_EQUAL(Animation::MODE_LOOP, animation.getMode()); - animation.stop(0); + animation.playSingle(0); + TEST_ASSERT_EQUAL(Animation::MODE_PLAY_SINGLE, animation.getMode()); + animation.stop(); TEST_ASSERT_EQUAL(Animation::MODE_STOP, animation.getMode()); animation.run(10000); - animation.play(0); - animation.pause(); - TEST_ASSERT_EQUAL(Animation::MODE_PAUSE, animation.getMode()); - animation.stop(0); + animation.playRandom(); + TEST_ASSERT_EQUAL(Animation::MODE_PLAY_RANDOM, animation.getMode()); + animation.stop(); TEST_ASSERT_EQUAL(Animation::MODE_STOP, animation.getMode()); animation.run(10000); - animation.live(mock); - TEST_ASSERT_EQUAL(Animation::MODE_LIVE, animation.getMode()); - animation.stop(0); + animation.loop(); + TEST_ASSERT_EQUAL(Animation::MODE_LOOP, animation.getMode()); + animation.stop(); TEST_ASSERT_EQUAL(Animation::MODE_STOP, animation.getMode()); } int main(int argc, char **argv) { UNITY_BEGIN(); - RUN_TEST(test_stop); - RUN_TEST(test_call_twice); - RUN_TEST(test_prevented); - RUN_TEST(test_allowed); + RUN_TEST(test_stop_play); + // RUN_TEST(test_stop_play_single); + // RUN_TEST(test_stop_play_random); + // RUN_TEST(test_stop_loop); + // RUN_TEST(test_prevented); + // RUN_TEST(test_allowed); UNITY_END(); } diff --git a/test/helper.h b/test/helper.h new file mode 100644 index 0000000..6ea68c5 --- /dev/null +++ b/test/helper.h @@ -0,0 +1,41 @@ +#include + +#define FPS 30 +#define FRAMES 5 +#define FRAME_MICROS 33333 +#define ANIMATION_MICROS 166665 +#define STOP_MICROS 10000 +#define LOG_SIZE 20 +#define DATA_SIZE 55 + +struct positionLog { + byte servoId = 0; + int position = 0; +}; + +positionLog positions[LOG_SIZE]; + +byte logIndex = 0; + +void resetPositionLog(void) { + for (int i = 0; i < LOG_SIZE; i++) { + positions[i].servoId = 0; + positions[i].position = 0; + } + + logIndex = 0; +} + +void move(byte servoID, int position) { + positions[logIndex].servoId = servoID; + positions[logIndex].position = position; + logIndex++; +} + +const byte PROGMEM PROGMEM_DATA[DATA_SIZE] = { + 60, 0, 1, 119, 62, 60, 1, 1, 119, 62, 10, + 60, 0, 1, 120, 62, 60, 1, 1, 120, 62, 10, + 60, 0, 1, 121, 62, 60, 1, 1, 123, 62, 10, + 60, 0, 1, 124, 62, 60, 1, 1, 127, 62, 10, + 60, 0, 1, 128, 62, 60, 1, 1, 132, 62, 10, +}; diff --git a/test/show/test_live/test_live.cpp b/test/show/test_live/test_live.cpp deleted file mode 100644 index c69ffc0..0000000 --- a/test/show/test_live/test_live.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#include "BlenderServoAnimation.h" -#include - -using namespace BlenderServoAnimation; -using namespace fakeit; - -#define FPS 60 -#define FRAMES 5 -#define FRAME_MICROS 16667 - -void setUp(void) { - ArduinoFakeReset(); -} - -void test_without_animations(void) { - Serial_ mock; - Show show; - show.live(mock); - TEST_ASSERT_EQUAL(Show::MODE_DEFAULT, show.getMode()); -} - -void test_prevented(void) { - Animation animation(FPS, FRAMES); - Serial_ mock; - Show show; - show.addAnimation(animation); - - When(OverloadedMethod(ArduinoFake(), random, long(long))).Return(0); - - show.loop(0); - TEST_ASSERT_EQUAL(Show::MODE_LOOP, show.getMode()); - show.live(mock); - TEST_ASSERT_EQUAL(Show::MODE_LOOP, show.getMode()); - show.pause(); - show.play(0); - TEST_ASSERT_EQUAL(Show::MODE_PLAY, show.getMode()); - show.live(mock); - TEST_ASSERT_EQUAL(Show::MODE_PLAY, show.getMode()); - show.pause(); - show.playSingle(0, 0); - TEST_ASSERT_EQUAL(Show::MODE_PLAY_SINGLE, show.getMode()); - show.live(mock); - TEST_ASSERT_EQUAL(Show::MODE_PLAY_SINGLE, show.getMode()); - show.pause(); - show.playRandom(0); - TEST_ASSERT_EQUAL(Show::MODE_PLAY_RANDOM, show.getMode()); - show.live(mock); - TEST_ASSERT_EQUAL(Show::MODE_PLAY_RANDOM, show.getMode()); - show.pause(); - TEST_ASSERT_EQUAL(Show::MODE_PAUSE, show.getMode()); - show.live(mock); - TEST_ASSERT_EQUAL(Show::MODE_PAUSE, show.getMode()); - show.stop(0); - TEST_ASSERT_EQUAL(Show::MODE_STOP, show.getMode()); - show.live(mock); - TEST_ASSERT_EQUAL(Show::MODE_STOP, show.getMode()); -} - -void test_allowed(void) { - Serial_ mock; - Animation animation(FPS, FRAMES); - Show show; - show.addAnimation(animation); - - TEST_ASSERT_EQUAL(Show::MODE_DEFAULT, show.getMode()); - show.live(mock); - TEST_ASSERT_EQUAL(Show::MODE_LIVE, show.getMode()); -} - -int main(int argc, char **argv) { - UNITY_BEGIN(); - RUN_TEST(test_without_animations); - RUN_TEST(test_prevented); - RUN_TEST(test_allowed); - UNITY_END(); -} diff --git a/test/show/test_loop/test_loop.cpp b/test/show/test_loop/test_loop.cpp deleted file mode 100644 index 0b88059..0000000 --- a/test/show/test_loop/test_loop.cpp +++ /dev/null @@ -1,108 +0,0 @@ -#include "BlenderServoAnimation.h" -#include - -using namespace BlenderServoAnimation; -using namespace fakeit; - -#define FPS 60 -#define FRAMES 5 -#define FRAME_MICROS 16667 - -void setUp(void) { - ArduinoFakeReset(); -} - -void test_loop(void) { - Animation animationA(FPS, 4); - Animation animationB(FPS, 5); - - Show show; - show.addAnimation(animationB); - show.addAnimation(animationA); - - TEST_ASSERT_TRUE(show.hasAnimations()); - TEST_ASSERT_EQUAL(2, show.countAnimations()); - - TEST_ASSERT_EQUAL(Show::MODE_DEFAULT, show.getMode()); - - show.loop(0); - - TEST_ASSERT_EQUAL(Show::MODE_LOOP, show.getMode()); - TEST_ASSERT_EQUAL(5, show.getCurrentAnimation()->getFrames()); - - for (long i = 0; i < FRAME_MICROS * (long)6; i += FRAME_MICROS) { - show.run(i); - } - - TEST_ASSERT_EQUAL(Show::MODE_LOOP, show.getMode()); - TEST_ASSERT_EQUAL(4, show.getCurrentAnimation()->getFrames()); - - for (long i = 0; i < FRAME_MICROS * (long)4; i += FRAME_MICROS) { - show.run(i); - } - - TEST_ASSERT_EQUAL(Show::MODE_LOOP, show.getMode()); - TEST_ASSERT_EQUAL(5, show.getCurrentAnimation()->getFrames()); -} - -void test_without_animations(void) { - Show show; - show.loop(0); - TEST_ASSERT_EQUAL(Show::MODE_DEFAULT, show.getMode()); -} - -void test_prevented(void) { - Animation animation(FPS, FRAMES); - Serial_ mock; - Show show; - show.addAnimation(animation); - - When(OverloadedMethod(ArduinoFake(), random, long(long))).Return(0); - - show.play(0); - TEST_ASSERT_EQUAL(Show::MODE_PLAY, show.getMode()); - show.loop(0); - TEST_ASSERT_EQUAL(Show::MODE_PLAY, show.getMode()); - show.pause(); - show.playSingle(0, 0); - TEST_ASSERT_EQUAL(Show::MODE_PLAY_SINGLE, show.getMode()); - show.loop(0); - TEST_ASSERT_EQUAL(Show::MODE_PLAY_SINGLE, show.getMode()); - show.pause(); - show.playRandom(0); - TEST_ASSERT_EQUAL(Show::MODE_PLAY_RANDOM, show.getMode()); - show.loop(0); - TEST_ASSERT_EQUAL(Show::MODE_PLAY_RANDOM, show.getMode()); - show.stop(0); - TEST_ASSERT_EQUAL(Show::MODE_STOP, show.getMode()); - show.loop(0); - TEST_ASSERT_EQUAL(Show::MODE_STOP, show.getMode()); - show.run(10000); - show.live(mock); - TEST_ASSERT_EQUAL(Show::MODE_LIVE, show.getMode()); - show.loop(0); - TEST_ASSERT_EQUAL(Show::MODE_LIVE, show.getMode()); -} - -void test_allowed(void) { - Animation animation(FPS, FRAMES); - Show show; - show.addAnimation(animation); - - TEST_ASSERT_EQUAL(Show::MODE_DEFAULT, show.getMode()); - show.loop(0); - TEST_ASSERT_EQUAL(Show::MODE_LOOP, show.getMode()); - show.pause(); - TEST_ASSERT_EQUAL(Show::MODE_PAUSE, show.getMode()); - show.loop(0); - TEST_ASSERT_EQUAL(Show::MODE_LOOP, show.getMode()); -} - -int main(int argc, char **argv) { - UNITY_BEGIN(); - RUN_TEST(test_loop); - RUN_TEST(test_without_animations); - RUN_TEST(test_prevented); - RUN_TEST(test_allowed); - UNITY_END(); -} diff --git a/test/show/test_mode_callback/test_mode_callback.cpp b/test/show/test_mode_callback/test_mode_callback.cpp deleted file mode 100644 index 041ab61..0000000 --- a/test/show/test_mode_callback/test_mode_callback.cpp +++ /dev/null @@ -1,104 +0,0 @@ -#include "BlenderServoAnimation.h" -#include - -using namespace BlenderServoAnimation; - -#define FPS 60 -#define FRAMES 5 - -int prevMode = -1; -int newMode = -1; - -void setUp(void) { - prevMode = -1; - newMode = -1; -} - -void onModeChange(byte prevArg, byte newArg) { - prevMode = prevArg; - newMode = newArg; -} - -void test_different_mode(void) { - Show show; - Animation animationA(FPS, FRAMES); - Animation animationB(FPS, FRAMES); - show.addAnimation(animationA); - show.addAnimation(animationB); - show.onModeChange(onModeChange); - - TEST_ASSERT_EQUAL(-1, prevMode); - TEST_ASSERT_EQUAL(-1, newMode); - show.playSingle(1, 0); - TEST_ASSERT_EQUAL(Show::MODE_DEFAULT, prevMode); - TEST_ASSERT_EQUAL(Show::MODE_PLAY_SINGLE, newMode); - TEST_ASSERT_EQUAL(1, show.getPlayIndex()); - show.pause(); - TEST_ASSERT_EQUAL(Show::MODE_PLAY_SINGLE, prevMode); - TEST_ASSERT_EQUAL(Show::MODE_PAUSE, newMode); -} - -void test_same_mode(void) { - Show show; - Animation animation(FPS, FRAMES); - show.addAnimation(animation); - show.onModeChange(onModeChange); - - show.loop(0); - TEST_ASSERT_EQUAL(Show::MODE_DEFAULT, prevMode); - TEST_ASSERT_EQUAL(Show::MODE_LOOP, newMode); - show.loop(0); - TEST_ASSERT_EQUAL(Show::MODE_DEFAULT, prevMode); - TEST_ASSERT_EQUAL(Show::MODE_LOOP, newMode); -} - -void test_all_modes(void) { - Serial_ mock; - Show show; - Animation animation(FPS, FRAMES); - show.addAnimation(animation); - show.onModeChange(onModeChange); - - show.play(0); - TEST_ASSERT_EQUAL(Show::MODE_DEFAULT, prevMode); - TEST_ASSERT_EQUAL(Show::MODE_PLAY, newMode); - TEST_ASSERT_EQUAL(0, show.getPlayIndex()); - show.pause(); - TEST_ASSERT_EQUAL(Show::MODE_PLAY, prevMode); - TEST_ASSERT_EQUAL(Show::MODE_PAUSE, newMode); - TEST_ASSERT_EQUAL(0, show.getPlayIndex()); - show.playRandom(0); - TEST_ASSERT_EQUAL(Show::MODE_PAUSE, prevMode); - TEST_ASSERT_EQUAL(Show::MODE_PLAY_RANDOM, newMode); - TEST_ASSERT_EQUAL(0, show.getPlayIndex()); - show.pause(); - show.playSingle(0, 0); - TEST_ASSERT_EQUAL(Show::MODE_PAUSE, prevMode); - TEST_ASSERT_EQUAL(Show::MODE_PLAY_SINGLE, newMode); - TEST_ASSERT_EQUAL(0, show.getPlayIndex()); - show.pause(); - show.loop(0); - TEST_ASSERT_EQUAL(Show::MODE_PAUSE, prevMode); - TEST_ASSERT_EQUAL(Show::MODE_LOOP, newMode); - TEST_ASSERT_EQUAL(0, show.getPlayIndex()); - show.stop(0); - TEST_ASSERT_EQUAL(Show::MODE_LOOP, prevMode); - TEST_ASSERT_EQUAL(Show::MODE_STOP, newMode); - TEST_ASSERT_EQUAL(0, show.getPlayIndex()); - show.run(10000); - TEST_ASSERT_EQUAL(Show::MODE_STOP, prevMode); - TEST_ASSERT_EQUAL(Show::MODE_DEFAULT, newMode); - TEST_ASSERT_EQUAL(0, show.getPlayIndex()); - show.live(mock); - TEST_ASSERT_EQUAL(Show::MODE_DEFAULT, prevMode); - TEST_ASSERT_EQUAL(Show::MODE_LIVE, newMode); - TEST_ASSERT_EQUAL(0, show.getPlayIndex()); -} - -int main(int argc, char **argv) { - UNITY_BEGIN(); - RUN_TEST(test_different_mode); - RUN_TEST(test_same_mode); - RUN_TEST(test_all_modes); - UNITY_END(); -} diff --git a/test/show/test_pause/test_pause.cpp b/test/show/test_pause/test_pause.cpp deleted file mode 100644 index 2d5b305..0000000 --- a/test/show/test_pause/test_pause.cpp +++ /dev/null @@ -1,141 +0,0 @@ -#include "BlenderServoAnimation.h" -#include - -using namespace BlenderServoAnimation; -using namespace fakeit; - -#define FPS 60 -#define FRAMES 5 -#define FRAME_MICROS 16667 - -void setUp(void) { - ArduinoFakeReset(); -} - -void test_pause(byte mode) { - Animation animationA(FPS, FRAMES); - Animation animationB(FPS, FRAMES); - - Show show; - show.addAnimation(animationA); - show.addAnimation(animationB); - - TEST_ASSERT_EQUAL(Show::MODE_DEFAULT, show.getMode()); - - switch (mode) { - case Show::MODE_PLAY: - show.play(0); - break; - case Show::MODE_PLAY_SINGLE: - show.playSingle(0, 0); - break; - case Show::MODE_PLAY_RANDOM: - show.playRandom(0); - break; - case Show::MODE_LOOP: - show.loop(0); - break; - } - - TEST_ASSERT_EQUAL(mode, show.getMode()); - TEST_ASSERT_EQUAL(0, show.getCurrentAnimation()->getFrame()); - - for (long i = 0; i < FRAME_MICROS * (long)3; i += FRAME_MICROS) { - show.run(i); - } - - TEST_ASSERT_EQUAL(2, show.getCurrentAnimation()->getFrame()); - - show.pause(); - - for (long i = 0; i < FRAME_MICROS * (long)3; i += FRAME_MICROS) { - show.run(i); - } - - TEST_ASSERT_EQUAL(Show::MODE_PAUSE, show.getMode()); - TEST_ASSERT_EQUAL(2, show.getCurrentAnimation()->getFrame()); - - switch (mode) { - case Show::MODE_PLAY: - show.play(0); - break; - case Show::MODE_PLAY_SINGLE: - show.playSingle(0, 0); - break; - case Show::MODE_PLAY_RANDOM: - show.playRandom(0); - break; - case Show::MODE_LOOP: - show.loop(0); - break; - } - - show.run(FRAME_MICROS); - - TEST_ASSERT_EQUAL(mode, show.getMode()); - TEST_ASSERT_EQUAL(3, show.getCurrentAnimation()->getFrame()); -} - -void test_pause_play(void) { - test_pause(Show::MODE_PLAY); -} - -void test_pause_loop(void) { - test_pause(Show::MODE_LOOP); -} - -void test_pause_play_single(void) { - test_pause(Show::MODE_PLAY_SINGLE); -} - -void test_pause_play_random(void) { - When(OverloadedMethod(ArduinoFake(), random, long(long))).Return(1, 0); - test_pause(Show::MODE_PLAY_RANDOM); -} - -void test_prevented(void) { - Serial_ mock; - Animation animation(FPS, FRAMES); - Show show; - show.addAnimation(animation); - - TEST_ASSERT_EQUAL(Show::MODE_DEFAULT, show.getMode()); - show.pause(); - TEST_ASSERT_EQUAL(Show::MODE_DEFAULT, show.getMode()); - show.play(0); - show.stop(0); - TEST_ASSERT_EQUAL(Show::MODE_STOP, show.getMode()); - show.pause(); - TEST_ASSERT_EQUAL(Show::MODE_STOP, show.getMode()); - show.run(10000); - show.live(mock); - TEST_ASSERT_EQUAL(Show::MODE_LIVE, show.getMode()); - show.pause(); - TEST_ASSERT_EQUAL(Show::MODE_LIVE, show.getMode()); -} - -void test_allowed(void) { - Animation animation(FPS, FRAMES); - Show show; - show.addAnimation(animation); - - show.play(0); - TEST_ASSERT_EQUAL(Show::MODE_PLAY, show.getMode()); - show.pause(); - TEST_ASSERT_EQUAL(Show::MODE_PAUSE, show.getMode()); - show.loop(0); - TEST_ASSERT_EQUAL(Show::MODE_LOOP, show.getMode()); - show.pause(); - TEST_ASSERT_EQUAL(Show::MODE_PAUSE, show.getMode()); -} - -int main(int argc, char **argv) { - UNITY_BEGIN(); - RUN_TEST(test_pause_play); - RUN_TEST(test_pause_loop); - RUN_TEST(test_pause_play_single); - RUN_TEST(test_pause_play_random); - RUN_TEST(test_prevented); - RUN_TEST(test_allowed); - UNITY_END(); -} diff --git a/test/show/test_play/test_play.cpp b/test/show/test_play/test_play.cpp deleted file mode 100644 index 65eca15..0000000 --- a/test/show/test_play/test_play.cpp +++ /dev/null @@ -1,117 +0,0 @@ -#include "BlenderServoAnimation.h" -#include - -using namespace BlenderServoAnimation; -using namespace fakeit; - -#define FPS 60 -#define FRAMES 5 -#define FRAME_MICROS 16667 - -void setUp(void) { - ArduinoFakeReset(); -} - -void test_play(void) { - Animation animationA(FPS, 5); - Animation animationB(FPS, 4); - - Show show; - - TEST_ASSERT_FALSE(show.hasAnimations()); - TEST_ASSERT_EQUAL(0, show.countAnimations()); - TEST_ASSERT_FALSE(show.hasAnimation(0)); - TEST_ASSERT_FALSE(show.hasAnimation(1)); - TEST_ASSERT_EQUAL(nullptr, show.getCurrentAnimation()); - - show.addAnimation(animationB); - show.addAnimation(animationA); - - TEST_ASSERT_TRUE(show.hasAnimations()); - TEST_ASSERT_EQUAL(2, show.countAnimations()); - TEST_ASSERT_TRUE(show.hasAnimation(0)); - TEST_ASSERT_TRUE(show.hasAnimation(1)); - - TEST_ASSERT_EQUAL(Show::MODE_DEFAULT, show.getMode()); - - show.play(0); - - TEST_ASSERT_EQUAL(Show::MODE_PLAY, show.getMode()); - TEST_ASSERT_NOT_EQUAL(nullptr, show.getCurrentAnimation()); - TEST_ASSERT_EQUAL(4, show.getCurrentAnimation()->getFrames()); - - for (long i = 0; i < FRAME_MICROS * (long)5; i += FRAME_MICROS) { - show.run(i); - } - - TEST_ASSERT_EQUAL(Show::MODE_PLAY, show.getMode()); - TEST_ASSERT_EQUAL(5, show.getCurrentAnimation()->getFrames()); - - for (long i = 0; i < FRAME_MICROS * (long)5; i += FRAME_MICROS) { - show.run(i); - } - - TEST_ASSERT_EQUAL(Show::MODE_DEFAULT, show.getMode()); -} - -void test_without_animations(void) { - Show show; - show.play(0); - TEST_ASSERT_EQUAL(Show::MODE_DEFAULT, show.getMode()); -} - -void test_prevented(void) { - Animation animation(FPS, FRAMES); - Serial_ mock; - Show show; - show.addAnimation(animation); - - When(OverloadedMethod(ArduinoFake(), random, long(long))).Return(0); - - show.loop(0); - TEST_ASSERT_EQUAL(Show::MODE_LOOP, show.getMode()); - show.play(0); - TEST_ASSERT_EQUAL(Show::MODE_LOOP, show.getMode()); - show.pause(); - show.playSingle(0, 0); - TEST_ASSERT_EQUAL(Show::MODE_PLAY_SINGLE, show.getMode()); - show.play(0); - TEST_ASSERT_EQUAL(Show::MODE_PLAY_SINGLE, show.getMode()); - show.pause(); - show.playRandom(0); - TEST_ASSERT_EQUAL(Show::MODE_PLAY_RANDOM, show.getMode()); - show.play(0); - TEST_ASSERT_EQUAL(Show::MODE_PLAY_RANDOM, show.getMode()); - show.stop(0); - TEST_ASSERT_EQUAL(Show::MODE_STOP, show.getMode()); - show.play(0); - TEST_ASSERT_EQUAL(Show::MODE_STOP, show.getMode()); - show.run(10000); - show.live(mock); - TEST_ASSERT_EQUAL(Show::MODE_LIVE, show.getMode()); - show.play(0); - TEST_ASSERT_EQUAL(Show::MODE_LIVE, show.getMode()); -} - -void test_allowed(void) { - Animation animation(FPS, FRAMES); - Show show; - show.addAnimation(animation); - - TEST_ASSERT_EQUAL(Show::MODE_DEFAULT, show.getMode()); - show.play(0); - TEST_ASSERT_EQUAL(Show::MODE_PLAY, show.getMode()); - show.pause(); - TEST_ASSERT_EQUAL(Show::MODE_PAUSE, show.getMode()); - show.play(0); - TEST_ASSERT_EQUAL(Show::MODE_PLAY, show.getMode()); -} - -int main(int argc, char **argv) { - UNITY_BEGIN(); - RUN_TEST(test_play); - RUN_TEST(test_without_animations); - RUN_TEST(test_prevented); - RUN_TEST(test_allowed); - UNITY_END(); -} diff --git a/test/show/test_play_random/test_play_random.cpp b/test/show/test_play_random/test_play_random.cpp deleted file mode 100644 index 03c3422..0000000 --- a/test/show/test_play_random/test_play_random.cpp +++ /dev/null @@ -1,108 +0,0 @@ -#include "BlenderServoAnimation.h" -#include - -using namespace BlenderServoAnimation; -using namespace fakeit; - -#define FPS 60 -#define FRAMES 5 -#define FRAME_MICROS 16667 - -void setUp(void) { - ArduinoFakeReset(); -} - -void test_play_random(void) { - Animation animations[3] = { - {FPS, 2}, - {FPS, 3}, - {FPS, 4}, - }; - - Show show; - show.addAnimations(animations, 3); - - TEST_ASSERT_EQUAL(3, show.countAnimations()); - TEST_ASSERT_EQUAL(Show::MODE_DEFAULT, show.getMode()); - - When(OverloadedMethod(ArduinoFake(), random, long(long))).Return(1, 0, 2); - - show.playRandom(0); - - TEST_ASSERT_EQUAL(Show::MODE_PLAY_RANDOM, show.getMode()); - TEST_ASSERT_EQUAL(3, show.getCurrentAnimation()->getFrames()); - - for (long i = 0; i < FRAME_MICROS * (long)4; i += FRAME_MICROS) { - show.run(i); - } - - TEST_ASSERT_EQUAL(Show::MODE_PLAY_RANDOM, show.getMode()); - TEST_ASSERT_EQUAL(2, show.getCurrentAnimation()->getFrames()); - - for (long i = 0; i < FRAME_MICROS * (long)2; i += FRAME_MICROS) { - show.run(i); - } - - TEST_ASSERT_EQUAL(Show::MODE_PLAY_RANDOM, show.getMode()); - TEST_ASSERT_EQUAL(4, show.getCurrentAnimation()->getFrames()); -} - -void test_without_animations(void) { - Show show; - show.playRandom(0); - TEST_ASSERT_EQUAL(Show::MODE_DEFAULT, show.getMode()); -} - -void test_prevented(void) { - Animation animation(FPS, FRAMES); - Serial_ mock; - Show show; - show.addAnimation(animation); - - show.loop(0); - TEST_ASSERT_EQUAL(Show::MODE_LOOP, show.getMode()); - show.playRandom(0); - TEST_ASSERT_EQUAL(Show::MODE_LOOP, show.getMode()); - show.pause(); - show.play(0); - TEST_ASSERT_EQUAL(Show::MODE_PLAY, show.getMode()); - show.playRandom(0); - TEST_ASSERT_EQUAL(Show::MODE_PLAY, show.getMode()); - show.pause(); - show.playSingle(0, 0); - TEST_ASSERT_EQUAL(Show::MODE_PLAY_SINGLE, show.getMode()); - show.playRandom(0); - TEST_ASSERT_EQUAL(Show::MODE_PLAY_SINGLE, show.getMode()); - show.stop(0); - TEST_ASSERT_EQUAL(Show::MODE_STOP, show.getMode()); - show.playRandom(0); - TEST_ASSERT_EQUAL(Show::MODE_STOP, show.getMode()); - show.run(10000); - show.live(mock); - TEST_ASSERT_EQUAL(Show::MODE_LIVE, show.getMode()); - show.playRandom(0); - TEST_ASSERT_EQUAL(Show::MODE_LIVE, show.getMode()); -} - -void test_allowed(void) { - Animation animation(FPS, FRAMES); - Show show; - show.addAnimation(animation); - - TEST_ASSERT_EQUAL(Show::MODE_DEFAULT, show.getMode()); - show.playRandom(0); - TEST_ASSERT_EQUAL(Show::MODE_PLAY_RANDOM, show.getMode()); - show.pause(); - TEST_ASSERT_EQUAL(Show::MODE_PAUSE, show.getMode()); - show.playRandom(0); - TEST_ASSERT_EQUAL(Show::MODE_PLAY_RANDOM, show.getMode()); -} - -int main(int argc, char **argv) { - UNITY_BEGIN(); - RUN_TEST(test_play_random); - RUN_TEST(test_without_animations); - RUN_TEST(test_prevented); - RUN_TEST(test_allowed); - UNITY_END(); -} diff --git a/test/show/test_play_single/test_play_single.cpp b/test/show/test_play_single/test_play_single.cpp deleted file mode 100644 index a796e6f..0000000 --- a/test/show/test_play_single/test_play_single.cpp +++ /dev/null @@ -1,118 +0,0 @@ -#include "BlenderServoAnimation.h" -#include - -using namespace BlenderServoAnimation; -using namespace fakeit; - -#define FPS 60 -#define FRAMES 5 -#define FRAME_MICROS 16667 - -void setUp(void) { - ArduinoFakeReset(); -} - -void test_play_single(void) { - Animation animations[4] = { - {FPS, FRAMES}, - {FPS, FRAMES}, - {FPS, 4}, - {FPS, FRAMES}, - }; - - Show show; - show.addAnimations(animations, 4); - - TEST_ASSERT_EQUAL(4, show.countAnimations()); - TEST_ASSERT_EQUAL(Show::MODE_DEFAULT, show.getMode()); - - show.playSingle(2, 0); - - TEST_ASSERT_EQUAL(Show::MODE_PLAY_SINGLE, show.getMode()); - TEST_ASSERT_EQUAL(4, show.getCurrentAnimation()->getFrames()); - - for (long i = 0; i < FRAME_MICROS * (long)6; i += FRAME_MICROS) { - show.run(i); - } - - TEST_ASSERT_EQUAL(Show::MODE_DEFAULT, show.getMode()); -} - -void test_without_animations(void) { - Show show; - show.playSingle(0, 0); - TEST_ASSERT_EQUAL(Show::MODE_DEFAULT, show.getMode()); -} - -void test_prevented(void) { - Animation animation(FPS, FRAMES); - Serial_ mock; - Show show; - show.addAnimation(animation); - - When(OverloadedMethod(ArduinoFake(), random, long(long))).Return(0); - - show.loop(0); - TEST_ASSERT_EQUAL(Show::MODE_LOOP, show.getMode()); - show.playSingle(0, 0); - TEST_ASSERT_EQUAL(Show::MODE_LOOP, show.getMode()); - show.pause(); - show.play(0); - TEST_ASSERT_EQUAL(Show::MODE_PLAY, show.getMode()); - show.playSingle(0, 0); - TEST_ASSERT_EQUAL(Show::MODE_PLAY, show.getMode()); - show.pause(); - show.playRandom(0); - TEST_ASSERT_EQUAL(Show::MODE_PLAY_RANDOM, show.getMode()); - show.playSingle(0, 0); - TEST_ASSERT_EQUAL(Show::MODE_PLAY_RANDOM, show.getMode()); - show.stop(0); - TEST_ASSERT_EQUAL(Show::MODE_STOP, show.getMode()); - show.playSingle(0, 0); - TEST_ASSERT_EQUAL(Show::MODE_STOP, show.getMode()); - show.run(10000); - show.live(mock); - TEST_ASSERT_EQUAL(Show::MODE_LIVE, show.getMode()); - show.playSingle(0, 0); - TEST_ASSERT_EQUAL(Show::MODE_LIVE, show.getMode()); -} - -void test_allowed(void) { - Animation animation(FPS, FRAMES); - Show show; - show.addAnimation(animation); - - TEST_ASSERT_EQUAL(Show::MODE_DEFAULT, show.getMode()); - show.playSingle(0, 0); - TEST_ASSERT_EQUAL(Show::MODE_PLAY_SINGLE, show.getMode()); - show.pause(); - TEST_ASSERT_EQUAL(Show::MODE_PAUSE, show.getMode()); - show.playSingle(0, 0); - TEST_ASSERT_EQUAL(Show::MODE_PLAY_SINGLE, show.getMode()); -} - -void test_prevent_sudden_index_change(void) { - Show show; - Animation animationA(FPS, FRAMES); - Animation animationB(FPS, FRAMES); - show.addAnimation(animationA); - show.addAnimation(animationB); - - show.play(0); - TEST_ASSERT_EQUAL(Show::MODE_PLAY, show.getMode()); - show.run(FRAME_MICROS); - show.pause(); - TEST_ASSERT_EQUAL(Show::MODE_PAUSE, show.getMode()); - show.playSingle(1, 0); - TEST_ASSERT_EQUAL(Show::MODE_PAUSE, show.getMode()); -} - -int main(int argc, char **argv) { - UNITY_BEGIN(); - RUN_TEST(test_play_single); - RUN_TEST(test_without_animations); - RUN_TEST(test_prevented); - RUN_TEST(test_allowed); - RUN_TEST(test_prevent_sudden_index_change); - UNITY_END(); -} diff --git a/test/show/test_stop/test_stop.cpp b/test/show/test_stop/test_stop.cpp deleted file mode 100644 index 0f5afaf..0000000 --- a/test/show/test_stop/test_stop.cpp +++ /dev/null @@ -1,143 +0,0 @@ -#include "BlenderServoAnimation.h" -#include - -using namespace BlenderServoAnimation; -using namespace fakeit; - -#define FPS 60 -#define FRAMES 5 -#define FRAME_MICROS 16667 - -void setUp(void) { - ArduinoFakeReset(); -} - -const int positionsA[5] PROGMEM = {350, 340, 330, 340, 330}; -const int positionsB[5] PROGMEM = {250, 240, 230, 240, 230}; - -void test_stop(byte mode) { - Animation animationA(FPS, FRAMES); - Animation animationB(FPS, FRAMES); - - Serial_ mock; - Show show; - show.addAnimation(animationA); - show.addAnimation(animationB); - - TEST_ASSERT_EQUAL(Show::MODE_DEFAULT, show.getMode()); - - switch (mode) { - case Show::MODE_PLAY: - show.play(0); - break; - case Show::MODE_PLAY_SINGLE: - show.playSingle(0, 0); - break; - case Show::MODE_PLAY_RANDOM: - show.playRandom(0); - break; - case Show::MODE_LOOP: - show.loop(0); - break; - case Show::MODE_LIVE: - show.live(mock); - break; - } - - TEST_ASSERT_EQUAL(mode, show.getMode()); - TEST_ASSERT_EQUAL(0, show.getCurrentAnimation()->getFrame()); - - for (long i = 0; i < FRAME_MICROS * (long)3; i += FRAME_MICROS) { - show.run(i); - } - - if (mode != Show::MODE_LIVE) { - TEST_ASSERT_EQUAL(2, show.getCurrentAnimation()->getFrame()); - } - - show.stop(0); - - TEST_ASSERT_EQUAL(Show::MODE_STOP, show.getMode()); - - for (long i = 0; i < FRAME_MICROS * (long)3; i += FRAME_MICROS) { - show.run(i); - } - - TEST_ASSERT_EQUAL(Show::MODE_DEFAULT, show.getMode()); - TEST_ASSERT_EQUAL(0, show.getCurrentAnimation()->getFrame()); -} - -void test_stop_play(void) { - test_stop(Show::MODE_PLAY); -} - -void test_stop_loop(void) { - test_stop(Show::MODE_LOOP); -} - -void test_stop_play_single(void) { - test_stop(Show::MODE_PLAY_SINGLE); -} - -void test_stop_play_random(void) { - When(OverloadedMethod(ArduinoFake(), random, long(long))).Return(1); - test_stop(Show::MODE_PLAY_RANDOM); -} - -void test_stop_live(void) { - test_stop(Show::MODE_LIVE); -} - -void test_prevented(void) { - Animation animation(FPS, FRAMES); - Show show; - show.addAnimation(animation); - - TEST_ASSERT_EQUAL(Show::MODE_DEFAULT, show.getMode()); - show.stop(0); - TEST_ASSERT_EQUAL(Show::MODE_DEFAULT, show.getMode()); -} - -void test_allowed(void) { - Serial_ mock; - Animation animation(FPS, FRAMES); - Show show; - show.addAnimation(animation); - - show.play(0); - TEST_ASSERT_EQUAL(Show::MODE_PLAY, show.getMode()); - show.stop(0); - TEST_ASSERT_EQUAL(Show::MODE_STOP, show.getMode()); - show.run(10000); - show.playSingle(0, 0); - TEST_ASSERT_EQUAL(Show::MODE_PLAY_SINGLE, show.getMode()); - show.stop(0); - TEST_ASSERT_EQUAL(Show::MODE_STOP, show.getMode()); - show.run(10000); - show.playRandom(0); - TEST_ASSERT_EQUAL(Show::MODE_PLAY_RANDOM, show.getMode()); - show.stop(0); - TEST_ASSERT_EQUAL(Show::MODE_STOP, show.getMode()); - show.run(10000); - show.loop(0); - TEST_ASSERT_EQUAL(Show::MODE_LOOP, show.getMode()); - show.stop(0); - TEST_ASSERT_EQUAL(Show::MODE_STOP, show.getMode()); - show.run(10000); - show.live(mock); - TEST_ASSERT_EQUAL(Show::MODE_LIVE, show.getMode()); - show.stop(0); - TEST_ASSERT_EQUAL(Show::MODE_STOP, show.getMode()); -} - -int main(int argc, char **argv) { - UNITY_BEGIN(); - RUN_TEST(test_stop_play); - RUN_TEST(test_stop_play_single); - RUN_TEST(test_stop_play_random); - RUN_TEST(test_stop_loop); - RUN_TEST(test_stop_live); - RUN_TEST(test_prevented); - RUN_TEST(test_allowed); - UNITY_END(); -} diff --git a/test/test_live_command/test_live_command.cpp b/test/test_command/test_command.cpp similarity index 50% rename from test/test_live_command/test_live_command.cpp rename to test/test_command/test_command.cpp index a99e130..a375be3 100644 --- a/test/test_live_command/test_live_command.cpp +++ b/test/test_command/test_command.cpp @@ -1,24 +1,20 @@ -#include "BlenderServoAnimation.h" +#include "internal/Command.h" #include using namespace BlenderServoAnimation; void test_valid(void) { byte values[5] = {60, 3, 1, 119, 62}; - LiveStream mock; - LiveCommand command = LiveCommand(); + Command command; for (int i = 0; i < 5; i++) { - mock.write(values[i]); - command.read(&mock); + command.write(values[i]); if (i == 4) { - TEST_ASSERT_TRUE(command.isComplete()); TEST_ASSERT_TRUE(command.isValid()); TEST_ASSERT_EQUAL(3, command.getServoID()); TEST_ASSERT_EQUAL(375, command.getServoPosition()); } else { - TEST_ASSERT_FALSE(command.isComplete()); TEST_ASSERT_FALSE(command.isValid()); } } @@ -26,42 +22,25 @@ void test_valid(void) { void test_invalid(void) { byte values[5] = {60, 3, 1, 119, 0}; - LiveStream mock; - LiveCommand command = LiveCommand(); + Command command; for (int i = 0; i < 5; i++) { - mock.write(values[i]); - command.read(&mock); - - if (i == 4) { - TEST_ASSERT_TRUE(command.isComplete()); - } else { - TEST_ASSERT_FALSE(command.isComplete()); - } - + command.write(values[i]); + TEST_ASSERT_FALSE(command.isValid()); } } void test_incomplete(void) { byte values[13] = {60, 3, 1, 60, 3, 1, 119, 62, 60, 3, 1, 144, 62}; - LiveStream mock; - LiveCommand command = LiveCommand(); + Command command; for (int i = 0; i < 13; i++) { - mock.write(values[i]); - command.read(&mock); + command.write(values[i]); - if (i == 12) { - TEST_ASSERT_TRUE(command.isComplete()); + if (i == 7 || i == 12) { TEST_ASSERT_TRUE(command.isValid()); - TEST_ASSERT_EQUAL(3, command.getServoID()); - TEST_ASSERT_EQUAL(400, command.getServoPosition()); - } else if (i >= 4 && i < 8) { - TEST_ASSERT_TRUE(command.isComplete()); - TEST_ASSERT_FALSE(command.isValid()); } else { - TEST_ASSERT_FALSE(command.isComplete()); TEST_ASSERT_FALSE(command.isValid()); } } diff --git a/test/test_live_stream/test_live_stream.cpp b/test/test_live_stream/test_live_stream.cpp new file mode 100644 index 0000000..f861b30 --- /dev/null +++ b/test/test_live_stream/test_live_stream.cpp @@ -0,0 +1,48 @@ +#include "internal/LiveStream.h" +#include + +using namespace BlenderServoAnimation; + +void test_read_write(void) { + LiveStream stream; + + TEST_ASSERT_FALSE(stream.available()); + + for (int i = 0; i < 200; i += 20) { + for (int x = i; x < i + 20; x++) { + TEST_ASSERT_EQUAL(1, stream.write(x)); + } + + TEST_ASSERT_EQUAL(20, stream.available()); + TEST_ASSERT_EQUAL(i, stream.peek()); + + for (int x = i; x < i + 20; x++) { + TEST_ASSERT_EQUAL(x, stream.read()); + } + } + + TEST_ASSERT_EQUAL(0, stream.available()); + TEST_ASSERT_EQUAL(-1, stream.peek()); +} + +void test_flush(void) { + byte values[5] = {60, 3, 1, 119, 62}; + LiveStream stream; + + for (int i = 0; i < 5; i++) { + TEST_ASSERT_EQUAL(1, stream.write(values[i])); + } + + stream.flush(); + + for (int i = 0; i < 5; i++) { + TEST_ASSERT_EQUAL(0, stream.read()); + } +} + +int main(int argc, char **argv) { + UNITY_BEGIN(); + RUN_TEST(test_read_write); + RUN_TEST(test_flush); + UNITY_END(); +} \ No newline at end of file diff --git a/test/test_progmem_stream/test_progmem_stream.cpp b/test/test_progmem_stream/test_progmem_stream.cpp new file mode 100644 index 0000000..752b327 --- /dev/null +++ b/test/test_progmem_stream/test_progmem_stream.cpp @@ -0,0 +1,28 @@ +#include "internal/ProgmemStream.h" +#include + +using namespace BlenderServoAnimation; + +const byte PROGMEM values[5] = {60, 3, 1, 119, 62}; + +void test_read(void) { + ProgmemStream stream(values, 5); + + TEST_ASSERT_EQUAL(5, stream.available()); + TEST_ASSERT_EQUAL(60, stream.peek()); + + byte exp[5] = {60, 3, 1, 119, 62}; + + for (int i = 0; i < 5; i++) { + TEST_ASSERT_EQUAL(exp[i], stream.read()); + } + + TEST_ASSERT_EQUAL(0, stream.available()); + TEST_ASSERT_EQUAL(-1, stream.peek()); +} + +int main(int argc, char **argv) { + UNITY_BEGIN(); + RUN_TEST(test_read); + UNITY_END(); +} \ No newline at end of file diff --git a/test/test_scene/test_scene.cpp b/test/test_scene/test_scene.cpp new file mode 100644 index 0000000..164b211 --- /dev/null +++ b/test/test_scene/test_scene.cpp @@ -0,0 +1,159 @@ +#include "internal/Scene.h" +#include "internal/ProgmemStream.h" +#include "../test/helper.h" +#include + +using namespace BlenderServoAnimation; + +void setUp(void) { + resetPositionLog(); +} + +void test_play_with_frames(void) { + ServoManager servoManager; + servoManager.setPositionCallback(move); + ProgmemStream stream(PROGMEM_DATA, DATA_SIZE); + Scene scene(servoManager, stream, FPS, FRAMES); + + positionLog exp[10] = { + {0, 375}, + {1, 375}, + {0, 376}, + {1, 376}, + {0, 377}, + {1, 379}, + {0, 380}, + {1, 383}, + {0, 384}, + {1, 388}, + }; + + for (int i = 0; i < ANIMATION_MICROS; i += FRAME_MICROS) { + scene.play(i); + } + + 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_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); + + 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}, + }; + + for (int i = 0; i < FRAME_MICROS * 4; i += FRAME_MICROS) { + scene.play(i); + } + + TEST_ASSERT_FALSE(scene.hasFinished()); + TEST_ASSERT_EQUAL(4, scene.getFrame()); + TEST_ASSERT_EQUAL(8, logIndex); + + for (int i = 0; i < STOP_MICROS * 10; i += STOP_MICROS) { + scene.stop(i); + } + + TEST_ASSERT_EQUAL(0, scene.getFrame()); + TEST_ASSERT_EQUAL(15, logIndex); + + for (byte i = 0; i < 15; i++) { + TEST_ASSERT_EQUAL(exp[i].servoId, positions[i].servoId); + TEST_ASSERT_EQUAL(exp[i].position, positions[i].position); + } +} + +void test_has_finished(void) { + ServoManager servoManager; + ProgmemStream stream(PROGMEM_DATA, DATA_SIZE); + Scene scene(servoManager, stream, FPS, FRAMES); + + TEST_ASSERT_FALSE(scene.hasFinished()); + + for (byte i = 0; i < FRAMES; i++) { + scene.play(i * FRAME_MICROS); + + if (i == FRAMES - 1) { + TEST_ASSERT_TRUE(scene.hasFinished()); + } else { + TEST_ASSERT_FALSE(scene.hasFinished()); + } + } +} + +void test_get_frame(void) { + ServoManager servoManager; + ProgmemStream stream(PROGMEM_DATA, DATA_SIZE); + Scene scene(servoManager, stream, FPS, FRAMES); + + TEST_ASSERT_EQUAL(0, scene.getFrame()); + + for (int i = 0; i < FRAMES; i++) { + scene.play(i * FRAME_MICROS); + + TEST_ASSERT_EQUAL(i + 1, scene.getFrame()); + } +} + +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); + UNITY_END(); +} \ No newline at end of file diff --git a/test/test_servo/test_servo.cpp b/test/test_servo/test_servo.cpp index cfd8383..100b7c5 100644 --- a/test/test_servo/test_servo.cpp +++ b/test/test_servo/test_servo.cpp @@ -1,74 +1,91 @@ -#include "BlenderServoAnimation.h" +#include "internal/Servo.h" +#include "../test/helper.h" #include using namespace BlenderServoAnimation; -struct positionLog { - int index; - int positions[20]; -}; +void setUp(void) { + resetPositionLog(); +} -positionLog lastPositions[16]; +void test_move(void) { + byte servoId = 2; + Servo servo(servoId, move); -void setUp(void) { - for (int id = 0; id < 16; id++) { - lastPositions[id].index = 0; + TEST_ASSERT_TRUE(servo.isNeutral()); - for (int i = 0; i < 20; i++) { - lastPositions[id].positions[i] = 0; - } - } -} + servo.move(340); -void move(byte servoID, int position) { - int index = lastPositions[servoID].index; - lastPositions[servoID].positions[index] = position; - lastPositions[servoID].index++; -} + TEST_ASSERT_EQUAL(servoId, positions[0].servoId); + TEST_ASSERT_EQUAL(340, positions[0].position); -const int PROGMEM positions[5] = {350, 340, 330, 340, 350}; + servo.move(330); -void test_move_by_frame(void) { - Servo servo(2, positions, move); - TEST_ASSERT_EQUAL(2, servo.getID()); - TEST_ASSERT_TRUE(servo.isNeutral()); - servo.moveByFrame(1); - TEST_ASSERT_EQUAL(340, lastPositions[2].positions[0]); - servo.moveByFrame(2); - TEST_ASSERT_EQUAL(330, lastPositions[2].positions[1]); - servo.moveByFrame(3); - TEST_ASSERT_EQUAL(340, lastPositions[2].positions[2]); + TEST_ASSERT_EQUAL(servoId, positions[1].servoId); + TEST_ASSERT_EQUAL(330, positions[1].position); + + servo.move(340); + + TEST_ASSERT_EQUAL(servoId, positions[2].servoId); + TEST_ASSERT_EQUAL(340, positions[2].position); + + TEST_ASSERT_EQUAL(3, logIndex); } void test_move_towards_neutral(void) { - Servo servo(0, positions, move, 10); + byte servoId = 123; + Servo servo(servoId, move, 10); + + servo.move(350); + + TEST_ASSERT_EQUAL(servoId, positions[0].servoId); + TEST_ASSERT_EQUAL(350, positions[0].position); TEST_ASSERT_TRUE(servo.isNeutral()); - servo.moveByFrame(1); - TEST_ASSERT_EQUAL(340, lastPositions[0].positions[0]); + + servo.move(340); + + TEST_ASSERT_EQUAL(servoId, positions[1].servoId); + TEST_ASSERT_EQUAL(340, positions[1].position); TEST_ASSERT_FALSE(servo.isNeutral()); for (int i = 0; i < 10; i++) { servo.moveTowardsNeutral(); - TEST_ASSERT_EQUAL(341 + i, lastPositions[0].positions[1 + i]); + + TEST_ASSERT_EQUAL(servoId, positions[2 + i].servoId); + TEST_ASSERT_EQUAL(341 + i, positions[2 + i].position); } TEST_ASSERT_TRUE(servo.isNeutral()); + TEST_ASSERT_EQUAL(12, logIndex); } void test_threshold(void) { - Servo servo(0, positions, move, 15); + byte servoId = 3; + Servo servo(servoId, move, 15); + TEST_ASSERT_TRUE(servo.isNeutral()); - servo.moveByFrame(1); - TEST_ASSERT_EQUAL(340, lastPositions[0].positions[0]); - servo.moveByFrame(2); - TEST_ASSERT_EQUAL(330, lastPositions[0].positions[1]); - servo.moveByFrame(4); - TEST_ASSERT_EQUAL(0, lastPositions[0].positions[2]); + + servo.move(340); + + TEST_ASSERT_EQUAL(servoId, positions[0].servoId); + TEST_ASSERT_EQUAL(340, positions[0].position); + + servo.move(330); + + TEST_ASSERT_EQUAL(servoId, positions[1].servoId); + TEST_ASSERT_EQUAL(330, positions[1].position); + + servo.move(310); + + TEST_ASSERT_EQUAL(0, positions[2].servoId); + TEST_ASSERT_EQUAL(0, positions[2].position); + + TEST_ASSERT_EQUAL(2, logIndex); } int main(int argc, char **argv) { UNITY_BEGIN(); - RUN_TEST(test_move_by_frame); + RUN_TEST(test_move); RUN_TEST(test_move_towards_neutral); RUN_TEST(test_threshold); UNITY_END(); diff --git a/test/test_servo_manager/test_servo_manager.cpp b/test/test_servo_manager/test_servo_manager.cpp new file mode 100644 index 0000000..e225c03 --- /dev/null +++ b/test/test_servo_manager/test_servo_manager.cpp @@ -0,0 +1,36 @@ +#include "internal/ServoManager.h" +#include "../test/helper.h" +#include + +using namespace BlenderServoAnimation; + +void setUp(void) { + resetPositionLog(); +} + +void test_handle_command(void) { + Command command; + 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); + + TEST_ASSERT_EQUAL(1, logIndex); + TEST_ASSERT_EQUAL(0, positions[0].servoId); + TEST_ASSERT_EQUAL(375, positions[0].position); +} + +int main(int argc, char **argv) { + UNITY_BEGIN(); + RUN_TEST(test_handle_command); + UNITY_END(); +} \ No newline at end of file