diff --git a/examples/companion_radio/DataStore.cpp b/examples/companion_radio/DataStore.cpp index 464516ed..46db233a 100644 --- a/examples/companion_radio/DataStore.cpp +++ b/examples/companion_radio/DataStore.cpp @@ -244,6 +244,9 @@ void DataStore::loadPrefsInt(const char *filename, NodePrefs& _prefs, double& no file.read((uint8_t *)&_prefs.ch_notif_muted, sizeof(_prefs.ch_notif_muted)); // 1552 file.read((uint8_t *)&_prefs.dm_show_all, sizeof(_prefs.dm_show_all)); // 1560 file.read((uint8_t *)&_prefs.room_fav_only, sizeof(_prefs.room_fav_only)); // 1561 + if (file.available()) { + file.read((uint8_t *)&_prefs.buzzer_volume, sizeof(_prefs.buzzer_volume)); // 1562 + } } file.close(); @@ -295,6 +298,7 @@ void DataStore::savePrefs(const NodePrefs& _prefs, double node_lat, double node_ file.write((uint8_t *)&_prefs.ch_notif_muted, sizeof(_prefs.ch_notif_muted)); // 1552 file.write((uint8_t *)&_prefs.dm_show_all, sizeof(_prefs.dm_show_all)); // 1560 file.write((uint8_t *)&_prefs.room_fav_only, sizeof(_prefs.room_fav_only)); // 1561 + file.write((uint8_t *)&_prefs.buzzer_volume, sizeof(_prefs.buzzer_volume)); // 1562 file.close(); } diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp index 2344a18d..62515031 100644 --- a/examples/companion_radio/MyMesh.cpp +++ b/examples/companion_radio/MyMesh.cpp @@ -864,6 +864,7 @@ MyMesh::MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMe _prefs.gps_enabled = 0; // GPS disabled by default _prefs.gps_interval = 0; // No automatic GPS updates by default _prefs.display_brightness = 2; // medium brightness by default + _prefs.buzzer_volume = 4; // max volume by default _prefs.auto_off_secs = 15; // 15 seconds auto-off by default _prefs.tz_offset_hours = 0; // UTC by default _prefs.low_batt_mv = 3400; // auto-shutdown at 3.4V by default diff --git a/examples/companion_radio/NodePrefs.h b/examples/companion_radio/NodePrefs.h index 667eb36d..76ea7ece 100644 --- a/examples/companion_radio/NodePrefs.h +++ b/examples/companion_radio/NodePrefs.h @@ -25,6 +25,7 @@ struct NodePrefs { // persisted to file uint32_t ble_pin; uint8_t advert_loc_policy; uint8_t buzzer_quiet; + uint8_t buzzer_volume; // 0=min..4=max, default 4 uint8_t gps_enabled; // GPS enabled flag (0=disabled, 1=enabled) uint32_t gps_interval; // GPS read interval in seconds uint8_t autoadd_config; // bitmask for auto-add contacts config diff --git a/examples/companion_radio/ui-new/UITask.cpp b/examples/companion_radio/ui-new/UITask.cpp index c4d9df9c..cbbfc6d1 100644 --- a/examples/companion_radio/ui-new/UITask.cpp +++ b/examples/companion_radio/ui-new/UITask.cpp @@ -116,6 +116,7 @@ class SettingsScreen : public UIScreen { // Sound section SECTION_SOUND, BUZZER, + BUZZER_VOLUME, // Radio section SECTION_RADIO, TX_POWER, @@ -273,6 +274,14 @@ class SettingsScreen : public UIScreen { display.print(_task->isBuzzerQuiet() ? "OFF" : "ON"); #else display.print("N/A"); +#endif + } else if (item == BUZZER_VOLUME) { + display.print("BzrVol"); +#ifdef PIN_BUZZER + renderBar(display, VAL_X, y, _task->getBuzzerVolume() + 1, 5); +#else + display.setCursor(VAL_X, y); + display.print("N/A"); #endif } else if (item == TX_POWER) { display.print("TX Pwr"); @@ -577,6 +586,14 @@ public: _task->toggleBuzzer(); // saves immediately internally return true; } + if (_selected == BUZZER_VOLUME) { +#ifdef PIN_BUZZER + uint8_t lvl = _task->getBuzzerVolume(); + if (right && lvl < 4) { _task->setBuzzerVolumeLevel(lvl + 1); _dirty = true; return true; } + if (left && lvl > 0) { _task->setBuzzerVolumeLevel(lvl - 1); _dirty = true; return true; } +#endif + return right || left; + } if (_selected == TX_POWER && p) { if (right && p->tx_power_dbm < 22) { p->tx_power_dbm++; _task->applyTxPower(); _dirty = true; return true; } if (left && p->tx_power_dbm > 2) { p->tx_power_dbm--; _task->applyTxPower(); _dirty = true; return true; } @@ -2157,6 +2174,7 @@ void UITask::begin(DisplayDriver* display, SensorManager* sensors, NodePrefs* no #ifdef PIN_BUZZER buzzer.quiet(_node_prefs->buzzer_quiet); + buzzer.setVolume(_node_prefs->buzzer_volume); buzzer.begin(); #endif @@ -2589,6 +2607,16 @@ void UITask::setBrightnessLevel(uint8_t level) { _next_refresh = 0; } +void UITask::setBuzzerVolumeLevel(uint8_t level) { +#ifdef PIN_BUZZER + if (_node_prefs == NULL) return; + if (level > 4) level = 4; + _node_prefs->buzzer_volume = level; + buzzer.setVolume(level); + _next_refresh = 0; +#endif +} + void UITask::toggleBuzzer() { // Toggle buzzer quiet mode #ifdef PIN_BUZZER diff --git a/examples/companion_radio/ui-new/UITask.h b/examples/companion_radio/ui-new/UITask.h index 35cecf3a..bfc2e6e1 100644 --- a/examples/companion_radio/ui-new/UITask.h +++ b/examples/companion_radio/ui-new/UITask.h @@ -107,6 +107,8 @@ public: void applyBrightness(); void setBrightnessLevel(uint8_t level); uint8_t getBrightnessLevel() const { return _node_prefs ? _node_prefs->display_brightness : 2; } + void setBuzzerVolumeLevel(uint8_t level); + uint8_t getBuzzerVolume() const { return _node_prefs ? _node_prefs->buzzer_volume : 4; } void applyTxPower(); void applyGPSInterval(); uint32_t autoOffMillis() const { diff --git a/src/helpers/ui/buzzer.cpp b/src/helpers/ui/buzzer.cpp index 983e5c93..9ef3fd0d 100644 --- a/src/helpers/ui/buzzer.cpp +++ b/src/helpers/ui/buzzer.cpp @@ -31,8 +31,24 @@ bool genericBuzzer::isPlaying() { return rtttl::isPlaying(); } +void genericBuzzer::applyVolume() { + // After tone() sets 50% duty, analogWrite overrides duty cycle on the same PWM channel. + // Level 4 = 50% (leave tone as-is), lower levels reduce duty = quieter output. + static const uint8_t duty[] = { 6, 20, 50, 90, 128 }; + uint8_t d = duty[_volume_level < 5 ? _volume_level : 4]; + if (d < 128) analogWrite(PIN_BUZZER, d); +} + +void genericBuzzer::setVolume(uint8_t level) { + _volume_level = level < 5 ? level : 4; + if (isPlaying()) applyVolume(); +} + void genericBuzzer::loop() { - if (!rtttl::done()) rtttl::play(); + if (!rtttl::done()) { + rtttl::play(); + if (_volume_level < 4) applyVolume(); + } } void genericBuzzer::startup() { diff --git a/src/helpers/ui/buzzer.h b/src/helpers/ui/buzzer.h index ae040814..a67e42fb 100644 --- a/src/helpers/ui/buzzer.h +++ b/src/helpers/ui/buzzer.h @@ -28,8 +28,12 @@ class genericBuzzer bool isPlaying(); // returns true if a sound is still playing else false void quiet(bool buzzer_state); // enables or disables the buzzer bool isQuiet(); // get buzzer state on/off + void setVolume(uint8_t level); // 0=min..4=max + uint8_t getVolume() const { return _volume_level; } private: + uint8_t _volume_level = 4; + void applyVolume(); // gemini's picks: const char *startup_song = "Startup:d=4,o=5,b=160:16c6,16e6,8g6"; const char *shutdown_song = "Shutdown:d=4,o=5,b=100:8g5,16e5,16c5";