@@ -154,6 +154,113 @@ impl Cea608 {
154
154
Self :: DeleteToEndOfRow ( chan) => * chan,
155
155
}
156
156
}
157
+
158
+ /// Convert into one or two [`Code`] values.
159
+ pub fn into_code ( & self , field : Field ) -> [ Code ; 2 ] {
160
+ match self {
161
+ Self :: Text ( text) => {
162
+ let mut ret = [ Code :: NUL , Code :: NUL ] ;
163
+ if let Some ( char1) = text. char1 {
164
+ ret[ 0 ] = Code :: from_char ( char1, text. channel ) . unwrap ( ) ;
165
+ }
166
+ if let Some ( char2) = text. char2 {
167
+ ret[ 1 ] = Code :: from_char ( char2, text. channel ) . unwrap ( ) ;
168
+ }
169
+ ret
170
+ }
171
+ Self :: NewMode ( chan, mode) => [
172
+ Code :: Control ( tables:: ControlCode {
173
+ field : Some ( field) ,
174
+ channel : * chan,
175
+ control : match mode {
176
+ Mode :: RollUp2 => tables:: Control :: RollUp2 ,
177
+ Mode :: RollUp3 => tables:: Control :: RollUp3 ,
178
+ Mode :: RollUp4 => tables:: Control :: RollUp4 ,
179
+ Mode :: PaintOn => tables:: Control :: ResumeDirectionCaptioning ,
180
+ Mode :: PopOn => tables:: Control :: ResumeCaptionLoading ,
181
+ } ,
182
+ } ) ,
183
+ Code :: NUL ,
184
+ ] ,
185
+ Self :: EraseDisplay ( chan) => [
186
+ Code :: Control ( tables:: ControlCode {
187
+ field : Some ( field) ,
188
+ channel : * chan,
189
+ control : tables:: Control :: EraseDisplayedMemory ,
190
+ } ) ,
191
+ Code :: NUL ,
192
+ ] ,
193
+ Self :: EraseNonDisplay ( chan) => [
194
+ Code :: Control ( tables:: ControlCode {
195
+ field : Some ( field) ,
196
+ channel : * chan,
197
+ control : tables:: Control :: EraseNonDisplayedMemory ,
198
+ } ) ,
199
+ Code :: NUL ,
200
+ ] ,
201
+ Self :: CarriageReturn ( chan) => [
202
+ Code :: Control ( tables:: ControlCode {
203
+ field : Some ( field) ,
204
+ channel : * chan,
205
+ control : tables:: Control :: CarriageReturn ,
206
+ } ) ,
207
+ Code :: NUL ,
208
+ ] ,
209
+ Self :: Backspace ( chan) => [
210
+ Code :: Control ( tables:: ControlCode {
211
+ field : Some ( field) ,
212
+ channel : * chan,
213
+ control : tables:: Control :: Backspace ,
214
+ } ) ,
215
+ Code :: NUL ,
216
+ ] ,
217
+ Self :: EndOfCaption ( chan) => [
218
+ Code :: Control ( tables:: ControlCode {
219
+ field : Some ( field) ,
220
+ channel : * chan,
221
+ control : tables:: Control :: EndOfCaption ,
222
+ } ) ,
223
+ Code :: NUL ,
224
+ ] ,
225
+ Self :: TabOffset ( chan, count) => [
226
+ Code :: Control ( tables:: ControlCode {
227
+ field : Some ( field) ,
228
+ channel : * chan,
229
+ control : match count {
230
+ 1 => tables:: Control :: TabOffset1 ,
231
+ 2 => tables:: Control :: TabOffset2 ,
232
+ 3 => tables:: Control :: TabOffset3 ,
233
+ _ => unreachable ! ( ) ,
234
+ } ,
235
+ } ) ,
236
+ Code :: NUL ,
237
+ ] ,
238
+ Self :: Preamble ( chan, preamble) => [
239
+ Code :: Control ( tables:: ControlCode {
240
+ field : Some ( field) ,
241
+ channel : * chan,
242
+ control : tables:: Control :: PreambleAddress ( * preamble) ,
243
+ } ) ,
244
+ Code :: NUL ,
245
+ ] ,
246
+ Self :: MidRowChange ( chan, midrow) => [
247
+ Code :: Control ( tables:: ControlCode {
248
+ field : Some ( field) ,
249
+ channel : * chan,
250
+ control : tables:: Control :: MidRow ( * midrow) ,
251
+ } ) ,
252
+ Code :: NUL ,
253
+ ] ,
254
+ Self :: DeleteToEndOfRow ( chan) => [
255
+ Code :: Control ( tables:: ControlCode {
256
+ field : Some ( field) ,
257
+ channel : * chan,
258
+ control : tables:: Control :: DeleteToEndOfRow ,
259
+ } ) ,
260
+ Code :: NUL ,
261
+ ] ,
262
+ }
263
+ }
157
264
}
158
265
159
266
/// Helper struct that has two purposes:
@@ -181,6 +288,7 @@ impl Cea608State {
181
288
}
182
289
}
183
290
self . last_data = Some ( data) ;
291
+ trace ! ( "decoded into codes {code:x?}" ) ;
184
292
185
293
// TODO: handle xds and text mode
186
294
@@ -278,43 +386,51 @@ impl Cea608Writer {
278
386
let mut prev = None :: < Code > ;
279
387
280
388
if let Some ( code) = self . pending_code . take ( ) {
389
+ trace ! ( "returning pending code {code:?}" ) ;
281
390
code. write_into ( & mut ret) ;
282
391
return ret;
283
392
}
284
393
285
394
while let Some ( code) = self . pending . pop_back ( ) {
286
395
if let Some ( prev) = prev {
396
+ trace ! ( "have prev {prev:?}" ) ;
287
397
if code. byte_len ( ) == 1 {
288
398
let mut data = [ 0 ; 2 ] ;
289
399
prev. write_into ( & mut ret) ;
290
400
code. write_into ( & mut data) ;
291
401
ret[ 1 ] = data[ 0 ] ;
402
+ trace ! ( "have 1 byte code {code:?}, returning {ret:x?}" ) ;
292
403
return ret;
293
404
} else if code. needs_backspace ( ) {
294
405
self . pending_code = Some ( code) ;
295
406
let mut data = [ 0 ; 2 ] ;
296
407
prev. write_into ( & mut ret) ;
297
408
Code :: Space . write_into ( & mut data) ;
298
409
ret[ 1 ] = data[ 0 ] ;
410
+ trace ! ( "have backspace needing code {code:?} stored as pending, pushing space with previous code {prev:?}" ) ;
299
411
return ret;
300
412
} else {
301
413
self . pending_code = Some ( code) ;
302
414
prev. write_into ( & mut ret) ;
415
+ trace ! ( "have two byte code {code:?} stored as pending, pushing space" ) ;
303
416
return ret;
304
417
}
305
418
} else if code. needs_backspace ( ) {
306
419
// all back space needing codes are 2 byte commands
307
420
self . pending_code = Some ( code) ;
308
421
Code :: Space . write_into ( & mut ret) ;
422
+ trace ! ( "have backspace needing code {code:?} stored as pending, pushing space" ) ;
309
423
return ret;
310
424
} else if code. byte_len ( ) == 1 {
311
425
prev = Some ( code) ;
312
426
} else {
427
+ trace ! ( "have standalone 2 byte code {code:?}" ) ;
313
428
code. write_into ( & mut ret) ;
314
429
return ret;
315
430
}
316
431
}
317
432
if let Some ( prev) = prev {
433
+ trace ! ( "have no more pending codes, writing prev {prev:?}" ) ;
318
434
prev. write_into ( & mut ret) ;
319
435
}
320
436
ret
@@ -553,6 +669,95 @@ mod test {
553
669
assert_eq ! ( writer. pop( ) , [ 0x91 , 0x31 ] ) ;
554
670
assert_eq ! ( writer. pop( ) , [ 0x80 , 0x80 ] ) ;
555
671
}
672
+
673
+ #[ test]
674
+ fn state_into_writer ( ) {
675
+ test_init_log ( ) ;
676
+ let stream = [ [ 0x20 , 0x80 ] , [ 0x13 , 0x2f ] , [ 0x80 , 0x80 ] ] ;
677
+ let mut state = Cea608State :: default ( ) ;
678
+ let mut writer = Cea608Writer :: default ( ) ;
679
+ for pair in stream {
680
+ let Some ( cea608) = state. decode ( pair) . unwrap ( ) else {
681
+ continue ;
682
+ } ;
683
+ for code in cea608. into_code ( Field :: ONE ) {
684
+ writer. push ( code) ;
685
+ }
686
+ }
687
+ assert_eq ! ( writer. pop( ) , [ 0x20 , 0x80 ] ) ;
688
+ assert_eq ! ( writer. pop( ) , [ 0x13 , 0x2f ] ) ;
689
+ assert_eq ! ( writer. pop( ) , [ 0x80 , 0x80 ] ) ;
690
+ }
691
+
692
+ #[ test]
693
+ fn cea608_to_from_code ( ) {
694
+ test_init_log ( ) ;
695
+
696
+ let controls = [
697
+ tables:: Control :: ResumeCaptionLoading ,
698
+ tables:: Control :: RollUp2 ,
699
+ tables:: Control :: RollUp3 ,
700
+ tables:: Control :: RollUp4 ,
701
+ tables:: Control :: EndOfCaption ,
702
+ tables:: Control :: ResumeDirectionCaptioning ,
703
+ tables:: Control :: tab_offset ( 1 ) . unwrap ( ) ,
704
+ tables:: Control :: tab_offset ( 2 ) . unwrap ( ) ,
705
+ tables:: Control :: tab_offset ( 3 ) . unwrap ( ) ,
706
+ tables:: Control :: PreambleAddress ( PreambleAddressCode :: new (
707
+ 3 ,
708
+ true ,
709
+ tables:: PreambleType :: Indent4 ,
710
+ ) ) ,
711
+ tables:: Control :: EraseDisplayedMemory ,
712
+ tables:: Control :: EraseNonDisplayedMemory ,
713
+ tables:: Control :: CarriageReturn ,
714
+ tables:: Control :: Backspace ,
715
+ tables:: Control :: DeleteToEndOfRow ,
716
+ ] ;
717
+ let controls_with_preceding_overwritten_char = [ tables:: Control :: MidRow (
718
+ MidRow :: new_color ( tables:: Color :: Green , true ) ,
719
+ ) ] ;
720
+
721
+ let codes = [ Code :: PercentSign , Code :: LatinLowerA ] ;
722
+
723
+ let mut writer = Cea608Writer :: default ( ) ;
724
+
725
+ let mut state = Cea608State :: default ( ) ;
726
+
727
+ for field in [ Field :: ONE , Field :: TWO ] {
728
+ for channel in [ Channel :: ONE , Channel :: TWO ] {
729
+ for control in controls {
730
+ let code = Code :: Control ( ControlCode {
731
+ field : Some ( field) ,
732
+ channel,
733
+ control,
734
+ } ) ;
735
+ writer. push ( code) ;
736
+ let cea608 = state. decode ( writer. pop ( ) ) . unwrap ( ) . unwrap ( ) ;
737
+ assert_eq ! ( cea608. into_code( field) [ 0 ] , code) ;
738
+ }
739
+ for control in controls_with_preceding_overwritten_char {
740
+ let code = Code :: Control ( ControlCode {
741
+ field : Some ( field) ,
742
+ channel,
743
+ control,
744
+ } ) ;
745
+ writer. push ( code) ;
746
+ writer. pop ( ) ; // eat the preceding char
747
+ let cea608 = state. decode ( writer. pop ( ) ) . unwrap ( ) . unwrap ( ) ;
748
+ assert_eq ! ( cea608. into_code( field) [ 0 ] , code) ;
749
+ }
750
+ }
751
+ }
752
+
753
+ for code in codes {
754
+ debug ! ( "pushing {code:?}" ) ;
755
+ writer. push ( code) ;
756
+ let data = writer. pop ( ) ;
757
+ let cea608 = state. decode ( data) . unwrap ( ) . unwrap ( ) ;
758
+ assert_eq ! ( cea608. into_code( Field :: ONE ) [ 0 ] , code) ;
759
+ }
760
+ }
556
761
}
557
762
558
763
#[ cfg( test) ]
0 commit comments