#!/bin/sh
#############################################################
path="${0%/*}"
. "$path/inc/gwhw.inc"
. "$path/inc/dali.inc"

needRoot
daliI2COK

usage() {
	die 'gwhw dali mem [short/group/br] [desc]'
}

ADDR="${1:-0}"
shift
DESC="$@"

# example $DESC: B2 L2 W1 0xAA R2 R2 R2 L10 R2 R2@15 r2@0x55
# example $DESC: B2 L2 W1 0xAA R1 R4

[ -z "${ADDR}" ] && usage
[ -z "${DESC}" ] && usage

ADDRHEX="$(addrToHex "$ADDR" 1)"
#############################################################

QueryGear() {
	printf "0x02 ${ADDRHEX} 0x91\n"
	printf "# <A> 0xff Y\n"
}

SetBank() {
	# $1: data byte
	printf "0x00 0xc3 0x%02x\n" "$1"
}

SetLocation() {
	# $1: data byte
	printf "0x00 0xa3 0x%02x\n" "$1"
}

ReadBytes() {
	# $1: Amount
	for i in $(seq "$1"); do
		printf "0x02 ${ADDRHEX} 0xc5\n"
	done
	printf "# <N>\n"
}

EnableWrite() {
	printf "0x01 ${ADDRHEX} 0x81\n"
}

WriteByte() {
	# $1: data byte
	printf "0x02 0xc7 0x%02x\n" "$1"
	printf "# <A> 0x%02x %d\n" "$1" "$1"
}

QueryDTR0() {
	# $1: expected value
	local pos
	pos="$1"
	[ "$(( pos ))" -gt 255 ] && pos=255
	printf "0x02 ${ADDRHEX} 0x98\n"
	printf "# <A> 0x%02x %d\n" "$pos" "$pos"
}

GenTableSeq() {
	SetLocation 0
	for i in $(seq 16); do
		ReadBytes 16
	done
}

parse_desc() {
	POS="0xff"
	QueryGear
	while : ; do
		v="$(echo "${1}" | tr '[:upper:]' '[:lower:]')"
		case "$v" in
		b*)
			SetBank "$(( ${v:1} ))"
		;;
		l*)
			POS="$(( ${v:1} ))"
			SetLocation "$POS"
		;;
		qg)
			QueryGear
		;;
		ql)
			QueryDTR0 "$POS"
		;;
		r)
			ReadBytes 1
			POS="$(( POS + 1 ))"
		;;
		r*)
			ReadBytes "$(( ${v:1} ))"
			POS="$(( POS + ${v:1} ))"
		;;
		w)
			EnableWrite
		;;
		0x[0-9a-f]|0x[0-9a-f][0-9a-f])
			WriteByte "$((v))"
			POS="$(( POS + 1 ))"
		;;
		[0-9]|[0-9][0-9]|[0-2][0-9][0-9])
			WriteByte "$((v))"
			POS="$(( POS + 1 ))"
		;;
		table)
			GenTableSeq
		;;
		*)
			break
		;;
		esac
		shift
	done
	QueryDTR0 "$POS"
}

daliTXRXSeq() {
	if "$MSPDALI"; then
		awk '/^#/{print;next}{print p;p=$0}END{print p}' \
		| mspdali \
		| awk '/^>/{p=and($2,2)}p&&/^</{print $2, $3, $4, $5}/^#/{print}'
		return
	fi

	# TODO: more generic
	A="${DSLOT0}"; B="${DSLOT1}"
	read a b c
	daliTX3B $a $b $c $B; usleep 1000
	C=$A; A=$B; B=$C
	pa=$a
	# TODO FIX: Things may get executed in different order,
	#           not good for sequential memory reads and writes.
	# MSP430 code should check for age or we should transmit
	# next one only after previous one has started transmitting,
	# but this would be too slow, if done entirely in shell script.
	while read a b c rest; do
		if [ "${a::1}" = "#" ]; then
			echo "$a $b $c $rest"
			continue
		fi
		daliTX3B $a $b $c $B
		[ "$(( pa & 2 ))" = "2" ] && daliRX4BW $A || waitTX $A
		C=$A; A=$B; B=$C
		pa=$a
	done
	daliRX4BW $A
}

format1() {
	newline=false
	checkVal=
	while read a b c d; do
		if [ "${a::1}" = "#" ]; then
			case "$b" in
				"<A>")
					checkVal="$c"
				;;
				"<N>")
					newline=true
			esac
			continue
		fi
		if [ -n "$checkVal" ]; then
			case "$a$b$c$d" in
				????0xc7*) printf "WRITE $c "
				;;
				????????0x91*) printf "QUERY GEAR "
				;;
				????????0x98*) printf "QUERY DTR0 "
				;;
				*) printf "XX "
				;;
			esac
			case "$a" in
				0x3*) d="timeout"
			esac
			[ "$checkVal" = "$d" ] || die "Expected '$checkVal', got '$d'"
			checkVal=
			printf "OK\n"
			continue
		fi
		
		# Data read
		case "$a$b$c$d" in
			0x2*) printf "${d:2} "
			;;
			0x3*) printf "TT "
			;;
			*) printf "XX "
			;;
		esac
		
		$newline && printf "\n"
		newline=false
	done
	printf "\nOK\n"
}

#############################################################

cmd="$(parse_desc $DESC)"

echo "$cmd" | daliTXRXSeq | format1

