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