#!/bin/bash
#
# Copyright (C) 2024 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    Henry LC Chen <HenryLC.Chen@moxa.com>
# Description:
#   A wrapper to control io like Moxa Computer Interface Manager (MCIM).

TOOLS_PATH="/usr/sbin"

usage() {
cat << EOF

 The Moxa Computer Interface Manager (MCIM) is a tool designed to simplify
 user control of peripherals. The design of MCIM aims to enhance
 operational efficiency, enabling users to conveniently handle tasks
 related to peripheral devices.
Usage:
  mx-interface-mgmt [command]

Available Commands:
  cellular     Manages the cellular modem
  dio          Manages digital inputs and outputs for external devices
  led          Manages LED indicators
  relay        Manages the relay mode
  serialport   Manages the serial port
  input_power  Manages the power input state
  usb_power    Manages the usb power state

Flags:
  -h, --help   help for mx-interface-mgmt

Use "mx-interface-mgmt [command] --help" for more information about a command.

EOF
}

### cellular wrapper

cellular_usage() {
cat << EOF

Usage:
  mx-interface-mgmt cellular <NAME> <COMMAND> [ARG]

Available Commands:
  Get the power state of a cellular
    $ mx-interface-mgmt cellular <cellular_name> get_power
  Set the power state of a cellular
    $ mx-interface-mgmt cellular <cellular_name> set_power <power_state>
  Get the SIM slot of a cellular
    $ mx-interface-mgmt cellular <cellular_name> get_sim_slot
  Set the SIM slot of a cellular
    $ mx-interface-mgmt cellular <cellular_name> set_sim_slot <sim_slot>

Arguments:
  cellular_name: The slot number of cellular (e.g. Cellular1)
  power_state: on|off
  sim_slot: 1|2

EOF
}

convert_cellular_name() {
	cell_slot="$1"
	prefix="Cellular"
	cell_slot=${cell_slot#"$prefix"}
	cell_slot=$((cell_slot - 1))

	echo $cell_slot
}

cellular_get_power() {
	cell_slot=$(convert_cellular_name "$1")
	if [[ $cell_slot -lt 0 ]]; then
		echo "Error: invalid cellular name"
		exit 1
	fi

	ret="$($TOOLS_PATH/mx-module-ctl -s "$cell_slot" -p | awk -F' ' '{print $6}')"
	case $ret in
		low)
			echo "off"
			;;
		high)
			echo "on"
			;;
		*)
			echo "Error: unknown power status"
			exit 1
			;;
	esac
}

cellular_set_power() {
	cell_slot=$(convert_cellular_name "$1")
	power_state="$2"
	if [[ $cell_slot -lt 0 ]]; then
		echo "Error: invalid cellular name"
		exit 1
	fi

	case $power_state in
		off)
			power_state="low"
			;;
		on)
			power_state="high"
			;;
		*)
			echo "Error: unknown power status"
			exit 1
			;;
	esac

	# check LTE/WiFi module dip status
	$TOOLS_PATH/mx-module-ctl -s "$cell_slot" --dip | grep -q low
	if [[ $? -eq 0 ]]; then
		echo "Socket power can't be controlled due to function select"
		exit 0
	fi

	$TOOLS_PATH/mx-module-ctl -s "$cell_slot" -p "$power_state" >/dev/null 2>&1
	if [[ $? -ne 0 ]]; then
		echo "Error: set power state failed"
		exit 1
	fi
}

cellular_get_sim_slot() {
	cell_slot=$(convert_cellular_name "$1")
	if [[ $cell_slot -lt 0 ]]; then
		echo "Error: invalid cellular name"
		exit 1
	fi

	ret="$($TOOLS_PATH/mx-module-ctl -s "$cell_slot" -i | awk -F' ' '{print $7}')"
	case $ret in
		'#1')
			echo "1"
			;;
		'#2')
			echo "2"
			;;
		*)
			echo "Error: SIM slot control is not allowed"
			;;
	esac
}

cellular_set_sim_slot() {
	cell_slot=$(convert_cellular_name "$1")
	sim_slot="$2"
	if [[ $cell_slot -lt 0 ]]; then
		echo "Error: invalid cellular name"
		exit 1
	fi

	# check SIM slot control is allowed or not
	$TOOLS_PATH/mx-module-ctl -s "$cell_slot" -i | grep -q "not supported"
	if [[ $? -eq 0 ]]; then
		echo "Error: SIM slot control is not allowed"
		exit 0
	fi

	$TOOLS_PATH/mx-module-ctl -s "$cell_slot" -i "$sim_slot" >/dev/null 2>&1
	if [[ $? -ne 0 ]]; then
		echo "Error: set SIM slot failed"
		exit 1
	fi
}

cellular_wrapper() {
	if [[ ! -f  "$TOOLS_PATH/mx-module-ctl" ]]; then
		echo "Error: cellular control is not available"
		exit 1
	fi
	case $2 in
		-h | --help | help)
			cellular_usage
			exit 0
			;;
		*)
			case $3 in
			get_power)
				if [[ ! $# -eq 3 ]]; then
					echo "Error: invalid cellular command, please check help menu"
					exit 1
				fi
				cellular_get_power "$2"
				;;
			set_power)
				if [[ ! $# -eq 4 ]]; then
					echo "Error: invalid cellular command, please check help menu"
					exit 1
				fi
				cellular_set_power "$2" "$4"
				;;
			get_sim_slot)
				if [[ ! $# -eq 3 ]]; then
					echo "Error: invalid cellular command, please check help menu"
					exit 1
				fi
				cellular_get_sim_slot "$2"
				;;
			set_sim_slot)
				if [[ ! $# -eq 4 ]]; then
					echo "Error: invalid cellular command, please check help menu"
					exit 1
				fi
				cellular_set_sim_slot "$2" "$4"
				;;
			*)
				echo "Error: invalid cellular command, please check help menu"
				exit 1
				;;
		esac
	esac
}

### dio wrapper

dio_usage() {
cat << EOF

Usage:
  mx-interface-mgmt dio <NAME> <COMMAND> [ARG]

Available Commands:
  Get the state of a dio
    $ mx-interface-mgmt dio <dio_name> get_state
  Set the state of a dio
    $ mx-interface-mgmt dio <dio_name> set_state <dio_state>

Arguments:
  dio_name: The name of dio (e.g. DI1、DO1)
  dio_state: low|high

EOF
}

dio_get_state() {
	dio_direction=$(echo "$1" | cut -c1-2)
	dio_num=$(echo "$1" | cut -c3-)
	dio_num=$((dio_num - 1))
	if [[ $dio_num -lt 0 ]]; then
		echo "Error: invalid DI/DO number"
		exit 1
	fi

	case $dio_direction in
		DI)
			$TOOLS_PATH/mx-dio-ctl -i "$dio_num" >/dev/null 2>&1 || { echo 'Error: invalid DI/DO number'; exit 1; }
			state="$($TOOLS_PATH/mx-dio-ctl -i "$dio_num" | awk -F' ' '{print $5}')"
			;;
		DO)
			$TOOLS_PATH/mx-dio-ctl -o "$dio_num" >/dev/null 2>&1 || { echo 'Error: invalid DI/DO number'; exit 1; }
			state="$($TOOLS_PATH/mx-dio-ctl -o "$dio_num" | awk -F' ' '{print $5}')"
			;;
		*)
			echo "Error: Unknown direction"
			exit 1
			;;
	esac

	case $state in
		HIGH)
			echo "high"
			;;
		LOW)
			echo "low"
			;;
		*)
			echo "Error: Unknown state"
			exit 1
			;;
	esac
}

dio_set_state() {
	dio_direction=$(echo "$1" | cut -c1-2)
	dio_num=$(echo "$1" | cut -c3-)
	dio_num=$((dio_num - 1))
	if [[ $dio_num -lt 0 ]]; then
		echo "Error: invalid DI/DO number"
		exit 1
	fi

	case $dio_direction in
		DI)
			echo "Error: DI cannot set state"
			exit 1
			;;
		DO)
			case "$2" in
				high)
					$TOOLS_PATH/mx-dio-ctl -o "$dio_num" -s 1 >/dev/null 2>&1
					;;
				low)
					$TOOLS_PATH/mx-dio-ctl -o "$dio_num" -s 0 >/dev/null 2>&1
					;;
				*)
					echo "Error: Unknown state"
					exit 1
					;;
			esac
			;;
		*)
			echo "Error: Unknown direction"
			exit 1
			;;
	esac

	if [[ $? -ne 0 ]]; then
		echo "Error: set DO state failed"
		exit 1
	fi
}

dio_wrapper() {
	if [[ ! -f  "$TOOLS_PATH/mx-dio-ctl" ]]; then
		echo "Error: dio control is not available"
		exit 1
	fi
	case $2 in
		-h | --help | help)
			dio_usage
			exit 0
			;;
		*)
			case $3 in
			get_state)
				if [[ ! $# -eq 3 ]]; then
					echo "Error: invalid dio command, please check help menu"
					exit 1
				fi
				dio_get_state "$2"
				;;
			set_state)
				if [[ ! $# -eq 4 ]]; then
					echo "Error: invalid dio command, please check help menu"
					exit 1
				fi
				dio_set_state "$2" "$4"
				;;
			*)
				echo "Error: invalid dio command, please check help menu"
				exit 1
				;;
		esac
	esac
}

### led wrapper

led_usage() {
cat << EOF

Usage:
  mx-interface-mgmt led <NAME> <COMMAND> [ARG]

Available Commands:
  Get the state of a LED
    $ mx-interface-mgmt led <led_name> get_state
  Set the state of a LED
    $ mx-interface-mgmt led <led_name> set_state <led_state>

Arguments:
  led_name: The number of LED (e.g. 0, 1, 2, ......)
  led_state: on|off

EOF
}

led_get_state() {
	led_num="$1"
	led_state=""

	led_state="$($TOOLS_PATH/mx-led-ctl -i "$1" | awk -F' ' '{print $4}')"
	case $led_state in
		off | on)
			echo "$led_state"
			;;
		*)
			echo "Error: Unknown LED state"
			exit 1
			;;
	esac
}

led_set_state() {
	led_num="$1"
	led_state="$2"

	$TOOLS_PATH/mx-led-ctl -i "$1" "$2" >/dev/null 2>&1
	if [[ $? -ne 0 ]]; then
		echo "Error: set LED state failed"
		exit 1
	fi
}

led_wrapper() {
	if [[ ! -f  "$TOOLS_PATH/mx-led-ctl" ]]; then
		echo "Error: led control is not available"
		exit 1
	fi
	case $2 in
		-h | --help | help)
			led_usage
			exit 0
			;;
		*)
			case $3 in
			get_state)
				if [[ ! $# -eq 3 ]]; then
					echo "Error: invalid led command, please check help menu"
					exit 1
				fi
				led_get_state "$2"
				;;
			set_state)
				if [[ ! $# -eq 4 ]]; then
					echo "Error: invalid led command, please check help menu"
					exit 1
				fi
				led_set_state "$2" "$4"
				;;
			*)
				echo "Error: invalid led command, please check help menu"
				exit 1
				;;
		esac
	esac
}

### relay wrapper

relay_usage() {
cat << EOF

Usage:
  mx-interface-mgmt relay <NAME> <COMMAND> [ARG]

Available Commands:
  Get the mode of a relay
    $ mx-interface-mgmt relay <relay_name> get_mode
  Set the mode of a relay
    $ mx-interface-mgmt relay <relay_name> set_mode <relay_mode>

Arguments:
  relay_name: The number of relay (e.g. 0, 1, 2, ......)
  relay_mode: 0|1
              0 --> set to NC (Normal Closed) mode
              1 --> set to NO (Normal Open) mode

EOF
}

relay_get_mode() {
	$TOOLS_PATH/mx-relay-ctl -p "$1"
}

relay_set_mode() {
	$TOOLS_PATH/mx-relay-ctl -p "$1" -m "$2"
}

relay_wrapper() {
	if [[ ! -f  "$TOOLS_PATH/mx-relay-ctl" ]]; then
		echo "Error: relay control is not available"
		exit 1
	fi
	case $2 in
		-h | --help | help)
			relay_usage
			exit 0
			;;
		*)
			case $3 in
			get_mode)
				if [[ ! $# -eq 3 ]]; then
					echo "Error: invalid relay command, please check help menu"
					exit 1
				fi
				relay_get_mode "$2"
				;;
			set_mode)
				if [[ ! $# -eq 4 ]]; then
					echo "Error: invalid relay command, please check help menu"
					exit 1
				fi
				relay_set_mode "$2" "$4"
				;;
			*)
				echo "Error: invalid relay command, please check help menu"
				exit 1
				;;
		esac
	esac
}

### input_power wrapper

input_power_usage() {
cat << EOF

Usage:
  mx-interface-mgmt input_power <NAME> <COMMAND> [ARG]

Available Commands:
  Get the state of a input_power
    $ mx-interface-mgmt input_power <input_power_name> get_state

Arguments:
  input_power_name: The number of input_power (e.g. 0, 1, 2, ......)

EOF
}

input_power_get_state() {
	$TOOLS_PATH/mx-input-power-state -i "$1"
}

input_power_wrapper() {
	if [[ ! -f  "$TOOLS_PATH/mx-input-power-state" ]]; then
		echo "Error: input_power command is not available"
		exit 1
	fi
	case $2 in
		-h | --help | help)
			input_power_usage
			exit 0
			;;
		*)
			case $3 in
			get_state)
				if [[ ! $# -eq 3 ]]; then
					echo "Error: invalid input_power command, please check help menu"
					exit 1
				fi
				input_power_get_state "$2"
				;;
			*)
				echo "Error: invalid input_power command, please check help menu"
				exit 1
				;;
		esac
	esac
}

### usb_power wrapper

usb_power_usage() {
cat << EOF

Usage:
  mx-interface-mgmt usb_power <NAME> <COMMAND> [ARG]

Available Commands:
  Get the usb power state of a port
    $ mx-interface-mgmt usb_power <usb_port> get_state
  Set the usb power state of a port
    $ mx-interface-mgmt usb_power <usb_port> set_state <state>

Arguments:
  usb_port: Get USB port power state
                        0: front
                        1: rear
                        2: internal
  state: Set USB port power state
                        0: off
                        1: on

EOF
}

usb_power_get_state() {
	$TOOLS_PATH/mx-usb-power-ctl -i "$1"
}

usb_power_set_state() {
	$TOOLS_PATH/mx-usb-power-ctl -i "$1" -s "$2"
}

usb_power_wrapper() {
	if [[ ! -f  "$TOOLS_PATH/mx-usb-power-ctl" ]]; then
		echo "Error: usb_power command is not available"
		exit 1
	fi
	case $2 in
		-h | --help | help)
			usb_power_usage
			exit 0
			;;
		*)
			case $3 in
			get_state)
				if [[ ! $# -eq 3 ]]; then
					echo "Error: invalid usb_power command, please check help menu"
					exit 1
				fi
				usb_power_get_state "$2"
				;;
			set_state)
				if [[ ! $# -eq 4 ]]; then
					echo "Error: invalid usb_power command, please check help menu"
					exit 1
				fi
				usb_power_set_state "$2" "$4"
				;;
			*)
				echo "Error: invalid usb_power command, please check help menu"
				exit 1
				;;
		esac
	esac
}


### serialport wrapper

serialport_usage() {
cat << EOF

Usage:
  mx-interface-mgmt serialport <NAME> <COMMAND> [ARG]

Available Commands:
  Get the interface of a serial port
    $ mx-interface-mgmt serialport <serialport_name> get_interface
  Set the interface of a serial port
    $ mx-interface-mgmt serialport <serialport_name> set_interface <serial_interface>

Arguments:
  serialport_name: The interface of serial port (e.g. COM1, COM2, ...)
  serial_interface: RS-232/RS-485-2W/RS-422/RS-485-4W

EOF
}

convert_serialport_name() {
	serial_slot="$1"
	prefix="COM"
	serial_slot=${serial_slot#"$prefix"}
	serial_slot=$((serial_slot - 1))

	echo $serial_slot
}

serialport_get_interface() {
	serial_slot=$(convert_serialport_name "$1")
	if [[ $serial_slot -lt 0 ]]; then
		echo "Error: invalid serialport name"
		exit 1
	fi

	$TOOLS_PATH/mx-uart-ctl -p "$serial_slot" >/dev/null 2>&1 || { echo 'Error: invalid serialport name'; exit 1; }
	$TOOLS_PATH/mx-uart-ctl -p "$serial_slot" | awk -F' ' '{print $5}'
}

serialport_set_interface() {
	serial_slot=$(convert_serialport_name "$1")
	serial_mode="$2"
	if [[ $serial_slot -lt 0 ]]; then
		echo "Error: invalid serialport name"
		exit 1
	fi

	$TOOLS_PATH/mx-uart-ctl -p "$serial_slot" >/dev/null 2>&1 || { echo 'Error: invalid serialport name'; exit 1; }

	case $serial_mode in
		RS-232)
			serial_mode="0"
			;;
		RS-485-2W)
			serial_mode="1"
			;;
		RS-422)
			serial_mode="2"
			;;
		RS-485-4W)
			serial_mode="3"
			;;
		*)
			echo "Error: unknown serial mode"
			exit 1
			;;
	esac

	$TOOLS_PATH/mx-uart-ctl -p "$serial_slot" -m "$serial_mode" >/dev/null 2>&1
	if [[ $? -ne 0 ]]; then
		echo "Error: set serialport mode failed"
		exit 1
	fi
}

serialport_wrapper() {
	if [[ ! -f  "$TOOLS_PATH/mx-uart-ctl" ]]; then
		echo "Error: serial port mode control is not available"
		exit 1
	fi
	case $2 in
		-h | --help | help)
			serialport_usage
			exit 0
			;;
		*)
			case $3 in
			get_interface)
				if [[ ! $# -eq 3 ]]; then
					echo "Error: invalid serialport command, please check help menu"
					exit 1
				fi
				serialport_get_interface "$2"
				;;
			set_interface)
				if [[ ! $# -eq 4 ]]; then
					echo "Error: invalid serialport command, please check help menu"
					exit 1
				fi
				serialport_set_interface "$2" "$4"
				;;
			*)
				echo "Error: invalid serialport command, please check help menu"
				exit 1
				;;
		esac
	esac
}

main() {
	### Parameter check
	if [[ $# -lt 1 ]]; then
		usage
		exit 0
	fi

	case $1 in
		cellular)
			cellular_wrapper "$@"
			;;
		dio)
			dio_wrapper "$@"
			;;
		led)
			led_wrapper "$@"
			;;
		relay)
			relay_wrapper "$@"
			;;
		serialport)
			serialport_wrapper "$@"
			;;
		input_power)
			input_power_wrapper "$@"
			;;
		usb_power)
			usb_power_wrapper "$@"
			;;
		-h | --help)
			usage
			exit 0
			;;
		*)
			echo "Error: unknown command: $1"
			exit 1
			;;
	esac
}

main $@
