#!/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[@]}

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

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

        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_ADDRESS1})
        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_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_ADDRESS2})
        elif [ "${slot}" == "1" ]; then
                PCA953X_GPIOCHIP_NAME=$(format_as_i2c_directory_name ${cp2112_module_num_str} ${PCA953X_CHIP_ADDRESS1})
        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}" == "0" ]; 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" "$slot" | 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}
        V3400::get_chip_name "$slot"
        get_sim_select_state_pca953x_libgpiod "$PCA953X_GPIOCHIP_NAME" "$slot"
}

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

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

        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

        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" == "0" ]]; 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" == "0" ]]; 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" != "0" ]]; then
                echo "Get DIP switch state is not supported on 5G module slot $slot"
                exit 0
        fi

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

function V3400::get_mode_state() {
        local slot

        slot=${1}
        if [[ "$slot" == "0" ]]; then
                V3400::get_chip_name2 "$slot"
                get_mpcie_mode_state_pca953x_libgpiod "$PCA953X_GPIOCHIP_NAME" "$slot"
                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 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, --disale [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 $@
