Skip to content

Commit 2c10424

Browse files
authored
Merge pull request #19 from Sympatron/channel-rework
Allow for Channels to be easily shared between PDs
2 parents 84eaf60 + 2dcc94b commit 2c10424

File tree

11 files changed

+100
-77
lines changed

11 files changed

+100
-77
lines changed

libosdp/examples/cp.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,10 @@ fn main() -> Result<(), OsdpError> {
5757
.address(101)?
5858
.baud_rate(115200)?
5959
.flag(OsdpFlag::EnforceSecure)
60-
.channel(Box::new(channel))
61-
.secure_channel_key(pd_0_key)
62-
.build();
63-
let mut cp = libosdp::ControlPanel::new(vec![pd_0])?;
60+
.secure_channel_key(pd_0_key);
61+
let mut cp = libosdp::ControlPanelBuilder::new()
62+
.add_channel(Box::new(channel), vec![pd_0])
63+
.build()?;
6464
loop {
6565
cp.refresh();
6666
thread::sleep(Duration::from_millis(50));

libosdp/examples/pd.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,8 @@ fn main() -> Result<(), OsdpError> {
6060
.baud_rate(115200)?
6161
.flag(OsdpFlag::EnforceSecure)
6262
.capability(PdCapability::CommunicationSecurity(PdCapEntity::new(1, 1)))
63-
.channel(Box::new(channel))
64-
.secure_channel_key(key)
65-
.build();
66-
let mut pd = libosdp::PeripheralDevice::new(pd_info)?;
63+
.secure_channel_key(key);
64+
let mut pd = libosdp::PeripheralDevice::new(pd_info, Box::new(channel))?;
6765
pd.set_command_callback(|_| {
6866
println!("Received command!");
6967
0

libosdp/src/channel.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ impl<E: embedded_io::Error + Sized> From<E> for ChannelError {
5151

5252
/// The Channel trait acts as an interface for all channel implementors. See
5353
/// module description for the definition of a "channel" in LibOSDP.
54-
pub trait Channel: Send + Sync {
54+
pub trait Channel: Send {
5555
/// Since OSDP channels can be multi-drop (more than one PD can talk to a
5656
/// CP on the same channel) and LibOSDP supports mixing multi-drop
5757
/// connections among PDs it needs a way to identify each unique channel by

libosdp/src/cp.rs

+44-12
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
//! (PD) on the OSDP bus. It can send commands to and receive events from PDs.
88
99
use crate::{
10-
file::OsdpFileOps, OsdpCommand, OsdpError, OsdpEvent, OsdpFlag, PdCapability, PdId, PdInfo,
10+
file::OsdpFileOps, Channel, OsdpCommand, OsdpError, OsdpEvent, OsdpFlag, PdCapability, PdId,
11+
PdInfoBuilder,
1112
};
1213
use alloc::{boxed::Box, vec::Vec};
1314
use core::ffi::c_void;
@@ -64,27 +65,58 @@ fn cp_setup(info: Vec<crate::OsdpPdInfoHandle>) -> Result<*mut c_void> {
6465
}
6566
}
6667

67-
/// OSDP CP device context.
68-
#[derive(Debug)]
69-
pub struct ControlPanel {
70-
ctx: *mut core::ffi::c_void,
68+
/// Builder for creating a new `ControlPanel`.
69+
#[derive(Debug, Default)]
70+
pub struct ControlPanelBuilder {
71+
channel_pds: Vec<(Box<dyn Channel>, Vec<PdInfoBuilder>)>,
7172
}
7273

73-
unsafe impl Send for ControlPanel {}
74+
impl ControlPanelBuilder {
75+
/// Create a new instance of [`ControlPanelBuilder`].
76+
pub const fn new() -> Self {
77+
Self {
78+
channel_pds: Vec::new(),
79+
}
80+
}
7481

75-
impl ControlPanel {
76-
/// Create a new CP context for the list of PDs described by the [`PdInfo`] vector.
77-
pub fn new(pd_info: Vec<PdInfo>) -> Result<Self> {
78-
if pd_info.len() > 126 {
82+
/// Add a new PDs and their shared channel to the CP.
83+
pub fn add_channel(mut self, channel: Box<dyn Channel>, pd_info: Vec<PdInfoBuilder>) -> Self {
84+
self.channel_pds.push((channel, pd_info));
85+
self
86+
}
87+
88+
/// Build the [`ControlPanel`] instance.
89+
pub fn build(self) -> Result<ControlPanel> {
90+
if self.channel_pds.len() > 126 {
7991
return Err(OsdpError::PdInfo("max PD count exceeded"));
8092
}
81-
let info: Vec<crate::OsdpPdInfoHandle> = pd_info.into_iter().map(|i| i.into()).collect();
93+
let info: Vec<crate::OsdpPdInfoHandle> = self
94+
.channel_pds
95+
.into_iter()
96+
.map(|(channel, pd_info)| {
97+
let channel: libosdp_sys::osdp_channel = channel.into();
98+
pd_info
99+
.into_iter()
100+
.map(move |pd| pd.channel(channel).build().into())
101+
})
102+
.flatten()
103+
.collect();
82104
unsafe { libosdp_sys::osdp_set_log_callback(Some(log_handler)) };
83-
Ok(Self {
105+
Ok(ControlPanel {
84106
ctx: cp_setup(info)?,
85107
})
86108
}
109+
}
110+
111+
/// OSDP CP device context.
112+
#[derive(Debug)]
113+
pub struct ControlPanel {
114+
ctx: *mut core::ffi::c_void,
115+
}
87116

117+
unsafe impl Send for ControlPanel {}
118+
119+
impl ControlPanel {
88120
/// The application must call this method periodically to refresh the
89121
/// underlying LibOSDP state. To meet the OSDP timing guarantees, this
90122
/// function must be called at least once every 50ms. This method does not

libosdp/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ use alloc::{borrow::ToOwned, boxed::Box, format, string::String};
8888
#[cfg(feature = "std")]
8989
use thiserror::Error;
9090

91-
pub use cp::ControlPanel;
91+
pub use cp::{ControlPanel, ControlPanelBuilder};
9292
pub use pd::PeripheralDevice;
9393

9494
/// OSDP public errors

libosdp/src/pd.rs

+7-5
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@
1212
//! happens on the PD itself (such as card read, key press, etc.,) snd sends it
1313
//! to the CP.
1414
15-
use crate::{OsdpCommand, OsdpError, OsdpEvent, OsdpFileOps, PdCapability, PdInfo};
16-
use alloc::{boxed::Box, vec::Vec};
15+
use crate::{
16+
Box, Channel, OsdpCommand, OsdpError, OsdpEvent, OsdpFileOps, PdCapability, PdInfo,
17+
PdInfoBuilder,
18+
};
1719
use core::ffi::c_void;
1820
use log::{debug, error, info, warn};
1921

@@ -77,10 +79,10 @@ pub struct PeripheralDevice {
7779
unsafe impl Send for PeripheralDevice {}
7880

7981
impl PeripheralDevice {
80-
/// Create a new Peripheral panel object for the list of PDs described by the
81-
/// corresponding PdInfo struct.
82-
pub fn new(info: PdInfo) -> Result<Self> {
82+
/// Create a new Peripheral panel object for the PD described by the corresponding PdInfo struct.
83+
pub fn new(info: PdInfoBuilder, channel: Box<dyn Channel>) -> Result<Self> {
8384
unsafe { libosdp_sys::osdp_set_log_callback(Some(log_handler)) };
85+
let info = info.channel(channel.into()).build();
8486
Ok(Self {
8587
ctx: pd_setup(info)?,
8688
})

libosdp/src/pdinfo.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
//
44
// SPDX-License-Identifier: Apache-2.0
55

6-
use core::ops::Deref;
6+
use crate::{OsdpError, OsdpFlag, PdCapability, PdId};
77
use alloc::{boxed::Box, ffi::CString, format, string::String, vec::Vec};
8-
use crate::{Channel, OsdpError, OsdpFlag, PdCapability, PdId};
8+
use core::ops::Deref;
99

1010
/// OSDP PD Information. This struct is used to describe a PD to LibOSDP
1111
#[derive(Debug, Default)]
@@ -16,7 +16,7 @@ pub struct PdInfo {
1616
flags: OsdpFlag,
1717
id: PdId,
1818
cap: Vec<libosdp_sys::osdp_pd_cap>,
19-
channel: Option<Box<dyn Channel>>,
19+
channel: Option<libosdp_sys::osdp_channel>,
2020
scbk: Option<[u8; 16]>,
2121
}
2222
impl PdInfo {
@@ -142,7 +142,7 @@ pub struct PdInfoBuilder {
142142
flags: OsdpFlag,
143143
id: PdId,
144144
cap: Vec<libosdp_sys::osdp_pd_cap>,
145-
channel: Option<Box<dyn Channel>>,
145+
channel: Option<libosdp_sys::osdp_channel>,
146146
scbk: Option<[u8; 16]>,
147147
}
148148

@@ -217,7 +217,7 @@ impl PdInfoBuilder {
217217
}
218218

219219
/// Set Osdp communication channel
220-
pub fn channel(mut self, channel: Box<dyn Channel>) -> PdInfoBuilder {
220+
pub fn channel(mut self, channel: libosdp_sys::osdp_channel) -> PdInfoBuilder {
221221
self.channel = Some(channel);
222222
self
223223
}
@@ -284,7 +284,7 @@ impl From<PdInfo> for OsdpPdInfoHandle {
284284
flags: info.flags.bits() as i32,
285285
id: info.id.into(),
286286
cap: cap as *mut _,
287-
channel: info.channel.unwrap().into(),
287+
channel: info.channel.expect("no channel provided"),
288288
scbk,
289289
})
290290
}

libosdp/tests/common/device.rs

+8-10
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ use std::{
99
};
1010

1111
use libosdp::{
12-
ControlPanel, OsdpCommand, OsdpEvent, PdCapEntity, PdCapability, PdInfoBuilder,
13-
PeripheralDevice,
12+
ControlPanel, ControlPanelBuilder, OsdpCommand, OsdpEvent, PdCapEntity, PdCapability,
13+
PdInfoBuilder, PeripheralDevice,
1414
};
1515
type Result<T> = core::result::Result<T, libosdp::OsdpError>;
1616

@@ -32,10 +32,10 @@ impl CpDevice {
3232
.name("PD 101")?
3333
.address(101)?
3434
.baud_rate(115200)?
35-
.channel(bus)
36-
.secure_channel_key(pd_0_key)
37-
.build();
38-
let mut cp = ControlPanel::new(vec![pd_0])?;
35+
.secure_channel_key(pd_0_key);
36+
let mut cp = ControlPanelBuilder::new()
37+
.add_channel(bus, vec![pd_0])
38+
.build()?;
3939
let (event_tx, event_rx) = std::sync::mpsc::channel::<(i32, OsdpEvent)>();
4040

4141
cp.set_event_callback(|pd, event| {
@@ -90,10 +90,8 @@ impl PdDevice {
9090
.capability(PdCapability::CommunicationSecurity(PdCapEntity::new(1, 1)))
9191
.capability(PdCapability::AudibleOutput(PdCapEntity::new(1, 1)))
9292
.capability(PdCapability::LedControl(PdCapEntity::new(1, 1)))
93-
.channel(bus)
94-
.secure_channel_key(key)
95-
.build();
96-
let mut pd = PeripheralDevice::new(pd_info)?;
93+
.secure_channel_key(key);
94+
let mut pd = PeripheralDevice::new(pd_info, bus)?;
9795
let (cmd_tx, cmd_rx) = std::sync::mpsc::channel::<OsdpCommand>();
9896
pd.set_command_callback(|command| {
9997
cmd_tx.send(command).unwrap();

osdpctl/src/config.rs

+22-29
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@
66
use anyhow::bail;
77
use anyhow::Context;
88
use configparser::ini::Ini;
9-
use libosdp::PdInfoBuilder;
10-
use libosdp::{OsdpFlag, PdCapability, PdId, PdInfo};
9+
use libosdp::{ControlPanelBuilder, OsdpFlag, PdCapability, PdId, PdInfoBuilder};
1110
use rand::Rng;
1211
use std::{
1312
fmt::Write,
@@ -134,30 +133,26 @@ impl CpConfig {
134133
})
135134
}
136135

137-
pub fn pd_info(&self) -> Result<Vec<PdInfo>> {
136+
pub fn pd_info(&self) -> Result<ControlPanelBuilder> {
138137
let mut runtime_dir = self.runtime_dir.clone();
139138
runtime_dir.pop();
140-
self.pd_data
141-
.iter()
142-
.map(|d| {
143-
let parts: Vec<&str> = d.channel.split("::").collect();
144-
if parts[0] != "unix" {
145-
bail!("Only unix channel is supported for now")
146-
}
147-
let path = runtime_dir.join(format!("{}/{}.sock", d.name, parts[1]).as_str());
148-
let channel =
149-
UnixChannel::connect(&path).context("Unable to connect to PD channel")?;
150-
let pd_info = PdInfoBuilder::new()
151-
.name(&self.name)?
152-
.address(d.address)?
153-
.baud_rate(115200)?
154-
.flag(d.flags)
155-
.channel(Box::new(channel))
156-
.secure_channel_key(d.key_store.load()?)
157-
.build();
158-
Ok(pd_info)
159-
})
160-
.collect()
139+
let mut cp = ControlPanelBuilder::new();
140+
for d in self.pd_data.iter() {
141+
let parts: Vec<&str> = d.channel.split("::").collect();
142+
if parts[0] != "unix" {
143+
bail!("Only unix channel is supported for now")
144+
}
145+
let path = runtime_dir.join(format!("{}/{}.sock", d.name, parts[1]).as_str());
146+
let channel = UnixChannel::connect(&path).context("Unable to connect to PD channel")?;
147+
let pd_info = PdInfoBuilder::new()
148+
.name(&self.name)?
149+
.address(d.address)?
150+
.baud_rate(115200)?
151+
.flag(d.flags)
152+
.secure_channel_key(d.key_store.load()?);
153+
cp = cp.add_channel(Box::new(channel), vec![pd_info]);
154+
}
155+
Ok(cp)
161156
}
162157
}
163158

@@ -238,7 +233,7 @@ impl PdConfig {
238233
})
239234
}
240235

241-
pub fn pd_info(&self) -> Result<PdInfo> {
236+
pub fn pd_info(&self) -> Result<(Box<dyn libosdp::Channel>, PdInfoBuilder)> {
242237
let parts: Vec<&str> = self.channel.split("::").collect();
243238
if parts[0] != "unix" {
244239
bail!("Only unix channel is supported for now")
@@ -252,10 +247,8 @@ impl PdConfig {
252247
.flag(self.flags)
253248
.capabilities(&self.pd_cap)
254249
.id(&self.pd_id)
255-
.channel(Box::new(channel))
256-
.secure_channel_key(self.key_store.load()?)
257-
.build();
258-
Ok(pd_info)
250+
.secure_channel_key(self.key_store.load()?);
251+
Ok((Box::new(channel), pd_info))
259252
}
260253
}
261254

osdpctl/src/cp.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use std::{thread, time::Duration};
77

88
use crate::config::CpConfig;
99
use anyhow::Context;
10-
use libosdp::{ControlPanel, OsdpEvent};
10+
use libosdp::OsdpEvent;
1111
use std::io::Write;
1212

1313
type Result<T> = anyhow::Result<T, anyhow::Error>;
@@ -29,8 +29,8 @@ fn setup(dev: &CpConfig, daemonize: bool) -> Result<()> {
2929

3030
pub fn main(dev: CpConfig, daemonize: bool) -> Result<()> {
3131
setup(&dev, daemonize)?;
32-
let pd_info = dev.pd_info().context("Failed to create PD info list")?;
33-
let mut cp = ControlPanel::new(pd_info)?;
32+
let cp = dev.pd_info().context("Failed to create PD info list")?;
33+
let mut cp = cp.build()?;
3434
cp.set_event_callback(|pd, event| {
3535
match event {
3636
OsdpEvent::CardRead(e) => {

osdpctl/src/pd.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ fn setup(dev: &PdConfig, daemonize: bool) -> Result<()> {
2929

3030
pub fn main(dev: PdConfig, daemonize: bool) -> Result<()> {
3131
setup(&dev, daemonize)?;
32-
let pd_info = dev.pd_info().context("Failed to create PD info")?;
33-
let mut pd = PeripheralDevice::new(pd_info)?;
32+
let (channel, pd_info) = dev.pd_info().context("Failed to create PD info")?;
33+
let mut pd = PeripheralDevice::new(pd_info, channel)?;
3434
pd.set_command_callback(|command| {
3535
match command {
3636
OsdpCommand::Led(c) => {

0 commit comments

Comments
 (0)