• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
5import logging
6import operator
7import 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.
14def 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', 'peach_pi', 'veyron_jerry'):
26        if (width, height) in [(1280, 800), (1440, 900), (1600, 900),
27                               (3840, 2160)]:
28            return False
29    if platform in ('kahlee', 'grunt'):
30        if (width, height) in [(3840, 2160)]:
31            return False
32    return True
33
34
35class 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.
112NO_EDID = Edid('', skip_verify=True)
113