work_sript/02.nicsensor/nicsensor.sh
2024-07-15 11:41:20 +08:00

646 lines
21 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/sh
# script Version 1.0 20240614
# 支持测试的传感器芯片 emc1413 ina3221 adc128
# ---------------------------------------------------------
# Project Feature Varible (按照项目需要修改)
# ---------------------------------------------------------
# ADC128 分压系数 (Ravel)
votage_division_factor_0="1"
votage_division_factor_1="1"
votage_division_factor_2="1"
votage_division_factor_3="0.8"
votage_division_factor_4="0.6"
votage_division_factor_5="0.6"
votage_division_factor_6="0.2326"
votage_division_factor_7="1"
# INA3221 分流电阻, 单位毫欧姆Ravel
shunt_resistor_0="2"
shunt_resistor_1="2"
shunt_resistor_2="5"
# fru 烧录的起始地址
fru_offset="0x00 0x00"
# ---------------------------------------------------------
# Common Varible (请勿随意修改)
# ---------------------------------------------------------
# Input Param
pcie_slot=$1
sensor_type=$2
chip_slave=$3
# Introduction of option_data
# 1.在FRU的处理过程中使用option_data来区分是读操作还是写操作将值设置为
# "read"或者"write"
# 2.在CPLD的处理过程中使用option_data来代表一条完整的i2c命令这条命令会
# 被发到CPLD上一个例子"i2ctransfer -y 12 w2@0x10 0x90 0x00 r9"
option_data=$4
# CHIP REGISTER
REG_pca9641_controll="0x01"
REG_adc128_config="0x00"
REG_adc128_advance="0x0b"
REG_adc128_status="0x0c"
REG_adc128_ch0="0x20"
REG_adc128_ch1="0x21"
REG_adc128_ch2="0x22"
REG_adc128_ch3="0x23"
REG_adc128_ch4="0x24"
REG_adc128_ch5="0x25"
REG_adc128_ch6="0x26"
REG_adc128_ch7="0x27"
REG_emc1413_TD1_H="0x00"
REG_emc1413_TD1_L="0x29"
REG_emc1413_TD2_H="0x01"
REG_emc1413_TD2_L="0x10"
REG_emc1413_TD3_H="0x23"
REG_emc1413_TD3_L="0x24"
REG_ina3221_ch1="0x01"
REG_ina3221_ch2="0x03"
REG_ina3221_ch3="0x05"
REG_ina3221_bus1="0x02"
REG_ina3221_bus2="0x04"
REG_ina3221_bus3="0x06"
# ---------------------------------------------------------
# Global Varible (请勿随意修改)
# ---------------------------------------------------------
# 选通网卡I2C通路的关键变量
pca9641_slave=0x41
i2c_bus=12
pca9548_channel=0x04
pca9548_slave=0x72
log="/tmp/nicsensor_debug.log"
fru_raw_file="/tmp/fru.bin"
INA3221_SHUNT_VOLT=0
INA3221_BUS_VOLT=1
INA3221_POWER=2
ina3221_ch0_volt="0"
ina3221_ch1_volt="0"
ina3221_ch2_volt="0"
ina3221_ch0_current="0"
ina3221_ch1_current="0"
ina3221_ch2_current="0"
# ---------------------------------------------------------
# Script Function Defination
# ---------------------------------------------------------
# script usage
print_usage(){
echo ""
echo "================>>> nicsensor script usage <<<================="
echo " format : ./nicsensor.sh [slot] [sensor tpye] [slave]"
echo " slot : 0 1 2 3 4 5"
echo " sensor type : emc1413, adc128, ina3221"
echo " slave : chip slave address , please provide 7 bit address"
echo " E.G. : ./nicsensor.sh 0 adc128 0x1f"
echo ""
}
# 根据输入信息调整选通芯片的配置PCA9641 PCA9548
# 配置信息的具体方案根据5280M7 riser映射表来配置
set_configuration(){
# set pca9641 address && I2C BUS
if [ $pcie_slot -le 2 ];then
pca9641_slave="0x41"
i2c_bus=12
else
pca9641_slave="0x42"
i2c_bus=13
fi
# set pca9548 switch channel
if [ $pcie_slot -eq 0 ];then
pca9548_channel="0x02"
elif [ $pcie_slot -eq 1 ];then
pca9548_channel="0x04"
elif [ $pcie_slot -eq 2 ];then
pca9548_channel="0x08"
elif [ $pcie_slot -eq 3 ];then
pca9548_channel="0x02"
elif [ $pcie_slot -eq 4 ];then
pca9548_channel="0x04"
elif [ $pcie_slot -eq 5 ];then
pca9548_channel="0x08"
fi
}
# 初始化调试日志
prepare_start_info(){
# 只保留一次日志读取记录
if [ -e $log ];then
rm $log
fi
# print time header
res_date=`date`
echo "=========================== $res_date" >> $log
# 记录单次配置信息到调试日志中去
echo "PCIE slot : $pcie_slot" >> $log
echo "I2C Bus: $i2c_bus" >> $log
echo "PCA9641 slave: $pca9641_slave" >> $log
echo "PCA9548 slave: $pca9548_slave" >> $log
echo "PCA9548 channel: $pca9548_channel" >> $log
# Record i2c device info to log
res_info=`i2cdetect -y $i2c_bus`
echo $res_info >> $log
}
# 获取PCA9641的控制权
get_pca9641_controll(){
# Request 9641 lock
res_lock=`i2ctransfer -y $i2c_bus w2@$pca9641_slave $REG_pca9641_controll 0x81 r1`
echo "After request 9641 lock, The REG value is $res_lock" >> $log
# Build 9641 Connection
res_build=`i2ctransfer -y $i2c_bus w2@$pca9641_slave $REG_pca9641_controll 0x85 r1`
echo "After Build 9641 connection, The REG value is $res_build" >> $log
# After get 9641 controll, Record i2c device info to log
res_after=`i2cdetect -y $i2c_bus`
echo $res_after >> $log
if [ "$res_build" != "0x87" ];then
echo "Cannot establish connection with pca9641 !!!"
exit 1
fi
}
# 选通PCA9548的channel
switch_pca9548_channel(){
# set 9548 channel
res_setchannel=`i2ctransfer -y $i2c_bus w1@$pca9548_slave $pca9548_channel`
echo "After switch channel" >> $log
# After set 9548 channel , record i2c device info
res_after=`i2cdetect -y $i2c_bus`
echo $res_after >> $log
}
# ---------------------------------------------------------
# Chip EMC1413
# ---------------------------------------------------------
# 处理EMC1413读到的数据并输出结果
# @Param1 emc1413读取数据高位
# @Param2 emc1413读取数据低位
# @Param3 channel号
convert_emc1413_data(){
# 将读取到的两位数据去掉 0x 前缀
hex_value1=$(echo "$1" | awk '{sub(/^0x/,""); print}')
hex_value2=$(echo "$2" | awk '{sub(/^0x/,""); print}')
# 由于 bc 计算器只能识别大写的 十六进制数据,将小写的十六进制数据全部转化为大写的数据
upper_hex_value1=$(echo "$hex_value1" | awk '{ for(i=1; i<=length($0); i++){ if(tolower(substr($0,i,1)) ~ /^[a-f]$/) printf toupper(substr($0,i,1)); else printf substr($0,i,1); } print "" }')
upper_hex_value2=$(echo "$hex_value2" | awk '{ for(i=1; i<=length($0); i++){ if(tolower(substr($0,i,1)) ~ /^[a-f]$/) printf toupper(substr($0,i,1)); else printf substr($0,i,1); } print "" }')
# 转化为10进制数据
dec_value1=$(echo "ibase=16; $upper_hex_value1" | bc)
dec_value2=$(echo "ibase=16; $upper_hex_value2" | bc)
# 计算温度值
temp=$(echo "scale=4; $dec_value1 + ($dec_value2 / 32 * 0.125 )" | bc)
# 格式化输出数据
format_temp=$(echo "$temp" | awk '{ if ($0 ~ /^\./) print "0" $0; else print $0 }')
echo "channel $3 : $format_temp C, hex value : $hex_value1 $hex_value2"
}
# 读取EMC1413芯片每个通道的数据,随后调用数据处理函数进行数据解析并输出
read_emc1413_channel_value(){
echo "Start EMC1413 channel data ..." >> $log
res_td1_h=`i2ctransfer -y $i2c_bus w1@$chip_slave $REG_emc1413_TD1_H r1`
res_td1_l=`i2ctransfer -y $i2c_bus w1@$chip_slave $REG_emc1413_TD1_L r1`
res_td2_h=`i2ctransfer -y $i2c_bus w1@$chip_slave $REG_emc1413_TD2_H r1`
res_td2_l=`i2ctransfer -y $i2c_bus w1@$chip_slave $REG_emc1413_TD2_L r1`
res_td3_h=`i2ctransfer -y $i2c_bus w1@$chip_slave $REG_emc1413_TD3_H r1`
res_td3_l=`i2ctransfer -y $i2c_bus w1@$chip_slave $REG_emc1413_TD3_L r1`
# 将 I2C 读取的 raw 数据记录到调试日志中
echo "channel 1 : $res_td1_h $res_td1_l" >> $log
echo "channel 2 : $res_td2_h $res_td2_l" >> $log
echo "channel 3 : $res_td3_h $res_td3_l" >> $log
# start parse raw data
echo ">>> The emc1413 value is:"
convert_emc1413_data $res_td1_h $res_td1_l 1
convert_emc1413_data $res_td2_h $res_td2_l 2
convert_emc1413_data $res_td3_h $res_td3_l 3
}
# EMC1413处理逻辑
process_emc1413(){
# emc1413 no need to init
# get chip emc1413 value
read_emc1413_channel_value
}
# ---------------------------------------------------------
# Chip ADC128
# ---------------------------------------------------------
# 进行ADC128芯片的初始化
check_adc128_init(){
# Get Reg 0x00 status
res_adc128_status=`i2cget -y $i2c_bus $chip_slave $REG_adc128_config`
echo "REG adc128 STATUS : $res_adc128_status" >> $log
# if stauts is not 0x01 (Start Monitor) ,then do init
if [ "$res_adc128_status" != "0x01" ];then
echo "Start Init ADC128 Chip" >> $log
# Init ADC128 work as mode 1 (0x02)
res_adc128_advance=`i2ctransfer -y $i2c_bus w2@$chip_slave $REG_adc128_advance 0x02`
# Set ADC128 on start (0x01)
res_adc128_setstart=`i2ctransfer -y $i2c_bus w2@$chip_slave $REG_adc128_config 0x01 r1`
echo "After Set status, the REG 0x00 value is $res_adc128_setstart" >> $log
fi
}
# 处理ADC128读到的数据并输出结果
# @Param 1 ADC128读取数据高位
# @Param 2 ADC128读取数据低位
# @Param 3 channel号
# @Param 4 分压系数
convert_adc128_data(){
# 将读取到的两位数据拼接起来
hex_value1=$(echo "$1" | awk '{sub(/^0x/,""); print}')
hex_value2=$(echo "$2" | awk '{sub(/^0x/,""); print}')
merge_value="${hex_value1}${hex_value2}"
# 由于 bc 计算器只能识别大写的 十六进制数据,这里将小写的十六进制数据全部转化为大写的数据
upper_hex_value=$(echo "$merge_value" | awk '{ for(i=1; i<=length($0); i++){ if(tolower(substr($0,i,1)) ~ /^[a-f]$/) printf toupper(substr($0,i,1)); else printf substr($0,i,1); } print "" }')
# 利用bc计算器进行运算并将返回值格式化后输出
dec_val=$(echo "ibase=16; $upper_hex_value" | bc)
volt=$(echo "scale=4; $dec_val / 16 / 4096 * 2.65 / $4" | bc)
format_volt=$(echo "$volt" | awk '{ if ($0 ~ /^\./) print "0" $0; else print $0 }')
echo "Channel $3 : $format_volt v, hex value: $upper_hex_value"
}
# 读取ADC128芯片每个通道的数据,随后调用数据处理函数进行数据解析并输出
read_adc128_channel_value(){
echo "Start Read ADC128 channel data ..." >> $log
res_ch0=`i2ctransfer -y $i2c_bus w1@$chip_slave $REG_adc128_ch0 r2`
res_ch1=`i2ctransfer -y $i2c_bus w1@$chip_slave $REG_adc128_ch1 r2`
res_ch2=`i2ctransfer -y $i2c_bus w1@$chip_slave $REG_adc128_ch2 r2`
res_ch3=`i2ctransfer -y $i2c_bus w1@$chip_slave $REG_adc128_ch3 r2`
res_ch4=`i2ctransfer -y $i2c_bus w1@$chip_slave $REG_adc128_ch4 r2`
res_ch5=`i2ctransfer -y $i2c_bus w1@$chip_slave $REG_adc128_ch5 r2`
res_ch6=`i2ctransfer -y $i2c_bus w1@$chip_slave $REG_adc128_ch6 r2`
res_ch7=`i2ctransfer -y $i2c_bus w1@$chip_slave $REG_adc128_ch7 r2`
# 将 I2C 读取的 raw 数据记录到调试日志中
echo "channel0 : $res_ch0" >> $log
echo "channel1 : $res_ch1" >> $log
echo "channel2 : $res_ch2" >> $log
echo "channel3 : $res_ch3" >> $log
echo "channel4 : $res_ch4" >> $log
echo "channel5 : $res_ch5" >> $log
echo "channel6 : $res_ch6" >> $log
echo "channel7 : $res_ch7" >> $log
# start parse raw data
echo ">>> The ADC128 value is :"
convert_adc128_data $res_ch0 0 $votage_division_factor_0
convert_adc128_data $res_ch1 1 $votage_division_factor_1
convert_adc128_data $res_ch2 2 $votage_division_factor_2
convert_adc128_data $res_ch3 3 $votage_division_factor_3
convert_adc128_data $res_ch4 4 $votage_division_factor_4
convert_adc128_data $res_ch5 5 $votage_division_factor_5
convert_adc128_data $res_ch6 6 $votage_division_factor_6
convert_adc128_data $res_ch7 7 $votage_division_factor_7
}
# ADC128处理逻辑
process_adc128(){
# check if chip adc128 need init
check_adc128_init
# get chip adc128 value
read_adc128_channel_value
}
# ---------------------------------------------------------
# Chip INA3221
# ---------------------------------------------------------
# 处理INA3221读到的电流数据并输出结果
# @Param1 ina3221读取数据高位
# @Param2 ina3221读取数据低位
# @Param3 channel号
# @Param4 0代表数据是shunt volt
# 1代表数据是bus volt
# @Param5 分流电阻 (仅在 Param4 是 shunt volt时有用)
convert_ina3221_data(){
# 将读取到的两位数据拼接起来
hex_value1=$(echo "$1" | awk '{sub(/^0x/,""); print}')
hex_value2=$(echo "$2" | awk '{sub(/^0x/,""); print}')
merge_value="${hex_value1}${hex_value2}"
# 由于 bc 计算器只能识别大写的 十六进制数据,这里将小写的十六进制数据全部转化为大写的数据
upper_hex_value=$(echo "$merge_value" | awk '{ for(i=1; i<=length($0); i++){ if(tolower(substr($0,i,1)) ~ /^[a-f]$/) printf toupper(substr($0,i,1)); else printf substr($0,i,1); } print "" }')
# 将16进制数据转化为10进制
dec_val=$(echo "ibase=16; $upper_hex_value" | bc)
# todo 检查这个数据的最高位是否为1
# max_unsigned_32bit_half=$(echo "scale=0; 2^31 / 2" | bc)
# if [ $(echo "$dec_val >= $max_unsigned_32bit_half" | bc) -eq 1 ];then
# echo ""
# else
# echo ""
# fi
if [ $4 -eq $INA3221_BUS_VOLT ];then
# 计算每个通道上的电压
volt=$(echo "scale=4; $dec_val / 8 * 40 / 10000 * 2" | bc)
# 格式化输出数据
format_volt=$(echo "$volt" | awk '{ if ($0 ~ /^\./) print "0" $0; else print $0 }')
echo "channel $3 : $format_volt V, hex value: $upper_hex_value"
if [ $3 -eq 0 ];then
ina3221_ch0_volt=$format_volt
elif [ $3 -eq 1 ];then
ina3221_ch1_volt=$format_volt
else
ina3221_ch2_volt=$format_volt
fi
elif [ $4 -eq $INA3221_SHUNT_VOLT ];then
# 计算每个分流电阻上的电压,同时计算出电流
current_mv=$(echo "scale=4; $dec_val / 8 * 40 / 1000" | bc)
current=$(echo "scale=4; $current_mv / $5" | bc)
# 格式化输出数据
format_current=$(echo "$current" | awk '{ if ($0 ~ /^\./) print "0" $0; else print $0 }')
format_current_mv=$(echo "$current_mv" | awk '{ if ($0 ~ /^\./) print "0" $0; else print $0 }')
echo "channel $3 : $format_current A, shunt volt: $format_current_mv mV, shunt resistor: $5 mOhm, hex value: $upper_hex_value"
if [ $3 -eq 0 ];then
ina3221_ch0_current=$format_current
elif [ $3 -eq 1 ];then
ina3221_ch1_current=$format_current
else
ina3221_ch2_current=$format_current
fi
elif [ $4 -eq $INA3221_POWER ];then
# 计算每个通道上的功耗,并算总和
power_ch0=$(echo "scale=4; $ina3221_ch0_volt * $ina3221_ch0_current" | bc)
power_ch1=$(echo "scale=4; $ina3221_ch1_volt * $ina3221_ch1_current" | bc)
power_ch2=$(echo "scale=4; $ina3221_ch2_volt * $ina3221_ch2_current" | bc)
# 格式化输出数据
format_power_ch0=$(echo "$power_ch0" | awk '{ if ($0 ~ /^\./) print "0" $0; else print $0 }')
format_power_ch1=$(echo "$power_ch1" | awk '{ if ($0 ~ /^\./) print "0" $0; else print $0 }')
format_power_ch2=$(echo "$power_ch2" | awk '{ if ($0 ~ /^\./) print "0" $0; else print $0 }')
total_power=$(echo "scale=4; $power_ch0 + $power_ch1 + $power_ch2" | bc)
echo "channel 0 : $format_power_ch0 W"
echo "channel 1 : $format_power_ch1 W"
echo "channel 2 : $format_power_ch2 W"
echo "total power: $total_power W"
fi
}
# 读取INA3221芯片每个通道的数据,随后调用数据处理函数进行数据解析并输出
read_ina3221_channel_value(){
echo "Start Read INA3221 channel data ..." >> $log
res_ch0=`i2ctransfer -y $i2c_bus w1@$chip_slave $REG_ina3221_ch1 r2`
res_ch1=`i2ctransfer -y $i2c_bus w1@$chip_slave $REG_ina3221_ch2 r2`
res_ch2=`i2ctransfer -y $i2c_bus w1@$chip_slave $REG_ina3221_ch3 r2`
res_bus0=`i2ctransfer -y $i2c_bus w1@$chip_slave $REG_ina3221_bus1 r2`
res_bus1=`i2ctransfer -y $i2c_bus w1@$chip_slave $REG_ina3221_bus2 r2`
res_bus2=`i2ctransfer -y $i2c_bus w1@$chip_slave $REG_ina3221_bus3 r2`
# 将 I2C 读取的 raw 数据记录到调试日志中
echo "channel 0 shunt volt: $res_ch0" >> $log
echo "channel 1 shunt volt: $res_ch1" >> $log
echo "channel 2 shunt volt: $res_ch2" >> $log
echo "Channel 0 bus volt : $res_bus0" >> $log
echo "Channel 1 bus volt : $res_bus1" >> $log
echo "Channel 2 bus volt : $res_bus2" >> $log
# start parse raw data
echo ">>> The INA3221 shunt value is :"
convert_ina3221_data $res_ch0 0 $INA3221_SHUNT_VOLT $shunt_resistor_0
convert_ina3221_data $res_ch1 1 $INA3221_SHUNT_VOLT $shunt_resistor_1
convert_ina3221_data $res_ch2 2 $INA3221_SHUNT_VOLT $shunt_resistor_2
echo ">>> The INA3221 bus value is :"
convert_ina3221_data $res_bus0 0 $INA3221_BUS_VOLT
convert_ina3221_data $res_bus1 1 $INA3221_BUS_VOLT
convert_ina3221_data $res_bus2 2 $INA3221_BUS_VOLT
echo ">>> The INA3221 bus power is :"
convert_ina3221_data 0 0 0 $INA3221_POWER
}
# INA3221处理逻辑
process_ina3221(){
# ina3221 no need to init first
# get chip ina3221 value
read_ina3221_channel_value
}
# ---------------------------------------------------------
# CPLD
# ---------------------------------------------------------
# 临时支持CPLD读取
write_read_cpld(){
# Modify i2c cmd which write to cpld if need
cmd_wr=$option_data
res_wr=`$cmd_wr`
echo ">>> CPLD Command: $cmd_wr"
echo ">>> The Result : $res_wr"
}
# cpld处理逻辑
process_cpld(){
# cpld no need to init first
# write and read cpld
write_read_cpld
}
# ---------------------------------------------------------
# FRU
# ---------------------------------------------------------
# 临时支持FRU读取
read_fru(){
res_fru=`i2ctransfer -y $i2c_bus w2@$chip_slave $fru_offset r256`
# 将FRU数据按照每行16个字符输出
echo "The Fru Data :"
echo "$res_fru" | \
awk '{
line="";
count=0;
for(i=1; i<=NF; i++){
hex=substr($i, 3);
if(line != ""){
line = line " ";
}
line = line hex;
count++;
if (count == 16){
print line;
line = "";
count = 0;
}
}
if(line != ""){
print line;
}
}'
}
# 暂时不支持FRU写入预留接口
write_fru(){
current_byte=0
echo "Not support write fru now ..."
exit 0
while IFS= read -r -n 1 byte || [[ -n "$byte" ]];do
i2cset -y $i2c_bus $chip_slave $current_byte $byte w
current_byte=$(($current_byte+1))
done < "$fru_raw_file"
}
# fru 处理逻辑
process_fru(){
# fru no need to init first
# write and read fru
if [ "$option_data" == "write" ];then
write_fru
else
# 默认为读取操作
read_fru
fi
}
# ---------------------------------------------------------
# END of CHIP Function
# ---------------------------------------------------------
# 读取sensor流程的起点
start_get_sensor(){
# print start info in log
prepare_start_info
# 从9641获取I2C控制权
get_pca9641_controll
# 选择9548 channel
switch_pca9548_channel
# get sensor detail value
if [ "$sensor_type" == "emc1413" ];then
process_emc1413
elif [ "$sensor_type" == "adc128" ];then
process_adc128
elif [ "$sensor_type" == "ina3221" ];then
process_ina3221
elif [ "$sensor_type" == "cpld" ];then
process_cpld
elif [ "$sensor_type" == "fru" ];then
process_fru
fi
}
# 搜索服务器所有PCIE插槽的I2C设备信息当前仅支持特定Riser卡上的设备
start_detect_device(){
# 从9641获取I2C控制权
i2c_bus=12
pca9641_slave="0x41"
get_pca9641_controll
echo ">>> PCIe slot 0 : bus12 9548channel1"
i2ctransfer -y $i2c_bus w1@0x72 0x02
i2cdetect -y $i2c_bus
echo ">>> PCIe slot 1 : bus12 9548channel2"
i2ctransfer -y $i2c_bus w1@0x72 0x04
i2cdetect -y $i2c_bus
echo ">>> PCIe slot 2 : bus12 9548channel3"
i2ctransfer -y $i2c_bus w1@0x72 0x08
i2cdetect -y $i2c_bus
i2c_bus=13
pca9641_slave="0x42"
get_pca9641_controll
echo ">>> PCIe slot 3 : bus13 9548channel1"
i2ctransfer -y $i2c_bus w1@0x72 0x02
i2cdetect -y $i2c_bus
echo ">>> PCIe slot 4 : bus13 9548channel2"
i2ctransfer -y $i2c_bus w1@0x72 0x04
i2cdetect -y $i2c_bus
echo ">>> PCIe slot 5 : bus13 9548channel3"
i2ctransfer -y $i2c_bus w1@0x72 0x08
i2cdetect -y $i2c_bus
}
# ---------------------------------------------------------
# Start Execute Script
# ---------------------------------------------------------
if [ "$1" == "detect" ];then
start_detect_device
exit 0
fi
if [ $# -le 2 ];then
print_usage
else
set_configuration
start_get_sensor
fi