Skip to content

Commit 016a20f

Browse files
roylee123MichelMoriniaux
authored andcommitted
[device][accton]Add fan monitor for as7816-64x (sonic-net#2859)
* catch signal SIGINT and SIGTERM to set all fans full-speed before end fan monitor. Signed-off-by: roy_lee <[email protected]> * Add fan_control monitor for as7816-64x. Signed-off-by: roy_lee <[email protected]> * Fix typo. Signed-off-by: roy_lee <[email protected]> * Correct typo and duty setting after verified. Signed-off-by: roy_lee <[email protected]>
1 parent ad880e9 commit 016a20f

File tree

7 files changed

+560
-5
lines changed

7 files changed

+560
-5
lines changed

platform/broadcom/sonic-platform-modules-accton/as5712-54x/utils/accton_as5712_monitor.py

+10
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import types
3434
import time # this is only being used as part of the example
3535
import traceback
36+
import signal
3637
from tabulate import tabulate
3738
from as5712_54x.fanutil import FanUtil
3839
from as5712_54x.thermalutil import ThermalUtil
@@ -42,6 +43,7 @@
4243
# Deafults
4344
VERSION = '1.0'
4445
FUNCTION_NAME = 'accton_as5712_monitor'
46+
DUTY_MAX = 100
4547

4648
global log_file
4749
global log_level
@@ -166,6 +168,12 @@ def manage_fans(self):
166168

167169
return True
168170

171+
def handler(signum, frame):
172+
fan = FanUtil()
173+
logging.debug('INFO:Cause signal %d, set fan speed max.', signum)
174+
fan.set_fan_duty_cycle(fan.get_idx_fan_start(), DUTY_MAX)
175+
sys.exit(0)
176+
169177
def main(argv):
170178
log_file = '%s.log' % FUNCTION_NAME
171179
log_level = logging.INFO
@@ -184,6 +192,8 @@ def main(argv):
184192
elif opt in ('-l', '--lfile'):
185193
log_file = arg
186194

195+
signal.signal(signal.SIGINT, handler)
196+
signal.signal(signal.SIGTERM, handler)
187197
monitor = accton_as5712_monitor(log_file, log_level)
188198

189199
# Loop forever, doing something useful hopefully:

platform/broadcom/sonic-platform-modules-accton/as7312-54x/setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#!/usr/bin/env pytho
1+
#!/usr/bin/env python
22

33
import os
44
import sys

platform/broadcom/sonic-platform-modules-accton/as7312-54x/utils/accton_as7312_monitor.py

+11-1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import types
3535
import time # this is only being used as part of the example
3636
import traceback
37+
import signal
3738
from tabulate import tabulate
3839
from as7312_54x.fanutil import FanUtil
3940
from as7312_54x.thermalutil import ThermalUtil
@@ -43,6 +44,7 @@
4344
# Deafults
4445
VERSION = '1.0'
4546
FUNCTION_NAME = 'accton_as7312_monitor'
47+
DUTY_MAX = 100
4648

4749
global log_file
4850
global log_level
@@ -98,7 +100,7 @@ def __init__(self, log_file, log_level):
98100
logging.debug('SET. logfile:%s / loglevel:%d', log_file, log_level)
99101

100102
def manage_fans(self):
101-
max_duty = 100
103+
max_duty = DUTY_MAX
102104
fan_policy_f2b = {
103105
0: [32, 0, 105000],
104106
1: [50, 105000, 120000],
@@ -179,6 +181,12 @@ def manage_fans(self):
179181
fan.set_fan_duty_cycle(new_duty_cycle)
180182
return True
181183

184+
def handler(signum, frame):
185+
fan = FanUtil()
186+
logging.debug('INFO:Cause signal %d, set fan speed max.', signum)
187+
fan.set_fan_duty_cycle(DUTY_MAX)
188+
sys.exit(0)
189+
182190
def main(argv):
183191
log_file = '%s.log' % FUNCTION_NAME
184192
log_level = logging.INFO
@@ -197,6 +205,8 @@ def main(argv):
197205
elif opt in ('-l', '--lfile'):
198206
log_file = arg
199207

208+
signal.signal(signal.SIGINT, handler)
209+
signal.signal(signal.SIGTERM, handler)
200210
monitor = accton_as7312_monitor(log_file, log_level)
201211

202212
# Loop forever, doing something useful hopefully:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
#!/usr/bin/env python
2+
#
3+
# Copyright (C) 2017 Accton Technology Corporation
4+
#
5+
# This program is free software: you can redistribute it and/or modify
6+
# it under the terms of the GNU General Public License as published by
7+
# the Free Software Foundation, either version 3 of the License, or
8+
# (at your option) any later version.
9+
#
10+
# This program is distributed in the hope that it will be useful,
11+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
# GNU General Public License for more details.
14+
#
15+
# You should have received a copy of the GNU General Public License
16+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
18+
# ------------------------------------------------------------------
19+
# HISTORY:
20+
# mm/dd/yyyy (A.D.)
21+
# 11/13/2017: Polly Hsu, Create
22+
# 1/10/2018: Jostar modify for as7716_32
23+
# 5/02/2019: Roy Lee modify for as7816_64x
24+
# ------------------------------------------------------------------
25+
26+
try:
27+
import time
28+
import logging
29+
from collections import namedtuple
30+
except ImportError as e:
31+
raise ImportError('%s - required module not found' % str(e))
32+
33+
34+
class FanUtil(object):
35+
"""Platform-specific FanUtil class"""
36+
37+
FAN_NUM_ON_MAIN_BROAD = 4
38+
FAN_NUM_1_IDX = 1
39+
FAN_NUM_2_IDX = 2
40+
FAN_NUM_3_IDX = 3
41+
FAN_NUM_4_IDX = 4
42+
43+
FAN_NODE_NUM_OF_MAP = 2
44+
FAN_NODE_FAULT_IDX_OF_MAP = 1
45+
#FAN_NODE_SPEED_IDX_OF_MAP = 2
46+
FAN_NODE_DIR_IDX_OF_MAP = 2
47+
#FAN_NODE_DUTY_IDX_OF_MAP = 4
48+
#FANR_NODE_FAULT_IDX_OF_MAP = 5
49+
50+
BASE_VAL_PATH = '/sys/bus/i2c/devices/17-0068/{0}'
51+
FAN_DUTY_PATH = '/sys/bus/i2c/devices/17-0068/fan_duty_cycle_percentage'
52+
53+
#logfile = ''
54+
#loglevel = logging.INFO
55+
56+
""" Dictionary where
57+
key1 = fan id index (integer) starting from 1
58+
key2 = fan node index (interger) starting from 1
59+
value = path to fan device file (string) """
60+
_fan_to_device_path_mapping = {}
61+
62+
#fan1_direction
63+
#fan1_fault
64+
#fan1_present
65+
66+
#(FAN_NUM_2_IDX, FAN_NODE_DUTY_IDX_OF_MAP): 'fan2_duty_cycle_percentage',
67+
_fan_to_device_node_mapping = {
68+
(FAN_NUM_1_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan1_fault',
69+
(FAN_NUM_1_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan1_direction',
70+
(FAN_NUM_2_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan2_fault',
71+
(FAN_NUM_2_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan2_direction',
72+
73+
(FAN_NUM_3_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan3_fault',
74+
(FAN_NUM_3_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan3_direction',
75+
76+
(FAN_NUM_4_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan4_fault',
77+
(FAN_NUM_4_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan4_direction',
78+
}
79+
80+
def _get_fan_to_device_node(self, fan_num, node_num):
81+
return self._fan_to_device_node_mapping[(fan_num, node_num)]
82+
83+
def _get_fan_node_val(self, fan_num, node_num):
84+
if fan_num < self.FAN_NUM_1_IDX or fan_num > self.FAN_NUM_ON_MAIN_BROAD:
85+
logging.debug('GET. Parameter error. fan_num:%d', fan_num)
86+
return None
87+
88+
if node_num < self.FAN_NODE_FAULT_IDX_OF_MAP or node_num > self.FAN_NODE_NUM_OF_MAP:
89+
logging.debug('GET. Parameter error. node_num:%d', node_num)
90+
return None
91+
92+
device_path = self.get_fan_to_device_path(fan_num, node_num)
93+
94+
try:
95+
val_file = open(device_path, 'r')
96+
except IOError as e:
97+
logging.error('GET. unable to open file: %s', str(e))
98+
return None
99+
100+
content = val_file.readline().rstrip()
101+
102+
if content == '':
103+
logging.debug('GET. content is NULL. device_path:%s', device_path)
104+
return None
105+
106+
try:
107+
val_file.close()
108+
except:
109+
logging.debug('GET. unable to close file. device_path:%s', device_path)
110+
return None
111+
112+
return int(content)
113+
114+
def _set_fan_node_val(self, fan_num, node_num, val):
115+
if fan_num < self.FAN_NUM_1_IDX or fan_num > self.FAN_NUM_ON_MAIN_BROAD:
116+
logging.debug('GET. Parameter error. fan_num:%d', fan_num)
117+
return None
118+
119+
if node_num < self.FAN_NODE_FAULT_IDX_OF_MAP or node_num > self.FAN_NODE_NUM_OF_MAP:
120+
logging.debug('GET. Parameter error. node_num:%d', node_num)
121+
return None
122+
123+
content = str(val)
124+
if content == '':
125+
logging.debug('GET. content is NULL. device_path:%s', device_path)
126+
return None
127+
128+
device_path = self.get_fan_to_device_path(fan_num, node_num)
129+
try:
130+
val_file = open(device_path, 'w')
131+
except IOError as e:
132+
logging.error('GET. unable to open file: %s', str(e))
133+
return None
134+
135+
val_file.write(content)
136+
137+
try:
138+
val_file.close()
139+
except:
140+
logging.debug('GET. unable to close file. device_path:%s', device_path)
141+
return None
142+
143+
return True
144+
145+
def __init__(self):
146+
fan_path = self.BASE_VAL_PATH
147+
148+
for fan_num in range(self.FAN_NUM_1_IDX, self.FAN_NUM_ON_MAIN_BROAD+1):
149+
for node_num in range(self.FAN_NODE_FAULT_IDX_OF_MAP, self.FAN_NODE_NUM_OF_MAP+1):
150+
self._fan_to_device_path_mapping[(fan_num, node_num)] = fan_path.format(
151+
self._fan_to_device_node_mapping[(fan_num, node_num)])
152+
153+
def get_num_fans(self):
154+
return self.FAN_NUM_ON_MAIN_BROAD
155+
156+
def get_idx_fan_start(self):
157+
return self.FAN_NUM_1_IDX
158+
159+
def get_num_nodes(self):
160+
return self.FAN_NODE_NUM_OF_MAP
161+
162+
def get_idx_node_start(self):
163+
return self.FAN_NODE_FAULT_IDX_OF_MAP
164+
165+
def get_size_node_map(self):
166+
return len(self._fan_to_device_node_mapping)
167+
168+
def get_size_path_map(self):
169+
return len(self._fan_to_device_path_mapping)
170+
171+
def get_fan_to_device_path(self, fan_num, node_num):
172+
return self._fan_to_device_path_mapping[(fan_num, node_num)]
173+
174+
def get_fan_fault(self, fan_num):
175+
return self._get_fan_node_val(fan_num, self.FAN_NODE_FAULT_IDX_OF_MAP)
176+
177+
#def get_fan_speed(self, fan_num):
178+
# return self._get_fan_node_val(fan_num, self.FAN_NODE_SPEED_IDX_OF_MAP)
179+
180+
def get_fan_dir(self, fan_num):
181+
return self._get_fan_node_val(fan_num, self.FAN_NODE_DIR_IDX_OF_MAP)
182+
183+
def get_fan_duty_cycle(self):
184+
#duty_path = self.FAN_DUTY_PATH
185+
try:
186+
val_file = open(self.FAN_DUTY_PATH)
187+
except IOError as e:
188+
print "Error: unable to open file: %s" % str(e)
189+
return False
190+
191+
content = val_file.readline().rstrip()
192+
val_file.close()
193+
194+
return int(content)
195+
#self._get_fan_node_val(fan_num, self.FAN_NODE_DUTY_IDX_OF_MAP)
196+
#static u32 reg_val_to_duty_cycle(u8 reg_val)
197+
#{
198+
# reg_val &= FAN_DUTY_CYCLE_REG_MASK;
199+
# return ((u32)(reg_val+1) * 625 + 75)/ 100;
200+
#}
201+
#
202+
def set_fan_duty_cycle(self, val):
203+
204+
try:
205+
fan_file = open(self.FAN_DUTY_PATH, 'r+')
206+
except IOError as e:
207+
print "Error: unable to open file: %s" % str(e)
208+
return False
209+
fan_file.write(str(val))
210+
fan_file.close()
211+
return True
212+
213+
#def get_fanr_fault(self, fan_num):
214+
# return self._get_fan_node_val(fan_num, self.FANR_NODE_FAULT_IDX_OF_MAP)
215+
216+
def get_fanr_speed(self, fan_num):
217+
return self._get_fan_node_val(fan_num, self.FANR_NODE_SPEED_IDX_OF_MAP)
218+
219+
def get_fan_status(self, fan_num):
220+
if fan_num < self.FAN_NUM_1_IDX or fan_num > self.FAN_NUM_ON_MAIN_BROAD:
221+
logging.debug('GET. Parameter error. fan_num, %d', fan_num)
222+
return None
223+
224+
if self.get_fan_fault(fan_num) is not None and self.get_fan_fault(fan_num) > 0:
225+
logging.debug('GET. FAN fault. fan_num, %d', fan_num)
226+
return False
227+
228+
#if self.get_fanr_fault(fan_num) is not None and self.get_fanr_fault(fan_num) > 0:
229+
# logging.debug('GET. FANR fault. fan_num, %d', fan_num)
230+
# return False
231+
232+
return True
233+
234+
#def main():
235+
# fan = FanUtil()
236+
#
237+
# print 'get_size_node_map : %d' % fan.get_size_node_map()
238+
# print 'get_size_path_map : %d' % fan.get_size_path_map()
239+
# for x in range(fan.get_idx_fan_start(), fan.get_num_fans()+1):
240+
# for y in range(fan.get_idx_node_start(), fan.get_num_nodes()+1):
241+
# print fan.get_fan_to_device_path(x, y)
242+
#
243+
#if __name__ == '__main__':
244+
# main()

0 commit comments

Comments
 (0)