1use crate::error::{Error, Result};
12use crate::objects;
13use crate::tag::ApduTag;
14use dvb_common::{Parse, Serialize};
15
16pub mod tag {
18 use crate::tag::ApduTag;
19 pub const EVENT_REQUEST: ApduTag = ApduTag::from_bytes(0x9F, 0x80, 0x00);
21 pub const EVENT_REQUEST_ACK: ApduTag = ApduTag::from_bytes(0x9F, 0x80, 0x01);
23 pub const EVENT_NOTIFICATION: ApduTag = ApduTag::from_bytes(0x9F, 0x80, 0x02);
25}
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq)]
29#[cfg_attr(feature = "serde", derive(serde::Serialize))]
30#[non_exhaustive]
31pub enum EventType {
32 Timer,
34 Reserved(u8),
36}
37
38impl EventType {
39 #[must_use]
41 pub fn from_u8(v: u8) -> Self {
42 match v {
43 0 => Self::Timer,
44 other => Self::Reserved(other),
45 }
46 }
47 #[must_use]
49 pub const fn to_u8(self) -> u8 {
50 match self {
51 Self::Timer => 0,
52 Self::Reserved(v) => v,
53 }
54 }
55 #[must_use]
57 pub fn name(&self) -> &'static str {
58 match self {
59 Self::Timer => "Timer",
60 Self::Reserved(_) => "reserved",
61 }
62 }
63}
64dvb_common::impl_spec_display!(EventType, Reserved);
65
66#[derive(Debug, Clone, Copy, PartialEq, Eq)]
68#[cfg_attr(feature = "serde", derive(serde::Serialize))]
69#[non_exhaustive]
70pub enum EventReply {
71 BookedOk,
73 TypeNotSupported,
75 ResourcesConsumed,
77 Reserved(u8),
79}
80
81impl EventReply {
82 #[must_use]
84 pub fn from_u8(v: u8) -> Self {
85 match v {
86 0 => Self::BookedOk,
87 1 => Self::TypeNotSupported,
88 2 => Self::ResourcesConsumed,
89 other => Self::Reserved(other),
90 }
91 }
92 #[must_use]
94 pub const fn to_u8(self) -> u8 {
95 match self {
96 Self::BookedOk => 0,
97 Self::TypeNotSupported => 1,
98 Self::ResourcesConsumed => 2,
99 Self::Reserved(v) => v,
100 }
101 }
102 #[must_use]
104 pub fn name(&self) -> &'static str {
105 match self {
106 Self::BookedOk => "Event booked OK",
107 Self::TypeNotSupported => "Event type not supported",
108 Self::ResourcesConsumed => "Event resources consumed",
109 Self::Reserved(_) => "reserved",
110 }
111 }
112}
113dvb_common::impl_spec_display!(EventReply, Reserved);
114
115#[derive(Debug, Clone, PartialEq, Eq)]
120#[cfg_attr(feature = "serde", derive(serde::Serialize))]
121pub struct EventRequest<'a> {
122 pub event_type: EventType,
124 #[cfg_attr(feature = "serde", serde(borrow, with = "crate::objects::bytes_serde"))]
126 pub event_desc: &'a [u8],
127}
128
129#[derive(Debug, Clone, Copy, PartialEq, Eq)]
131#[cfg_attr(feature = "serde", derive(serde::Serialize))]
132pub struct EventRequestAck {
133 pub event_type: EventType,
135 pub reply: EventReply,
137}
138
139#[derive(Debug, Clone, Copy, PartialEq, Eq)]
141#[cfg_attr(feature = "serde", derive(serde::Serialize))]
142pub struct EventNotification {
143 pub event_type: EventType,
145}
146
147const EVENT_REQUEST_PREFIX: usize = 1;
151
152impl<'a> Parse<'a> for EventRequest<'a> {
153 type Error = Error;
154 fn parse(bytes: &'a [u8]) -> Result<Self> {
155 let body = objects::parse_apdu_header(bytes, tag::EVENT_REQUEST, "event_request")?;
156 if body.len() < EVENT_REQUEST_PREFIX {
157 return Err(Error::BufferTooShort {
158 need: EVENT_REQUEST_PREFIX,
159 have: body.len(),
160 what: "event_request",
161 });
162 }
163 Ok(Self {
164 event_type: EventType::from_u8(body[0]),
165 event_desc: &body[EVENT_REQUEST_PREFIX..],
166 })
167 }
168}
169impl Serialize for EventRequest<'_> {
170 type Error = Error;
171 fn serialized_len(&self) -> usize {
172 objects::apdu_len(EVENT_REQUEST_PREFIX + self.event_desc.len())
173 }
174 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
175 let body_len = EVENT_REQUEST_PREFIX + self.event_desc.len();
176 let mut pos = objects::write_apdu_header(tag::EVENT_REQUEST, body_len, buf)?;
177 buf[pos] = self.event_type.to_u8();
178 pos += EVENT_REQUEST_PREFIX;
179 buf[pos..pos + self.event_desc.len()].copy_from_slice(self.event_desc);
180 Ok(pos + self.event_desc.len())
181 }
182}
183
184const EVENT_REQUEST_ACK_BODY: usize = 2;
188
189impl<'a> Parse<'a> for EventRequestAck {
190 type Error = Error;
191 fn parse(bytes: &'a [u8]) -> Result<Self> {
192 let body = objects::parse_apdu_header(bytes, tag::EVENT_REQUEST_ACK, "event_request_ack")?;
193 if body.len() < EVENT_REQUEST_ACK_BODY {
194 return Err(Error::BufferTooShort {
195 need: EVENT_REQUEST_ACK_BODY,
196 have: body.len(),
197 what: "event_request_ack",
198 });
199 }
200 Ok(Self {
201 event_type: EventType::from_u8(body[0]),
202 reply: EventReply::from_u8(body[1]),
203 })
204 }
205}
206impl Serialize for EventRequestAck {
207 type Error = Error;
208 fn serialized_len(&self) -> usize {
209 objects::apdu_len(EVENT_REQUEST_ACK_BODY)
210 }
211 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
212 let pos = objects::write_apdu_header(tag::EVENT_REQUEST_ACK, EVENT_REQUEST_ACK_BODY, buf)?;
213 buf[pos] = self.event_type.to_u8();
214 buf[pos + 1] = self.reply.to_u8();
215 Ok(pos + EVENT_REQUEST_ACK_BODY)
216 }
217}
218
219const EVENT_NOTIFICATION_BODY: usize = 1;
223
224impl<'a> Parse<'a> for EventNotification {
225 type Error = Error;
226 fn parse(bytes: &'a [u8]) -> Result<Self> {
227 let body =
228 objects::parse_apdu_header(bytes, tag::EVENT_NOTIFICATION, "event_notification")?;
229 if body.len() < EVENT_NOTIFICATION_BODY {
230 return Err(Error::BufferTooShort {
231 need: EVENT_NOTIFICATION_BODY,
232 have: body.len(),
233 what: "event_notification",
234 });
235 }
236 Ok(Self {
237 event_type: EventType::from_u8(body[0]),
238 })
239 }
240}
241impl Serialize for EventNotification {
242 type Error = Error;
243 fn serialized_len(&self) -> usize {
244 objects::apdu_len(EVENT_NOTIFICATION_BODY)
245 }
246 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
247 let pos =
248 objects::write_apdu_header(tag::EVENT_NOTIFICATION, EVENT_NOTIFICATION_BODY, buf)?;
249 buf[pos] = self.event_type.to_u8();
250 Ok(pos + EVENT_NOTIFICATION_BODY)
251 }
252}
253
254#[derive(Debug, Clone, PartialEq, Eq)]
256#[cfg_attr(feature = "serde", derive(serde::Serialize))]
257#[non_exhaustive]
258pub enum EventManagerApdu<'a> {
259 EventRequest(EventRequest<'a>),
261 EventRequestAck(EventRequestAck),
263 EventNotification(EventNotification),
265}
266
267impl<'a> EventManagerApdu<'a> {
268 pub fn parse(body: &'a [u8]) -> Result<Self> {
270 if body.len() < 3 {
271 return Err(Error::BufferTooShort {
272 need: 3,
273 have: body.len(),
274 what: "event_manager apdu_tag",
275 });
276 }
277 let t = ApduTag::from_bytes(body[0], body[1], body[2]);
278 match t {
279 tag::EVENT_REQUEST => Ok(Self::EventRequest(EventRequest::parse(body)?)),
280 tag::EVENT_REQUEST_ACK => Ok(Self::EventRequestAck(EventRequestAck::parse(body)?)),
281 tag::EVENT_NOTIFICATION => Ok(Self::EventNotification(EventNotification::parse(body)?)),
282 _ => Err(Error::UnexpectedApduTag {
283 got: t.as_u24(),
284 expected: tag::EVENT_REQUEST.as_u24(),
285 what: "event_manager",
286 }),
287 }
288 }
289}
290
291impl Serialize for EventManagerApdu<'_> {
292 type Error = Error;
293 fn serialized_len(&self) -> usize {
294 match self {
295 Self::EventRequest(o) => o.serialized_len(),
296 Self::EventRequestAck(o) => o.serialized_len(),
297 Self::EventNotification(o) => o.serialized_len(),
298 }
299 }
300 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
301 match self {
302 Self::EventRequest(o) => o.serialize_into(buf),
303 Self::EventRequestAck(o) => o.serialize_into(buf),
304 Self::EventNotification(o) => o.serialize_into(buf),
305 }
306 }
307}
308
309#[cfg(test)]
310mod tests {
311 use super::*;
312
313 #[test]
314 fn event_request_timer_round_trips_and_bites() {
315 let desc = [0x11, 0x22, 0x33, 0x44, 0x55, 0x06, 0x07, 0x08];
317 let r = EventRequest {
318 event_type: EventType::Timer,
319 event_desc: &desc,
320 };
321 let bytes = r.to_bytes();
322 assert_eq!(
324 bytes,
325 [0x9F, 0x80, 0x00, 0x09, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x06, 0x07, 0x08]
326 );
327 assert_eq!(EventRequest::parse(&bytes).unwrap(), r);
328 let mut desc2 = desc;
330 desc2[0] = 0xFF;
331 let other = EventRequest {
332 event_type: EventType::Timer,
333 event_desc: &desc2,
334 };
335 assert_ne!(bytes, other.to_bytes());
336 }
337
338 #[test]
339 fn event_request_cancel_empty_desc() {
340 let r = EventRequest {
341 event_type: EventType::Timer,
342 event_desc: &[],
343 };
344 let bytes = r.to_bytes();
345 assert_eq!(bytes, [0x9F, 0x80, 0x00, 0x01, 0x00]);
346 assert_eq!(EventRequest::parse(&bytes).unwrap(), r);
347 }
348
349 #[test]
350 fn event_request_ack_round_trips_and_bites() {
351 let a = EventRequestAck {
352 event_type: EventType::Timer,
353 reply: EventReply::ResourcesConsumed,
354 };
355 let bytes = a.to_bytes();
356 assert_eq!(bytes, [0x9F, 0x80, 0x01, 0x02, 0x00, 0x02]);
357 assert_eq!(EventRequestAck::parse(&bytes).unwrap(), a);
358 assert_eq!(a.reply.name(), "Event resources consumed");
359 let mut other = a;
360 other.reply = EventReply::BookedOk;
361 assert_ne!(bytes, other.to_bytes());
362 }
363
364 #[test]
365 fn event_notification_round_trips() {
366 let n = EventNotification {
367 event_type: EventType::Timer,
368 };
369 let bytes = n.to_bytes();
370 assert_eq!(bytes, [0x9F, 0x80, 0x02, 0x01, 0x00]);
371 assert_eq!(EventNotification::parse(&bytes).unwrap(), n);
372 }
373
374 #[test]
375 fn dispatch_routes_each_tag() {
376 let req = EventRequest {
377 event_type: EventType::Timer,
378 event_desc: &[],
379 }
380 .to_bytes();
381 assert!(matches!(
382 EventManagerApdu::parse(&req).unwrap(),
383 EventManagerApdu::EventRequest(_)
384 ));
385 let notif = EventNotification {
386 event_type: EventType::Timer,
387 }
388 .to_bytes();
389 let parsed = EventManagerApdu::parse(¬if).unwrap();
390 assert!(matches!(parsed, EventManagerApdu::EventNotification(_)));
391 assert_eq!(parsed.to_bytes(), notif);
392 }
393}