3 .. module:: hailo_control_protocol
4 :synopsis: Implements a Hailo Control Protocol message.
7 from builtins import object
8 from enum import Enum, IntEnum
12 # Supported protocol and Firmware version of current SDK.
13 SUPPORTED_PROTOCOL_VERSION = 2
14 SUPPORTED_FW_MAJOR = 4
15 SUPPORTED_FW_MINOR = 6
16 SUPPORTED_FW_REVISION = 0
18 MEGA_MULTIPLIER = 1000.0 * 1000.0
21 class HailoControlProtocolException(Exception):
25 class DeviceArchitectureTypes(IntEnum):
33 class BoardInformation(object):
34 def __init__(self, protocol_version, fw_version_major, fw_version_minor, fw_version_revision,
35 logger_version, board_name, is_release, device_architecture, serial_number, part_number, product_name):
36 self.protocol_version = protocol_version
37 self.firmware_version = HailoFirmwareVersion.construct_from_params(fw_version_major, fw_version_minor, fw_version_revision, is_release, HailoFirmwareType.APP)
38 self.logger_version = logger_version
39 self.board_name = board_name
40 self.is_release = is_release
41 self.device_architecture = DeviceArchitectureTypes(device_architecture)
42 self.serial_number = serial_number
43 self.part_number = part_number
44 self.product_name = product_name
46 def _string_field_str(self, string_field):
47 # Return <Not Configured> if the string field is empty
48 return string_field.rstrip('\x00') or "<Not Configured>"
52 str: Human readable string.
54 return 'Control Protocol Version: {}\n' \
55 'Firmware Version: {}\n' \
56 'Logger Version: {}\n' \
58 'Device Architecture: {}\n' \
59 'Serial Number: {}\n' \
61 'Product Name: {}\n'.format(
62 self.protocol_version,
63 self.firmware_version,
65 self.board_name.rstrip('\x00'),
66 str(self.device_architecture),
67 self._string_field_str(self.serial_number),
68 self._string_field_str(self.part_number),
69 self._string_field_str(self.product_name))
73 str: Human readable string.
78 def get_hw_arch_str(device_arch):
79 if device_arch == DeviceArchitectureTypes.HAILO8_B0:
81 elif device_arch == DeviceArchitectureTypes.MERCURY_CA:
84 raise HailoControlProtocolException("Unsupported device architecture.")
86 class CoreInformation(object):
87 def __init__(self, fw_version_major, fw_version_minor, fw_version_revision, is_release):
88 self.firmware_version = HailoFirmwareVersion.construct_from_params(fw_version_major, fw_version_minor, fw_version_revision, is_release, HailoFirmwareType.CORE)
89 self.is_release = is_release
93 str: Human readable string.
95 return 'Core Firmware Version: {}'.format(
96 self.firmware_version)
100 str: Human readable string.
102 return self.__str__()
104 class TemperatureThrottlingLevel(object):
105 def __init__(self, level_number, temperature_threshold, hysteresis_temperature_threshold, throttling_nn_clock_freq):
106 self.level_number = level_number
107 self.temperature_threshold = temperature_threshold
108 self.hysteresis_temperature_threshold = hysteresis_temperature_threshold
109 self.throttling_nn_clock_freq = throttling_nn_clock_freq
113 str: Human readable string.
115 return 'Temperature Throttling Level {}: \n' \
116 'Temperature Threshold: {}\n' \
117 'Hysteresis Temperature Threshold: {}\n' \
118 'Throttling NN Clock Frequency: {}\n' \
119 .format(self.level_number, self.temperature_threshold, self.hysteresis_temperature_threshold, self.throttling_nn_clock_freq)
122 return self.__str__()
124 class HealthInformation(object):
125 def __init__(self, overcurrent_protection_active, current_overcurrent_zone, red_overcurrent_threshold, orange_overcurrent_threshold,
126 temperature_throttling_active, current_temperature_zone, current_temperature_throttling_level,
127 temperature_throttling_levels, orange_temperature_threshold, orange_hysteresis_temperature_threshold,
128 red_temperature_threshold, red_hysteresis_temperature_threshold):
129 self.overcurrent_protection_active = overcurrent_protection_active
130 self.current_overcurrent_zone = current_overcurrent_zone
131 self.red_overcurrent_threshold = red_overcurrent_threshold
132 self.orange_overcurrent_threshold = orange_overcurrent_threshold
133 self.temperature_throttling_active = temperature_throttling_active
134 self.current_temperature_zone = current_temperature_zone
135 self.current_temperature_throttling_level = current_temperature_throttling_level
136 self.orange_temperature_threshold = orange_temperature_threshold
137 self.orange_hysteresis_temperature_threshold = orange_hysteresis_temperature_threshold
138 self.red_temperature_threshold = red_temperature_threshold
139 self.red_hysteresis_temperature_threshold = red_hysteresis_temperature_threshold
141 # Add TemperatureThrottlingLevel in case it has new throttling_nn_clock_freq. level_number can be used as only last
142 # levels can be with the same freq
143 self.temperature_throttling_levels = []
144 if self.temperature_throttling_active:
145 throttling_nn_clock_frequencies = []
146 for level_number, temperature_throttling_level in enumerate(temperature_throttling_levels):
147 if temperature_throttling_level.throttling_nn_clock_freq not in throttling_nn_clock_frequencies:
148 throttling_nn_clock_frequencies.append(temperature_throttling_level.throttling_nn_clock_freq)
149 self.temperature_throttling_levels.append(TemperatureThrottlingLevel(level_number,
150 temperature_throttling_level.temperature_threshold,
151 temperature_throttling_level.hysteresis_temperature_threshold,
152 temperature_throttling_level.throttling_nn_clock_freq))
154 return self.__str__()
158 str: Human readable string.
160 temperature_throttling_levels_str = "\n".join(["\n\n{}\n".format(str(temperature_throttling_level)) for temperature_throttling_level in self.temperature_throttling_levels]) \
161 if self.temperature_throttling_active else "<Temperature throttling is disabled>"
162 return 'Overcurrent Protection Active: {}\n' \
163 'Overcurrent Protection Current Overcurrent Zone: {}\n' \
164 'Overcurrent Protection Red Threshold: {}\n' \
165 'Overcurrent Protection Orange Threshold: {}\n' \
166 'Temperature Protection Red Threshold: {}\n' \
167 'Temperature Protection Red Hysteresis Threshold: {}\n' \
168 'Temperature Protection Orange Threshold: {}\n' \
169 'Temperature Protection Orange Hysteresis Threshold: {}\n' \
170 'Temperature Protection Throttling State: {}\n' \
171 'Temperature Protection Current Zone: {}\n' \
172 'Temperature Protection Current Throttling Level: {}\n' \
173 'Temperature Protection Throttling Levels: {}' \
174 .format(self.overcurrent_protection_active, self.current_overcurrent_zone, self.red_overcurrent_threshold,
175 self.orange_overcurrent_threshold, self.red_temperature_threshold,
176 self.red_hysteresis_temperature_threshold, self.orange_temperature_threshold,
177 self.orange_hysteresis_temperature_threshold, self.temperature_throttling_active,
178 self.current_temperature_zone, self.current_temperature_throttling_level, temperature_throttling_levels_str)
180 class ExtendedDeviceInformation(object):
181 def __init__(self, neural_network_core_clock_rate, supported_features, boot_source, lcs, soc_id, eth_mac_address, unit_level_tracking_id, soc_pm_values):
182 self.neural_network_core_clock_rate = neural_network_core_clock_rate
183 self.supported_features = SupportedFeatures(supported_features)
184 self.boot_source = boot_source
187 self.eth_mac_address = eth_mac_address
188 self.unit_level_tracking_id = unit_level_tracking_id
189 self.soc_pm_values = soc_pm_values
193 str: Human readable string.
195 string = 'Neural Network Core Clock Rate: {}MHz\n' \
197 'Boot source: {}\n' \
199 self.neural_network_core_clock_rate / MEGA_MULTIPLIER,
200 str(self.supported_features),
201 str(self.boot_source.name),
204 string += 'SoC ID: ' + (self.soc_id.hex())
206 if any(self.eth_mac_address):
207 string += '\nMAC Address: ' + (":".join("{:02X}".format(i) for i in self.eth_mac_address))
209 if any(self.unit_level_tracking_id):
210 string += '\nULT ID: ' + (self.unit_level_tracking_id.hex())
212 if any(self.soc_pm_values):
213 string += '\nPM Values: ' + (self.soc_pm_values.hex())
220 str: Human readable string.
222 return self.__str__()
224 class HailoFirmwareMode(Enum):
225 """Indication that firmware version is stable and official """
230 class HailoFirmwareType(Enum):
231 """Indication the firmware type """
236 class HailoResetTypes(Enum):
237 """Defines the available reset types."""
241 FORCED_SOFT = 'forced_soft'
244 class HailoFirmwareVersion(object):
245 """Represents a Hailo chip firmware version."""
247 CORE_BIT = 0x08000000
248 FW_VERSION_FORMAT = '<III'
250 def __init__(self, firmware_version_buffer, is_release, fw_type):
251 """Initialize a new Hailo Firmware Version object.
254 firmware_version_buffer (str): A buffer containing the firmware version struct.
255 is_release (bool, optional): Flag indicating if firmware is at develop/release mode.
256 None indicates unknown
258 self.major, self.minor, self.revision = struct.unpack(
259 self.FW_VERSION_FORMAT,
260 firmware_version_buffer)
262 self.fw_type = fw_type
263 self.mode = HailoFirmwareMode.RELEASE if is_release else HailoFirmwareMode.DEVELOP
265 self.revision &= ~(self.CORE_BIT | self.DEV_BIT)
269 str: Firmware version in a human readable format.
271 return '{}.{}.{} ({},{})'.format(self.major, self.minor, self.revision, self.mode.value, self.fw_type.value)
274 def construct_from_params(cls, major, minor, revision, is_release, fw_type):
276 class HailoFirmwareVersion : with the given Firmware version.
278 return cls(struct.pack(HailoFirmwareVersion.FW_VERSION_FORMAT, major, minor, revision), is_release, fw_type)
281 def comparable_value(self):
282 """A value that could be compared to other firmware versions."""
283 return (self.major << 64) + (self.minor << 32) + (self.revision)
286 return self.comparable_value
288 def __eq__(self, other):
289 return self.comparable_value == other.comparable_value
291 # TODO: Required for Python2 BW compatibility (SDK-10038)
292 # This impl' comes by default in Python3
293 def __ne__(self, other):
294 return not (self == other)
296 def __lt__(self, other):
297 return self.comparable_value < other.comparable_value
299 def check_protocol_compatibility(self, other):
300 return ((self.major == other.major) and (self.minor == other.minor))
302 class SupportedFeatures(object):
303 def __init__(self, supported_features):
304 self.ethernet = supported_features.ethernet
305 self.mipi = supported_features.mipi
306 self.pcie = supported_features.pcie
307 self.current_monitoring = supported_features.current_monitoring
308 self.mdio = supported_features.mdio
310 def _feature_str(self, feature_name, is_feature_enabled):
311 return '{}: {}\n'.format(feature_name, 'Enabled' if is_feature_enabled else 'Disabled')
315 str: Human readable string.
317 return 'Device supported features: \n' + \
318 self._feature_str('Ethernet', self.ethernet) + \
319 self._feature_str('MIPI', self.mipi) + \
320 self._feature_str('PCIE', self.pcie) + \
321 self._feature_str('Current Monitoring', self.current_monitoring) + \
322 self._feature_str('MDIO', self.mdio)
326 str: Human readable string.
328 return self.__str__()
330 def _is_feature_enabled(self, feature):
331 return (self.supported_features & feature) != 0