#!/bin/sh

source /usr/local/bin/telem/functions # for logg function

logg "StartPPP"

GENPATH=/usr/local/bin/ppp/
GPIO=/usr/local/bin/telem/gpio.sh
CHECKUSB=/usr/local/bin/telem/check-usb.sh
# port_address: usually content from /var/local/telem/modem_tty
# InitPPP script should quarantee that "modem_tty" content is correct (waits for usb_ok_file)
# In normal situations "modem_tty" contents do not change after usb_ok_file
port_address=$1

sim_try_count=1
sim_try_max=5
sim_cur=SIM1
sim_switch=false

modem_errors=0
modem_errors_cycle=9
modem_errors_reboot=19
modem_io_errors=0
modem_io_errors_max=9
#############################################################
read rev < /tmp/telem/board/rev
#############################################################
#### tiemouts
timeout_terminate=10
timeout_default=5
timeout_connect=180
# from HE910 AT reference guide (R4)
timeout_clip=180
timeout_cops=180
timeout_cpin=20
timeout_gmi=5
timeout_gmm=5
timeout_gmr=5
timeout_gsn=20
timeout_cgatt=180
timeout_csq=5
#############################################################
noPIN=false
modem_log="/var/log/modem.log"
modem_full_log="/var/log/modem-full.log"
modem_port_file=/var/local/telem/modem_tty
#############################################################

powerCycleModem() {
	noPIN=false
	modem_reset_lock
}

getSerialPort() {
	echo "$port_address" | grep -qF -- 'usb' &>/dev/null
	if [ "$?" == "0" ]; then
		serport="/dev/$(ls -1 "$port_address/" | grep -F -- 'tty')" 2>/dev/null
	else
		serport=$1
	fi
	echo $serport | grep -qF -- 'tty' &>/dev/null || return 1
	return 0
}

selectSIM() {
	if [ x"$sim_cur" = x"SIM1" ]; then
		[ -f /etc/ppp/peers/sim1.conf ] && source /etc/ppp/peers/sim1.conf
		$GPIO -c MODEM_SIM_SELECT >/dev/null
	else
		[ -f /etc/ppp/peers/sim2.conf ] && source /etc/ppp/peers/sim2.conf
		$GPIO -s MODEM_SIM_SELECT >/dev/null
	fi
	# override simX.conf value, if PIN was not required in previous run
	$noPIN && PIN="-"
}

switchSIM() {
	sim_switch=true
	# reset SIM try count
	sim_try_count=1
	[ "$sim_cur" == "SIM1" ] && sim_id=2 || sim_id=1
	# For rev 8 do not switch if SIM is not physically available
	[ "$rev" -ge "8" ] && $GPIO --is-off "MODEM_SIM${sim_id}" && {
		logg "Can't switch to SIM${sim_id}, because SIM is not available according to GPIO MODEM_SIM${sim_id}"
		sim_switch=false
		return 1
	}
	# Cancel SIM switch if configuration file is missing
	[ -f "/etc/ppp/peers/sim${sim_id}.conf" ] || {
		logg "Can't switch to SIM${sim_id}, because configuration is missing"
		sim_switch=false
		return 1
	}
	$sim_switch && {
		logg "Switch to SIM${sim_id}"
		sim_cur="SIM${sim_id}"
	}
	sim_switch=false
	return 0
}

generateFiles() {
	# update USB_MODEM variable
	[ -f /var/local/telem/usb-modem-vidpid ] && source /var/local/telem/usb-modem-vidpid
	case "$USB_MODEM" in
		#12d1:1c25) source "${GENPATH}huawei.sh"
		12d1:*) source "${GENPATH}huawei.sh"
		;;
		1bc7:0021) source "${GENPATH}telit.sh"
		;;
		*)
			# by default find scripts by usb id
			# ex: match pattern is "*12d1?1c25.sh" for device 12d1:1c25
			fname=$(find "${GENPATH}" -name "*$(echo "$USB_MODEM" | tr : ? ).sh" | head -n1)
			[ -f "$fname" ] && source "$fname" || logg "Modem configuration not found for usb id $USB_MODEM"
		;;
	esac
}

doOnModemError() {
	let modem_errors=modem_errors+1
	[ $modem_errors -eq $modem_errors_cycle ] && {
		logg "Failed to connect $modem_errors times, Power cycle modem"
		powerCycleModem
	}
	[ $modem_errors -gt $modem_errors_reboot ] && {
		logg "Unable to connect to modem, do reboot"
		reboot;	sleep 60
	}
}

#############################################################
#### main part

[ -z "$port_address" ] && logg "No modem device provided"

modprobe cdc-acm
[ "$rev" -ge "8" ] && {
	modprobe option
	$GPIO --is-off MODEM_SIM1 && switchSIM
}

logg "For starters, Power cycle modem"
powerCycleModem

while true; do
	read port_address < $modem_port_file
	getSerialPort
	if [ "$?" = "0" ]; then
		# defaults
		APN="-"
		PIN="-"
		# Select wireless network
		# 12 - GSM Digital Cellular System(GERAN aka GSM EDGE aka GPRS only)
		# 22 - UTRAN aka UMTS Terrestrial Radio Access Network aka 3G only
		# 25 - 3GPP systems(both GERAN and UTRAN)(factory default)
		NETWORK="25"
		OPERATOR="-"

		selectSIM # and update variables
		# generate modem_init and modem_chat
		generateFiles

		logg "Using $sim_cur, try $sim_try_count"
		logg "Port found: '$serport'"

		# Turn on status led, because it is disabled by default on HUAWEI MU709 & MU909.
		# Can't use chat script, because it fails with 'NO CARRIER'
		# MU609 does not have this command, we will just get an error.
		case "$USB_MODEM" in
                    12d1:*) echo "at^ledctrl=1" | socat $serport,raw,echo=0,crlf -
                esac

		pppd_cmd="$serport 115200 call modem_init"

		rm -f /var/local/telem/was_connected 2>/dev/null
		cat "$modem_log" >> "$modem_full_log"
		! rm "$modem_log"
		echo "========================================" > "$modem_log"
		echo "New PPP session @ `date`" >> "$modem_log"
		! rm /var/local/telem/kill-pppd
		# wait for modem just in case if it was recently reset
		wait_for_modem || logg "Waited for modem"
		logg "Starting PPPD ($pppd_cmd)"
		pppd $pppd_cmd

		# error handling
		pppd_ret=$?
		logg "PPPD stopped, exit status: $pppd_ret"

		# log last error from temporary $modem_log to messages
		if grep -q -- "+CM[E|S] ERROR" "$modem_log"; then
			endoflog=$(tail -n15 "$modem_log")
			err_msg="$(echo "$endoflog" | grep -o -- "CM[E|S] ERROR: .*")"
			last_send="$(echo "$endoflog" | grep -o -- "send.*" | tail -n1)"
			logg "$err_msg, last send command: $last_send"

			# try to solve(trivial) PIN issues
			grep -qF -- '+CPIN: READY' "$modem_log" && noPIN=true || noPIN=false
		fi

		doOnModemError

		grep -qF -- 'Input/output error' "$modem_log" && {
			logg "PPPD IO errors: $modem_io_errors"
			let modem_io_errors=modem_io_errors+1
			# potentially unrecoverable?
			powerCycleModem
		}
		[ $modem_io_errors -gt $modem_io_errors_max ] && {
			logg "Modem Input/output errors problem, do reboot"
			touch /var/local/telem/errors/modem-io
			reboot; sleep 60
		}

		$CHECKUSB

		test -e /var/local/telem/was_connected && {
			modem_errors=0
			modem_io_errors=0
			sim_switch=true
			rm /var/local/telem/was_connected
		}
		let sim_try_count=sim_try_count+1
		[ $sim_try_count -gt $sim_try_max ] && sim_switch=true
		$sim_switch && switchSIM
	else
		logg "Error, no valid port! ($port_address)"
		doOnModemError
		$CHECKUSB
		sleep 10
	fi
done
