260 lines
5.8 KiB
Bash
260 lines
5.8 KiB
Bash
|
#!/usr/bin/env bash
|
||
|
# pure sh has no implementation of hash tables, bash is present on x6100
|
||
|
MODE="undef"
|
||
|
|
||
|
NO_ARGS=0
|
||
|
E_OPTERROR=85
|
||
|
# TODO: unify keys in constants
|
||
|
# ============================== Option descriptions for help output
|
||
|
declare -A description
|
||
|
description["first_ch"]="icom offset for freqs"
|
||
|
CH_STEP=0x29 # 40 bytes
|
||
|
|
||
|
# ============================== Channel address pointers
|
||
|
declare -A addrs
|
||
|
addrs["1"]=0000050b
|
||
|
addrs["2"]=00000537
|
||
|
addrs["3"]=00000563
|
||
|
addrs["4"]=0000058f
|
||
|
addrs["5"]=000005bb
|
||
|
addrs["6"]=000005e7
|
||
|
addrs["7"]=00000613
|
||
|
addrs["8"]=0000063f
|
||
|
addrs["9"]=00000673
|
||
|
addrs["10"]=0000069f
|
||
|
addrs["11"]=000006cb
|
||
|
addrs["12"]=000006f7
|
||
|
addrs["13"]=00000723
|
||
|
addrs["14"]=0000074f
|
||
|
addrs["15"]=0000077b
|
||
|
addrs["16"]=000007b5
|
||
|
addrs["17"]=000007db
|
||
|
addrs["18"]=00000807
|
||
|
addrs["19"]=00000833
|
||
|
addrs["20"]=0000085f
|
||
|
addrs["21"]=0000088b
|
||
|
addrs["22"]=000008b7
|
||
|
addrs["23"]=000008e3
|
||
|
addrs["24"]=0000091d
|
||
|
addrs["25"]=00000943
|
||
|
addrs["26"]=0000096f
|
||
|
addrs["27"]=0000099b
|
||
|
addrs["28"]=000009c7
|
||
|
addrs["29"]=000009f3
|
||
|
addrs["30"]=00000a1f
|
||
|
|
||
|
# ============================== Power address pointers
|
||
|
declare -A pwr
|
||
|
pwr["l1"]=1
|
||
|
pwr["l2"]=2
|
||
|
pwr["h"]=3
|
||
|
|
||
|
power_offset=0x13
|
||
|
# ============================== Modulation address pointers
|
||
|
declare -A mod
|
||
|
mod["n"]=8
|
||
|
mod["w"]=0
|
||
|
|
||
|
modulation_offset=0x18
|
||
|
help()
|
||
|
{
|
||
|
echo "Script, that patches ICOM IC-F320 firmware"
|
||
|
echo
|
||
|
echo "Keys:"
|
||
|
echo "-s %ch%=%frequency_mhz%"
|
||
|
echo "-h see this help"
|
||
|
echo
|
||
|
echo "Syntax: $0 -s %ch%=%frequency_mhz% [-f %path/to/ICF_FILE%"]
|
||
|
echo "takes one %ch%=%frequency_mhz% pair at once for now"
|
||
|
echo
|
||
|
echo "Filename would be created based on date and time,"
|
||
|
echo "if not provided"
|
||
|
echo
|
||
|
echo "Available options:"
|
||
|
for k in "${!description[@]}"
|
||
|
do
|
||
|
printf " - %s\n" "$k: ${description[$k]}"
|
||
|
done
|
||
|
echo
|
||
|
|
||
|
exit 1
|
||
|
}
|
||
|
|
||
|
|
||
|
# ============================== Argparse
|
||
|
if [ $# -eq "$NO_ARGS" ] # Script invoked with no command-line args?
|
||
|
then
|
||
|
echo "Arguments required"
|
||
|
echo
|
||
|
help
|
||
|
exit $E_OPTERROR
|
||
|
fi
|
||
|
|
||
|
ARG_REGEX="(.+)=(.+)"
|
||
|
|
||
|
while getopts "s:g:p:m:f:h" arg; do
|
||
|
case $arg in
|
||
|
h)
|
||
|
help
|
||
|
;;
|
||
|
s)
|
||
|
# TODO: populate a hashtable here and then cycle throug them in a main cycle
|
||
|
MODE="set"
|
||
|
if [[ $OPTARG =~ $ARG_REGEX ]]
|
||
|
then
|
||
|
key="${BASH_REMATCH[1]}"
|
||
|
value="${BASH_REMATCH[2]}"
|
||
|
else
|
||
|
echo "Syntax error at -s parametr"
|
||
|
exit $E_OPTERROR
|
||
|
fi
|
||
|
;;
|
||
|
g)
|
||
|
# TODO get values
|
||
|
# hexdump -s0x50b -n44 $filename
|
||
|
# and parse
|
||
|
MODE="get"
|
||
|
;;
|
||
|
p)
|
||
|
#TODO power
|
||
|
# l1 l2 h (default)
|
||
|
power="${OPTARG:-l1}"
|
||
|
power=$(echo "$power" | tr '[:upper:]' '[:lower:]')
|
||
|
;;
|
||
|
m)
|
||
|
#todo modulation
|
||
|
# n w (n to default?)
|
||
|
modulation="${OPTARG:-n}"
|
||
|
modulation=$(echo "$modulation" | tr '[:upper:]' '[:lower:]')
|
||
|
;;
|
||
|
f)
|
||
|
file="$OPTARG"
|
||
|
;;
|
||
|
esac
|
||
|
done
|
||
|
|
||
|
|
||
|
# ============================== Main code part
|
||
|
generate_filename() {
|
||
|
# is just date
|
||
|
# cho $(date +'%Y-%m-%d_%H-%M').ICF
|
||
|
echo $(date +'%Y-%m').ICF
|
||
|
}
|
||
|
|
||
|
hexify_string() {
|
||
|
# arg1 - value to prepare for inserting into binary
|
||
|
# returns - hex ascii code
|
||
|
local value="$1"
|
||
|
|
||
|
echo "$value" | xxd -ps | head -c-3
|
||
|
}
|
||
|
|
||
|
calculate_offset() {
|
||
|
# ar1 - initial offset
|
||
|
# arg2 - additional offset
|
||
|
local initial=$1
|
||
|
local additional=$2
|
||
|
echo $(printf "%X" $(( 0x$(echo $initial | sed 's/^0*//') + $additional )))
|
||
|
}
|
||
|
|
||
|
compose_patchstring() {
|
||
|
# arg1 - option offset
|
||
|
# arg2 - value in ASCII
|
||
|
# returns - <addr: hex value> formatted string to use in xxd
|
||
|
local addr="$1"
|
||
|
local val="$2"
|
||
|
|
||
|
echo "<$addr: $(hexify_string $val)>"
|
||
|
}
|
||
|
|
||
|
patch_bin() {
|
||
|
# arg1 - prepared binary patch string
|
||
|
# arg2 - path to the file to parch
|
||
|
# returns - void
|
||
|
local patchstring="$1"
|
||
|
local target="$2"
|
||
|
|
||
|
echo "$patchstring" | xxd -r - "$target"
|
||
|
}
|
||
|
|
||
|
patch_value() {
|
||
|
# arg1 - prepared binary patch string
|
||
|
# arg2 - path to the file to parch
|
||
|
# returns - void
|
||
|
local offset="$1"
|
||
|
local value="$2"
|
||
|
patchstring=$(compose_patchstring $offset $value)
|
||
|
# here we might want to convert csv to number of patchstrings
|
||
|
echo "writing :: $patchstring into $filename"
|
||
|
patch_bin "$patchstring" "$filename"
|
||
|
}
|
||
|
|
||
|
prepare_file(){
|
||
|
# arg1 - prepared binary patch string
|
||
|
local filepath="$1"
|
||
|
|
||
|
if [ -z "$filepath" ]; then
|
||
|
local filename=$(generate_filename)
|
||
|
cp ./EMPTY.ICF "./$filename"
|
||
|
echo "./$filename"
|
||
|
else
|
||
|
if [ ! -f "$filepath" ]; then
|
||
|
cp ./EMPTY.ICF "$filepath"
|
||
|
fi
|
||
|
echo "$filepath"
|
||
|
fi
|
||
|
}
|
||
|
|
||
|
main(){
|
||
|
local ch=$1
|
||
|
local freq=$2
|
||
|
# if no $3, then copy EMPTY.ICF to %date%.icf and patch it
|
||
|
local file=$3
|
||
|
|
||
|
local power=$power
|
||
|
local modulation=$modulation
|
||
|
|
||
|
local chan_offset=${addrs["$ch"]}
|
||
|
# TODO IF MODE
|
||
|
filename=$(prepare_file $file)
|
||
|
patch_value $chan_offset $freq
|
||
|
|
||
|
if [ -n "$power" ]; then
|
||
|
offset=$(calculate_offset $chan_offset $power_offset)
|
||
|
echo $offset
|
||
|
patch_value $offset ${pwr["$power"]}
|
||
|
fi
|
||
|
|
||
|
if [ -n "$modulation" ]; then
|
||
|
offset=$(calculate_offset $chan_offset $modulation_offset)
|
||
|
patch_value $offset ${mod["$modulation"]}
|
||
|
fi
|
||
|
}
|
||
|
|
||
|
# ============================== Sanity checks
|
||
|
# TODO optimize
|
||
|
# if [ -z ${file+x} ]; then echo "No file provided"; exit $E_OPTERROR; fi
|
||
|
# if [ ! -f "$file" ]; then
|
||
|
# echo "File $file does not exist."
|
||
|
# exit $E_OPTERROR
|
||
|
# fi
|
||
|
|
||
|
if [ -z ${key+x} ]; then echo "No channel provided"; exit $E_OPTERROR; fi
|
||
|
if [ -z ${value+x} ]; then echo "No frequency provided"; exit $E_OPTERROR; fi
|
||
|
if [ -z ${addrs["$key"]+x} ]; then
|
||
|
echo "Wrong key: $key"
|
||
|
exit $E_OPTERROR
|
||
|
fi
|
||
|
|
||
|
if [ -n "${power+x}" ] && [ -z "${pwr["$power"]+x}" ]; then
|
||
|
echo "Wrong power setting: $power"
|
||
|
exit $E_OPTERROR
|
||
|
fi
|
||
|
if [ -n "${modulation+x}" ] && [ -z ${mod["$modulation"]+x} ]; then
|
||
|
echo "Wrong moudlation: $modulation"
|
||
|
exit $E_OPTERROR
|
||
|
fi
|
||
|
|
||
|
# we should review arguments string
|
||
|
main $key $value $file #$power $modulation
|