#!/bin/sh
#############################################################
# Using binary search method to assign addresses.
# It is quite slow, it takes about 3 seconds per device.
# By default addresses all devices from 0 to 63.
# If there are more devices than 64, then addressing restarts from 0,
# so in the end we will have multiple devices with same address.
#############################################################
path="${0%/*}"
. "$path/inc/gwhw.inc"
. "$path/inc/dali.inc"

needRoot
daliI2COK
daliNotInUse

usage() {
	die 'gwhw dali assign [all/new/[short-address]] [start] [end]'
}

OPT="${1:-all}"
shift
ASTART="${1:-0}"
shift
AEND="${1:-63}"
shift
#############################################################

case "${OPT}" in
	# All devices
	a|all) INIT="00"
	;;
	# All devices without short address
	n|new) INIT="ff"
	;;
	# All devices with specific short address
	*) INIT="$(printf "%02x" "$(( ((OPT & 0x3f)<<1) +1 ))")" 
esac

[ '1' = "$(( AEND>63 ))" ] && AEND=63
[ '1' = "$(( ASTART>AEND ))" ] && ASTART=AEND

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

daliTX3Baddr() {
	[ "$p1" = "$1" ] || { daliTX3Bh 00 b1 $1; p1="$1"; }
	[ "$p2" = "$2" ] || { daliTX3Bh 00 b3 $2; p2="$2"; }
	[ "$p3" = "$3" ] || { daliTX3Bh 00 b5 $3; p3="$3"; }
}

binary_test() {
	daliTX3Bh 02 a9 00 # cmd 260: compare
	waitRX
	case "$(daliRX4B)" in
		0x2??0xa9?0x00?0xff) return 0 # Answer YES
		;;
		0x3??0xa9?0x00*) return 1  # TIME OUT, answer NO
		;;
		*) return 0 # garbage, can be answer YES (different products answer in different times)
	esac
}

binary_search(){
	if "$MSPDALI"; then
		mspdali --bs
		return
	fi

	L=0
	R=$((0xffffff))
	M=0
	count=0
	while [ "$L" -le "$R" ]; do
		M="$(( (L + R)/2 ))"
		printf "M(%02d): %06x  \n" "$count" "$M"
		daliTX3Baddr $(printf "%06x\n" "$M" | sed 's/.\{2\}/& /g')
		if binary_test; then
			[ "$L" = "$R" ] && return 0
			R="$M"
		else
			[ "$((0xffffff))" = "$M" ] && return 1
			[ "$L" = "$M" ] && L=$R || L=$M;
		fi
		: $((count++))
	done
	printf "D: 0x%06x 0x%06x 0x%06x\n" "$L" "$R" "$M"
	return 1
}

# INIT
daliTX3Bh 01 a5 ${INIT} # cmd 258
# RANDOMISE
daliTX3Bh 01 a7 00 # cmd 259

# FIND
addr="$((ASTART))"
while binary_search; do
	addrh="$(printf "%02x" "$(( (addr<<1) +1 ))")"
	daliTX3Bh 00 b7 "${addrh}"
	daliTX3Bh 02 bb 00
	waitRX
	case "$(daliRX4B)" in
		0x22?0xbb?0x00?0x${addrh})
			printf "OK: ${addr}\n"
			# WITHDRAW
			daliTX3Bh 00 ab 00 # cmd 261
			: $(( addr=(addr-ASTART+1)%(AEND-ASTART+1)+ASTART ))
			;;
		*)
			printf "FAILED\n"
			continue
	esac
done \
| awk '/^M/{printf "\r%s", $0;next}{print}'

# TERMINATE
daliTX3Bh 01 a1 00 # cmd 256

printf "DONE\n"
