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