Skip to content

Commit

Permalink
Refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
ztroop committed Mar 18, 2024
1 parent c266d2c commit 9dc2445
Show file tree
Hide file tree
Showing 8 changed files with 79 additions and 57 deletions.
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![allow(dead_code)]
#[macro_use]
extern crate lazy_static;
use crate::viewer::viewer;
Expand Down
8 changes: 7 additions & 1 deletion src/scan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use tokio::sync::mpsc;

use crate::structs::DeviceInfo;
use crate::structs::{Characteristic, DeviceInfo};

/// Scans for Bluetooth devices and sends the information to the provided `mpsc::Sender`.
/// The scan can be paused by setting the `pause_signal` to `true`.
Expand Down Expand Up @@ -58,3 +58,9 @@ pub async fn bluetooth_scan(

Ok(())
}

/// Gets the characteristics of a Bluetooth device and returns them as a `Vec<Characteristic>`.
/// The device is identified by its address or UUID.
pub async fn get_characteristics(_device_id: &str) -> Result<Vec<Characteristic>, Box<dyn Error>> {
unimplemented!();
}
14 changes: 13 additions & 1 deletion src/structs.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::collections::HashMap;

use btleplug::api::CharPropFlags;
use uuid::Uuid;

/// A struct to hold the information of a Bluetooth device.
Expand Down Expand Up @@ -37,7 +38,18 @@ impl DeviceInfo {
manufacturer_data,
services,
detected_at: chrono::Local::now().format("%Y-%m-%d %H:%M:%S").to_string(),
service_data
service_data,
}
}
}

pub struct Characteristic {
pub uuid: Uuid,
pub properties: CharPropFlags,
pub descriptors: Vec<Uuid>,
}

pub struct ManufacturerData {
pub company_code: String,
pub data: String,
}
16 changes: 11 additions & 5 deletions src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ use std::collections::HashMap;

use ratatui::layout::Rect;

use crate::company_codes::COMPANY_CODE;
use crate::{company_codes::COMPANY_CODE, structs::ManufacturerData};

/// Extracts the manufacturer data from a `HashMap<u16, Vec<u8>>` and returns a tuple with the company name and the manufacturer data as a string.
/// If the manufacturer data is empty, it returns "n/a" as the company name and the manufacturer data.
/// If the company code is not found in the `company_codes` module, it returns "n/a" as the company name.
pub fn extract_manufacturer_data(manufacturer_data: &HashMap<u16, Vec<u8>>) -> (String, String) {
pub fn extract_manufacturer_data(manufacturer_data: &HashMap<u16, Vec<u8>>) -> ManufacturerData {
let mut c = None;
let mut m = manufacturer_data
.iter()
Expand All @@ -24,8 +24,14 @@ pub fn extract_manufacturer_data(manufacturer_data: &HashMap<u16, Vec<u8>>) -> (
.join(" ");
m = if m.is_empty() { "n/a".to_string() } else { m };
match c {
Some(code) => (COMPANY_CODE.get(&code).unwrap_or(&"n/a").to_string(), m),
None => ("n/a".to_string(), m),
Some(code) => ManufacturerData {
company_code: COMPANY_CODE.get(&code).unwrap_or(&"n/a").to_string(),
data: m,
},
None => ManufacturerData {
company_code: "n/a".to_string(),
data: m,
},
}
}

Expand All @@ -41,4 +47,4 @@ pub fn centered_rect(percent_x: u16, percent_y: u16, size: Rect) -> Rect {
y: (size.height - popup_size.height) / 2,
..popup_size
}
}
}
34 changes: 16 additions & 18 deletions src/viewer.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crossterm::event::{self, Event, KeyCode};
use ratatui::backend::Backend;
use ratatui::widgets::{Clear, TableState};
use ratatui::widgets::TableState;
use ratatui::{
layout::{Constraint, Direction, Layout},
Terminal,
Expand All @@ -12,11 +12,9 @@ use std::time::Duration;
use tokio::sync::mpsc;

use crate::structs::DeviceInfo;
use crate::utils::centered_rect;
use crate::widgets::detail_table::detail_table;
use crate::widgets::device_table::device_table;
use crate::widgets::info_table::info_table;
use crate::widgets::inspect_overlay::inspect_overlay;

/// Displays the detected Bluetooth devices in a table and handles the user input.
/// The user can navigate the table, pause the scanning, and quit the application.
Expand All @@ -29,7 +27,8 @@ pub async fn viewer<B: Backend>(
let mut table_state = TableState::default();
table_state.select(Some(0));
let mut devices = Vec::<DeviceInfo>::new();
let mut inspect_view = false;
// let mut inspect_view = false;
// let mut selected_characteristics: Vec<Characteristic> = Vec::new();

loop {
// Draw UI
Expand All @@ -47,28 +46,29 @@ pub async fn viewer<B: Backend>(
)
.split(f.size());

let device_binding = &DeviceInfo::default();
let selected_device = devices
.get(table_state.selected().unwrap_or(0))
.unwrap_or(device_binding);

// Draw the device table
let device_table = device_table(table_state.selected(), &devices);
f.render_stateful_widget(device_table, chunks[0], &mut table_state);

// Draw the detail table
let detail_table = detail_table(table_state.selected(), &devices);
let detail_table = detail_table(&selected_device);
f.render_widget(detail_table, chunks[1]);

// Draw the info table
let info_table = info_table(pause_signal.load(Ordering::SeqCst));
f.render_widget(info_table, chunks[2]);

let selected = table_state.selected();
if inspect_view && selected.is_some() {
let device: &DeviceInfo = &devices[selected.unwrap()];
if !device.service_data.is_empty() {
let inspect_overlay = inspect_overlay(device);
let area = centered_rect(60, 60, f.size());
f.render_widget(Clear, area);
f.render_widget(inspect_overlay, area);
}
}
// if inspect_view {
// let inspect_overlay = inspect_overlay(&selected_characteristics);
// let area = centered_rect(60, 60, f.size());
// f.render_widget(Clear, area);
// f.render_widget(inspect_overlay, area);
// }
})?;

// Event handling
Expand All @@ -80,9 +80,7 @@ pub async fn viewer<B: Backend>(
let current_state = pause_signal.load(Ordering::SeqCst);
pause_signal.store(!current_state, Ordering::SeqCst);
}
KeyCode::Enter => {
inspect_view = !inspect_view;
}
KeyCode::Enter => {}
KeyCode::Down => {
let next = match table_state.selected() {
Some(selected) => {
Expand Down
15 changes: 7 additions & 8 deletions src/widgets/detail_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,7 @@ use ratatui::{
use crate::{structs::DeviceInfo, utils::extract_manufacturer_data};

/// Creates a table with more detailed information about a selected device.
pub fn detail_table(selected: Option<usize>, devices: &[DeviceInfo]) -> Table {
let device_binding = DeviceInfo::default();
let selected_device = devices
.get(selected.unwrap_or(0))
.unwrap_or(&device_binding);
pub fn detail_table(selected_device: &DeviceInfo) -> Table {
let services_binding = selected_device.services.len().to_string();
let manufacturer_data = extract_manufacturer_data(&selected_device.manufacturer_data);
let table = Table::new(
Expand All @@ -22,15 +18,18 @@ pub fn detail_table(selected: Option<usize>, devices: &[DeviceInfo]) -> Table {
Row::new(vec!["Services:".to_owned(), services_binding]),
Row::new(vec![
"Company Code Identifier:".to_owned(),
manufacturer_data.0,
manufacturer_data.company_code,
]),
Row::new(vec![
"Manufacturer Data:".to_owned(),
manufacturer_data.data,
]),
Row::new(vec!["Manufacturer Data:".to_owned(), manufacturer_data.1]),
],
[Constraint::Length(30), Constraint::Length(70)],
)
.block(
Block::default()
.title("More Detail".to_owned())
.title("More Details".to_owned())
.borders(Borders::ALL),
);

Expand Down
46 changes: 23 additions & 23 deletions src/widgets/inspect_overlay.rs
Original file line number Diff line number Diff line change
@@ -1,39 +1,39 @@
use ratatui::{
layout::Constraint,
style::{Color, Modifier, Style},
style::{Modifier, Style},
widgets::{Block, Borders, Row, Table},
};

use crate::structs::DeviceInfo;
use crate::structs::Characteristic;

/// Provides an overlay with the selected device's service data.
pub fn inspect_overlay(selected_device: &DeviceInfo) -> Table<'static> {
// Iterate through the selected device's service_data to create rows
let rows: Vec<Row> = selected_device
.service_data
pub fn inspect_overlay(characteristics: &Vec<Characteristic>) -> Table<'static> {
// Iterate through the selected device's characteristics to create rows
let rows: Vec<Row> = characteristics
.iter()
.map(|(uuid, data)| {
let data_str = data
.map(|characteristic| {
let properties = format!("{:?}", characteristic.properties);
let descriptors = characteristic
.descriptors
.iter()
.map(|byte| format!("{:02x}", byte))
.map(|uuid| uuid.to_string())
.collect::<Vec<String>>()
.join(" ");
// Create a row for each UUID and its corresponding data
Row::new(vec![uuid.to_string(), data_str])
.join(", ");
Row::new(vec![
characteristic.uuid.to_string(),
properties,
descriptors,
])
})
.collect();

let table = Table::new(
rows,
[Constraint::Percentage(50), Constraint::Percentage(50)],
)
.header(Row::new(vec!["UUID", "Data"]).style(Style::default().fg(Color::Yellow)))
.block(
Block::default()
.borders(Borders::ALL)
.title("Data Overview"),
)
.highlight_style(Style::default().add_modifier(Modifier::BOLD));
let table = Table::new(rows, [Constraint::Percentage(100)])
.block(
Block::default()
.borders(Borders::ALL)
.title("Inspecting Device Characteristics"),
)
.highlight_style(Style::default().add_modifier(Modifier::BOLD));

table
}
2 changes: 1 addition & 1 deletion src/widgets/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pub mod detail_table;
pub mod device_table;
pub mod info_table;
pub mod inspect_overlay;
pub mod inspect_overlay;

0 comments on commit 9dc2445

Please sign in to comment.