2019-06-25 14:22:13 -05:00
|
|
|
#############################################################################
|
|
|
|
# Celestica
|
|
|
|
#
|
|
|
|
# Module contains an implementation of SONiC Platform Base API and
|
|
|
|
# provides the PSUs status which are available in the platform
|
|
|
|
#
|
|
|
|
#############################################################################
|
|
|
|
|
2019-09-06 16:58:12 -05:00
|
|
|
import os
|
2019-06-25 14:22:13 -05:00
|
|
|
import sonic_platform
|
|
|
|
|
|
|
|
try:
|
|
|
|
from sonic_platform_base.psu_base import PsuBase
|
|
|
|
from sonic_platform.fan import Fan
|
2020-11-25 12:28:36 -06:00
|
|
|
from .helper import APIHelper
|
2019-06-25 14:22:13 -05:00
|
|
|
except ImportError as e:
|
|
|
|
raise ImportError(str(e) + "- required module not found")
|
|
|
|
|
|
|
|
GREEN_LED_PATH = "/sys/devices/platform/leds_dx010/leds/dx010:green:p-{}/brightness"
|
2019-09-06 16:58:12 -05:00
|
|
|
HWMON_PATH = "/sys/bus/i2c/devices/i2c-{0}/{0}-00{1}/hwmon"
|
|
|
|
GPIO_DIR = "/sys/class/gpio"
|
|
|
|
GPIO_LABEL = "pca9505"
|
2019-07-23 12:00:02 -05:00
|
|
|
PSU_NAME_LIST = ["PSU-1", "PSU-2"]
|
2019-09-06 16:58:12 -05:00
|
|
|
PSU_NUM_FAN = [1, 1]
|
|
|
|
PSU_I2C_MAPPING = {
|
|
|
|
0: {
|
|
|
|
"num": 10,
|
|
|
|
"addr": "5a"
|
|
|
|
},
|
|
|
|
1: {
|
|
|
|
"num": 11,
|
|
|
|
"addr": "5b"
|
|
|
|
},
|
|
|
|
}
|
2019-06-25 14:22:13 -05:00
|
|
|
|
|
|
|
|
|
|
|
class Psu(PsuBase):
|
|
|
|
"""Platform-specific Psu class"""
|
|
|
|
|
|
|
|
def __init__(self, psu_index):
|
2019-11-12 17:26:11 -06:00
|
|
|
PsuBase.__init__(self)
|
2019-06-25 14:22:13 -05:00
|
|
|
self.index = psu_index
|
2020-05-22 05:50:43 -05:00
|
|
|
self._api_helper = APIHelper()
|
2019-06-25 14:22:13 -05:00
|
|
|
self.green_led_path = GREEN_LED_PATH.format(self.index+1)
|
2019-07-23 12:00:02 -05:00
|
|
|
self.dx010_psu_gpio = [
|
2019-09-06 16:58:12 -05:00
|
|
|
{'base': self.__get_gpio_base()},
|
2019-07-23 12:00:02 -05:00
|
|
|
{'prs': 27, 'status': 22},
|
|
|
|
{'prs': 28, 'status': 25}
|
|
|
|
]
|
2019-09-06 16:58:12 -05:00
|
|
|
self.i2c_num = PSU_I2C_MAPPING[self.index]["num"]
|
|
|
|
self.i2c_addr = PSU_I2C_MAPPING[self.index]["addr"]
|
|
|
|
self.hwmon_path = HWMON_PATH.format(self.i2c_num, self.i2c_addr)
|
|
|
|
for fan_index in range(0, PSU_NUM_FAN[self.index]):
|
|
|
|
fan = Fan(fan_index, 0, is_psu_fan=True, psu_index=self.index)
|
|
|
|
self._fan_list.append(fan)
|
2019-07-23 12:00:02 -05:00
|
|
|
|
2019-09-06 16:58:12 -05:00
|
|
|
def __search_file_by_contain(self, directory, search_str, file_start):
|
|
|
|
for dirpath, dirnames, files in os.walk(directory):
|
|
|
|
for name in files:
|
|
|
|
file_path = os.path.join(dirpath, name)
|
2020-05-22 05:50:43 -05:00
|
|
|
if name.startswith(file_start) and search_str in self._api_helper.read_txt_file(file_path):
|
2019-09-06 16:58:12 -05:00
|
|
|
return file_path
|
|
|
|
return None
|
|
|
|
|
|
|
|
def __get_gpio_base(self):
|
|
|
|
for r in os.listdir(GPIO_DIR):
|
|
|
|
label_path = os.path.join(GPIO_DIR, r, "label")
|
2020-05-22 05:50:43 -05:00
|
|
|
if "gpiochip" in r and GPIO_LABEL in self._api_helper.read_txt_file(label_path):
|
2019-07-23 12:00:02 -05:00
|
|
|
return int(r[8:], 10)
|
|
|
|
return 216 # Reserve
|
|
|
|
|
2019-09-06 16:58:12 -05:00
|
|
|
def __get_gpio_value(self, pinnum):
|
2019-07-23 12:00:02 -05:00
|
|
|
gpio_base = self.dx010_psu_gpio[0]['base']
|
2019-09-06 16:58:12 -05:00
|
|
|
gpio_dir = GPIO_DIR + '/gpio' + str(gpio_base+pinnum)
|
|
|
|
gpio_file = gpio_dir + "/value"
|
2020-05-22 05:50:43 -05:00
|
|
|
retval = self._api_helper.read_txt_file(gpio_file)
|
2019-09-06 16:58:12 -05:00
|
|
|
return retval.rstrip('\r\n')
|
2019-07-23 12:00:02 -05:00
|
|
|
|
2019-09-06 16:58:12 -05:00
|
|
|
def get_voltage(self):
|
2019-06-25 14:22:13 -05:00
|
|
|
"""
|
2019-09-06 16:58:12 -05:00
|
|
|
Retrieves current PSU voltage output
|
2019-06-25 14:22:13 -05:00
|
|
|
Returns:
|
2019-09-06 16:58:12 -05:00
|
|
|
A float number, the output voltage in volts,
|
|
|
|
e.g. 12.1
|
2019-06-25 14:22:13 -05:00
|
|
|
"""
|
2019-09-06 16:58:12 -05:00
|
|
|
psu_voltage = 0.0
|
|
|
|
voltage_name = "in{}_input"
|
|
|
|
voltage_label = "vout1"
|
|
|
|
|
|
|
|
vout_label_path = self.__search_file_by_contain(
|
|
|
|
self.hwmon_path, voltage_label, "in")
|
|
|
|
if vout_label_path:
|
|
|
|
dir_name = os.path.dirname(vout_label_path)
|
|
|
|
basename = os.path.basename(vout_label_path)
|
2020-12-04 15:41:20 -06:00
|
|
|
in_num = ''.join(list(filter(str.isdigit, basename)))
|
2019-09-06 16:58:12 -05:00
|
|
|
vout_path = os.path.join(
|
|
|
|
dir_name, voltage_name.format(in_num))
|
2020-05-22 05:50:43 -05:00
|
|
|
vout_val = self._api_helper.read_txt_file(vout_path)
|
2019-09-06 16:58:12 -05:00
|
|
|
psu_voltage = float(vout_val) / 1000
|
|
|
|
|
|
|
|
return psu_voltage
|
|
|
|
|
|
|
|
def get_current(self):
|
|
|
|
"""
|
|
|
|
Retrieves present electric current supplied by PSU
|
|
|
|
Returns:
|
|
|
|
A float number, the electric current in amperes, e.g 15.4
|
|
|
|
"""
|
|
|
|
psu_current = 0.0
|
|
|
|
current_name = "curr{}_input"
|
|
|
|
current_label = "iout1"
|
|
|
|
|
|
|
|
curr_label_path = self.__search_file_by_contain(
|
|
|
|
self.hwmon_path, current_label, "cur")
|
|
|
|
if curr_label_path:
|
|
|
|
dir_name = os.path.dirname(curr_label_path)
|
|
|
|
basename = os.path.basename(curr_label_path)
|
2020-12-04 15:41:20 -06:00
|
|
|
cur_num = ''.join(list(filter(str.isdigit, basename)))
|
2019-09-06 16:58:12 -05:00
|
|
|
cur_path = os.path.join(
|
|
|
|
dir_name, current_name.format(cur_num))
|
2020-05-22 05:50:43 -05:00
|
|
|
cur_val = self._api_helper.read_txt_file(cur_path)
|
2019-09-06 16:58:12 -05:00
|
|
|
psu_current = float(cur_val) / 1000
|
|
|
|
|
|
|
|
return psu_current
|
|
|
|
|
|
|
|
def get_power(self):
|
|
|
|
"""
|
|
|
|
Retrieves current energy supplied by PSU
|
|
|
|
Returns:
|
|
|
|
A float number, the power in watts, e.g. 302.6
|
|
|
|
"""
|
|
|
|
psu_power = 0.0
|
|
|
|
current_name = "power{}_input"
|
|
|
|
current_label = "pout1"
|
|
|
|
|
|
|
|
pw_label_path = self.__search_file_by_contain(
|
|
|
|
self.hwmon_path, current_label, "power")
|
|
|
|
if pw_label_path:
|
|
|
|
dir_name = os.path.dirname(pw_label_path)
|
|
|
|
basename = os.path.basename(pw_label_path)
|
2020-12-04 15:41:20 -06:00
|
|
|
pw_num = ''.join(list(filter(str.isdigit, basename)))
|
2019-09-06 16:58:12 -05:00
|
|
|
pw_path = os.path.join(
|
|
|
|
dir_name, current_name.format(pw_num))
|
2020-05-22 05:50:43 -05:00
|
|
|
pw_val = self._api_helper.read_txt_file(pw_path)
|
2019-09-06 16:58:12 -05:00
|
|
|
psu_power = float(pw_val) / 1000000
|
|
|
|
|
|
|
|
return psu_power
|
|
|
|
|
|
|
|
def get_powergood_status(self):
|
|
|
|
"""
|
|
|
|
Retrieves the powergood status of PSU
|
|
|
|
Returns:
|
|
|
|
A boolean, True if PSU has stablized its output voltages and passed all
|
|
|
|
its internal self-tests, False if not.
|
|
|
|
"""
|
|
|
|
return self.get_status()
|
2019-06-25 14:22:13 -05:00
|
|
|
|
|
|
|
def set_status_led(self, color):
|
|
|
|
"""
|
|
|
|
Sets the state of the PSU status LED
|
|
|
|
Args:
|
|
|
|
color: A string representing the color with which to set the PSU status LED
|
|
|
|
Note: Only support green and off
|
|
|
|
Returns:
|
|
|
|
bool: True if status LED state is set successfully, False if not
|
|
|
|
"""
|
|
|
|
|
|
|
|
set_status_str = {
|
|
|
|
self.STATUS_LED_COLOR_GREEN: '1',
|
|
|
|
self.STATUS_LED_COLOR_OFF: '0'
|
|
|
|
}.get(color, None)
|
|
|
|
|
|
|
|
if not set_status_str:
|
|
|
|
return False
|
|
|
|
|
|
|
|
try:
|
|
|
|
with open(self.green_led_path, 'w') as file:
|
|
|
|
file.write(set_status_str)
|
|
|
|
except IOError:
|
|
|
|
return False
|
|
|
|
|
|
|
|
return True
|
2019-07-23 12:00:02 -05:00
|
|
|
|
2019-09-06 16:58:12 -05:00
|
|
|
def get_status_led(self):
|
|
|
|
"""
|
|
|
|
Gets the state of the PSU status LED
|
|
|
|
Returns:
|
|
|
|
A string, one of the predefined STATUS_LED_COLOR_* strings above
|
|
|
|
"""
|
2020-05-22 05:50:43 -05:00
|
|
|
status = self._api_helper.read_txt_file(self.green_led_path)
|
2019-09-06 16:58:12 -05:00
|
|
|
status_str = {
|
|
|
|
'255': self.STATUS_LED_COLOR_GREEN,
|
|
|
|
'0': self.STATUS_LED_COLOR_OFF
|
|
|
|
}.get(status, None)
|
|
|
|
|
|
|
|
return status_str
|
|
|
|
|
2019-07-23 12:00:02 -05:00
|
|
|
def get_name(self):
|
|
|
|
"""
|
|
|
|
Retrieves the name of the device
|
|
|
|
Returns:
|
|
|
|
string: The name of the device
|
|
|
|
"""
|
|
|
|
return PSU_NAME_LIST[self.index]
|
|
|
|
|
|
|
|
def get_presence(self):
|
|
|
|
"""
|
|
|
|
Retrieves the presence of the PSU
|
|
|
|
Returns:
|
|
|
|
bool: True if PSU is present, False if not
|
|
|
|
"""
|
2019-09-06 16:58:12 -05:00
|
|
|
raw = self.__get_gpio_value(self.dx010_psu_gpio[self.index+1]['prs'])
|
2019-07-23 12:00:02 -05:00
|
|
|
return int(raw, 10) == 0
|
|
|
|
|
|
|
|
def get_status(self):
|
|
|
|
"""
|
|
|
|
Retrieves the operational status of the device
|
|
|
|
Returns:
|
|
|
|
A boolean value, True if device is operating properly, False if not
|
|
|
|
"""
|
2019-09-06 16:58:12 -05:00
|
|
|
raw = self.__get_gpio_value(
|
|
|
|
self.dx010_psu_gpio[self.index+1]['status'])
|
2019-07-23 12:00:02 -05:00
|
|
|
return int(raw, 10) == 1
|