use crate::OsdpError;
use alloc::vec::Vec;
use serde::{Deserialize, Serialize};
use super::ConvertEndian;
type Result<T> = core::result::Result<T, OsdpError>;
#[cfg(feature = "defmt-03")]
use defmt::panic;
#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "defmt-03", derive(defmt::Format))]
pub enum OsdpCardFormats {
#[default]
Unspecified,
Wiegand,
}
impl From<libosdp_sys::osdp_event_cardread_format_e> for OsdpCardFormats {
fn from(value: libosdp_sys::osdp_event_cardread_format_e) -> Self {
match value {
libosdp_sys::osdp_event_cardread_format_e_OSDP_CARD_FMT_RAW_UNSPECIFIED => {
OsdpCardFormats::Unspecified
}
libosdp_sys::osdp_event_cardread_format_e_OSDP_CARD_FMT_RAW_WIEGAND => {
OsdpCardFormats::Wiegand
}
_ => panic!("Unknown osdp card format"),
}
}
}
impl From<OsdpCardFormats> for libosdp_sys::osdp_event_cardread_format_e {
fn from(val: OsdpCardFormats) -> Self {
match val {
OsdpCardFormats::Unspecified => {
libosdp_sys::osdp_event_cardread_format_e_OSDP_CARD_FMT_RAW_UNSPECIFIED
}
OsdpCardFormats::Wiegand => {
libosdp_sys::osdp_event_cardread_format_e_OSDP_CARD_FMT_RAW_WIEGAND
}
}
}
}
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "defmt-03", derive(defmt::Format))]
pub struct OsdpEventCardRead {
pub reader_no: i32,
pub format: OsdpCardFormats,
pub direction: bool,
pub nr_bits: usize,
pub data: Vec<u8>,
}
impl OsdpEventCardRead {
pub fn new_raw(data: Vec<u8>) -> Self {
Self {
reader_no: 0,
format: OsdpCardFormats::Unspecified,
direction: false,
nr_bits: data.len() * 8,
data,
}
}
pub fn new_wiegand(nr_bits: usize, data: Vec<u8>) -> Result<Self> {
if nr_bits > data.len() * 8 {
return Err(OsdpError::Command);
}
Ok(Self {
reader_no: 0,
format: OsdpCardFormats::Wiegand,
direction: false,
nr_bits,
data,
})
}
}
impl From<libosdp_sys::osdp_event_cardread> for OsdpEventCardRead {
fn from(value: libosdp_sys::osdp_event_cardread) -> Self {
let direction = value.direction == 1;
let format = value.format.into();
let len = value.length as usize;
let (nr_bits, nr_bytes) = (len, len.div_ceil(8));
let data = value.data[0..nr_bytes].to_vec();
OsdpEventCardRead {
reader_no: value.reader_no,
format,
direction,
nr_bits,
data,
}
}
}
impl From<OsdpEventCardRead> for libosdp_sys::osdp_event_cardread {
fn from(value: OsdpEventCardRead) -> Self {
let mut data = [0; libosdp_sys::OSDP_EVENT_CARDREAD_MAX_DATALEN as usize];
let length = value.nr_bits as i32;
data[..value.data.len()].copy_from_slice(&value.data[..]);
libosdp_sys::osdp_event_cardread {
reader_no: value.reader_no,
format: value.format.into(),
direction: value.direction as i32,
length,
data,
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[cfg_attr(feature = "defmt-03", derive(defmt::Format))]
pub struct OsdpEventKeyPress {
pub reader_no: i32,
pub data: Vec<u8>,
}
impl OsdpEventKeyPress {
pub fn new(data: Vec<u8>) -> Self {
Self { reader_no: 0, data }
}
}
impl From<libosdp_sys::osdp_event_keypress> for OsdpEventKeyPress {
fn from(value: libosdp_sys::osdp_event_keypress) -> Self {
let n = value.length as usize;
let data = value.data[0..n].to_vec();
OsdpEventKeyPress {
reader_no: value.reader_no,
data,
}
}
}
impl From<OsdpEventKeyPress> for libosdp_sys::osdp_event_keypress {
fn from(value: OsdpEventKeyPress) -> Self {
let mut data = [0; libosdp_sys::OSDP_EVENT_KEYPRESS_MAX_DATALEN as usize];
data[..value.data.len()].copy_from_slice(&value.data[..]);
libosdp_sys::osdp_event_keypress {
reader_no: value.reader_no,
length: value.data.len() as i32,
data,
}
}
}
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "defmt-03", derive(defmt::Format))]
pub struct OsdpEventMfgReply {
pub vendor_code: (u8, u8, u8),
pub data: Vec<u8>,
}
impl From<libosdp_sys::osdp_event_mfgrep> for OsdpEventMfgReply {
fn from(value: libosdp_sys::osdp_event_mfgrep) -> Self {
let n = value.length as usize;
let data = value.data[0..n].to_vec();
let bytes = value.vendor_code.to_le_bytes();
let vendor_code: (u8, u8, u8) = (bytes[0], bytes[1], bytes[2]);
OsdpEventMfgReply {
vendor_code,
data,
}
}
}
impl From<OsdpEventMfgReply> for libosdp_sys::osdp_event_mfgrep {
fn from(value: OsdpEventMfgReply) -> Self {
let mut data = [0; libosdp_sys::OSDP_EVENT_MFGREP_MAX_DATALEN as usize];
data[..value.data.len()].copy_from_slice(&value.data[..]);
libosdp_sys::osdp_event_mfgrep {
vendor_code: value.vendor_code.as_le(),
length: value.data.len() as u8,
data,
}
}
}
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "defmt-03", derive(defmt::Format))]
pub enum OsdpStatusReportType {
Input,
Output,
Remote,
Local,
}
impl From<libosdp_sys::osdp_status_report_type> for OsdpStatusReportType {
fn from(value: libosdp_sys::osdp_status_report_type) -> Self {
match value {
libosdp_sys::osdp_status_report_type_OSDP_STATUS_REPORT_INPUT => {
OsdpStatusReportType::Input
}
libosdp_sys::osdp_status_report_type_OSDP_STATUS_REPORT_OUTPUT => {
OsdpStatusReportType::Output
}
libosdp_sys::osdp_status_report_type_OSDP_STATUS_REPORT_REMOTE => {
OsdpStatusReportType::Remote
}
libosdp_sys::osdp_status_report_type_OSDP_STATUS_REPORT_LOCAL => {
OsdpStatusReportType::Local
}
_ => panic!("Invalid enum entry"),
}
}
}
impl From<OsdpStatusReportType> for libosdp_sys::osdp_status_report_type {
fn from(value: OsdpStatusReportType) -> Self {
match value {
OsdpStatusReportType::Input => {
libosdp_sys::osdp_status_report_type_OSDP_STATUS_REPORT_INPUT
}
OsdpStatusReportType::Output => {
libosdp_sys::osdp_status_report_type_OSDP_STATUS_REPORT_OUTPUT
}
OsdpStatusReportType::Remote => {
libosdp_sys::osdp_status_report_type_OSDP_STATUS_REPORT_REMOTE
}
OsdpStatusReportType::Local => {
libosdp_sys::osdp_status_report_type_OSDP_STATUS_REPORT_LOCAL
}
}
}
}
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "defmt-03", derive(defmt::Format))]
pub struct OsdpStatusReport {
pub type_: OsdpStatusReportType,
pub nr_entries: usize,
#[serde(with = "serde_arrays")]
pub report: [u8; 64],
}
impl From<libosdp_sys::osdp_status_report> for OsdpStatusReport {
fn from(value: libosdp_sys::osdp_status_report) -> Self {
OsdpStatusReport {
type_: value.type_.into(),
nr_entries: value.nr_entries as usize,
report: value.report,
}
}
}
impl From<OsdpStatusReport> for libosdp_sys::osdp_status_report {
fn from(value: OsdpStatusReport) -> Self {
libosdp_sys::osdp_status_report {
type_: value.type_.into(),
nr_entries: value.nr_entries as i32,
report: value.report,
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[cfg_attr(feature = "defmt-03", derive(defmt::Format))]
pub enum OsdpEvent {
CardRead(OsdpEventCardRead),
KeyPress(OsdpEventKeyPress),
MfgReply(OsdpEventMfgReply),
Status(OsdpStatusReport),
}
impl From<OsdpEvent> for libosdp_sys::osdp_event {
fn from(value: OsdpEvent) -> Self {
match value {
OsdpEvent::CardRead(e) => libosdp_sys::osdp_event {
type_: libosdp_sys::osdp_event_type_OSDP_EVENT_CARDREAD,
flags: 0,
__bindgen_anon_1: libosdp_sys::osdp_event__bindgen_ty_1 {
cardread: e.clone().into(),
},
},
OsdpEvent::KeyPress(e) => libosdp_sys::osdp_event {
type_: libosdp_sys::osdp_event_type_OSDP_EVENT_KEYPRESS,
flags: 0,
__bindgen_anon_1: libosdp_sys::osdp_event__bindgen_ty_1 {
keypress: e.clone().into(),
},
},
OsdpEvent::MfgReply(e) => libosdp_sys::osdp_event {
type_: libosdp_sys::osdp_event_type_OSDP_EVENT_MFGREP,
flags: 0,
__bindgen_anon_1: libosdp_sys::osdp_event__bindgen_ty_1 {
mfgrep: e.clone().into(),
},
},
OsdpEvent::Status(e) => libosdp_sys::osdp_event {
type_: libosdp_sys::osdp_event_type_OSDP_EVENT_STATUS,
flags: 0,
__bindgen_anon_1: libosdp_sys::osdp_event__bindgen_ty_1 { status: e.into() },
},
}
}
}
impl From<libosdp_sys::osdp_event> for OsdpEvent {
fn from(value: libosdp_sys::osdp_event) -> Self {
match value.type_ {
libosdp_sys::osdp_event_type_OSDP_EVENT_CARDREAD => {
OsdpEvent::CardRead(unsafe { value.__bindgen_anon_1.cardread.into() })
}
libosdp_sys::osdp_event_type_OSDP_EVENT_KEYPRESS => {
OsdpEvent::KeyPress(unsafe { value.__bindgen_anon_1.keypress.into() })
}
libosdp_sys::osdp_event_type_OSDP_EVENT_MFGREP => {
OsdpEvent::MfgReply(unsafe { value.__bindgen_anon_1.mfgrep.into() })
}
libosdp_sys::osdp_event_type_OSDP_EVENT_STATUS => {
OsdpEvent::Status(unsafe { value.__bindgen_anon_1.status.into() })
}
_ => panic!("Unknown event"),
}
}
}
#[cfg(test)]
mod tests {
use super::OsdpEventCardRead;
use libosdp_sys::{
osdp_event_cardread, osdp_event_cardread_format_e_OSDP_CARD_FMT_RAW_UNSPECIFIED,
osdp_event_cardread_format_e_OSDP_CARD_FMT_RAW_WIEGAND,
};
#[test]
fn test_event_cardread() {
let event = OsdpEventCardRead::new_raw(vec![0x55, 0xAA]);
let event_struct: osdp_event_cardread = event.clone().into();
assert_eq!(event_struct.length, 2 * 8);
assert_eq!(event_struct.direction, 0);
assert_eq!(
event_struct.format,
osdp_event_cardread_format_e_OSDP_CARD_FMT_RAW_UNSPECIFIED
);
assert_eq!(event_struct.data[0], 0x55);
assert_eq!(event_struct.data[1], 0xAA);
assert_eq!(event, event_struct.into());
let event = OsdpEventCardRead::new_wiegand(15, vec![0x55, 0xAA]).unwrap();
let event_struct: osdp_event_cardread = event.clone().into();
assert_eq!(event_struct.length, 15);
assert_eq!(event_struct.direction, 0);
assert_eq!(
event_struct.format,
osdp_event_cardread_format_e_OSDP_CARD_FMT_RAW_WIEGAND
);
assert_eq!(event_struct.data[0], 0x55);
assert_eq!(event_struct.data[1], 0xAA);
assert_eq!(event, event_struct.into());
}
}