Skip to content

Commit d2a3266

Browse files
committed
Add support for parsing standard Xorg.log output
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.
1 parent 0675d67 commit d2a3266

File tree

7 files changed

+623
-2
lines changed

7 files changed

+623
-2
lines changed

frontend/django_tests/data/xorg.log

+462
Large diffs are not rendered by default.

frontend/django_tests/test_forms.py

+9
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,15 @@ def test_text_xrandr_no_edid(self):
200200
u'No EDID was parsed.'
201201
)
202202

203+
def test_text_xorglog_no_edid(self):
204+
# Test Xorg.log with no EDIDs
205+
data = self.valid_data
206+
data['text_type'] = 'xorglog'
207+
self._test_non_field_error(
208+
self.valid_data,
209+
u'No EDID was parsed.'
210+
)
211+
203212
def test_text_type_empty(self):
204213
# Test an invalid value
205214
data = self.valid_data

frontend/django_tests/test_helpers.py

+40
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,43 @@ def test_xrandr2(self):
6363
'00415355532056473233410a2020008f'
6464
]
6565
self.assertEqual(edid_list, expected_edid_list)
66+
67+
def test_xorglog(self):
68+
xorglog_text = self._read_from_file('xorg.log')
69+
edid_list = list(EDIDUploadFormCleaner.clean_xorglog(xorglog_text))
70+
expected_edid_list = [
71+
'00ffffffffffff0010acbaa053334530' +
72+
'171c010380342078ea0495a9554d9d26' +
73+
'105054a54b00714f8180a940d1c0d100' +
74+
'010101010101283c80a070b023403020' +
75+
'360006442100001e000000ff00434656' +
76+
'394e383638304533530a000000fc0044' +
77+
'454c4c2055323431350a2020000000fd' +
78+
'00313d1e5311000a20202020202001a5' +
79+
'020322f14f9005040302071601141f12' +
80+
'132021222309070765030c0010008301' +
81+
'0000023a801871382d40582c45000644' +
82+
'2100001e011d8018711c1620582c2500' +
83+
'06442100009e011d007251d01e206e28' +
84+
'550006442100001e8c0ad08a20e02d10' +
85+
'103e9600064421000018000000000000' +
86+
'00000000000000000000000000000082',
87+
88+
'00ffffffffffff0010acbaa053504730' +
89+
'171c010380342078ea0495a9554d9d26' +
90+
'105054a54b00714f8180a940d1c0d100' +
91+
'010101010101283c80a070b023403020' +
92+
'360006442100001e000000ff00434656' +
93+
'394e383638304750530a000000fc0044' +
94+
'454c4c2055323431350a2020000000fd' +
95+
'00313d1e5311000a2020202020200167' +
96+
'020322f14f9005040302071601141f12' +
97+
'132021222309070765030c0010008301' +
98+
'0000023a801871382d40582c45000644' +
99+
'2100001e011d8018711c1620582c2500' +
100+
'06442100009e011d007251d01e206e28' +
101+
'550006442100001e8c0ad08a20e02d10' +
102+
'103e9600064421000018000000000000' +
103+
'00000000000000000000000000000082'
104+
]
105+
self.assertEqual(edid_list, expected_edid_list)

frontend/django_tests/test_views.py

+74
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ def test_invalid_checksum(self):
131131
class EDIDTextUploadTestCase(TestCase):
132132
def setUp(self):
133133
Manufacturer.objects.bulk_create([
134+
Manufacturer(name_id='DEL', name='Dell Inc.'),
134135
Manufacturer(name_id='SEC', name='Seiko Epson Corporation'),
135136
Manufacturer(name_id='UNK', name='Unknown'),
136137
])
@@ -241,6 +242,41 @@ def test_xrandr(self):
241242
self.assertEqual(response.context_data['failed'], 1)
242243
self.assertEqual(response.context_data['duplicate'], 0)
243244

245+
def test_xorglog(self):
246+
xorglog_text = self._read_from_file('xorg.log')
247+
248+
# Submit Xorg.log output
249+
response = self.client.post(
250+
self.post_url, {'text': xorglog_text, 'text_type': 'xorglog'}
251+
)
252+
253+
# Check an EDID was parsed and added
254+
self.assertEqual(response.context_data['succeeded'], 2)
255+
self.assertEqual(response.context_data['failed'], 0)
256+
self.assertEqual(response.context_data['duplicate'], 0)
257+
258+
# Check some of EDID values
259+
edid = EDID.objects.get(pk=1)
260+
self.assertEqual(
261+
len([timing for timing in edid.get_est_timings()
262+
if timing['supported']]),
263+
8
264+
)
265+
self.assertEqual(edid.manufacturer.name_id, 'DEL')
266+
self.assertEqual(edid.bdp_video_input, EDID.bdp_video_input_digital)
267+
self.assertEqual(edid.monitor_range_limits, True)
268+
269+
# Duplicate test
270+
# Submit Xorg.log output again
271+
response = self.client.post(
272+
self.post_url, {'text': xorglog_text, 'text_type': 'xorglog'}
273+
)
274+
275+
# Check an EDID was parsed and rejected for duplicate
276+
self.assertEqual(response.context_data['succeeded'], 0)
277+
self.assertEqual(response.context_data['failed'], 0)
278+
self.assertEqual(response.context_data['duplicate'], 2)
279+
244280

245281
class EDIDTestCase(EDIDTestMixin, TestCase):
246282
def test_list(self):
@@ -983,6 +1019,7 @@ def test_duplicate(self):
9831019
class APITextUploadTestCase(TestCase):
9841020
def setUp(self):
9851021
Manufacturer.objects.bulk_create([
1022+
Manufacturer(name_id='DEL', name='Dell Inc.'),
9861023
Manufacturer(name_id='SEC', name='Seiko Epson Corporation'),
9871024
Manufacturer(name_id='UNK', name='Unknown'),
9881025
])
@@ -1099,6 +1136,43 @@ def test_xrandr(self):
10991136
self.assertEqual(data['failed'], 1)
11001137
self.assertEqual(data['duplicate'], 0)
11011138

1139+
def test_xorglog(self):
1140+
xorglog_text = self._read_from_file('xorg.log')
1141+
1142+
# Submit Xorglog output
1143+
response = self.client.post(
1144+
self.post_url, {'text': xorglog_text, 'text_type': 'xorglog'}
1145+
)
1146+
data = json.loads(response.content)
1147+
1148+
# Check an EDID was parsed and added
1149+
self.assertEqual(data['succeeded'], 2)
1150+
self.assertEqual(data['failed'], 0)
1151+
self.assertEqual(data['duplicate'], 0)
1152+
1153+
# Check some of EDID values
1154+
edid = EDID.objects.get(pk=1)
1155+
self.assertEqual(
1156+
len([timing for timing in edid.get_est_timings()
1157+
if timing['supported']]),
1158+
8
1159+
)
1160+
self.assertEqual(edid.manufacturer.name_id, 'DEL')
1161+
self.assertEqual(edid.bdp_video_input, EDID.bdp_video_input_digital)
1162+
self.assertEqual(edid.monitor_range_limits, True)
1163+
1164+
# Duplicate test
1165+
# Submit Xorglog output again
1166+
response = self.client.post(
1167+
self.post_url, {'text': xorglog_text, 'text_type': 'xorglog'}
1168+
)
1169+
data = json.loads(response.content)
1170+
1171+
# Check an EDID was parsed and rejected for duplicate
1172+
self.assertEqual(data['succeeded'], 0)
1173+
self.assertEqual(data['failed'], 0)
1174+
self.assertEqual(data['duplicate'], 2)
1175+
11021176
def test_invalid(self):
11031177
response = self.client.post(
11041178
self.post_url, {'text': 'BAD TEXT', 'text_type': 'None'}

frontend/forms.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ def __init__(self, *args, **kwargs):
6262
def clean_text_type(self):
6363
text_type = self.cleaned_data['text_type']
6464

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

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

90+
elif text_type == 'xorglog':
91+
for edid in EDIDUploadFormCleaner.clean_xorglog(text):
92+
self.edid_list.append(codecs.decode(edid, encoding='hex'))
93+
9094
if self.edid_list == []:
9195
raise forms.ValidationError('No EDID was parsed.')
9296

frontend/helpers/EDIDUploadFormCleaner.py

+27
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,30 @@ def clean_xrandr(text):
6161
elif edid_pattern.match(line):
6262
inside_edid = True
6363
edid_hex = ''
64+
65+
@staticmethod
66+
def clean_xorglog(text):
67+
"This matches the printing logic in hw/xfree86/ddc/print_edid.c"
68+
69+
inside_edid = False
70+
edid_hex = ''
71+
72+
edid_pattern = re.compile(r'^.*: EDID \(in hex\):$')
73+
hex_pattern = re.compile(r'^.*:\s*([0-9a-fA-F]+)$')
74+
75+
# Parse text line-by-line
76+
for line in text.splitlines():
77+
# If inside edid block
78+
if inside_edid:
79+
match = hex_pattern.match(line.strip())
80+
if match:
81+
edid_hex += match.group(1)
82+
# edid block ended
83+
else:
84+
inside_edid = False
85+
# Convert hex to binary and add it to EDIDs list
86+
yield edid_hex
87+
# Look for edid block
88+
elif edid_pattern.match(line):
89+
inside_edid = True
90+
edid_hex = ''

templates/frontend/edid_upload_text.html

+6-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ <h4>Thanks!</h4>
3232
<div class="span9">
3333
<div class="control-group{% if form.text.errors %} error{% endif %}">
3434
<div class="controls">
35-
<textarea id="id_text" name="text" cols="40" rows="10">{% if form.text.value %}{{ form.text.value }}{% endif %}</textarea>
35+
<textarea id="id_text" name="text" cols="40" rows="20">{% if form.text.value %}{{ form.text.value }}{% endif %}</textarea>
3636
{% for error in form.text.errors %}
3737
<span class="help-block">{{ error|escape }}</span>
3838
{% endfor %}
@@ -52,6 +52,11 @@ <h4>Thanks!</h4>
5252
<input type="radio" id="id_text_type_xrandr" name="text_type" value="xrandr"{% ifequal form.text_type.value 'xrandr' %} checked{% endifequal %}> XRandR
5353
</label>
5454
<p>Linux users, run <code>xrandr --props</code> and paste its output.</p>
55+
<label class="radio">
56+
<input type="radio" id="id_text_type_xoglog" name="text_type" value="xorglog"{% ifequal form.text_type.value 'xorglog' %} checked{% endifequal %}> Xorg.log
57+
</label>
58+
<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>
59+
</label>
5560
</div>
5661
</div>
5762
</div>

0 commit comments

Comments
 (0)