use crate::{
Error, NegativeResponseCode, SecurityAccessType, SingleValueWireFormat,
SuppressablePositiveResponse, WireFormat,
};
use byteorder::{ReadBytesExt, WriteBytesExt};
use std::io::{Read, Write};
const SECURITY_ACCESS_NEGATIVE_RESPONSE_CODES: [NegativeResponseCode; 8] = [
NegativeResponseCode::SubFunctionNotSupported,
NegativeResponseCode::IncorrectMessageLengthOrInvalidFormat,
NegativeResponseCode::ConditionsNotCorrect,
NegativeResponseCode::RequestSequenceError,
NegativeResponseCode::RequestOutOfRange,
NegativeResponseCode::InvalidKey,
NegativeResponseCode::ExceedNumberOfAttempts,
NegativeResponseCode::RequiredTimeDelayNotExpired,
];
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct SecurityAccessRequest {
access_type: SuppressablePositiveResponse<SecurityAccessType>,
request_data: Vec<u8>,
}
impl SecurityAccessRequest {
pub(crate) fn new(
suppress_positive_response: bool,
access_type: SecurityAccessType,
request_data: Vec<u8>,
) -> Self {
Self {
access_type: SuppressablePositiveResponse::new(suppress_positive_response, access_type),
request_data,
}
}
#[must_use]
pub fn suppress_positive_response(&self) -> bool {
self.access_type.suppress_positive_response()
}
#[must_use]
pub fn access_type(&self) -> SecurityAccessType {
self.access_type.value()
}
#[must_use]
pub fn request_data(&self) -> &[u8] {
&self.request_data
}
#[must_use]
pub fn allowed_nack_codes() -> &'static [NegativeResponseCode] {
&SECURITY_ACCESS_NEGATIVE_RESPONSE_CODES
}
}
impl WireFormat for SecurityAccessRequest {
fn decode<T: std::io::Read>(reader: &mut T) -> Result<Option<Self>, Error> {
let access_type = SuppressablePositiveResponse::try_from(reader.read_u8()?)?;
let mut request_data: Vec<u8> = Vec::new();
_ = reader.read_to_end(&mut request_data)?;
Ok(Some(Self {
access_type,
request_data,
}))
}
fn required_size(&self) -> usize {
1 + self.request_data().len()
}
fn encode<T: std::io::Write>(&self, writer: &mut T) -> Result<usize, Error> {
writer.write_u8(u8::from(self.access_type))?;
writer.write_all(&self.request_data)?;
Ok(self.required_size())
}
fn is_positive_response_suppressed(&self) -> bool {
self.suppress_positive_response()
}
}
impl SingleValueWireFormat for SecurityAccessRequest {}
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[derive(Clone, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub struct SecurityAccessResponse {
pub access_type: SecurityAccessType,
pub security_seed: Vec<u8>,
}
impl SecurityAccessResponse {
pub(crate) fn new(access_type: SecurityAccessType, security_seed: Vec<u8>) -> Self {
Self {
access_type,
security_seed,
}
}
}
impl WireFormat for SecurityAccessResponse {
fn decode<T: Read>(reader: &mut T) -> Result<Option<Self>, Error> {
let access_type = SecurityAccessType::try_from(reader.read_u8()?)?;
let mut security_seed = Vec::new();
let _ = reader.read_to_end(&mut security_seed)?;
Ok(Some(Self {
access_type,
security_seed,
}))
}
fn required_size(&self) -> usize {
1 + self.security_seed.len()
}
fn encode<T: Write>(&self, writer: &mut T) -> Result<usize, Error> {
writer.write_u8(u8::from(self.access_type))?;
writer.write_all(&self.security_seed)?;
Ok(self.required_size())
}
}
impl SingleValueWireFormat for SecurityAccessResponse {}
#[cfg(test)]
mod request {
use super::*;
#[test]
fn request_seed() {
let bytes: [u8; 6] = [
0x01, 0x00, 0x01, 0x02, 0x03, 0x04, ];
let req = SecurityAccessRequest::decode_single_value(&mut bytes.as_slice()).unwrap();
assert_eq!(
req.access_type,
SuppressablePositiveResponse::new(false, SecurityAccessType::RequestSeed(0x01))
);
let mut buf = Vec::new();
let written = req.encode(&mut buf).unwrap();
assert_eq!(written, bytes.len());
assert_eq!(written, req.required_size());
}
}
#[cfg(test)]
mod response {
use super::*;
#[test]
fn response_send() {
let bytes: [u8; 6] = [
0x02, 0x00, 0x01, 0x02, 0x03, 0x04, ];
let resp = SecurityAccessResponse::decode_single_value(&mut bytes.as_slice()).unwrap();
assert_eq!(resp.access_type, SecurityAccessType::SendKey(0x02));
assert_eq!(resp.security_seed, vec![0x00, 0x01, 0x02, 0x03, 0x04]);
let mut buf = Vec::new();
let written = resp.encode(&mut buf).unwrap();
assert_eq!(written, bytes.len());
assert_eq!(written, resp.required_size());
}
}