kopia lustrzana https://github.com/OpenRTX/OpenRTX
Adding voice prompts skeleton.
rodzic
7e660f2fe8
commit
d5568b8ab3
|
@ -0,0 +1,172 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2022 by Federico Amedeo Izzo IU2NUO, *
|
||||
* Niccolò Izzo IU2KIN, *
|
||||
* 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 <http://www.gnu.org/licenses/> *
|
||||
***************************************************************************/
|
||||
#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! this enum must match the order of prompts defined in the wordlist.csv file
|
||||
in the voicePrompts generator project.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
PROMPT_SILENCE, //
|
||||
PROMPT_POINT, // POINT
|
||||
PROMPT_0, // 0
|
||||
PROMPT_1, // 1
|
||||
PROMPT_2, // 2
|
||||
PROMPT_3, // 3
|
||||
PROMPT_4, // 4
|
||||
PROMPT_5, // 5
|
||||
PROMPT_6, // 6
|
||||
PROMPT_7, // 7
|
||||
PROMPT_8, // 8
|
||||
PROMPT_9, // 9
|
||||
PROMPT_A, // A
|
||||
PROMPT_B, // B
|
||||
PROMPT_C, // C
|
||||
PROMPT_D, // D
|
||||
PROMPT_E, // E
|
||||
PROMPT_F, // F
|
||||
PROMPT_G, // G
|
||||
PROMPT_H, // H
|
||||
PROMPT_I, // I
|
||||
PROMPT_J, // J
|
||||
PROMPT_K, // K
|
||||
PROMPT_L, // L
|
||||
PROMPT_M, // M
|
||||
PROMPT_N, // N
|
||||
PROMPT_O, // O
|
||||
PROMPT_P, // P
|
||||
PROMPT_Q, // Q
|
||||
PROMPT_R, // R
|
||||
PROMPT_S, // S
|
||||
PROMPT_T, // T
|
||||
PROMPT_U, // U
|
||||
PROMPT_V, // V
|
||||
PROMPT_W, // W
|
||||
PROMPT_X, // X
|
||||
PROMPT_Y, // Y
|
||||
PROMPT_Z, // Zed
|
||||
PROMPT_A_PHONETIC, // alpha
|
||||
PROMPT_B_PHONETIC, // bravo
|
||||
PROMPT_C_PHONETIC, // charlie
|
||||
PROMPT_D_PHONETIC, // delta
|
||||
PROMPT_E_PHONETIC, // echo
|
||||
PROMPT_F_PHONETIC, // foxtrot
|
||||
PROMPT_G_PHONETIC, // golf
|
||||
PROMPT_H_PHONETIC, // hotel
|
||||
PROMPT_I_PHONETIC, // india
|
||||
PROMPT_J_PHONETIC, // juliet
|
||||
PROMPT_K_PHONETIC, // kilo
|
||||
PROMPT_L_PHONETIC, // lema
|
||||
PROMPT_M_PHONETIC, // mike
|
||||
PROMPT_N_PHONETIC, // november
|
||||
PROMPT_O_PHONETIC, // oscar
|
||||
PROMPT_P_PHONETIC, // papa
|
||||
PROMPT_Q_PHONETIC, // quebec
|
||||
PROMPT_R_PHONETIC, // romeo
|
||||
PROMPT_S_PHONETIC, // siera
|
||||
PROMPT_T_PHONETIC, // tango
|
||||
PROMPT_U_PHONETIC, // uniform
|
||||
PROMPT_V_PHONETIC, // victor
|
||||
PROMPT_W_PHONETIC, // whisky
|
||||
PROMPT_X_PHONETIC, // exray
|
||||
PROMPT_Y_PHONETIC, // yankie
|
||||
PROMPT_Z_PHONETIC, // zulu
|
||||
PROMPT_CAP, // cap
|
||||
PROMPT_HERTZ, // hertz
|
||||
PROMPT_KILOHERTZ, // Kilohertz
|
||||
PROMPT_MEGAHERTZ, // Megahertz
|
||||
PROMPT_VFO, // V F O
|
||||
PROMPT_MILLISECONDS, // Milliseconds
|
||||
PROMPT_SECONDS, // Seconds
|
||||
PROMPT_MINUTES, // Minutes
|
||||
PROMPT_VOLTS, // Volts
|
||||
PROMPT_MILLIWATTS, // Milliwatts
|
||||
PROMPT_WATT, // Wattt
|
||||
PROMPT_WATTS, // Watts
|
||||
PROMPT_PERCENT, // Percent
|
||||
PROMPT_RECEIVE, // Receive
|
||||
PROMPT_TRANSMIT, // Transmit
|
||||
PROMPT_MODE, // Mode
|
||||
PROMPT_DMR, // D M R
|
||||
PROMPT_FM, // F M
|
||||
PROMPT_M17, // M seventeen
|
||||
PROMPT_PLUS, // Plus
|
||||
PROMPT_MINUS, // Minus
|
||||
PROMPT_STAR, // Star
|
||||
PROMPT_HASH, // Hash
|
||||
PROMPT_SPACE, // space
|
||||
PROMPT_EXCLAIM, // exclaim
|
||||
PROMPT_COMMA, // comma
|
||||
PROMPT_AT, // at
|
||||
PROMPT_COLON, // colon
|
||||
PROMPT_QUESTION, // question
|
||||
PROMPT_LEFT_PAREN, // left paren
|
||||
PROMPT_RIGHT_PAREN, // right paren
|
||||
PROMPT_TILDE, // tilde
|
||||
PROMPT_SLASH, // slash
|
||||
PROMPT_LEFT_BRACKET, // left bracket
|
||||
PROMPT_RIGHT_BRACKET, // right bracket
|
||||
PROMPT_LESS, // less
|
||||
PROMPT_GREATER, // greater
|
||||
PROMPT_EQUALS, // equals
|
||||
PROMPT_DOLLAR, // dollar
|
||||
PROMPT_APOSTROPHE, // apostrophe
|
||||
PROMPT_GRAVE, // grave
|
||||
PROMPT_AMPERSAND, // and
|
||||
PROMPT_BAR, // bar
|
||||
PROMPT_UNDERLINE, // underline
|
||||
PROMPT_CARET, // caret
|
||||
PROMPT_LEFT_BRACE, // left brace
|
||||
NUM_VOICE_PROMPTS,
|
||||
__MAKE_ENUM_16BITS = INT16_MAX
|
||||
} voicePrompt_t;
|
||||
|
||||
#define PROMPT_VOICE_NAME (NUM_VOICE_PROMPTS + (sizeof(stringsTable_t)/sizeof(char*)))
|
||||
typedef enum
|
||||
{
|
||||
vpAnnounceCaps=0x01,
|
||||
vpAnnounceCustomPrompts=0x02,
|
||||
vpAnnounceSpaceAndSymbols=0x04,
|
||||
vpAnnouncePhoneticRendering=0x08,
|
||||
} VoicePromptFlags_T;
|
||||
|
||||
extern bool voicePromptDataIsLoaded;
|
||||
extern const uint32_t VOICE_PROMPTS_FLASH_HEADER_ADDRESS;
|
||||
// Loads just the TOC from Flash and stores in RAM for fast access.
|
||||
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
|
||||
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 vpPlay(void);// Starts prompt playback
|
||||
extern bool vpIsPlaying(void);
|
||||
bool vpHasDataToPlay(void);
|
||||
void vpTerminate(void);
|
||||
bool vpCheckHeader(uint32_t *bufferAddress);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,318 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2022 by Federico Amedeo Izzo IU2NUO, *
|
||||
* Niccolò Izzo IU2KIN, *
|
||||
* Silvano Seva IU2KWO *
|
||||
* Joseph Stephen VK7JS *
|
||||
* Roger Clark VK3KYY *
|
||||
* 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 <http://www.gnu.org/licenses/> *
|
||||
***************************************************************************/
|
||||
#include <ctype.h>
|
||||
#include "core/voicePrompts.h"
|
||||
#include "ui/UIStrings.h"
|
||||
const uint32_t VOICE_PROMPTS_DATA_MAGIC = 0x5056;//'VP'
|
||||
const uint32_t VOICE_PROMPTS_DATA_VERSION = 0x1000; // v1000 OpenRTX
|
||||
#define VOICE_PROMPTS_TOC_SIZE 350
|
||||
static void getM17Data(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
|
||||
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
|
||||
|
||||
bool voicePromptDataIsLoaded = false;
|
||||
static bool voicePromptIsActive = false;
|
||||
static int promptDataPosition = -1;
|
||||
static int currentPromptLength = -1;
|
||||
|
||||
#define PROMPT_TAIL 30
|
||||
static int promptTail = 0;
|
||||
|
||||
static uint8_t M17Data[M17_DATA_BUFFER_SIZE];
|
||||
|
||||
#define VOICE_PROMPTS_SEQUENCE_BUFFER_SIZE 128
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t Buffer[VOICE_PROMPTS_SEQUENCE_BUFFER_SIZE];
|
||||
int Pos;
|
||||
int Length;
|
||||
} vpSequence_t;
|
||||
|
||||
static vpSequence_t vpCurrentSequence =
|
||||
{
|
||||
.Pos = 0,
|
||||
.Length = 0
|
||||
};
|
||||
|
||||
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));
|
||||
|
||||
if (vpCheckHeader((uint32_t *)&header))
|
||||
{
|
||||
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 ;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool vpCheckHeader(uint32_t *bufferAddress)
|
||||
{
|
||||
voicePromptsDataHeader_t *header = (voicePromptsDataHeader_t *)bufferAddress;
|
||||
|
||||
return ((header->magic == VOICE_PROMPTS_DATA_MAGIC) && (header->version == VOICE_PROMPTS_DATA_VERSION));
|
||||
}
|
||||
|
||||
static void getM17Data(int offset,int length)
|
||||
{
|
||||
if (length <= M17_DATA_BUFFER_SIZE)
|
||||
{
|
||||
SPI_Flash_read(vpFlashDataAddress + offset, (uint8_t *)&M17Data, length);
|
||||
}
|
||||
}
|
||||
|
||||
void vpTick(void)
|
||||
{
|
||||
if (voicePromptIsActive)
|
||||
{
|
||||
if (promptDataPosition < currentPromptLength)
|
||||
{
|
||||
//if (wavbuffer_count <= (WAV_BUFFER_COUNT / 2))
|
||||
{
|
||||
// codecDecode((uint8_t *)&M17Data[promptDataPosition], 3);
|
||||
promptDataPosition += 27;
|
||||
}
|
||||
|
||||
//soundTickRXBuffer();
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( vpCurrentSequence.Pos < (vpCurrentSequence.Length - 1))
|
||||
{
|
||||
vpCurrentSequence.Pos++;
|
||||
promptDataPosition = 0;
|
||||
|
||||
int promptNumber = vpCurrentSequence.Buffer[vpCurrentSequence.Pos];
|
||||
currentPromptLength = tableOfContents[promptNumber + 1] - tableOfContents[promptNumber];
|
||||
getM17Data(tableOfContents[promptNumber], currentPromptLength);
|
||||
}
|
||||
else
|
||||
{
|
||||
// wait for wave buffer to empty when prompt has finished playing
|
||||
|
||||
// if (wavbuffer_count == 0)
|
||||
{
|
||||
vpTerminate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (promptTail > 0)
|
||||
{
|
||||
promptTail--;
|
||||
|
||||
if ((promptTail == 0) && trxCarrierDetected() && (trxGetMode() == RADIO_MODE_ANALOG))
|
||||
{
|
||||
//GPIO_PinWrite(GPIO_RX_audio_mux, Pin_RX_audio_mux, 1); // Set the audio path to AT1846 -> audio amp.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void vpTerminate(void)
|
||||
{
|
||||
if (voicePromptIsActive)
|
||||
{
|
||||
//disableAudioAmp(AUDIO_AMP_MODE_PROMPT);
|
||||
|
||||
vpCurrentSequence.Pos = 0;
|
||||
//soundTerminateSound();
|
||||
//soundInit();
|
||||
promptTail = PROMPT_TAIL;
|
||||
|
||||
voicePromptIsActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
void vpInit(void)
|
||||
{
|
||||
if (voicePromptIsActive)
|
||||
{
|
||||
vpTerminate();
|
||||
}
|
||||
|
||||
vpCurrentSequence.Length = 0;
|
||||
vpCurrentSequence.Pos = 0;
|
||||
}
|
||||
|
||||
void vpQueuePrompt(uint16_t prompt)
|
||||
{
|
||||
if (voicePromptIsActive)
|
||||
{
|
||||
vpInit();
|
||||
}
|
||||
if (vpCurrentSequence.Length < VOICE_PROMPTS_SEQUENCE_BUFFER_SIZE)
|
||||
{
|
||||
vpCurrentSequence.Buffer[vpCurrentSequence.Length] = prompt;
|
||||
vpCurrentSequence.Length++;
|
||||
}
|
||||
}
|
||||
|
||||
// This function spells out a string letter by letter.
|
||||
void vpQueueString(char *promptString, VoicePromptFlags_T flags)
|
||||
{
|
||||
const char indexedSymbols[] = "!,@:?()~/[]<>=$'`&|_^{}"; // handles most of them in indexed order, must match order of vps.
|
||||
if (voicePromptIsActive)
|
||||
{
|
||||
vpInit();
|
||||
}
|
||||
while (*promptString != 0)
|
||||
{
|
||||
if ((*promptString >= '0') && (*promptString <= '9'))
|
||||
{
|
||||
vpQueuePrompt(*promptString - '0' + PROMPT_0);
|
||||
}
|
||||
else if ((*promptString >= 'A') && (*promptString <= 'Z'))
|
||||
{
|
||||
if (flags&vpAnnounceCaps)
|
||||
vpQueuePrompt(PROMPT_CAP);
|
||||
if (flags&vpAnnouncePhoneticRendering)
|
||||
vpQueuePrompt((*promptString - 'A') + PROMPT_A_PHONETIC);
|
||||
else
|
||||
vpQueuePrompt(*promptString - 'A' + PROMPT_A);
|
||||
}
|
||||
else if ((*promptString >= 'a') && (*promptString <= 'z'))
|
||||
{
|
||||
if (flags&vpAnnouncePhoneticRendering)
|
||||
vpQueuePrompt((*promptString - 'a') + PROMPT_A_PHONETIC);
|
||||
else
|
||||
vpQueuePrompt(*promptString - 'a' + PROMPT_A);
|
||||
}
|
||||
else if (*promptString == '.')
|
||||
{
|
||||
vpQueuePrompt(PROMPT_POINT);
|
||||
}
|
||||
else if (*promptString == '+')
|
||||
{
|
||||
vpQueuePrompt(PROMPT_PLUS);
|
||||
}
|
||||
else if (*promptString == '-')
|
||||
{
|
||||
vpQueuePrompt(PROMPT_MINUS);
|
||||
}
|
||||
else if (*promptString == '%')
|
||||
{
|
||||
vpQueuePrompt(PROMPT_PERCENT);
|
||||
}
|
||||
else if (*promptString == '*')
|
||||
{
|
||||
vpQueuePrompt(PROMPT_STAR);
|
||||
}
|
||||
else if (*promptString == '#')
|
||||
{
|
||||
vpQueuePrompt(PROMPT_HASH);
|
||||
}
|
||||
else if (flags&(vpAnnounceSpaceAndSymbols))
|
||||
{
|
||||
if (*promptString==' ')
|
||||
vpQueuePrompt(PROMPT_SPACE);
|
||||
else
|
||||
{
|
||||
char* ptr=strchr(indexedSymbols, *promptString);
|
||||
if (ptr)
|
||||
{
|
||||
vpQueuePrompt(PROMPT_EXCLAIM+(ptr-indexedSymbols));
|
||||
}
|
||||
else
|
||||
{
|
||||
int32_t val = *promptString;
|
||||
vpQueueLanguageString(¤tLanguage->dtmf_code); // just the word "code" as we don't have character.
|
||||
vpQueueInteger(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
// otherwise just add silence
|
||||
vpQueuePrompt(PROMPT_SILENCE);
|
||||
|
||||
promptString++;
|
||||
}
|
||||
}
|
||||
|
||||
void vpQueueInteger(int32_t value)
|
||||
{
|
||||
char buf[12] = {0}; // min: -2147483648, max: 2147483647
|
||||
itoa(value, buf, 10);
|
||||
vpQueueString(buf, 0);
|
||||
}
|
||||
|
||||
// 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:
|
||||
// NUM_VOICE_PROMPTS + (stringTableStringPtr - currentLanguage->languageName)
|
||||
void vpQueueStringTableEntry(const char * const *stringTableStringPtr)
|
||||
{
|
||||
if (stringTableStringPtr == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
vpQueuePrompt(NUM_VOICE_PROMPTS + (stringTableStringPtr - currentLanguage->languageName));
|
||||
}
|
||||
|
||||
void vpPlay(void)
|
||||
{
|
||||
if ((voicePromptIsActive == false) && (vpCurrentSequence.Length > 0))
|
||||
{
|
||||
voicePromptIsActive = true;// Start the playback
|
||||
int promptNumber = vpCurrentSequence.Buffer[0];
|
||||
|
||||
vpCurrentSequence.Pos = 0;
|
||||
|
||||
currentPromptLength = tableOfContents[promptNumber + 1] - tableOfContents[promptNumber];
|
||||
getM17Data(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);
|
||||
|
||||
//codecInit(true);
|
||||
promptDataPosition = 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
inline bool vpIsPlaying(void)
|
||||
{
|
||||
return (voicePromptIsActive || (promptTail > 0));
|
||||
}
|
||||
|
||||
bool vpHasDataToPlay(void)
|
||||
{
|
||||
return (vpCurrentSequence.Length > 0);
|
||||
}
|
||||
|
|
@ -28,7 +28,7 @@
|
|||
#include <interfaces/platform.h>
|
||||
#include <interfaces/delays.h>
|
||||
#include <memory_profiling.h>
|
||||
#include <ui/uiStrings.h>
|
||||
#include <ui/UIStrings.h>
|
||||
|
||||
/* UI main screen helper functions, their implementation is in "ui_main.c" */
|
||||
extern void _ui_drawMainBottom();
|
||||
|
|
Ładowanie…
Reference in New Issue