#!/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 - 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