#!/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 MC-1111::profile() {
        MC_11xx_profile
}

function MC-1112::profile() {
        MC_11xx_profile
}

function MC-1121::profile() {
        MC_11xx_profile
}

function MC-1122::profile() {
        MC_11xx_profile
}

function MC_11xx_profile() {
        NUM_OF_MODULE_SLOTS=1
        POWER_CONTROL_TBL=(60)
        RESET_PIN_TBL=()
        DISABLE_PIN_TBL=()
        DIP_SWITCH_SELECT_TBL=()
        SIM_CARD_SELECT_TBL=()
}

function MC-1111::init() {
        MC_111x_init
}

function MC-1112::init() {
        MC_111x_init
}

function MC-1121::init() {
        MC_111x_init
}

function MC-1122::init() {
        MC_111x_init
}

function MC_111x_init() {
        # skip init
        return 0
}

function MC-1111::set_power_state() {
        MC_111x_set_power_state "$1" "$2"
}

function MC-1112::set_power_state() {
        MC_111x_set_power_state "$1" "$2"
}

function MC-1121::set_power_state() {
        MC_111x_set_power_state "$1" "$2"
}

function MC-1122::set_power_state() {
        MC_111x_set_power_state "$1" "$2"
}

function MC_111x_set_power_state() {
        local slot
        local state

        slot="$1"
        state="$2"
        # keep on using BXPA101S set power pin function
        BXPA101S::set_power_state "${slot}" "${state}"
}

function MC-1111::get_power_state() {
        MC_111x_get_power_state "$1"
}

function MC-1112::get_power_state() {
        MC_111x_get_power_state "$1"
}

function MC-1121::get_power_state() {
        MC_111x_get_power_state "$1"
}

function MC-1122::get_power_state() {
        MC_111x_get_power_state "$1"
}

function MC_111x_get_power_state() {
        local slot

        slot="$1"
        # keep on using BXPA101S get power pin function
        BXPA101S::get_power_state "${slot}"
}

function V2201::profile() {
        NUM_OF_MODULE_SLOTS=2
        POWER_CONTROL_TBL=(22 24)
        RESET_PIN_TBL=(23 26)
        DISABLE_PIN_TBL=()
        DIP_SWITCH_SELECT_TBL=()
        SIM_CARD_SELECT_TBL=()
}

function V2201::init() {
        # skip init
        return 0
}

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

        slot="$1"
        state="$2"
        # keep on using BXPA101S set reset pin function
        BXPA101S::set_reset_state "${slot}" "${state}"
}

function V2201::get_reset_state() {
        local slot

        slot="$1"
        # keep on using BXPA101S get reset pin function
        BXPA101S::get_reset_state "${slot}"
}

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

        slot="$1"
        state="$2"
        # keep on using BXPA101S set power pin function
        BXPA101S::set_power_state "${slot}" "${state}"
}

function V2201::get_power_state() {
        local slot

        slot="$1"
        # keep on using BXPA101S get power pin function
        BXPA101S::get_power_state "${slot}"
}

function DRPC100::profile() {
        DRP100:profile
}

function DRPC100::init() {
        DRP100:init
}

function DRPC100::get_dip_switch_state() {
        local slot

        slot="$1"
        DRP100::get_dip_switch_state "${slot}"
}

function DRPC100::get_reset_state() {
        local slot

        slot="$1"
        DRP100::get_reset_state "${slot}"
}

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

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

        DRP100::set_reset_state "${slot}" "${state}"
}

function DRPC100::get_disable_state() {
        local slot

        slot="$1"
        DRP100::get_disable_state "${slot}"
}

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

        slot="$1"
        state="$2"
        DRP100::set_disable_state "${slot}" "${state}"
}

function DRPC100::get_mode_state() {
        local slot

        slot=${1}
        DRP100::get_mode_state "${slot}"
}

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

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

        DRP100::set_power_state "${slot}" "${state}"
}

function DRPC100::get_power_state() {
        local slot

        slot="$1"
        DRP100::get_power_state "${slot}"
}

function DRPA100::profile() {
        DRP100:profile
}

function DRPA100::init() {
        DRP100:init
}

function DRPA100::get_dip_switch_state() {
        local slot

        slot="$1"
        DRP100::get_dip_switch_state "${slot}"
}

function DRPA100::get_power_state() {
        local slot

        slot="$1"
        DRP100::get_power_state "${slot}"
}

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

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

        DRP100::set_power_state "${slot}" "${state}"
}

function DRPA100::get_reset_state() {
        local slot

        slot="$1"
        DRP100::get_reset_state "${slot}"
}

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

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

        DRP100::set_reset_state "${slot}" "${state}"
}

function DRPA100::get_disable_state() {
        local slot

        slot="$1"
        DRP100::get_disable_state "${slot}"
}

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

        slot="$1"
        state="$2"
        DRP100::set_disable_state "${slot}" "${state}"
}

function DRPA100::get_mode_state() {
        local slot

        slot=${1}
        DRP100::get_mode_state "${slot}"
}

function DRP100:profile() {
        NUM_OF_MODULE_SLOTS=""
        IO_BOARD_GPIOCHIP_LABEL=""
        IO_BOARD_EEPROM_INDEX=""
        MAIN_BOARD_EEPROM_ADDRESS="0x54"
        MAIN_BOARD_EEPROM_IO_BOARD_INDEX_OFFSET="0x06"
        IO_BOARD_GPIO_TBL=(33 34 36 37)

        IO_BOARD_DUAL_WIRELESS_GPIO_VAL=(0 1 1 1)
        IO_BOARD_DUAL_WIRELESS_I2C_ADDR="0x27"

        IO_BOARD_FUNCTION_PLUS_INDEX="0x01"
        IO_BOARD_FUNCTION_PLUS_I2C_ADDR="0x27"

        POWER_CONTROL_TBL=()
        RESET_PIN_TBL=()
        DISABLE_PIN_TBL=()
        DIP_SWITCH_SELECT_TBL=()
        MPCIE_ALIVE_GPIO_TBL=()
        SIM_CARD_SELECT_TBL=()
}

function DRP100:init() {
        local io_board_gpio_pins
        local io_board_gpio_val
        local gpc_name
        local ret

        io_board_gpio_pins=(
                $(gpc_it8786_remap ${IO_BOARD_GPIO_TBL[0]})
                $(gpc_it8786_remap ${IO_BOARD_GPIO_TBL[1]})
                $(gpc_it8786_remap ${IO_BOARD_GPIO_TBL[2]})
                $(gpc_it8786_remap ${IO_BOARD_GPIO_TBL[3]})
        )

        # Determine I/O board by GPIO truth table
        gpc_name=$(gpio_get_gpiochip_name gpio_it87)
        io_board_gpio_val[0]=$(gpio_get_value_libgpiod ${io_board_gpio_pins[0]} $gpc_name)
        io_board_gpio_val[1]=$(gpio_get_value_libgpiod ${io_board_gpio_pins[1]} $gpc_name)
        io_board_gpio_val[2]=$(gpio_get_value_libgpiod ${io_board_gpio_pins[2]} $gpc_name)
        io_board_gpio_val[3]=$(gpio_get_value_libgpiod ${io_board_gpio_pins[3]} $gpc_name)

        # Determine I/O board by EEPROM information
        IO_BOARD_EEPROM_INDEX=$(get_board_index_from_eeprom $MAIN_BOARD_EEPROM_ADDRESS $MAIN_BOARD_EEPROM_IO_BOARD_INDEX_OFFSET)

        if [[ "${IO_BOARD_DUAL_WIRELESS_GPIO_VAL[*]}" == "${io_board_gpio_val[*]}" ]]; then
                ret=$(bind_i2c_driver "SMBus" "pca9535" $IO_BOARD_DUAL_WIRELESS_I2C_ADDR)
                if [[ $ret -ne 0 ]]; then
                        echo "Bind i2c device fail"
                        exit $ret
                fi
                IO_BOARD_GPIOCHIP_LABEL=$(get_i2c_slave_gpiochip_label "SMBus" ${IO_BOARD_DUAL_WIRELESS_I2C_ADDR})
                NUM_OF_MODULE_SLOTS=2
                POWER_CONTROL_TBL=(1 9)
                RESET_PIN_TBL=(2 10)
                DISABLE_PIN_TBL=(3 11)
                DIP_SWITCH_SELECT_TBL=(0 8)
                MPCIE_ALIVE_GPIO_TBL=(4 12)
                SIM_CARD_SELECT_TBL=""
        elif [[ "${IO_BOARD_EEPROM_INDEX}" == ${IO_BOARD_FUNCTION_PLUS_INDEX} ]]; then
                ret=$(bind_i2c_driver "SMBus" "pca9535" $IO_BOARD_FUNCTION_PLUS_I2C_ADDR)
                if [[ $ret -ne 0 ]]; then
                        echo "Bind i2c device fail"
                        exit $ret
                fi
                IO_BOARD_GPIOCHIP_LABEL=$(get_i2c_slave_gpiochip_label "SMBus" ${IO_BOARD_FUNCTION_PLUS_I2C_ADDR})
                NUM_OF_MODULE_SLOTS=1
                POWER_CONTROL_TBL=(36)
                RESET_PIN_TBL=(33)
                DISABLE_PIN_TBL=()
                DIP_SWITCH_SELECT_TBL=(37)
                MPCIE_ALIVE_GPIO_TBL=()
                SIM_CARD_SELECT_TBL=()
        else
                echo "Can not recognize I/O board"
                exit 1
        fi
}

function DRP100::get_dip_switch_state() {
        local slot
        local state

        slot="$1"

        if [[ "${IO_BOARD_EEPROM_INDEX}" == ${IO_BOARD_FUNCTION_PLUS_INDEX} ]]; then
                state=$(get_dip_switch_state_it87 ${DIP_SWITCH_SELECT_TBL[$slot]})
        else
                state=$(gpio_get_value_i2c_gpiochip_libgpiod ${DIP_SWITCH_SELECT_TBL[$slot]} ${IO_BOARD_GPIOCHIP_LABEL})
        fi

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

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

        slot="$1"

        if [[ ${#POWER_CONTROL_TBL[@]} -eq 0 ]]; then
                echo "Power control pin is not defined"
                exit 1
        fi

        if [[ "${IO_BOARD_EEPROM_INDEX}" == ${IO_BOARD_FUNCTION_PLUS_INDEX} ]]; then
                state=$(get_power_state_it87 ${POWER_CONTROL_TBL[$slot]})
        else
                state=$(gpio_get_value_i2c_gpiochip_libgpiod ${POWER_CONTROL_TBL[$slot]} ${IO_BOARD_GPIOCHIP_LABEL})
        fi

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

function DRP100::set_power_state() {
        local slot
        local state
        local dip_switch_state

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

        if [[ ${#POWER_CONTROL_TBL[@]} -eq 0 ]]; then
                echo "Power control pin is not defined"
                exit 1
        fi

        if [[ "${IO_BOARD_EEPROM_INDEX}" == ${IO_BOARD_FUNCTION_PLUS_INDEX} ]]; then
                dip_switch_state=$(get_dip_switch_state_it87 ${DIP_SWITCH_SELECT_TBL[$slot]})
        else
                dip_switch_state=$(gpio_get_value_i2c_gpiochip_libgpiod ${DIP_SWITCH_SELECT_TBL[$slot]} ${IO_BOARD_GPIOCHIP_LABEL})
        fi

        if [ "${dip_switch_state}" == "0" ]; then
                echo "Operation not supported. The DIP switch is under WiFi mode."
                exit 0
        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

        if [[ "${IO_BOARD_EEPROM_INDEX}" == ${IO_BOARD_FUNCTION_PLUS_INDEX} ]]; then
                set_power_state_it87 ${POWER_CONTROL_TBL[$slot]} $state
        else
                gpio_set_value_i2c_gpiochip_libgpiod ${POWER_CONTROL_TBL[$slot]} $state ${IO_BOARD_GPIOCHIP_LABEL}
        fi

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

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

        slot="$1"

        if [[ ${#RESET_PIN_TBL[@]} -eq 0 ]]; then
                echo "Reset pin is not defined"
                exit 1
        fi

        if [[ "${IO_BOARD_EEPROM_INDEX}" == ${IO_BOARD_FUNCTION_PLUS_INDEX} ]]; then
                state=$(get_reset_state_it87 ${RESET_PIN_TBL[$slot]})
        else
                state=$(gpio_get_value_i2c_gpiochip_libgpiod ${RESET_PIN_TBL[$slot]} ${IO_BOARD_GPIOCHIP_LABEL})
        fi

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

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

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

        if [[ ${#RESET_PIN_TBL[@]} -eq 0 ]]; then
                echo "Reset pin is not defined"
                exit 1
        fi

        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

        if [[ "${IO_BOARD_EEPROM_INDEX}" == ${IO_BOARD_FUNCTION_PLUS_INDEX} ]]; then
                set_reset_state_it87 ${RESET_PIN_TBL[$slot]} $state
        else
                gpio_set_value_i2c_gpiochip_libgpiod ${RESET_PIN_TBL[$slot]} $state ${IO_BOARD_GPIOCHIP_LABEL}
        fi

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

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

        slot="$1"

        if [[ ${#DISABLE_PIN_TBL[@]} -eq 0 ]]; then
                echo "Disable pin is not defined"
                exit 1
        fi

        state=$(gpio_get_value_i2c_gpiochip_libgpiod ${DISABLE_PIN_TBL[$slot]} ${IO_BOARD_GPIOCHIP_LABEL})

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

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

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

        if [[ ${#DISABLE_PIN_TBL[@]} -eq 0 ]]; then
                echo "Disable pin is not defined"
                exit 1
        fi

        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

        gpio_set_value_i2c_gpiochip_libgpiod ${DISABLE_PIN_TBL[$slot]} $state ${IO_BOARD_GPIOCHIP_LABEL}

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

function DRP100::get_mode_state() {
        local slot
        local state
        local pwr_state

        slot=${1}

        pwr_state=$(gpio_get_value_i2c_gpiochip_libgpiod ${POWER_CONTROL_TBL[$slot]} ${IO_BOARD_GPIOCHIP_LABEL})

        if [[ "$pwr_state" == "0" ]]; then
                echo "Please power on slot."
                exit 1
        fi

        if [[ ${#MPCIE_ALIVE_GPIO_TBL[@]} -eq 0 ]]; then
                echo "Alive pin is not defined"
                exit 1
        fi

        state=$(gpio_get_value_i2c_gpiochip_libgpiod ${MPCIE_ALIVE_GPIO_TBL[$slot]} ${IO_BOARD_GPIOCHIP_LABEL})

        case "$state" in
        0) state="inactive" ;;
        1) state="active" ;;
        *) state="unknown" ;;
        esac

        echo "Module status on slot #${slot}: $state"
}

function BXPA100::profile() {
        BXP100::profile
        IO_BOARD_GPIO_TBL=(91 92 93)
}

function BXPA100::init() {
        BXP100::init
}

function BXPA100::get_power_state() {
        local slot

        slot="$1"
        BXP100::get_power_state "${slot}"
}

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

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

        BXP100::set_power_state "${slot}" "${state}"
}

function BXPA100::get_reset_state() {
        local slot

        slot="$1"
        BXP100::get_reset_state "${slot}"
}

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

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

        BXP100::set_reset_state "${slot}" "${state}"
}

function BXPA100::get_dip_switch_state() {
        local slot

        slot="$1"
        BXP100::get_dip_switch_state "${slot}"
}

function BXPC100::profile() {
        BXP100::profile
        IO_BOARD_GPIO_TBL=(80 81 82)
}

function BXPC100::init() {
        BXP100::init
}

function BXPC100::get_power_state() {
        local slot

        slot="$1"
        BXP100::get_power_state "${slot}"
}

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

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

        BXP100::set_power_state "${slot}" "${state}"
}

function BXPC100::get_reset_state() {
        local slot

        slot="$1"
        BXP100::get_reset_state "${slot}"
}

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

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

        BXP100::set_reset_state "${slot}" "${state}"
}

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

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

        BXP100::set_reset_state "${slot}" "${state}"
}

function BXPC100::get_dip_switch_state() {
        local slot

        slot="$1"
        BXP100::get_dip_switch_state "${slot}"
}

function BXP100::profile() {
        NUM_OF_MODULE_SLOTS=""
        ADDRESS_OF_DAUGHTER_BOARD_EEPROM="0x54"
        BOARD_INDEX_OFFSET="0x06"

        IO_BOARD_M2_MPCIE_BOARD_I2C_ADDR="0x20"
        IO_BOARD_M2_MPCIE_GPIO=(1 0 0)

        IO_BOARD_FUNCTION_BOARD_I2C_ADDR="0x27"
        IO_BOARD_GPIOCHIP_LABEL=""
}

function BXP100::init() {
        local ret
        local board_index
        local io_board_gpio_pins
        local io_board_gpio_val
        local gpc_name

        ret=0
        if ! is_module_loaded gpio_it87; then
                echo "gpio_it87 driver is not loaded"
                exit 1
        fi

        if [[ "${OS_ID}" == "centos" ]]; then
                io_board_gpio_pins[0]=$(gpc_it8786 ${IO_BOARD_GPIO_TBL[0]})
                [[ $? -ne 0 ]] && ret=1
                io_board_gpio_pins[1]=$(gpc_it8786 ${IO_BOARD_GPIO_TBL[1]})
                [[ $? -ne 0 ]] && ret=1
                io_board_gpio_pins[2]=$(gpc_it8786 ${IO_BOARD_GPIO_TBL[2]})
                [[ $? -ne 0 ]] && ret=1

                if [[ $ret -ne 0 ]]; then
                        echo "Initialization Failed"
                        exit $ret
                fi

                io_board_gpio_val[0]=$(gpio_get_value_sysfs ${io_board_gpio_pins[0]})
                [[ $? -ne 0 ]] && ret=2
                io_board_gpio_val[1]=$(gpio_get_value_sysfs ${io_board_gpio_pins[1]})
                [[ $? -ne 0 ]] && ret=2
                io_board_gpio_val[2]=$(gpio_get_value_sysfs ${io_board_gpio_pins[2]})
                [[ $? -ne 0 ]] && ret=2

                if [[ $ret -ne 0 ]]; then
                        echo "Initialization Failed"
                        exit $ret
                fi
        else
                io_board_gpio_pins=(
                        $(gpc_it8786_remap ${IO_BOARD_GPIO_TBL[0]})
                        $(gpc_it8786_remap ${IO_BOARD_GPIO_TBL[1]})
                        $(gpc_it8786_remap ${IO_BOARD_GPIO_TBL[2]})
                )

                gpc_name=$(gpio_get_gpiochip_name gpio_it87)
                [[ $? -ne 0 ]] && ret=1
                io_board_gpio_val[0]=$(gpio_get_value_libgpiod ${io_board_gpio_pins[0]} $gpc_name)
                [[ $? -ne 0 ]] && ret=1
                io_board_gpio_val[1]=$(gpio_get_value_libgpiod ${io_board_gpio_pins[1]} $gpc_name)
                [[ $? -ne 0 ]] && ret=1
                io_board_gpio_val[2]=$(gpio_get_value_libgpiod ${io_board_gpio_pins[2]} $gpc_name)
                [[ $? -ne 0 ]] && ret=1

                if [[ $ret -ne 0 ]]; then
                        echo "Initialization Failed"
                        exit $ret
                fi
        fi

        board_index=$(get_board_index_from_eeprom $ADDRESS_OF_DAUGHTER_BOARD_EEPROM $BOARD_INDEX_OFFSET)
        if [[ "${board_index}" == "0x02" ]]; then
                ret=$(bind_i2c_driver "SMBus" "pca9535" $IO_BOARD_FUNCTION_BOARD_I2C_ADDR)
                if [[ $ret -ne 0 ]]; then
                        echo "Bind i2c device fail"
                        exit $ret
                fi
                IO_BOARD_GPIOCHIP_LABEL=$(get_i2c_slave_gpiochip_label "SMBus" ${IO_BOARD_FUNCTION_BOARD_I2C_ADDR})
                NUM_OF_MODULE_SLOTS=1
                POWER_CONTROL_TBL=(0)
                DIP_SWITCH_SELECT_TBL=(1)
                RESET_PIN_TBL=(2)
        elif [[ "${IO_BOARD_M2_MPCIE_GPIO[*]}" == "${io_board_gpio_val[*]}" ]]; then
                NUM_OF_MODULE_SLOTS=2
                ret=$(bind_i2c_driver "SMBus" "pca9535" $IO_BOARD_M2_MPCIE_BOARD_I2C_ADDR)
                if [[ $ret -ne 0 ]]; then
                        echo "Bind i2c device fail"
                        exit $ret
                fi
                IO_BOARD_GPIOCHIP_LABEL=$(get_i2c_slave_gpiochip_label "SMBus" ${IO_BOARD_M2_MPCIE_BOARD_I2C_ADDR})
                NUM_OF_MODULE_SLOTS=2
                POWER_CONTROL_TBL=(0 1)
                DIP_SWITCH_SELECT_TBL=(2 3)
        else
                echo "Can not support the I/O board on this model"
                exit 1
        fi
}

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

        slot="$1"

        state=$(gpio_get_value_i2c_gpiochip_libgpiod ${POWER_CONTROL_TBL[$slot]} ${IO_BOARD_GPIOCHIP_LABEL})

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

function BXP100::set_power_state() {
        local slot
        local state
        local dip_switch_state

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

        dip_switch_state=$(gpio_get_value_i2c_gpiochip_libgpiod ${DIP_SWITCH_SELECT_TBL[$slot]} ${IO_BOARD_GPIOCHIP_LABEL})
        if [ "${dip_switch_state}" == "0" ]; then
                echo "Operation not supported. The DIP switch is under WiFi mode."
                exit 0
        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

        gpio_set_value_i2c_gpiochip_libgpiod ${POWER_CONTROL_TBL[$slot]} $state ${IO_BOARD_GPIOCHIP_LABEL}

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

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

        if [[ ${#RESET_PIN_TBL[@]} -eq 0 ]]; then
                echo "Reset pin is not defined"
                exit 1
        fi

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

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

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

        if [[ ${#RESET_PIN_TBL[@]} -eq 0 ]]; then
                echo "Reset pin is not defined"
                exit 1
        fi

        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

        gpio_set_value_i2c_gpiochip_libgpiod ${RESET_PIN_TBL[$slot]} $state ${IO_BOARD_GPIOCHIP_LABEL}

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

function BXP100::get_dip_switch_state() {
        local slot

        slot=${1}
        state=$(gpio_get_value_i2c_gpiochip_libgpiod ${DIP_SWITCH_SELECT_TBL[$slot]} ${IO_BOARD_GPIOCHIP_LABEL})
        echo "Slot #${slot} dip switch status is ${DIP_SWITCH_STATE[$state]}"
}

function BXPA101M::profile() {
        NUM_OF_MODULE_SLOTS=1
        POWER_CONTROL_TBL=(102)
        RESET_PIN_TBL=(67)
        DISABLE_PIN_TBL=(90)
        DIP_SWITCH_SELECT_TBL=(86)
        MPCIE_ALIVE_GPIO_TBL=(27)
        SIM_CARD_SELECT_TBL=()
}

function BXPA101M::init() {
        return 0
}

function BXPA101M::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 BXPA101M::set_power_state() {
        local slot
        local state
        local dip_switch_state

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

        dip_switch_state=$(get_dip_switch_state_it87 ${DIP_SWITCH_SELECT_TBL[$slot]})
        if [ "${dip_switch_state}" == "0" ]; then
                echo "Operation not supported. The DIP switch is under WiFi mode."
                exit 0
        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

        set_power_state_it87 ${POWER_CONTROL_TBL[$slot]} $state

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

function BXPA101M::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 BXPA101M::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 BXPA101M::get_dip_switch_state() {
        local slot
        local state

        slot="$1"
        state=$(get_dip_switch_state_it87 ${DIP_SWITCH_SELECT_TBL[$slot]})

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

function BXPA101M::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 BXPA101M::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}"
}

function BXPA101M::get_mode_state() {
        local slot
        local state
        local pwr_state

        slot=${1}

        state=$(get_mpcie_mode_state_it87_via_libgpiod ${MPCIE_ALIVE_GPIO_TBL[$slot]})
        pwr_state=$(get_power_state_it87 ${POWER_CONTROL_TBL[$slot]})

        if [[ "$pwr_state" == "0" ]]; then
                echo "Please power on slot."
                exit 1
        fi

        # Reverse logic in the circuit
        case "$state" in
        0) state="active";;
        1) state="inactive";;
        *) state="unknown";;
        esac

        echo "Module status on slot #${slot}: $state"
}


function get_mpcie_mode_state_it87_via_libgpiod() {
        local gpio_pin
        local gpc_name
        local state

        gpc_name=$(gpio_get_gpiochip_name gpio_it87)
        gpio_pin=$(gpc_it8786_remap $1)
        state=$(gpio_get_value_libgpiod $gpio_pin $gpc_name)
        echo $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_reset_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}"
}

function RKPA110::profile() {
        RKP110::profile
}

function RKPA110::init() {
        RKP110::init
}

function RKPA110::get_power_state() {
        local slot

        slot="$1"
        RKP110::get_power_state "${slot}"
}

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

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

        RKP110::set_power_state "${slot}" "${state}"
}

function RKPA110::get_reset_state() {
        local slot

        slot="$1"
        RKP110::get_reset_state "${slot}"
}

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

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

        RKP110::set_reset_state "${slot}" "${state}"
}

function RKPA110::get_dip_switch_state() {
        local slot

        slot="$1"
        RKP110::get_dip_switch_state "${slot}"
}

function RKPC110::profile() {
        RKP110::profile
}

function RKPC110::init() {
        RKP110::init
}

function RKPC110::get_power_state() {
        local slot

        slot="$1"
        RKP110::get_power_state "${slot}"
}

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

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

        RKP110::set_power_state "${slot}" "${state}"
}

function RKPC110::get_reset_state() {
        local slot

        slot="$1"
        RKP110::get_reset_state "${slot}"
}

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

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

        RKP110::set_reset_state "${slot}" "${state}"
}

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

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

        RKP110::set_reset_state "${slot}" "${state}"
}

function RKPC110::get_dip_switch_state() {
        local slot

        slot="$1"
        RKP110::get_dip_switch_state "${slot}"
}

function RKP110::profile() {
        NUM_OF_MODULE_SLOTS=""
        IO_BOARD_GPIOCHIP_LABEL=""
        IO_BOARD_GPIO_TBL=(47 50 63)

        IO_BOARD_DUAL_WIRELESS_GPIO_VAL=(1 1 0)
        IO_BOARD_DUAL_WIRELESS_I2C_ADDR="0x27"

        POWER_CONTROL_TBL=()
        RESET_PIN_TBL=()
        DISABLE_PIN_TBL=()
        DIP_SWITCH_SELECT_TBL=()
        MPCIE_ALIVE_GPIO_TBL=()
        SIM_CARD_SELECT_TBL=()
}

function RKP110::init() {
        local io_board_gpio_pins
        local io_board_gpio_val
        local gpc_name
        local ret

        io_board_gpio_pins=(
                $(gpc_it8786_remap ${IO_BOARD_GPIO_TBL[0]})
                $(gpc_it8786_remap ${IO_BOARD_GPIO_TBL[1]})
                $(gpc_it8786_remap ${IO_BOARD_GPIO_TBL[2]})
        )

        # Determine I/O board by GPIO truth table
        gpc_name=$(gpio_get_gpiochip_name gpio_it87)
        io_board_gpio_val[0]=$(gpio_get_value_libgpiod ${io_board_gpio_pins[0]} $gpc_name)
        io_board_gpio_val[1]=$(gpio_get_value_libgpiod ${io_board_gpio_pins[1]} $gpc_name)
        io_board_gpio_val[2]=$(gpio_get_value_libgpiod ${io_board_gpio_pins[2]} $gpc_name)

        if [[ "${IO_BOARD_DUAL_WIRELESS_GPIO_VAL[*]}" == "${io_board_gpio_val[*]}" ]]; then
                ret=$(bind_i2c_driver "CP2112" "pca9535" $IO_BOARD_DUAL_WIRELESS_I2C_ADDR)
                if [[ $ret -ne 0 ]]; then
                        echo "Bind i2c device fail"
                        exit $ret
                fi
                IO_BOARD_GPIOCHIP_LABEL=$(get_i2c_slave_gpiochip_label "CP2112" ${IO_BOARD_DUAL_WIRELESS_I2C_ADDR})
                NUM_OF_MODULE_SLOTS=2
                POWER_CONTROL_TBL=(1 6)
                RESET_PIN_TBL=(2 7)
                DISABLE_PIN_TBL=()
                DIP_SWITCH_SELECT_TBL=(0 5)
                MPCIE_ALIVE_GPIO_TBL=()
                SIM_CARD_SELECT_TBL=""
        else
                echo "Can not recognize I/O board"
                exit 1
        fi
}

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

        slot="$1"

        state=$(gpio_get_value_i2c_gpiochip_libgpiod ${POWER_CONTROL_TBL[$slot]} ${IO_BOARD_GPIOCHIP_LABEL})

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

function RKP110::set_power_state() {
        local slot
        local state
        local dip_switch_state

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

        dip_switch_state=$(gpio_get_value_i2c_gpiochip_libgpiod ${DIP_SWITCH_SELECT_TBL[$slot]} ${IO_BOARD_GPIOCHIP_LABEL})
        if [ "${dip_switch_state}" == "0" ]; then
                echo "Operation not supported. The DIP switch is under WiFi mode."
                exit 0
        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

        gpio_set_value_i2c_gpiochip_libgpiod ${POWER_CONTROL_TBL[$slot]} $state ${IO_BOARD_GPIOCHIP_LABEL}

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

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

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

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

function RKP110::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

        gpio_set_value_i2c_gpiochip_libgpiod ${RESET_PIN_TBL[$slot]} $state ${IO_BOARD_GPIOCHIP_LABEL}

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

function RKP110::get_dip_switch_state() {
        local slot

        slot=${1}
        state=$(gpio_get_value_i2c_gpiochip_libgpiod ${DIP_SWITCH_SELECT_TBL[$slot]} ${IO_BOARD_GPIOCHIP_LABEL})
        echo "Slot #${slot} dip switch status is ${DIP_SWITCH_STATE[$state]}"
}

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

        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_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_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_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 set_reset_state_it87() {
        local gpio_pin
        local state_val

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

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

function set_reset_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 reset 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 reset state failed"
                exit $ret
        fi
}

function set_reset_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 reset 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_dip_switch_state_it87() {
        local gpio_pin
        local dip_switch_state

        gpio_pin="$1"

        if [[ "${OS_ID}" == "centos" ]]; then
                dip_switch_state=$(get_dip_switch_state_it87_via_sysfs $gpio_pin)
        else
                dip_switch_state=$(get_dip_switch_state_it87_via_libgpiod $gpio_pin)
        fi

        echo $dip_switch_state
}

function get_dip_switch_state_it87_via_sysfs() {
        local gpio
        local dip_switch_state

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

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

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

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

        echo $dip_switch_state
}

function get_dip_switch_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)
        dip_switch_state=$(gpio_get_value_libgpiod $gpio $gpc_name)
        [[ $? -ne 0 ]] && ret=1

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

        echo $dip_switch_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 $@
