diff --git a/openrtx/include/core/voicePromptUtils.h b/openrtx/include/core/voicePromptUtils.h index a72776e2..dcdf136f 100644 --- a/openrtx/include/core/voicePromptUtils.h +++ b/openrtx/include/core/voicePromptUtils.h @@ -16,10 +16,8 @@ * You should have received a copy of the GNU General Public License * * along with this program; if not, see * ***************************************************************************/ -// This file contains functions for announcing radio operations using the -// building blocks in voicePrompts.h/c. -#ifndef VOICE_PROMPT_UTILS_H_INCLUDED -#define VOICE_PROMPT_UTILS_H_INCLUDED +#ifndef VOICE_PROMPT_UTILS_H +#define VOICE_PROMPT_UTILS_H #include "cps.h" #include "ui/ui_strings.h" @@ -37,47 +35,162 @@ When an announceXX function is called in isolation, vpqInit|vpqPlayImmediately should be used to ensure that the message interupts the current prompt and plays immediately. */ -void announceVFO(); -void announceChannelName(channel_t* channel, uint16_t channelIndex, - VoicePromptQueueFlags_T flags); -void vpQueueFrequency(freq_t freq); -void announceFrequencies(freq_t rx, freq_t tx, VoicePromptQueueFlags_T flags); -void announceRadioMode(uint8_t mode, VoicePromptQueueFlags_T flags); -void announceBandwidth(uint8_t bandwidth, VoicePromptQueueFlags_T flags); -void announceChannelSummary(channel_t* channel, uint16_t channelIndex, - uint16_t bank); -void AnnounceInputChar(char ch); -void announceInputReceiveOrTransmit(bool tx, VoicePromptQueueFlags_T flags); -void ReplayLastPrompt(); -void announceError(VoicePromptQueueFlags_T flags); + +/** + * + */ +void vp_announceVFO(); + +/** + * + */ +void vp_announceChannelName(const channel_t* channel, + const uint16_t channelIndex, + const vpQueueFlags_t flags); + +/** + * + */ +void vp_queueFrequency(const freq_t freq); + +/** + * + */ +void vp_announceFrequencies(const freq_t rx, const freq_t tx, + const vpQueueFlags_t flags); + +/** + * + */ +void vp_announceRadioMode(const uint8_t mode, const vpQueueFlags_t flags); + +/** + * + */ +void vp_announceBandwidth(const uint8_t bandwidth, const vpQueueFlags_t flags); + +/** + * + */ +void vp_announceChannelSummary(const channel_t* channel, + const uint16_t channelIndex, const uint16_t bank); + +/** + * + */ +void vp_announceInputChar(const char ch); + +/** + * + */ +void vp_announceInputReceiveOrTransmit(const bool tx, const vpQueueFlags_t flags); + +/** + * + */ +void vp_replayLastPrompt(); + +/** + * + */ +void vp_announceError(const vpQueueFlags_t flags); /* This function first tries to see if we have a prompt for the text passed in and if so, queues it, but if not, just spells the text character by character. */ -void announceText(char* text, VoicePromptQueueFlags_T flags); -void announceCTCSS(bool rxToneEnabled, uint8_t rxTone, bool txToneEnabled, - uint8_t txTone, VoicePromptQueueFlags_T flags); -void anouncePower(float power, VoicePromptQueueFlags_T flags); -void announceBrightness(uint8_t brightness, VoicePromptQueueFlags_T flags); -void announceSquelch(uint8_t squelch, VoicePromptQueueFlags_T flags); -void announceContact(contact_t* contact, VoicePromptQueueFlags_T flags); -void announceContactWithIndex(uint16_t index, VoicePromptQueueFlags_T flags); -void announceTimeslot(uint8_t timeslot, VoicePromptQueueFlags_T flags); -void announceColorCode(uint8_t rxColorCode, uint8_t txColorCode, - VoicePromptQueueFlags_T flags); -void announceBank(uint16_t bank, VoicePromptQueueFlags_T flags); -void announceM17Info(channel_t* channel, VoicePromptQueueFlags_T flags); -#ifdef GPS_PRESENT -void announceGPSInfo(); -#endif // GPS_PRESENT -void announceAboutScreen(); -void announceBackupScreen(); -void announceRestoreScreen(); -#ifdef RTC_PRESENT -void announceSettingsTimeDate(); -#endif // RTC_PRESENT -VoicePromptQueueFlags_T GetQueueFlagsForVoiceLevel(); -#endif // VOICE_PROMPT_UTILS_H_INCLUDED +/** + * + */ +void vp_announceText(const char* text, const vpQueueFlags_t flags); + +/** + * + */ +void vp_announceCTCSS(const bool rxToneEnabled, const uint8_t rxTone, + const bool txToneEnabled, const uint8_t txTone, + const vpQueueFlags_t flags); + +/** + * + */ +void vp_anouncePower(const float power, const vpQueueFlags_t flags); + +/** + * + */ +void vp_announceBrightness(const uint8_t brightness, const vpQueueFlags_t flags); + +/** + * + */ +void vp_announceSquelch(const uint8_t squelch,const vpQueueFlags_t flags); + +/** + * + */ +void vp_announceContact(const contact_t* contact, const vpQueueFlags_t flags); + +/** + * + */ +void vp_announceContactWithIndex(const uint16_t index, const vpQueueFlags_t flags); + +/** + * + */ +void vp_announceTimeslot(const uint8_t timeslot, const vpQueueFlags_t flags); + +/** + * + */ +void vp_announceColorCode(const uint8_t rxColorCode, const uint8_t txColorCode, + const vpQueueFlags_t flags); + +/** + * + */ +void vp_announceBank(const uint16_t bank, const vpQueueFlags_t flags); + +/** + * + */ +void vp_announceM17Info(const channel_t* channel, const vpQueueFlags_t flags); + +/** + * + */ +#ifdef GPS_PRESENT +void vp_announceGPSInfo(); +#endif + +/** + * + */ +void vp_announceAboutScreen(); + +/** + * + */ +void vp_announceBackupScreen(); + +/** + * + */ +void vp_announceRestoreScreen(); + +/** + * + */ +#ifdef RTC_PRESENT +void vp_announceSettingsTimeDate(); +#endif + +/** + * + */ +vpQueueFlags_t vp_getVoiceLevelQueueFlags(); + +#endif // VOICE_PROMPT_UTILS_H diff --git a/openrtx/include/core/voicePrompts.h b/openrtx/include/core/voicePrompts.h index 9e44a1d0..cdad2920 100644 --- a/openrtx/include/core/voicePrompts.h +++ b/openrtx/include/core/voicePrompts.h @@ -184,6 +184,7 @@ voicePrompt_t; */ typedef enum { + vpDefault = 0x00, vpAnnounceCaps = 0x01, vpAnnounceCustomPrompts = 0x02, vpAnnounceSpace = 0x04, @@ -192,7 +193,7 @@ typedef enum vpAnnounceASCIIValueForUnknownChars = 0x20, vpAnnouncePhoneticRendering = 0x40, } -VoicePromptFlags_T; +vpFlags_t; /** * Queuing flags determining if speech is interrupted, played immediately, @@ -207,7 +208,7 @@ typedef enum vpqIncludeDescriptions = 0x08, vpqAddSeparatingSilence = 0x10 } -VoicePromptQueueFlags_T; +vpQueueFlags_t; /** * Voice prompt verbosity levels. @@ -251,7 +252,7 @@ void vp_queuePrompt(const uint16_t prompt); * @param string: string to be spelled. * @param flags: control flags. */ -void vp_queueString(const char* string, VoicePromptFlags_T flags); +void vp_queueString(const char* string, vpFlags_t flags); /** * Append a signed integer to the queue. diff --git a/openrtx/src/core/voicePromptUtils.c b/openrtx/src/core/voicePromptUtils.c index c58373ff..e70fbecf 100644 --- a/openrtx/src/core/voicePromptUtils.c +++ b/openrtx/src/core/voicePromptUtils.c @@ -31,12 +31,13 @@ #include "interfaces/cps_io.h" -static void vp_clearCurrPromptIfNeeded(VoicePromptQueueFlags_T flags) +static void clearCurrPromptIfNeeded(const vpQueueFlags_t flags) { - if (flags & vpqInit) vp_clearCurrPrompt(); + if (flags & vpqInit) + vp_clearCurrPrompt(); } -static void vp_playIfNeeded(VoicePromptQueueFlags_T flags) +static void playIfNeeded(const vpQueueFlags_t flags) { uint8_t vpLevel = state.settings.vpLevel; @@ -45,9 +46,10 @@ static void vp_playIfNeeded(VoicePromptQueueFlags_T flags) vp_play(); } -static void addSilenceIfNeeded(VoicePromptQueueFlags_T flags) +static void addSilenceIfNeeded(const vpQueueFlags_t flags) { - if ((flags & vpqAddSeparatingSilence) == 0) return; + if ((flags & vpqAddSeparatingSilence) == 0) + return; vp_queuePrompt(PROMPT_SILENCE); vp_queuePrompt(PROMPT_SILENCE); @@ -61,209 +63,242 @@ static void removeUnnecessaryZerosFromVoicePrompts(char* str) { if ((str[i - 1] != '0') || (str[i - (NUM_DECIMAL_PLACES + 1)] == '.')) { - str[i] = 0; + str[i] = '\0'; return; } } } -void announceVFO() + + +void vp_announceVFO() { vp_clearCurrPrompt(); - vp_queuePrompt(PROMPT_VFO); - vp_play(); } -void announceChannelName(channel_t* channel, uint16_t channelIndex, - VoicePromptQueueFlags_T flags) +void vp_announceChannelName(const channel_t* channel, + const uint16_t channelIndex, + const vpQueueFlags_t flags) { - vp_clearCurrPromptIfNeeded(flags); + clearCurrPromptIfNeeded(flags); if (flags & vpqIncludeDescriptions) { vp_queuePrompt(PROMPT_CHANNEL); } + vp_queueInteger(channelIndex); // Only queue the name if it is not the same as the raw number. // Otherwise the radio will say channel 1 1 for channel 1. char numAsStr[16] = "\0"; snprintf(numAsStr, 16, "%d", channelIndex); - if (strcmp(numAsStr, channel->name) != 0) - vp_queueString(channel->name, vpAnnounceCommonSymbols); - vp_playIfNeeded(flags); + if (strcmp(numAsStr, channel->name) != 0) + { + vp_queueString(channel->name, vpAnnounceCommonSymbols); + } + + playIfNeeded(flags); } -void vpQueueFrequency(freq_t freq) +void vp_queueFrequency(const freq_t freq) { char buffer[16]; - int mhz = (freq / 1000000); - int khz = ((freq % 1000000) / 10); + int MHz = (freq / 1000000); + int kHz = ((freq % 1000000) / 10); + + snprintf(buffer, 16, "%d.%05d", MHz, kHz); - snprintf(buffer, 16, "%d.%05d", mhz, khz); removeUnnecessaryZerosFromVoicePrompts(buffer); vp_queueString(buffer, vpAnnounceCommonSymbols); - vp_queuePrompt(PROMPT_MEGAHERTZ); } -void announceFrequencies(freq_t rx, freq_t tx, VoicePromptQueueFlags_T flags) +void vp_announceFrequencies(const freq_t rx, const freq_t tx, + const vpQueueFlags_t flags) { - vp_clearCurrPromptIfNeeded(flags); + clearCurrPromptIfNeeded(flags); + // If rx and tx frequencies differ, announce both, otherwise just one if (rx == tx) - vpQueueFrequency(rx); + { + vp_queueFrequency(rx); + } else { vp_queuePrompt(PROMPT_RECEIVE); - vpQueueFrequency(rx); + vp_queueFrequency(rx); vp_queuePrompt(PROMPT_TRANSMIT); - vpQueueFrequency(tx); + vp_queueFrequency(tx); } - vp_playIfNeeded(flags); + + playIfNeeded(flags); } -void announceRadioMode(uint8_t mode, VoicePromptQueueFlags_T flags) +void vp_announceRadioMode(const uint8_t mode, const vpQueueFlags_t flags) { - vp_clearCurrPromptIfNeeded(flags); + clearCurrPromptIfNeeded(flags); - if (flags & vpqIncludeDescriptions) vp_queuePrompt(PROMPT_MODE); + if (flags & vpqIncludeDescriptions) + { + vp_queuePrompt(PROMPT_MODE); + } switch (mode) { case OPMODE_DMR: vp_queueStringTableEntry(¤tLanguage->dmr); break; + case OPMODE_FM: vp_queueStringTableEntry(¤tLanguage->fm); break; + case OPMODE_M17: vp_queueStringTableEntry(¤tLanguage->m17); break; } - vp_playIfNeeded(flags); + playIfNeeded(flags); } -void announceBandwidth(uint8_t bandwidth, VoicePromptQueueFlags_T flags) +void vp_announceBandwidth(const uint8_t bandwidth, const vpQueueFlags_t flags) { - if (bandwidth > BW_25) bandwidth = BW_25; // Should probably never happen! + clearCurrPromptIfNeeded(flags); - vp_clearCurrPromptIfNeeded(flags); - - if (flags & vpqIncludeDescriptions) vp_queuePrompt(PROMPT_BANDWIDTH); + if (flags & vpqIncludeDescriptions) + { + vp_queuePrompt(PROMPT_BANDWIDTH); + } char* bandwidths[] = {"12.5", "20", "25"}; vp_queueString(bandwidths[bandwidth], vpAnnounceCommonSymbols); vp_queuePrompt(PROMPT_KILOHERTZ); - - vp_playIfNeeded(flags); + playIfNeeded(flags); } -void anouncePower(float power, VoicePromptQueueFlags_T flags) +void vp_anouncePower(const float power, const vpQueueFlags_t flags) { - vp_clearCurrPromptIfNeeded(flags); + clearCurrPromptIfNeeded(flags); + + if (flags & vpqIncludeDescriptions) + { + vp_queuePrompt(PROMPT_POWER); + } char buffer[16] = "\0"; - - if (flags & vpqIncludeDescriptions) vp_queuePrompt(PROMPT_POWER); - snprintf(buffer, 16, "%1.1f", power); + vp_queueString(buffer, vpAnnounceCommonSymbols); vp_queuePrompt(PROMPT_WATTS); - - vp_playIfNeeded(flags); + playIfNeeded(flags); } -void announceChannelSummary(channel_t* channel, uint16_t channelIndex, - uint16_t bank) +void vp_announceChannelSummary(const channel_t* channel, + const uint16_t channelIndex, const uint16_t bank) { - if (!channel) return; + if (channel == NULL) + return; vp_clearCurrPrompt(); - VoicePromptQueueFlags_T localFlags = vpqAddSeparatingSilence; + vpQueueFlags_t localFlags = vpqAddSeparatingSilence; + // Force on the descriptions for level 3. - if (state.settings.vpLevel == vpHigh) localFlags |= vpqIncludeDescriptions; + if (state.settings.vpLevel == vpHigh) + { + localFlags |= vpqIncludeDescriptions; + } + // If VFO mode, announce VFO. // channelIndex will be 0 if called from VFO mode. if (channelIndex == 0) + { vp_queuePrompt(PROMPT_VFO); + } else - announceChannelName(channel, channelIndex, localFlags); - announceFrequencies(channel->rx_frequency, channel->tx_frequency, + { + vp_announceChannelName(channel, channelIndex, localFlags); + } + + vp_announceFrequencies(channel->rx_frequency, channel->tx_frequency, localFlags); - announceRadioMode(channel->mode, localFlags); + vp_announceRadioMode(channel->mode, localFlags); + if (channel->mode == OPMODE_FM) { - announceBandwidth(channel->bandwidth, localFlags); + vp_announceBandwidth(channel->bandwidth, localFlags); addSilenceIfNeeded(localFlags); if (channel->fm.rxToneEn || channel->fm.txToneEn) { - announceCTCSS(channel->fm.rxToneEn, channel->fm.rxTone, - channel->fm.txToneEn, channel->fm.txTone, localFlags); + vp_announceCTCSS(channel->fm.rxToneEn, channel->fm.rxTone, + channel->fm.txToneEn, channel->fm.txTone, localFlags); } } else if (channel->mode == OPMODE_M17) { addSilenceIfNeeded(localFlags); - announceM17Info(channel, localFlags); + vp_announceM17Info(channel, localFlags); } else if (channel->mode == OPMODE_DMR) { addSilenceIfNeeded(localFlags); - announceContactWithIndex(channel->dmr.contact_index, localFlags); + vp_announceContactWithIndex(channel->dmr.contact_index, localFlags); + // Force announcement of the words timeslot and colorcode to avoid // ambiguity. - announceTimeslot(channel->dmr.dmr_timeslot, + vp_announceTimeslot(channel->dmr.dmr_timeslot, (localFlags | vpqIncludeDescriptions)); - announceColorCode(channel->dmr.rxColorCode, channel->dmr.txColorCode, + vp_announceColorCode(channel->dmr.rxColorCode, channel->dmr.txColorCode, (localFlags | vpqIncludeDescriptions)); } - addSilenceIfNeeded(localFlags); - anouncePower(channel->power, localFlags); + addSilenceIfNeeded(localFlags); + vp_anouncePower(channel->power, localFlags); addSilenceIfNeeded(localFlags); if (channelIndex > 0) // i.e. not called from VFO. - announceBank(bank, localFlags); + { + vp_announceBank(bank, localFlags); + } vp_play(); } - -void AnnounceInputChar(char ch) + +void vp_announceInputChar(const char ch) { char buf[2] = "\0"; buf[0] = ch; vp_clearCurrPrompt(); - uint8_t flags = vpAnnounceCaps | vpAnnounceSpace | vpAnnounceCommonSymbols | - vpAnnounceLessCommonSymbols; + uint8_t flags = vpAnnounceCaps + | vpAnnounceSpace + | vpAnnounceCommonSymbols + | vpAnnounceLessCommonSymbols; vp_queueString(buf, flags); - vp_play(); } -void announceInputReceiveOrTransmit(bool tx, VoicePromptQueueFlags_T flags) +void vp_announceInputReceiveOrTransmit(const bool tx, const vpQueueFlags_t flags) { - vp_clearCurrPromptIfNeeded(flags); + clearCurrPromptIfNeeded(flags); if (tx) vp_queuePrompt(PROMPT_TRANSMIT); else vp_queuePrompt(PROMPT_RECEIVE); - vp_playIfNeeded(flags); + playIfNeeded(flags); } -void ReplayLastPrompt() +void vp_replayLastPrompt() { if (vp_isPlaying()) vp_terminate(); @@ -271,20 +306,20 @@ void ReplayLastPrompt() vp_play(); } -void announceError(VoicePromptQueueFlags_T flags) +void vp_announceError(const vpQueueFlags_t flags) { - vp_clearCurrPromptIfNeeded(flags); - + clearCurrPromptIfNeeded(flags); vp_queueStringTableEntry(¤tLanguage->error); - - vp_playIfNeeded(flags); + playIfNeeded(flags); } -void announceText(char* text, VoicePromptQueueFlags_T flags) +void vp_announceText(const char* text, const vpQueueFlags_t flags) { - if (!text || !*text) return; + if ((text == NULL) || (*text == '\0')) + return; + + clearCurrPromptIfNeeded(flags); - vp_clearCurrPromptIfNeeded(flags); // See if we have a prompt for this string. int offset = GetEnglishStringTableOffset(text); @@ -294,19 +329,20 @@ void announceText(char* text, VoicePromptQueueFlags_T flags) else // Just spell it out vp_queueString(text, vpAnnounceCommonSymbols); - vp_playIfNeeded(flags); + playIfNeeded(flags); } -void announceCTCSS(bool rxToneEnabled, uint8_t rxTone, bool txToneEnabled, - uint8_t txTone, VoicePromptQueueFlags_T flags) +void vp_announceCTCSS(const bool rxToneEnabled, const uint8_t rxTone, + const bool txToneEnabled, const uint8_t txTone, + const vpQueueFlags_t flags) { - vp_clearCurrPromptIfNeeded(flags); + clearCurrPromptIfNeeded(flags); - if (!rxToneEnabled && !txToneEnabled) + if ((rxToneEnabled == false) && (txToneEnabled == false)) { vp_queuePrompt(PROMPT_TONE); vp_queueStringTableEntry(¤tLanguage->off); - vp_playIfNeeded(flags); + playIfNeeded(flags); return; } @@ -316,97 +352,118 @@ void announceCTCSS(bool rxToneEnabled, uint8_t rxTone, bool txToneEnabled, if ((rxToneEnabled && txToneEnabled) && (rxTone == txTone)) { vp_queuePrompt(PROMPT_TONE); + snprintf(buffer, 16, "%3.1f", ctcss_tone[rxTone] / 10.0f); - vp_queueString(buffer, vpqDefault); + vp_queueString(buffer, vpDefault); vp_queuePrompt(PROMPT_HERTZ); - vp_playIfNeeded(flags); + playIfNeeded(flags); + return; } + // Speak the individual rx and tx tones. if (rxToneEnabled) { vp_queuePrompt(PROMPT_RECEIVE); vp_queuePrompt(PROMPT_TONE); + snprintf(buffer, 16, "%3.1f", ctcss_tone[rxTone] / 10.0f); - vp_queueString(buffer, vpqDefault); + vp_queueString(buffer, vpDefault); vp_queuePrompt(PROMPT_HERTZ); } if (txToneEnabled) { vp_queuePrompt(PROMPT_TRANSMIT); vp_queuePrompt(PROMPT_TONE); + snprintf(buffer, 16, "%3.1f", ctcss_tone[txTone] / 10.0f); - vp_queueString(buffer, vpqDefault); + vp_queueString(buffer, vpDefault); vp_queuePrompt(PROMPT_HERTZ); } - vp_playIfNeeded(flags); + playIfNeeded(flags); } -void announceBrightness(uint8_t brightness, VoicePromptQueueFlags_T flags) +void vp_announceBrightness(const uint8_t brightness, const vpQueueFlags_t flags) { - vp_clearCurrPromptIfNeeded(flags); + clearCurrPromptIfNeeded(flags); if (flags & vpqIncludeDescriptions) + { vp_queueStringTableEntry(¤tLanguage->brightness); + } vp_queueInteger(brightness); - - vp_playIfNeeded(flags); + playIfNeeded(flags); } -void announceSquelch(uint8_t squelch, VoicePromptQueueFlags_T flags) +void vp_announceSquelch(const uint8_t squelch, const vpQueueFlags_t flags) { - vp_clearCurrPromptIfNeeded(flags); + clearCurrPromptIfNeeded(flags); - if (flags & vpqIncludeDescriptions) vp_queuePrompt(PROMPT_SQUELCH); + if (flags & vpqIncludeDescriptions) + { + vp_queuePrompt(PROMPT_SQUELCH); + } vp_queueInteger(squelch); - - vp_playIfNeeded(flags); + playIfNeeded(flags); } -void announceContact(contact_t* contact, VoicePromptQueueFlags_T flags) +void vp_announceContact(const contact_t* contact, const vpQueueFlags_t flags) { - if (!contact) return; + if (contact == NULL) + return; - vp_clearCurrPromptIfNeeded(flags); + clearCurrPromptIfNeeded(flags); - if (flags & vpqIncludeDescriptions) vp_queuePrompt(PROMPT_CONTACT); + if (flags & vpqIncludeDescriptions) + { + vp_queuePrompt(PROMPT_CONTACT); + } - if (contact->name[0]) vp_queueString(contact->name, vpAnnounceCommonSymbols); + if (contact->name[0] != '\0') + { + vp_queueString(contact->name, vpAnnounceCommonSymbols); + } - vp_playIfNeeded(flags); + playIfNeeded(flags); } -void announceContactWithIndex(uint16_t index, VoicePromptQueueFlags_T flags) +void vp_announceContactWithIndex(const uint16_t index, const vpQueueFlags_t flags) { - if (index == 0) return; + if (index == 0) + return; contact_t contact; + if (cps_readContact(&contact, index) == -1) + return; - if (cps_readContact(&contact, index) == -1) return; - - announceContact(&contact, flags); + vp_announceContact(&contact, flags); } -void announceTimeslot(uint8_t timeslot, VoicePromptQueueFlags_T flags) +void vp_announceTimeslot(const uint8_t timeslot, const vpQueueFlags_t flags) { - vp_clearCurrPromptIfNeeded(flags); + clearCurrPromptIfNeeded(flags); - if (flags & vpqIncludeDescriptions) vp_queuePrompt(PROMPT_TIMESLOT); + if (flags & vpqIncludeDescriptions) + { + vp_queuePrompt(PROMPT_TIMESLOT); + } vp_queueInteger(timeslot); - - vp_playIfNeeded(flags); + playIfNeeded(flags); } -void announceColorCode(uint8_t rxColorCode, uint8_t txColorCode, - VoicePromptQueueFlags_T flags) +void vp_announceColorCode(const uint8_t rxColorCode, const uint8_t txColorCode, + const vpQueueFlags_t flags) { - vp_clearCurrPromptIfNeeded(flags); + clearCurrPromptIfNeeded(flags); - if (flags & vpqIncludeDescriptions) vp_queuePrompt(PROMPT_COLORCODE); + if (flags & vpqIncludeDescriptions) + { + vp_queuePrompt(PROMPT_COLORCODE); + } if (rxColorCode == txColorCode) { @@ -420,14 +477,17 @@ void announceColorCode(uint8_t rxColorCode, uint8_t txColorCode, vp_queueInteger(txColorCode); } - vp_playIfNeeded(flags); + playIfNeeded(flags); } -void announceBank(uint16_t bank, VoicePromptQueueFlags_T flags) +void vp_announceBank(const uint16_t bank, const vpQueueFlags_t flags) { - vp_clearCurrPromptIfNeeded(flags); + clearCurrPromptIfNeeded(flags); + if (flags & vpqIncludeDescriptions) + { vp_queueStringTableEntry(¤tLanguage->banks); + } if (state.bank_enabled) { @@ -436,35 +496,46 @@ void announceBank(uint16_t bank, VoicePromptQueueFlags_T flags) vp_queueString(bank_hdr.name, vpAnnounceCommonSymbols); } else + { vp_queueStringTableEntry(¤tLanguage->allChannels); + } - vp_playIfNeeded(flags); + playIfNeeded(flags); } -void announceM17Info(channel_t* channel, VoicePromptQueueFlags_T flags) +void vp_announceM17Info(const channel_t* channel, const vpQueueFlags_t flags) { - if (!channel) return; + if (channel == NULL) + return; - vp_clearCurrPromptIfNeeded(flags); - if (state.m17_data.dst_addr[0]) + clearCurrPromptIfNeeded(flags); + + if (state.m17_data.dst_addr[0] != '\0') { - if (flags & vpqIncludeDescriptions) vp_queuePrompt(PROMPT_DEST_ID); + if (flags & vpqIncludeDescriptions) + { + vp_queuePrompt(PROMPT_DEST_ID); + } + vp_queueString(state.m17_data.dst_addr, vpAnnounceCommonSymbols); } - else if (channel->m17.contact_index) - announceContactWithIndex(channel->m17.contact_index, flags); + else if (channel->m17.contact_index != 0) + { + vp_announceContactWithIndex(channel->m17.contact_index, flags); + } - vp_playIfNeeded(flags); + playIfNeeded(flags); } #ifdef GPS_PRESENT -void announceGPSInfo() +void vp_announceGPSInfo() { - if (!state.settings.gps_enabled) return; + if (!state.settings.gps_enabled) + return; vp_clearCurrPrompt(); - VoicePromptQueueFlags_T flags = - vpqIncludeDescriptions | vpqAddSeparatingSilence; + vpQueueFlags_t flags = vpqIncludeDescriptions + | vpqAddSeparatingSilence; vp_queueStringTableEntry(¤tLanguage->gps); @@ -473,18 +544,23 @@ void announceGPSInfo() case 0: vp_queueStringTableEntry(¤tLanguage->noFix); break; + case 1: vp_queueString("SPS", vpAnnounceCommonSymbols); break; + case 2: vp_queueString("DGPS", vpAnnounceCommonSymbols); break; + case 3: vp_queueString("PPS", vpAnnounceCommonSymbols); break; + case 6: vp_queueStringTableEntry(¤tLanguage->fixLost); break; + default: vp_queueStringTableEntry(¤tLanguage->error); @@ -492,6 +568,7 @@ void announceGPSInfo() return; } + addSilenceIfNeeded(flags); switch (state.gps_data.fix_type) @@ -499,36 +576,43 @@ void announceGPSInfo() case 2: vp_queueString("2D", vpAnnounceCommonSymbols); break; + case 3: vp_queueString("3D", vpAnnounceCommonSymbols); break; } + addSilenceIfNeeded(flags); + // lat/long char buffer[16] = "\0"; - vp_queuePrompt(PROMPT_LATITUDE); snprintf(buffer, 16, "%8.6f", state.gps_data.latitude); + vp_queuePrompt(PROMPT_LATITUDE); vp_queueString(buffer, vpAnnounceCommonSymbols); vp_queuePrompt(PROMPT_NORTH); + float longitude = state.gps_data.longitude; voicePrompt_t direction = (longitude < 0) ? PROMPT_WEST : PROMPT_EAST; longitude = (longitude < 0) ? -longitude : longitude; snprintf(buffer, 16, "%8.6f", longitude); + vp_queuePrompt(PROMPT_LONGITUDE); vp_queueString(buffer, vpAnnounceCommonSymbols); vp_queuePrompt(direction); addSilenceIfNeeded(flags); + // speed/altitude: - vp_queuePrompt(PROMPT_SPEED); snprintf(buffer, 16, "%4.1fkm/h", state.gps_data.speed); + vp_queuePrompt(PROMPT_SPEED); vp_queueString(buffer, vpAnnounceCommonSymbols); vp_queuePrompt(PROMPT_ALTITUDE); + snprintf(buffer, 16, "%4.1fm", state.gps_data.altitude); vp_queueString(buffer, vpAnnounceCommonSymbols); addSilenceIfNeeded(flags); - vp_queuePrompt(PROMPT_COMPASS); snprintf(buffer, 16, "%3.1f", state.gps_data.tmg_true); + vp_queuePrompt(PROMPT_COMPASS); vp_queueString(buffer, vpAnnounceCommonSymbols); vp_queuePrompt(PROMPT_DEGREES); addSilenceIfNeeded(flags); @@ -540,7 +624,7 @@ void announceGPSInfo() } #endif // GPS_PRESENT -void announceAboutScreen() +void vp_announceAboutScreen() { vp_clearCurrPrompt(); @@ -555,7 +639,7 @@ void announceAboutScreen() vp_play(); } -void announceBackupScreen() +void vp_announceBackupScreen() { vp_clearCurrPrompt(); @@ -569,7 +653,7 @@ void announceBackupScreen() vp_play(); } -void announceRestoreScreen() +void vp_announceRestoreScreen() { vp_clearCurrPrompt(); @@ -584,70 +668,58 @@ void announceRestoreScreen() } #ifdef RTC_PRESENT -void announceSettingsTimeDate() +void vp_announceSettingsTimeDate() { vp_clearCurrPrompt(); vp_queueStringTableEntry(¤tLanguage->timeAndDate); - datetime_t local_time = utcToLocalTime(state.time, state.settings.utc_timezone); + datetime_t local_time = utcToLocalTime(state.time, + state.settings.utc_timezone); char buffer[16] = "\0"; snprintf(buffer, 16, "%02d/%02d/%02d", local_time.date, local_time.month, - local_time.year); - vp_queueString(buffer, - (vpAnnounceCommonSymbols | vpAnnounceLessCommonSymbols)); + local_time.year); + vp_queueString(buffer, vpAnnounceCommonSymbols | + vpAnnounceLessCommonSymbols); snprintf(buffer, 16, "%02d:%02d:%02d", local_time.hour, local_time.minute, - local_time.second); - vp_queueString(buffer, - (vpAnnounceCommonSymbols | vpAnnounceLessCommonSymbols)); + local_time.second); + vp_queueString(buffer, vpAnnounceCommonSymbols | + vpAnnounceLessCommonSymbols); vp_play(); } #endif // RTC_PRESENT -/* - * There are 5 levels of verbosity: - * - * vpNone: no voice or beeps. - * vpBeep: beeps only. - * vpLow: menus talk, but channel and frequency changes are indicated with a - * beep and only voiced on demand with f1. - * vpMedium: menus, channel and frequency changes talk but with extra - * descriptions eliminated unless ambiguity would result. E.g. We'd say "FM" - * rather than "Mode: FM" in the channel summary. - * vpHigh: like vpMedium except with extra descriptions: e.g. "Mode fm". - * - * Also, if a voice prompt is in progress, e.g. changing a menu item, the - * descriptions are eliminated, e.g., changing ctcss tones would not repeat - * "ctcss" when arrowing through the options rapidly. - */ -VoicePromptQueueFlags_T GetQueueFlagsForVoiceLevel() +vpQueueFlags_t vp_getVoiceLevelQueueFlags() { - VoicePromptQueueFlags_T flags = vpqInit | vpqAddSeparatingSilence; - uint8_t vpLevel = state.settings.vpLevel; + vpQueueFlags_t flags = vpqInit + | vpqAddSeparatingSilence; + switch (vpLevel) { case vpNone: case vpBeep: return vpqDefault; - // Play some immediately, other things on demand. + case vpLow: + // Play some immediately, other things on demand. flags |= vpqPlayImmediatelyAtMediumOrHigher; break; - // Play all immediately but without extra descriptions + case vpMedium: - { + // Play all immediately but without extra descriptions flags |= vpqPlayImmediately; break; - } - // Play immediately with descriptions unless speech is in progress. + case vpHigh: + // Play immediately with descriptions unless speech is in progress. flags |= vpqPlayImmediately; - if (!vp_isPlaying()) flags |= vpqIncludeDescriptions; + if (!vp_isPlaying()) + flags |= vpqIncludeDescriptions; break; } diff --git a/openrtx/src/core/voicePrompts.c b/openrtx/src/core/voicePrompts.c index 61318042..c6e54dbe 100644 --- a/openrtx/src/core/voicePrompts.c +++ b/openrtx/src/core/voicePrompts.c @@ -163,7 +163,7 @@ static uint16_t UserDictLookup(const char* ptr, int* advanceBy) } static bool GetSymbolVPIfItShouldBeAnnounced(char symbol, - VoicePromptFlags_T flags, + vpFlags_t flags, voicePrompt_t* vp) { *vp = PROMPT_SILENCE; @@ -274,7 +274,7 @@ void vp_queuePrompt(const uint16_t prompt) } } -void vp_queueString(const char* string, VoicePromptFlags_T flags) +void vp_queueString(const char* string, vpFlags_t flags) { if (state.settings.vpLevel < vpLow) return; diff --git a/openrtx/src/ui/ui.c b/openrtx/src/ui/ui.c index b15ff3db..34173507 100644 --- a/openrtx/src/ui/ui.c +++ b/openrtx/src/ui/ui.c @@ -624,10 +624,10 @@ void _ui_fsm_confirmVFOInput(bool *sync_rtx) // Reset input position ui_state.input_position = 0; // announce the rx frequency just confirmed with Enter. - vpQueueFrequency(ui_state.new_rx_frequency); + vp_queueFrequency(ui_state.new_rx_frequency); // defer playing till the end. // indicate that the user has moved to the tx freq field. - announceInputReceiveOrTransmit(true, vpqDefault); + vp_announceInputReceiveOrTransmit(true, vpqDefault); } else if(ui_state.input_set == SET_TX) { @@ -647,10 +647,10 @@ void _ui_fsm_confirmVFOInput(bool *sync_rtx) // force init to clear any prompts in progress. // defer play because play is called at the end of the function //due to above freq queuing. - announceFrequencies(state.channel.rx_frequency, state.channel.tx_frequency, vpqInit); + vp_announceFrequencies(state.channel.rx_frequency, state.channel.tx_frequency, vpqInit); } else - announceError(vpqInit); + vp_announceError(vpqInit); state.ui_screen = MAIN_VFO; } vp_play(); @@ -679,7 +679,7 @@ void _ui_fsm_insertVFONumber(kbd_msg_t msg, bool *sync_rtx) ui_state.input_position, ui_state.input_number); if(ui_state.input_position >= FREQ_DIGITS) {// queue the rx freq just completed. - vpQueueFrequency(ui_state.new_rx_frequency); + vp_queueFrequency(ui_state.new_rx_frequency); /// now queue tx as user has changed fields. vp_queuePrompt(PROMPT_TRANSMIT); // Switch to TX input @@ -707,7 +707,7 @@ void _ui_fsm_insertVFONumber(kbd_msg_t msg, bool *sync_rtx) state.channel.tx_frequency = ui_state.new_tx_frequency; *sync_rtx = true; // play is called at end. - announceFrequencies(state.channel.rx_frequency, state.channel.tx_frequency, vpqInit); + vp_announceFrequencies(state.channel.rx_frequency, state.channel.tx_frequency, vpqInit); } state.ui_screen = MAIN_VFO; } @@ -835,7 +835,7 @@ void _ui_fsm_menuMacro(kbd_msg_t msg, bool *sync_rtx) bool tone_tx_enable = state.channel.fm.txToneEn; bool tone_rx_enable = state.channel.fm.rxToneEn; uint8_t tone_flags = tone_tx_enable << 1 | tone_rx_enable; - VoicePromptQueueFlags_T queueFlags=GetQueueFlagsForVoiceLevel(); + vpQueueFlags_t queueFlags=vp_getVoiceLevelQueueFlags(); switch(ui_state.input_number) { @@ -846,7 +846,7 @@ void _ui_fsm_menuMacro(kbd_msg_t msg, bool *sync_rtx) state.channel.fm.txTone %= MAX_TONE_INDEX; state.channel.fm.rxTone = state.channel.fm.txTone; *sync_rtx = true; - announceCTCSS(state.channel.fm.rxToneEn, state.channel.fm.rxTone, + vp_announceCTCSS(state.channel.fm.rxToneEn, state.channel.fm.rxTone, state.channel.fm.txToneEn, state.channel.fm.txTone, queueFlags); } @@ -870,7 +870,7 @@ void _ui_fsm_menuMacro(kbd_msg_t msg, bool *sync_rtx) state.channel.fm.txToneEn = tone_tx_enable; state.channel.fm.rxToneEn = tone_rx_enable; *sync_rtx = true; - announceCTCSS(state.channel.fm.rxToneEn, state.channel.fm.rxTone, + vp_announceCTCSS(state.channel.fm.rxToneEn, state.channel.fm.rxTone, state.channel.fm.txToneEn, state.channel.fm.txTone, queueFlags); } @@ -881,7 +881,7 @@ void _ui_fsm_menuMacro(kbd_msg_t msg, bool *sync_rtx) state.channel.bandwidth++; state.channel.bandwidth %= 3; *sync_rtx = true; - announceBandwidth(state.channel.bandwidth, queueFlags); + vp_announceBandwidth(state.channel.bandwidth, queueFlags); } break; case 5: @@ -893,7 +893,7 @@ void _ui_fsm_menuMacro(kbd_msg_t msg, bool *sync_rtx) else //catch any invalid states so they don't get locked out state.channel.mode = OPMODE_FM; *sync_rtx = true; - announceRadioMode(state.channel.mode, queueFlags); + vp_announceRadioMode(state.channel.mode, queueFlags); break; case 6: if (state.channel.power == 100) @@ -901,16 +901,16 @@ void _ui_fsm_menuMacro(kbd_msg_t msg, bool *sync_rtx) else state.channel.power = 100; *sync_rtx = true; - anouncePower(state.channel.power, queueFlags); + vp_anouncePower(state.channel.power, queueFlags); break; break; case 7: _ui_changeBrightness(-5); - announceBrightness(state.settings.brightness, queueFlags); + vp_announceBrightness(state.settings.brightness, queueFlags); break; case 8: _ui_changeBrightness(+5); - announceBrightness(state.settings.brightness, queueFlags); + vp_announceBrightness(state.settings.brightness, queueFlags); break; } @@ -932,7 +932,7 @@ void _ui_fsm_menuMacro(kbd_msg_t msg, bool *sync_rtx) { state.settings.sqlLevel -= 1; *sync_rtx = true; - announceSquelch(state.settings.sqlLevel, queueFlags); + vp_announceSquelch(state.settings.sqlLevel, queueFlags); RestartFunctionLatchTimer(); // reset the timer. } } @@ -947,7 +947,7 @@ void _ui_fsm_menuMacro(kbd_msg_t msg, bool *sync_rtx) { state.settings.sqlLevel += 1; *sync_rtx = true; - announceSquelch(state.settings.sqlLevel, queueFlags); + vp_announceSquelch(state.settings.sqlLevel, queueFlags); RestartFunctionLatchTimer(); // reset the timer. } } @@ -1031,7 +1031,7 @@ void _ui_textInputKeypad(char *buf, uint8_t max_len, kbd_msg_t msg, bool callsig buf[ui_state.input_position] = symbols_ITU_T_E161[num_key][ui_state.input_set]; } // Announce the character - AnnounceInputChar(buf[ui_state.input_position]); + vp_announceInputChar(buf[ui_state.input_position]); // Update reference values ui_state.input_number = num_key; ui_state.last_keypress = now; @@ -1049,7 +1049,7 @@ void _ui_textInputDel(char *buf) if(ui_state.input_position > 0) { ui_state.input_position--; - AnnounceInputChar(buf[ui_state.input_position]); + vp_announceInputChar(buf[ui_state.input_position]); // If we deleted the initial character, reset starting condition } else @@ -1100,7 +1100,7 @@ void ui_updateFSM(bool *sync_rtx) kbd_msg_t msg; msg.value = event.payload; bool f1Handled = false; - VoicePromptQueueFlags_T queueFlags = GetQueueFlagsForVoiceLevel(); + vpQueueFlags_t queueFlags = vp_getVoiceLevelQueueFlags(); // If we get out of standby, we ignore the kdb event // unless is the MONI key for the MACRO functions if (_ui_exitStandby(now) && !(msg.keys & KEY_MONI)) @@ -1183,7 +1183,7 @@ void ui_updateFSM(bool *sync_rtx) // Switch to MEM screen state.ui_screen = MAIN_MEM; // anounce the active channel name. - announceChannelName(&state.channel, state.channel_index, queueFlags); + vp_announceChannelName(&state.channel, state.channel_index, queueFlags); } } else if(msg.keys & KEY_HASH) @@ -1202,7 +1202,7 @@ void ui_updateFSM(bool *sync_rtx) state.channel.rx_frequency += 12500; state.channel.tx_frequency += 12500; *sync_rtx = true; - announceFrequencies(state.channel.rx_frequency, state.channel.tx_frequency, queueFlags); + vp_announceFrequencies(state.channel.rx_frequency, state.channel.tx_frequency, queueFlags); } } else if(msg.keys & KEY_DOWN || msg.keys & KNOB_LEFT) @@ -1214,10 +1214,21 @@ void ui_updateFSM(bool *sync_rtx) state.channel.rx_frequency -= 12500; state.channel.tx_frequency -= 12500; *sync_rtx = true; - announceFrequencies(state.channel.rx_frequency, state.channel.tx_frequency, queueFlags); + vp_announceFrequencies(state.channel.rx_frequency, state.channel.tx_frequency, queueFlags); } } else if(msg.keys & KEY_F1) + { + if (state.settings.vpLevel > vpBeep) + {// quick press repeat vp, long press summary. + if (msg.long_press) + vp_announceChannelSummary(&state.channel, 0, state.bank); + else + vp_replayLastPrompt(); + f1Handled = true; + } + } + else if(msg.keys & KEY_F1) { if (state.settings.vpLevel > vpBeep) {// quick press repeat vp, long press summary. @@ -1236,14 +1247,14 @@ void ui_updateFSM(bool *sync_rtx) ui_state.input_position = 1; ui_state.input_set = SET_RX; // do not play because we will also announce the number just entered. - announceInputReceiveOrTransmit(false, vpqInit); + vp_announceInputReceiveOrTransmit(false, vpqInit); ui_state.new_rx_frequency = 0; ui_state.new_tx_frequency = 0; // Save pressed number to calculare frequency and show in GUI ui_state.input_number = input_getPressedNumber(msg); // Calculate portion of the new frequency ui_state.new_rx_frequency = _ui_freq_add_digit(ui_state.new_rx_frequency, - ui_state.input_position, ui_state.input_number); + ui_state.input_position, ui_state.input_number); } } break; @@ -1263,12 +1274,12 @@ void ui_updateFSM(bool *sync_rtx) if(ui_state.input_set == SET_RX) { ui_state.input_set = SET_TX; - announceInputReceiveOrTransmit(true, queueFlags); + vp_announceInputReceiveOrTransmit(true, queueFlags); } else if(ui_state.input_set == SET_TX) { ui_state.input_set = SET_RX; - announceInputReceiveOrTransmit(false, queueFlags); + vp_announceInputReceiveOrTransmit(false, queueFlags); } // Reset input position ui_state.input_position = 0; @@ -1308,9 +1319,9 @@ void ui_updateFSM(bool *sync_rtx) if (state.settings.vpLevel > vpBeep) {// quick press repeat vp, long press summary. if (msg.long_press) - announceChannelSummary(&state.channel, state.channel_index, state.bank); + vp_announceChannelSummary(&state.channel, state.channel_index, state.bank); else - ReplayLastPrompt(); + vp_replayLastPrompt(); f1Handled=true; } } @@ -1490,9 +1501,9 @@ void ui_updateFSM(bool *sync_rtx) if ((msg.keys & KEY_F1) && (state.settings.vpLevel > vpBeep)) {// quick press repeat vp, long press summary. if (msg.long_press) - announceGPSInfo(); + vp_announceGPSInfo(); else - ReplayLastPrompt(); + vp_replayLastPrompt(); f1Handled = true; } else if(msg.keys & KEY_ESC) @@ -1581,9 +1592,9 @@ void ui_updateFSM(bool *sync_rtx) if ((msg.keys & KEY_F1) && (state.settings.vpLevel > vpBeep)) {// quick press repeat vp, long press summary. if (msg.long_press) - announceAboutScreen(); + vp_announceAboutScreen(); else - ReplayLastPrompt(); + vp_replayLastPrompt(); f1Handled = true; } else if(msg.keys & KEY_ESC) @@ -1595,9 +1606,9 @@ void ui_updateFSM(bool *sync_rtx) if ((msg.keys & KEY_F1) && (state.settings.vpLevel > vpBeep)) {// quick press repeat vp, long press summary. if (msg.long_press) - announceSettingsTimeDate(); + vp_announceSettingsTimeDate(); else - ReplayLastPrompt(); + vp_replayLastPrompt(); f1Handled = true; } else if(msg.keys & KEY_ENTER) @@ -1833,7 +1844,7 @@ void ui_updateFSM(bool *sync_rtx) } if (!f1Handled && (msg.keys & KEY_F1) && (state.settings.vpLevel > vpBeep)) { - ReplayLastPrompt(); + vp_replayLastPrompt(); } } diff --git a/openrtx/src/ui/ui_menu.c b/openrtx/src/ui/ui_menu.c index c04c5ec7..76d3610c 100644 --- a/openrtx/src/ui/ui_menu.c +++ b/openrtx/src/ui/ui_menu.c @@ -104,10 +104,10 @@ static void announceMenuItemIfNeeded(char* name, char* value) vp_clearCurrPrompt(); // If no value is supplied, or, no prompt is in progress, announce the name. if (!voicePromptWasPlaying || !value || !*value) - announceText(name, vpqDefault); + vp_announceText(name, vpqDefault); if (value && *value) - announceText(value, vpqDefault); + vp_announceText(value, vpqDefault); vp_play(); } @@ -568,7 +568,7 @@ void _ui_drawMenuBackup(ui_state_t* ui_state) color_white, currentLanguage->pressPTTToStart); // read this screen. - announceBackupScreen(); + vp_announceBackupScreen(); if (!platform_getPttStatus()) return; @@ -595,7 +595,7 @@ void _ui_drawMenuRestore(ui_state_t* ui_state) gfx_print(line, FONT_SIZE_8PT, TEXT_ALIGN_CENTER, color_white, currentLanguage->pressPTTToStart); - announceRestoreScreen(); + vp_announceRestoreScreen(); if (!platform_getPttStatus()) return; diff --git a/tests/unit/voice_prompts.c b/tests/unit/voice_prompts.c index a33dbe7a..b28be722 100644 --- a/tests/unit/voice_prompts.c +++ b/tests/unit/voice_prompts.c @@ -32,7 +32,7 @@ int main() { state.settings.vpLevel = 3; - VoicePromptQueueFlags_T flags = GetQueueFlagsForVoiceLevel(); + vpQueueFlags_t flags = vp_getVoiceLevelQueueFlags(); vp_init(); vp_clearCurrPrompt();