1use crate::error::Error;
6
7#[cfg(feature = "alloc")]
8use alloc::vec::Vec;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
12#[repr(u8)]
13#[allow(missing_docs)]
14pub enum ReplyCode {
15 Ack = 0x40,
16 Nak = 0x41,
17 PdId = 0x45,
18 PdCap = 0x46,
19 LStatR = 0x48,
20 IStatR = 0x49,
21 OStatR = 0x4A,
22 RStatR = 0x4B,
23 Raw = 0x50,
24 Fmt = 0x51,
25 Keypad = 0x53,
26 Com = 0x54,
27 BioReadR = 0x57,
28 BioMatchR = 0x58,
29 CCrypt = 0x76,
30 RMacI = 0x78,
31 Busy = 0x79,
32 FtStat = 0x7A,
33 PivDataR = 0x80,
34 GenAuthR = 0x81,
35 CrAuthR = 0x82,
36 MfgStatR = 0x83,
37 MfgErrR = 0x84,
38 MfgRep = 0x90,
39 Xrd = 0xB1,
40}
41
42impl ReplyCode {
43 pub const fn from_byte(b: u8) -> Result<Self, Error> {
45 Ok(match b {
46 0x40 => Self::Ack,
47 0x41 => Self::Nak,
48 0x45 => Self::PdId,
49 0x46 => Self::PdCap,
50 0x48 => Self::LStatR,
51 0x49 => Self::IStatR,
52 0x4A => Self::OStatR,
53 0x4B => Self::RStatR,
54 0x50 => Self::Raw,
55 0x51 => Self::Fmt,
56 0x53 => Self::Keypad,
57 0x54 => Self::Com,
58 0x57 => Self::BioReadR,
59 0x58 => Self::BioMatchR,
60 0x76 => Self::CCrypt,
61 0x78 => Self::RMacI,
62 0x79 => Self::Busy,
63 0x7A => Self::FtStat,
64 0x80 => Self::PivDataR,
65 0x81 => Self::GenAuthR,
66 0x82 => Self::CrAuthR,
67 0x83 => Self::MfgStatR,
68 0x84 => Self::MfgErrR,
69 0x90 => Self::MfgRep,
70 0xB1 => Self::Xrd,
71 other => return Err(Error::UnknownReply(other)),
72 })
73 }
74
75 pub const fn as_byte(self) -> u8 {
77 self as u8
78 }
79}
80
81pub mod ack;
82pub mod bio;
83pub mod busy;
84pub mod ccrypt;
85pub mod com;
86pub mod crauth;
87pub mod ft_stat;
88pub mod genauth;
89pub mod istat;
90pub mod keypad;
91pub mod lstat;
92pub mod mfg;
93pub mod nak;
94pub mod ostat;
95pub mod pdcap;
96pub mod pdid;
97pub mod piv;
98pub mod raw_card;
99pub mod rmac_i;
100pub mod rstat;
101pub mod xrd;
102
103pub use ack::Ack;
104pub use bio::{BioMatchR, BioReadR};
105pub use busy::Busy;
106pub use ccrypt::CCrypt;
107pub use com::Com;
108pub use crauth::CrAuthR;
109pub use ft_stat::FtStat;
110pub use genauth::GenAuthR;
111pub use istat::IStatR;
112pub use keypad::Keypad;
113pub use lstat::LStatR;
114pub use mfg::{MfgErrR, MfgRep, MfgStatR};
115pub use nak::{Nak, NakErrorCode};
116pub use ostat::OStatR;
117pub use pdcap::PdCap;
118pub use pdid::PdId;
119pub use piv::PivDataR;
120pub use raw_card::{Fmt, Raw};
121pub use rmac_i::RMacI;
122pub use rstat::RStatR;
123pub use xrd::Xrd;
124
125#[cfg(feature = "alloc")]
127#[derive(Debug, Clone, PartialEq, Eq)]
128#[non_exhaustive]
129#[allow(missing_docs)]
130pub enum Reply {
131 Ack(Ack),
132 Nak(Nak),
133 PdId(PdId),
134 PdCap(PdCap),
135 LStatR(LStatR),
136 IStatR(IStatR),
137 OStatR(OStatR),
138 RStatR(RStatR),
139 Raw(Raw),
140 Fmt(Fmt),
141 Keypad(Keypad),
142 Com(Com),
143 BioReadR(BioReadR),
144 BioMatchR(BioMatchR),
145 CCrypt(CCrypt),
146 RMacI(RMacI),
147 Busy(Busy),
148 FtStat(FtStat),
149 PivDataR(PivDataR),
150 GenAuthR(GenAuthR),
151 CrAuthR(CrAuthR),
152 MfgStatR(MfgStatR),
153 MfgErrR(MfgErrR),
154 MfgRep(MfgRep),
155 Xrd(Xrd),
156}
157
158#[cfg(feature = "alloc")]
159impl Reply {
160 pub fn code(&self) -> ReplyCode {
162 match self {
163 Reply::Ack(_) => ReplyCode::Ack,
164 Reply::Nak(_) => ReplyCode::Nak,
165 Reply::PdId(_) => ReplyCode::PdId,
166 Reply::PdCap(_) => ReplyCode::PdCap,
167 Reply::LStatR(_) => ReplyCode::LStatR,
168 Reply::IStatR(_) => ReplyCode::IStatR,
169 Reply::OStatR(_) => ReplyCode::OStatR,
170 Reply::RStatR(_) => ReplyCode::RStatR,
171 Reply::Raw(_) => ReplyCode::Raw,
172 Reply::Fmt(_) => ReplyCode::Fmt,
173 Reply::Keypad(_) => ReplyCode::Keypad,
174 Reply::Com(_) => ReplyCode::Com,
175 Reply::BioReadR(_) => ReplyCode::BioReadR,
176 Reply::BioMatchR(_) => ReplyCode::BioMatchR,
177 Reply::CCrypt(_) => ReplyCode::CCrypt,
178 Reply::RMacI(_) => ReplyCode::RMacI,
179 Reply::Busy(_) => ReplyCode::Busy,
180 Reply::FtStat(_) => ReplyCode::FtStat,
181 Reply::PivDataR(_) => ReplyCode::PivDataR,
182 Reply::GenAuthR(_) => ReplyCode::GenAuthR,
183 Reply::CrAuthR(_) => ReplyCode::CrAuthR,
184 Reply::MfgStatR(_) => ReplyCode::MfgStatR,
185 Reply::MfgErrR(_) => ReplyCode::MfgErrR,
186 Reply::MfgRep(_) => ReplyCode::MfgRep,
187 Reply::Xrd(_) => ReplyCode::Xrd,
188 }
189 }
190
191 pub fn encode_data(&self) -> Result<Vec<u8>, Error> {
193 match self {
194 Reply::Ack(r) => r.encode(),
195 Reply::Nak(r) => r.encode(),
196 Reply::PdId(r) => r.encode(),
197 Reply::PdCap(r) => r.encode(),
198 Reply::LStatR(r) => r.encode(),
199 Reply::IStatR(r) => r.encode(),
200 Reply::OStatR(r) => r.encode(),
201 Reply::RStatR(r) => r.encode(),
202 Reply::Raw(r) => r.encode(),
203 Reply::Fmt(r) => r.encode(),
204 Reply::Keypad(r) => r.encode(),
205 Reply::Com(r) => r.encode(),
206 Reply::BioReadR(r) => r.encode(),
207 Reply::BioMatchR(r) => r.encode(),
208 Reply::CCrypt(r) => r.encode(),
209 Reply::RMacI(r) => r.encode(),
210 Reply::Busy(r) => r.encode(),
211 Reply::FtStat(r) => r.encode(),
212 Reply::PivDataR(r) => r.encode(),
213 Reply::GenAuthR(r) => r.encode(),
214 Reply::CrAuthR(r) => r.encode(),
215 Reply::MfgStatR(r) => r.encode(),
216 Reply::MfgErrR(r) => r.encode(),
217 Reply::MfgRep(r) => r.encode(),
218 Reply::Xrd(r) => r.encode(),
219 }
220 }
221
222 pub fn decode(code: ReplyCode, data: &[u8]) -> Result<Self, Error> {
224 Ok(match code {
225 ReplyCode::Ack => Reply::Ack(Ack::decode(data)?),
226 ReplyCode::Nak => Reply::Nak(Nak::decode(data)?),
227 ReplyCode::PdId => Reply::PdId(PdId::decode(data)?),
228 ReplyCode::PdCap => Reply::PdCap(PdCap::decode(data)?),
229 ReplyCode::LStatR => Reply::LStatR(LStatR::decode(data)?),
230 ReplyCode::IStatR => Reply::IStatR(IStatR::decode(data)?),
231 ReplyCode::OStatR => Reply::OStatR(OStatR::decode(data)?),
232 ReplyCode::RStatR => Reply::RStatR(RStatR::decode(data)?),
233 ReplyCode::Raw => Reply::Raw(Raw::decode(data)?),
234 ReplyCode::Fmt => Reply::Fmt(Fmt::decode(data)?),
235 ReplyCode::Keypad => Reply::Keypad(Keypad::decode(data)?),
236 ReplyCode::Com => Reply::Com(Com::decode(data)?),
237 ReplyCode::BioReadR => Reply::BioReadR(BioReadR::decode(data)?),
238 ReplyCode::BioMatchR => Reply::BioMatchR(BioMatchR::decode(data)?),
239 ReplyCode::CCrypt => Reply::CCrypt(CCrypt::decode(data)?),
240 ReplyCode::RMacI => Reply::RMacI(RMacI::decode(data)?),
241 ReplyCode::Busy => Reply::Busy(Busy::decode(data)?),
242 ReplyCode::FtStat => Reply::FtStat(FtStat::decode(data)?),
243 ReplyCode::PivDataR => Reply::PivDataR(PivDataR::decode(data)?),
244 ReplyCode::GenAuthR => Reply::GenAuthR(GenAuthR::decode(data)?),
245 ReplyCode::CrAuthR => Reply::CrAuthR(CrAuthR::decode(data)?),
246 ReplyCode::MfgStatR => Reply::MfgStatR(MfgStatR::decode(data)?),
247 ReplyCode::MfgErrR => Reply::MfgErrR(MfgErrR::decode(data)?),
248 ReplyCode::MfgRep => Reply::MfgRep(MfgRep::decode(data)?),
249 ReplyCode::Xrd => Reply::Xrd(Xrd::decode(data)?),
250 })
251 }
252}
253
254#[cfg(test)]
255mod tests {
256 use super::*;
257
258 #[test]
259 fn code_roundtrip() {
260 for byte in [
261 0x40u8, 0x41, 0x45, 0x46, 0x48, 0x49, 0x4A, 0x4B, 0x50, 0x51, 0x53, 0x54, 0x57, 0x58,
262 0x76, 0x78, 0x79, 0x7A, 0x80, 0x81, 0x82, 0x83, 0x84, 0x90, 0xB1,
263 ] {
264 assert_eq!(ReplyCode::from_byte(byte).unwrap().as_byte(), byte);
265 }
266 }
267
268 #[test]
269 fn unknown_byte_errors() {
270 assert!(matches!(
271 ReplyCode::from_byte(0xFF),
272 Err(Error::UnknownReply(0xFF))
273 ));
274 }
275}