-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathhmi.c
224 lines (206 loc) · 4.34 KB
/
hmi.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
#include "hmi.h"
/**
* @brief Blink LEDs a defined number of times.
*
* @param[in] count number of blinks.
* @param[in] time that LEDs are ON and OFF.
*/
void repeat_blink(uint8_t count, uint16_t time)
{
int i;
for (i = 0; i < count; i++) {
led_left_on();
led_right_on();
sleep_ticks(time);
led_left_off();
led_right_off();
sleep_ticks(time);
}
}
/**
* @brief Blink both LEDs alternately to report collision detection.
*/
void blink_collision(void)
{
int i;
for (i = 0; i < 10; i++) {
led_left_on();
led_right_off();
sleep_ticks(200);
led_left_off();
led_right_on();
sleep_ticks(200);
}
led_right_off();
}
/**
* @brief Read user button, requiring consecutive positive reads.
*
* @param[in] limit Maximum number of seconds (returns anyway when reached).
*
* @return Seconds of consecutive positive reads.
*/
static float button_user_count_seconds(float limit)
{
stopwatch_start();
while (stopwatch_stop() < limit) {
if (!button_read_user())
break;
}
return stopwatch_stop();
}
/**
* @brief Check for any user button response.
*
* A user button response can either be an action or no-response.
*
* @return The user button response.
*/
enum button_response button_user_response(void)
{
float readings = button_user_count_seconds(.5);
if (readings < 0.05)
return BUTTON_NONE;
if (readings < 0.3) {
speaker_play_beeps(1);
return BUTTON_SHORT;
}
led_left_on();
led_right_on();
while (button_read_user())
;
led_left_off();
led_right_off();
speaker_play_beeps(2);
return BUTTON_LONG;
}
/**
* @brief Wait for an user button action.
*
* This function blocks until an action is detected.
*
* @return The action that was detected.
*/
enum button_action button_user_wait_action(void)
{
enum button_response action;
while (1) {
action = button_user_response();
if (action == BUTTON_NONE)
continue;
return (enum button_action)action;
}
}
/**
* @brief Warn low battery using speaker sounds.
*/
void speaker_warn_low_battery(void)
{
music_play('C', 4, 0, 0.05);
sleep_ticks(50);
music_play('C', 3, 0, 0.05);
sleep_ticks(50);
}
/**
* @brief Notify about an error with a low pitch sustained sound.
*/
void speaker_play_error(void)
{
music_play('C', 3, 0, 2.);
}
/**
* @brief Play consecutive beeps.
*
* A beep is a short, high tone followed by a short silence.
*
* @param[in] beeps Number of beeps to play.
*/
void speaker_play_beeps(uint8_t beeps)
{
for (int i = 0; i < beeps; i++) {
music_play('C', 8, 0, 0.05);
sleep_ticks(50);
}
}
/**
* @brief Play three fast, high tones to note a successful operation.
*/
void speaker_play_success(void)
{
speaker_play_beeps(3);
}
/**
* @brief Play an epic composition before competition.
*/
void speaker_play_competition(void)
{
music_play('C', 7, 0, 0.15);
sleep_seconds(0.15);
music_play('C', 7, 0, 0.15);
music_play('G', 7, 0, 0.60);
sleep_seconds(0.15);
music_play('G', 7, 0, 0.15);
music_play('A', 7, 0, 0.15);
music_play('G', 7, 0, 0.15);
music_play('F', 7, 0, 0.15);
music_play('G', 7, 0, 0.45);
}
/**
* @brief Wait for a close front sensor signal.
*
* @param[in] close_distance Distance to be considered as close, in meters.
*/
void wait_front_sensor_close_signal(float close_distance)
{
while (1) {
if (get_front_right_distance() < close_distance ||
get_front_left_distance() < close_distance)
break;
}
}
/**
* @brief Configure initial search direction for the solver.
*/
void configure_solver_direction(void)
{
switch (button_user_wait_action()) {
case BUTTON_SHORT:
set_search_initial_direction(NORTH);
led_left_on();
break;
case BUTTON_LONG:
set_search_initial_direction(EAST);
led_right_on();
break;
}
}
/**
* @brief Select a force level for exploration or run phases.
*
* It starts at a minimum defined force and increases that force by steps.
*
* @param[in] minimum_force Minimum force.
* @param[in] force_step Force increase on each step.
*
* @return The selected force.
*/
float hmi_configure_force(float minimum_force, float force_step)
{
uint8_t force = 0;
music_play('C', 6, 0, 0.1);
music_play('E', 6, 0, 0.1);
music_play('G', 6, 0, 0.1);
music_play('C', 7, 0, 0.1);
while (1) {
switch (button_user_wait_action()) {
case BUTTON_SHORT:
force += 1;
break;
case BUTTON_LONG:
led_left_on();
led_right_on();
sleep_ticks(1000);
return force * force_step + minimum_force;
}
}
}