Skip to content

Commit 2b51617

Browse files
committed
add mode change callback
1 parent 189e958 commit 2b51617

File tree

5 files changed

+94
-30
lines changed

5 files changed

+94
-30
lines changed

examples/SwitchModeButton/SwitchModeButton.ino

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,13 @@
33
44
In this example we are using the OneButton library to handle both short and
55
long button presses. Note that the animation will be in default mode first,
6-
meaning that the servo will not move until the button is pressed shortly to
7-
start the animation. See the comments below to understand what happens when
8-
pressing the button short or long according to the current mode.
6+
meaning that the servo will not move until the button is shortly pressed to
7+
start the animation.
8+
9+
We also register a callback which is triggered whenever the animation mode
10+
changes. For example, this can be used to control the animation audio. See the
11+
comments below to understand what happens on a short or long button press
12+
based on the current mode.
913
*/
1014

1115
#include "simple.h"
@@ -31,6 +35,22 @@ void move(byte servoID, int angle) {
3135
myServo.write(angle);
3236
}
3337

38+
// Callback function which is called whenever the animation mode changes
39+
void modeChanged(byte prevMode, byte newMode) {
40+
switch (newMode) {
41+
case BlenderServoAnimation::Animation::MODE_PLAY:
42+
if (prevMode == BlenderServoAnimation::Animation::MODE_PAUSE) {
43+
// E.g. resume audio
44+
} else {
45+
// E.g. start audio
46+
}
47+
break;
48+
case BlenderServoAnimation::Animation::MODE_PAUSE:
49+
// E.g. pause audio
50+
break;
51+
}
52+
}
53+
3454
// Animation object to represent the original Blender animation
3555
BlenderServoAnimation::Animation animation(FPS, FRAMES);
3656

@@ -43,17 +63,14 @@ void onPressed() {
4363
switch (animation.getMode()) {
4464
// On short press in default mode, we want to start the animation
4565
case BlenderServoAnimation::Animation::MODE_DEFAULT:
46-
// Hint: here you could also trigger some audio
4766
animation.play();
4867
break;
4968
// On short press in play mode, we want to pause the animation
5069
case BlenderServoAnimation::Animation::MODE_PLAY:
5170
animation.pause();
52-
// Hint: here you could also pause some audio
5371
break;
5472
// On short press in pause mode, we want to resume the animation
5573
case BlenderServoAnimation::Animation::MODE_PAUSE:
56-
// Hint: here you could also resume some audio
5774
animation.play();
5875
break;
5976
}
@@ -86,6 +103,9 @@ void setup() {
86103

87104
// Add the Blender servo object to the animation
88105
animation.addServo(myBlenderServo);
106+
107+
// Register the mode change callback function
108+
animation.onModeChange(modeChanged);
89109
}
90110

91111
void loop() {

src/BlenderServoAnimation.cpp

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,19 @@ void Animation::addServos(Servo servos[], byte servoAmount) {
2525
}
2626
}
2727

28+
void Animation::onModeChange(mcb modeCallback) {
29+
this->modeCallback = modeCallback;
30+
}
31+
32+
void Animation::changeMode(byte mode) {
33+
byte prevMode = this->mode;
34+
this->mode = mode;
35+
36+
if (this->modeCallback) {
37+
this->modeCallback(prevMode, mode);
38+
}
39+
}
40+
2841
void Animation::run(unsigned long currentMicros) {
2942
switch (mode) {
3043
case MODE_PLAY:
@@ -79,7 +92,7 @@ void Animation::handleStopMode() {
7992
}
8093

8194
if (allNeutral) {
82-
this->mode = Animation::MODE_DEFAULT;
95+
this->changeMode(Animation::MODE_DEFAULT);
8396
return;
8497
}
8598

@@ -111,23 +124,23 @@ void Animation::handleLiveMode() {
111124
}
112125

113126
void Animation::play() {
114-
this->mode = Animation::MODE_PLAY;
115127
this->lastMicros = micros();
128+
this->changeMode(Animation::MODE_PLAY);
116129
}
117130

118131
void Animation::pause() {
119-
this->mode = Animation::MODE_PAUSE;
132+
this->changeMode(Animation::MODE_PAUSE);
120133
}
121134

122135
void Animation::stop(byte stepDelay) {
123-
this->mode = Animation::MODE_STOP;
124136
this->stopStepDelay = stepDelay;
125137
this->frame = 0;
138+
this->changeMode(Animation::MODE_STOP);
126139
}
127140

128141
void Animation::live(Stream &serial) {
129-
this->mode = Animation::MODE_LIVE;
130142
this->serial = &serial;
143+
this->changeMode(Animation::MODE_LIVE);
131144
}
132145

133146
byte Animation::getMode() {

src/BlenderServoAnimation.h

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
namespace BlenderServoAnimation {
99
class Animation {
10+
typedef void (*mcb)(byte, byte);
11+
1012
private:
1113
static const int MAX_SERVO_COUNT = 256;
1214
static const long SECOND_IN_MICROS = 1000000;
@@ -26,11 +28,11 @@ class Animation {
2628
Servo *servos[MAX_SERVO_COUNT] = {};
2729
Stream *serial;
2830
Command command;
31+
mcb modeCallback = nullptr;
2932

33+
void changeMode(byte mode);
3034
void handlePlayMode(unsigned long currentMicros);
31-
3235
void handleStopMode();
33-
3436
void handleLiveMode();
3537

3638
public:
@@ -41,25 +43,16 @@ class Animation {
4143
static const byte MODE_LIVE = 4;
4244

4345
Animation();
44-
4546
Animation(byte fps, int frames);
46-
4747
void addServo(Servo &servo);
48-
4948
void addServos(Servo servos[], byte servoAmount);
50-
49+
void onModeChange(mcb modeCallback);
5150
void run(unsigned long currentMicros = micros());
52-
5351
void play();
54-
5552
void pause();
56-
5753
void stop(byte stepDelay = 20);
58-
5954
void live(Stream &serial);
60-
6155
byte getMode();
62-
6356
int getFrame();
6457
};
6558
} // namespace BlenderServoAnimation

src/servo/Servo.h

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,19 +20,12 @@ class Servo {
2020

2121
public:
2222
Servo(byte id, const int positions[], cb moveCallback, byte threshold = 20);
23-
2423
Servo(byte id, cb moveCallback, byte threshold = 20);
25-
2624
void move(int position, bool force = false);
27-
2825
void moveByStep(int step);
29-
3026
void moveTowardsNeutral(bool inSteps = true);
31-
3227
bool isNeutral();
33-
3428
bool hasPositions();
35-
3629
byte getID();
3730
};
3831
} // namespace BlenderServoAnimation

test/test_animation/test_animation.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,14 @@ struct positionLog {
1515

1616
positionLog lastPositions[16];
1717

18+
struct modeLog {
19+
byte prevMode;
20+
byte newMode;
21+
};
22+
23+
byte modeIndex = 0;
24+
modeLog lastModes[10];
25+
1826
void setUp(void) {
1927
for (int id = 0; id < 16; id++) {
2028
lastPositions[id].index = 0;
@@ -23,6 +31,13 @@ void setUp(void) {
2331
lastPositions[id].positions[i] = 0;
2432
}
2533
}
34+
35+
for (int i = 0; i < 10; i++) {
36+
lastModes[i].prevMode = 0;
37+
lastModes[i].newMode = 0;
38+
}
39+
40+
modeIndex = 0;
2641
}
2742

2843
void move(byte servoID, int position) {
@@ -31,6 +46,12 @@ void move(byte servoID, int position) {
3146
lastPositions[servoID].index++;
3247
}
3348

49+
void onModeChange(byte prevMode, byte newMode) {
50+
lastModes[modeIndex].prevMode = prevMode;
51+
lastModes[modeIndex].newMode = newMode;
52+
modeIndex++;
53+
}
54+
3455
const int positionsA[5] PROGMEM = {350, 340, 330, 340, 330};
3556
const int positionsB[5] PROGMEM = {250, 240, 230, 240, 230};
3657

@@ -155,11 +176,35 @@ void test_live(void) {
155176
TEST_ASSERT_EQUAL(355, lastPositions[1].positions[1]);
156177
}
157178

179+
void test_mode_change(void) {
180+
SerialMock mock;
181+
Animation animation(FPS, FRAMES);
182+
183+
animation.onModeChange(onModeChange);
184+
185+
animation.play();
186+
TEST_ASSERT_EQUAL(Animation::MODE_DEFAULT, lastModes[0].prevMode);
187+
TEST_ASSERT_EQUAL(Animation::MODE_PLAY, lastModes[0].newMode);
188+
animation.pause();
189+
TEST_ASSERT_EQUAL(Animation::MODE_PLAY, lastModes[1].prevMode);
190+
TEST_ASSERT_EQUAL(Animation::MODE_PAUSE, lastModes[1].newMode);
191+
animation.stop();
192+
TEST_ASSERT_EQUAL(Animation::MODE_PAUSE, lastModes[2].prevMode);
193+
TEST_ASSERT_EQUAL(Animation::MODE_STOP, lastModes[2].newMode);
194+
animation.run();
195+
TEST_ASSERT_EQUAL(Animation::MODE_STOP, lastModes[3].prevMode);
196+
TEST_ASSERT_EQUAL(Animation::MODE_DEFAULT, lastModes[3].newMode);
197+
animation.live(mock);
198+
TEST_ASSERT_EQUAL(Animation::MODE_DEFAULT, lastModes[4].prevMode);
199+
TEST_ASSERT_EQUAL(Animation::MODE_LIVE, lastModes[4].newMode);
200+
}
201+
158202
int main(int argc, char **argv) {
159203
UNITY_BEGIN();
160204
RUN_TEST(test_play);
161205
RUN_TEST(test_pause);
162206
RUN_TEST(test_stop);
163207
RUN_TEST(test_live);
208+
RUN_TEST(test_mode_change);
164209
UNITY_END();
165210
}

0 commit comments

Comments
 (0)