예제 #1
0
    def __init__(self):
        self._api_common = Common()

        # Init cpld reg path
        self.setreg_path = os.path.join(PLATFORM_CPLD_PATH, SETREG_FILE)
        self.getreg_path = os.path.join(PLATFORM_CPLD_PATH, GETREG_FILE)

        # Set default value
        self._disable()
        self.armed = False
        self.timeout = self._gettimeout()
예제 #2
0
    def __init__(self):
        ChassisBase.__init__(self)
        self.CHASSIS_CONFIG = 'chassis.json'
        self.THERMAL_CONFIG = 'thermal.json'
        self.SFP_CONFIG = 'sfp.json'
        self.PSU_CONFIG = 'psu.json'
        self.FAN_CONFIG = 'fan.json'
        self.COMPONENT_CONFIG = 'component.json'

        self.SFP_STATUS_INSERTED = "1"
        self.SFP_STATUS_REMOVED = "0"
        self.port_dict = {}
        self.enable_read = "i2cset -f -y 2 0x35 0x2a 0x01"
        self.disable_read = "i2cset -f -y 2 0x35 0x2a 0x00"
        self.enable_write = "i2cset -f -y 2 0x35 0x2b 0x00"
        self.disable_write = "i2cset -f -y 2 0x35 0x2b 0x01"
        self.enable_erase = "i2cset -f -y 2 0x35 0x2c 0x01"
        self.disable_erase = "i2cset -f -y 2 0x35 0x2c 0x00"
        self.read_value = "i2cget -f -y 2 0x35 0x25"
        self.write_value = "i2cset -f -y 2 0x35 0x21 0x0a"
        self.set_sys_led_cmd = "i2cset -f -y 2 0x33 0xb2 "
        self.get_sys_led_cmd = "i2cget -f -y 2 0x33 0xb2"
        self.led_status = "red"
        # Initialize SFP list
        # sfp.py will read eeprom contents and retrive the eeprom data.
        # It will also provide support sfp controls like reset and setting
        # low power mode.
        # We pass the eeprom path and sfp control path from chassis.py
        # So that sfp.py implementation can be generic to all platforms
        for index in range(PORT_START, PORTS_IN_BLOCK):
            sfp_node = Sfp(index)
            self._sfp_list.append(sfp_node)
            if sfp_node.get_presence():
                self.port_dict[index] = self.SFP_STATUS_INSERTED
            else:
                self.port_dict[index] = self.SFP_STATUS_REMOVED

        self._api_common = Common()
        config_path = self._api_common.get_config_path(self.CHASSIS_CONFIG)
        self._config = self._api_common.load_json_file(config_path)
        self.__initialize_eeprom()

        if self._api_common.is_host():
            self.__initialize_fan()
            self.__initialize_psu()
            self.__initialize_thermals()
        else:
            self.__initialize_components()
예제 #3
0
 def __init__(self, sfp_list):
     self.num_sfp = len(sfp_list)
     self._api_common = Common()
     self._initialize_interrupts()
예제 #4
0
class SfpEvent:
    ''' Listen to insert/remove sfp events '''

    PORT_INFO_DIR = 'SFF'
    PATH_INT_SYSFS = "{0}/{port_name}/{type_prefix}_isr_flags"
    PATH_INTMASK_SYSFS = "{0}/{port_name}/{type_prefix}_isr_mask"
    PATH_PRS_SYSFS = "{0}/{port_name}/{prs_file_name}"
    PRESENT_EN = 0x01

    def __init__(self, sfp_list):
        self.num_sfp = len(sfp_list)
        self._api_common = Common()
        self._initialize_interrupts()

    def _initialize_interrupts(self):
        sfp_info_obj = {}
        port_info_path = os.path.join(PLATFORM_PATH, SWITCH_BRD_PLATFORM,
                                      self.PORT_INFO_DIR)

        for index in range(self.num_sfp):
            port_num = index + 1
            if port_num <= 32:
                port_name = "QSFP{}".format(port_num)
                port_type = "qsfp"
                sysfs_prs_file = "{}_modprs".format(port_type)
            else:
                port_name = "SFP{}".format(port_num - 32)
                port_type = "sfp"
                sysfs_prs_file = "{}_modabs".format(port_type)

            sfp_info_obj[index] = {}
            sfp_info_obj[index][
                'intmask_sysfs'] = self.PATH_INTMASK_SYSFS.format(
                    port_info_path, port_name=port_name, type_prefix=port_type)

            sfp_info_obj[index]['int_sysfs'] = self.PATH_INT_SYSFS.format(
                port_info_path, port_name=port_name, type_prefix=port_type)

            sfp_info_obj[index]['prs_sysfs'] = self.PATH_PRS_SYSFS.format(
                port_info_path,
                port_name=port_name,
                prs_file_name=sysfs_prs_file)

            self._api_common.write_txt_file(
                sfp_info_obj[index]["intmask_sysfs"], hex(self.PRESENT_EN))

        self.sfp_info_obj = sfp_info_obj

    def _is_port_device_present(self, port_idx):
        prs_path = self.sfp_info_obj[port_idx]["prs_sysfs"]
        is_present = 1 - int(self._api_common.read_txt_file(prs_path))
        return is_present

    def _update_port_event_object(self, interrup_devices, port_dict):
        for port_idx in interrup_devices:
            device_id = str(port_idx + 1)
            port_dict[device_id] = str(self._is_port_device_present(port_idx))
        return port_dict

    def _clear_event_flag(self, path):
        self._api_common.write_txt_file(path, hex(0xff))
        time.sleep(0.1)
        self._api_common.write_txt_file(path, hex(0x0))

    def _check_all_port_interrupt_event(self):
        interrupt_devices = {}
        for i in range(self.num_sfp):
            int_sysfs = self.sfp_info_obj[i]["int_sysfs"]
            interrupt_flags = self._api_common.read_txt_file(int_sysfs)
            if interrupt_flags != '0x00':
                interrupt_devices[i] = 1
                self._clear_event_flag(int_sysfs)
        return interrupt_devices

    def get_event(self, timeout):
        sleep_time = min(timeout,
                         POLL_INTERVAL) if timeout != 0 else POLL_INTERVAL
        start_milli_time = int(round(time.time() * 1000))
        int_sfp = {}

        while True:
            chk_sfp = self._check_all_port_interrupt_event()
            int_sfp = self._update_port_event_object(
                chk_sfp, int_sfp) if chk_sfp else int_sfp
            current_milli_time = int(round(time.time() * 1000))
            if (int_sfp) or \
                    (timeout != 0 and current_milli_time - start_milli_time > timeout):
                break

            time.sleep(sleep_time)

        change_dict = dict()
        change_dict['sfp'] = int_sfp

        return True, change_dict
예제 #5
0
class Watchdog(WatchdogBase):
    def __init__(self):
        WatchdogBase.__init__(self)

        self._api_common = Common()

        # Init cpld reg path
        self.setreg_path = os.path.join(PLATFORM_CPLD_PATH, SETREG_FILE)
        self.getreg_path = os.path.join(PLATFORM_CPLD_PATH, GETREG_FILE)

        # Set default value
        self._disable()
        self.armed = False
        self.timeout = self._gettimeout()

    def _enable(self):
        """
        Turn on the watchdog timer
        """
        # echo 0xA181 0x1 > /sys/devices/platform/baseboard/setreg
        enable_val = '{} {}'.format(WDT_ENABLE_REG, ENABLE_CMD)
        return self._api_common.write_txt_file(self.setreg_path, enable_val)

    def _disable(self):
        """
        Turn off the watchdog timer
        """
        # echo 0xA181 0x0 > /sys/devices/platform/baseboard/setreg
        disable_val = '{} {}'.format(WDT_ENABLE_REG, DISABLE_CMD)
        return self._api_common.write_txt_file(self.setreg_path, disable_val)

    def _keepalive(self):
        """
        Keep alive watchdog timer
        """
        # echo 0xA185 0x1 > /sys/devices/platform/baseboard/setreg
        enable_val = '{} {}'.format(WDT_KEEP_ALVIVE_REG, ENABLE_CMD)
        return self._api_common.write_txt_file(self.setreg_path, enable_val)

    def _get_level_hex(self, sub_hex):
        sub_hex_str = sub_hex.replace("x", "0")
        return hex(int(sub_hex_str, 16))

    def _seconds_to_lmh_hex(self, seconds):
        ms = seconds * 1000  # calculate timeout in ms format
        hex_str = hex(ms)
        l = self._get_level_hex(hex_str[-2:])
        m = self._get_level_hex(hex_str[-4:-2])
        h = self._get_level_hex(hex_str[-6:-4])
        return (l, m, h)

    def _settimeout(self, seconds):
        """
        Set watchdog timer timeout
        @param seconds - timeout in seconds
        @return is the actual set timeout
        """
        # max = 0xffffff = 16777.215 seconds

        (l, m, h) = self._seconds_to_lmh_hex(seconds)
        set_h_val = '{} {}'.format(WDT_TIMER_H_BIT_REG, h)
        set_m_val = '{} {}'.format(WDT_TIMER_M_BIT_REG, m)
        set_l_val = '{} {}'.format(WDT_TIMER_L_BIT_REG, l)

        self._api_common.write_txt_file(self.setreg_path,
                                        set_h_val)  # set high bit
        self._api_common.write_txt_file(self.setreg_path,
                                        set_m_val)  # set med bit
        self._api_common.write_txt_file(self.setreg_path,
                                        set_l_val)  # set low bit

        return seconds

    def _gettimeout(self):
        """
        Get watchdog timeout
        @return watchdog timeout
        """

        h_bit = self._api_common.get_reg(self.getreg_path, WDT_TIMER_H_BIT_REG)
        m_bit = self._api_common.get_reg(self.getreg_path, WDT_TIMER_M_BIT_REG)
        l_bit = self._api_common.get_reg(self.getreg_path, WDT_TIMER_L_BIT_REG)

        hex_time = '0x{}{}{}'.format(h_bit[2:], m_bit[2:], l_bit[2:])
        ms = int(hex_time, 16)
        return int(float(ms) / 1000)

    #################################################################

    def arm(self, seconds):
        """
        Arm the hardware watchdog with a timeout of <seconds> seconds.
        If the watchdog is currently armed, calling this function will
        simply reset the timer to the provided value. If the underlying
        hardware does not support the value provided in <seconds>, this
        method should arm the watchdog with the *next greater* available
        value.
        Returns:
            An integer specifying the *actual* number of seconds the watchdog
            was armed with. On failure returns -1.
        """

        ret = WDT_COMMON_ERROR
        if seconds < 0:
            return ret

        try:
            if self.timeout != seconds:
                self.timeout = self._settimeout(seconds)

            if self.armed:
                self._keepalive()
            else:
                self._enable()
                self.armed = True

            ret = self.timeout
            self.arm_timestamp = time.time()
        except IOError as e:
            pass

        return ret

    def disarm(self):
        """
        Disarm the hardware watchdog
        Returns:
            A boolean, True if watchdog is disarmed successfully, False if not
        """
        disarmed = False
        if self.is_armed():
            try:
                self._disable()
                self.armed = False
                disarmed = True
            except IOError:
                pass

        return disarmed

    def is_armed(self):
        """
        Retrieves the armed state of the hardware watchdog.
        Returns:
            A boolean, True if watchdog is armed, False if not
        """

        return self.armed

    def get_remaining_time(self):
        """
        If the watchdog is armed, retrieve the number of seconds remaining on
        the watchdog timer
        Returns:
            An integer specifying the number of seconds remaining on thei
            watchdog timer. If the watchdog is not armed, returns -1.
        """

        return int(self.timeout -
                   (time.time() -
                    self.arm_timestamp)) if self.armed else WDT_COMMON_ERROR
예제 #6
0
class Chassis(ChassisBase):
    """
    Ruijie B6510-48VS8CQ Platform-specific Chassis class
    """
    def __init__(self):
        ChassisBase.__init__(self)
        self.CHASSIS_CONFIG = 'chassis.json'
        self.THERMAL_CONFIG = 'thermal.json'
        self.SFP_CONFIG = 'sfp.json'
        self.PSU_CONFIG = 'psu.json'
        self.FAN_CONFIG = 'fan.json'
        self.COMPONENT_CONFIG = 'component.json'

        self.SFP_STATUS_INSERTED = "1"
        self.SFP_STATUS_REMOVED = "0"
        self.port_dict = {}
        self.enable_read = "i2cset -f -y 2 0x35 0x2a 0x01"
        self.disable_read = "i2cset -f -y 2 0x35 0x2a 0x00"
        self.enable_write = "i2cset -f -y 2 0x35 0x2b 0x00"
        self.disable_write = "i2cset -f -y 2 0x35 0x2b 0x01"
        self.enable_erase = "i2cset -f -y 2 0x35 0x2c 0x01"
        self.disable_erase = "i2cset -f -y 2 0x35 0x2c 0x00"
        self.read_value = "i2cget -f -y 2 0x35 0x25"
        self.write_value = "i2cset -f -y 2 0x35 0x21 0x0a"
        self.set_sys_led_cmd = "i2cset -f -y 2 0x33 0xb2 "
        self.get_sys_led_cmd = "i2cget -f -y 2 0x33 0xb2"
        self.led_status = "red"
        # Initialize SFP list
        # sfp.py will read eeprom contents and retrive the eeprom data.
        # It will also provide support sfp controls like reset and setting
        # low power mode.
        # We pass the eeprom path and sfp control path from chassis.py
        # So that sfp.py implementation can be generic to all platforms
        for index in range(PORT_START, PORTS_IN_BLOCK):
            sfp_node = Sfp(index)
            self._sfp_list.append(sfp_node)
            if sfp_node.get_presence():
                self.port_dict[index] = self.SFP_STATUS_INSERTED
            else:
                self.port_dict[index] = self.SFP_STATUS_REMOVED

        self._api_common = Common()
        config_path = self._api_common.get_config_path(self.CHASSIS_CONFIG)
        self._config = self._api_common.load_json_file(config_path)
        self.__initialize_eeprom()

        if self._api_common.is_host():
            self.__initialize_fan()
            self.__initialize_psu()
            self.__initialize_thermals()
        else:
            self.__initialize_components()

    def __initialize_fan(self):
        from sonic_platform.fan import Fan
        from sonic_platform.fan_drawer import FanDrawer

        fan_config_path = self._api_common.get_config_path(self.FAN_CONFIG)
        self.fan_config = self._api_common.load_json_file(
            fan_config_path)["fans"]

        if self.fan_config:
            drawer_fan_list = []
            for index in range(0, len(self.fan_config)):
                fan = Fan(index, config=self.fan_config[index])
                self._fan_list.append(fan)
                drawer_fan_list.append(fan)
            fan_drawer = FanDrawer(0, fan_list=drawer_fan_list)
            self._fan_drawer_list.append(fan_drawer)

    def __initialize_psu(self):
        from sonic_platform.psu import Psu

        psu_config_path = self._api_common.get_config_path(self.PSU_CONFIG)
        self.psu_config = self._api_common.load_json_file(
            psu_config_path)["psus"]

        if self.psu_config:
            for index in range(0, len(self.psu_config)):
                psu = Psu(index, config=self.psu_config[index])
                self._psu_list.append(psu)

    def __initialize_thermals(self):
        from sonic_platform.thermal import Thermal

        thermal_config_path = self._api_common.get_config_path(
            self.THERMAL_CONFIG)
        self.thermal_config = self._api_common.load_json_file(
            thermal_config_path)['thermals']

        if self.thermal_config:
            for index in range(0, len(self.thermal_config)):
                thermal = Thermal(index, config=self.thermal_config[index])
                self._thermal_list.append(thermal)

    def __initialize_eeprom(self):
        from sonic_platform.eeprom import Eeprom
        self._eeprom = Eeprom(config=self._config["eeprom"])

    def __initialize_components(self):
        from sonic_platform.component import Component

        component_config_path = self._api_common.get_config_path(
            self.COMPONENT_CONFIG)
        self.component_config = self._api_common.load_json_file(
            component_config_path)['components']

        if self.component_config:
            for index in range(0, len(self.component_config)):
                component = Component(index,
                                      config=self.component_config[index])
                self._component_list.append(component)

    def _init_standard_config(self, conflist, class_name, objlist):
        for conf in conflist:
            obj = globals()[class_name](conf.get("name"), config=conf)
            objlist.append(obj)

    def _init_by_hal(self, hal_interface):
        self.hal_interface = hal_interface
        self.hal_interface.get_fans()

    def get_name(self):
        """
        Retrieves the name of the chassis
        Returns:
            string: The name of the chassis
        """
        return self._eeprom.modelstr()

    def get_presence(self):
        """
        Retrieves the presence of the chassis
        Returns:
            bool: True if chassis is present, False if not
        """
        return True

    def get_model(self):
        """
        Retrieves the model number (or part number) of the chassis
        Returns:
            string: Model/part number of chassis
        """
        return self._eeprom.part_number_str()

    def get_serial(self):
        """
        Retrieves the serial number of the chassis (Service tag)
        Returns:
            string: Serial number of chassis
        """
        return self._eeprom.serial_str()

    def get_status(self):
        """
        Retrieves the operational status of the chassis
        Returns:
            bool: A boolean value, True if chassis is operating properly
            False if not
        """
        return True

    def get_base_mac(self):
        """
        Retrieves the base MAC address for the chassis

        Returns:
            A string containing the MAC address in the format
            'XX:XX:XX:XX:XX:XX'
        """
        return self._eeprom.base_mac_addr()

    def get_system_eeprom_info(self):
        """
        Retrieves the full content of system EEPROM information for the chassis
        Returns:
            A dictionary where keys are the type code defined in
            OCP ONIE TlvInfo EEPROM format and values are their corresponding
            values.
        """
        return self._eeprom.system_eeprom_info()

    def get_reboot_cause(self):
        """
        Retrieves the cause of the previous reboot
        Returns:
            A tuple (string, string) where the first element is a string
            containing the cause of the previous reboot. This string must be
            one of the predefined strings in this class. If the first string
            is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used
            to pass a description of the reboot cause.
        """
        try:
            is_power_loss = False
            # enable read
            subprocess.getstatusoutput(self.disable_write)
            subprocess.getstatusoutput(self.enable_read)
            ret, log = subprocess.getstatusoutput(self.read_value)
            if ret == 0 and "0x0a" in log:
                is_power_loss = True

            # erase i2c and e2
            subprocess.getstatusoutput(self.enable_erase)
            time.sleep(1)
            subprocess.getstatusoutput(self.disable_erase)
            # clear data
            subprocess.getstatusoutput(self.enable_write)
            subprocess.getstatusoutput(self.disable_read)
            subprocess.getstatusoutput(self.disable_write)
            subprocess.getstatusoutput(self.enable_read)
            # enable write and set data
            subprocess.getstatusoutput(self.enable_write)
            subprocess.getstatusoutput(self.disable_read)
            subprocess.getstatusoutput(self.write_value)
            if is_power_loss:
                return (self.REBOOT_CAUSE_POWER_LOSS, None)
        except Exception as e:
            logger.error(str(e))

        return (self.REBOOT_CAUSE_NON_HARDWARE, None)

    def get_change_event(self, timeout=0):
        """
        Returns a nested dictionary containing all devices which have
        experienced a change at chassis level

        Args:
            timeout: Timeout in milliseconds (optional). If timeout == 0,
                this method will block until a change is detected.

        Returns:
            (bool, dict):
                - True if call successful, False if not;
                - A nested dictionary where key is a device type,
                  value is a dictionary with key:value pairs in the format of
                  {'device_id':'device_event'},
                  where device_id is the device ID for this device and
                        device_event,
                             status='1' represents device inserted,
                             status='0' represents device removed.
                  Ex. {'fan':{'0':'0', '2':'1'}, 'sfp':{'11':'0'}}
                      indicates that fan 0 has been removed, fan 2
                      has been inserted and sfp 11 has been removed.
                  Specifically for SFP event, besides SFP plug in and plug out,
                  there are some other error event could be raised from SFP, when
                  these error happened, SFP eeprom will not be avalaible, XCVRD shall
                  stop to read eeprom before SFP recovered from error status.
                      status='2' I2C bus stuck,
                      status='3' Bad eeprom,
                      status='4' Unsupported cable,
                      status='5' High Temperature,
                      status='6' Bad cable.
        """
        change_event_dict = {"fan": {}, "sfp": {}}
        sfp_status, sfp_change_dict = self.get_transceiver_change_event(
            timeout)
        change_event_dict["sfp"] = sfp_change_dict
        if sfp_status is True:
            return True, change_event_dict

        return False, {}

    def get_transceiver_change_event(self, timeout=0):

        start_time = time.time()
        currernt_port_dict = {}
        forever = False

        if timeout == 0:
            forever = True
        elif timeout > 0:
            timeout = timeout / float(1000)  # Convert to secs
        else:
            print("get_transceiver_change_event:Invalid timeout value",
                  timeout)
            return False, {}

        end_time = start_time + timeout
        if start_time > end_time:
            print(
                "get_transceiver_change_event:"
                "time wrap / invalid timeout value",
                timeout,
            )
            return False, {}  # Time wrap or possibly incorrect timeout

        while timeout >= 0:
            # Check for OIR events and return updated port_dict
            for index in range(PORT_START, PORTS_IN_BLOCK):
                if self._sfp_list[index].get_presence():
                    currernt_port_dict[index] = self.SFP_STATUS_INSERTED
                else:
                    currernt_port_dict[index] = self.SFP_STATUS_REMOVED
            if currernt_port_dict == self.port_dict:
                if forever:
                    time.sleep(1)
                else:
                    timeout = end_time - time.time()
                    if timeout >= 1:
                        time.sleep(1)  # We poll at 1 second granularity
                    else:
                        if timeout > 0:
                            time.sleep(timeout)
                        return True, {}
            else:
                # Update reg value
                self.port_dict = currernt_port_dict
                print(self.port_dict)
                return True, self.port_dict
        print("get_transceiver_change_event: Should not reach here.")
        return False, {}

    def get_all_components(self):
        return self._component_list

    def get_all_fans(self):
        return self._fan_list

    def get_all_psus(self):
        return self._psu_list

    def get_all_thermals(self):
        return self._thermal_list

    def get_supervisor_slot(self):
        """
        Retrieves the physical-slot of the supervisor-module in the modular
        chassis. On the supervisor or line-card modules, it will return the
        physical-slot of the supervisor-module.
        On the fixed-platforms, the API can be ignored.
        Users of the API can catch the exception and return a default
        ModuleBase.MODULE_INVALID_SLOT and bypass code for fixed-platforms.
        Returns:
            An integer, the vendor specific physical slot identifier of the
            supervisor module in the modular-chassis.
        """
        return 0

    def get_my_slot(self):
        """
        Retrieves the physical-slot of this module in the modular chassis.
        On the supervisor, it will return the physical-slot of the supervisor
        module. On the linecard, it will return the physical-slot of the
        linecard module where this instance of SONiC is running.
        On the fixed-platforms, the API can be ignored.
        Users of the API can catch the exception and return a default
        ModuleBase.MODULE_INVALID_SLOT and bypass code for fixed-platforms.
        Returns:
            An integer, the vendor specific physical slot identifier of this
            module in the modular-chassis.
        """
        return 0

    def is_modular_chassis(self):
        """
        Retrieves whether the sonic instance is part of modular chassis
        Returns:
            A bool value, should return False by default or for fixed-platforms.
            Should return True for supervisor-cards, line-cards etc running as part
            of modular-chassis.
        """
        return True

    def init_midplane_switch(self):
        """
        Initializes the midplane functionality of the modular chassis. For
        example, any validation of midplane, populating any lookup tables etc
        can be done here. The expectation is that the required kernel modules,
        ip-address assignment etc are done before the pmon, database dockers
        are up.
        Returns:
            A bool value, should return True if the midplane initialized
            successfully.
        """
        return True

    def get_module_index(self, module_name):
        """
        Retrieves module index from the module name
        Args:
            module_name: A string, prefixed by SUPERVISOR, LINE-CARD or FABRIC-CARD
            Ex. SUPERVISOR0, LINE-CARD1, FABRIC-CARD5
        Returns:
            An integer, the index of the ModuleBase object in the module_list
        """
        return 0

    def set_status_led(self, color):
        """
        Sets the state of the system LED
        Args:
            color: A string representing the color with which to set the
                   system LED
        Returns:
            bool: True if system LED state is set successfully, False if not
        """
        colors = {"amber": "0x00", "red": "0x02", "green": "0x04"}
        regval = colors.get(color, None)
        if regval is None:
            print("Invaild color input.")
            return False
        ret, log = subprocess.getstatusoutput(self.set_sys_led_cmd + regval)
        if ret != 0:
            print("Cannot execute %s" % self.set_sys_led_cmd + regval)
            return False
        self.led_status = color
        return True

    def get_status_led(self):
        """
        Gets the state of the system LED
        Returns:
            A string, one of the valid LED color strings which could be vendor
            specified.
        """
        ret, log = subprocess.getstatusoutput(self.get_sys_led_cmd)
        if ret != 0:
            print("Cannot execute %s" % self.get_sys_led_cmd)
            return False
        colors = {"0x00": "amber", "0x02": "red", "0x04": "green"}
        color = colors.get(log, None)
        if color is None:
            return "Unknown color status"
        self.led_status = color
        return self.led_status