-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathControls.cpp
2597 lines (2246 loc) · 98.9 KB
/
Controls.cpp
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
//
// Controls.cpp
//
#include "RadioConfig.h"
#include "ICOM_IC-905_CIV.h"
#include <CIVmaster.h>
#include "Controls.h"
#ifdef USE_RA8875
extern RA8875 tft;
#else
extern RA8876_t3 tft;
#endif
extern uint8_t display_state; // something to hold the button state for the display pop-up window later.
extern uint8_t curr_band; // global tracks our current band setting.
extern uint64_t VFOA; // 0 value should never be used more than 1st boot before EEPROM since init should read last used from table.
extern uint64_t VFOB;
extern struct Modes_List modeList[];
extern struct Band_Memory bandmem[];
extern struct cmdList cmd_List[];
extern struct User_Settings user_settings[];
extern struct Standard_Button std_btn[];
extern struct Label labels[];
extern struct Filter_Settings filter[];
extern struct AGC agc_set[];
extern struct NB nb[];
extern struct Zoom_Lvl zoom[];
extern struct EncoderList encoder_list[];
extern struct TuneSteps tstep[];
extern uint8_t user_Profile;
extern Metro popup_timer; // used to check for popup screen request
extern Metro TX_Timeout; // RunawayTX timeout
extern uint8_t popup;
extern volatile int64_t Freq_Peak;
extern void set_MF_Service(uint8_t client_name);
extern void unset_MF_Service(uint8_t client_name);
extern uint8_t MF_client; // Flag for current owner of MF knob services
extern void touchBeep(bool enable);
extern bool MeterInUse; // S-meter flag to block updates while the MF knob has control
extern Metro MF_Timeout;
extern bool MF_default_is_active;
extern uint8_t default_MF_slot;
extern int32_t ModeOffset;
extern uint16_t fft_size;
extern int16_t fft_bins;
#ifdef USE_FREQ_SHIFTER
extern AudioEffectFreqShiftFD_OA_F32 FFT_SHIFT_I;
extern AudioEffectFreqShiftFD_OA_F32 FFT_SHIFT_Q;
#endif
#ifdef USE_FFT_LO_MIXER
extern RadioIQMixer_F32 FFT_LO_Mixer_I;
extern RadioIQMixer_F32 FFT_LO_Mixer_Q;
#endif
//extern float pan;
float pan;
extern int64_t xvtr_offset; // LO to apply to actual PLL freq
extern int16_t rit_offset; // global RIT offset value in Hz.
extern int16_t xit_offset; // global XIT offset value in Hz.
extern int16_t rit_offset_last; // global RIT offset value in Hz.
extern int16_t xit_offset_last; // global RIT offset value in Hz.
extern void update_icon_outline(void);
extern void ringMeter(int val, int minV, int maxV, int16_t x, int16_t y, uint16_t r, const char* units, uint16_t colorScheme, uint16_t backSegColor, int16_t angle, uint8_t inc);
extern uint8_t getRadioMode(void);
extern CIV civ;
extern CIVresult_t writeMsg (const uint8_t deviceAddr, const uint8_t cmd_body[], const uint8_t cmd_data[],writeMode_t mode);
extern uint8_t check_CIV(uint32_t time_current_baseloop);
extern uint8_t Check_radio(void);
extern uint8_t radio_mode; // mode from radio messages
extern uint8_t radio_filter; // filter from radio messages
extern uint8_t radio_data; // filter from radio messages
const String retValStr[7] = {
"CIV_OK",
"CIV_OK_DAV",
"CIV_NOK",
"CIV_HW_FAULT",
"CIV_BUS_BUSY",
"CIV_BUS_CONFLICT",
"CIV_NO_MSG"
};
void changeBands(int8_t direction);
void pop_win_up(uint8_t win_num);
void pop_win_down(uint8_t win_num);
void Mute();
void Menu();
void Display();
void Band(uint8_t new_band);
void BandDn();
void BandUp();
void Notch();
void Spot();
void Enet();
void setNR();
void setNB(int8_t toggle);
void Xmit(uint8_t state);
void Ant();
void Fine();
void Rate(int8_t dir);
void setMode(int8_t dir);
void AGC(int8_t dir);
void Filter(int8_t dir);
void ATU();
void Split();
void setXIT(int8_t toggle);
void XIT(int8_t delta);
void setRIT(int8_t toggle);
void RIT(int8_t delta);
void Preamp(int8_t toggle);
void setAttn(int8_t toggle);
void VFO_AB();
void Attn(int8_t delta);
void setAFgain(int8_t toggle);
void AFgain(int8_t delta);
void setRFgain(int8_t toggle);
void RFgain(int8_t delta);
void setRefLevel(int8_t toggle);
void NBLevel(int8_t delta);
void RefLevel(int8_t newval);
void TouchTune(int16_t touch_Freq);
void selectStep(uint8_t fndx);
void selectAgc(uint8_t andx);
void clearMeter(void);
void setMeter(uint8_t id);
void Zoom(int8_t dir);
void setZoom(int8_t toggle);
void PAN(int8_t delta);
void setPAN(int8_t toggle);
void digital_step_attenuator_PE4302(int16_t _attn); // Takes a 0 to 100 input, converts to the appropriate hardware steps such as 0-31dB in 1 dB steps
void setEncoderMode(uint8_t role);
//
//----------------------------------- Skip to Ham Bands only ---------------------------------
//
// Increment band up or down from present. To be used with touch or physical band UP/DN buttons.
// A alternate method (not in this function) is to use a band button or gesture to do a pop up selection map.
// A rotary encoder can cycle through the choices and push to select or just touch the desired band.
//
// --------------------- Change bands using database -----------------------------------
// Returns 0 if cannot change bands
// Returns 1 if success
// For CIV ops, call CHeck_Radio periodically to prevent message buffer filling up. Seen TXchk * 5 is a clue this has happened
// In this function many requests are queued up, it will overflow before returning to the main loop to process Check_Radio().
COLD void changeBands(int8_t direction) // neg value is down. Can jump multiple bandswith value > 1.
{
int8_t target_band;
// TODO search bands column for match to account for mapping that does not start with 0 and bands could be in odd order and disabled.
DPRINTF("\nchangeBands: Previous Band was "); DPRINT(bandmem[curr_band].band_name); DPRINTF(" Current Freq: "); DPRINT(VFOA);
DPRINTF(" Current Last_VFOA: "); DPRINT(bandmem[curr_band].vfo_A_last); DPRINTF(" Current Mode: "); DPRINT(bandmem[curr_band].mode_A);
DPRINTF(" Xvtr_Offset: "); DPRINTLN(xvtr_offset);
target_band = bandmem[curr_band].band_num + direction;
// target_band = curr_band + direction;
Split(0);
DPRINTF("changeBands: Proposed Target Band is "); DPRINT(bandmem[target_band].band_name); DPRINTF(" Proposed Target Mode is "); DPRINTLN(bandmem[target_band].mode_A);
uint16_t top_band = BANDS-1;
uint16_t bottom_band = 0;
// See if the proposed new band is enabled in the bandmap or not. If not skip to the next one and check again until true.
while (1) // loop around up or down until we find a valid band to switch to.
{
if (target_band > top_band)
target_band = bottom_band;
if (target_band < bottom_band) // bottom
target_band = top_band;
if (bandmem[target_band].bandmap_en)
{
DPRINTF("changeBands: Target band index "); DPRINT(target_band); DPRINTF(" is in the Bandmap. Target band is "); DPRINTLN(bandmem[target_band].band_name);
break;
}
else
{
DPRINTF("changeBands: Target band "); DPRINT(bandmem[target_band].band_name); DPRINTLNF(" NOT in Bandmap. Trying next Band.");
target_band += direction; // maintain change direction up or down.
if (direction == 0)
target_band +=1; // force a search of current is invalid, possible if VFO set externally to disabled band
}
}
curr_band = target_band; // We have a good band so can new band
DPRINTF("changeBands: curr_band is "); DPRINT(bandmem[curr_band].band_name); DPRINTF(" Last used VFO on this band: "); DPRINTLN(bandmem[curr_band].vfo_A_last);
if (direction != 0)
{ // use this to get the last known frequency on a new band
if (find_new_band(bandmem[curr_band].vfo_A_last, curr_band))
{
VFOA = bandmem[curr_band].vfo_A_last; // last used frequencies
DPRINTF("changeBands: Direction not 0, Last used VFOA is "); DPRINTLN(VFOA);
}
else
{
DPRINTF("changeBands: ***** Direction not 0, failed to get Last used VFOA, likely wrong VFO value for this band ****"); DPRINTLN(VFOA);
VFOA = bandmem[curr_band].edge_lower;
DPRINTF("changeBands: ***** Defaulting to lower edge frequencing on current band: ");DPRINTLN(VFOA);
}
}
else // use this for when updating settings on same band
{
if (!find_new_band(VFOA, curr_band)) // returns 0 when out of band
{
VFOA = bandmem[curr_band].vfo_A_last; // keep last valid frequency
DPRINTF("changeBands: after find new band, Last used VFOA is "); DPRINTLN(VFOA);
}
}
// When changing bands always use the db modse_A and Filter A values. These are the last used values on that band.
// The modeList table only remembers the last filter used for each mode and a new band may have diffent needs.
// The modList table will attempt to set the filter appropriate for a new mode on the same band using the last time that mode was used
// which could have been any band and a long time past. But is the the best guess as some modes allows only FIL1 which using that woud cause all modes to be set to FIL 1.
// An option to so have a modeList table per band.
// In summary: Set modeList filter on mode changes from radio or remote
// On band changes use teh ModeA and filter_A, set teh modeList filter for the new band mode to Filter_A, it could have been different.
DPRINTF("changeBands: New Band is "); DPRINT(bandmem[curr_band].band_name);
DPRINTF(" New VFOA: "); DPRINT(VFOA);
DPRINTF(" xvtr_IF: "); DPRINT(bandmem[curr_band].xvtr_IF);
DPRINTF(" Xvtr_Offset: "); DPRINT(xvtr_offset);
DPRINTF(" Mode: "); DPRINT(bandmem[curr_band].mode_A);
DPRINTF(" Filter: "); DPRINT(bandmem[curr_band].filter_A);
DPRINTF(" modeList Filter: "); DPRINTLN(modeList[bandmem[curr_band].mode_A].Width);
// Calculate frequency difference between the designated xvtr IF band's lower edge and the current VFO band's lower edge (the LO frequency).
if (bandmem[curr_band].xvtr_IF)
xvtr_offset = bandmem[curr_band].edge_lower - bandmem[bandmem[curr_band].xvtr_IF].edge_lower; // if band is 144 then PLL will be set to VFOA-xvtr_offset
else
xvtr_offset = 0;
DPRINTF("changeBands: xvtr_offset is "); DPRINTLN(xvtr_offset);
DPRINTLNF("changeBands: Set RIT if On");
/* ToDo - Fix up RIT and XIT later
if (bandmem[curr_band].RIT_en)
setRIT(1); // turn on if it was on before. Also calls selectFrequency(0);
else
setRIT(0); // turn off if it was off before on this new band
*/
selectFrequency(0);
// If the current band is configured as a Transverter IF Band then we need to store the direct band's values in a safe place and
// push down the transverter band values for all settings that matter.
// On leaving the transverter band we need to reset the direct band values on next use.
// This makes an argument for controlling all bands for the remote.
// Maybe update the database on startup by scanning all bands, or on a band's first use.
DPRINTLNF("changeBands: Set other related band settings");
// Split(0);
// The get_XXX functions were used when the radio was the master source.
// It can be sometimes problematic when the radio seems to not want to remember the mode when changing banmds. Works for a while then stops.
// With tehe need to use a radio band for both direct and transvters uses, we need to control what settings are for each usage
// Making the remote the master source is the easy answer to all issues so far.
setMode(3);
Check_radio();
//get_Preamp_from_Radio(); // sync up with radio
Preamp(-1); // -1 sets to database state. 2 is toggle state. 0 and 1 are Off and On. Operate relays if any.
Check_radio(); // do a check to make sure we service our rx buffer before it overflows. Normally called in main loop but we are not there yet.
//get_Attn_from_Radio(); //sync up with radio
setAttn(-1); // -1 sets to database state. 2 is toggle state. 0 and 1 are Off and On. Operate relays if any.
Check_radio();
//get_AGC_from_Radio();
AGC(2);
Check_radio();
get_RIT_from_Radio();
//send_RIT_to_Radio(); // The offset for XIT and RIT is shared so call this for either one. Only 1 can be enabled at time and they use this value
get_RIT_ON_OFF_to_Radio();
//send_RIT_ON_OFF_to_Radio();
get_XIT_ON_OFF_to_Radio();
//send_XIT_ON_OFF_to_Radio();
//get_Mode_from_Radio();
modeList[bandmem[curr_band].mode_A].Width = bandmem[curr_band].filter_A; // update width in table to current band last used.
send_Mode_to_Radio(bandmem[curr_band].mode_A); // set to last known mode on this band
// will send this later when I add storage for it, for now just read it to prove it works.
get_DUP_from_Radio();
//send_DUP_to_Radio(void)
//delay(10);
RefLevel(0); // 0 just updates things to be current value
RFgain(0);
AFgain(0);
NBLevel(0); // 0 just updates things to be current value
// converts the current band number to a pattern which is then applied to a group of GPIO pins.
// You can edit the patern for each band in RadioConfig.h
Band_Decode_Output(curr_band);
// Rate(0); Not needed
// Ant() when there is hardware to setup in the future
// ATU() when there is hardware to setup in the future
ATU(-1); // -1 sets to database state. 2 is toggle state. 0 and 1 are Off and On.
//
// insert any future features, software or hardware, that need to be altered
//
user_settings[user_Profile].last_band = curr_band;
user_settings[user_Profile].sub_VFO = VFOB;
write_db_tables(); // Save to SD card
displayRefresh();
DPRINTLNF("changeBands: Complete\n");
}
//
// ----------------------- Button Functions --------------------------------------------
// Called by Touch, Encoder, or Switch events
//
// ---------------------------setMode() ---------------------------
// selects old or new value and updates buttons, labels to match
//
// Input: 0 = step to next based on last direction (starts upwards). Ramps up then down then up.
// 1 = step up 1
// -1 = step down 1
// 2 = use last in dB
// 3 = set from dB but do not send to radio (read radio and set dB to match)
//
COLD void setMode(int8_t dir)
{
static int8_t direction = 1;
int8_t _mndx;
_mndx = (int8_t)bandmem[curr_band].mode_A; // get current mode
//DPRINTF("setMode: Mode Index before change: "); DPRINT(bandmem[curr_band].mode_A);
//DPRINTF(" Dir: "); DPRINTLN(dir);
if (dir < 2)
{
// 1. Limit to allowed step range
// 2. Cycle up and at top, cycle back down, do nto roll over.
if (_mndx <= 0)
{
_mndx = 0; // mode = 0 then change to -1 will add direction == +1 to get 0 later.
direction = 1; // cycle upwards
}
if (_mndx >= MODES_NUM - 1)
{
_mndx = MODES_NUM - 1;
direction = -1; // go downward
}
if (dir == 0)
_mndx += direction; // Index our step up or down, if dir == 0 then no change to current value
else
_mndx += dir; // forces a step higher or lower then current
if (_mndx > MODES_NUM - 1) // limit in case of encoder countssetMode
_mndx = MODES_NUM - 1;
if (_mndx < 0) // limit in case of encoder counts
_mndx = 0;
//DPRINTF("setMode: Mode Index changed to "); DPRINTLN(bandmem[curr_band].mode_A);
bandmem[curr_band].mode_A = (uint8_t)_mndx; // store it
}
// digital modes only allow AGC Fast
switch (modeList[bandmem[curr_band].mode_A].mode_num) // loop though the list look for these modes numbers
{
case 0x22: bandmem[curr_band].filter_A = FILT1; // in addition to mode restrictions, if mode is DD then only FIL1 allowed
//Filter(2);
case 0x17: // these modes only allow FAST so do not change radio, just update local buttons, labels They do allow filter changes
case 0x23:
case 0x05: bandmem[curr_band].agc_mode = AGC_FAST; // force state to FAST, radio does not auto-report AGC changes
}
DPRINTF("setMode: Mode Index final: "); DPRINT(bandmem[curr_band].mode_A); DPRINTF(" curr_band: "); DPRINTLN(curr_band);
if (dir < 3) // Only update radio for local button pushes
send_Mode_to_Radio((uint8_t) _mndx); // Select the mode for the Active VFO
displayMode();
displayFilter();
displayDATA();
//get_AGC_from_Radio(); // let the radio update to the per mode AGC setting it has
//get_Attn_from_Radio(); // radio wont tell us it changed so have to ask
//get_Preamp_from_Radio(); // radio wont tell us it changed so have to ask
}
// ---------------------------Filter() ---------------------------
// selects old or new value and updates buttons, labels to match
//
// Input: 0 = step to next based on last direction (starts upwards). Ramps up then down then up.
// 1 = step up 1 filter (wider)
// -1 = step down 1 filter (narrower)
// 2 = use last filter width used in this mode from the dB (from modeList table)
// 3 = set from dB but do not send to radio (read radio and set dB to match)
//
// This is mode-aware. In non-CW modes we will only cycle through SSB width filters as set in the filter tables
//
// FILTER button
COLD void Filter(int8_t dir)
{
static int8_t direction = 1;
int8_t _bw = bandmem[curr_band].filter_A; // Change Bandwidth - cycle down then back to the top
if (dir < 2)
{
// 1. Limit to allowed step range
// 2. Cycle up and at top, cycle back down, do not roll over.
if (_bw <= FILT1)
{
_bw = FILT1; // mode = 0 then change to -1 will add direction == +1 to get 0 later.
direction = 1; // cycle upwards
}
if (_bw >= FILT3)
{
_bw = FILT3;
direction = -1; // go downward
}
if (dir == 0)
_bw += direction; // Index our step up or down, if dir == 0 then no change to current value
else
_bw += dir; // forces a step higher or lower then current
if (_bw > FILT3) // limit in case of encoder counts setMode
_bw = FILT3;
if (_bw < FILT1) // limit in case of encoder counts
_bw = FILT1;
}
// DD mode only allow AGC Fast
if (modeList[bandmem[curr_band].mode_A].mode_num == 0x22)
{
_bw = FILT1;
dir = 3; // do not send to radio, it is already there in DD mode
}
if (_bw == bandmem[curr_band].filter_A)
{
modeList[bandmem[curr_band].mode_A].Width = bandmem[curr_band].filter_A = (uint8_t) _bw; // ensure modeList is sync'd up for current mode and band
return; // mothing changed so do nothing
}
modeList[bandmem[curr_band].mode_A].Width = bandmem[curr_band].filter_A = (uint8_t) _bw;
DPRINTF("Filter: Set Filter to "); DPRINTLN(filter[bandmem[curr_band].filter_A].Filter_name);
if (dir < 3)
send_Mode_to_Radio(bandmem[curr_band].mode_A);
displayFilter();
}
// ---------------------------Rate() ---------------------------
// Input: 0 = step to next based on last direction (starts upwards). Ramps up then down then up.
// 1 = step up 1 tune rate
// -1 = step down 1 tune step rate
// If FINE is OFF, we will not use 1Hz. If FINE = ON we only use 1 and 10Hz steps.
// RATE button
COLD void Rate(int8_t dir)
{
static int direction = 1;
int _tstep = bandmem[curr_band].tune_step;
if (user_settings[user_Profile].fine == 0)
{
// 1. Limit to allowed step range
// 2. Cycle up and at top, cycle back down, do nto roll over.
if (_tstep <= 1)
{
_tstep = 1;
direction = 1; // cycle upwards
}
if (_tstep >= 3) // TS_STEPS-1)
{
_tstep = 3; // TS_STEPS-1;
direction = -1;
}
if (dir == 0)
_tstep += direction; // Index our step up or down
else
_tstep += dir; // forces a step higher or lower then current
if (_tstep >= 3) // TS_STEPS-1) // ensure we are still in range
_tstep = 3; // TS_STEPS - 1; // just in case it over ranges, bad stuff happens when it does
if (_tstep < 1)
_tstep = 1; // just in case it over ranges, bad stuff happens when it does
}
if (user_settings[user_Profile].fine && dir == -1) // 1 Hz steps
bandmem[curr_band].tune_step = 0; // set to 1 hz steps
else if (user_settings[user_Profile].fine && dir == 1)
bandmem[curr_band].tune_step = 1; // normally swiped is +1 or -1
else if (user_settings[user_Profile].fine && dir == 0)
{
if (_tstep > 0)
_tstep = 0;
else
_tstep = 1;
bandmem[curr_band].tune_step = _tstep;
}
else
bandmem[curr_band].tune_step = _tstep; // Fine tunig mode is off, allow all steps 10hz and higher
// DPRINT("Set Rate to ");
// DPRINTLN(tstep[bandmem[curr_band].tune_step].ts_name);
displayRate();
}
// AGC button
// ---------------------------AGC() ---------------------------
// selects old or new value and updates buttons, labels to match
//.
// Input: 0 = step to next based on last direction (starts upwards). Ramps up then down then up.
// 1 = step up 1
// -1 = step down 1
// 2 = use last in dB
// 3 = set from dB but do not send to radio (read radio and set dB to match)
//
COLD void AGC(int8_t dir)
{
static int8_t direction = 1;
int8_t _agc = bandmem[curr_band].agc_mode;
if (dir < 2)
{
// 1. Limit to allowed step range
// 2. Cycle up and at top, cycle back down, do not roll over.
if (_agc <= AGC_FAST)
{
_agc = AGC_FAST; // mode = 0 then change to -1 will add direction == +1 to get 0 later.
direction = 1; // cycle upwards
}
if (_agc >= AGC_SLOW)
{
_agc = AGC_SLOW;
direction = -1; // go downward
}
if (dir == 0)
_agc += direction; // Index our step up or down, if dir == 0 then no change to current value
else
_agc += dir; // forces a step higher or lower then current
if (_agc > AGC_SLOW) // limit in case of encoder counts setMode
_agc = AGC_SLOW;
if (_agc < AGC_FAST) // limit in case of encoder counts
_agc = AGC_FAST;
bandmem[curr_band].agc_mode = (uint8_t) _agc;
}
// digital modes only allow AGC Fast
switch (modeList[bandmem[curr_band].mode_A].mode_num) // loop though the list look for these modes numbers
{
case 0x17: // these modes only allow FAST so do nto change radio, just update local buttons, labels
case 0x22:
case 0x23:
case 0x05: bandmem[curr_band].agc_mode = AGC_FAST; // force state to FAST, radio does not auto-report AGC changes
dir = 3; // send only only if not a digital mode - radio is already in FAST in digital modes
DPRINTLNF("AGC(): Changed AGC to FAST for Digital Modes);");
break;
}
// dir > 1 just use the unchanged dB value.
// dir 3 skip sending to radio, just syncing our state to the radio's state
if (dir < 3)
send_AGC_to_Radio();
DPRINTF("Set AGC to "); DPRINTLN(agc_set[bandmem[curr_band].agc_mode].agc_name);
sprintf(std_btn[AGC_BTN].label, "%s", agc_set[bandmem[curr_band].agc_mode].agc_name);
sprintf(labels[AGC_LBL].label, "%s", agc_set[bandmem[curr_band].agc_mode].agc_name);
displayAgc();
}
// MUTE button
COLD void Mute()
{
// float _afLevel = (float) user_settings[user_Profile].afGain/100;
if (user_settings[user_Profile].spkr_en)
{
if (!user_settings[user_Profile].mute)
{
//RampVolume(0.0f, 1); // 0 ="No Ramp (instant)" // loud pop due to instant change || 1="Normal Ramp" // graceful transition between volume levels || 2= "Linear Ramp"
user_settings[user_Profile].mute = ON;
}
else
{ // codec1.muteHeadphone();
// RampVolume(_afLevel, 1); // 0 ="No Ramp (instant)" // loud pop due to instant change || 1="Normal Ramp" // graceful transition between volume levels || 2= "Linear Ramp"
user_settings[user_Profile].mute = OFF;
AFgain(0);
}
displayMute();
}
}
// MENU
COLD void Menu()
{
pop_win_up(SPECTUNE_BTN);
// tft.fillRect(t_ptr->bx, t_ptr->by, t_ptr->bw, t_ptr->bh, RA8875_BLACK);
tft.setFont(Arial_24);
tft.setTextColor(BLUE);
tft.setCursor(CENTER, CENTER, true);
tft.print(F("this is a future keyboard"));
delay(1000);
pop_win_down(SPECTUNE_BTN); // remove window, restore old screen info, clear popup flag and timer
displayMenu();
DPRINTLN("Menu Pressed");
}
// VFO A/B - swap VFO A and B values.
COLD void VFO_AB(void)
{
// feedback beep
touchBeep(true); // a timer will shut it off.
// collect some settings in prep for swapping
uint64_t old_VFOA = VFOA;
uint8_t old_A_mode = bandmem[curr_band].mode_A;
// uint8_t old_A_band = curr_band;
uint64_t old_VFOB = user_settings[user_Profile].sub_VFO;
uint8_t old_B_mode = user_settings[user_Profile].sub_VFO_mode;
#ifdef USE_RS_HFIQXXX
// Compute the band index for the new target band an ensure it is in limits
// if (RS_HFIQ.find_new_band(old_VFOB, &curr_band)) // return the updated band index for the new freq
#else
if (find_new_band(old_VFOB, curr_band))
#endif
{
// all good, now start swapping
// DPRINT("\nStart Swapping - VFO A: ");
// DPRINT(old_VFOB);
// DPRINT(" VFO A Mode: ");
// DPRINT(old_B_mode);
// DPRINT(" VFO A band: ");
// DPRINTLN(curr_band);
VFOA = bandmem[curr_band].vfo_A_last = old_VFOB; // Update VFOA to new freq, then update the band index to match
bandmem[curr_band].mode_A = old_B_mode;
send_Mode_to_Radio(old_B_mode); // copy to VFOA mode and apply
// DPRINT("Stash sub_VFO values - VFO B: ");
// DPRINT(old_VFOA);
// DPRINT(" VFO B Mode: ");
// DPRINT(old_A_mode);
// DPRINT(" VFO B band: ");
// DPRINTLN(old_A_band);
VFOB = user_settings[user_Profile].sub_VFO = old_VFOA; // save A into the database
user_settings[user_Profile].sub_VFO_mode = old_A_mode; // Udpate VFOB
}
selectFrequency(0);
changeBands(0);
displayVFO_AB();
displayMode();
DPRINT("Set VFO_A to ");
DPRINTLN(VFOA);
DPRINT("Set VFO_B to ");
DPRINTLN(VFOB);
}
// ----------------------------------- setAttn ---------------------------------------------------------
// setAttn - valid on bands < 2400 for IC-905
// -1 sets attenuator state to current database value. Used for startup or changing bands.
// 0 sets attenuator state off
// 1 sets attenuator state on
// 2 toggles attenuator state
// 3 set attenuator state to current database value but does not send to radio (likely came from radio)
//
COLD void setAttn(int8_t toggle)
{
//DPRINTF("setAttn: toggle = "); DPRINTLN(toggle);
//DPRINTF("setAttn: Attn start state = "); DPRINTLN(bandmem[curr_band].attenuator);
CIVresult_t CIVresultL;
if (toggle == 2) // toggle if ordered, else just set to current state such as for startup.
{
if (bandmem[curr_band].attenuator == ATTN_ON) // toggle the attenuator tracking state
toggle = 0;
else
toggle = 1;
}
if (toggle == 1) // toggle is 1, turn on Attn
{
bandmem[curr_band].attenuator = ATTN_ON; // set the attenuator tracking state to ON
}
if (toggle == 0 || curr_band > BAND1296) // preamp and atten not available on IC905 on bands above 1296
{
bandmem[curr_band].attenuator = ATTN_OFF; // set attenuator tracking state to OFF
}
MeterInUse = false;
if (bandmem[curr_band].preamp == PREAMP_ON && bandmem[curr_band].attenuator == ATTN_ON) // turn off if the preamp is on
bandmem[curr_band].preamp = PREAMP_OFF;
// Reading from the radio we just want to update database and screen and not repeat back to radio.
// 0 = no change to set attenuator level to value in database for this band
if (curr_band < BAND2400)
{
if (toggle < 3)
{
if (bandmem[curr_band].attenuator)
{
delay(20);
CIVresultL = civ.writeMsg(CIV_ADDR, reinterpret_cast<const uint8_t*>(&cmd_List[CIV_C_ATTN_ON].cmdData), CIV_D_NIX, CIV_wChk);
DPRINTF("setAttn: Send to Radio ON: retVal: "); DPRINTLN(retValStr[CIVresultL.value]);
}
else
{
CIVresultL = civ.writeMsg(CIV_ADDR, reinterpret_cast<const uint8_t*>(&cmd_List[CIV_C_ATTN_OFF].cmdData), CIV_D_NIX, CIV_wChk);
DPRINTF("setAttn: Send to Radio OFF: retVal: "); DPRINTLN(retValStr[CIVresultL.value]);
}
}
}
else // the band is > 1296
{
DPRINTF("setAttn: Skipping for bands > 1296 - curr band is "); DPRINTLN(bandmem[curr_band].band_name);
}
displayAttn();
displayPreamp();
DPRINTF("setAttn: Set Attenuator to "); DPRINTLN(bandmem[curr_band].attenuator);
// DPRINTF("Set Attenuator Relay to "); DPRINT(bandmem[curr_band].attenuator_byp); DPRINTF(" Attn_dB is "); DPRINTLN(bandmem[curr_band].attenuator_dB);
// DPRINTF(" and Ref Level is "); DPRINTLN(Sp_Parms_Def[user_settings[user_Profile].sp_preset].spect_floor);
}
/*******************************************************************************
* Function Name: Attn()
********************************************************************************
*
* Summary:
* Main function performs following functions:
* 1: Configures the solid state attenuator by shifting 16 bits of address and
* attn level in LSB first.
*
* Parameters:
* attn = attenuation level to set in range of 0 to 100% (0 to 31 (in dB))
*
* Return:
* None.
*
*******************************************************************************/
COLD void Attn(int8_t delta)
{
int8_t _attn = bandmem[curr_band].attenuator_dB;
_attn += delta * 10;
if (_attn > 10) // Keep in 0-100 range 10 for IC-905 on bands < 2400
{
bandmem[curr_band].attenuator_dB = _attn = 10;
setAttn(1);
}
if (_attn <= 0 || curr_band > BAND1296) // skip for high bands and force off
{
bandmem[curr_band].attenuator_dB = _attn = 0;
setAttn(0);
}
DPRINT("Setting attenuator value to "); DPRINTLN(bandmem[curr_band].attenuator_dB);
//displayAttn(); // update the button value
}
// ------------------------PREAMP button - valid on bands < 2400 for IC-905 -----------------------
// 0 sets Preamp state off
// 1 sets Preamp state on
// 2 toggles Preamp state
// -1 or any value other than 0-2 sets Preamp state to current database value. Used for startup or changing bands.
// 3 use value from dB but do not send to radio (was likely read from radio)
//
COLD void Preamp(int8_t toggle)
{
CIVresult_t CIVresultL;
//DPRINTF("Preamp: toggle = "); DPRINTLN(toggle);
//DPRINTF("Preamp: Preamp start state = "); DPRINTLN(bandmem[curr_band].preamp);
if (toggle == 2) // toggle state
{
if (bandmem[curr_band].preamp == PREAMP_ON)
toggle = 0;
else
toggle = 1;
}
if (toggle == 1) // set to ON
{
bandmem[curr_band].preamp = PREAMP_ON;
}
if (toggle == 0 || curr_band > BAND1296) // set to OFF
{
bandmem[curr_band].preamp = PREAMP_OFF;
}
// any other value of toggle pass through with unchanged state, jsut set the relays to current state
if (bandmem[curr_band].attenuator == ATTN_ON && bandmem[curr_band].preamp ==PREAMP_ON)
bandmem[curr_band].attenuator = ATTN_OFF; // turn off if attn is on
// Reading from the radio we just want to update database and screen and not repeat back to radio.
if (curr_band < BAND2400)
{
if (toggle < 3 )
{
if (bandmem[curr_band].preamp)
{
CIVresultL = civ.writeMsg(CIV_ADDR, reinterpret_cast<const uint8_t*>(&cmd_List[CIV_C_PREAMP_ON].cmdData), CIV_D_NIX, CIV_wChk);
DPRINTF("Preamp: Send to Radio ON: retVal: "); DPRINTLN(retValStr[CIVresultL.value]);
}
else
{
CIVresultL = civ.writeMsg(CIV_ADDR, reinterpret_cast<const uint8_t*>(&cmd_List[CIV_C_PREAMP_OFF].cmdData), CIV_D_NIX, CIV_wChk);
DPRINTF("Preamp: Send to Radio OFF: retVal: "); DPRINTLN(retValStr[CIVresultL.value]);
}
}
}
else // preamp and atten not available on IC905 on bands above 1296
{
DPRINTF("Preamp: Skipping for bands > 1296 - curr band is "); DPRINTLN(bandmem[curr_band].band_name);
}
displayAttn();
displayPreamp();
DPRINTF("Preamp: Set Preamp to "); DPRINTLN(bandmem[curr_band].preamp);
}
// RIT button
// Input:
// -1 = Clear MF knob and meter, use current value
// 0 = OFF - turn off button highlight color
// 1 = ON - turn off button highlight and center pan window
// 2 = Toggle RIT ON/OFF state.
// 3 = Zero RIT offset value
// 4 = use dB state, do nto send to radio
COLD void setRIT(int8_t toggle)
{
CIVresult_t CIVresultL;
// global rit_offset is used add to VFOA when displaying or reporting or setting frequency.
// It never changes VFOA value to keep memory and band change complications.
// Will be toggled between 0 and the offset value when active.
// This eliminates the need to test for RIT at every VFOA handling point
if (toggle == 3 && bandmem[curr_band].RIT_en == ON) // Adjust the RIT value if active
{
toggle = 1;
}
else if (toggle == 3 && bandmem[curr_band].RIT_en == OFF) // Zero the RIT value
{
rit_offset_last = rit_offset = 0;
RIT(0); // update frequency offset
}
if (toggle == 2) // toggle if ordered, else just set to current state such as for startup.
{
if (bandmem[curr_band].RIT_en == ON) // toggle the tracking state
toggle = 0;
else
toggle = 1;
}
if (toggle == 1) // Turn on RIT and set to last stored offset
{
bandmem[curr_band].RIT_en = ON;
rit_offset = rit_offset_last; // restore last used value
MeterInUse = true;
setMeter(RIT_BTN);
RIT(0);
}
if (toggle == 0) // prevent acting on multiple calls
{
bandmem[curr_band].RIT_en = OFF;
rit_offset = 0; // now clear it
RIT(0);
}
if (toggle == 0 || toggle == -1)
{
MeterInUse = false;
if (toggle != -1) clearMeter();
}
if (toggle < 4 )
{
CIVresultL = civ.writeMsg(CIV_ADDR, reinterpret_cast<const uint8_t*>(&cmd_List[CIV_C_RIT_ON_OFF].cmdData), reinterpret_cast<const uint8_t*>(&bandmem[curr_band].RIT_en), CIV_wChk);
DPRINTF("Preamp: Send to Radio ON: retVal: "); DPRINTLN(retValStr[CIVresultL.value]);
}
DPRINTF("setRIT: Set RIT ON/OFF to "); DPRINTLN(bandmem[curr_band].RIT_en);
DPRINTF("setRIT: Set RIT OFFSET to "); DPRINT(rit_offset); DPRINTF(" rit_offset_last = "); DPRINTLN(rit_offset_last);
displayRIT();
}
// RIT offset control
COLD void RIT(int8_t delta)
{
int16_t _offset;
if (bandmem[curr_band].RIT_en == ON)
{
_offset = rit_offset; // Get cuurent value
_offset += delta * tstep[user_settings[user_Profile].RIT_ts].step;
if (_offset > 9999) // Limit the value between -10K and +10K
_offset = 9999;
if (_offset < -9999)
_offset = -9999;
rit_offset = _offset; // store in the global RIT offset value
if (bandmem[curr_band].RIT_en == ON)
rit_offset_last = rit_offset; // only store when RIT is active, prevent false zero for things like delayed calls from S-meter box updates
// DPRINTF(RIT: Set RIT OFFSET to "); DPRINT(rit_offset); DPRINTF(" rit_offset_last = "); DPRINTLN(rit_offset_last);
}
// ToDo: Form up rit_offset to send
//CIVresultL = civ.writeMsg(CIV_ADDR, reinterpret_cast<const uint8_t*>(&cmd_List[CIV_C_RIT_ON_OFF].cmdData), reinterpret_cast<const uint8_t*>(rit_offset), CIV_wChk);
//DPRINTF("XIT: Send to Radio XIT: retVal: "); DPRINTLN(retValStr[CIVresultL.value]);
selectFrequency(0); // no base freq change, just correct for RIT offset
displayFreq();
displayRIT();
}
// XIT button
// Input:
// -1 = Clear MF knob and meter, use current value
// 0 = OFF - turn off button highlight color
// 1 = ON - turn off button highlight and center pan window
// 2 = Toggle XIT ON/OFF state.
// 3 = Zero XIT offset value
// 4 = update XIT on/OFf, do not send to radio
COLD void setXIT(int8_t toggle)
{
CIVresult_t CIVresultL;
// global xit_offset is used add to VFOA when displaying or reporting or setting frequency.
// It never changes VFOA value to keep memory and band change complications.
// Will be toggled between 0 and the offset value when active.
// This eliminates the need to test for XIT at every VFO handling point
if (toggle == 3 && bandmem[curr_band].XIT_en == ON) // Adjust the RIT value if active
{
toggle = 1;
}
else if (toggle == 3 && bandmem[curr_band].XIT_en == OFF) // Zero the RIT value
{
xit_offset_last = xit_offset = 0;
XIT(0); // update frequency offset
}
if (toggle == 2) // toggle if ordered, else just set to current state such as for startup.
{
if (bandmem[curr_band].XIT_en == ON) // toggle the tracking state
toggle = 0;
else
toggle = 1;
}
if (toggle == 1) // Turn on XIT and set to last stored offset
{
bandmem[curr_band].XIT_en = ON;
xit_offset = xit_offset_last; // restore last used value
MeterInUse = true;
setMeter(XIT_BTN);
XIT(0);
}