-
Notifications
You must be signed in to change notification settings - Fork 18
Expand file tree
/
Copy pathka9q-utils.sh
More file actions
executable file
·1911 lines (1715 loc) · 90.6 KB
/
ka9q-utils.sh
File metadata and controls
executable file
·1911 lines (1715 loc) · 90.6 KB
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
#!/bin/bash
### The previous line signals to the vim editor that it should use its 'bash' editing mode when editing this file
### Wsprdaemon: A robust decoding and reporting system for WSPR
### Copyright (C) 2020-2024 Robert S. Robinett
###
### This program is free software: you can redistribute it and/or modify
### it under the terms of the GNU General Public License as published by
### the Free Software Foundation, either version 3 of the License, or
### (at your option) any later version.
###
### This program is distributed in the hope that it will be useful,
### but WITHOUT ANY WARRANTY; without even the implied warranty of
### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
### GNU General Public License for more details.
###
### You should have received a copy of the GNU General Public License
### along with this program. If not, see <https://www.gnu.org/licenses/>.
### Default to getting Phl's 9/2/23 18:00 PDT sources
declare KA9Q_RADIO_DIR="${WSPRDAEMON_ROOT_DIR}/ka9q-radio"
declare KA9Q_TEMPLATE_FILE="${WSPRDAEMON_ROOT_DIR}/radiod@rx888-wsprdaemon-template.conf"
declare KA9Q_RADIO_ROOT_DIR="${WSPRDAEMON_ROOT_DIR}/ka9q-radio"
declare KA9Q_RADIO_WD_RECORD_CMD="${KA9Q_RADIO_ROOT_DIR}/wd-record"
# 11/15/24 - Scott N5TNL enhanced wd-record to output wav files with 32bit float samples
# wd-record has some new command line options. -p enables float32 wav output (without the -p it'll do int wav files). You'll probably have to also pass -c (channels) and -S (sample rate) because the float
# encoded RTP streams don't include the right bits to ID channel count and sample rate.
declare KA9Q_RADIO_WD_RECORD_CMD_FLOAT_ARGS="${KA9Q_RADIO_WD_RECORD_CMD_FLOAT_ARGS--p -c 1 -S 12000}"
### As of 1/12/2026 WD runs the wd-record command in ka9q-radio comes from Scott instead of a custom version of pcmrecord.
### So KA9Q_RADIO_PCMRECORD_CMD should really be KA9Q_RADIO_WD_RECORD_CMD, but there are too many places that would need to be changed
declare KA9Q_RADIO_PCMRECORD_CMD="/usr/local/bin/wd-record"
declare ka9q_receivers
get_ka9q_receivers "ka9q_receivers"
if [[ -z "${ka9q_receivers}" ]]; then
wd_logger 2 "There are no KA9Q receivers defined in wsprdaemon.conf, so there is no need to setup for them"
return 0
fi
wd_logger 2 "We are running on a server which will host and/or receeive streams from KA9Q SDRs"
function find-pcmrecord()
{
if [[ ! -x "${KA9Q_RADIO_PCMRECORD_CMD}" ]]; then
wd_logger 1 "ERROR: can't find the needed ${KA9Q_RADIO_PCMRECORD_CMD}"
exit 1
fi
wd_logger 1 "Found ${KA9Q_RADIO_PCMRECORD_CMD}"
return 0
}
declare KA9Q_RADIO_TUNE_CMD="${KA9Q_RADIO_ROOT_DIR}/tune"
declare KA9Q_DEFAULT_CONF_NAME="rx888-wsprdaemon"
declare KA9Q_RADIOD_CONF_DIR="/etc/radio"
declare KA9Q_RADIOD_LIB_DIR="/var/lib/ka9q-radio"
### These are the libraries needed by KA9Q, but it is too hard to extract them from the Makefile, so I just copied them here
declare KA9Q_RADIO_LIBS_NEEDED="curl rsync build-essential libusb-1.0-0-dev libusb-dev libncurses-dev libfftw3-dev libbsd-dev libhackrf-dev \
libopus-dev libairspy-dev libairspyhf-dev librtlsdr-dev libiniparser-dev libavahi-client-dev portaudio19-dev libopus-dev \
libnss-mdns mdns-scan avahi-utils avahi-discover libogg-dev python3-soundfile"
declare KA9Q_RADIO_ROOT_DIR="${WSPRDAEMON_ROOT_DIR}/ka9q-radio" ### Where WD installs KA9Q-radio
declare KA9Q_RADIO_WISDOM_FILE_PATH="/var/lib/ka9q-radio/wisdom" ### This is the preferred wisdom file used by KA9Q-radio, and the file created and/or updated each time WD starts
declare FFTW_SYSTEM_WISDOM_FILE_PATH="/etc/fftw/wisdomf" ### The FFTW looko here too and WD ensures they are the some
declare GIT_LOG_OUTPUT_FILE="${WSPRDAEMON_TMP_DIR}/git_log.txt"
### function wd_logger() { echo $@; } ### Only for use when unit testing this file
### Ensure that the set of source code in a git-managed directory is what you want
### Returns: 0 => already that COMMIT, so no change 1 => successfully checked out that commit COMMIT, else 2,3,4 ERROR in trying to execute
function pull_commit(){
local git_directory=$1
local desired_git_sha=$2
local git_project=${git_directory##*/}
local rc
if [[ ! -d ${git_directory} ]]; then
wd_logger 1 "ERROR: project '${git_directory}' does not exist"
return 2
fi
if [[ ${desired_git_sha} =~ main|master ]]; then
wd_logger 2 "Loading the most recent '${desired_git_sha}' COMMIT for project ${git_project}"
(
cd "${git_directory}" || exit 2
# Fetch from origin
if ! git fetch origin; then
exit 2
fi
# Check if update is needed
if [ "$(git rev-parse HEAD)" == "$(git rev-parse origin/${desired_git_sha})" ]; then
exit 0 # No changes needed
else
# Changes needed - attempt update which cleans out all .o and other files and dirs which are not used in the new commit
if rm -f Makefile && git reset --hard "origin/${desired_git_sha}" && git clean -fdx ; then
exit 1 # Success with changes
else
exit 2 # Error during update
fi
fi
) >& git.log
rc=$?
case ${rc} in
0)
wd_logger 2 "Git made no changes"
;;
1)
wd_logger 2 "Git successfully updated this project"
;;
*)
wd_logger 1 "ERROR: rc=${rc}, so failed to update to latest commit:\n$(< git.log)"
;;
esac
return ${rc}
fi
### desired COMMIT SHA was specified
local git_root="main" ### Now github's default. older projects like wsprdaemon have the root 'master'
if [[ ${git_project} == "ft8_lib" ]]; then
git_root="master"
fi
local current_commit_sha
get_current_commit_sha current_commit_sha ${git_directory}
rc=$? ; if (( rc )); then
wd_logger 1 "ERROR: 'get_current_commit_sha current_commit_sha ${git_directory}' => ${rc}"
return 3
fi
if [[ "${current_commit_sha}" == "${desired_git_sha}" ]]; then
wd_logger 2 "Current git COMMIT in ${git_directory} is the expected ${current_commit_sha}"
return 0
fi
wd_logger 1 "Current git commit COMMIT in ${git_directory} is ${current_commit_sha}, not the desired COMMIT ${desired_git_sha}, so update the code from git"
wd_logger 2 "First 'git checkout ${git_root}'"
( cd ${git_directory}; git restore . ; git checkout ${git_root} ) >& git.log
rc=$? ; if (( rc )); then
wd_logger 1 "ERROR: 'git checkout ${git_root}' => ${rc}. git.log:\n $(< git.log)"
exit
return 4
fi
wd_logger 2 "Then 'git pull' to be sure the code is current"
( cd ${git_directory}; git pull ) >& git.log
rc=$? ; if (( rc )); then
wd_logger 1 "ERROR: 'git pull' => ${rc}. git.log:\n$(< git.log)"
return 5
fi
wd_logger 2 "Finally 'git checkout ${desired_git_sha}, which is the COMMIT we want"
( cd ${git_directory}; git clean -fdx; git checkout ${desired_git_sha} ) >& git.log
rc=$? ; if (( rc )); then
wd_logger 1 "ERROR: 'git checkout ${desired_git_sha}' => ${rc} git.log:\n$(< git.log)"
return 6
fi
wd_logger 1 "Successfully updated the ${git_directory} directory to COMMIT ${desired_git_sha}"
return 1
}
##############
function wd_get_config_value() {
local __return_variable_name=$1
local return_variable_type=$2
wd_logger 3 "Find the value of the '${return_variable_type}' from the config settings in the WD.conf file"
if ! declare -p WSPR_SCHEDULE &> /dev/null ; then
wd_logger 1 "ERROR: the array WSPR_SCHEDULE has not been declared in the WD.conf file"
return 1
fi
local -A receiver_reference_count_list=()
local schedule_index
for (( schedule_index=0; schedule_index < ${#WSPR_SCHEDULE[@]}; ++schedule_index )); do
local job_line="${WSPR_SCHEDULE[${schedule_index}]}"
wd_logger 3 "Getting the names and counts of radios defined for job ${schedule_index}: ${job_line}"
local job_line_list=( ${job_line} )
local job_field
for job_field in ${job_line_list[@]:1}; do
local job_receiver=${job_field%%,*}
((receiver_reference_count_list["${job_receiver}"]++))
wd_logger 3 "Found receiver ${job_receiver} referenced in job ${job_field} has been referenced ${receiver_reference_count_list["${job_receiver}"]} times"
done
done
local largest_reference_count=0
local most_referenced_receiver
local receiver_name
for receiver_name in "${!receiver_reference_count_list[@]}"; do
if [[ ${receiver_reference_count_list[${receiver_name}]} -gt ${largest_reference_count} ]]; then
largest_reference_count=${receiver_reference_count_list[${receiver_name}]}
most_referenced_receiver="${receiver_name}"
fi
done
wd_logger 3 "Found the most referenced receiver in the WSPR_SCHEDULE[] is '${most_referenced_receiver}' which was referenced in ${largest_reference_count} jobs"
if ! declare -p RECEIVER_LIST >& /dev/null ; then
wd_logger 1 "ERROR: the RECEIVER_LIST array is not declared in WD.conf"
return 2
fi
local receiver_index
for (( receiver_index=0; receiver_index < ${#RECEIVER_LIST[@]}; ++receiver_index )); do
local receiver_line_list=( ${RECEIVER_LIST[${receiver_index}]} )
local receiver_name=${receiver_line_list[0]}
local receiver_call=${receiver_line_list[2]}
local receiver_grid=${receiver_line_list[3]}
if [[ ${receiver_name} == ${most_referenced_receiver} ]]; then
case ${return_variable_type} in
CALLSIGN)
eval ${__return_variable_name}=\${receiver_call}
wd_logger 2 "Receiver ${receiver_name} is reporting as ${receiver_call} to return variable ${__return_variable_name}"
return 0
;;
LOCATOR)
eval ${__return_variable_name}=\${receiver_grid}
wd_logger 2 "Assigned ${__return_variable_name}=${receiver_grid}"
return 0
;;
ANTENNA)
#local receiver_description=$( sed -n "/${receiver_name}.*${receiver_grid}/s/${receiver_name}.*${receiver_grid}//p" ${WSPRDAEMON_CONFIG_FILE} )
local receiver_line=$( grep "\"${receiver_name} .*${receiver_grid}" ${WSPRDAEMON_CONFIG_FILE} )
local antenna_description
if [[ -n "${ANTENNA_DESCRIPTION-}" ]]; then
antenna_description="${ANTENNA_DESCRIPTION}"
wd_logger 2 "Found the description ANTENNA_DESCRIPTION='${ANTENNA_DESCRIPTION}' in WD.conf"
elif [[ "${receiver_line}" =~ \#.*ANTENNA: ]]; then
antenna_description="${receiver_line##*\#*ANTENNA:}"
shopt -s extglob
antenna_description="${antenna_description##+([[:space:]])}" ### trim off leading white space
wd_logger 2 "Found the description '${antenna_description}' in line: ${receiver_line}"
else
antenna_description="No antenna information"
wd_logger 2 "Can't find comments about receiver ${receiver_call}, so use 'No antenna information'"
fi
eval ${__return_variable_name}="\${antenna_description}"
wd_logger 2 "Assigned ${__return_variable_name}=${antenna_description}"
return 0
;;
*)
wd_logger 1 "ERROR: invalid return_variable_type='${return_variable_type}"
return 0
esac
fi
done
wd_logger 1 "ERROR: can't find ${return_variable_type} config information"
return 1
}
### Assumes ka9q-radio has been successfully installed and setup to run
function get_conf_section_variable() {
local __return_variable_name=$1
local conf_file_name=$2
local conf_section=${3^^} ### forces to UPPER CASE
local conf_variable_name=$4
wd_logger 2 "__return_variable_name-$__return_variable_name, conf_file_name=$conf_file_name, conf_section=$conf_section, conf_variable_name=$conf_variable_name"
local conf_dir_name="${conf_file_name}.d"
if [[ -d ${conf_dir_name} ]]; then
wd_logger 2 "Search for variable '${conf_variable_name}' in section '${conf_section}' among the files found in ${conf_dir_name}"
local files_list=( $(find ${conf_dir_name} -maxdepth 1 -type f ! -name '*~' ) )
if (( ${#files_list[@]} == 0 )); then
wd_logger 1 "ERROR: can't find any files in ${conf_dir_name}"
echo ${force_abort}
fi
if [[ ${conf_section:0:3} == "FT8" ]]; then
wd_logger 2 "Perform special search for FT8 sections since there are multiple sections which start '[FT8-....]'"
conf_section="FT8.*"
fi
local files_with_section_list=( $(grep -i -l "^\[${conf_section}\]" ${files_list[@]} ) )
case ${#files_with_section_list[@]} in
0)
wd_logger 1 "ERROR: can't find a file with section '${conf_section}' in ${conf_dir_name}"
echo ${force_abort}
;;
1)
conf_file_name=${files_with_section_list[0]}
wd_logger 2 "Found section '${conf_section}' in ${conf_file_name}"
;;
*)
wd_logger 1 "ERROR: found ${#files_with_section_list[@]} files with a section '${conf_section}': ${files_with_section_list[*]}"
echo ${force_abort}
;;
esac
### conf_file_name has been changed to that of the conf_file_name.d/NNN file which contans the desired section/variable
fi
if [[ ! -f ${conf_file_name} ]] ; then
wd_logger 1 "ERROR: config file '${conf_file_name}' doesn't exist"
echo ${force_abort}
fi
local section_lines=$( grep -i -A 40 "\[.*${conf_section}\]" ${conf_file_name} | awk '/^\[/ {++count} count == 2 {exit} {print}' )
if [[ -z "${section_lines}" ]]; then
wd_logger 1 "ERROR: couldn't find section '\[${conf_section}\]' in ${conf_file_name}"
echo ${force_abort}
fi
wd_logger 2 "Got section '\[.*${conf_section}\]' in ${conf_file_name}:\n${section_lines}"
local section_variable_value=$( echo "${section_lines}" | awk "/${conf_variable_name} *=/ { print \$3 }" )
if [[ -z "${section_variable_value}" ]]; then
wd_logger 1 "ERROR: couldn't find variable ${conf_variable_name} in ${conf_section} section of config file ${conf_file_name}"
echo ${force_abort}
fi
eval ${__return_variable_name}="\${section_variable_value}"
wd_logger 2 "Returned the value '${section_variable_value}' of variable '${conf_variable_name}' in '${conf_section}' section of config file '${conf_file_name}' to variable '${__return_variable_name}'"
return 0
}
function get_current_commit_sha() {
local __return_commit_sha_variable=$1
local git_directory=$2
local rc
if [[ ! -d ${git_directory} ]]; then
wd_logger 1 "ERROR: directory '${git_directory}' doesn't exist"
return 1
fi
wd_logger 2 "Getting git commit from ${git_directory}"
( cd ${git_directory}; git log >& ${GIT_LOG_OUTPUT_FILE} )
rc=$? ; if (( rc )); then
wd_logger 1 "ERROR: 'cd ${git_directory}; git log' => ${rc}:\n$(head ${GIT_LOG_OUTPUT_FILE})"
echo ${force_abort}
fi
local commit_sha=$( awk '/commit/{print $2; exit}' ${GIT_LOG_OUTPUT_FILE} )
if [[ -z "${commit_sha}" ]]; then
wd_logger 1 "ERROR: 'git log' output does not contain a line with 'commit' in it"
echo ${force_abort}
fi
wd_logger 2 "'git log' is returning the current commit COMMIT = ${commit_sha}"
eval ${__return_commit_sha_variable}=\${commit_sha}
return 0
}
function ka9q-get-configured-radiod() {
local -n __return_radio_conf_file_name=$1
local ka9q_conf_file_name
if [[ -n "${KA9Q_CONF_NAME-}" ]]; then
ka9q_conf_file_name=${KA9Q_RADIOD_CONF_DIR}/radiod@${KA9Q_CONF_NAME}.conf
if [[ ! -f ${ka9q_conf_file_name} ]]; then
wd_logger 1 "ERROR: The conf file ${ka9q_conf_file_name} specified by KA9Q_CONF_NAME=${KA9Q_CONF_NAME} doesn't exist"
exit 1
fi
wd_logger 1 "In WD.conf found KA9Q_CONF_NAME='${KA9Q_CONF_NAME}' => ${ka9q_conf_file_name}"
__return_radio_conf_file_name="${ka9q_conf_file_name}"
return 0
fi
local _radiod_conf_file_list=$( ps aux | awk '!/awk/ && /\/sbin\/radiod /{print $NF}')
if [[ -n "${_radiod_conf_file_list}" ]]; then
local _radiod_conf_file_count=$(wc -l <<< "${_radiod_conf_file_list}")
if (( _radiod_conf_file_count > 1 )); then
wd_logger 1 "WARNING: found ${_radiod_conf_file_count} running radiod instances:\n${_radiod_conf_file_list}\nUsing only the first one"
fi
local _radiod_conf_file_name=$(head -1 <<< "${_radiod_conf_file_list}")
wd_logger 2 "Found radiod is running and configured by ${_radiod_conf_file_name}"
__return_radio_conf_file_name="${_radiod_conf_file_name}"
return 0
fi
wd_logger 2 "radiod isn't running, so find the conf file to use"
ka9q_conf_file_name=${KA9Q_RADIOD_CONF_DIR}/radiod@rx888-wsprdaemon.conf
wd_logger 2 "Found that KA9Q_CONF_NAME has not been defined in WD.conf, so use the default radiod conf file ${ka9q_conf_file_name}"
if [[ ! -f ${ka9q_conf_file_name} ]]; then
wd_logger 1 "ERROR: KA9Q_CONF_NAME was not defined in WD.conf, but the default ${ka9q_conf_file_name} doesn't exist"
exit 1
fi
wd_logger 2 "The default radiod conf file ${ka9q_conf_file_name} has been found"
__return_radio_conf_file_name="${ka9q_conf_file_name}"
wd_logger 2 "Assigned ${!__return_radio_conf_file_name}='${ka9q_conf_file_name}'"
return 0
}
### Checks that the radiod config file is set with the desired low = 1300, high = 1700 and fix them if they were set to 100, 5000 by WD 3.1.4
function ka9q_conf_file_bw_check() {
local conf_name=$1
local running_radiod_conf_file=$( sudo systemctl status | grep -v awk | awk '/\/etc\/radio\/radiod.*conf/{print $NF}' | grep "${conf_name}" )
if [[ -z "${running_radiod_conf_file}" ]]; then
wd_logger 1 "radiod@${conf_name} is not running on this server"
return 0
fi
local rx_audio_low=$( awk '/^low =/{print $3;exit}' ${running_radiod_conf_file}) ### Assume that the first occurence of '^low' and '^high' is in the [WSPR] section
local rx_audio_high=$( awk '/^high =/{print $3;exit}' ${running_radiod_conf_file})
wd_logger 2 "In ${running_radiod_conf_file}: low = ${rx_audio_low}, high = ${rx_audio_high}"
if [[ -z "${rx_audio_low}" || -z "${rx_audio_high}" ]]; then
wd_logger 1 "ERROR: can't find the expected low and/or high settings in ${running_radiod_conf_file}"
return 1
fi
local rx_needs_restart="no"
if [[ "${rx_audio_low}" != "1300" ]]; then
wd_logger 1 "WARNING: found low = ${rx_audio_low}, so changing it to the desired value of 1300"
sed -i "0, /^low =/{s/low = ${rx_audio_low}/low = 1300/}" ${running_radiod_conf_file} ### Only change the first 'low = ' line in the conf file
rx_needs_restart="yes"
fi
if [[ "${rx_audio_high}" != "1700" ]]; then
wd_logger 1 "WARNING: found high = ${rx_audio_high}, so changing it to the desired value of 1700"
sed -i "0, /^high/{s/high = ${rx_audio_high}/high = 1700/}" ${running_radiod_conf_file}
rx_needs_restart="yes"
fi
if [[ ${rx_needs_restart} == "no" ]]; then
wd_logger 2 "No changes needed"
else
wd_logger 1 "Restarting the radiod service"
local radiod_service_name=${running_radiod_conf_file##*/}
radiod_service_name=${radiod_service_name/.conf/.service}
sudo systemctl restart ${radiod_service_name}
fi
return 0
}
### Parses the data fields in the first line with the word 'STAT' in it into the global associative array ka9q_status_list()
declare KA9Q_MIN_LINES_IN_USEFUL_STATUS=20
declare KA9Q_GET_STATUS_TRIES=${KA9Q_GET_STATUS_TRIES-1}
declare KA9Q_METADUMP_WAIT_SECS=${KA9Q_METADUMP_WAIT_SEC-15} ### low long to wait for a 'metadump...&' to complete
declare -A ka9q_status_list=()
### ka9q_get_metadump ${receiver_ip_address} ${receiver_freq_hz} ${status_log_file}
function ka9q_get_metadump() {
local receiver_ip_address=$1
local receiver_freq_khz=$2
local status_log_file=$3
local got_status="no"
local timeout=${KA9Q_GET_STATUS_TRIES}
while [[ "${got_status}" == "no" && ${timeout} -gt 0 ]]; do
(( --timeout ))
wd_logger 2 "Spawning 'metadump --newline --count 2 --ssrc ${receiver_freq_khz} ${receiver_ip_address} > ${status_log_file} &' and waiting ${KA9Q_METADUMP_WAIT_SECS} seconds for it to complete"
local metadump_pid
metadump --newline --count 2 --ssrc ${receiver_freq_khz} ${receiver_ip_address} > ${status_log_file} &
metadump_pid=$!
local i
for (( i=0; i<${KA9Q_METADUMP_WAIT_SECS}; ++i)); do
if ! kill -0 ${metadump_pid} 2> /dev/null; then
wd_logger 2 "metadump pid ${metadump_pid} has exited after ${i} seconds, collecting status"
break
fi
wd_logger 2 "Waiting another second for metadump pid ${metadump_pid} to finish"
sleep 1
done
wait ${metadump_pid} 2>/dev/null
rc=$?
if [[ ${i} -lt ${KA9Q_METADUMP_WAIT_SECS} ]]; then
wd_logger 2 "'metadump..&' finished after ${i} seconds of waiting"
else
wd_logger 2 "ERROR: timing out after ${i} seconds of waiting for 'metadump..&' to terminate itself, so killing its pid ${metadump_pid}:\n$(< ${status_log_file})"
kill ${metadump_pid} 2>/dev/null
rc=124
fi
if (( rc )); then
wd_logger 1 "ERROR: failed to get any status stream information from 'metadump --newline --count 2 --ssrc ${receiver_freq_khz} ${receiver_ip_address} > ${status_log_file} &':\n$(< ${status_log_file})"
else
local status_log_line_count=$(wc -l < ${status_log_file} )
if (( status_log_line_count > KA9Q_MIN_LINES_IN_USEFUL_STATUS )); then
wd_logger 2 "Got useful status file"
got_status="yes"
else
wd_logger 1 "ERROR: There are only ${status_log_line_count} lines, not the expected ${KA9Q_MIN_LINES_IN_USEFUL_STATUS} or more lines in ${status_log_file}:\n$(< ${status_log_file})\nSo try metadump again"
fi
fi
done
if [[ "${got_status}" == "no" ]]; then
wd_logger 2 "ERROR: couldn't get useful status after ${KA9Q_GET_STATUS_TRIES}"
return 1
else
wd_logger 2 "Got new status from: 'metadump -s ${receiver_freq_khz} ${receiver_ip_address} > ${status_log_file}'"
return 0
fi
}
function ka9q_parse_metadump_file_to_status_file() {
local metadump_log_file=${1}
local metadump_status_file=${2}
wd_logger 2 "Parse last STAT line in ${metadump_log_file}"
local last_stat_line=$(grep "STAT" ${metadump_log_file} | tail -n 1)
wd_logger 2 "Last STAT line: ${last_stat_line}"
local last_stat_line_list=(${last_stat_line})
local last_stat_line_date="${last_stat_line_list[@]:0:6}"
local last_stat_line_epoch=$(date -d "${last_stat_line_date}" +%s)
local last_stat_line_host="${last_stat_line_list[6]}"
local last_stat_line_data="${last_stat_line_list[@]:8}"
wd_logger 2 "Last STAT date: ${last_stat_line_date} === epoch ${last_stat_line_epoch}"
wd_logger 2 "Last STAT host: ${last_stat_line_host}"
wd_logger 2 "Last STAT data: '${last_stat_line_data}'"
> ${metadump_status_file}.tmp ### create or truncate the output file
local parsed_status_line="${last_stat_line_data}"
while [[ -n "${parsed_status_line}" ]]; do
local leading_status_field="${parsed_status_line%% \[*}"
echo "${leading_status_field}" >> ${metadump_status_file}.tmp
wd_logger 2 "Got leading_status_field=${leading_status_field}"
local no_left_parens="${parsed_status_line#\[}"
if ! [[ ${no_left_parens} =~ \[ ]]; then
wd_logger 2 "No '[' left after stripping the first one. So we are done parsing"
break
fi
parsed_status_line="[${parsed_status_line#* \[}"
done
sort -t '[' -k2n ${metadump_status_file}.tmp > ${metadump_status_file}
rm -f ${metadump_status_file}.tm
}
function ka9q_parse_status_value() {
declare -n ___return_var="$1"
local status_file=$2
local search_val="$3"
### Parsing metadump's status report lines has proved to be a RE challenge since some lines include a subset of other status report lines
### Also each line starts with its enum value '[xxx]' while some lines include a '/'. This sed expression avoids problems with '/' by delimiting the 's' seach
### and replace command fields with ';' which isn't found in any of the current status lines
if [[ ! -f ${status_file} ]]; then
wd_logger 1 "ERROR: can't find ${status_file}"
___return_var=""
return 1
fi
local search_results
search_results=$( sed -n -e "s#^\[[0-9]*\] ${search_val}##; t print; b; :print; p; q" "${status_file}" 2> sed.stderr | xargs )
local rc=$? ; if (( rc )); then
wd_logger 1 "ERROR: 'sed -n -e 's#^\[[0-9]*\] ${search_val}##; t print; b; :print; p; q' ${status_file}'=> ${rc}:\n$(<sed.stderr)"
___return_var=""
return 1
fi
if [[ -s sed.stderr ]]; then
wd_logger 1 "ERROR: 'sed -n -e 's#^\[[0-9]*\] ${search_val}##; t print; b; :print; p; q' ${status_file}'=> ${rc}, but sed.stderr has:\n$(<sed.stderr)"
fi
if [[ -z "${search_results}" ]]; then
wd_logger 1 "ERROR: can't find '${search_val}' in ${status_file}"
___return_var=""
return 2
fi
wd_logger 2 "Found search string '${search_val}' in line and returning '${search_results}'"
___return_var="${search_results}"
return 0
}
### To avoid executing multiple calls to 'metadump' cache its ouput in ./ka9q_status.log. Each channel needs one of these
declare KA9Q_METADUMP_CACHE_FILE_NAME="./ka9q_status.log"
declare MAX_KA9Q_STATUS_FILE_AGE_SECONDS=${MAX_KA9Q_STATUS_FILE_AGE_SECONDS-5 }
function ka9q_get_current_status_value() {
declare -n __return_var="$1"
local receiver_ip_address=$2
local receiver_freq_khz=$3
local search_val="$4"
local rc
local status_log_file="${KA9Q_METADUMP_CACHE_FILE_NAME}" ### each receiver+channel will have status fields unique to it, so there needs to be a file for each of them
local status_log_file_epoch=0
if [[ -f ${status_log_file} ]]; then
status_log_file_epoch=$(stat -c %Y ${status_log_file} )
fi
local current_epoch=$(printf "%(%s)T")
if [[ $(( current_epoch - status_log_file_epoch )) -lt ${MAX_KA9Q_STATUS_FILE_AGE_SECONDS} ]]; then
wd_logger 2 "Getting value from ${KA9Q_METADUMP_CACHE_FILE_NAME} which is less than ${MAX_KA9Q_STATUS_FILE_AGE_SECONDS} seconds old"
else
wd_logger 2 "Updating ${status_log_file}"
ka9q_get_metadump ${receiver_ip_address} ${receiver_freq_khz} ${status_log_file}
rc=$? ; if (( rc )); then
wd_logger 1 "ERROR: failed to update ${status_log_file}"
return ${rc}
fi
fi
local value_found
ka9q_parse_status_value "value_found" ${status_log_file} "${search_val}"
rc=$? ; if (( rc )); then
wd_logger 1 "ERROR: failed to get new status"
return ${rc}
fi
wd_logger 2 "Returning '${value_found}'"
__return_var="${value_found}"
return 0
}
function ka9q_status_service_test() {
local ad_value
local rc
ka9q_get_current_status_value ad_value wspr-pcm.local 14095600 "A/D overrange:"
rc=$?
if [[ ${rc} -ne 0 ]]; then
printf "'ka9q_get_current_status_value (ad_value wspr-pcm.local 14095600 \"A/D overrange:\") ' => ${rc}\n"
exit ${rc}
fi
printf "'ka9q_get_current_status_value (ad_value wspr-pcm.local 1409660 \"A/D overrange:\") ' returned '${ad_value}'\n"
return -1
}
# ka9q_status_service_test
# exit
#!/bin/bash
# script to install the latest version of ka9q-web
# should be run from BASEDIR (i.e. /home/wsprdaemon/wsprdaemon) and it assumes
# that ka9q-radio has already been built in the ka9q-radio directory
#shopt -s -o nounset ### bash stops with error if undeclared variable is referenced
#set -euo pipefail
# function wd_logger() { echo $@; } ### Only for use when unit testing this file
# function is_uint() { return 0; }
function ka9q-get-conf-file-name() {
local __return_pid_var_name=$1
local __return_conf_file_var_name=$2
local ka9q_ps_line
ka9q_ps_line=$( ps aux | grep "sbin/radiod .*radiod@" | grep -v grep | head -n 14)
if [[ -z "${ka9q_ps_line}" ]]; then
wd_logger 1 "The ka9q-radiod service is not running"
return 1
fi
local ka9q_pid_value
ka9q_pid_value=$(echo "${ka9q_ps_line}" | awk '{print $2}')
if [[ -z "${ka9q_pid_value}" ]]; then
wd_logger 1 "ERROR: couldn't extract the pid value from this ps' line: '${ka9q_ps_line}"
return 2
fi
if ! is_uint "${ka9q_pid_value}" ]]; then
wd_logger 1 "ERROR: couldn't extract a PID(unsigned integer) from the 2nd field of this ps' line: '${ka9q_ps_line}"
return 3
fi
eval ${__return_pid_var_name}=\"\${ka9q_pid_value}\"
local ka9q_conf_file
ka9q_conf_file=$(echo "${ka9q_ps_line}" | awk '{print $NF}')
if [[ -z "${ka9q_conf_file}" ]]; then
wd_logger 1 "ERROR: couldn't extract the conf file path from this ps' line: '${ka9q_ps_line}"
return 2
fi
eval ${__return_conf_file_var_name}=\"\${ka9q_conf_file}\"
wd_logger 1 "Found pid =${ka9q_pid_value} and conf_file = '${ka9q_conf_file}'"
return 0
}
#declare test_pid=foo
#declare test_file_name=bar
#ka9q-get-conf-file-name test_pid test_file_name
#echo "Gpt pid = ${test_pid} amd conf_file = '${test_file_name}'"
#exit
function ka9q-get-status-dns() {
declare -n ___return_status_dns_var_name=$1
local ka9q_web_pid
local ka9q_web_conf_file
local rc
local conf_web_dns
get_config_file_variable "conf_web_dns" "KA9Q_WEB_DNS"
if [[ -n "${conf_web_dns-}" ]]; then
wd_logger 1 "Found KA9Q_WEB_DNS='$conf_web_dns' in WD.conf, so set KA9Q-web to display that"
___return_status_dns_var_name="${conf_web_dns}"
return 0
else
wd_logger 1 "Found no KA9Q_WEB_DNS='<DNS_URL>' in WD.conf, so lookup on the LAN using the avahi DNS service"
fi
ka9q-get-conf-file-name "ka9q_web_pid" "ka9q_web_conf_file"
rc=$? ; if (( rc == 0 )); then
wd_logger 1 "'ka9q-get-conf-file-name "ka9q_web_pid" "ka9q_web_conf_file"' => ${ka9q_web_conf_file}"
else
wd_logger 1 "Can't get ka9q-get-conf-file-name, so no local radiod is running. See if radiod is running remotely"
avahi-browse -t -r _ka9q-ctl._udp 2> /dev/null | grep hf.*.local | sort -u > avahi-browse.log
rc=$? ; if (( rc )); then
wd_logger 1 "ERROR: 'avahi-browse -t -r _ka9q-ctl._udp ' -> ${rc}"
return 1
fi
wd_logger 2 "'avahi-browse -t -r _ka9q-ctl._udp 2> /dev/null | grep hf.*.local | sort -u > avahi-browse.log' => $rc. avahi-browse.log=>'$(< avahi-browse.log)'"
local status_dns_list=( $( sed -n 's/.*\[\(.*\)\].*/\1/p' avahi-browse.log ) )
wd_logger 1 "{#status_dns_list[@]} = ${#status_dns_list[@]}, status_dns_list[] = '${status_dns_list[*]}'"
case ${#status_dns_list[@]} in
0)
wd_logger 1 "Can't find any hf...local streams"
return 1
;;
1)
wd_logger 1 "Found one radiod outputing '${status_dns_list[0]}', so there must be an active radiod service running remotely"
___return_status_dns_var_name="${status_dns_list[0]}"
return 0
;;
*)
local wd_logger_print_arg=$(printf "Found ${#status_dns_list[@]} radiod servers running on this LAN:\n${status_dns_list[*]}\nChose which to display by adding a line like this to wsprdemon.conf:\nKA9Q_WEB_DNS=\"${status_dns_list[0]}\"")
echo -e "$wd_logger_print_arg" >&2 ### wd_logger output goes into the daemon.log file, so echo this to stderr so the user sees it
wd_logger 1 "Multiple DNS:\n$wd_logger_print_arg"
return 1
;;
esac
fi
local ka9q_web_conf_temp_file_path="/tmp/ka9q_web_conf.txt"
local ka9q_web_conf_dir="${ka9q_web_conf_file}.d"
if [[ -d ${ka9q_web_conf_dir} ]] ; then
wd_logger 1 "Getting conf lines from ${ka9q_web_conf_dir}/*"
cat ${ka9q_web_conf_dir}/* > ${ka9q_web_conf_temp_file_path}
elif [[ -z "${ka9q_web_conf_file}" || ! -f "${ka9q_web_conf_file}" ]]; then
wd_logger 1 "Can't find the conf file '${ka9q_web_conf_file}' for radiod"
echo ${force_abort}
else
cp -p ${ka9q_web_conf_file} ${ka9q_web_conf_temp_file_path}
fi
local ka9q_radiod_dns
ka9q_radiod_dns=$( grep -A 20 "\[global\]" "${ka9q_web_conf_temp_file_path}" | awk '/^status =/{print $3}' )
if [[ -z "${ka9q_radiod_dns}" ]]; then
wd_logger 1 "Can't find the 'status =' line in '${ka9q_web_conf_temp_file_path}'"
echo ${force_abort}
fi
wd_logger 1 "Found the radiod status DNS = '${ka9q_radiod_dns}'"
___return_status_dns_var_name="${ka9q_radiod_dns}"
return 0
}
#declare test_dns=foo
#ka9q-get-status-dns "test_dns"
#echo "Gpt status DNS = '${test_dns}'"
#exit
declare KA9Q_WEB_CMD="/usr/local/sbin/ka9q-web"
declare KA9Q_WEB_TITLE="${KA9Q_WEB_TITLE-}"
if [[ -z "${KA9Q_WEB_TITLE}" ]]; then
declare ANTENNA_DESCRIPTION="${ANTENNA_DESCRIPTION-<ANTENNA_NOT_DEFINED>}"
if [[ -n "${WSPRNET_REPORTER_ID-}" && -n "${REPORTER_GRID-}" ]]; then
KA9Q_WEB_TITLE="${WSPRNET_REPORTER_ID}_@${REPORTER_GRID}_${ANTENNA_DESCRIPTION}"
else
KA9Q_WEB_TITLE="<REPORTER_AND_GRID_NOT_DEFINED>"
fi
fi
declare ka9q_service_daemons_list=(
"hf1.local 8081 WW0WWV"
)
### This is called by the watchdog daemon and needs to be extended to support multiple RX888 servers at a site.
function ka9q_web_daemon() {
wd_logger 1 "Starting"
while true; do
local rc
wd_logger 1 "Starting loop by checking for DNS of status stream"
local ka9q_radiod_status_dns=""
while [[ -z "$ka9q_radiod_status_dns" ]]; do
ka9q-get-status-dns "ka9q_radiod_status_dns" #>& /dev/null
rc=$? ; if (( rc )); then
wd_logger 1 "ERROR: ka9q-get-status-dns() => ${rc}"
fi
if [[ -z "${ka9q_radiod_status_dns}" ]]; then
wd_logger 1 "ERROR: can't find ka9q_radiod_status_dns, so sleep for 5 seconds and try again"
sleep 5
fi
done
ka9q_service_daemons_list=()
ka9q_service_daemons_list[0]="${ka9q_radiod_status_dns} ${KA9Q_WEB_IP_PORT-8081} ${KA9Q_WEB_TITLE-NOT_DEFINED}" ### This is hack to get this one service implementation working
local i
for (( i=0; i < ${#ka9q_service_daemons_list[@]}; ++i )); do
local ka9q_service_daemon_info="${ka9q_service_daemons_list[i]}"
wd_logger 1 "Running 'ka9q_web_service_daemon '${ka9q_service_daemon_info}'"
ka9q_web_service_daemon ${ka9q_service_daemon_info} ### These should be spawned off
rc=$?
wd_logger 1 "ERROR: ka9q_web_service_daemon $ka9q_service_daemon_info => $rc. Sleep 5 and run it aagain"
sleep 5
done
done
}
### We could spawn multiple q-web daemons, so I've coded for this to be a spawned daemom. But for now WD supports only one KA9Q-web daemon per server
function ka9q_web_service_daemon() {
local status_dns_name=$1 ### Where to get the spectrum stream (e.g. hf.local)
local server_ip_port=$2 ### On what IP port to offer the UI
local server_description="${3:-}" ### KA9Q_WEB_TITLE, if defined.
server_description="${server_description//_/ }" ### Replace all '_' with ' '
while true; do
if [[ ! -x ${KA9Q_WEB_CMD} ]]; then
wd_logger 1 "ERROR: can't find '${KA9Q_WEB_CMD}'. Sleep and check again"
#exit 1
wd_sleep 3
continue
fi
local daemon_log_file="ka9q_web_service_${server_ip_port}.log"
wd_logger 1 "Got status_dns_name='${status_dns_name}', IP port = ${server_ip_port}, server description = '${server_description}'"
# Conditionally add -n "${server_description}" if KA9Q_WEB_TITLE is defined
if [[ -n "${server_description}" ]]; then
${KA9Q_WEB_CMD} -m ${status_dns_name} -p ${server_ip_port} -n "${server_description}" >& ${daemon_log_file}
else
${KA9Q_WEB_CMD} -m ${status_dns_name} -p ${server_ip_port} >& ${daemon_log_file}
fi
rc=$? ; if (( rc )); then
wd_logger 1 "ERROR: '${KA9Q_WEB_CMD} -m ${status_dns_name} -p ${server_ip_port} -n '${server_description}' => ${rc}:\n$(< ${daemon_log_file})"
fi
wd_logger 1 "Sleeping for 5 seconds before restarting"
wd_sleep 5
done
}
#function test_ka9q-web-setup() {
# ka9q-web-setup
#}
# test_ka9q-web-setup
### This function is executed once the ka9q-radio dirrectory is created and has the configured version of SW installed
function build_ka9q_radio() {
local project_subdir=$1
local project_logfile="${project_subdir}_build.log"
wd_logger 2 "Starting"
if [[ ! -e ${project_subdir} ]]; then
wd_logger 1 "ERROR: project_subdir=${project_subdir} doesn't exist"
return 1
fi
local rc
find ${project_subdir} -type f -exec stat -c "%Y %n" {} \; | sort -n > before_make.txt
rc=$? ; if (( rc )); then
wd_logger 1 "ERROR: 'find ${project_subdir} -type... > before_make.txt' => ${rc}"
return 2
fi
wd_logger 2 "Building ${project_subdir}"
local makefile_name="Makefile"
if [[ ${project_subdir} == "ka9q-radio" && -f "${project_subdir}/Makefile.linux" ]]; then
makefile_name="Makefile.linux"
fi
( cd ${project_subdir} ; make -f ${makefile_name} ) >& ${project_logfile}
rc=$? ; if (( rc )); then
wd_logger 1 "ERROR: compile of '${project_subdir}' returned ${rc}:\n$(< ${project_logfile})"
return 3
fi
find ${project_subdir} -type f -exec stat -c "%Y %n" {} \; | sort -n > after_make.txt
rc=$? ; if (( rc )); then
wd_logger 1 "ERROR: 'find ${project_subdir} -type...' > after_make.tx => ${rc} "
return 3
fi
diff before_make.txt after_make.txt > diff.log
rc=$? ; case ${rc} in
0)
wd_logger 2 "No new files were created, so no need for a 'sudo make install"
;;
1)
( cd ${project_subdir}; sudo make install ) >& ${project_logfile}
;;
*)
wd_logger 1 "ERROR: 'diff before_make.txt after_make.txt' => ${rc}:\n$(< diff.log)"
exit 1
esac
shopt -s nullglob
local -a conf_files=( /etc/radio/radiod@*.conf )
local -a conf_dirs=( /etc/radio/radiod@*.conf.d/ )
shopt -u nullglob
if (( ${#conf_files[@]} + ${#conf_dirs[@]} == 0 )); then
wd_logger 1 "There are no radiod config files or directories in /etc/radio/, so we need to configure and start radiod"
fi
if (( ${#conf_files[@]} + ${#conf_dirs[@]} > 1 )); then
wd_logger 1 "WARNING: There are multiple radiod configs: ${conf_files[*]} ${conf_dirs[*]}. For now such configurations must be manually managed"
fi
### We are configured to decode from a local RX888.
if ! getent group "radio" > /dev/null 2>&1; then
wd_logger 1 "ERROR: the group 'radio' which should have been created by KA9Q-radio doesn't exist"
exit 1
fi
if id -nG "${USER}" | grep -qw "radio" ; then
if ! touch ${KA9Q_RADIOD_CONF_DIR}/test_writing 2> /dev/null ; then
wd_logger 1 "You are a member of the group 'radio', but you need to log out of Linux and log in again in order to install KA9Q-radio files"
exit 1
fi
rm ${KA9Q_RADIOD_CONF_DIR}/test_writing
wd_logger 2 "'${USER}' is a member of the group 'radio', so we can proceed to create and/or create the radiod@conf file needed to run radios"
else
sudo usermod -aG radio ${USER}
wd_logger 1 "NOTE: Needed to add user '${USER}' to the group 'radio', so YOU NEED TO logout/login to this server before KA9Q services can run"
exit 1
fi
if [[ ! -d ${KA9Q_RADIOD_CONF_DIR} ]]; then
wd_logger 1 "ERROR: can't find expected KA9Q-radio configuration directory '${KA9Q_RADIOD_CONF_DIR}'"
exit 1
fi
### Setup the radiod@conf files before starting or restarting it
local ka9q_conf_name
get_config_file_variable "ka9q_conf_name" "KA9Q_CONF_NAME"
if [[ -n "${ka9q_conf_name}" ]]; then
wd_logger 2 "KA9Q radiod is using configuration '${ka9q_conf_name}' found in the WD.conf file"
else
ka9q_conf_name="${KA9Q_DEFAULT_CONF_NAME}"
wd_logger 2 "KA9Q radiod is using the default configuration '${ka9q_conf_name}'"
fi
local radio_restart_needed="no"
local ka9q_conf_dir="${KA9Q_RADIOD_CONF_DIR}"
local ka9q_conf_file_name="radiod@${ka9q_conf_name}.conf"
### Default is to find the config sections in the old style single ..conf file
local ka9q_conf_file_path="${KA9Q_RADIOD_CONF_DIR}/${ka9q_conf_file_name}"
local rx888_rf_gain="#"
if [[ -n "${RX888_RF_AGC_FIXED_GAIN-}" ]]; then
wd_logger 1 "We are configured to set the RX888's RF AGC to the fixed value '${RX888_RF_AGC_FIXED_GAIN}'"
rx888_rf_gain=${RX888_RF_AGC_FIXED_GAIN} ## This must be a signed INT and shoud be in the range of -5 to 34"
fi
### INI/CONF FILE SECTION VARIABLE DESIRED VALUE
local init_file_section_variable_value_list=(
"${ka9q_conf_file_path} rx888 gain ${rx888_rf_gain}" ### Default is to remark out any active gain = <INTEGER> lines so that RF AGC will be enabled, but that can be overridden
"${ka9q_conf_file_path} rx888 description 63" ### avahi DNS names can be at most 63 characters and can't include '/' and other special chars, so error out if that isn't the case
"${ka9q_conf_file_path} WSPR agc 0"
"${ka9q_conf_file_path} WSPR gain 0"
"${ka9q_conf_file_path} WSPR low 1300"
"${ka9q_conf_file_path} WSPR high 1700"
"${ka9q_conf_file_path} WSPR encoding float"
"${ka9q_conf_file_path} WWV-IQ disable no"
"${ka9q_conf_file_path} WWV-IQ agc 0"
"${ka9q_conf_file_path} WWV-IQ gain 0"
"${ka9q_conf_file_path} WWV-IQ encoding float"
)
if [[ "${RX888_64_MSPS-no}" == "yes" ]]; then
init_file_section_variable_value_list+=("${ka9q_conf_file_path} rx888 samprate 64800000")
else
### The default is to run the RX888 at 129.6 Msps
init_file_section_variable_value_list+=("${ka9q_conf_file_path} rx888 samprate 129600000")
fi
if ! [[ -d ${ka9q_conf_file_path}.d ]]; then
wd_logger 2 "Checking KA9Q configurations in files in old style single file ${ka9q_conf_file_path}"
if [[ ! -f ${ka9q_conf_file_path} ]]; then
if ! [[ -f ${KA9Q_TEMPLATE_FILE} ]]; then
wd_logger 1 "ERROR: the conf file '${ka9q_conf_file_path}' for configuration ${ka9q_conf_name} does not exist"
echo ${force-abort}
else
wd_logger 1 "Creating ${ka9q_conf_file_path} from template ${KA9Q_TEMPLATE_FILE}"
cp ${KA9Q_TEMPLATE_FILE} ${ka9q_conf_file_path}
radio_restart_needed="yes"
fi
fi
if grep -q "m[0-9]*k" ${ka9q_conf_file_path} ; then
### 3/12/25 - RR The template radiod@rx888-wsprdaemon.conf included in Ka9q-radio installations to date includes an invalid 17m FT4 band frequency specification "18m10k000"
### This section repairs that and any other similarly corrupted frequency specs
wd_logger 1 "Fixing corrupt frequency value(s) '$(grep -oE "m[0-9]*k" ${ka9q_conf_file_path})' found in ${ka9q_conf_file_path}"
sed -i -E 's/(m[0-9]*)k/\1/g' ${ka9q_conf_file_path}
rc=$? ; if (( rc )); then
wd_logger 1 "ERROR: 'sed -i -E 's/(m[0-9]*)k/\1/g' ${ka9q_conf_file_path}' => $rc, so failed to correct corrupt freq line(s)"
else
wd_logger 1 "Fixed correct corrupt freq line(s), so restart radiod"
radio_restart_needed="yes"
fi
fi
else
ka9q_conf_dir="${ka9q_conf_file_path}.d"
wd_logger 2 "Checking KA9Q configurations in files in new style directory ${ka9q_conf_dir}"
if find ${ka9q_conf_dir} -mindepth 1 -type f -print -quit | grep -q .; then
wd_logger 2 "There are flat files in ${ka9q_conf_dir}"
else
wd_logger 1 "${ka9q_conf_dir} exists, but there are no files in it"
echo ${force_abort}
fi
local new_style_conf_file
local index
for (( index=0; index < ${#init_file_section_variable_value_list[@]}; ++index )); do
local config_variable_info_list=( ${init_file_section_variable_value_list[index]} )
local target_section=${config_variable_info_list[1]}
local target_section_regex="^\[.*${target_section}\]"
local target_section_file_path_list=( $(grep -il "${target_section_regex}" $( find ${ka9q_conf_dir} -type f ! -name '*~') ) ) ## Ignore Phil's editor's ...~ files
if (( ${#target_section_file_path_list[@]} == 0 )); then
wd_logger 1 "ERROR: can't find a file in ${ka9q_conf_dir} which contains [${target_section}]"
echo ${force_abort}
elif (( ${#target_section_file_path_list[@]} > 1 )); then
wd_logger 1 "ERROR: found ${#target_section_file_path_list[@]} which contain [${target_section}]: ${target_section_file_path_list[*]}"
echo ${force_abort}
else
wd_logger 2 "Found regex of [${target_section}] in ${target_section_file_path_list[0]}"