1use crate::error::Error;
9use alloc::vec::Vec;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
13#[repr(u8)]
14#[allow(missing_docs)]
15pub enum NakErrorCode {
16 NoError = 0x00,
17 BadCrcOrChecksum = 0x01,
18 CommandLengthError = 0x02,
19 UnknownCommandCode = 0x03,
20 UnexpectedSequenceNumber = 0x04,
21 SecurityBlockTypeNotSupported = 0x05,
22 EncryptedCommunicationRequired = 0x06,
23 BioTypeNotSupported = 0x07,
24 BioFormatNotSupported = 0x08,
25 UnableToProcessCommandRecord = 0x09,
26}
27
28impl NakErrorCode {
29 pub const fn from_byte(b: u8) -> Result<Self, Error> {
31 Ok(match b {
32 0x00 => Self::NoError,
33 0x01 => Self::BadCrcOrChecksum,
34 0x02 => Self::CommandLengthError,
35 0x03 => Self::UnknownCommandCode,
36 0x04 => Self::UnexpectedSequenceNumber,
37 0x05 => Self::SecurityBlockTypeNotSupported,
38 0x06 => Self::EncryptedCommunicationRequired,
39 0x07 => Self::BioTypeNotSupported,
40 0x08 => Self::BioFormatNotSupported,
41 0x09 => Self::UnableToProcessCommandRecord,
42 _ => {
43 return Err(Error::MalformedPayload {
44 code: 0x41,
45 reason: "unknown NAK error code",
46 });
47 }
48 })
49 }
50
51 pub const fn as_byte(self) -> u8 {
53 self as u8
54 }
55}
56
57#[derive(Debug, Clone, PartialEq, Eq)]
59pub struct Nak {
60 pub error: NakErrorCode,
62 pub completion_codes: Vec<u8>,
64}
65
66impl Nak {
67 pub fn simple(err: NakErrorCode) -> Self {
69 Self {
70 error: err,
71 completion_codes: Vec::new(),
72 }
73 }
74
75 pub fn encode(&self) -> Result<Vec<u8>, Error> {
77 let mut out = Vec::with_capacity(1 + self.completion_codes.len());
78 out.push(self.error.as_byte());
79 out.extend_from_slice(&self.completion_codes);
80 Ok(out)
81 }
82
83 pub fn decode(data: &[u8]) -> Result<Self, Error> {
87 if data.is_empty() {
88 return Err(Error::MalformedPayload {
89 code: 0x41,
90 reason: "NAK requires at least 1 byte",
91 });
92 }
93 let error = NakErrorCode::from_byte(data[0])?;
94 let completion_codes = if error == NakErrorCode::UnableToProcessCommandRecord {
95 data[1..].to_vec()
96 } else {
97 Vec::new()
98 };
99 Ok(Self {
100 error,
101 completion_codes,
102 })
103 }
104}
105
106#[cfg(test)]
107mod tests {
108 use super::*;
109
110 #[test]
111 fn simple_roundtrip() {
112 let n = Nak::simple(NakErrorCode::BadCrcOrChecksum);
113 let bytes = n.encode().unwrap();
114 let parsed = Nak::decode(&bytes).unwrap();
115 assert_eq!(parsed, n);
116 }
117
118 #[test]
119 fn record_completion_codes() {
120 let n = Nak {
121 error: NakErrorCode::UnableToProcessCommandRecord,
122 completion_codes: alloc::vec![0xAA, 0xBB, 0xCC],
123 };
124 let bytes = n.encode().unwrap();
125 let parsed = Nak::decode(&bytes).unwrap();
126 assert_eq!(parsed, n);
127 }
128
129 #[test]
130 fn rejects_unknown_code() {
131 assert!(Nak::decode(&[0xFE]).is_err());
132 }
133}