PDA

View Full Version : My Nav/Comm Radio with 32 Channel Memory and my Transponder



Tom_G_2010
03-28-2014, 11:45 PM
OK, so here it is. After a very long time away from my build. I came back to find FS2Multi in full bloom so I had to redo my old code to work with it. Instead of trying to edit the old code, I decided to start from scratch and leverage more of the FS2Muti functionality.

I have sketches written and under test for my Whiskey Compass, my Annunciator panel, my Autopilot, my elevator trim servo for the auto pilot, and a few other things.

But, tonight, I finally finished testing on my Nav Comm Radio and my Transponder. It's bread boarded and working well. I have a face plate kit from DIY Realism that I am building the boards and display mount for now and I'llpost some updates when that's in a more finished state, likely some time early next month.

I'm using some of those MAX7219 serial display boards, an Arduino Mega, a pair of ELMA 37 encoders, and the DIY Realism face plate kit which comes with all the other switches and a set of 5 character seven segment displays. The Serial display boards are made to drive two 4 character displays and as many of you know they come pre fab'd with the chip, misc components, pin headers, and the two 7 segment displays.

With the displays mounted on them, they don't fit behind the face plate kit. However, they are a simple enough circuit that I was going to buy some chips and solder up my own on a breadboard. Then I priced them and found that the pref fab'd displays where less expensive. So my cost cutting solution is to use the circuit board from the prefab'd 8 segment displays to drive my 5 segment displays. It turns out to work quite well.

I was looking at some online info about the actual Bendix King Radio and discovered that they at some point added the ability to have up to 32 channel presets and that tickled my fancy so I purchased an SD Card Shield and wrote the code to create the same functionality. I am still reading through that code because I find it to be bulky and messy. I want to put it on a diet but haven't figured out just how yet.

So with that long winded intro here are some pics and the code. I have a couple videos as well, but my phone is refusing to send them so I'll have to post them later.

8944894689478945

Unlike my old code, in this code I learned how to use some array variables and did a much better job of replacing repeat code with sub routines. I'm sure it could all be done much cleaner and in far fewer lines by someone who knows how to write code, but I'm not them. And, for a hack like me I figure what I've dons is fairly slick.

The code will be in the next post. Apparently I exceeded the per post character limit...

Tom_G_2010
03-28-2014, 11:46 PM
#include <ledcontrol.h>
#include <sd.h>
#include "math.h"
#include "Quadrature.h"


// lc0=LedControl(<datain>,<clock>,<load>,<number of="" displays="" daisy="" chained="">)
LedControl lc0=LedControl(10,12,11,5);


int dspCnt0=lc0.getDeviceCount(); // sets the variable to indicate the number of serial display modules


int dspBrghtns = 8; // These three variables are used with a potentiometer
int dspBrghtVal = 511; // to adjust the brighness of the displays
int dspBrghtValLast = 0;


/*
It is cheaper to buy the pre fab'd 8 character display mosdules to drive my 5 character displays in the radios
than it is to but MAX72xx chips and fab my own drivers.
The following two dimensional array variableis helps me to manage my 7 Segment LED Displays
You will see it used in the "SVN_SEG_DSP" and "KILL_DSP" functions. I am using the first five character positions
of four 8 charcter boards for each radio display. I then use the two of the remaining charcter segemtns off two of
the boards to show my trnasponder display
*/


int strtPstn[24][24]= // 7 Segment LED Display Driver array. Used by SVN_SEG_DSP and KILL_DSP functions
{
{
0,0,0,0,0,1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,1,1,3,3 }
,
{
7,6,5,4,3,7,6,5,4,3,7,6,5,4,3,7,6,5,4,3,2,1,2,1 }
};


//Variables and configuration for my SD Card Shield
File sdCrdFile;
int sdCrdSlctDgOut = 53;
Sd2Card card;
SdVolume volume;
SdFile root;


//Varibles used for the 32 channel memory
char chnMem_1_State = 'X';
char chnWrt_1_State = 'X';
char chnMem_2_State = 'X';
char chnWrt_2_State = 'X';
int memChnRad1[2] = {
0,1};
int memChnRad2[2] = {
0,1};
int memChnRadNo = 1;
char chnFreqC[] = "----";
String chnFreqS = "----";
int chnWrtNo = 0;
char freqWrtC[] = "----";


/*
Outputs below are for the backlight LED and an RGB LED (my Actv/Stdby swap buttons are illuminated)
The LED colors indicate the tuning mode
Off (or backlight only on) = normal tuning with standby freq and swap button
Red = Channel Tuning mode. The standby display is replaced by a "ch__"
Blue = Frequency programing mode
Green = Storage channel select mode for programming
*/
//keep these pins sequential
int memRead_1_DgOutLED = 44; //Red
int memWrite_1F_DgOutLED = 45; //Blue
int memWrite_1C_DgOutLED = 46; //Green
int btnBckLt_1_DgOutLED = 47;


int memRead_2_DgOutLED = 40; //Red
int memWrite_2F_DgOutLED = 41; //Blue
int memWrite_2C_DgOutLED = 42; //Green
int btnBckLt_2_DgOutLED = 43;


// switch inputs
int com_1_PwrDgIn = 4;
int com_1_ActvStdbySwapDgIn = 5;
int com_1_ChanModeDgIn = 6;
int nav_1_PwrDgIn = 7;
int nav_1_ActvStdbySwapDgIn = 8;
int nav_1_ChanModeDgIn = 9;


int xPndrBtn_0_DgIn = 23;
int xPndrBtn_1_DgIn = 22;
int xPndrBtn_2_DgIn = 25;
int xPndrBtn_3_DgIn = 24;
int xPndrBtn_4_DgIn = 27;
int xPndrBtn_5_DgIn = 26;
int xPndrBtn_6_DgIn = 29;
int xPndrBtn_7_DgIn = 28;
int xPndrIdentDgIn = 34;
int xPndrVFRDgIn = 35;
int xPndrClrDgIn = 36;
int xPndrPwrDgIn = 37;


//Encoder Inputs
Quadrature quad_1_Otr(14, 15);
Quadrature quad_1_Inr(16, 17);
Quadrature quad_2_Otr(18, 19);
Quadrature quad_2_Inr(20, 21);


int R1;
int Rold1;
int Rdif1;
String R1Drctn = "X";
int R2;
int R3;
int R4;
int Rold2;
int Rdif2;
int Rold3;
int Rdif3;
int Rold4;
int Rdif4;
String R2Drctn = "X";
String R3Drctn = "X";
String R4Drctn = "X";


int ExtTyp; // Gets the serial read of the first two characters of an Extraction
String ExtVal = ""; // Gets the serial read of the value of an Extraction


//Variables to detect single and double click for channel Memory mode select
unsigned long dblClkStart_1;
int dblClkDrtn_1 = 500;
int dblClkCnt_1 = 0;


unsigned long dblClkStart_2;
int dblClkDrtn_2 = 500;
int dblClkCnt_2 = 0;


// Switch debounce timing variables
long debounceTimeLast = 0;
long debounceDelay = 50;


// Input button state variables
const int btnCnt = 18; // Number of switch inputs
int btnRead;
// Array variable used so I have flaxability on what input pins I use
//Doing it this way I don't need to have them sequential or concurrent
int btnList[btnCnt]={
com_1_PwrDgIn, // 0 "XX0",
com_1_ActvStdbySwapDgIn, // 1 "A06",
com_1_ChanModeDgIn, // 2 "XX1",
nav_1_ActvStdbySwapDgIn, // 3 "A18",
nav_1_PwrDgIn, // 4 "XX2",
nav_1_ChanModeDgIn, // 5 "XX3",
xPndrBtn_0_DgIn, // 6 "A42",
xPndrBtn_1_DgIn, // 7 "A42",
xPndrBtn_2_DgIn, // 8 "A42",
xPndrBtn_3_DgIn, // 9 "A42",
xPndrBtn_4_DgIn, // 10 "A42",
xPndrBtn_5_DgIn, // 11 "A42",
xPndrBtn_6_DgIn, // 12 "A42",
xPndrBtn_7_DgIn, // 13 "A42",
xPndrIdentDgIn, // 14 "XX7",
xPndrVFRDgIn, // 15 "A42",
xPndrClrDgIn, // 16 "A42",
xPndrPwrDgIn}; // 17 "XX9",


// Two more array variables to track currrent and last button state
// Those with 3's and 4's are the power buttons and were done to
// force an immediate check of the switch state
int btnState[btnCnt]={
3,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,3};
int btnStateLast[btnCnt]={
4,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,4};
// Serial string associated with each button
// The |XX_" strings are dummy strings for monitoring and debugging of
//Functions that don't send anything to FSX
String btnString[btnCnt]={
"XX0",
"A06",
"XX1",
"A18",
"XX2",
"XX3",
"A42",
"A42",
"A42",
"A42",
"A42",
"A42",
"A42",
"A42",
"XX7",
"A42",
"A42",
"XX9"};


// Bus Voltage variables
String mstrBusVoltLast = "--.-";
String avncsBusVoltLast = "--.-";
String mstrBusVolt = "--.-";
String avncsBusVolt = "--.-";
int mstrBusVoltInt = 0;
int avncsBusVoltInt = 0;
int avncsBusVoltIntLast = 0;
int lowVolThshld = 20;


// Last Frequency Variables
String com_1_ActvLast = "---.---";
String com_1_StbyLast = "---.---";
String nav_1_ActvLast = "---.--";
String nav_1_StbyLast = "---.--";
String xPndrLast = "----";


// Power State Variables
boolean com_1_Pwr = 0;
boolean nav_1_Pwr = 0;
boolean xPndrPwr = 0;


// Trnasponder input time out variables
unsigned long xPndrStart;
int xPndrDelay = 7000;
boolean xPndrRefresh = 1;
String SQUAWKCode = "XXXX";


void setup(){


pinMode(memRead_1_DgOutLED, OUTPUT);
pinMode(memWrite_1F_DgOutLED, OUTPUT);
pinMode(memWrite_1C_DgOutLED, OUTPUT);
pinMode(btnBckLt_1_DgOutLED,OUTPUT);
pinMode(memRead_2_DgOutLED, OUTPUT);
pinMode(memWrite_2F_DgOutLED, OUTPUT);
pinMode(memWrite_2C_DgOutLED, OUTPUT);
pinMode(btnBckLt_2_DgOutLED,OUTPUT);
pinMode(sdCrdSlctDgOut, OUTPUT);


for(int fCnt = memRead_1_DgOutLED;fCnt <= btnBckLt_2_DgOutLED;fCnt++){
digitalWrite(fCnt,HIGH);
}


for(int fCnt=0;fCnt < btnCnt; fCnt++){
pinMode(btnList[fCnt], INPUT_PULLUP);
btnStateLast[fCnt] = HIGH;
}


INIT_LED_DSP(0,24); // A sub routine that initialises the serial displays
delay(100);


// Check the state of the radio power buttons
if(digitalRead(com_1_PwrDgIn) == LOW){
com_1_Pwr = 1;
}
else{
com_1_Pwr = 0;
}
CHANNEL_MODE_LED('X',1); // A sub Routine that sets the color of the RGB channel mode LED


if(digitalRead(nav_1_PwrDgIn) == LOW){
nav_1_Pwr = 1;
}
else{
nav_1_Pwr = 0;
}
CHANNEL_MODE_LED('X',2);


if(digitalRead(xPndrPwrDgIn) == LOW){
xPndrPwr = 1;
}
else{
xPndrPwr = 0;
}


if (!SD.begin(sdCrdSlctDgOut))Serial.println("initialization failed!");


Serial.begin(115200);
}


void loop() {


{OTHER();}
{SIMCONNECT();}
{ENCODERS();}


if (Serial.available()) {
ExtTyp = getChar();


if (ExtTyp == '=') {
EQUALS();
}
if (ExtTyp == '<') {
LESSTHAN();
}
if (ExtTyp == '?') {
QUESTION();
}
if (ExtTyp == '/') {
SLASH();
}
}
}


char getChar(){
while(Serial.available() == 0);
return((char)Serial.read());
}


void GetString(int ChrCnt){
ExtVal = "";
for(int fCnt=0;fCnt<chrcnt;fcnt++){
ExtVal += getChar();
delay(10);
}
}


void OTHER(){
// Serial LED Dsiplay brightness control
dspBrghtVal = analogRead(A0);
if(dspBrghtVal != dspBrghtValLast){
dspBrghtns = map(dspBrghtVal, 0, 1023, 0, 15);
for(int fCnt=0;fCnt<dspcnt0;fcnt++) {
lc0.setIntensity(fCnt,dspBrghtns);
}
dspBrghtValLast = dspBrghtVal;
}


// Times out the transponder display if you stop partway through inputing a code
if(xPndrRefresh == 0 && SQUAWKCode != "XXXX"){
if(millis() > xPndrStart + xPndrDelay){
SQUAWK(16);
}
}
}


void SIMCONNECT(){
// Added Switch Debounce to the Sim Connect code and used the array variables to determine what swith to act on
for(int fCnt = 0; fCnt < btnCnt;fCnt++){
btnRead = digitalRead(btnList[fCnt]);
if(btnRead != btnStateLast[fCnt]){
debounceTimeLast = millis();
}
if ((millis() - debounceTimeLast) > debounceDelay) {
if (btnRead != btnState[fCnt]) {
btnState[fCnt] = btnRead;
if (btnState[fCnt] == LOW) {
switch(fCnt){
case 0: // Com Power Buttin
com_1_Pwr = 1; // Sets Power State variable to high
INIT_LED_DSP(0,10); // Initialises the LED Dsiaplays
SVN_SEG_DSP(0,6,2,com_1_ActvLast); // Sends the last tuned freq to the displays
SVN_SEG_DSP(5,6,2,com_1_StbyLast);
CHANNEL_MODE_LED('X',1); // Defaults the channel mode to normal tuning on power up
break;
case 1: // Com Act Stby Swap AND Channel Store functions
if(com_1_Pwr == 0)break; // Do nothing if radio power is off
if(chnMem_1_State == 'W'){ // Button swaps between freq and chan in Store (Write) mode
if(chnWrt_1_State == 'F'){ // Frequency Select
chnWrt_1_State = 'C'; // Channel Select
CHANNEL_MODE_LED('C',1); // Set color of RGB mode LED to Green
}
else if(chnWrt_1_State == 'C'){ // Channel Select
CHANNEL_STORE(chnWrtNo,freqWrtC,1); // Sub Routine to Store the selected freq/chan pair on the SD card
chnWrt_1_State = 'F'; // swap back to freq select mode
CHANNEL_MODE_LED('F',1); // Set color of RGB mode LED to Blue
}
}
else if(chnMem_1_State == 'X'){ // Normal tuning mode
chnWrt_1_State = 'X'; // defualt chasnnel write state to off
CHANNEL_MODE_LED('X',1); // Turn off RGB LED and turn on back light LED
Serial.println(btnString[fCnt]); // Send Sim Connect String
}
break;
case 2: // Channel Memory Mode Slector Switch Click and
if(com_1_Pwr == 0)break; // Double Click count and timer start
dblClkCnt_1++;
if(dblClkCnt_1 == 1){
dblClkStart_1 = millis();
}
break;
case 3: // Same set of functions for Nav side of radio
if(nav_1_Pwr == 0)break;
if(chnMem_2_State == 'W'){
if(chnWrt_2_State == 'F'){
chnWrt_2_State = 'C';
CHANNEL_MODE_LED('C',2);
}
else if(chnWrt_2_State == 'C'){
CHANNEL_STORE(chnWrtNo,freqWrtC,2);
chnWrt_2_State = 'F';
CHANNEL_MODE_LED('F',2);
}
}
else if(chnMem_2_State == 'X'){
chnWrt_2_State = 'X';
CHANNEL_MODE_LED('X',2);
Serial.println(btnString[fCnt]);
}
break;
case 4: // Nav Power
nav_1_Pwr = 1;
INIT_LED_DSP(10,10);
SVN_SEG_DSP(10,6,2,nav_1_ActvLast);
SVN_SEG_DSP(15,6,2,nav_1_StbyLast);
CHANNEL_MODE_LED('X',2);
break;
case 5: // Nav Radio Mode Switch
if(nav_1_Pwr == 0)break;
dblClkCnt_2++;
if(dblClkCnt_2 == 1){
dblClkStart_2 = millis();
}
break;
case 6: // Transponder Digit Inputs
case 7: //breaks intetionaly omitted for Transponser Digits
case 8:
case 9:
case 10:
case 11:
case 12:
case 13:
case 14:
case 15:
case 16:
SQUAWK(fCnt); // Transponder Sub Routine
ExtVal = "";
break;
case 17: // Transponder Power
xPndrPwr = 1;
INIT_LED_DSP(20,4);
delay(200);
SVN_SEG_DSP(20,4,99,xPndrLast);
break;
default: // All other Button Serial sends
Serial.println(btnString[fCnt]);
}
}
else if (btnState[fCnt] == HIGH) { // Opposite button condition Actions
switch(fCnt){
case 0: // Com 1 Power
com_1_Pwr = 0;
CHANNEL_MODE_LED('O',1);
KILL_LED_DSP(0,10);
chnMem_1_State = 'X';
chnWrt_1_State = 'X';
break;
case 4: // Nav 1 Power
nav_1_Pwr = 0;
CHANNEL_MODE_LED('O',2);
KILL_LED_DSP(10,10);
break;
case 17: // Transponder Power
xPndrPwr = 0;
KILL_LED_DSP(20,4);
break;
}
}
}
}
btnStateLast[fCnt] = btnRead;
if(fCnt == 2){ // Click and Double Click Capture for Radio Channel Mode Switches
if(dblClkCnt_1 == 1){
if(millis()- dblClkStart_1 > dblClkDrtn_1){
dblClkCnt_1 = 0;
CHANNEL_MODE('R',1); // Sub Routine, single click toggles between normal tuning and channel mode
}
}
else if(dblClkCnt_1 == 2){
if(millis()- dblClkStart_1 <= dblClkDrtn_1){
dblClkCnt_1 = 0;
CHANNEL_MODE('W',1); // double click toggles between frequency store mode andd normal tuning mode
}
}
}
if(fCnt == 5){ // Click and Double Click Capture for Nav Radio Mode Switches
if(dblClkCnt_2 == 1){
if(millis()- dblClkStart_2 > dblClkDrtn_2){
dblClkCnt_2 = 0;
CHANNEL_MODE('R',2);
}
}
else if(dblClkCnt_2 == 2){
if(millis()- dblClkStart_2 <= dblClkDrtn_2){
dblClkCnt_2 = 0;
CHANNEL_MODE('W',2);
}
}
}
}
}


void ENCODERS(){ // Encoder sub Routinhe
R1 =(quad_1_Otr.position()); // Outer knob Mhz tuning
if (R1 != Rold1 && com_1_Pwr == 1){
(Rdif1 = (R1-Rold1));
if (Rdif1 == 1) R1Drctn = "Down";
if (Rdif1 == -1) R1Drctn = "Up";
Rold1 = R1;


// Encoder action determined by Channel Mode


if(chnMem_1_State == 'X'){ // X = normal Standby Frequency Tuning
if (R1Drctn == "Up")Serial.println("A02");
if (R1Drctn == "Down")Serial.println("A01");
}
else if(chnMem_1_State == 'R'){ // R = channel tuning mode (Read)
if (R1Drctn == "Up")SET_CHANNEL(10,"Up",1); // Channel Display Subroutine, tens digit up/down
if (R1Drctn == "Down")SET_CHANNEL(10,"Down",1);
}
else if(chnMem_1_State == 'W'){ // W = Channel Storage mode (Write), Frequency select
if(chnWrt_1_State == 'F'){
if (R1Drctn == "Up")Serial.println("A02");
if (R1Drctn == "Down")Serial.println("A01");
}
else if(chnWrt_1_State == 'C'){ // C = Channel Storage mode (Write), Channel select
if (R1Drctn == "Up")SET_CHANNEL(10,"Up",1); // Channel Display Subroutine, ones digit up/down
if (R1Drctn == "Down")SET_CHANNEL(10,"Down",1);
}
}


}
R2 =(quad_1_Inr.position()); // Inner knob khz tuning
if (R2 != Rold2 && com_1_Pwr == 1) {
(Rdif2 = (R2-Rold2));
if (Rdif2 == 1) R2Drctn = "Down";
if (Rdif2 == -1) R2Drctn = "Up";
Rold2 = R2;


if(chnMem_1_State == 'X'){
if (R2Drctn == "Up")Serial.println("A04");
if (R2Drctn == "Down")Serial.println("A03");
}
else if(chnMem_1_State == 'R'){
if (R2Drctn == "Up")SET_CHANNEL(1,"Up",1);
if (R2Drctn == "Down")SET_CHANNEL(1,"Down",1);
}
else if(chnMem_1_State == 'W'){
if(chnWrt_1_State == 'F'){
if (R2Drctn == "Up")Serial.println("A04");
if (R2Drctn == "Down")Serial.println("A03");
}
else if(chnWrt_1_State == 'C'){
if (R2Drctn == "Up")SET_CHANNEL(1,"Up",1);
if (R2Drctn == "Down")SET_CHANNEL(1,"Down",1);
}
}


}
R3 =(quad_2_Otr.position());
if (R3 != Rold3 && nav_1_Pwr == 1) {
(Rdif3 = (R3-Rold3));
if (Rdif3 == 1) R3Drctn = "Down";
if (Rdif3 == -1) R3Drctn = "Up";
Rold3 = R3;


if(chnMem_2_State == 'X'){
if (R3Drctn == "Up")Serial.println("A14");
if (R3Drctn == "Down")Serial.println("A13");
}
else if(chnMem_2_State == 'R'){
if (R3Drctn == "Up")SET_CHANNEL(10,"Up",2);
if (R3Drctn == "Down")SET_CHANNEL(10,"Down",2);
}
else if(chnMem_2_State == 'W'){
if(chnWrt_2_State == 'F'){
if (R3Drctn == "Up")Serial.println("A14");
if (R3Drctn == "Down")Serial.println("A13");
}
else if(chnWrt_2_State == 'C'){
if (R3Drctn == "Up")SET_CHANNEL(10,"Up",2);
if (R3Drctn == "Down")SET_CHANNEL(10,"Down",2);
}
}


}
R4 =(quad_2_Inr.position());
if (R4 != Rold4 && nav_1_Pwr == 1) {
(Rdif4 = (R4-Rold4));
if (Rdif4 == 1) R4Drctn = "Down";
if (Rdif4 == -1) R4Drctn = "Up";
Rold4 = R4;


if(chnMem_2_State == 'X'){
if (R4Drctn == "Up")Serial.println("A16");
if (R4Drctn == "Down")Serial.println("A15");
}
else if(chnMem_2_State == 'R'){
if (R4Drctn == "Up")SET_CHANNEL(1,"Up",2);
if (R4Drctn == "Down")SET_CHANNEL(1,"Down",2);
}
else if(chnMem_2_State == 'W'){
if(chnWrt_2_State == 'F'){
if (R4Drctn == "Up")Serial.println("A16");
if (R4Drctn == "Down")Serial.println("A15");
}
else if(chnWrt_2_State == 'C'){
if (R4Drctn == "Up")SET_CHANNEL(1,"Up",2);
if (R4Drctn == "Down")SET_CHANNEL(1,"Down",2);
}
}


}


}


void EQUALS(){


ExtTyp = getChar();
switch(ExtTyp) {


case 'A': // Com 1 Active Freq
GetString(7); // sub routine to get extraction value
if(ExtVal != com_1_ActvLast){ // has value changed
if(com_1_Pwr == 1){ // is power on
SVN_SEG_DSP (0,6,2,ExtVal); // send extraction value to 7 segment diaply
}
com_1_ActvLast = ExtVal; // update last freq
}
ExtVal = "";
break;
case 'B': // Com 1 Standby Freq
GetString(7);
if(ExtVal != com_1_StbyLast){
if(com_1_Pwr == 1 && chnMem_1_State != 'R'){ // if power is on and channel mode is not in channel tune
if(chnMem_1_State == 'W' && chnWrt_1_State == 'F'){ // if channel mode is in Write/Freq Select Mode
SVN_SEG_DSP (0,6,2,ExtVal); // display frequency in active radio display
}
else{
SVN_SEG_DSP (5,6,2,ExtVal); // else display it in the standby display
}
}
com_1_StbyLast = ExtVal; // set last to new freq
freqWrtC[0] = com_1_StbyLast.charAt(1); // store last in char array variable for writing to SD Card
freqWrtC[1] = com_1_StbyLast.charAt(2);
freqWrtC[2] = com_1_StbyLast.charAt(4);
freqWrtC[3] = com_1_StbyLast.charAt(5);
}
ExtVal = "";
break;
case 'E': // Nav 1 Active freq
GetString(6);
if(ExtVal != nav_1_ActvLast){
if(nav_1_Pwr == 1){
SVN_SEG_DSP (10,6,2,ExtVal);
}
nav_1_ActvLast = ExtVal;
}
ExtVal = "";
break;
case 'F': // Nav 1 Standby freq
GetString(6);
if(ExtVal != nav_1_StbyLast){
if(nav_1_Pwr == 1 && chnMem_2_State != 'R'){
if(chnMem_2_State == 'W' && chnWrt_2_State == 'F'){
SVN_SEG_DSP (10,6,2,ExtVal);
}
else{
SVN_SEG_DSP (15,6,2,ExtVal);
}
}
nav_1_StbyLast = ExtVal;
freqWrtC[0] = nav_1_StbyLast.charAt(1);
freqWrtC[1] = nav_1_StbyLast.charAt(2);
freqWrtC[2] = nav_1_StbyLast.charAt(4);
freqWrtC[3] = nav_1_StbyLast.charAt(5);
}
ExtVal = "";
break;
case 'J': // Transponder freq
GetString(4);
if(ExtVal != xPndrLast){
if(xPndrRefresh == 1){ // used to freeze upates while a new code is being keyed in
if(xPndrPwr == 1){
SVN_SEG_DSP (20,4,99,ExtVal); // send squack code to display
}
}
xPndrLast = ExtVal;
}
ExtVal = "";
break;
}
}


void LESSTHAN(){


}


void QUESTION(){


ExtTyp = getChar();
switch(ExtTyp) {


case 'K':
// mstrBusVolt = "";
GetString(4);
// for (int fCnt=0;fCnt<4;fCnt++) {
// mstrBusVolt += getChar();
// delay(10);
// }
if (ExtVal != mstrBusVoltLast){
mstrBusVoltInt = ExtVal.toInt();
if (mstrBusVoltInt > lowVolThshld) {
// MASTER BUS VOLTAGE RESTORED
}
else {
// MASTER BUS VOLTAGE TOO LOW
}
mstrBusVoltLast = ExtVal;
}
ExtVal = "";
break;


case 'U':
// avncsBusVolt = "";
GetString(4);
// for (int fCnt=0;fCnt<4;fCnt++) {
// avncsBusVolt += getChar();
// delay(10);
// }
if (ExtVal != avncsBusVoltLast){
avncsBusVoltInt = ExtVal.toInt();
if (avncsBusVoltInt > lowVolThshld) {
// AVIONICS BUS VOLTAGE RESTORED
if(avncsBusVoltIntLast <= lowVolThshld && avncsBusVoltInt > lowVolThshld && mstrBusVoltInt > lowVolThshld){
INIT_LED_DSP(0,24);
}
com_1_ActvLast = "---.---";
com_1_StbyLast = "---.---";
nav_1_ActvLast = "---.--";
nav_1_StbyLast = "---.--";
xPndrLast = "----";
CHANNEL_MODE_LED('X',1);
CHANNEL_MODE_LED('X',2);
}
else {
// AVIONICS BUS VOLTAGE TOO LOW
CHANNEL_MODE_LED('O',1);
CHANNEL_MODE_LED('O',2);
KILL_LED_DSP(0,24);
delay(250);
}
avncsBusVoltLast = ExtVal;
avncsBusVoltIntLast = avncsBusVoltLast.toInt();
}
ExtVal = "";
break;
}
}


void SLASH(){


}


// sub routine to drive 7 segment displays
void SVN_SEG_DSP (int dspChrStrt,int dspChrCnt, int dspDcmPlc, String dspVal){


int dcmOfst = 0; // used to skip decimal point in string


for(int fCnt=0;fCnt<dspchrcnt;fcnt++){ ="" for="" loop="" runs="" out="" to="" count="" of="" characters="" being="" diaplyed
if(fCnt == dspDcmPlc + 1){ // sets decimal point and sets offset to skip one character
dcmOfst++;
}
else{
if(fCnt != dspDcmPlc){ // displays charcter with or without decimal point
lc0.setChar(strtPstn[0][fCnt + dspChrStrt - dcmOfst],strtPstn[1][fCnt + dspChrStrt - dcmOfst],dspVal.charAt(fCnt),false);
}
else{
lc0.setChar(strtPstn[0][fCnt + dspChrStrt - dcmOfst],strtPstn[1][fCnt + dspChrStrt - dcmOfst],dspVal.charAt(fCnt),true);
}
}
}
dcmOfst = 0;
}


// Sun Routine to kill displays for power off
void KILL_LED_DSP(int dspChrStrt,int dspChrCnt){


for(int fCnt=0;fCnt<dspchrcnt;fcnt++){
lc0.setChar(strtPstn[0][fCnt + dspChrStrt],strtPstn[1][fCnt + dspChrStrt],' ',false);
}
}


// Sub Routine to initialize displays at board powwer up and following radio power up
void INIT_LED_DSP(int dspChrStrt,int dspChrCnt){


if(dspChrStrt == 0 && dspChrCnt == 24){
for(int dsp=0;dsp<dspcnt0;dsp++) {
lc0.shutdown(dsp,false);
lc0.setIntensity(dsp,dspBrghtns);
lc0.clearDisplay(dsp);
}
}


for(int chr=0;chr<dspchrcnt;chr++){
SVN_SEG_DSP(dspChrStrt+chr,1,dspChrStrt+chr,"8");
delay(50);
}


if(dspChrStrt == 0 && (dspChrCnt == 20 || dspChrCnt == 24)){
for(int fCnt = memRead_1_DgOutLED;fCnt <= btnBckLt_2_DgOutLED;fCnt++){
digitalWrite(fCnt,LOW);
delay(200);
digitalWrite(fCnt,HIGH);
delay(200);
}
CHANNEL_MODE_LED('X',1);
CHANNEL_MODE_LED('X',2);
}


for(int chr=0;chr<dspchrcnt;chr++){
KILL_LED_DSP(dspChrStrt+chr,1);
delay(50);
}


}


// Sub Routine to set transponder code and display it
void SQUAWK(int xDig){


if(xPndrPwr == 0)return;
xDig = xDig - 6; // shifts value form button state case value to transponder digit value
char xDigC = xDig+48; // converts trnasponder button digit value to ascii char equivilent


switch(xDig){


case 0: // for any transponder value entered execute case 7
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
if (SQUAWKCode.charAt(0) == 'X'){ // if first digit is not populated set it
xPndrRefresh = 0; // suspend acting on incoming transponder extractions while inputting new squack
xPndrStart = millis(); // Start inactivity timer
SVN_SEG_DSP (20,4,99,"____"); // Change display to all underscores
SQUAWKCode.setCharAt(0, xDigC); // Store first digit in position one of Squack Code array variable
SVN_SEG_DSP (20,1,99,String(xDigC)); // Send first digit to display
}
else if (SQUAWKCode.charAt(1) == 'X'){ // Repeat above sequence for each subsequent digit entered
xPndrStart = millis();
SQUAWKCode.setCharAt(1, xDigC);
SVN_SEG_DSP (21,1,99,String(xDigC));
}
else if (SQUAWKCode.charAt(2) == 'X'){
xPndrStart = millis();
SQUAWKCode.setCharAt(2, xDigC);
SVN_SEG_DSP (22,1,99,String(xDigC));
}
else if (SQUAWKCode.charAt(3) == 'X'){
xPndrStart = millis();
SQUAWKCode.setCharAt(3, xDigC);
SVN_SEG_DSP (23,1,99,String(xDigC));
}
if(SQUAWKCode.charAt(3) != 'X'){ // After all four digits are entered send them to FSX
Serial.println("A42"+SQUAWKCode);
xPndrRefresh = 1;
SQUAWKCode = "XXXX";
}
break; // Future (can FSX empulate transponder pings?)
case 8: //Ident
break;
case 9: //VFR // b1 utton reset to 1200
Serial.println("A421200");
if(SQUAWKCode != "XXXX"){
xPndrRefresh = 1;
ExtVal = xPndrLast;
SVN_SEG_DSP (20,4,99,ExtVal);
}
break;
case 10: //Clr // Clear partial entry of squack code
if(SQUAWKCode != "XXXX"){
SQUAWKCode = "XXXX";
xPndrRefresh = 1;
ExtVal = xPndrLast;
SVN_SEG_DSP (20,4,99,ExtVal);
}
break;
}
}


</dspchrcnt;chr++){
</dspchrcnt;chr++){
</dspcnt0;dsp++)></dspchrcnt;fcnt++){
</dspchrcnt;fcnt++){></dspcnt0;fcnt++)></chrcnt;fcnt++){
</number></load></clock></datain></sd.h></ledcontrol.h>

Tom_G_2010
03-28-2014, 11:48 PM
Continued...




// Channel Mode toggle sub routine

void CHANNEL_MODE(char chMode, int radioNo){

/*
This and the remaining sub routines create the ability to set and use 32 channel presets
For each of the two radios, comm and nav. I may add dedicated button to each but for now
the mode selection is donw using the push button in the encpoders
A single click toggles the channel read mode on and off
A double click toggles the Write Mode on and off
When in write mode swap button steps from freq input, chan input, and store
*/


if(radioNo == 1){ // Radio 1 = comm radio
if(chMode == 'R'){ // channel mode sent to sub routine is Read
switch(chnMem_1_State){
case 'R': // if already in Read mode
chnMem_1_State = 'X'; // set back to normal tuning mode
chnWrt_1_State = 'X'; // set write mode to off
CHANNEL_MODE_LED('X',1); // turn off RGB LED and turn back light LED on
SVN_SEG_DSP(0,6,2,com_1_ActvLast); // restore last used freq to active display
SVN_SEG_DSP(5,6,2,com_1_StbyLast); // resotre last used freq to standby display
break;
case 'X': // mode is currently normal switch to read
case 'W': // or if mode is currently write switch to read
chnMem_1_State = 'R'; // set channel memory state variable to Read
chnWrt_1_State = 'X'; // set write state variable to off
CHANNEL_MODE_LED('R',1); // Turn on Red RGB LED
SET_CHANNEL(0,"X",1); // set standby display to show last selected memory channel
break;
}
}
else if (chMode == 'W'){ // channel mode sent to sub routine is Read
switch(chnMem_1_State){
case 'X': // mode is currently normal set to write
case 'R': // or mode is currently read set to write
chnMem_1_State = 'W'; // set channel memory state variable to Write
chnWrt_1_State = 'F'; // set channel write state variable to frequency select
CHANNEL_MODE_LED('F',1); // Turn on Blue RGB LED
SET_CHANNEL(99,"X",1); // set standby display to show no channel selected
break;
case 'W':
chnMem_1_State = 'X'; // mode is currently Write set back to normal
chnWrt_1_State = 'X'; // set write mode to off
SVN_SEG_DSP(0,6,2,com_1_ActvLast); // restore last used freq to active display
SVN_SEG_DSP(5,6,2,com_1_StbyLast); // resotre last used freq to standby display
CHANNEL_MODE_LED('X',1); // turn off RGB LED and turn back light LED on
break;
}
}
}


else if(radioNo == 2){ // All the same for the Nav Radio
if(chMode == 'R'){
switch(chnMem_2_State){
case 'X':
chnMem_2_State = 'R';
chnWrt_2_State = 'X';
CHANNEL_MODE_LED('R',2);
SET_CHANNEL(0,"X",2);
break;
case 'R':
chnMem_2_State = 'X';
chnWrt_2_State = 'X';
CHANNEL_MODE_LED('X',2);
SVN_SEG_DSP(10,6,2,nav_1_ActvLast);
SVN_SEG_DSP(15,6,2,nav_1_StbyLast);
break;
case 'W':
chnMem_2_State = 'R';
chnWrt_2_State = 'X';
CHANNEL_MODE_LED('R',2);
SET_CHANNEL(0,"X",2);
break;
}
}
else if (chMode == 'W'){
switch(chnMem_2_State){
case 'X':
chnMem_2_State = 'W';
chnWrt_2_State = 'F';
CHANNEL_MODE_LED('F',2);
SET_CHANNEL(99,"X",2);
break;
case 'R':
chnMem_2_State = 'W';
chnWrt_2_State = 'F';
CHANNEL_MODE_LED('F',2);
SET_CHANNEL(99,"X",2);
break;
case 'W':
chnMem_2_State = 'X';
chnWrt_2_State = 'X';
SVN_SEG_DSP(10,6,2,nav_1_ActvLast);
SVN_SEG_DSP(15,6,2,nav_1_StbyLast);
CHANNEL_MODE_LED('X',2);
break;
}
}
}
}


// Sub Routine to control the channel selection and display


void SET_CHANNEL(int dgtMlt, String chnDrctn, int radioNo){


int dspNo;
int chnNoDsp[2] = {
0,1 }; // channel selection array
dspNo = 0;


if(radioNo == 1){ // code for radio 1 - Comm
chnNoDsp[0] = memChnRad1[0]; // Read last selected channel tens digit into temp variable
chnNoDsp[1] = memChnRad1[1]; // read last selected channel ones digit onto temp variable
}
else if(radioNo == 2){
chnNoDsp[0] = memChnRad2[0];
chnNoDsp[1] = memChnRad2[1];
}


if(dgtMlt == 10){ // Tens digit is being changed
if(chnDrctn == "Up"){ // incremented up by encoder
chnNoDsp[0]++; // increment the temp variable
if(chnNoDsp[0] > 2 && chnNoDsp[1] > 2){ // The next few if statements insure that the tens digit can never go above three
chnNoDsp[0] = 0; // but instead wraps back around to 0 or 1 depending on the ones digit.
}
if(chnNoDsp[0] > 3 && chnNoDsp[1] == '0'){
chnNoDsp[0] = 1;
}
if(chnNoDsp[0] > 3){
chnNoDsp[0] = 0;
}
}
else if(chnDrctn == "Down"){ // Similar to the tens digit increment code but for tens digit decrement
chnNoDsp[0]--;
if(chnNoDsp[0] < 1 && chnNoDsp[1] == 0){ // These if statements ensure the tens digit can never go below 0 OR
chnNoDsp[0] = 3; // below 1 if the ones digit is a zero
}
if(chnNoDsp[0] < 0 && chnNoDsp[1] < 3){
chnNoDsp[0] = 3;
}
if(chnNoDsp[0] < 0 && chnNoDsp[1] > 2){
chnNoDsp[0] = 2;
}
}
}
else if(dgtMlt == 1){ // Increment code for the ones digit
if(chnDrctn == "Up"){
chnNoDsp[1]++;
if(chnNoDsp[1] > 2 && chnNoDsp[0] == 3){ // ensures the ones digit wraps form 9 back around
chnNoDsp[1] = 0; // except when the tens digits is a 3 in which case it wraps after 2
} // And the wrap will be to 1 if the tens digit is a 0
if(chnNoDsp[1] > 9 && chnNoDsp[0] == 0){ // Or to 1 if the tens digit is anything else
chnNoDsp[1] = 1;
}
if(chnNoDsp[1] > 9){
chnNoDsp[1] = 0;
}
}
else if(chnDrctn == "Down"){
chnNoDsp[1]--;
if(chnNoDsp[1] < 1 && chnNoDsp[0] == 0){
chnNoDsp[1] = 9;
}
if(chnNoDsp[1] < 0 && chnNoDsp[0] == 3){
chnNoDsp[1] = 2;
}
if(chnNoDsp[1] < 0){
chnNoDsp[1] = 9;
}
}
}


if(dgtMlt == 99){ // Sets the default starting display when entering one of the memory modes
if(radioNo == 1){ // 99 is used for the defaut start to the Write mode
SVN_SEG_DSP (0,11,2,"---.-- ch--");
}
else if(radioNo == 2){
SVN_SEG_DSP (10,11,2,"---.-- ch--");
}
}
else{ // Else shows the approriate channel value in the Standby slot
if(radioNo == 1){
SVN_SEG_DSP (5,5,2," ch--");
SVN_SEG_DSP (8,1,99,String(chnNoDsp[0]));
SVN_SEG_DSP (9,1,99,String(chnNoDsp[1]));
}
else if(radioNo == 2){
SVN_SEG_DSP (15,5,2," ch--");
SVN_SEG_DSP (18,1,99,String(chnNoDsp[0]));
SVN_SEG_DSP (19,1,99,String(chnNoDsp[1]));
}
}


if(radioNo == 1){ // Store the last selected channel
memChnRad1[0] = chnNoDsp[0];
memChnRad1[1] = chnNoDsp[1];
}
else if(radioNo == 2){
memChnRad2[0] = chnNoDsp[0];
memChnRad2[1] = chnNoDsp[1];
}


//Read the selected channel or Define channel for Writing


if(radioNo == 1){
if(chnMem_1_State == 'R'){ // If in Read Mode
int chN = chnNoDsp[0]*10 + chnNoDsp[1]; // format channel
CHANNEL_READ(chN,1); // Channel Read Sub Routine
if(chnFreqS == "----"){ // If returned channel memory is blank
SVN_SEG_DSP (0,6,2,"---.---"); // display all dashes
}
else{
Serial.println("A05"+chnFreqS); // Otherwise tune radio to slected channel
}
}
else if(chnMem_1_State == 'W'){ // If in Write Mode
chnWrtNo = chnNoDsp[0]*10 + chnNoDsp[1]; // Set Channel Write Number
}
}
else if(radioNo == 2){ // Same for Radio 2 - Nav
if(chnMem_2_State == 'R'){
int chN = chnNoDsp[0]*10 + chnNoDsp[1];
CHANNEL_READ(chN,2);
if(chnFreqS == "----"){
SVN_SEG_DSP (10,6,2,"---.---");
}
else{
Serial.println("A17"+chnFreqS);
}
}
else if(chnMem_2_State == 'W'){
chnWrtNo = chnNoDsp[0]*10 + chnNoDsp[1];
}
}




} //End of Set Channel


// Channel Read Sub Routine
void CHANNEL_READ(int chnNo, int radioNo){


char fileExtradioNo = 0; //Clear file Extention Radio Number variable


if(radioNo == 1){ // For Radsio 1 - Comm
fileExtradioNo = '1'; // Set Radio number portion of file name variable
}
else if(radioNo == 2){ // Or for Rasdio 2 - Nav
fileExtradioNo = '2';
}


char fileName[] = "CHNMEM00.RD0"; // Set Defualt File Name to read
int onesDigit = 0; // Set defuial channel number ones digit to 0
int tensDigit = chnNo / 10; // Extracxt tens digit form channel number
if(tensDigit > 0){ // set ones digit if channel is above 09
onesDigit = chnNo - (tensDigit * 10); // Then set ones digit
}
else{
onesDigit = chnNo; // Otherwise juct setr ones digit
}


fileName[6] = tensDigit + '0'; // Modifiy file names to read requested channel memory
fileName[7] = onesDigit + '0';
fileName[11] = fileExtradioNo;


sdCrdFile = SD.open(fileName); // open selected file on the SD Card
if (sdCrdFile) { // If opened ok Read selected file contents
sdCrdFile.seek(0); // Start Readomg file contents from position 0
chnFreqC[0] = sdCrdFile.read(); // Store read channel in character array variable
chnFreqC[1] = sdCrdFile.read(); // as it is read one character at a time
chnFreqC[2] = sdCrdFile.read();
chnFreqC[3] = sdCrdFile.read();
chnFreqS = String(chnFreqC); // Convert character array to String
sdCrdFile.close(); // Close the file on the SD Card
}
else {
Serial.println("ERROR Reading Freq"); // Trouble shooting error message
}
}




// Channel Sore Sub routine
void CHANNEL_STORE(int chnNo, String chnFrq, int radioNo){


char fileExtradioNo = 0; // Same file name setup steps as with channel read


if(radioNo == 1){
fileExtradioNo = '1';
}
else if(radioNo == 2){
fileExtradioNo = '2';
}


char fileName[] = "CHNMEM00.RD0";
int onesDigit = 0;
int tensDigit = chnNo / 10;
if(tensDigit > 0){
onesDigit = chnNo - (tensDigit * 10);
}
else{
onesDigit = chnNo;
}


fileName[6] = tensDigit + '0';
fileName[7] = onesDigit + '0';
fileName[11] = fileExtradioNo;


sdCrdFile = SD.open(fileName, FILE_WRITE); // Opne selected file on SD Card
if (sdCrdFile) {
sdCrdFile.seek(0); // Start writing to file at position zero
sdCrdFile.print(chnFrq); // Store slected frequency
sdCrdFile.close(); // Close file




CHANNEL_MODE_LED('X',radioNo); // Blink Channel Mode LED twice green if file stored ok
delay(500);
CHANNEL_MODE_LED('C',radioNo);
delay(500);
CHANNEL_MODE_LED('X',radioNo);
delay(500);
CHANNEL_MODE_LED('C',radioNo);
delay(500);
}
else {
Serial.println("ERROR Storing Freq"); // If file did not sore ok blink channel LED Red three times


CHANNEL_MODE_LED('X',radioNo);
delay(250);
CHANNEL_MODE_LED('R',radioNo);
delay(250);
CHANNEL_MODE_LED('X',radioNo);
delay(250);
CHANNEL_MODE_LED('R',radioNo);
delay(250);
CHANNEL_MODE_LED('X',radioNo);
delay(250);
CHANNEL_MODE_LED('R',radioNo);
delay(250);
CHANNEL_MODE_LED('X',radioNo);


}
}


// Channel Mode LED Sub Rouitine
void CHANNEL_MODE_LED(char ledMode, int radioNo){


// Set state of RGB LED


int pinShft = 0; // Variable to switch between the two channel Mode LEDS


if(radioNo == 1){ // Use first four digital outputs for radio one RGB LED
pinShft = 0;
}
else if(radioNo == 2){ // Use second four digital outputs for radio one RGB LED
pinShft = 4;
}
else{
return;
}


if(ledMode == 'X' && radioNo == 1){ // Modify requested Channel Mem LED Mode based on radio being on or off
if(com_1_Pwr == 1){
ledMode = 'X';
}
else if(com_1_Pwr == 0){
ledMode = 'O';
}
}


if(ledMode == 'X' && radioNo == 2){
if(nav_1_Pwr == 1){
ledMode = 'X';
}
else if(nav_1_Pwr == 0){
ledMode = 'O';
}
}


switch(ledMode){
case 'R': // Red LED On for Read
digitalWrite(memRead_1_DgOutLED + pinShft, LOW);
digitalWrite(memWrite_1F_DgOutLED + pinShft, HIGH);
digitalWrite(memWrite_1C_DgOutLED + pinShft, HIGH);
digitalWrite(btnBckLt_1_DgOutLED + pinShft, HIGH);
break;
case 'F': // Blue LED On for Write, Freq Select
digitalWrite(memRead_1_DgOutLED + pinShft, HIGH);
digitalWrite(memWrite_1F_DgOutLED + pinShft, LOW);
digitalWrite(memWrite_1C_DgOutLED + pinShft, HIGH);
digitalWrite(btnBckLt_1_DgOutLED + pinShft, HIGH);
break;
case 'C': // Green LED On for Write, Chan Select
digitalWrite(memRead_1_DgOutLED + pinShft, HIGH);
digitalWrite(memWrite_1F_DgOutLED + pinShft, HIGH);
digitalWrite(memWrite_1C_DgOutLED + pinShft, LOW);
digitalWrite(btnBckLt_1_DgOutLED + pinShft, HIGH);
break;
case 'X': // Stanard backlight LED On for Normal Mode
digitalWrite(memRead_1_DgOutLED + pinShft, HIGH);
digitalWrite(memWrite_1F_DgOutLED + pinShft, HIGH);
digitalWrite(memWrite_1C_DgOutLED + pinShft, HIGH);
digitalWrite(btnBckLt_1_DgOutLED + pinShft, LOW);
break;
case 'O': // All LEDs off for radio power off or loss of bus voltage.
digitalWrite(memRead_1_DgOutLED + pinShft, HIGH);
digitalWrite(memWrite_1F_DgOutLED + pinShft, HIGH);
digitalWrite(memWrite_1C_DgOutLED + pinShft, HIGH);
digitalWrite(btnBckLt_1_DgOutLED + pinShft, HIGH);
break;
}
}