//FM Radio with Audio Assist for the Visually Impaired V2.0
//Developed by Simon Carter
//January 23, 2026

#include <SoftwareSerial.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,16,2); 
#include <TEA5767.h>
#include <tea5767_core.h>
#include <Wire.h>
#include <EEPROM.h>

SoftwareSerial mySerial(4, 5); // RX pin, TX pin. Set up soft serial pins for communicating with SYN6988


unsigned long timeout = 600000;
volatile byte state = LOW;

int aState;                 //State of the first encoder switch contact
int bState;                 //State of the second encoder switch contact
int dig1;                   //First digit of the frequency value (MSB)
int dig2;                   //Second digit of the frequency value
int dig3;                   //Third digit of the frequency value
int dig4;                   //Fourth digit of the frequency value
int dig5;                   //Fifth digit of the frequency value
int n = 0;                  //General purpose counter
int i = 0;                  //General purpose counter
int z = 0;                  //General purpose variable used for announcements
int c = 0;                  //General purpose variable used as a flag
int BV;                     //General purpose variable used to store battery voltage value
int MS = 1;                 //General purpose variable used to indicate loudspeaker mute status
int EE = 0;                 //Variable not used, on standby if needed.
char x = 0;                 //General purpose variable used in the announcement
String k;                   //General purpose variable used in the announcement
volatile float frequency = 97.10;    //The radio frequency value
int Rfreq = 0;              //Variable used to round the frequency value
int freq;                   //Variable used to round the frequency value
float freq_ref = 0.0;       //Variable used to represent frequency when writing and reading to and from memory
float frq = 100.0;          //Variable used to represent frequency when writing and reading to and from memory
float epsilon = 0.15;       //Variable not used, on standby if needed.
int lvl = 0;                //Variable used for the receive level reported by the radio module
volatile int Announce_SW = 2;        //The button used for frequency announcement
int Rot_Enc_SW = 3;         //The rotary encoder button
int Mute_Speaker = 6;       //The pin that controls the transistor used to power up/down the audio amplifier
int outputA = 8;            //The pin connected to the A contact on the encoder switch
int outputB = 7;            //The pin connected to the B contact on the encoder switch
int f1_SW = 9;              //The pin connected to the button used for the first pre-set frequency
int f2_SW = 10;             //The pin connected to the button used for the second pre-set frequency
int f3_SW = 11;             //The pin connected to the button used for the third pre-set frequency
int USBC = 12;              //Connected to USBC +5V input pin on the battery charging module
int Mute_SW = 13;           //The pin connected to the button used to mute/unmute the speaker
int Switch_State_f1 = 0;    //State of the first pre-set frequency button
int Switch_State_f2 = 0;    //State of the second pre-set frequency button
int Switch_State_f3 = 0;    //State of the third pre-set frequency button
int Switch_State_Announce;  //State of the announce frequency button
int Switch_State_Rot_Enc = 0; //State of the rotary encoder switch button
int EEgg_Announce = 0;
int IMode_Announce = 0;
int USBC_State = 0;         //State of USBC +5V input
int USBC_Flag = 0;          //Flag used to control USB-C related announcements
int Mute_SW_State = 0;      //State of the mute button
unsigned long StartTime = 0;//Variable used to record the instantaneous UProcessor millis() time
int info;
int signal_level;
float BattVolts = 0.00;     //Variable used to store measured battery voltage value
float LogicVolts = 0.00;    //Variable used to store measured logic voltage (+5V) value
int ext = 0;                //Flag used to control exit from radio information mode

//The following are text of radio announcement statements, radio information etc stored in program memory
const char string_0[] PROGMEM = "[t3][s1][v10]Power";
const char string_1[] PROGMEM = "[t3][s1][v10]On";
const char string_2[] PROGMEM = "[t3][s5][v10]Welcome to the FM Radio with audio assist";
const char string_3[] PROGMEM = "[t3][s5][v10]The Battery level is low, please plug in the USB C cable to charge it";
const char string_4[] PROGMEM = "[t3][s5][v10]The Radio is tuning to preset frequency number one. Please enjoy. Radio on.";

const char string_5[] PROGMEM = "[t3][s5][v10]The USB C power cable is not presently connected. The Radio is running on battery only. Battery level normal.";
const char string_6[] PROGMEM = "[t3][s5][v10]The USB C power cable is connected. The Battery is charging.";
const char string_7[] PROGMEM = "[t3][s5][v10]Congratulations, you have found the Easter eggs. Would you like to hear some jokes? If yes, just wait a moment while I access my memory.";
const char string_8[] PROGMEM = "[t3][s5][v10]Exiting Easter Egg mode. Returning to Radio mode.";
const char string_9[] PROGMEM = "[t3][s5][v10]Congratulations, you have found the radio instruction section. The following gives directions on how to use this radio.";
const char string_10[] PROGMEM = "[t3][s5][v10]Exiting radio instruction mode. Returning to Radio mode.";
const char string_11[] PROGMEM = "[t3][s5][v10]To exit, just press and hold the announce button until you hear a tone or beep, then you will hear the exit announcement shortly after. Exit may take several seconds while the microprocessor waits for the current dialog to end.";
const char string_12[] PROGMEM = "[t3][s5][v10]USB C power cable is connected.";
const char string_13[] PROGMEM = "[t3][s5][v10]USB C power cable is disconnected.";

const char string_14[] PROGMEM = "[t3][s5][v10]This radio is an FM only radio capable of receiving FM channels between 88 and 108 megahertz. It has audio prompts to assist you. First let's discuss the controls. Place the radio in front of you,";
const char string_15[] PROGMEM = "[t3][s5][v10]Starting on the left side, at the bottom is the USB C power connector for charging the battery. Above that, is the three point five millimeter head phone jack, and next to it is the loud speaker mute button.";
const char string_16[] PROGMEM = "[t3][s5][v10]if you press the mute button, the loud speaker will be silenced but you will still receive audio through the head phone jack. Just press the mute button again to restore sound to the loud speaker.";
const char string_17[] PROGMEM = "[t3][s5][v10]On the top of the radio starting at the left side, the first button is the announce or talk button. Press this button moment arily to hear what frequency you are currently on.";
const char string_18[] PROGMEM = "[t3][s5][v10]Moving to the right, there are three buttons grouped together. These are the radio channel preset buttons. To use these, first tune the radio to a frequency that you want to save.";
const char string_19[] PROGMEM = "[t3][s5][v10]Then Press and hold a preset button for more than three seconds. Next release the button and the radio will tell you if the button has been programmed. Now whenever you press that button moment arily,";
const char string_20[] PROGMEM = "[t3][s5][v10]the radio will go to that frequency. The button on the left side of the group is the first preset button. The radio will automatically go to this preset frequency when you turn on the radio.";
const char string_21[] PROGMEM = "[t3][s5][v10]So program your favourite station into this button. You can reprogram these buttons repeatedly anytime you like. Moving further to the right there are two knobs. The first knob is for the radio volume";
const char string_22[] PROGMEM = "[t3][s5][v10]this controls the volume in both the speaker and the earphone. The next knob is the tuning knob, it is a rotary knob that controls the radio frequency. Each incremental turn of this knob in a clockwise direction ";
const char string_23[] PROGMEM = "[t3][s5][v10]will increase the radio frequency by one hundred kilo hertz. Each incremental turn of this knob in an anti clockwise direction will decrease the radio frequency by one hundred kilo hertz.";
const char string_24[] PROGMEM = "[t3][s5][v10]With each turn of this knob you will hear a pip sound. A higher frequency pip indicates an increase in radio frequenc,y and a lower frequency pip indicates a decrease in radio frequency.";
const char string_25[] PROGMEM = "[t3][s5][v10]You may turn this knob infinitely; the radio will always stay in the FM band. When you tune the radio to the end of the band it will automatically roll over to the other end of the band. ";
const char string_26[] PROGMEM = "[t3][s5][v10]For example, if you tune the radio past 108 mega hertz, it will automatically go to 88 mega hertz, and vice-versa. This rotary knob also contains a button, press down on this knob to activate the button.";
const char string_27[] PROGMEM = "[t3][s5][v10]A moment ary press will tell you what frequency you are currently on. This is the same function as the announce or talk button in case you prefer to use this method.";
const char string_28[] PROGMEM = "[t3][s5][v10]If you press and hold this button for more than three seconds, you will get an update on the radio USB C connection and the battery level.";
const char string_29[] PROGMEM = "[t3][s5][v10]If you first tune the radio to 107 mega hertz and then press and hold this button, you will also access the radio instruction mode which will read out the radio operating instructions.";
const char string_30[] PROGMEM = "[t3][s5][v10]If you first tune the radio to 108 mega hertz and then press and hold this button, you will also access the radio easter egg mode which will tell you some jokes.";
const char string_31[] PROGMEM = "[t3][s5][v10]On the right side of the radio at the top is the antenna. This is a 1.5 meter length of wire. Stretch out this wire either horizontally or vertically for better reception.";
const char string_32[] PROGMEM = "[t3][s5][v10]Below this is the radio power switch. This is a rock er switch. If the USB C cable is plugged in, the radio battery will charge regard less of the whether this switch is on or off.";
const char string_33[] PROGMEM = "[t3][s5][v10]Now let me tell you about the radio battery. The radio contains two, 3.7 volt, 18650 form factor, button top, 3300 milli amp hour lithium ion batteries.";
const char string_34[] PROGMEM = "[t3][s5][v10]These are extremely powerful batteries which contains a lot of energy. As such, you can expect that the radio will run continuously for approximately 30 hours or more on one charge when the batteries are new.";
const char string_35[] PROGMEM = "[t3][s5][v10]These batteries have a lifetime of approximately 300 to 500 charges. Charging will take about 4 to 6 hours. The batteries will last longer if you charge up the batteries ";
const char string_36[] PROGMEM = "[t3][s5][v10]and then unplug the USB C cable until the next time they need to be charged. The radio will tell you when to charge the batteries. The nominal battery voltage is 7.4 volts.";
const char string_37[] PROGMEM = "[t3][s5][v10]When fully charged the battery level will be at between approximately 7.9 and 8 volts. When the battery level is below 6.2 volts charging is required. The batteries and the charger circuit have several protection mechanisms";
const char string_38[] PROGMEM = "[t3][s5][v10]such as short circuit, over voltage, over charging and over temperature protection. That said, lithium ion batteries must be treated with respect.";
const char string_39[] PROGMEM = "[t3][s5][v10]As with any lithium ion batteries, you should never leave the batteries charging unattended. The radio should not be operated with the batteries removed; it is not designed to operate without the batteries";
const char string_40[] PROGMEM = "[t3][s5][v10]on USB power only. If you need to replace the batteries, turn the radio off, unplug the USB C cable and remove the radio case back cover by removing the 4 screws holding the cover in place.";
const char string_41[] PROGMEM = "[t3][s5][v10]Note that items on the back cover are attached with wires. Take care not to pull on these wires. The batteries are located in a battery holder attached to the back cover.";
const char string_42[] PROGMEM = "[t3][s5][v10]The batteries are held in place by the spring pressure of the holder. On the back cover there are two small holes.";
const char string_43[] PROGMEM = "[t3][s5][v10]You may insert a small slot head screwdriver, less than 0.2 inches in diameter into these holes and adjust the beep audio volume and the announce audio volume levels.";
const char string_44[] PROGMEM = "[t3][s5][v10]These volume levels are preset to a comfortable mid-range position and should not require frequent adjustment, however they are provide should you wish to change these levels. ";
const char string_45[] PROGMEM = "[t3][s5][v10]This completes the radio instructions. Goodbye and have a nice day.";
const char string_46[] PROGMEM = "[t3][s5][v10]";
const char string_47[] PROGMEM = "[t3][s5][v10]";

const char string_48[] PROGMEM = "[t3][s5][v10]Joke 1. A weasel walks into a bar. The bar tender says we've never had a weasel in here before. In fact I don't think I've ever served a weasel.";
const char string_49[] PROGMEM = "[t3][s5][v10]What can I get you to drink? Pop, goes the weasel. Joke 2. It is said that Married men live longer, but they are more willing to die.";
const char string_50[] PROGMEM = "[t3][s5][v10]Joke 3. A man is relaxing at home reading the newspaper. His wife comes in and whacks him in the head with a magazine. He said, what was that for?";
const char string_51[] PROGMEM = "[t3][s5][v10]She said, last week when I took your suit to the dry cleaner, I found a piece of paper in the pocket with the name lolita on it.";
const char string_52[] PROGMEM = "[t3][s5][v10]Oh I can explain that dear, he said. Lolita is the name of a hor se that I placed a bet on. A week later he was relaxing reading the newspaper again.";
const char string_53[] PROGMEM = "[t3][s5][v10]His wife came in and wacked him in the head with a frying pan, knocking him out. When he regained consciousness, he said, what the hell was that for?";
const char string_54[] PROGMEM = "[t3][s5][v10]His wife said, your hor se called looking for you.";
const char string_55[] PROGMEM = "[t3][s5][v10]Joke 4. A man is dying in hospital, his family are there to visit him. He says, my dear wife you get the buildings in the one hundred block of University Avenue.";
const char string_56[] PROGMEM = "[t3][s5][v10]My oldest son, to you go the buildings in the three hundred block of King street. My dear daughter, to you go the buildings in the six hundred block of Queen street.";
const char string_57[] PROGMEM = "[t3][s5][v10]And my youngest son, to you go the buildings in the four hundred block of Dundas street. The nurse overhears this and says to the wife,";
const char string_58[] PROGMEM = "[t3][s5][v10]What a wonderful inheritance your husband is leaving the family. She says, No he isn't, The idiot had a paper route.";
const char string_59[] PROGMEM = "[t3][s5][v10]Joke 5. A man feels that his wife's psychological problems are so bad that he needs to place her in a mental asylum. He goes to the asylum for a tour given by the head doctor.";
const char string_60[] PROGMEM = "[t3][s5][v10]After the tour he asks the doctor, how will we tell when my wife can come home? Doctor, how do you know when some one is psychologically normal? The doctor says, well we have a test,";
const char string_61[] PROGMEM = "[t3][s5][v10]We fill a bathtub with water and we give the patient the choice of the following, a coffee cup, a tea spoon, or a bucket and we ask them to empty the tub. ";
const char string_62[] PROGMEM = "[t3][s5][v10]Ah, I see, says the husband, a normal person would definitely ask for the bucket. No, the doctor says, a normal person would pull the plug. Would you like a bed by the window?";
const char string_63[] PROGMEM = "[t3][s5][v10]Joke 6. An engineer dies and reports to the pearly gates. St. Peter checks his list and says, oh, you're an engineer. You're in the wrong place fella. So the engineer disappointedly reports to the gates of Hell";
const char string_64[] PROGMEM = "[t3][s5][v10]wondering what he had done to deserve this. Pretty soon, after having accepted his fate, he gets tired of the conditions in Hell and sets about making improvements.";
const char string_65[] PROGMEM = "[t3][s5][v10]After a while, they've got air conditioning and flush toilets and escalators, and the engineer is a pretty popular guy. One day, God calls Satan up on His telepathic connection and asks,"; 
const char string_66[] PROGMEM = "[t3][s5][v10]So, how's it going down there in hell, Satan? Satan replies, hey, things are going great. We've got air conditioning and flush toilets and escalators now,";
const char string_67[] PROGMEM = "[t3][s5][v10]and there's no telling what this engineer is going to come up with next. We're having a wonderful time. God replies, What? You've got an engineer? That's a mistake - he should never have been sent down there.";
const char string_68[] PROGMEM = "[t3][s5][v10]Send him up here, or I'll sue you. Satan laughs loudly and answers, oh yeah, right. And just where are you going to get a lawyer?";
const char string_69[] PROGMEM = "[t3][s5][v10]Joke 7. Four surgeons were taking a coffee break and were discussing their work. The first said, I think accountants are the easiest to operate on. You open them up and everything inside is numbered.";
const char string_70[] PROGMEM = "[t3][s5][v10]The second said, I think librarians are the easiest to operate on. You open them up and everything inside is in alphabetical order. The third said, I like to operate on electricians."; 
const char string_71[] PROGMEM = "[t3][s5][v10]You open them up and everything inside is color cod ed. The fourth one said, I like to operate on politicians. They're heartless, spineless and gutless, and their brains and their butts are interchangeable.";
const char string_72[] PROGMEM = "[t3][s5][v10]Joke 8. A man comes home to find his wife upset. What is wrong dear, he says. I called the pharmacy and they didn't answer the phone for a long time and then when they did the pharmacist was very rude to me.";
const char string_73[] PROGMEM = "[t3][s5][v10]The man drives down to the pharmacy and demands to know what is going on. The pharmacist says, well hear me out. I've had a terrible day. First of all I over slept and had no time for breakfast. Then I forgot my keys in the house.";
const char string_74[] PROGMEM = "[t3][s5][v10]But the door was locked so I had to break a window and I cut my hand. Then I had a flat tire. After that I got to work half an hour late. There was a line up of angry people waiting for me to open up. I started serving them.";
const char string_75[] PROGMEM = "[t3][s5][v10]But the phone kept ringing and ringing. Finally I answered it and it was your wife asking me how to use a rectal thermometer. And I swear to God, all I said was shove it up your dot dot dot";
const char string_76[] PROGMEM = "[t3][s5][v10]This ends to jokes section. I hope you found that entertaining. Goodbye and have a nice day.";
const char string_77[] PROGMEM = "[t3][s5][v10]To access the radio instructions, tune the radio to 107 mega hertz and then return to this section. To access the easter eggs, tune the radio to 108 mega hertz and then return to this section.";
const char string_78[] PROGMEM = "[t3][s5][v10]The battery is fully charged. Please unplug the USB C cable.";

//Create a table (array of pointers) to refer to the strings in PROGMEM
const char* const string_table[] PROGMEM = {
  string_0, string_1, string_2, string_3, string_4, string_5, string_6, string_7, string_8, string_9, string_10, string_11, string_12, string_13,
  string_14, string_15, string_16, string_17, string_18, string_19, string_20, string_21, string_22, string_23, string_24, string_25, string_26,
  string_27, string_28, string_29, string_30, string_31, string_32, string_33, string_34, string_35, string_36, string_37, string_38, string_39, 
  string_40, string_41, string_42, string_43, string_44, string_45, string_46, string_47, string_48, string_49, string_50, string_51, string_52,
  string_53, string_54, string_55, string_56, string_57, string_58, string_59, string_60, string_61, string_62, string_63, string_64, string_65,
  string_66, string_67, string_68, string_69, string_70, string_71, string_72, string_73, string_74, string_75, string_76, string_77, string_78,};

// Define the number of strings in the table
const uint8_t num_strings = sizeof(string_table) / sizeof(string_table[0]);
char buffer[180]; // A temporary buffer in RAM, large enough for the longest string

TEA5767 radio(&radioPrintInfo, &radioUpdateConfig);  //Define radio parmeters

void setup() {
delay(500);
//EEPROM.put(0, 99.1); EEPROM.put(10, 98.1);  EEPROM.put(20, 107.0);  //To PREPROGRAMME THE PRESELECTS USE THE FIRST TIME YOU PROGRAM THE ATMEGA 328P then reprogram without this line.

pinMode(Announce_SW, INPUT);    //Set Announce switche to input
pinMode(f1_SW, INPUT);          //Set Preset switch to input
pinMode(f2_SW, INPUT);          //Set Preset switch to input
pinMode(f3_SW, INPUT);          //Set Preset switch to input
pinMode(A0, INPUT);             //Set A0 pin as an input
pinMode(A1, INPUT);             //Set A1 pin as an input
pinMode(A2, OUTPUT);            //Set A2 pin as an output
pinMode(A3, OUTPUT);            //Set A3 pin as an output (not currently in use)
pinMode(2, INPUT);              //Set D2 pin as an input
pinMode(3, INPUT);              //Set D3 pin as an input
pinMode(6, OUTPUT);             //Set D6 pin as an output
pinMode(9, INPUT);              //Set D9 pin as an input
pinMode(10, INPUT);             //Set D10 pin as an input
pinMode(11, INPUT);             //Set D11 pin as an input
pinMode(12, INPUT);             //Set D12 pin as an input
pinMode(13, INPUT);             //Set D13 pin as an input
pinMode (outputA, INPUT);       //Set rotary encoder A pin to input
pinMode (outputB, INPUT);       //Set rotary encoder B pin to input

digitalWrite(Mute_Speaker, LOW); //Turn on the loudspeaker

Wire.begin();                   //Initialize "Wire"
Serial.begin(9600);             //Intitalize serial communications for serial monitor window as needed
mySerial.begin(9600);           //Initialize soft serial connection to SYN6988 on pins D4 and D5
radio.mute();                   //Mute radio initially
lcd.init();                     // initialize the lcd
lcd.backlight();                // Turn on the lcd backlight

lcd.clear();                    //Clear the LCD screen
lcd.setCursor(0, 0);            //Begin Welcome Message top line of lcd
lcd.print("   Welcome");
lcd.setCursor(0, 1);
lcd.print("   FM Radio");

z = 0;                          //Announce "Power"
Select_String();                //Pull the string from program memory
z = 1;                          //Announce "on"
Select_String();                //Pull the string from program memory
z = 2;                          //Announce "Welcome to the FM Radio with audio assist"
Select_String();                //Pull the string from program memory

EEPROM.get(0, freq_ref);        //Go get the frequency value programmed into EEProm location 0. This is preset number 1.
frequency = freq_ref;           //Set the frequency value to the value in memory. EEProm memory location 0. That is pre-set 1.
radio.setFrequency(frequency);  //Set the radio to the frequency value     

LogicVolts = analogRead(A0);    //Read 5V logic level voltage
LogicVolts = LogicVolts/1023*5; //Convert to volts
LogicVolts = LogicVolts*1.07;   //Correction factor
USBC_State = digitalRead(USBC); //Read USB-C state. 1 if connected, 0 if not connected

lcd.clear();                    //Clear the lcd screen
lcd.setCursor(0, 0);            //Display Logic level voltage measured
lcd.print("Logic = ");           
lcd.setCursor(8, 0);            //Move cursor to position 8, first line of lcd
lcd.print(LogicVolts);
lcd.setCursor(12, 0);
lcd.print("V");

BattVolts = analogRead(A1);     //Read Battery voltage
BattVolts = BattVolts/1023*5;   //Convert to volts
BattVolts = BattVolts*1.944;     //Correction factor

lcd.setCursor(0, 1);            //Move cursor to position to second line of lcd
lcd.print("Battery = ");        //Proceed to display battery voltage measured
lcd.setCursor(10, 1);
lcd.print(BattVolts);
lcd.setCursor(14, 1);
lcd.print("V");

USBC_State = digitalRead(USBC); //Read the USB-C state. Checks if there is +5V on USB input pin. Status is 1 if connected, 0 if not connected

if(BattVolts < 6.2 && USBC_State == 0){     //If USB-C cable is not plugged in and battery voltage is below 6.2V alert the user to plug in and charge
radio.mute();                   //Mute radio during announcement
Say_Batt_Level();               //Go to subroutinme that announces the measure battery volatage
z = 3;                          //Announce "The Battery level is low, please plug in the USB C cable to charge it"
Select_String();                //Pull the string from program memory
}

if(BattVolts > 7.9 && USBC_State == 1){     //If USB-C cable is plugged in and battery voltage is above 7.9 V alert the user battery is charged
radio.mute();                   //Mute radio during announcement
Say_Batt_Level();               //Go to subroutinme that announces the measure battery volatage
z = 78;                         //Announce "The battery is fully charged. Please unplug the USB cable."
Select_String();                //Pull the string from program memory
}
//Some Optional preamble statements that can be used but they delay radio turn on quite a bit
/*if (USBC_State == 0 && BattVolts >3.2) {  //If USB-C cable not plugged in and battery voltage okay, alert user that USB-C power was not found
radio.mute();

z = 5;                          //Announce "The USB C power cable is not presently connected. Radio running on battery only. Battery level is normal"
Select_String();

Say_Batt_Level();

USBC_Flag = 0;                  //Set Flag to 0. Flag used to control when announcements commence

}

if (USBC_State == 1 && BattVolts <4.1) {  //If USB-C cable is plugged in and battery voltage below full charge, let the user know it is charging.
radio.mute();

z = 6;                           //Announce "The USB C power cable is connected. The Battery is charging."
Select_String();

USBC_Flag = 1;                   //Set Flag to 1. Flag used to control when announcements commence

}
*/
z = 4;                           //Announce "The Radio is tuning to preset frequency number one. Please enjoy. Radio on."
Select_String();                 //Pull the string from program memory
lcd.clear();
frequencyDisplay();              //Go to the sub that displays frequency and rx level on the LCD
radio.awake();                   //Ensure radio is active
radio.unmute();                  //un-mute the radio sound
MS = 1;                          //Set flag - mute speaker is off i.e speaker audio on

}

void loop() {

ext = 0;                         //Exit from radio announcements flag set to zero (off)
if (c == 0) {                    //When radio is first turned on, do not announce USBC status until there is a change in USB status

USBC_State = digitalRead(USBC);  //Set up flags for USBC status announcements
if (USBC_State == 0) {
  USBC_Flag = 0;
}

if (USBC_State == 1) {
  USBC_Flag = 1;
}
c = 1;                          //Allow USBC Status change announcements after initial radio turn on
 }

USB_C_Status();                 //Go to sub that checks if USB-C cable is plugged in with power available
LCD_Backlight();                //Go to sub that checks if LCD Backlight should be turned off to save power (1 minute time out)

Switch_State_Rot_Enc = digitalRead(Rot_Enc_SW);   //Check the rotary encoder button button state
if(Switch_State_Rot_Enc == HIGH) {                //If button is pressed...
delay(100);
StartTime = millis();                             //Note the current UProcessor time
lcd.backlight();                                  //Turn on backlight if the button is pressed

while (Switch_State_Rot_Enc == HIGH) {            //While the button is pressed
Switch_State_Rot_Enc = digitalRead(Rot_Enc_SW);   //Keep reading the button state and wait here
}

if (millis() - StartTime < 3000){                 //If the button was pressed for less than 3 seconds
radio.mute();                                     //Mute radio
Talk();                                           //Go to sub routine announcing current frequency setting
radio.unmute();                                   //Un-mute radio after announcement
}

else if (millis() - StartTime >= 3000){           //If the button was pressed for more than 3 seconds
Radio_Status_Report();                            //Go to the radio status report sub routine
radio.unmute();                                   //Un-mute radio after announcement
}
 }

Mute_SW_State = digitalRead(Mute_SW);             //Check the Mute button state
if(Mute_SW_State == HIGH) {                       //If button is pressed...
delay(100);
StartTime = millis();                             //Note the current UProcessor time
lcd.backlight();                                  //Turn on backlight if the button is pressed

while (Mute_SW_State == HIGH) {                   //While the button is pressed
Mute_SW_State = digitalRead(Mute_SW);             //Keep reading the button state and wait here
}

MS = !MS;                                         //Toggle the mute state indication flag


if (MS == 0) {                                    //If speaker is NOT muted...
radio.mute();                                     //Mute radio
speak("[t3][s10][v10]Muteing Speaker");           //Announce Muting Speaker
waitForSpeech();                                  //Continue speaking until the SYN6988 sendsout 0x4F finished code
digitalWrite(Mute_Speaker, HIGH);                 //mute the speaker
radio.unmute();                                   //Un-mute radio after announcement
lcd.clear();                                      //Clear the lcd screen
lcd.setCursor(0, 0);           
lcd.print("MUTE");                                //Display muted
delay(1000);
lcd.clear();
frequencyDisplay();                               //Go to the sub to display the frequency and rx level on the LCD
}
else if (MS == 1){                                //If speaker is muted...
radio.mute();                                     //Mute radio
digitalWrite(Mute_Speaker, LOW);                  //Unmute the speaker
speak("[t3][s10][v10]Un muteing Speaker");        //Announce Un-muting Speaker
waitForSpeech();                                  //Continue speaking until the SYN6988 sendsout 0x4F finished code
radio.unmute();                                   //Un-mute radio after announcement
lcd.clear();                                      //Clear the lcd screen
lcd.setCursor(0, 0);           
lcd.print("UNMUTE");                                //Display muted
delay(1000);
lcd.clear();
frequencyDisplay();                               //Go to the sub to display the frequency and rx level on the LCD
}
 }

Switch_State_Announce = digitalRead(Announce_SW); //Check the Announce button state
if(Switch_State_Announce == HIGH) {               //If button is pressed 
delay(100);
StartTime = millis();                             //Note the current UProcessor time
lcd.backlight();                                  //Turn on backlight

while (Switch_State_Announce == HIGH) {           //While the button is pressed...
Switch_State_Announce = digitalRead(Announce_SW); //Keep reading the button state and wait here
}
radio.mute();                                     //Mute radio during announcement
Talk();                                           //Go to the Talk sub to announce the frequency
radio.unmute();                                   //Un-mute radio after announcement
}

Switch_State_f1 = digitalRead(f1_SW);             //Check the first pre-set frequency button state
if(Switch_State_f1 == HIGH) {                     //If button is pressed...
delay(100);
StartTime = millis();                             //Note the current UProcessor time
lcd.backlight();                                  //Turn on backlight

while (Switch_State_f1 == HIGH) {                 //While the button is pressed...
Switch_State_f1 = digitalRead(f1_SW);             //Keep reading the button state and wait here
}

if (millis() - StartTime < 3000){                 //If the button was pressed for less than 3 seconds
radio.mute();                                     //Mute radio during announcement
EEPROM.get(0, freq_ref);                          //Go get the frequency value programmed into EEProm location 0. (Pre-set 1)
frequency = freq_ref;                             //Set the frequency value to the value in memory
radio.setFrequency(frequency);                    //Set the radio to the frequency value
delay(100);                                       //wait a moment
frequencyDisplay();                               //Go to the sub to display the frequency and rx level on the LCD
speak("[t3][s5][v10]Preset 1 selected");          //Announce Preset 1 selected
waitForSpeech();                                  //Continue speaking until the SYN6988 sends out 0x4F finished code
delay(100);                                       //wait a moment
Talk();                                           //Go to the Speak sub to announce the frequency
radio.unmute();                                   //Un-mute radio after announcement
}
else if (millis() - StartTime >= 3000){           //If the button was pressed for more than 3 seconds...
radio.mute();                                     //Mute radio during announcement
frq = frequency;                                  //Set variable frq to the current frequency value
EEPROM.put(0, frq);                               //Put the frequency value into the first pre-set frequency location in memory at address 0.
frequencyDisplay();                               //Go to the sub to display the frequency and rx level on the LCD
speak("[t3][s5][v10]Preset 1 programmed");        //Announce Preset 1 programmed successfully
waitForSpeech();                                  //Continue speaking until the SYN6988 sendsout 0x4F finished code
delay(100);                                       //wait a moment
Talk();                                           //Go to the Talk sub to announce the frequency
radio.unmute();                                   //Un-mute radio after announcement
}
 }
Switch_State_f2 = digitalRead(f2_SW);             //Check the second pre-set frequency button state...
if(Switch_State_f2 == HIGH) {                     //etc almost identical to above
delay(100);
StartTime = millis();
lcd.backlight();                                  

while (Switch_State_f2 == HIGH) {
Switch_State_f2 = digitalRead(f2_SW);            
}

if (millis() - StartTime < 3000){
radio.mute();
EEPROM.get(10, freq_ref);                         
frequency = freq_ref;
radio.setFrequency(frequency);
frequencyDisplay();
speak("[t3][s5][v10]Preset 2 selected");
waitForSpeech();
delay(100);
Talk();
radio.unmute();
}
else if (millis() - StartTime >= 3000){
radio.mute();
frq = frequency;
EEPROM.put(10, frq);                                
frequencyDisplay();
speak("[t3][s5][v10]Preset 2 programmed");
waitForSpeech();
delay(100);
Talk();
radio.unmute();
}
 }
Switch_State_f3 = digitalRead(f3_SW);             //Check the third pre-set frequency button state...
if(Switch_State_f3 == HIGH) {                     //etc almost identical to above
delay(100);
StartTime = millis();
lcd.backlight();                                  

while (Switch_State_f3 == HIGH) {
Switch_State_f3 = digitalRead(f3_SW);             
}

if (millis() - StartTime < 2000){
radio.mute();
EEPROM.get(20, freq_ref);                         
frequency = freq_ref;
radio.setFrequency(frequency);
frequencyDisplay();
speak("[t3][s5][v10]Preset 3 selected");
waitForSpeech();
delay(100);
Talk();
radio.unmute();
}
else if (millis() - StartTime >= 2000){
radio.mute();
frq = frequency;
EEPROM.put(20, frq);                                 
frequencyDisplay();
speak("[t3][s5][v10]Preset 3 programmed");
waitForSpeech();
delay(100);
Talk();
radio.unmute();
}
 }
for (i=0;i<15;i++) {                                //Hover on encoder state reading for a while...
delay(10);
Encoder();                                          //Go to the sub that checks if the encoder switch is turned
}
 }

void Radio_Status_Report(){                         //Sub that reports USB and batteey status. Also includes optional radio operating instructions

Rfreq = round(frequency);
if (Rfreq != 107 && Rfreq != 108) {                //If frequency not set to 107 or 108 megahertz 
  lcd.clear();                                      //Clear the LCD screen
  lcd.setCursor(0, 0);                              //Begin Welcome Message top line of lcd
  lcd.print("Radio Status");
  lcd.setCursor(0, 1);
  lcd.print("  Report");
radio.mute();                                     
speak("[t3][s5][v10]Radio Status");
waitForSpeech();
delay(100);

USBC_State = digitalRead(USBC);                     //Read USB-C state. 1 if connected, 0 if not connected


if (USBC_State == 0) {                              //If USB-C not present...
radio.mute();

z = 13;                                             //Announce "USB C is disconnected."
Select_String();                                    //Pull the string from program memory
Say_Batt_Level();                                   //Go to sub that reads battery voltage and announces it
}

if (USBC_State == 1) {                             //If USB-C present...
radio.mute();

z = 12;                                            //Announce "USB C is connected."
Select_String();                                   //Pull the string from program memory
Say_Batt_Level();                                  //Go to sub that reads battery voltage and announces it 

z = 77;                                            //Announce how to reach radio instructions or easter eggs
Select_String();                                   //Pull the string from program memory
} 
 }
  
 
 Rfreq = round(frequency);                         //Round up/down the frequency value
 if (Rfreq == 107)  {  //107 Mhz                   //If frequency is at or near 107.0 Mhz...
 Instruction_Mode();                               //Go to the Radio instructions sub which reads out radio operating instructions
}
 
 else if (Rfreq == 108) {  //108 Mhz               //If frequency is at or near 108.0 Mhz...
 Easter_Egg();                                     //Go to the Easter Eggs sub which reads out some jokes
 }
 lcd.clear();
                                                   //After providing information return to the default frequency in preset 1.
 EEPROM.get(0, freq_ref);                          //Go get the frequency value programmed into EEProm location 0.
 delay(100);                                       //wait a moment
 frequency = freq_ref;                             //Set the frequency value to the value located in EEProm memory location 0. That is pre-set 1. 
 radio.setFrequency(frequency);                    //Set the radio frequency
 frequencyDisplay();                               //Display the radio frequency and receive level on the lcd
 Talk();                                           //Announce the new frequency
 radio.unmute();                                   //Unmute the radio after announcements
 }


void Encoder() {                                   //Sub that check which direction the rotary encoder switch is turned and counts turns
  
aState = digitalRead(outputA);                     //Check the state of rotary encoder contact A
bState = digitalRead(outputB);                     //Check the state of rotary encoder contact B
                   
    if (aState == 1 && bState == 0){               //If rotary encoder is turning clockwise
    
    while (aState == 1 || bState == 1) {           //While switch is in the state where both contacts A and B are high
    aState = digitalRead(outputA);                 //Continue checking state of contact A
    bState = digitalRead(outputB);                 //Continue checking state of contact B
}

for (n=0;n<10;n++){                                //For a count of 10 (to make a higher frequency click sound as the rotary encoder is turned)
analogWrite(A2, 254);                              //Write pin A2 high
delay(2);                                          //Wait 2 millisecs

analogWrite(A2, 0);                                //Write pin A2 low                       
delay(2);                                          //Wait 2 millisecs

StartTime = millis();                              //Note the current UProcessor time
lcd.backlight();                                   //Turn on LCD backlight

}

frequency = frequency + 0.1;                       //Increase frequency by 100Khz
frequency = constrain(frequency, 87.9, 108.1);     //Limit frequency range to 87.9 - 108.1 MHz

if (frequency > 108.0) {frequency = 88.0;}         //If frequency exceeds upper limit of 108 MHz roll it back to bottom of range
radio.setFrequency(frequency);                     //Set the radio to the new frequency

frequencyDisplay();                                //Go to the sub to display the frequency and rx level on the LCD
}
          
    if (bState == 1 && aState == 0){               //If rotary encoder is turning counter-clockwise 
 
    while (aState == 1 || bState == 1) {           //While switch is in the state where both contacts A and B are high
    aState = digitalRead(outputA);                 //Continue checking state of contact A
    bState = digitalRead(outputB);                 //Continue checking state of contact B    
}
    
for (n=0;n<10;n++){                                //For a count of 10 (to make a lower frequency click sound as the rotary encoder is turned)
analogWrite(A2, 254);                              //Write pin A2 high
delay(4);                                          //Wait 4 millisecs

analogWrite(A2, 0);                                //Write pin A2 low
delay(4);                                          //Wait 4 millisecs

StartTime = millis();                              //Note the current UProcessor time
lcd.backlight();                                   //Turn on LCD backlight

}

frequency = frequency - 0.1;                       //Decrease frequency by 100Khz
frequency = constrain(frequency, 87.9, 108.1);     //Limit frequency range to 87.9 - 108.1 MHz
    
if (frequency < 88.0) {frequency = 108.0;}         //If frequency goes beyond lower limit of 88 MHz roll it back to top of range
radio.setFrequency(frequency);                     //Set the radio to the new frequency
frequencyDisplay();                                //Go to the sub to display the frequency and rx level on the LCD
}
 }

void frequencyDisplay()                             //This sub displays the current frequency and rx level on the LCD
{
  lcd.setCursor(0, 0);                              //Set cursor to first position, first line
  lcd.print("FM:");                                 //Display "FM"
  lcd.setCursor(4, 0);                              //Set cursor to fourth position, first line
  lcd.print(frequency);                             //Display the current frequency setting
  lcd.setCursor(9, 0);                              //Set cursor to ninth position, first line
  lcd.print("  MHz");                               //display a blank to remove unwanted zero left when frequency set below 100 MHz. Display MHz.

  lcd.setCursor(0, 1);                              //Set cursor to first position, second line
  lcd.print("Rx Level:");                           //Display "Rx Level"
  lcd.setCursor(9, 1);                              //Set cursor to ninth position, second line
  lcd.print(lvl);                                   //display the RX level reported by radio module                  
  lcd.setCursor(11, 1);                             //Set cursor to eleventh position, second line                         
  lcd.print("%");                                   //display % symbol
  
}
void Talk() {                                       //This sub announces the frequency value
  
freq = round(frequency * 10);                       //Round the frequency value, multiply by 10 to remove decimal point and assign to variable freq

if (frequency < 100) {                              //If the frequency is below 100 MHz (4 digits when including decimal point)
dig1 = (freq / 100U) % 10;                          //Obtain the first digit
dig2 = (freq / 10U) % 10;                           //Obtain the second digit
dig3 = 10;                                          //Assign the third digit as decimal point. i.e a value of 10 means decimal point
dig4 = (freq / 1U) % 10;                            //Obtain the fourth digit

n = 4;                                              //Set the digit count to 4 for frequencies below 100 MHz. Decimal point counts as a digit.
}

if (frequency >= 100) {                             //If the frequency is 100 MHz or above (5 digits when including decimal point)
dig1 = (freq / 1000U) % 10;                         //Obtain the first digit
dig2 = (freq / 100U) % 10;                          //Obtain the second digit
dig3 = (freq / 10U) % 10;                           //Obtain the third digit
dig4 = 10;                                          //Assign the fourth digit as decimal point. i.e a value of 10 means decimal point
dig5 = (freq / 1U) % 10;                            //Obtain the fifth digit

n = 5;                                              //Set the digit count to 5 for frequencies of 100 MHz and above. Decimal point counts as a digit.
}

for (i=0;i<n;i++){                                  //Count through the digits for 4 or 5 digit frequency number
  if (i == 0) { x = dig1;}                          //For first  digit assign dig1 to variable x
  if (i == 1) { x = dig2;}                          //For second digit assign dig2 to variable x
  if (i == 2) { x = dig3;}                          //For third  digit assign dig3 to variable x
  if (i == 3) { x = dig4;}                          //For fourth digit assign dig4 to variable x
  if (i == 4) { x = dig5;}                          //For fifth  digit assign dig5 to variable x
  
Find_Sound();                                       //This sub will assign a word to be announced based on the value of x

String voice = k;                                   //Assign the value of k to the string to be spoken (This comes from the switch table in void Find_Sound sub)
speak((char*)voice.c_str());                        //Announce the number assigned
waitForSpeech();                                    //Continue speaking until the SYN6988 sends out 0x4F finished code               
delay(50);                                          //wait a moment
}

speak("[t3][s5][v10]FM");                           //Announce "FM" after frequency read out
waitForSpeech();                                    //Continue speaking until the SYN6988 sends out 0x4F finished code 
delay(50);                                          //wait a moment
}

void Find_Sound(){                                  //This sub looks at the digit temporarily assigned to variable x and then sets the variable k equal to the word to be spoken
  
  switch (x) {                                      //Depending on the current value of x, look at all cases and assign the correct word to k
    
    case 0: k= "[s10]0"; break; case 1: k= "[s10]1"; break; case 2: k= "[s10]2"; break; case 3: k= "[s10]3"; break; case 4: k= "[s10]4"; break; case 5: k= "[s10]5"; break;
    case 6: k= "[s10]6"; break; case 7: k= "[s10]7"; break; case 8: k= "[s10]8"; break; case 9: k= "[s10]9"; break; case 10: k= "[s10]POINT"; break;
    default:                                        //Default character is a blank
      k = "ERROR";                                  //For errors, say "Error"
      break;
  }
}

void radioPrintInfo(const tea5767_info_t *info) {   //Sub to get radio info
  
  lvl = (info->signal_level);                       //Get the RX level reported by the radio module
}

void radioUpdateConfig(tea5767_config_t *config) {  //Not sure what this does, required by the radio library code
  config->standby = false;
}

void USB_C_Status(){                                //sub that checks if USB-C cable is plugged in with power available

USBC_State = digitalRead(USBC);                     //Read status of USB-C power. 1 present, 0 not present

if (USBC_State == 1 && USBC_Flag == 0) {            //If USB-C present and flag set for an announcement...
radio.mute();                                       //Mute the radio

z = 12;                                             //Announce "USB C power cable is connected."
Select_String();                                    //Pull the string from program memory

USBC_Flag = 1;                                      //Set this flag so that message is not repeated until there is a change of state with respect to USB-C
radio.unmute();                                     //Unmute radio after announcements
}

if (USBC_State == 0 && USBC_Flag == 1) {            //IF USB-C NOT present and flag set for an announcement...
radio.mute();                                       //mute radio

z = 13;                                             //Announce "USB C power cable is disconnected."
Select_String();                                    //Pull the string from program memory    
USBC_Flag = 0;                                      //Set this flag so that message is not repeated until there is a change of state with respect to USB-C
radio.unmute();
}
 }

 void LCD_Backlight() {                             //Sub that turns off the lcd backlight after 1 minute to conserve power

 if (millis() - StartTime > 60000){                 //If the radio is on with no activity for 1 minute, turn off the display to save power
lcd.noBacklight();                                  //Turn off backlight
}
 }

 void speak(char* msg) {                            //Sub that sets up the SYN6988 to speak as per SYN6988 Specs
  mySerial.write(0xFD);                             //Header
  mySerial.write((byte)0x0);                        
  mySerial.write(2 + strlen(msg));                  //Length of text string is equal to length of current message
  mySerial.write(0x01);                             
  mySerial.write((byte)0x0);
  mySerial.write(msg);
  
}

void waitForSpeech() {                              //Sun=b that monitors if the SYN6988 has finished speaking indicated by 0x4F or times out
  unsigned long start = millis();
  bool done = false;
  while ( ! done && (millis() - start) < timeout ) {
    while ( mySerial.available() ) {
      if ( mySerial.read() == 0x4F ) {
        done = true;
        break;
      }
    }
  }
}


void Say_Batt_Level() {                             //Sub that announces the battery voltage. Works the same way as frequency announcement

BattVolts = analogRead(A1);                         //Read Battery voltage
BattVolts = BattVolts/1023*5;                       //Convert to volts
BattVolts = BattVolts*1.944;                         //Correction factor

speak("[t3][s5][v10]Battery Voltage is");           //Announce "Battery voltage is"
waitForSpeech();                                    //Continue speaking until the SYN6988 sendsout 0x4F finished code
delay(50);                                          //Wait a moment

BV = round(BattVolts * 10);                         //Round the battery voltage value, multiply by 10 and assign to variable BV

                                                    //Expect 2 digits and a decimal point
dig1 = (BV / 10U) % 10;                             //Obtain the first digit
dig2 = 10;                                          //Assign the second digit as decimal point. i.e a value of 10 means decimal point
dig3 = (BV / 1U) % 10;                              //Obtain the third digit
 
n = 3;                                              //Set the digit count to 3. Decimal point counts as a digit.

for (i=0;i<n;i++){                                  //Count through the digits
  if (i == 0) { x = dig1;}                          //For first  digit assign dig1 to variable x
  if (i == 1) { x = dig2;}                          //For second digit assign dig2 to variable x
  if (i == 2) { x = dig3;}                          //For third  digit assign dig3 to variable x
  
  
  Find_BV_Sound();                                  //This sub will assign a word to be announced based on the value of x

String voice = k;                                   //Assign the value of k to the string to be spoken (This comes from the switch table in void Find_BV_Sound sub)
speak((char*)voice.c_str());                        //Announce the number assigned
waitForSpeech();                                    //Continue speaking until the SYN6988 sendsout 0x4F finished code
delay(50);                                          //Wait a moment
}

speak("[t3][s5][v10]Volts");                        //Announce "Volts after the number"
waitForSpeech();                                    //Continue speaking until the SYN6988 sendsout 0x4F finished code
delay(50);                                          //Wait a moment
 
}

void Find_BV_Sound(){                               //This sub looks at the digit temporarily assigned to variable x and then sets the variable k equal to the word to be spoken
  
  switch (x) {                                      //Depending on the current value of x, look at all cases and assign the correct word to k
    
    case 0: k= "0"; break; case 1: k= "1"; break; case 2: k= "2"; break; case 3: k= "3"; break; case 4: k= "4"; break; case 5: k= "5"; break;
    case 6: k= "6"; break; case 7: k= "7"; break; case 8: k= "8"; break; case 9: k= "9"; break; case 10: k= "POINT"; break;

    default:                                        //Default character is a blank
      k = "ERROR";                                  //For errors, say "Error"
      break;
  }
}

void Easter_Egg(){                                  //This sub tells a few jokes stored in surplus program memory
  ext = 0;                                          //Set the exit flag to zero. i.e do not exit until told to do so
  lcd.clear();                                      //Clear the LCD screen
  lcd.setCursor(0, 0);                              //Begin Welcome Message top line of lcd
  lcd.print("Easter Eggs");
  lcd.setCursor(0, 1);
  lcd.print("   Mode");
  radio.mute();                                     //Mute the radio prior to announcements
  
  z = 7;                                            //Announce "Congratulations you have found the Easter Eggs..."
  Select_String();                                  //Pull the string from program memory 
  z = 11;                                           //Announce instructions on hoe to exit from Easter Eggs.
  Select_String();                                  //Pull the string from program memory 

for (z=48;z<77;z++){                                //Count through the text strings containing the jokes text

Switch_State_Announce = digitalRead(Announce_SW);   //Check the Announce button state. If pressed initiate exit procedure.
if(Switch_State_Announce == HIGH) {                 //If button is pressed...
delay(100);                                         //Wait a moment
ext = 1;                                            //Set the exit flag
for (n=0;n<10;n++){                                 //Make a chirp sound to acknowledge that exit button press has been recognized
analogWrite(A2, 254);                               //Write pin A2 high
delay(6);                                           //Wait 6 millisecs
analogWrite(A2, 0);                                 //Write pin A2 low
delay(6); 
}
 }

if (ext == 1) {                                     //If the exit flag is set, 1 means exit, proceed to exit the subroutine.
z = 8;                                              //Announce exiting...
Select_String();                                    //Pull the string from program memory 
return;                                             //Return to previous subroutine
}        

delay(100);                                         //Wait a moment
Select_String();                                    //Announce joke text in the present selected strings
delay(100);                                         //Wait a moment
 
}
lcd.clear();
}

void Instruction_Mode(){                            //Sub that accesses the radio instruction manual and speaks it out from program memory
  ext = 0;                                          //Set the exit flag to zero. i.e do not exit until told to do so
  lcd.clear();                                      //Clear the LCD screen
  lcd.setCursor(0, 0);                              //Begin Welcome Message top line of lcd
  lcd.print("Radio Info");
  lcd.setCursor(0, 1);
  lcd.print("   Mode");
  
  radio.mute();                                     //Mute the radio befor announcement
  z = 9;                                            //Announce "Congratulations you have found the radio instructions..."
  Select_String();                                  //Pull the string from program memory 
  z = 11;                                           //Announce instructions on hoe to exit from Radio Instructions.
  Select_String();                                  //Pull the string from program memory 


for (z=14;z<46;z++){                                //Count through the text strings containing the radio information

Switch_State_Announce = digitalRead(Announce_SW);   //Check the Announce button state. If pressed initiate exit procedure.
if(Switch_State_Announce == HIGH) {                 //If button is pressed... 
delay(100);                                         //Wait a moment
ext = 1;                                            //Set the exit flag
for (n=0;n<10;n++){                                 //Make a chirp sound to acknowledge that exit button press has been recognized
analogWrite(A2, 254);                               //Write pin A2 high
delay(6);                                           //Wait 6 millisecs
analogWrite(A2, 0);                                 //Write pin A2 low
delay(6); 
}
 }

if (ext == 1) {                                     //If the exit flag is set, 1 means exit, proceed to exit the subroutine.
z = 10;                                             //Announce exiting...
Select_String();                                    //Pull the string from program memory          
return;                                             //Return to previous subroutine
}        

delay(100);                                         //Wait a moment
Select_String();                                    //Announce radio information text in the present selected strings
delay(100);

}
lcd.clear();
}

void speakFromProgmem(int index) {                  //Sub to point at the text in program memory and retrieve it based on the index
  
  const char* flash_address = reinterpret_cast<const char*>(pgm_read_word(&(string_table[index]))); // Get the address of the string from the pointer table
  strcpy_P(buffer, flash_address);                                                                  // Copy the string from PROGMEM to the RAM buffer. Use strcpy_P for string copy from program memory 
  mySerial.print(buffer);                                                                           // Send the RAM buffer content to the SYN6988
}

void Select_String(){                               //Sub to extract and read out text
  
    strcpy_P(buffer, (char*)pgm_read_word(&(string_table[z])));  //Put the string of text into the buffer
    
    Serial.println(buffer);                                      //print the buffer content
    speak(buffer);                                               //Say the buffer content
    waitForSpeech();                                             //Continue speaking until the SYN6988 sendsout 0x4F finished code
    delay(100);                                                  //Wait a moment
  
}

