#!/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:
  audio        Manages the audio output
  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
}

### audio wrapper

audio_usage() {
cat << EOF

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

Available Commands:
  Get the speaker status
    $ mx-interface-mgmt audio get_speaker_status
  Set the speaker status
    $ mx-interface-mgmt audio set_speaker_status <speaker_status>

Arguments:
  speaker_status: external|embedded

EOF
}

audio_get_speaker_status() {
	ret="$($TOOLS_PATH/mx-audio-ctl -s)"
	case $ret in
		external | embedded)
			echo "$ret"
			;;
		*"DIP SW forced"*)
			echo "external"
			;;
		*)
			echo "Error: unknown speaker status"
			exit 1
			;;
	esac
}

audio_set_speaker_status() {
	local status="$1"
	case $status in
		external | embedded)
			;;
		*)
			echo "Error: unknown speaker status"
			exit 1
			;;
	esac

	$TOOLS_PATH/mx-audio-ctl -s "$status" >/dev/null 2>&1
	if [[ $? -ne 0 ]]; then
		echo "Error: set speaker status failed"
		exit 1
	fi
}

audio_wrapper() {
	if [[ ! -f "$TOOLS_PATH/mx-audio-ctl" ]]; then
		echo "Error: audio control is not available"
		exit 1
	fi
	case $2 in
		-h | --help | help)
			audio_usage
			exit 0
			;;
		get_speaker_status)
			if [[ ! $# -eq 2 ]]; then
				echo "Error: invalid audio command, please check help menu"
				exit 1
			fi
			audio_get_speaker_status
			;;
		set_speaker_status)
			if [[ ! $# -eq 3 ]]; then
				echo "Error: invalid audio command, please check help menu"
				exit 1
			fi
			audio_set_speaker_status "$3"
			;;
		*)
			echo "Error: invalid audio command, please check help menu"
			exit 1
			;;
	esac
}

### 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
		audio)
			audio_wrapper "$@"
			;;
		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 $@
