#!/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:
#	2024	Elvis Yao <ElvisCW.Yao@moxa.com>
#	2024    Wilson Huang <WilsonYS.Huang@moxa.com>
#	2024    Henry LC Chen <HenryLC.Chen@moxa.com>
# Description:
#	Utility for controlling LTE/5G modules pin states
#

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

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

POWER_STATE=("low" "high")
NUM_OF_POWER_STATE=${#POWER_STATE[@]}

RESET_STATE=("low" "high")
NUM_OF_RESET_STATE=${#RESET_STATE[@]}

DISABLE_STATE=("low" "high")
NUM_OF_DISABLE_STATE=${#DISABLE_STATE[@]}

TURN_ON_STATE=("low" "high")
NUM_OF_TURN_ON_STATE=${#TURN_ON_STATE[@]}

SIM_SELECT_STATE=("2" "1")
NUM_OF_SIM_SELECT=${#SIM_SELECT_STATE[@]}

DIP_SWITCH_STATE=("low" "high")
NUM_OF_DIP_SWITCH_STATE=${#DIP_SWITCH_STATE[@]}

ALIVE_LTE_STATE=("low" "high")
NUM_OF_ALIVE_LTE_STATE=${#ALIVE_LTE_STATE[@]}

ALIVE_FN990_STATE=("low" "high")
NUM_OF_ALIVE_FN990_STATE=${#ALIVE_FN990_STATE[@]}

ALIVE_RM520N_STATE=("low" "high")
NUM_OF_ALIVE_RM520N_STATE=${#ALIVE_RM520N_STATE[@]}

function BXPA101S::profile() {
        NUM_OF_MODULE_SLOTS=1
        POWER_CONTROL_TBL=(102)
        RESET_PIN_TBL=(67)
        DISABLE_PIN_TBL=(90)
        DIP_SWITCH_SELECT_TBL=()
        SIM_CARD_SELECT_TBL=()
}

function BXPA101S::init() {
        return 0
}

function BXPA101S::get_power_state() {
        local slot
        local state

        slot="$1"
        state=$(get_power_state_it87 ${POWER_CONTROL_TBL[$slot]})

        echo "Slot #${slot} power status is ${POWER_STATE[$state]}"
}

function BXPA101S::set_power_state() {
        local slot
        local state

        slot="$1"
        state="$2"

        if [[ "$TARGET_POWER_STATE" == "high" ]]; then
                state=1
        elif [[ "$TARGET_POWER_STATE" == "low" ]]; then
                state=0
        else
                echo "Power state $TARGET_POWER_STATE is invalid"
                exit 1
        fi

        set_power_state_it87 ${POWER_CONTROL_TBL[$slot]} $state

        echo "Set power enable as ${POWER_STATE[$state]} status for slot #${slot}"
}

function BXPA101S::get_reset_state() {
        local slot
        local state

        slot="$1"
        state=$(get_reset_state_it87 ${RESET_PIN_TBL[$slot]})

        echo "Slot #${slot} reset status is ${RESET_STATE[$state]}"
}

function BXPA101S::set_reset_state() {
        local slot
        local state

        slot="$1"
        state="$2"

        if [[ "$TARGET_RESET_STATE" == "high" ]]; then
                state=1
        elif [[ "$TARGET_RESET_STATE" == "low" ]]; then
                state=0
        else
                echo "Reset state $TARGET_RESET_STATE is invalid"
                exit 1
        fi

        set_power_state_it87 ${RESET_PIN_TBL[$slot]} $state

        echo "Set reset enable as ${RESET_STATE[$state]} status for slot #${slot}"
}

function BXPA101S::get_disable_state() {
        local slot
        local state

        slot="$1"
        state=$(get_disable_state_it87 ${DISABLE_PIN_TBL[$slot]})

        echo "Slot #${slot} disable status is ${DISABLE_STATE[$state]}"
}

function BXPA101S::set_disable_state() {
        local slot
        local state

        slot="$1"
        state="$2"

        if [[ "$TARGET_DISABLE_STATE" == "high" ]]; then
                state=1
        elif [[ "$TARGET_DISABLE_STATE" == "low" ]]; then
                state=0
        else
                echo "Disable state $TARGET_RESET_STATE is invalid"
                exit 1
        fi

        set_power_state_it87 ${DISABLE_PIN_TBL[$slot]} $state

        echo "Set disable enable as ${RESET_STATE[$state]} status for slot #${slot}"
}

# product functions
function V3400::profile() {
        NUM_OF_MODULE_SLOTS=3
        PCA953X_CHIP_ADDRESS1="0x27"
        PCA953X_CHIP_ADDRESS2="0x26"

        POWER_ENABLE_PCA953X_GPIO_TBL=(0 0 12)
        RESET_PCA953X_GPIO_TBL=(6 6 13)
        DISABLE_PCA953X_GPIO_TBL=(2 2 14)
        SIM_SELECT_PCA953X_GPIO_TBL=(na na 14)
        TURN_ON_PCA953X_GPIO_TBL=(1 1 na)
        M2B_ALIVE_FN990_PCA953X_TBL=(4 4 na)
        M2B_ALIVE_RM520N_PCA953X_TBL=(5 5 na)
        M2B_CONFIG_0_PCA953X_TBL=(8 8 na)
        M2B_CONFIG_1_PCA953X_TBL=(9 9 na)
        M2B_CONFIG_2_PCA953X_TBL=(10 10 na)
        M2B_CONFIG_3_PCA953X_TBL=(11 11 na)

        DIP_SWITCH_PCA953X_GPIO_TBL=(15)
        MPCIE_ALIVE_PCA953X_GPIO_TBL=(15)
}

function V3400::init() {
        local ret=0

        ret=$(bind_i2c_driver "CP2112" "pca9535" $PCA953X_CHIP_ADDRESS1 $PCA953X_CHIP_ADDRESS2)
        if [[ $ret -ne 0 ]]; then
                echo "Bind i2c device fail"
                exit $ret
        fi
}

function V3400::get_chip_name() {
        local slot
        local cp2112_module_num_str=""

        slot=${1}
        cp2112_module_num_str=$(get_i2c_device_minor_number_list "CP2112")

        if [ "${slot}" == "0" ]; then
                PCA953X_GPIOCHIP_NAME=$(format_as_i2c_directory_name ${cp2112_module_num_str} ${PCA953X_CHIP_ADDRESS1})
        elif [ "${slot}" == "1" ]; then
                PCA953X_GPIOCHIP_NAME=$(format_as_i2c_directory_name ${cp2112_module_num_str} ${PCA953X_CHIP_ADDRESS2})
        elif [ "${slot}" == "2" ]; then
                PCA953X_GPIOCHIP_NAME=$(format_as_i2c_directory_name ${cp2112_module_num_str} ${PCA953X_CHIP_ADDRESS1})
        else
                echo "Get chip address from slot [$slot] is failed"
                exit 1
        fi
}

function V3400::get_chip_name2() {
        local slot
        local cp2112_module_num_str=""

        slot=${1}
        cp2112_module_num_str=$(get_i2c_device_minor_number_list "CP2112")

        if [ "${slot}" == "0" ]; then
                PCA953X_GPIOCHIP_NAME=$(format_as_i2c_directory_name ${cp2112_module_num_str} ${PCA953X_CHIP_ADDRESS1})
        elif [ "${slot}" == "1" ]; then
                PCA953X_GPIOCHIP_NAME=$(format_as_i2c_directory_name ${cp2112_module_num_str} ${PCA953X_CHIP_ADDRESS2})
        elif [ "${slot}" == "2" ]; then
                PCA953X_GPIOCHIP_NAME=$(format_as_i2c_directory_name ${cp2112_module_num_str} ${PCA953X_CHIP_ADDRESS2})
        else
                echo "Get chip address from slot [$slot] is failed"
                exit 1
        fi
}

function V3400::get_power_state() {
        local slot

        slot=${1}
        V3400::get_chip_name "$slot"
        get_power_state_pca953x_libgpiod "$PCA953X_GPIOCHIP_NAME" "$slot"
}

function V3400::set_power_state() {
        local slot
        local state

        slot=${1}
        state==${2}

        if [ "${slot}" == "2" ]; then
                # check mPCIe dip switch state, if on wifi mode (low),
                # it's not allowed to control mPCIe power
               V3400::get_chip_name "$slot"
               get_dip_switch_state_pca953x_libgpiod "$PCA953X_GPIOCHIP_NAME" "0" | grep "low" 2>&1 > /dev/null
               if [[ $? -eq 0 ]]; then
                       echo "Operation not supported. The DIP switch is under WiFi mode."
                       exit 0
               fi
        fi

        if [[ "$TARGET_POWER_STATE" == "high" ]]; then
                state=1
        elif [[ "$TARGET_POWER_STATE" == "low" ]]; then
                state=0
        else
                echo "Power state $TARGET_POWER_STATE is invalid"
                exit 1
        fi

        V3400::get_chip_name "$slot"
        set_power_state_pca953x_libgpiod "$PCA953X_GPIOCHIP_NAME" "$slot" "$state"
}

function V3400::get_reset_state() {
        local slot

        slot=${1}
        V3400::get_chip_name "$slot"
        get_reset_state_pca953x_libgpiod "$PCA953X_GPIOCHIP_NAME" "$slot"
}

function V3400::set_reset_state() {
        local slot
        local state

        slot=${1}
        state==${2}

        if [[ "$TARGET_RESET_STATE" == "high" ]]; then
                state=1
        elif [[ "$TARGET_RESET_STATE" == "low" ]]; then
                state=0
        else
                echo "Reset state $TARGET_RESET_STATE is invalid"
                exit 1
        fi

        V3400::get_chip_name "$slot"
        set_reset_state_pca953x_libgpiod "$PCA953X_GPIOCHIP_NAME" "$slot" "$state"
}

function V3400::get_disable_state() {
        local slot

        slot=${1}
        V3400::get_chip_name2 "$slot"
        get_disable_state_pca953x_libgpiod "$PCA953X_GPIOCHIP_NAME" "$slot"
}

function V3400::set_disable_state() {
        local slot
        local state

        slot=${1}
        state==${2}

        if [[ "$TARGET_DISABLE_STATE" == "high" ]]; then
                state=1
        elif [[ "$TARGET_DISABLE_STATE" == "low" ]]; then
                state=0
        else
                echo "Disable state $TARGET_DISABLE_STATE is invalid"
                exit 1
        fi

        V3400::get_chip_name2 "$slot"
        set_disable_state_pca953x_libgpiod "$PCA953X_GPIOCHIP_NAME" "$slot" "$state"
}

function V3400::get_sim_select_state() {
        local slot

        slot=${1}

        if [[ "$slot" == "2" ]]; then
                V3400::get_chip_name "$slot"
                get_sim_select_state_pca953x_libgpiod "$PCA953X_GPIOCHIP_NAME" "$slot"
        else
                echo "SIM card slot control is not supported on slot $slot"
                exit 0
        fi
}

function V3400::set_sim_select_state() {
        local slot
        local state

        slot=${1}
        state==${2}

        if [[ "$slot" == "2" ]]; then
                if [[ "$TARGET_SIM_SELECT_STATE" == "1" ]]; then
                        state=1
                elif [[ "$TARGET_SIM_SELECT_STATE" == "2" ]]; then
                        state=0
                else
                        echo "SIM card state $TARGET_SIM_SELECT_STATE is invalid"
                        exit 1
                fi
        else
                echo "SIM card slot control is not supported on slot $slot"
                exit 0
        fi

        V3400::get_chip_name "$slot"
        set_sim_select_state_pca953x_libgpiod "$PCA953X_GPIOCHIP_NAME" "$slot" "$state"
}

function V3400::get_turn_on_state() {
        local slot

        slot=${1}
        if [[ "$slot" == "2" ]]; then
                echo "Turn On control is not supported on LTE module slot $slot"
                exit 0
        fi

        V3400::get_chip_name "$slot"
        get_turn_on_state_pca953x_libgpiod "$PCA953X_GPIOCHIP_NAME" "$slot"
}

function V3400::set_turn_on_state() {
        local slot
        local state

        slot=${1}
        state==${2}

        if [[ "$TARGET_TURN_ON_STATE" == "high" ]]; then
                state=1
        elif [[ "$TARGET_TURN_ON_STATE" == "low" ]]; then
                state=0
        else
                echo "Turn on state $TARGET_TURN_ON_STATE is invalid"
                exit 1
        fi

        if [[ "$slot" == "2" ]]; then
                echo "Turn On control is not supported on LTE module slot $slot"
                exit 0
        fi

        V3400::get_chip_name "$slot"
        set_turn_on_state_pca953x_libgpiod "$PCA953X_GPIOCHIP_NAME" "$slot" "$state"
}

function V3400::get_dip_switch_state() {
        local slot

        slot=${1}
        if [[ "$slot" != "2" ]]; then
                echo "Get DIP switch state is not supported on 5G module slot $slot"
                exit 0
        fi

        V3400::get_chip_name "$slot"
        # for LTE module
        get_dip_switch_state_pca953x_libgpiod "$PCA953X_GPIOCHIP_NAME" "0"
}

function V3400::get_mode_state() {
        local slot

        slot=${1}
        if [[ "$slot" == "2" ]]; then
                # for LTE module
                V3400::get_chip_name2 "$slot"
                get_mpcie_mode_state_pca953x_libgpiod "$PCA953X_GPIOCHIP_NAME" "0"
                exit 0
        fi

        V3400::get_chip_name "$slot"
        get_m2b_mode_state_pca953x_libgpiod "$PCA953X_GPIOCHIP_NAME" "$slot"
}

## main functions
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
}

function get_power_state_pca953x_libgpiod() {
        local gpiochip_name=$1
        local idx=$2
        local pca953x_gpio_pin
        local gpc_name
        local state

        pca953x_gpio_pin=${POWER_ENABLE_PCA953X_GPIO_TBL[$idx]}
        gpc_name=$(gpio_get_gpiochip_name $gpiochip_name)
        state=$(gpio_get_value_libgpiod $pca953x_gpio_pin $gpc_name)

        echo "Slot #${idx} power status is ${POWER_STATE[$state]}"
}

function set_power_state_pca953x_libgpiod() {
        local gpiochip_name=$1
        local idx=$2
        local state=$3
        local check_state
        local pca953x_gpio_pin
        local gpc_name
        local ret

        pca953x_gpio_pin=${POWER_ENABLE_PCA953X_GPIO_TBL[$idx]}
        gpc_name=$(gpio_get_gpiochip_name $gpiochip_name)
        gpio_set_value_libgpiod $pca953x_gpio_pin $state $gpc_name
        [[ $? -ne 0 ]] && ret=1

        check_state=$(gpio_get_value_libgpiod $pca953x_gpio_pin $gpc_name)
        [[ $? -ne 0 ]] && ret=1
        if [[ $ret -ne 0 || "$state" -ne "$check_state" ]]; then
                echo "Set State Failed"
                exit $ret
        fi

        echo "Set power enable as ${POWER_STATE[$state]} status for slot #${idx}"
}

function get_reset_state_pca953x_libgpiod() {
        local gpiochip_name=$1
        local idx=$2
        local pca953x_gpio_pin
        local gpc_name
        local state

        pca953x_gpio_pin=${RESET_PCA953X_GPIO_TBL[$idx]}
        gpc_name=$(gpio_get_gpiochip_name $gpiochip_name)
        state=$(gpio_get_value_libgpiod $pca953x_gpio_pin $gpc_name)

        echo "Slot #${idx} power status is ${RESET_STATE[$state]}"
}

function set_reset_state_pca953x_libgpiod() {
        local gpiochip_name=$1
        local idx=$2
        local state=$3
        local check_state
        local pca953x_gpio_pin
        local gpc_name
        local ret

        pca953x_gpio_pin=${RESET_PCA953X_GPIO_TBL[$idx]}
        gpc_name=$(gpio_get_gpiochip_name $gpiochip_name)
	gpio_set_value_libgpiod $pca953x_gpio_pin $state $gpc_name
        [[ $? -ne 0 ]] && ret=1

        check_state=$(gpio_get_value_libgpiod $pca953x_gpio_pin $gpc_name)
        [[ $? -ne 0 ]] && ret=1
        if [[ $ret -ne 0 || "$state" -ne "$check_state" ]]; then
                echo "Set State Failed"
                exit $ret
        fi

        echo "Set reset as ${RESET_STATE[$state]} status for slot #${idx}"
}

function get_disable_state_pca953x_libgpiod() {
        local gpiochip_name=$1
	local idx=$2
        local pca953x_gpio_pin
        local gpc_name
        local state

        pca953x_gpio_pin=${DISABLE_PCA953X_GPIO_TBL[$idx]}
        gpc_name=$(gpio_get_gpiochip_name $gpiochip_name)
        state=$(gpio_get_value_libgpiod $pca953x_gpio_pin $gpc_name)

        echo "Slot #${idx} disable status is ${DISABLE_STATE[$state]}"
}

function set_disable_state_pca953x_libgpiod() {
        local gpiochip_name=$1
        local idx=$2
        local state=$3
        local check_state
        local pca953x_gpio_pin
        local gpc_name
        local ret

        pca953x_gpio_pin=${DISABLE_PCA953X_GPIO_TBL[$idx]}
        gpc_name=$(gpio_get_gpiochip_name $gpiochip_name)
	gpio_set_value_libgpiod $pca953x_gpio_pin $state $gpc_name
        [[ $? -ne 0 ]] && ret=1

        check_state=$(gpio_get_value_libgpiod $pca953x_gpio_pin $gpc_name)
        [[ $? -ne 0 ]] && ret=1
        if [[ $ret -ne 0 || "$state" -ne "$check_state" ]]; then
                echo "Set State Failed"
                exit $ret
        fi

        echo "Set disable as ${DISABLE_STATE[$state]} status for slot #${idx}"
}

function get_sim_select_state_pca953x_libgpiod() {
        local gpiochip_name=$1
        local idx=$2
        local pca953x_gpio_pin
        local gpc_name
        local state

        pca953x_gpio_pin=${SIM_SELECT_PCA953X_GPIO_TBL[$idx]}
        gpc_name=$(gpio_get_gpiochip_name $gpiochip_name)
        state=$(gpio_get_value_libgpiod $pca953x_gpio_pin $gpc_name)

        echo "Slot #${idx} SIM card select is #${SIM_SELECT_STATE[$state]}"
}

function set_sim_select_state_pca953x_libgpiod() {
        local gpiochip_name=$1
        local idx=$2
        local state=$3
        local check_state
        local pca953x_gpio_pin
        local gpc_name
        local ret

        pca953x_gpio_pin=${SIM_SELECT_PCA953X_GPIO_TBL[$idx]}
        gpc_name=$(gpio_get_gpiochip_name $gpiochip_name)
	gpio_set_value_libgpiod $pca953x_gpio_pin $state $gpc_name
        [[ $? -ne 0 ]] && ret=1

        check_state=$(gpio_get_value_libgpiod $pca953x_gpio_pin $gpc_name)
        [[ $? -ne 0 ]] && ret=1
        if [[ $ret -ne 0 || "$state" -ne "$check_state" ]]; then
                echo "Set State Failed"
                exit $ret
        fi

        echo "Set SIM card select as #${SIM_SELECT_STATE[$state]} for module slot #${idx}"
}

function get_turn_on_state_pca953x_libgpiod() {
        local gpiochip_name=$1
        local idx=$2
        local pca953x_gpio_pin
        local gpc_name
        local state

        pca953x_gpio_pin=${TURN_ON_PCA953X_GPIO_TBL[$idx]}
        gpc_name=$(gpio_get_gpiochip_name $gpiochip_name)
        state=$(gpio_get_value_libgpiod $pca953x_gpio_pin $gpc_name)

        echo "Slot #${idx} turn on status is ${TURN_ON_STATE[$state]}"
}

function set_turn_on_state_pca953x_libgpiod() {
        local gpiochip_name=$1
        local idx=$2
        local state=$3
        local check_state
        local pca953x_gpio_pin
        local gpc_name
        local ret

        pca953x_gpio_pin=${TURN_ON_PCA953X_GPIO_TBL[$idx]}
        gpc_name=$(gpio_get_gpiochip_name $gpiochip_name)
	gpio_set_value_libgpiod $pca953x_gpio_pin $state $gpc_name
        [[ $? -ne 0 ]] && ret=1

        check_state=$(gpio_get_value_libgpiod $pca953x_gpio_pin $gpc_name)
        [[ $? -ne 0 ]] && ret=1
        if [[ $ret -ne 0 || "$state" -ne "$check_state" ]]; then
                echo "Set State Failed"
                exit $ret
        fi

        echo "Set turn on as ${TURN_ON_STATE[$state]} status for slot #${idx}"
}

function get_dip_switch_state_pca953x_libgpiod() {
        local gpiochip_name=$1
        local idx=$2
        local pca953x_gpio_pin
        local gpc_name
        local state

        pca953x_gpio_pin=${DIP_SWITCH_PCA953X_GPIO_TBL[$idx]}
        gpc_name=$(gpio_get_gpiochip_name $gpiochip_name)
        state=$(gpio_get_value_libgpiod $pca953x_gpio_pin $gpc_name)

        echo "Slot #${idx} dip switch state is ${DIP_SWITCH_STATE[$state]}"
}

function get_m2b_mode_state_pca953x_libgpiod() {
        local gpiochip_name=$1
        local idx=$2
        local pca953x_gpio_pin
        local gpc_name
        local state
        gpc_name=$(gpio_get_gpiochip_name $gpiochip_name)

        echo "Module status on slot #${2}:"
        pca953x_gpio_pin=${M2B_ALIVE_FN990_PCA953X_TBL[$idx]}
        state=$(gpio_get_value_libgpiod $pca953x_gpio_pin $gpc_name)
        echo -e "FN990=${state}"

        pca953x_gpio_pin=${M2B_ALIVE_RM520N_PCA953X_TBL[$idx]}
        state=$(gpio_get_value_libgpiod $pca953x_gpio_pin $gpc_name)
        echo -e "RM520N=${state}"

        pca953x_gpio_pin=${M2B_CONFIG_0_PCA953X_TBL[$idx]}
        state=$(gpio_get_value_libgpiod $pca953x_gpio_pin $gpc_name)
        echo -e "CONFIG_0=${state}"

        pca953x_gpio_pin=${M2B_CONFIG_1_PCA953X_TBL[$idx]}
        state=$(gpio_get_value_libgpiod $pca953x_gpio_pin $gpc_name)
        echo -e "CONFIG_1=${state}"

        pca953x_gpio_pin=${M2B_CONFIG_2_PCA953X_TBL[$idx]}
        state=$(gpio_get_value_libgpiod $pca953x_gpio_pin $gpc_name)
        echo -e "CONFIG_2=${state}"

        pca953x_gpio_pin=${M2B_CONFIG_3_PCA953X_TBL[$idx]}
        state=$(gpio_get_value_libgpiod $pca953x_gpio_pin $gpc_name)
        echo -e "CONFIG_3=${state}"
}

function get_mpcie_mode_state_pca953x_libgpiod() {
        local gpiochip_name=$1
        local idx=$2
        local pca953x_gpio_pin
        local gpc_name
        local state
        gpc_name=$(gpio_get_gpiochip_name $gpiochip_name)

        echo "Module status on slot #${2}:"
        pca953x_gpio_pin=${MPCIE_ALIVE_PCA953X_GPIO_TBL[$idx]}
        state=$(gpio_get_value_libgpiod $pca953x_gpio_pin $gpc_name)
        echo -e "LE910C4-WWXD=${state}"
}

function get_power_state_it87() {
        local gpio_pin
        local state_val

        gpio_pin="$1"

        if [[ "${OS_ID}" == "centos" ]]; then
                state_val=$(get_power_state_it87_via_sysfs $gpio_pin)
        else
                state_val=$(get_power_state_it87_via_libgpiod $gpio_pin)
        fi

        echo $state_val
}

function get_power_state_it87_via_sysfs() {
        local gpio
        local pwr_state

        gpio=$(gpc_it8786 $1)
        [[ $? -ne 0 ]] && ret=1

        if [[ $ret -ne 0 ]]; then
                echo "Get power state failed"
                exit $ret
        fi

        pwr_state=$(gpio_get_value_sysfs $gpio)
        [[ $? -ne 0 ]] && ret=2

        if [[ $ret -ne 0 ]]; then
                echo "Get power state failed"
                exit $ret
        fi

        echo $pwr_state
}

function get_power_state_it87_via_libgpiod() {
        local gpio
        local gpc_name
        local pwr_state
        local ret

        ret=0

        gpc_name=$(gpio_get_gpiochip_name gpio_it87)
        gpio=$(gpc_it8786_remap $1)
        pwr_state=$(gpio_get_value_libgpiod $gpio $gpc_name)
        [[ $? -ne 0 ]] && ret=1

        if [[ $ret -ne 0 ]]; then
                echo "Get power state failed"
                exit $ret
        fi

        echo $pwr_state
}

function set_power_state_it87() {
        local gpio_pin
        local state_val

        gpio_pin="$1"
        state_val="$2"

        if [[ "${OS_ID}" == "centos" ]]; then
                set_power_state_it87_via_sysfs $gpio_pin $state_val
        else
                set_power_state_it87_via_libgpiod $gpio_pin $state_val
        fi
}

function set_power_state_it87_via_sysfs() {
        local gpio
        local pwr_state
        local ret

        gpio=$(gpc_it8786 $1)
        [[ $? -ne 0 ]] && ret=1

        if [[ $ret -ne 0 ]]; then
                echo "Set power state failed"
                exit $ret
        fi

        pwr_state="$2"

        gpio_set_value_sysfs $gpio $pwr_state
        [[ $? -ne 0 ]] && ret=2

        if [[ $ret -ne 0 ]]; then
                echo "Set power state failed"
                exit $ret
        fi
}

function set_power_state_it87_via_libgpiod() {
        local gpio
        local gpc_name
        local pwr_state
        local ret

        ret=0

        gpc_name=$(gpio_get_gpiochip_name gpio_it87)
        gpio=$(gpc_it8786_remap $1)
        pwr_state="$2"
        gpio_set_value_libgpiod $gpio $pwr_state $gpc_name
        [[ $? -ne 0 ]] && ret=1

        if [[ $ret -ne 0 ]]; then
                echo "Set power state failed"
                return $ret
        fi
}

function get_reset_state_it87() {
        local gpio_pin
        local state_val

        gpio_pin="$1"

        if [[ "${OS_ID}" == "centos" ]]; then
                state_val=$(get_reset_state_it87_via_sysfs $gpio_pin)
        else
                state_val=$(get_reset_state_it87_via_libgpiod $gpio_pin)
        fi

        echo $state_val
}

function get_reset_state_it87_via_sysfs() {
        local gpio
        local rst_state

        gpio=$(gpc_it8786 $1)
        [[ $? -ne 0 ]] && ret=1

        if [[ $ret -ne 0 ]]; then
                echo "Get reset state failed"
                exit $ret
        fi

        rst_state=$(gpio_get_value_sysfs $gpio)
        [[ $? -ne 0 ]] && ret=2

        if [[ $ret -ne 0 ]]; then
                echo "Get reset state failed"
                exit $ret
        fi

        echo $rst_state
}

function get_reset_state_it87_via_libgpiod() {
        local gpio
        local gpc_name
        local rst_state
        local ret

        ret=0

        gpc_name=$(gpio_get_gpiochip_name gpio_it87)
        gpio=$(gpc_it8786_remap $1)
        rst_state=$(gpio_get_value_libgpiod $gpio $gpc_name)
        [[ $? -ne 0 ]] && ret=1

        if [[ $ret -ne 0 ]]; then
                echo "Get reset state failed"
                exit $ret
        fi

        echo $rst_state
}

function get_disable_state_it87() {
        local gpio_pin
        local state_val

        gpio_pin="$1"

        if [[ "${OS_ID}" == "centos" ]]; then
                state_val=$(get_disable_state_it87_via_sysfs $gpio_pin)
        else
                state_val=$(get_disable_state_it87_via_libgpiod $gpio_pin)
        fi

        echo $state_val
}

function get_disable_state_it87_via_sysfs() {
        local gpio
        local disable_state

        gpio=$(gpc_it8786 $1)
        [[ $? -ne 0 ]] && ret=1

        if [[ $ret -ne 0 ]]; then
                echo "Get disable state failed"
                exit $ret
        fi

        disable_state=$(gpio_get_value_sysfs $gpio)
        [[ $? -ne 0 ]] && ret=2

        if [[ $ret -ne 0 ]]; then
                echo "Get disable state failed"
                exit $ret
        fi

        echo $disable_state
}

function get_disable_state_it87_via_libgpiod() {
        local gpio
        local gpc_name
        local disable_state
        local ret

        ret=0

        gpc_name=$(gpio_get_gpiochip_name gpio_it87)
        gpio=$(gpc_it8786_remap $1)
        disable_state=$(gpio_get_value_libgpiod $gpio $gpc_name)
        [[ $? -ne 0 ]] && ret=1

        if [[ $ret -ne 0 ]]; then
                echo "Get disable state failed"
                exit $ret
        fi

        echo $disable_state
}

function script_usage() {
cat << EOF
Usage:
       mx-module-ctl [Options]

Operations:
       -s, --slot <module_slot_id>
               Select module slot
       -p, --pwren [high|low]
               Get/Set power enable pin high/low status
       -r, --reset [high|low]
               Get/Set reset pin high/low status
       -d, --disable [high|low]
               Get/Set disable pin high/low status
       -t, --turnon [high|low]
               Get/Set turn-on pin high/low status
       -i, --sim [1|2]
               Get/Set sim card slot 1/2
       --dip,
               Get dip switch status
       --mod,
               Get module and config status

Example:
       Set power enable to [high] status for module 0
       # mx-module-ctl -s 0 -p high
       Get power enable pin status of module 0
       # mx-module-ctl -s 0 -p

       Set disable pin to [high] status for module 0
       # mx-module-ctl -s 0 -d high
       Get disable pin status of module 0
       # mx-module-ctl -s 0 -d

       Set turn-on pin to [high] status for module 1
       # mx-module-ctl -s 1 -t high
       Get turn-on pin status of module 1
       # mx-module-ctl -s 1 -t

       Set reset pin to [low] status for module 2
       # mx-module-ctl -s 2 -r low
       Get reset pin status of module 2
       # mx-module-ctl -s 2 -r

       Select SIM slot 2 for module 2
       # mx-module-ctl -s 2 -i 2
       Get current SIM slot of module 2
       # mx-module-ctl -s 2 -i

       Get dip switch status for module 1
       # mx-module-ctl -s 1 --dip

       Get module config for module 2
       # mx-module-ctl -s 2 --mod
EOF
}

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

        while true
        do
                case $1 in
                        -s|--slot)
                                TARGET_MODULE_SLOT=$2
                                shift 2
                                ;;
                        -p|--pwren)
                                case $2 in
                                        "")
                                                TARGET_POWER_STATE=""
                                                shift
                                                ;;
                                        *)
                                                TARGET_POWER_STATE=$2;
                                                shift 2
                                                ;;
                                esac
                                TARGET_OPCODE="PWREN"
                                ;;
                        -r|--reset)
                                case $2 in
                                        "")
                                                TARGET_RESET_STATE=""
                                                shift
                                                ;;
                                        *)
                                                TARGET_RESET_STATE=$2;
                                                shift 2
                                                ;;
                                esac
                                TARGET_OPCODE="RESET"
                                ;;
                        -d|--disable)
                                case $2 in
                                        "")
                                                TARGET_DISABLE_STATE=""
                                                shift
                                                ;;
                                        *)
                                                TARGET_DISABLE_STATE=$2;
                                                shift 2
                                                ;;
                                esac
                                TARGET_OPCODE="DISABLE"
                                ;;
                        -i|--sim)
                                case $2 in
                                        "")
                                                TARGET_SIM_SELECT_STATE=""
                                                shift
                                                ;;
                                        *)
                                                TARGET_SIM_SELECT_STATE=$2;
                                                shift 2
                                                ;;
                                esac
                                TARGET_OPCODE="SIM_SELECT"
                                ;;
                        -t|--turnon)
                                case $2 in
                                        "")
                                                TARGET_TURN_ON_STATE=""
                                                shift
                                                ;;
                                        *)
                                                TARGET_TURN_ON_STATE=$2;
                                                shift 2
                                                ;;
                                esac
                                TARGET_OPCODE="TURN_ON"
                                ;;
                        --dip)
                                case $2 in
                                        "")
                                                TARGET_DIP_SWITCH_STATE=""
                                                shift
                                                ;;
                                esac
                                TARGET_OPCODE="DIP_SWITCH"
                                ;;
                        --mod)
                                case $2 in
                                        "")
                                                arg=""
                                                shift
                                                ;;
                                esac
                                TARGET_OPCODE="MOD_STATUS"
                                ;;
                        "")
                                break
                                ;;
                        *)
                                script_usage
                                exit 1
                                ;;
                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_module_slot() {
        if ! check_leading_zero_digit $TARGET_MODULE_SLOT; then
                echo "Invaild module slot format."
                exit 1
        fi

        if [[ $TARGET_MODULE_SLOT -lt 0 || $TARGET_MODULE_SLOT -ge $NUM_OF_MODULE_SLOTS ]]; then
                echo "Invalid module slot index."
                exit 1
        fi
}

function main() {
        script_params "$@"
        script_init

        verify_module_slot

        case $TARGET_OPCODE in
        "PWREN")
                if [[ ! $(type -t "${MODEL_NAME}"::get_power_state) == function ]]; then
                        echo "${MODEL_NAME} get_power_state function is not define"
                        exit 1
                fi
                if [ -z $TARGET_POWER_STATE ]; then
                        "${MODEL_NAME}"::get_power_state $TARGET_MODULE_SLOT
                else
                        "${MODEL_NAME}"::set_power_state $TARGET_MODULE_SLOT $TARGET_POWER_STATE
                fi
                ;;
        "RESET")
                if [[ ! $(type -t "${MODEL_NAME}"::get_reset_state) == function ]]; then
                        echo "${MODEL_NAME} get_reset_state function is not define"
                        exit 1
                fi
                if [ -z $TARGET_RESET_STATE ]; then
                        "${MODEL_NAME}"::get_reset_state $TARGET_MODULE_SLOT
                else
                        "${MODEL_NAME}"::set_reset_state $TARGET_MODULE_SLOT $TARGET_RESET_STATE
                fi
                ;;
        "DISABLE")
                if [[ ! $(type -t "${MODEL_NAME}"::get_disable_state) == function ]]; then
                        echo "${MODEL_NAME} get_disable_state function is not define"
                        exit 1
                fi
                if [ -z $TARGET_DISABLE_STATE ]; then
                        "${MODEL_NAME}"::get_disable_state $TARGET_MODULE_SLOT
                else
                        "${MODEL_NAME}"::set_disable_state $TARGET_MODULE_SLOT $TARGET_DISABLE_STATE
                fi
                ;;
        "SIM_SELECT")
                if [[ ! $(type -t "${MODEL_NAME}"::get_sim_select_state) == function ]]; then
                        echo "${MODEL_NAME} get_sim_select_state function is not define"
                        exit 1
                fi
                if [ -z $TARGET_SIM_SELECT_STATE ]; then
                        "${MODEL_NAME}"::get_sim_select_state $TARGET_MODULE_SLOT
                else
                        "${MODEL_NAME}"::set_sim_select_state $TARGET_MODULE_SLOT $TARGET_SIM_SELECT_STATE
                fi
                ;;
        "TURN_ON")
                if [[ ! $(type -t "${MODEL_NAME}"::get_turn_on_state) == function ]]; then
                        echo "${MODEL_NAME} get_turn_on_state function is not define"
                        exit 1
                fi
                if [ -z $TARGET_TURN_ON_STATE ]; then
                        "${MODEL_NAME}"::get_turn_on_state $TARGET_MODULE_SLOT
                else
                        "${MODEL_NAME}"::set_turn_on_state $TARGET_MODULE_SLOT $TARGET_TURN_ON_STATE
                fi
                ;;
        "DIP_SWITCH")
                if [[ ! $(type -t "${MODEL_NAME}"::get_dip_switch_state) == function ]]; then
                        echo "${MODEL_NAME} get_dip_switch_state function is not define"
                        exit 1
                fi
                if [ -z $TARGET_DIP_SWITCH_STATE ]; then
                        "${MODEL_NAME}"::get_dip_switch_state $TARGET_MODULE_SLOT
                fi
                ;;
        "MOD_STATUS")
                if [[ ! $(type -t "${MODEL_NAME}"::get_mode_state) == function ]]; then
                        echo "${MODEL_NAME} get_mode_state function is not define"
                        exit 1
                fi
                if [ -z $TARGET_MOD_STATUS_STATE ]; then
                        "${MODEL_NAME}"::get_mode_state $TARGET_MODULE_SLOT
                fi
                ;;
        *)
                script_usage
                exit 1
                ;;
        esac

        exit 0
}

main $@
