# Copyright 2014 The Chromium OS Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. """Provides EDID class with methods for parsing info.""" import array from . import basic_display from . import chromaticity from . import descriptor from . import error_check from . import established_timings from . import extensions from . import standard_timings class Edid(object): """Defines methods and properties for accesing an EDID object's content.""" def __init__(self, e): """Create an Edid object with a list of bytes. Args: e: The list of bytes that make up this EDID. """ self._edid = e def GetData(self, start=None, end=None): """Fetch the raw data for the entire or part of the EDID. Args: start: The index of the first element to include. end: The index of the first element to exclude. Returns: A list of bytes. """ return self._edid[start:end] @property def manufacturer_id(self): """Fetch the manufacturer ID. Returns: A three letter string that represents the manufacturer ID. """ manu_id = ((self._edid[0x08] << 8) + self._edid[0x09]) c1 = self._ConvertToLetter((manu_id >> 10) & 0x1F) c2 = self._ConvertToLetter((manu_id >> 5) & 0x1F) c3 = self._ConvertToLetter(manu_id & 0x1F) return c1 + c2 + c3 @property def product_code(self): """Fetch the ID Product code. This code is used to differentiate between different models from the same manufacturer (i.e., a model number). Bytes 10-11, little endian. Returns: An integer denoting the product code. """ return (self._edid[0x0B] << 8) + self._edid[0x0A] @property def serial_number(self): """Fetch the serial number. Used to differentiate between instances of the same display model. Returns: An integer denoting serial number or None. """ sn = 0 sn += self._edid[0x0F] << 24 sn += self._edid[0x0E] << 16 sn += self._edid[0x0D] << 8 sn += self._edid[0x0C] return sn if sn else None @property def manufacturing_week(self): """Fetch the week of manufacturing. Returns: None, if unspecified, or an integer indicating the week number. """ if self._edid[0x10] in [0, 255]: return None else: return self._edid[0x10] @property def manufacturing_year(self): """Fetch the year of manufacturing. Returns: None, if unspecified, or an integer indicating the year. """ if self._edid[0x10] == 255: return None else: return self._edid[0x11] + 1990 @property def model_year(self): """Fetch the model year. Model year is only specified if week is set to 255. Returns: None, if unspecified, or an integer indicating the model year. """ if self._edid[0x10] == 255: return self._edid[0x11] + 1990 else: return None @property def extension_count(self): """Fetch the number of extensions in this EDID. Returns: An integer denoting the number of extensions. """ return self._edid[0x7E] def _ConvertToLetter(self, b): """Convert a 5-digit binary number into a letter. Called when printing manufacturing info. Args: b: The binary number being converted into a character. Returns: A single character (upper-case letter). """ return chr(b + 64) @property def edid_version(self): """Fetch the EDID version (1.3 or 1.4). Returns: A string indicating the EDID version. """ return '%d.%d' % (self._edid[0x12], self._edid[0x13]) @property def basic_display(self): """Fetch the Basic Display information in this EDID. Returns: A basic_display.BasicDisplay object. """ return basic_display.BasicDisplay(self._edid, self.edid_version) @property def chromaticity(self): """Fetch the Chromaticity information in this EDID. Returns: A chromaticity.Chromaticity object. """ return chromaticity.Chromaticity(self._edid) @property def established_timings(self): """Fetch the Established Timings information in this EDID. Returns: An established_timings.EstablishedTimings object. """ return established_timings.EstablishedTimings(self._edid) @property def standard_timings(self): """Fetch the Standard Timing information in this EDID. Returns: A standard_timings.StandardTiming object. """ base = 38 sts = [] for x in range(0, 8): st = standard_timings.GetStandardTiming(self._edid, (base + (x * 2)), self.edid_version) if st: sts.append(st) return sts def GetDescriptor(self, index): """Fetch a single Descriptor's information in this EDID. Args: index: The descriptor index (0-3) within the EDID. Returns: A single descriptor.Descriptor object. Raises: IndexError: If index is not in the range 0-3. """ base = 54 # Descriptor blocks begin at byte 54 in base EDID return descriptor.GetDescriptor(self._edid, (base + (index * 18)), self.edid_version) @property def descriptors(self): """Fetch all descriptors in a base EDID. Returns: A list of descriptor.Descriptor objects. """ descs = [] for x in range(0, 4): desc = self.GetDescriptor(x) if desc: descs.append(desc) return descs def GetExtension(self, index): """Fetch an Extension's information in this EDID. Args: index: The index of the extension (starting at 1). Returns: A single extensions.Extension object. """ return extensions.GetExtension(self._edid, index, self.edid_version) def GetErrors(self): """Check an EDID for errors by calling error_check module. Returns: A list of error.Error objects. """ return error_check.GetErrors(self.GetData(), self.edid_version) def ConvertToBinary(self, filename): """Convert an EDID object into a binary blob. Args: filename: The string filename of the text file. """ with open(filename, 'wb') as myfile: blob = array.array('B', self._edid).tobytes() myfile.write(blob)