#!/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>
#	2024    Henry LC Chen <HenryLC.Chen@moxa.com>
# Description:
#	For controlling gpio-sysfs value from Relay mode
#

source "/usr/lib/mx-gpio-lib"
source "/usr/lib/mx-common-lib"

# Set GPIO Low = Normal Closed
# Set GPIO High = Normal Open
RELAY_MODE_STR=("NC" "NO")
MODEL_NAME=""
TARGET_RELAY_PORT=""
TARGET_RELAY_MODE=0
TARGET_OPCODE=0
TARGET_GET_RELAY_MODE_OPCODE=1
TARGET_SET_RELAY_MODE_OPCODE=3

OS_ID="$(awk -v opt="ID" -F= '$1==opt { print $2 ;}' /etc/os-release | tr -d '"')"

function DA820E::profile() {
	RELAY_IT87_GPIO_TBL=(47)
	RELAY_MODE_TBL=(0 1)
}

function DA820E::init() {
	NUM_OF_RELAY=${#RELAY_IT87_GPIO_TBL[@]}
	NUM_OF_RELAY_MODE=${#RELAY_MODE_TBL[@]}
}

function DA820E::get_relay_state() {
	if [[ "${OS_ID}" == "centos" ]]; then
		get_relay_mode_it87_via_sysfs "$1"
	else
		get_relay_mode_it87_via_libgpiod "$1"
	fi
}

function DA820E::set_relay_state() {
	if [[ "${OS_ID}" == "centos" ]]; then
		set_relay_mode_it87_via_sysfs "$1" "$2"
	else
		set_relay_mode_it87_via_libgpiod "$1" "$2"
	fi
}

function DA820C::profile() {
	RELAY_IT87_GPIO_TBL=(65)
	RELAY_MODE_TBL=(0 1)
}

function DA820C::init() {
	NUM_OF_RELAY=${#RELAY_IT87_GPIO_TBL[@]}
	NUM_OF_RELAY_MODE=${#RELAY_MODE_TBL[@]}
}

function DA820C::get_relay_state() {
	if [[ "${OS_ID}" == "centos" ]]; then
		get_relay_mode_it87_via_sysfs "$1"
	else
		get_relay_mode_it87_via_libgpiod "$1"
	fi
}

function DA820C::set_relay_state() {
	if [[ "${OS_ID}" == "centos" ]]; then
		set_relay_mode_it87_via_sysfs "$1" "$2"
	else
		set_relay_mode_it87_via_libgpiod "$1" "$2"
	fi
}

function DA682C::profile() {
	RELAY_IT87_GPIO_TBL=(65)
	RELAY_MODE_TBL=(0 1)
}

function DA682C::init() {
	NUM_OF_RELAY=${#RELAY_IT87_GPIO_TBL[@]}
	NUM_OF_RELAY_MODE=${#RELAY_MODE_TBL[@]}
}

function DA682C::get_relay_state() {
	if [[ "${OS_ID}" == "centos" ]]; then
		get_relay_mode_it87_via_sysfs "$1"
	else
		get_relay_mode_it87_via_libgpiod "$1"
	fi
}

function DA682C::set_relay_state() {
	if [[ "${OS_ID}" == "centos" ]]; then
		set_relay_mode_it87_via_sysfs "$1" "$2"
	else
		set_relay_mode_it87_via_libgpiod "$1" "$2"
	fi
}

function DA681C::profile() {
	RELAY_IT87_GPIO_TBL=(65)
	RELAY_MODE_TBL=(0 1)
}

function DA681C::init() {
	NUM_OF_RELAY=${#RELAY_IT87_GPIO_TBL[@]}
	NUM_OF_RELAY_MODE=${#RELAY_MODE_TBL[@]}
}

function DA681C::get_relay_state() {
	if [[ "${OS_ID}" == "centos" ]]; then
		get_relay_mode_it87_via_sysfs "$1"
	else
		get_relay_mode_it87_via_libgpiod "$1"
	fi
}

function DA681C::set_relay_state() {
	if [[ "${OS_ID}" == "centos" ]]; then
		set_relay_mode_it87_via_sysfs "$1" "$2"
	else
		set_relay_mode_it87_via_libgpiod "$1" "$2"
	fi
}

function DA680::profile() {
	RELAY_IT87_GPIO_TBL=(65)
	RELAY_MODE_TBL=(0 1)
}

function DA680::init() {
	NUM_OF_RELAY=${#RELAY_IT87_GPIO_TBL[@]}
	NUM_OF_RELAY_MODE=${#RELAY_MODE_TBL[@]}
}

function DA680::get_relay_state() {
	if [[ "${OS_ID}" == "centos" ]]; then
		get_relay_mode_it87_via_sysfs "$1"
	else
		get_relay_mode_it87_via_libgpiod "$1"
	fi
}

function DA680::set_relay_state() {
	if [[ "${OS_ID}" == "centos" ]]; then
		set_relay_mode_it87_via_sysfs "$1" "$2"
	else
		set_relay_mode_it87_via_libgpiod "$1" "$2"
	fi
}

function load_model_name() {
        for name in $(get_model_name_from_dmi_type12); do
                if [[ "$(type -t "${name}::profile")" = 'function' ]]; then
                        MODEL_NAME="${name}"
                        break
                fi
        done

        if [[ -z "${MODEL_NAME}" ]]; then
                for name in $(get_model_name_from_dmi_type1); do
                        if [[ "$(type -t "${name}::profile")" = 'function' ]]; then
                                MODEL_NAME="${name}"
                                break
                        fi
                done
        fi

        if [[ -z "${MODEL_NAME}" ]]; then
                echo "Unsupported model"
                exit 38
        fi
}

## relay

function get_relay_mode_it87_via_libgpiod() {
	local idx=$1
	local num=${RELAY_IT87_GPIO_TBL[$idx]}
	local gpc_name

	gpc_name=$(gpio_get_gpiochip_name gpio_it87)
	local mode=$(gpio_get_value_libgpiod $(gpc_it8786_remap $num) $gpc_name)

	echo "Current relay mode is ${RELAY_MODE_STR[mode]} interface."
}

function set_relay_mode_it87_via_libgpiod() {
	local idx=$1
	local mode=$2
	local num=${RELAY_IT87_GPIO_TBL[$idx]}
	local gpc_name

	gpc_name=$(gpio_get_gpiochip_name gpio_it87)
	gpio_set_value_libgpiod $(gpc_it8786_remap $num) $mode $gpc_name

	echo "Set OK."
}

function get_relay_mode_it87_via_sysfs() {
	local idx=$1
	local num=${RELAY_IT87_GPIO_TBL[$idx]}
	local mode=$(gpio_get_value_sysfs $(gpc_it8786 $num))

	echo "Current relay mode is ${RELAY_MODE_STR[mode]} interface."
}

function set_relay_mode_it87_via_sysfs() {
	local idx=$1
	local state=$2
	local num=${RELAY_IT87_GPIO_TBL[$idx]}

	gpio_set_value_sysfs $(gpc_it8786 $num) $state

	echo "Set OK."
}

function script_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
}

function script_params() {
        if [[ $# -eq 0 ]]; then
                script_usage
                exit 1
        fi

        while getopts "hp:m:" opt; do
                case "${opt}" in
                p)
                        TARGET_RELAY_PORT="$OPTARG"
                        TARGET_OPCODE=$((TARGET_OPCODE += 1))
                        ;;
                m)
                        TARGET_RELAY_MODE="$OPTARG"
                        TARGET_OPCODE=$((TARGET_OPCODE += 2))
                        ;;
                h)
                        script_usage
                        exit 0
                        ;;
                \?)
                        script_usage
                        exit 22
                        ;;
                :)
                        echo "Option -$OPTARG requires an argument." >&2
                        script_usage
                        exit 22
                        ;;
                esac
        done
}

function script_init() {
        load_model_name

        if [[ ! $(type -t "${MODEL_NAME}"::profile) == function ]]; then
                echo "${MODEL_NAME} profile function is not define"
                exit 1
        fi

        "${MODEL_NAME}"::profile

        if [[ ! $(type -t "${MODEL_NAME}"::init) == function ]]; then
                echo "${MODEL_NAME} init function is not define"
                exit 1
        fi

        "${MODEL_NAME}"::init
}

function verify_relay_port() {
        if ! check_leading_zero_digit $TARGET_RELAY_PORT; then
                echo "Invaild relay port format."
                exit 1
        fi

        if [[ $TARGET_RELAY_PORT -lt 0 || $TARGET_RELAY_PORT -ge $NUM_OF_RELAY ]]; then
                echo "Invalid relay port."
                exit 1
        fi
}

function verify_mode() {
        if ! check_leading_zero_digit $TARGET_RELAY_MODE; then
                echo "Invalid relay mode format."
                exit 1
        fi

        if [[ $TARGET_RELAY_MODE -lt 0 || $TARGET_RELAY_MODE -ge $NUM_OF_RELAY_MODE ]]; then
                echo "Invalid relay mode."
                exit 1
        fi
}

function main() {
        script_params "$@"
        script_init

        case $TARGET_OPCODE in
        $TARGET_GET_RELAY_MODE_OPCODE)
                verify_relay_port
				verify_mode

                if [[ ! $(type -t "${MODEL_NAME}"::get_relay_state) == function ]]; then
                        echo "${MODEL_NAME} get_relay_state function is not define"
                        exit 1
                fi

                "${MODEL_NAME}"::get_relay_state $TARGET_RELAY_PORT
                ;;
	$TARGET_SET_RELAY_MODE_OPCODE)
				verify_relay_port
				verify_mode

                if [[ ! $(type -t "${MODEL_NAME}"::set_relay_state) == function ]]; then
                        echo "${MODEL_NAME} set_relay_state function is not define"
                        exit 1
                fi

                "${MODEL_NAME}"::set_relay_state $TARGET_RELAY_PORT $TARGET_RELAY_MODE
                "${MODEL_NAME}"::get_relay_state $TARGET_RELAY_PORT
                ;;
        *)
                script_usage
                exit 1
                ;;
        esac
}

main $@
