Skip to content
This repository was archived by the owner on Oct 11, 2020. It is now read-only.

Commit 92b71b2

Browse files
committed
Add code page 437, add EDID 1.4 descriptors
1 parent e8ef755 commit 92b71b2

File tree

5 files changed

+124
-15
lines changed

5 files changed

+124
-15
lines changed

Cargo.toml

+4-1
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,7 @@ license = "MIT"
1111
authors = ["emersion"]
1212

1313
[dependencies]
14-
nom = "3.2.0"
14+
15+
[dependencies.nom]
16+
version = "3.2.0"
17+
features = ["verbose-errors"]

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
An [EDID](https://en.wikipedia.org/wiki/Extended_Display_Identification_Data) parser in Rust.
77

8+
Full spec: https://app.box.com/s/vcocw3z73ta09txiskj7cnk6289j356b/file/93518350906
9+
810
## License
911

1012
MIT

src/cp437.rs

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
use std::char;
2+
3+
// See https://en.wikipedia.org/wiki/Code_page_437
4+
5+
const FORWARD_TABLE: &'static [u16] = &[
6+
0x0000, 0x263A, 0x263B, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, 0x25D8, 0x25CB, 0x25D9, 0x2642, 0x2640, 0x266A, 0x266B, 0x263C,
7+
0x25BA, 0x25C4, 0x2195, 0x203C, 0x00B6, 0x00A7, 0x25AC, 0x21A8, 0x2191, 0x2193, 0x2192, 0x2190, 0x221F, 0x2194, 0x25B2, 0x25BC,
8+
0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
9+
0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
10+
0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
11+
0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
12+
0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
13+
0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x2302,
14+
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
15+
0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192,
16+
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
17+
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
18+
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
19+
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
20+
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
21+
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0,
22+
];
23+
24+
pub fn forward(code: u8) -> char {
25+
char::from_u32(FORWARD_TABLE[code as usize] as u32).unwrap()
26+
}

src/lib.rs

+92-14
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
#[macro_use]
22
extern crate nom;
33

4-
use std::str;
54
use nom::{be_u16, le_u8, le_u16, le_u32};
65

6+
mod cp437;
7+
78
#[derive(Debug, PartialEq)]
89
pub struct Header {
910
pub vendor: [char; 3],
@@ -67,18 +68,31 @@ named!(parse_standard_timing<&[u8], ()>, do_parse!(
6768
take!(16) >> ()
6869
));
6970

70-
// TODO: code page 437 (https://en.wikipedia.org/wiki/Code_page_437)
71-
named!(parse_descriptor_text<&[u8], &str>, map!(map_res!(take!(13), str::from_utf8), |s| s.trim()));
71+
named!(parse_descriptor_text<&[u8], String>,
72+
map!(
73+
map!(take!(13), |b| {
74+
b.iter()
75+
.filter(|c| **c != 0x0A)
76+
.map(|b| cp437::forward(*b))
77+
.collect::<String>()
78+
}),
79+
|s| s.trim().to_string()
80+
)
81+
);
7282

7383
#[derive(Debug, PartialEq)]
7484
pub enum Descriptor {
7585
DetailedTiming, // TODO
7686
SerialNumber(String),
7787
UnspecifiedText(String),
7888
RangeLimits, // TODO
79-
Name(String),
89+
ProductName(String),
8090
WhitePoint, // TODO
8191
StandardTiming, // TODO
92+
ColorManagement,
93+
TimingCodes,
94+
EstablishedTimings,
95+
Dummy,
8296
Unknown([u8; 13]),
8397
}
8498

@@ -90,12 +104,12 @@ named!(parse_descriptor<&[u8], Descriptor>,
90104
0xFF => do_parse!(
91105
take!(1)
92106
>> s: parse_descriptor_text
93-
>> (Descriptor::SerialNumber(s.to_string()))
107+
>> (Descriptor::SerialNumber(s))
94108
) |
95109
0xFE => do_parse!(
96110
take!(1)
97111
>> s: parse_descriptor_text
98-
>> (Descriptor::UnspecifiedText(s.to_string()))
112+
>> (Descriptor::UnspecifiedText(s))
99113
) |
100114
0xFD => do_parse!(
101115
take!(1)
@@ -105,7 +119,7 @@ named!(parse_descriptor<&[u8], Descriptor>,
105119
0xFC => do_parse!(
106120
take!(1)
107121
>> s: parse_descriptor_text
108-
>> (Descriptor::Name(s.to_string()))
122+
>> (Descriptor::ProductName(s))
109123
) |
110124
0xFB => do_parse!(
111125
take!(1)
@@ -117,10 +131,30 @@ named!(parse_descriptor<&[u8], Descriptor>,
117131
>> take!(13)
118132
>> (Descriptor::StandardTiming)
119133
) |
134+
0xF9 => do_parse!(
135+
take!(1)
136+
>> take!(13)
137+
>> (Descriptor::ColorManagement)
138+
) |
139+
0xF8 => do_parse!(
140+
take!(1)
141+
>> take!(13)
142+
>> (Descriptor::TimingCodes)
143+
) |
144+
0xF7 => do_parse!(
145+
take!(1)
146+
>> take!(13)
147+
>> (Descriptor::EstablishedTimings)
148+
) |
149+
0x10 => do_parse!(
150+
take!(1)
151+
>> take!(13)
152+
>> (Descriptor::Dummy)
153+
) |
120154
_ => do_parse!(
121-
take!(1) >>
122-
data: count_fixed!(u8, le_u8, 13) >>
123-
(Descriptor::Unknown(data))
155+
take!(1)
156+
>> data: count_fixed!(u8, le_u8, 13)
157+
>> (Descriptor::Unknown(data))
124158
)
125159
)
126160
>> (d)
@@ -160,9 +194,18 @@ mod tests {
160194
use super::*;
161195

162196
fn test(d: &[u8], expected: &EDID) {
163-
let (remaining, parsed) = parse(d).unwrap();
164-
assert_eq!(remaining.len(), 0);
165-
assert_eq!(&parsed, expected);
197+
match parse(d) {
198+
nom::IResult::Done(remaining, parsed) => {
199+
assert_eq!(remaining.len(), 0);
200+
assert_eq!(&parsed, expected);
201+
},
202+
nom::IResult::Error(err) => {
203+
panic!(format!("{}", err));
204+
},
205+
nom::IResult::Incomplete(_) => {
206+
panic!("Incomplete");
207+
},
208+
}
166209
}
167210

168211
#[test]
@@ -192,11 +235,46 @@ mod tests {
192235
descriptors: vec!(
193236
Descriptor::DetailedTiming,
194237
Descriptor::RangeLimits,
195-
Descriptor::Name("SyncMaster".to_string()),
238+
Descriptor::ProductName("SyncMaster".to_string()),
196239
Descriptor::SerialNumber("HS3P701105".to_string()),
197240
),
198241
};
199242

200243
test(d, &expected);
201244
}
245+
246+
#[test]
247+
fn test_card0_edp_1() {
248+
let d = include_bytes!("../testdata/card0-eDP-1");
249+
250+
let expected = EDID{
251+
header: Header{
252+
vendor: ['S', 'H', 'P'],
253+
product: 5193,
254+
serial: 0,
255+
week: 32,
256+
year: 25,
257+
version: 1,
258+
revision: 4,
259+
},
260+
display: Display{
261+
video_input: 165,
262+
width: 29,
263+
height: 17,
264+
gamma: 120,
265+
features: 14,
266+
},
267+
chromaticity: (),
268+
established_timing: (),
269+
standard_timing: (),
270+
descriptors: vec!(
271+
Descriptor::DetailedTiming,
272+
Descriptor::Dummy,
273+
Descriptor::UnspecifiedText("DJCP6ÇLQ133M1".to_string()),
274+
Descriptor::Unknown([2, 65, 3, 40, 0, 18, 0, 0, 11, 1, 10, 32, 32]),
275+
),
276+
};
277+
278+
test(d, &expected);
279+
}
202280
}

testdata/card0-eDP-1

128 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)