1use crate::error::{Error, Result};
23use crate::objects;
24use crate::tag::ApduTag;
25use alloc::vec::Vec;
26use dvb_common::{Parse, Serialize};
27
28pub mod tag {
30 use crate::tag::ApduTag;
31 pub const SERVICE_LIST_REQ: ApduTag = ApduTag::from_bytes(0x9F, 0x80, 0x00);
33 pub const SERVICE_LIST_ACK: ApduTag = ApduTag::from_bytes(0x9F, 0x80, 0x01);
35 pub const SERVICE_LIST_VERSION_REQ: ApduTag = ApduTag::from_bytes(0x9F, 0x80, 0x02);
37 pub const SERVICE_LIST_VERSION_ACK: ApduTag = ApduTag::from_bytes(0x9F, 0x80, 0x03);
39 pub const SERVICE_LIST_CHANGED: ApduTag = ApduTag::from_bytes(0x9F, 0x80, 0x04);
41 pub const SERVICE_DESC_REQ: ApduTag = ApduTag::from_bytes(0x9F, 0x80, 0x05);
43 pub const SERVICE_DESC_ACK: ApduTag = ApduTag::from_bytes(0x9F, 0x80, 0x06);
45 pub const GET_SERVICE_REQ: ApduTag = ApduTag::from_bytes(0x9F, 0x80, 0x07);
47 pub const GET_SERVICE_ACK: ApduTag = ApduTag::from_bytes(0x9F, 0x80, 0x08);
49}
50
51#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
53#[cfg_attr(feature = "serde", derive(serde::Serialize))]
54pub struct ServiceReference {
55 pub original_network_id: u16,
57 pub service_id: u16,
59}
60
61#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
63#[cfg_attr(feature = "serde", derive(serde::Serialize))]
64pub struct ServiceListReq;
65
66#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
68#[cfg_attr(feature = "serde", derive(serde::Serialize))]
69pub struct ServiceListVersionReq;
70
71#[derive(Debug, Clone, PartialEq, Eq, Default)]
73#[cfg_attr(feature = "serde", derive(serde::Serialize))]
74pub struct ServiceListAck {
75 pub version_number: u8,
77 pub services: Vec<ServiceReference>,
79}
80
81#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
83#[cfg_attr(feature = "serde", derive(serde::Serialize))]
84pub struct ServiceListVersionAck {
85 pub version_number: u8,
87}
88
89#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
91#[cfg_attr(feature = "serde", derive(serde::Serialize))]
92pub struct ServiceListChanged {
93 pub version_number: u8,
95}
96
97#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
99#[cfg_attr(feature = "serde", derive(serde::Serialize))]
100pub struct ServiceDescReq {
101 pub service: ServiceReference,
103}
104
105#[derive(Debug, Clone, PartialEq, Eq)]
108#[cfg_attr(feature = "serde", derive(serde::Serialize))]
109pub struct ServiceDescAck<'a> {
110 pub service: ServiceReference,
112 pub eit_schedule_flag: bool,
114 pub eit_present_following_flag: bool,
116 pub running_status: u8,
119 pub free_ca_mode: bool,
121 #[cfg_attr(feature = "serde", serde(borrow, with = "crate::objects::bytes_serde"))]
124 pub descriptors: &'a [u8],
125}
126
127#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
131#[cfg_attr(feature = "serde", derive(serde::Serialize))]
132pub struct GetServiceReq {
133 pub service: Option<ServiceReference>,
135}
136
137#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
139#[cfg_attr(feature = "serde", derive(serde::Serialize))]
140pub struct GetServiceAck {
141 pub service: ServiceReference,
143 pub service_terminated: bool,
146 pub service_not_available: bool,
148 pub ca_service_flag: bool,
150 pub actual_service: u16,
153}
154
155macro_rules! empty_object {
158 ($ty:ty, $tag:expr, $what:literal) => {
159 impl<'a> Parse<'a> for $ty {
160 type Error = Error;
161 fn parse(bytes: &'a [u8]) -> Result<Self> {
162 objects::parse_empty_apdu(bytes, $tag, $what)?;
163 Ok(Self)
164 }
165 }
166 impl Serialize for $ty {
167 type Error = Error;
168 fn serialized_len(&self) -> usize {
169 objects::empty_apdu_len()
170 }
171 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
172 objects::serialize_empty_apdu($tag, buf)
173 }
174 }
175 };
176}
177
178empty_object!(ServiceListReq, tag::SERVICE_LIST_REQ, "ServiceListReq");
179empty_object!(
180 ServiceListVersionReq,
181 tag::SERVICE_LIST_VERSION_REQ,
182 "ServiceListVersionReq"
183);
184
185macro_rules! version_byte_object {
188 ($ty:ty, $tag:expr, $what:literal) => {
189 impl<'a> Parse<'a> for $ty {
190 type Error = Error;
191 fn parse(bytes: &'a [u8]) -> Result<Self> {
192 let body = objects::parse_apdu_header(bytes, $tag, $what)?;
193 if body.is_empty() {
194 return Err(Error::BufferTooShort {
195 need: 1,
196 have: 0,
197 what: $what,
198 });
199 }
200 Ok(Self {
201 version_number: body[0],
202 })
203 }
204 }
205 impl Serialize for $ty {
206 type Error = Error;
207 fn serialized_len(&self) -> usize {
208 objects::apdu_len(1)
209 }
210 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
211 let pos = objects::write_apdu_header($tag, 1, buf)?;
212 buf[pos] = self.version_number;
213 Ok(pos + 1)
214 }
215 }
216 };
217}
218
219version_byte_object!(
220 ServiceListVersionAck,
221 tag::SERVICE_LIST_VERSION_ACK,
222 "ServiceListVersionAck"
223);
224version_byte_object!(
225 ServiceListChanged,
226 tag::SERVICE_LIST_CHANGED,
227 "ServiceListChanged"
228);
229
230const SERVICE_REF_LEN: usize = 4;
234const SERVICE_LIST_ACK_PREFIX: usize = 3;
236
237impl<'a> Parse<'a> for ServiceListAck {
238 type Error = Error;
239 fn parse(bytes: &'a [u8]) -> Result<Self> {
240 let body = objects::parse_apdu_header(bytes, tag::SERVICE_LIST_ACK, "ServiceListAck")?;
241 if body.len() < SERVICE_LIST_ACK_PREFIX {
242 return Err(Error::BufferTooShort {
243 need: SERVICE_LIST_ACK_PREFIX,
244 have: body.len(),
245 what: "ServiceListAck",
246 });
247 }
248 let version_number = body[0];
249 let count = u16::from_be_bytes([body[1], body[2]]) as usize;
250 let list = &body[SERVICE_LIST_ACK_PREFIX..];
251 if list.len() < count * SERVICE_REF_LEN {
252 return Err(Error::LengthMismatch {
253 what: "ServiceListAck services",
254 declared: count * SERVICE_REF_LEN,
255 actual: list.len(),
256 });
257 }
258 let mut services = Vec::with_capacity(count);
259 for chunk in list[..count * SERVICE_REF_LEN].chunks_exact(SERVICE_REF_LEN) {
260 services.push(ServiceReference {
261 original_network_id: u16::from_be_bytes([chunk[0], chunk[1]]),
262 service_id: u16::from_be_bytes([chunk[2], chunk[3]]),
263 });
264 }
265 Ok(Self {
266 version_number,
267 services,
268 })
269 }
270}
271impl Serialize for ServiceListAck {
272 type Error = Error;
273 fn serialized_len(&self) -> usize {
274 objects::apdu_len(SERVICE_LIST_ACK_PREFIX + self.services.len() * SERVICE_REF_LEN)
275 }
276 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
277 if self.services.len() > u16::MAX as usize {
278 return Err(Error::InvalidObject {
279 what: "ServiceListAck",
280 reason: "more than 65535 services",
281 });
282 }
283 let body_len = SERVICE_LIST_ACK_PREFIX + self.services.len() * SERVICE_REF_LEN;
284 let mut pos = objects::write_apdu_header(tag::SERVICE_LIST_ACK, body_len, buf)?;
285 buf[pos] = self.version_number;
286 buf[pos + 1..pos + 3].copy_from_slice(&(self.services.len() as u16).to_be_bytes());
287 pos += SERVICE_LIST_ACK_PREFIX;
288 for s in &self.services {
289 buf[pos..pos + 2].copy_from_slice(&s.original_network_id.to_be_bytes());
290 buf[pos + 2..pos + 4].copy_from_slice(&s.service_id.to_be_bytes());
291 pos += SERVICE_REF_LEN;
292 }
293 Ok(pos)
294 }
295}
296
297impl<'a> Parse<'a> for ServiceDescReq {
300 type Error = Error;
301 fn parse(bytes: &'a [u8]) -> Result<Self> {
302 let body = objects::parse_apdu_header(bytes, tag::SERVICE_DESC_REQ, "ServiceDescReq")?;
303 if body.len() < SERVICE_REF_LEN {
304 return Err(Error::BufferTooShort {
305 need: SERVICE_REF_LEN,
306 have: body.len(),
307 what: "ServiceDescReq",
308 });
309 }
310 Ok(Self {
311 service: ServiceReference {
312 original_network_id: u16::from_be_bytes([body[0], body[1]]),
313 service_id: u16::from_be_bytes([body[2], body[3]]),
314 },
315 })
316 }
317}
318impl Serialize for ServiceDescReq {
319 type Error = Error;
320 fn serialized_len(&self) -> usize {
321 objects::apdu_len(SERVICE_REF_LEN)
322 }
323 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
324 let pos = objects::write_apdu_header(tag::SERVICE_DESC_REQ, SERVICE_REF_LEN, buf)?;
325 buf[pos..pos + 2].copy_from_slice(&self.service.original_network_id.to_be_bytes());
326 buf[pos + 2..pos + 4].copy_from_slice(&self.service.service_id.to_be_bytes());
327 Ok(pos + SERVICE_REF_LEN)
328 }
329}
330
331const SERVICE_DESC_ACK_PREFIX: usize = SERVICE_REF_LEN + 3;
335
336impl<'a> Parse<'a> for ServiceDescAck<'a> {
337 type Error = Error;
338 fn parse(bytes: &'a [u8]) -> Result<Self> {
339 let body = objects::parse_apdu_header(bytes, tag::SERVICE_DESC_ACK, "ServiceDescAck")?;
340 if body.len() < SERVICE_DESC_ACK_PREFIX {
341 return Err(Error::BufferTooShort {
342 need: SERVICE_DESC_ACK_PREFIX,
343 have: body.len(),
344 what: "ServiceDescAck",
345 });
346 }
347 let flags = body[4];
349 let b5 = body[5];
351 let b6 = body[6];
352 let running_status = (b5 >> 5) & 0x07;
353 let free_ca_mode = (b5 & 0x10) != 0;
354 let loop_len = ((u16::from(b5 & 0x0F) << 8) | u16::from(b6)) as usize;
355 let desc_start = SERVICE_DESC_ACK_PREFIX;
356 let desc_end = desc_start + loop_len;
357 if body.len() < desc_end {
358 return Err(Error::LengthMismatch {
359 what: "ServiceDescAck descriptors",
360 declared: loop_len,
361 actual: body.len() - desc_start,
362 });
363 }
364 Ok(Self {
365 service: ServiceReference {
366 original_network_id: u16::from_be_bytes([body[0], body[1]]),
367 service_id: u16::from_be_bytes([body[2], body[3]]),
368 },
369 eit_schedule_flag: (flags & 0x02) != 0,
370 eit_present_following_flag: (flags & 0x01) != 0,
371 running_status,
372 free_ca_mode,
373 descriptors: &body[desc_start..desc_end],
374 })
375 }
376}
377impl Serialize for ServiceDescAck<'_> {
378 type Error = Error;
379 fn serialized_len(&self) -> usize {
380 objects::apdu_len(SERVICE_DESC_ACK_PREFIX + self.descriptors.len())
381 }
382 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
383 if self.descriptors.len() > 0x0FFF {
384 return Err(Error::InvalidObject {
385 what: "ServiceDescAck",
386 reason: "descriptors loop longer than 4095 bytes",
387 });
388 }
389 let body_len = SERVICE_DESC_ACK_PREFIX + self.descriptors.len();
390 let mut pos = objects::write_apdu_header(tag::SERVICE_DESC_ACK, body_len, buf)?;
391 buf[pos..pos + 2].copy_from_slice(&self.service.original_network_id.to_be_bytes());
392 buf[pos + 2..pos + 4].copy_from_slice(&self.service.service_id.to_be_bytes());
393 buf[pos + 4] = 0xFC
395 | (u8::from(self.eit_schedule_flag) << 1)
396 | u8::from(self.eit_present_following_flag);
397 let loop_len = self.descriptors.len() as u16;
398 buf[pos + 5] = ((self.running_status & 0x07) << 5)
400 | (u8::from(self.free_ca_mode) << 4)
401 | ((loop_len >> 8) as u8 & 0x0F);
402 buf[pos + 6] = loop_len as u8;
403 pos += SERVICE_DESC_ACK_PREFIX;
404 buf[pos..pos + self.descriptors.len()].copy_from_slice(self.descriptors);
405 Ok(pos + self.descriptors.len())
406 }
407}
408
409impl<'a> Parse<'a> for GetServiceReq {
412 type Error = Error;
413 fn parse(bytes: &'a [u8]) -> Result<Self> {
414 let body = objects::parse_apdu_header(bytes, tag::GET_SERVICE_REQ, "GetServiceReq")?;
415 let service = if body.is_empty() {
416 None
417 } else {
418 if body.len() < SERVICE_REF_LEN {
419 return Err(Error::BufferTooShort {
420 need: SERVICE_REF_LEN,
421 have: body.len(),
422 what: "GetServiceReq",
423 });
424 }
425 Some(ServiceReference {
426 original_network_id: u16::from_be_bytes([body[0], body[1]]),
427 service_id: u16::from_be_bytes([body[2], body[3]]),
428 })
429 };
430 Ok(Self { service })
431 }
432}
433impl Serialize for GetServiceReq {
434 type Error = Error;
435 fn serialized_len(&self) -> usize {
436 objects::apdu_len(if self.service.is_some() {
437 SERVICE_REF_LEN
438 } else {
439 0
440 })
441 }
442 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
443 match self.service {
444 None => objects::write_apdu_header(tag::GET_SERVICE_REQ, 0, buf),
445 Some(s) => {
446 let pos = objects::write_apdu_header(tag::GET_SERVICE_REQ, SERVICE_REF_LEN, buf)?;
447 buf[pos..pos + 2].copy_from_slice(&s.original_network_id.to_be_bytes());
448 buf[pos + 2..pos + 4].copy_from_slice(&s.service_id.to_be_bytes());
449 Ok(pos + SERVICE_REF_LEN)
450 }
451 }
452 }
453}
454
455const GET_SERVICE_ACK_BODY: usize = SERVICE_REF_LEN + 1 + 2;
459
460impl<'a> Parse<'a> for GetServiceAck {
461 type Error = Error;
462 fn parse(bytes: &'a [u8]) -> Result<Self> {
463 let body = objects::parse_apdu_header(bytes, tag::GET_SERVICE_ACK, "GetServiceAck")?;
464 if body.len() < GET_SERVICE_ACK_BODY {
465 return Err(Error::BufferTooShort {
466 need: GET_SERVICE_ACK_BODY,
467 have: body.len(),
468 what: "GetServiceAck",
469 });
470 }
471 let flags = body[4];
473 Ok(Self {
474 service: ServiceReference {
475 original_network_id: u16::from_be_bytes([body[0], body[1]]),
476 service_id: u16::from_be_bytes([body[2], body[3]]),
477 },
478 service_terminated: (flags & 0x04) != 0,
479 service_not_available: (flags & 0x02) != 0,
480 ca_service_flag: (flags & 0x01) != 0,
481 actual_service: u16::from_be_bytes([body[5], body[6]]),
482 })
483 }
484}
485impl Serialize for GetServiceAck {
486 type Error = Error;
487 fn serialized_len(&self) -> usize {
488 objects::apdu_len(GET_SERVICE_ACK_BODY)
489 }
490 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
491 let pos = objects::write_apdu_header(tag::GET_SERVICE_ACK, GET_SERVICE_ACK_BODY, buf)?;
492 buf[pos..pos + 2].copy_from_slice(&self.service.original_network_id.to_be_bytes());
493 buf[pos + 2..pos + 4].copy_from_slice(&self.service.service_id.to_be_bytes());
494 buf[pos + 4] = (u8::from(self.service_terminated) << 2)
496 | (u8::from(self.service_not_available) << 1)
497 | u8::from(self.ca_service_flag);
498 buf[pos + 5..pos + 7].copy_from_slice(&self.actual_service.to_be_bytes());
499 Ok(pos + GET_SERVICE_ACK_BODY)
500 }
501}
502
503#[derive(Debug, Clone, PartialEq, Eq)]
505#[cfg_attr(feature = "serde", derive(serde::Serialize))]
506#[non_exhaustive]
507pub enum ServiceGatewayApdu<'a> {
508 ServiceListReq(ServiceListReq),
510 ServiceListAck(ServiceListAck),
512 ServiceListVersionReq(ServiceListVersionReq),
514 ServiceListVersionAck(ServiceListVersionAck),
516 ServiceListChanged(ServiceListChanged),
518 ServiceDescReq(ServiceDescReq),
520 ServiceDescAck(ServiceDescAck<'a>),
522 GetServiceReq(GetServiceReq),
524 GetServiceAck(GetServiceAck),
526}
527
528impl<'a> ServiceGatewayApdu<'a> {
529 pub fn parse(body: &'a [u8]) -> Result<Self> {
531 if body.len() < 3 {
532 return Err(Error::BufferTooShort {
533 need: 3,
534 have: body.len(),
535 what: "service_gateway apdu_tag",
536 });
537 }
538 let t = ApduTag::from_bytes(body[0], body[1], body[2]);
539 match t {
540 tag::SERVICE_LIST_REQ => Ok(Self::ServiceListReq(ServiceListReq::parse(body)?)),
541 tag::SERVICE_LIST_ACK => Ok(Self::ServiceListAck(ServiceListAck::parse(body)?)),
542 tag::SERVICE_LIST_VERSION_REQ => Ok(Self::ServiceListVersionReq(
543 ServiceListVersionReq::parse(body)?,
544 )),
545 tag::SERVICE_LIST_VERSION_ACK => Ok(Self::ServiceListVersionAck(
546 ServiceListVersionAck::parse(body)?,
547 )),
548 tag::SERVICE_LIST_CHANGED => {
549 Ok(Self::ServiceListChanged(ServiceListChanged::parse(body)?))
550 }
551 tag::SERVICE_DESC_REQ => Ok(Self::ServiceDescReq(ServiceDescReq::parse(body)?)),
552 tag::SERVICE_DESC_ACK => Ok(Self::ServiceDescAck(ServiceDescAck::parse(body)?)),
553 tag::GET_SERVICE_REQ => Ok(Self::GetServiceReq(GetServiceReq::parse(body)?)),
554 tag::GET_SERVICE_ACK => Ok(Self::GetServiceAck(GetServiceAck::parse(body)?)),
555 _ => Err(Error::UnexpectedApduTag {
556 got: t.as_u24(),
557 expected: tag::SERVICE_LIST_REQ.as_u24(),
558 what: "service_gateway",
559 }),
560 }
561 }
562}
563
564impl Serialize for ServiceGatewayApdu<'_> {
565 type Error = Error;
566 fn serialized_len(&self) -> usize {
567 match self {
568 Self::ServiceListReq(o) => o.serialized_len(),
569 Self::ServiceListAck(o) => o.serialized_len(),
570 Self::ServiceListVersionReq(o) => o.serialized_len(),
571 Self::ServiceListVersionAck(o) => o.serialized_len(),
572 Self::ServiceListChanged(o) => o.serialized_len(),
573 Self::ServiceDescReq(o) => o.serialized_len(),
574 Self::ServiceDescAck(o) => o.serialized_len(),
575 Self::GetServiceReq(o) => o.serialized_len(),
576 Self::GetServiceAck(o) => o.serialized_len(),
577 }
578 }
579 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
580 match self {
581 Self::ServiceListReq(o) => o.serialize_into(buf),
582 Self::ServiceListAck(o) => o.serialize_into(buf),
583 Self::ServiceListVersionReq(o) => o.serialize_into(buf),
584 Self::ServiceListVersionAck(o) => o.serialize_into(buf),
585 Self::ServiceListChanged(o) => o.serialize_into(buf),
586 Self::ServiceDescReq(o) => o.serialize_into(buf),
587 Self::ServiceDescAck(o) => o.serialize_into(buf),
588 Self::GetServiceReq(o) => o.serialize_into(buf),
589 Self::GetServiceAck(o) => o.serialize_into(buf),
590 }
591 }
592}
593
594#[cfg(test)]
595mod tests {
596 use super::*;
597
598 #[test]
599 fn header_only_objects_round_trip() {
600 assert_eq!(ServiceListReq.to_bytes(), [0x9F, 0x80, 0x00, 0x00]);
601 assert_eq!(ServiceListVersionReq.to_bytes(), [0x9F, 0x80, 0x02, 0x00]);
602 assert_eq!(
603 ServiceListReq::parse(&[0x9F, 0x80, 0x00, 0x00]).unwrap(),
604 ServiceListReq
605 );
606 }
607
608 #[test]
609 fn service_list_ack_multi_round_trips_and_bites() {
610 let ack = ServiceListAck {
611 version_number: 0x07,
612 services: alloc::vec![
613 ServiceReference {
614 original_network_id: 0x0001,
615 service_id: 0x0064,
616 },
617 ServiceReference {
618 original_network_id: 0x0001,
619 service_id: 0x0065,
620 },
621 ],
622 };
623 let bytes = ack.to_bytes();
624 assert_eq!(
626 bytes,
627 [
628 0x9F, 0x80, 0x01, 0x0B, 0x07, 0x00, 0x02, 0x00, 0x01, 0x00, 0x64, 0x00, 0x01, 0x00,
629 0x65
630 ]
631 );
632 assert_eq!(ServiceListAck::parse(&bytes).unwrap(), ack);
633 let mut other = ack.clone();
634 other.services[1].service_id = 0x0066;
635 assert_ne!(bytes, other.to_bytes());
636 }
637
638 #[test]
639 fn service_list_ack_empty_round_trips() {
640 let ack = ServiceListAck {
641 version_number: 0x02,
642 services: alloc::vec![],
643 };
644 let bytes = ack.to_bytes();
645 assert_eq!(bytes, [0x9F, 0x80, 0x01, 0x03, 0x02, 0x00, 0x00]);
646 assert_eq!(ServiceListAck::parse(&bytes).unwrap(), ack);
647 }
648
649 #[test]
650 fn version_ack_and_changed_round_trip_and_bite() {
651 let v = ServiceListVersionAck { version_number: 9 };
652 let bytes = v.to_bytes();
653 assert_eq!(bytes, [0x9F, 0x80, 0x03, 0x01, 0x09]);
654 assert_eq!(ServiceListVersionAck::parse(&bytes).unwrap(), v);
655 assert_ne!(
656 bytes,
657 ServiceListVersionAck { version_number: 10 }.to_bytes()
658 );
659
660 let c = ServiceListChanged { version_number: 3 };
661 let cbytes = c.to_bytes();
662 assert_eq!(cbytes, [0x9F, 0x80, 0x04, 0x01, 0x03]);
663 assert_eq!(ServiceListChanged::parse(&cbytes).unwrap(), c);
664 }
665
666 #[test]
667 fn service_desc_req_round_trips_and_bites() {
668 let r = ServiceDescReq {
669 service: ServiceReference {
670 original_network_id: 0x1234,
671 service_id: 0x5678,
672 },
673 };
674 let bytes = r.to_bytes();
675 assert_eq!(bytes, [0x9F, 0x80, 0x05, 0x04, 0x12, 0x34, 0x56, 0x78]);
676 assert_eq!(ServiceDescReq::parse(&bytes).unwrap(), r);
677 let mut other = r;
678 other.service.service_id = 0x5679;
679 assert_ne!(bytes, other.to_bytes());
680 }
681
682 #[test]
683 fn service_desc_ack_round_trips_and_bites() {
684 let desc = [0x48, 0x02, 0xAA, 0xBB, 0x52, 0x01, 0x03];
686 let ack = ServiceDescAck {
687 service: ServiceReference {
688 original_network_id: 0x0001,
689 service_id: 0x0064,
690 },
691 eit_schedule_flag: true,
692 eit_present_following_flag: false,
693 running_status: 4, free_ca_mode: true,
695 descriptors: &desc,
696 };
697 let bytes = ack.to_bytes();
698 assert_eq!(
703 bytes,
704 [
705 0x9F, 0x80, 0x06, 0x0E, 0x00, 0x01, 0x00, 0x64, 0xFE, 0x90, 0x07, 0x48, 0x02, 0xAA,
706 0xBB, 0x52, 0x01, 0x03
707 ]
708 );
709 let parsed = ServiceDescAck::parse(&bytes).unwrap();
710 assert_eq!(parsed, ack);
711 assert_eq!(parsed.running_status, 4);
712 assert!(parsed.eit_schedule_flag);
713 assert!(!parsed.eit_present_following_flag);
714 assert!(parsed.free_ca_mode);
715 let mut other = ack.clone();
716 other.running_status = 1;
717 assert_ne!(bytes, other.to_bytes());
718 }
719
720 #[test]
721 fn service_desc_ack_empty_loop() {
722 let ack = ServiceDescAck {
723 service: ServiceReference {
724 original_network_id: 0xAAAA,
725 service_id: 0xBBBB,
726 },
727 eit_schedule_flag: false,
728 eit_present_following_flag: true,
729 running_status: 0,
730 free_ca_mode: false,
731 descriptors: &[],
732 };
733 let bytes = ack.to_bytes();
734 assert_eq!(
736 bytes,
737 [0x9F, 0x80, 0x06, 0x07, 0xAA, 0xAA, 0xBB, 0xBB, 0xFD, 0x00, 0x00]
738 );
739 assert_eq!(ServiceDescAck::parse(&bytes).unwrap(), ack);
740 }
741
742 #[test]
743 fn get_service_req_with_and_without_ref() {
744 let r = GetServiceReq {
745 service: Some(ServiceReference {
746 original_network_id: 0x0001,
747 service_id: 0x0064,
748 }),
749 };
750 let bytes = r.to_bytes();
751 assert_eq!(bytes, [0x9F, 0x80, 0x07, 0x04, 0x00, 0x01, 0x00, 0x64]);
752 assert_eq!(GetServiceReq::parse(&bytes).unwrap(), r);
753
754 let disconnect = GetServiceReq { service: None };
755 let dbytes = disconnect.to_bytes();
756 assert_eq!(dbytes, [0x9F, 0x80, 0x07, 0x00]);
757 assert_eq!(GetServiceReq::parse(&dbytes).unwrap(), disconnect);
758 assert_ne!(bytes, dbytes);
759 }
760
761 #[test]
762 fn get_service_ack_round_trips_and_bites() {
763 let ack = GetServiceAck {
764 service: ServiceReference {
765 original_network_id: 0x0001,
766 service_id: 0x0064,
767 },
768 service_terminated: false,
769 service_not_available: false,
770 ca_service_flag: true,
771 actual_service: 0x0064,
772 };
773 let bytes = ack.to_bytes();
774 assert_eq!(
776 bytes,
777 [0x9F, 0x80, 0x08, 0x07, 0x00, 0x01, 0x00, 0x64, 0x01, 0x00, 0x64]
778 );
779 assert_eq!(GetServiceAck::parse(&bytes).unwrap(), ack);
780 let mut other = ack;
782 other.ca_service_flag = false;
783 other.service_not_available = true;
784 other.actual_service = 0;
785 assert_ne!(bytes, other.to_bytes());
786 assert_eq!(other.to_bytes()[8], 0x02);
787 }
788
789 #[test]
790 fn dispatch_routes_each_tag() {
791 let req = ServiceListReq.to_bytes();
792 assert!(matches!(
793 ServiceGatewayApdu::parse(&req).unwrap(),
794 ServiceGatewayApdu::ServiceListReq(_)
795 ));
796 let gs = GetServiceAck {
797 service: ServiceReference::default(),
798 service_terminated: true,
799 service_not_available: false,
800 ca_service_flag: false,
801 actual_service: 0,
802 }
803 .to_bytes();
804 let parsed = ServiceGatewayApdu::parse(&gs).unwrap();
805 assert!(matches!(parsed, ServiceGatewayApdu::GetServiceAck(_)));
806 assert_eq!(parsed.to_bytes(), gs);
807 }
808}