Paparazzi UAS v7.1_unstable
Paparazzi is a free software Unmanned Aircraft System.
Loading...
Searching...
No Matches
buzzer_tunes.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2026 Tomaso De Ponti <tomaso@aerogriduav.com>
3 *
4 * This file is part of paparazzi
5 *
6 * paparazzi is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * paparazzi is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with paparazzi; see the file COPYING. If not, see
18 * <http://www.gnu.org/licenses/>.
19 */
20
25
28#include "mcu_periph/sys_time.h"
29#include "generated/airframe.h"
30
32#ifdef BUZZER_TUNES_ALERT_HEADER
33#include BUZZER_TUNES_ALERT_HEADER
34#endif
35
37#ifndef BUZZER_TUNES_EVENTS_ON
38#define BUZZER_TUNES_EVENTS_ON FALSE
39#endif
40
42#ifdef BUZZER_TUNES_ARMED_TUNE
43#include "autopilot.h"
44#endif
45
47#ifndef BUZZER_TUNES_ALERT_TUNE
48#define BUZZER_TUNES_ALERT_TUNE BUZZER_TUNES_NONE
49#endif
50
52#ifndef BUZZER_TUNES_ALERT_END_TUNE
53#define BUZZER_TUNES_ALERT_END_TUNE BUZZER_TUNES_NONE
54#endif
55
57#ifndef BUZZER_TUNES_STARTUP_TUNE
58#define BUZZER_TUNES_STARTUP_TUNE BUZZER_TUNES_STARTUP
59#endif
60
62#define BUZZER_TUNES_GAP_MS 30
63
65#define REST 0
66#define C4 262
67#define Cs4 277
68#define D4 294
69#define Ds4 311
70#define E4 330
71#define F4 349
72#define Fs4 370
73#define G4 392
74#define Gs4 415
75#define A4 440
76#define As4 466
77#define B4 494
78#define C5 523
79#define Cs5 554
80#define D5 587
81#define Ds5 622
82#define E5 659
83#define F5 698
84#define Fs5 740
85#define G5 784
86#define Gs5 831
87#define A5 880
88#define As5 932
89#define B5 988
90#define C6 1047
91#define Cs6 1109
92#define D6 1175
93#define Ds6 1245
94#define E6 1319
95#define F6 1397
96#define Fs6 1480
97#define G6 1568
98#define Gs6 1661
99#define A6 1760
100#define As6 1865
101#define B6 1976
102#define C7 2093
103#define Cs7 2217
104#define D7 2349
105#define Ds7 2489
106#define E7 2637
107#define F7 2794
108#define Fs7 2960
109#define G7 3136
110#define Gs7 3322
111#define A7 3520
112#define As7 3729
113#define B7 3951
114
116#define BEATS(_b, _bpm) ((uint16_t)((_b) * 60000.0 / (_bpm)))
117
122
123#define TUNE_END {0, 0}
124
126#ifndef BUZZER_TUNES_RTTTL_1
127#define BUZZER_TUNES_RTTTL_1 ""
128#endif
129#ifndef BUZZER_TUNES_RTTTL_2
130#define BUZZER_TUNES_RTTTL_2 ""
131#endif
132#ifndef BUZZER_TUNES_RTTTL_3
133#define BUZZER_TUNES_RTTTL_3 ""
134#endif
135
137static const struct buzzer_note tune_startup[] = {
138 {C6, 120}, {E6, 120}, {G6, 120}, {C7, 360}, TUNE_END
139};
140
142static const struct buzzer_note tune_ode_to_joy[] = {
143 {E6, 300}, {E6, 300}, {F6, 300}, {G6, 300}, {G6, 300}, {F6, 300}, {E6, 300}, {D6, 300},
144 {C6, 300}, {C6, 300}, {D6, 300}, {E6, 300}, {E6, 450}, {D6, 150}, {D6, 600},
145 {E6, 300}, {E6, 300}, {F6, 300}, {G6, 300}, {G6, 300}, {F6, 300}, {E6, 300}, {D6, 300},
146 {C6, 300}, {C6, 300}, {D6, 300}, {E6, 300}, {D6, 450}, {C6, 150}, {C6, 600},
147 {D6, 300}, {D6, 300}, {E6, 300}, {C6, 300}, {D6, 300}, {E6, 150}, {F6, 150}, {E6, 300}, {C6, 300},
148 {D6, 300}, {E6, 150}, {F6, 150}, {E6, 300}, {D6, 300}, {C6, 300}, {D6, 300}, {G5, 600},
149 {E6, 300}, {E6, 300}, {F6, 300}, {G6, 300}, {G6, 300}, {F6, 300}, {E6, 300}, {D6, 300},
150 {C6, 300}, {C6, 300}, {D6, 300}, {E6, 300}, {D6, 450}, {C6, 150}, {C6, 600}, TUNE_END
151};
152
154static const struct buzzer_note tune_twinkle[] = {
155 {C6, 300}, {C6, 300}, {G6, 300}, {G6, 300}, {A6, 300}, {A6, 300}, {G6, 600},
156 {F6, 300}, {F6, 300}, {E6, 300}, {E6, 300}, {D6, 300}, {D6, 300}, {C6, 600},
157 {G6, 300}, {G6, 300}, {F6, 300}, {F6, 300}, {E6, 300}, {E6, 300}, {D6, 600},
158 {G6, 300}, {G6, 300}, {F6, 300}, {F6, 300}, {E6, 300}, {E6, 300}, {D6, 600},
159 {C6, 300}, {C6, 300}, {G6, 300}, {G6, 300}, {A6, 300}, {A6, 300}, {G6, 600},
160 {F6, 300}, {F6, 300}, {E6, 300}, {E6, 300}, {D6, 300}, {D6, 300}, {C6, 600}, TUNE_END
161};
162
164#define IT_BPM 112
165static const struct buzzer_note tune_anthem_italy[] = {
166 {F5, BEATS(1, IT_BPM)}, {F5, BEATS(0.75, IT_BPM)}, {G5, BEATS(0.25, IT_BPM)}, {F5, BEATS(1, IT_BPM)},
167 {REST, BEATS(1, IT_BPM)}, {D6, BEATS(1, IT_BPM)}, {D6, BEATS(0.75, IT_BPM)}, {Ds6, BEATS(0.25, IT_BPM)},
168 {D6, BEATS(1, IT_BPM)}, {REST, BEATS(1, IT_BPM)}, {D6, BEATS(1, IT_BPM)}, {F6, BEATS(0.75, IT_BPM)},
169 {Ds6, BEATS(0.25, IT_BPM)}, {D6, BEATS(2, IT_BPM)}, {C6, BEATS(1, IT_BPM)}, {D6, BEATS(0.75, IT_BPM)},
170 {C6, BEATS(0.25, IT_BPM)}, {As5, BEATS(1, IT_BPM)}, {REST, BEATS(1, IT_BPM)}, {D6, BEATS(1, IT_BPM)},
171 {D6, BEATS(1, IT_BPM)}, {A5, BEATS(2, IT_BPM)}, {As5, BEATS(0.75, IT_BPM)}, {C6, BEATS(0.25, IT_BPM)},
172 {As5, BEATS(0.75, IT_BPM)}, {A5, BEATS(0.25, IT_BPM)}, {G5, BEATS(1, IT_BPM)}, {REST, BEATS(1, IT_BPM)},
173 {As5, BEATS(1, IT_BPM)}, {A5, BEATS(0.75, IT_BPM)}, {As5, BEATS(0.25, IT_BPM)}, {C6, BEATS(1, IT_BPM)},
174 {REST, BEATS(1, IT_BPM)}, {D5, BEATS(1, IT_BPM)}, {D6, BEATS(2, IT_BPM)}, {Ds6, BEATS(1, IT_BPM)},
175 {F5, BEATS(1, IT_BPM)}, {F5, BEATS(0.75, IT_BPM)}, {G5, BEATS(0.25, IT_BPM)}, {F5, BEATS(0.5, IT_BPM)},
176 {REST, BEATS(1.5, IT_BPM)}, {D6, BEATS(1, IT_BPM)}, {D6, BEATS(0.75, IT_BPM)}, {Ds6, BEATS(0.25, IT_BPM)},
177 {D6, BEATS(2, IT_BPM)}, {D6, BEATS(1, IT_BPM)}, {F6, BEATS(0.75, IT_BPM)}, {Ds6, BEATS(0.25, IT_BPM)},
178 {D6, BEATS(1.5, IT_BPM)}, {F6, BEATS(0.5, IT_BPM)}, {C6, BEATS(0.5, IT_BPM)}, {F6, BEATS(0.5, IT_BPM)},
179 {As5, BEATS(2, IT_BPM)}, TUNE_END
180};
181
183#define NL_BPM 90
184static const struct buzzer_note tune_anthem_netherlands[] = {
185 {D5, BEATS(1, NL_BPM)}, {G5, BEATS(1, NL_BPM)}, {G5, BEATS(1, NL_BPM)}, {A5, BEATS(0.5, NL_BPM)},
186 {B5, BEATS(0.5, NL_BPM)}, {C6, BEATS(0.5, NL_BPM)}, {A5, BEATS(0.5, NL_BPM)}, {B5, BEATS(1, NL_BPM)},
187 {A5, BEATS(0.5, NL_BPM)}, {B5, BEATS(0.5, NL_BPM)}, {C6, BEATS(1, NL_BPM)}, {B5, BEATS(1, NL_BPM)},
188 {A5, BEATS(0.5, NL_BPM)}, {G5, BEATS(0.5, NL_BPM)}, {A5, BEATS(1, NL_BPM)}, {G5, BEATS(3, NL_BPM)},
189 {B5, BEATS(0.5, NL_BPM)}, {C6, BEATS(0.5, NL_BPM)}, {D6, BEATS(2, NL_BPM)}, {E6, BEATS(1, NL_BPM)},
190 {D6, BEATS(2, NL_BPM)}, {C6, BEATS(1, NL_BPM)}, {B5, BEATS(1, NL_BPM)}, {A5, BEATS(0.5, NL_BPM)},
191 {B5, BEATS(0.5, NL_BPM)}, {C6, BEATS(1, NL_BPM)}, {B5, BEATS(1, NL_BPM)}, {A5, BEATS(1, NL_BPM)},
192 {G5, BEATS(1, NL_BPM)}, {A5, BEATS(3, NL_BPM)}, {D5, BEATS(1, NL_BPM)}, {G5, BEATS(0.5, NL_BPM)},
193 {Fs5, BEATS(0.5, NL_BPM)}, {G5, BEATS(0.5, NL_BPM)}, {A5, BEATS(0.5, NL_BPM)}, {B5, BEATS(1, NL_BPM)},
194 {A5, BEATS(2, NL_BPM)}, {G5, BEATS(1, NL_BPM)}, {Fs5, BEATS(1, NL_BPM)}, {D5, BEATS(1, NL_BPM)},
195 {E5, BEATS(0.5, NL_BPM)}, {Fs5, BEATS(0.5, NL_BPM)}, {G5, BEATS(1, NL_BPM)}, {G5, BEATS(1, NL_BPM)},
196 {Fs5, BEATS(1, NL_BPM)}, {G5, BEATS(3, NL_BPM)}, TUNE_END
197};
198
200#define FR_BPM 105
201static const struct buzzer_note tune_anthem_france[] = {
202 {D5, BEATS(0.25, FR_BPM)}, {D5, BEATS(0.75, FR_BPM)}, {D5, BEATS(0.25, FR_BPM)}, {G5, BEATS(1, FR_BPM)},
203 {G5, BEATS(1, FR_BPM)}, {A5, BEATS(1, FR_BPM)}, {A5, BEATS(1, FR_BPM)}, {D6, BEATS(1.5, FR_BPM)},
204 {B5, BEATS(0.5, FR_BPM)}, {G5, BEATS(0.75, FR_BPM)}, {G5, BEATS(0.25, FR_BPM)}, {B5, BEATS(0.75, FR_BPM)},
205 {G5, BEATS(0.25, FR_BPM)}, {E5, BEATS(1, FR_BPM)}, {C6, BEATS(1, FR_BPM)}, {REST, BEATS(1, FR_BPM)},
206 {A5, BEATS(0.75, FR_BPM)}, {Fs5, BEATS(0.25, FR_BPM)}, {G5, BEATS(1, FR_BPM)}, {REST, BEATS(2, FR_BPM)},
207 {G5, BEATS(0.75, FR_BPM)}, {A5, BEATS(0.25, FR_BPM)}, {B5, BEATS(1, FR_BPM)}, {B5, BEATS(1, FR_BPM)},
208 {B5, BEATS(1, FR_BPM)}, {C6, BEATS(0.75, FR_BPM)}, {B5, BEATS(0.25, FR_BPM)}, {B5, BEATS(1, FR_BPM)},
209 {A5, BEATS(1, FR_BPM)}, {REST, BEATS(1, FR_BPM)}, {A5, BEATS(0.75, FR_BPM)}, {B5, BEATS(0.25, FR_BPM)},
210 {C6, BEATS(1, FR_BPM)}, {C6, BEATS(1, FR_BPM)}, {C6, BEATS(1, FR_BPM)}, {D6, BEATS(0.75, FR_BPM)},
211 {C6, BEATS(0.25, FR_BPM)}, {B5, BEATS(1, FR_BPM)}, {REST, BEATS(2, FR_BPM)}, {D6, BEATS(0.75, FR_BPM)},
212 {D6, BEATS(0.25, FR_BPM)}, {D6, BEATS(1, FR_BPM)}, {B5, BEATS(0.75, FR_BPM)}, {G5, BEATS(0.25, FR_BPM)},
213 {D6, BEATS(1, FR_BPM)}, {B5, BEATS(0.75, FR_BPM)}, {G5, BEATS(0.25, FR_BPM)}, {D5, BEATS(3, FR_BPM)}, TUNE_END
214};
215
217static const struct buzzer_note tune_happy_birthday[] = {
218 {G5, 300}, {G5, 100}, {A5, 400}, {G5, 400}, {C6, 400}, {B5, 800},
219 {G5, 300}, {G5, 100}, {A5, 400}, {G5, 400}, {D6, 400}, {C6, 800},
220 {G5, 300}, {G5, 100}, {G6, 400}, {E6, 400}, {C6, 400}, {B5, 400}, {A5, 800},
221 {F6, 300}, {F6, 100}, {E6, 400}, {C6, 400}, {D6, 400}, {C6, 800}, TUNE_END
222};
223
224
226static const struct buzzer_note tune_mushroom[] = {
227 {E7, 150}, {E7, 150}, {REST, 150}, {E7, 150}, {REST, 150}, {C7, 150}, {E7, 150}, {REST, 150},
228 {G7, 300}, {REST, 300}, {G6, 300}, {REST, 300}, {C7, 450}, {G6, 150}, {REST, 300}, {E6, 450},
229 {A6, 300}, {B6, 300}, {As6, 150}, {A6, 300}, {G6, 200}, {E7, 200}, {G7, 200}, {A7, 300},
230 {F7, 150}, {G7, 150}, {REST, 150}, {E7, 300}, {C7, 150}, {D7, 150}, {B6, 450}, {C7, 450},
231 {G6, 150}, {REST, 300}, {E6, 450}, {A6, 300}, {B6, 300}, {As6, 150}, {A6, 300}, {G6, 200},
232 {E7, 200}, {G7, 200}, {A7, 300}, {F7, 150}, {G7, 150}, {REST, 150}, {E7, 300}, {C7, 150},
233 {D7, 150}, {B6, 450}, {REST, 300}, {G7, 150}, {Fs7, 150}, {F7, 150}, {D7, 300}, {E7, 150},
234 {REST, 150}, {G6, 150}, {A6, 150}, {C7, 150}, {REST, 150}, {A6, 150}, {C7, 150}, {D7, 150},
235 {REST, 300}, {G7, 150}, {Fs7, 150}, {F7, 150}, {D7, 300}, {E7, 150}, {REST, 150}, {C5, 300},
236 {C5, 150}, {C5, 300}, {REST, 300}, {REST, 300}, {G7, 150}, {Fs7, 150}, {F7, 150}, {D7, 300},
237 {E7, 150}, {REST, 150}, {G6, 150}, {A6, 150}, {C7, 150}, {REST, 150}, {A6, 150}, {C7, 150},
238 {D7, 150}, {REST, 300}, {Ds7, 300}, {REST, 150}, {D7, 450}, {C7, 600}, {REST, 600}, {C7, 150},
239 {C7, 300}, {C7, 150}, {REST, 150}, {C7, 150}, {D7, 300}, {E7, 150}, {C7, 300}, {A6, 150},
240 {G6, 600}, {C7, 150}, {C7, 300}, {C7, 150}, {REST, 150}, {C7, 150}, {D7, 150}, {E7, 150},
241 {REST, 1200}, {C7, 150}, {C7, 300}, {C7, 150}, {REST, 150}, {C7, 150}, {D7, 300}, {E7, 150},
242 {C7, 300}, {A6, 150}, {G6, 600}, {E7, 150}, {E7, 150}, {REST, 150}, {E7, 150}, {REST, 150},
243 {C7, 150}, {E7, 300}, {G7, 300}, {REST, 300}, {G6, 300}, {REST, 300}, {C7, 450}, {G6, 150},
244 {REST, 300}, {E6, 450}, {A6, 300}, {B6, 300}, {As6, 150}, {A6, 300}, {G6, 200}, {E7, 200},
245 {G7, 200}, {A7, 300}, {F7, 150}, {G7, 150}, {REST, 150}, {E7, 300}, {C7, 150}, {D7, 150},
246 {B6, 450}, {C7, 450}, {G6, 150}, {REST, 300}, {E6, 450}, {A6, 300}, {B6, 300}, {As6, 150},
247 {A6, 300}, {G6, 200}, {E7, 200}, {G7, 200}, {A7, 300}, {F7, 150}, {G7, 150}, {REST, 150},
248 {E7, 300}, {C7, 150}, {D7, 150}, {B6, 450}, {E7, 150}, {C7, 300}, {G6, 150}, {REST, 300},
249 {G6, 300}, {A6, 150}, {F7, 300}, {F7, 150}, {A6, 600}, {B6, 200}, {A7, 200}, {A7, 200},
250 {A7, 200}, {G7, 200}, {F7, 200}, {E7, 150}, {C7, 300}, {A6, 150}, {G6, 600}, {E7, 150},
251 {C7, 300}, {G6, 150}, {REST, 300}, {G6, 300}, {A6, 150}, {F7, 300}, {F7, 150}, {A6, 600},
252 {B6, 150}, {F7, 300}, {F7, 150}, {F7, 200}, {E7, 200}, {D7, 200}, {C7, 150}, {G6, 300},
253 {E6, 150}, {C6, 600}, {C7, 450}, {G6, 450}, {E6, 300}, {A6, 200}, {B6, 200}, {A6, 200},
254 {Gs6, 200}, {As6, 200}, {Gs6, 200}, {G6, 150}, {Fs6, 150}, {G6, 900},
256};
257
258
260static const struct buzzer_note tune_gran_vals[] = {
261 {E6, 160}, {D6, 160}, {Fs5, 320}, {Gs5, 320}, {Cs6, 160}, {B5, 160}, {D5, 320}, {E5, 320},
262 {B5, 160}, {A5, 160}, {Cs5, 320}, {E5, 320}, {A5, 960}, TUNE_END
263};
264
266static const struct buzzer_note tune_fur_elise[] = {
267 {E6, 150}, {Ds6, 150}, {E6, 150}, {Ds6, 150}, {E6, 150}, {B5, 150}, {D6, 150}, {C6, 150},
268 {A5, 300}, {REST, 150}, {C5, 150}, {E5, 150}, {A5, 150}, {B5, 300}, {REST, 150},
269 {E5, 150}, {Gs5, 150}, {B5, 150}, {C6, 300}, {REST, 150}, {E5, 150}, {E6, 150}, {Ds6, 150},
270 {E6, 150}, {Ds6, 150}, {E6, 150}, {B5, 150}, {D6, 150}, {C6, 150},
271 {A5, 300}, {REST, 150}, {C5, 150}, {E5, 150}, {A5, 150}, {B5, 300}, {REST, 150},
272 {E5, 150}, {C6, 150}, {B5, 150}, {A5, 600}, TUNE_END
273};
274
276static const struct buzzer_note tune_la_cucaracha[] = {
277 {C6, 150}, {C6, 150}, {C6, 150}, {F6, 450}, {A6, 300},
278 {C6, 150}, {C6, 150}, {C6, 150}, {F6, 450}, {A6, 600},
279 {F6, 300}, {F6, 150}, {E6, 150}, {E6, 150}, {D6, 150}, {D6, 150}, {C6, 600},
280 {C6, 150}, {C6, 150}, {C6, 150}, {E6, 450}, {G6, 300},
281 {C6, 150}, {C6, 150}, {C6, 150}, {E6, 450}, {G6, 600},
282 {C7, 300}, {D7, 150}, {C7, 150}, {As6, 150}, {A6, 150}, {G6, 150}, {F6, 600}, TUNE_END
283};
284
286static const struct buzzer_note tune_william_tell[] = {
287 {G6, 100}, {G6, 100}, {G6, 200}, {G6, 100}, {G6, 100}, {G6, 200},
288 {G6, 100}, {G6, 100}, {C7, 200}, {D7, 200}, {E7, 400}, {REST, 200},
289 {G6, 100}, {G6, 100}, {G6, 200}, {G6, 100}, {G6, 100}, {G6, 200},
290 {G6, 100}, {G6, 100}, {C7, 200}, {D7, 200}, {E7, 400}, {C7, 600}, TUNE_END
291};
292
294static const struct buzzer_note tune_star[] = {
295 {C7, 150}, {REST, 50}, {C7, 150}, {REST, 50}, {C7, 150}, {REST, 150}, {C7, 150}, {REST, 50},
296 {C7, 150}, {REST, 150}, {C7, 80}, {REST, 20}, {C7, 80}, {REST, 20}, {C7, 150}, {REST, 50},
297 {B6, 150}, {REST, 50}, {B6, 150}, {REST, 50}, {B6, 150}, {REST, 150}, {B6, 150}, {REST, 50},
298 {B6, 150}, {REST, 150}, {B6, 150}, {REST, 50}, {B6, 150}, {REST, 50}, {C7, 150}, {REST, 50},
299 {C7, 150}, {REST, 50}, {C7, 150}, {REST, 150}, {C7, 150}, {REST, 50}, {C7, 150}, {REST, 150},
300 {C7, 150}, {REST, 50}, {C7, 150}, {REST, 50}, {B6, 150}, {REST, 50}, {B6, 150}, {REST, 50},
301 {B6, 150}, {REST, 150}, {B6, 150}, {REST, 50}, {B6, 150}, {REST, 150}, {B6, 150}, {REST, 50},
302 {B6, 150}, {REST, 50}, {C7, 150}, {REST, 50}, {C7, 150}, {REST, 50}, {C7, 150}, {REST, 150},
303 {C7, 150}, {REST, 50}, {C7, 150}, {REST, 150}, {C7, 150}, {REST, 50}, {C7, 150}, {REST, 50},
304 {B6, 150}, {REST, 50}, {B6, 150}, {REST, 50}, {B6, 150}, {REST, 150}, {B6, 150}, {REST, 50},
305 {B6, 150}, {REST, 150}, {B6, 150}, {REST, 50}, {B6, 150},
307};
308
325
330
332
333static const struct buzzer_note *tune_notes = NULL;
334static const char *rtttl = NULL;
335static uint8_t rtttl_d = 4, rtttl_o = 6;
336static uint16_t rtttl_bpm = 63;
337static struct buzzer_note note;
338static bool playing = false;
340static bool note_gap = false;
341
343static bool event_tune = false;
344#ifdef BUZZER_TUNES_ALERT
345static bool alert_active = false;
346static bool alert_muted = false;
347#endif
348#ifdef BUZZER_TUNES_ARMED_TUNE
349static bool motors_were_on = false;
350static bool armed_muted = false;
351#endif
352
353static void tune_start(uint8_t tune);
354
355static uint16_t rtttl_number(const char **p)
356{
357 uint16_t n = 0;
358 while (**p >= '0' && **p <= '9') {
359 n = n * 10 + (*(*p)++ - '0');
360 }
361 return n;
362}
363
365static bool rtttl_start(const char *str)
366{
367 const char *p = str;
368 while (*p && *p != ':') { p++; } // skip name
369 if (*p != ':') { return false; }
370 p++;
371 rtttl_d = 4; rtttl_o = 6; rtttl_bpm = 63;
372 while (*p && *p != ':') {
373 char key = *p;
374 if (key == 'd' || key == 'o' || key == 'b') {
375 p += 2; // skip "x="
376 uint16_t v = rtttl_number(&p);
377 if (key == 'd' && v > 0) { rtttl_d = v; }
378 if (key == 'o' && v > 0) { rtttl_o = v; }
379 if (key == 'b' && v > 0) { rtttl_bpm = v; }
380 } else {
381 p++;
382 }
383 }
384 if (*p != ':') { return false; }
385 rtttl = p + 1;
386 return true;
387}
388
390static bool rtttl_next(struct buzzer_note *n)
391{
392 // semitone frequencies of octave 4 [Hz], C to B
393 static const uint16_t octave4[12] = {262, 277, 294, 311, 330, 349, 370, 392, 415, 440, 466, 494};
394 static const int8_t semitone['h' - 'a' + 1] = {9, 11, 0, 2, 4, 5, 7, 11}; // a b c d e f g h(=b)
395 const char *p = rtttl;
396 while (*p == ' ' || *p == ',') { p++; }
397 if (*p == '\0') { return false; }
398 uint16_t d = rtttl_number(&p);
399 if (d == 0) { d = rtttl_d; }
400 char c = *p | 0x20; // lower case
401 if (c != 'p' && (c < 'a' || c > 'h')) { return false; }
402 p++;
403 int8_t semi = (c == 'p') ? -1 : semitone[c - 'a'];
404 if (*p == '#') { semi++; p++; }
405 bool dotted = false;
406 if (*p == '.') { dotted = true; p++; }
407 uint8_t o = rtttl_o;
408 if (*p >= '0' && *p <= '9') { o = *p++ - '0'; }
409 if (*p == '.') { dotted = true; p++; }
410 while (*p && *p != ',') { p++; } // ignore anything else
411 rtttl = p;
412
413 uint32_t ms = (240000UL / rtttl_bpm) / d; // whole note = 4 beats
414 if (dotted) { ms = ms * 3 / 2; }
415 n->ms = Min(ms, 65535);
416 if (semi < 0) {
417 n->freq = REST;
418 } else {
419 uint8_t oct = o + semi / 12; // B# goes to the next octave
420 uint32_t f = octave4[semi % 12];
421 n->freq = (oct >= 4) ? (f << (oct - 4)) : (f >> (4 - oct));
422 }
423 return true;
424}
425
427static bool next_note(struct buzzer_note *n)
428{
429 if (tune_notes != NULL) {
430 if (tune_notes->ms == 0) { return false; }
431 *n = *tune_notes++;
432 return true;
433 }
434 if (rtttl != NULL) {
435 return rtttl_next(n);
436 }
437 return false;
438}
439
440static void start_next_note(void)
441{
442 if (!next_note(&note)) {
443 tune_start(BUZZER_TUNES_NONE); // end of tune
444 return;
445 }
447 note_gap = false;
449}
450
452{
453 // Stop from the GCS silences the event tunes until the next alert or arming
454 if (tune == BUZZER_TUNES_NONE) {
455#ifdef BUZZER_TUNES_ALERT
456 alert_muted = alert_active;
457#endif
458#ifdef BUZZER_TUNES_ARMED_TUNE
459 armed_muted = motors_were_on;
460#endif
461 }
462 tune_start(tune);
463}
464
466static void event_start(uint8_t tune)
467{
468 tune_start(tune);
470}
471
473{
475 if (!on && event_tune) {
477 }
478 // follow the current state again when enabled
479#ifdef BUZZER_TUNES_ALERT
480 alert_active = false;
481 alert_muted = false;
482#endif
483#ifdef BUZZER_TUNES_ARMED_TUNE
484 motors_were_on = false;
485 armed_muted = false;
486#endif
487}
488
489static void tune_start(uint8_t tune)
490{
491 event_tune = false;
492 playing = false;
493 tune_notes = NULL;
494 rtttl = NULL;
497 if (tune == BUZZER_TUNES_NONE || tune >= BUZZER_TUNES_NB) {
498 return;
499 }
500 if (tune >= BUZZER_TUNES_CUSTOM_1) {
502 return; // empty or invalid custom tune
503 }
504 } else {
506 }
507 buzzer_tunes_tune = tune;
508 playing = true;
510}
511
517
521static void event_update(void)
522{
524 return;
525 }
526 bool in_alert = false;
527#ifdef BUZZER_TUNES_ALERT
528 bool alert = BUZZER_TUNES_ALERT;
529 if (alert && !alert_active) {
530 alert_active = true;
531 alert_muted = false;
533 } else if (!alert && alert_active) {
534 alert_active = false;
536 } else if (alert && !playing && !alert_muted) {
538 }
539 in_alert = alert_active;
540#endif
541#ifdef BUZZER_TUNES_ARMED_TUNE
542 bool motors_on = autopilot_get_motors_on();
543 if (motors_on && !motors_were_on) {
544 armed_muted = false;
545 if (!in_alert) {
546 event_start(BUZZER_TUNES_ARMED_TUNE);
547 }
548 } else if (!motors_on && motors_were_on && event_tune && !in_alert) {
549 tune_start(BUZZER_TUNES_NONE); // disarmed: stop the armed (or alert end) tune
550 } else if (motors_on && !in_alert && !playing && !armed_muted) {
551 event_start(BUZZER_TUNES_ARMED_TUNE); // loop, also after an alert
552 }
553 motors_were_on = motors_on;
554#endif
555 (void)in_alert;
556}
557
559{
560 event_update();
561 if (!playing) {
562 return;
563 }
565 if (!note_gap && elapsed + BUZZER_TUNES_GAP_MS >= note.ms) {
567 note_gap = true;
568 }
569 if (elapsed >= note.ms) {
571 }
572}
bool autopilot_get_motors_on(void)
get motors status
Definition autopilot.c:302
Core autopilot interface common to all firmwares.
void buzzer_arch_init(void)
Definition buzzer_arch.c:49
void buzzer_arch_tone(uint16_t freq)
Play a square wave at freq Hz, 0 for silence.
Definition buzzer_arch.c:57
Piezo buzzer tone output with a ChibiOS PWM driver.
#define BUZZER_TUNES_RTTTL_1
Custom tunes (Custom 1..3) in RTTTL format ("name:d=4,o=6,b=120:c,e,g"), set in the airframe,...
static bool playing
static const struct buzzer_note tune_startup[]
Short rising arpeggio.
static struct buzzer_note note
note being played
#define G5
#define Fs6
static const struct buzzer_note tune_star[]
Star Song.
#define BUZZER_TUNES_GAP_MS
Silence at the end of each note, so repeated notes are heard separately [ms].
static const struct buzzer_note tune_twinkle[]
Twinkle Twinkle Little Star, full song (public domain).
static const struct buzzer_note tune_william_tell[]
Rossini, William Tell Overture, galop opening, played twice (public domain).
#define BUZZER_TUNES_ALERT_END_TUNE
Tune played once when BUZZER_TUNES_ALERT becomes false (stopped if the motors are disarmed).
#define D7
void buzzer_tunes_init(void)
#define D5
#define F5
#define TUNE_END
#define Cs5
#define C5
#define C6
static uint8_t rtttl_d
#define A7
#define Fs7
static const struct buzzer_note tune_anthem_netherlands[]
#define Fs5
#define Cs6
void buzzer_tunes_set_events(uint8_t on)
Settings handler: enable or disable the armed and alert tunes.
static bool note_gap
in the silent gap at the end of the note
#define BUZZER_TUNES_EVENTS_ON
Optional header needed by the alert condition.
#define FR_BPM
France, La Marseillaise, opening to "l'étendard sanglant est levé" (Rouget de Lisle 1792,...
#define BUZZER_TUNES_RTTTL_3
static const struct buzzer_note tune_la_cucaracha[]
La Cucaracha, chorus (traditional, public domain).
static const char * rtttl
next note of a RTTTL tune
#define A5
#define NL_BPM
Netherlands, Wilhelmus, first verse (16th century, public domain).
#define E7
static const char *const buzzer_tunes_custom[]
Custom tunes, RTTTL strings.
void buzzer_tunes_periodic(void)
#define D6
static void event_update(void)
Event tunes: alert tune in a loop while the alert condition is true, armed tune in a loop while the m...
static void event_start(uint8_t tune)
Start a tune from an event.
#define F7
#define B6
static const struct buzzer_note tune_ode_to_joy[]
Beethoven, Ode to Joy, full theme (public domain).
static uint8_t rtttl_o
RTTTL default duration and octave.
static uint32_t note_start_ms
start time of the note
static const struct buzzer_note tune_gran_vals[]
Tarrega, Gran Vals, the phrase known as the Nokia ringtone (public domain).
#define Gs5
#define A6
static bool next_note(struct buzzer_note *n)
Get the next note of the tune, false at the end.
uint8_t buzzer_tunes_tune
tune being played, BUZZER_TUNES_NONE when silent
#define BUZZER_TUNES_STARTUP_TUNE
Tune played at startup, BUZZER_TUNES_NONE for silence.
#define E6
#define BUZZER_TUNES_RTTTL_2
#define BUZZER_TUNES_ALERT_TUNE
Tune played in a loop while the motors are armed (optional), stopped when disarmed.
static void tune_start(uint8_t tune)
static bool rtttl_next(struct buzzer_note *n)
Parse the next RTTTL note "[duration]note[#][.][octave][.]", false at the end.
#define Gs6
#define Ds7
static bool event_tune
current tune was started by an event
#define E5
#define IT_BPM
Italy, Il Canto degli Italiani, first verse (Novaro 1847, public domain).
static const struct buzzer_note tune_mushroom[]
Mushroom Song.
#define B5
static const struct buzzer_note *const buzzer_tunes_list[BUZZER_TUNES_CUSTOM_1]
static bool rtttl_start(const char *str)
Parse the RTTTL header "name:d=4,o=6,b=120:", false if invalid.
#define BEATS(_b, _bpm)
Duration of a number of beats at a tempo [ms].
void buzzer_tunes_play(uint8_t tune)
Start a tune (BUZZER_TUNES_NONE stops), also the settings handler.
static uint16_t rtttl_bpm
RTTTL tempo.
#define Ds6
#define G7
#define G6
static const struct buzzer_note tune_anthem_france[]
static uint16_t rtttl_number(const char **p)
#define As5
#define As6
static const struct buzzer_note tune_fur_elise[]
Beethoven, Fur Elise, first section (public domain).
static const struct buzzer_note tune_anthem_italy[]
static void start_next_note(void)
#define F6
uint8_t buzzer_tunes_events_on
armed and alert tunes enabled
uint16_t ms
duration [ms]
static const struct buzzer_note * tune_notes
next note of a built-in tune
static const struct buzzer_note tune_happy_birthday[]
Happy Birthday (public domain).
uint16_t freq
[Hz], REST for silence
#define C7
#define REST
Note frequencies [Hz], s for sharp, octaves 5 to 7 sound loudest on a piezo (octave 4 is quieter).
Play tunes on a passive piezo buzzer (e.g.
@ BUZZER_TUNES_TWINKLE
@ BUZZER_TUNES_CUSTOM_1
custom RTTTL tunes, see BUZZER_TUNES_RTTTL_x
@ BUZZER_TUNES_STARTUP
@ BUZZER_TUNES_STAR
@ BUZZER_TUNES_MUSHROOM
@ BUZZER_TUNES_FUR_ELISE
@ BUZZER_TUNES_ODE_TO_JOY
@ BUZZER_TUNES_WILLIAM_TELL
@ BUZZER_TUNES_ANTHEM_NETHERLANDS
@ BUZZER_TUNES_HAPPY_BIRTHDAY
@ BUZZER_TUNES_ANTHEM_ITALY
@ BUZZER_TUNES_NONE
@ BUZZER_TUNES_NB
@ BUZZER_TUNES_ANTHEM_FRANCE
@ BUZZER_TUNES_GRAN_VALS
@ BUZZER_TUNES_LA_CUCARACHA
uint32_t get_sys_time_msec(void)
Get the time in milliseconds since startup.
#define Min(x, y)
Definition esc_dshot.c:110
static float p[2][2]
Architecture independent timing functions.
unsigned short uint16_t
Typedef defining 16 bit unsigned short type.
unsigned int uint32_t
Typedef defining 32 bit unsigned int type.
unsigned char uint8_t
Typedef defining 8 bit unsigned char type.
signed char int8_t
Typedef defining 8 bit char type.
uint16_t f
Camera baseline, in meters (i.e. horizontal distance between the two cameras of the stereo setup).
Definition wedgebug.c:204