121 lines
3.8 KiB
Python
121 lines
3.8 KiB
Python
# Lint as: python2, python3
|
|
# Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
# found in the LICENSE file.
|
|
|
|
from __future__ import absolute_import
|
|
from __future__ import division
|
|
from __future__ import print_function
|
|
from functools import reduce
|
|
import codecs
|
|
import logging
|
|
import operator
|
|
import os
|
|
import six
|
|
from six.moves import map
|
|
from six.moves import range
|
|
|
|
|
|
# TODO: This is a quick workaround; some of our arm devices so far only
|
|
# support the HDMI EDIDs and the DP one at 1680x1050. A more proper
|
|
# solution is to build a database of supported resolutions and pixel
|
|
# clocks for each model and check if the EDID is in the supported list.
|
|
def is_edid_supported(host, width, height):
|
|
"""Check whether the EDID is supported by DUT
|
|
|
|
@param host: A CrosHost object.
|
|
@param width: The screen width
|
|
@param height: The screen height
|
|
|
|
@return: True if the check passes; False otherwise.
|
|
"""
|
|
# TODO: Support client test that the host is not a CrosHost.
|
|
platform = host.get_platform()
|
|
if platform in ('snow', 'spring', 'skate', 'peach_pi', 'veyron_jerry'):
|
|
if (width, height) in [(1280, 800), (1440, 900), (1600, 900),
|
|
(3840, 2160)]:
|
|
return False
|
|
if platform in ('kahlee', 'grunt'):
|
|
if (width, height) in [(3840, 2160)]:
|
|
return False
|
|
return True
|
|
|
|
|
|
class Edid(object):
|
|
"""Edid is an abstraction of EDID (Extended Display Identification Data).
|
|
|
|
It provides methods to get the properties, manipulate the structure,
|
|
import from a file, export to a file, etc.
|
|
|
|
"""
|
|
|
|
BLOCK_SIZE = 128
|
|
|
|
|
|
def __init__(self, data, skip_verify=False):
|
|
"""Construct an Edid.
|
|
|
|
@param data: A byte-array of EDID data.
|
|
@param skip_verify: True to skip the correctness check.
|
|
"""
|
|
if not Edid.verify(data) and not skip_verify:
|
|
raise ValueError('Not a valid EDID.')
|
|
self.data = data
|
|
|
|
|
|
@staticmethod
|
|
def verify(data):
|
|
"""Verify the correctness of EDID.
|
|
|
|
@param data: A byte-array of EDID data.
|
|
|
|
@return True if the EDID is correct; False otherwise.
|
|
"""
|
|
data_len = len(data)
|
|
if data_len % Edid.BLOCK_SIZE != 0:
|
|
logging.debug('EDID has an invalid length: %d', data_len)
|
|
return False
|
|
|
|
for start in range(0, data_len, Edid.BLOCK_SIZE):
|
|
# Each block (128-byte) has a checksum at the last byte.
|
|
checksum = reduce(operator.add,
|
|
list(map(ord, data[start:start+Edid.BLOCK_SIZE])))
|
|
if checksum % 256 != 0:
|
|
logging.debug('Wrong checksum in the block %d of EDID',
|
|
start // Edid.BLOCK_SIZE)
|
|
return False
|
|
|
|
return True
|
|
|
|
|
|
@classmethod
|
|
def from_file(cls, filename, skip_verify=False):
|
|
"""Construct an Edid from a file.
|
|
|
|
@param filename: A string of filename.
|
|
@param skip_verify: True to skip the correctness check.
|
|
"""
|
|
if not os.path.exists(filename):
|
|
raise ValueError('EDID file %r does not exist' % filename)
|
|
|
|
if filename.upper().endswith('.TXT'):
|
|
# Convert the EDID text format, returning from xrandr.
|
|
data = reduce(operator.add,
|
|
[codecs.decode(s.strip(), 'hex') for s in open(filename).readlines()])
|
|
else:
|
|
data = open(filename).read()
|
|
return cls(data, skip_verify)
|
|
|
|
|
|
def to_file(self, filename):
|
|
"""Export the EDID to a file.
|
|
|
|
@param filename: A string of filename.
|
|
"""
|
|
with open(filename, 'w+') as f:
|
|
f.write(self.data)
|
|
|
|
|
|
# A constant object to represent no EDID.
|
|
NO_EDID = Edid('', skip_verify=True)
|