use async_std::os::unix::net::UnixStream;
use std::os::unix::net::UnixStream as StdUnixStream;
use std::{
io::{Read, Write},
str, time,
};
use crate::platform;
#[derive(Debug)]
pub struct BtSocket(platform::BtSocket);
impl BtSocket {
pub fn new(protocol: BtProtocol) -> Result<BtSocket, BtError> {
Ok(From::from(platform::BtSocket::new(protocol)?))
}
pub fn connect(&mut self, addr: BtAddr) -> Result<(), BtError> {
let evtloop = mio::Poll::new().unwrap();
let token = mio::Token(0);
let mut events = mio::Events::with_capacity(2);
let mut connect = self.0.connect(addr);
loop {
match connect.advance()? {
BtAsync::WaitFor(evented, interest) => {
let mut event_received = false;
while !event_received {
evtloop
.register(evented, token, interest, mio::PollOpt::oneshot())
.unwrap();
evtloop.poll(&mut events, None).unwrap();
for event in events.iter() {
if event.token() == token {
event_received = true;
evtloop.deregister(evented).unwrap();
}
}
}
}
BtAsync::Done => {
return Ok(());
}
}
}
}
pub fn connect_async(&mut self, addr: BtAddr) -> BtSocketConnect {
BtSocketConnect(self.0.connect(addr))
}
pub fn get_stream_std(&self) -> StdUnixStream {
self.0.get_stream_std()
}
pub fn get_stream(&self) -> UnixStream {
self.0.get_stream()
}
pub fn get_fd(&self) -> i32 {
self.0.fd
}
}
impl From<platform::BtSocket> for BtSocket {
fn from(socket: platform::BtSocket) -> BtSocket {
BtSocket(socket)
}
}
impl mio::Evented for BtSocket {
fn register(
&self,
poll: &mio::Poll,
token: mio::Token,
interest: mio::Ready,
opts: mio::PollOpt,
) -> std::io::Result<()> {
self.0.register(poll, token, interest, opts)
}
fn reregister(
&self,
poll: &mio::Poll,
token: mio::Token,
interest: mio::Ready,
opts: mio::PollOpt,
) -> std::io::Result<()> {
self.0.reregister(poll, token, interest, opts)
}
fn deregister(&self, poll: &mio::Poll) -> std::io::Result<()> {
self.0.deregister(poll)
}
}
impl Read for BtSocket {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
self.0.read(buf)
}
}
impl Write for BtSocket {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
self.0.write(buf)
}
fn flush(&mut self) -> std::io::Result<()> {
self.0.flush()
}
}
#[allow(missing_debug_implementations)]
pub enum BtAsync<'a> {
WaitFor(&'a dyn mio::Evented, mio::Ready),
Done,
}
#[derive(Debug)]
pub struct BtSocketConnect<'a>(platform::BtSocketConnect<'a>);
impl<'a> BtSocketConnect<'a> {
pub fn advance(&mut self) -> Result<BtAsync, BtError> {
self.0.advance()
}
}
pub fn scan_devices(timeout: time::Duration) -> Result<Vec<BtDevice>, BtError> {
platform::scan_devices(timeout)
}
#[derive(Debug)]
pub enum BtError {
Unknown,
Errno(u32, String),
Desc(String),
IoError(std::io::Error),
}
#[allow(deprecated)]
impl std::fmt::Display for BtError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{:}", std::error::Error::description(self))
}
}
impl std::error::Error for BtError {
fn description(&self) -> &str {
match self {
BtError::Unknown => "Unknown Bluetooth Error",
BtError::Errno(_, ref message) => message.as_str(),
BtError::Desc(ref message) => message.as_str(),
BtError::IoError(_) => "io error",
}
}
}
impl From<std::io::Error> for BtError {
fn from(error: std::io::Error) -> Self {
BtError::IoError(error)
}
}
#[repr(C, packed)]
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct BtAddr(pub [u8; 6]);
impl std::fmt::Debug for BtAddr {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5]
)
}
}
impl BtAddr {
pub fn any() -> BtAddr {
BtAddr([0, 0, 0, 0, 0, 0])
}
#[doc(hidden)]
#[inline(always)]
#[cfg(target_endian = "little")]
pub fn convert_host_byteorder(mut self) -> BtAddr {
{
let (value_1, value_2) = (&mut self.0).split_at_mut(3);
std::mem::swap(&mut value_1[0], &mut value_2[2]);
std::mem::swap(&mut value_1[1], &mut value_2[1]);
std::mem::swap(&mut value_1[2], &mut value_2[0]);
}
self
}
#[doc(hidden)]
#[inline(always)]
#[cfg(target_endian = "big")]
pub fn convert_host_byteorder(self) -> BtAddr {
self
}
}
impl ToString for BtAddr {
fn to_string(&self) -> String {
format!(
"{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5]
)
}
}
impl str::FromStr for BtAddr {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
let splits_iter = s.split(':');
let mut addr = BtAddr::any();
let mut i = 0;
for split_str in splits_iter {
if i == 6 || split_str.len() != 2 {
return Err(());
}
let high = (split_str.as_bytes()[0] as char).to_digit(16).ok_or(())?;
let low = (split_str.as_bytes()[1] as char).to_digit(16).ok_or(())?;
addr.0[i] = (high * 16 + low) as u8;
i += 1;
}
if i != 6 {
return Err(());
}
Ok(addr)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BtDevice {
pub name: String,
pub addr: BtAddr,
}
#[derive(Clone, Copy, Debug)]
pub enum BtProtocol {
RFCOMM,
}
impl BtDevice {
pub fn new(name: String, addr: BtAddr) -> BtDevice {
BtDevice { name, addr }
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::str::FromStr;
#[test()]
fn btaddr_from_string() {
match BtAddr::from_str("00:00:00:00:00:00") {
Ok(addr) => assert_eq!(addr, BtAddr([0u8; 6])),
Err(_) => panic!(""),
}
let fail_strings = [
"addr : String",
"00:00:00:00:00",
"00:00:00:00:00:00:00",
"-00:00:00:00:00:00",
"0G:00:00:00:00:00",
];
for &s in &fail_strings {
match BtAddr::from_str(s) {
Ok(_) => panic!("Somehow managed to parse \"{}\" as an address?!", s),
Err(_) => (),
}
}
}
#[test()]
fn btaddr_to_string() {
assert_eq!(BtAddr::any().to_string(), "00:00:00:00:00:00");
assert_eq!(BtAddr([1, 2, 3, 4, 5, 6]).to_string(), "01:02:03:04:05:06");
}
#[test()]
fn btaddr_roundtrips_to_from_str() {
let addr = BtAddr([0, 22, 4, 1, 33, 192]);
let addr_string = "00:ff:ee:ee:dd:12";
assert_eq!(addr, BtAddr::from_str(&addr.to_string()).unwrap());
assert!(
addr_string.eq_ignore_ascii_case(&BtAddr::from_str(addr_string).unwrap().to_string())
);
}
#[cfg(not(feature = "test_without_hardware"))]
#[test()]
fn creates_rfcomm_socket() {
BtSocket::new(BtProtocol::RFCOMM).unwrap();
}
#[cfg(not(feature = "test_without_hardware"))]
#[test()]
fn scans_devices() {
scan_devices(time::Duration::from_secs(20)).unwrap();
}
}