summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRomeo Disca <romeo.disca@gmail.com>2020-08-08 04:24:43 +0200
committerRomeo Disca <romeo.disca@gmail.com>2020-08-08 12:08:08 +0200
commitf2630bbb255dab230348dff8cedfcef40787e57e (patch)
tree5de013a9b7c0a1a0b822348e88b776cd6a911518
parent36bfd7c66ad1332eaedecde3b6273f4db0559103 (diff)
chore: bring everything together
-rw-r--r--Cargo.lock38
-rw-r--r--Cargo.toml4
-rw-r--r--src/client.rs66
-rw-r--r--[-rwxr-xr-x]src/commands/mod.rs (renamed from src/commands.rs)25
-rw-r--r--src/commands/stream_mapper.rs192
-rw-r--r--[-rwxr-xr-x]src/enums.rs0
-rw-r--r--src/events/mod.rs (renamed from src/events.rs)69
-rw-r--r--src/events/stream_mapper.rs581
-rw-r--r--src/main.rs10
9 files changed, 897 insertions, 88 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 9513666..64df848 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1,6 +1,15 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
+name = "aho-corasick"
+version = "0.7.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "043164d8ba5c4c3035fec9bbee8647c0261d788f3474306f93bb65901cae0e86"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
name = "arc-swap"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -265,6 +274,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
[[package]]
+name = "regex"
+version = "1.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+ "thread_local",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.6.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8"
+
+[[package]]
name = "serde"
version = "1.0.114"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -284,7 +311,9 @@ dependencies = [
name = "simpleclient"
version = "0.1.0"
dependencies = [
+ "bytes",
"num_enum",
+ "regex",
"tokio",
]
@@ -318,6 +347,15 @@ dependencies = [
]
[[package]]
+name = "thread_local"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
+dependencies = [
+ "lazy_static",
+]
+
+[[package]]
name = "tokio"
version = "0.2.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index de433c6..cfacbb8 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -7,5 +7,7 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
+bytes = "0.5"
num_enum = "0.4.2"
-tokio = { version = "0.2", features = ["full"] } \ No newline at end of file
+regex = "1"
+tokio = { version = "0.2", features = ["full"] }
diff --git a/src/client.rs b/src/client.rs
index b6b681a..320ae86 100644
--- a/src/client.rs
+++ b/src/client.rs
@@ -1,22 +1,31 @@
-use std::sync::Arc;
-
use tokio::io::*;
+
+use bytes::BufMut;
use tokio::net::TcpStream;
-use super::events::*;
+use std::net::Shutdown;
+use std::sync::{Arc, Mutex, MutexGuard};
+use std::time::Duration;
+
+use super::events::Event;
+use super::events::stream_mapper::*;
+use super::commands::stream_mapper::CommandToByteMapper;
use super::commands::Command;
-pub fn event_handler<F>(f: F) -> Box<dyn FnMut(Event)>
- where F: FnMut(Event) + 'static
+type EventClosure = dyn FnMut(Event) + Sync + Send + 'static;
+type EventClosureMutex = Box<EventClosure>;
+
+pub fn event_handler<F>(f: F) -> EventClosureMutex
+ where F: FnMut(Event) + Sync + Send + 'static
{
Box::new(f)
}
pub struct FlicClient {
- reader: Arc<TcpStream>,
- writer: Arc<TcpStream>,
- map: Vec<Box<dyn FnMut(Event)>>,
+ stream: TcpStream,
+ command_mapper: CommandToByteMapper,
+ map: Vec<EventClosureMutex>,
is_running: bool,
}
@@ -24,12 +33,10 @@ impl FlicClient {
pub async fn new(conn: &str) -> Result<FlicClient> {
match TcpStream::connect(conn).await {
Ok(stream) => {
- let reader = Arc::new(stream);
- let writer = reader.clone();
-
+ println!("stream open");
Ok(FlicClient{
- reader,
- writer,
+ stream,
+ command_mapper: CommandToByteMapper::new(),
map: vec![],
is_running: true,
})
@@ -38,30 +45,41 @@ impl FlicClient {
}
}
- pub fn register_event_handler(mut self, event: Box<dyn FnMut(Event)>) -> Self {
+ pub fn register_event_handler(mut self, event: EventClosureMutex) -> Self {
self.map.push(event);
self
}
pub async fn listen(&mut self) {
+ let mut mapper = ByteToEventMapper::new();
+ let (mut reader, _writer) = self.stream.split();
+ let mut buffer = vec![];
while self.is_running {
- if let Some(mut r) = Arc::get_mut(&mut self.reader) {
- if let Ok(value) = r.read_u8().await {
- for ref mut f in self.map.as_mut_slice() {
- f(Event::read_event(value, &mut r));
+ if let Some(size) = reader.read_buf(&mut buffer).await.ok() {
+ for b in buffer.iter() {
+ match mapper.map(*b) {
+ EventResult::Some(Event::NoOp) => {}
+ EventResult::Some(event) => for ref mut f in &mut self.map {
+ f(event.clone());
+ }
+ _ => {}
}
}
+
}
}
}
- pub fn stop(&mut self) {
+ pub async fn stop(&mut self) {
self.is_running = false;
+ self.stream.shutdown(Shutdown::Both);
+ println!("stopped");
}
- pub fn submit(&mut self, cmd: Command) -> Result<()> {
- if let Some(mut w) = Arc::get_mut(&mut self.writer) {
- cmd.write_command(&mut w)?;
- }
- Ok(())
+ pub async fn submit(&mut self, cmd: Command) {
+ let (_reader, mut writer) = self.stream.split();
+ for b in self.command_mapper.map(cmd) {
+ writer.write_u8(b).await;
+ println!("{:?}", b);
+ }
}
}
diff --git a/src/commands.rs b/src/commands/mod.rs
index d84d9cd..e2b886b 100755..100644
--- a/src/commands.rs
+++ b/src/commands/mod.rs
@@ -1,8 +1,5 @@
-use num_enum::TryFromPrimitive;
-use num_enum::IntoPrimitive;
-use tokio::io::*;
-use tokio::net::TcpStream;
+pub mod stream_mapper;
use super::enums::LatencyMode;
@@ -76,24 +73,4 @@ impl Command {
Self::RemoveBatteryStatusListener{..} => 13,
}
}
- pub fn write_command(&self, writer: &mut TcpStream) -> Result<()> {
- match self {
- Self::GetInfo{..} => 0,
- Self::CreateScanner{..} => 1,
- Self::RemoveScanner{..} => 2,
- Self::CreateConnectionChannel{..} => 3,
- Self::RemoveConnectionChannel{..} => 4,
- Self::ForceDisconnect{..} => 5,
- Self::ChangeModeParameters{..} => 6,
- Self::Ping{..} => 7,
- Self::GetButtonInfo{..} => 8,
- Self::CreateScanWizard{..} => 9,
- Self::CancelScanWizard{..} => 10,
- Self::DeleteButton{..} => 11,
- Self::CreateBatteryStatusListener{..} => 12,
- Self::RemoveBatteryStatusListener{..} => 13,
- };
-
- Ok(())
- }
} \ No newline at end of file
diff --git a/src/commands/stream_mapper.rs b/src/commands/stream_mapper.rs
new file mode 100644
index 0000000..2b6f612
--- /dev/null
+++ b/src/commands/stream_mapper.rs
@@ -0,0 +1,192 @@
+
+use regex::Regex;
+
+use std::collections::VecDeque;
+use std::collections::vec_deque::Drain;
+use std::convert::TryInto;
+
+use super::*;
+
+pub struct CommandToByteMapper {
+ buffer: VecDeque<u8>,
+}
+impl CommandToByteMapper {
+
+ pub fn new() -> CommandToByteMapper {
+ CommandToByteMapper{ buffer: VecDeque::new() }
+ }
+
+ pub fn map(&mut self, command: Command) -> Drain<u8> {
+ self.clear_buffer();
+
+ self.write_u8(command.opcode());
+ match command {
+ Command::GetInfo => {},
+ Command::CreateScanner {
+ scan_id,
+ } => {
+
+ self.write_u32(scan_id);
+ },
+ Command::RemoveScanner {
+ scan_id,
+ } => {
+
+ self.write_u32(scan_id);
+ },
+ Command::CreateConnectionChannel {
+ conn_id,
+ bd_addr,
+ latency_mode,
+ auto_disconnect_time,
+ } => {
+
+ self.write_u32(conn_id);
+ self.write_bdaddr(&bd_addr[..]);
+ if let Ok(latency_mode) = latency_mode.try_into() {
+ self.write_u8(latency_mode);
+ }
+ self.write_i16(auto_disconnect_time);
+ },
+ Command::RemoveConnectionChannel {
+ conn_id,
+ } => {
+
+ self.write_u32(conn_id);
+ },
+ Command::ForceDisconnect {
+ bd_addr,
+ } => {
+
+ self.write_bdaddr(&bd_addr[..]);
+ },
+ Command::ChangeModeParameters {
+ conn_id,
+ latency_mode,
+ auto_disconnect_time,
+ } => {
+
+ self.write_u32(conn_id);
+ if let Ok(latency_mode) = latency_mode.try_into() {
+ self.write_u8(latency_mode);
+ }
+ self.write_i16(auto_disconnect_time);
+ },
+ Command::Ping {
+ ping_id,
+ } => {
+
+ self.write_u32(ping_id);
+ },
+ Command::GetButtonInfo {
+ bd_addr,
+ } => {
+
+ self.write_bdaddr(&bd_addr[..]);
+ },
+ Command::CreateScanWizard {
+ scan_wizard_id,
+ } => {
+
+ self.write_u32(scan_wizard_id);
+ },
+ Command::CancelScanWizard {
+ scan_wizard_id,
+ } => {
+
+ self.write_u32(scan_wizard_id);
+ },
+ Command::DeleteButton {
+ bd_addr,
+ } => {
+
+ self.write_bdaddr(&bd_addr[..]);
+ },
+ Command::CreateBatteryStatusListener {
+ listener_id,
+ bd_addr,
+ } => {
+
+ self.write_u32(listener_id);
+ self.write_bdaddr(&bd_addr[..]);
+ },
+ Command::RemoveBatteryStatusListener {
+ listener_id,
+ } => {
+
+ self.write_u32(listener_id);
+ },
+ }
+
+ self.prepend_size();
+
+ self.buffer.drain(..)
+ }
+
+ fn clear_buffer(&mut self) {
+ self.buffer.drain(..);
+ }
+
+ fn prepend_size(&mut self) {
+ let len = self.buffer.len();
+ self.buffer.push_front((len >> 8) as u8);
+ self.buffer.push_front((len & 255) as u8);
+ }
+ fn write_u8(&mut self, value: u8) {
+ let mut buf = vec![value].into_iter().collect();
+ self.buffer.append(&mut buf);
+ }
+/*
+ fn write_bool(&mut self, value: bool) {
+ if value {
+ self.write_u8(1);
+ }
+ else {
+ self.write_u8(0);
+ }
+ }
+*/
+ fn write_u16(&mut self, value: u16) {
+ self.write_u8(value as u8);
+ self.write_u8((value >> 8) as u8);
+ }
+ fn write_i16(&mut self, value: i16) {
+ self.write_u8(value as u8);
+ self.write_u8((value >> 8) as u8);
+ }
+ fn write_u32(&mut self, value: u32) {
+ self.write_u16(value as u16);
+ self.write_u16((value >> 16) as u16);
+ }
+/*
+ fn write_i32(&mut self, value: i32) {
+ self.write_i16(value as i16);
+ self.write_i16((value >> 16) as i16);
+ }
+*/
+ fn write_bdaddr(&mut self, str: &str) {
+ let re = Regex::new(r"([0-9a-z]{2}:){5}[0-9a-z]{2}").unwrap();
+ if re.is_match(str) {
+ if let Some(b) = hex_to_u8(&str[15..]) { self.write_u8(b); }
+ if let Some(b) = hex_to_u8(&str[12..]) { self.write_u8(b); }
+ if let Some(b) = hex_to_u8(&str[ 9..]) { self.write_u8(b); }
+ if let Some(b) = hex_to_u8(&str[ 6..]) { self.write_u8(b); }
+ if let Some(b) = hex_to_u8(&str[ 3..]) { self.write_u8(b); }
+ if let Some(b) = hex_to_u8(&str[ ..]) { self.write_u8(b); }
+ }
+ }
+
+}
+
+fn hex_to_u8(buffer: &str) -> Option<u8> {
+ let mut char_indices = buffer.char_indices();
+ match (char_indices.next(), char_indices.next()) {
+ (Some((0, upper)), Some((1, lower))) => {
+ let mut b = 0u8;
+ if let Some(v) = upper.to_digit(16) { b += (v as u8) << 4; }
+ if let Some(v) = lower.to_digit(16) { b += v as u8; }
+ Some(b)
+ },
+ _ => None,
+ }
+}
diff --git a/src/enums.rs b/src/enums.rs
index 64284a2..64284a2 100755..100644
--- a/src/enums.rs
+++ b/src/enums.rs
diff --git a/src/events.rs b/src/events/mod.rs
index ac00472..0cfd910 100644
--- a/src/events.rs
+++ b/src/events/mod.rs
@@ -1,11 +1,41 @@
-use tokio::net::TcpStream;
+pub mod stream_mapper;
+
+use num_enum::TryFromPrimitive;
+use num_enum::IntoPrimitive;
use super::enums::*;
+#[repr(u8)]
+#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, IntoPrimitive, TryFromPrimitive)]
+pub enum OpCode {
+ AdvertisementPacket = 0,
+ CreateConnectionChannelResponse = 1,
+ ConnectionStatusChanged = 2,
+ ConnectionChannelRemoved = 3,
+ ButtonUpOrDown = 4,
+ ButtonClickOrHold = 5,
+ ButtonSingleOrDoubleClick = 6,
+ ButtonSingleOrDoubleClickOrHold = 7,
+ NewVerifiedButton = 8,
+ GetInfoResponse = 9,
+ NoSpaceForNewConnection = 10,
+ GotSpaceForNewConnection = 11,
+ BluetoothControllerStateChange = 12,
+ PingResponse = 13,
+ GetButtonInfoResponse = 14,
+ ScanWizardFoundPrivateButton = 15,
+ ScanWizardFoundPublicButton = 16,
+ ScanWizardButtonConnected = 17,
+ ScanWizardCompleted = 18,
+ ButtonDeleted = 19,
+ BatteryStatus = 20,
+}
+
#[allow(dead_code)]
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum Event {
+ NoOp,
CorruptEvent,
AdvertisementPacket {
@@ -130,40 +160,3 @@ pub enum Event {
},
}
-impl Event {
- pub fn opcode(&self) -> u8 {
- match self {
- Self::CorruptEvent => 255,
- Self::AdvertisementPacket{..} => 0,
- Self::CreateConnectionChannelResponse{..} => 1,
- Self::ConnectionStatusChanged{..} => 2,
- Self::ConnectionChannelRemoved{..} => 3,
- Self::ButtonUpOrDown{..} => 4,
- Self::ButtonClickOrHold{..} => 5,
- Self::ButtonSingleOrDoubleClick{..} => 6,
- Self::ButtonSingleOrDoubleClickOrHold{..} => 7,
- Self::NewVerifiedButton{..} => 8,
- Self::GetInfoResponse{..} => 9,
- Self::NoSpaceForNewConnection{..} => 10,
- Self::GotSpaceForNewConnection{..} => 11,
- Self::BluetoothControllerStateChange{..} => 12,
- Self::PingResponse{..} => 13,
- Self::GetButtonInfoResponse{..} => 14,
- Self::ScanWizardFoundPrivateButton{..} => 15,
- Self::ScanWizardFoundPublicButton{..} => 16,
- Self::ScanWizardButtonConnected{..} => 17,
- Self::ScanWizardCompleted{..} => 18,
- Self::ButtonDeleted{..} => 19,
- Self::BatteryStatus{..} => 20,
- }
- }
-
- pub fn read_event(opcode: u8, reader: &mut TcpStream) -> Event {
- match opcode {
- 13 => Self::PingResponse{ping_id: 8},
- _ => Self::CorruptEvent,
- }
- }
-
-}
-
diff --git a/src/events/stream_mapper.rs b/src/events/stream_mapper.rs
new file mode 100644
index 0000000..5244d58
--- /dev/null
+++ b/src/events/stream_mapper.rs
@@ -0,0 +1,581 @@
+
+use super::*;
+use std::collections::VecDeque;
+use std::usize;
+use std::convert::TryInto;
+use std::convert::TryFrom;
+
+#[derive(Debug, PartialEq, Eq, Clone)]
+pub enum EventResult {
+ Some(Event),
+ None,
+ Failure(Event),
+ Drained,
+ Pending,
+ CorruptPackage,
+}
+enum HasPacketResult {
+ Yes,
+ NotYet,
+ Failure(Event),
+}
+
+pub struct ByteToEventMapper {
+ fifo: VecDeque<u8>,
+}
+impl ByteToEventMapper {
+
+ pub fn new() -> ByteToEventMapper {
+ ByteToEventMapper { fifo: VecDeque::new() }
+ }
+
+ pub fn map(&mut self, value: u8) -> EventResult {
+
+ self.fifo.push_back(value);
+
+ match self.fifo.len() {
+ 0..=2 => EventResult::None,
+ 3..=2047 => match self.has_packet() {
+ HasPacketResult::NotYet => EventResult::Pending,
+ HasPacketResult::Failure(event) => {
+ self.fifo.drain(..);
+ EventResult::Failure(event)
+ },
+ HasPacketResult::Yes => match self.read_event() {
+ Event::CorruptEvent => EventResult::CorruptPackage,
+ event => EventResult::Some(event),
+ }
+ },
+ _ => {
+ self.fifo.drain(..);
+ EventResult::Drained
+ },
+ }
+
+ }
+
+ pub fn has_packet(&self) -> HasPacketResult {
+ match (self.fifo.get(0), self.fifo.get(1), self.fifo.get(2)) {
+ (Some(&lower), Some(&upper), Some(&opcode)) => {
+ let len = ((upper as usize) << 8) + (lower as usize);
+ if OpCode::try_from(opcode).is_err() {
+ HasPacketResult::Failure(Event::CorruptEvent)
+ }
+ else if self.fifo.len() >= len + 2 {
+ HasPacketResult::Yes
+ }
+ else {
+ HasPacketResult::NotYet
+ }
+ },
+ _ => HasPacketResult::NotYet,
+ }
+ }
+ fn read_u8(&mut self) -> Option<u8> {
+ if self.fifo.is_empty() { return None; }
+ let mut iter = self.fifo.drain(..1);
+ iter.next()
+ }
+ fn read_u16(&mut self) -> Option<u16> {
+ match (self.read_u8(), self.read_u8()) {
+ (Some(lower), Some(higher)) => Some((lower as u16) | (higher as u16) << 8),
+ _ => None,
+ }
+ }
+ fn read_u32(&mut self) -> Option<u32> {
+ match (self.read_u16(), self.read_u16()) {
+ (Some(lower), Some(higher)) => Some((lower as u32) | (higher as u32) << 16),
+ _ => None,
+ }
+ }
+ fn read_u64(&mut self) -> Option<u64> {
+ match (self.read_u32(), self.read_u32()) {
+ (Some(lower), Some(higher)) => Some((lower as u64) | (higher as u64) << 32),
+ _ => None,
+ }
+ }
+ fn read_i8(&mut self) -> Option<i8> {
+ match self.read_u8() {
+ Some(expr) => Some(expr as i8),
+ None => None,
+ }
+ }
+ fn read_i16(&mut self) -> Option<i16> {
+ match self.read_u16() {
+ Some(expr) => Some(expr as i16),
+ None => None,
+ }
+ }
+ fn read_i32(&mut self) -> Option<i32> {
+ match self.read_u32() {
+ Some(expr) => Some(expr as i32),
+ None => None,
+ }
+ }
+ fn read_bool(&mut self) -> Option<bool> {
+ match self.read_u8() {
+ Some(expr) => Some(expr != 0),
+ None => None,
+ }
+ }
+ fn read_enum(&mut self) -> Option<u8> {
+ self.read_u8()
+ }
+ fn read_bdaddr(&mut self) -> Option<String> {
+ let mut out = String::new();
+ let mut buffer = vec![self.read_u8(), self.read_u8(), self.read_u8(), self.read_u8(), self.read_u8(), self.read_u8()];
+ buffer.reverse();
+ for (idx, b) in buffer.iter().enumerate() {
+ if idx > 0 { out.push(':'); }
+ match b {
+ Some(v) => {
+ out.push(u8_to_hex(v >> 4));
+ out.push(u8_to_hex(v << 4 >> 4));
+ },
+ None => return None,
+ }
+ }
+ Some(out)
+ }
+ fn read_string(&mut self) -> Option<String> {
+ match self.read_u8() {
+ Some(len) => {
+ let mut buf = vec![];
+ for _ in 0..len {
+ match self.read_u8() {
+ Some(b) => buf.push(b),
+ _ => return None,
+ }
+ }
+ String::from_utf8(buf).ok()
+ },
+ _ => None,
+ }
+ }
+ fn read_uuid(&mut self) -> Option<String> {
+ let mut out = String::new();
+ for _ in 0..16 {
+ let b = self.read_u8();
+ match b {
+ Some(v) => {
+ out.push(u8_to_hex(v >> 4));
+ out.push(u8_to_hex(v << 4 >> 4));
+ },
+ None => return None,
+ }
+ }
+ if &out[..] == "00000000000000000000000000000000" {
+ None
+ }
+ else {
+ Some(out)
+ }
+ }
+
+ fn read_event(&mut self) -> Event {
+ self.read_u8();
+ self.read_u8();
+ match self.read_u8() {
+ Some(opcode) => match opcode.try_into().ok() {
+
+ Some(OpCode::AdvertisementPacket) => match (
+ self.read_u32(),
+ self.read_bdaddr(),
+ self.read_string(),
+ self.read_u8(),
+ self.read_bool(),
+ self.read_bool(),
+ self.read_bool(),
+ self.read_bool(),
+ ) {
+ (
+ Some(scan_id),
+ Some(bd_addr),
+ Some(name),
+ Some(rssi),
+ Some(is_private),
+ Some(already_verified),
+ Some(already_connected_to_this_device),
+ Some(already_connected_to_other_device),
+ ) => Event::AdvertisementPacket {
+ scan_id,
+ bd_addr,
+ name,
+ rssi,
+ is_private,
+ already_verified,
+ already_connected_to_this_device,
+ already_connected_to_other_device,
+ },
+ _ => Event::CorruptEvent,
+ },
+ Some(OpCode::CreateConnectionChannelResponse) => match (
+ self.read_u32(),
+ self.read_enum(),
+ self.read_enum(),
+ ) {
+ (
+ Some(conn_id),
+ Some(error),
+ Some(connection_status),
+
+ ) =>
+ match (error.try_into().ok(), connection_status.try_into().ok()) {
+ (Some(error), Some(connection_status)) =>
+ Event::CreateConnectionChannelResponse {
+ conn_id,
+ error,
+ connection_status,
+ },
+ _ => Event::CorruptEvent,
+ },
+ _ => Event::CorruptEvent,
+ },
+ Some(OpCode::ConnectionStatusChanged) => match (
+ self.read_u32(),
+ self.read_enum(),
+ self.read_enum(),
+ ) {
+ (
+ Some(conn_id),
+ Some(connection_status),
+ Some(disconnect_reason),
+ ) =>
+ match (connection_status.try_into().ok(), disconnect_reason.try_into().ok()) {
+ (Some(connection_status), Some(disconnect_reason)) =>
+ Event::ConnectionStatusChanged {
+ conn_id,
+ connection_status,
+ disconnect_reason,
+ },
+ _ => Event::CorruptEvent,
+ },
+ _ => Event::CorruptEvent,
+ },
+ Some(OpCode::ConnectionChannelRemoved) => match (
+ self.read_u32(),
+ self.read_enum(),
+ ) {
+ (
+ Some(conn_id),
+ Some(removed_reason),
+ ) =>
+ match removed_reason.try_into().ok() {
+ Some(removed_reason) =>
+ Event::ConnectionChannelRemoved {
+ conn_id,
+ removed_reason,
+ },
+ _ => Event::CorruptEvent,
+ },
+ _ => Event::CorruptEvent,
+ },
+ Some(OpCode::ButtonUpOrDown) => match (
+ self.read_u32(),
+ self.read_enum(),
+ self.read_bool(),
+ self.read_i32(),
+ ) {
+ (
+ Some(conn_id),
+ Some(click_type),
+ Some(was_queued),
+ Some(time_diff),
+ ) =>
+ match click_type.try_into().ok() {
+ Some(click_type) =>
+ Event::ButtonUpOrDown {
+ conn_id,
+ click_type,
+ was_queued,
+ time_diff,
+ },
+ _ => Event::CorruptEvent,
+ }
+ _ => Event::CorruptEvent,
+ },
+ Some(OpCode::ButtonClickOrHold) => match (
+ self.read_u32(),
+ self.read_enum(),
+ self.read_bool(),
+ self.read_i32(),
+ ) {
+ (
+ Some(conn_id),
+ Some(click_type),
+ Some(was_queued),
+ Some(time_diff),
+ ) =>
+ match click_type.try_into().ok() {
+ Some(click_type) =>
+ Event::ButtonClickOrHold {
+ conn_id,
+ click_type,
+ was_queued,
+ time_diff,
+ },
+ _ => Event::CorruptEvent,
+ }
+ _ => Event::CorruptEvent,
+ },
+ Some(OpCode::ButtonSingleOrDoubleClick) => match (
+ self.read_u32(),
+ self.read_enum(),
+ self.read_bool(),
+ self.read_i32(),
+ ) {
+ (
+ Some(conn_id),
+ Some(click_type),
+ Some(was_queued),
+ Some(time_diff),
+ ) =>
+ match click_type.try_into().ok() {
+ Some(click_type) =>
+ Event::ButtonSingleOrDoubleClick {
+ conn_id,
+ click_type,
+ was_queued,
+ time_diff,
+ },
+ _ => Event::CorruptEvent,
+ }
+ _ => Event::CorruptEvent,
+ },
+ Some(OpCode::ButtonSingleOrDoubleClickOrHold) => match (
+ self.read_u32(),
+ self.read_enum(),
+ self.read_bool(),
+ self.read_i32(),
+ ) {
+ (
+ Some(conn_id),
+ Some(click_type),
+ Some(was_queued),
+ Some(time_diff),
+ ) =>
+ match click_type.try_into().ok() {
+ Some(click_type) =>
+ Event::ButtonSingleOrDoubleClickOrHold {
+ conn_id,
+ click_type,
+ was_queued,
+ time_diff,
+ },
+ _ => Event::CorruptEvent,
+ }
+ _ => Event::CorruptEvent,
+ },
+ Some(OpCode::NewVerifiedButton) => match (
+ self.read_bdaddr(),
+ ) {
+ (
+ Some(bd_addr),
+ ) => Event::NewVerifiedButton {
+ bd_addr,
+ },
+ _ => Event::CorruptEvent,
+ },
+ Some(OpCode::GetInfoResponse) => match (
+ self.read_enum(),
+ self.read_bdaddr(),
+ self.read_enum(),
+ self.read_u8(),
+ self.read_i16(),
+ self.read_u8(),
+ self.read_bool(),
+ self.read_u16(),
+ ) {
+ (
+ Some(bluetooth_controller_state),
+ Some(my_bd_addr),
+ Some(my_bd_addr_type),
+ Some(max_pending_connections),
+ Some(max_concurrently_connected_buttons),
+ Some(current_pending_connections),
+ Some(currently_no_space_for_new_connection),
+ Some(buttons_size),
+ ) => {
+ let mut bd_addr_of_verified_buttons = vec![];
+ for _ in 0..buttons_size {
+ match self.read_bdaddr() {
+ Some(bd_addr) => bd_addr_of_verified_buttons.push(bd_addr),
+ None => return Event::CorruptEvent,
+ }
+ }
+ match (bluetooth_controller_state.try_into().ok(), my_bd_addr_type.try_into().ok()) {
+ (Some(bluetooth_controller_state), Some(my_bd_addr_type)) =>
+ Event::GetInfoResponse {
+ bluetooth_controller_state,
+ my_bd_addr,
+ my_bd_addr_type,
+ max_pending_connections,
+ max_concurrently_connected_buttons,
+ current_pending_connections,
+ currently_no_space_for_new_connection,
+ bd_addr_of_verified_buttons,
+ },
+ _ => Event::CorruptEvent,
+ }
+ },
+ _ => Event::CorruptEvent,
+ },
+ Some(OpCode::NoSpaceForNewConnection) => match (
+ self.read_u8(),
+ ) {
+ (
+ Some(max_concurrently_connected_buttons),
+ ) => Event::NoSpaceForNewConnection {
+ max_concurrently_connected_buttons,
+ },
+ _ => Event::CorruptEvent,
+ },
+ Some(OpCode::GotSpaceForNewConnection) => match (
+ self.read_u8(),
+ ) {
+ (
+ Some(max_concurrently_connected_buttons),
+ ) => Event::GotSpaceForNewConnection {
+ max_concurrently_connected_buttons,
+ },
+ _ => Event::CorruptEvent,
+ },
+ Some(OpCode::BluetoothControllerStateChange) => match (
+ self.read_enum(),
+ ) {
+ (
+ Some(state),
+ ) =>
+ match state.try_into().ok() {
+ Some(state) =>
+ Event::BluetoothControllerStateChange {
+ state,
+ },
+ _ => Event::CorruptEvent,
+ }
+ _ => Event::CorruptEvent,
+ },
+ Some(OpCode::PingResponse) => match (
+ self.read_u32(),
+ ) {
+ (
+ Some(ping_id),
+ ) => Event::PingResponse {
+ ping_id,
+ },
+ _ => Event::CorruptEvent,
+ },
+ Some(OpCode::GetButtonInfoResponse) => match (
+ self.read_bdaddr(),
+ self.read_uuid(),
+ self.read_string(),
+ self.read_string(),
+ ) {
+ (
+ Some(bd_addr),
+ Some(uuid),
+ color,
+ serial_number,
+ ) => Event::GetButtonInfoResponse {
+ bd_addr,
+ uuid,
+ color,
+ serial_number,
+ },
+ _ => Event::CorruptEvent,
+ },
+ Some(OpCode::ScanWizardFoundPrivateButton) => match (
+ self.read_u32(),
+ ) {
+ (
+ Some(scan_wizard_id),
+ ) => Event::ScanWizardFoundPrivateButton {
+ scan_wizard_id,
+ },
+ _ => Event::CorruptEvent,
+ },
+ Some(OpCode::ScanWizardButtonConnected) => match (
+ self.read_u32(),
+ ) {
+ (
+ Some(scan_wizard_id),
+ ) => Event::ScanWizardButtonConnected {
+ scan_wizard_id,
+ },
+ _ => Event::CorruptEvent,
+ },
+ Some(OpCode::ScanWizardFoundPublicButton) => match (
+ self.read_u32(),
+ self.read_bdaddr(),
+ self.read_string(),
+ ) {
+ (
+ Some(scan_wizard_id),
+ Some(bd_addr),
+ Some(name),
+ ) => Event::ScanWizardFoundPublicButton {
+ scan_wizard_id,
+ bd_addr,
+ name,
+ },
+ _ => Event::CorruptEvent,
+ },