#!/bin/bash
#
# Copyright (C) 2023 MOXA Inc. All rights reserved.
# This software is distributed under the terms of the MOXA SOFTWARE NOTICE.
# See the file LICENSE for details.
#
# Authors:
#	2022	Elvis Yao <ElvisCW.Yao@moxa.com>
# Description:
#	For controlling gpio-sysfs value from Relay mode
#

# Set GPIO Low = Normal Closed
# Set GPIO High = Normal Open
RELAY_MODE_STR=("NC" "NO")
DMIDECODE="/usr/sbin/dmidecode"

## Product Profile
#
# _product_<model name>() {
#	GPIO_MODULE=""
#	RELAY_GPIO_TBL=()
#	RELAY_MODE_TBL=()
# }
#

_product_DA682C() {
	GPIO_MODULE="gpio_it87"
	RELAY_GPIO_TBL=("65")
	RELAY_MODE_TBL=("0" "1")
}

_product_DA681C() {
	GPIO_MODULE="gpio_it87"
	RELAY_GPIO_TBL=("65")
	RELAY_MODE_TBL=("0" "1")
}

_product_DA820C() {
	GPIO_MODULE="gpio_it87"
	RELAY_GPIO_TBL=("65")
	RELAY_MODE_TBL=("0" "1")
}

_product_DA680() {
	GPIO_MODULE="gpio_it87"
	RELAY_GPIO_TBL=("65")
	RELAY_MODE_TBL=("0" "1")
}

declare -A PRODUCT_PROFILE=(
	["DA820C"]=_product_DA820C
	["DA682C"]=_product_DA682C
	["DA681C"]=_product_DA681C
	["DA680"]=_product_DA680
)

load_product_name_from_dmi() {
	local ret=1

	for m in $($DMIDECODE -t 12 | grep "Option " | awk -F ':' '{print substr($2,1,11)}' | sed 's/ //g');
	do
		if [[ ${PRODUCT_PROFILE[$m]} ]]; then
			TARGET_PRODUCT=$m
			${PRODUCT_PROFILE[$TARGET_PRODUCT]}
			ret=0
			break
		fi
	done

	for m in $($DMIDECODE -t 1 | grep "Product Name" | awk -F ':' '{print $2}' | sed 's/ //g');
	do
		if [[ ${PRODUCT_PROFILE[$m]} ]]; then
			TARGET_PRODUCT=$m
			${PRODUCT_PROFILE[$TARGET_PRODUCT]}
			ret=0
			break
		fi
	done

	return $ret
}

## gpio
gpc_it8786() {
	local gpio=$1
	local GPIO_TABLE=(
		10 11 12 13 14 15 16 17
		20 21 22 23 24 25 26 27
		30 31 32 33 34 35 36 37
		40 41 42 43 44 45 46 47
		50 51 52 53 54 55 56 57
		60 61 62 63 64 65 66 67
		70 71 72 73 74 75 76 77
		80 81 82 83 84 85 86 87
		90 91 92 93 94 95 96 97
                100 101 102 103 104 105
	)

	[[ ! ${GPIO_TABLE[*]} =~ $gpio ]] && \
			echo "Invalid gpio number." && exit 1

	for gpiochip in /sys/class/gpio/gpiochip*
	do
		if cat "${gpiochip}"/label | grep -q "gpio_it87"
		then
			base=$(cat "${gpiochip}"/base)
			break
		fi
	done

	group=$(($gpio / 10 - 1))
	bit=$(($gpio % 10))
	echo $((base + 8 * group + bit))
}

declare -A GPIO_CHIP=(
	["gpio_it87"]=gpc_it8786
)

load_product_name_from_file() {
	echo "TBD"
}

load_product_config() {
	if load_product_name_from_dmi; then
			# Determine gpio chip profile
		gpc=${GPIO_CHIP[$GPIO_MODULE]}
			# Determine number of serial and mode
		NUM_OF_RELAY=$(( ${#RELAY_GPIO_TBL[@]} ))
		NUM_OF_RELAY_MODE=$(( ${#RELAY_MODE_TBL[@]} ))
	else
		echo "Error: model profile not found."
		exit 1
	fi
}

gpio_request() {
	local gpio=${1}

	if [ ! -e "/sys/class/gpio/gpio${gpio}" ]
	then
		echo "${gpio}" > /sys/class/gpio/export
	fi
}

gpio_set_value() {
	local gpio=${1}
	local value=${2}

	gpio_request "${gpio}"
	case "${value}" in
	0)
		echo "low" > "/sys/class/gpio/gpio${gpio}/direction"
		;;
	1)
		echo "high" > "/sys/class/gpio/gpio${gpio}/direction"
		;;
	*)
		usage
	;;
	esac
}

gpio_get_value() {
	local gpio=${1}

	gpio_request "${gpio}"
	cat "/sys/class/gpio/gpio${gpio}/value"
}

## relay
set_relay_mode() {
	local relay_num=$1
	local mode_num=$2

	gpio_set_value $($gpc ${RELAY_GPIO_TBL[$relay_num]}) $mode_num

	echo "Set OK."
}

get_relay_mode() {
	local relay_num=$1
	local mode_num=""

	mode_num=$(gpio_get_value $($gpc ${RELAY_GPIO_TBL[$relay_num]}))

	if [[ ${RELAY_MODE_TBL[0]} -eq $mode_num ]]; then
		echo "Current relay mode is ${RELAY_MODE_STR[0]} interface."
		return 0
	elif [[ ${RELAY_MODE_TBL[1]} -eq $mode_num ]]; then
		echo "Current relay mode is ${RELAY_MODE_STR[1]} interface."
		return 0
	fi

	echo "Unknown relay mode"
	return 1
}

usage() {
cat << EOF
Usage:
		mx-relay-ctl -p <port_number> [-m <relay_mode>]

OPTIONS:
		-p <port_number>
				Set target port.
		-m <relay_mode>
				Set target port to relay_mode
				0 --> set to NC (Normal Closed) mode
				1 --> set to NO (Normal Open) mode

Example:
		Get mode from port 0
		# mx-relay-ctl -p 0

		Set port 0 to mode NC
		# mx-relay-ctl -p 0 -m 0

		Set port 0 to mode NO
		# mx-relay-ctl -p 0 -m 1
EOF
}

is_module_loaded() {
	local mod_name=$1
	if lsmod | grep -w $mod_name &> /dev/null; then
		echo 0
	else
		echo 1
	fi
}

load_product_config

# Module check
[[ $(is_module_loaded $GPIO_MODULE) -ne 0 ]] && \
	echo "$GPIO_MODULE is not loaded." && exit 1

# Parameter check
if [[ $# -lt 2 ]]; then
	usage
	exit 1
fi

while [[ "$#" -gt 0 ]]; do
	case $1 in
		-p)
			TARGET_RELAY_PORT="$2"
			TARGET_OPT="get"
			shift
			;;
		-m)
			TARGET_RELAY_MODE="$2"
			TARGET_OPT="set"
			shift
			;;
		*)
			echo "Unknown parameter passed"
			usage
			exit 1
			;;
		esac
		shift
done

[[ $TARGET_RELAY_PORT -lt 0 || $TARGET_RELAY_PORT -ge $NUM_OF_RELAY ]] && \
	echo "Invalid relay port." && exit 1

case $TARGET_OPT in
	get)
		[[ -z $TARGET_RELAY_PORT ]] && \
			echo "Invalid relay port." && exit 1

		get_relay_mode $TARGET_RELAY_PORT
		;;
	set)
		[[ -z $TARGET_RELAY_PORT || -z $TARGET_RELAY_MODE ]] && \
			echo "Invalid relay port or relay mode." && exit 1

		[[ $TARGET_RELAY_MODE -lt 0 || $TARGET_RELAY_MODE -ge $NUM_OF_RELAY_MODE ]] && \
			echo "Invalid relay mode." && exit 1

		set_relay_mode $TARGET_RELAY_PORT $TARGET_RELAY_MODE
		get_relay_mode $TARGET_RELAY_PORT
		;;
	*)
		exit 1
		;;
esac
