Skip to content

Commit

Permalink
feat: Timer Voice & Haptic option, show elapsed speak time value when…
Browse files Browse the repository at this point in the history
… countdown (EdgeTX#2711)

* fix "odd" elapsed time announcement

* announce elapsed seconds

* Add support for "Beeps and Haptic" and "Voice and Haptic" for timer countdown.
  • Loading branch information
eshifri authored and mha1 committed Jan 27, 2023
1 parent 369bfd2 commit db655bc
Show file tree
Hide file tree
Showing 45 changed files with 252 additions and 145 deletions.
17 changes: 16 additions & 1 deletion companion/src/firmwares/edgetx/yaml_modeldata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -274,17 +274,27 @@ namespace YAML
{
Node convert<TimerData>::encode(const TimerData& rhs)
{
unsigned int countdownBeep = rhs.countdownBeep;
unsigned int extraHaptic = rhs.extraHaptic;
if (countdownBeep > TimerData::COUNTDOWNBEEP_VOICE + 1) {
extraHaptic = 1;
countdownBeep -= TimerData::COUNTDOWNBEEP_VOICE + 1;
}
else {
extraHaptic = 0;
}
Node node;
node["swtch"] = rhs.swtch;
node["mode"] = timerModeLut << rhs.mode;
node["name"] = rhs.name;
node["minuteBeep"] = (int)rhs.minuteBeep;
node["countdownBeep"] = rhs.countdownBeep;
node["countdownBeep"] = countdownBeep;
node["start"] = rhs.val;
node["persistent"] = rhs.persistent;
node["countdownStart"] = rhs.countdownStart;
node["value"] = rhs.pvalue;
node["showElapsed"] = rhs.showElapsed;
node["extraHaptic"] = extraHaptic;
return node;
}

Expand All @@ -300,6 +310,11 @@ bool convert<TimerData>::decode(const Node& node, TimerData& rhs)
node["countdownStart"] >> rhs.countdownStart;
node["value"] >> rhs.pvalue;
node["showElapsed"] >> rhs.showElapsed;
node["extraHaptic"] >> rhs.extraHaptic;

if (rhs.extraHaptic)
rhs.countdownBeep += TimerData::COUNTDOWNBEEP_VOICE + 1;

return true;
}

Expand Down
4 changes: 4 additions & 0 deletions companion/src/firmwares/timerdata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,10 @@ QString TimerData::countdownBeepToString(const int value)
return tr("Voice");
case COUNTDOWNBEEP_HAPTIC:
return tr("Haptic");
case COUNTDOWNBEEP_BEEPS_AND_HAPTIC:
return tr("Beeps and Haptic");
case COUNTDOWNBEEP_VOICE_AND_HAPTIC:
return tr("Voice and Haptic");
default:
return CPN_STR_UNKNOWN_ITEM;
}
Expand Down
168 changes: 86 additions & 82 deletions companion/src/firmwares/timerdata.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,86 +40,90 @@ class TimerData {
Q_DECLARE_TR_FUNCTIONS(TimerData)

public:
enum CountDownBeepType {
COUNTDOWNBEEP_SILENT,
COUNTDOWNBEEP_BEEPS,
COUNTDOWNBEEP_VOICE,
COUNTDOWNBEEP_HAPTIC,
COUNTDOWNBEEP_COUNT
};

enum CountDownStart {
COUNTDOWNSTART_5 = -2,
COUNTDOWNSTART_FIRST = COUNTDOWNSTART_5,
COUNTDOWNSTART_10,
COUNTDOWNSTART_20,
COUNTDOWNSTART_30,
COUNTDOWNSTART_LAST = COUNTDOWNSTART_30
};

enum PersistentType {
PERSISTENT_NOT,
PERSISTENT_FLIGHT,
PERSISTENT_MANUALRESET,
PERSISTENT_COUNT
};

enum TimerMode {
TIMERMODE_OFF,
TIMERMODE_ON,
TIMERMODE_START,
TIMERMODE_THR,
TIMERMODE_THR_REL,
TIMERMODE_THR_START,
TIMERMODE_COUNT,
TIMERMODE_MAX = TIMERMODE_COUNT - 1
};

enum TimerShowDirection {
TIMER_SHOW_REMAINING,
TIMER_SHOW_ELAPSED,
TIMER_SHOW_COUNT
};

TimerData() { clear(); }

RawSwitch swtch;
unsigned int mode;
char name[TIMER_NAME_LEN + 1];
bool minuteBeep;
unsigned int countdownBeep;
unsigned int val;
unsigned int persistent;
int countdownStart;
int pvalue;
unsigned int showElapsed;

void convert(RadioDataConversionState & cstate);
void clear();
bool isEmpty() const;
bool isModeOff();
QString nameToString(int index) const;
QString countdownBeepToString() const;
QString countdownStartToString() const;
QString persistentToString(const bool verbose = true) const;
QString pvalueToString() const;
QString valToString() const;
QString modeToString() const;
QString showElapsedToString() const;

void countdownBeepChanged();
void modeChanged();

static QString countdownBeepToString(const int value);
static QString countdownStartToString(const int value);
static QString persistentToString(const int value, const bool verbose = true);
static QString pvalueToString(const int value);
static QString valToString(const int value);
static QString modeToString(const int value);
static QString showElapsedToString(const unsigned int value);
static AbstractStaticItemModel * countdownBeepItemModel();
static AbstractStaticItemModel * countdownStartItemModel();
static AbstractStaticItemModel * persistentItemModel();
static AbstractStaticItemModel * modeItemModel();
static AbstractStaticItemModel * showElapsedItemModel();
enum CountDownBeepType {
COUNTDOWNBEEP_SILENT,
COUNTDOWNBEEP_BEEPS,
COUNTDOWNBEEP_VOICE,
COUNTDOWNBEEP_HAPTIC,
COUNTDOWNBEEP_BEEPS_AND_HAPTIC,
COUNTDOWNBEEP_VOICE_AND_HAPTIC,
COUNTDOWNBEEP_COUNT
};

enum CountDownStart {
COUNTDOWNSTART_5 = -2,
COUNTDOWNSTART_FIRST = COUNTDOWNSTART_5,
COUNTDOWNSTART_10,
COUNTDOWNSTART_20,
COUNTDOWNSTART_30,
COUNTDOWNSTART_LAST = COUNTDOWNSTART_30
};

enum PersistentType {
PERSISTENT_NOT,
PERSISTENT_FLIGHT,
PERSISTENT_MANUALRESET,
PERSISTENT_COUNT
};

enum TimerMode {
TIMERMODE_OFF,
TIMERMODE_ON,
TIMERMODE_START,
TIMERMODE_THR,
TIMERMODE_THR_REL,
TIMERMODE_THR_START,
TIMERMODE_COUNT,
TIMERMODE_MAX = TIMERMODE_COUNT - 1
};

enum TimerShowDirection {
TIMER_SHOW_REMAINING,
TIMER_SHOW_ELAPSED,
TIMER_SHOW_COUNT
};

TimerData() { clear(); }

RawSwitch swtch;
unsigned int mode;
char name[TIMER_NAME_LEN + 1];
bool minuteBeep;
unsigned int countdownBeep;
unsigned int val;
unsigned int persistent;
int countdownStart;
int pvalue;
unsigned int showElapsed;
unsigned int extraHaptic;

void convert(RadioDataConversionState& cstate);
void clear();
bool isEmpty() const;
bool isModeOff();
QString nameToString(int index) const;
QString countdownBeepToString() const;
QString countdownStartToString() const;
QString persistentToString(const bool verbose = true) const;
QString pvalueToString() const;
QString valToString() const;
QString modeToString() const;
QString showElapsedToString() const;

void countdownBeepChanged();
void modeChanged();

static QString countdownBeepToString(const int value);
static QString countdownStartToString(const int value);
static QString persistentToString(const int value,
const bool verbose = true);
static QString pvalueToString(const int value);
static QString valToString(const int value);
static QString modeToString(const int value);
static QString showElapsedToString(const unsigned int value);
static AbstractStaticItemModel* countdownBeepItemModel();
static AbstractStaticItemModel* countdownStartItemModel();
static AbstractStaticItemModel* persistentItemModel();
static AbstractStaticItemModel* modeItemModel();
static AbstractStaticItemModel* showElapsedItemModel();
};
34 changes: 19 additions & 15 deletions radio/src/audio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -996,32 +996,36 @@ void audioTrimPress(int value)
void audioTimerCountdown(uint8_t timer, int value)
{
if (g_model.timers[timer].countdownBeep == COUNTDOWN_VOICE) {
if (value >= 0 && value <= TIMER_COUNTDOWN_START(timer)) {
playNumber(value, 0, 0, 0);
int announceValue = value;
if (g_model.timers[timer].showElapsed) {
announceValue = g_model.timers[timer].start - value;
}
else if (value == 30 || value == 20) {
playDuration(value, 0, 0);
if (value >= 0 && value <= TIMER_COUNTDOWN_START(timer)) {
if (announceValue > 60 && !(announceValue % 2) && (announceValue % 30) &&
(announceValue % 30))
playNumber(announceValue / 60, 0, 0, 0);
if (announceValue < 60 ||
(announceValue > 60 && !(announceValue % 2) && (announceValue % 60)))
playNumber(announceValue % 60, 0, 0, 0);
} else if ((!(announceValue % 30) || !(announceValue % 20)) && value < 31) {
playDuration(announceValue, 0, 0);
}
}
else if (g_model.timers[timer].countdownBeep == COUNTDOWN_BEEPS) {
} else if (g_model.timers[timer].countdownBeep == COUNTDOWN_BEEPS) {
if (value == 0) {
audioQueue.playTone(BEEP_DEFAULT_FREQ + 150, 300, 20, PLAY_NOW);
}
else if (value > 0 && value <= TIMER_COUNTDOWN_START(timer)) {
} else if (value > 0 && value <= TIMER_COUNTDOWN_START(timer)) {
audioQueue.playTone(BEEP_DEFAULT_FREQ + 150, 100, 20, PLAY_NOW);
}
else if (value == 30) {
} else if (value == 30) {
audioQueue.playTone(BEEP_DEFAULT_FREQ + 150, 120, 20, PLAY_REPEAT(2));
}
else if (value == 20) {
} else if (value == 20) {
audioQueue.playTone(BEEP_DEFAULT_FREQ + 150, 120, 20, PLAY_REPEAT(1));
}
else if (value == 10) {
} else if (value == 10) {
audioQueue.playTone(BEEP_DEFAULT_FREQ + 150, 120, 20, PLAY_NOW);
}
}
#if defined(HAPTIC)
else if (g_model.timers[timer].countdownBeep == COUNTDOWN_HAPTIC) {
if ( (g_model.timers[timer].countdownBeep == COUNTDOWN_HAPTIC) ||
(g_model.timers[timer].extraHaptic) ) {
if (value == 0) {
haptic.play(15, 3, PLAY_NOW);
}
Expand Down
3 changes: 3 additions & 0 deletions radio/src/dataconstants.h
Original file line number Diff line number Diff line change
Expand Up @@ -866,8 +866,11 @@ enum CountDownModes {
COUNTDOWN_SILENT,
COUNTDOWN_BEEPS,
COUNTDOWN_VOICE,
COUNTDOWN_NON_HAPTIC_LAST = COUNTDOWN_VOICE,
#if defined(HAPTIC)
COUNTDOWN_HAPTIC,
COUNTDOWN_BEEPS_AND_HAPTIC,
COUNTDOWN_VOICE_AND_HPTIC,
#endif
COUNTDOWN_COUNT SKIP
};
Expand Down
3 changes: 2 additions & 1 deletion radio/src/datastructs_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,8 @@ PACK(struct TimerData {
uint32_t persistent:2;
int32_t countdownStart:2;
uint8_t showElapsed:1;
uint8_t spare:7 SKIP;
uint8_t extraHaptic:1;
uint8_t spare:6 SKIP;
NOBACKUP(char name[LEN_TIMER_NAME]);
});

Expand Down
21 changes: 17 additions & 4 deletions radio/src/gui/128x64/model_setup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -341,16 +341,29 @@ void editTimerCountdown(int timerIdx, coord_t y, LcdFlags attr, event_t event)
{
TimerData & timer = g_model.timers[timerIdx];
lcdDrawTextAlignedLeft(y, STR_BEEPCOUNTDOWN);
lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_VBEEPCOUNTDOWN, timer.countdownBeep, (menuHorizontalPosition == 0 ? attr : 0));
int value = timer.countdownBeep;
if (timer.extraHaptic) value += (COUNTDOWN_VOICE + 1);
lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_VBEEPCOUNTDOWN, value, (menuHorizontalPosition == 0 ? attr : 0));
if (timer.countdownBeep != COUNTDOWN_SILENT) {
lcdDrawNumber(MODEL_SETUP_2ND_COLUMN + 6 * FW, y, TIMER_COUNTDOWN_START(timerIdx), (menuHorizontalPosition == 1 ? attr : 0) | LEFT);
lcdDrawChar(lcdLastRightPos, y, 's');
}
if (attr && s_editMode > 0) {
switch (menuHorizontalPosition) {
case 0:
CHECK_INCDEC_MODELVAR(event, timer.countdownBeep, COUNTDOWN_SILENT, COUNTDOWN_COUNT - 1);
break;
case 0:
{
value = timer.countdownBeep;
if (timer.extraHaptic) value += (COUNTDOWN_NON_HAPTIC_LAST + 1);
CHECK_INCDEC_MODELVAR(event, value, COUNTDOWN_SILENT,
COUNTDOWN_COUNT - 1);
if (value > COUNTDOWN_VOICE + 1) {
timer.extraHaptic = 1;
timer.countdownBeep = value - (COUNTDOWN_NON_HAPTIC_LAST + 1);
} else {
timer.extraHaptic = 0;
timer.countdownBeep = value;
}
} break;
case 1:
timer.countdownStart = -checkIncDecModel(event, -timer.countdownStart, -1, +2);
break;
Expand Down
21 changes: 18 additions & 3 deletions radio/src/gui/212x64/model_setup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -262,16 +262,31 @@ void editTimerCountdown(int timerIdx, coord_t y, LcdFlags attr, event_t event)
{
TimerData & timer = g_model.timers[timerIdx];
lcdDrawTextAlignedLeft(y, STR_BEEPCOUNTDOWN);
lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_VBEEPCOUNTDOWN, timer.countdownBeep, (menuHorizontalPosition==0 ? attr : 0));
int value = timer.countdownBeep;
if (timer.extraHaptic) value += (COUNTDOWN_NON_HAPTIC_LAST + 1);
lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_VBEEPCOUNTDOWN, value,
(menuHorizontalPosition == 0 ? attr : 0));
if (timer.countdownBeep != COUNTDOWN_SILENT) {
lcdDrawNumber(MODEL_SETUP_3RD_COLUMN, y, TIMER_COUNTDOWN_START(timerIdx), (menuHorizontalPosition == 1 ? attr : 0) | LEFT);
lcdDrawChar(lcdLastRightPos, y, 's');
}
if (attr && s_editMode>0) {
switch (menuHorizontalPosition) {
case 0:
CHECK_INCDEC_MODELVAR(event, timer.countdownBeep, COUNTDOWN_SILENT, COUNTDOWN_COUNT - 1);
break;
{
value = timer.countdownBeep;
if (timer.extraHaptic) value += (COUNTDOWN_NON_HAPTIC_LAST + 1);
TRACE("value=%d\ttimer.extraHaptic=%d", value, timer.extraHaptic);
CHECK_INCDEC_MODELVAR(event, value, COUNTDOWN_SILENT, COUNTDOWN_COUNT - 1);
if (value > COUNTDOWN_VOICE + 1) {
timer.extraHaptic = 1;
timer.countdownBeep = value - (COUNTDOWN_NON_HAPTIC_LAST + 1);
} else {
timer.extraHaptic = 0;
timer.countdownBeep = value;
}
}
break;
case 1:
timer.countdownStart = -checkIncDecModel(event, -timer.countdownStart, -1, +2);
break;
Expand Down
24 changes: 22 additions & 2 deletions radio/src/gui/colorlcd/timer_setup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,28 @@ TimerWindow::TimerWindow(uint8_t timer) : Page(ICON_STATS_TIMERS)
box->setFlexLayout(LV_FLEX_FLOW_ROW);
lv_obj_set_width(box->getLvObj(), LV_SIZE_CONTENT);

new Choice(box, rect_t{}, STR_VBEEPCOUNTDOWN, COUNTDOWN_SILENT,
COUNTDOWN_COUNT - 1, GET_SET_DEFAULT(p_timer->countdownBeep));
new Choice(
box, rect_t{}, STR_VBEEPCOUNTDOWN, COUNTDOWN_SILENT, COUNTDOWN_COUNT - 1,
[=]() -> int {
int value = p_timer->countdownBeep;
if (p_timer->extraHaptic) {
value += (COUNTDOWN_NON_HAPTIC_LAST + 1);
}
return (value);
},
[=](int value) {
if (value > COUNTDOWN_NON_HAPTIC_LAST + 1) {
p_timer->extraHaptic = 1;
p_timer->countdownBeep = value - (COUNTDOWN_NON_HAPTIC_LAST + 1);
} else {
p_timer->extraHaptic = 0;
p_timer->countdownBeep = value;
}
SET_DIRTY();
TRACE("value=%d\tcountdownBeep = %d\textraHaptic = %d", value,
p_timer->countdownBeep, p_timer->extraHaptic);
});

new Choice(box, rect_t{}, STR_COUNTDOWNVALUES, 0, 3,
GET_SET_WITH_OFFSET(p_timer->countdownStart, 2));

Expand Down
Loading

0 comments on commit db655bc

Please sign in to comment.