#!/bin/sh

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

logg "StartPPP"

GENPATH=/usr/local/bin/ppp/
CHECKUSB=/usr/local/bin/telem/check-usb.sh

sim_try_count=1
sim_try_max=5
sim_id=1

modem_errors=0
modem_errors_cycle=9
modem_errors_reboot=19
modem_io_errors=0
modem_io_errors_max=9
#############################################################
#############################################################
#### 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"
#############################################################

powerCycleModem() {
	noPIN=false
	modem_reset_lock
}

sourceConf() {
	# defaults
	APN="-"
	PIN="-"
	# Select wireless network (Telit specific)
	# 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="-"

	[ -f "/etc/ppp/peers/sim${sim_id}.conf" ] || {
		logg "sim${sim_id}.conf is missing"
		return 1
	}
	source "/etc/ppp/peers/sim${sim_id}.conf"
	# override sim${sim_id}.conf value, if PIN was not required in previous run
	$noPIN && PIN="-"

	return 0
}

switchSIM() {
	canSwitchSIM || return
	local new_sim_id=1
	[ "${sim_id}" == "1" ] && new_sim_id=2
	# reset SIM try count
	sim_try_count=1
	# Reselect current SIM just in case if other SIM is not available or not configured
	selectSIM${sim_id}
	# Check if SIM is inserted
	insertedSIM${new_sim_id} || {
		logg "Can't switch to SIM${new_sim_id}, because SIM is not available according to GPIO MODEM_SIM${new_sim_id}"
		return 1
	}
	# Cancel SIM switch if configuration file is missing
	[ -f "/etc/ppp/peers/sim${new_sim_id}.conf" ] || {
		logg "Can't switch to SIM${new_sim_id}, because configuration is missing"
		return 1
	}
	# Everything OK, do the switch
	logg "Switch to SIM${new_sim_id}"
	selectSIM${new_sim_id}
	sim_id=${new_sim_id}

	return 0
}

initSIM() {
	# Check if we can control multiple SIMs
	canSwitchSIM || return
	# Always start from SIM1
	sim_id=1
	selectSIM1
	# Switch over if needed
	insertedSIM1 || switchSIM
}

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}genchat.sh"
		;;
		1bc7:0021) source "${GENPATH}telit.sh"
		;;
		2c7c:*)    source "${GENPATH}genchat.sh"
		;;
		1e0e:*)    source "${GENPATH}genchat.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

initSIM

logg "For starters, Power cycle modem"
powerCycleModem

while true; do
	serport='/dev/modem_tty'
	if [ -e "${serport}" ]; then
		# load variables
		sourceConf "${sim_id}"
		# generate modem_init and modem_chat
		generateFiles

		logg "Using SIM${sim_id}, try $sim_try_count"
		logg "Port found: '$serport'"

		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

		let sim_try_count=sim_try_count+1
		if [ -e /var/local/telem/was_connected ]; then
			modem_errors=0
			modem_io_errors=0
			rm /var/local/telem/was_connected
			switchSIM
		elif [ $sim_try_count -gt $sim_try_max ]; then
			switchSIM
		fi
	else
		logg "Error, not valid port! (${serport})"
		doOnModemError
		$CHECKUSB
		sleep 10
	fi
done
