// Copyright 2019 Robin Krahl // SPDX-License-Identifier: GPL-3.0-or-later use core::default::Default; use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; use crate::device::{CommandStatus, RequestData, ResponseData}; enum_cmd! { #[derive(Clone, Copy, Debug, PartialEq)] pub enum CommandId { GetStatus(GetStatusCommand) = 0, ReadSlotName(ReadSlotNameCommand) = 2, } } trait Command { type Request: DeserializeOwned; type Response: Serialize; fn execute(data: Self::Request) -> Result; } #[derive(Debug, Default, Serialize)] 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, } assert_maximum_size!(GetStatusResponse, crate::device::RESPONSE_DATA_LEN); #[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, Deserialize)] struct ReadSlotNameRequest { internal_slot_number: u8, } assert_maximum_size!(ReadSlotNameRequest, crate::device::REQUEST_DATA_LEN); #[derive(Debug, Default, Serialize)] struct ReadSlotNameResponse { slot_name: [u8; 15], } assert_maximum_size!(ReadSlotNameResponse, crate::device::RESPONSE_DATA_LEN); #[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) } } } fn execute(data: &RequestData, buf: &mut ResponseData) -> CommandStatus { // TODO: better error if (de-)serialization fails if let Ok((request, _)) = ssmarshal::deserialize::(data) { match C::execute(request) { Ok(response) => match ssmarshal::serialize(buf, &response) { Ok(_) => CommandStatus::Ok, Err(_) => CommandStatus::NotSupported, }, Err(status) => status, } } else { CommandStatus::NotSupported } }