#!/bin/sh

FACTORY_MODE_FLAG="/tmp/factoryMode"
COUNTRY_REGION_CFGFILE="/etc/wifi/4359/country_region_map.txt"
WIFI_CHIP_INFO_FILE="/sys/module/bcmdhd/parameters/info_string"

SWEEP_AUDIO_FILE="file:///usr/share/factory-mode/sweep_20_20K.wav"
DOWNLOADED_SWEEP_FILE="/tmp/sweep.wav"

MACHINE_NAME_FILE="/etc/machine"

# Speaker volume: 25% user setting (arbitrary value which is loud enough for the test) --> -37.5 dB in Harman volume map
#																						--> 69% on the linear Alsa scale [-120 dB;0 dB]
SPEAKER_VOLUME=69
SPEAKER_TIMEOUT=15

# just wild guesses
FACTORY_RESET_WAIT=15
NSDK_STOP_WAIT=15
NSDK_RESTART_WAIT=15
ETHERNET_WAIT=10
WIFI_WAIT=10

MIC_VOLUME=100
MIC_TIMEOUT=60
MIC_ALSA_DEVICE="hw:0,3"

ANTCFG_SLEEP=3

#touch test constants
pointRadius=32
pointA_x=160
pointA_y=94
pointB_x=400
pointB_y=94
pointC_x=640
pointC_y=94
TOUCH_TIMEOUT=10

# Print usage
usage() {
  echo -n "Usage: FactoryTest <command>

Available commands: (prefix - means not implemented, prefix ? means partial implementation)
	bt <DEVICE> - outputs RSSI
	bt discoverable - Enable BT discoverable mode
	dct write <DCT> - writes debug certificate to NAND flash. This cert. is checked by u-boot and disables secure-boot if the cert. is valid.
	-dct check <FLAG> - checks that the debug certificate is valid and corresponds to the device's unique ID.
	eth connect
	factoryreset - perform factory reset and reboot
	-gen-certificate <google|harman> <MKEY>
	get ethernetmac - get ethernet mac address
	get btaddress - get bluetooth mac address
	get serialnumber - gets the serial number
	get SKUColor - gets the color of the SKU, 1 -> White, 0 -> Black
	lcd test <IMAGE_NAME> - default image name is colorimage
	lcd backlight <OFF|ON|DIM>
	lcd touch
	lock - does nothing. We never received requirements.
	microphone <SECONDS> <FTP-URL-DIR>
			- record audio from microphones for <SECONDS> seconds
			- URL-DIR: Directory to upload recorded files to. Example '10.1.14.109:/'
			(one file per microphone with filename 'mic_test_c0.wav' 'mic_test_c1.wav').
			The FTP server must be configured with one user 'citation' and password 'citation'
	read chipid|version|serials
	-security-test
	set serialnumber <the_serial_number> - sets the serial number to <the_serial_number>
	set SKUColor <the_color_of_sku> - sets the color of SKU, 1 -> White, 0 -> Black
	set ethernetmac <MAC1> - store ethernet MAC address
							MAC address format: 11:22:33:AA:BB:CC
	set btaddress <MAC1> - store BT MAC address
							MAC address format: 11:22:33:AA:BB:CC
	source <auto|aux|hdmi1|hdmi2|hdmi3|hdmi4|hdmiARC|optical>
	source stop - stop playback from source
	speaker  <100|1000|10000> - play a sine wave at given frequency (Hz)
	speaker stop - stop playback
	standby - enter standby
	start - start/enable factory mode (also returns sw version)
	stop - stops/exits/disables the factory mode
	sweep <FTP-URL-FILE> <FTP-URL-DIR>
			- playback and record audio simultaneously from FTP server/local file
			- FTP-URL-FILE: File to download and play. Example '10.1.14.109:/file.wav'.
			  The string 'local' can also be used in which cased a default file is used.
			- FTP-URL-DIR: Directory to upload recorded files to
				(one file per microphone with filename 'mic_sweep_c0.wav' 'mic_sweep_c1.wav')
			  Use 'local' to play the file contained in A113's filesystem.
			- The FTP servers must be configured with one user 'citation' and password 'citation'
	wifi get-region
	wifi set-country <US|CA|TW|SG|DE|KR|VN|MY|PH|NZ|AU|AE|ZA|HR|JP|RU|IN|CN|ID|IL|BR>
	wifi connect <SSID> <PASSWORD>
	wifi antenna <default|ANT1|ANT2> - return RSSI regarding the chosen antenna configuration
	wisatx get-region - get wisa TX regulatory region
	wisatx pair - pair with the first discovered WiSA RX speaker
	wisatx test <c> - play a sine wave at 1 KHz on paired WiSA RX speaker on I2S channel <c>
	wisatx test stop - stop sine wave playback on paired WiSA RX speaker
	write wisarxmac <MAC1> <MAC2> - store pre-paired WiSA RX speaker(s), multiple MAC addresses separated by spaces may
							be specified. For freedom8 the order of the MAC addresses must be
							leftFront, rightFront, leftRear, rightRear, center, subwoofer.
							MAC address format: 11:22:33:AA:BB:CC
	freedom8 <true|false> - set device model to Freedom8 (Adapt only; performs Factory Reset!)
	lexicon <true|false> - set device model to Lexicon SCL-1 (Adapt only; performs Factory Reset!)
	loadkey - loads model key, tests it against template certificate and if it matches, creates device certificate.
	usage - prints this usage informations
	help - same as usage
"
}

error_message() {
	# When user provides wrong arguments, transfering the whole error_message information over HostLink is not possible due to length limitation.
	# Showing this error message. Usage informations can be obtained if requested.
	echo "Error: wrong arguments provided"
}

success_message() {
	echo "ok"
}

#------------------------------------
# Safe exit cleanup
cleanup() {
	killall arecord &>/dev/null
}

trap cleanup EXIT INT TERM

readonly NETWORK_PATH="/media/settings/settings/network"
readonly NETWORK_PROFILE_PATH=${NETWORK_PATH}"/profile"
readonly NETWORK_PROFILE_BACKUP_PATH=${NETWORK_PROFILE_PATH}"_backup"

# Basic start/stop factory mode, should be OK
factory_mode_start() {
	echo "Starting Factory Mode."
	echo "1 1 1 1 1" > /proc/sys/kernel/printk # Disable kernel output
	touch $FACTORY_MODE_FLAG

	# --------------------------------------------------
	# Setting the network profile start
	echo "Setting the FactoryTest mode network profile"
	mkdir -p ${NETWORK_PATH}

	# FactoryTest mode network profile is a symlink (in other cases it's a proper file)
	# If there is a proper profile file we will save it, so that we can restore it later
	if [ -e ${NETWORK_PROFILE_PATH} ] && [ ! -h ${NETWORK_PROFILE_PATH} ]; then
		mv ${NETWORK_PROFILE_PATH} ${NETWORK_PROFILE_BACKUP_PATH}
	fi
	# And now we can create the symlink
	ln -f -s "/settings-default/network/factoryModeConfig" ${NETWORK_PROFILE_PATH}
	# Setting the network profile end
	# --------------------------------------------------

	# change alsa settings (for Citation 300, 500 and Tower in order to enable DSP1)
	machineName=`cat ${MACHINE_NAME_FILE}`
	if [[ "${machineName}" != "a113dBleSetup" ]]; then
		storedModel=$(fw_printconst model 2> /dev/null)
		if [ "x${storedModel##model=}" == "xcit_300" ] || [ "x${storedModel##model=}" == "xcit_500" ] || [ "x${storedModel##model=}" == "xcit_tower" ]; then
			model=${storedModel##model=}
			echo "Changing alsa configuration for the Factory Test mode (device model: ${model})"

			# workaround: If factory doesn't execute factory_mode_stop for some reason, we get into not recoverable issue till next OTA.
			# To avoid this we change the symlink and we make sure symlinks are regenerated after boot.
			ln -s -f /etc/asound.conf_${model}_factoryMode /etc/asound.conf

			# Playback alsa device for Streamer: delete 'softvol_nsdk' from the setting
			cp /settings-default/mediaPlayer/alsaDevice /media/settings/settings/mediaPlayer/alsaDevice
			sed -i 's/softvol_nsdk//g' /media/settings/settings/mediaPlayer/alsaDevice
		fi
	else
		echo "a113dBleSetup machine, no need to change alsa settings"
	fi

	/etc/init.d/nsdk restart 1>/dev/null 2>&1

	sleep ${NSDK_RESTART_WAIT}
	#FIRMWARE_VERSION=$(nsdk_cli get "settings:/version" 2> /dev/null | awk -F. '{ print $3 }' 2> /dev/null)
	# for now?
	FIRMWARE_VERSION=$(nsdk_cli get "settings:/version" 2> /dev/null)
	echo "swver=${FIRMWARE_VERSION}"

	# Clear the postinstall_done flag file, which will make the nSDK init script re-create all links
	postInstallDonePath=/usr/share/nsdk/postinstall_done
	rm -f ${postInstallDonePath}
}

factory_mode_stop() {
	echo "Stopping Factory Mode."
	rm -f $FACTORY_MODE_FLAG
	speaker_stop

	# --------------------------------------------------
	# Restoring the network profile start
	# If the network profile is a symlink it was created by the "FactoryTest start" command
	# That means we need to remove it
	if [ -h ${NETWORK_PROFILE_PATH} ]; then
		rm ${NETWORK_PROFILE_PATH}

		# If we have a profile backed up here is where we restore it
		if [ -e ${NETWORK_PROFILE_BACKUP_PATH} ]; then
			mv ${NETWORK_PROFILE_BACKUP_PATH} ${NETWORK_PROFILE_PATH}
		fi
	fi
	# Restoring the network profile end
	# --------------------------------------------------

	# restore alsa settings (for Citation 300, 500 and Tower)
	storedModel=$(fw_printconst model 2> /dev/null)
	model=${storedModel##model=}
	ln -s -f /etc/asound.conf_${model} /etc/asound.conf
	if [ -f /media/settings/settings/mediaPlayer/alsaDevice ]; then
		rm /media/settings/settings/mediaPlayer/alsaDevice
	fi

	/etc/init.d/nsdk restart 1>/dev/null 2>&1
}

print_ethernet_mac() {
	# It's important to read from the const partition and not from ifconfig directly in case there was not yet
	# a reboot after the MAC address has been set in the const partition.
	ETH_MAC_CONST=$(fw_printconst eth_int_addr | sed s/"_int_addr"//)
	if [ "x$ETH_MAC_CONST" != "x" ]; then
		echo "$ETH_MAC_CONST"
	else
		# ETH_MAC=$(nsdk_cli get "network:state/ethernet_mac" 2> /dev/null)
		# For unknown reason if we use the command above we will get all zeroes in ETH_MAC = 00:00:00:00:00:00
		# Therefore we will extract the information from ifconfig command
		ETH_MAC=$(ifconfig eth0 2> /dev/null | grep "HWaddr" | tr -d " " | sed s/"addr"/" "/ | cut -d " " -f 2)
		echo "eth=${ETH_MAC}"
	fi
}

print_bluetooth_mac() {
	# It's important to read from the const partition and not from hciconfig directly in case there was not yet
	# a reboot after the MAC address has been set in the const partition.
	BT_MAC_CONST=$(fw_printconst bt_addr | sed s/"_addr"//)
	if [ "x$BT_MAC_CONST" != "x" ]; then
		echo "$BT_MAC_CONST"
	else
		BT_MAC=$(hciconfig hc0 2> /dev/null | grep "BD Address" 2> /dev/null | cut -d " " -f 3 2> /dev/null)
		echo "bt=${BT_MAC}"
	fi
}

get_impl() {
	case "$1" in
	"ethernetmac")
		print_ethernet_mac
		;;
	"btaddress")
		print_bluetooth_mac
		;;
	"serialnumber")
		fw_printconst serialnumber
		;;
	"SKUColor")
		fw_printconst SKUColor
		;;
	*)
		error_message
		;;
	esac
}

#------------------------------------
## FAC_017
# returns RSSI
bt() {
	if [ -z "$1" ]; then
		usage
		return
	fi

	if [ "$1" = "discoverable" ]; then
		nsdk_cli invoke "bluetooth:externalDiscoverable" 1>/dev/null
		return
	fi

	DEVICE_NAME=$1

	if [ -z "$(pidof hcidump)" ]; then
		#echo -e "Start hcidump and capture output"
		hcidump >> /tmp/hcidump.txt &
	fi

	#echo -e "Scan for $DEVICE_NAME"
	OUTPUT=$(hcitool scan)

	#echo "$OUTPUT" > "/tmp/hciscan.txt"
	#OUTPUT=$(cat /tmp/hciscan.txt)

	DEVICE_ADDR=$(echo -e "$OUTPUT" | grep "$DEVICE_NAME" 2> /dev/null | awk '{ split($0, a, "\t"); print a[2]; }' 2> /dev/null)
	#echo ${DEVICE_ADDR}

	if [ -n "$DEVICE_ADDR" ]; then
		#echo "Found device $DEVICE_NAME with addr $DEVICE_ADDR"
		# Read hcidump output, search for bt addr, extract rssi and return the last rssi value found
		RSSI=$(cat /tmp/hcidump.txt 2> /dev/null | grep $DEVICE_ADDR 2> /dev/null | awk '/rssi\s/ { match($0, /rssi\s(-?[0-9]+)/); print substr($0, RSTART+5, RLENGTH-5); }' | tail -n 1 2> /dev/null)
		if [ -z "$RSSI" ]; then
			echo "Error: Device $DEVICE_NAME found but could not read signal level from hcidump output!"
		else
			echo "$RSSI"
		fi
	else
	  echo "Error: Device not found"
	fi
}

#------------------------------------
# handles "Debug Certificate" (DCT) used to debug locked devices.
dct() {
	case "$1" in
	"write")
		fw_setenv dct "$2"
		success_message
		;;
	"check")
		echo "dct check not yet implemented"
		# gets argument <flag>
		# outputs value
		error_message
		;;
	*)
		error_message
		;;
	esac
}

#------------------------------------
eth() {
	# Note: on devices that don't have ethernet, MAC address and IP address will be empty!
	case "$1" in
		"connect")
		nsdk_cli invoke network:setNetworkProfile '{"type":"networkProfile","networkProfile":{"type":"wired","wired":{"dhcp":true}}}' 1>/dev/null
		sleep ${ETHERNET_WAIT}
		# output mac=<MAC> ip=<IPv4>
		# ETH_MAC=$(nsdk_cli get "network:state/ethernet_mac" 2>/dev/null)
		# For unknown reason if we use the command above we will get all zeroes in ETH_MAC = 00:00:00:00:00:00
		# Therefore we will extract the information from ifconfig command
		ETH_MAC=$(ifconfig eth0 2> /dev/null | grep "HWaddr" | tr -d " " | sed s/"addr"/" "/ | cut -d " " -f 2)
		ETH_IP=$(ifconfig eth0 2> /dev/null | grep "inet addr:" | sed -e 's/^[[:space:]]*//' | tr ":" " " |cut -d " " -f 3)
		echo "mac=$ETH_MAC ip=$ETH_IP"
		;;
	*)
		error_message
		;;
	esac
}

#------------------------------------
factoryreset() {
	speaker_stop
    nsdk_cli invoke systemmanager:factoryReset/initiate # 2>/dev/null
    sleep ${FACTORY_RESET_WAIT}
	/etc/init.d/nsdk stop #1>/dev/null 2>&1
	sleep ${NSDK_STOP_WAIT}
	shutdown -r now
}

#------------------------------------
# Loads the model private key which is encrypted, tests it against the template certificate and if it matches, creates device certificate.
# Template certificate that is being used is the file that is being pointed to by /factory/template.crt
# WARNING: After the model key has been successfully loaded, device will be locked by calling the lock function!
# WARNING: Setting the fuses still needs to be implemented in the TA!
load_key() {
	echo "# import key"
	if echo "$1" | teeStoreKey -g -e -c; then
		# remove old generated certificates/..
		rm /factory/client.*
		sync

		# NOTE: make sure tee-supplicant has time to save the data before power-off/reboot !!!
		#       (with optee, there is a 1-sec delay; the nsdk restart below does "sleep 2")

		# restart everything to apply new keys
		/etc/init.d/nsdk restart

		echo "# done importing key"
		success_message
		# We need to reboot the board!
		reboot
	else
		echo "# error importing key."
		error_message
	fi
}

is_in() {
	#compare X coordinate
	tmp=$(($1 - $3))
	if [ "$tmp" -gt "$pointRadius" ] || [ "$tmp" -lt $(($pointRadius * -1)) ]; then
		return 1
	fi

	#compare Y coordinate
	tmp=$(($2 - $4))
	if [ "$tmp" -gt "$pointRadius" ] || [ "$tmp" -lt $(($pointRadius * -1)) ]; then
		return 1
	fi

	return 0
}

process_events() {
	START=$(date +%s)
	while read line; do
		x=$(echo $line | grep "^Event:" | grep "ABS_MT_POSITION_X" | \
			   cut -d',' -f4 | cut -d' ' -f3)
		y=$(echo $line | grep "^Event:" | grep "ABS_MT_POSITION_Y" | \
			   cut -d',' -f4 | cut -d' ' -f3)

		if [ -n "$x" ]; then
			X=$x
		fi

		if [ -n "$y" ]; then
			Y=$y
		fi

		if [ -n "$X" ] && [ -n "$Y" ]; then
			if [ "$point" -eq 1 ]; then
				if is_in $pointA_x $pointA_y $X $Y; then
					return 0
				fi
			elif [ "$point" -eq 2 ]; then
				if is_in $pointB_x $pointB_y $X $Y; then
					return 0
				fi
			elif [ "$point" -eq 3 ]; then
				if is_in $pointC_x $pointC_y $X $Y; then
					return 0
				fi
			fi
		fi

		DIFF=$(( $(date +%s) - $START ))
		if [ "$DIFF" -gt "$TOUCH_TIMEOUT" ]; then
			return 1
		fi
	done
	return 1
}

touch_test() {
	point=1
	#show first point A
	bzcat /usr/share/factory-mode/touchTestA.fb.bz2 > /dev/fb0
	evtest /dev/input/event0 | process_events
	if [ "$?" -eq 1 ]; then
		return 1
	fi

	point=2
	#show second point B
	bzcat /usr/share/factory-mode/touchTestB.fb.bz2 > /dev/fb0
	evtest /dev/input/event0 | process_events
	if [ "$?" -eq 1 ]; then
		return 1
	fi

	point=3
	#show third point C
	bzcat /usr/share/factory-mode/touchTestC.fb.bz2 > /dev/fb0
	evtest /dev/input/event0 | process_events
	if [ "$?" -eq 1 ]; then
		return 1
	fi

	return 0
}

#------------------------------------
# TODO: learn commands for testing image and touch
lcd() {
	case "$1" in
	"backlight")
		case "$2" in
		"OFF")
			success_message
			echo 0 > /sys/devices/platform/backlight/backlight/aml-bl/brightness
			;;
		"ON")
			success_message
			echo 255 > /sys/devices/platform/backlight/backlight/aml-bl/brightness
			;;
		"DIM")
			success_message
			echo 64 > /sys/devices/platform/backlight/backlight/aml-bl/brightness
			;;
		*)
			error_message
			;;
		esac
		;;
	"test")
		if [ -z $2 ]; then
			IMAGENAME=colorimage
		else
			IMAGENAME=$2
		fi
		echo "LCD showing $2"
		# extract image into framebuffer
		bzcat "/usr/share/factory-mode/${IMAGENAME}.fb.bz2" > /dev/fb0
		;;
	"touch")
		echo "LCD touch test started"
		# Print "ok" on success, "fail" otherwise
		if touch_test; then echo "ok"; else echo "fail"; fi
		#clear framebuffer
		dd if=/dev/zero of=/dev/fb0 >& /dev/null
		;;
	*)
		error_message
		;;
	esac
}

#------------------------------------
lock() {
	success_message
}

#------------------------------------
split_and_upload()
{
	cd /tmp
	# Split channels to separate mono recordings
	echo "Splitting /tmp/$1.wav into /tmp/$1_c0.wav and /tmp/$1_c1.wav"
	gst-launch-1.0 filesrc location="$1.wav" ! wavparse ! deinterleave name=d d.src_0 ! wavenc ! filesink location="$1_c0.wav" &>/dev/null
	gst-launch-1.0 filesrc location="$1.wav" ! wavparse ! deinterleave name=d d.src_1 ! wavenc ! filesink location="$1_c1.wav" &>/dev/null
	rm -f "$1.wav"

	# if argument $2 exists
	if ! [ -z "$2" ];  then
		FILES="$1_c0.wav $1_c1.wav"
		for f in $FILES
		do
			echo "Uploading /tmp/$f to ${2}${f}"
			curl  -T "/tmp/$f" --ftp-create-dirs  "ftp://${2}" --user citation:citation #&>/dev/null
		done
		# shouldn't test whether succesfully uploaded?
		rm -f "$1_c0.wav"
		rm -f "$1_c1.wav"
	fi
}

## FAC_018: do a microphone recording, store result in a .WAV
mic() {
	# Check whether the passed recording time parameter is a valid integer
	if echo $1 | egrep -q '^[0-9]+$'; then
		MIC_TIMEOUT=$1
	else
		echo "Using default timeout ${MIC_TIMEOUT}"
	fi

	# Now we're all set for actual recording!
	echo -n "Recording to /tmp/mic_test.wav from ${MIC_ALSA_DEVICE} for ${MIC_TIMEOUT}s... "
	arecord -f S32_LE -c 2 -r 16000 -D $MIC_ALSA_DEVICE -d $MIC_TIMEOUT /tmp/mic_test.wav
	echo "Done recording, splitting channels..."

	# TODO: can I write simply 'split_and_upload "/tmp/mic_test" "$2"' even if $2 does not exist
	# would it create an empty second argument in such case? or throw an error?
	if ! [ -z "$2" ]; then
		split_and_upload "mic_test" "$2"
	else
		split_and_upload "mic_test"
	fi

	success_message
}


#------------------------------------
readCmd() {
	case "$1" in
	"chipid")
		cat /proc/cpuinfo | grep Serial | awk '{print $3}'
		;;
	"version")
		#FIRMWARE_VERSION=$(nsdk_cli get "settings:/version" 2> /dev/null | awk -F. '{ print $3 }' 2> /dev/null)
		# for now?
		FIRMWARE_VERSION=$(nsdk_cli get "settings:/version" 2> /dev/null)
		echo "${FIRMWARE_VERSION}"
		;;
	"serials")
		BT_MAC=$(hciconfig hc0 2> /dev/null | grep "BD Address" 2> /dev/null | cut -d " " -f 3 2> /dev/null)
		WIFI_MAC=$(nsdk_cli get "network:state/wireless_mac" 2> /dev/null)
		WISATX_MAC=$(nsdk_cli get "summit:txMac" 2> /dev/null)
		echo "bt=${BT_MAC}"
		echo "wifi=${WIFI_MAC}"
		print_ethernet_mac
		echo "wisatx=${WISATX_MAC}"
		;;
	*)
		error_message
		;;
	esac
}

set_impl() {
	case "$1" in
	"ethernetmac")
		fw_setconst eth_int_addr $2
		success_message
		;;
	"btaddress")
		fw_setconst bt_addr $2
		success_message
		;;
	"serialnumber")
		fw_setconst serialnumber $2
		success_message
		;;
	"SKUColor")
		fw_setconst SKUColor $2
		success_message
		;;
	*)
		error_message
		;;
	esac
}

#------------------------------------
## FAC_015: play a sine wave at given frequency
speaker_start() {
	# In case it was already started before
	speaker_stop
	echo "Playing a ${1}Hz sine wave at ${SPEAKER_VOLUME}% volume."

	# Set the volume
	amixer sset Master $SPEAKER_VOLUME% 1>/dev/null 2>&1
	amixer sset MasterLocal $SPEAKER_VOLUME% 1>/dev/null 2>&1

	# Play the sine wave
	gst-launch-1.0 audiotestsrc wave=sine freq=${1} ! audioconvert ! alsasink 1>/dev/null 2>&1 &

	# Stop playback after a timeout
	# sleep $SPEAKER_TIMEOUT
	# speaker_stop
}

speaker_stop() {
	echo "Stopping speaker"
	killall gst-launch-1.0 1>/dev/null 2>&1
}

#---WiSA-----------------------------
set_wisa_country() {
	local COUNTRY_CODE=$1
	local REGREV=$(awk "\$2==\"$COUNTRY_CODE\" {print \$3}" <"$COUNTRY_REGION_CFGFILE" | head -n1)
	local POWER_TABLE=$(awk "\$2==\"$COUNTRY_CODE\" {print \$4}" <"$COUNTRY_REGION_CFGFILE" | head -n1)

	# if wrong country
	if [ -z "$COUNTRY_CODE" ]; then
		echo "fail"
		return
	fi

	# assign proper region code
	local wisaRegionCode=""
	case "$COUNTRY_CODE" in
	"US" | "CA")
		wisaRegionCode=0
		;;
	"KR")
		wisaRegionCode=2
		;;
	"IL" | "RU")
		wisaRegionCode=3
		;;
	"CN")
		wisaRegionCode=8
		;;
	"JP")
		wisaRegionCode=5
		;;
	"TW")
		wisaRegionCode=6
		;;
	*)
		# this covers all the EU states
		if [ "$POWER_TABLE" == "EU" ]; then
			wisaRegionCode=1
		else
			echo "fail"
			return
		fi
		;;
	esac

	# issue StreamAPI command
	local regionSetTo=$(nsdk_cli invoke citation:summitRegion '{"type":"i32_", "i32_":'$wisaRegionCode'}' | grep region | awk '{print substr ($2, 0, 1)}')
	# print "ok" on success, "fail" otherwise
	if [ $regionSetTo == $wisaRegionCode ]; then
		echo "ok"
	elif [ $regionSetTo == "-" ]; then
		# This device does not have Summit WiSA module but we got the expected result for such device - we can return "ok"
		echo "ok"
	else
		echo "fail"
	fi
}

get_wisa_region() {
	local wisaRegionCode=$(nsdk_cli invoke citation:summitRegion | grep region | awk '{print substr ($2, 0, 1)}')
	case "$wisaRegionCode" in
	'0')
		echo "USA"
		;;
	'1')
		echo "EU"
		;;
	'2')
		echo "KR"
		;;
	'3')
		echo "IL"
		;;
	'4')
		echo "CN"
		;;
	'8')
		echo "CN"
		;;
	'5')
		echo "JP"
		;;
	'6')
		echo "TW"
		;;
	'7')
		echo "JO"
		;;
	'-')
		echo "This device does not have Summit WiSA module"
		;;
	*)
		echo "INVALID ($wisaRegionCode)"
		;;
	esac
}

wisa_pair() {
	# Reset transmitter and its configuration
	nsdk_cli invoke summit:networkReset >/dev/null

	# Discover nearby receivers
	nsdk_cli invoke summit:networkDiscovery >/dev/null

	# Pair with the first receiver
	local success=$(nsdk_cli invoke summit:configureSpeaker '{"summitRequest":{"rxIndex":0,"type":"leftFront"}}' | grep 'success": true' | wc -l)

	# Start the network, dropping other receivers
	nsdk_cli invoke summit:networkStart >/dev/null

	# Print "ok" on success, "fail" otherwise
	if [ "$success" == "1" ]; then
		success_message
	else
		error_message
	fi
}

wisa_prepair() {
	# replace possible whitespaces in MACs with commas
	local macs=$(echo "$@" | tr '[ \t]' ',')

	# write MACs to const partition
	fw_setconst summitPrepairedRxMacs $macs

	# set first-time setup flag for next boot
	cp /settings-default/summit/doFirstTimeSetup /media/settings/settings/summit/doFirstTimeSetup

	success_message
}

wisa_start_test() {
	# Make sure no previous test is running
	wisa_stop_test

	# Configure speaker to use the appropriate I2S channel
	local success=$(nsdk_cli invoke summit:configureSpeaker '{"summitRequest":{"rxIndex":0,"type":"'${1}'"}}' \
	 				| grep '"success": true' | wc -l)

	# On configuration success, start speaker test, otherwise print "fail"
	if [ "$success" == "1" ]; then
		# Play a 1 KHz sine wave infinitely
		gst-launch-1.0 audiotestsrc wave=sine freq=1000 ! audioconvert ! audio/x-raw,channels=8 ! alsasink 1>/dev/null 2>&1 &
		success_message
	else
		error_message
	fi
}

wisa_stop_test() {
	# Kill any instances of speaker-test
	killall gst-launch-1.0 1>/dev/null 2>&1
}

freedom8() {
	if ! [ -z "$1" ]; then
		if [ "x$1" = "xtrue" -o "x$1" = "xfalse" ]; then
			fw_setconst isFreedom8 $1
			nsdk_cli invoke systemmanager:factoryReset/initiate 2>/dev/null
			sleep ${FACTORY_RESET_WAIT}
			return
		fi
	fi
	usage
}

lexicon() {
	if ! [ -z "$1" ]; then
		if [ "x$1" = "xtrue" -o "x$1" = "xfalse" ]; then
			fw_setconst isLexiconSLC1 $1
			fw_setenv isLexiconSLC1 $1
			nsdk_cli invoke systemmanager:factoryReset/initiate 2>/dev/null
			sleep ${FACTORY_RESET_WAIT}
			return
		fi
	fi
	usage
}

#------------------------------------
speaker() {
	case "$1" in
	"100")
		speaker_start 100
		;;
	"1000")
		speaker_start 1000
		;;
	"10000")
		speaker_start 10000
		;;
	"stop")
		speaker_stop
		;;
	*)
		error_message
		;;
	esac
}

#------------------------------------
source_stop() {
	# In case some source is still playing, stop it
	echo "Stopping source"
	nsdk_cli invoke /player/control '{"control":"stop"}' 1>/dev/null
}

#------------------------------------
source_start() {
	source_stop

	case "$1" in
	"auto")
		echo "Selected source $1 not yet implemented."
		;;
	"aux")
		echo "Start playback from source $1"
		nsdk_cli invoke citation:streamAudioSource "{\"source\":\"$1\"}" 1>/dev/null
		;;
	"hdmi1")
		echo "Start playback from source $1"
		nsdk_cli invoke citation:streamAudioSource "{\"source\":\"$1\"}" 1>/dev/null
		;;
	"hdmi2")
		echo "Start playback from source $1"
		nsdk_cli invoke citation:streamAudioSource "{\"source\":\"$1\"}" 1>/dev/null
		;;
	"hdmi3")
		echo "Start playback from source $1"
		nsdk_cli invoke citation:streamAudioSource "{\"source\":\"$1\"}" 1>/dev/null
		;;
	"hdmi4")
		echo "Start playback from source $1"
		nsdk_cli invoke citation:streamAudioSource "{\"source\":\"$1\"}" 1>/dev/null
		;;
	"hdmiARC")
		echo "Start playback from source $1"
		nsdk_cli invoke citation:streamAudioSource "{\"source\":\"$1\"}" 1>/dev/null
		;;
	"optical")
		echo "Start playback from source $1"
		nsdk_cli invoke citation:streamAudioSource "{\"source\":\"$1\"}" 1>/dev/null
		;;
	*)
		error_message
		;;
	esac
}

#------------------------------------
sourceCmd() {
	if [ "$1" = "stop" ]; then
		source_stop
	else
		source_start $1
	fi
}

#------------------------------------
sweep() {
	# Set file to play, if given
	if ! [ -z "$1" ]; then
		if [ "$1" = "local" ]; then
			echo "using LOCAL file ${SWEEP_AUDIO_FILE}"
		else
			echo "Downloading $1 to ${DOWNLOADED_SWEEP_FILE}"
			curl "ftp://{$1}" -o ${DOWNLOADED_SWEEP_FILE} --user citation:citation
			SWEEP_AUDIO_FILE="file://${DOWNLOADED_SWEEP_FILE}"
		fi
	else
		echo "using local file ${SWEEP_AUDIO_FILE}"
	fi

	# In case sine playback is running, stop it
	speaker_stop

	# Start recording in the background
	arecord -f S32_LE -c 2 -r 16000 -D $MIC_ALSA_DEVICE /tmp/mic_sweep.wav 1>/dev/null 2>&1 &

	# Play the sweep audio file
	echo -n "Playing ${SWEEP_AUDIO_FILE} ... "
	gst-launch-1.0 playbin uri=${SWEEP_AUDIO_FILE} &>/dev/null
	#sleep 10

	# Stop recording in the background
	kill -INT "$!"
	rm -f ${DOWNLOADED_SWEEP_FILE}

	# TODO: can I write simply 'split_and_upload "/tmp/mic_test" "$2"' even if $2 does not exist
	# would it create an empty second argument in such case? or throw an error?
	if ! [ -z "$2" ]; then
		split_and_upload "mic_sweep" "$2"
		echo "Recording uploaded to $2mic_sweep_c0.wav and $2mic_sweep_c0.wav"
	else
		split_and_upload "mic_sweep"
		echo "Recorded to: /tmp/mic_sweep_c0.wav and /tmp/mic_sweep_c0.wav"
	fi

	success_message
}

wifi() {
	case "$1" in
	"antenna")
		case "$2" in
		"default")
			wl -i wlan0 rssi
			;;
		"ANT1")
			wl phy_rssi_ant | awk '{print $2}'
			;;
		"ANT2")
			wl phy_rssi_ant | awk '{print $4}'
			;;
		*)
			error_message
			;;
		esac
		;;
	"get-region")
		wl country | awk '{print $1}'
		;;
	"set-country")
		set_wifi_country "$2"
		;;
	"connect")
		shift
		wifi_connect "$@"
		;;
	*)
		error_message
		;;
	esac
}

wifi_connect() {
	if [ -z "$1" -o -z "$2" ]; then
		error_message
		return
	fi
	# echo "Connecting to SSID: $1 using password: $2"
	nsdk_cli invoke network:setNetworkProfile '{"type":"networkProfile","networkProfile":{"type":"wireless","wired":{"dhcp":true},"wireless":{"dhcp":true,"ssid":"'"${1}"'","encryption":"wpa_psk","key":"'"${2}"'"}}}' 1>/dev/null
	sleep ${WIFI_WAIT}
	# Let's print the WiFi MAC address and IP address
	WIFI_MAC=$(nsdk_cli get "network:state/wireless_mac" 2>/dev/null)
	WIFI_IP=$(ifconfig wlan0 | grep "inet addr:" | sed -e 's/^[[:space:]]*//' | tr ":" " " |cut -d " " -f 3)
	echo "mac=$WIFI_MAC ip=$WIFI_IP"
}

# automatically sets also corresponding region
set_wifi_country() {
	local COUNTRY_CODE=$1
	local REGREV=$(awk "\$2==\"$COUNTRY_CODE\" {print \$3}" <"$COUNTRY_REGION_CFGFILE" | head -n1)
	local POWER_TABLE=$(awk "\$2==\"$COUNTRY_CODE\" {print \$4}" <"$COUNTRY_REGION_CFGFILE" | head -n1)
	local WIFI_CHIP=$(cat $WIFI_CHIP_INFO_FILE | grep "Chip" | awk -F'Chip: ' '{print $2}' | cut -d' ' -f1)

	# if wrong country
	if [ -z "$COUNTRY_CODE" -o -z "$REGREV" -o -z "$POWER_TABLE" -o -z "$WIFI_CHIP" ]; then
		#echo "ERROR: Unrecognized country $1!"
		echo "fail, cc: $COUNTRY_CODE, regrev: $REGREV, pwr_tbl: $POWER_TABLE, chip: $WIFI_CHIP"
	else
		set_wifi_region_google_locale $POWER_TABLE
		fw_setconst ccode $COUNTRY_CODE

		# set wl bin
		fw_setconst wifichip $WIFI_CHIP
		/etc/init.d/select_wl_binary restart
		
		case "$WIFI_CHIP" in
			"4359")
				echo "Found AP6398S chip..."
				fw_setconst regrev $REGREV
				;;
			"aae8")
				echo "Found AP72598V chip..."
				fw_setconst regrev 0
				if [ "$COUNTRY_CODE" == "DE" ]; then
					# Overwrite with different params expected by new chip
					fw_setconst ccode EU
					fw_setconst country_list EU:EU/1
				fi
				;;
			*)
				echo "failed to identify WiFi Chip"
				return;
				;;
		esac

		# copy contants to config file of driver
		/etc/init.d/wifi-regulatory-domain restart
		# restart nsdk to re-create wifi interfaces
		/etc/init.d/nsdk restart 1>/dev/null 2>&1
		echo "ok"
	fi
}

set_wifi_region_google_locale () {
	# variable processStatus holds the information about the process of replacing the WiFi power table.
	# 0 (zero) and 3 - process successful
	# 1 - process failed while replacing wifi region table
	# 2 - process failed while creating wifi region flag on const partition
	processStatus=0
	replaceError=1
	skipCreateFlag=2 #used if wrong argument is set. Setting flag to default (GB)
	case "$1" in
	"EU")
		fw_setconst wifiRegulatoryDomain GB
		fw_setconst googleFactoryLocale en-GB
		;;
	"USA" | "CA")
		fw_setconst wifiRegulatoryDomain US
		fw_setconst googleFactoryLocale en-US
		;;
	"JP")
		fw_setconst wifiRegulatoryDomain JP
		fw_setconst googleFactoryLocale ja-JP
		;;
	"BR")
		fw_setconst wifiRegulatoryDomain US
		fw_setconst googleFactoryLocale pt-BR
		;;
	"KR")
		fw_setconst wifiRegulatoryDomain KR
		fw_setconst googleFactoryLocale ko-KR
		;;
	"IN")
		fw_setconst wifiRegulatoryDomain IN
		fw_setconst googleFactoryLocale en-IN
		;;
	"CN")
		fw_setconst wifiRegulatoryDomain CN
		;;
	*)
		echo "ERROR! Wrong argument provided. Setting WiFi region to default (GB). Please see usage!"
		fw_setconst wifiRegulatoryDomain GB
		fw_setconst googleFactoryLocale en-GB
		;;
	esac

	set_wifi_region_message $processStatus
}

set_wifi_region_message () {
	# function expects one argument!
	# 0 (zero) AND 2 - process successful.
	# 1 - process failed while replacing wifi region table
	if [ $1 -eq 0 ]; then
		echo "WiFi region configured successfully! Power table and region are set!"
	elif [ $1 -eq 1 ]; then
		echo "ERROR: Setting WiFi region failed. Failed linking power table file!"
	else
		# will be executed for value 3
		echo "WARNING: WiFi region set to default (GB)!"
	fi
}


#------------------------------------
wisatx()
{
	case "$1" in
	"pair")
		wisa_pair
		;;
	"test")
		case "$2" in
		"1")
			wisa_start_test 'leftFront'
			;;
		"2")
			wisa_start_test 'left'
			;;
		"3")
			wisa_start_test 'leftRear'
			;;
		"4")
			wisa_start_test 'center'
			;;
		"stop")
			wisa_stop_test
			;;
		"gpio")
			echo "wisatx test gpio not yet implemented"
			;;
		*)
			error_message
			;;
		esac
		;;
	"get-region")
		get_wisa_region
		;;
	"set-country")
		set_wisa_country $2
		;;
	*)
		error_message
		;;
	esac
}

go_to_standby()
{
	nsdk_cli invoke powermanager:goNetworkStandby
}

#------------------------------------
# Process command(s)
case "$1" in
"bt")
	shift
	bt "$@"
	;;
"dct")
	shift
	dct "$@"
	;;
"eth")
	shift
	eth "$@"
	;;
"factoryreset")
	factoryreset
	;;
"gen_certificate")
	shift
	gen_certificate "$@"
	;;
"get")
	shift
	get_impl "$@"
	;;
"lcd")
	shift
	lcd "$@"
	;;
"lock")
	shift
	lock "$@"
	;;
"microphone")
	shift
	mic "$@"
	;;
"read")
	shift
	readCmd "$@"
	;;
"set")
	shift
	set_impl "$@"
	;;
"source")
	shift
	sourceCmd "$@"
	;;
"speaker")
	shift
	speaker "$@"
	;;
"start")
	factory_mode_start
	;;
"standby")
	go_to_standby
	;;
"stop")
	factory_mode_stop
	;;
"sweep")
	shift
	sweep "$@"
	;;
"wifi")
	shift
	wifi "$@"
	;;
"wisatx")
	shift
	wisatx "$@"
	;;
"write")
	[[ "x$2" == "xwisarxmac" ]] && (shift 2; wisa_prepair "$@") || usage
	;;
"freedom8")
	shift
	freedom8 "$@"
	;;
"lexicon")
	shift
	lexicon "$@"
	;;

"loadkey")
	shift
	load_key "$@"
	;;
"usage")
	usage
	;;
"help")
	usage
	;;
*)
	usage
	;;
esac

cleanup
