Home | History | Annotate | Download | only in chameleon
      1 # Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 
      5 import logging
      6 import operator
      7 import os
      8 
      9 
     10 # TODO: This is a quick workaround; some of our arm devices so far only
     11 # support the HDMI EDIDs and the DP one at 1680x1050. A more proper
     12 # solution is to build a database of supported resolutions and pixel
     13 # clocks for each model and check if the EDID is in the supported list.
     14 def is_edid_supported(host, width, height):
     15     """Check whether the EDID is supported by DUT
     16 
     17     @param host: A CrosHost object.
     18     @param width: The screen width
     19     @param height: The screen height
     20 
     21     @return: True if the check passes; False otherwise.
     22     """
     23     # TODO: Support client test that the host is not a CrosHost.
     24     platform = host.get_platform()
     25     if platform in ('snow', 'spring', 'skate', 'pi', 'jerry'):
     26         if (width, height) in [(1280, 800), (1440, 900), (1600, 900),
     27                                (3840, 2160)]:
     28             return False
     29     if platform in ('kahlee',):
     30         if (width, height) in [(3840, 2160)]:
     31             return False
     32     return True
     33 
     34 
     35 class Edid(object):
     36     """Edid is an abstraction of EDID (Extended Display Identification Data).
     37 
     38     It provides methods to get the properties, manipulate the structure,
     39     import from a file, export to a file, etc.
     40 
     41     """
     42 
     43     BLOCK_SIZE = 128
     44 
     45 
     46     def __init__(self, data, skip_verify=False):
     47         """Construct an Edid.
     48 
     49         @param data: A byte-array of EDID data.
     50         @param skip_verify: True to skip the correctness check.
     51         """
     52         if not Edid.verify(data) and not skip_verify:
     53             raise ValueError('Not a valid EDID.')
     54         self.data = data
     55 
     56 
     57     @staticmethod
     58     def verify(data):
     59         """Verify the correctness of EDID.
     60 
     61         @param data: A byte-array of EDID data.
     62 
     63         @return True if the EDID is correct; False otherwise.
     64         """
     65         data_len = len(data)
     66         if data_len % Edid.BLOCK_SIZE != 0:
     67             logging.debug('EDID has an invalid length: %d', data_len)
     68             return False
     69 
     70         for start in xrange(0, data_len, Edid.BLOCK_SIZE):
     71             # Each block (128-byte) has a checksum at the last byte.
     72             checksum = reduce(operator.add,
     73                               map(ord, data[start:start+Edid.BLOCK_SIZE]))
     74             if checksum % 256 != 0:
     75                 logging.debug('Wrong checksum in the block %d of EDID',
     76                               start / Edid.BLOCK_SIZE)
     77                 return False
     78 
     79         return True
     80 
     81 
     82     @classmethod
     83     def from_file(cls, filename, skip_verify=False):
     84         """Construct an Edid from a file.
     85 
     86         @param filename: A string of filename.
     87         @param skip_verify: True to skip the correctness check.
     88         """
     89         if not os.path.exists(filename):
     90             raise ValueError('EDID file %r does not exist' % filename)
     91 
     92         if filename.upper().endswith('.TXT'):
     93             # Convert the EDID text format, returning from xrandr.
     94             data = reduce(operator.add,
     95                           map(lambda s: s.strip().decode('hex'),
     96                               open(filename).readlines()))
     97         else:
     98             data = open(filename).read()
     99         return cls(data, skip_verify)
    100 
    101 
    102     def to_file(self, filename):
    103         """Export the EDID to a file.
    104 
    105         @param filename: A string of filename.
    106         """
    107         with open(filename, 'w+') as f:
    108             f.write(self.data)
    109 
    110 
    111 # A constant object to represent no EDID.
    112 NO_EDID = Edid('', skip_verify=True)
    113