mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-07-26 23:08:11 +00:00
Merge remote-tracking branch 'origin/wio-unified' into wio-unified
# Conflicts: # examples/companion_radio/DataStore.cpp
This commit is contained in:
@@ -18,7 +18,7 @@ enum class UIEventType {
|
|||||||
contactMessage,
|
contactMessage,
|
||||||
channelMessage,
|
channelMessage,
|
||||||
roomMessage,
|
roomMessage,
|
||||||
newContactMessage,
|
advertReceived,
|
||||||
ack
|
ack
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -317,10 +317,12 @@ void DataStore::loadPrefsInt(const char *filename, NodePrefs& _prefs, double& no
|
|||||||
rd(&_prefs.trail_units_idx, sizeof(_prefs.trail_units_idx));
|
rd(&_prefs.trail_units_idx, sizeof(_prefs.trail_units_idx));
|
||||||
rd(&_prefs.ch_fav_bitmask, sizeof(_prefs.ch_fav_bitmask));
|
rd(&_prefs.ch_fav_bitmask, sizeof(_prefs.ch_fav_bitmask));
|
||||||
rd(&_prefs.ch_fav_only, sizeof(_prefs.ch_fav_only));
|
rd(&_prefs.ch_fav_only, sizeof(_prefs.ch_fav_only));
|
||||||
|
rd(&_prefs.notif_melody_ad, sizeof(_prefs.notif_melody_ad));
|
||||||
rd(&_prefs.units_imperial, sizeof(_prefs.units_imperial));
|
rd(&_prefs.units_imperial, sizeof(_prefs.units_imperial));
|
||||||
rd(&_prefs.trail_show_pace, sizeof(_prefs.trail_show_pace));
|
rd(&_prefs.trail_show_pace, sizeof(_prefs.trail_show_pace));
|
||||||
// Both are booleans: an older file leaves stray bytes here (the old tail
|
// These three were appended together; an older file leaves stray bytes here
|
||||||
// sentinel gets partly consumed), so clamp anything other than 0/1 to 0.
|
// (the old tail sentinel gets partly consumed), so clamp out-of-range values.
|
||||||
|
if (_prefs.notif_melody_ad > 2) _prefs.notif_melody_ad = 0;
|
||||||
if (_prefs.units_imperial > 1) _prefs.units_imperial = 0;
|
if (_prefs.units_imperial > 1) _prefs.units_imperial = 0;
|
||||||
if (_prefs.trail_show_pace > 1) _prefs.trail_show_pace = 0;
|
if (_prefs.trail_show_pace > 1) _prefs.trail_show_pace = 0;
|
||||||
|
|
||||||
@@ -341,14 +343,16 @@ void DataStore::loadPrefsInt(const char *filename, NodePrefs& _prefs, double& no
|
|||||||
// 0xC0DE0003 → 0xC0DE0004: trail_units_idx added after trail_min_delta_idx.
|
// 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,
|
// 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
|
// 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.
|
// the field saved correctly and must not be clobbered.
|
||||||
if (sentinel == 0xC0DE0003) {
|
if (sentinel == 0xC0DE0003) {
|
||||||
_prefs.trail_units_idx = 0;
|
_prefs.trail_units_idx = 0;
|
||||||
}
|
}
|
||||||
// 0xC0DE0005 → 0xC0DE0006: units_imperial + trail_show_pace replaced the
|
// → 0xC0DE0007: merge of two parallel 0xC0DE0006 layouts — notif_melody_ad
|
||||||
// combined trail_units_idx. The new bytes overlap the old tail sentinel and
|
// (advert sound) and units_imperial + trail_show_pace were appended after
|
||||||
// are already clamped to 0 above, so upgraders default to metric + speed.
|
// ch_fav_only. Any older file (incl. either single-feature 0006) leaves
|
||||||
|
// stray/old bytes in these fields; they're clamped above, so upgraders fall
|
||||||
|
// back to built-in advert sound + metric + speed.
|
||||||
}
|
}
|
||||||
|
|
||||||
file.close();
|
file.close();
|
||||||
@@ -437,6 +441,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.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_bitmask, sizeof(_prefs.ch_fav_bitmask));
|
||||||
file.write((uint8_t *)&_prefs.ch_fav_only, sizeof(_prefs.ch_fav_only));
|
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));
|
||||||
file.write((uint8_t *)&_prefs.units_imperial, sizeof(_prefs.units_imperial));
|
file.write((uint8_t *)&_prefs.units_imperial, sizeof(_prefs.units_imperial));
|
||||||
file.write((uint8_t *)&_prefs.trail_show_pace, sizeof(_prefs.trail_show_pace));
|
file.write((uint8_t *)&_prefs.trail_show_pace, sizeof(_prefs.trail_show_pace));
|
||||||
|
|
||||||
|
|||||||
@@ -360,6 +360,8 @@ void MyMesh::onContactsFull() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MyMesh::onDiscoveredContact(ContactInfo &contact, bool is_new, uint8_t path_len, const uint8_t* path) {
|
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 (_serial->isConnected()) {
|
||||||
if (is_new) {
|
if (is_new) {
|
||||||
writeContactRespFrame(PUSH_CODE_NEW_ADVERT, contact);
|
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);
|
memcpy(&out_frame[1], contact.id.pub_key, PUB_KEY_SIZE);
|
||||||
_serial->writeFrame(out_frame, 1 + 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
|
// 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);
|
memcpy(r.pub_key, pub_key, PUB_KEY_SIZE);
|
||||||
r.timestamp = getRTCClock()->getCurrentTime();
|
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
|
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_bpm_idx = 2; // 120 bpm default
|
||||||
_prefs.ringtone_len = 0; // no custom ringtone by default
|
_prefs.ringtone_len = 0; // no custom ringtone by default
|
||||||
_prefs.ringtone2_bpm_idx = 2; // 120 bpm 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.home_pages_mask = 0x01FF; // all pages visible
|
||||||
_prefs.bot_enabled = 0;
|
_prefs.bot_enabled = 0;
|
||||||
_prefs.bot_channel_enabled = 0;
|
_prefs.bot_channel_enabled = 0;
|
||||||
@@ -2498,7 +2497,7 @@ void MyMesh::loop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DISPLAY_CLASS
|
#ifdef DISPLAY_CLASS
|
||||||
if (_ui) _ui->setHasConnection(_serial->isBLEConnected());
|
if (_ui) _ui->setHasConnection(_serial->isConnected());
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -69,9 +69,10 @@ struct NodePrefs { // persisted to file
|
|||||||
uint8_t ringtone2_bpm_idx;
|
uint8_t ringtone2_bpm_idx;
|
||||||
uint8_t ringtone2_len;
|
uint8_t ringtone2_len;
|
||||||
uint8_t ringtone2_notes[32];
|
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_dm;
|
||||||
uint8_t notif_melody_ch;
|
uint8_t notif_melody_ch;
|
||||||
|
uint8_t notif_melody_ad;
|
||||||
// Per-channel melody override (2 bitmasks, 1 bit per channel)
|
// 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_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)
|
uint64_t ch_notif_melody_2; // bit i = use melody 2 (else melody 1, when set bit is set)
|
||||||
@@ -119,7 +120,7 @@ struct NodePrefs { // persisted to file
|
|||||||
// adding/removing/reordering fields in DataStore::savePrefs/loadPrefsInt so
|
// adding/removing/reordering fields in DataStore::savePrefs/loadPrefsInt so
|
||||||
// older saves are detected on load and skipped (zero-init defaults kept).
|
// 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.
|
// High 24 bits identify the file format; low byte is the schema revision.
|
||||||
static const uint32_t SCHEMA_SENTINEL = 0xC0DE0006;
|
static const uint32_t SCHEMA_SENTINEL = 0xC0DE0007;
|
||||||
|
|
||||||
// Bit-index for each home page. Used by page_order (entries store bit+1) and
|
// 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
|
// by home_pages_mask. Single source of truth — both HomeScreen::pageBit/bitToPage
|
||||||
@@ -187,4 +188,4 @@ struct NodePrefs { // persisted to file
|
|||||||
}
|
}
|
||||||
if (pos < size) buf[pos] = '\0';
|
if (pos < size) buf[pos] = '\0';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ class SettingsScreen : public UIScreen {
|
|||||||
BUZZER_VOLUME,
|
BUZZER_VOLUME,
|
||||||
DM_MELODY,
|
DM_MELODY,
|
||||||
CH_MELODY,
|
CH_MELODY,
|
||||||
|
AD_SOUND,
|
||||||
// Home pages section
|
// Home pages section
|
||||||
SECTION_HOME_PAGES,
|
SECTION_HOME_PAGES,
|
||||||
HOME_CLOCK, HOME_FAVOURITES, HOME_RECENT, HOME_RADIO, HOME_BT, HOME_ADVERT,
|
HOME_CLOCK, HOME_FAVOURITES, HOME_RECENT, HOME_RADIO, HOME_BT, HOME_ADVERT,
|
||||||
@@ -446,6 +447,12 @@ class SettingsScreen : public UIScreen {
|
|||||||
{ static const char* L[] = { "built-in", "M1", "M2" };
|
{ static const char* L[] = { "built-in", "M1", "M2" };
|
||||||
uint8_t v = p ? p->notif_melody_ch : 0;
|
uint8_t v = p ? p->notif_melody_ch : 0;
|
||||||
display.print(L[v < 3 ? v : 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)) {
|
} else if (isHomePage(item)) {
|
||||||
if (p) ensurePageOrderInit(p);
|
if (p) ensurePageOrderInit(p);
|
||||||
int pos = homePagePosition(item, p);
|
int pos = homePagePosition(item, p);
|
||||||
@@ -696,6 +703,10 @@ public:
|
|||||||
p->notif_melody_ch = (p->notif_melody_ch + (left ? 2 : 1)) % 3;
|
p->notif_melody_ch = (p->notif_melody_ch + (left ? 2 : 1)) % 3;
|
||||||
_dirty = true; return true;
|
_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 (isHomePage(_selected) && p) {
|
||||||
if (left || right) {
|
if (left || right) {
|
||||||
movePageInOrder(_selected, left ? -1 : 1, p);
|
movePageInOrder(_selected, left ? -1 : 1, p);
|
||||||
|
|||||||
@@ -1448,11 +1448,28 @@ switch(t){
|
|||||||
_last_notif_ch_idx = -1;
|
_last_notif_ch_idx = -1;
|
||||||
break;
|
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:
|
case UIEventType::ack:
|
||||||
buzzer.play("ack:d=32,o=8,b=120:c");
|
buzzer.play("ack:d=32,o=8,b=120:c");
|
||||||
break;
|
break;
|
||||||
case UIEventType::roomMessage:
|
case UIEventType::roomMessage:
|
||||||
case UIEventType::newContactMessage:
|
|
||||||
case UIEventType::none:
|
case UIEventType::none:
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ switch(t){
|
|||||||
buzzer.play("ack:d=32,o=8,b=120:c");
|
buzzer.play("ack:d=32,o=8,b=120:c");
|
||||||
break;
|
break;
|
||||||
case UIEventType::roomMessage:
|
case UIEventType::roomMessage:
|
||||||
case UIEventType::newContactMessage:
|
case UIEventType::advertReceived:
|
||||||
case UIEventType::none:
|
case UIEventType::none:
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -443,4 +443,4 @@ void UITask::handleButtonLongPress() {
|
|||||||
} else {
|
} else {
|
||||||
shutdown();
|
shutdown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user