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, } 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 { if self.fifo.is_empty() { return None; } let mut iter = self.fifo.drain(..1); iter.next() } fn read_u16(&mut self) -> Option { 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 { 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 { 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 { match self.read_u8() { Some(expr) => Some(expr as i8), None => None, } } fn read_i16(&mut self) -> Option { match self.read_u16() { Some(expr) => Some(expr as i16), None => None, } } fn read_i32(&mut self) -> Option { match self.read_u32() { Some(expr) => Some(expr as i32), None => None, } } fn read_bool(&mut self) -> Option { match self.read_u8() { Some(expr) => Some(expr != 0), None => None, } } fn read_enum(&mut self) -> Option { self.read_u8() } fn read_bdaddr(&mut self) -> Option { 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 { 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 { 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, }, Some(OpCode::ScanWizardCompleted) => match ( self.read_u32(), self.read_enum(), ) { ( Some(scan_wizard_id), Some(result), ) => match result.try_into().ok() { Some(result) => Event::ScanWizardCompleted { scan_wizard_id, result, }, _ => Event::CorruptEvent, } _ => Event::CorruptEvent, }, Some(OpCode::ButtonDeleted) => match ( self.read_bdaddr(), self.read_bool(), ) { ( Some(bd_addr), Some(deleted_by_this_client), ) => Event::ButtonDeleted { bd_addr, deleted_by_this_client, }, _ => Event::CorruptEvent, }, Some(OpCode::BatteryStatus) => match ( self.read_u32(), self.read_i8(), self.read_u64(), ) { ( Some(listener_id), Some(battery_percentage), Some(timestamp), ) => Event::BatteryStatus { listener_id, battery_percentage, timestamp, }, _ => Event::CorruptEvent, }, _ => Event::CorruptEvent, }, None => Event::NoOp, } } } fn u8_to_hex(value: u8) -> char { match value { 0u8..=9u8 => (value + b'0') as char, _ => (value - 10u8 + b'a') as char, } }