Add Advert sound and settings

This commit is contained in:
vanous
2026-06-04 08:46:15 +02:00
parent 49536cb3a5
commit 0630e127d4
7 changed files with 46 additions and 14 deletions

View File

@@ -18,7 +18,7 @@ enum class UIEventType {
contactMessage,
channelMessage,
roomMessage,
newContactMessage,
advertReceived,
ack
};

View File

@@ -317,6 +317,9 @@ void DataStore::loadPrefsInt(const char *filename, NodePrefs& _prefs, double& no
rd(&_prefs.trail_units_idx, sizeof(_prefs.trail_units_idx));
rd(&_prefs.ch_fav_bitmask, sizeof(_prefs.ch_fav_bitmask));
rd(&_prefs.ch_fav_only, sizeof(_prefs.ch_fav_only));
if (file.available() >= (int)(sizeof(_prefs.notif_melody_ad) + sizeof(uint32_t))) {
file.read((uint8_t *)&_prefs.notif_melody_ad, sizeof(_prefs.notif_melody_ad));
}
// Schema sentinel: bumped on layout changes. Mismatch means an older file
// (or a different schema); rd() already zero-inits any fields not present,
@@ -335,7 +338,7 @@ void DataStore::loadPrefsInt(const char *filename, NodePrefs& _prefs, double& no
// 0xC0DE0003 → 0xC0DE0004: trail_units_idx added after trail_min_delta_idx.
// On a 0xC0DE0003 file the sentinel bytes sit where trail_units_idx is now,
// so rd() picks up 0x03 (low byte of the old sentinel) — reset just that
// case to default 0. Newer mismatches (e.g. 0xC0DE0004 → 0xC0DE0005) had
// case to default 0. Newer mismatches (e.g. 0xC0DE0005 → 0xC0DE0006) had
// the field saved correctly and must not be clobbered.
if (sentinel == 0xC0DE0003) {
_prefs.trail_units_idx = 0;
@@ -428,6 +431,7 @@ void DataStore::savePrefs(const NodePrefs& _prefs, double node_lat, double node_
file.write((uint8_t *)&_prefs.trail_units_idx, sizeof(_prefs.trail_units_idx));
file.write((uint8_t *)&_prefs.ch_fav_bitmask, sizeof(_prefs.ch_fav_bitmask));
file.write((uint8_t *)&_prefs.ch_fav_only, sizeof(_prefs.ch_fav_only));
file.write((uint8_t *)&_prefs.notif_melody_ad, sizeof(_prefs.notif_melody_ad));
// Tail sentinel — must be last. See NodePrefs::SCHEMA_SENTINEL.
uint32_t sentinel = NodePrefs::SCHEMA_SENTINEL;

View File

@@ -360,6 +360,8 @@ void MyMesh::onContactsFull() {
}
void MyMesh::onDiscoveredContact(ContactInfo &contact, bool is_new, uint8_t path_len, const uint8_t* path) {
if (_ui) _ui->notify(UIEventType::advertReceived);
if (_serial->isConnected()) {
if (is_new) {
writeContactRespFrame(PUSH_CODE_NEW_ADVERT, contact);
@@ -368,10 +370,6 @@ void MyMesh::onDiscoveredContact(ContactInfo &contact, bool is_new, uint8_t path
memcpy(&out_frame[1], contact.id.pub_key, PUB_KEY_SIZE);
_serial->writeFrame(out_frame, 1 + PUB_KEY_SIZE);
}
} else {
#ifdef DISPLAY_CLASS
if (_ui) _ui->notify(UIEventType::newContactMessage);
#endif
}
// add inbound-path to mem cache
@@ -920,7 +918,7 @@ void MyMesh::onControlDataRecv(mesh::Packet *packet) {
memcpy(r.pub_key, pub_key, PUB_KEY_SIZE);
r.timestamp = getRTCClock()->getCurrentTime();
}
if (_ui) _ui->notify(UIEventType::newContactMessage);
if (_ui) _ui->notify(UIEventType::advertReceived);
return; // our discover — don't forward to BLE app
}
}
@@ -1090,6 +1088,7 @@ MyMesh::MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMe
_prefs.ringtone_bpm_idx = 2; // 120 bpm default
_prefs.ringtone_len = 0; // no custom ringtone by default
_prefs.ringtone2_bpm_idx = 2; // 120 bpm default
_prefs.notif_melody_ad = 0; // built-in advert sound by default
_prefs.home_pages_mask = 0x01FF; // all pages visible
_prefs.bot_enabled = 0;
_prefs.bot_channel_enabled = 0;
@@ -2498,7 +2497,7 @@ void MyMesh::loop() {
}
#ifdef DISPLAY_CLASS
if (_ui) _ui->setHasConnection(_serial->isBLEConnected());
if (_ui) _ui->setHasConnection(_serial->isConnected());
#endif
}

View File

@@ -69,9 +69,10 @@ struct NodePrefs { // persisted to file
uint8_t ringtone2_bpm_idx;
uint8_t ringtone2_len;
uint8_t ringtone2_notes[32];
// Global melody for notifications: 0=built-in, 1=melody1, 2=melody2
// Global melodies for notifications: 0=built-in, 1=melody1, 2=melody2
uint8_t notif_melody_dm;
uint8_t notif_melody_ch;
uint8_t notif_melody_ad;
// Per-channel melody override (2 bitmasks, 1 bit per channel)
uint64_t ch_notif_melody_set; // bit i = channel i has explicit melody
uint64_t ch_notif_melody_2; // bit i = use melody 2 (else melody 1, when set bit is set)
@@ -112,7 +113,7 @@ struct NodePrefs { // persisted to file
// adding/removing/reordering fields in DataStore::savePrefs/loadPrefsInt so
// older saves are detected on load and skipped (zero-init defaults kept).
// High 24 bits identify the file format; low byte is the schema revision.
static const uint32_t SCHEMA_SENTINEL = 0xC0DE0005;
static const uint32_t SCHEMA_SENTINEL = 0xC0DE0006;
// Bit-index for each home page. Used by page_order (entries store bit+1) and
// by home_pages_mask. Single source of truth — both HomeScreen::pageBit/bitToPage

View File

@@ -38,6 +38,7 @@ class SettingsScreen : public UIScreen {
BUZZER_VOLUME,
DM_MELODY,
CH_MELODY,
AD_SOUND,
// Home pages section
SECTION_HOME_PAGES,
HOME_CLOCK, HOME_FAVOURITES, HOME_RECENT, HOME_RADIO, HOME_BT, HOME_ADVERT,
@@ -445,6 +446,12 @@ class SettingsScreen : public UIScreen {
{ static const char* L[] = { "built-in", "M1", "M2" };
uint8_t v = p ? p->notif_melody_ch : 0;
display.print(L[v < 3 ? v : 0]); }
} else if (item == AD_SOUND) {
display.print("AD sound");
display.setCursor(display.valCol(), y);
{ static const char* L[] = { "built-in", "M1", "M2" };
uint8_t v = p ? p->notif_melody_ad : 0;
display.print(L[v < 3 ? v : 0]); }
} else if (isHomePage(item)) {
if (p) ensurePageOrderInit(p);
int pos = homePagePosition(item, p);
@@ -691,6 +698,10 @@ public:
p->notif_melody_ch = (p->notif_melody_ch + (left ? 2 : 1)) % 3;
_dirty = true; return true;
}
if (_selected == AD_SOUND && p && (left || right || enter)) {
p->notif_melody_ad = (p->notif_melody_ad + (left ? 2 : 1)) % 3;
_dirty = true; return true;
}
if (isHomePage(_selected) && p) {
if (left || right) {
movePageInOrder(_selected, left ? -1 : 1, p);

View File

@@ -1380,11 +1380,28 @@ switch(t){
_last_notif_ch_idx = -1;
break;
}
case UIEventType::advertReceived: {
if (!buzzer.isQuiet()) {
int slot = _node_prefs ? (int)_node_prefs->notif_melody_ad : 0;
bool custom_played = false;
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");
}
}
break;
}
case UIEventType::ack:
buzzer.play("ack:d=32,o=8,b=120:c");
break;
case UIEventType::roomMessage:
case UIEventType::newContactMessage:
case UIEventType::none:
default:
break;

View File

@@ -103,7 +103,7 @@ switch(t){
buzzer.play("ack:d=32,o=8,b=120:c");
break;
case UIEventType::roomMessage:
case UIEventType::newContactMessage:
case UIEventType::advertReceived:
case UIEventType::none:
default:
break;