5 * th9x - http://code.google.com/p/th9x
6 * er9x - http://code.google.com/p/er9x
7 * gruvin9x - http://code.google.com/p/gruvin9x
9 * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
28 Implements a bit field, number of bits is set by the template,
29 each bit can be modified and read by the provided methods.
31 template <unsigned int NUM_BITS
> class BitField
{
33 uint8_t bits
[(NUM_BITS
+7)/8];
42 memset(bits
, 0, sizeof(bits
));
45 void setBit(unsigned int bitNo
)
47 if (bitNo
>= NUM_BITS
) return;
48 bits
[bitNo
>> 3] = bits
[bitNo
>> 3] | (1 << (bitNo
& 0x07));
51 bool getBit(unsigned int bitNo
) const
53 // assert(bitNo < NUM_BITS);
54 if (bitNo
>= NUM_BITS
) return false;
55 return bits
[bitNo
>> 3] & (1 << (bitNo
& 0x07));
58 unsigned int getSize() const
64 #define INDEX_LOGICAL_SWITCH_AUDIO_FILE(index, event) (2*(index)+(event))
65 #define INDEX_PHASE_AUDIO_FILE(index, event) (2*(index)+(event))
68 #define AUDIO_FILENAME_MAXLEN (42) // max length (example: /SOUNDS/fr/123456789012/1234567890-off.wav)
69 #define AUDIO_QUEUE_LENGTH (16) // must be a power of 2!
71 #define AUDIO_SAMPLE_RATE (32000)
72 #define AUDIO_BUFFER_DURATION (10)
73 #define AUDIO_BUFFER_SIZE (AUDIO_SAMPLE_RATE*AUDIO_BUFFER_DURATION/1000)
75 #if defined(SIMU) && defined(SIMU_AUDIO)
76 #define AUDIO_BUFFER_COUNT (10) // simulator needs more buffers for smooth audio
77 #elif defined(PCBHORUS)
78 #define AUDIO_BUFFER_COUNT (2) // smaller than Taranis since there is also a buffer on the ADC chip
80 #define AUDIO_BUFFER_COUNT (3)
83 #define BEEP_MIN_FREQ (150)
84 #define BEEP_MAX_FREQ (15000)
85 #define BEEP_DEFAULT_FREQ (2250)
86 #define BEEP_KEY_UP_FREQ (BEEP_DEFAULT_FREQ+150)
87 #define BEEP_KEY_DOWN_FREQ (BEEP_DEFAULT_FREQ-150)
99 typedef uint16_t audio_data_t
;
100 #define AUDIO_DATA_SILENCE 0x8000
101 #define AUDIO_DATA_MIN 0
102 #define AUDIO_DATA_MAX 0xffff
103 #define AUDIO_BITS_PER_SAMPLE 16
104 #elif defined(PCBHORUS)
105 typedef int16_t audio_data_t
;
106 #define AUDIO_DATA_SILENCE 0
107 #define AUDIO_DATA_MIN INT16_MIN
108 #define AUDIO_DATA_MAX INT16_MAX
109 #define AUDIO_BITS_PER_SAMPLE 16
111 typedef uint16_t audio_data_t
;
112 #define AUDIO_DATA_SILENCE (0x8000 >> 4)
113 #define AUDIO_DATA_MIN 0
114 #define AUDIO_DATA_MAX 0x0fff
115 #define AUDIO_BITS_PER_SAMPLE 12
119 audio_data_t data
[AUDIO_BUFFER_SIZE
];
124 extern AudioBuffer audioBuffers
[AUDIO_BUFFER_COUNT
];
139 Tone(uint16_t freq
, uint16_t duration
, uint16_t pause
, int8_t freqIncr
, bool reset
):
149 struct AudioFragment
{
155 char file
[AUDIO_FILENAME_MAXLEN
+1];
158 AudioFragment() { clear(); };
160 AudioFragment(uint16_t freq
, uint16_t duration
, uint16_t pause
, uint8_t repeat
, int8_t freqIncr
, bool reset
, uint8_t id
=0):
164 tone(freq
, duration
, pause
, freqIncr
, reset
)
167 AudioFragment(const char * filename
, uint8_t repeat
, uint8_t id
=0):
172 strcpy(file
, filename
);
175 void clear() { memset(this, 0, sizeof(AudioFragment
)); };
181 inline void clear() { memset(this, 0, sizeof(ToneContext
)); };
182 bool isFree() const { return fragment
.type
== FRAGMENT_EMPTY
; };
183 int mixBuffer(AudioBuffer
*buffer
, int volume
, unsigned int fade
);
185 void setFragment(uint16_t freq
, uint16_t duration
, uint16_t pause
, uint8_t repeat
, int8_t freqIncr
, bool reset
, uint8_t id
=0)
187 fragment
= AudioFragment(freq
, duration
, pause
, repeat
, freqIncr
, reset
, id
);
191 AudioFragment fragment
;
207 inline void clear() { fragment
.clear(); };
209 int mixBuffer(AudioBuffer
*buffer
, int volume
, unsigned int fade
);
210 bool hasId(uint8_t id
) const { return fragment
.id
== id
; };
212 void setFragment(const char * filename
, uint8_t repeat
, uint8_t id
)
214 fragment
= AudioFragment(filename
, repeat
, id
);
217 void stop(uint8_t id
)
219 if (fragment
.id
== id
) {
225 AudioFragment fragment
;
232 uint8_t resampleRatio
;
239 friend void printAudioVars();
248 void setFragment(const AudioFragment
* frag
)
257 tone
.clear(); // the biggest member of the uninon
260 bool isEmpty() const { return fragment
.type
== FRAGMENT_EMPTY
; };
261 bool isTone() const { return fragment
.type
== FRAGMENT_TONE
; };
262 bool isFile() const { return fragment
.type
== FRAGMENT_FILE
; };
263 bool hasId(uint8_t id
) const { return fragment
.id
== id
; };
265 int mixBuffer(AudioBuffer
*buffer
, int toneVolume
, int wavVolume
, unsigned int fade
)
267 if (isTone()) return tone
.mixBuffer(buffer
, toneVolume
, fade
);
268 else if (isFile()) return wav
.mixBuffer(buffer
, wavVolume
, fade
);
274 AudioFragment fragment
; // a hack: fragment is used to access the fragment members of tone and wav
281 class AudioBufferFifo
{
283 friend void printAudioVars();
287 volatile uint8_t readIdx
;
288 volatile uint8_t writeIdx
;
289 volatile bool bufferFull
;
291 // readIdx == writeIdx -> buffer empty
292 // readIdx == writeIdx + 1 -> buffer full
294 inline uint8_t nextBufferIdx(uint8_t idx
) const
296 return (idx
>= AUDIO_BUFFER_COUNT
-1 ? 0 : idx
+1);
304 return (readIdx
== writeIdx
) && !bufferFull
;
308 return bufferFull
? AUDIO_BUFFER_COUNT
: writeIdx
- readIdx
;
312 AudioBufferFifo() : readIdx(0), writeIdx(0), bufferFull(false)
314 memset(audioBuffers
, 0, sizeof(audioBuffers
));
317 // returns an empty buffer to be filled wit data and put back into FIFO with audioPushBuffer()
318 AudioBuffer
* getEmptyBuffer() const
320 #if defined(PCBSKY9X)
321 AudioBuffer
* buffer
= &audioBuffers
[writeIdx
];
322 return buffer
->state
== AUDIO_BUFFER_FREE
? buffer
: NULL
;
324 return full() ? NULL
: &audioBuffers
[writeIdx
];
328 // puts filled buffer into FIFO
329 void audioPushBuffer()
332 #if defined(PCBSKY9X)
333 AudioBuffer
* buffer
= &audioBuffers
[writeIdx
];
334 buffer
->state
= AUDIO_BUFFER_FILLED
;
336 writeIdx
= nextBufferIdx(writeIdx
);
337 bufferFull
= (writeIdx
== readIdx
);
341 // returns a pointer to the audio buffer to be played
342 const AudioBuffer
* getNextFilledBuffer()
344 #if defined(PCBSKY9X)
345 uint8_t idx
= readIdx
;
347 AudioBuffer
* buffer
= &audioBuffers
[idx
];
348 if (buffer
->state
== AUDIO_BUFFER_FILLED
) {
349 buffer
->state
= AUDIO_BUFFER_PLAYING
;
353 idx
= nextBufferIdx(idx
);
354 } while (idx
!= writeIdx
); // this fixes a bug if all buffers are filled
357 return empty() ? NULL
: &audioBuffers
[readIdx
];
361 // frees the last played buffer
362 void freeNextFilledBuffer()
365 #if defined(PCBSKY9X)
366 if (audioBuffers
[readIdx
].state
== AUDIO_BUFFER_PLAYING
) {
367 audioBuffers
[readIdx
].state
= AUDIO_BUFFER_FREE
;
368 readIdx
= nextBufferIdx(readIdx
);
372 readIdx
= nextBufferIdx(readIdx
);
378 bool filledAtleast(int noBuffers
) const
380 #if defined(PCBSKY9X)
382 for(int n
= 0; n
<AUDIO_BUFFER_COUNT
; ++n
) {
383 if (audioBuffers
[n
].state
== AUDIO_BUFFER_FILLED
) {
384 if (++count
>= noBuffers
) {
391 return used() >= noBuffers
;
397 class AudioFragmentFifo
400 friend void printAudioVars();
403 volatile uint8_t ridx
;
404 volatile uint8_t widx
;
405 AudioFragment fragments
[AUDIO_QUEUE_LENGTH
];
407 uint8_t nextIdx(uint8_t idx
) const
409 return (idx
+ 1) & (AUDIO_QUEUE_LENGTH
- 1);
413 AudioFragmentFifo() : ridx(0), widx(0), fragments() {};
415 bool hasId(uint8_t id
)
419 AudioFragment
& fragment
= fragments
[i
];
420 if (fragment
.id
== id
) return true;
433 return ridx
== nextIdx(widx
);
438 widx
= ridx
; // clean the queue
441 const AudioFragment
* get()
444 const AudioFragment
* result
= &fragments
[ridx
];
445 if (!fragments
[ridx
].repeat
--) {
446 // repeat is done, move to the next fragment
447 ridx
= nextIdx(ridx
);
454 void push(const AudioFragment
& fragment
)
457 // TRACE("fragment %d at %d", fragment.type, widx);
458 fragments
[widx
] = fragment
;
459 widx
= nextIdx(widx
);
467 #if defined(SIMU_AUDIO)
468 friend void fillAudioBuffer(void *, uint8_t *, int);
471 friend void printAudioVars();
475 void start() { _started
= true; };
476 void playTone(uint16_t freq
, uint16_t len
, uint16_t pause
=0, uint8_t flags
=0, int8_t freqIncr
=0);
477 void playFile(const char *filename
, uint8_t flags
=0, uint8_t id
=0);
478 void stopPlay(uint8_t id
);
481 void pause(uint16_t tLen
);
483 bool isPlaying(uint8_t id
);
484 bool isEmpty() const { return fragmentsFifo
.empty(); };
486 bool started() const { return _started
; };
488 AudioBufferFifo buffersFifo
;
491 volatile bool _started
;
492 MixedContext normalContext
;
493 WavContext backgroundContext
;
494 ToneContext priorityContext
;
495 ToneContext varioContext
;
496 AudioFragmentFifo fragmentsFifo
;
499 extern uint8_t currentSpeakerVolume
;
500 extern AudioQueue audioQueue
;
503 ID_PLAY_FROM_SD_MANAGER
= 254,
508 void audioEvent(unsigned int index
);
509 void audioPlay(unsigned int index
, uint8_t id
=0);
512 #if defined(AUDIO) && defined(BUZZER)
513 #define AUDIO_BUZZER(a, b) do { a; b; } while(0)
515 #define AUDIO_BUZZER(a, b) a
517 #define AUDIO_BUZZER(a, b) b
521 #define AUDIO_ERROR_MESSAGE(e) audioEvent(e)
522 #define AUDIO_TIMER_MINUTE(t) playDuration(t, 0, 0)
524 #define AUDIO_ERROR_MESSAGE(e) audioEvent(AU_ERROR)
525 #define AUDIO_TIMER_MINUTE(t) audioDefevent(AU_WARNING1)
528 void audioKeyPress();
529 void audioKeyError();
530 void audioTrimPress(int value
);
531 void audioTimerCountdown(uint8_t timer
, int value
);
533 #define AUDIO_KEY_PRESS() audioKeyPress()
534 #define AUDIO_KEY_ERROR() audioKeyError()
536 #define AUDIO_HELLO() audioPlay(AUDIO_HELLO)
537 #define AUDIO_BYE() audioPlay(AU_BYE, ID_PLAY_BYE)
538 #define AUDIO_WARNING1() AUDIO_BUZZER(audioEvent(AU_WARNING1), beep(3))
539 #define AUDIO_WARNING2() AUDIO_BUZZER(audioEvent(AU_WARNING2), beep(2))
540 #define AUDIO_TX_BATTERY_LOW() AUDIO_BUZZER(audioEvent(AU_TX_BATTERY_LOW), beep(4))
541 #if defined(PCBSKY9X)
542 #define AUDIO_TX_MAH_HIGH() audioEvent(AU_TX_MAH_HIGH)
543 #define AUDIO_TX_TEMP_HIGH() audioEvent(AU_TX_TEMP_HIGH)
545 #define AUDIO_ERROR() AUDIO_BUZZER(audioEvent(AU_ERROR), beep(4))
546 #define AUDIO_TIMER_COUNTDOWN(idx, val) audioTimerCountdown(idx, val)
547 #define AUDIO_TIMER_ELAPSED(idx) AUDIO_BUZZER(audioEvent(AU_TIMER1_ELAPSED+idx), beep(3))
548 #define AUDIO_INACTIVITY() AUDIO_BUZZER(audioEvent(AU_INACTIVITY), beep(3))
549 #define AUDIO_MIX_WARNING(x) AUDIO_BUZZER(audioEvent(AU_MIX_WARNING_1+x-1), beep(1))
550 #define AUDIO_POT_MIDDLE(x) AUDIO_BUZZER(audioEvent(AU_STICK1_MIDDLE+x), beep(2))
551 #define AUDIO_TRIM_MIDDLE() AUDIO_BUZZER(audioEvent(AU_TRIM_MIDDLE), beep(2))
552 #define AUDIO_TRIM_MIN() AUDIO_BUZZER(audioEvent(AU_TRIM_MIN), beep(2))
553 #define AUDIO_TRIM_MAX() AUDIO_BUZZER(audioEvent(AU_TRIM_MAX), beep(2))
554 #define AUDIO_TRIM_PRESS(val) audioTrimPress(val)
555 #define AUDIO_PLAY(p) audioEvent(p)
556 #define AUDIO_VARIO(fq, t, p, f) audioQueue.playTone(fq, t, p, f)
557 #define AUDIO_RSSI_ORANGE() audioEvent(AU_RSSI_ORANGE)
558 #define AUDIO_RSSI_RED() audioEvent(AU_RSSI_RED)
559 #define AUDIO_SWR_RED() audioEvent(AU_SWR_RED)
560 #define AUDIO_TELEMETRY_LOST() audioEvent(AU_TELEMETRY_LOST)
561 #define AUDIO_TELEMETRY_BACK() audioEvent(AU_TELEMETRY_BACK)
562 #define AUDIO_TRAINER_LOST() audioEvent(AU_TRAINER_LOST)
563 #define AUDIO_TRAINER_BACK() audioEvent(AU_TRAINER_BACK)
565 #define AUDIO_HEARTBEAT()
567 enum AutomaticPromptsCategories
{
568 SYSTEM_AUDIO_CATEGORY
,
569 MODEL_AUDIO_CATEGORY
,
570 PHASE_AUDIO_CATEGORY
,
571 SWITCH_AUDIO_CATEGORY
,
572 LOGICAL_SWITCH_AUDIO_CATEGORY
,
575 enum AutomaticPromptsEvents
{
581 void pushPrompt(uint16_t prompt
, uint8_t id
=0);
582 void pushUnit(uint8_t unit
, uint8_t idx
, uint8_t id
);
583 void playModelName();
585 #define I18N_PLAY_FUNCTION(lng, x, ...) void lng ## _ ## x(__VA_ARGS__, uint8_t id)
586 #define PLAY_FUNCTION(x, ...) void x(__VA_ARGS__, uint8_t id)
587 #define PUSH_NUMBER_PROMPT(p) pushPrompt((p), id)
588 #define PUSH_UNIT_PROMPT(p, i) pushUnit((p), (i), id)
589 #define PLAY_NUMBER(n, u, a) playNumber((n), (u), (a), id)
590 #define PLAY_DURATION(d, att) playDuration((d), (att), id)
591 #define PLAY_DURATION_ATT , uint8_t flags
593 #define IS_PLAY_TIME() (flags&PLAY_TIME)
594 #define IS_PLAYING(id) audioQueue.isPlaying((id))
595 #define PLAY_VALUE(v, id) playValue((v), (id))
596 #define PLAY_FILE(f, flags, id) audioQueue.playFile((f), (flags), (id))
597 #define STOP_PLAY(id) audioQueue.stopPlay((id))
598 #define AUDIO_RESET() audioQueue.stopAll()
599 #define AUDIO_FLUSH() audioQueue.flush()
602 extern tmr10ms_t timeAutomaticPromptsSilence
;
603 void playModelEvent(uint8_t category
, uint8_t index
, event_t event
=0);
604 #define PLAY_PHASE_OFF(phase) playModelEvent(PHASE_AUDIO_CATEGORY, phase, AUDIO_EVENT_OFF)
605 #define PLAY_PHASE_ON(phase) playModelEvent(PHASE_AUDIO_CATEGORY, phase, AUDIO_EVENT_ON)
606 #define PLAY_SWITCH_MOVED(sw) playModelEvent(SWITCH_AUDIO_CATEGORY, sw)
607 #define PLAY_LOGICAL_SWITCH_OFF(sw) playModelEvent(LOGICAL_SWITCH_AUDIO_CATEGORY, sw, AUDIO_EVENT_OFF)
608 #define PLAY_LOGICAL_SWITCH_ON(sw) playModelEvent(LOGICAL_SWITCH_AUDIO_CATEGORY, sw, AUDIO_EVENT_ON)
609 #define PLAY_MODEL_NAME() playModelName()
610 #define START_SILENCE_PERIOD() timeAutomaticPromptsSilence = get_tmr10ms()
611 #define IS_SILENCE_PERIOD_ELAPSED() (get_tmr10ms()-timeAutomaticPromptsSilence > 50)
613 #define PLAY_PHASE_OFF(phase)
614 #define PLAY_PHASE_ON(phase)
615 #define PLAY_SWITCH_MOVED(sw)
616 #define PLAY_LOGICAL_SWITCH_OFF(sw)
617 #define PLAY_LOGICAL_SWITCH_ON(sw)
618 #define PLAY_MODEL_NAME()
619 #define START_SILENCE_PERIOD()
622 char * getAudioPath(char * path
);
624 void referenceSystemAudioFiles();
625 void referenceModelAudioFiles();
627 bool isAudioFileReferenced(uint32_t i
, char * filename
/*at least AUDIO_FILENAME_MAXLEN+1 long*/);
629 #endif // _AUDIO_ARM_H_