diff --git a/libosdp/src/commands.rs b/libosdp/src/commands.rs index 296ebad..2f65426 100644 --- a/libosdp/src/commands.rs +++ b/libosdp/src/commands.rs @@ -7,12 +7,15 @@ //! are specified by OSDP specification. This module is responsible to handling //! such commands though [`OsdpCommand`]. +use crate::OsdpError; use crate::OsdpStatusReport; use alloc::vec::Vec; use serde::{Deserialize, Serialize}; use super::ConvertEndian; +type Result = core::result::Result; + /// LED Colors as specified in OSDP for the on_color/off_color parameters. #[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, PartialEq, Eq, Hash)] pub enum OsdpLedColor { @@ -37,6 +40,9 @@ pub enum OsdpLedColor { /// Cyan Color Cyan, + + /// Unknown/Unsupported Color + Unknown(u8), } impl From for OsdpLedColor { @@ -49,7 +55,7 @@ impl From for OsdpLedColor { libosdp_sys::osdp_led_color_e_OSDP_LED_COLOR_BLUE => OsdpLedColor::Blue, libosdp_sys::osdp_led_color_e_OSDP_LED_COLOR_MAGENTA => OsdpLedColor::Magenta, libosdp_sys::osdp_led_color_e_OSDP_LED_COLOR_CYAN => OsdpLedColor::Cyan, - _ => panic!("Invalid LED color code"), + cc => OsdpLedColor::Unknown(cc), } } } @@ -64,6 +70,7 @@ impl From for u8 { OsdpLedColor::Blue => libosdp_sys::osdp_led_color_e_OSDP_LED_COLOR_BLUE as u8, OsdpLedColor::Magenta => libosdp_sys::osdp_led_color_e_OSDP_LED_COLOR_MAGENTA as u8, OsdpLedColor::Cyan => libosdp_sys::osdp_led_color_e_OSDP_LED_COLOR_CYAN as u8, + OsdpLedColor::Unknown(cc) => cc, } } } @@ -583,40 +590,43 @@ impl From for libosdp_sys::osdp_cmd { } } -impl From for OsdpCommand { - fn from(value: libosdp_sys::osdp_cmd) -> Self { +impl TryFrom for OsdpCommand { + type Error = OsdpError; + + fn try_from(value: libosdp_sys::osdp_cmd) -> Result { match value.id { libosdp_sys::osdp_cmd_e_OSDP_CMD_LED => { - OsdpCommand::Led(unsafe { value.__bindgen_anon_1.led.into() }) + Ok(OsdpCommand::Led(unsafe { value.__bindgen_anon_1.led.into() })) } libosdp_sys::osdp_cmd_e_OSDP_CMD_BUZZER => { - OsdpCommand::Buzzer(unsafe { value.__bindgen_anon_1.buzzer.into() }) + Ok(OsdpCommand::Buzzer(unsafe { value.__bindgen_anon_1.buzzer.into() })) } libosdp_sys::osdp_cmd_e_OSDP_CMD_TEXT => { - OsdpCommand::Text(unsafe { value.__bindgen_anon_1.text.into() }) + Ok(OsdpCommand::Text(unsafe { value.__bindgen_anon_1.text.into() })) } libosdp_sys::osdp_cmd_e_OSDP_CMD_OUTPUT => { - OsdpCommand::Output(unsafe { value.__bindgen_anon_1.output.into() }) + Ok(OsdpCommand::Output(unsafe { value.__bindgen_anon_1.output.into() })) } libosdp_sys::osdp_cmd_e_OSDP_CMD_COMSET => { - OsdpCommand::ComSet(unsafe { value.__bindgen_anon_1.comset.into() }) + Ok(OsdpCommand::ComSet(unsafe { value.__bindgen_anon_1.comset.into() })) } libosdp_sys::osdp_cmd_e_OSDP_CMD_COMSET_DONE => { - OsdpCommand::ComSetDone(unsafe { value.__bindgen_anon_1.comset.into() }) + Ok(OsdpCommand::ComSetDone(unsafe { value.__bindgen_anon_1.comset.into() })) } libosdp_sys::osdp_cmd_e_OSDP_CMD_KEYSET => { - OsdpCommand::KeySet(unsafe { value.__bindgen_anon_1.keyset.into() }) + Ok(OsdpCommand::KeySet(unsafe { value.__bindgen_anon_1.keyset.into() })) } libosdp_sys::osdp_cmd_e_OSDP_CMD_MFG => { - OsdpCommand::Mfg(unsafe { value.__bindgen_anon_1.mfg.into() }) + Ok(OsdpCommand::Mfg(unsafe { value.__bindgen_anon_1.mfg.into() })) } libosdp_sys::osdp_cmd_e_OSDP_CMD_FILE_TX => { - OsdpCommand::FileTx(unsafe { value.__bindgen_anon_1.file_tx.into() }) + Ok(OsdpCommand::FileTx(unsafe { value.__bindgen_anon_1.file_tx.into() })) } libosdp_sys::osdp_cmd_e_OSDP_CMD_STATUS => { - OsdpCommand::Status(unsafe { value.__bindgen_anon_1.status.into() }) + let data = unsafe { value.__bindgen_anon_1.status.try_into() }?; + Ok(OsdpCommand::Status(data)) } - _ => panic!("Unknown event"), + _ => Err(OsdpError::Parse("Unknown event".into())), } } } diff --git a/libosdp/src/cp.rs b/libosdp/src/cp.rs index 49a3a01..d476e8a 100644 --- a/libosdp/src/cp.rs +++ b/libosdp/src/cp.rs @@ -47,9 +47,13 @@ extern "C" fn trampoline(data: *mut c_void, pd: i32, event: *mut libosdp_sys: where F: FnMut(i32, OsdpEvent) -> i32, { - let event: OsdpEvent = unsafe { (*event).into() }; - let callback: &mut F = unsafe { &mut *(data as *mut F) }; - callback(pd, event) + match unsafe { (*event).try_into() } { + Ok(event) => { + let callback: &mut F = unsafe { &mut *(data as *mut F) }; + callback(pd, event) + }, + Err(_) => -1, // Failed to parse the event data -> Send NAK + } } type EventCallback = @@ -178,7 +182,7 @@ impl ControlPanel { if rc < 0 { Err(OsdpError::Query("capability")) } else { - Ok(cap.into()) + Ok(cap.try_into()?) } } diff --git a/libosdp/src/events.rs b/libosdp/src/events.rs index 71db220..06dce29 100644 --- a/libosdp/src/events.rs +++ b/libosdp/src/events.rs @@ -9,7 +9,7 @@ //! module is responsible to handling such events though [`OsdpEvent`]. use crate::OsdpError; -use alloc::vec::Vec; +use alloc::{vec::Vec, format}; use serde::{Deserialize, Serialize}; use super::ConvertEndian; @@ -32,16 +32,18 @@ pub enum OsdpCardFormats { Wiegand, } -impl From for OsdpCardFormats { - fn from(value: libosdp_sys::osdp_event_cardread_format_e) -> Self { +impl TryFrom for OsdpCardFormats { + type Error = OsdpError; + + fn try_from(value: libosdp_sys::osdp_event_cardread_format_e) -> Result { match value { libosdp_sys::osdp_event_cardread_format_e_OSDP_CARD_FMT_RAW_UNSPECIFIED => { - OsdpCardFormats::Unspecified + Ok(OsdpCardFormats::Unspecified) } libosdp_sys::osdp_event_cardread_format_e_OSDP_CARD_FMT_RAW_WIEGAND => { - OsdpCardFormats::Wiegand + Ok(OsdpCardFormats::Wiegand) } - _ => panic!("Unknown osdp card format"), + cf => Err(OsdpError::Parse(format!("Unknown card format ({cf})").into())), } } } @@ -117,20 +119,21 @@ impl OsdpEventCardRead { } } -impl From for OsdpEventCardRead { - fn from(value: libosdp_sys::osdp_event_cardread) -> Self { - let direction = value.direction == 1; - let format = value.format.into(); +impl TryFrom for OsdpEventCardRead { + type Error = OsdpError; + + fn try_from(value: libosdp_sys::osdp_event_cardread) -> Result { + let format = value.format.try_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 { + + Ok(OsdpEventCardRead { reader_no: value.reader_no, format, - direction, + direction: value.direction == 1, nr_bits, - data, - } + data: value.data[0..nr_bytes].to_vec(), + }) } } @@ -245,22 +248,24 @@ pub enum OsdpStatusReportType { Local, } -impl From for OsdpStatusReportType { - fn from(value: libosdp_sys::osdp_status_report_type) -> Self { +impl TryFrom for OsdpStatusReportType { + type Error = OsdpError; + + fn try_from(value: libosdp_sys::osdp_status_report_type) -> Result { match value { libosdp_sys::osdp_status_report_type_OSDP_STATUS_REPORT_INPUT => { - OsdpStatusReportType::Input + Ok(OsdpStatusReportType::Input) } libosdp_sys::osdp_status_report_type_OSDP_STATUS_REPORT_OUTPUT => { - OsdpStatusReportType::Output + Ok(OsdpStatusReportType::Output) } libosdp_sys::osdp_status_report_type_OSDP_STATUS_REPORT_REMOTE => { - OsdpStatusReportType::Remote + Ok(OsdpStatusReportType::Remote) } libosdp_sys::osdp_status_report_type_OSDP_STATUS_REPORT_LOCAL => { - OsdpStatusReportType::Local + Ok(OsdpStatusReportType::Local) } - _ => panic!("Invalid enum entry"), + rt => Err(OsdpError::Parse(format!("Unknown report type ({rt})").into())), } } } @@ -304,13 +309,15 @@ pub struct OsdpStatusReport { pub report: [u8; 64], } -impl From for OsdpStatusReport { - fn from(value: libosdp_sys::osdp_status_report) -> Self { - OsdpStatusReport { - type_: value.type_.into(), +impl TryFrom for OsdpStatusReport { + type Error = OsdpError; + + fn try_from(value: libosdp_sys::osdp_status_report) -> Result { + Ok(OsdpStatusReport { + type_: value.type_.try_into()?, nr_entries: value.nr_entries as usize, report: value.report, - } + }) } } @@ -377,22 +384,26 @@ impl From for libosdp_sys::osdp_event { } } -impl From for OsdpEvent { - fn from(value: libosdp_sys::osdp_event) -> Self { +impl TryFrom for OsdpEvent { + type Error = OsdpError; + + fn try_from(value: libosdp_sys::osdp_event) -> Result { match value.type_ { libosdp_sys::osdp_event_type_OSDP_EVENT_CARDREAD => { - OsdpEvent::CardRead(unsafe { value.__bindgen_anon_1.cardread.into() }) + let data = unsafe { value.__bindgen_anon_1.cardread.try_into() }?; + Ok(OsdpEvent::CardRead(data)) } libosdp_sys::osdp_event_type_OSDP_EVENT_KEYPRESS => { - OsdpEvent::KeyPress(unsafe { value.__bindgen_anon_1.keypress.into() }) + Ok(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() }) + Ok(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() }) + let data = unsafe { value.__bindgen_anon_1.status.try_into() }?; + Ok(OsdpEvent::Status(data)) } - _ => panic!("Unknown event"), + et => Err(OsdpError::Parse(format!("Unknown event ({et})").into())), } } } @@ -419,7 +430,7 @@ mod tests { assert_eq!(event_struct.data[0], 0x55); assert_eq!(event_struct.data[1], 0xAA); - assert_eq!(event, event_struct.into()); + assert_eq!(event, event_struct.try_into().unwrap()); let event = OsdpEventCardRead::new_wiegand(15, vec![0x55, 0xAA]).unwrap(); let event_struct: osdp_event_cardread = event.clone().into(); @@ -433,6 +444,6 @@ mod tests { assert_eq!(event_struct.data[0], 0x55); assert_eq!(event_struct.data[1], 0xAA); - assert_eq!(event, event_struct.into()); + assert_eq!(event, event_struct.try_into().unwrap()); } } diff --git a/libosdp/src/pd.rs b/libosdp/src/pd.rs index cdffb9a..f7bb4f8 100644 --- a/libosdp/src/pd.rs +++ b/libosdp/src/pd.rs @@ -54,14 +54,17 @@ extern "C" fn trampoline(data_ptr: *mut c_void, cmd_ptr: *mut libosdp_sys::os where F: FnMut(&mut OsdpCommand) -> i32, { - let mut cmd: OsdpCommand = unsafe { cmd_ptr.read().into() }; - let callback: &mut F = unsafe { &mut *(data_ptr as *mut F) }; - let res = callback(&mut cmd); - // TODO: Free data_ptr's box? - unsafe { - cmd_ptr.write(cmd.into()); + match unsafe { cmd_ptr.read().try_into() } { + Ok(mut cmd) => { + let callback: &mut F = unsafe { &mut *(data_ptr as *mut F) }; + let res = callback(&mut cmd); + unsafe { + cmd_ptr.write(cmd.into()); + } + res + }, + Err(_) => -1, // Failed to parse the command data -> Send NAK } - res } fn get_trampoline(_closure: &F) -> CommandCallback diff --git a/libosdp/src/pdcap.rs b/libosdp/src/pdcap.rs index 0d0556a..9701bbe 100644 --- a/libosdp/src/pdcap.rs +++ b/libosdp/src/pdcap.rs @@ -146,6 +146,9 @@ pub enum PdCapability { /// 1 - IEC 60839-11-5 /// 2 - SIA OSDP 2.2 OsdpVersion(PdCapEntity), + + /// Unknown/Unsupported capability + Unknown(u8, PdCapEntity), } #[rustfmt::skip] @@ -267,7 +270,7 @@ impl From for PdCapability { libosdp_sys::osdp_pd_cap_function_code_e_OSDP_PD_CAP_OSDP_VERSION => { PdCapability::OsdpVersion(e) } - _ => panic!("Unknown function code"), + fc => PdCapability::Unknown(fc, e) } } } @@ -324,6 +327,7 @@ impl From for u8 { PdCapability::OsdpVersion(_) => { libosdp_sys::osdp_pd_cap_function_code_e_OSDP_PD_CAP_OSDP_VERSION as u8 } + PdCapability::Unknown(fc, _) => fc } } } @@ -412,6 +416,11 @@ impl From for libosdp_sys::osdp_pd_cap { compliance_level: e.compliance, num_items: e.num_items, }, + PdCapability::Unknown(_, e) => libosdp_sys::osdp_pd_cap { + function_code, + compliance_level: e.compliance, + num_items: e.num_items, + }, } } }