Skip to content

Commit dced752

Browse files
authored
Merge pull request #71 from arduino-libraries/fix-arr-overflow
Rewrite `examples/Braccio_Learn_and_Repeat` using State design pattern
2 parents 7976a7d + b2384df commit dced752

File tree

3 files changed

+434
-152
lines changed

3 files changed

+434
-152
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
/**************************************************************************************
2+
* INCLUDE
3+
**************************************************************************************/
4+
5+
#include "AppState.h"
6+
7+
/**************************************************************************************
8+
* DEFINE
9+
**************************************************************************************/
10+
11+
#define COLOR_TEAL 0x00878F
12+
#define COLOR_LIGHT_TEAL 0x62AEB2
13+
#define COLOR_ORANGE 0xE47128
14+
15+
#define BUTTON_ENTER 6
16+
17+
/**************************************************************************************
18+
* CONSTANT
19+
**************************************************************************************/
20+
21+
static int const SAMPLE_BUF_SIZE = 6*200*2; /* 20 seconds. */
22+
static float const HOME_POS[6] = {157.5, 157.5, 157.5, 157.5, 157.5, 90.0};
23+
24+
/**************************************************************************************
25+
* GLOBAL VARIABLES
26+
**************************************************************************************/
27+
28+
lv_obj_t * counter;
29+
lv_obj_t * btnm;
30+
const char * btnm_map[] = { "RECORD", "\n", "REPLAY", "\n", "ZERO_POSITION", "\n", "\0" };
31+
32+
static float sample_buf[SAMPLE_BUF_SIZE];
33+
static int sample_cnt;
34+
35+
extern LearnAndRepeatApp app;
36+
37+
/**************************************************************************************
38+
* FUNCTION DEFINITION
39+
**************************************************************************************/
40+
41+
static void event_handler_menu(lv_event_t * e)
42+
{
43+
lv_event_code_t code = lv_event_get_code(e);
44+
45+
if (code == LV_EVENT_CLICKED || (code == LV_EVENT_KEY && Braccio.getKey() == BUTTON_ENTER))
46+
{
47+
lv_obj_t * obj = lv_event_get_target(e);
48+
uint32_t const id = lv_btnmatrix_get_selected_btn(obj);
49+
50+
switch (id)
51+
{
52+
case 0: app.update(EventSource::Button_Record); break;
53+
case 1: app.update(EventSource::Button_Replay); break;
54+
case 2: app.update(EventSource::Button_ZeroPosition); break;
55+
}
56+
}
57+
}
58+
59+
void custom_main_menu()
60+
{
61+
Braccio.lvgl_lock();
62+
static lv_style_t style_focus;
63+
lv_style_init(&style_focus);
64+
lv_style_set_outline_color(&style_focus, lv_color_hex(COLOR_ORANGE));
65+
lv_style_set_outline_width(&style_focus, 4);
66+
67+
static lv_style_t style_btn;
68+
lv_style_init(&style_btn);
69+
lv_style_set_bg_color(&style_btn, lv_color_hex(COLOR_LIGHT_TEAL));
70+
lv_style_set_text_color(&style_btn, lv_color_white());
71+
72+
btnm = lv_btnmatrix_create(lv_scr_act());
73+
lv_obj_set_size(btnm, 240, 240);
74+
lv_btnmatrix_set_map(btnm, btnm_map);
75+
lv_obj_align(btnm, LV_ALIGN_CENTER, 0, 0);
76+
77+
lv_obj_add_style(btnm, &style_btn, LV_PART_ITEMS);
78+
lv_obj_add_style(btnm, &style_focus, LV_PART_ITEMS | LV_STATE_FOCUS_KEY);
79+
80+
lv_btnmatrix_set_btn_ctrl(btnm, 0, LV_BTNMATRIX_CTRL_DISABLED);
81+
lv_btnmatrix_set_btn_ctrl(btnm, 1, LV_BTNMATRIX_CTRL_DISABLED);
82+
lv_btnmatrix_set_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_DISABLED);
83+
84+
lv_btnmatrix_set_one_checked(btnm, true);
85+
lv_btnmatrix_set_selected_btn(btnm, 0);
86+
lv_btnmatrix_set_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_CHECKED);
87+
88+
counter = lv_label_create(btnm);
89+
lv_label_set_text_fmt(counter, "Counter: %d" , 0);
90+
lv_obj_align(counter, LV_ALIGN_CENTER, 0, 80);
91+
92+
lv_obj_add_event_cb(btnm, event_handler_menu, LV_EVENT_ALL, NULL);
93+
Braccio.lvgl_unlock();
94+
95+
Braccio.connectJoystickTo(btnm);
96+
}
97+
98+
/**************************************************************************************
99+
* State
100+
**************************************************************************************/
101+
102+
State * State::handle_OnZeroPosition()
103+
{
104+
return new ZeroState();
105+
}
106+
107+
/**************************************************************************************
108+
* IdleState
109+
**************************************************************************************/
110+
111+
void IdleState::onEnter()
112+
{
113+
lv_btnmatrix_set_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_CHECKED);
114+
}
115+
116+
void IdleState::onExit()
117+
{
118+
lv_btnmatrix_clear_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_CHECKED);
119+
}
120+
121+
State * IdleState::handle_OnRecord()
122+
{
123+
return new RecordState();
124+
}
125+
126+
State * IdleState::handle_OnReplay()
127+
{
128+
return new ReplayState();
129+
}
130+
131+
/**************************************************************************************
132+
* RecordState
133+
**************************************************************************************/
134+
135+
void RecordState::onEnter()
136+
{
137+
btnm_map[0] = "STOP";
138+
lv_btnmatrix_set_btn_ctrl(btnm, 0, LV_BTNMATRIX_CTRL_CHECKED);
139+
lv_btnmatrix_set_btn_ctrl(btnm, 1, LV_BTNMATRIX_CTRL_DISABLED);
140+
141+
Braccio.disengage();
142+
sample_cnt = 0;
143+
}
144+
145+
void RecordState::onExit()
146+
{
147+
btnm_map[0] = "RECORD";
148+
lv_btnmatrix_clear_btn_ctrl(btnm, 0, LV_BTNMATRIX_CTRL_CHECKED);
149+
lv_btnmatrix_clear_btn_ctrl(btnm, 1, LV_BTNMATRIX_CTRL_DISABLED);
150+
lv_label_set_text_fmt(counter, "Counter: %d" , 0);
151+
152+
Braccio.engage();
153+
}
154+
155+
State * RecordState::handle_OnRecord()
156+
{
157+
return new IdleState();
158+
}
159+
160+
State * RecordState::handle_OnTimerTick()
161+
{
162+
/* The sample buffer is full. */
163+
if (sample_cnt >= SAMPLE_BUF_SIZE) {
164+
return new IdleState();
165+
}
166+
167+
/* We still have space, let's sample some data. */
168+
Braccio.positions(sample_buf + sample_cnt);
169+
sample_cnt += 6;
170+
171+
/* Update sample counter. */
172+
lv_label_set_text_fmt(counter, "Counter: %d" , (sample_cnt / 6));
173+
174+
return this;
175+
}
176+
177+
/**************************************************************************************
178+
* ReplayState
179+
**************************************************************************************/
180+
181+
void ReplayState::onEnter()
182+
{
183+
btnm_map[2] = "STOP";
184+
lv_btnmatrix_set_btn_ctrl(btnm, 0, LV_BTNMATRIX_CTRL_DISABLED);
185+
lv_btnmatrix_set_btn_ctrl(btnm, 1, LV_BTNMATRIX_CTRL_CHECKED);
186+
}
187+
188+
void ReplayState::onExit()
189+
{
190+
btnm_map[2] = "REPLAY";
191+
lv_btnmatrix_clear_btn_ctrl(btnm, 0, LV_BTNMATRIX_CTRL_DISABLED);
192+
lv_btnmatrix_clear_btn_ctrl(btnm, 1, LV_BTNMATRIX_CTRL_CHECKED);
193+
lv_label_set_text_fmt(counter, "Counter: %d" , 0);
194+
}
195+
196+
State * ReplayState::handle_OnReplay()
197+
{
198+
return new IdleState();
199+
}
200+
201+
State * ReplayState::handle_OnTimerTick()
202+
{
203+
/* All samples have been replayed. */
204+
if (_replay_cnt >= sample_cnt) {
205+
return new IdleState();
206+
}
207+
208+
/* Replay recorded movements. */
209+
Braccio.moveTo(sample_buf[_replay_cnt + 0],
210+
sample_buf[_replay_cnt + 1],
211+
sample_buf[_replay_cnt + 2],
212+
sample_buf[_replay_cnt + 3],
213+
sample_buf[_replay_cnt + 4],
214+
sample_buf[_replay_cnt + 5]);
215+
_replay_cnt += 6;
216+
217+
lv_label_set_text_fmt(counter, "Counter: %d" , (_replay_cnt / 6));
218+
219+
return this;
220+
}
221+
222+
/**************************************************************************************
223+
* ReplayState
224+
**************************************************************************************/
225+
226+
State * ZeroState::handle_OnTimerTick()
227+
{
228+
return new IdleState();
229+
}
230+
231+
void ZeroState::onEnter()
232+
{
233+
lv_btnmatrix_set_btn_ctrl(btnm, 1, LV_BTNMATRIX_CTRL_DISABLED);
234+
lv_btnmatrix_set_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_CHECKED);
235+
236+
Braccio.engage();
237+
delay(100);
238+
Braccio.moveTo(HOME_POS[0], HOME_POS[1], HOME_POS[2], HOME_POS[3], HOME_POS[4], HOME_POS[5]);
239+
delay(500);
240+
}
241+
242+
void ZeroState::onExit()
243+
{
244+
lv_btnmatrix_clear_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_CHECKED);
245+
}
246+
247+
/**************************************************************************************
248+
* LearnAndRepeatApp
249+
**************************************************************************************/
250+
251+
void LearnAndRepeatApp::enableButtons()
252+
{
253+
/* Enable buttons once init is complete. */
254+
lv_btnmatrix_clear_btn_ctrl(btnm, 0, LV_BTNMATRIX_CTRL_DISABLED);
255+
lv_btnmatrix_clear_btn_ctrl(btnm, 2, LV_BTNMATRIX_CTRL_DISABLED);
256+
}

0 commit comments

Comments
 (0)