Skip to content

Commit

Permalink
Add support for parsing standard Xorg.log output
Browse files Browse the repository at this point in the history
There's a wealth of xorg.log files posted for various debug purposes.
Make it easy to import data from these.

This output is produced by hw/xfree86/ddc/print_edid.c so all DDX's
should produce the same output.
  • Loading branch information
imirkin committed Nov 24, 2019
1 parent 0675d67 commit ce486e2
Show file tree
Hide file tree
Showing 7 changed files with 623 additions and 2 deletions.
462 changes: 462 additions & 0 deletions frontend/django_tests/data/xorg.log

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions frontend/django_tests/test_forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,15 @@ def test_text_xrandr_no_edid(self):
u'No EDID was parsed.'
)

def test_text_xorglog_no_edid(self):
# Test Xorg.log with no EDIDs
data = self.valid_data
data['text_type'] = 'xorglog'
self._test_non_field_error(
self.valid_data,
u'No EDID was parsed.'
)

def test_text_type_empty(self):
# Test an invalid value
data = self.valid_data
Expand Down
40 changes: 40 additions & 0 deletions frontend/django_tests/test_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,43 @@ def test_xrandr2(self):
'00415355532056473233410a2020008f'
]
self.assertEqual(edid_list, expected_edid_list)

def test_xorglog(self):
xorglog_text = self._read_from_file('xorg.log')
edid_list = list(EDIDUploadFormCleaner.clean_xorglog(xorglog_text))
expected_edid_list = [
'00ffffffffffff0010acbaa053334530' +
'171c010380342078ea0495a9554d9d26' +
'105054a54b00714f8180a940d1c0d100' +
'010101010101283c80a070b023403020' +
'360006442100001e000000ff00434656' +
'394e383638304533530a000000fc0044' +
'454c4c2055323431350a2020000000fd' +
'00313d1e5311000a20202020202001a5' +
'020322f14f9005040302071601141f12' +
'132021222309070765030c0010008301' +
'0000023a801871382d40582c45000644' +
'2100001e011d8018711c1620582c2500' +
'06442100009e011d007251d01e206e28' +
'550006442100001e8c0ad08a20e02d10' +
'103e9600064421000018000000000000' +
'00000000000000000000000000000082',

'00ffffffffffff0010acbaa053504730' +
'171c010380342078ea0495a9554d9d26' +
'105054a54b00714f8180a940d1c0d100' +
'010101010101283c80a070b023403020' +
'360006442100001e000000ff00434656' +
'394e383638304750530a000000fc0044' +
'454c4c2055323431350a2020000000fd' +
'00313d1e5311000a2020202020200167' +
'020322f14f9005040302071601141f12' +
'132021222309070765030c0010008301' +
'0000023a801871382d40582c45000644' +
'2100001e011d8018711c1620582c2500' +
'06442100009e011d007251d01e206e28' +
'550006442100001e8c0ad08a20e02d10' +
'103e9600064421000018000000000000' +
'00000000000000000000000000000082'
]
self.assertEqual(edid_list, expected_edid_list)
74 changes: 74 additions & 0 deletions frontend/django_tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ def test_invalid_checksum(self):
class EDIDTextUploadTestCase(TestCase):
def setUp(self):
Manufacturer.objects.bulk_create([
Manufacturer(name_id='DEL', name='Dell Inc.'),
Manufacturer(name_id='SEC', name='Seiko Epson Corporation'),
Manufacturer(name_id='UNK', name='Unknown'),
])
Expand Down Expand Up @@ -241,6 +242,41 @@ def test_xrandr(self):
self.assertEqual(response.context_data['failed'], 1)
self.assertEqual(response.context_data['duplicate'], 0)

def test_xorglog(self):
xorglog_text = self._read_from_file('xorg.log')

# Submit Xorg.log output
response = self.client.post(
self.post_url, {'text': xorglog_text, 'text_type': 'xorglog'}
)

# Check an EDID was parsed and added
self.assertEqual(response.context_data['succeeded'], 2)
self.assertEqual(response.context_data['failed'], 0)
self.assertEqual(response.context_data['duplicate'], 0)

# Check some of EDID values
edid = EDID.objects.get(pk=1)
self.assertEqual(
len([timing for timing in edid.get_est_timings()
if timing['supported']]),
8
)
self.assertEqual(edid.manufacturer.name_id, 'DEL')
self.assertEqual(edid.bdp_video_input, EDID.bdp_video_input_digital)
self.assertEqual(edid.monitor_range_limits, True)

# Duplicate test
# Submit Xorg.log output again
response = self.client.post(
self.post_url, {'text': xorglog_text, 'text_type': 'xorglog'}
)

# Check an EDID was parsed and rejected for duplicate
self.assertEqual(response.context_data['succeeded'], 0)
self.assertEqual(response.context_data['failed'], 0)
self.assertEqual(response.context_data['duplicate'], 2)


class EDIDTestCase(EDIDTestMixin, TestCase):
def test_list(self):
Expand Down Expand Up @@ -983,6 +1019,7 @@ def test_duplicate(self):
class APITextUploadTestCase(TestCase):
def setUp(self):
Manufacturer.objects.bulk_create([
Manufacturer(name_id='DEL', name='Dell Inc.'),
Manufacturer(name_id='SEC', name='Seiko Epson Corporation'),
Manufacturer(name_id='UNK', name='Unknown'),
])
Expand Down Expand Up @@ -1099,6 +1136,43 @@ def test_xrandr(self):
self.assertEqual(data['failed'], 1)
self.assertEqual(data['duplicate'], 0)

def test_xorglog(self):
xorglog_text = self._read_from_file('xorg.log')

# Submit Xorglog output
response = self.client.post(
self.post_url, {'text': xorglog_text, 'text_type': 'xorglog'}
)
data = json.loads(response.content)

# Check an EDID was parsed and added
self.assertEqual(data['succeeded'], 2)
self.assertEqual(data['failed'], 0)
self.assertEqual(data['duplicate'], 0)

# Check some of EDID values
edid = EDID.objects.get(pk=1)
self.assertEqual(
len([timing for timing in edid.get_est_timings()
if timing['supported']]),
8
)
self.assertEqual(edid.manufacturer.name_id, 'DEL')
self.assertEqual(edid.bdp_video_input, EDID.bdp_video_input_digital)
self.assertEqual(edid.monitor_range_limits, True)

# Duplicate test
# Submit Xorglog output again
response = self.client.post(
self.post_url, {'text': xorglog_text, 'text_type': 'xorglog'}
)
data = json.loads(response.content)

# Check an EDID was parsed and rejected for duplicate
self.assertEqual(data['succeeded'], 0)
self.assertEqual(data['failed'], 0)
self.assertEqual(data['duplicate'], 2)

def test_invalid(self):
response = self.client.post(
self.post_url, {'text': 'BAD TEXT', 'text_type': 'None'}
Expand Down
6 changes: 5 additions & 1 deletion frontend/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def __init__(self, *args, **kwargs):
def clean_text_type(self):
text_type = self.cleaned_data['text_type']

if text_type not in ['hex', 'xrandr']:
if text_type not in ['hex', 'xrandr', 'xorglog']:
raise forms.ValidationError('Text type is invalid.')

return text_type
Expand All @@ -87,6 +87,10 @@ def clean(self):
for edid in EDIDUploadFormCleaner.clean_xrandr(text):
self.edid_list.append(codecs.decode(edid, encoding='hex'))

elif text_type == 'xorglog':
for edid in EDIDUploadFormCleaner.clean_xorglog(text):
self.edid_list.append(codecs.decode(edid, encoding='hex'))

if self.edid_list == []:
raise forms.ValidationError('No EDID was parsed.')

Expand Down
27 changes: 27 additions & 0 deletions frontend/helpers/EDIDUploadFormCleaner.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,30 @@ def clean_xrandr(text):
elif edid_pattern.match(line):
inside_edid = True
edid_hex = ''

@staticmethod
def clean_xorglog(text):
"This matches the printing logic in hw/xfree86/ddc/print_edid.c"

inside_edid = False
edid_hex = ''

edid_pattern = re.compile(r'^.*: EDID \(in hex\):$')
hex_pattern = re.compile(r'^.*:\s*([0-9a-fA-F]+)$')

# Parse text line-by-line
for line in text.splitlines():
# If inside edid block
if inside_edid:
match = hex_pattern.match(line.strip())
if match:
edid_hex += match.group(1)
# edid block ended
else:
inside_edid = False
# Convert hex to binary and add it to EDIDs list
yield edid_hex
# Look for edid block
elif edid_pattern.match(line):
inside_edid = True
edid_hex = ''
7 changes: 6 additions & 1 deletion templates/frontend/edid_upload_text.html
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ <h4>Thanks!</h4>
<div class="span9">
<div class="control-group{% if form.text.errors %} error{% endif %}">
<div class="controls">
<textarea id="id_text" name="text" cols="40" rows="10">{% if form.text.value %}{{ form.text.value }}{% endif %}</textarea>
<textarea id="id_text" name="text" cols="40" rows="20">{% if form.text.value %}{{ form.text.value }}{% endif %}</textarea>
{% for error in form.text.errors %}
<span class="help-block">{{ error|escape }}</span>
{% endfor %}
Expand All @@ -52,6 +52,11 @@ <h4>Thanks!</h4>
<input type="radio" id="id_text_type_xrandr" name="text_type" value="xrandr"{% ifequal form.text_type.value 'xrandr' %} checked{% endifequal %}> XRandR
</label>
<p>Linux users, run <code>xrandr --props</code> and paste its output.</p>
<label class="radio">
<input type="radio" id="id_text_type_xorglog" name="text_type" value="xorglog"{% ifequal form.text_type.value 'xorglog' %} checked{% endifequal %}> Xorg.log
</label>
<p>Xorg users, paste the contents of <code>/var/log/Xorg.0.log</code>, or the part starting with <code>EDID (in hex)</code></p>
</label>
</div>
</div>
</div>
Expand Down

0 comments on commit ce486e2

Please sign in to comment.