-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathka9q-utils.sh
executable file
·1495 lines (1331 loc) · 67.9 KB
/
ka9q-utils.sh
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}/[email protected]"
declare KA9Q_RADIO_ROOT_DIR="${WSPRDAEMON_ROOT_DIR}/ka9q-radio"
declare KA9Q_RADIO_WD_RECORD_CMD="${KA9Q_RADIO_ROOT_DIR}/wd-record"
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"
declare KA9Q_RADIO_ROOT_DIR="${WSPRDAEMON_ROOT_DIR}/ka9q-radio"
declare KA9Q_RADIO_NWSIDOM="${KA9Q_RADIO_ROOT_DIR}/nwisdom" ### This is created by running fft_wisdom during the KA9Q installation
declare FFTW_DIR="/etc/fftw" ### This is the directory where radiod looks for a wisdomf
declare FFTW_WISDOMF="${FFTW_DIR}/wisdomf" ### This the wisdom file it looks for
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 COMMIT for project ${git_project}"
rc=0
if [[ "$(cd ${git_directory}; git rev-parse HEAD)" == "$( cd ${git_directory}; git fetch origin && git rev-parse origin/${desired_git_sha})" ]]; then
wd_logger 2 "You have asked for and are on the latest commit of the main branch"
else
wd_logger 1 "You have asked for but are not on the latest commit of the main branch, so update the local copy of the code"
( cd ${git_directory}; git fetch origin && git checkout origin/${desired_git_sha} ) >& git.log
rc=$?
if [[ ${rc} -ne 0 ]]; then
wd_logger 1 "ERROR: failed to update to latest commit:\n$(< git.log)"
else
wd_logger 1 "Updated to latest commit"
fi
fi
return ${rc}
fi
### desired COMMIT SHA was specified
local git_root="main" ### Now github's default. older projects like wsprdaemon have the root 'master'
local current_commit_sha
get_current_commit_sha current_commit_sha ${git_directory}
rc=$?
if [[ ${rc} -ne 0 ]]; then
wd_logger 1 "ERROR: 'get_current_commit_sha current_commit_sha ${git_director}' => ${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 1 "First 'git checkout ${git_root}'"
( cd ${git_directory}; git checkout ${git_root} ) >& git.log
rc=$?
if [[ ${rc} -ne 0 ]]; then
wd_logger 1 "ERROR: 'git checkout ${git_root}' => ${rc}. git.log:\n $(< git.log)"
return 4
fi
wd_logger 1 "Then 'git pull' to be sure the code is current"
( cd ${git_directory}; git pull ) >& git.log
rc=$?
if [[ ${rc} -ne 0 ]]; then
wd_logger 1 "ERROR: 'git pull' => ${rc}. git.log:\n$(< git.log)"
return 5
fi
wd_logger 1 "Finally 'git checkout ${desired_git_sha}, which is the COMMIT we want"
( cd ${git_directory}; git checkout ${desired_git_sha} ) >& git.log
rc=$?
if [[ ${rc} -ne 0 ]]; 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 "Assigned ${__return_variable_name}=${receiver_call}"
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 [[ "${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
local conf_variable_name=$4
if [[ ! -f ${conf_file_name} ]] ; then
wd_logger 1 "ERROR: '' doesn't exist"
return 1
fi
local section_lines=$( grep -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}"
return 2
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}"
return 3
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
( cd ${git_directory}; git log ) >& ${GIT_LOG_OUTPUT_FILE}
rc=$?
if [[ ${rc} -ne 0 ]]; then
wd_logger 1 "ERROR: directory ${git_directory} is not a git-created directory:\n$(< ${GIT_LOG_OUTPUT_FILE})"
return 2
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"
return 3
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 __return_radio_conf_file_name=$1
local _radiod_conf_file_name=$( ps aux | awk '!/awk/ && /\/sbin\/radiod /{print $NF}')
if [[ -n "${_radiod_conf_file_name}" ]]; then
wd_logger 2 "Found radiod is running and configured by ${_radiod_conf_file_name}"
eval ${__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"
local ka9q_conf_file_name
if [[ -z "${KA9Q_CONF_NAME-}" ]]; then
ka9q_conf_file_name=${KA9Q_RADIOD_CONF_DIR}/[email protected]
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"
else
ka9q_conf_file_name=${KA9Q_RADIOD_CONF_DIR}/radiod@${KA9Q_CONF_NAME}.conf
wd_logger 2 "In WD.conf found KA9Q_CONF_NAME='${KA9Q_CONF_NAME}' => ${ka9q_conf_file_name}"
if [[ ! -f ${ka9q_conf_file_name} ]]; then
wd_logger 1 "ERROR: The conf file ${ka9q_conf_file_nam} specified by KA9Q_CONF_NAME=${KA9Q__CONF_NAME} doesn't exist"
exit 1
fi
wd_logger 2 "The configured radio conf file ${ka9q_conf_file_name} has been found"
fi
eval ${__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=5
declare KA9Q_METADUMP_WAIT_SECS=${KA9Q_METADUMP_WAIT_SEC-5} ### 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_hz=$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 1 "Spawning 'metadump -c 2 -s ${receiver_freq_hz} ${receiver_ip_address} > metadump.log &' and waiting ${KA9Q_METADUMP_WAIT_SECS} seconds for it to complete"
local metadump_pid
metadump -c 2 -s ${receiver_freq_hz} ${receiver_ip_address} > metadump.log &
metadump_pid=$!
local i
for (( i=0; i<${KA9Q_METADUMP_WAIT_SECS}; ++i)); do
if ! kill -0 ${metadump_pid} 2> /dev/null; then
wait ${metadump_pid}
rc=$?
wd_logger 1 "'metadump...&' has finished before we timed out"
break
fi
wd_logger 2 "Waiting another second for 'metadump...&' to finish"
sleep 1
done
if [[ ${i} -lt ${KA9Q_METADUMP_WAIT_SECS} ]]; then
wd_logger 1 "'metadump..&' finished after ${i} seconds of waiting"
else
wd_logger 1 "ERROR: timing out waiting for 'metadump..&' to terminate itself, so killing its pid ${metadump_pid}"
kill ${metadump_pid} 2>/dev/null
rc=124
fi
if [[ ${rc} -ne 0 ]]; then
wd_logger 1 "ERROR: failed to get any status stream information from 'metadump -c 2 -s ${receiver_freq_hz} ${receiver_ip_address} > metadump.log &'"
else
sed -e 's/ \[/\n[/g' metadump.log > ${status_log_file}
local status_log_line_count=$(wc -l < ${status_log_file} )
wd_logger 1 "Parsed the $(wc -c < metadump.log) bytes of html in 'metadump.log' into ${status_log_line_count} lines in '${status_log_file}'"
if [[ ${status_log_line_count} -gt ${KA9Q_MIN_LINES_IN_USEFUL_STATUS} ]]; then
wd_logger 2 "Got useful status file"
got_status="yes"
else
local wd_logger_string=$(echo "WARNING: there are only ${status_log_line_count} lines in ${status_log_file}:\n$(< ${status_log_file})\nSo try metdump again")
wd_logger 1 "${wd_logger_string}\nmetadum.log:\n$(< metadump.log)"
fi
fi
done
if [[ "${got_status}" == "no" ]]; then
wd_logger 1 "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_hz} ${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() {
local ___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}"
eval ${___return_var}=\"""\" ### ensures that return variable is initialized
return 1
fi
local search_results
search_results=$( sed -n -e "s;^\[[0-9]*\] ${search_val};;p" ${status_file} )
if [[ -z "${search_results}" ]]; then
wd_logger 1 "ERROR: can't find '${search_val}' in ${status_file}"
eval ${___return_var}=\"""\" ### ensures that return variable is initialized
return 2
fi
wd_logger 2 "Found search string '${search_val}' in line and returning '${search_results}'"
eval ${___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() {
local __return_var="$1"
local receiver_ip_address=$2
local receiver_freq_hz=$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_hz} ${status_log_file}
rc=$?
if [[ ${rc} -ne 0 ]]; 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} -ne 0 ]]; then
wd_logger 1 "ERROR: failed to get new status"
return ${rc}
fi
wd_logger 2 "Returning '${value_found}'"
eval ${__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-web 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 2 "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() {
local ___return_status_dns_var_name=$1
local ka9q_web_pid
local ka9q_web_conf_file
local rc
ka9q-get-conf-file-name "ka9q_web_pid" "ka9q_web_conf_file"
rc=$?
if [[ ${rc} -ne 0 ]]; then
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
local hf_locals_count=$(wc -l < avahi-browse.log)
local status_dns=$( sed -n 's/.*\[\(.*\)\].*/\1/p' avahi-browse.log )
case ${hf_locals_count} in
0)
wd_logger 1 "Can't find any hf...local streams"
return 1
;;
1)
wd_logger 1 "Found one radiod outputing ${status_dns}, so there must be an active radiod service running remotely"
eval ${___return_status_dns_var_name}=\"${status_dns}\"
return 0
;;
*)
wd_logger 1 "Found ${hf_locals_count} radiod iservers running on this LAN. Chose which to listen to by adding a line to wsprdaemon.conf:\n$(< avahi-browse.log)"
return 1
;;
esac
fi
if [[ -z "${ka9q_web_conf_file}" || ! -f "${ka9q_web_conf_file}" ]]; then
wd_logger 1 "Cant' find the conf file '${conf_file}' for radiod"
returm 2
fi
local ka9q_radiod_dns
ka9q_radiod_dns=$( grep -A 20 "\[global\]" "${ka9q_web_conf_file}" | awk '/^status =/{print $3}' )
if [[ -z "${ka9q_radiod_dns}" ]]; then
wd_logger 1 "Can't find the 'status =' line in '${conf_file}'"
returm 3
fi
wd_logger 2 "Found the radiod status DNS = '${ka9q_radiod_dns}'"
eval ${___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_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 loop by checking for DNS of status stream"
local ka9q_radiod_status_dns
ka9q-get-status-dns "ka9q_radiod_status_dns" >& /dev/null
rc=$?
if [[ ${rc} -ne 0 ]]; then
wd_logger 1 "ERROR: failed to find the status DNS => ${rc}"
else
local web_title
get_config_file_variable "web_title" "KA9Q_WEB_TITLE"
if [[ -n "${web_title:-}" ]]; then ### note the ':-' syntax which expands to a null string if wd_title is undefined or empty
wd_logger 1 "KA9Q_WEB_TITLE is defined to '${web_title}' in WD.conf"
else
get_first_receiver_reporter "web_title"
if [[ -n "${web_title:-}" ]]; then
wd_logger 1 "KA9Q_WEB_TITLE will be set to the reporter id '${web_title}' of the first receiver in WD.conf"
else
web_title="WSPRDAEMON RX888"
wd_logger 1 "Couldn't find a reporter id in WD.conf, so KA9Q_WEB_TITLE is set to the default '${web_title}'"
fi
fi
ka9q_service_daemons_list[0]="${ka9q_radiod_status_dns} ${KA9Q_WEB_IP_PORT-8081} ${web_title}" ### This is hack to get this one service imlmewntationb 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
sleep 1
done
fi
}
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 web_page_title="$3" ### The description string at the top of the UI page
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 = '${web_page_title}"
${KA9Q_WEB_CMD} -m ${status_dns_name} -p ${server_ip_port} -n "${web_page_title}" >& ${daemon_log_file} ### DANGER: nothing limits the size of this log file!!!
rc=$?
if [[ ${rc} -ne 0 ]]; then
wd_logger 1 "ERROR: '${KA9Q_WEB_CMD} -m ${status_dns_name} -p ${server_ip_port} -n '${web_page_title}' => ${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"
find ${project_subdir} -type f -exec stat -c "%Y %n" {} \; | sort -n > before_make.txt
wd_logger 2 "Building ${project_subdir}"
(
cd ${project_subdir}
if [[ ! -L Makefile ]]; then
if [[ -f Makefile ]]; then
wd_logger 1 "WARNING: Makefile exists but it isn't a symbolic link to Makefile.linux"
rm -f Makefile
fi
wd_logger 1 "Creating a symbolic link from Makefile.linux to Makefile"
ln -s Makefile.linux Makefile
fi
make
) >& ${project_logfile}
rc=$?
if [[ ${rc} -ne 0 ]]; then
wd_logger 1 "ERROR: compile of '${project_subdir}' returned ${rc}:\n$(< ${project_logfile})"
exit 1
fi
find ${project_subdir} -type f -exec stat -c "%Y %n" {} \; | sort -n > after_make.txt
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)
wd_logger 1 "New files were created, so run 'sudo make install"
( 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
### KA9Q installed, so see if it needs to be started or restarted
local ka9q_runs_only_remotely
get_config_file_variable "ka9q_runs_only_remotely" "KA9Q_RUNS_ONLY_REMOTELY"
if [[ ${ka9q_runs_only_remotely} == "yes" ]]; then
if [[ -x ${KA9Q_RADIO_WD_RECORD_CMD} ]]; then
wd_logger 2 "KA9Q software wasn't updated and WD needs only the executable 'wd-record' which exists. So nothing more to do"
return 0
else
wd_logger 1 "ERROR: KA9Q software wasn't updated and only needs the executable 'wd-record' but it isn't present"
exit 1
fi
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
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 1 "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 ka9q_conf_file_name="radiod@${ka9q_conf_name}.conf"
local ka9q_conf_file_path="${KA9Q_RADIOD_CONF_DIR}/${ka9q_conf_file_name}"
local radio_restart_needed="no"
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"
exit 1
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
### By default WD configures radiod to enable RF AGC
local agc_enabled="${KA9Q_RF_AGC_ENABLED-yes}"
if [[ ${agc_enabled} == "yes" ]]; then
sed '/^\[rx888\]/,/^\[/s/^gain/#gain/' ${ka9q_conf_file_path} > /tmp/radiod.conf
if diff -q ${ka9q_conf_file_path} /tmp/radiod.conf > /dev/null ; then
wd_logger 2 "KA9Q_RF_AGC_ENABLED=${agc_enabled} is 'yes', and ${ka9q_conf_file_path} already was configured without a 'gain = ...' linei, so no radiod restart is needed"
else
wd_logger 1 "KA9Q_RF_AGC_ENABLED=${agc_enabled} is 'yes', but ${ka9q_conf_file_path} was configured a 'gain = ...' line. So fix the conf file and restart radiod"
mv /tmp/radiod.conf ${ka9q_conf_file_path}
radio_restart_needed="yes"
fi
else
local rx888_section_gain_line=$(sed -n '/^\[rx888\]/,/^\[/s/^gain/#gain/p' ${ka9q_conf_file_path})
if [[ -z "${rx888_section_gain_line}" ]]; then
wd_logger 1 "KA9Q_RF_AGC_ENABLED=${agc_enabled} is not 'yes', but there is no 'gain = NN' line in ${ka9q_conf_file_path}. So add that line and run WD again"
exit 1
else
wd_logger 2 "KA9Q_RF_AGC_ENABLED=${agc_enabled} is not 'yes' and the needed line '${rx888_section_gain_line}' is present in ${ka9q_conf_file_path}. so no radiod restart is needed"
fi
fi
### Make sure the config doesn't have the broken low = 100, high = 5000 values
ka9q_conf_file_bw_check ${ka9q_conf_name}
### Make sure the wisdomf needed for effecient execution of radiod exists
if [[ -f ${KA9Q_RADIO_NWSIDOM} ]]; then
wd_logger 2 "Found ${KA9Q_RADIO_NWSIDOM} used by radio, so no need to create it"
else
wd_logger 1 "Didn't find ${KA9Q_RADIO_NWSIDOM} by radiod, so need to create it. This may take minutes or even hours..."
cd ${KA9Q_RADIO_ROOT_DIR}
time fftwf-wisdom -v -T 1 -o nwisdom rof1620000 cob9600 cob4800 cob1920 cob1200 cob960 cob800 cob600 cob480 cob400 cob320 cob300 cob200 cob160 cob150
rc=$?
cd - > /dev/null
if [[ ${rc} -ne 0 ]]; then
wd_logger 1 "ERROR: failed to 'time fftwf-wisdom -v -T 1 -o nwisdom rof500000...'"
return 3
fi
if [[ ! -f ${KA9Q_RADIO_NWSIDOM} ]]; then
wd_logger 1 "ERROR: can't find expected '${KA9Q_RADIO_NWSIDOM}'"
return 3
fi
wd_logger 1 "${KA9Q_RADIO_NWSIDOM} has been created"
fi
if [[ ! -f ${FFTW_WISDOMF} || ${KA9Q_RADIO_NWSIDOM} -nt ${FFTW_WISDOMF} ]]; then
if [[ -f ${FFTW_WISDOMF} ]]; then
wd_logger 1 "Backing up the exisitng ${FFTW_WISDOMF} to ${FFTW_WISDOMF}.save before installing a new ${KA9Q_RADIO_NWSIDOM}"
sudo cp -p ${FFTW_WISDOMF} ${FFTW_WISDOMF}.save
fi
wd_logger 1 "Copying ${KA9Q_RADIO_NWSIDOM} to ${FFTW_WISDOMF}"
sudo cp -p ${KA9Q_RADIO_NWSIDOM} ${FFTW_WISDOMF}
local dir_user_group=$(stat --printf "%U:%G" ${FFTW_DIR})
sudo chown ${dir_user_group} ${FFTW_WISDOMF}
wd_logger 1 "Changed ownership of ${FFTW_WISDOMF} to ${dir_user_group}"
radio_restart_needed="yes"
fi
wd_logger 2 "${FFTW_WISDOMF} is current"
### Make sure the udev permissions are set to allow radiod access to the RX888 on the USB bus
wd_logger 2 "Instructing the udev system to give radiod permissions to access the RS888"
sudo udevadm control --reload-rules
sudo udevadm trigger
sudo chmod g+w ${KA9Q_RADIOD_LIB_DIR}
if ! lsusb | grep -q "Cypress Semiconductor Corp" ; then
wd_logger 1 "KA9Q-radio software is installed and configured, but can't find a RX888 MkII attached to a USB port"
exit 1
fi
wd_logger 2 "Found a RX888 MkII attached to a USB port"
if [[ ${radio_restart_needed} == "no" ]] ; then
sudo systemctl is-active radiod@${ka9q_conf_name} > /dev/null
rc=$?
if [[ ${rc} -eq 0 ]]; then
wd_logger 2 "The installiation and configuration checks found no changes were needed and radiod is running, so nothing more to do"
return 0
fi
wd_logger 1 "The installiation and configuration checks found no changes were needed but radiod is not running, so we need to start it"
else
wd_logger 1 "Istalliation and configuration checks made changes that require radiod to be started/restarted"
fi
if sudo systemctl restart radiod@${ka9q_conf_name} > /dev/null ; then
wd_logger 2 "KA9Q-radio was started"
return 0
else
wd_logger 2 "KA9Q-radio failed to start"
return 1
fi
}
#function test_get_conf_section_variable() {
# get_conf_section_variable "test_value" /etc/radio/[email protected] FT8 "data"
#}
#declare test_value
#test_get_conf_section_variable
#printf "%s\n" ${test_value}
#exit
declare KA9Q_FT_TMP_ROOT="${KA9Q_FT_TMP_ROOT-/run}" ### The KA9q FT decoder puts its wav files in the /tmp/ftX/... trees and logs spots to /var/log/ftX.log
declare KA9Q_DECODE_FT_CMD="/usr/local/bin/decode_ft8" ### hacked code which decodes both FT4 and FT8
declare KA9Q_FT8_LIB_REPO_URL="https://github.com/ka9q/ft8_lib.git" ### Where to get that code
declare KA9Q_DECODE_FT8_DIR="${WSPRDAEMON_ROOT_DIR}/ft8_lib" ### Like ka9q-radio, ka9q-web amd onion, build 'decode-ft' in a subdirectory of WD's home
function ka9q-ft-setup() {
local ft_type=$1 ## can be 4 or 8
local ka9q_ft_tmp_dir=${KA9Q_FT_TMP_ROOT}/${ft_type} ### The ftX-decoded will create this directory and put the wav files it needs in it. We don't need to create it.
wd_logger 2 "Find the ka9q conf file"
local rc
local radiod_conf_file_name
ka9q-get-configured-radiod "radiod_conf_file_name"
rc=$?
if [[ ${rc} -ne 0 ]]; then
wd_logger 1 "ERROR: can't find expected 'radiod_conf_file_name'"
return ${rc}
fi
wd_logger 2 "Found the radiod conf file is '${radiod_conf_file_name}'"
wd_logger 2 "Find the multicast DNS name of the stream"
local dns_name
get_conf_section_variable "dns_name" ${radiod_conf_file_name} ${ft_type^^} "data"
rc=$?
if [[ ${rc} -ne 0 ]]; then
wd_logger 1 "ERROR: can't find section ${ft_type^^} 'data =' line 'radiod_conf_file_name'"
return ${rc}
fi
wd_logger 2 "Found the multicast DNS name of the ${ft_type^^} stream is '${dns_name}'"
local decoded_conf_file_name="${KA9Q_RADIOD_CONF_DIR}/${ft_type}-decode.conf"
local mcast_line="MCAST=${dns_name}"
local directory_line="DIRECTORY=${ka9q_ft_tmp_dir}"
local needs_update="no"
if [[ ! -f ${decoded_conf_file_name} ]]; then
wd_logger 1 "File '${decoded_conf_file_name}' doesn't exist, so create it"
needs_update="yes"
elif ! grep -q "${mcast_line}" ${decoded_conf_file_name} ; then
wd_logger 1 "File '${decoded_conf_file_name}' doesn't contain the expected multicast line '${mcast_line}', so recreate the file"
needs_update="yes"
elif ! grep -q "${directory_line}" ${decoded_conf_file_name} ; then
wd_logger 1 "File '${decoded_conf_file_name}' doesn't contain the expected directory line '${directory_line}', so recreate the file"
needs_update="yes"
else
wd_logger 2 "File '${decoded_conf_file_name}' is correct, so no update is needed"
fi
if [[ ${needs_update} == "yes" ]]; then
echo "${mcast_line}" > ${decoded_conf_file_name}
echo "${directory_line}" >> ${decoded_conf_file_name}
wd_logger 1 "Created ${decoded_conf_file_name} which contains:\n$(< ${decoded_conf_file_name})"
fi
local rc
getent group "radio" > /dev/null 2>&1
rc=$?
if [[ ${rc} -ne 0 ]]; then
wd_logger 1 "ERROR: the expected group 'radio' created by ka9q-radio doesn't exist"
return ${rc}
fi
local group_owner=$( stat -c "%G" ${decoded_conf_file_name} )
if [[ ${group_owner} != "radio" ]]; then
wd_logger 1 "'${decoded_conf_file_name}' is owned by group '${group_owner}', not the required group 'radio', so change the ownership"
sudo chgrp "radio" ${decoded_conf_file_name}
rc=$?
if [[ ${rc} -ne 0 ]]; then
wd_logger 1 ""
return ${rc}
fi
fi
local needs_restart="no"
local service_name="${ft_type}-decoded.service"
if [[ ${needs_update} == "yes" ]]; then
wd_logger 1 "We need to restart the '${service_name} because the conf file changed"
needs_restart="yes"
elif ! sudo systemctl status ${service_name} >& /dev/null; then
wd_logger 1 "${service_name} is not running, so it needs to be started"
needs_restart="yes"
else
wd_logger 2 "${service_name} is running and its conf file hasn't changed, so it doesn't need to be restarted"
fi
if [[ ${needs_restart} == "yes" ]]; then
local rc
sudo systemctl restart ${service_name} >& /dev/null
rc=$?
if [[ ${rc} -ne 0 ]]; then
wd_logger 1 "ERROR: failed to restart ${service_name} => ${rc}"
return ${rc}
fi
wd_logger 1 "Restarted service ${service_name}"
fi
### When WD is running KA9Q's FTx decode services it could be configured to decode the wav files with WSJT-x's 'jt9' decoder,
### so create a bash script which can be run by ftX-decoded,
### But since jt9 can't decode ft4 wav files, WD continues to use the 'decode-ft8' program normally used by ka9q-radio.
### Since jt9 appears to be more sensitive than the FT4/8 decoder 'decode-ft8' specified by KA9Q-radio, create this script so that as some point in the future we can run jt9.
### In order that the jt9 spot line format matches that of 'decode-ft8', create a bash shell script which accepts the same arguments, runs jt9 and pipes its output through an awk script
### It is awkward to embed an awk script inline like this, but the alternative would be to add it to WD homne directory. When we strt using jt9 we should put it there.
sudo mkdir -p ${ka9q_ft_tmp_dir}
sudo chmod 777 ${ka9q_ft_tmp_dir}
local ka9q_ft_jt9_decoder="${ka9q_ft_tmp_dir}/wsjtx-ft-decoder.sh"
wd_logger 2 "Creating ${ka9q_ft_jt9_decoder} ft_type=${ft_type}"