amdgpu_fan 0.3.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +65 -21
- data/bin/amdgpu_fan +2 -2
- data/config/environment.rb +13 -1
- data/config/icons.yml +10 -0
- data/lib/amdgpu_fan.rb +7 -0
- data/lib/amdgpu_fan/cli.rb +203 -0
- data/lib/amdgpu_fan/connector.rb +71 -0
- data/lib/amdgpu_fan/mixin/cli_output_format.rb +25 -0
- data/lib/amdgpu_fan/mixin/fan.rb +42 -0
- data/lib/amdgpu_fan/mixin/sys_write.rb +14 -0
- data/lib/amdgpu_fan/pci.rb +62 -0
- data/lib/amdgpu_fan/service.rb +189 -0
- data/lib/amdgpu_fan/stat_set.rb +24 -0
- data/lib/amdgpu_fan/version.rb +6 -0
- data/lib/amdgpu_fan/watcher.rb +55 -0
- metadata +62 -11
- data/lib/amdgpu_fan_cli.rb +0 -120
- data/lib/amdgpu_service.rb +0 -156
- data/lib/radeon_r_black_red_100x100.ascii +0 -40
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a499ce52639612b25843b04c3497c7c36f23f3a960d0946b7dc2e249e9a18874
|
4
|
+
data.tar.gz: fa87ca342988d97a91773b1272829a3b825b88dbd65420d6abd26fed8d97ac92
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 06b3bd73191b39da57ac9c14e7ada8fa2cf1a069e8401f45af10eab6ede0bf79a5ebd2f80ba5c464e60f960e24d11783cf20d698c640a38e36c80846b305772e
|
7
|
+
data.tar.gz: 794e28fd6ae71a898b1e897a0fd612add4585e901ece8bc3928e62de9d8245107767848352fe7203d4aa5b6ec60c4e78b28523cc0c893d4d0bcb2f67fdd52044
|
data/README.md
CHANGED
@@ -1,10 +1,17 @@
|
|
1
|
-
#
|
1
|
+
# amdgpu_fan
|
2
2
|
|
3
|
-
[![
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/amdgpu_fan.svg)](https://badge.fury.io/rb/amdgpu_fan)
|
4
|
+
[![Build Status](https://travis-ci.org/HarlemSquirrel/amdgpu-fan-rb.svg?branch=master)](https://travis-ci.org/HarlemSquirrel/amdgpu-fan-rb) [![Maintainability](https://api.codeclimate.com/v1/badges/27233cee17ef6a2c14fd/maintainability)](https://codeclimate.com/github/HarlemSquirrel/amdgpu-fan-rb/maintainability)
|
4
5
|
|
5
|
-
A Ruby CLI to read and set
|
6
|
+
A Ruby CLI to read and set fan speed, power profiles, and more for AMD Radeon graphics cards running on the AMDGPU Linux driver.
|
6
7
|
|
7
|
-
|
8
|
+
**amdgpu_fan** aims to provide a more user friendly interface on top of [sysfs](https://en.wikipedia.org/wiki/Sysfs) for displaying statistics and interacting with AMD Radeon graphics hardware running on the [AMDgpu](https://dri.freedesktop.org/docs/drm/gpu/amdgpu.html) driver.
|
9
|
+
|
10
|
+
#### Further reading
|
11
|
+
|
12
|
+
- https://wiki.archlinux.org/index.php/AMDGPU#Overclocking
|
13
|
+
- https://wiki.archlinux.org/index.php/Fan_speed_control#AMDGPU_sysfs_fan_control
|
14
|
+
- https://phoronix.com/scan.php?page=news_item&px=AMDGPU-Quick-WattMan-Cap-Test
|
8
15
|
|
9
16
|
## Installation
|
10
17
|
|
@@ -28,27 +35,56 @@ gem install amdgpu_fan
|
|
28
35
|
## Usage
|
29
36
|
|
30
37
|
```
|
31
|
-
➤ amdgpu_fan help
|
38
|
+
➤ bin/amdgpu_fan help
|
32
39
|
Commands:
|
33
|
-
amdgpu_fan
|
34
|
-
amdgpu_fan
|
35
|
-
amdgpu_fan
|
36
|
-
amdgpu_fan
|
37
|
-
amdgpu_fan
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
40
|
+
amdgpu_fan connectors # View the status of the display connectors.
|
41
|
+
amdgpu_fan fan # View fan details.
|
42
|
+
amdgpu_fan fan_set PERCENTAGE/AUTO # Set fan speed to percentage or automatic mode. (requires sudo)
|
43
|
+
amdgpu_fan help [COMMAND] # Describe available commands or one specific command
|
44
|
+
amdgpu_fan profile # View power profile details.
|
45
|
+
amdgpu_fan profile_auto # Set the power profile to automatic mode.
|
46
|
+
amdgpu_fan profile_force PROFILE_NUM # Manually set a power profile. (requires sudo)
|
47
|
+
amdgpu_fan status [--logo] # View device info, current fan speed, and temperature.
|
48
|
+
amdgpu_fan watch [SECONDS] # Watch fan speed, load, power, and temperature refreshed every n seconds.
|
49
|
+
amdgpu_fan watch_csv [SECONDS] # Watch stats in CSV format refreshed every n seconds defaulting to 1 second.
|
50
|
+
|
51
|
+
➤ bin/amdgpu_fan status
|
52
|
+
📺 GPU: Advanced Micro Devices, Inc. [AMD/ATI] Radeon R9 FURY X / NANO
|
53
|
+
📄 vBIOS: 113-C8800100-102
|
54
|
+
⏰ Clocks: 724Mhz Core, 500Mhz Memory
|
55
|
+
💾 Memory: 4096 MiB
|
56
|
+
🌀 Fan: auto mode running at 1809 rpm (48%)
|
57
|
+
🌞 Temp: 21.0°C
|
58
|
+
⚡ Power: 3D_FULL_SCREEN profile in performance mode using 16.2 / 300.0 Watts (5%)
|
59
|
+
⚖ Load: [ ]0%
|
45
60
|
|
46
61
|
➤ bin/amdgpu_fan watch 3
|
47
62
|
Watching Advanced Micro Devices, Inc. [AMD/ATI] Radeon R9 FURY X / NANO every 3 second(s)...
|
48
63
|
<Press Ctrl-C to exit>
|
49
|
-
2019-05-
|
50
|
-
2019-05-
|
51
|
-
2019-05-
|
64
|
+
2019-05-28 20:57:41 | Core: 724Mhz | Memory: 500Mhz | Fan: 948 rpm [* ]14% | Load: [** ]24% | Power: 16.07 W [* ]6% | Temp: 34.0°C
|
65
|
+
2019-05-28 20:57:45 | Core: 512Mhz | Memory: 500Mhz | Fan: 948 rpm [* ]14% | Load: [ ]0% | Power: 16.13 W [* ]7% | Temp: 34.0°C
|
66
|
+
2019-05-28 20:57:49 | Core: 892Mhz | Memory: 500Mhz | Fan: 948 rpm [* ]14% | Load: [ ]0% | Power: 25.22 W [* ]5% | Temp: 33.0°C
|
67
|
+
2019-05-28 20:57:53 | Core: 300Mhz | Memory: 500Mhz | Fan: 948 rpm [* ]14% | Load: [ ]0% | Power: 19.1 W [* ]6% | Temp: 33.0°C
|
68
|
+
2019-05-28 20:57:57 | Core: 1050Mhz | Memory: 500Mhz | Fan: 948 rpm [* ]14% | Load: [********* ]94% | Power: 103.04 W [*** ]31% | Temp: 36.0°C
|
69
|
+
2019-05-28 20:58:01 | Core: 1050Mhz | Memory: 500Mhz | Fan: 954 rpm [** ]15% | Load: [********* ]91% | Power: 158.07 W [***** ]53% | Temp: 38.0°C
|
70
|
+
2019-05-28 20:58:05 | Core: 1050Mhz | Memory: 500Mhz | Fan: 977 rpm [** ]16% | Load: [**********]100% | Power: 218.01 W [******* ]73% | Temp: 40.0°C
|
71
|
+
2019-05-28 20:58:09 | Core: 1050Mhz | Memory: 500Mhz | Fan: 1005 rpm [** ]16% | Load: [**********]100% | Power: 216.24 W [******* ]71% | Temp: 40.0°C
|
72
|
+
2019-05-28 20:58:13 | Core: 1050Mhz | Memory: 500Mhz | Fan: 1033 rpm [** ]17% | Load: [**********]97% | Power: 109.25 W [**** ]39% | Temp: 38.0°C
|
73
|
+
2019-05-28 20:58:17 | Core: 724Mhz | Memory: 500Mhz | Fan: 1058 rpm [** ]17% | Load: [ ]0% | Power: 17.17 W [* ]6% | Temp: 35.0°C
|
74
|
+
^C
|
75
|
+
And now the watch is ended.
|
76
|
+
```
|
77
|
+
|
78
|
+
```
|
79
|
+
➤ bin/amdgpu_fan watch_avg
|
80
|
+
Watching Sapphire Technology Limited Vega 10 XL/XT [Radeon RX Vega 56/64] min, max and averges since
|
81
|
+
2020-06-02 23:05:20 -0400...
|
82
|
+
<Press Ctrl-C to exit>
|
83
|
+
⏰ Core clock min: 852 MHz avg: 887.0 MHz max: 1200 MHz now: 852 MHz
|
84
|
+
💾 Memory clk min: 167 MHz avg: 227.1 MHz max: 945 MHz now: 167 MHz
|
85
|
+
🌀 Fan speed min: 1231 RPM avg: 1231.0 RPM max: 1231 RPM now: 1231 RPM
|
86
|
+
⚡ Power usage min: 6.0 W avg: 21.8 W max: 141.0 W now: 6.0 W
|
87
|
+
🌡 Temperature min: 30 °C avg: 31.3 °C max: 35 °C now: 32 °C
|
52
88
|
^C
|
53
89
|
And now the watch is ended.
|
54
90
|
```
|
@@ -57,4 +93,12 @@ And now the watch is ended.
|
|
57
93
|
|
58
94
|
- [Ruby](https://www.ruby-lang.org) with [Bundler](https://bundler.io)
|
59
95
|
- [Thor](http://whatisthor.com/) (installed with `bundle install`)
|
60
|
-
-
|
96
|
+
- Internet connection - Device info is retrieved from https://pci-ids.ucw.cz/
|
97
|
+
|
98
|
+
## Building a binary
|
99
|
+
|
100
|
+
[Ruby Packer](https://github.com/pmq20/ruby-packer) provides a convenient way to compile this into a single executable. For the best results, compile Ruby Packer from source from the lastest master branch.
|
101
|
+
|
102
|
+
```sh
|
103
|
+
rubyc amdgpu_fan --output amdgpu_fan
|
104
|
+
```
|
data/bin/amdgpu_fan
CHANGED
data/config/environment.rb
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'thor'
|
2
4
|
|
3
|
-
require_relative '../lib/
|
5
|
+
require_relative '../lib/amdgpu_fan'
|
6
|
+
require_relative '../lib/amdgpu_fan/version'
|
7
|
+
|
8
|
+
require_relative '../lib/amdgpu_fan/mixin/cli_output_format'
|
9
|
+
require_relative '../lib/amdgpu_fan/mixin/sys_write'
|
10
|
+
|
11
|
+
require_relative '../lib/amdgpu_fan/service'
|
12
|
+
require_relative '../lib/amdgpu_fan/cli'
|
13
|
+
require_relative '../lib/amdgpu_fan/pci'
|
14
|
+
require_relative '../lib/amdgpu_fan/stat_set'
|
15
|
+
require_relative '../lib/amdgpu_fan/watcher'
|
data/config/icons.yml
ADDED
data/lib/amdgpu_fan.rb
ADDED
@@ -0,0 +1,203 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
module AmdgpuFan
|
6
|
+
# The command-line interface class
|
7
|
+
class Cli < Thor
|
8
|
+
include CliOutputFormat
|
9
|
+
|
10
|
+
ICONS = YAML.safe_load(File.read(File.join(__dir__, '../../config/icons.yml')))
|
11
|
+
.transform_keys(&:to_sym).freeze
|
12
|
+
WATCH_FIELD_SEPARATOR = ' | '
|
13
|
+
|
14
|
+
desc 'connectors', 'View the status of the display connectors.'
|
15
|
+
def connectors
|
16
|
+
amdgpu_service.connectors.each do |connector|
|
17
|
+
puts "#{connector.type} #{connector.index}:\t" +
|
18
|
+
(connector.connected? ? connector.display_name : connector.status)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
desc 'profile', 'View power profile details.'
|
23
|
+
def profile
|
24
|
+
puts amdgpu_service.profile_summary
|
25
|
+
end
|
26
|
+
|
27
|
+
desc 'profile_auto', 'Set the power profile to automatic mode.'
|
28
|
+
def profile_auto
|
29
|
+
amdgpu_service.profile_auto
|
30
|
+
puts amdgpu_service.profile_summary
|
31
|
+
end
|
32
|
+
|
33
|
+
desc 'profile_force PROFILE_NUM', 'Manually set a power profile. (requires sudo)'
|
34
|
+
def profile_force(state)
|
35
|
+
amdgpu_service.profile_force = state
|
36
|
+
puts amdgpu_service.profile_summary
|
37
|
+
end
|
38
|
+
|
39
|
+
desc 'fan', 'View fan details.'
|
40
|
+
def fan
|
41
|
+
puts fan_status
|
42
|
+
end
|
43
|
+
|
44
|
+
desc 'fan_set PERCENTAGE/AUTO', 'Set fan speed to percentage or automatic mode. (requires sudo)'
|
45
|
+
def fan_set(value)
|
46
|
+
if value.strip.casecmp('auto').zero?
|
47
|
+
amdgpu_service.fan_mode = :auto
|
48
|
+
else
|
49
|
+
return puts 'Invalid percentage' unless (0..100).cover?(value.to_i)
|
50
|
+
|
51
|
+
amdgpu_service.fan_speed = value
|
52
|
+
end
|
53
|
+
puts fan_status
|
54
|
+
end
|
55
|
+
|
56
|
+
desc 'status [--logo]', 'View device info, current fan speed, and temperature.'
|
57
|
+
def status(option = nil)
|
58
|
+
puts radeon_logo if option == '--logo'
|
59
|
+
puts ICONS[:gpu] + ' GPU:'.ljust(9) + amdgpu_service.name,
|
60
|
+
ICONS[:vbios] + ' vBIOS:'.ljust(9) + amdgpu_service.vbios_version,
|
61
|
+
ICONS[:display] + ' Displays:' + amdgpu_service.display_names.join(', '),
|
62
|
+
ICONS[:clock] + ' Clocks:'.ljust(9) + clock_status,
|
63
|
+
ICONS[:memory] + ' Memory:'.ljust(9) + mem_total_mibibyes,
|
64
|
+
ICONS[:fan] + ' Fan:'.ljust(9) + fan_status,
|
65
|
+
ICONS[:temp] + ' Temp:'.ljust(9) + "#{amdgpu_service.temperature}°C",
|
66
|
+
ICONS[:power] + ' Power:'.ljust(9) + "#{amdgpu_service.profile_mode} profile in " \
|
67
|
+
"#{amdgpu_service.power_dpm_state} mode using " \
|
68
|
+
"#{amdgpu_service.power_draw} / #{amdgpu_service.power_max} Watts "\
|
69
|
+
"(#{amdgpu_service.power_draw_percent}%)",
|
70
|
+
ICONS[:load] + ' Load:'.ljust(9) + percent_meter(amdgpu_service.busy_percent, 20)
|
71
|
+
end
|
72
|
+
|
73
|
+
desc 'version', 'Print the application version.'
|
74
|
+
def version
|
75
|
+
puts AmdgpuFan::VERSION
|
76
|
+
end
|
77
|
+
|
78
|
+
desc 'watch [SECONDS]', 'Watch fan speed, load, power, and temperature ' \
|
79
|
+
'refreshed every n seconds.'
|
80
|
+
def watch(seconds = 1)
|
81
|
+
return puts 'Seconds must be from 1 to 600' unless (1..600).cover?(seconds.to_i)
|
82
|
+
|
83
|
+
puts "Watching #{amdgpu_service.name} every #{seconds} second(s)...",
|
84
|
+
' <Press Ctrl-C to exit>'
|
85
|
+
|
86
|
+
trap 'SIGINT' do
|
87
|
+
puts "\nAnd now the watch is ended."
|
88
|
+
exit 0
|
89
|
+
end
|
90
|
+
|
91
|
+
loop do
|
92
|
+
time = Time.now
|
93
|
+
puts [time.strftime('%F %T'), summary_clock, summary_fan, summary_load, summary_power,
|
94
|
+
summary_temp].join(WATCH_FIELD_SEPARATOR)
|
95
|
+
|
96
|
+
# It can take a second or two to run the above so we remove them from the wait
|
97
|
+
# here to get a more consistant watch interval.
|
98
|
+
sec_left_to_wait = time.to_i + seconds.to_i - Time.now.to_i
|
99
|
+
sleep sec_left_to_wait if sec_left_to_wait.positive?
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
desc 'watch_avg',
|
104
|
+
<<~DOC
|
105
|
+
Watch min, max, average, and current stats.
|
106
|
+
DOC
|
107
|
+
def watch_avg
|
108
|
+
puts "Watching #{amdgpu_service.name} min, max and averges since #{Time.now}...",
|
109
|
+
' <Press Ctrl-C to exit>',
|
110
|
+
"\n\n\n\n\n"
|
111
|
+
|
112
|
+
trap 'SIGINT' do
|
113
|
+
puts "\nAnd now the watch is ended."
|
114
|
+
exit 0
|
115
|
+
end
|
116
|
+
|
117
|
+
watcher = Watcher.new amdgpu_service
|
118
|
+
|
119
|
+
loop do
|
120
|
+
watcher.measure
|
121
|
+
5.times { print "\033[K\033[A" } # move up a line and clear to end of line
|
122
|
+
|
123
|
+
puts ICONS[:clock] + ' Core clock ' + watcher.core_clock.to_s,
|
124
|
+
ICONS[:memory] + ' Memory clk ' + watcher.mem_clock.to_s,
|
125
|
+
ICONS[:fan] + ' Fan speed ' + watcher.fan_speed.to_s,
|
126
|
+
ICONS[:power] + ' Power usage ' + watcher.power.to_s,
|
127
|
+
ICONS[:temp] + ' Temperature ' + watcher.temp.to_s
|
128
|
+
sleep 1
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
desc 'watch_csv [SECONDS]', 'Watch stats in CSV format ' \
|
133
|
+
'refreshed every n seconds defaulting to 1 second.'
|
134
|
+
def watch_csv(seconds = 1)
|
135
|
+
return puts 'Seconds must be from 1 to 600' unless (1..600).cover?(seconds.to_i)
|
136
|
+
|
137
|
+
puts 'Timestamp, Core Clock (Mhz),Memory Clock (Mhz),Fan speed (rpm), '\
|
138
|
+
'Load (%),Power (Watts),Temp (°C)'
|
139
|
+
|
140
|
+
trap 'SIGINT' do
|
141
|
+
exit 0
|
142
|
+
end
|
143
|
+
|
144
|
+
loop do
|
145
|
+
puts [Time.now.strftime('%F %T'),
|
146
|
+
amdgpu_service.core_clock,
|
147
|
+
amdgpu_service.memory_clock,
|
148
|
+
amdgpu_service.fan_speed_rpm,
|
149
|
+
amdgpu_service.busy_percent,
|
150
|
+
amdgpu_service.power_draw,
|
151
|
+
amdgpu_service.temperature].join(',')
|
152
|
+
sleep seconds.to_i
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
private
|
157
|
+
|
158
|
+
def amdgpu_service
|
159
|
+
@amdgpu_service ||= AmdgpuFan::Service.new
|
160
|
+
end
|
161
|
+
|
162
|
+
def clock_status
|
163
|
+
"#{amdgpu_service.core_clock} Core, #{amdgpu_service.memory_clock} Memory"
|
164
|
+
end
|
165
|
+
|
166
|
+
def fan_status
|
167
|
+
"#{amdgpu_service.fan_mode} mode running at " \
|
168
|
+
"#{amdgpu_service.fan_speed_rpm} rpm (#{amdgpu_service.fan_speed_percent}%)"
|
169
|
+
end
|
170
|
+
|
171
|
+
def mem_total_mibibyes
|
172
|
+
"#{amdgpu_service.memory_total / (2**20)} MiB"
|
173
|
+
end
|
174
|
+
|
175
|
+
def power_max
|
176
|
+
format('%<num>0.2f', num: amdgpu_service.power_max)
|
177
|
+
end
|
178
|
+
|
179
|
+
def summary_clock
|
180
|
+
"Core: #{amdgpu_service.core_clock.rjust(7)}#{WATCH_FIELD_SEPARATOR}"\
|
181
|
+
"Memory: #{amdgpu_service.memory_clock.rjust(7)}"
|
182
|
+
end
|
183
|
+
|
184
|
+
def summary_fan
|
185
|
+
fan_speed_string = "#{amdgpu_service.fan_speed_rpm} rpm".rjust(8)
|
186
|
+
"Fan: #{fan_speed_string} #{percent_meter(amdgpu_service.fan_speed_percent)}"
|
187
|
+
end
|
188
|
+
|
189
|
+
def summary_load
|
190
|
+
"Load: #{percent_meter amdgpu_service.busy_percent}"
|
191
|
+
end
|
192
|
+
|
193
|
+
def summary_power
|
194
|
+
"Power: #{format('%<num>0.02f', num: amdgpu_service.power_draw).rjust(power_max.length)} W" \
|
195
|
+
" #{percent_meter amdgpu_service.power_draw_percent}"
|
196
|
+
end
|
197
|
+
|
198
|
+
def summary_temp
|
199
|
+
temp_string = "#{amdgpu_service.temperature}°C".rjust(7)
|
200
|
+
"Temp: #{temp_string}"
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AmdgpuFan
|
4
|
+
## Connector
|
5
|
+
#
|
6
|
+
# A model class for a GPU connector
|
7
|
+
class Connector
|
8
|
+
EDID_DESCRIPTORS_CONF = {
|
9
|
+
display_name_leading_bytes: String.new('\x00\xFC\x00', encoding: 'ascii-8bit'),
|
10
|
+
unspecified_text_leading_bytes: String.new('\x00\xFE\x00', encoding: 'ascii-8bit'),
|
11
|
+
index_range: (54..125)
|
12
|
+
}.freeze
|
13
|
+
|
14
|
+
attr_reader :card_num, :dir_path, :index, :type
|
15
|
+
|
16
|
+
class << self
|
17
|
+
##
|
18
|
+
# Return an array of connector objects for the provided card number.
|
19
|
+
# The files are sorted to improve how they are displayed to the user.
|
20
|
+
def where(card_num:)
|
21
|
+
Dir["/sys/class/drm/card#{card_num}/card#{card_num}-*"].sort.map do |dir_path|
|
22
|
+
Connector.new card_num: card_num,
|
23
|
+
dir_path: dir_path,
|
24
|
+
index: dir_path[-1],
|
25
|
+
type: dir_path.slice(/(?<=card#{card_num}-)[A-z]+/)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def initialize(card_num:, dir_path:, index:, type:)
|
31
|
+
@card_num = card_num
|
32
|
+
@dir_path = dir_path
|
33
|
+
@index = index
|
34
|
+
@type = type
|
35
|
+
end
|
36
|
+
|
37
|
+
def connected?
|
38
|
+
status.casecmp('connected').zero?
|
39
|
+
end
|
40
|
+
|
41
|
+
def display_name
|
42
|
+
return if edid.to_s.empty?
|
43
|
+
|
44
|
+
(display_name_text + unspecified_text).join(' ').strip
|
45
|
+
end
|
46
|
+
|
47
|
+
def status
|
48
|
+
File.read(File.join(dir_path, 'status')).strip
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def display_descriptors_raw
|
54
|
+
edid.slice EDID_DESCRIPTORS_CONF[:index_range]
|
55
|
+
end
|
56
|
+
|
57
|
+
def display_name_text
|
58
|
+
display_descriptors_raw
|
59
|
+
.scan(/(?<=#{EDID_DESCRIPTORS_CONF[:display_name_leading_bytes]}).{1,13}/)
|
60
|
+
end
|
61
|
+
|
62
|
+
def edid
|
63
|
+
File.read("#{dir_path}/edid", encoding: 'ascii-8bit')
|
64
|
+
end
|
65
|
+
|
66
|
+
def unspecified_text
|
67
|
+
display_descriptors_raw
|
68
|
+
.scan(/(?<=#{EDID_DESCRIPTORS_CONF[:unspecified_text_leading_bytes]}).{1,13}/)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AmdgpuFan
|
4
|
+
# A mixin to help with CLI output formatting
|
5
|
+
module CliOutputFormat
|
6
|
+
METER_CHAR = '*'
|
7
|
+
TIME_FORMAT = '%F %T'
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def current_time
|
12
|
+
Time.now.strftime(TIME_FORMAT)
|
13
|
+
end
|
14
|
+
|
15
|
+
def percent_meter(percent, length = 10)
|
16
|
+
progress_bar_count = (length * percent.to_f / 100).round
|
17
|
+
percent_string = "#{format '%<num>0.2i', num: percent}%".ljust(3)
|
18
|
+
"[#{METER_CHAR * progress_bar_count}#{' ' * (length - progress_bar_count)}]#{percent_string}"
|
19
|
+
end
|
20
|
+
|
21
|
+
def radeon_logo
|
22
|
+
File.read(File.join(__dir__, '../../../assets/radeon_r_black_red_100x100.ascii'))
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|