# Parser DATA form XMM and T7xx modems
# copyright by Konstantine Shevlakov (koshev-msk) 2026

function modem_data(){
	generic_data
	# hwdata
	OIFS="$IFS";IFS="|"
	set -- $(echo "$O" | awk '
		/\+GTPKGVER:/{gsub("\"","");fw=$2}
		/CGMI:/ {gsub("\"|\r","",$0); split($0,a,":"); manuf=a[2]}
		/GMM:|FMM:/ {gsub("\"|\r","",$0); split($0,a,/[:,]/);  model=a[2]}
		/CCID:/ {iccid=$2; getline imsi; getline imei}
		/\+CIMI:/ {imsi=$2}
		/\+CGSN:/ {imei=$2}
		/\+MTSM:/ {split($0,a,":"); temp=a[2]}
		END { print manuf "|" model "|" fw "|" iccid "|" imsi "|" imei "|" temp }
	')
	DEVICE="$(echo ${1} ${2})"; FW=${3}; ICCID=${4}; IMSI=${5}; IMEI=${6}; CHIPTEMP=${7}
	IFS="$OIFS"; unset OIFS
	# signal data
	OIFS="$IFS";IFS="|"
	set -- $(echo "$O" | awk -v mode="$MODE" '
		# define maps and variables
		BEGIN {
			map[1]=15; map[2]=25; map[3]=50; map[4]=75; map[5]=100
			csq_range["black"] = "0:0"; csq_range["red"] = "1:10"
			csq_range["orange"] = "11:20"; csq_range["green"] = "21:50"
			rsrp = rsrq = bwc = csq = rssi = csq_per = ""; csq_col = "black";
		}
		# text color percentage
		function get_csq_color(csq_raw_val) {
			if (csq_raw_val == "") return "black"
			csq_num = csq_raw_val + 0
			for (color in csq_range) {
				split(csq_range[color], limits, ":")
				min = limits[1] + 0; max = limits[2] + 0
				if (csq_num >= min && csq_num <= max) {return color}
			} return "black"
		}
		# lte mode
		mode ~ /LTE/ {
			if (/\+CEREG/){gsub("\"","");split($0,a,",");reg=a[2];lac=a[3]; cid=a[4]}
			if (/\+XLEC:/){gsub("\r","");split($0,a,/[:,]/);lte_ca=a[3]-1;bw=a[4];bwc=(bw in map)?map[bw]:""}
			if (/\+RSRP:/){split($0,a,/[:,]/);pci=a[2];earfcn=a[3];rsrp=sprintf("%.0f",a[4])}
			if (/\+RSRQ:/){split($0,a,/[:,]/);rsrq=sprintf("%.0f",a[4])}
			if (/\+XMCI: 4/){gsub(/"/,"");gsub("\r","");split($0,a,/[:,]/)
				pci=sprintf("%d", a[7])
				if (a[8] != "") earfcn=sprintf("%d", a[8])
				if (a[11] != "" && (rsrp == "" || rsrp !~ /^-?[0-9]+$/ || rsrp < -141 || rsrp > -41))
					rsrp=sprintf("%.0f", a[11] - 141)
				if (a[12] != "" && (rsrq == "" || rsrq !~ /^-?[0-9]+$/ || rsrq < -40 || rsrq > -3))
					rsrq=sprintf("%.0f", a[12] / 2 - 20)
				if (a[13] != "") sinr=sprintf("%.0f", a[13] / 4 + 5)
				if (a[14] != "") distance=sprintf("%.2f", (a[14] * 78.125 / 1000))
			}
			# RSSI not correct sending via modem. Calc manually.
			if (rsrp != "" && bwc != "" && bwc > 0) {
				csq_raw=sprintf("%.0f", ((rsrp+10*log(12*bwc)/log(10))+113)/2)
				csq = (csq_raw > 50) ? 50 : csq_raw
				csq_col = get_csq_color(csq)
				csq_per = (csq > 30) ? 100 : sprintf("%.0f", csq*100/31); rssi=(2*csq-113)
			}
		}
		# 3g mode
		mode !~ /LTE/{
			if (/\+CREG/){gsub("\"","");split($0,a,",");reg=a[2];lac=a[3];cid=a[4]}
			if (/\+RSCP:/){split($0,a,",");earfcn=a[2]}
			if (/\+XMCI: 2/) {n=split($0,a,",");sinr_raw=a[n-1]; rssi_raw=a[n-2]; sinr = sprintf("%.0f", (sinr_raw*24)/24-50); rssi = (rssi_raw*64/64-110)
				csq=rssi_raw/2; csq_col = get_csq_color(csq); csq_per = (csq > 30) ? 100 : sprintf("%.0f", csq*100/31)}
			rsrp=""
		}
		END {print reg "|" earfcn "|" lac "|" cid "|" rssi "|" sinr "|" rsrp "|" rsrq "|" bw "|" bwc "|" pci "|" lte_ca "|" csq_col "|" csq_per "|" distance}
	')
	REGST=${1}; EARFCN=${2}; LAC=${3}; CID=${4}; CSQ_RSSI=${5}; SINR=${6}; RSRP=${7}; RSRQ=${8}; BWDL=${9}; BWCx=${10}
	PCI=${11}; LTE_CA=${12}; CSQ_COL=${13}; CSQ_PER=${14}; DISTANCE=${15}
	IFS="$OIFS"; unset OIFS
	if [ "$MODE" = LTE ]; then
		ENBx=$(echo "$CID" | sed -e 's/..$//')
		CELLx=$(echo "$CID" | sed -e 's/^.*\(..\)$/\1/')
		CELL=$(printf %d 0x$CELLx)
		ENBID=$(printf %d 0x$ENBx)
		OIFS="$IFS";IFS="|"
		set -- $(echo "$O"| awk -F '[:,]' -v lte_ca="${LTE_CA:-0}" -v mode="$MODE" '
			# define maps and variables
			BEGIN { map[1]=3; map[2]=5; map[3]=10; map[4]=15; map[5]=20; scc = "" }
			function earfcn_to_band(channel, cmd, band) {
				if (channel == "" || channel == "0") return "N/A"
				cmd = "/usr/share/modeminfo/scripts/ch_to_band " mode " " channel
				cmd | getline band
				close(cmd)
				return (band != "" ? band : "")
			}
			# find secondary CA bands
			/\+RSRP:/ {
				for (i = 1; i <= lte_ca; i++) {
					field_num = 6 + 3 * (i - 1)
					if (field_num <= NF) {
						earfcn = $field_num; band = earfcn_to_band(earfcn)
						if (band != "") {
							scc = (scc == "") ? "+" band : scc "+" band
				                }
					}
				}
			}
			# bandwith summ CA
			/\+XLEC/ {
				gsub("\r", "", $0); bwca = 0
			        if (lte_ca >= 1 && NF >= 5) {
					val1 = $4 + 0; val2 = $5 + 0
					if (val1 in map) bwca += map[val1]
					if (val2 in map) bwca += map[val2]
				}
				for (i = 2; i <= lte_ca; i++) {
					field_num = 4 + i  # 6, 7, 8, ...
					if (field_num <= NF) {
						val = $(field_num) + 0
						if (val in map) {
							bwca += map[val]
						}
					}
				}
			}
			END { print scc "|" bwca }
		')
		SCC=${1}; BWCA=${2}
		IFS="$OIFS"; unset OIFS
	fi

	if [ "$(uci -q get modeminfo.@general[0].decimail)" = "1" ]; then
		LAC=$(printf %d 0x$LAC)
		CID=$(printf %d 0x$CID)
	fi
}
