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 prefix = platform.lower().split('_')[0] 26 if prefix in ('snow', 'spring', 'skate', 'peach', 'veyron'): 27 if (width, height) in [(1280, 800), (1440, 900), (1600, 900), 28 (3840, 2160)]: 29 return False 30 return True 31 32 33class Edid(object): 34 """Edid is an abstraction of EDID (Extended Display Identification Data). 35 36 It provides methods to get the properties, manipulate the structure, 37 import from a file, export to a file, etc. 38 39 """ 40 41 BLOCK_SIZE = 128 42 43 44 def __init__(self, data, skip_verify=False): 45 """Construct an Edid. 46 47 @param data: A byte-array of EDID data. 48 @param skip_verify: True to skip the correctness check. 49 """ 50 if not Edid.verify(data) and not skip_verify: 51 raise ValueError('Not a valid EDID.') 52 self.data = data 53 54 55 @staticmethod 56 def verify(data): 57 """Verify the correctness of EDID. 58 59 @param data: A byte-array of EDID data. 60 61 @return True if the EDID is correct; False otherwise. 62 """ 63 data_len = len(data) 64 if data_len % Edid.BLOCK_SIZE != 0: 65 logging.debug('EDID has an invalid length: %d', data_len) 66 return False 67 68 for start in xrange(0, data_len, Edid.BLOCK_SIZE): 69 # Each block (128-byte) has a checksum at the last byte. 70 checksum = reduce(operator.add, 71 map(ord, data[start:start+Edid.BLOCK_SIZE])) 72 if checksum % 256 != 0: 73 logging.debug('Wrong checksum in the block %d of EDID', 74 start / Edid.BLOCK_SIZE) 75 return False 76 77 return True 78 79 80 @classmethod 81 def from_file(cls, filename, skip_verify=False): 82 """Construct an Edid from a file. 83 84 @param filename: A string of filename. 85 @param skip_verify: True to skip the correctness check. 86 """ 87 if not os.path.exists(filename): 88 raise ValueError('EDID file %r does not exist' % filename) 89 90 if filename.upper().endswith('.TXT'): 91 # Convert the EDID text format, returning from xrandr. 92 data = reduce(operator.add, 93 map(lambda s: s.strip().decode('hex'), 94 open(filename).readlines())) 95 else: 96 data = open(filename).read() 97 return cls(data, skip_verify) 98 99 100 def to_file(self, filename): 101 """Export the EDID to a file. 102 103 @param filename: A string of filename. 104 """ 105 with open(filename, 'w+') as f: 106 f.write(self.data) 107 108 109# A constant object to represent no EDID. 110NO_EDID = Edid('', skip_verify=True) 111