1use bacnet_types::enums::{
14 AbortReason, ConfirmedServiceChoice, ErrorClass, ErrorCode, PduType, RejectReason,
15 UnconfirmedServiceChoice,
16};
17use bacnet_types::error::Error;
18use bytes::{BufMut, Bytes, BytesMut};
19
20use crate::primitives;
21use crate::tags;
22
23const MAX_SEGMENTS_DECODE: [Option<u8>; 8] = [
30 None, Some(2), Some(4), Some(8), Some(16), Some(32), Some(64), Some(255), ];
39
40fn encode_max_segments(value: Option<u8>) -> u8 {
42 match value {
43 None => 0,
44 Some(2) => 1,
45 Some(4) => 2,
46 Some(8) => 3,
47 Some(16) => 4,
48 Some(32) => 5,
49 Some(64) => 6,
50 Some(_) => 7, }
52}
53
54fn decode_max_segments(value: u8) -> Option<u8> {
56 MAX_SEGMENTS_DECODE[(value & 0x07) as usize]
57}
58
59const MAX_APDU_DECODE: [u16; 6] = [50, 128, 206, 480, 1024, 1476];
65
66fn encode_max_apdu(value: u16) -> u8 {
68 match value {
69 50 => 0,
70 128 => 1,
71 206 => 2,
72 480 => 3,
73 1024 => 4,
74 _ => 5, }
76}
77
78fn decode_max_apdu(value: u8) -> u16 {
80 let idx = (value & 0x0F) as usize;
81 if idx < MAX_APDU_DECODE.len() {
82 MAX_APDU_DECODE[idx]
83 } else {
84 1476
85 }
86}
87
88#[derive(Debug, Clone, PartialEq, Eq)]
94pub struct ConfirmedRequest {
95 pub segmented: bool,
96 pub more_follows: bool,
97 pub segmented_response_accepted: bool,
98 pub max_segments: Option<u8>,
99 pub max_apdu_length: u16,
100 pub invoke_id: u8,
101 pub sequence_number: Option<u8>,
102 pub proposed_window_size: Option<u8>,
103 pub service_choice: ConfirmedServiceChoice,
104 pub service_request: Bytes,
105}
106
107#[derive(Debug, Clone, PartialEq, Eq)]
109pub struct UnconfirmedRequest {
110 pub service_choice: UnconfirmedServiceChoice,
111 pub service_request: Bytes,
112}
113
114#[derive(Debug, Clone, PartialEq, Eq)]
116pub struct SimpleAck {
117 pub invoke_id: u8,
118 pub service_choice: ConfirmedServiceChoice,
119}
120
121#[derive(Debug, Clone, PartialEq, Eq)]
123pub struct ComplexAck {
124 pub segmented: bool,
125 pub more_follows: bool,
126 pub invoke_id: u8,
127 pub sequence_number: Option<u8>,
128 pub proposed_window_size: Option<u8>,
129 pub service_choice: ConfirmedServiceChoice,
130 pub service_ack: Bytes,
131}
132
133#[derive(Debug, Clone, PartialEq, Eq)]
135pub struct SegmentAck {
136 pub negative_ack: bool,
137 pub sent_by_server: bool,
138 pub invoke_id: u8,
139 pub sequence_number: u8,
140 pub actual_window_size: u8,
141}
142
143#[derive(Debug, Clone, PartialEq, Eq)]
145pub struct ErrorPdu {
146 pub invoke_id: u8,
147 pub service_choice: ConfirmedServiceChoice,
148 pub error_class: ErrorClass,
149 pub error_code: ErrorCode,
150 pub error_data: Bytes,
151}
152
153#[derive(Debug, Clone, PartialEq, Eq)]
155pub struct RejectPdu {
156 pub invoke_id: u8,
157 pub reject_reason: RejectReason,
158}
159
160#[derive(Debug, Clone, PartialEq, Eq)]
162pub struct AbortPdu {
163 pub sent_by_server: bool,
164 pub invoke_id: u8,
165 pub abort_reason: AbortReason,
166}
167
168#[derive(Debug, Clone, PartialEq, Eq)]
170pub enum Apdu {
171 ConfirmedRequest(ConfirmedRequest),
172 UnconfirmedRequest(UnconfirmedRequest),
173 SimpleAck(SimpleAck),
174 ComplexAck(ComplexAck),
175 SegmentAck(SegmentAck),
176 Error(ErrorPdu),
177 Reject(RejectPdu),
178 Abort(AbortPdu),
179}
180
181pub fn encode_apdu(buf: &mut BytesMut, apdu: &Apdu) {
187 match apdu {
188 Apdu::ConfirmedRequest(pdu) => encode_confirmed_request(buf, pdu),
189 Apdu::UnconfirmedRequest(pdu) => encode_unconfirmed_request(buf, pdu),
190 Apdu::SimpleAck(pdu) => encode_simple_ack(buf, pdu),
191 Apdu::ComplexAck(pdu) => encode_complex_ack(buf, pdu),
192 Apdu::SegmentAck(pdu) => encode_segment_ack(buf, pdu),
193 Apdu::Error(pdu) => encode_error(buf, pdu),
194 Apdu::Reject(pdu) => encode_reject(buf, pdu),
195 Apdu::Abort(pdu) => encode_abort(buf, pdu),
196 }
197}
198
199fn encode_confirmed_request(buf: &mut BytesMut, pdu: &ConfirmedRequest) {
200 let mut byte0 = PduType::CONFIRMED_REQUEST.to_raw() << 4;
202 if pdu.segmented {
203 byte0 |= 0x08;
204 }
205 if pdu.more_follows {
206 byte0 |= 0x04;
207 }
208 if pdu.segmented_response_accepted {
209 byte0 |= 0x02;
210 }
211 buf.put_u8(byte0);
212
213 let byte1 = (encode_max_segments(pdu.max_segments) << 4) | encode_max_apdu(pdu.max_apdu_length);
215 buf.put_u8(byte1);
216
217 buf.put_u8(pdu.invoke_id);
218
219 if pdu.segmented {
220 buf.put_u8(pdu.sequence_number.unwrap_or(0));
221 buf.put_u8(pdu.proposed_window_size.unwrap_or(1));
222 }
223
224 buf.put_u8(pdu.service_choice.to_raw());
225 buf.put_slice(&pdu.service_request);
226}
227
228fn encode_unconfirmed_request(buf: &mut BytesMut, pdu: &UnconfirmedRequest) {
229 buf.put_u8(PduType::UNCONFIRMED_REQUEST.to_raw() << 4);
230 buf.put_u8(pdu.service_choice.to_raw());
231 buf.put_slice(&pdu.service_request);
232}
233
234fn encode_simple_ack(buf: &mut BytesMut, pdu: &SimpleAck) {
235 buf.put_u8(PduType::SIMPLE_ACK.to_raw() << 4);
236 buf.put_u8(pdu.invoke_id);
237 buf.put_u8(pdu.service_choice.to_raw());
238}
239
240fn encode_complex_ack(buf: &mut BytesMut, pdu: &ComplexAck) {
241 let mut byte0 = PduType::COMPLEX_ACK.to_raw() << 4;
242 if pdu.segmented {
243 byte0 |= 0x08;
244 }
245 if pdu.more_follows {
246 byte0 |= 0x04;
247 }
248 buf.put_u8(byte0);
249
250 buf.put_u8(pdu.invoke_id);
251
252 if pdu.segmented {
253 buf.put_u8(pdu.sequence_number.unwrap_or(0));
254 buf.put_u8(pdu.proposed_window_size.unwrap_or(1));
255 }
256
257 buf.put_u8(pdu.service_choice.to_raw());
258 buf.put_slice(&pdu.service_ack);
259}
260
261fn encode_segment_ack(buf: &mut BytesMut, pdu: &SegmentAck) {
262 let mut byte0 = PduType::SEGMENT_ACK.to_raw() << 4;
263 if pdu.negative_ack {
264 byte0 |= 0x02;
265 }
266 if pdu.sent_by_server {
267 byte0 |= 0x01;
268 }
269 buf.put_u8(byte0);
270 buf.put_u8(pdu.invoke_id);
271 buf.put_u8(pdu.sequence_number);
272 buf.put_u8(pdu.actual_window_size);
273}
274
275fn encode_error(buf: &mut BytesMut, pdu: &ErrorPdu) {
276 buf.put_u8(PduType::ERROR.to_raw() << 4);
277 buf.put_u8(pdu.invoke_id);
278 buf.put_u8(pdu.service_choice.to_raw());
279 primitives::encode_app_enumerated(buf, pdu.error_class.to_raw() as u32);
281 primitives::encode_app_enumerated(buf, pdu.error_code.to_raw() as u32);
282 if !pdu.error_data.is_empty() {
283 buf.put_slice(&pdu.error_data);
284 }
285}
286
287fn encode_reject(buf: &mut BytesMut, pdu: &RejectPdu) {
288 buf.put_u8(PduType::REJECT.to_raw() << 4);
289 buf.put_u8(pdu.invoke_id);
290 buf.put_u8(pdu.reject_reason.to_raw());
291}
292
293fn encode_abort(buf: &mut BytesMut, pdu: &AbortPdu) {
294 let mut byte0 = PduType::ABORT.to_raw() << 4;
295 if pdu.sent_by_server {
296 byte0 |= 0x01;
297 }
298 buf.put_u8(byte0);
299 buf.put_u8(pdu.invoke_id);
300 buf.put_u8(pdu.abort_reason.to_raw());
301}
302
303pub fn decode_apdu(data: Bytes) -> Result<Apdu, Error> {
309 if data.is_empty() {
310 return Err(Error::decoding(0, "APDU data is empty"));
311 }
312
313 let pdu_type_raw = (data[0] >> 4) & 0x0F;
314 let pdu_type = PduType::from_raw(pdu_type_raw);
315
316 if pdu_type == PduType::CONFIRMED_REQUEST {
317 decode_confirmed_request(data).map(Apdu::ConfirmedRequest)
318 } else if pdu_type == PduType::UNCONFIRMED_REQUEST {
319 decode_unconfirmed_request(data).map(Apdu::UnconfirmedRequest)
320 } else if pdu_type == PduType::SIMPLE_ACK {
321 decode_simple_ack(data).map(Apdu::SimpleAck)
322 } else if pdu_type == PduType::COMPLEX_ACK {
323 decode_complex_ack(data).map(Apdu::ComplexAck)
324 } else if pdu_type == PduType::SEGMENT_ACK {
325 decode_segment_ack(data).map(Apdu::SegmentAck)
326 } else if pdu_type == PduType::ERROR {
327 decode_error(data).map(Apdu::Error)
328 } else if pdu_type == PduType::REJECT {
329 decode_reject(data).map(Apdu::Reject)
330 } else if pdu_type == PduType::ABORT {
331 decode_abort(data).map(Apdu::Abort)
332 } else {
333 Err(Error::decoding(
334 0,
335 format!("unknown PDU type nibble: {:#x}", pdu_type_raw),
336 ))
337 }
338}
339
340fn decode_confirmed_request(data: Bytes) -> Result<ConfirmedRequest, Error> {
341 if data.len() < 4 {
342 return Err(Error::buffer_too_short(4, data.len()));
343 }
344
345 let byte0 = data[0];
346 let segmented = byte0 & 0x08 != 0;
347 let more_follows = byte0 & 0x04 != 0;
348 let segmented_response_accepted = byte0 & 0x02 != 0;
349
350 let byte1 = data[1];
351 let max_segments = decode_max_segments((byte1 >> 4) & 0x07);
352 let max_apdu_length = decode_max_apdu(byte1 & 0x0F);
353
354 let invoke_id = data[2];
355 let mut offset = 3;
356
357 let (sequence_number, proposed_window_size) = if segmented {
358 if data.len() < 6 {
359 return Err(Error::decoding(
360 offset,
361 "segmented ConfirmedRequest too short for sequence/window fields",
362 ));
363 }
364 let seq = data[offset];
365 let win = data[offset + 1];
366 offset += 2;
367 (Some(seq), Some(win))
368 } else {
369 (None, None)
370 };
371
372 if offset >= data.len() {
373 return Err(Error::decoding(
374 offset,
375 "ConfirmedRequest missing service choice",
376 ));
377 }
378 let service_choice = ConfirmedServiceChoice::from_raw(data[offset]);
379 offset += 1;
380
381 let service_request = data.slice(offset..);
382
383 Ok(ConfirmedRequest {
384 segmented,
385 more_follows,
386 segmented_response_accepted,
387 max_segments,
388 max_apdu_length,
389 invoke_id,
390 sequence_number,
391 proposed_window_size,
392 service_choice,
393 service_request,
394 })
395}
396
397fn decode_unconfirmed_request(data: Bytes) -> Result<UnconfirmedRequest, Error> {
398 if data.len() < 2 {
399 return Err(Error::buffer_too_short(2, data.len()));
400 }
401
402 let service_choice = UnconfirmedServiceChoice::from_raw(data[1]);
403 let service_request = data.slice(2..);
404
405 Ok(UnconfirmedRequest {
406 service_choice,
407 service_request,
408 })
409}
410
411fn decode_simple_ack(data: Bytes) -> Result<SimpleAck, Error> {
412 if data.len() < 3 {
413 return Err(Error::buffer_too_short(3, data.len()));
414 }
415
416 Ok(SimpleAck {
417 invoke_id: data[1],
418 service_choice: ConfirmedServiceChoice::from_raw(data[2]),
419 })
420}
421
422fn decode_complex_ack(data: Bytes) -> Result<ComplexAck, Error> {
423 if data.len() < 3 {
424 return Err(Error::buffer_too_short(3, data.len()));
425 }
426
427 let byte0 = data[0];
428 let segmented = byte0 & 0x08 != 0;
429 let more_follows = byte0 & 0x04 != 0;
430
431 let invoke_id = data[1];
432 let mut offset = 2;
433
434 let (sequence_number, proposed_window_size) = if segmented {
435 if data.len() < 5 {
436 return Err(Error::decoding(
437 offset,
438 "segmented ComplexAck too short for sequence/window fields",
439 ));
440 }
441 let seq = data[offset];
442 let win = data[offset + 1];
443 offset += 2;
444 (Some(seq), Some(win))
445 } else {
446 (None, None)
447 };
448
449 if offset >= data.len() {
450 return Err(Error::decoding(offset, "ComplexAck missing service choice"));
451 }
452 let service_choice = ConfirmedServiceChoice::from_raw(data[offset]);
453 offset += 1;
454
455 let service_ack = data.slice(offset..);
456
457 Ok(ComplexAck {
458 segmented,
459 more_follows,
460 invoke_id,
461 sequence_number,
462 proposed_window_size,
463 service_choice,
464 service_ack,
465 })
466}
467
468fn decode_segment_ack(data: Bytes) -> Result<SegmentAck, Error> {
469 if data.len() < 4 {
470 return Err(Error::buffer_too_short(4, data.len()));
471 }
472
473 let byte0 = data[0];
474 Ok(SegmentAck {
475 negative_ack: byte0 & 0x02 != 0,
476 sent_by_server: byte0 & 0x01 != 0,
477 invoke_id: data[1],
478 sequence_number: data[2],
479 actual_window_size: data[3],
480 })
481}
482
483fn decode_error(data: Bytes) -> Result<ErrorPdu, Error> {
484 if data.len() < 5 {
485 return Err(Error::buffer_too_short(5, data.len()));
486 }
487
488 let invoke_id = data[1];
489 let service_choice = ConfirmedServiceChoice::from_raw(data[2]);
490
491 let mut offset = 3;
493 let (tag, tag_end) = tags::decode_tag(&data, offset)?;
494 let class_end = tag_end + tag.length as usize;
495 if class_end > data.len() {
496 return Err(Error::decoding(
497 tag_end,
498 "ErrorPDU truncated at error class",
499 ));
500 }
501 let error_class_raw = primitives::decode_unsigned(&data[tag_end..class_end])? as u16;
502 offset = class_end;
503
504 let (tag, tag_end) = tags::decode_tag(&data, offset)?;
506 let code_end = tag_end + tag.length as usize;
507 if code_end > data.len() {
508 return Err(Error::decoding(tag_end, "ErrorPDU truncated at error code"));
509 }
510 let error_code_raw = primitives::decode_unsigned(&data[tag_end..code_end])? as u16;
511 offset = code_end;
512
513 let error_data = if offset < data.len() {
515 data.slice(offset..)
516 } else {
517 Bytes::new()
518 };
519
520 Ok(ErrorPdu {
521 invoke_id,
522 service_choice,
523 error_class: ErrorClass::from_raw(error_class_raw),
524 error_code: ErrorCode::from_raw(error_code_raw),
525 error_data,
526 })
527}
528
529fn decode_reject(data: Bytes) -> Result<RejectPdu, Error> {
530 if data.len() < 3 {
531 return Err(Error::buffer_too_short(3, data.len()));
532 }
533
534 Ok(RejectPdu {
535 invoke_id: data[1],
536 reject_reason: RejectReason::from_raw(data[2]),
537 })
538}
539
540fn decode_abort(data: Bytes) -> Result<AbortPdu, Error> {
541 if data.len() < 3 {
542 return Err(Error::buffer_too_short(3, data.len()));
543 }
544
545 let byte0 = data[0];
546 Ok(AbortPdu {
547 sent_by_server: byte0 & 0x01 != 0,
548 invoke_id: data[1],
549 abort_reason: AbortReason::from_raw(data[2]),
550 })
551}
552
553#[cfg(test)]
558mod tests {
559 use super::*;
560
561 fn encode_to_vec(apdu: &Apdu) -> Vec<u8> {
562 let mut buf = BytesMut::with_capacity(64);
563 encode_apdu(&mut buf, apdu);
564 buf.to_vec()
565 }
566
567 #[test]
570 fn max_segments_round_trip() {
571 assert_eq!(decode_max_segments(encode_max_segments(None)), None);
572 assert_eq!(decode_max_segments(encode_max_segments(Some(2))), Some(2));
573 assert_eq!(decode_max_segments(encode_max_segments(Some(4))), Some(4));
574 assert_eq!(decode_max_segments(encode_max_segments(Some(8))), Some(8));
575 assert_eq!(decode_max_segments(encode_max_segments(Some(16))), Some(16));
576 assert_eq!(decode_max_segments(encode_max_segments(Some(32))), Some(32));
577 assert_eq!(decode_max_segments(encode_max_segments(Some(64))), Some(64));
578 assert_eq!(
580 decode_max_segments(encode_max_segments(Some(100))),
581 Some(255)
582 );
583 }
584
585 #[test]
586 fn max_apdu_round_trip() {
587 assert_eq!(decode_max_apdu(encode_max_apdu(50)), 50);
588 assert_eq!(decode_max_apdu(encode_max_apdu(128)), 128);
589 assert_eq!(decode_max_apdu(encode_max_apdu(206)), 206);
590 assert_eq!(decode_max_apdu(encode_max_apdu(480)), 480);
591 assert_eq!(decode_max_apdu(encode_max_apdu(1024)), 1024);
592 assert_eq!(decode_max_apdu(encode_max_apdu(1476)), 1476);
593 assert_eq!(decode_max_apdu(encode_max_apdu(9999)), 1476);
595 }
596
597 #[test]
600 fn confirmed_request_non_segmented_round_trip() {
601 let pdu = ConfirmedRequest {
602 segmented: false,
603 more_follows: false,
604 segmented_response_accepted: true,
605 max_segments: Some(4),
606 max_apdu_length: 1476,
607 invoke_id: 42,
608 sequence_number: None,
609 proposed_window_size: None,
610 service_choice: ConfirmedServiceChoice::READ_PROPERTY,
611 service_request: Bytes::from_static(&[0x0C, 0x02, 0x00, 0x00, 0x01]),
612 };
613 let apdu = Apdu::ConfirmedRequest(pdu);
614 let encoded = encode_to_vec(&apdu);
615 let decoded = decode_apdu(Bytes::from(encoded)).unwrap();
616 assert_eq!(apdu, decoded);
617 }
618
619 #[test]
620 fn confirmed_request_segmented_round_trip() {
621 let pdu = ConfirmedRequest {
622 segmented: true,
623 more_follows: true,
624 segmented_response_accepted: true,
625 max_segments: Some(64),
626 max_apdu_length: 480,
627 invoke_id: 7,
628 sequence_number: Some(3),
629 proposed_window_size: Some(16),
630 service_choice: ConfirmedServiceChoice::WRITE_PROPERTY,
631 service_request: Bytes::from_static(&[0xAA, 0xBB]),
632 };
633 let apdu = Apdu::ConfirmedRequest(pdu);
634 let encoded = encode_to_vec(&apdu);
635 let decoded = decode_apdu(Bytes::from(encoded)).unwrap();
636 assert_eq!(apdu, decoded);
637 }
638
639 #[test]
640 fn confirmed_request_wire_format() {
641 let pdu = ConfirmedRequest {
642 segmented: false,
643 more_follows: false,
644 segmented_response_accepted: false,
645 max_segments: None,
646 max_apdu_length: 1476,
647 invoke_id: 1,
648 sequence_number: None,
649 proposed_window_size: None,
650 service_choice: ConfirmedServiceChoice::READ_PROPERTY,
651 service_request: Bytes::new(),
652 };
653 let encoded = encode_to_vec(&Apdu::ConfirmedRequest(pdu));
654 assert_eq!(&encoded[..4], &[0x00, 0x05, 0x01, 0x0C]);
659 }
660
661 #[test]
664 fn unconfirmed_request_round_trip() {
665 let pdu = UnconfirmedRequest {
666 service_choice: UnconfirmedServiceChoice::WHO_IS,
667 service_request: Bytes::from_static(&[0x01, 0x02, 0x03]),
668 };
669 let apdu = Apdu::UnconfirmedRequest(pdu);
670 let encoded = encode_to_vec(&apdu);
671 let decoded = decode_apdu(Bytes::from(encoded)).unwrap();
672 assert_eq!(apdu, decoded);
673 }
674
675 #[test]
676 fn unconfirmed_request_wire_format() {
677 let pdu = UnconfirmedRequest {
678 service_choice: UnconfirmedServiceChoice::I_AM,
679 service_request: Bytes::new(),
680 };
681 let encoded = encode_to_vec(&Apdu::UnconfirmedRequest(pdu));
682 assert_eq!(encoded, vec![0x10, 0x00]);
685 }
686
687 #[test]
690 fn simple_ack_round_trip() {
691 let pdu = SimpleAck {
692 invoke_id: 99,
693 service_choice: ConfirmedServiceChoice::WRITE_PROPERTY,
694 };
695 let apdu = Apdu::SimpleAck(pdu);
696 let encoded = encode_to_vec(&apdu);
697 assert_eq!(encoded.len(), 3);
698 let decoded = decode_apdu(Bytes::from(encoded)).unwrap();
699 assert_eq!(apdu, decoded);
700 }
701
702 #[test]
703 fn simple_ack_wire_format() {
704 let pdu = SimpleAck {
705 invoke_id: 5,
706 service_choice: ConfirmedServiceChoice::READ_PROPERTY,
707 };
708 let encoded = encode_to_vec(&Apdu::SimpleAck(pdu));
709 assert_eq!(encoded, vec![0x20, 0x05, 0x0C]);
711 }
712
713 #[test]
716 fn complex_ack_non_segmented_round_trip() {
717 let pdu = ComplexAck {
718 segmented: false,
719 more_follows: false,
720 invoke_id: 42,
721 sequence_number: None,
722 proposed_window_size: None,
723 service_choice: ConfirmedServiceChoice::READ_PROPERTY,
724 service_ack: Bytes::from_static(&[0xDE, 0xAD]),
725 };
726 let apdu = Apdu::ComplexAck(pdu);
727 let encoded = encode_to_vec(&apdu);
728 let decoded = decode_apdu(Bytes::from(encoded)).unwrap();
729 assert_eq!(apdu, decoded);
730 }
731
732 #[test]
733 fn complex_ack_segmented_round_trip() {
734 let pdu = ComplexAck {
735 segmented: true,
736 more_follows: false,
737 invoke_id: 10,
738 sequence_number: Some(5),
739 proposed_window_size: Some(8),
740 service_choice: ConfirmedServiceChoice::READ_PROPERTY_MULTIPLE,
741 service_ack: Bytes::from_static(&[0x01]),
742 };
743 let apdu = Apdu::ComplexAck(pdu);
744 let encoded = encode_to_vec(&apdu);
745 let decoded = decode_apdu(Bytes::from(encoded)).unwrap();
746 assert_eq!(apdu, decoded);
747 }
748
749 #[test]
752 fn segment_ack_round_trip() {
753 let pdu = SegmentAck {
754 negative_ack: true,
755 sent_by_server: false,
756 invoke_id: 55,
757 sequence_number: 12,
758 actual_window_size: 4,
759 };
760 let apdu = Apdu::SegmentAck(pdu);
761 let encoded = encode_to_vec(&apdu);
762 assert_eq!(encoded.len(), 4);
763 let decoded = decode_apdu(Bytes::from(encoded)).unwrap();
764 assert_eq!(apdu, decoded);
765 }
766
767 #[test]
768 fn segment_ack_flags() {
769 let pdu = SegmentAck {
771 negative_ack: true,
772 sent_by_server: true,
773 invoke_id: 1,
774 sequence_number: 0,
775 actual_window_size: 1,
776 };
777 let encoded = encode_to_vec(&Apdu::SegmentAck(pdu));
778 assert_eq!(encoded[0], 0x43);
780 }
781
782 #[test]
785 fn error_round_trip() {
786 let pdu = ErrorPdu {
787 invoke_id: 10,
788 service_choice: ConfirmedServiceChoice::READ_PROPERTY,
789 error_class: ErrorClass::PROPERTY,
790 error_code: ErrorCode::UNKNOWN_PROPERTY,
791 error_data: Bytes::new(),
792 };
793 let apdu = Apdu::Error(pdu);
794 let encoded = encode_to_vec(&apdu);
795 let decoded = decode_apdu(Bytes::from(encoded)).unwrap();
796 assert_eq!(apdu, decoded);
797 }
798
799 #[test]
800 fn error_with_trailing_data_round_trip() {
801 let pdu = ErrorPdu {
802 invoke_id: 20,
803 service_choice: ConfirmedServiceChoice::CREATE_OBJECT,
804 error_class: ErrorClass::OBJECT,
805 error_code: ErrorCode::NO_OBJECTS_OF_SPECIFIED_TYPE,
806 error_data: Bytes::from_static(&[0x01, 0x02, 0x03]),
807 };
808 let apdu = Apdu::Error(pdu);
809 let encoded = encode_to_vec(&apdu);
810 let decoded = decode_apdu(Bytes::from(encoded)).unwrap();
811 assert_eq!(apdu, decoded);
812 }
813
814 #[test]
817 fn reject_round_trip() {
818 let pdu = RejectPdu {
819 invoke_id: 77,
820 reject_reason: RejectReason::INVALID_TAG,
821 };
822 let apdu = Apdu::Reject(pdu);
823 let encoded = encode_to_vec(&apdu);
824 assert_eq!(encoded.len(), 3);
825 let decoded = decode_apdu(Bytes::from(encoded)).unwrap();
826 assert_eq!(apdu, decoded);
827 }
828
829 #[test]
832 fn abort_round_trip() {
833 let pdu = AbortPdu {
834 sent_by_server: true,
835 invoke_id: 33,
836 abort_reason: AbortReason::BUFFER_OVERFLOW,
837 };
838 let apdu = Apdu::Abort(pdu);
839 let encoded = encode_to_vec(&apdu);
840 assert_eq!(encoded.len(), 3);
841 let decoded = decode_apdu(Bytes::from(encoded)).unwrap();
842 assert_eq!(apdu, decoded);
843 }
844
845 #[test]
846 fn abort_server_flag() {
847 let pdu = AbortPdu {
848 sent_by_server: true,
849 invoke_id: 0,
850 abort_reason: AbortReason::OTHER,
851 };
852 let encoded = encode_to_vec(&Apdu::Abort(pdu));
853 assert_eq!(encoded[0], 0x71);
855
856 let pdu = AbortPdu {
857 sent_by_server: false,
858 invoke_id: 0,
859 abort_reason: AbortReason::OTHER,
860 };
861 let encoded = encode_to_vec(&Apdu::Abort(pdu));
862 assert_eq!(encoded[0], 0x70);
864 }
865
866 #[test]
869 fn decode_empty_data() {
870 assert!(decode_apdu(Bytes::new()).is_err());
871 }
872
873 #[test]
874 fn decode_unknown_pdu_type() {
875 assert!(decode_apdu(Bytes::from_static(&[0xF0])).is_err());
877 }
878
879 #[test]
880 fn decode_truncated_confirmed_request() {
881 assert!(decode_apdu(Bytes::from_static(&[0x00, 0x05])).is_err());
883 }
884
885 #[test]
886 fn decode_truncated_simple_ack() {
887 assert!(decode_apdu(Bytes::from_static(&[0x20, 0x01])).is_err());
889 }
890
891 #[test]
894 fn decode_truncated_segmented_confirmed_request() {
895 assert!(decode_apdu(Bytes::from_static(&[0x08, 0x05, 0x01])).is_err());
901 }
902
903 #[test]
904 fn decode_segmented_confirmed_request_missing_service() {
905 assert!(decode_apdu(Bytes::from_static(&[0x08, 0x05, 0x01, 0x00, 0x01])).is_err());
908 }
909
910 #[test]
911 fn decode_truncated_segmented_complex_ack() {
912 assert!(decode_apdu(Bytes::from_static(&[0x38, 0x01])).is_err());
917 }
918
919 #[test]
920 fn decode_complex_ack_missing_service_choice() {
921 assert!(decode_apdu(Bytes::from_static(&[0x30, 0x01])).is_err());
923 }
924
925 #[test]
926 fn decode_truncated_segment_ack() {
927 assert!(decode_apdu(Bytes::from_static(&[0x40, 0x01, 0x02])).is_err());
929 }
930
931 #[test]
932 fn decode_truncated_error_pdu() {
933 assert!(decode_apdu(Bytes::from_static(&[0x50, 0x01, 0x0C, 0x91])).is_err());
935 }
936
937 #[test]
938 fn decode_truncated_reject() {
939 assert!(decode_apdu(Bytes::from_static(&[0x60, 0x01])).is_err());
941 }
942
943 #[test]
944 fn decode_truncated_abort() {
945 assert!(decode_apdu(Bytes::from_static(&[0x70, 0x01])).is_err());
947 }
948
949 #[test]
952 fn confirmed_request_empty_service_data() {
953 let pdu = ConfirmedRequest {
954 segmented: false,
955 more_follows: false,
956 segmented_response_accepted: false,
957 max_segments: None,
958 max_apdu_length: 1476,
959 invoke_id: 0,
960 sequence_number: None,
961 proposed_window_size: None,
962 service_choice: ConfirmedServiceChoice::READ_PROPERTY,
963 service_request: Bytes::new(),
964 };
965 let apdu = Apdu::ConfirmedRequest(pdu);
966 let encoded = encode_to_vec(&apdu);
967 let decoded = decode_apdu(Bytes::from(encoded)).unwrap();
968 assert_eq!(apdu, decoded);
969 }
970
971 #[test]
972 fn confirmed_request_invoke_id_zero() {
973 let pdu = ConfirmedRequest {
974 segmented: false,
975 more_follows: false,
976 segmented_response_accepted: true,
977 max_segments: Some(64),
978 max_apdu_length: 1476,
979 invoke_id: 0,
980 sequence_number: None,
981 proposed_window_size: None,
982 service_choice: ConfirmedServiceChoice::WRITE_PROPERTY,
983 service_request: Bytes::from_static(&[0xAA]),
984 };
985 let apdu = Apdu::ConfirmedRequest(pdu);
986 let encoded = encode_to_vec(&apdu);
987 let decoded = decode_apdu(Bytes::from(encoded)).unwrap();
988 assert_eq!(apdu, decoded);
989 }
990
991 #[test]
992 fn confirmed_request_invoke_id_255() {
993 let pdu = ConfirmedRequest {
994 segmented: false,
995 more_follows: false,
996 segmented_response_accepted: true,
997 max_segments: None,
998 max_apdu_length: 480,
999 invoke_id: 255,
1000 sequence_number: None,
1001 proposed_window_size: None,
1002 service_choice: ConfirmedServiceChoice::READ_PROPERTY,
1003 service_request: Bytes::from_static(&[0x01]),
1004 };
1005 let apdu = Apdu::ConfirmedRequest(pdu);
1006 let encoded = encode_to_vec(&apdu);
1007 let decoded = decode_apdu(Bytes::from(encoded)).unwrap();
1008 assert_eq!(apdu, decoded);
1009 }
1010
1011 #[test]
1012 fn segmented_request_sequence_zero() {
1013 let pdu = ConfirmedRequest {
1014 segmented: true,
1015 more_follows: true,
1016 segmented_response_accepted: true,
1017 max_segments: Some(64),
1018 max_apdu_length: 480,
1019 invoke_id: 5,
1020 sequence_number: Some(0),
1021 proposed_window_size: Some(1),
1022 service_choice: ConfirmedServiceChoice::READ_PROPERTY_MULTIPLE,
1023 service_request: Bytes::from_static(&[0x01, 0x02]),
1024 };
1025 let apdu = Apdu::ConfirmedRequest(pdu);
1026 let encoded = encode_to_vec(&apdu);
1027 let decoded = decode_apdu(Bytes::from(encoded)).unwrap();
1028 assert_eq!(apdu, decoded);
1029 }
1030
1031 #[test]
1032 fn error_pdu_truncated_error_class() {
1033 assert!(decode_apdu(Bytes::from_static(&[0x50, 0x01, 0x0C])).is_err());
1036 }
1037
1038 #[test]
1039 fn error_pdu_truncated_error_code() {
1040 let mut buf = BytesMut::with_capacity(16);
1043 buf.put_u8(0x50); buf.put_u8(1); buf.put_u8(0x0C); primitives::encode_app_enumerated(&mut buf, 2); assert!(decode_apdu(buf.freeze()).is_err());
1049 }
1050
1051 #[test]
1052 fn unconfirmed_request_empty_service_data() {
1053 let pdu = UnconfirmedRequest {
1054 service_choice: UnconfirmedServiceChoice::WHO_IS,
1055 service_request: Bytes::new(),
1056 };
1057 let apdu = Apdu::UnconfirmedRequest(pdu);
1058 let encoded = encode_to_vec(&apdu);
1059 let decoded = decode_apdu(Bytes::from(encoded)).unwrap();
1060 assert_eq!(apdu, decoded);
1061 }
1062}