Skip to content

Commit 4ac1882

Browse files
committed
add support for both field 1 and 2 data
1 parent 789e279 commit 4ac1882

File tree

2 files changed

+183
-13
lines changed

2 files changed

+183
-13
lines changed

src/lib.rs

+88-9
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
1313
use std::collections::VecDeque;
1414

15-
use tables::{Channel, Code, MidRow, PreambleAddressCode};
15+
use tables::{Channel, Code, Field, MidRow, PreambleAddressCode};
1616

1717
#[macro_use]
1818
extern crate log;
@@ -147,10 +147,13 @@ impl Cea608 {
147147
/// Helper struct that has two purposes:
148148
/// 1. Tracks the previous data for control code de-duplication
149149
/// 2. Adds the last received channel to non control codes.
150+
///
151+
/// This object only keeps data for a single [`Field`]
150152
#[derive(Debug, Default)]
151153
pub struct Cea608State {
152154
last_data: Option<[u8; 2]>,
153155
last_channel: Option<Channel>,
156+
last_received_field: Option<Field>,
154157
}
155158

156159
impl Cea608State {
@@ -173,6 +176,9 @@ impl Cea608State {
173176
[Code::Control(control_code), _] => {
174177
let channel = control_code.channel();
175178
self.last_channel = Some(channel);
179+
if let Some(field) = control_code.field() {
180+
self.last_received_field = Some(field);
181+
}
176182
Ok(Some(match control_code.code() {
177183
tables::Control::MidRow(midrow) => Cea608::MidRowChange(channel, midrow),
178184
tables::Control::PreambleAddress(preamble) => {
@@ -229,6 +235,12 @@ impl Cea608State {
229235
}
230236
}
231237

238+
/// The [`Field`] that some specific [`tables::Control`] codes referenced. Can be used to detect field
239+
/// reversal of the incoming data.
240+
pub fn last_received_field(&self) -> Option<Field> {
241+
self.last_received_field
242+
}
243+
232244
/// Reset the state to that of an initially constructed object.
233245
pub fn reset(&mut self) {
234246
*self = Self::default();
@@ -307,6 +319,55 @@ impl Cea608Writer {
307319
}
308320
}
309321

322+
/// A CEA-608 caption identifier unique within a CEA-608 stream
323+
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
324+
pub enum Id {
325+
CC1,
326+
CC2,
327+
CC3,
328+
CC4,
329+
// TODO: add Text1/2
330+
}
331+
332+
impl Id {
333+
/// The [`Field`] that this [`Id`] is contained within
334+
pub fn field(&self) -> Field {
335+
match self {
336+
Self::CC1 | Self::CC2 => Field::ONE,
337+
Self::CC3 | Self::CC4 => Field::TWO,
338+
}
339+
}
340+
341+
/// The caption [`Channel`] that this [`Id`] references
342+
pub fn channel(&self) -> Channel {
343+
match self {
344+
Self::CC1 | Self::CC3 => Channel::ONE,
345+
Self::CC2 | Self::CC4 => Channel::TWO,
346+
}
347+
}
348+
349+
/// Construct an [`Id`] from a [`Field`] and [`Channel`]
350+
pub fn from_caption_field_channel(field: Field, channel: Channel) -> Self {
351+
match (field, channel) {
352+
(Field::ONE, Channel::ONE) => Self::CC1,
353+
(Field::ONE, Channel::TWO) => Self::CC2,
354+
(Field::TWO, Channel::ONE) => Self::CC3,
355+
(Field::TWO, Channel::TWO) => Self::CC4,
356+
}
357+
}
358+
359+
/// Construct an [`Id`] from its integer value in the range [1, 4]
360+
pub fn from_value(value: i8) -> Self {
361+
match value {
362+
1 => Self::CC1,
363+
2 => Self::CC2,
364+
3 => Self::CC3,
365+
4 => Self::CC4,
366+
_ => unreachable!(),
367+
}
368+
}
369+
}
370+
310371
#[cfg(test)]
311372
mod test {
312373
use self::tables::ControlCode;
@@ -319,17 +380,20 @@ mod test {
319380
test_init_log();
320381
let mut data = vec![];
321382
Code::Control(ControlCode::new(
322-
Channel(true),
383+
Field::ONE,
384+
Channel::ONE,
323385
tables::Control::EraseDisplayedMemory,
324386
))
325387
.write(&mut data)
326388
.unwrap();
327389
let mut state = Cea608State::default();
328390
assert_eq!(
329-
Ok(Some(Cea608::EraseDisplay(Channel(true)))),
391+
Ok(Some(Cea608::EraseDisplay(Channel::ONE))),
330392
state.decode([data[0], data[1]])
331393
);
394+
assert_eq!(state.last_received_field(), Some(Field::ONE));
332395
assert_eq!(Ok(None), state.decode([data[0], data[1]]));
396+
assert_eq!(state.last_received_field(), Some(Field::ONE));
333397
}
334398

335399
#[test]
@@ -338,13 +402,18 @@ mod test {
338402
let mut state = Cea608State::default();
339403

340404
let mut data = vec![];
341-
Code::Control(ControlCode::new(Channel::ONE, tables::Control::RollUp2))
342-
.write(&mut data)
343-
.unwrap();
405+
Code::Control(ControlCode::new(
406+
Field::ONE,
407+
Channel::ONE,
408+
tables::Control::RollUp2,
409+
))
410+
.write(&mut data)
411+
.unwrap();
344412
assert_eq!(
345413
Ok(Some(Cea608::NewMode(Channel::ONE, Mode::RollUp2))),
346414
state.decode([data[0], data[1]])
347415
);
416+
assert_eq!(state.last_received_field(), Some(Field::ONE));
348417

349418
let mut data = vec![];
350419
Code::LatinCapitalA.write(&mut data).unwrap();
@@ -357,15 +426,21 @@ mod test {
357426
}))),
358427
state.decode([data[0], 0x80])
359428
);
429+
assert_eq!(state.last_received_field(), Some(Field::ONE));
360430

361431
let mut data = vec![];
362-
Code::Control(ControlCode::new(Channel::TWO, tables::Control::RollUp2))
363-
.write(&mut data)
364-
.unwrap();
432+
Code::Control(ControlCode::new(
433+
Field::TWO,
434+
Channel::TWO,
435+
tables::Control::RollUp2,
436+
))
437+
.write(&mut data)
438+
.unwrap();
365439
assert_eq!(
366440
Ok(Some(Cea608::NewMode(Channel::TWO, Mode::RollUp2))),
367441
state.decode([data[0], data[1]])
368442
);
443+
assert_eq!(state.last_received_field(), Some(Field::TWO));
369444

370445
let mut data = vec![];
371446
Code::LatinCapitalA.write(&mut data).unwrap();
@@ -412,6 +487,7 @@ mod test {
412487
let mut writer = Cea608Writer::default();
413488
writer.push(Code::LatinLowerA);
414489
writer.push(Code::Control(ControlCode::new(
490+
Field::ONE,
415491
Channel::ONE,
416492
tables::Control::DegreeSign,
417493
)));
@@ -426,6 +502,7 @@ mod test {
426502
let mut writer = Cea608Writer::default();
427503
writer.push(Code::LatinLowerA);
428504
writer.push(Code::Control(ControlCode::new(
505+
Field::ONE,
429506
Channel::ONE,
430507
tables::Control::Tilde,
431508
)));
@@ -439,6 +516,7 @@ mod test {
439516
test_init_log();
440517
let mut writer = Cea608Writer::default();
441518
writer.push(Code::Control(ControlCode::new(
519+
Field::ONE,
442520
Channel::ONE,
443521
tables::Control::Tilde,
444522
)));
@@ -452,6 +530,7 @@ mod test {
452530
test_init_log();
453531
let mut writer = Cea608Writer::default();
454532
writer.push(Code::Control(ControlCode::new(
533+
Field::ONE,
455534
Channel::ONE,
456535
tables::Control::DegreeSign,
457536
)));

src/tables.rs

+95-4
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,33 @@ impl Channel {
4242
}
4343
}
4444

45+
/// The field that the control code references
46+
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
47+
pub struct Field(pub(crate) bool);
48+
49+
impl Field {
50+
/// Field 1
51+
pub const ONE: Field = Field(true);
52+
/// Field 2
53+
pub const TWO: Field = Field(false);
54+
55+
/// The numerical identifier of this field
56+
pub fn id(&self) -> u8 {
57+
if self.0 {
58+
1
59+
} else {
60+
2
61+
}
62+
}
63+
}
64+
4565
/// A control code
4666
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
4767
// must be ordered the same as the byte values
4868
// These codes start with 0x11 (channel 1, odd-parity: 0x91) or 0x19 (channel 2, odd-parity: 0x19)
4969
pub struct ControlCode {
70+
/// The field
71+
pub field: Option<Field>,
5072
/// The channel
5173
pub channel: Channel,
5274
/// The control code
@@ -55,15 +77,24 @@ pub struct ControlCode {
5577

5678
impl ControlCode {
5779
/// Construct a new [`ControlCode`]
58-
pub fn new(channel: Channel, control: Control) -> Self {
59-
Self { channel, control }
80+
pub fn new(field: Field, channel: Channel, control: Control) -> Self {
81+
Self {
82+
field: Some(field),
83+
channel,
84+
control,
85+
}
6086
}
6187

6288
/// The [`Channel`] for this [`ControlCode`]
6389
pub fn channel(&self) -> Channel {
6490
self.channel
6591
}
6692

93+
/// The [`Field`] for this [`ControlCode`]
94+
pub fn field(&self) -> Option<Field> {
95+
self.field
96+
}
97+
6798
/// The [`Control`] code for this [`ControlCode`]
6899
pub fn code(&self) -> Control {
69100
self.control
@@ -91,6 +122,9 @@ impl ControlCode {
91122
}
92123
}
93124
}
125+
if (0x20..=0x2f).contains(&data[1]) && data[0] == 0x14 && self.field == Some(Field::TWO) {
126+
data[0] |= 0x01;
127+
}
94128
if self.channel == Channel::TWO {
95129
data[0] |= 0x08;
96130
}
@@ -860,10 +894,24 @@ fn check_odd_parity(byte: u8) -> bool {
860894
fn parse_control_code(data: [u8; 2]) -> ControlCode {
861895
let channel = data[0] & 0x08;
862896
let underline = data[1] & 0x1 != 0;
897+
let mut byte0 = data[0] & !0x08;
898+
let field = if (0x20..=0x2f).contains(&data[1]) {
899+
match data[0] & !0x08 {
900+
0x14 => Some(Field::ONE),
901+
0x15 => {
902+
byte0 &= !0x01;
903+
Some(Field::TWO)
904+
}
905+
_ => None,
906+
}
907+
} else {
908+
None
909+
};
863910

864911
ControlCode {
912+
field,
865913
channel: Channel(channel == 0),
866-
control: match (data[0] & !0x08, data[1]) {
914+
control: match (byte0, data[1]) {
867915
(0x11, 0x20 | 0x21) => Control::MidRow(MidRow {
868916
color: MidRowColor::Color(Color::White),
869917
underline,
@@ -898,7 +946,7 @@ fn parse_control_code(data: [u8; 2]) -> ControlCode {
898946
}),
899947
(0x10..=0x19, 0x20..=0x3f) => {
900948
let idx = CONTROL_MAP_TABLE
901-
.binary_search_by_key(&[data[0] & !0x08, data[1]], |control_map| {
949+
.binary_search_by_key(&[byte0, data[1]], |control_map| {
902950
control_map.cea608_bytes
903951
});
904952
idx.map(|idx| CONTROL_MAP_TABLE[idx].control)
@@ -1130,6 +1178,7 @@ impl Code {
11301178
CONTROL_MAP_TABLE.iter().find_map(|control_map| {
11311179
if code_map.utf8 == Some(c) {
11321180
Some(Code::Control(ControlCode {
1181+
field: None,
11331182
channel,
11341183
control: control_map.control,
11351184
}))
@@ -1144,6 +1193,7 @@ impl Code {
11441193
/// Whether or not this code requires there to have a backspace prepended for correct display
11451194
pub fn needs_backspace(&self) -> bool {
11461195
let Code::Control(ControlCode {
1196+
field: _,
11471197
channel: _,
11481198
control,
11491199
}) = self
@@ -1317,6 +1367,7 @@ mod test {
13171367
for ty in tys {
13181368
for channel in [Channel::ONE, Channel::TWO] {
13191369
let preamble = Code::Control(ControlCode {
1370+
field: None,
13201371
channel,
13211372
control: Control::PreambleAddress(PreambleAddressCode {
13221373
row,
@@ -1353,6 +1404,7 @@ mod test {
13531404
for color in colors {
13541405
for channel in [Channel::ONE, Channel::TWO] {
13551406
let midrow = Code::Control(ControlCode {
1407+
field: None,
13561408
channel,
13571409
control: Control::MidRow(MidRow { underline, color }),
13581410
});
@@ -1366,4 +1418,43 @@ mod test {
13661418
}
13671419
}
13681420
}
1421+
1422+
#[test]
1423+
fn field2_control_to_from_bytes() {
1424+
let codes = [
1425+
Control::ResumeCaptionLoading,
1426+
Control::Backspace,
1427+
Control::AlarmOff,
1428+
Control::AlarmOn,
1429+
Control::DeleteToEndOfRow,
1430+
Control::RollUp2,
1431+
Control::RollUp3,
1432+
Control::RollUp4,
1433+
Control::FlashOn,
1434+
Control::ResumeDirectionCaptioning,
1435+
Control::TextRestart,
1436+
Control::ResumeTextDisplay,
1437+
Control::EraseDisplayedMemory,
1438+
Control::CarriageReturn,
1439+
Control::EraseNonDisplayedMemory,
1440+
Control::EndOfCaption,
1441+
];
1442+
for control in codes {
1443+
for field in [Field::ONE, Field::TWO] {
1444+
for channel in [Channel::ONE, Channel::TWO] {
1445+
let control = Code::Control(ControlCode {
1446+
field: Some(field),
1447+
channel,
1448+
control,
1449+
});
1450+
debug!("{control:?}");
1451+
let mut data = vec![];
1452+
control.write(&mut data).unwrap();
1453+
debug!("{data:x?}");
1454+
let parsed = Code::from_data([data[0], data[1]]).unwrap();
1455+
assert_eq!(control, parsed[0]);
1456+
}
1457+
}
1458+
}
1459+
}
13691460
}

0 commit comments

Comments
 (0)