Skip to content

Commit b3e9fd7

Browse files
authored
Merge pull request #708 from csrutil/feature/vibration-feedback
✨ feat: add vibration feedback system
2 parents f77fd15 + 6f8ce42 commit b3e9fd7

File tree

8 files changed

+119
-22
lines changed

8 files changed

+119
-22
lines changed

examples/companion_radio/AbstractUITask.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,6 @@ class AbstractUITask {
4141
void disableSerial() { _serial->disable(); }
4242
virtual void msgRead(int msgcount) = 0;
4343
virtual void newMsg(uint8_t path_len, const char* from_name, const char* text, int msgcount) = 0;
44-
virtual void soundBuzzer(UIEventType bet = UIEventType::none) = 0;
44+
virtual void notify(UIEventType t = UIEventType::none) = 0;
4545
virtual void loop() = 0;
4646
};

examples/companion_radio/MyMesh.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ void MyMesh::onDiscoveredContact(ContactInfo &contact, bool is_new, uint8_t path
243243
}
244244
} else {
245245
#ifdef DISPLAY_CLASS
246-
if (_ui) _ui->soundBuzzer(UIEventType::newContactMessage);
246+
if (_ui) _ui->notify(UIEventType::newContactMessage);
247247
#endif
248248
}
249249

@@ -353,7 +353,7 @@ void MyMesh::queueMessage(const ContactInfo &from, uint8_t txt_type, mesh::Packe
353353
if (should_display && _ui) {
354354
_ui->newMsg(path_len, from.name, text, offline_queue_len);
355355
if (!_serial->isConnected()) {
356-
_ui->soundBuzzer(UIEventType::contactMessage);
356+
_ui->notify(UIEventType::contactMessage);
357357
}
358358
}
359359
#endif
@@ -412,7 +412,7 @@ void MyMesh::onChannelMessageRecv(const mesh::GroupChannel &channel, mesh::Packe
412412
_serial->writeFrame(frame, 1);
413413
} else {
414414
#ifdef DISPLAY_CLASS
415-
if (_ui) _ui->soundBuzzer(UIEventType::channelMessage);
415+
if (_ui) _ui->notify(UIEventType::channelMessage);
416416
#endif
417417
}
418418
#ifdef DISPLAY_CLASS

examples/companion_radio/ui-new/UITask.cpp

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -356,9 +356,7 @@ class HomeScreen : public UIScreen {
356356
return true;
357357
}
358358
if (c == KEY_ENTER && _page == HomePage::ADVERT) {
359-
#ifdef PIN_BUZZER
360-
_task->soundBuzzer(UIEventType::ack);
361-
#endif
359+
_task->notify(UIEventType::ack);
362360
if (the_mesh.advert()) {
363361
_task->showAlert("Advert sent!", 1000);
364362
} else {
@@ -495,6 +493,10 @@ void UITask::begin(DisplayDriver* display, SensorManager* sensors, NodePrefs* no
495493
buzzer.begin();
496494
#endif
497495

496+
#ifdef PIN_VIBRATION
497+
vibration.begin();
498+
#endif
499+
498500
ui_started_at = millis();
499501
_alert_expiry = 0;
500502

@@ -509,9 +511,9 @@ void UITask::showAlert(const char* text, int duration_millis) {
509511
_alert_expiry = millis() + duration_millis;
510512
}
511513

512-
void UITask::soundBuzzer(UIEventType bet) {
514+
void UITask::notify(UIEventType t) {
513515
#if defined(PIN_BUZZER)
514-
switch(bet){
516+
switch(t){
515517
case UIEventType::contactMessage:
516518
// gemini's pick
517519
buzzer.play("MsgRcv3:d=4,o=6,b=200:32e,32g,32b,16c7");
@@ -529,8 +531,16 @@ switch(bet){
529531
break;
530532
}
531533
#endif
534+
535+
#ifdef PIN_VIBRATION
536+
// Trigger vibration for all UI events except none
537+
if (t != UIEventType::none) {
538+
vibration.trigger();
539+
}
540+
#endif
532541
}
533542

543+
534544
void UITask::msgRead(int msgcount) {
535545
_msgcount = msgcount;
536546
if (msgcount == 0) {
@@ -699,6 +709,10 @@ void UITask::loop() {
699709
#endif
700710
}
701711

712+
#ifdef PIN_VIBRATION
713+
vibration.loop();
714+
#endif
715+
702716
#ifdef AUTO_SHUTDOWN_MILLIVOLTS
703717
if (millis() > next_batt_chck) {
704718
uint16_t milliVolts = getBattMilliVolts();
@@ -767,11 +781,11 @@ void UITask::toggleGPS() {
767781
if (strcmp(_sensors->getSettingName(i), "gps") == 0) {
768782
if (strcmp(_sensors->getSettingValue(i), "1") == 0) {
769783
_sensors->setSettingValue("gps", "0");
770-
soundBuzzer(UIEventType::ack);
784+
notify(UIEventType::ack);
771785
showAlert("GPS: Disabled", 800);
772786
} else {
773787
_sensors->setSettingValue("gps", "1");
774-
soundBuzzer(UIEventType::ack);
788+
notify(UIEventType::ack);
775789
showAlert("GPS: Enabled", 800);
776790
}
777791
_next_refresh = 0;
@@ -786,7 +800,7 @@ void UITask::toggleBuzzer() {
786800
#ifdef PIN_BUZZER
787801
if (buzzer.isQuiet()) {
788802
buzzer.quiet(false);
789-
soundBuzzer(UIEventType::ack);
803+
notify(UIEventType::ack);
790804
showAlert("Buzzer: ON", 800);
791805
} else {
792806
buzzer.quiet(true);

examples/companion_radio/ui-new/UITask.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
#ifdef PIN_BUZZER
1212
#include <helpers/ui/buzzer.h>
1313
#endif
14+
#ifdef PIN_VIBRATION
15+
#include <helpers/ui/vibration.h>
16+
#endif
1417

1518
#include "../AbstractUITask.h"
1619
#include "../NodePrefs.h"
@@ -20,6 +23,9 @@ class UITask : public AbstractUITask {
2023
SensorManager* _sensors;
2124
#ifdef PIN_BUZZER
2225
genericBuzzer buzzer;
26+
#endif
27+
#ifdef PIN_VIBRATION
28+
genericVibration vibration;
2329
#endif
2430
unsigned long _next_refresh, _auto_off;
2531
NodePrefs* _node_prefs;
@@ -71,7 +77,7 @@ class UITask : public AbstractUITask {
7177
// from AbstractUITask
7278
void msgRead(int msgcount) override;
7379
void newMsg(uint8_t path_len, const char* from_name, const char* text, int msgcount) override;
74-
void soundBuzzer(UIEventType bet = UIEventType::none) override;
80+
void notify(UIEventType t = UIEventType::none) override;
7581
void loop() override;
7682

7783
void shutdown(bool restart = false);

examples/companion_radio/ui-orig/UITask.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,9 @@ void UITask::begin(DisplayDriver* display, SensorManager* sensors, NodePrefs* no
8888
ui_started_at = millis();
8989
}
9090

91-
void UITask::soundBuzzer(UIEventType bet) {
91+
void UITask::notify(UIEventType t) {
9292
#if defined(PIN_BUZZER)
93-
switch(bet){
93+
switch(t){
9494
case UIEventType::contactMessage:
9595
// gemini's pick
9696
buzzer.play("MsgRcv3:d=4,o=6,b=200:32e,32g,32b,16c7");
@@ -108,8 +108,8 @@ switch(bet){
108108
break;
109109
}
110110
#endif
111-
// Serial.print("DBG: Buzzzzzz -> ");
112-
// Serial.println((int) bet);
111+
// Serial.print("DBG: Alert user -> ");
112+
// Serial.println((int) t);
113113
}
114114

115115
void UITask::msgRead(int msgcount) {
@@ -370,7 +370,7 @@ void UITask::handleButtonDoublePress() {
370370
MESH_DEBUG_PRINTLN("UITask: double press triggered, sending advert");
371371
// ADVERT
372372
#ifdef PIN_BUZZER
373-
soundBuzzer(UIEventType::ack);
373+
notify(UIEventType::ack);
374374
#endif
375375
if (the_mesh.advert()) {
376376
MESH_DEBUG_PRINTLN("Advert sent!");
@@ -388,7 +388,7 @@ void UITask::handleButtonTriplePress() {
388388
#ifdef PIN_BUZZER
389389
if (buzzer.isQuiet()) {
390390
buzzer.quiet(false);
391-
soundBuzzer(UIEventType::ack);
391+
notify(UIEventType::ack);
392392
sprintf(_alert, "Buzzer: ON");
393393
} else {
394394
buzzer.quiet(true);
@@ -407,11 +407,11 @@ void UITask::handleButtonQuadruplePress() {
407407
if (strcmp(_sensors->getSettingName(i), "gps") == 0) {
408408
if (strcmp(_sensors->getSettingValue(i), "1") == 0) {
409409
_sensors->setSettingValue("gps", "0");
410-
soundBuzzer(UIEventType::ack);
410+
notify(UIEventType::ack);
411411
sprintf(_alert, "GPS: Disabled");
412412
} else {
413413
_sensors->setSettingValue("gps", "1");
414-
soundBuzzer(UIEventType::ack);
414+
notify(UIEventType::ack);
415415
sprintf(_alert, "GPS: Enabled");
416416
}
417417
break;

examples/companion_radio/ui-orig/UITask.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ class UITask : public AbstractUITask {
6666
// from AbstractUITask
6767
void msgRead(int msgcount) override;
6868
void newMsg(uint8_t path_len, const char* from_name, const char* text, int msgcount) override;
69-
void soundBuzzer(UIEventType bet = UIEventType::none) override;
69+
void notify(UIEventType t = UIEventType::none) override;
7070
void loop() override;
7171

7272
void shutdown(bool restart = false);

src/helpers/ui/vibration.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#ifdef PIN_VIBRATION
2+
#include "vibration.h"
3+
4+
void genericVibration::begin()
5+
{
6+
pinMode(PIN_VIBRATION, OUTPUT);
7+
digitalWrite(PIN_VIBRATION, LOW);
8+
duration = 0;
9+
}
10+
11+
void genericVibration::trigger()
12+
{
13+
duration = millis();
14+
digitalWrite(PIN_VIBRATION, HIGH);
15+
}
16+
17+
void genericVibration::loop()
18+
{
19+
if (isVibrating()) {
20+
if ((millis() / 1000) % 2 == 0) {
21+
digitalWrite(PIN_VIBRATION, LOW);
22+
} else {
23+
digitalWrite(PIN_VIBRATION, HIGH);
24+
}
25+
26+
if (millis() - duration > VIBRATION_TIMEOUT) {
27+
stop();
28+
}
29+
}
30+
}
31+
32+
bool genericVibration::isVibrating()
33+
{
34+
return duration > 0;
35+
}
36+
37+
void genericVibration::stop()
38+
{
39+
duration = 0;
40+
digitalWrite(PIN_VIBRATION, LOW);
41+
}
42+
43+
#endif // ifdef PIN_VIBRATION

src/helpers/ui/vibration.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#pragma once
2+
3+
#ifdef PIN_VIBRATION
4+
5+
#include <Arduino.h>
6+
7+
/*
8+
* Vibration motor control class
9+
*
10+
* Provides vibration feedback for events like new messages and new contacts
11+
* Features:
12+
* - 1-second vibration pulse
13+
* - 5-second nag timeout (cooldown between vibrations)
14+
* - Non-blocking operation
15+
*/
16+
17+
#ifndef VIBRATION_TIMEOUT
18+
#define VIBRATION_TIMEOUT 5000 // 5 seconds default
19+
#endif
20+
21+
class genericVibration
22+
{
23+
public:
24+
void begin(); // set up vibration pin
25+
void trigger(); // trigger vibration if cooldown has passed
26+
void loop(); // non-blocking timer handling
27+
bool isVibrating(); // returns true if currently vibrating
28+
void stop(); // stop vibration immediately
29+
30+
private:
31+
unsigned long duration;
32+
};
33+
34+
#endif // ifdef PIN_VIBRATION

0 commit comments

Comments
 (0)