-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy path710.sh
executable file
·977 lines (912 loc) · 29.4 KB
/
710.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
#!/bin/bash
#================================================================
# HEADER
#================================================================
#% SYNOPSIS
#+ ${SCRIPT_NAME} [-hv] [-s STRING] [-p PORT] COMMAND
#%
#% DESCRIPTION
#% CAT control script for Kenwood TM-D710G/TM-V71A.
#% Set radio's PC port speed to ${SPEED} or change SPEED variable in this script to
#% match radio's setting.
#%
#% OPTIONS
#% -s STRING, --string=STRING
#% String to grep for in /dev/serial/by-id
#% to determine the serial port used to connect to your
#% radio. Default string: ${DEFAULT_PORTSTRING}
#%
#% -p PORT, --port=PORT
#% Serial port connection to radio (ex. /dev/ttyUSB0).
#% If both -p and -s are supplied, -p will be used.
#%
#% -h, --help
#% Print this help
#% -v, --version
#% Print script version
#%
#% COMMANDS
#% ${SCRIPT_NAME} [OPTIONS] get apo Prints Auto Power Off setting
#% ${SCRIPT_NAME} [OPTIONS] get data Prints the side configured for external data
#% ${SCRIPT_NAME} [OPTIONS] get firmware Prints firmware version
#% ${SCRIPT_NAME} [OPTIONS] get info Prints some radio settings
#% ${SCRIPT_NAME} [OPTIONS] get memory <channel>|<Ch1>-<Ch2>
#% Prints memory channel information for a specific
#% channel or a range of channels between Ch1 and Ch2.
#% Channel numbers must range between 0 and 999 and
#% Ch1 < Ch2. Printing all the channels, 0-999, will take
#% a VERY long time!
#% ${SCRIPT_NAME} [OPTIONS] get menu Prints raw menu contents output
#% (diagnostic command)
#% ${SCRIPT_NAME} [OPTIONS] get a|b mode Prints mode (modulation) settings
#% ${SCRIPT_NAME} [OPTIONS] get power Prints power settings
#% ${SCRIPT_NAME} [OPTIONS] get pttctrl Prints PTT and CTRL settings
#% ${SCRIPT_NAME} [OPTIONS] get speed Prints external data speed (1200|9600)
#% ${SCRIPT_NAME} [OPTIONS] get sqc Prints SQC source
#% ${SCRIPT_NAME} [OPTIONS] get a|b squelch
#% Prints squelch settings for side A or B
#% ${SCRIPT_NAME} [OPTIONS] get timeout Prints TX timeout setting
#% ${SCRIPT_NAME} [OPTIONS] get aip
#% Prints Advanced Intercept Point setting for VHF and UHF
#% ${SCRIPT_NAME} [OPTIONS] set apo off|30|60|90|120|180
#% Sets Automatic Power Off (minutes)
#% ${SCRIPT_NAME} [OPTIONS] set a|b ctrl
#% Sets CTRL to side A or B
#% ${SCRIPT_NAME} [OPTIONS] set a|b data
#% Sets external data to side A or B
#% ${SCRIPT_NAME} [OPTIONS] set a|b freq <MHz>
#% Sets side A or B to VFO and sets frequency to <MHz>
#% ${SCRIPT_NAME} [OPTIONS] set a|b memory <memory>
#% Sets side A or B to memory mode and assigns
#% <memory> location to it
#% ${SCRIPT_NAME} [OPTIONS] set a|b mode vfo|memory|call|wx
#% Sets side A or B mode
#% ${SCRIPT_NAME} [OPTIONS] set a|b power l|m|h
#% Sets side A or B to Low, Medium or High power
#% ${SCRIPT_NAME} [OPTIONS] set a|b ptt
#% Sets PTT to side A or B
#% ${SCRIPT_NAME} [OPTIONS] set a|b pttctrl
#% Sets PTT and CTRL to side A or B
#% ${SCRIPT_NAME} [OPTIONS] set speed 1200|9600
#% Sets external data speed to 1200 or 9600
#% ${SCRIPT_NAME} [OPTIONS] set a|b squelch <0-31>
#% Sets squelch level for side A or B
#% ${SCRIPT_NAME} [OPTIONS] set timeout 3|5|10
#% Sets transmit timeout (minutes)
#% ${SCRIPT_NAME} [OPTIONS] set vhf|uhf aip on|off
#% Sets Advanced Intercept Point for VHF or UHF
#% ${SCRIPT_NAME} [OPTIONS] help Prints this help screen
#%
#% NOTES
#%
#% This script will check to see if 710.py (the GUI) is already running and if so,
#% will attempt to communicate with it using XML-RPC. Failing that, it will attempt
#% to start 710.py in non-GUI "one shot" mode and pass the command and serial port
#% to it.
#%
#% Kenwood makes no commands available to change frequencies from one frequency band to
#% another. For example, if the current VFO is 145.020, you cannot change the frequency
#% using the script to 445.020. The workaround is to program memories as needed with
#% frequencies in different frequency bands and then use the "set a|b memory <memory>"
#% command as described above.
#%
#% This script uses the Kenwood rig control commands documented by LA3QMA at
#% https://github.com/LA3QMA/TM-V71_TM-D710-Kenwood
#%
#% EXAMPLES
#%
#% Check to see if 710.py is running, and if so, pass the command to it via XML-RPC.
#% If not, locate serial port file name containing ${DEFAULT_PORTSTRING}
#% (default search string), then set APO to 30 minutes:
#%
#% ${SCRIPT_NAME} set apo 30
#%
#% Override the default search string ${DEFAULT_PORTSTRING} to locate serial port
#% connected to radio, then get radio information (will use XML-RPC, if 710.py is
#% running, even if you supply the search string):
#%
#% ${SCRIPT_NAME} -s Prolific_Technology get info
#%
#% Specify the serial port used to connect to your radio then set radio TX timeout
#% to 3 minutes:
#%
#% ${SCRIPT_NAME} -p /dev/ttyUSB0 set timeout 3
#%
#================================================================
#- IMPLEMENTATION
#- version ${SCRIPT_NAME} 5.3.3
#- author Steve Magnuson, AG7GN
#- license CC-BY-SA Creative Commons License
#- script_id 0
#-
#================================================================
# HISTORY
# 20180125 : Steve Magnuson : Script creation
# 20200203 : Steve Magnuson : New script template
# 20200330 : Steve Magnuson : Improved debugging of serial port problems, added
# ability to print multiple memory locations.
# 20201215 : Steve Magnuson : Removed dependency on rigctl. Now uses 710.py.
# 20210615 : Steve Magnuson : Fixed DCS values (thanks, AI3I)
# 20220129 : Steve Magnuson : Added XML-RPC compatibility
#================================================================
# DEBUG OPTION
# set -n # Uncomment to check your syntax, without execution.
# set -x # Uncomment to debug this shell script
#
#================================================================
# END_OF_HEADER
#================================================================
SYNTAX=false
DEBUG=false
#============================
# FUNCTIONS
#============================
function TrapCleanup() {
[[ -d "${TMPDIR}" ]] && rm -r "${TMPDIR}"
exit 0
}
function SafeExit() {
# Delete temp files, if any
[[ -d "${TMPDIR}" ]] && rm -r "${TMPDIR}"
trap - INT TERM EXIT
exit $1
}
function ScriptInfo() {
HEAD_FILTER="^#-"
[[ "$1" = "usage" ]] && HEAD_FILTER="^#+"
[[ "$1" = "full" ]] && HEAD_FILTER="^#[%+]"
[[ "$1" = "version" ]] && HEAD_FILTER="^#-"
head -${SCRIPT_HEADSIZE:-99} ${0} | grep -e "${HEAD_FILTER}" | \
sed -e "s/${HEAD_FILTER}//g" \
-e "s/\${SCRIPT_NAME}/${SCRIPT_NAME}/g" \
-e "s/\${SPEED}/${SPEED}/g" \
-e "s/\${DEFAULT_PORTSTRING}/${DEFAULT_PORTSTRING}/g"
}
function Usage() {
printf "Usage: "
ScriptInfo usage
exit 0
}
function Die () {
echo -e "${*}"
SafeExit 1
}
#----------------------------
function CheckForXMLRPC() {
for PID in $(pgrep -f $(basename $MAIN_SCRIPT) | xargs)
do
local SOCKET="$(netstat -lp tcp 2>/dev/null | grep "$PID/python" | tr -s ' ' | tr ' ' ',')"
[[ -n $SOCKET ]] || continue
local PORT=$(echo $SOCKET | cut -d, -f4 | cut -d: -f2)
if [[ -n $PORT ]]
then
echo $PORT
break
fi
done
echo ""
}
function GetSet () {
RESULT="$($RIGCTL "$1")"
if (( $? != 0 ))
then
if [[ -n $XMLRPC_PORT ]]
then
Die "Unable to contact XML-RPC server http://localhost:$XMLRPC_PORT"
else
Die "Unable to communicate with radio via $PORT @ $SPEED bps.\nCheck serial port connection to radio and make sure radio's \"PC PORT BAUDRATE\" is set to $SPEED.\nOn the TM-D710G, the serial cable must be plugged in to the PC port on the TX/RX Unit,\nnot the COM port on the Operation panel."
fi
fi
local CMD="$(echo $1 | cut -d' ' -f1)"
if [[ $RESULT =~ ^($CMD|N|\?) ]]
then
RESULT="$(echo $RESULT | cut -d' ' -f2- | tr -cd '\40-\176')"
echo "$RESULT"
else
kill -SIGUSR1 $$
fi
}
function set_FREQ () {
[[ $P4 =~ ^[0-9]+([.][0-9]+)?$ ]] || Die "Frequency must be number between $(PrintMHz ${MINFREQ[$1]}) and $(PrintMHz ${MAXFREQ[$1]}) MHz"
FR=$(printf "%0.f" $(bc -l <<< "$P4*1000000"))
if (( $FR <= ${MAXFREQ[$1]} )) && (( $FR >= ${MINFREQ[$1]} ))
then
ANS="$(GetSet "VM ${SIDE[$1]},0")" # Set side to VFO before setting frequency
ANS="$(GetSet "FO ${SIDE[$1]},$(printf "%010d" $((10#$FR))),0,0,0,0,0,0,00,00,000,00000000,0")"
else
Die "Frequency must be number between $(PrintMHz ${MINFREQ[$1]}) and $(PrintMHz ${MAXFREQ[$1]}) MHz"
fi
}
function get_FREQ () {
ANS="$(GetSet "FO ${SIDE[$1]}")"
PrintFreq "$ANS" "FO" ""
ANS="$(GetSet "VM ${SIDE[$1]}")"
echo -n "Side $1 is in ${MODE1[${ANS#*,}]} mode"
if [[ ${MODE1[${ANS#*,}]} == "Memory" ]]
then
ANS="$(GetSet "MR ${SIDE[$1]}")"
ANS="$(GetSet "MN ${ANS#*,}")"
echo ": Memory location: $ANS"
else
echo
fi
}
function get_PTTCTRL () {
ANS="$(GetSet "BC")"
CTRL=${ANS%,*}
PTT=${ANS#*,}
case "$PTT" in
0|1)
echo "PTT is on Side ${SIDE[$PTT]}"
;;
*)
Die "ERROR: Unable to determine PTT state $PTT"
;;
esac
case "$CTRL" in
0|1)
echo "CTRL is on Side ${SIDE[$CTRL]}"
;;
*)
Die "ERROR: Unable to determine CTRL state $CTRL."
;;
esac
}
function PrintMHz () {
echo "$(printf "%0.4f" $(bc -l <<< "$1/1000000"))"
}
function PrintMenu () {
MU=($(echo $1 | tr -s ',' ' '))
echo $MU
}
function SetMenu () {
# $1 is the menu input, comma separated
# $2 is the parameter to change (1-42)
# $3 is the value to set that parameter to
MU=($(echo $1 | tr -s ',' ' '))
MU[$2]="$3"
# Convert back to comma separated string
UM="${MU[@]}"
echo ${UM// /,}
}
function PrintDataSide () {
local S=( "A" "B" "TX A, RX B" "TX B, RX A" )
local MU=($(echo $1 | tr -s ',' ' '))
echo ${S[${MU[37]}]}
}
function PrintTimeout () {
local T=( "3 minutes" "5 minutes" "10 minutes" )
local MU=($(echo $1 | tr -s ',' ' '))
echo ${T[${MU[15]}]}
}
function PrintAIP () {
local ST=( Off On )
local MU=($(echo $1 | tr -s ',' ' '))
echo -e "VHF AIP is ${ST[${MU[11]}]}\nUHF AIP is ${ST[${MU[12]}]}"
}
function PrintAPO () {
local T=( "off" "30 minutes" "60 minutes" "90 minutes" "120 minutes" "180 minutes" )
local MU=($(echo $1 | tr -s ',' ' '))
echo ${T[${MU[36]}]}
}
function PrintSQCsource () {
local T=( "off" "busy" "SQL" "TX" "BUSY or TX" "SQL or TX" )
local MU=($(echo $1 | tr -s ',' ' '))
echo ${T[${MU[39]}]}
}
function PrintSpeed () {
local T=( "1200" "9600" )
local MU=($(echo $1 | tr -s ',' ' '))
echo ${T[${MU[38]}]}
}
function PrintFreq () {
F=($(echo $1 | tr -s ',' ' '))
declare -a FF
if [[ "$2" == "ME" ]]
then
FF[0]="Memory Channel"
else
FF[0]="Side"
fi
FF[1]="Frequency"
FF[2]="Step Size"
FF[3]="Shift Direction"
FF[4]="Reverse"
FF[5]="Tone Status"
FF[6]="CTCSS Status"
FF[7]="DCS Status"
FF[8]="Tone frequency"
FF[9]="CTCSS frequency"
FF[10]="DCS frequency"
FF[11]="Offset frequency in Hz"
FF[12]="Mode"
if [[ "$2" == "ME" ]]
then
FF[13]="Frequency"
FF[14]="Unknown"
FF[15]="Lock out"
fi
SS=( "5" "6.25" "8.33" "10" "12.5" "15" "20" "25" "30" "50" "100" )
SD=( "Simplex" "Up" "Down" "Split" )
TF=( "67" "69.3" "71.9" "74.4" "77" "79.7" "82.5" "85.4" "88.5" "91.5" "94.8" \
"97.4" "100" "103.5" "107.2" "110.9" "114.8" "118.8" "123" "127.3" "131.8" \
"136.5" "141.3" "146.2" "151.4" "156.7" "162.2" "167.9" "173.8" "179.9" \
"186.2" "192.8" "203.5" "240.7" "210.7" "218.1" "225.7" "229.1" "233.6" \
"241.8" "250.3" "254.1" )
DCS=( "23" "25" "26" "31" "32" "36" "43" "47" "51" "53" "54" "65" "71" "72" \
"73" "74" "114" "115" "116" "122" "125" "131" "132" "134" "143" "145" \
"152" "155" "156" "162" "165" "172" "174" "205" "212" "223" "225" "226" \
"243" "244" "245" "246" "251" "252" "255" "261" "263" "265" "266" "271" \
"274" "306" "311" "315" "325" "331" "332" "343" "346" "351" "356" "364" \
"365" "371" "411" "412" "413" "423" "431" "432" "445" "446" "452" "454" \
"455" "462" "464" "465" "466" "503" "506" "516" "523" "526" "532" "546" \
"565" "606" "612" "624" "627" "631" "632" "654" "662" "664" "703" "712" \
"723" "731" "732" "734" "743" "754" )
M=( "FM" "NFM" "AM" )
L=( "Off" "On" )
S=( "A" "B" )
if [[ $2 == "ME" && $3 == "LIST" ]]
then
echo -e "$(PrintMHz ${F[1]})\t${SS[$((10#${F[2]}))]}\t${SD[$((10#${F[3]}))]}\t${L[${F[4]}]}\t${L[${F[5]}]}\t${L[${F[6]}]}\t${L[${F[7]}]}\t${TF[$((10#${F[8]}))]}\t${TF[$((10#${F[9]}))]}\t${DCS[$((10#${F[10]}))]}\t$(PrintMHz ${F[11]})\t${M[${F[12]}]}\t${L[${F[15]}]}"
else
if [[ $2 == "ME" ]]
then
echo "Memory Channel: ${F[0]}"
else
echo "Side: ${S[${F[0]}]}"
fi
echo "Frequency: $(PrintMHz ${F[1]}) MHz"
echo "Step Size: ${SS[$((10#${F[2]}))]} KHz"
echo "Shift Direction: ${SD[$((10#${F[3]}))]}"
echo "Reverse: ${L[${F[4]}]}"
echo "Tone Status: ${L[${F[5]}]}"
echo "CTCSS Status: ${L[${F[6]}]}"
echo "DCS Status: ${L[${F[7]}]}"
echo "Tone Frequency: ${TF[$((10#${F[8]}))]} Hz"
echo "CTCSS Frequency: ${TF[$((10#${F[9]}))]} Hz"
echo "DCS Frequency: ${DCS[$((10#${F[10]}))]} Hz"
echo "Offset Frequency: $(PrintMHz ${F[11]}) MHz"
echo "Modulation: ${M[${F[12]}]}"
if [[ $2 == "ME" ]]
then
#echo "Frequency?: $(PrintMHz ${F[13]}) MHz"
#echo "Unknown Parameter: ${F[14]}"
echo "Lockout: ${L[${F[15]}]}"
fi
fi
}
#============================
# FILES AND VARIABLES
#============================
#== general variables ==#
SCRIPT_NAME="$(basename ${0})" # scriptname without path
SCRIPT_DIR="$( cd $(dirname "$0") && pwd )" # script directory
SCRIPT_FULLPATH="${SCRIPT_DIR}/${SCRIPT_NAME}"
SCRIPT_ID="$(ScriptInfo | grep script_id | tr -s ' ' | cut -d' ' -f3)"
SCRIPT_HEADSIZE=$(grep -sn "^# END_OF_HEADER" ${0} | head -1 | cut -f1 -d:)
# Set Temp Directory
# -----------------------------------
# Create temp directory with three random numbers and the process ID
# in the name. This directory is removed automatically at exit.
# -----------------------------------
#TMPDIR="/tmp/${SCRIPT_NAME}.$RANDOM.$RANDOM.$RANDOM.$$"
#(umask 077 && mkdir "${TMPDIR}") || {
# Die "Could not create temporary directory! Exiting."
#}
VERSION="$(ScriptInfo version | grep version | tr -s ' ' | cut -d' ' -f 4)"
SPEED=57600
DIR="/dev/serial/by-id"
# The following PORTSTRING will be used if the '-s PORTSTRING' argument is not supplied
DEFAULT_PORTSTRING="USB-Serial|RT_Systems|usb-FTDI"
PORTSTRING="$DEFAULT_PORTSTRING"
XMLRPC_CLIENT_SCRIPT="client710.py"
MAIN_SCRIPT="710.py"
declare -A MINFREQ
MINFREQ[A]="118000000"
MINFREQ[B]="136000000"
declare -A MAXFREQ
MAXFREQ[A]="524000000"
MAXFREQ[B]="1300000000"
declare -A SIDE
SIDE[A]=0; SIDE[B]=1; SIDE[0]="A"; SIDE[1]="B"
MINCHAN=0
MAXCHAN=999
declare -A POWER
POWER[H]=0; POWER[M]=1; POWER[L]=2
POWER[0]="high"; POWER[1]="medium"; POWER[2]="low"
declare -A MODE1
MODE1[0]="VFO"; MODE1[1]="Memory"; MODE1[2]="Call"; MODE1[3]="WX"
MODE1[VFO]=0; MODE1[MEMORY]=1; MODE1[CALL]=2; MODE1[WX]=3
declare -A SQC
SQC[OFF]=0; SQC[BUSY]=1; SQC[SQL]=2; SQC[TX]=3; SQC[BUSYTX]=4; SQC[SQLTX]=5
declare -A APO
APO[OFF]=0; APO[30]=1; APO[60]=2; APO[90]=3; APO[120]=4; APO[180]=5
declare -A TIMEOUT
TIMEOUT[3]=0; TIMEOUT[5]=1; TIMEOUT[10]=2
declare -A SPEED
SPEED[1200]=0; SPEED[9600]=1
declare -A STATE
STATE[OFF]=0; STATE[ON]=1
FOUND_XML=false
#============================
# PARSE OPTIONS WITH GETOPTS
#============================
Optnum=$#
#== set short options ==#
SCRIPT_OPTS=':hp:s:v-:'
#== set long options associated with short one ==#
typeset -A ARRAY_OPTS
ARRAY_OPTS=(
[help]=h
[version]=v
[string]=s
[port]=p
)
LONG_OPTS="^($(echo "${!ARRAY_OPTS[@]}" | tr ' ' '|'))="
# Parse options
while getopts ${SCRIPT_OPTS} OPTION
do
# Translate long options to short
if [[ "x$OPTION" == "x-" ]]
then
LONG_OPTION=$OPTARG
LONG_OPTARG=$(echo $LONG_OPTION | egrep "$LONG_OPTS" | cut -d'=' -f2-)
LONG_OPTIND=-1
[[ "x$LONG_OPTARG" = "x" ]] && LONG_OPTIND=$OPTIND || LONG_OPTION=$(echo $OPTARG | cut -d'=' -f1)
[[ $LONG_OPTIND -ne -1 ]] && eval LONG_OPTARG="\$$LONG_OPTIND"
OPTION=${ARRAY_OPTS[$LONG_OPTION]}
[[ "x$OPTION" = "x" ]] && OPTION="?" OPTARG="-$LONG_OPTION"
if [[ $( echo "${SCRIPT_OPTS}" | grep -c "${OPTION}:" ) -eq 1 ]]; then
if [[ "x${LONG_OPTARG}" = "x" ]] || [[ "${LONG_OPTARG}" = -* ]]; then
OPTION=":" OPTARG="-$LONG_OPTION"
else
OPTARG="$LONG_OPTARG";
if [[ $LONG_OPTIND -ne -1 ]]; then
[[ $OPTIND -le $Optnum ]] && OPTIND=$(( $OPTIND+1 ))
shift $OPTIND
OPTIND=1
fi
fi
fi
fi
# Options followed by another option instead of argument
if [[ "x${OPTION}" != "x:" ]] && [[ "x${OPTION}" != "x?" ]] && [[ "${OPTARG}" = -* ]]; then
OPTARG="$OPTION" OPTION=":"
fi
# Finally, manage options
case "$OPTION" in
h)
ScriptInfo full
exit 0
;;
p)
PORT="$OPTARG"
;;
s)
PORTSTRING="$OPTARG"
;;
v)
ScriptInfo version
exit 0
;;
:)
Die "${SCRIPT_NAME}: -$OPTARG: option requires an argument"
;;
?)
Die "${SCRIPT_NAME}: -$OPTARG: unknown option"
;;
esac
done
shift $((${OPTIND} - 1)) ## shift options
#============================
# MAIN SCRIPT
#============================
# Trap bad exits with cleanup function
trap TrapCleanup EXIT INT TERM
trap 'echo "Error communicating with radio!"; exit 1' SIGUSR1
# Exit on error. Append '||true' when you run the script if you expect an error.
set -o errexit
# Check Syntax if set
$SYNTAX && set -n
# Run in debug mode, if set
$DEBUG && set -x
(( $# == 0 )) && Usage
command -v bc >/dev/null || Die "Cannot find bc application. To install it, run: sudo apt update && sudo apt install -y bc"
command -v $MAIN_SCRIPT >/dev/null || Die "Cannot find 710.py."
command -v $XMLRPC_CLIENT_SCRIPT >/dev/null || Die "Cannot find client710.py."
P1="${1^^}"
P2="${2^^}"
P3="${3^^}"
P4="${4^^}"
# If XMLRPC_PORT is empty, then no $MAIN_SCRIPT was found running
# an XML_RPC server. In that case, this script will attempt to interact
# with $MAIN_SCRIPT directly using the '-c' argument. $MAIN_SCRIPT
# cannot already be running in this case
XMLRPC_PORT=$(CheckForXMLRPC)
[[ $P1 == "HELP" ]] && ScriptInfo full
if [[ -z $XMLRPC_PORT && $PORT == "" ]]
then
# XMLRPC server not found and serial port not supplied
# Search for the serial port using $PORTSTRING
MATCHES=$(ls $DIR 2>/dev/null | egrep -i "$PORTSTRING" | wc -l)
case $MATCHES in
0)
Die "No devices found in $DIR with file names that contain string \"$PORTSTRING\""
;;
1)
PORT="$(ls -l $DIR 2>/dev/null | egrep -i "$PORTSTRING")"
PORT="$(echo "$PORT" | cut -d '>' -f2 | tr -d ' ./')"
[[ "$PORT" == "" ]] && Die "Unable to find serial port connection to radio using search string '$PORTSTRING'"
PORT="/dev/${PORT}"
;;
*)
Die "More than one cable in $DIR matches $PORTSTRING. You must specify the cable to use with the '-p' or '-s' options."
;;
esac
fi
if [[ -n $XMLRPC_PORT ]]
then
RIGCTL="$(command -v $XMLRPC_CLIENT_SCRIPT) -x $XMLRPC_PORT"
else
pgrep -f $(basename $MAIN_SCRIPT) &>/dev/null && Die "Cannot run this script while $MAIN_SCRIPT is running without XML-RPC active."
RIGCTL="$(command -v $MAIN_SCRIPT) -p $PORT -b $SPEED -c"
MODEL="$(GetSet "ID")"
fi
case "$P1" in
GET)
case "$P2" in
INFO)
echo "Model: $(GetSet "ID")"
echo "Serial: $(GetSet "AE")"
echo "APO is $(PrintAPO $(GetSet "MU"))"
echo "TX Timeout is $(PrintTimeout $(GetSet "MU"))"
get_PTTCTRL
echo "External Data is on Side $(PrintDataSide $(GetSet "MU"))"
echo "External data speed is $(PrintSpeed $(GetSet "MU"))"
PrintAIP $(GetSet "MU")
echo "------------------------------------"
get_FREQ A
ANS="$(GetSet "PC 0")"
echo "Side A is at ${POWER[${ANS#*,}]} power"
echo "------------------------------------"
get_FREQ B
ANS="$(GetSet "PC 1")"
echo "Side B is at ${POWER[${ANS#*,}]} power"
exit 0
;;
A|B)
;;
AIP)
PrintAIP $(GetSet "MU")
exit 0
;;
DATA)
echo "External Data is on Side $(PrintDataSide $(GetSet "MU"))"
exit 0
;;
FIRM*)
ID="$(GetSet "ID")"
if [[ $ID =~ 710 ]]
then # This is a TM-D710G
echo "Transceiver firmware: $(echo "$(GetSet "FV 0")" | cut -d, -f3)"
echo "Operation panel firmware: $(echo "$(GetSet "FV 1")" | cut -d, -f3)"
else # This is a TM-V71A
echo "Transceiver firmware: $(echo "$(GetSet "FV 0")" | cut -d, -f3)"
fi
exit 0
;;
TIME*)
echo "TX Timeout is $(PrintTimeout $(GetSet "MU"))"
exit 0
;;
APO)
echo "APO is $(PrintAPO $(GetSet "MU"))"
exit 0
;;
SQC)
echo "SQC source is $(PrintSQCsource $(GetSet "MU"))"
exit 0
;;
SPEED)
echo "External data speed is $(PrintSpeed $(GetSet "MU"))"
exit 0
;;
PTTCTRL)
get_PTTCTRL
exit 0
;;
PO*)
ANS="$(GetSet "PC 0")"
echo "Side A is at ${POWER[${ANS#*,}]} power"
ANS="$(GetSet "PC 1")"
echo "Side B is at ${POWER[${ANS#*,}]} power"
exit 0
;;
MEM*)
if [[ $P3 =~ ^[0-9]{1,3}-[0-9]{1,3}$ ]]
then
C1="$(echo "$P3" | cut -d'-' -f1)"
C2="$(echo "$P3" | cut -d'-' -f2)"
if (( C1 < C2 && C1 >= $MINCHAN && C2 <= $MAXCHAN ))
then
echo -e "Memory\t\tRX Freq\t\tRX Step\t\t\t\t\t\tTone\tCTCSS\tDCS\tOffset"
echo -e "Channel\tName\t(MHz)\t\t(KHz)\tShift\tRev\tTone\tCTCSS\tDCS\t(Hz)\t(Hz)\t(Hz)\t(MHz)\tMod\tLockout"
for I in $(seq -f "%03g" $C1 $C2)
do
ANS="$(GetSet "ME $I")"
if [[ "$ANS" == "N" ]]
then
echo -e "$I\tEmpty"
else
echo -n -e "$(echo "$(GetSet "MN $I")," | sed 's/,/\\t/g')"
PrintFreq "$ANS" "ME" "LIST"
fi
done
exit 0
else
Die "Channel range must be between $MINCHAN and $MAXCHAN and lower number channel must be listed first"
exit 1
fi
elif [[ $P3 =~ ^[0-9]{1,3}$ ]] && ((P3>=$MINCHAN && P3<=$MAXCHAN))
then
ANS="$(GetSet "ME $(printf "%03d" $((10#$P3)))")"
if [[ "$ANS" == "N" ]]
then
echo "Memory $(printf "%03d" $((10#$P3))) is empty."
else
PrintFreq "$ANS" "ME" ""
ANS="$(GetSet "MN $(printf "%03d" $((10#$P3)))")"
echo "Name: ${ANS#*,}"
fi
exit 0
else
Die "Must provide a channel between $MINCHAN and $MAXCHAN or a channel range, for example 1-100"
exit 1
fi
;;
MEN*)
GetSet "MU"
exit 0
;;
*)
Die "Invalid GET command"
;;
esac
;;
SET)
case $P2 in
A|B|VHF|UHF) # Handled in case $P3 section below
;;
SP*) # External Data Speed
ANS="$(GetSet "MU")"
case $P3 in
1200|9600)
ANS="$(GetSet "MU $(SetMenu $ANS 38 ${SPEED[$P3]})")"
;;
*)
Die "Valid speed options are 1200 and 9600"
;;
esac
echo "External data speed is $(PrintSpeed $ANS)"
exit 0
;;
APO) # Auto power off
ANS="$(GetSet "MU")"
case $P3 in
OFF|30|60|90|120|180)
ANS="$(GetSet "MU $(SetMenu $ANS 36 ${APO[$P3]})")"
;;
*)
Die "Valid APO options are off, 30, 60, 90, 120, 180"
;;
esac
echo "APO is $(PrintAPO $ANS)"
exit 0
;;
SQC) # SQC source
ANS="$(GetSet "MU")"
case $P3 in
OFF|BUSY|SQL|TX|BUSYTX|SQLTX)
ANS="$(GetSet "MU $(SetMenu $ANS 39 ${SQC[$P3]})")"
;;
*)
Die "Valid SQC options are off, busy, sql, tx, busytx, sqltx"
;;
esac
echo "SQC source is $(PrintSQCsource $ANS)"
exit 0
;;
TIME*) # TX Timeout
ANS="$(GetSet "MU")"
case $P3 in
3|5|10)
ANS="$(GetSet "MU $(SetMenu $ANS 15 ${TIMEOUT[$P3]})")"
;;
*)
Die "Valid timeout options are 3, 5, 10"
;;
esac
echo "TX Timeout is $(PrintTimeout $ANS)"
exit 0
;;
*)
Die "Invalid SET command"
;;
esac
;;
CO*) # Command
ANS="$(GetSet "$P2")"
echo "$ANS"
exit 0
;;
HELP)
Usage
;;
*)
Die "Valid commands are GET, SET, and HELP."
;;
esac
case "$P3" in
AIP) # Advanced Intercept Point
ANS="$(GetSet "MU")"
case "$P2" in
VHF)
case "$P4" in
OFF|ON)
ANS="$(GetSet "MU $(SetMenu $ANS 11 ${STATE[$P4]})")"
;;
*)
Die "AIP state must be OFF or ON"
;;
esac
;;
UHF)
case "$P4" in
OFF|ON)
ANS="$(GetSet "MU $(SetMenu $ANS 12 ${STATE[$P4]})")"
;;
*)
Die "AIP state must be OFF or ON"
;;
esac
;;
esac
PrintAIP $(GetSet "MU")
;;
FREQ*) # Frequency
case "$P1" in
GET)
get_FREQ $P2
;;
SET)
set_FREQ $P2
get_FREQ $P2
;;
esac
;;
MO*) # Mode
if [[ $P1 == "SET" ]]
then
case "$P4" in
VFO|MEMORY|CALL|WX)
ANS="$(GetSet "VM ${SIDE[$P2]},${MODE1[$P4]}")"
;;
*)
Die "Valid modes are VFO, MEMORY, CALL, and WX"
;;
esac
fi
ANS="$(GetSet "VM ${SIDE[$P2]}")"
echo -n "Side $P2 is in ${MODE1[${ANS#*,}]} mode"
if [[ ${MODE1[${ANS#*,}]} == "Memory" ]]
then
ANS="$(GetSet "MR ${SIDE[$P2]}")"
echo ": Memory location ${ANS#*,}"
else
echo
fi
;;
PO*) # Power
case "$P1" in
GET)
ANS="$(GetSet "PC ${SIDE[$P2]}")"
;;
SET)
case "$P4" in
H|M|L)
ANS="$(GetSet "PC ${SIDE[$P2]},${POWER[$P4]}")"
;;
*)
Die "Valid power settings are H, M, and L"
;;
esac
;;
esac
echo "Side $P2 is at ${POWER[${ANS#*,}]} power"
;;
SQ*) # Squelch
case "$P1" in
GET)
ANS="$(GetSet "SQ ${SIDE[$P2]}")"
;;
SET)
if ((P4>=0 && P4<=31))
then
P4="$(printf "%02X" $P4)"
ANS="$(GetSet "SQ ${SIDE[$P2]},$P4")"
else
Die "Valid squelch settings are between 0 and 31 inclusive"
fi
;;
esac
echo "Side $P2 squelch is at $((16#${ANS#*,})) out of 31"
;;
PTTCTRL) # PTT/CTRL
ANS="$(GetSet "BC ${SIDE[$P2]},${SIDE[$P2]}")"
get_PTTCTRL
;;
PTT) # PTT
ANS="$(GetSet "BC")"
CTRL=${ANS%,*}
PTT=${ANS#*,}
if [[ "$P2" == "A" ]]
then
ANS="$(GetSet "BC $CTRL,0")"
else
ANS="$(GetSet "BC $CTRL,1")"
fi
get_PTTCTRL
;;
CTRL) # CTRL
ANS="$(GetSet "BC")"
CTRL=${ANS%,*}
PTT=${ANS#*,}
if [[ "$P2" == "A" ]]
then
ANS="$(GetSet "BC 0,$PTT")"
else
ANS="$(GetSet "BC 1,$PTT")"
fi
get_PTTCTRL
;;
DA*) # External Data Side
ANS="$(GetSet "MU")"
if [[ "$P2" == "A" ]]
then
ANS="$(GetSet "MU $(SetMenu $ANS 37 0)")"
else
ANS="$(GetSet "MU $(SetMenu $ANS 37 1)")"
fi
# Setting PTT+CTRL is needed to refresh display after changing
# data side. This is due to a bug in Kenwood firmware.
ANS="$(GetSet "BC")"
CTRL=${ANS%,*}
PTT=${ANS#*,}
ANS="$(GetSet "BC $CTRL,$PTT")"
echo "External Data is on Side $(PrintDataSide $(GetSet "MU"))"
;;
MEM*)
if ((P4>=$MINCHAN && P4<=$MAXCHAN))
then
ANS="$(GetSet "ME $(printf "%03d" $((10#$P4)))")"
if [[ "$ANS" == "N" ]]
then
echo "Memory $(printf "%03d" $((10#$P4))) is empty"
else
ANS="$(GetSet "VM ${SIDE[$P2]},1")" # Set side to memory mode
ANS="$(GetSet "MR ${SIDE[$P2]},$(printf "%03d" $((10#$P4)))")"
echo "Side: $P2"
ANS="$(GetSet "ME ${ANS#*,}")"
PrintFreq "$ANS" "ME" ""
ANS="$(GetSet "MN $(printf "%03d" $((10#$P4)))")"
echo "Name: ${ANS#*,}"
fi
else
Die "Memory location must be between $MINCHAN and $MAXCHAN"
fi
;;
*)
Die "Valid $P1 options are AIP, FREQUENCY, MODE, POWER, PTTCTRL, PTT, CTRL, DATA, and MEMORY"
;;
esac
SafeExit 0