-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathLCD_and_CDI_1.0.ino
1378 lines (1232 loc) · 46 KB
/
LCD_and_CDI_1.0.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
LCD & CDI for FS2020
--------------------
This program uses two alphanumeric LCDs and 2 LED bars
to show and manage some in-flight parameters for FS2020.
The 2 LCDs are used to:
1) Radio - display & edit stack radio NAV1, NAV2 e ADF
2) Flight parameter - display some flight parameters (IAS, HDG, etc)
The communications with the simulator is made
using "FS2020TA.exe" on the PC side.
For the documentation see:
https://github.com/IWILZ/FS2020-LCD-Panel/blob/main/README.md
UPDATE LOG
----------
V 1.0.0 -> First english version.
IN_BUTTON and OUT_LED_3 still not used.
*/
#define PROGRAM_NAME1 "LCD & CDI FS2020"
#define PROGRAM_NAME2 "V 1.0.0"
#define PROGRAM_NAME3 "Initializing..."
#include <Arduino.h>
#include <BasicEncoder.h> // Rotary encoder library
#include <LiquidCrystal_I2C.h> // Manages serial communications with LCD 16x2
#include <Grove_LED_Bar.h> // Manages LED bars
/*************************************************************
Parameter IDs received from FS2020
*************************************************************/
#define ID_ADF_HDG 9 // ADF CARD (degrees HDG ADF)
#define ID_ADF_ACT_FREQ 7 // ADF ACTIVE FREQUENCY
#define ID_NAV_ACT_FREQ 502 // NAV 1 & 2 ACTIVE FREQ
#define ID_NAV_SBY_FREQ 526 // NAV 1 & 2 STANDBY FREQ
#define ID_NAV_OBS 519 // OBS 1 & 2 (degrees)
#define ID_HEADING 413 // HEADING INDICATOR
#define ID_AIRSPEED 37 // AIRSPEED INDICATED
#define ID_ALTITUDE 431 // INDICATED ALTITUDE
#define ID_QFE 557 // PLANE ALT ABOVE GROUND
#define ID_VARIOMETER 763 // VERTICAL SPEED
#define ID_NAV_CDI 505 // NAV CDI value of VORx/NAVx (range -127...+127) (index 1/2)
#define ID_NAV_HAS_NAV 516 // (Bool) NAVx active (index 1/2)
#define ID_NAV_CODES 506 // Binary mask for NAVx state (index 1/2)
#define NUM_FS_PARAM 19 // Number of parameters from FS2020
/*************************************************************
Commands to FS2020
*************************************************************/
#define NAV1_INC_MHZ "@568/$" // NAV1_RADIO_WHOLE_INC
#define NAV2_INC_MHZ "@577/$" // NAV2_RADIO_WHOLE_INC
#define NAV1_DEC_MHZ "@567/$" // NAV1_RADIO_WHOLE_DEC
#define NAV2_DEC_MHZ "@576/$" // NAV2_RADIO_WHOLE_DEC
#define NAV1_INC_KHZ "@564/$" // NAV1_RADIO_FRACT_INC_CARRY
#define NAV2_INC_KHZ "@573/$" // NAV2_RADIO_FRACT_INC_CARRY
#define NAV1_DEC_KHZ "@562/$" // NAV1_RADIO_FRACT_DEC_CARRY
#define NAV2_DEC_KHZ "@571/$" // NAV2_RADIO_FRACT_DEC_CARRY
#define NAV1_SWAP "@566/$" // NAV1_RADIO_SWAP
#define NAV2_SWAP "@575/$" // NAV2_RADIO_SWAP
#define OBI1_INC "@972/$" // VOR1_OBI_INC
#define OBI1_DEC "@971/$" // VOR1_OBI_DEC
#define OBI2_INC "@975/$" // VOR2_OBI_INC
#define OBI2_DEC "@974/$" // VOR2_OBI_DEC
#define ADF_100_INC "@8/$" // ADF_100_INC
#define ADF_100_DEC "@7/$" // ADF_100_DEC
#define ADF_1_INC "@19/$" // ADF1_WHOLE_INC
#define ADF_1_DEC "@18/$" // ADF1_WHOLE_DEC
#define ADF_HDG_INC "@10/$" // ADF_CARD_INC
#define ADF_HDG_DEC "@9/$" // ADF_CARD_DEC
#define ADF_FRACT_INC_CARRY "@14/$" // Inc, ADF 1 freq. by 0.1 KHz, with carry
#define ADF_FRACT_DEC_CARRY "@13/$" // Dec, ADF 1 freq. by 0.1 KHz, with carry
// Editing buttons
#define BTN_ENC 4 // D4 - Encoder button x "Start editing" & "CONFIRM new value"
#define BTN_EXT 5 // D5 - Button x "Abort editing"
// Other I/O pins
#define IN_BUTTON A0 // Button next to 3 LEDs over LED bars
#define OUT_LED_1 A1 // 1° LED over LED bars
#define OUT_LED_2 A2 // 2° LED over LED bars
#define OUT_LED_3 A3 // 3° LED over LED bars
#define OUT_LED_CDI 11 // LED between the 2 LED bars
#define N_STATUS_MAIN 5 // Number of states of the finite-state machine on the Radio LCD
#define N_VAL 10 // Number of values used by CalcMeanValue()
#define VAL_ALT 0 // CalcMeanValue() works on Altitude values
#define VAL_VARIO 1 // CalcMeanValue() works on Vertical Speed values
#define ASCII_ARROW (char)0x7f // Simbol code showing the actual parameter edited for frequency and HDG
#define MAX_COUNT_ALT_VAR 40 // Number of cycles to switch between QFE/vert.speed on the parameter LCD
// Defines for LED bars
#define CDI_ZERO_RANGE 5 // Value range to swicth-on central LED
#define CDI_BAR_RANGE 3 // Minimum value to switch-on the first LED on the bars
/*************************************************************
GLOBAL VARIABLES
*************************************************************/
// Pins D2 & D3 must be used on the Arduino Nano to manage hardware
// interrupts provided by rotation of the encoder.
const int8_t EncoderPin1 = 3;
const int8_t EncoderPin2 = 2;
float PrevActNav1, PrevSbyNav1; // Previous NAV1 frequencies
float PrevActNav2, PrevSbyNav2; // Previous NAV2 frequencies
int PrevNavObs1, PrevNavObs2; // Previous OBS 1 e 2 radials
float PrevAdf; //
int PrevHdg = 999; //
int PrevVario, PrevAltezza; // Previous QFE & vert. speed
int PrevLedCdi; //
int CountAltVar = 0, CountSlowDown = 0;
bool ShowVario = false; //
int ValArray[2][N_VAL]; // Used by CalcMeanValue()
long int MeanVal; // Used by CalcMeanValue()
int Vor1Active=0, Vor2Active=0;
int PrevVORActive=0;
/*********** Few vars useful for some debugging ****************/
unsigned long time_prev=0L, time_now=0L;
String dummy, tmp_str;
// ************** Struct of data received from FS2020 ******************
struct t_FromFS {
int id;
int index;
String value;
};
t_FromFS FromFS;
// Array storing all the parameters received from FS2020
// Each "value" field is filled by GetParamFromFS2020()
t_FromFS FromFSArray[NUM_FS_PARAM] = {
{ID_ADF_HDG, -1, "0"}, // 0
{ID_ADF_ACT_FREQ, 1, "0.0"}, // 1
{ID_NAV_ACT_FREQ, 1, "0.0"}, // 2
{ID_NAV_ACT_FREQ, 2, "0.0"}, // 3
{ID_NAV_SBY_FREQ, 1, "0.0"}, // 4
{ID_NAV_SBY_FREQ, 2, "0.0"}, // 5
{ID_NAV_OBS, 1, "0"}, // 6
{ID_NAV_OBS, 2, "0"}, // 7
{ID_HEADING, -1, "0"}, // 8
{ID_AIRSPEED, -1, "0"}, // 9
{ID_ALTITUDE, -1, "0"}, // 10
{ID_QFE, -1, "0"}, // 11
{ID_VARIOMETER, -1, "0"}, // 12
{ID_NAV_CDI, 1, "0"}, // 13
{ID_NAV_CDI, 2, "0"}, // 14
{ID_NAV_HAS_NAV, 1, "0"}, // 15
{ID_NAV_HAS_NAV, 2, "0"}, // 16
{ID_NAV_CODES, 1, "0"}, // 17
{ID_NAV_CODES, 2, "0"} // 18
};
// Define of each position inside the previous array of struct
#define POS_ADF_HDG 0 // ADF CARD (degrees HDG ADF)
#define POS_ADF_ACT_FREQ 1 // ADF ACTIVE FREQUENCY
#define POS_NAV_ACT_FREQ1 2 // NAV 1 & 2 ACTIVE FREQ
#define POS_NAV_ACT_FREQ2 3 // NAV 1 & 2 ACTIVE FREQ
#define POS_NAV_SBY_FREQ1 4 // NAV 1 & 2 STANDBY FREQ
#define POS_NAV_SBY_FREQ2 5 // NAV 1 & 2 STANDBY FREQ
#define POS_NAV_OBS1 6 // OBS 1 & 2 (degrees)
#define POS_NAV_OBS2 7 // OBS 1 & 2 (degrees)
#define POS_HEADING 8 // HEADING INDICATOR
#define POS_AIRSPEED 9 // AIRSPEED INDICATED
#define POS_ALTITUDE 10 // INDICATED ALTITUDE
#define POS_QFE 11 // PLANE ALT ABOVE GROUND
#define POS_VARIOMETER 12 // VERTICAL SPEED
#define POS_NAV_CDI1 13 // NAV CDI value of VORx/NAVx (range -127...+127) (index 1/2)
#define POS_NAV_CDI2 14 // NAV CDI value of VORx/NAVx (range -127...+127) (index 1/2)
#define POS_NAV_HAS_NAV1 15 // (Bool) NAV1 active
#define POS_NAV_HAS_NAV2 16 // (Bool) NAV2 active
#define POS_NAV_CODES1 17 // (Mask) NAV1 detail
#define POS_NAV_CODES2 18 // (Mask) NAV2 detail
// *****************************************************
// Starting status of the main finite-state machine
int StatusMain = 1, PrevStatusMain = -1;
// There is also a secondary finite-state machine for the
// editing functions of NAV (with OBS) and ADF (with HDG).
int StatusEdit;
// ********* Defines of LCDs, encoder and LED bars **************
LiquidCrystal_I2C lcdRadio = LiquidCrystal_I2C(0x26, 16, 2); // Radio Stack
LiquidCrystal_I2C lcdParam = LiquidCrystal_I2C(0x27, 16, 2); // IAS, ALTITUDE, ecc
// Encoder
BasicEncoder encoder(EncoderPin1, EncoderPin2);
// LED bars
Grove_LED_Bar BarL(7, 8, 1); // Clock pin=D7, Data pin=D8, Orientation
Grove_LED_Bar BarR(9, 10, 1); // Clock pin=D9, Data pin=D10, Orientation
// ***********************************************************************
// Interrupt Service Routine --> detects each "click" of the encoder
// ***********************************************************************
void ISRoutine()
{
encoder.service();
}
// ***********************************************************************
// setup()
// ***********************************************************************
void setup() {
// USB initialization
Serial.begin(115200);
Serial.setTimeout(3);
// before to start i write something on each LCD just for test
ChkLCDs();
BarL.begin();
BarR.begin();
// Switches off each LED on bars
BarL.setLevel(0);
BarR.setLevel(0);
CheckBars();
pinMode(OUT_LED_1, OUTPUT);
pinMode(OUT_LED_2, OUTPUT);
pinMode(OUT_LED_3, OUTPUT);
pinMode(OUT_LED_CDI, OUTPUT);
pinMode(IN_BUTTON, INPUT_PULLUP);
pinMode(BTN_ENC, INPUT_PULLUP);
pinMode(BTN_EXT, INPUT_PULLUP);
// Setup Encoder
pinMode(EncoderPin1, INPUT_PULLUP);
pinMode(EncoderPin2, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(EncoderPin1), ISRoutine, CHANGE);
attachInterrupt(digitalPinToInterrupt(EncoderPin2), ISRoutine, CHANGE);
CheckLEDs(); // Switches on each LED for a while for test
delay(300);
InitLCDs();
} // setup()
// ***********************************************************************
// loop()
// ***********************************************************************
void loop() {
String strTmp;
int int_tmp;
// Reads a parameter from FS stores it into FromFSArray[]
GetParamFromFS2020();
// The VORs status (and CDI) is checked at each loop
CheckVORs();
// Updates the status of the finite-state machine checking the encoder "clicks"
StatusMain += encoder.get_change();
if (StatusMain < 1) StatusMain = N_STATUS_MAIN - StatusMain;
if (StatusMain > N_STATUS_MAIN) StatusMain = StatusMain - N_STATUS_MAIN;
// Shows flight parameters
ShowFlightParam();
// Reads again a parameter from FS stores it into FromFSArray[]
// in this way i can update the parameter list 2 times/loop
GetParamFromFS2020();
// What is the current status?
switch (StatusMain) {
case 1: // Act Nav1 & Nav2 + OBS1 & OBS2
// The Radio LCD layout is drawn every time the previous status was different
if (PrevStatusMain != 1) {
ShowDisplayRadio();
}
// --------- Reads both active frequencies from the array ----------
PrevActNav1 = FromFSArray[POS_NAV_ACT_FREQ1].value.toFloat();
PrevActNav2 = FromFSArray[POS_NAV_ACT_FREQ2].value.toFloat();
// --------------- Reads both OBS from the array -------------------
PrevNavObs1 = FromFSArray[POS_NAV_OBS1].value.toInt();
PrevNavObs2 = FromFSArray[POS_NAV_OBS2].value.toInt();
// ------------- We can show NAV1 & NAV2 on two lines ----------------
ShowNav(PrevActNav1, PrevNavObs1, 1); // NAV1 on the first row
ShowNav(PrevActNav2, PrevNavObs2, 2); // NAV2 on the second row
PrevStatusMain = 1;
break;
case 2: // ADF & HDG
// The Radio LCD layout is drawn every time the previous status was different
if (PrevStatusMain != 2) {
ShowDisplayRadio();
}
PrevAdf = FromFSArray[POS_ADF_ACT_FREQ].value.toFloat();
PrevHdg = FromFSArray[POS_ADF_HDG].value.toInt();
ShowAdf (PrevAdf, PrevHdg, 1); // show ADF freq and HDG on the first row
PrevStatusMain = 2;
break;
case 3: // Edit Nav1 (stdby) & OBS1
// The Radio LCD layout is drawn every time the previous status was different
if (PrevStatusMain != 3) {
ShowDisplayRadio();
}
// Read stby freq of NAV1 from the array
PrevSbyNav1 = FromFSArray[POS_NAV_SBY_FREQ1].value.toFloat();
ShowNav(PrevSbyNav1, PrevNavObs1, 2);
// Is the encoder button pressed? (to start editing)
if (ButtonActive(BTN_ENC)) {
EditNav(PrevSbyNav1, PrevNavObs1, 1); // go to edit NAV1
}
PrevStatusMain = 3;
break;
case 4: // Edit Nav2 (stdby) & OBS2
// The Radio LCD layout is drawn every time the previous status was different
if (PrevStatusMain != 4) {
ShowDisplayRadio();
}
// Read stby freq of NAV2 from the array
PrevSbyNav2 = FromFSArray[POS_NAV_SBY_FREQ2].value.toFloat();
ShowNav(PrevSbyNav2, PrevNavObs2, 2);
// Is the encoder button pressed? (to start editing)
if (ButtonActive(BTN_ENC)) {
EditNav(PrevSbyNav2, PrevNavObs2, 2); // go to edit NAV2
}
PrevStatusMain = 4;
break;
case 5: // Edit ADF & HDG
// The Radio LCD layout is drawn every time the previous status was different
if (PrevStatusMain != 5) {
ShowDisplayRadio();
}
// Read ADF freq and HDG from the array
PrevAdf = FromFSArray[POS_ADF_ACT_FREQ].value.toFloat();
PrevHdg = FromFSArray[POS_ADF_HDG].value.toInt();
ShowAdf (PrevAdf, PrevHdg, 2);
// Is the encoder button pressed? (to start editing)
if (ButtonActive(BTN_ENC)) {
EditAdf(PrevAdf, PrevHdg); // go to edit ADF freq & HDG
}
PrevStatusMain = 5;
break;
} // switch
} // loop()
/***********************************************************
ShowNav - Shows NavX freq. & OBSX on the row number "Row"
***********************************************************/
void ShowNav(float Nav, int Obs, byte Row) {
float ActNav;
char str[5];
// To achieve the format NNN.DD we need to divide
// the frequency by 1000
ActNav = Nav / 1000.0;
lcdRadio.setCursor(4, Row - 1);
lcdRadio.print(ActNav);
sprintf (str, "%03d", Obs);
lcdRadio.setCursor(13, Row - 1);
lcdRadio.print(str);
} // ShowNav()
/***********************************************************
ShowAdf - Shows ADF active frequency and HDG on the row "Row"
***********************************************************/
void ShowAdf(float Adf, int Hdg, byte Row) {
char str_val[8];
// *********** WARNING *************
// Floating to string conversion using sprintf() don't works
// The statement sprintf(str_val,"%6.1f",Adf)
// produces a "?" into str_val
// To solve this problem i use dtostrf()
lcdRadio.setCursor(4, Row - 1);
dtostrf(Adf, 6, 1, str_val); // Works great!
lcdRadio.print(str_val);
sprintf (str_val, "%03d", Hdg);
lcdRadio.setCursor(13, Row - 1);
lcdRadio.print(str_val);
} // ShowAdf()
/***********************************************************
InitLCDs
***********************************************************/
void InitLCDs() {
// Radio stack LCD initialization
lcdRadio.init();
lcdRadio.backlight();
// Ready for the status number 1
lcdRadio.setCursor(0, 0);
lcdRadio.print("N1: -");
lcdRadio.setCursor(0, 1);
lcdRadio.print("N2: -");
// Flight parameter LCD initialization
lcdParam.init();
lcdParam.backlight();
lcdParam.setCursor(0, 0);
lcdParam.print("IAS: HDG: ");
lcdParam.setCursor(0, 1);
lcdParam.print("A/V: / ");
} // InitLCDs()
/***********************************************************
ShowDisplayRadio
***********************************************************/
void ShowDisplayRadio() {
// Initializes the Radio LCD according to StatusMain value
switch (StatusMain) {
case 1:
lcdRadio.clear();
lcdRadio.setCursor(0, 0);
lcdRadio.print("N1: -");
lcdRadio.setCursor(0, 1);
lcdRadio.print("N2: -");
break;
case 2:
lcdRadio.clear();
lcdRadio.setCursor(0, 0);
lcdRadio.print("ADF: -");
break;
case 3:
lcdRadio.clear();
lcdRadio.setCursor(0, 0);
lcdRadio.print("-- Edit NAV 1 --");
lcdRadio.setCursor(0, 1);
lcdRadio.print("S1: -");
break;
case 4:
lcdRadio.clear();
lcdRadio.setCursor(0, 0);
lcdRadio.print("-- Edit NAV 2 --");
lcdRadio.setCursor(0, 1);
lcdRadio.print("S2: -");
break;
case 5:
lcdRadio.clear();
lcdRadio.setCursor(0, 0);
lcdRadio.print("--- Edit ADF ---");
lcdRadio.setCursor(0, 1);
lcdRadio.print("ADF: -");
break;
} // switch
} // ShowDisplayRadio
/***********************************************************
ButtonActive
Checks a button status implementing a simple anti-bounce
***********************************************************/
bool ButtonActive(byte Button) {
bool active = false;
if (digitalRead(Button) == LOW) {
delay(30);
if (digitalRead(Button) == LOW) {
active = true;
}
}
// If button active i will wait until it will be released
if (active) {
do {
// just wait for the release
} while (digitalRead(Button) == LOW);
// delay anti-bounce
delay(20);
return (true);
}
else return (false);
} // ButtonActive()
/***********************************************************
EditNav - edit NAVx frequency and OBS
***********************************************************/
void EditNav(float Nav, int Obs, byte NavNumber) {
float ActNav, NavTmp, NavOrig;
char str[5];
bool continue_loop = true, abort_edit = false;
int encoderClick = 0, ObsTmp, ObsOrig;
bool switch_flag=true;
// Write constant strings on the LCD
lcdRadio.clear();
lcdRadio.setCursor(0, 0);
lcdRadio.print("NAV Frq:");
lcdRadio.setCursor(3, 0);
lcdRadio.print(NavNumber);
lcdRadio.setCursor(0, 1);
lcdRadio.print("Sw:Y OBS:");
NavOrig = Nav;
ObsOrig = Obs;
NavTmp = Nav;
ObsTmp = Obs;
// To achieve the format NNN.DD we need to divide
// the frequency by 1000
ActNav = NavTmp / 1000.0;
lcdRadio.setCursor(9, 0);
lcdRadio.print(ActNav);
sprintf (str, "%03d", ObsTmp);
lcdRadio.setCursor(12, 1);
lcdRadio.print(str);
// Blinka the cursor on the arrow
lcdRadio.setCursor(12, 0);
// this symbol shows which is the parameter we are editing
lcdRadio.print(ASCII_ARROW);
lcdRadio.setCursor(12, 0);
lcdRadio.blink();
// Secondary finite-state machine for the editing
StatusEdit = 1; // We start editing MHz
do {
// Which is the status?
switch (StatusEdit) {
case 1: // Edit MHz
encoderClick = encoder.get_change();
if (encoderClick > 0) {
NavTmp = NavTmp + 1000.0;
if (NavTmp > 117950.0) NavTmp = 108000.0;
}
if (encoderClick < 0) {
NavTmp = NavTmp - 1000.0;
if (NavTmp < 108000.0) NavTmp = 117950.0;
}
// We need to update the MHz?
if (encoderClick != 0) {
ActNav = NavTmp / 1000.0;
lcdRadio.setCursor(9, 0);
lcdRadio.print(ActNav);
// Blink the cursor on the decimal point
lcdRadio.setCursor(12, 0);
lcdRadio.print(ASCII_ARROW);
lcdRadio.setCursor(12, 0);
}
// Is the encoder button pressed?
if (ButtonActive(BTN_ENC)) {
StatusEdit = 2; // go to the next status
lcdRadio.setCursor(12, 0);
lcdRadio.print(".");
lcdRadio.setCursor(15, 0);
lcdRadio.print(ASCII_ARROW);
}
// is the BTN_EXT (abort) pressed?
if (ButtonActive(BTN_EXT)) {
abort_edit = true; // Abort edit
continue_loop = false;
}
break;
case 2: // Edit KHz
// Blink the cursor after the decimal digits
lcdRadio.setCursor(15, 0);
encoderClick = encoder.get_change();
if (encoderClick > 0) {
NavTmp = NavTmp + 50.0;
if (NavTmp > 117950.0) NavTmp = 108000.0;
}
if (encoderClick < 0) {
NavTmp = NavTmp - 50.0;
if (NavTmp < 108000.0) NavTmp = 117950.0;
}
// We need to update the frequency?
if (encoderClick != 0) {
ActNav = NavTmp / 1000.0;
lcdRadio.setCursor(9, 0);
lcdRadio.print(ActNav);
}
// Is the encoder button pressed?
if (ButtonActive(BTN_ENC)) {
StatusEdit = 3; // go to the next status
lcdRadio.setCursor(15, 0);
lcdRadio.print(" ");
// move the arrow after "Sw:Y"
lcdRadio.setCursor(4, 1);
lcdRadio.print(ASCII_ARROW);
}
// is the BTN_EXT (abort) pressed?
if (ButtonActive(BTN_EXT)) {
abort_edit = true; // Abort edit
continue_loop = false;
}
break;
case 3: // Edit switch flag
// This flag indicates if the user want to switch
// stdby<->active frequency or not.
// Blink the cursor after "Sw:Y"
lcdRadio.setCursor(4, 1);
encoderClick = encoder.get_change();
if (encoderClick != 0) {
switch_flag=!switch_flag;
lcdRadio.setCursor(3, 1);
if (switch_flag) lcdRadio.print('Y');
else lcdRadio.print('N');
lcdRadio.setCursor(4, 1);
}
// Is the encoder button pressed?
if (ButtonActive(BTN_ENC)) {
StatusEdit = 4; // go to the next status
lcdRadio.setCursor(4, 1);
lcdRadio.print(" ");
// move the arrow after "OBS:"
lcdRadio.setCursor(15, 1);
lcdRadio.print(ASCII_ARROW);
}
// is the BTN_EXT (abort) pressed?
if (ButtonActive(BTN_EXT)) {
abort_edit = true; // Abort edit
continue_loop = false;
}
break;
case 4: // Edit OBS
// Blink the cursor after OBS digits
lcdRadio.setCursor(15, 1);
encoderClick = encoder.get_change();
if (encoderClick > 0) {
ObsTmp++;
if (ObsTmp > 359) ObsTmp = 0;
}
if (encoderClick < 0) {
ObsTmp--;
if (ObsTmp < 0) ObsTmp = 359;
}
// We need to update OBS value?
if (encoderClick != 0) {
sprintf (str, "%03d", ObsTmp);
lcdRadio.setCursor(12, 1);
lcdRadio.print(str);
// Blink the cursor after the digits
lcdRadio.setCursor(15, 1);
}
// Is the encoder button pressed?
if (ButtonActive(BTN_ENC)) {
continue_loop = false;
}
// is the BTN_EXT (abort) pressed?
if (ButtonActive(BTN_EXT)) {
abort_edit = true; // Abort edit
continue_loop = false;
}
break;
} // switch
} while (continue_loop);
lcdRadio.clear();
lcdRadio.noBlink();
lcdRadio.setCursor(0, 0);
// We need to store new data on FS?
if (!abort_edit) {
lcdRadio.print("- Saving data -");
// Saves new values for the NAV "NavNumber" and if needed switches stby-active
SaveNewNavSetup(NavTmp, NavOrig, NavNumber, switch_flag);
delay(50);
SaveNewObsSetup(ObsTmp, ObsOrig, NavNumber);
}
else {
lcdRadio.print("-- NO CHANGE --");
} // if abort_edit
delay (2000); // just shows the message exiting the edit function
StatusMain = 1; // We restart from the main status 1
} // EditNav()
/***********************************************************
EditAdf - edit ADF frequency and course
***********************************************************/
void EditAdf(float Adf, int Hdg) {
int Adf1Tmp, Adf100Tmp, AdfDecTmp, HdgOrig, HdgTmp;
float AdfOrig;
int i_tmp;
float f_tmp;
char str[5];
bool continue_loop = true, abort_edit = false;
int encoderClick = 0, ObsTmp, ObsOrig;
// Draw fixed strings on the LCD
lcdRadio.clear();
lcdRadio.setCursor(0, 0);
lcdRadio.print("ADF Frq: .");
lcdRadio.setCursor(10, 0);
lcdRadio.print(ASCII_ARROW);
lcdRadio.setCursor(4, 1);
lcdRadio.print("HDG: ");
AdfOrig = Adf;
HdgOrig = Hdg;
Adf100Tmp = (int) (Adf / 100.0); // Hundreds of KHz (1..17)
Adf1Tmp = (int) (Adf - Adf100Tmp*100); // Units of KHz (1..99)
// Extracting the first decimal digit after "."
i_tmp=((int)Adf)*10;
f_tmp=(Adf*10.0-(float)i_tmp);
AdfDecTmp=(int)f_tmp; // First decimal digit of the frequency
HdgTmp = Hdg;
sprintf (str, "%2d", Adf100Tmp);
lcdRadio.setCursor(8, 0);
lcdRadio.print(str);
sprintf (str, "%02d", Adf1Tmp);
lcdRadio.setCursor(11, 0);
lcdRadio.print(str);
sprintf (str, "%1d", AdfDecTmp);
lcdRadio.setCursor(14, 0);
lcdRadio.print(str);
sprintf (str, "%03d", HdgTmp);
lcdRadio.setCursor(8, 1);
lcdRadio.print(str);
lcdRadio.setCursor(10, 0);
lcdRadio.blink();
// Secondary finite-state machine for the editing
StatusEdit = 1; // We start editing hundred of KHz
do {
// Which is the status?
switch (StatusEdit) {
case 1: // Edit hundred of Khz (1..17)
encoderClick = encoder.get_change();
if (encoderClick > 0) {
Adf100Tmp++;
if (Adf100Tmp > 17) Adf100Tmp = 1;
}
if (encoderClick < 0) {
Adf100Tmp--;
if (Adf100Tmp < 1) Adf100Tmp = 17;
}
// We need to update the hundreds?
if (encoderClick != 0) {
lcdRadio.setCursor(8, 0);
sprintf (str, "%2d", Adf100Tmp);
lcdRadio.print(str);
// Blink the cursor after the hundreds
lcdRadio.setCursor(10, 0);
}
// Is the encoder button pressed?
if (ButtonActive(BTN_ENC)) {
StatusEdit = 2; // go to the next status
lcdRadio.setCursor(10, 0);
lcdRadio.print("-");
lcdRadio.setCursor(13, 0);
lcdRadio.print(ASCII_ARROW);
}
// is the BTN_EXT (abort) pressed?
if (ButtonActive(BTN_EXT)) {
abort_edit = true; // Abort edit
continue_loop = false;
}
break;
case 2: // Edit KHz (1..99)
// Blink the cursor after the digits
lcdRadio.setCursor(13, 0);
encoderClick = encoder.get_change();
if (encoderClick > 0) {
Adf1Tmp++;
if (Adf1Tmp > 99) Adf1Tmp = 0;
}
if (encoderClick < 0) {
Adf1Tmp--;
if (Adf1Tmp < 0) Adf1Tmp = 99;
}
// We need to update the frequency?
if (encoderClick != 0) {
sprintf (str, "%02d", Adf1Tmp);
lcdRadio.setCursor(11, 0);
lcdRadio.print(str);
}
// Is the encoder button pressed?
if (ButtonActive(BTN_ENC)) {
StatusEdit = 3; // go to the next status
lcdRadio.setCursor(13, 0);
lcdRadio.print(".");
// predispone la freccia dopo l'HDG
lcdRadio.setCursor(15, 0);
lcdRadio.print(ASCII_ARROW);
}
// is the BTN_EXT (abort) pressed?
if (ButtonActive(BTN_EXT)) {
abort_edit = true; // Abort edit
continue_loop = false;
}
break;
case 3: // edit decimal (0..9)
lcdRadio.setCursor(15, 0);
encoderClick = encoder.get_change();
if (encoderClick > 0) {
AdfDecTmp++;
if (AdfDecTmp > 9) AdfDecTmp = 0;
}
if (encoderClick < 0) {
AdfDecTmp--;
if (AdfDecTmp < 0) AdfDecTmp = 9;
}
// We need to update the frequency?
if (encoderClick != 0) {
sprintf (str, "%d", AdfDecTmp);
lcdRadio.setCursor(14, 0);
lcdRadio.print(str);
}
// Is the encoder button pressed?
if (ButtonActive(BTN_ENC)) {
StatusEdit = 4; // go to the next status
lcdRadio.setCursor(15, 0);
lcdRadio.print(" ");
lcdRadio.setCursor(11, 1);
lcdRadio.print(ASCII_ARROW);
}
// is the BTN_EXT (abort) pressed?
if (ButtonActive(BTN_EXT)) {
abort_edit = true; // Abort edit
continue_loop = false;
}
break;
case 4: // Edit HDG
// Blink the cursor after HDG digits
lcdRadio.setCursor(11, 1);
encoderClick = encoder.get_change();
if (encoderClick > 0) {
HdgTmp++;
if (HdgTmp > 359) HdgTmp = 0;
}
if (encoderClick < 0) {
HdgTmp--;
if (HdgTmp < 0) HdgTmp = 359;
}
// We need to update HDG value?
if (encoderClick != 0) {
sprintf (str, "%03d", HdgTmp);
lcdRadio.setCursor(8, 1);
lcdRadio.print(str);
}
// Is the encoder button pressed?
if (ButtonActive(BTN_ENC)) {
continue_loop = false;
}
// is the BTN_EXT (abort) pressed?
if (ButtonActive(BTN_EXT)) {
abort_edit = true; // Abort edit
continue_loop = false;
}
break;
} // switch
} while (continue_loop);
lcdRadio.clear();
lcdRadio.noBlink();
lcdRadio.setCursor(0, 0);
// We need to store new data on FS?
if (!abort_edit) {
lcdRadio.print("- Saving data -");
// Send new values for ADF frequency and HDG
SaveNewAdfSetup(Adf100Tmp, Adf1Tmp, AdfDecTmp, AdfOrig, HdgTmp, HdgOrig);
}
else {
lcdRadio.print("-- NO CHANGE --");
} // if abort_edit
delay (2000); // just shows the message exiting the edit function
StatusMain = 2; // // We restart from the main status 2 (display ADF & HDG)
} // EditAdf()
/***********************************************************
SaveNewAdfSetup - Send new values for ADF frequency & HDG
***********************************************************/
void SaveNewAdfSetup(int Adf100New, int Adf1New, int AdfDecNew, float AdfOrig, int HdgNew, int HdgOrig) {
int freq_tmp, i, i_tmp;
// Sending first 2 ADF frequency digits (hundreds)
freq_tmp = AdfOrig / 100;
if (Adf100New > freq_tmp)
for (i = freq_tmp; i < Adf100New; i++)
Serial.print(ADF_100_INC); // ADF_100_INC
if (Adf100New < freq_tmp)
for (i = Adf100New; i < freq_tmp; i++)
Serial.print(ADF_100_DEC); // ADF_100_DEC
// Sending last 2 ADF frequency digits (units)
freq_tmp = (int) (AdfOrig - freq_tmp*100); // KHz units (1..99)
if (Adf1New > freq_tmp)
for (i = freq_tmp; i < Adf1New; i++)
Serial.print(ADF_1_INC); // Increments ADF by 1 KHz
if (Adf1New < freq_tmp)
for (i = Adf1New; i < freq_tmp; i++)
Serial.print(ADF_1_DEC); // Decrements ADF by 1 KHz
// Extracting the first decimal digit after "."
i_tmp=((int)AdfOrig)*10;
freq_tmp=(int)(AdfOrig*10.0-(float)i_tmp); // First decimal digit of the frequency
if (AdfDecNew > freq_tmp)
for (i = freq_tmp; i < AdfDecNew; i++)
Serial.print(ADF_FRACT_INC_CARRY); //
if (AdfDecNew < freq_tmp)
for (i = AdfDecNew; i < freq_tmp; i++)
Serial.print(ADF_FRACT_DEC_CARRY); //
// Sending new HDG
if (HdgNew > HdgOrig)
for (i = HdgOrig; i < HdgNew; i++)
Serial.print(ADF_HDG_INC); // ADF_CARD_INC
if (HdgNew < HdgOrig)
for (i = HdgNew; i < HdgOrig; i++)
Serial.print(ADF_HDG_DEC); // ADF_CARD_DEC
} // SaveNewAdfSetup()
/***********************************************************
SaveNewNavSetup
Send new freq values for NavNumber stdby NAV and OBS
***********************************************************/
void SaveNewNavSetup(float FreqNew, float FreqOrig, byte NavNumber, bool switch_flag) {
int MHzFreqNew, MHzFreqOrig;
int KHzFreqNew, KHzFreqOrig;
int i, delta;
MHzFreqNew = GetMHz(FreqNew);
KHzFreqNew = GetKHz(FreqNew);
MHzFreqOrig = GetMHz(FreqOrig);
KHzFreqOrig = GetKHz(FreqOrig);
// Are the MHz changed?
if (MHzFreqNew != MHzFreqOrig) {
delta = MHzFreqOrig - MHzFreqNew;
delta = abs(delta);
for (i = 0; i < delta; i++) {
if (MHzFreqNew > MHzFreqOrig) {
switch (NavNumber) {
case 1:
Serial.print(NAV1_INC_MHZ);
break;
case 2:
Serial.print(NAV2_INC_MHZ);
break;
} // switch
} // if
if (MHzFreqNew < MHzFreqOrig) {
switch (NavNumber) {
case 1:
Serial.print(NAV1_DEC_MHZ);
break;
case 2:
Serial.print(NAV2_DEC_MHZ);
break;
} // switch
} // if
} // for
} // if (MHzFreqNew!=MHzFreqOrig)
// Are KHz changed?
if (KHzFreqNew != KHzFreqOrig) {
delta = KHzFreqOrig - KHzFreqNew;
delta = abs(delta);
// each "inc" or "dec" acts on 50KHz
delta = delta / 5;
for (i = 0; i < delta; i++) {
if (KHzFreqNew > KHzFreqOrig) {
switch (NavNumber) {
case 1:
Serial.print(NAV1_INC_KHZ);
break;
case 2:
Serial.print(NAV2_INC_KHZ);
break;
} // switch
} // if
if (KHzFreqNew < KHzFreqOrig) {
switch (NavNumber) {
case 1:
Serial.print(NAV1_DEC_KHZ);
break;
case 2:
Serial.print(NAV2_DEC_KHZ);
break;
} // switch
} // if
} // for
} // if (KHzFreqNew!=KHzFreqOrig)
// If switch_flag=true i need also to switch the frequencies