-
-
Notifications
You must be signed in to change notification settings - Fork 71
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
rust: Add initial template for tests
Signed-off-by: Siddharth Chandrasekaran <[email protected]>
- Loading branch information
Showing
4 changed files
with
297 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
use std::{sync::MutexGuard, thread, time}; | ||
|
||
use libosdp::{ | ||
channel::{MemoryChannel, Read, Write}, | ||
ControlPanel, OsdpCommand, OsdpCommandBuzzer, OsdpEvent, OsdpEventCardRead, PeripheralDevice, | ||
}; | ||
|
||
use crate::common::{device::CpDevice, device::PdDevice, threadbus::ThreadBus}; | ||
|
||
mod common; | ||
|
||
type Result<T> = core::result::Result<T, libosdp::OsdpError>; | ||
|
||
fn send_command(mut cp: MutexGuard<'_, ControlPanel>, command: OsdpCommand) -> Result<()> { | ||
cp.send_command(0, command) | ||
} | ||
|
||
fn notify_event(mut pd: MutexGuard<'_, PeripheralDevice>, event: OsdpEvent) -> Result<()> { | ||
pd.notify_event(event) | ||
} | ||
|
||
#[test] | ||
fn test_thread_bus_channel() -> Result<()> { | ||
let mut a = ThreadBus::new("conn-0"); | ||
let mut b = a.clone(); | ||
let mut c = a.clone(); | ||
|
||
let buf_write = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; | ||
let mut buf_read = [0; 100]; | ||
assert_eq!(a.write(&buf_write)?, buf_write.len()); | ||
assert_eq!(b.read(&mut buf_read)?, buf_write.len()); | ||
assert_eq!(c.read(&mut buf_read)?, buf_write.len()); | ||
Ok(()) | ||
} | ||
|
||
#[test] | ||
fn test_commands() -> Result<()> { | ||
common::setup(); | ||
let (cp_bus, pd_bus) = MemoryChannel::new(); | ||
let pd = PdDevice::new(pd_bus)?; | ||
let cp = CpDevice::new(cp_bus)?; | ||
|
||
thread::sleep(time::Duration::from_secs(2)); | ||
loop { | ||
if pd.get_device().is_sc_active() { | ||
break; | ||
} | ||
println!("Waiting for devices to establish a secure channel"); | ||
thread::sleep(time::Duration::from_secs(1)); | ||
} | ||
|
||
let command = OsdpCommand::Buzzer(OsdpCommandBuzzer::default()); | ||
send_command(cp.get_device(), command.clone())?; | ||
println!("Send, waiting for cmd in PD"); | ||
let cmd_rx = pd.receiver.recv().unwrap(); | ||
println!("Got command"); | ||
assert_eq!(cmd_rx, command, "Buzzer command check failed"); | ||
|
||
let event = OsdpEvent::CardRead(OsdpEventCardRead::new_ascii(vec![0x55, 0xAA])); | ||
notify_event(pd.get_device(), event.clone())?; | ||
assert_eq!( | ||
cp.receiver.recv().unwrap(), | ||
(0 as i32, event), | ||
"Cardread event check failed" | ||
); | ||
|
||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
use std::{ | ||
sync::{mpsc::Receiver, Arc, Mutex, MutexGuard}, | ||
thread, time, | ||
}; | ||
|
||
use libosdp::{ | ||
channel::{Channel, OsdpChannel}, | ||
ControlPanel, OsdpCommand, OsdpEvent, OsdpFlag, PdCapEntity, PdCapability, PdId, PdInfo, | ||
PeripheralDevice, | ||
}; | ||
type Result<T> = core::result::Result<T, libosdp::OsdpError>; | ||
|
||
pub struct CpDevice { | ||
dev: Arc<Mutex<ControlPanel>>, | ||
pub receiver: Receiver<(i32, OsdpEvent)>, | ||
} | ||
|
||
impl CpDevice { | ||
pub fn new<T: Channel + 'static>(bus: T) -> Result<Self> { | ||
let pd_info = vec![PdInfo::for_cp( | ||
"PD 101", | ||
101, | ||
115200, | ||
OsdpFlag::empty(), | ||
OsdpChannel::new::<T>(Box::new(bus)), | ||
[ | ||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, | ||
0x0e, 0x0f, | ||
], | ||
)]; | ||
let mut cp = ControlPanel::new(pd_info)?; | ||
let (event_tx, event_rx) = std::sync::mpsc::channel::<(i32, OsdpEvent)>(); | ||
|
||
cp.set_event_callback(|pd, event| { | ||
event_tx.send((pd, event)).unwrap(); | ||
0 | ||
}); | ||
|
||
let dev = Arc::new(Mutex::new(cp)); | ||
let dev_clone = dev.clone(); | ||
let _ = thread::Builder::new() | ||
.name("CP Thread".to_string()) | ||
.spawn(move || { | ||
let dev = dev_clone; | ||
let sender = event_tx; | ||
dev.lock().unwrap().set_event_callback(|pd, event| { | ||
sender.send((pd, event)).expect("CP event send"); | ||
0 | ||
}); | ||
loop { | ||
dev.lock().unwrap().refresh(); | ||
thread::sleep(time::Duration::from_millis(10)); | ||
} | ||
}); | ||
Ok(Self { | ||
dev, | ||
receiver: event_rx, | ||
}) | ||
} | ||
|
||
pub fn get_device(&self) -> MutexGuard<'_, ControlPanel> { | ||
self.dev.lock().unwrap() | ||
} | ||
} | ||
|
||
pub struct PdDevice { | ||
dev: Arc<Mutex<PeripheralDevice>>, | ||
pub receiver: Receiver<OsdpCommand>, | ||
} | ||
|
||
impl PdDevice { | ||
pub fn new<T: Channel + 'static>(bus: T) -> Result<Self> { | ||
let pd_info = PdInfo::for_pd( | ||
"PD 101", | ||
101, | ||
115200, | ||
OsdpFlag::empty(), | ||
PdId::from_number(101), | ||
vec![ | ||
PdCapability::CommunicationSecurity(PdCapEntity::new(1, 1)), | ||
PdCapability::AudibleOutput(PdCapEntity::new(1, 1)), | ||
PdCapability::LedControl(PdCapEntity::new(1, 1)), | ||
], | ||
OsdpChannel::new::<T>(Box::new(bus)), | ||
[ | ||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, | ||
0x0e, 0x0f, | ||
], | ||
); | ||
let mut pd = PeripheralDevice::new(pd_info)?; | ||
let (cmd_tx, cmd_rx) = std::sync::mpsc::channel::<OsdpCommand>(); | ||
pd.set_command_callback(|command| { | ||
cmd_tx.send(command).unwrap(); | ||
0 | ||
}); | ||
|
||
let dev = Arc::new(Mutex::new(pd)); | ||
let dev_clone = dev.clone(); | ||
let _ = thread::Builder::new() | ||
.name("PD Thread".to_string()) | ||
.spawn(move || { | ||
let dev = dev_clone; | ||
let sender = cmd_tx; | ||
dev.lock().unwrap().set_command_callback(|command| { | ||
println!("--> Got here! {:?}", command); | ||
sender.send(command).expect("PD command send"); | ||
println!("<-- Got out!"); | ||
0 | ||
}); | ||
loop { | ||
dev.lock().unwrap().refresh(); | ||
thread::sleep(time::Duration::from_millis(10)); | ||
} | ||
}); | ||
|
||
Ok(Self { | ||
dev, | ||
receiver: cmd_rx, | ||
}) | ||
} | ||
|
||
pub fn get_device(&self) -> MutexGuard<'_, PeripheralDevice> { | ||
self.dev.lock().unwrap() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
pub mod device; | ||
pub mod threadbus; | ||
|
||
pub fn setup() { | ||
env_logger::builder() | ||
.filter_level(log::LevelFilter::Debug) | ||
.format_target(false) | ||
.format_timestamp(None) | ||
.init(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
use multiqueue::{BroadcastReceiver, BroadcastSender}; | ||
use std::{ | ||
collections::hash_map::DefaultHasher, | ||
fmt::Debug, | ||
hash::{Hash, Hasher}, | ||
io::Error, | ||
io::ErrorKind, | ||
sync::Mutex, | ||
}; | ||
|
||
fn str_to_channel_id(key: &str) -> i32 { | ||
let mut hasher = DefaultHasher::new(); | ||
key.hash(&mut hasher); | ||
let mut id: u64 = hasher.finish(); | ||
id = (id >> 32) ^ id & 0xffffffff; | ||
id as i32 | ||
} | ||
|
||
pub struct ThreadBus { | ||
name: String, | ||
id: i32, | ||
send: Mutex<BroadcastSender<Vec<u8>>>, | ||
recv: Mutex<BroadcastReceiver<Vec<u8>>>, | ||
} | ||
|
||
impl ThreadBus { | ||
pub fn new(name: &str) -> Self { | ||
let (send, recv) = multiqueue::broadcast_queue(4); | ||
Self { | ||
name: name.into(), | ||
id: str_to_channel_id(name), | ||
send: Mutex::new(send), | ||
recv: Mutex::new(recv), | ||
} | ||
} | ||
} | ||
|
||
impl Clone for ThreadBus { | ||
fn clone(&self) -> Self { | ||
let send = Mutex::new(self.send.lock().unwrap().clone()); | ||
let recv = Mutex::new(self.recv.lock().unwrap().add_stream()); | ||
Self { | ||
name: self.name.clone(), | ||
id: self.id, | ||
send, | ||
recv, | ||
} | ||
} | ||
} | ||
|
||
impl Debug for ThreadBus { | ||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
f.debug_struct("ThreadBus") | ||
.field("name", &self.name) | ||
.field("id", &self.id) | ||
.finish() | ||
} | ||
} | ||
|
||
impl std::io::Read for ThreadBus { | ||
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> { | ||
let v = self.recv.lock().unwrap().try_recv().map_err(|e| match e { | ||
std::sync::mpsc::TryRecvError::Empty => Error::new(ErrorKind::WouldBlock, "No data"), | ||
std::sync::mpsc::TryRecvError::Disconnected => { | ||
Error::new(ErrorKind::ConnectionReset, "disconnected") | ||
} | ||
})?; | ||
buf[..v.len()].copy_from_slice(&v[..]); | ||
Ok(v.len()) | ||
} | ||
} | ||
|
||
impl std::io::Write for ThreadBus { | ||
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> { | ||
let v = buf.into(); | ||
self.send.lock().unwrap().try_send(v).map_err(|e| match e { | ||
std::sync::mpsc::TrySendError::Full(_) => Error::new(ErrorKind::WouldBlock, "No space"), | ||
std::sync::mpsc::TrySendError::Disconnected(_) => { | ||
Error::new(ErrorKind::ConnectionReset, "disconnected") | ||
} | ||
})?; | ||
Ok(buf.len()) | ||
} | ||
|
||
fn flush(&mut self) -> std::io::Result<()> { | ||
Ok(()) | ||
} | ||
} | ||
|
||
impl libosdp::channel::Channel for ThreadBus { | ||
fn get_id(&self) -> i32 { | ||
self.id | ||
} | ||
} |