diff --git a/openrtx/include/core/voicePromptUtils.h b/openrtx/include/core/voicePromptUtils.h index 84eb1a4c..f206bb38 100644 --- a/openrtx/include/core/voicePromptUtils.h +++ b/openrtx/include/core/voicePromptUtils.h @@ -16,7 +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 functions using the building blocks in voicePrompts.h/c. + // 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 @@ -24,9 +25,10 @@ #include "ui/UIStrings.h" #include "cps.h" - void announceChannelName(channel_t* channel, uint16_t channelIndex, VoicePromptQueueFlags_T flags); - void announceFrequencies(freq_t rx, freq_t tx, VoicePromptQueueFlags_T flags); +void announceChannelName(channel_t* channel, uint16_t channelIndex, VoicePromptQueueFlags_T flags); +void announceFrequencies(freq_t rx, freq_t tx, VoicePromptQueueFlags_T flags); void announceRadioMode(uint8_t mode, VoicePromptQueueFlags_T flags); -void vpAnnounceChannelSummary(channel_t* channel, VoicePromptQueueFlags_T flags); +void announceChannelSummary(channel_t* channel, uint16_t channelIndex, +VoicePromptQueueFlags_T flags); #endif //VOICE_PROMPT_UTILS_H_INCLUDED \ No newline at end of file diff --git a/openrtx/include/core/voicePrompts.h b/openrtx/include/core/voicePrompts.h index 3a7e0fcc..5a3d9a33 100644 --- a/openrtx/include/core/voicePrompts.h +++ b/openrtx/include/core/voicePrompts.h @@ -19,12 +19,14 @@ #ifndef voice_prompts_h_included #define voice_prompts_h_included /* -Please note, these prompts represent spoken words or phrases which are not in the UI string table. -For example letters of the alphabet, digits, and descriptive words not displayed in the UI -The voice prompt data file stores these first, then after the data for these prompts, the data for the indexed string table phrases. +Please note, these prompts represent spoken words or phrases which are not in +the UI string table, for example letters of the alphabet, digits, and +descriptive words not displayed in the UI. +The voice prompt data file stores these first, then after the data for these +prompts, the data for the indexed string table phrases. */ -/* Please note! this enum must match the order of prompts defined in the wordlist.csv file -in the voicePrompts generator project. +/* Please note! this enum must match the order of prompts defined in the +wordlist.csv file in the voicePrompts generator project. */ typedef enum { @@ -143,7 +145,8 @@ NUM_VOICE_PROMPTS, __MAKE_ENUM_16BITS = INT16_MAX } voicePrompt_t; -// PROMPT_VOICE_NAME is always the very last prompt after the indexed prompts from the strings table. +// PROMPT_VOICE_NAME is always the very last prompt after the indexed prompts +// from the strings table. #define PROMPT_VOICE_NAME (NUM_VOICE_PROMPTS + (sizeof(stringsTable_t)/sizeof(char*))) typedef enum @@ -170,13 +173,22 @@ extern const uint32_t VOICE_PROMPTS_FLASH_HEADER_ADDRESS; void vpCacheInit(void); // event driven to play a voice prompt in progress. void vpTick(void); - -void vpInit(void);// Call before building the prompt sequence -void vpAppendPrompt(uint16_t prompt);// Append an individual prompt item. This can be a single letter number or a phrase +// Call before building the prompt sequence to clear prompt in progress. +void vpInit(void); +// This function appends an individual prompt item to the prompt queue. +// This can be a single letter, number, or a phrase. +void vpAppendPrompt(uint16_t prompt); +// This function appends the spelling of a complete string to the queue. +// It is used to pronounce strings for which we do not have a recorded voice +//prompt. void vpQueueString(char *promptString, VoicePromptFlags_T flags); -void vpQueueInteger(int32_t value); // Append a signed integer -void vpQueueStringTableEntry(const char * const *);//Append a text string from the current language e.g. currentLanguage->off -void vpQueueFrequency(freq_t freq, bool includeMHz); + // This function appends a signed integer to the queue. +void vpQueueInteger(int32_t value); +// This function appends a text string from the current language to the queue. +// e.g. currentLanguage->off +// These are recorded prompts which correspond to the strings in the strings +// table. +void vpQueueStringTableEntry(const char * const *); void vpPlay(void);// Starts prompt playback extern bool vpIsPlaying(void); diff --git a/openrtx/include/ui/EnglishStrings.h b/openrtx/include/ui/EnglishStrings.h new file mode 100644 index 00000000..94243360 --- /dev/null +++ b/openrtx/include/ui/EnglishStrings.h @@ -0,0 +1,29 @@ +/*************************************************************************** + * Copyright (C) 2022 by Federico Amedeo Izzo IU2NUO, * + * Niccolò Izzo IU2KIN * + * Frederik Saraci IU2NRO * + * Silvano Seva IU2KWO * + * Joseph Stephen VK7JS * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, see * + ***************************************************************************/ +#ifndef EnglishStrings_h_included +#define EnglishStrings_h_included +#include "ui/UIStrings.h" +const stringsTable_t englishStrings = +{ + .languageName="English", + .off = "OFF", + .on="ON", +}; +#endif //EnglishStrings_h_included diff --git a/openrtx/include/ui/UIStrings.h b/openrtx/include/ui/UIStrings.h index 8ad97ea6..a38f567f 100644 --- a/openrtx/include/ui/UIStrings.h +++ b/openrtx/include/ui/UIStrings.h @@ -20,6 +20,8 @@ /* This string table's order must not be altered as voice prompts will be indexed in the same order as these strings. */ +#ifndef UIStrings_h_included +#define UIStrings_h_included #define NUM_LANGUAGES 1 typedef struct @@ -29,13 +31,7 @@ typedef struct const char* on; } stringsTable_t; -const stringsTable_t englishStrings = -{ - .languageName="English", - .off = "OFF", - .on="ON", -}; - -const stringsTable_t languages[NUM_LANGUAGES]={englishStrings}; // add more languages here. -const stringsTable_t* currentLanguage=&languages[0]; // default to English. +extern const stringsTable_t languages[]; +extern const stringsTable_t* currentLanguage; +#endif \ No newline at end of file diff --git a/openrtx/src/core/voicePromptUtils.c b/openrtx/src/core/voicePromptUtils.c index 337d4973..5d76f25f 100644 --- a/openrtx/src/core/voicePromptUtils.c +++ b/openrtx/src/core/voicePromptUtils.c @@ -32,7 +32,22 @@ static void vpPlayIfNeeded(VoicePromptQueueFlags_T flags) vpPlay(); } -void announceChannelName(channel_t* channel, uint16_t channelIndex, VoicePromptQueueFlags_T flags) +static void removeUnnecessaryZerosFromVoicePrompts(char *str) +{ + const int NUM_DECIMAL_PLACES = 1; + int len = strlen(str); + for(int i = len; i > 2; i--) + { + if ((str[i - 1] != '0') || (str[i - (NUM_DECIMAL_PLACES + 1)] == '.')) + { + str[i] = 0; + return; + } + } +} + +void announceChannelName(channel_t* channel, uint16_t channelIndex, +VoicePromptQueueFlags_T flags) { vpInitIfNeeded(flags); @@ -50,18 +65,29 @@ void announceChannelName(channel_t* channel, uint16_t channelIndex, VoicePromptQ vpPlayIfNeeded(flags); } +static void vpQueueFrequency(freq_t freq) +{ + char buffer[10]; + + snprintf(buffer, 10, "%d.%05d", (freq / 1000000), ((freq%1000000)/10)); + removeUnnecessaryZerosFromVoicePrompts(buffer); + + vpQueueString(buffer); + + vpQueuePrompt(PROMPT_MEGAHERTZ); +} + void announceFrequencies(freq_t rx, freq_t tx, VoicePromptQueueFlags_T flags) { vpInitIfNeeded(flags); - // if rx and tx frequencies differ, announce both, otherwise just announce one. if (rx==tx) - announceFrequency(rx); + vpQueueFrequency(rx); else { vpQueuePrompt(PROMPT_RECEIVE); - announceFrequency(rx); + vpQueueFrequency(rx); vpQueuePrompt(PROMPT_TRANSMIT); - announceFrequency(tx); + vpQueueFrequency(tx); } vpPlayIfNeeded(flags); } @@ -89,12 +115,15 @@ void announceRadioMode(uint8_t mode, VoicePromptQueueFlags_T flags) vpPlayIfNeeded(flags); } -void vpAnnounceChannelSummary(channel_t* channel, uint16_t channelIndex, bool init, VoicePromptQueueFlags_T flags) +void vpAnnounceChannelSummary(channel_t* channel, uint16_t channelIndex, +VoicePromptQueueFlags_T flags) { if (!channel) return; - vpInitIfNeeded(flags); - VoicePromptQueueFlags_T localFlags=flags&vpqIncludeDescriptions; // mask off init and play because this function will handle init and play. + vpInitIfNeeded(flags); + + // mask off init and play because this function will handle init and play. + VoicePromptQueueFlags_T localFlags=flags&vpqIncludeDescriptions; announceChannelName(channel, channelIndex, localFlags); announceFrequencies(channel->rx_frequency , channel->tx_frequency, localFlags); @@ -102,4 +131,4 @@ void vpAnnounceChannelSummary(channel_t* channel, uint16_t channelIndex, bool in vpPlayIfNeeded(flags); } - \ No newline at end of file + diff --git a/openrtx/src/core/voicePrompts.c b/openrtx/src/core/voicePrompts.c index eb206b42..e8410e10 100644 --- a/openrtx/src/core/voicePrompts.c +++ b/openrtx/src/core/voicePrompts.c @@ -22,32 +22,38 @@ #include "ui/UIStrings.h" const uint32_t VOICE_PROMPTS_DATA_MAGIC = 0x5056;//'VP' const uint32_t VOICE_PROMPTS_DATA_VERSION = 0x1000; // v1000 OpenRTX +// Must match the number of voice prompts allowed by the generator script. #define VOICE_PROMPTS_TOC_SIZE 350 -static void getM17Data(int offset,int length); +// This gets the data for a voice prompt to be demodulated using Codec2. +// The offset is relative to the start of the voice prompt data. +// The length is the length in bytes of the data. +static void GetCodec2Data(int offset,int length); typedef struct { uint32_t magic; uint32_t version; } voicePromptsDataHeader_t; - - - -const uint32_t VOICE_PROMPTS_FLASH_HEADER_ADDRESS = 0x8F400; // todo figure this out for OpenRTX +// ToDo: may be a file on flashdisk. +// ToDo figure this out for OpenRTX +// Address of voice prompt header for checking version etc. +const uint32_t VOICE_PROMPTS_FLASH_HEADER_ADDRESS = 0x8F400; +// Start of actual voice prompt data. static uint32_t vpFlashDataAddress;// = VOICE_PROMPTS_FLASH_HEADER_ADDRESS + sizeof(voicePromptsDataHeader_t) + sizeof(uint32_t)*VOICE_PROMPTS_TOC_SIZE ; -// TODO figure out M17 frame equivalent. -// 76 x 27 byte ambe frames -#define M17_DATA_BUFFER_SIZE 2052 +// TODO figure out Codec2 frame equivalent. +// 76 x 27 byte Codec2 frames +#define Codec2DataBufferSize 2052 bool voicePromptDataIsLoaded = false; static bool voicePromptIsActive = false; +// Uninitialized is -1. static int promptDataPosition = -1; static int currentPromptLength = -1; - +// Number of ms from end of playing prompt to disabling amp. #define PROMPT_TAIL 30 static int promptTail = 0; -static uint8_t M17Data[M17_DATA_BUFFER_SIZE]; +static uint8_t Codec2Data[Codec2DataBufferSize]; #define VOICE_PROMPTS_SEQUENCE_BUFFER_SIZE 128 @@ -70,11 +76,11 @@ uint32_t tableOfContents[VOICE_PROMPTS_TOC_SIZE]; void vpCacheInit(void) { voicePromptsDataHeader_t header; - - SPI_Flash_read(VOICE_PROMPTS_FLASH_HEADER_ADDRESS,(uint8_t *)&header,sizeof(voicePromptsDataHeader_t)); +// ToDo not sure where this is coming from yet. + //SPI_Flash_read(VOICE_PROMPTS_FLASH_HEADER_ADDRESS,(uint8_t *)&header,sizeof(voicePromptsDataHeader_t)); if (vpCheckHeader((uint32_t *)&header)) - { + {// ToDo see above voicePromptDataIsLoaded = SPI_Flash_read(VOICE_PROMPTS_FLASH_HEADER_ADDRESS + sizeof(voicePromptsDataHeader_t), (uint8_t *)&tableOfContents, sizeof(uint32_t) * VOICE_PROMPTS_TOC_SIZE); vpFlashDataAddress = VOICE_PROMPTS_FLASH_HEADER_ADDRESS + sizeof(voicePromptsDataHeader_t) + sizeof(uint32_t)*VOICE_PROMPTS_TOC_SIZE ; } @@ -88,11 +94,11 @@ bool vpCheckHeader(uint32_t *bufferAddress) return ((header->magic == VOICE_PROMPTS_DATA_MAGIC) && (header->version == VOICE_PROMPTS_DATA_VERSION)); } -static void getM17Data(int offset,int length) +static void GetCodec2Data(int offset,int length) { - if (length <= M17_DATA_BUFFER_SIZE) - { - SPI_Flash_read(vpFlashDataAddress + offset, (uint8_t *)&M17Data, length); + if (length <= Codec2DataBufferSize) + {// ToDo where are we reading this from? + SPI_Flash_read(vpFlashDataAddress + offset, (uint8_t *)&Codec2Data, length); } } @@ -101,10 +107,10 @@ void vpTick(void) if (voicePromptIsActive) { if (promptDataPosition < currentPromptLength) - { + {// ToDo figure out buffering. //if (wavbuffer_count <= (WAV_BUFFER_COUNT / 2)) { -// codecDecode((uint8_t *)&M17Data[promptDataPosition], 3); +// codecDecode((uint8_t *)&Codec2Data[promptDataPosition], 3); promptDataPosition += 27; } @@ -119,7 +125,7 @@ void vpTick(void) int promptNumber = vpCurrentSequence.Buffer[vpCurrentSequence.Pos]; currentPromptLength = tableOfContents[promptNumber + 1] - tableOfContents[promptNumber]; - getM17Data(tableOfContents[promptNumber], currentPromptLength); + GetCodec2Data(tableOfContents[promptNumber], currentPromptLength); } else { @@ -139,7 +145,7 @@ void vpTick(void) promptTail--; if ((promptTail == 0) && trxCarrierDetected() && (trxGetMode() == RADIO_MODE_ANALOG)) - { + {// ToDo disable amp. //GPIO_PinWrite(GPIO_RX_audio_mux, Pin_RX_audio_mux, 1); // Set the audio path to AT1846 -> audio amp. } } @@ -185,7 +191,8 @@ void vpQueuePrompt(uint16_t prompt) } } -static bool GetSymbolVPIfItShouldBeAnnounced(char symbol, VoicePromptFlags_T flags, voicePrompt_t* vp) +static bool GetSymbolVPIfItShouldBeAnnounced(char symbol, +VoicePromptFlags_T flags, voicePrompt_t* vp) { *vp=PROMPT_SILENCE; @@ -274,7 +281,8 @@ void vpQueueInteger(int32_t value) } // This function looks up a voice prompt corresponding to a string table entry. -// These are stored in the voice data after the voice prompts with no corresponding string table entry, hence the offset calculation: +// These are stored in the voice data after the voice prompts with no +// corresponding string table entry, hence the offset calculation: // NUM_VOICE_PROMPTS + (stringTableStringPtr - currentLanguage->languageName) void vpQueueStringTableEntry(const char * const *stringTableStringPtr) { @@ -295,7 +303,7 @@ void vpPlay(void) vpCurrentSequence.Pos = 0; currentPromptLength = tableOfContents[promptNumber + 1] - tableOfContents[promptNumber]; - getM17Data(tableOfContents[promptNumber], currentPromptLength); + GetCodec2Data(tableOfContents[promptNumber], currentPromptLength); // GPIO_PinWrite(GPIO_RX_audio_mux, Pin_RX_audio_mux, 0);// set the audio mux HR-C6000 -> audio amp //enableAudioAmp(AUDIO_AMP_MODE_PROMPT); @@ -315,33 +323,3 @@ bool vpHasDataToPlay(void) { return (vpCurrentSequence.Length > 0); } - -static void removeUnnecessaryZerosFromVoicePrompts(char *str) -{ - const int NUM_DECIMAL_PLACES = 1; - int len = strlen(str); - for(int i = len; i > 2; i--) - { - if ((str[i - 1] != '0') || (str[i - (NUM_DECIMAL_PLACES + 1)] == '.')) - { - str[i] = 0; - return; - } - } -} - -void vpQueueFrequency(freq_t freq, bool includeMHz) -{ - char buffer[10]; - - snprintf(buffer, 10, "%d.%05d", (freq / 1000000), ((freq%1000000)/10)); - removeUnnecessaryZerosFromVoicePrompts(buffer); - - vpQueueString(buffer); - - if (includeMHz) - { - vpQueuePrompt(PROMPT_MEGAHERTZ); - } -} - diff --git a/openrtx/src/ui/UIStrings.c b/openrtx/src/ui/UIStrings.c new file mode 100644 index 00000000..f0037743 --- /dev/null +++ b/openrtx/src/ui/UIStrings.c @@ -0,0 +1,30 @@ +/*************************************************************************** + * Copyright (C) 2022 by Federico Amedeo Izzo IU2NUO, * + * Niccolò Izzo IU2KIN * + * Frederik Saraci IU2NRO * + * Silvano Seva IU2KWO * + * Joseph Stephen VK7JS * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, see * + ***************************************************************************/ +/* +This string table's order must not be altered as voice prompts will be indexed in the same order as these strings. +*/ +#include "ui/UIStrings.h" + #include "ui/EnglishStrings.h" + + // add more languages here. + const stringsTable_t languages[NUM_LANGUAGES]={ englishStrings }; + // default to English. + const stringsTable_t* currentLanguage=&languages[0]; +