// Copyright 2019 Robin Krahl // SPDX-License-Identifier: GPL-3.0-or-later use core::default::Default; use core::marker::Sized; use crate::device::CommandStatus; pub const COMMAND_LEN: usize = 53; enum_cmd! { #[derive(Clone, Copy, Debug, PartialEq)] pub enum CommandId { GetStatus(GetStatusCommand) = 0, ReadSlotName(ReadSlotNameCommand) = 2, } } trait RequestData: Sized { fn from_bytes(data: &[u8]) -> Option; } impl RequestData for () { fn from_bytes(_data: &[u8]) -> Option { Some(()) } } trait ResponseData { fn write_bytes(&self, buf: &mut [u8]); } trait Command { type Request: RequestData; type Response: ResponseData; fn execute(data: Self::Request) -> Result; fn execute_raw(data: &[u8], buf: &mut [u8]) -> CommandStatus { if let Some(request) = Self::Request::from_bytes(data) { match Self::execute(request) { Ok(response) => { response.write_bytes(buf); CommandStatus::Ok } Err(status) => status, } } else { CommandStatus::NotSupported } } } #[derive(Debug, Default)] struct GetStatusResponse { firmware_version_minor: u8, firmware_version_major: u8, card_serial: u32, config_numlock: u8, config_capslock: u8, config_enable_user_password: u8, config_delete_user_password: u8, buf: [u8; 10], } impl ResponseData for GetStatusResponse { fn write_bytes(&self, buf: &mut [u8]) { let card_serial = self.card_serial.to_le_bytes(); let data = &[ self.firmware_version_minor, self.firmware_version_major, card_serial[0], card_serial[1], card_serial[2], card_serial[3], self.config_numlock, self.config_capslock, self.config_enable_user_password, self.config_delete_user_password, ]; assert!(buf.len() >= data.len()); buf[..data.len()].copy_from_slice(data); } } #[derive(Debug, Default)] struct GetStatusCommand {} impl Command for GetStatusCommand { type Request = (); type Response = GetStatusResponse; fn execute(_data: Self::Request) -> Result { let mut response: Self::Response = Default::default(); response.firmware_version_minor = 1; Ok(response) } } #[derive(Debug, Default)] struct ReadSlotNameRequest { internal_slot_number: u8, } impl RequestData for ReadSlotNameRequest { fn from_bytes(data: &[u8]) -> Option { if data.is_empty() { None } else { Some(ReadSlotNameRequest { internal_slot_number: data[0], }) } } } #[derive(Debug, Default)] struct ReadSlotNameResponse { slot_name: [u8; 15], } impl ResponseData for ReadSlotNameResponse { fn write_bytes(&self, buf: &mut [u8]) { assert!(buf.len() >= self.slot_name.len()); buf[..self.slot_name.len()].copy_from_slice(&self.slot_name) } } #[derive(Debug, Default)] struct ReadSlotNameCommand {} impl Command for ReadSlotNameCommand { type Request = ReadSlotNameRequest; type Response = ReadSlotNameResponse; fn execute(data: Self::Request) -> Result { if data.internal_slot_number != 0x20 { Err(CommandStatus::SlotNotProgrammed) } else { let mut response: Self::Response = Default::default(); response.slot_name[0] = 0x74; // t response.slot_name[1] = 0x65; // e response.slot_name[2] = 0x73; // s response.slot_name[3] = 0x74; // t Ok(response) } } }