From 2da50882c006930678b93cfee6025225ef2971da Mon Sep 17 00:00:00 2001 From: csrutil Date: Sun, 7 Sep 2025 15:16:15 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat:=20add=20vibration=20feedback?= =?UTF-8?q?=20support=20for=20UI=20events?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add genericVibration class with 5-second cooldown and 1-second pulse - Integrate vibration triggers for new messages and contact discoveries - Add conditional compilation support with PIN_VIBRATION guard - Implement abstract interface for vibration in UITask system --- examples/companion_radio/AbstractUITask.h | 3 ++ examples/companion_radio/MyMesh.cpp | 5 +++ examples/companion_radio/ui-new/UITask.cpp | 18 +++++++++ examples/companion_radio/ui-new/UITask.h | 9 +++++ src/helpers/ui/vibration.cpp | 43 ++++++++++++++++++++++ src/helpers/ui/vibration.h | 34 +++++++++++++++++ 6 files changed, 112 insertions(+) create mode 100644 src/helpers/ui/vibration.cpp create mode 100644 src/helpers/ui/vibration.h diff --git a/examples/companion_radio/AbstractUITask.h b/examples/companion_radio/AbstractUITask.h index 1277bba9..fa0146a1 100644 --- a/examples/companion_radio/AbstractUITask.h +++ b/examples/companion_radio/AbstractUITask.h @@ -42,5 +42,8 @@ public: virtual void msgRead(int msgcount) = 0; virtual void newMsg(uint8_t path_len, const char* from_name, const char* text, int msgcount) = 0; virtual void soundBuzzer(UIEventType bet = UIEventType::none) = 0; +#ifdef PIN_VIBRATION + virtual void triggerVibration() = 0; +#endif virtual void loop() = 0; }; diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp index 04d5577e..ea54e051 100644 --- a/examples/companion_radio/MyMesh.cpp +++ b/examples/companion_radio/MyMesh.cpp @@ -244,6 +244,11 @@ void MyMesh::onDiscoveredContact(ContactInfo &contact, bool is_new, uint8_t path } else { #ifdef DISPLAY_CLASS if (_ui) _ui->soundBuzzer(UIEventType::newContactMessage); + if (_ui) { +#ifdef PIN_VIBRATION + if (is_new) _ui->triggerVibration(); +#endif + } #endif } diff --git a/examples/companion_radio/ui-new/UITask.cpp b/examples/companion_radio/ui-new/UITask.cpp index 1e03f086..0e906e41 100644 --- a/examples/companion_radio/ui-new/UITask.cpp +++ b/examples/companion_radio/ui-new/UITask.cpp @@ -483,6 +483,10 @@ void UITask::begin(DisplayDriver* display, SensorManager* sensors, NodePrefs* no buzzer.begin(); #endif +#ifdef PIN_VIBRATION + vibration.begin(); +#endif + ui_started_at = millis(); _alert_expiry = 0; @@ -519,6 +523,12 @@ switch(bet){ #endif } +#ifdef PIN_VIBRATION +void UITask::triggerVibration() { + vibration.trigger(); +} +#endif + void UITask::msgRead(int msgcount) { _msgcount = msgcount; if (msgcount == 0) { @@ -532,6 +542,10 @@ void UITask::newMsg(uint8_t path_len, const char* from_name, const char* text, i ((MsgPreviewScreen *) msg_preview)->addPreview(path_len, from_name, text); setCurrScreen(msg_preview); +#ifdef PIN_VIBRATION + triggerVibration(); +#endif + if (_display != NULL) { if (!_display->isOn()) _display->turnOn(); _auto_off = millis() + AUTO_OFF_MILLIS; // extend the auto-off timer @@ -687,6 +701,10 @@ void UITask::loop() { #endif } +#ifdef PIN_VIBRATION + vibration.loop(); +#endif + #ifdef AUTO_SHUTDOWN_MILLIVOLTS if (millis() > next_batt_chck) { uint16_t milliVolts = getBattMilliVolts(); diff --git a/examples/companion_radio/ui-new/UITask.h b/examples/companion_radio/ui-new/UITask.h index 769b2c64..7aaeabc7 100644 --- a/examples/companion_radio/ui-new/UITask.h +++ b/examples/companion_radio/ui-new/UITask.h @@ -11,6 +11,9 @@ #ifdef PIN_BUZZER #include #endif +#ifdef PIN_VIBRATION + #include +#endif #include "../AbstractUITask.h" #include "../NodePrefs.h" @@ -20,6 +23,9 @@ class UITask : public AbstractUITask { SensorManager* _sensors; #ifdef PIN_BUZZER genericBuzzer buzzer; +#endif +#ifdef PIN_VIBRATION + genericVibration vibration; #endif unsigned long _next_refresh, _auto_off; NodePrefs* _node_prefs; @@ -72,6 +78,9 @@ public: void msgRead(int msgcount) override; void newMsg(uint8_t path_len, const char* from_name, const char* text, int msgcount) override; void soundBuzzer(UIEventType bet = UIEventType::none) override; +#ifdef PIN_VIBRATION + void triggerVibration() override; +#endif void loop() override; void shutdown(bool restart = false); diff --git a/src/helpers/ui/vibration.cpp b/src/helpers/ui/vibration.cpp new file mode 100644 index 00000000..37db54ed --- /dev/null +++ b/src/helpers/ui/vibration.cpp @@ -0,0 +1,43 @@ +#ifdef PIN_VIBRATION +#include "vibration.h" + +void genericVibration::begin() +{ + pinMode(PIN_VIBRATION, OUTPUT); + digitalWrite(PIN_VIBRATION, LOW); + duration = 0; +} + +void genericVibration::trigger() +{ + duration = millis(); + digitalWrite(PIN_VIBRATION, HIGH); +} + +void genericVibration::loop() +{ + if (isVibrating()) { + if ((millis() / 1000) % 2 == 0) { + digitalWrite(PIN_VIBRATION, LOW); + } else { + digitalWrite(PIN_VIBRATION, HIGH); + } + + if (millis() - duration > VIBRATION_TIMEOUT) { + stop(); + } + } +} + +bool genericVibration::isVibrating() +{ + return duration > 0; +} + +void genericVibration::stop() +{ + duration = 0; + digitalWrite(PIN_VIBRATION, LOW); +} + +#endif // ifdef PIN_VIBRATION diff --git a/src/helpers/ui/vibration.h b/src/helpers/ui/vibration.h new file mode 100644 index 00000000..42cd0f67 --- /dev/null +++ b/src/helpers/ui/vibration.h @@ -0,0 +1,34 @@ +#pragma once + +#ifdef PIN_VIBRATION + +#include + +/* + * Vibration motor control class + * + * Provides vibration feedback for events like new messages and new contacts + * Features: + * - 1-second vibration pulse + * - 5-second nag timeout (cooldown between vibrations) + * - Non-blocking operation + */ + +#ifndef VIBRATION_TIMEOUT +#define VIBRATION_TIMEOUT 5000 // 5 seconds default +#endif + +class genericVibration +{ + public: + void begin(); // set up vibration pin + void trigger(); // trigger vibration if cooldown has passed + void loop(); // non-blocking timer handling + bool isVibrating(); // returns true if currently vibrating + void stop(); // stop vibration immediately + + private: + unsigned long duration; +}; + +#endif // ifdef PIN_VIBRATION