#!/bin/bash
#
#       Copyright (C) MOXA Inc. All rights reserved.
#       Copyright (C) 2014-2015  Lock Lin <Lock.Lin@moxa.com>
#       Copyright (C) 2015       Harry YJ Jhou <HarryYJ.Jhou@moxa.com>
#
#       This software is distributed under the terms of the
#       MOXA License.  See the file COPYING-MOXA for details.
#
#       cell_mgmt
#               cellular management. It supports sierra MC9090 MC7304 MC7354.
#
 

#--------- Initialize Global variables ---------
VERSION="1.7"
BUILD_DATE="16011914"
SCRIPTNAME=$(basename $0)
LOCK_DIR="/var/lock/${SCRIPTNAME}"
CELL_MGMT_PID=$$

# check lock file and creat lock file
check_lockfile(){
for pid in $(pidof -x cell_mgmt); do
    if [ $pid != $$ ]; then
        echo "cell_mgmt is busy, please wait a moment and try again"
        _exit 60
    fi
done
}
#check_lockfile

#QMI
#new libqmi includes a tool called "qmi-proxy"
#use qmicli -p means interaction with the QMI interface of modem by "qmi-proxy"
QMICLI="/usr/bin/qmicli"
QMICLI_END="-p"
if [ -e /usr/local/libexec/qmi-proxy ]; then
	QMI_PROXY="/usr/local/libexec/qmi-proxy"
else
	QMI_PROXY="/usr/lib/libqmi/qmi-proxy"
fi

# profile
PROFILE_FILE=/etc/qmi-network.conf
#PROFILE_FILE=./qmi-network.conf
KVERSION="$(kversion | awk '{print $1}')"

load_profile ()
{
        . $PROFILE_FILE
	#KVERSION=UC-8162-LX
        eval "${KVERSION}_profile" 2>/dev/null
	if [ x"$?" != x"0" ]; then
		echo "Error: kversion or profile not found."
		_exit 9
	fi
}

search_wwan_node ()
{
	
	local module_name
	local temp_path1
	local temp_path2
	local slot_num="0"
	for i in ${MODULE_NAME_PATH[@]}
	do
		let slot_num++
		if [ -f $i ]; then
			ALL_MODULE_NAME[${#ALL_MODULE_NAME[@]}]=$(cat $i 2>/dev/null)
			ALL_SLOT_NUM[${#ALL_SLOT_NUM[@]}]=$slot_num
		else
			continue
		fi
		
                # example:
        	# i=/sys/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.3/1-1.3.1/product
                # temp_path1=/sys/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.3/1-1.3.1
                # temp_path2=1-1.3.1
		# temp_path3=1-1.3.1:?.?
		temp_path1=${i//\/product/} && temp_path2=${temp_path1//\/*\//}
                
		for temp_path3 in $(ls $temp_path1 2>/dev/null | grep $temp_path2)
		do
			if [ x"$(ls $temp_path1/$temp_path3 2>/dev/null | grep $SYS_NET)" != x"" ]; then
				SYS_NET_0=$temp_path3
			fi
			if [ x"$(ls $temp_path1/$temp_path3 2>/dev/null | grep $SYS_USB)" != x"" ]; then
				SYS_USB_0=$temp_path3
			fi
		done

		case "$(cat $i 2>/dev/null)" in
			"MC7354"|"MC7304")
				ALL_INTERFACE[${#ALL_INTERFACE[@]}]=$(ls $temp_path1/$SYS_NET_0/$SYS_NET/ 2>/dev/null)
				ALL_QMI_PORT[${#ALL_QMI_PORT[@]}]=$(ls $temp_path1/$SYS_USB_0/$SYS_USB/ 2>/dev/null)
				ALL_GPS_PORT[${#ALL_GPS_PORT[@]}]=$(ls $temp_path1/$temp_path2:1.2/ 2>/dev/null | grep tty)
				ALL_AT_PORT[${#ALL_AT_PORT[@]}]=$(ls $temp_path1/$temp_path2:1.3/ 2>/dev/null | grep tty)
				;;
			"MC9090")
                                ALL_INTERFACE[${#ALL_INTERFACE[@]}]=$(ls $temp_path1/$SYS_NET_0/$SYS_NET/ 2>/dev/null)
				ALL_QMI_PORT[${#ALL_QMI_PORT[@]}]=$(ls $temp_path1/$SYS_USB_0/$SYS_USB/ 2>/dev/null)
				ALL_GPS_PORT[${#ALL_GPS_PORT[@]}]=$(ls $temp_path1/$temp_path2:1.3/ 2>/dev/null | grep tty)
				ALL_AT_PORT[${#ALL_AT_PORT[@]}]=$(ls $temp_path1/$temp_path2:1.2/ 2>/dev/null | grep tty)
				;;
			"PH8"|"LTE Modem")
				ALL_INTERFACE[${#ALL_INTERFACE[@]}]=$(ls $temp_path1/$temp_path2:1.4/$SYS_NET/ 2>/dev/null)
				ALL_QMI_PORT[${#ALL_QMI_PORT[@]}]=$(ls $temp_path1/$temp_path2:1.4/$SYS_USB/ 2>/dev/null)
				ALL_GPS_PORT[${#ALL_GPS_PORT[@]}]=$(ls $temp_path1/$temp_path2:1.1/ 2>/dev/null | grep tty)
				ALL_AT_PORT[${#ALL_AT_PORT[@]}]=$(ls $temp_path1/$temp_path2:1.2/ 2>/dev/null | grep tty)
				;;
			#for U-Blox L280
			"MODEM-LTE")
				ALL_INTERFACE[${#ALL_INTERFACE[@]}]=$(ls $temp_path1/$temp_path2:1.0/$SYS_NET/ 2>/dev/null)
				ALL_QMI_PORT[${#ALL_QMI_PORT[@]}]="NotSupport"
				ALL_GPS_PORT[${#ALL_GPS_PORT[@]}]="NotSupport"
				ALL_AT_PORT[${#ALL_AT_PORT[@]}]=$(ls $temp_path1/$temp_path2:1.2/tty 2>/dev/null | grep tty)
				;;
			"YUGA Incorporated")
				ALL_INTERFACE[${#ALL_INTERFACE[@]}]=$(ls $temp_path1/$SYS_NET_0/$SYS_NET/ 2>/dev/null)
				ALL_QMI_PORT[${#ALL_QMI_PORT[@]}]=$(ls $temp_path1/$SYS_USB_0/$SYS_USB/ 2>/dev/null)
				ALL_GPS_PORT[${#ALL_GPS_PORT[@]}]=""
				ALL_AT_PORT[${#ALL_AT_PORT[@]}]=$(ls $temp_path1/$temp_path2:1.2/ 2>/dev/null | grep tty)
				;;
			#FIX Telit LE910
			"Android")
				ALL_INTERFACE[${#ALL_INTERFACE[@]}]=$(ls $temp_path1/$temp_path2:1.2/$SYS_NET/ 2>/dev/null)
				ALL_QMI_PORT[${#ALL_QMI_PORT[@]}]=$(ls $temp_path1/$temp_path2:1.2/$SYS_USB/ 2>/dev/null)
				ALL_GPS_PORT[${#ALL_GPS_PORT[@]}]=$(ls $temp_path1/$temp_path2:1.3/ 2>/dev/null | grep tty)
				ALL_AT_PORT[${#ALL_AT_PORT[@]}]=$(ls $temp_path1/$temp_path2:1.4/ 2>/dev/null | grep tty)
				;;
			*)
				echo "Unknown Module : $module_name"
				;;
		esac

	done
}

# search GPS_PORT AT_PORT QMI_PORT QMI_NODE
set_port ()
{
	MODULE_NAME="${ALL_MODULE_NAME[$INTERFACE]}"	
	SLOT="${ALL_SLOT_NUM[$INTERFACE]}"

	QMI_NODE="${ALL_INTERFACE[$INTERFACE]}"
	QMI_PORT="/dev/${ALL_QMI_PORT[$INTERFACE]}"
	AT_PORT="/dev/${ALL_AT_PORT[$INTERFACE]}"
	if [ x"${ALL_GPS_PORT[$INTERFACE]}" == x"NotSupport" ]; then
		GPS_PORT="NotSupport"
	else
		GPS_PORT="/dev/${ALL_GPS_PORT[$INTERFACE]}"
	fi
	##for ublox L2xx
	#[ x"MODEM-LTE" == x"$MODULE_NAME" ] && AT_PORT="/dev/ttyACM0"
}

init ()
{
	if [ -f $PROFILE_FILE ]; then
		load_profile
		search_wwan_node
		set_port
	else
		echo "Error: $PROFILE_FILE does not exist." && _exit
	fi
}

init
#__debug__
# state file for different interface
if [ x"$INTERFACE" == x"" -o x"$INTERFACE" == x"0" ]; then
	STATE_FILE=/tmp/qmi-network-state
else
	STATE_FILE=/tmp/qmi-network-state$INTERFACE
fi


#--------- Initialize Global variables ---------

#--------- qmi-network functions -----------
save_state ()
{
    local KEY=$1
    local VAL=$2

    echo "Saving state... ($KEY: $VAL)"

    if [ -f $STATE_FILE ]; then
        PREVIOUS=`cat $STATE_FILE 2>/dev/null`
        PREVIOUS=`echo "$PREVIOUS" | grep -v $KEY`
        if [ "x$PREVIOUS" != "x" ]; then
            echo $PREVIOUS > $STATE_FILE
        else
            rm $STATE_FILE
        fi
    fi

    if [ "x$VAL" != "x" ]; then
        echo "$KEY=\"$VAL\"" >> $STATE_FILE
    fi
}

load_state ()
{
    if [ -f $STATE_FILE ]; then
        # Loading previous state
        . $STATE_FILE
    fi
}

clear_state ()
{
    echo "Clearing state..."
    rm -f $STATE_FILE
}

start_network ()
{
    if [ "x$CID" != "x" ]; then
        USE_PREVIOUS_CID="--client-cid=$CID"
    fi

    if [ "x$PDH" != "x" ]; then
        echo "error: cannot re-start network, PDH already exists" 1>&2
        _exit 3
    fi

    START_NETWORK_CMD="$QMICLI -d $QMI_PORT --wds-start-network=$APN --client-no-release-cid --device-open-net=net-802-3|net-no-qos-header $QMICLI_END"
    echo "Starting network with '$START_NETWORK_CMD'..."

    if [ "x$QMIDEBUG" != "x" ]; then
        if [ x"$INTERFACE" == x"" -o x"$INTERFACE" == x"1" ]; then
        START_NETWORK_OUT="\
[/dev/cdc-wdm0] Network started
        Packet data handle: '3634026241'
[/dev/cdc-wdm0] Client ID not released:
        Service: 'wds'
        CID: '80'"
        else
        START_NETWORK_OUT="\
[/dev/cdc-wdm1] Network started
        Packet data handle: '363402624$3'
[/dev/cdc-wdm1] Client ID not released:
        Service: 'wds'
        CID: '80'"
        fi
    else
        START_NETWORK_OUT=`$START_NETWORK_CMD`
    fi

    # Save the new CID if we didn't use any before
    if [ "x$CID" = "x" ]; then
        CID=`echo "$START_NETWORK_OUT" | sed -n "s/.*CID.*'\(.*\)'.*/\1/p"`
        if [ "x$CID" = "x" ]; then
            echo "error: network start failed, client not allocated" 1>&2
            _exit 1
        else
            save_state "CID" $CID
        fi
    fi

    PDH=`echo "$START_NETWORK_OUT" | sed -n "s/.*handle.*'\(.*\)'.*/\1/p"`
    if [ "x$PDH" = "x" ]; then
        echo "error: network start failed, no packet data handle" 1>&2
        # Cleanup the client
        $QMICLI -d "$QMI_PORT" --wds-noop --client-cid="$CID" $QMICLI_END
        clear_state
        _exit 2
    else
        save_state "PDH" $PDH
    fi

    echo "Network started successfully"
}

stop_network ()
{
    if [ "x$CID" = "x" ]; then
        echo "Network already stopped"
    elif [ "x$PDH" = "x" ]; then
        echo "Network already stopped; need to cleanup CID $CID"
        # Cleanup the client
        $QMICLI -d "$QMI_PORT" --wds-noop --client-cid="$CID" $QMICLI_END
    else
        STOP_NETWORK_CMD="$QMICLI -d $QMI_PORT --wds-stop-network=$PDH --client-cid=$CID $QMICLI_END"
        echo "Stopping network with '$STOP_NETWORK_CMD'..."

        if [ "x$QMIDEBUG" != "x" ]; then
            STOP_NETWORK_OUT="\
[/dev/cdc-wdm$INTERFACE] Network stopped
"
        else
            STOP_NETWORK_OUT=`$STOP_NETWORK_CMD`
        fi

        echo "Network stopped successfully"
    fi

    clear_state
}

packet_service_status ()
{
    if [ "x$CID" != "x" ]; then
        USE_PREVIOUS_CID="--client-cid=$CID --client-no-release-cid"
    fi

    STATUS_CMD="$QMICLI -d $QMI_PORT --wds-get-packet-service-status $USE_PREVIOUS_CID $QMICLI_END"
    echo "Getting status with '$STATUS_CMD'..."

    if [ "x$QMIDEBUG" != "x" ]; then
        STATUS_OUT="\
[/dev/cdc-wdm0] Connection status: 'disconnected'
"
    else
        STATUS_OUT=`$STATUS_CMD`
    fi

    CONN=`echo "$STATUS_OUT" | sed -n "s/.*Connection status:.*'\(.*\)'.*/\1/p"`
    if [ "x$CONN" = "x" ]; then
        echo "error: couldn't get packet service status" 1>&2
        _exit 2
    else
        echo "Status: $CONN"
        if [ "x$CONN" != "xconnected" ]; then
            _exit 64
        fi
    fi
}

# Load previous state, if any
load_state

#--------- qmi-network functions -----------


#check proxy status
chk_proxy_status () {
	local proxy_status=`ps ax | grep -v "grep" | grep "qmi-proxy"`	

	#if [ ! -e ${QMI_PORT} ]; then
	#	_exit 
	#fi

	if [ -z "$proxy_status" ]; then
                #running in the background
                ${QMI_PROXY} &
        fi
}

#check cellular status
cell_status () {

	# check Ublox L2xx module
	if [ x"MODEM-LTE" == x"$MODULE_NAME" ]; then
		Ublox_L2xx_cell_status
		_exit 0
	fi
	
	# check proxy status
        chk_proxy_status

	local con_status=$(packet_service_status | grep "Status")
	echo ${con_status}
        if [ x"$(echo ${con_status}| awk '{print $2}')" == x"connected" ]; then
            _exit 0
        else
            _exit 1
        fi
}

#cellular signal strength in dbm
cell_signal () {
	
	# check Ublox L2xx module
	if [ x"MODEM-LTE" == x"$MODULE_NAME" ]; then
		Ublox_L2xx_cell_signal
		_exit 0
	fi

	# check proxy status
        chk_proxy_status
        local signal 
        signal=`$QMICLI -d ${QMI_PORT} --nas-get-signal-strength $QMICLI_END | tr "'" " " | grep "Network" | head -1 | awk '{print $2 " " $4}'`
        signal_dbm="$(echo $signal | awk '{print $2}')"
        if [ "$signal_dbm" -le "-1" 2>/dev/null ] && [ "$signal_dbm" -ge "-110" 2>/dev/null ] ; then
                echo "${signal} dbm"
                return 0
        else
                echo "signal out of range"
                return 1
        fi
}

#cellular power on by GPIO
cell_power_on () {
	local module_name
	local at_port

	IFS=$'\n'
	for i in $POWER_ON_FUN ;
	do
		eval "$i"
	done

	while ((1))
	do
		# reset port
		init
		module_name=$(cell_m_info | grep Module)
		at_port=$(cell_m_info | grep AT_port)
		[ x"$module_name" != x"Module=" ] && [ x"$at_port" != x"AT_port=/dev/" ] && break
		sleep 1
	done

}

#cellular power off by GPIO
cell_power_off () {
	
	cell_stop;
	
	IFS=$'\n'
	for i in $POWER_OFF_FUN ;
	do
		eval "$i"
	done
}


#dhclient
cell_dhclient () {
	local node="$1"
	local ignore_dns_gw="$2"
	local info_ip_mask=""
	local info_ip=""
	local info_mask=""
	local info_gw=""
	local info_dns=""
	local ret=""

	if [ x"$ignore_dns_gw" == x"1" ];   then
		# check Ublox L2xx module
		if [ x"MODEM-LTE" == x"$MODULE_NAME" ]; then
cat << EOF > /etc/dhcp/dhclient-enter-hooks.d/no-default-route
case \$reason in
    BOUND|RENEW|REBIND|REBOOT)
        unset new_domain_name_servers
        unset new_routers
      ;;
esac
EOF
		else
cat << EOF > /etc/dhcp/dhclient-enter-hooks.d/no-default-route
case \$reason in
    BOUND|RENEW|REBIND|REBOOT)
        echo "IP=\$new_ip_address"
        echo "SubnetMask=\$new_subnet_mask"
        echo "Gateway=\$new_routers"
        echo "DNS=\$new_domain_name_servers"
        unset new_domain_name_servers
        unset new_routers
      ;;
esac
EOF
		fi

	fi
	
	# check Ublox L2xx module
	if [ x"MODEM-LTE" == x"$MODULE_NAME" ]; then
		ret="$(cell_at_cmd 'AT+CGCONTRDP' 1)"
		# e.g. +CGCONTRDP: 1,0,"internet","10.38.142.94.255.255.255.255","10.38.142.94","168.95.1.1","168.95.192.1","0.0.0.0","0.0.0.0",0 OK
		ret=${ret#*\",\"}
		info_ip_mask=${ret%%\",\"*}
		info_ip=$(echo $info_ip_mask | awk -F "." '{print $1"."$2"."$3"."$4}')
		info_mask=$(echo $info_ip_mask | awk -F "." '{print $5"."$6"."$7"."$8}')
		
		ret=${ret#*\",\"}
		info_gw=${ret%%\",\"*}
	
		ret=${ret#*\",\"}
		dns1=${ret%%\",\"*}

		ret=${ret#*\",\"}
		dns2=${ret%%\",\"*}
		
		if [ x"$ignore_dns_gw" == x"1" ]; then
			echo "IP=$info_ip"
			echo "SubnetMask=$info_mask"
			echo "Gateway=$info_gw"
			echo "DNS=$dns1 $dns2"
		else
			echo "nameserver $dns1" > /etc/resolv.conf
			echo "nameserver $dns2" >> /etc/resolv.conf
		fi
		ifconfig $node $info_ip
		return
	fi

	dhclient $node
	rm /etc/dhcp/dhclient-enter-hooks.d/no-default-route 2>/dev/null
	
}

#	---------------for Ublox L2xx---------------
Ublox_L2xx_cell_start () {
	local ignore_dns_gw=$1
	local retry=0
	local ret
	stty -F ${AT_PORT} -echo -onlcr -icrnl

	# check USB interface (RNDIS)
	ret=$(cell_at_cmd 'AT+UUSBCONF?' | grep "RNDIS" )
	if [ x"$ret" == x"" ]; then
		echo "Switch USB interface to RNDIS"
		cell_at_cmd 'AT+UUSBCONF=3'
		echo "Please try again"
		_exit 5
	fi

	# check networking mode (bridge mode)
	ret=$(cell_at_cmd 'AT+UBMCONF?' | grep "+UBMCONF:" )
	if [ x"$ret" != x"+UBMCONF: 2" ]; then
		echo "Switch networking mode to bridge mode"
		cell_at_cmd 'AT+UBMCONF=2'
		echo "Please try again"
		_exit 6
	fi

	# APN
	cell_at_cmd "AT+CGDCONT=1,\"IP\",\"$APN\"" > /dev/null
	cell_at_cmd "AT+UCGDFLT=1,\"IP\",\"$APN\"" > /dev/null

	# connect
	if [ x"$(cell_at_cmd 'AT+CFUN?'| grep '+CFUN: 1' )" == x"" ]; then
		cell_at_cmd 'AT+CFUN=1' > /dev/null
		sleep 8
	fi

	# check 3G/4G
	ret=$(cell_at_cmd 'AT+COPS?' | grep "+COPS:" )
	cell_at_cmd 'AT+CGACT=1,1' 2 > /dev/null
	
	#echo $ret
	#if [ x"$ret" == x"+COPS: 0" ]; then
	#	cell_at_cmd 'AT+CGACT=1,1' > /dev/null
	#fi
	#sleep 3
	ret=""
	ret=$(cell_at_cmd 'AT+COPS?' | grep "+COPS:" )
	if [ x"$ret" == x"" -o x"$ret" == x"+COPS: 0" ]; then
		echo "Error: Can't connect to ISP"
		_exit 7
	#else
	#	if [ x"$(echo $ret| grep '",7')" != x"" ]; then
	#		#echo "4G"
	#	elif [ x"$(echo $ret| grep '",2')" != x"" ]; then
	#		echo "3G"
	#	else
	#		echo "Error: Can't identify 3G/4G signal"
	#		_exit 8
	#	fi
	fi

	cell_dhclient usb0 $ignore_dns_gw

}

Ublox_L2xx_cell_stop () {
	#echo -n -e '+++\r\n' > ${AT_PORT}
	#echo -n -e 'AT+CGACT=0,1\r\n' > ${AT_PORT}
	dhclient -r $QMI_NODE
	cell_at_cmd 'AT+CFUN=4' > /dev/null
}

Ublox_L2xx_cell_restart () {

	Ublox_L2xx_cell_stop
	sleep 5
	Ublox_L2xx_cell_start

}

Ublox_L2xx_cell_status () {

	local status_cops
	local status_3g
	local status_4g

	status_cops="$(cell_at_cmd 'AT+COPS?\r\n' | grep '+COPS: 0')"
	status_3g=$(cell_at_cmd 'AT+CGACT?\r\n' | grep '+CGACT: 1,1')
	status_4g=$(cell_at_cmd 'AT+CGACT?\r\n' | grep '+CGACT: 4,1')

	if [ x"$status_3g" != x"" -o x"$status_4g" != x"" ]; then
		if [ x"$status_cops" == x"+COPS: 0" ]; then
			echo "Status: disconnected"
		else
			echo "Status: connected"
		fi
	else
		echo "Status: disconnected"
	fi

}

Ublox_L2xx_cell_sim_status () {

	local ret
	ret=$(cell_at_cmd 'AT+CPIN?' | grep '+CPIN:')

	if [ x"$ret" != x"" ]; then
		echo "$ret"
	else
		echo "Please insert the cellular module and reboot."
	fi

}

Ublox_L2xx_cell_signal () {
	local signal

	signal=$(cell_at_cmd 'AT+CSQ\r\n' | awk '{print $2}')
	signal=${signal##*AT}
	signal=${signal%%,*}
	
	if [ x"$signal" != x"" ]; then
		if [ "$signal" -le "30" 2>/dev/null ] && [ "$signal" -ge "2" 2>/dev/null ] ; then
			let signal=signal-2
			let signal=signal*2-109
			echo "umts $signal dbm"	
		else
			echo "signal out of range"
		fi
	else
		echo "signal out of range"
	fi
}

Ublox_L2xx_cell_pin_protection () {
	local pin_num="$1"
	local pin_enable="$2"
	local pin_current="$3"
	local ret

	if [ x"$pin_num" != x"PIN" ]; then
		echo "For this module, pin_protection support PIN(1) only."
		_exit 99
	fi

	ret="$(cell_sim_status | grep 'READY')"
	if [ x"$ret" == x"" ]; then
		#unlock sim card
		ret="$(cell_at_cmd "AT+CPIN=\"$pin_current\"" | grep 'ERROR')"
		if [ x"$ret" != x"" ]; then
			echo "PIN code error"
			_exit 99
		fi
	fi

	if [ x"$pin_enable" == x"enable" ]; then
		pin_enable=1
	elif [ x"$pin_enable" == x"disable" ]; then
		pin_enable=0
	else
		echo "Usage:"	
		echo -e "\033[1;37;40mcell_mgmt pin_protection [PIN|PIN2] [enable|disable] [current_PIN]\033[0;37;40m"
		_exit 99
	fi

	if [ x"" == x"" ]; then
		ret="$(cell_at_cmd \"AT+CLCK="SC",$pin_enable,\"$pin_current\"\" | grep 'ERROR')"
		if [ x"$ret" != x"" ]; then
			echo "Set PIN protection error."
			_exit 99
		fi
	fi

}

#	--------------------------------------------

# AT command 
cell_at_cmd () {

	local cmd="$1"
	local time_out="$2"

	if [ x"$cmd" == x"" ]; then
		echo "command is null."
		return
	fi
	
	if [ x"${AT_PORT}" == x"/dev/" ]; then
		echo "modem port not found."
		return
	fi
	
	if [ x"$time_out" == x"" ]; then
		time_out=0.3
	fi
	
	echo -n -e "ATE0\r\n" > ${AT_PORT}
	timeout 0.3 cat ${AT_PORT} >/dev/null
	echo -n -e "$cmd\r\n" > ${AT_PORT}
	timeout $time_out cat ${AT_PORT} | tr -d '\r'

}

# module info
cell_m_info () {

	local lac=""
	local cellid=""
	local info_apn=""
	local ret=""
	local iccid=""
	local imei=""

	cell_at_cmd 'AT+CREG=2' > /dev/null
	ret=$(cell_at_cmd 'AT+CREG?' | grep '+CREG:' )
	[ "${#ret}" -lt "11" ] && ret=""
	if [ x"$ret" == x"" ]; then
		lac="Unknown"
		cellid="Unknown"
	else
		lac=${ret#*\"}
		lac=${lac%%\"*}
		cellid=${ret%\"*}
		cellid=${cellid##*\"}
	fi

	#for ublox L2xx
	if [ x"MODEM-LTE" == x"$MODULE_NAME" ]; then
		iccid=$(cell_at_cmd 'AT+CCID' | grep '+CCID:' | awk '{print $2}' )
		imei=$(cell_at_cmd 'at+cgsn' | grep -v "OK" | grep -v '^[[:space:]]*$')
	elif [ x"MC7304" == x"$MODULE_NAME" ]; then
		iccid=$(cell_at_cmd 'AT!ICCID?' | grep 'ICCID:' | awk '{print $2}' )
		imei=$(cell_at_cmd 'at+cgsn' | grep -v "OK" | grep -v '^[[:space:]]*$')
	elif [ x"MC7354" == x"$MODULE_NAME" ]; then
		iccid=$(cell_at_cmd 'AT!ICCID?' | grep 'ICCID:' | awk '{print $2}' )
		imei=$(cell_at_cmd 'at+cgsn' | grep -v "OK" | grep -v '^[[:space:]]*$')
	fi

	echo Module=$MODULE_NAME
	echo WWAN_node=$QMI_NODE
	echo AT_port=$AT_PORT
	echo GPS_port=$GPS_PORT	
	echo LAC=$lac
	echo CellID=$cellid
	echo ICC-ID=$iccid
	echo IMEI=$imei
	echo QMI_port=$QMI_PORT
	#echo slot=$SLOT
        #echo SYS_USB=$SYS_USB	

}

#cellular start
cell_start () {

	local ignore_dns_gw=0
        # check proxy status
        chk_proxy_status
        	
	local interface_num="$INTERFACE"
	[ x"$interface_num" == x"0" ] && interface_num=""
	
	local pin_status
	APN="$(eval echo \$APN$interface_num)"
	Username="$(eval echo \$Username$interface_num)"
	Password="$(eval echo \$Password$interface_num)"
	PIN="$(eval echo \$PIN$interface_num)" 

	# modify APN Username Password PIN
	for args in $@
	do
		for par in "APN" "Username" "Password" "PIN"
		do
			if [ $(echo $args | grep "$par=") ]; then
				eval "$par=${args##*$par=}"
				eval "sed -i s/$par$interface_num=.*/$par$interface_num=\$$par/ $PROFILE_FILE"
			fi
		done
		[ x"$args" == x"ignore-dns-gw" ] && ignore_dns_gw=1
	done
	
	# check APN
	if [ x"$(eval echo \$APN$interface_num)" == x"" ]; then
		echo "warning : APN is NULL."
		echo "Usage:"
		echo "	cell_mgmt \"start\"[APN=[APN], Username=[username], Password=[password], PIN=[pin_code]]"
		echo "example:"
		echo "          cell_mgmt start APN=internet Username=user Password=pass PIN=0000"
		_exit 1
	fi

	# check Ublox L2xx module
	if [ x"MODEM-LTE" == x"$MODULE_NAME" ]; then
		Ublox_L2xx_cell_start $ignore_dns_gw
		_exit 0
	fi

	# Check PIN status
	# if PIN status are not verified
	# use the PIN code user input to verify automatically.
	pin_status="$($QMICLI -d $QMI_PORT --dms-uim-get-pin-status $QMICLI_END | grep "Status" | head -n 1)"
	if [ "$(echo $pin_status | grep "disabled")" ]; then
		echo "PIN code:Verified" # no pin code
	elif [ "$(echo $pin_status | grep "enabled-verified" )" ]; then
		echo "PIN code:Verified"
	else
		echo "PIN code:Not Verified"
		# Verify
		$QMICLI -d $QMI_PORT --dms-uim-verify-pin=PIN,$PIN $QMICLI_END
		echo "Please wait ..."
		sleep 10
	fi
	
	start_network
	# query IP from DHCP Server 
	cell_dhclient ${QMI_NODE} $ignore_dns_gw	

        _exit 0
}


cell_pin_code_status () {

	local pin_status

	pin_status="$($QMICLI -d $QMI_PORT --dms-uim-get-pin-status $QMICLI_END | grep "Status" | head -n 1)"
        if [ "$(echo $pin_status | grep "disabled")" ]; then
		echo "PIN code:Verified" && _exit 2
        elif [ "$(echo $pin_status | grep "enabled-verified" )" ]; then
		echo "PIN code:Verified" && _exit 0
	else
		echo "PIN code:Not Verified" && _exit 1 
	fi

}

# cellular stop
cell_stop () {
	# check Ublox L2xx module
	if [ x"MODEM-LTE" == x"$MODULE_NAME" ]; then
		Ublox_L2xx_cell_stop
		return 0
	fi

	# release IP by dhclient -r
	if [ x"${QMI_NODE}" != x"" ]; then
		dhclient -r ${QMI_NODE}
	fi
	# cellular stop by qmi-network
	stop_network
}

# cellular restart
cell_restart () {
	# check Ublox L2xx module
	if [ x"MODEM-LTE" == x"$MODULE_NAME" ]; then
		Ublox_L2xx_cell_restart
		return 0
	fi
	# restart cellular (reconnect)
	cell_stop
	sleep 5
        cell_start
}

# cellular reset
cell_reset () {
	# reset cellular (module)
	echo -e -n "AT!RESET\r\n" > ${AT_PORT}
	echo "Done!"
}

# cellular set to default
cell_set_to_default () {
	
	local choise
	
	printf "\E[0;31;40m"
	echo "WARNING:It will RESET module to factory default"	
	printf "\E[0m"
	read -p "Do you want to continune?(y/n):" choice

	
	# check module status 
	cell_check_module 2>/dev/null
	[ x"$?" != x"0" ] && _exit
	
	if [ $choice = "y" ]; then
		# entercnd : Enable access to password-protected commands
		echo -e -n "AT!NVBACKUP=0" > ${AT_PORT} &> /dev/null
		# set to default
		echo -e -n "AT!NVBACKUP=0" > ${AT_PORT} &> /dev/null
		echo -e -n "AT!NVDEF" > ${AT_PORT} &> /dev/null
		echo -e -n "AT!NVRESTORE=0" > ${AT_PORT} &> /dev/null
		echo -e -n "AT!NVRESTORE=1" > ${AT_PORT} &> /dev/null
		echo -e -n "AT!NVRESTORE=2" > ${AT_PORT} &> /dev/null

        	if [ -e "$PROFILE_FILE" ]; then
			cell_restart	
        	else
        		echo "warning : file $PROFILE_FILE does not exist."
        		cell_stop
        		sleep 5
        		echo "you neet to set the config file by 'cell_mgmt start'."
        	fi
	fi
}

# cellular sim status
cell_sim_status () {

	local ret
	ret=$(cell_at_cmd 'AT+CPIN?' | grep '+CPIN:')

	if [ x"$ret" != x"" ]; then
		echo "$ret"
	else
		echo "Please insert the sim card and reboot."
		_exit 1
	fi

	_exit 0
}


# set pin code
cell_set_pin () {

	local ret
	# check proxy status
	chk_proxy_status

	local pin_code="$1"
	[ -z $pin_code ] && echo "Usage: cell_mgmt set_pin [pin_code]" && _exit 1
	if [ -e $PROFILE_FILE ]; then
		echo "old PIN=$PIN, new PIN=$pin_code"
		sed -i "s/PIN=.*/PIN=$pin_code/" $PROFILE_FILE
		if [ x"$(cell_sim_status |grep READY)" == x"" ]; then
			ret=$(cell_at_cmd "AT+CPIN=$pin_code" | grep 'ERROR')
			if [ x"$ret" != x"" ]; then
				echo $ret
				_exit 8
			fi
		fi
		#verify pin code
		#$QMICLI -d $QMI_PORT --dms-uim-verify-pin=PIN,$pin_code $QMICLI_END
	else
		echo -e "APN=\nusername=\npassword=\nPIN=$pin_code"
	fi
        _exit 0
}

# sim card pin code protection
cell_pin_protection (){

	# check Ublox L2xx module
	if [ x"MODEM-LTE" == x"$MODULE_NAME" ]; then
		Ublox_L2xx_cell_pin_protection $1 $2 $3
		_exit 0
	fi
	# check proxy status
	chk_proxy_status

	local pin_num="$1"
	local pin_enable="$2"
	local pin_current="$3"
	local par_fail="0"		
	# user does not give current pin
	[ $# -ne 3 ] && par_fail="1"
	[ x"$pin_num" != x"PIN" ] && [ x$pin_num != x"PIN2" ] && par_fail="1"
	[ x"$pin_enable" != x"enable" ] && [ x$pin_enable != x"disable" ] && par_fail="1"

	if [ $par_fail = "1" ]; then
		echo "Usage: cell_mgmt pin_protection [PIN|PIN2] [enable|disable] [current_PIN]"
		_exit 1
	else
		$QMICLI -d $QMI_PORT --dms-uim-set-pin-protection=$pin_num,$pin_enable,$pin_current $QMICLI_END
		_exit 0
	fi

}

# cellular gps on
cell_gps_on () {
	case "$MODULE_NAME" in
		"MC7354"|"MC7304"|"MC9090")
			echo -n "\$GPS_START" > ${GPS_PORT}
			;;
		"PH8")
			echo -n -e 'AT^SGPSC="Engine","1"\r\n' > ${AT_PORT}
			;;
		"Android")
			echo -n -e 'AT$GPSNMUN=1,1,0,0,0,0,0\r\n' > ${AT_PORT}
			sleep 1
			echo -n -e 'AT$GPSP=1\r\n' > ${AT_PORT}
			;;
		*)
			echo "errro module name: $MODULE_NAME" && _exit 1
			;;
        esac        
        echo "GPS function is *ENABLE*"
}

# cellular gps off
cell_gps_off () {
	case "$MODULE_NAME" in
		"MC7354"|"MC7304"|"MC9090")
			echo -n "\$GPS_STOP" > ${GPS_PORT}
			;;
		"PH8")
			echo -n -e 'AT^SGPSC="Engine","0"\r\n' > ${AT_PORT}
			;;
		"Android")
			echo -n -e 'AT$GPSNMUN=0,1,0,0,0,0,0\r\n' > ${AT_PORT}
			;;
		*)
			echo "errro module name: $MODULE_NAME" && _exit 1
			;;
	esac        
	echo "GPS function is *DISABLE*"
}


# check module
cell_check_module () {

	if [ x"${AT_PORT}" == x"/dev/" ]; then
		echo "Please insert the cellular module and reboot."
		return "1"
	else
		return "0"
	fi

}

# chekc current carrier
cell_check_carrier () {

	# check proxy status
        chk_proxy_status

	# chekc module status 
	cell_check_module
	[ x"$?" != x"0" ] && _exit

	if [ x"$MODULE_NAME" == x"MC7354" ]; then

                local module_info=""
                local time="4"
                
		cell_at_cmd 'ATE0' > /dev/null
		cell_at_cmd 'AT!entercnd="A710"' > /dev/null
		module_info=$(cell_at_cmd 'AT!GOBISETIMAGEPREF?')
                
                #preffered
                local pre_fw=$(echo "$module_info" |grep "pre" | grep "fw" | awk -F: '{print $2}') && pre_fw=${pre_fw// /}
                local pre_carrier_name=$(echo "$module_info"|grep "pre" | grep "carrier" | awk -F: '{print $2}') && \
                	pre_carrier_name=${pre_carrier_name// /}	
                local pre_config=$(echo "$module_info"|grep "pre" | grep "config" | awk -F: '{print $2}' ) && \
                	pre_config=${pre_config// /}
                
                #current
                local fw=$(echo "$module_info" |grep "current" | grep "fw" | awk -F: '{print $2}') && fw=${fw// /}
                local carrier_name=$(echo "$module_info"|grep "current" | grep "carrier" | awk -F: '{print $2}') && \
                	carrier_name=${carrier_name// /}	
                local config=$(echo "$module_info"|grep "current" | grep "config" | awk -F: '{print $2}' ) && \
                	config=${config// /}
                
                echo "----------Carrier Info----------"
                echo "preffered firmware=$pre_fw"
                echo "preffered carrier name=$pre_carrier_name"
                echo "preffered carrier config=$pre_config"
                
                echo "firmware=$fw"
                echo "carrier name=$carrier_name"
                echo "carrier config=$config"
                echo -e "--------------------------------"
                _exit 0
        elif [ x"$MODULE_NAME" == x"MC9090" ]; then
                $QMICLI -d ${QMI_PORT} --dms-list-stored-images $QMICLI_END
                _exit 0 
        else    
                echo "Check Carrier Frequency Bands support for MC7354 MC9090"
                _exit 1 
        fi
}

# switching between US carrier frequency bands
cell_switch_carrier () {
	
        # check proxy status
        chk_proxy_status

	# chekc module information
	cell_check_module
	[ x"$?" != x"0" ] && _exit
	
        if [ x"$MODULE_NAME" == x"MC7354" ]; then
	
                local ISP=$1	
                local module_info=""
                local choice="1"	
                local cmd="AT!GOBISETIMAGEPREF="
               
		cell_at_cmd 'ATE0' > /dev/null
                
		# enable password protected command
                cell_at_cmd 'AT!entercnd="A710"' > /dev/null
                #wait
                
                echo "----------switch_carrier------------"	
            
                # use AT+CGMR to get firmware infomation
                module_info=$(cell_at_cmd 'AT+CGMR' | grep "_" )
                module_info=${module_info/*_/}
                module_info=${module_info/ */}
                fw="$module_info"
                
                [ x"$1" = x"ATT" ] && carrier="ATT"
                [ x"$1" = x"Verizon" ] && carrier="VZW"
                [ x"$1" = x"Sprint" ] && carrier="SPRINT"
                [ x"$1" = x"Generic" ] && carrier="GENNA-UMTS"
                
		# use AT!priid? to get carrier information 
		module_info=$(cell_at_cmd 'AT!priid?' 2 | grep "$carrier")
                config=$(echo $module_info | awk 'BEGIN {FS="_"}; {print $7}' )
		config=${config}_$(echo $module_info | awk 'BEGIN {FS="_"}; {print $8}' )
                
		case "$1" in
                	Verizon)	
                		cmd="${cmd}\"${fw}\",\"VZW\",\"VZW_${config}\""
                		;;
                	ATT)
                		cmd="${cmd}\"${fw}\",\"ATT\",\"ATT_${config}\""
                		;;
                	Sprint)
                		cmd="${cmd}\"${fw}\",\"SPRINT\",\"SPRINT_${config}\""
                		;;
                	Generic)
                		cmd="${cmd}\"${fw}\",\"GENNA-UMTS\",\"GENNA-UMTS_${config}\""
                		;;
                	*)	
                		echo -e "\033[1;37;40mUsage: \033[0;37;40m"
                		echo -e "\033[1;37;40m       switch_carrier [$CARRIER]\033[0;37;40m"	
                		choice="0"
                		;;
                esac
		# switching function is MC7354 only
                if [ "$choice" -eq "1" ]; then
                	
                	echo "cmd=$cmd"
                	cell_at_cmd 'ATE0'
                	cell_at_cmd 'AT!entercnd="A710"'
                	cell_at_cmd "$cmd"
			
			echo "wait for power off..."
                	cell_power_off
                	echo "wait for power on..."
                	cell_power_on
                
                fi
        elif [ x"$MODULE_NAME" == x"MC9090" ]; then
                carrier=""
                [ x"$1" = x"ATT" ] && carrier="pri0"
                [ x"$1" = x"Verizon" ] && carrier="pri2"
                [ x"$1" = x"Sprint" ] && carrier="pri1"
                [ x"$1" = x"Generic" ] && carrier="pri0"
                if [ x"$carrier" == x"" ]; then
                        echo -e "\033[1;37;40mUsage: \033[0;37;40m"
                        echo -e "\033[1;37;40m       switch_carrier [$CARRIER]\033[0;37;40m"
                        _exit 1
                fi
                $QMICLI -d ${QMI_PORT} --dms-select-stored-image=modem2,$carrier $QMICLI_END 
                sleep 1
                $QMICLI -d ${QMI_PORT} --dms-set-operating-mode=offline $QMICLI_END
                sleep 1
                $QMICLI -d ${QMI_PORT} --dms-set-operating-mode=reset $QMICLI_END
                sleep 1 
                _exit 0
        else
   	        echo "Switching Carrier Frequency Bands support for MC7354 MC9090"
                _exit 1
        fi
}


# telecommunication operator
cell_operator () {
	local result
	result=$(cell_at_cmd 'AT+COPS?' | grep COPS:)
	result=${result#*,\"}
	result=${result%%\",*}
	if [ x"$(echo $result | grep COPS)" != x ]; then
		echo "Unknown telecom operator"
	else
		echo $result
	fi
	
}

# cell_mgmt setinterface
cell_interface () {

	case $1 in
		"0" | "1" | "2" | "3")
	               	[ $1 -ge ${#ALL_INTERFACE[@]} ] && echo "Interface out of range." && _exit 1 
			sed -i "s/INTERFACE=.*/INTERFACE=$1/" $PROFILE_FILE
	                echo "set interface=$1"
	                _exit 0
			;;
		"")
			for (( i=0 ; i<${#ALL_INTERFACE[@]} ; i++ ))
			do
				echo "[$i] ${ALL_INTERFACE[$i]}$([ x$i == x$INTERFACE ] && echo '   <Current>')"
			done
			;;
		*)
	                echo "Usage: cell_mgmt \"interface\" [0~3]"
	                echo "example:"
	                echo "          cell_mgmt interface 0"
	                _exit 1
			;;
	esac

}

# cell_mgmt version
cell_version () {
        echo "cell_mgmt"
        echo "version:$VERSION"
}

# show cell_mgmt usage list
cell_usage () {
        echo -e "\033[1;37;40mcell_mgmt support sierra MC9090 MC7304 MC7354\033[0;37;40m"
	echo -e "\033[1;37;40mUsage: \033[0;37;40m"
	echo -e "\033[1;37;40m      $0 \033[0;37;40m[\033[4;37;40mOPTIONS\033[0;37;40m]\n"
	echo -e "\033[1;37;40mOPTIONS\033[0;37;40m"
	#start
	echo -e "\033[1;37;40m       start\033[0;37;40m [APN=[APN],Username=[user],Password=[pass],PIN=[pin_code]]"
	echo -e "		Start network."
	echo -e ""
 	echo -e "               example:"
	echo -e "                       cell_mgmt start"
	echo -e "                       cell_mgmt start APN=internet"
	echo -e "                       cell_mgmt start APN=internet PIN=0000"
	echo -e "                       cell_mgmt start APN=internet Username=moxa Password=pass PIN=0000"
	#stop
	echo -e "\033[1;37;40m       stop\033[0;37;40m"	
	echo -e "		Stop network."
	#restart
	echo -e "\033[1;37;40m       restart\033[0;37;40m"	
	echo -e "		Restart network."
	#reset
	echo -e "\033[1;37;40m       reset\033[0;37;40m"	
	echo -e "		Reset cellular."
	#power on
	echo -e "\033[1;37;40m       power_on\033[0;37;40m"	
	echo -e "		Power ON."
	#power off 
	echo -e "\033[1;37;40m       power_off\033[0;37;40m"	
	echo -e "		Power OFF."
	#gps on
	echo -e "\033[1;37;40m       gps_on\033[0;37;40m"	
	echo -e "		GPS ON."
	#gps off 
	echo -e "\033[1;37;40m       gps_off\033[0;37;40m"	
	echo -e "		GPS OFF."
	#status 
	echo -e "\033[1;37;40m       status\033[0;37;40m"	
	echo -e "		Query network connection status."
	#signal 
	echo -e "\033[1;37;40m       signal\033[0;37;40m"	
	echo -e "		Get signal strength."
	#set_default 
	echo -e "\033[1;37;40m       set_default\033[0;37;40m"	
	echo -e "		RESET module to factory default."
	#at 
	echo -e "\033[1;37;40m       at\033[0;37;40m ['AT_COMMAND']"	
	echo -e "		Input AT Command."
	echo -e "		Must use SINGLE QUOTATION to enclose AT Command."
	#sim_status
	echo -e "\033[1;37;40m       sim_status\033[0;37;40m"	
	echo -e "		Query sim card status."
	#set_pin 
	echo -e "\033[1;37;40m       set_pin [PIN]\033[0;37;40m"	
	echo -e "		Set PIN code to configuration file."
	#protection_pin 
	echo -e "\033[1;37;40m       pin_protection [PIN|PIN2] [enable|disable] [current_PIN]\033[0;37;40m"	
	echo -e "		Set PIN protection in the UIM."
	#check_carrier 
	echo -e "\033[1;37;40m       check_carrier\033[0;37;40m"	
	echo -e "		Check current carrier."
	#switch_carrier 
	echo -e "\033[1;37;40m       switch_carrier [$CARRIER]\033[0;37;40m"	
	echo -e "		Switching between US carrier frequency bands."
	#interface
	echo -e "\033[1;37;40m       interface [#slot]\033[0;37;40m"	
	echo -e "		Switching and checking module slot."
	#m_info
	echo -e "\033[1;37;40m       m_info\033[0;37;40m"	
	echo -e "		Module information."
	#operator
	echo -e "\033[1;37;40m       operator\033[0;37;40m"	
	echo -e "		Telecommunication operator."
	#version
        echo -e "\033[1;37;40m       version\033[0;37;40m"	
	echo -e "		Cellular management version."
    

}

_exit() {
	flock -u 9
	exit $1
}

(
	flock -w 60 9 || { echo "cell_mgmt is busy, please wait a moment and try again" ; _exit 1; }
	case "$1" in
		start)
			cell_start $2 $3 $4 $5
			;;
		stop)
			cell_stop
			;;
		reset)
			cell_reset
			;;
		restart)
			cell_restart
			;;
		gps_on)
			cell_gps_on
			;;
		gps_off)
			cell_gps_off
			;;
		power_on)
			cell_power_on
			;;
		power_off)
			cell_power_off
			;;
		status)
			cell_status
			;;
		signal)
			cell_signal
			;;
		set_default)
			cell_set_to_default
			;;
		sim_status)
			cell_sim_status
			;;
	        pin_code_status)
        	        cell_pin_code_status
			;;
		set_pin)
			cell_set_pin $2
			;;
		pin_protection)
			cell_pin_protection $2 $3 $4
			;;
		check_carrier)
			cell_check_carrier
			;;
		switch_carrier)
			cell_switch_carrier $2
			;;
		at)
			cell_at_cmd $2 $3
			;;
		version)
        	        cell_version
                	;;
	        interface)
			cell_interface $2
			;;
		m_info)
			cell_m_info
			;;
		operator)
			cell_operator
			;;
		help)
			cell_usage	
			;;
		*)
			cell_usage
			_exit 3
			;;
	esac

	flock -u 9
) 9> /tmp/cell_mgmt.lock
