use btleplug::api::{Characteristic, Peripheral as _, WriteType};
use btleplug::platform::Peripheral;
use std::collections::BTreeMap;
use std::fmt::Debug;
use std::sync::Arc;
use tokio_util::sync::CancellationToken;
use crate::consts::{HubPropertyOperation, HubPropertyRef, HubType};
use crate::error::{Error, OptionContext, Result};
use crate::notifications::{
AlertOperation, AlertPayload, AlertType, ErrorMessageFormat, HubAction,
HubActionRequest, HubAlert, HubProperty, HubPropertyValue,
InformationRequest, InformationType, InputSetupSingle,
ModeInformationRequest, ModeInformationType, NetworkCommand,
NotificationMessage, PortOutputCommandFeedbackFormat,
PortValueCombinedFormat, PortValueSingleFormat,
};
use crate::{IoDevice, IoTypeId};
pub type Tokens = Arc<(Peripheral, Characteristic)>;
pub mod generic_hub;
pub mod io_event;
#[async_trait::async_trait]
pub trait Hub: Debug + Send + Sync {
async fn name(&self) -> Result<String>;
async fn disconnect(&self) -> Result<()>;
async fn shutdown(&self) -> Result<()>;
async fn is_connected(&self) -> Result<bool>;
fn properties(&self) -> &HubProperties;
fn kind(&self) -> HubType;
fn connected_io(&self) -> &BTreeMap<u8, IoDevice>;
fn connected_io_mut(&mut self) -> &mut BTreeMap<u8, IoDevice>;
fn channels(&mut self) -> &mut crate::hubs::Channels;
async fn subscribe(&self, char: Characteristic) -> Result<()>;
fn io_from_port(&self, port_id: u8) -> Result<IoDevice>;
fn io_from_kind(&self, kind: IoTypeId) -> Result<IoDevice>;
fn io_multi_from_kind(&self, kind: IoTypeId) -> Result<Vec<IoDevice>>;
fn tokens(&self) -> Tokens;
fn attach_io(&mut self, io_type_id: IoTypeId, port_id: u8) -> Result<()>;
fn peripheral(&self) -> Arc<Peripheral>;
fn characteristic(&self) -> Arc<Characteristic>;
fn device_cache(&self, d: IoDevice) -> IoDevice;
fn cancel_token(&self) -> CancellationToken;
async fn request_port_info(
&self,
port_id: u8,
infotype: InformationType,
) -> Result<()> {
let msg =
NotificationMessage::PortInformationRequest(InformationRequest {
port_id,
information_type: infotype,
});
self.send(msg).await
}
async fn req_mode_info(
&self,
port_id: u8,
mode: u8,
infotype: ModeInformationType,
) -> Result<()> {
let msg = NotificationMessage::PortModeInformationRequest(
ModeInformationRequest {
port_id,
mode,
information_type: infotype,
},
);
self.send(msg).await
}
async fn set_port_mode(
&self,
port_id: u8,
mode: u8,
delta: u32,
notification_enabled: bool,
) -> Result<()> {
let msg =
NotificationMessage::PortInputFormatSetupSingle(InputSetupSingle {
port_id,
mode,
delta,
notification_enabled,
});
self.send(msg).await
}
async fn hub_props(
&self,
reference: HubPropertyRef,
operation: HubPropertyOperation,
) -> Result<()> {
let msg = NotificationMessage::HubProperties(HubProperty {
reference,
operation,
property: HubPropertyValue::SecondaryMacAddress, });
self.send(msg).await
}
async fn hub_action(&self, action_type: HubAction) -> Result<()> {
let msg =
NotificationMessage::HubActions(HubActionRequest { action_type });
self.send(msg).await
}
async fn hub_alerts(
&self,
alert_type: AlertType,
operation: AlertOperation,
) -> Result<()> {
let msg = NotificationMessage::HubAlerts(HubAlert {
alert_type,
operation,
payload: AlertPayload::StatusOk,
});
self.send(msg).await
}
async fn send(&self, msg: NotificationMessage) -> Result<()> {
let buf = msg.serialise();
let tokens = self.tokens();
tokens
.0
.write(&tokens.1, &buf, WriteType::WithoutResponse)
.await?;
Ok(())
}
async fn send_raw(&self, msg: &[u8]) -> Result<()>;
}
pub type VersionNumber = u8;
#[derive(Debug, Default)]
pub struct HubProperties {
pub name: String,
pub fw_version: String,
pub hw_version: String,
pub mac_address: String,
pub battery_level: usize,
pub rssi: i16,
}
pub async fn send(tokens: Tokens, msg: NotificationMessage) -> Result<()> {
let buf = msg.serialise();
tokens
.0
.write(&tokens.1, &buf, WriteType::WithoutResponse)
.await?;
Ok(())
}
#[derive(Debug, Default, Clone)]
pub struct Channels {
pub singlevalue_sender:
Option<tokio::sync::broadcast::Sender<PortValueSingleFormat>>,
pub combinedvalue_sender:
Option<tokio::sync::broadcast::Sender<PortValueCombinedFormat>>,
pub networkcmd_sender:
Option<tokio::sync::broadcast::Sender<NetworkCommand>>,
pub hubnotification_sender:
Option<tokio::sync::broadcast::Sender<HubNotification>>,
pub commandfeedback_sender:
Option<tokio::sync::broadcast::Sender<PortOutputCommandFeedbackFormat>>,
}
#[derive(Debug, Default, Clone)]
pub struct HubNotification {
pub hub_property: Option<HubProperty>,
pub hub_action: Option<HubActionRequest>,
pub hub_alert: Option<HubAlert>,
pub hub_error: Option<ErrorMessageFormat>,
}