#!/bin/bash
# ---------------------------------------------------------------------------
# NAME
#
#     ConfigOctalUartLine - configures the octal UART transceiver for a
#                           single port
#
# SYNOPSIS
#
#     sudo ConfigOctalUartLine line-number protocol
#
# DESCRIPTION
#
#     The octal UART uses configurable transceivers that can be set to
#     either RS-232, RS-422, RS-485 or turned off.  This script configures
#     the protocol on a single line.
#
#     line-number is a value in the range of 3..8 (/dev/ttyLX2 - /dev/ttyLX7)
#
#     protocol can be one of:
#
#         rs232:   configures the transceiver for RS-232
#         rs422:   configures the transceiver for RS-422
#         rs485:   configures the transceiver for RS-485
#         off:     disables the transceiver
#
#     Note that the first two ports (/dev/ttyLX0 and /dev/ttyLX1) are
#     configured in hardware for RS-232
#
# EXAMPLES
#
#     Configure the 3rd port for RS-232:
#
#         sudo ConfigOctalUartLine 3 rs232
#
#     Configure the last port for RS-485:
#
#         sudo ConfigOctalUartLine 8 rs485
#
# ---------------------------------------------------------------------------

# determines if the parameter is a valid state name; a return value of
# 0 indicates a good token
function ValidState()
{
	local __stateName="$1"
	local __retval

	shopt -s nocasematch

	if [ -z "$__stateName" ]
	then
		__stateName="OFF"
	fi

	case $__stateName in
		RS232|RS422|RS485|OFF)
			__retval="0"
			;;
		*)
			echo 1>&2 "Invalid state name $__stateName"
			__retval="1"
			;;
	esac

	shopt -u nocasematch
	return $__retval
}

# converts a state name to a nibble value (echoed); the return
# value is 0 on success
function NibbleValue()
{
	local __stateName="$1"
	local __retval

	shopt -s nocasematch

	if [ -z "$__stateName" ]
	then
		__stateName="OFF"
	fi

	case $__stateName in
		RS232)
			echo 8
			__retval="0"
			;;
		RS422)
			echo 9
			__retval="0"
			;;
		RS485)
			echo 13
			__retval="0"
			;;
		OFF)
			echo 0
			__retval="0"
			;;
		*)
			echo 1>&2 "Invalid state name $__stateName"
			__retval="1"
			;;
	esac

	shopt -u nocasematch
	return $__retval
}

# exit if not run as root
CURUSER=`whoami`

if [ "$CURUSER" != "root" ]
then
	echo "This script must be run as root "
	exit 1
fi

# alias parameters and check them
lineNumber="$1"
portState="$2"

if [ -z "$lineNumber" ]
then
	echo "Line number was not specified"
	exit 1
fi

lineNumberOutOfRange=$(( ($lineNumber < 3) || ($lineNumber > 8) ))

if [ "$lineNumberOutOfRange" -ne 0 ]
then
	echo "Line number ($lineNumber) expected range is 3..8"
	exit 1
fi

if [ -z "$portState" ]
then
	echo "Port state was not specified"
	exit 1
fi

# any commands that fail will terminate the script
set -e

ValidState "$portState"

# alias addresses
nibbleValue=$( NibbleValue "$portState" )
lineNumber=$(( $lineNumber-3 ))
chipAddress=$(( 0x39 + ($lineNumber >> 1) ))
shiftCount=$(( ($lineNumber & 1)*4 ))
affectMask=$(( 15 << $shiftCount ))
updateMask=$(( nibbleValue << $shiftCount ))

# set the direction of all registers to output (I'm going to write them)
i2cset -y 2 0x39 0x03 0x00
i2cset -y 2 0x3A 0x03 0x00
i2cset -y 2 0x3B 0x03 0x00

# update the mask for the port as necessary
i2cset -y -mask $affectMask 2 $chipAddress 0x01 $updateMask

# show the resulting states
base=`basename $0`
resultA=`i2cget -y 2 0x39 0x01`
resultB=`i2cget -y 2 0x3A 0x01`
resultC=`i2cget -y 2 0x3B 0x01`
echo "$base: $resultA $resultB $resultC"

exit 1

