goToMain / libosdp

Implementation of IEC 60839-11-5 OSDP (Open Supervised Device Protocol); provides a C library with support for C++, Rust and Python3
https://libosdp.sidcha.dev
Apache License 2.0
140 stars 73 forks source link

Connection could not be established in Rust project #147

Closed Sympatron closed 11 months ago

Sympatron commented 11 months ago

Connection could not be established in Rust project. I tried running the CP and a PD in the same program in different threads. But the two could not communicate successfully. I am running this in WSL so maybe that's the problem. Can somebody confirm this?

main.rs:

use libosdp::{
    channel::{OsdpChannel, UnixChannel},
    cp::ControlPanel,
    pd::PeripheralDevice,
    OsdpError, OsdpFlag, PdCapEntity, PdCapability, PdId, PdInfo,
};
use std::{result::Result, thread, time::Duration};

const SCBK: [u8; 16] = [
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
];

fn main() -> Result<(), Box<dyn std::any::Any + Send>> {
    env_logger::builder()
        .filter_level(log::LevelFilter::Trace)
        .format_target(false)
        .format_timestamp(None)
        .init();

    let pd = thread::spawn(|| {
        pd().ok();
    });
    thread::sleep(Duration::from_millis(150));
    let cp = thread::spawn(|| {
        cp().ok();
    });

    pd.join()?;
    cp.join()
}

fn cp() -> Result<(), OsdpError> {
    let stream = UnixChannel::connect("conn-1")?;
    let pd_info = vec![PdInfo::for_cp(
        "PD 101",
        101,
        115200,
        OsdpFlag::EnforceSecure,
        OsdpChannel::new::<UnixChannel>(Box::new(stream)),
        SCBK,
    )];
    let mut cp = ControlPanel::new(pd_info)?;
    loop {
        cp.refresh();
        thread::sleep(Duration::from_millis(50));
    }
}

fn pd() -> Result<(), OsdpError> {
    let stream = UnixChannel::new("conn-1")?;
    let pd_info = PdInfo::for_pd(
        "PD 101",
        101,
        115200,
        OsdpFlag::EnforceSecure,
        PdId::from_number(101),
        vec![PdCapability::CommunicationSecurity(PdCapEntity::new(1, 1))],
        OsdpChannel::new::<UnixChannel>(Box::new(stream)),
        SCBK,
    );
    let mut pd = PeripheralDevice::new(pd_info)?;
    pd.set_command_callback(|_| {
        println!("Received command!");
        0
    });
    loop {
        pd.refresh();
        thread::sleep(Duration::from_millis(50));
    }
}

Logs:

Waiting for connection to unix::/tmp/osdp-conn-1
[INFO ] Setup complete; PDs:1 Channels:1 - libosdp-rust-0.1.5
[INFO ] Setup complete - libosdp-rust-0.1.5
[ERROR] Channel send for 9 bytes failed! ret: 0
[ERROR] Failed to build packet for CMD(96)
[ERROR] Channel send for 9 bytes failed! ret: 0
[ERROR] Failed to build packet for CMD(96)
[ERROR] Channel send for 9 bytes failed! ret: 0
[ERROR] Failed to build packet for CMD(96)
Sympatron commented 11 months ago

I got both to communicate with a custom in memory channel:

use libosdp::{
    channel::{Channel, OsdpChannel},
    commands::OsdpCommandBuzzer,
    cp::ControlPanel,
    events::OsdpEventCardRead,
    pd::PeripheralDevice,
    OsdpError, OsdpFlag, PdCapEntity, PdCapability, PdId, PdInfo,
};
use ringbuf::HeapRb;
use std::{
    io::{Read, Write},
    result::Result,
    sync::Arc,
    thread,
    time::Duration,
};

const SCBK: [u8; 16] = [
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
];

fn main() -> Result<(), Box<dyn std::any::Any + Send>> {
    env_logger::builder()
        .filter_level(log::LevelFilter::Trace)
        .format_target(false)
        .format_timestamp(None)
        .init();

    let (channel1, channel2) = MemoryChannel::new();

    let cp = thread::spawn(move || {
        cp(channel1).ok();
    });
    thread::sleep(Duration::from_millis(150));
    let pd = thread::spawn(move || {
        pd(channel2).ok();
    });

    pd.join()?;
    cp.join()
}

fn cp(stream: MemoryChannel) -> Result<(), OsdpError> {
    // let stream = UnixChannel::new("conn-1")?;
    let pd_info = vec![PdInfo::for_cp(
        "PD 101",
        1,
        115200,
        OsdpFlag::EnforceSecure,
        OsdpChannel::new::<MemoryChannel>(Box::new(stream)),
        SCBK,
    )];
    let mut cp = ControlPanel::new(pd_info)?;
    let mut i = 0;
    loop {
        cp.refresh();
        thread::sleep(Duration::from_millis(5));
        i += 5;
        if i % 1600 == 0 {
            let _ = cp.send_command(
                1,
                libosdp::commands::OsdpCommand::Buzzer(OsdpCommandBuzzer {
                    reader: 0,
                    control_code: 2,
                    on_count: 1,
                    off_count: 0,
                    rep_count: 1,
                }),
            );
        }
    }
}

fn pd(stream: MemoryChannel) -> Result<(), OsdpError> {
    // let stream = UnixChannel::connect("conn-1")?;
    let pd_info = PdInfo::for_pd(
        "PD 101",
        1,
        115200,
        OsdpFlag::EnforceSecure,
        PdId::from_number(101),
        vec![PdCapability::CommunicationSecurity(PdCapEntity::new(1, 1))],
        OsdpChannel::new::<MemoryChannel>(Box::new(stream)),
        SCBK,
    );
    let mut pd = PeripheralDevice::new(pd_info)?;
    pd.set_command_callback(|_| {
        println!("Received command!");
        0
    });
    let mut i = 0;
    loop {
        pd.refresh();
        thread::sleep(Duration::from_millis(5));
        i += 5;
        if i % 2000 == 0 {
            let _ = pd.notify_event(libosdp::events::OsdpEvent::CardRead(
                OsdpEventCardRead::new(libosdp::events::OsdpCardFormats::Weigand, vec![0x55, 0x33]),
            ));
        }
    }
}

struct MemoryChannel {
    id: i32,
    sender: ringbuf::Producer<u8, Arc<HeapRb<u8>>>,
    receiver: ringbuf::Consumer<u8, Arc<HeapRb<u8>>>,
}

impl MemoryChannel {
    pub fn new() -> (Self, Self) {
        let rb1 = HeapRb::<u8>::new(1024);
        let (prod1, cons1) = rb1.split();
        let rb2 = HeapRb::<u8>::new(1024);
        let (prod2, cons2) = rb2.split();
        (
            Self {
                id: 0,
                sender: prod1,
                receiver: cons2,
            },
            Self {
                id: 1,
                sender: prod2,
                receiver: cons1,
            },
        )
    }
}

impl Write for MemoryChannel {
    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
        self.sender.write(buf)
    }
    fn flush(&mut self) -> std::io::Result<()> {
        Ok(())
    }
}
impl Read for MemoryChannel {
    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
        self.receiver.read(buf)
    }
}

impl Channel for MemoryChannel {
    fn get_id(&self) -> i32 {
        self.id
    }
}

Dependencies:

[dependencies]
env_logger = "0.10.1"
libosdp = "0.1.5"
log = "0.4.20"
ringbuf = "0.3.3"

Now send_command gives me: [INFO ] Invalid PD number 101 And notify_event gives me this every time:

[ERROR] Failed to decode reply RAW(50) for command POLL(60)
[INFO ] PD SC session timeout!
[ERROR] CMD: POLL(60) not allowed due to ENFORCE_SECURE
[WARN ] PD replied with NAK(6) for CMD(60)
[DEBUG] CMD: ID(61) REPLY: PDID(45)
[DEBUG] CMD: ID(61) REPLY: PDID(45)
[DEBUG] CMD: CAP(62) REPLY: PDCAP(46)
[DEBUG] Reports capability 'CheckCharacter' (1/0)
[DEBUG] Reports capability 'CommunicationSecurity' (1/0)
[DEBUG] Reports capability 'ReceiveBufferSize' (0/1)
[DEBUG] CMD: CAP(62) REPLY: PDCAP(46)
[DEBUG] CMD: CHLNG(76) REPLY: CCRYPT(76)
[DEBUG] CMD: CHLNG(76) REPLY: CCRYPT(76)
[DEBUG] CMD: SCRYPT(77) REPLY: RMAC_I(78)
[INFO ] SC Active
[DEBUG] CMD: SCRYPT(77) REPLY: RMAC_I(78)
[INFO ] SC Active
[ERROR] Failed to decode reply RAW(50) for command POLL(60)
[INFO ] PD SC session timeout!
[ERROR] CMD: POLL(60) not allowed due to ENFORCE_SECURE
[WARN ] PD replied with NAK(6) for CMD(60)
[DEBUG] CMD: ID(61) REPLY: PDID(45)
[DEBUG] CMD: ID(61) REPLY: PDID(45)
[DEBUG] CMD: CAP(62) REPLY: PDCAP(46)
[DEBUG] Reports capability 'CheckCharacter' (1/0)
[DEBUG] Reports capability 'CommunicationSecurity' (1/0)
[DEBUG] Reports capability 'ReceiveBufferSize' (0/1)
[DEBUG] CMD: CAP(62) REPLY: PDCAP(46)
[DEBUG] CMD: CHLNG(76) REPLY: CCRYPT(76)
[DEBUG] CMD: CHLNG(76) REPLY: CCRYPT(76)
[DEBUG] CMD: SCRYPT(77) REPLY: RMAC_I(78)
[INFO ] SC Active
[DEBUG] CMD: SCRYPT(77) REPLY: RMAC_I(78)
[INFO ] SC Active
[ERROR] Failed to decode reply RAW(50) for command POLL(60)
[INFO ] PD SC session timeout!
sidcha commented 11 months ago

I am running this in WSL so maybe that's the problem. Can somebody confirm this?

If you are you using WSL2 it should just work. Not sure what is going wrong.

I got both to communicate with a custom in memory channel

Nice, please feel free to send a PR alongside the UnixChannel :)

Now send_command gives me: [INFO ] Invalid PD number 101

Not sure how you got 101 there (maybe this output is from a different run?) but the issue arrises due to the PD number in command; it has to be offsets of the PD in the pd info vector of the CP. In your case, the PD has to be addressed with offset number 0. So the code becomes:

let _ = cp.send_command(0, ...),

And notify_event gives me this every time

This was a bug; the card data length should be in bits for Weigand. Should be addressed in the latest master.

sidcha commented 11 months ago

Closing this as no-action needed. Feel free to re-open if needed.