#!/bin/bash -p
######################################################################################
#                                                                                    #
#  Ericsson AB 2001-2021    - All Rights Reserved                                   #
#                                                                                    #
# The copyright to the computer program(s) herein is the property   of Ericsson AB,  #
# Sweden. The programs may be used and/or copied only with the written permission    #
# from Ericsson AB or in accordance with the terms and  conditions stipulated in the #
# agreement/contract under which the program(s) have been supplied.                  #
#                                                                                    #
######################################################################################
#To decode the output of rdsfp -d <port>  or sfp -d <port>  or DU/XMU/RU/RRU
#Based on SFF-8472 : Specification for Diagnostic Monitoring Interface for Optical Transceivers

moshelldir=`dirname "$0"`
if [[ $moshelldir != /* ]] ; then moshelldir=`pwd`/$moshelldir ; fi
vobsinstallation=0
unamea=$(uname -a)
gawkext=""
gawklib=""
if [[ $unamea = [Ll][iI][nN][uU][xX]*x86_64* ]] ; then gawklib="lin64"   ; if [[ $vobsinstallation = 1 ]] ; then gawkext=".lin64" ; fi
elif [[ $unamea = [Ll][iI][nN][uU][xX]* ]]      ; then gawklib="linux"   ; if [[ $vobsinstallation = 1 ]] ; then gawkext=".linux" ; fi
elif [[ $unamea = SunOS*sparc* ]]               ; then gawklib="solaris" ; if [[ $vobsinstallation = 1 ]] ; then gawkext=".solaris" ; fi
elif [[ $unamea = SunOS* ]]                     ; then gawklib="sol86"   ; if [[ $vobsinstallation = 1 ]] ; then gawkext=".sol86" ; fi
else gawklib="cygwin" ; gawkext=".exe"
fi
gawkprog="gawk${gawkext}"
gawk="$moshelldir/$gawkprog"
#special case where moshell has been installed on a linux 32 bit machine but should be run on linux 64 sharing the same file system
if [[ $unamea = [Ll][iI][nN][uU][xX]*x86_64* && $vobsinstallation != 1 && `file "$moshelldir/gawk"` = *32-bit* ]] ; then gawklib="linux" ; fi
filefunc="$moshelldir/commonjars/lib/${gawklib}/filefuncs"
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH:+${LD_LIBRARY_PATH}:}$moshelldir/commonjars/lib/${gawklib}
export LANG=C
export LC_ALL=C

globmoshellrc=$moshelldir/jarxml/moshellrc
commonjardir=$moshelldir/commonjars
jarxmldir=$moshelldir/jarxml
defLogDir=$commonjardir/defLogDir.sh
moshellrc=$($defLogDir)


$gawk -f $moshelldir/funcs.awk -v moshelldir="$moshelldir" -v vobsinstallation="$vobsinstallation" -v globmoshellrc="$globmoshellrc" -v moshellrc="$moshellrc" -l "$filefunc" --source '
BEGIN{
	loadFilefuncs()
	parse_user_variables(moshell)
	parse_user_variables(globmoshellrc)
	parse_user_variables(moshellrc)
	make_xx_table()
	make_yy_table()
	make_zz_table()
	if (java=="") java="java"
	if (os~"cygwin") { "cygpath -m "moshelldir | getline moshelldir ; close("cygpath -m "moshelldir) }
	#print java,moshelldir
	sfpdecoder=java" -cp "moshelldir"/commonjars/sfpdecoder.jar Main"
}
{
	gsub(/\r|\x00|\xa1/,"")
	if (!($0~/^====================+$/ || $2=="lhsh" || $0=="$ " || $1=="coli>/fruacc/lhsh")) print
	if ($1~/^[^: ]+:$/)
	{
		#dont use any of the below as prefix
		#sfpChecksumBase: Valid
		#sfpChecksumExtended: Valid
		#sfpChecksumDMI: Valid
		if ($1!~/^sfp/) prefix=$1" "
		sub(/^[^: ]+: +/,"")
		$0=$0
	}
	#=============================================================================================
	#lhsh xxx sfp -d 0
	#lhsh xxx sfp -d 0 -m
	#lhsh xxx sfp -m -d 1   => when command is run with "-m" option first then we shall substract 1 to the port, this is when we are running sfp command on AIR64
	#lhsh xxx sfp -d 00 -m  => when the port is double-digit 00 or 01 then we must switch around port 0 and 1 so that port 0 becomes 1 and port 1 becomes 0
	#coli>/fruacc/lhsh BXP_2 sfp -d 0
	if ($0~/^====================+$/ || $2=="lhsh" || $0=="$ " || $1=="coli>/fruacc/lhsh")
	{
		if ($2=="lhsh" || $1=="coli>/fruacc/lhsh")
		{
			if ($NF=="-m")
			{
				port=$(NF-1)
				if (port=="00") port=1
				else if (port=="01") port=0
			}
			else if (NF>2 && $(NF-1)=="-d" && $(NF-2)=="-m") port=$NF - 1  #AIR64: port 1,2,3 map to 0,1,2
			else port=$NF
			tcommand=$0
			rioport=-1
			if ($1=="coli>/fruacc/lhsh") tmpbd=$2
		}
		if (buffer!="") { sdec(buffer) ; buffer="" }
		print
		delete bVal
	}
	if (/^ *[0-9A-Fa-f]{4} +[0-9A-Fa-f]{8} +[0-9A-Fa-f]{8} +[0-9A-Fa-f]{8} +[0-9A-Fa-f]{8} +["]?................["]? *$/)
	{
		buffer=buffer"\n"$0
	}
	else if (tcommand ~ /\/sfpdump +[0-9]/ && $1=="|" && $0~/ (TX|RX) Power (Low|High) Alarm \(uW\)|Temperature (Low|High) Alarm \(C\)/)
	{
		#| Temperature Low Alarm (C)        | -48.000        |
		#| Temperature High Alarm (C)       | 93.000         |
		#| TX Power Low Alarm (uW)      | 95               |
		#| TX Power High Alarm (uW)     | 1584             |
		#| RX Power Low Alarm (uW)      | 22               |
		#| RX Power High Alarm (uW)     | 1778             |
		#New format in 19.Q1:
		#| TX Power Low Alarm (uW) [dBm]    | 794 [-1.002]     |
		#| TX Power High Alarm (uW) [dBm]   | 3981 [6.000]     |
		#| RX Power Low Alarm (uW) [dBm]    | 12 [-19.208]     |
		#| RX Power High Alarm (uW) [dBm]   | 1778 [2.499]     |
		t_header=prefix "SFPDECODER ("port"): "
		if ($(NF-1)~/^\[.*\]$/) gsub(/[ \t]+\[[^\]]*\][ \t]+/," ")
		split($0,arr,/\|/)
		for (y in arr) gsub(/^[ \t]+|[ \t]+$/,"",arr[y])
		if (arr[2]=="Temperature Low Alarm (C)") t_buff=t_header xx[arr[2]] " = "sprintf("%.0f C",arr[3])
		else t_buff=t_buff"\n"t_header xx[arr[2]] " = "(arr[2]~"Temperature"?sprintf("%.0f C",arr[3]):sprintf("%.1f dBm",10*mylog(arr[3]/1000)/log(10)))
	}
	else if ((tcommand ~ /\/sfpdump +[0-9]/ && $0 ~ / \((C|V|mA|mW)\): /) ||\
	         (tcommand ~ /\/sfpdump +[0-9]/ && $1=="|" && $0~/ (Temperature \(C\)|Voltage \(mV\)|TX Power \(uW\)|RX Power \(uW\)|TX Bias Low Warning \(mA\)|TX Bias \(mA\)|TX Bias High Warning \(mA\)|(TX|RX) Power (Low|High) Alarm \(uW\)) /))
	{
		#coli>/fruacc/lhsh 000100 /fruacc/du/sfpdump 0
		#Temperature           (C): 30.816
		#Vcc                   (V):  3.319
		#TX Power             (mW):  0.701
		#RX Power             (mW):  0.729
		#TX Bias              (mA): 40.314
		#TX Bias Low Warning  (mA): 20.000
		#TX Bias High Warning (mA): 80.000

		#New format in 18.Q2:
		#| Temperature (C)              | 52               |
		#| Voltage (mV)                 | 3323             |
		#| TX Power (uW)                | 763              |
		#| RX Power (uW)                | 685              |
		#| TX Bias Low Warning (mA)     | 12               |
		#| TX Bias (mA)                 | 45               |
		#| TX Bias High Warning (mA)    | 93               |
		#New format in 19.Q1:
		#| Temperature (C)                  | 28.824           |
		#| Voltage (mV)                 | 3323             |
		#| TX Power (uW) [dBm]              | 1681 [2.256]     |
		#| RX Power (uW) [dBm]              | 1610 [2.068]     |
		#| TX Bias Low Warning (mA)         | 37.500           |
		#| TX Bias (mA)                     | 79.472           |
		#| TX Bias High Warning (mA)        | 108.000          |
		if ($1=="|" && $2~/^(Temperature|Voltage|TX|RX)$/)
		{
			#convert the new format to old format
			gsub(/\|/,"")
			if ($NF~/^\[.*\]$/) gsub(/[ \t]+\[[^\]]*\][ \t]+/," ")
			if ($1=="Voltage" && $2=="(mV)") { $1="Vcc" ; $2="(V)" ; $NF=sprintf("%.3f",$NF/1000) }
			else if ($2=="Power" && $3=="(uW)") { $3="(mW)" ; $NF=sprintf("%.3f",$NF/1000) }
			$0=$0
			#print "DEBUG: "$0
		}

		t_header=prefix "SFPDECODER ("port"): "
		if ($1=="Temperature") t_buff=t_buff"\n"t_header "SFP Temperature = "sprintf("%.0f C",$NF)
		else if ($1=="Vcc")    t_buff=t_buff"\n"t_header "SFP Voltage = "sprintf("%.2f Volts",$NF)
		else if ($2=="Power")  t_buff=t_buff"\n"t_header "SFP "$1" power = "sprintf("%.5f dBm",10*mylog($NF)/log(10))
		else if ($2=="Bias")
		{
			if ($3=="(mA):" || $3=="(mA)")
			{
				t_bias=$NF
				t_buff=t_buff"\n"t_header "SFP TX Bias = "sprintf("%.1f mA",$NF)
			}
			else if ($3=="Low") t_low=$NF
			else if ($3=="High")
			{
				t_high=$NF
				t_buff=t_buff"\n"t_header "SFP TX Bias Level = "sprintf("%.0f%",mDiv(100 * (t_bias - t_low) , (t_high - t_low)))
				print t_buff
				t_buff=""
			}
		}
	}
	else if (tcommand ~ /rioistat (moddiag all|modinfo all)/)
	{
		#Port:                        0x2
		#Port:                        0x80000000
		#Port:          0x80000025
		#Temperature           | (0.1 C)   | 402
		#Voltage               | (100 mV)  | 32943
		#TX Bias Low Warning   | (0.01 mA) | 2000
		#TX Bias High Warning  | (0.01 mA) | 8000
		#TX Bias               | (0.01 mA) | 3985
		#TX Power              | (uW)      | 610
		#RX Power              | (uW)      | 616

		if ($1=="Port:")
		{
			#port=sprintf("%d",strtonum($2))-1
			#match($2,/([0-9a-fA-F])$/,ab)
			#port=ab[1]
			port=++rioport
			t_header=prefix "SFPDECODER ("port"): "
		}
		if ($1=="Temperature" && $2=="|")  t_buff=t_header "SFP Temperature = "sprintf("%.0f C",$NF/10)
		else if ($1=="Voltage" && $2=="|") t_buff=t_buff"\n"t_header "SFP Voltage = "sprintf("%.2f Volts",$NF/10000)
		else if ($2=="Power" && $3=="|")  t_buff=t_buff"\n"t_header "SFP "$1" power = "sprintf("%.5f dBm",10*mylog($NF/1000)/log(10))
		else if ($2=="Bias")
		{
			if ($3=="|")
			{
				t_bias=$NF
				t_buff=t_buff"\n"t_header "SFP TX Bias = "sprintf("%.1f mA",$NF/100)
				t_buff=t_buff"\n"t_header "SFP TX Bias Level = "sprintf("%.0f%",mDiv(100 * (t_bias - t_low) , (t_high - t_low)))
			}
			else if ($3=="Low" && $4=="Warning") t_low=$NF
			else if ($3=="High" && $4=="Warning")
			{
				t_high=$NF
			}
		}
		if ($1=="RX" && $2=="Power" && $3=="|")
		{
			print t_buff
			t_buff=""
		}

		if (tcommand ~ /rioistat modinfo all/)
		{
			#Vendor:                       SOURCEPHOTONICS
			#Vendor part number:           SPP10ELRIDFFEN1
			#Vendor serial number:         H722002378
			#Vendor revision:              10
			#Manufacturing date(YYMMDDLL): 170601
			#Manufacturing date(YYMMDDLL): 2017-03-15
			#Speed:                        10.0 Gbps
			#Ericsson SFP:                 TRUE
			#Product number:               RDH10265/3
			#Revision:                     R1A

			split($0,arr,":")
			for (y in arr) gsub(/^[ \t]+|[ \t]+$/,"",arr[y])
			if (yy[arr[1]]=="") next
			#if (arr[1]~/Ericsson SFP|^Product number|^Revision)/) next #skip the Ericsson part
			if (arr[1]~/Ericsson SFP/ && tolower(arr[2])=="true") arr[2]="MONI"
			if (arr[1]~/Manufacturing date/)
			{
				if (arr[2]~/^20[0-9][0-9]-/) gsub(/-/,"",arr[2])
				else arr[2]="20"(length(arr[2])==8?gensub(/..$/,"",1,arr[2]):arr[2])
			}
			if (arr[1]=="Vendor")
			{
				t_buff="" ; gsub(/[? \t]/,"",arr[2])
			}
			if (arr[1]=="Speed") arr[2]=10*gensub(/ .*$/,"",1,arr[2])
			t_buff=t_buff"\n"t_header yy[arr[1]] " = "arr[2]
			if (arr[1]=="Revision")
			{
				print gensub(/^\n/,"",1,t_buff)
				t_buff=""
			}
		}
	}
	#AIR6468 without RIO interface:
	#SFP port: 1
	#module info:
	#SFP type = Optical
	#Ericsson approved SFP = Yes
	#Ericsson Product Number = RDH10265/31
	#Ericsson Product Revision = R1A
	#sfpVendorName = DELTA
	#sfpVendorOUI = 20F85E
	#sfpProductNumber = LCP-10G3B4QDRTJA
	#sfpProductRevision = A
	#sfpSerialNumber = 164609M02491
	#sfpManufactureDate = 2016-11-11
	#sfpMinBitRate (units of 100Mbps) = 24
	#sfpNominalBitRate (units of 100Mbps) = 103
	#sfpMaxBitRate (units of 100Mbps) = 103
	#sfpETHSpeed = 10 Gbit/s
	#sfpETHCompliance = 10G Base_LR
	#sfpWavelength (nm) = 1310
	#sfpCablelength 9/125 μm fiber (units of 1km) = 10
	#module diagnostic:
	#Temperature:     33343mC (AL:-48000, WL:-43000 .. WH:88000, AH:93000)
	#Voltage    :   3277400uV (AL:2970000, WL:3102000 .. WH:3498000, AH:3630000)
	#TX Bias    :     35094uA (AL:5000, WL:10000 .. WH:95000, AH:100000)
	#TX Power   :       573uW (AL:95, WL:120 .. WH:1258, AH:1584)
	#RX Power   :       566uW (AL:22, WL:28 .. WH:1412, AH:1778)
	else if (tcommand ~ /sfp -d[12]/ && $0~/^[^:]+: /)
	{
		split($0,arr,": ")
		for (y in arr) gsub(/^[ \t]+|[ \t]+$/,"",arr[y])
		if (arr[1]=="SFP port")
		{
			#port 2 is 0 (DATA_1), port 1 is 1 (DATA_2), port 0 is not applicable
			port=arr[2]
			if (port==2) port=0
			t_header=prefix "SFPDECODER ("port"): "
			t_buff=""
		}
		if (arr[1]=="Temperature")  t_buff=t_buff"\n"t_header "SFP Temperature = "sprintf("%.0f C",$2/1000)
		else if ($1=="Voltage") t_buff=t_buff"\n"t_header "SFP Voltage = "sprintf("%.2f Volts",$3/1000000)
		else if ($2=="Power")  t_buff=t_buff"\n"t_header "SFP "$1" power = "sprintf("%.5f dBm",10*mylog($4/1000)/log(10))
		else if ($2=="Bias")
		{
			t_bias=$4
			t_low=gensub(/WL:/,"",1,$6)
			t_high=gensub(/WH:/,"",1,$8)
			t_buff=t_buff"\n"t_header "SFP TX Bias = "sprintf("%.1f mA",t_bias/1000)
			t_buff=t_buff"\n"t_header "SFP TX Bias Level = "sprintf("%.0f%",mDiv(100 * (t_bias - t_low) , (t_high - t_low)))

		}
		if (arr[1]=="RX Power")
		{
			print gensub(/^\n/,"",1,t_buff)
			t_buff=""
		}
	}
	else if (tcommand ~ /sfp -d[12]/ && $0~/^[^=]+ = /)
	{
		split($0,arr," = ")
		gsub(/[? \t]/,"",arr[2])
		for (y in arr) gsub(/^[ \t]+|[ \t]+$/,"",arr[y])
		if (arr[1]~/Ericsson approved SFP/ && tolower(arr[2])=="Yes") arr[2]="MONI"
		else if (arr[1]~/sfpManufactureDate/)
		{
			if (arr[2]~/^20[0-9][0-9]-/) gsub(/-/,"",arr[2])
			else arr[2]="20"(length(arr[2])==8?gensub(/..$/,"",1,arr[2]):arr[2])
		}
		else if (arr[1]~/sfpWavelength/) arr[2]=sprintf("%.2f",arr[2])
		t_buff=t_buff"\n"t_header (yy[arr[1]]!=""?yy[arr[1]]:arr[1]) " = "arr[2]
	}
	else if (tcommand ~ /\/sfpdump +[0-9]/ && $1=="|" && $0~/ (Type|Vendor (Name|Product No|Revision)|Serial No|Production Date|Nom Bit Rate|Supported Rate|Ericsson (SFP|Product No|Revision)|Wavelength \(nm\)) /)
	{
		#0001: | Type                         | Electrical       |
		#0001: | Type                         | Optical          |
		#0001: | Vendor Name                  | FINISAR CORP.    |
		#0001: | Vendor Product No            | FTLX1471D3BCL-E1 |
		#0001: | Vendor Revision              | A                |
		#0001: | Serial No                    | AYR0Z1G          |
		#0001: | Production Date              | 171222           |
		#0001: | Ericsson SFP                 | True             |
		#0001: | Ericsson Product No          | RDH10250/3       |
		#0001: | Ericsson Revision            |                  |
		#0001: | Nom Bit Rate (100MBd)        | 103              |
		#0001: | Supported Rate (100MBd)      | 26               |
		#0001: | Wavelength (nm)              | 1552.52          |
		t_header=prefix "SFPDECODER ("port"): "
		split($0,arr,/\|/)
		for (y in arr) gsub(/^[ \t]+|[ \t]+$/,"",arr[y])
		if (arr[2]~/Ericsson SFP/ && tolower(arr[3])=="true") arr[3]="MONI"
		#if (arr[2]~/Ericsson (SFP|Product No|Revision)/) next #skip the Ericsson part, seems sometimes unreliable in sfpdump  ==> we keep it now
		#the production is sometimes shown like 151231 or 15123101 instead of 20151231
		if (arr[2]~/Production Date/)
		{
			#The date is always 6 digits but sometimes there are two characters at the end such as "01" , or two letters, or a letter and a number: 200720KZ, 2006055S , 200724Q9, 16072701
			#if (length(arr[3])==8 && arr[3]!~/^20/ && arr[3]~/0[01]$/) arr[3]="20"gensub(/0[01]$/,"",1,arr[3])
			#else if (length(arr[3])==6) arr[3]="20"arr[3]
			arr[3]="20"(length(arr[3])==8?gensub(/..$/,"",1,arr[3]):arr[3])
		}
		if (arr[2]=="Vendor Name") gsub(/[ \t]|[?]/,"",arr[3])
		t_buff=t_buff"\n"t_header xx[arr[2]] " = "arr[3]
		if (/ Nom Bit Rate |[|] Supported Rate \(/)
		{
			#DU:
			#0001: | Nom Bit Rate (100MBd)        | 103              |
			#RU/XMU:
			#0001: | Supported Rate (100MBd)      | 26               |
			print gensub(/^\n/,"",1,t_buff)
			t_buff=""
		}
		if (/ Wavelength \(nm\) / && arr[3]!="0.00") print t_header xx[arr[2]] " = "arr[3]
	}
	else if (tcommand ~ /\/sfpdump +[0-9]/ && $1=="|" && $2~/^(preamble|cc_base|cc_ext|cc_dmi)$/)
	{
		#0001: | preamble                         | Valid            |
		#0001: | cc_base                          | Invalid          |
		#0001: | cc_ext                           | Valid            |
		#0001: | cc_dmi                           | Valid            |
		t_header=prefix "SFPDECODER ("port"): "
		split($0,arr,/\|/)
		for (y in arr) gsub(/^[ \t]+|[ \t]+$/,"",arr[y])
		if (arr[2]=="preamble") t_buff2=""
		if (arr[3]=="Invalid") t_buff2=t_buff2 zz[arr[2]]","
		if (arr[2]=="cc_dmi" && t_buff2!="")
		{
			#print t_header xx["Vendor Name"]" = FAULTY_SFP"
			#print t_header xx["Production Date"]" = FAIL#"gensub(/,$/,"",1,t_buff2)
			print t_header xx["Vendor Name"]" = CKSFAIL#"gensub(/,$/,"",1,t_buff2)
			t_buff2=""
		}
	}
	else if (tcommand ~ / eqpm rdSfp diagnostic_data all/)
	{
		#RdId: 0
		#Temperature(C):  51
		#Voltage(100 uV): 32191
		#Tx Power(uW):    501
		#Rx Power(uW):    389
		#Tx Bias(2uA):    24525
		#Temperature Alarm Threshold Low (C):   -48
		#Temperature Alarm Threshold High (C):  93
		#Voltage Alarm Threshold Low (100 uV):  29700
		#Voltage Alarm Threshold High (100 uV): 36300
		#TX Power Alarm Threshold Low (uW):     95
		#TX Power Alarm Threshold High (uW):    1778
		#Rx Power Alarm Threshold Low (uW):     34
		#Rx Power Alarm Threshold High (uW):    1778
		#Tx Bias Alarm Threshold Low (2uA):     7600
		#Tx Bias Alarm Threshold High (2uA):    40250
		if ($1=="RdId:")
		{
			port=101+$2
			t_header=prefix "SFPDECODER ("port"): "
		}
		if ($1=="Temperature(C):")  t_buff=t_header "SFP Temperature = "sprintf("%.0f C",$NF)
		else if ($1=="Voltage(100") t_buff=t_buff"\n"t_header "SFP Voltage = "sprintf("%.2f Volts",$NF/10000)
		else if ($2=="Power(uW):")  t_buff=t_buff"\n"t_header "SFP "toupper($1)" power = "sprintf("%.5f dBm",10*mylog($NF/1000)/log(10))
		else if ($2=="Bias(2uA):")
		{
			t_bias=$NF
			t_buff=t_buff"\n"t_header "SFP TX Bias = "sprintf("%.1f mA",$NF/500)
			print t_buff
			t_buff=""
		}
		else if ($2=="Bias")
		{
			if ($5=="Low") t_low=$NF
			else if ($5=="High")
			{
				t_high=$NF
				t_buff=t_buff"\n"t_header "SFP TX Bias Level = "sprintf("%.0f%",mDiv(100 * (t_bias - t_low) , (t_high - t_low)))
				print t_buff
				t_buff=""
			}
		}
	}
	else if (tcommand ~ /\/fruacc\/lhlist +ldn/)
	{
		#ManagedElement=1,Equipment=1,FieldReplaceableUnit=2              BXP_0                XMU 03 01              KDU 137 949/1          R1D/A          D16K238685          20141107
		#ManagedElement=1,Equipment=1,FieldReplaceableUnit=2              BXP_1                XMU 03 01              KDU 137 949/1          R1D/A          D16K238685          20141107
		#ManagedElement=1,Equipment=1,FieldReplaceableUnit=3              BXP_2                XMU 03 01              KDU 137 949/1          R1D/A          D16N036434          20150217
		#ManagedElement=1,Equipment=1,FieldReplaceableUnit=3              BXP_3                XMU 03 01              KDU 137 949/1          R1D/A          D16N036434          20150217
		#ManagedElement=1,Equipment=1,FieldReplaceableUnit=4              BXP_4                Baseband R503          KDU 137 949/1          R1H            D16T149957          20160503
		#ManagedElement=1,Equipment=1,FieldReplaceableUnit=4              BXP_5                Baseband R503          KDU 137 949/1          R1H            D16T149957          20160503
		if (/ XMU *03|d *R503 /) is_xmu[$2]=1
		#ManagedElement=1,Equipment=1,FieldReplaceableUnit=2          BXP_2048_0           Radio 4466 B1B3B7          KRC 161 923/1          P1A          EA8A532176          20210622       
		if ($2~/^BXP_/) bxpList[$2]=bxpTable[$2]=$2

	}
	else if (tcommand ~ /\/sfpvalues/)
	{
		if (/ SFP thresholds on /)
		{
			tboard=tport=""
			#the BXP can be like BXP_1024 or BXP_1024_X  -> only keep the first part, eg BXP_1024
			if ($0 ~ /\(BXP_/)
			{
				#new SW >= 19Q1: 0001: |  SFP thresholds on DU_1 (BXP_2049) for port 0  |
				match($0,/ SFP thresholds on DU_[_0-9]+ \((BXP_[0-9]+)[_0-9]*\) for port ([0-9]+)/,a)
			}
			else
			{
				#old SW: 0001: |  SFP thresholds on DU_3 for port 15            |
				match($0,/ SFP thresholds on DU_([_0-9]+) for port ([0-9]+)/,a)
				a[1]="BXP_"a[1]
			}
			tport=a[2]
			if (tmpbd!="000100") tboard=tmpbd a[1]    #eg du3/ , du4/ ...
			else tboard=a[1]
			if (tboard~/BXP_[0-5]$/ && is_xmu[tboard]==1)
			{
				if (tport~/^(8|9|10|11)$/) a[1]-=1   #XMU ports on second splitter group RU side
				else if (tport~/^[3-7]$/)  a[1]-=2   #XMU ports on third  splitter group RU side
				else if (tport==1) a[1]-=1 #XMU port on second splitter group DU side
				else if (tport==2) a[1]-=2 #XMU port on third  splitter group DU side
			}
		}
		if (/High Warning/) twh=$9
		else if (/Low Warning/) twl=$9
		else if ($2~/^[1-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]$/ && $3~/^[0-9][0-9]:[0-9][0-9]:[0-9][0-9]\.[0-9]+$/)
		{
			invals=1;tt1=$5;tt2=$7;tt3=$9;tt4=$11;tt5=$13
			#current bugs in sfpvalues command (now ignored)
			#TX bias value is doubled on RU
			#TX/RX power is 10 times too high on XMU
			#Below fixes removed:
			#### if (is_xmu[tboard]==1 && (tt4+0)>1000) { tt4=tt4/10 ; tt5=tt5/10 }
			#### if (is_xmu[tboard]!=1) tt3*=2
		}
		else if (invals==1)
		{
			invals=0
			if (tboard=="" || tport=="") next
			print "coli>/fruacc/lhsh "tboard" /fake/sfpdump "tport
			print tboard": SFPDECODER ("tport"): SFP Temperature = "sprintf("%.0f C",tt1)
			print tboard": SFPDECODER ("tport"): SFP Voltage = "tt2" Volts"
			print tboard": SFPDECODER ("tport"): SFP TX Bias = "sprintf("%.1f mA",tt3/1000)
			print tboard": SFPDECODER ("tport"): SFP TX Bias Level = "sprintf("%.0f%",mDiv(100 * (tt3 - twl),(twh - twl)))
			print tboard": SFPDECODER ("tport"): SFP TX power = "sprintf("%.3f dBm",10*mylog(tt4/1000)/log(10))
			print tboard": SFPDECODER ("tport"): SFP RX power = "sprintf("%.3f dBm",10*mylog(tt5/1000)/log(10))
		}
	}
	#|            Unit DU_4 (BXP_1026) : Port 0            |
	#fru_512: |                   Unit DU : Port 0                  |
	else if (($1=="|" && $2=="Unit" && $5==":" && $6=="Port" && $3~/^DU_/ )||\
	         ($1=="|" && $2=="Unit" && $4==":" && $5=="Port" && $3=="DU" && tmpbd~/fru_/))
	{
		tboard=tport=""
		#the BXP can be like BXP_1024 or BXP_1024_X  -> only keep the first part, eg BXP_1024
		if ($3~/^DU_/) match($0,/ Unit DU_[_0-9]+ \((BXP_[0-9]+)[_0-9]*\) : Port ([0-9]+)/,a)
		else if ($3=="DU") { a[1]=tmpbd ; a[2]=$6 }
		#print "HERE",a[1],a[2]
		tport=a[2]
		if (tmpbd=="000100") tboard=a[1]
		else if ($3=="DU" && tmpbd~/fru_/) tboard=tmpbd  #RGW ports
		else tboard=gensub(/\/$/,"",1,tmpbd) "/" a[1]    #boards connected to du3/ , du4/ , fru_512

		if (tboard~/BXP_102/ && is_xmu[tboard]==1)
		{
			if (tport~/^(8|9|10|11)$/) a[1]-=1   #XMU ports on second splitter group RU side
			else if (tport~/^[3-7]$/)  a[1]-=2   #XMU ports on third  splitter group RU side
			else if (tport==1) a[1]-=1 #XMU port on second splitter group DU side
			else if (tport==2) a[1]-=2 #XMU port on third  splitter group DU side
		}
		#print "HERE2",tboard,tport
		if (bxpList[tboard]=="") 
		{
			#the board was not found in lhlist, for instance sometimes lhlist only has BXP_2048_0 but not BXP_2048
			#try to find the corresponding board from lhlist
			q=xpsort(bxpTable)
			for (g=1;g<=q;g++)
			{
				tmpboard=gensub(/_[0-9]$/,"",1,bxpTable[g])
				if (tmpboard==tboard) 
				{
					tboard=bxpTable[g]
					break
				}
			}
		}
		#print "HERE3",tboard,tport
		#if (tboard=="" || tport=="") next
		port=tport
		tcommand="coli>/fruacc/lhsh "tboard" /fake/sfpdump "tport
		print tcommand
	}
	else if ($1=="sfpWaveLength(nm)" && $2=="=") bVal[$1]=$3
}
END{
	if (buffer!="") sdec(buffer)
}
function sdec(input,  n,a,i,b,j,c,s,z,v,k,m,w,d,t,start,stop,area,byte,theVal,f,cal,r,r0,r1,r2,r3,r4,docheck,checkRes,tsum,tres,ec,e)
{
	header=prefix "SFPDECODER ("port"): "
	idec()
	n=split(input,a,"\n")
	for (i=1;i<=n;i++)
	{
		w=split(a[i],b," ")
		if (w<5) continue
		s=h2d(b[1])+0
		if (s>=256)
		{
			s-=256
			#On most RU/RRU , the byte numbering for A2 starts again at 0000 .
			#But on RRUS31, the byte number for A2 starts at 0100 (= 256) so we remove 256 if s is greater than 256
		}
		#print s,a[i]
		if (s==0) z++
		#print z,s,b[2],b[3],b[4],b[5]
		t=b[2] b[3] b[4] b[5]
		v=0
		split(t,c,"")
		for (k=1;k<=32;k++)
		{
			byte[z,s+v]=c[k] c[k+1]
			v++
			k++
		}
	}
	#for (m in byte) { split(m,d,SUBSEP) ; printf("%3s %3s %s\n",d[1],d[2],byte[m]) }
	#consistency checks
	docheck=tres=0
	ec=""
	for (i=0;i<=255;i++) { if ((1,i) in byte && byte[1,i]!="00") docheck=1 }
	if (tcommand ~ /tnsfpinfo/) docheck=0
	delete checkRes
	checkRes[1]=checkRes[2]=checkRes[3]=0
	if (docheck==1)
	{
		if (sprintf("%s%s",byte[1,0],byte[1,1])!~/^0[3bB]04$/) { checkRes[1]=tres=1 ; ec="1" }  #the first byte must be 03 (SFP) or 0b (DWDM-SFP) => first two bytes 0304 or 0b04
		tsum=0
		for (i=0;i<=62;i++) tsum+=sprintf("%d",strtonum("0x"byte[1,i]))
		if (tsum%256 != sprintf("%d",strtonum("0x"byte[1,63]))) { checkRes[2]=tres=1 ; ec=ec",2" }
		tsum=0
		for (i=64;i<=94;i++) tsum+=sprintf("%d",strtonum("0x"byte[1,i]))
		if (tsum%256 != sprintf("%d",strtonum("0x"byte[1,95]))) { checkRes[3]=tres=1 ; ec=ec",3" }
		if (checkRes[1]==1 || checkRes[2]==1)
		{
			#print header "sfpVendorName = FAULTY_SFP"
			#print header "sfpManufactureDate = FAIL#"gensub(/^,/,"",1,ec)
			print header "sfpVendorName = CKSFAIL#"gensub(/^,/,"",1,ec)
			return
		}
	}
	#decoding
	for (i=1;i<=Max;i++)
	{
		split(fPos[i],e,",")
		if (e[1]=="A0") area=1 ; else area=2
		start=e[2] ; stop=e[3]
		for (j=start;j<=stop;j++)
		{
			thebyte=byte[area,j]
			if (i<Max1)
			{
				if (j==2) thebyte=translate_connector_type(thebyte)
				else if (byte[area,j]=="00" || byte[area,j]=="20") thebyte=""
				else thebyte=sprintf("%c",strtonum("0x"byte[area,j]))
			}
			else if (i==Max1) thebyte=h2d(byte[area,j])
			fVal[i]=fVal[i] thebyte
		}
		if (fName[i]=="sfpManufactureDate")
		{
			fVal[i]=todate(fVal[i])
			#if (checkRes[3]==1) fVal[i]="FAIL#3"
		}
		else if (fName[i]=="EricssonProductRev")
		{
			split(fVal[i],f,"")
			if (f[1]==0 || f[1]>31) fVal[i]=""
			else fVal[i]="R" f[1] int2char(f[2])
		}
		else if (fName[i]=="sfpWaveLength(nm)")
		{
			split(fVal[i],f,"")
			fVal[i]=sprintf("%d.%02d",h2d(sprintf("%s%s%s%s",f[1],f[2],f[3],f[4])),h2d(sprintf("%s%s",f[5],f[6])))
			#sub(/\.0*$/,"",fVal[i])
			if (bVal[fName[i]]!="") 
			{
				fVal[i]=bVal[fName[i]] 
				delete bVal
			}
		}
		else if (i>Max1 && i<=Max3) fVal[i]=h2d(fVal[i])
		#if (fName[i]=="sfpSerialNumber" && checkRes[3]==1) fVal[i]="FAULTY_SFP"
		if (fName[i]=="sfpVendorName" && checkRes[3]==1) fVal[i]="CKSFAIL#3"

		#print i" "fName[i]" "fVal[i]
	}
	if (fVal[1]=="" && fVal[2]=="" && fVal[3]=="" && fVal[4]=="" && fVal[5]=="" && fVal[6]=="") return
	for (i=1;i<=Max2;i++)
	{
		gsub(/\xa1|\x01/,"",fVal[i])
		print header fName[i]" = "fVal[i]
	}
	#print byte[1,92],h2b(byte[1,92])
	split(h2b(byte[1,92]),a,"")  #internal cal : a[3] , external cal: a[4]
	if (a[3]==a[4])
	{
		print header "Erroneous value in byte 92 internalcal=externalcal"
		return
	}
	if (a[3]==1) cal="i" ; else cal="e"
	for (i=Max3+1;i<=Max;i++) fVal[fName[i]]=fVal[i]
	print header "Diagnostics data ("(cal=="i"?"internal":"external")" calibration)"
	for (i=Max2+1;i<=Max3;i++)
	{
		if (fName[i]=="SFP TX Bias")
		{
			if (cal=="i") fVal[i]=sprintf("%.1f mA",fVal[i]/500)
			else
			{
				#print r,r1,r2
				r=fVal[i] ; r1=h2p(fVal["ISlope"]) ; r2=h2s(fVal["IOffset"])
				fVal[i]=sprintf("%.1f mA",(r*r1+r2)/500)
			}
		}
		else if (fName[i]=="SFP TX Bias Level")
		{
			fVal[i]=sprintf("%.0f%",mDiv(100 * (fVal[i] - h2d(fVal["BiasLowWarning"])) , (h2d(fVal["BiasHighWarning"]) - h2d(fVal["BiasLowWarning"]))))
		}
		else if (fName[i]~"SFP .X power")
		{
			if (cal=="i")
			{
				fVal[i]=10*mylog(fVal[i]/10000)/log(10)" dBm"
			}
			else if (fName[i]=="SFP RX power")
			{
				r=fVal[i] ; r0=h2f(fVal["RxPwr0"]) ; r1=h2f(fVal["RxPwr1"]) ; r2=h2f(fVal["RxPwr2"]) ; r3=h2f(fVal["RxPwr3"]) ; r4=h2f(fVal["RxPwr4"])
				#print r,r0,r1,r2,r3,r4
				#print (r0+ r1*r + r2*(r^2) + r3*(r^3) + r4*(r^4))
				fVal[i]=10*mylog((r0+ r1*r + r2*(r^2) + r3*(r^3) + r4*(r^4))/10000)/log(10)" dBm"
			}
			else if (fName[i]=="SFP TX power")
			{
				r=fVal[i] ; r1=h2p(fVal["TxPwrSlope"]) ; r2=h2s(fVal["TxPwrOffset"])
				#print r,r1,r2,h2p(r1),h2s("ffff"),h2s("7fff")
				fVal[i]=10*mylog((r*r1+r2)/10000)/log(10)" dBm"
			}
		}
		else if (fName[i]~"SFP .X (low|high) alarm")
		{
			r=fVal[i]
			fVal[i]=sprintf("%.1f dBm",10*mylog(r/10000)/log(10))
		}
		else if ((fName[i]=="SFP Temperature")||(fName[i]~"SFP Temp (low|high) alarm"))
		{
			#fVal[1] contains the sfpVendorName . For OCLARO (OPNEXT), there is a issue with temperature calibration values so we always consider internal calibration
			if (cal=="i" || fVal[1]~/^(OPNEXT|OCLARO|AOI)/) fVal[i]=sprintf("%.0f",fVal[i]/256)
			else
			{
				r=fVal[i] ; r1=h2p(fVal["TSlope"]) ; r2=h2s(fVal["TOffset"])
				#print r,fVal["TSlope"],r1,fVal["TOffset"],r2
				fVal[i]=sprintf("%.0f",(r*r1+r2)/256)
			}
			#Now do the unsigned to signed conversion
			if ((fVal[i]+0) >= 128) fVal[i]-=256
			fVal[i]=fVal[i]" C"
		}
		else if (fName[i]=="SFP Voltage")
		{
			if (cal=="i") fVal[i]=sprintf("%.2f Volts",fVal[i]/10000)
			else
			{
				r=fVal[i] ; r1=h2p(fVal["VSlope"]) ; r2=h2s(fVal["VOffset"])
				#print r,r1,r2
				fVal[i]=sprintf("%.2f Volts",(r*r1+r2)/10000)
			}
		}
		print header fName[i]" = "fVal[i]
	}
}
function h2b(h,   a,h2b_table,res,i,z)
{
	h2b_table["0"]="0000"
	h2b_table["1"]="0001"
	h2b_table["2"]="0010"
	h2b_table["3"]="0011"
	h2b_table["4"]="0100"
	h2b_table["5"]="0101"
	h2b_table["6"]="0110"
	h2b_table["7"]="0111"
	h2b_table["8"]="1000"
	h2b_table["9"]="1001"
	h2b_table["A"]="1010"
	h2b_table["B"]="1011"
	h2b_table["C"]="1100"
	h2b_table["D"]="1101"
	h2b_table["E"]="1110"
	h2b_table["F"]="1111"
	h=toupper(h)
	z=split(h,a,"")
	res=""
	for(i=1;i<=z;i++) res=res h2b_table[a[i]]
	return res
}
function todate(h,   a,n)
{
	n=split(h,a,"")
	if (n==6) h="20"a[1] a[2]"-"a[3] a[4]"-"a[5] a[6]
	return h
}
function h2d(h)
{
	return sprintf("%d",strtonum("0x"h))
}
function idec(    ref,i,a)
{
	#initialisation, done for each individual A0+A2 buffer
	delete ref
	delete fName
	delete fPos
	delete fVal
	Max=0
	Max1=0
	#fist ASCII fields until Max1 (except the Ericsson product rev)
	ref[++Max]="sfpConnectorType=A0,2,2"
	ref[++Max]="sfpVendorName=A0,20,35"
	ref[++Max]="sfpProductNumber=A0,40,55"
	ref[++Max]="sfpProductRevision=A0,56,59"
	ref[++Max]="sfpSerialNumber=A0,68,83"
	ref[++Max]="sfpManufactureDate=A0,84,89"
	ref[++Max]="Logo=A0,96,99"
	ref[++Max]="EricssonProductNrPart1=A0,119,127"
	ref[++Max]="EricssonProductNrPart2=A0,112,117"
	ref[++Max]="EricssonProductRev=A0,118,119"  #Important: the EricssonProductRev must always be in position "Max1"
	Max1=Max   #the number of ascii fields
	#then decimal values until Max3
	ref[++Max]="sfpBitRate (units of 100MBd)=A0,12,12"
	ref[++Max]="sfpWaveLength(nm)=A0,60,62"
	ref[++Max]="sfpSingleModeMaxLength(1Km)=A0,14,14"
	ref[++Max]="sfpSingleModeMaxLength(100m)=A0,15,15"
	ref[++Max]="sfpLinkLengthSupported(50UM-OM2, 10m)=A0,16,16"
	ref[++Max]="sfpLinkLengthSupported(62.5UM-OM1, 10m)=A0,17,17"
	ref[++Max]="sfpLinkLengthSupported(Active Cable or Copper, 1m)=A0,18,18"
	ref[++Max]="sfpLinkLengthSupported(50UM-OM3, 10m)=A0,19,19"
	Max2=Max
	#start diagnostics at Max2+1
	ref[++Max]="SFP Temp high alarm=A2,0,1"
	ref[++Max]="SFP Temp low alarm=A2,2,3"
	ref[++Max]="SFP Temperature=A2,96,97"
	ref[++Max]="SFP Voltage=A2,98,99"
	ref[++Max]="SFP TX Bias=A2,100,101"
	ref[++Max]="SFP TX Bias Level=A2,100,101"
	ref[++Max]="SFP TX power=A2,102,103"
	ref[++Max]="SFP RX power=A2,104,105"
	ref[++Max]="SFP TX high alarm=A2,24,25"
	ref[++Max]="SFP TX low alarm=A2,26,27"
	ref[++Max]="SFP RX high alarm=A2,32,33"
	ref[++Max]="SFP RX low alarm=A2,34,35"
	Max3=Max
	#additional values needed for diagnostics calculations, starts at Max3+1, not printed, and kept as hexadecimal
	ref[++Max]="BiasLowWarning=A2,22,23"
	ref[++Max]="BiasHighWarning=A2,20,21"
	ref[++Max]="RxPwr4=A2,56,59"
	ref[++Max]="RxPwr3=A2,60,63"
	ref[++Max]="RxPwr2=A2,64,67"
	ref[++Max]="RxPwr1=A2,68,71"
	ref[++Max]="RxPwr0=A2,72,75"
	ref[++Max]="TxPwrSlope=A2,80,81"
	ref[++Max]="TxPwrOffset=A2,82,83"
	ref[++Max]="TSlope=A2,84,85"
	ref[++Max]="TOffset=A2,86,87"
	ref[++Max]="VSlope=A2,88,89"
	ref[++Max]="VOffset=A2,90,91"
	ref[++Max]="ISlope=A2,76,77"
	ref[++Max]="IOffset=A2,78,79"

	for (i=1;i<=Max;i++)
	{
		split(ref[i],a,"=")
		fName[i]=a[1]
		fPos[i]=a[2]
		#print i" "fName[i],fPos[i]
	}
}
function int2char(i,   char)
{
	char["1"]="A"
	char["2"]="B"
	char["3"]="C"
	char["4"]="D"
	char["5"]="E"
	char["6"]="F"
	char["7"]="G"
	char["8"]="H"
	char["9"]="I"
	char["10"]="J"
	char["11"]="K"
	char["12"]="L"
	char["13"]="M"
	char["14"]="N"
	char["15"]="O"
	char["16"]="P"
	char["17"]="Q"
	char["18"]="R"
	char["19"]="S"
	char["20"]="T"
	char["21"]="U"
	char["22"]="V"
	char["23"]="W"
	char["24"]="X"
	char["25"]="Y"
	char["26"]="Z"
	char["27"]="AA"
	char["28"]="AB"
	char["29"]="AC"
	char["30"]="AD"
	char["31"]="AE"
	return char[i]
}
function h2s(h,   a,v,b2h_table,sign)
{
	#16bit hex to signed integer. The first bit is the sign, the next 15 bits are the value
	b2h_table["0000"]="0"
	b2h_table["0001"]="1"
	b2h_table["0010"]="2"
	b2h_table["0011"]="3"
	b2h_table["0100"]="4"
	b2h_table["0101"]="5"
	b2h_table["0110"]="6"
	b2h_table["0111"]="7"
	b2h_table["1000"]="8"
	b2h_table["1001"]="9"
	b2h_table["1010"]="A"
	b2h_table["1011"]="B"
	b2h_table["1100"]="C"
	b2h_table["1101"]="D"
	b2h_table["1110"]="E"
	b2h_table["1111"]="F"
	split(h,a,"")
	split(h2b(a[1]),b,"")
	if (b[1]=="1") sign="-"
	a[1]=b2h_table["0"b[2] b[3] b[4]]
	h=a[1] a[2] a[3] a[4]
	return sprintf("%s%d",sign,strtonum("0x"h))
}
function h2p(h,   a,b1,b2)
{
	#16bit hex to fixed point: the first byte is 0 to 255, the second byte is the decimal part 0 to 255/256
	split(h,a,"")
	b1=a[1] a[2]
	b2=a[3] a[4]
	b1=sprintf("%f",strtonum("0x"b1))
	b2=sprintf("%f",strtonum("0x"b2)/256)
	return b1+b2
}
function h2f(h,   a,b0,b1,b2,b3)
{
	#convert a raw 4 byte hexadecimal to single precision float
	#can also be done with perl:
	#perl -e \x27 my $hex = "be88a84d";print unpack "f", reverse pack "H*", $hex;\x27
	split(h,a,"")
	b3=a[1] a[2] ; b2=a[3] a[4] ; b1=a[5] a[6] ; b0=a[7] a[8]
	return HexToFP(b3,b2,b1,b0)
}
# function to convert 4 "bytes" of hex chars into a floating point
# bytes are ordered
# [high....low]
#  b3 b2 b1 b0
# based on http://ecpe.ece.iastate.edu/arun/CprE281_F05/ieee754/ie5.html
# http://babbage.cs.qc.edu/IEEE-754/Decimal.html was used to test my code
#
function HexToFP(b3,b2,b1,b0,   i0,i1,i2,i3,tmp,exponent,fraction,decfrac,fval,bias,sign,i)
{
	fval = 0
	bias=127

	# convert the character bytes into numbers
	i3=strtonum("0x" b3)
	i2=strtonum("0x" b2)
	i1=strtonum("0x" b1)
	i0=strtonum("0x" b0)

	# first, we need to separate all the parts of the floating point

	# upper most bit is the sign
	sign=and(i3, 0x80)

	# bits 23-30 (next 8) are the exponent
	exponent=and(i3,0x7F)
	tmp=and(i2,0x80)
	tmp=rshift(tmp, 7)
	exponent=lshift(exponent, 1)
	exponent=or(exponent,tmp)

	# bits 0-22 are the fraction
	fraction=and(i2,0x7F)
	fraction=lshift(fraction,8)
	fraction=or(fraction,i1)
	fraction=lshift(fraction,8)
	fraction=or(fraction,i0)

	#convert the fraction part into a decimal. need to look at the
	# individual bits and compute the base 10 value
	decfrac=0
	for(i=22;i>=0;i--)
	{
		if( and( fraction , lshift(0x01,i) ))
			decfrac = decfrac+2^(i-23)
	}

	fval=(1+decfrac) * 2^(exponent-bias)

	if(sign)
		fval=fval*-1

	return fval
}
function translate_connector_type(theb,   t,i)
{
	t["01"]="SC"
	t["02"]="Fibre Channel Style 1 copper connector"
	t["03"]="Fibre Channel Style 2 copper connector"
	t["04"]="BNC/TNC"
	t["05"]="Fibre Channel coaxial headers"
	t["06"]="FiberJack"
	t["07"]="LC"
	t["08"]="MT-RJ"
	t["09"]="MU"
	t["0A"]="SG"
	t["0B"]="Optical pigtail"
	t["0C"]="MPO Parallel Optic"
	t["20"]="HSSDC II"
	t["21"]="Copper pigtail"
	t["22"]="RJ45"
	for (i in t) t[tolower(i)]=t[i]
	return t[theb]
}
function mylog(theval)
{
	if (theval+0 < 0) theval=0
	return log(theval)
}
function make_xx_table()
{
	#0001: | Vendor Name                  | FINISAR CORP.    |
	#0001: | Vendor Product No            | FTLX1471D3BCL-E1 |
	#0001: | Vendor Revision              | A                |
	#0001: | Serial No                    | AYR0Z1G          |
	#0001: | Production Date              | 171222           |
	#0001: | Ericsson SFP                 | True             |
	#0001: | Ericsson Product No          | RDH10250/3       |
	#0001: | Ericsson Revision            |                  |
	#0001: | Nom Bit Rate (100MBd)        | 103              |
	#BXP_0: SFPDECODER (0): sfpVendorName = FINISARCORP.
	#BXP_0: SFPDECODER (0): sfpProductNumber = FTLX1471D3BCL-E1
	#BXP_0: SFPDECODER (0): sfpProductRevision = A
	#BXP_0: SFPDECODER (0): sfpSerialNumber = AYQ0P76
	#BXP_0: SFPDECODER (0): sfpManufactureDate = 2017-12-21
	#BXP_0: SFPDECODER (0): Logo = MONI
	#BXP_0: SFPDECODER (0): EricssonProductNrPart1 = RDH10250/3
	#BXP_0: SFPDECODER (0): EricssonProductRev =
	#BXP_0: SFPDECODER (0): sfpBitRate (units of 100MBd) = 103
	delete xx
	xx["Type"]                 ="sfpType"
	xx["Vendor Name"]          ="sfpVendorName"
	xx["Vendor Product No"]    ="sfpProductNumber"
	xx["Vendor Revision"]      ="sfpProductRevision"
	xx["Serial No"]            ="sfpSerialNumber"
	xx["Production Date"]      ="sfpManufactureDate"
	xx["Ericsson SFP"]         ="Logo"
	xx["Ericsson Product No"]  ="EricssonProductNrPart1"
	xx["Ericsson Revision"]    ="EricssonProductRev"
	xx["Nom Bit Rate (100MBd)"]="sfpBitRate (units of 100MBd)"
	xx["Supported Rate (100MBd)"]="sfpBitRate (units of 100MBd)"
	xx["RX Power Low Alarm (uW)"]="SFP RX low alarm"
	xx["RX Power High Alarm (uW)"]="SFP RX high alarm"
	xx["TX Power Low Alarm (uW)"]="SFP TX low alarm"
	xx["TX Power High Alarm (uW)"]="SFP TX high alarm"
	xx["Wavelength (nm)"]       ="sfpWaveLength(nm)"
	xx["Temperature Low Alarm (C)"]="SFP Temp low alarm"
	xx["Temperature High Alarm (C)"]="SFP Temp high alarm"
}
function make_yy_table()
{
	#Vendor:                       SOURCEPHOTONICS
	#Vendor part number:           SPP10ELRIDFFEN1
	#Vendor serial number:         H722002378
	#Vendor revision:              10
	#Manufacturing date(YYMMDDLL): 170601
	#Speed:                        10.0 Gbps
	#Ericsson SFP:                 TRUE
	#Product number:               RDH10265/3
	#Revision:                     R1A
	#SFPDECODER (0): sfpVendorName = FINISARCORP.
	#SFPDECODER (0): sfpProductNumber = FTLX1471D3BCL-E1
	#SFPDECODER (0): sfpProductRevision = A
	#SFPDECODER (0): sfpSerialNumber = AYQ0P76
	#SFPDECODER (0): sfpManufactureDate = 2017-12-21
	#SFPDECODER (0): Logo = MONI
	#SFPDECODER (0): EricssonProductNrPart1 = RDH10250/3
	#SFPDECODER (0): EricssonProductRev =
	#SFPDECODER (0): sfpBitRate (units of 100MBd) = 103
	delete yy
	yy["Vendor"]                        ="sfpVendorName"
	yy["Vendor part number"]            ="sfpProductNumber"
	yy["Vendor revision"]               ="sfpProductRevision"
	yy["Vendor serial number"]          ="sfpSerialNumber"
	yy["Manufacturing date(YYMMDDLL)"]  ="sfpManufactureDate"
	yy["Ericsson SFP"]                  ="Logo"
	yy["Product number"]                ="EricssonProductNrPart1"
	yy["Revision"]                      ="EricssonProductRev"
	yy["Speed"]                         ="sfpBitRate (units of 100MBd)"
	#Ericsson approved SFP = Yes
	#Ericsson Product Number = RDH10265/31
	#Ericsson Product Revision = R1A
	yy["Ericsson Product Number"]="EricssonProductNrPart1"
	yy["Ericsson Product Revision"]="EricssonProductRev"
	yy["Ericsson approved SFP"]="Logo"
	yy["sfpWavelength (nm)"]="sfpWaveLength(nm)"
}
function make_zz_table()
{
	zz["preamble"]=1
	zz["cc_base"]=2
	zz["cc_ext"]=3
	zz["cc_dmi"]=4
}
function xpsort(xpList,   i,a,n,x,j)
{
	for (i in xpList)
	{
		x=xpList[i]
		#if (x !~ /^BXP_|^fru_[0-9]+$/) continue
		if (x=="" || x !~ /^(du[2-9]\/)?(BXP_[_0-9]+|fru_[0-9]+(\/(fru|BXP).*)?)?$/) continue
		n=split(x,a,"_")
		x=""
		for (j=1;j<=n;j++) x=sprintf("%s%8s_",x,a[j])  #BXP can have many digits, eg BXP_2048
		sub(/_$/,"",x)
		xpList[i]=x
	}
	n=asort(xpList)
	for (i=1;i<=n;i++) gsub(/ /,"",xpList[i])
	return n
}
'
