1use crate::error::Error;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
14#[repr(u8)]
15pub enum FunctionCode {
16 ContactStatus = 1,
18 OutputControl = 2,
20 CardDataFormat = 3,
22 LedControl = 4,
24 AudibleOutput = 5,
26 TextOutput = 6,
28 TimeKeeping = 7,
30 CheckCharacter = 8,
32 CommunicationSecurity = 9,
34 ReceiveBufferSize = 10,
37 LargestCombinedSize = 11,
39 SmartCardSupport = 12,
41 Readers = 13,
43 Biometrics = 14,
45 SecurePinEntry = 15,
47 OsdpVersion = 16,
49}
50
51impl FunctionCode {
52 pub const fn from_byte(b: u8) -> Result<Self, Error> {
54 Ok(match b {
55 1 => Self::ContactStatus,
56 2 => Self::OutputControl,
57 3 => Self::CardDataFormat,
58 4 => Self::LedControl,
59 5 => Self::AudibleOutput,
60 6 => Self::TextOutput,
61 7 => Self::TimeKeeping,
62 8 => Self::CheckCharacter,
63 9 => Self::CommunicationSecurity,
64 10 => Self::ReceiveBufferSize,
65 11 => Self::LargestCombinedSize,
66 12 => Self::SmartCardSupport,
67 13 => Self::Readers,
68 14 => Self::Biometrics,
69 15 => Self::SecurePinEntry,
70 16 => Self::OsdpVersion,
71 other => {
72 return Err(Error::MalformedPayload {
73 code: other,
74 reason: "unknown PDCAP function code",
75 });
76 }
77 })
78 }
79
80 pub const fn as_byte(self) -> u8 {
82 self as u8
83 }
84}
85
86#[derive(Debug, Clone, Copy, PartialEq, Eq)]
88pub struct Capability {
89 pub code: u8,
91 pub compliance: u8,
93 pub number_of: u8,
95}
96
97impl Capability {
98 pub const WIRE_LEN: usize = 3;
100
101 pub const fn encode(self) -> [u8; 3] {
103 [self.code, self.compliance, self.number_of]
104 }
105
106 pub const fn decode(bytes: [u8; 3]) -> Self {
108 Self {
109 code: bytes[0],
110 compliance: bytes[1],
111 number_of: bytes[2],
112 }
113 }
114
115 pub fn function(self) -> Option<FunctionCode> {
117 FunctionCode::from_byte(self.code).ok()
118 }
119
120 pub const fn u16_value(self) -> u16 {
122 u16::from_le_bytes([self.compliance, self.number_of])
123 }
124}
125
126#[cfg(test)]
127mod tests {
128 use super::*;
129
130 #[test]
131 fn rx_size_combined() {
132 let c = Capability {
133 code: FunctionCode::ReceiveBufferSize.as_byte(),
134 compliance: 0x80, number_of: 0x00,
136 };
137 assert_eq!(c.u16_value(), 128);
138 }
139
140 #[test]
141 fn function_roundtrip() {
142 for raw in 1u8..=16 {
143 let f = FunctionCode::from_byte(raw).unwrap();
144 assert_eq!(f.as_byte(), raw);
145 }
146 }
147}