feat: add vibration feedback support for UI events

- 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
This commit is contained in:
csrutil
2025-09-07 15:16:15 +08:00
parent d86851b881
commit 2da50882c0
6 changed files with 112 additions and 0 deletions

View File

@@ -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;
};

View File

@@ -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
}

View File

@@ -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();

View File

@@ -11,6 +11,9 @@
#ifdef PIN_BUZZER
#include <helpers/ui/buzzer.h>
#endif
#ifdef PIN_VIBRATION
#include <helpers/ui/vibration.h>
#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);

View File

@@ -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

View File

@@ -0,0 +1,34 @@
#pragma once
#ifdef PIN_VIBRATION
#include <Arduino.h>
/*
* 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