#!/usr/bin/env perl use strict; use utf8; use Config; use Time::HiRes qw /usleep/; binmode(STDOUT, ":utf8"); sub get_soc_temp { my $t=shift; my @fnames=( '/sys/devices/virtual/thermal/thermal_zone0/temp', '/sys/devices/platform/scpi/scpi:sensors/hwmon/hwmon0/temp1_input', ); my $temp = "Unknown"; for my $fname (@fnames) { if( -f $fname ) { open my $fh, "<", $fname; if($t) { $temp = sprintf "%0.1f", <$fh> / 1000; } else { $temp = sprintf "%0.1f℃", <$fh> / 1000; } close $fh; return $temp; } } return $temp; } sub get_cpu_freq { my $f=shift; my @fnames=; my $freq_str = ""; for (my $i=0; $i < $#fnames + 1; $i++) { my $fname = $fnames[$i]; open my $fh, "<", $fname; usleep(50000); my $freq; if($f =~ /-F(\d*)/) { my $alert_mhz = 1500; if($1 ne "") { $alert_mhz = $1; } my $color = "\x1b[92m"; $freq = <$fh> / 1000; if($freq > $alert_mhz) { $color = "\x1b[91m"; } $freq = sprintf "%s%d Mhz\x1b[0m", $color, $freq; } else { $freq = sprintf "%dMhz", <$fh> / 1000; } close $fh; $freq_str .= $freq; if($i < $#fnames) { $freq_str .= " & "; } } if($#fnames > 0 && $f eq "") { $freq_str = "(" . $freq_str . ")"; } if($freq_str eq "") { $freq_str = "Unknown"; } return $freq_str; } sub get_arch_info { my $a=shift; my @cpus = ; my @cpu_groups; my %group_core_count; for my $cpu (@cpus) { open my $fh, "<", "${cpu}/uevent"; while(<$fh>) { chomp; my($key,$value) = split /=/; if($key eq "OF_COMPATIBLE_0") { my($cortex, $a) = split /-/, (split /,/, $value)[1]; my $core_type_name = ucfirst($cortex) . "-" . ucfirst($a); if(not exists $group_core_count{$core_type_name}) { push @cpu_groups, $core_type_name; $group_core_count{$core_type_name} = 0; } $group_core_count{$core_type_name} += 1; } } close $fh; } my $arch_info; if($a) { $arch_info = "AArch64 : " if ($a); } else { $arch_info = "AArch64 Processor : "; } for (my $i = 0; $i < $#cpu_groups + 1; $i++) { my $group = $cpu_groups[$i]; #if($i == 0) { # $arch_info .= ""; #} $arch_info .= $group; if($a) { $arch_info .= " x "; } else { $arch_info .= " * "; } $arch_info .= $group_core_count{$group}; if($i < $#cpu_groups) { $arch_info .= " & "; } #else { # $arch_info .= ""; #} } return "$arch_info"; } sub get_uptime { my $fh; my $result; open $fh, "<", "/proc/uptime" or die; my $str_uptime = <$fh>; if($str_uptime =~ /(\d*)/) { my $day = int($1/86400); my $hour = int(($1%86400)/3600); my $min = int(($1%3600)/60); my $sec = $1%60; my $sday = $day . "天 " if($day>0); my $shour = $hour . "小时 " if($hour>0 || $day>0) ; my $smin = $min . "分钟 "; my $ssec = $sec . "秒"; $result .= $sday . $shour . $smin . $ssec; } close $fh; return $result; } sub get_avgload { my $fh; my $result; open $fh, "<", "/proc/loadavg" or die; my $str = <$fh>; $result = join(' ', (split(/\s+/, $str))[0,1,2]); close $fh; return $result; } sub get_eth_name { my $eth = shift; return (split /\//, $eth)[-1]; } sub get_eth_operstate { my $eth = shift; my $fh; open $fh, "<", "$eth/operstate" or warn $!; my $operstate = <$fh>; close $fh; $operstate =~ s/\n//; return $operstate; } sub get_eth_driver { my $eth = shift; my $fh; if (-d "$eth/device") { open $fh, "<", "$eth/device/uevent" or warn $eth; } elsif(-f "$eth/uevent") { open $fh, "<", "$eth/uevent" or warn $eth; } my $driver; while(<$fh>) { chomp; if(/^DRIVER=/) { $driver = (split /=/, $_)[-1]; last; } elsif(/^DEVTYPE=/) { $driver = (split /=/, $_)[-1]; last; } } close $fh; return $driver; } sub get_eth_duplex { my $eth = shift; my $fh; open $fh, "<", "$eth/duplex" or warn $!; my $duplex = <$fh>; close $fh; $duplex =~ s/\n//; return $duplex; } sub get_eth_speed { my $eth = shift; my $fh; open $fh, "<", "$eth/speed" or warn $!; my $speed = <$fh>; close $fh; $speed =~ s/\n//; if($speed == -1) { my $driver = &get_eth_driver("$eth"); if($driver eq "virtio_net") { $speed = "Maximum"; } else { $speed = ""; } } elsif($speed <= 100) { $speed .= "Mb/s"; } else { $speed = sprintf "%.1fGb/s", $speed / 1000; } $speed =~ s/\.0//; return $speed; } sub get_eth_temperature { my($driver, $eth_name) = @_; my $ret = ""; return $ret if (! -d "/proc/net/r8125/$eth_name"); if($driver eq 'r8125') { my $fh; if (-f "/proc/net/r8125/$eth_name/test/temp") { open $fh, "<", "/proc/net/r8125/$eth_name/test/temp" or die $!; } elsif (-f "/proc/net/r8125/$eth_name/temp") { open $fh, "<", "/proc/net/r8125/$eth_name/temp" or die $!; } else { return $ret; } while(<$fh>) { chomp; if(/^Cel:/) { $ret = (split /:/, $_)[-1]."℃"; last; } } close $fh; } return $ret; } sub get_ethlist() { my $board = &get_boardinfo; if($board =~ m/FastRhino R66S/i) { return reverse sort (); } elsif($board eq "Hlink H68K") { return reverse sort (); } elsif($board eq "Hlink H88K-V3") { return reverse sort (); } elsif($board =~ m/NLnet Watermelon Pi/i) { return reverse sort (); } elsif($board =~ m/Radxa E54C/i) { return reverse sort (); } else { return sort (); } } sub get_ethcount() { my @eth_ary = &get_ethlist; return $#eth_ary + 1; } sub get_ethinfo { my @eth_ary = &get_ethlist; my $ret = "[\n"; for (my $i = 0; $i <= $#eth_ary; $i++) { $ret .= " {\n"; my $eth_name = &get_eth_name($eth_ary[$i]); my $driver = &get_eth_driver($eth_ary[$i]); my $operstate = &get_eth_operstate($eth_ary[$i]) eq "up" ? 1 : 0; my $speed = &get_eth_speed($eth_ary[$i]); my $duplex = &get_eth_duplex($eth_ary[$i]); my $temperature = &get_eth_temperature($driver, $eth_name); if($temperature eq "") { $temperature = "☰"; } if(($duplex eq "unknown")) { if(($driver eq "virtio_net") && ($operstate == 1)) { $duplex = "full"; } } if($operstate == 1) { $speed .= " $duplex duplex"; } else { $speed = "☷"; } $ret .= qq| "name": "| . $eth_name . qq|",\n|; $ret .= qq| "driver": "| . $driver . qq|",\n|; $ret .= qq| "temperature": "| . $temperature . qq|",\n|; $ret .= qq| "operstate": | . $operstate . ",\n"; $ret .= qq| "speed": "| . $speed . qq|"\n|; if($i < $#eth_ary) { $ret .= " },\n"; } else { $ret .= " }\n"; } } $ret .= "]"; return $ret; } sub get_archname() { return $Config{archname}; } sub get_boardinfo() { my $ret="unknown"; my $arch=&get_archname; if($arch =~ /^aarch64/) { if(-f "/proc/device-tree/model") { open my $fh, "<", "/proc/device-tree/model" or warn $!; read $fh, $ret, 100; close $fh; $ret =~ s/\0//; } elsif(-d "/sys/firmware/qemu_fw_cfg") { $ret = "QEMU KVM Virtual Machine"; } } elsif($arch =~ /^x86/) { open my $fh, "<", "/proc/cpuinfo" or warn $!; while(<$fh>) { chomp; if(/^model name/) { $ret = (split /:/, $_)[-1]; $ret =~ s/\A\s+//; } } } return $ret; } sub get_dc_voltage() { my $precision = shift; my $board = &get_boardinfo; my $up_res = 0; my $down_res = 0; my $iio_channel; my $ret = 0; my $fh; if($board =~ m/Hlink H88K-V3/) { # 如果显示值与测量值偏差较大,可适当调整 $up_res 及 $down_res 的值 $up_res = 510; $down_res = 27; $iio_channel = 6; $ret = "(Probably) 12"; } elsif($board =~ m/Hlink H88K V3\.1/) { $up_res = 324.1; $down_res = 27; $iio_channel = 6; $ret = "(Probably) 12"; } elsif($board =~ m/Hlink H6[689]K/) { $up_res = 300; $down_res = 27; $iio_channel = 4; $ret = "(Probably) 12"; } elsif(($board =~ m/Radxa ROCK 5B/i) || ($board =~ m/Radxa ROCK 5 Model B/i)) { $up_res = 100; $down_res = 8.2; $iio_channel = 6; $ret = "(Probably) 12"; } if($up_res && $down_res) { my $voltage_raw = 0; my $voltage_scale = 0; open $fh, "<", "/sys/bus/iio/devices/iio:device0/in_voltage_scale" or die; read $fh, $voltage_scale, 40; close $fh; open $fh, "<", "/sys/bus/iio/devices/iio:device0/in_voltage${iio_channel}_raw" or die; read $fh, $voltage_raw, 40; close $fh; if($voltage_raw && $voltage_scale && (($voltage_raw + 1) * $voltage_scale < 1800)) { $precision = 0 unless $precision; my $fmt = "%0.${precision}f"; $ret = sprintf $fmt, $voltage_raw * $voltage_scale * ($up_res + $down_res) / $down_res / 1000.0; } } return $ret; } ##### main program ##### my $argc = scalar( @ARGV ); if($argc == 0) { print &get_cpu_freq, " / ", &get_soc_temp, "\n"; } elsif($ARGV[0] eq "-a") { print &get_arch_info, "\n"; } elsif($ARGV[0] eq "-A") { print &get_arch_info("A"), "\n"; } elsif($ARGV[0] eq "-t") { print &get_soc_temp, "\n"; } elsif($ARGV[0] eq "-T") { print &get_soc_temp("T"), "\n"; } elsif($ARGV[0] eq "-f") { print &get_cpu_freq, "\n"; } elsif($ARGV[0] =~ /-F/) { print &get_cpu_freq($ARGV[0]), "\n"; } elsif($ARGV[0] eq "-u") { print &get_uptime, "\n"; } elsif($ARGV[0] eq "-l") { print &get_avgload, "\n"; } elsif($ARGV[0] eq "-e") { print &get_ethinfo, "\n"; } elsif($ARGV[0] eq "-ec") { print &get_ethcount, "\n"; } elsif($ARGV[0] eq "-b") { print &get_boardinfo, "\n"; } elsif($ARGV[0] =~ m/-V(\d{0,1})/) { print &get_dc_voltage($1), "\n"; }