mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-07-26 14:58:12 +00:00
refactor: extract SoundNotifier helper from UITask::notify()
Move all buzzer/melody dispatch (DM, channel, advert) into a new SoundNotifier class in SoundNotifier.h, isolating fork-specific sound code so upstream changes to notify() no longer cause merge conflicts. The shared playSlot() helper also removes the custom_played duplication that existed across the three cases. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
96
examples/companion_radio/ui-new/SoundNotifier.h
Normal file
96
examples/companion_radio/ui-new/SoundNotifier.h
Normal file
@@ -0,0 +1,96 @@
|
||||
#pragma once
|
||||
// Fork-specific buzzer/melody dispatch — isolated here so upstream changes to
|
||||
// UITask::notify() don't create merge conflicts.
|
||||
#ifdef PIN_BUZZER
|
||||
#include <helpers/ui/buzzer.h>
|
||||
#include "NodePrefs.h"
|
||||
|
||||
class SoundNotifier {
|
||||
genericBuzzer& _buz;
|
||||
const NodePrefs* _prefs;
|
||||
char* _mel_buf;
|
||||
int _mel_buf_sz;
|
||||
|
||||
static void buildMelody(const NodePrefs* p, int slot, char* buf, int size) {
|
||||
const uint8_t* notes = (slot == 2) ? p->ringtone2_notes : p->ringtone_notes;
|
||||
uint8_t len = (slot == 2) ? p->ringtone2_len : p->ringtone_len;
|
||||
uint8_t bpm_i = (slot == 2) ? p->ringtone2_bpm_idx : p->ringtone_bpm_idx;
|
||||
NodePrefs::buildRTTTLString(notes, len, bpm_i, buf, size);
|
||||
}
|
||||
|
||||
// Play custom slot (1/2) or fall back to built-in RTTTL. Slot 3 = explicit silence.
|
||||
void playSlot(int slot, bool force, const char* fallback) {
|
||||
if (slot == 3) return;
|
||||
if (slot > 0 && _prefs) {
|
||||
if (_buz.isPlaying()) _buz.stop();
|
||||
buildMelody(_prefs, slot, _mel_buf, _mel_buf_sz);
|
||||
if (_mel_buf[0]) {
|
||||
if (force) _buz.playForced(_mel_buf); else _buz.play(_mel_buf);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (force) _buz.playForced(fallback); else _buz.play(fallback);
|
||||
}
|
||||
|
||||
public:
|
||||
SoundNotifier(genericBuzzer& buz, const NodePrefs* prefs, char* buf, int sz)
|
||||
: _buz(buz), _prefs(prefs), _mel_buf(buf), _mel_buf_sz(sz) {}
|
||||
|
||||
void playDM(bool dm_valid, const uint8_t* dm_prefix) {
|
||||
bool play = false, force = false;
|
||||
if (dm_valid && _prefs) {
|
||||
uint8_t state = 0;
|
||||
for (int i = 0; i < NodePrefs::DM_NOTIF_TABLE_MAX; i++) {
|
||||
if (_prefs->dm_notif[i].state &&
|
||||
memcmp(_prefs->dm_notif[i].prefix, dm_prefix, 4) == 0)
|
||||
{ state = _prefs->dm_notif[i].state; break; }
|
||||
}
|
||||
if (state == 2) { play = true; force = true; }
|
||||
else if (state == 1) { /* muted */ }
|
||||
else { play = !_buz.isQuiet(); }
|
||||
} else {
|
||||
play = !_buz.isQuiet();
|
||||
}
|
||||
if (!play) return;
|
||||
|
||||
int slot = _prefs ? (int)_prefs->notif_melody_dm : 0;
|
||||
if (dm_valid && _prefs) {
|
||||
for (int i = 0; i < NodePrefs::DM_MELODY_TABLE_MAX; i++)
|
||||
if (_prefs->dm_melody[i].slot &&
|
||||
memcmp(_prefs->dm_melody[i].prefix, dm_prefix, 4) == 0)
|
||||
{ slot = _prefs->dm_melody[i].slot; break; }
|
||||
}
|
||||
playSlot(slot, force, "MsgRcv3:d=4,o=6,b=200:32e,32g,32b,16c7");
|
||||
}
|
||||
|
||||
void playCH(int ch_idx) {
|
||||
bool play = false, force = false;
|
||||
if (ch_idx >= 0 && ch_idx < 64 && _prefs) {
|
||||
uint64_t mask = 1ULL << ch_idx;
|
||||
if (_prefs->ch_notif_override & mask) {
|
||||
if (!(_prefs->ch_notif_muted & mask)) { play = true; force = true; }
|
||||
} else {
|
||||
play = !_buz.isQuiet();
|
||||
}
|
||||
} else {
|
||||
play = !_buz.isQuiet();
|
||||
}
|
||||
if (!play) return;
|
||||
|
||||
int slot = _prefs ? (int)_prefs->notif_melody_ch : 0;
|
||||
if (ch_idx >= 0 && ch_idx < 64 && _prefs) {
|
||||
uint64_t mask = 1ULL << ch_idx;
|
||||
if (_prefs->ch_notif_melody_set & mask)
|
||||
slot = (_prefs->ch_notif_melody_2 & mask) ? 2 : 1;
|
||||
}
|
||||
playSlot(slot, force, "kerplop:d=16,o=6,b=120:32g#,32c#");
|
||||
}
|
||||
|
||||
void playAD(bool is_flood) {
|
||||
if (_prefs && _prefs->advert_sound_scope == ADVERT_SOUND_SCOPE_ZERO_HOP && is_flood) return;
|
||||
if (_buz.isQuiet()) return;
|
||||
int slot = _prefs ? (int)_prefs->notif_melody_ad : 0;
|
||||
playSlot(slot, false, "MsgRcv3:d=4,o=6,b=200:32e,32g,32b,16c7");
|
||||
}
|
||||
};
|
||||
#endif
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "UITask.h"
|
||||
#include "SoundNotifier.h"
|
||||
#include <helpers/TxtDataHelpers.h>
|
||||
#include "../MyMesh.h"
|
||||
#include "../MsgExpand.h"
|
||||
@@ -1375,124 +1376,23 @@ void UITask::showAlert(const char* text, int duration_millis) {
|
||||
_alert_expiry = millis() + duration_millis;
|
||||
}
|
||||
|
||||
static void buildMelodyFromPrefs(const NodePrefs* p, int slot, char* buf, int size) {
|
||||
const uint8_t* notes = (slot == 2) ? p->ringtone2_notes : p->ringtone_notes;
|
||||
uint8_t len = (slot == 2) ? p->ringtone2_len : p->ringtone_len;
|
||||
uint8_t bpm_i = (slot == 2) ? p->ringtone2_bpm_idx : p->ringtone_bpm_idx;
|
||||
NodePrefs::buildRTTTLString(notes, len, bpm_i, buf, size);
|
||||
}
|
||||
|
||||
void UITask::notify(UIEventType t) {
|
||||
#if defined(PIN_BUZZER)
|
||||
switch(t){
|
||||
case UIEventType::contactMessage: {
|
||||
bool play = false;
|
||||
bool force = false;
|
||||
if (_last_notif_dm_valid && _node_prefs) {
|
||||
uint8_t state = 0;
|
||||
for (int i = 0; i < NodePrefs::DM_NOTIF_TABLE_MAX; i++) {
|
||||
if (_node_prefs->dm_notif[i].state &&
|
||||
memcmp(_node_prefs->dm_notif[i].prefix, _last_notif_dm_prefix, 4) == 0) {
|
||||
state = _node_prefs->dm_notif[i].state; break;
|
||||
}
|
||||
}
|
||||
if (state == 2) { play = true; force = true; } // force-on
|
||||
else if (state == 1) { /* muted */ }
|
||||
else { play = !buzzer.isQuiet(); } // default: follow global
|
||||
} else {
|
||||
play = !buzzer.isQuiet();
|
||||
}
|
||||
{
|
||||
SoundNotifier sn(buzzer, _node_prefs, _notif_mel_buf, sizeof(_notif_mel_buf));
|
||||
switch(t){
|
||||
case UIEventType::contactMessage:
|
||||
sn.playDM(_last_notif_dm_valid, _last_notif_dm_prefix);
|
||||
_last_notif_dm_valid = false;
|
||||
if (play) {
|
||||
int slot = _node_prefs ? (int)_node_prefs->notif_melody_dm : 0;
|
||||
if (_node_prefs) {
|
||||
for (int i = 0; i < NodePrefs::DM_MELODY_TABLE_MAX; i++)
|
||||
if (_node_prefs->dm_melody[i].slot &&
|
||||
memcmp(_node_prefs->dm_melody[i].prefix, _last_notif_dm_prefix, 4) == 0)
|
||||
{ slot = _node_prefs->dm_melody[i].slot; break; }
|
||||
}
|
||||
bool custom_played = false;
|
||||
if (slot == 3) {
|
||||
custom_played = true; // explicit silence
|
||||
} else if (slot > 0 && _node_prefs) {
|
||||
if (buzzer.isPlaying()) buzzer.stop(); // stop before overwriting _notif_mel_buf
|
||||
buildMelodyFromPrefs(_node_prefs, slot, _notif_mel_buf, sizeof(_notif_mel_buf));
|
||||
if (_notif_mel_buf[0]) {
|
||||
if (force) buzzer.playForced(_notif_mel_buf); else buzzer.play(_notif_mel_buf);
|
||||
custom_played = true;
|
||||
}
|
||||
}
|
||||
if (!custom_played) {
|
||||
if (force) buzzer.playForced("MsgRcv3:d=4,o=6,b=200:32e,32g,32b,16c7");
|
||||
else buzzer.play("MsgRcv3:d=4,o=6,b=200:32e,32g,32b,16c7");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case UIEventType::channelMessage: {
|
||||
bool play = false;
|
||||
bool force = false;
|
||||
if (_last_notif_ch_idx >= 0 && _last_notif_ch_idx < 64 && _node_prefs) {
|
||||
uint64_t mask = 1ULL << _last_notif_ch_idx;
|
||||
if (_node_prefs->ch_notif_override & mask) {
|
||||
if (!(_node_prefs->ch_notif_muted & mask)) { play = true; force = true; }
|
||||
} else {
|
||||
play = !buzzer.isQuiet();
|
||||
}
|
||||
} else {
|
||||
play = !buzzer.isQuiet();
|
||||
}
|
||||
if (play) {
|
||||
int slot = _node_prefs ? (int)_node_prefs->notif_melody_ch : 0;
|
||||
if (_last_notif_ch_idx >= 0 && _last_notif_ch_idx < 64 && _node_prefs) {
|
||||
uint64_t mask = 1ULL << _last_notif_ch_idx;
|
||||
if (_node_prefs->ch_notif_melody_set & mask)
|
||||
slot = (_node_prefs->ch_notif_melody_2 & mask) ? 2 : 1;
|
||||
}
|
||||
bool custom_played = false;
|
||||
if (slot == 3) {
|
||||
custom_played = true; // explicit silence
|
||||
} else if (slot > 0 && _node_prefs) {
|
||||
if (buzzer.isPlaying()) buzzer.stop(); // stop before overwriting _notif_mel_buf
|
||||
buildMelodyFromPrefs(_node_prefs, slot, _notif_mel_buf, sizeof(_notif_mel_buf));
|
||||
if (_notif_mel_buf[0]) {
|
||||
if (force) buzzer.playForced(_notif_mel_buf); else buzzer.play(_notif_mel_buf);
|
||||
custom_played = true;
|
||||
}
|
||||
}
|
||||
if (!custom_played) {
|
||||
if (force) buzzer.playForced("kerplop:d=16,o=6,b=120:32g#,32c#");
|
||||
else buzzer.play("kerplop:d=16,o=6,b=120:32g#,32c#");
|
||||
}
|
||||
}
|
||||
case UIEventType::channelMessage:
|
||||
sn.playCH(_last_notif_ch_idx);
|
||||
_last_notif_ch_idx = -1;
|
||||
break;
|
||||
}
|
||||
case UIEventType::advertReceivedFlood:
|
||||
case UIEventType::advertReceivedZeroHop: {
|
||||
bool is_flood = (t == UIEventType::advertReceivedFlood);
|
||||
if (_node_prefs && _node_prefs->advert_sound_scope == ADVERT_SOUND_SCOPE_ZERO_HOP && is_flood) {
|
||||
break;
|
||||
}
|
||||
if (!buzzer.isQuiet()) {
|
||||
int slot = _node_prefs ? (int)_node_prefs->notif_melody_ad : 0;
|
||||
bool custom_played = false;
|
||||
if (slot == 3) {
|
||||
custom_played = true; // explicit silence
|
||||
} else if (slot > 0 && _node_prefs) {
|
||||
if (buzzer.isPlaying()) buzzer.stop(); // stop before overwriting _notif_mel_buf
|
||||
buildMelodyFromPrefs(_node_prefs, slot, _notif_mel_buf, sizeof(_notif_mel_buf));
|
||||
if (_notif_mel_buf[0]) {
|
||||
buzzer.play(_notif_mel_buf);
|
||||
custom_played = true;
|
||||
}
|
||||
}
|
||||
if (!custom_played) {
|
||||
buzzer.play("MsgRcv3:d=4,o=6,b=200:32e,32g,32b,16c7");
|
||||
}
|
||||
}
|
||||
case UIEventType::advertReceivedZeroHop:
|
||||
sn.playAD(t == UIEventType::advertReceivedFlood);
|
||||
break;
|
||||
}
|
||||
case UIEventType::ack:
|
||||
buzzer.play("ack:d=32,o=8,b=120:c");
|
||||
break;
|
||||
@@ -1500,6 +1400,7 @@ switch(t){
|
||||
case UIEventType::none:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
Reference in New Issue
Block a user