<commit_before># Copyright (c) 2014  Kontron Europe GmbH
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

import os
import codecs
import array
import struct
import collections
import hashlib
import time

from pyipmi.errors import DecodingError, CompletionCodeError, HpmError, TimeoutError
from pyipmi.msgs import create_request_by_name
from pyipmi.msgs import constants
from pyipmi.utils import check_completion_code, bcd_search, chunks


PROPERTY_GENERAL_PROPERTIES = 0
PROPERTY_CURRENT_VERSION = 1
PROPERTY_DESCRIPTION_STRING = 2
PROPERTY_ROLLBACK_VERSION = 3
PROPERTY_DEFERRED_VERSION = 4
PROPERTY_OEM = range(192, 255)

ACTION_BACKUP_COMPONENT = 0x00
ACTION_PREPARE_COMPONENT = 0x01
ACTION_UPLOAD_FOR_UPGRADE = 0x02
ACTION_UPLOAD_FOR_COMPARE = 0x03

LONG_DURATION_CMD_IN_PROGRESS_CC = 0x80

CC_GET_COMP_PROP_UPGRADE_NOT_SUPPORTED_OVER_INTF = 0x81
CC_GET_COMP_PROP_INVALID_COMPONENT = 0x82
CC_GET_COMP_PROP_INVALID_PROPERTIES_SELECTOR = 0x83

CC_INITIATE_UPGRADE_CMD_IN_PROGRESS = 0x80
CC_INITIATE_UPGRADE_INVALID_COMPONENT = 0x81

CC_QUERY_SELFTEST_COMPLETED = 0x00
CC_QUERY_SELFTEST_IN_PROGRESS = 0x80
CC_QUERY_SELFTEST_UPGRADE_NOT_SUPPORTED_OVER_INTF = 0x81
CC_QUERY_SELFTEST_NO_RESULTS_AVAILABLE = 0xD5

CC_ABORT_UPGRADE_CANNOT_ABORT = 0x80
CC_ABORT_UPGRADE_CANNOT_RESUME_OPERATION = 0x81

class Hpm:

    def _check_completion_code(self, rsp):
        check_completion_code(rsp.completion_code)

    def _get_component_count(self, components):
        """Return the number of components"""
        return bin(components).count('1')

    def get_target_upgrade_capabilities(self):
        req = create_request_by_name('GetTargetUpgradeCapabilities')
        rsp = self.send_message(req)
        self._check_completion_code(rsp)
        return TargetUpgradeCapabilities(rsp)

    def get_component_property(self, component_id, property_id):
        req = create_request_by_name('GetComponentProperties')
        req.id = component_id
        req.selector = property_id
        rsp = self.send_message(req)
        self._check_completion_code(rsp)
        return ComponentProperty.create_from_id(property_id, rsp)

    def get_component_properties(self, component_id):
        properties = []
        for p in (PROPERTY_GENERAL_PROPERTIES, PROPERTY_CURRENT_VERSION,
                PROPERTY_DESCRIPTION_STRING, PROPERTY_ROLLBACK_VERSION,
                PROPERTY_DEFERRED_VERSION):
            property = self.get_component_property(component_id, p)
            if property is not None:
                properties.append(property)
        return properties

    def find_component_id_by_descriptor(self, descriptor):
        caps = self.get_target_upgrade_capabilities()
        for component_id in caps.components:
            property = self.get_component_property(component_id, PROPERTY_DESCRIPTION_STRING)
            if property is not None:
                if property.description == descriptor:
                    return component_id
        return None

    def abort_firmware_upgrade(self):
        req = create_request_by_name('AbortFirmwareUpgrade')
        rsp = self.send_message(req)
        self._check_completion_code(rsp)

    def initiate_upgrade_action(self, components_mask, action):
        """ Initiate Upgrade Action
        components:
        action:
            ACTION_BACKUP_COMPONENT = 0x00
            ACTION_PREPARE_COMPONENT = 0x01
            ACTION_UPLOAD_FOR_UPGRADE = 0x02
            ACTION_UPLOAD_FOR_COMPARE = 0x03
        """

        if action in (ACTION_UPLOAD_FOR_UPGRADE, ACTION_UPLOAD_FOR_COMPARE):
            if self._get_component_count(components_mask) != 1:
                raise HpmError("more than 1 component not support for action")

        req = create_request_by_name('InitiateUpgradeAction')
        req.components = components_mask
        req.action = action

        rsp = self.send_message(req)
        check_completion_code(rsp.completion_code)

    def initiate_upgrade_action_and_wait(self, components_mask, action,
            timeout=2, interval=0.1):
        """ Initiate Upgrade Action and wait for
            long running command. """
        try:
            self.initiate_upgrade_action(components_mask, action)
        except CompletionCodeError, e:
            if e.cc == LONG_DURATION_CMD_IN_PROGRESS_CC:
                self.wait_for_long_duration_command(
                        constants.CMDID_HPM_INITIATE_UPGRADE_ACTION,
                        timeout, interval)
            else:
                raise HpmError('initiate_upgrade_action CC=0x%02x' % e.cc)

    def upload_firmware_block(self, block_number, data):
        req = create_request_by_name('UploadFirmwareBlock')
        req.number = block_number
        req.data = data
        rsp = self.send_message(req)
        check_completion_code(rsp.completion_code)

    def _determine_max_block_size(self):
        #tbd
        return 22

    def upload_binary(self, binary, timeout=2, interval=0.1):
        """ Upload all firmware blocks from binary and wait for
            long running command. """
        block_number = 0
        block_size = self._determine_max_block_size()

        for chunk in chunks(binary, block_size):
            try:
                self.upload_firmware_block(block_number, chunk)
            except CompletionCodeError, e:
                if e.cc == LONG_DURATION_CMD_IN_PROGRESS_CC:
                    self.wait_for_long_duration_command(
                            constants.CMDID_HPM_UPLOAD_FIRMWARE_BLOCK,
                            timeout, interval)
                else:
                    raise HpmError('upload_firmware_block CC=0x%02x' % e.cc)
            block_number += 1
            block_number &= 0xff

    def finish_firmware_upload(self, component, length):
        req = create_request_by_name('FinishFirmwareUpload')
        req.component_id = component
        req.image_length = length
        rsp = self.send_message(req)
        check_completion_code(rsp.completion_code)

    def finish_upload_and_wait(self, component, length,
            timeout=2, interval=0.1):
        """ Finish the firmware upload process and wait for
            long running command. """
        try:
            rsp = self.finish_firmware_upload(component, length)
            check_completion_code(rsp.completion_code)
        except CompletionCodeError, e:
            if e.cc == LONG_DURATION_CMD_IN_PROGRESS_CC:
                self.wait_for_long_duration_command(
                            constants.CMDID_HPM_FINISH_FIRMWARE_UPLOAD,
                            timeout, interval)
            else:
                raise HpmError('finish_firmware_upload CC=0x%02x' % e.cc)

    def get_upgrade_status(self):
        req = create_request_by_name('GetUpgradeStatus')
        rsp = self.send_message(req)
        self._check_completion_code(rsp)
        return UpgradeStatus(rsp)

    def wait_for_long_duration_command(self, expected_cmd,
            timeout=5, interval=1):

        start_time = time.time()
        while time.time() < start_time + timeout:
            try:
                status = self.get_upgrade_status()
                if status.command_in_progress is not expected_cmd \
                        and status.command_in_progress is not 0x34:
                    #raise HpmError('unexpected cmd=0x%02x' \
                    #        % status.command_in_progress)
                    pass
                if status.last_completion_code == LONG_DURATION_CMD_IN_PROGRESS_CC:
                    time.sleep(interval)
                else:
                    return
            except TimeoutError:
                time.sleep(interval)


    def activate_firmware(self, rollback_override=None):
        req = create_request_by_name('ActivateFirmware')
        if rollback_override != None:
            req.rollback_override_policy = rollback_override
        rsp = self.send_message(req)
        self._check_completion_code(rsp)

    def activate_firmware_and_wait(self, rollback_override=None,
            timeout=2, interval=1):
        """ Activate the new uploaded firmware and wait for
            long running command. """
        try:
            self.activate_firmware(rollback_override)
        except CompletionCodeError, e:
            if e.cc == LONG_DURATION_CMD_IN_PROGRESS_CC:
                self.wait_for_long_duration_command(
                            constants.CMDID_HPM_ACTIVATE_FIRMWARE,
                            timeout, interval)
            else:
                raise HpmError('activate_firmware CC=0x%02x' % e.cc)
        except TimeoutError:
            # controller is in reset and flashed new firmware
            pass

    def query_selftest_results(self):
        req = create_request_by_name('QuerySelftestResults')
        rsp = self.send_message(req)
        self._check_completion_code(rsp)
        return SelfTestResult(rsp.data)

    def query_rollback_status(self):
        req = create_request_by_name('QueryRollbackStatus')
        rsp = self.send_message(req)
        self._check_completion_code(rsp)
        return RollbackStatus(rsp)

    def initiate_manual_rollback(self):
        req = create_request_by_name('InitiateManualRollback')
        rsp = self.send_message(req)
        self._check_completion_code(rsp)
        return RollbackStatus(rsp)

    def initiate_maunal_rollback_and_wait(self, timeout=2, interval=0.1):
        try:
            self.initiate_manual_rollback()
        except CompletionCodeError, e:
            if e.cc == LONG_DURATION_CMD_IN_PROGRESS_CC:
                self.wait_for_long_duration_command(
                            constants.CMDID_HPM_INITIATE_MANUAL_ROLLBACK,
                            60, interval)
            else:
                raise HpmError('activate_firmware CC=0x%02x' % e.cc)
        except TimeoutError:
            # controller is in reset and flashed new firmware
            pass

    def open_upgrade_image(self, filename):
        image = UpgradeImage(filename)
        return image

    def get_upgrade_version_from_file(self, filename):
        image = UpgradeImage(filename)
        for action in image.actions:
            if action.type == ACTION_UPLOAD_FOR_UPGRADE:
                return action.firmware_version
        return None

    def _do_upgrade_action_backup(self, image):
        for action in image.actions:
            if action.type == ACTION_BACKUP_COMPONENT:
                pass

    def _do_upgrade_action_prepare(self, image):
        for action in image.actions:
            if action.type == ACTION_PREPARE_COMPONENT:
                print "do ACTION_PREPARE_COMPONENT"

    def _do_upgrade_action_upload(self, image):
        for action in image.actions:
            if action.type == ACTION_UPLOAD_FOR_UPGRADE:
                print "do ACTION_UPLOAD_FOR_UPGRADE"


    def preparation_stage(self, image):
        ####################################################
        # match device ID, manfuacturer ID, etc.
        device_id = self.get_device_id()

        header = image.header

        if header.device_id != device_id.id:
            raise HpmError('Device ID: image=0x%x device=0x%x' \
                    % (header.device_id, device_id.id))
        if header.manufacturer_id != device_id.manufacturer_id:
            raise HpmError('Manufacturer ID: image=0x%x device=0x%x' \
                    % (header.manufacturer_id, device_id.manufacturer_id))
        if header.product_id != device_id.product_id:
            raise HpmError('Product ID: image=0x%x device=0x%x' \
                    % (header.product_id, device_id.product_id))

        # tbd check version

        ####################################################
        # compare current revision with upgrade image earlist comp rev
        targetCap = self.get_target_upgrade_capabilities()
        # tbd check version

        ####################################################
        # Match IPM Controller capabilities with Upgrade Image capabilities
        for imageComponent in header.components:
            if imageComponent in targetCap.components:
                support = True

        if support != True:
            raise HpmError('no supported component in image')

    def upgrade_stage(self, image, component):
        for action in image.actions:
            if action.components & (1 << component) == 0:
                continue
            self.initiate_upgrade_action_and_wait(1 << component, action.type)
            if action.type == ACTION_UPLOAD_FOR_UPGRADE:
                self.upload_binary(action.firmware_image_data)
                self.finish_upload_and_wait(component, action.firmware_length)

    def _activation_state_do_self_testing(self):
        pass

    def wait_until_new_firmware_comes_up(self, timeout, interval):
        self.wait_until_ipmb_is_accessible(timeout, interval)

    def activation_stage(self, image, component):
        self.activate_firmware_and_wait(image.header.inaccessibility_timeout, 1)
        self.wait_until_new_firmware_comes_up(image.header.inaccessibility_timeout, 1)
        self._activation_state_do_self_testing()

    def install_component_from_image(self, image, component):
        self.abort_firmware_upgrade()
        if component not in image.header.components:
            raise HpmError('component=%d not in image' % component)
        self.preparation_stage(image)
        self.upgrade_stage(image, component)
        self.activation_stage(image, component)

    def install_component_from_file(self, filename, component):
        image = UpgradeImage(filename)
        self.install_component_from_image(image, component)
<commit_msg>hpm: fix in wait until new firmware comes up<commit_after># Copyright (c) 2014  Kontron Europe GmbH
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

import os
import codecs
import array
import struct
import collections
import hashlib
import time

from pyipmi.errors import DecodingError, CompletionCodeError, HpmError, TimeoutError
from pyipmi.msgs import create_request_by_name
from pyipmi.msgs import constants
from pyipmi.utils import check_completion_code, bcd_search, chunks


PROPERTY_GENERAL_PROPERTIES = 0
PROPERTY_CURRENT_VERSION = 1
PROPERTY_DESCRIPTION_STRING = 2
PROPERTY_ROLLBACK_VERSION = 3
PROPERTY_DEFERRED_VERSION = 4
PROPERTY_OEM = range(192, 255)

ACTION_BACKUP_COMPONENT = 0x00
ACTION_PREPARE_COMPONENT = 0x01
ACTION_UPLOAD_FOR_UPGRADE = 0x02
ACTION_UPLOAD_FOR_COMPARE = 0x03

LONG_DURATION_CMD_IN_PROGRESS_CC = 0x80

CC_GET_COMP_PROP_UPGRADE_NOT_SUPPORTED_OVER_INTF = 0x81
CC_GET_COMP_PROP_INVALID_COMPONENT = 0x82
CC_GET_COMP_PROP_INVALID_PROPERTIES_SELECTOR = 0x83

CC_INITIATE_UPGRADE_CMD_IN_PROGRESS = 0x80
CC_INITIATE_UPGRADE_INVALID_COMPONENT = 0x81

CC_QUERY_SELFTEST_COMPLETED = 0x00
CC_QUERY_SELFTEST_IN_PROGRESS = 0x80
CC_QUERY_SELFTEST_UPGRADE_NOT_SUPPORTED_OVER_INTF = 0x81
CC_QUERY_SELFTEST_NO_RESULTS_AVAILABLE = 0xD5

CC_ABORT_UPGRADE_CANNOT_ABORT = 0x80
CC_ABORT_UPGRADE_CANNOT_RESUME_OPERATION = 0x81

class Hpm:

    def _check_completion_code(self, rsp):
        check_completion_code(rsp.completion_code)

    def _get_component_count(self, components):
        """Return the number of components"""
        return bin(components).count('1')

    def get_target_upgrade_capabilities(self):
        req = create_request_by_name('GetTargetUpgradeCapabilities')
        rsp = self.send_message(req)
        self._check_completion_code(rsp)
        return TargetUpgradeCapabilities(rsp)

    def get_component_property(self, component_id, property_id):
        req = create_request_by_name('GetComponentProperties')
        req.id = component_id
        req.selector = property_id
        rsp = self.send_message(req)
        self._check_completion_code(rsp)
        return ComponentProperty.create_from_id(property_id, rsp)

    def get_component_properties(self, component_id):
        properties = []
        for p in (PROPERTY_GENERAL_PROPERTIES, PROPERTY_CURRENT_VERSION,
                PROPERTY_DESCRIPTION_STRING, PROPERTY_ROLLBACK_VERSION,
                PROPERTY_DEFERRED_VERSION):
            property = self.get_component_property(component_id, p)
            if property is not None:
                properties.append(property)
        return properties

    def find_component_id_by_descriptor(self, descriptor):
        caps = self.get_target_upgrade_capabilities()
        for component_id in caps.components:
            property = self.get_component_property(component_id, PROPERTY_DESCRIPTION_STRING)
            if property is not None:
                if property.description == descriptor:
                    return component_id
        return None

    def abort_firmware_upgrade(self):
        req = create_request_by_name('AbortFirmwareUpgrade')
        rsp = self.send_message(req)
        self._check_completion_code(rsp)

    def initiate_upgrade_action(self, components_mask, action):
        """ Initiate Upgrade Action
        components:
        action:
            ACTION_BACKUP_COMPONENT = 0x00
            ACTION_PREPARE_COMPONENT = 0x01
            ACTION_UPLOAD_FOR_UPGRADE = 0x02
            ACTION_UPLOAD_FOR_COMPARE = 0x03
        """

        if action in (ACTION_UPLOAD_FOR_UPGRADE, ACTION_UPLOAD_FOR_COMPARE):
            if self._get_component_count(components_mask) != 1:
                raise HpmError("more than 1 component not support for action")

        req = create_request_by_name('InitiateUpgradeAction')
        req.components = components_mask
        req.action = action

        rsp = self.send_message(req)
        check_completion_code(rsp.completion_code)

    def initiate_upgrade_action_and_wait(self, components_mask, action,
            timeout=2, interval=0.1):
        """ Initiate Upgrade Action and wait for
            long running command. """
        try:
            self.initiate_upgrade_action(components_mask, action)
        except CompletionCodeError, e:
            if e.cc == LONG_DURATION_CMD_IN_PROGRESS_CC:
                self.wait_for_long_duration_command(
                        constants.CMDID_HPM_INITIATE_UPGRADE_ACTION,
                        timeout, interval)
            else:
                raise HpmError('initiate_upgrade_action CC=0x%02x' % e.cc)

    def upload_firmware_block(self, block_number, data):
        req = create_request_by_name('UploadFirmwareBlock')
        req.number = block_number
        req.data = data
        rsp = self.send_message(req)
        check_completion_code(rsp.completion_code)

    def _determine_max_block_size(self):
        #tbd
        return 22

    def upload_binary(self, binary, timeout=2, interval=0.1):
        """ Upload all firmware blocks from binary and wait for
            long running command. """
        block_number = 0
        block_size = self._determine_max_block_size()

        for chunk in chunks(binary, block_size):
            try:
                self.upload_firmware_block(block_number, chunk)
            except CompletionCodeError, e:
                if e.cc == LONG_DURATION_CMD_IN_PROGRESS_CC:
                    self.wait_for_long_duration_command(
                            constants.CMDID_HPM_UPLOAD_FIRMWARE_BLOCK,
                            timeout, interval)
                else:
                    raise HpmError('upload_firmware_block CC=0x%02x' % e.cc)
            block_number += 1
            block_number &= 0xff

    def finish_firmware_upload(self, component, length):
        req = create_request_by_name('FinishFirmwareUpload')
        req.component_id = component
        req.image_length = length
        rsp = self.send_message(req)
        check_completion_code(rsp.completion_code)

    def finish_upload_and_wait(self, component, length,
            timeout=2, interval=0.1):
        """ Finish the firmware upload process and wait for
            long running command. """
        try:
            rsp = self.finish_firmware_upload(component, length)
            check_completion_code(rsp.completion_code)
        except CompletionCodeError, e:
            if e.cc == LONG_DURATION_CMD_IN_PROGRESS_CC:
                self.wait_for_long_duration_command(
                            constants.CMDID_HPM_FINISH_FIRMWARE_UPLOAD,
                            timeout, interval)
            else:
                raise HpmError('finish_firmware_upload CC=0x%02x' % e.cc)

    def get_upgrade_status(self):
        req = create_request_by_name('GetUpgradeStatus')
        rsp = self.send_message(req)
        self._check_completion_code(rsp)
        return UpgradeStatus(rsp)

    def wait_for_long_duration_command(self, expected_cmd,
            timeout=5, interval=1):

        start_time = time.time()
        while time.time() < start_time + timeout:
            try:
                status = self.get_upgrade_status()
                if status.command_in_progress is not expected_cmd \
                        and status.command_in_progress is not 0x34:
                    #raise HpmError('unexpected cmd=0x%02x' \
                    #        % status.command_in_progress)
                    pass
                if status.last_completion_code == LONG_DURATION_CMD_IN_PROGRESS_CC:
                    time.sleep(interval)
                else:
                    return
            except TimeoutError:
                time.sleep(interval)


    def activate_firmware(self, rollback_override=None):
        req = create_request_by_name('ActivateFirmware')
        if rollback_override != None:
            req.rollback_override_policy = rollback_override
        rsp = self.send_message(req)
        self._check_completion_code(rsp)

    def activate_firmware_and_wait(self, rollback_override=None,
            timeout=2, interval=1):
        """ Activate the new uploaded firmware and wait for
            long running command. """
        try:
            self.activate_firmware(rollback_override)
        except CompletionCodeError, e:
            if e.cc == LONG_DURATION_CMD_IN_PROGRESS_CC:
                self.wait_for_long_duration_command(
                            constants.CMDID_HPM_ACTIVATE_FIRMWARE,
                            timeout, interval)
            else:
                raise HpmError('activate_firmware CC=0x%02x' % e.cc)
        except TimeoutError:
            # controller is in reset and flashed new firmware
            pass

    def query_selftest_results(self):
        req = create_request_by_name('QuerySelftestResults')
        rsp = self.send_message(req)
        self._check_completion_code(rsp)
        return SelfTestResult(rsp.data)

    def query_rollback_status(self):
        req = create_request_by_name('QueryRollbackStatus')
        rsp = self.send_message(req)
        self._check_completion_code(rsp)
        return RollbackStatus(rsp)

    def initiate_manual_rollback(self):
        req = create_request_by_name('InitiateManualRollback')
        rsp = self.send_message(req)
        self._check_completion_code(rsp)
        return RollbackStatus(rsp)

    def initiate_maunal_rollback_and_wait(self, timeout=2, interval=0.1):
        try:
            self.initiate_manual_rollback()
        except CompletionCodeError, e:
            if e.cc == LONG_DURATION_CMD_IN_PROGRESS_CC:
                self.wait_for_long_duration_command(
                            constants.CMDID_HPM_INITIATE_MANUAL_ROLLBACK,
                            60, interval)
            else:
                raise HpmError('activate_firmware CC=0x%02x' % e.cc)
        except TimeoutError:
            # controller is in reset and flashed new firmware
            pass

    def open_upgrade_image(self, filename):
        image = UpgradeImage(filename)
        return image

    def get_upgrade_version_from_file(self, filename):
        image = UpgradeImage(filename)
        for action in image.actions:
            if action.type == ACTION_UPLOAD_FOR_UPGRADE:
                return action.firmware_version
        return None

    def _do_upgrade_action_backup(self, image):
        for action in image.actions:
            if action.type == ACTION_BACKUP_COMPONENT:
                pass

    def _do_upgrade_action_prepare(self, image):
        for action in image.actions:
            if action.type == ACTION_PREPARE_COMPONENT:
                print "do ACTION_PREPARE_COMPONENT"

    def _do_upgrade_action_upload(self, image):
        for action in image.actions:
            if action.type == ACTION_UPLOAD_FOR_UPGRADE:
                print "do ACTION_UPLOAD_FOR_UPGRADE"


    def preparation_stage(self, image):
        ####################################################
        # match device ID, manfuacturer ID, etc.
        device_id = self.get_device_id()

        header = image.header

        if header.device_id != device_id.id:
            raise HpmError('Device ID: image=0x%x device=0x%x' \
                    % (header.device_id, device_id.id))
        if header.manufacturer_id != device_id.manufacturer_id:
            raise HpmError('Manufacturer ID: image=0x%x device=0x%x' \
                    % (header.manufacturer_id, device_id.manufacturer_id))
        if header.product_id != device_id.product_id:
            raise HpmError('Product ID: image=0x%x device=0x%x' \
                    % (header.product_id, device_id.product_id))

        # tbd check version

        ####################################################
        # compare current revision with upgrade image earlist comp rev
        targetCap = self.get_target_upgrade_capabilities()
        # tbd check version

        ####################################################
        # Match IPM Controller capabilities with Upgrade Image capabilities
        for imageComponent in header.components:
            if imageComponent in targetCap.components:
                support = True

        if support != True:
            raise HpmError('no supported component in image')

    def upgrade_stage(self, image, component):
        for action in image.actions:
            if action.components & (1 << component) == 0:
                continue
            self.initiate_upgrade_action_and_wait(1 << component, action.type)
            if action.type == ACTION_UPLOAD_FOR_UPGRADE:
                self.upload_binary(action.firmware_image_data)
                self.finish_upload_and_wait(component, action.firmware_length)

    def _activation_state_do_self_testing(self):
        pass

    def wait_until_new_firmware_comes_up(self, timeout, interval):
        start_time = time.time()
        while time.time() < start_time + timeout:
            try:
                status = self.get_upgrade_status()
                self.get_device_id()
            except TimeoutError:
                time.sleep(interval)
        time.sleep(5)

    def activation_stage(self, image, component):
        self.activate_firmware_and_wait(image.header.inaccessibility_timeout, 1)
        self.wait_until_new_firmware_comes_up(image.header.inaccessibility_timeout, 1)
        self._activation_state_do_self_testing()

    def install_component_from_image(self, image, component):
        self.abort_firmware_upgrade()
        if component not in image.header.components:
            raise HpmError('component=%d not in image' % component)
        self.preparation_stage(image)
        self.upgrade_stage(image, component)
        self.activation_stage(image, component)

    def install_component_from_file(self, filename, component):
        image = UpgradeImage(filename)
        self.install_component_from_image(image, component)

{'fraction_non_alphanumeric': 0.07508390713124113, 'fraction_numerical': 0.010068855748936022, 'mean_word_length': 2.590310559006211, 'pattern_counts': {'":': 0, '<': 14, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1012401', 'n_tokens_mistral': 8687, 'n_tokens_neox': 8232, 'n_words': 1760}