#!/bin/bash

#########################################
# Name: gwsig
#
# Summary: Get/Set Gateway GPIO signals
#
# Description:
#
# Author: kheadley
#
# Copyright 2015 MBARI
#
#########################################

#########################################
# Script configuration defaults
# casual users should not need to change
# anything below this section
#########################################
description="Get/Set Gateway GPIO signals"

#################################
# Script variable initialization
#################################
VERBOSE="FALSE"
declare -a XOPS
declare -a XARGS
TEST="" #"echo"
declare -a ON_ADDR=( "1,14" "1,12" "1,28" "1,7" )
declare -a OFF_ADDR=( "1,15" "1,13" "1,2" "1,6" )
declare -a STATE_ADDR=( "2,22" "2,23" "2,24" "2,25" )
declare -a EEPROM_ADDR=( "0,26" "0,27" "2,1" "1,30" )
declare -a ENV_ADDR=( "1,31" )
declare -a H2O_ADDR=( "1,5" )

# relay pulse width (msec)
PWIDTH_MSEC=100
unset PDELAY_SEC

#################################
# Function Definitions
#################################
#################################
# name: sigTrap
# description: signal trap callback
# will interrupt
# args: none
#################################
sigTrap(){
    exit 0;
}

#################################
# name: printUsage
# description: print use message
# args: none
#################################
printUsage(){
    echo
    echo " Description: $description"
    echo
    echo " usage: `basename $0` [options]"
	echo " Options:"
    echo "  -r <rlist> : read signal(s)"
    echo "                <rlist>: <sig>[,<sig>...]"
    echo "  -s <slist> : set signal(s)"
    echo "                <slist>: <sig>:<state=0|1>[,<sig>:<state>...]"
    echo "  -w <s>     : wait <s> msec between switching "
    echo "  -t         : test [don't execute commands]"
    echo "  -v         : verbose output"
    echo "  -h         : print use message"
    echo
    echo " signals:"
    echo "  read:"
    echo "     node[0-3] : Sensor node power [may also use 0-3]"
    echo "   eeprom[0-3] : EEPROM_WP_N"
    echo "           env : environmental alarm"
    echo "           h2o : water alarm"
    echo "         all|a : all signals"
    echo
    echo "  set:"
    echo "     node[0-3]|0-3 : Sensor node power"
    echo "             all|a : all sensor node power"
    echo "  states:"
    echo "           H||h|1 : high/ON"
    echo "           L||l|0 : low/OFF"
    echo
}

########################################
# name: vout
# description: print verbose message to stderr
# args:
#     msg: message
########################################
vout(){
    if [ "$VERBOSE" == "TRUE" ]
    then
	echo "$1" >&2
    fi
}

########################################
# name: imsg
# description: echos with indent
# args:
#     msg: message
#  indent: indent level
########################################
imsg(){
  OIFS=$IFS
  IFS=""
  msg_pad="                                        "
  let "msg_indent=${1}"
  shift
  all="${@}"
  printf "%s%s\n" ${msg_pad:0:${msg_indent}} ${all}
  IFS=$OIFS
}

########################################
# name: msg
# description: echos with default indent
# args:
#     msg: message
########################################
msg(){
 imsg $MSG_INDENT "${*}"
}

########################################
# name: exitError
# description: print use message to stderr
# args:
#     msg:        error message
#     returnCode: exit status to return
########################################
exitError(){
    echo >&2
    echo "`basename $0`: error - $1" >&2
    echo >&2
    exit $2
}

########################################
# name: processCmdLine
# description: do command line processsing
# args:
#     args:       positional paramters
#     returnCode: none
########################################
processCmdLine(){
	OPTIND=1
	vout "`basename $0` all args[$*]"

let "i=0"

while getopts hr:s:tVw: Option
	do
		vout "processing $Option[$OPTARG]"
		case $Option in
            r ) XOPS[$i]="r"
                XARGS[$i]="$OPTARG"
                let "i+=1"
            ;;
            s ) XOPS[$i]="s"
               XARGS[$i]=$OPTARG
               let "i+=1"
            ;;
            t ) TEST="echo"
            ;;
            w ) PDELAY_SEC=$(echo "scale=3; ${OPTARG}/1000"|bc)
            ;;
            V ) VERBOSE="TRUE"
			;;
			h ) printUsage
				exit 0
			;;
			*) exit 0 # getopts outputs error message
			;;
		esac
	done
}



########################################
# name: doSet
# description: set signal
# args:
#     args:       positional paramters
#     returnCode: none
########################################
doSet(){
    OIFS=$IFS
    IFS=":" read sig state <<< "$1"
    vout "doSet sig[${sig}] state[${state}]"
    local chip=""
    local pin=""
    local op="gwgpio"
    local opargs="-l l,${PWIDTH_MSEC}"
declare -a OP_ADDR

    case $sig in
    '0' )
        if [ "${state}" == "1" ] || [ "${state}" == "H" ] || [ "${state}" == "h" ]
        then
        OP_ADDR[${#OP_ADDR[@]}]=${ON_ADDR[0]}
        elif [ "${state}" == "0" ] || [ "${state}" == "L" ] || [ "${state}" == "l" ]
        then
        OP_ADDR[${#OP_ADDR[@]}]=${OFF_ADDR[0]}
        fi
    ;;
    '1' )
        if [ "${state}" == "1" ] || [ "${state}" == "H" ] || [ "${state}" == "h" ]
        then
        OP_ADDR[${#OP_ADDR[@]}]=${ON_ADDR[1]}
        elif [ "${state}" == "0" ] || [ "${state}" == "L" ] || [ "${state}" == "l" ]
        then
        OP_ADDR[${#OP_ADDR[@]}]=${OFF_ADDR[1]}
        fi
    ;;
    '2' )
        if [ "${state}" == "1" ] || [ "${state}" == "H" ] || [ "${state}" == "h" ]
        then
        OP_ADDR[${#OP_ADDR[@]}]=${ON_ADDR[2]}
        elif [ "${state}" == "0" ] || [ "${state}" == "L" ] || [ "${state}" == "l" ]
        then
        OP_ADDR[${#OP_ADDR[@]}]=${OFF_ADDR[2]}
        fi
    ;;
    '3' )
        if [ "${state}" == "1" ] || [ "${state}" == "H" ] || [ "${state}" == "h" ]
        then
        OP_ADDR[${#OP_ADDR[@]}]=${ON_ADDR[3]}
        elif [ "${state}" == "0" ] || [ "${state}" == "L" ] || [ "${state}" == "l" ]
        then
        OP_ADDR[${#OP_ADDR[@]}]=${OFF_ADDR[3]}
        fi
    ;;
    node0 )
        if [ "${state}" == "1" ] || [ "${state}" == "H" ] || [ "${state}" == "h" ]
        then
        OP_ADDR[${#OP_ADDR[@]}]=${ON_ADDR[0]}
        elif [ "${state}" == "0" ] || [ "${state}" == "L" ] || [ "${state}" == "l" ]
        then
        OP_ADDR[${#OP_ADDR[@]}]=${OFF_ADDR[0]}
        fi
    ;;
    node1 )
        if [ "${state}" == "1" ] || [ "${state}" == "H" ] || [ "${state}" == "h" ]
        then
        OP_ADDR[${#OP_ADDR[@]}]=${ON_ADDR[1]}
        elif [ "${state}" == "0" ] || [ "${state}" == "L" ] || [ "${state}" == "l" ]
        then
        OP_ADDR[${#OP_ADDR[@]}]=${OFF_ADDR[1]}
        fi
    ;;
    node2 )
         if [ "${state}" == "1" ] || [ "${state}" == "H" ] || [ "${state}" == "h" ]
        then
        OP_ADDR[${#OP_ADDR[@]}]=${ON_ADDR[2]}
        elif [ "${state}" == "0" ] || [ "${state}" == "L" ] || [ "${state}" == "l" ]
        then
        OP_ADDR[${#OP_ADDR[@]}]=${OFF_ADDR[2]}
        fi
    ;;
    node3 )
        if [ "${state}" == "1" ] || [ "${state}" == "H" ] || [ "${state}" == "h" ]
        then
        OP_ADDR[${#OP_ADDR[@]}]=${ON_ADDR[3]}
        elif [ "${state}" == "0" ] || [ "${state}" == "L" ] || [ "${state}" == "l" ]
        then
        OP_ADDR[${#OP_ADDR[@]}]=${OFF_ADDR[3]}
        fi
    ;;
    all )
        if [ "${state}" == "1" ] || [ "${state}" == "H" ] || [ "${state}" == "h" ]
        then
        OP_ADDR[0]=${ON_ADDR[0]}
        OP_ADDR[1]=${ON_ADDR[1]}
        OP_ADDR[2]=${ON_ADDR[2]}
        OP_ADDR[3]=${ON_ADDR[3]}
        elif [ "${state}" == "0" ] || [ "${state}" == "L" ] || [ "${state}" == "l" ]
        then
        OP_ADDR[0]=${OFF_ADDR[0]}
        OP_ADDR[1]=${OFF_ADDR[1]}
        OP_ADDR[2]=${OFF_ADDR[2]}
        OP_ADDR[3]=${OFF_ADDR[3]}
        fi
    ;;
    a )
        if [ "${state}" == "1" ] || [ "${state}" == "H" ] || [ "${state}" == "h" ]
        then
        OP_ADDR[0]=${ON_ADDR[0]}
        OP_ADDR[1]=${ON_ADDR[1]}
        OP_ADDR[2]=${ON_ADDR[2]}
        OP_ADDR[3]=${ON_ADDR[3]}
        elif [ "${state}" == "0" ] || [ "${state}" == "L" ] || [ "${state}" == "l" ]
        then
        OP_ADDR[0]=${OFF_ADDR[0]}
        OP_ADDR[1]=${OFF_ADDR[1]}
        OP_ADDR[2]=${OFF_ADDR[2]}
        OP_ADDR[3]=${OFF_ADDR[3]}
        fi
    ;;

    * )
    echo "doSet: invalid sig"
    ;;
    esac

    if [ "${#OP_ADDR[@]}" -gt 0 ]
    then
        vout "signal[$sig]:"
        for OP in "${OP_ADDR[@]}"
        do
            $TEST $op -g ${OP} $opargs
            if [ "${PDELAY_SEC}" ]
            then
               $TEST sleep ${PDELAY_SEC}
            fi
        done
    else
        echo "doSet: invalid arg sig[${sig}] state[${state}]"
    fi

    IFS=$OIFS
}

doRead(){
    vout "doRead sig[$1]"
    local sig="$1"
    local chip=""
    local pin=""
    local op="gwgpio"

    declare -a OP_ADDR
    declare -a OP_NAME

    case $sig in
    '0' )
    OP_ADDR[${#OP_ADDR[@]}]=${STATE_ADDR[0]}
    OP_NAME[${#OP_NAME[@]}]="NODE0"
    ;;
    '1' )
    OP_ADDR[${#OP_ADDR[@]}]=${STATE_ADDR[1]}
    OP_NAME[${#OP_NAME[@]}]="NODE1"
    ;;
    '2' )
    OP_ADDR[${#OP_ADDR[@]}]=${STATE_ADDR[2]}
    OP_NAME[${#OP_NAME[@]}]="NODE2"
    ;;
    '3' )
    OP_ADDR[${#OP_ADDR[@]}]=${STATE_ADDR[3]}
    OP_NAME[${#OP_NAME[@]}]="NODE3"
    ;;
    node0 )
    OP_ADDR[${#OP_ADDR[@]}]=${STATE_ADDR[0]}
    OP_NAME[${#OP_NAME[@]}]="NODE0"
    ;;
    node0 )
    OP_ADDR[${#OP_ADDR[@]}]=${STATE_ADDR[1]}
    OP_NAME[${#OP_NAME[@]}]="NODE1"
    ;;
    node2 )
    OP_ADDR[${#OP_ADDR[@]}]=${STATE_ADDR[2]}
    OP_NAME[${#OP_NAME[@]}]="NODE2"
    ;;
    node3 )
    OP_ADDR[${#OP_ADDR[@]}]=${STATE_ADDR[3]}
    OP_NAME[${#OP_NAME[@]}]="NODE3"
    ;;
    eeprom1 )
    OP_ADDR[${#OP_ADDR[@]}]=${EEPROM_ADDR[0]}
    OP_NAME[${#OP_NAME[@]}]="EEPROM0"
    ;;
    eeprom2 )
    OP_ADDR[${#OP_ADDR[@]}]=${EEPROM_ADDR[1]}
    OP_NAME[${#OP_NAME[@]}]="EEPROM1"
    ;;
    eeprom3 )
    OP_ADDR[${#OP_ADDR[@]}]=${EEPROM_ADDR[2]}
    OP_NAME[${#OP_NAME[@]}]="EEPROM2"
    ;;
    eeprom4 )
    OP_ADDR[${#OP_ADDR[@]}]=${EEPROM_ADDR[3]}
    OP_NAME[${#OP_NAME[@]}]="EEPROM3"
    ;;
    env )
    OP_ADDR[${#OP_ADDR[@]}]=${ENV_ADDR[0]}
    OP_NAME[${#OP_NAME[@]}]="ENV"
    ;;
    h2o )
    OP_ADDR[${#OP_ADDR[@]}]=${H2O_ADDR[0]}
    OP_NAME[${#OP_NAME[@]}]="H2O"
    ;;
    all )
    OP_ADDR[${#OP_ADDR[@]}]=${STATE_ADDR[0]}
    OP_NAME[${#OP_NAME[@]}]="NODE0  "
    OP_ADDR[${#OP_ADDR[@]}]=${STATE_ADDR[1]}
    OP_NAME[${#OP_NAME[@]}]="NODE1  "
    OP_ADDR[${#OP_ADDR[@]}]=${STATE_ADDR[2]}
    OP_NAME[${#OP_NAME[@]}]="NODE2  "
    OP_ADDR[${#OP_ADDR[@]}]=${STATE_ADDR[3]}
    OP_NAME[${#OP_NAME[@]}]="NODE3  "
    OP_ADDR[${#OP_ADDR[@]}]=${EEPROM_ADDR[0]}
    OP_NAME[${#OP_NAME[@]}]="EEPROM0"
    OP_ADDR[${#OP_ADDR[@]}]=${EEPROM_ADDR[1]}
    OP_NAME[${#OP_NAME[@]}]="EEPROM1"
    OP_ADDR[${#OP_ADDR[@]}]=${EEPROM_ADDR[2]}
    OP_NAME[${#OP_NAME[@]}]="EEPROM2"
    OP_ADDR[${#OP_ADDR[@]}]=${EEPROM_ADDR[3]}
    OP_NAME[${#OP_NAME[@]}]="EEPROM3"
    OP_ADDR[${#OP_ADDR[@]}]=${ENV_ADDR[0]}
    OP_NAME[${#OP_NAME[@]}]="ENV    "
    OP_ADDR[${#OP_ADDR[@]}]=${H2O_ADDR[0]}
    OP_NAME[${#OP_NAME[@]}]="H2O    "
    ;;
    a )
    OP_ADDR[${#OP_ADDR[@]}]=${STATE_ADDR[0]}
    OP_NAME[${#OP_NAME[@]}]="NODE0  "
    OP_ADDR[${#OP_ADDR[@]}]=${STATE_ADDR[1]}
    OP_NAME[${#OP_NAME[@]}]="NODE1  "
    OP_ADDR[${#OP_ADDR[@]}]=${STATE_ADDR[2]}
    OP_NAME[${#OP_NAME[@]}]="NODE2  "
    OP_ADDR[${#OP_ADDR[@]}]=${STATE_ADDR[3]}
    OP_NAME[${#OP_NAME[@]}]="NODE3  "
    OP_ADDR[${#OP_ADDR[@]}]=${EEPROM_ADDR[0]}
    OP_NAME[${#OP_NAME[@]}]="EEPROM0"
    OP_ADDR[${#OP_ADDR[@]}]=${EEPROM_ADDR[1]}
    OP_NAME[${#OP_NAME[@]}]="EEPROM1"
    OP_ADDR[${#OP_ADDR[@]}]=${EEPROM_ADDR[2]}
    OP_NAME[${#OP_NAME[@]}]="EEPROM2"
    OP_ADDR[${#OP_ADDR[@]}]=${EEPROM_ADDR[3]}
    OP_NAME[${#OP_NAME[@]}]="EEPROM3"
    OP_ADDR[${#OP_ADDR[@]}]=${ENV_ADDR[0]}
    OP_NAME[${#OP_NAME[@]}]="ENV    "
    OP_ADDR[${#OP_ADDR[@]}]=${H2O_ADDR[0]}
    OP_NAME[${#OP_NAME[@]}]="H2O    "
    ;;
   * )
    echo "doRead: invalid sig"
    ;;
    esac

    if [ "${#OP_ADDR[@]}" -gt 0 ]
    then
    vout "signal[$sig]:"
    local i
    let "i=0"
    for OP in "${OP_ADDR[@]}"
    do
    echo -n "${OP_NAME[$i]} - "
    $TEST $op -g ${OP}
    let "i=$i+1"
    done
    else
    echo "doRead: invalid arg sig[${sig}]"
    fi

}

##########################
# Script main entry point
##########################


# Argument processing
# Accepts arguments from command line
# or pipe/file redirect
# Comand line settings override config
# file settings

if [ -t 0 ]
then
	if [ "$#" -eq 0 ];then
		printUsage
#exit -1
	else
		processCmdLine $*
		let "i=$OPTIND-1"
		#while [ "${i}" -gt 0  ]
		#do
		#	shift
		#	let "i-=1"
		#done
	fi
else	
	declare -a cline_args
	let "i=1"
	while [ "$i" -le "$#" ]
	do
		cline_args[$i]="${@:$i:1}"
		let "i+=1"
	done

  	declare -a arg_array
	let "z=0"
	while read line ; do
		IFS=" " read opt val <<< $line
		if [ "${opt}" ] && [[ $opt != \#* ]]
		then
		    vout "opt $opt $z"
			arg_array[$z]=${opt}
			let "z+=1"
			if [ "${val}" ]
			then
				vout "val $val $z"
				arg_array[$z]=${val}
				let "z+=1"
			fi
		else 
			vout "skipping line $line"
		fi
	done
	
	# set default delimiter to 
	# newline for parsing/setting
	# positional parameters
	# [must restore after processing]
	IFSO=$IFS
	IFS=`echo` 
	set - ${arg_array[*]}
	
	# apply config file settings
	processCmdLine ${arg_array[*]}

	# apply command line settings
	# (override config file options)
	set - ${cline_args[*]}	
	processCmdLine ${cline_args[*]}

	# restore default delimiter
	IFS=$IFSO
	
	#let "i=$OPTIND-1"
	#while [ "${i}" -gt 0  ]
	#do
	#shift
	#let "i-=1"
	#done		
fi

#vout "X_ARG   : $X_ARG"
#vout "VERBOSE : $VERBOSE"

# call sigTrap on INT,TERM or EXIT
# trap sigTrap INT TERM EXIT

# reset trapped signals
# trap - INT TERM EXIT

# Execute the command stack defined
# by XOPS (operations) and XARGS (arguments)
let "i=0"
while [ "$i" -lt "${#XOPS[@]}" ]
do
    # initialize op, signal and state
    op=${XOPS[$i]}
    sig="-"
    state="-"

    # initialize and parse arguments
    unset ARGLIST
    declare -a ARGLIST
    IFS="," read -a ARGLIST <<< "${XARGS[$i]}"

    # iterate over args
    let "j=0"
    while [ "${j}" -lt "${#ARGLIST[@]}" ]
    do
        # call operation for each argument
        if [ "${op}" == "r" ]
        then
            doRead ${ARGLIST[$j]}
        elif [ "${op}" == "s" ]
        then
            doSet ${ARGLIST[$j]}
        fi

        # update index
        let "j+=1"
    done

    IFS=$OIFS
    let "i+=1"
done

