Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion check/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ async fn pcapify(qmdl_path: &PathBuf) {
for msg in container.into_messages().into_iter().flatten() {
if let Ok(Some((timestamp, parsed))) = gsmtap_parser::parse(msg) {
pcap_writer
.write_gsmtap_message(parsed, timestamp)
.write_gsmtap_message(parsed, timestamp, None)
.await
.expect("failed to write");
}
Expand Down
1 change: 1 addition & 0 deletions daemon/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ rayhunter = { path = "../lib" }
wifi-station = { git = "https://github.com/BeigeBox/wifi-station", rev = "e8ec5b4" }
toml = "0.8.8"
serde = { version = "1.0.193", features = ["derive"] }
serde_repr = "0.1"
tokio = { version = "1.44.2", default-features = false, features = ["fs", "signal", "process", "rt"] }
axum = { version = "0.8", default-features = false, features = ["http1", "tokio", "json"] }
thiserror = "1.0.52"
Expand Down
47 changes: 43 additions & 4 deletions daemon/src/config.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,40 @@
use log::warn;
use serde::{Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr};

use rayhunter::Device;
use rayhunter::analysis::analyzer::AnalyzerConfig;

use crate::error::RayhunterError;

#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Serialize_repr, Deserialize_repr)]
#[cfg_attr(feature = "apidocs", derive(utoipa::ToSchema))]
pub enum GpsMode {
Disabled = 0,
Fixed = 1,
Api = 2,
}

#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Serialize_repr, Deserialize_repr)]
#[cfg_attr(feature = "apidocs", derive(utoipa::ToSchema))]
pub enum UiLevel {
Invisible = 0,
Subtle = 1,
Demo = 2,
EffLogo = 3,
HighVisibility = 4,
TransFlag = 128,
}

#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Serialize_repr, Deserialize_repr)]
#[cfg_attr(feature = "apidocs", derive(utoipa::ToSchema))]
pub enum KeyInputMode {
Disabled = 0,
DoubleTapPower = 1,
}
Comment thread
CGurity marked this conversation as resolved.
use crate::notifications::NotificationType;

/// The structure of a valid rayhunter configuration
Expand All @@ -21,11 +51,11 @@ pub struct Config {
/// Internal device name
pub device: Device,
/// UI level
pub ui_level: u8,
pub ui_level: UiLevel,
/// Colorblind mode
pub colorblind_mode: bool,
/// Key input mode
pub key_input_mode: u8,
pub key_input_mode: KeyInputMode,
/// ntfy.sh URL
pub ntfy_url: Option<String>,
/// Vector containing the types of enabled notifications
Expand All @@ -36,6 +66,12 @@ pub struct Config {
pub min_space_to_start_recording_mb: u64,
/// Minimum disk space required to continue a recording
pub min_space_to_continue_recording_mb: u64,
/// GPS mode
pub gps_mode: GpsMode,
/// Fixed latitude used when gps_mode=1
pub gps_fixed_latitude: Option<f64>,
Comment thread
CGurity marked this conversation as resolved.
/// Fixed longitude used when gps_mode=1
pub gps_fixed_longitude: Option<f64>,
/// Wifi client SSID
pub wifi_ssid: Option<String>,
/// Wifi client password
Expand Down Expand Up @@ -96,14 +132,17 @@ impl Default for Config {
port: 8080,
debug_mode: false,
device: Device::Orbic,
ui_level: 1,
ui_level: UiLevel::Subtle,
colorblind_mode: false,
key_input_mode: 0,
key_input_mode: KeyInputMode::Disabled,
analyzers: AnalyzerConfig::default(),
ntfy_url: None,
enabled_notifications: vec![NotificationType::Warning, NotificationType::LowBattery],
min_space_to_start_recording_mb: 1,
min_space_to_continue_recording_mb: 1,
gps_mode: GpsMode::Disabled,
gps_fixed_latitude: None,
gps_fixed_longitude: None,
wifi_ssid: None,
wifi_password: None,
wifi_security: None,
Expand Down
43 changes: 40 additions & 3 deletions daemon/src/diag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ use futures::{StreamExt, TryStreamExt, future};
use log::{debug, error, info, warn};
use rayhunter::Device;
use tokio::fs::File;
use tokio::io::{AsyncBufReadExt, BufReader};
use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};

use crate::gps::GpsRecord;
use tokio::sync::mpsc::{Receiver, Sender};
use tokio::sync::{RwLock, oneshot};
use tokio_stream::wrappers::LinesStream;
Expand All @@ -26,6 +28,7 @@ use rayhunter::diag_device::DiagDevice;
use rayhunter::qmdl::QmdlWriter;

use crate::analysis::{AnalysisCtrlMessage, AnalysisWriter};
use crate::config::GpsMode;
use crate::display;
use crate::notifications::{Notification, NotificationType};
use crate::qmdl_store::{RecordingStore, RecordingStoreError};
Expand Down Expand Up @@ -56,6 +59,8 @@ pub struct DiagTask {
notification_channel: tokio::sync::mpsc::Sender<Notification>,
min_space_to_start_mb: u64,
min_space_to_continue_mb: u64,
gps_mode: GpsMode,
gps_fixed_coords: Option<(f64, f64)>,
state: DiagState,
max_type_seen: EventType,
bytes_since_space_check: usize,
Expand Down Expand Up @@ -104,6 +109,8 @@ impl DiagTask {
notification_channel: tokio::sync::mpsc::Sender<Notification>,
min_space_to_start_mb: u64,
min_space_to_continue_mb: u64,
gps_mode: GpsMode,
gps_fixed_coords: Option<(f64, f64)>,
) -> Self {
Self {
ui_update_sender,
Expand All @@ -112,6 +119,8 @@ impl DiagTask {
notification_channel,
min_space_to_start_mb,
min_space_to_continue_mb,
gps_mode,
gps_fixed_coords,
state: DiagState::Stopped,
max_type_seen: EventType::Informational,
bytes_since_space_check: 0,
Expand Down Expand Up @@ -144,14 +153,38 @@ impl DiagTask {
DiskSpaceCheck::Failed => {}
}

let (qmdl_file, analysis_file) = match qmdl_store.new_entry().await {
let (qmdl_file, analysis_file) = match qmdl_store.new_entry(self.gps_mode).await {
Ok(files) => files,
Err(e) => {
let msg = format!("failed creating QMDL file entry: {e}");
error!("{msg}");
return Err(msg);
}
};
// For fixed-mode sessions, write the configured coordinates to the sidecar
// immediately so the per-session GPS is stored durably and isn't affected
// by future config changes or GPS API calls.
if self.gps_mode == GpsMode::Fixed
&& let Some((lat, lon)) = self.gps_fixed_coords
&& let Some((entry_idx, _)) = qmdl_store.get_current_entry()
{
match qmdl_store.open_entry_gps_for_append(entry_idx).await {
Ok(Some(mut gps_file)) => {
let record = GpsRecord {
unix_ts: 0,
lat,
lon,
};
if let Ok(json) = serde_json::to_string(&record) {
let _ = gps_file.write_all(format!("{json}\n").as_bytes()).await;
}
}
Ok(None) => {
error!("GPS sidecar directory not found, cannot write fixed-mode coordinates")
}
Err(e) => error!("failed to open GPS sidecar for fixed-mode entry: {e}"),
}
}
self.stop_current_recording().await;
let qmdl_writer = QmdlWriter::new(qmdl_file);
let analysis_writer = match AnalysisWriter::new(analysis_file, &self.analyzer_config).await
Expand Down Expand Up @@ -381,6 +414,8 @@ pub fn run_diag_read_thread(
notification_channel: tokio::sync::mpsc::Sender<Notification>,
min_space_to_start_mb: u64,
min_space_to_continue_mb: u64,
gps_mode: GpsMode,
gps_fixed_coords: Option<(f64, f64)>,
) {
task_tracker.spawn(async move {
info!("Using configuration for device: {0:?}", device);
Expand All @@ -396,7 +431,9 @@ pub fn run_diag_read_thread(
analyzer_config,
notification_channel,
min_space_to_start_mb,
min_space_to_continue_mb
min_space_to_continue_mb,
gps_mode,
gps_fixed_coords,
);
qmdl_file_tx
.send(DiagDeviceCtrlMessage::StartRecording { response_tx: None })
Expand Down
19 changes: 9 additions & 10 deletions daemon/src/display/generic_framebuffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use image::{AnimationDecoder, DynamicImage, codecs::gif::GifDecoder, imageops::F
use std::io::Cursor;
use std::time::Duration;

use crate::config;
use crate::config::{self, UiLevel};
use crate::display::DisplayState;
use rayhunter::analysis::analyzer::EventType;

Expand Down Expand Up @@ -176,7 +176,7 @@ pub fn update_ui(
) {
static IMAGE_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/images/");
let display_level = config.ui_level;
if display_level == 0 {
if display_level == UiLevel::Invisible {
info!("Invisible mode, not spawning UI.");
return;
}
Expand All @@ -187,14 +187,14 @@ pub fn update_ui(
task_tracker.spawn(async move {
// this feels wrong, is there a more rusty way to do this?
let mut img: Option<&[u8]> = None;
if display_level == 2 {
if display_level == UiLevel::Demo {
img = Some(
IMAGE_DIR
.get_file("orca.gif")
.expect("failed to read orca.gif")
.contents(),
);
} else if display_level == 3 {
} else if display_level == UiLevel::EffLogo {
img = Some(
IMAGE_DIR
.get_file("eff.png")
Expand All @@ -217,20 +217,19 @@ pub fn update_ui(

let mut status_bar_height = 2;
match display_level {
2 => fb.draw_gif(img.unwrap()).await,
3 => fb.draw_img(img.unwrap()).await,
4 => {
UiLevel::Demo => fb.draw_gif(img.unwrap()).await,
UiLevel::EffLogo => fb.draw_img(img.unwrap()).await,
UiLevel::HighVisibility => {
status_bar_height = fb.dimensions().height;
}
128 => {
UiLevel::TransFlag => {
fb.draw_line(Color::Cyan, 128).await;
fb.draw_line(Color::Pink, 102).await;
fb.draw_line(Color::White, 76).await;
fb.draw_line(Color::Pink, 50).await;
fb.draw_line(Color::Cyan, 25).await;
}
// this branch is for ui_level 1, which is also the default if an
// unknown value is used
// UiLevel::Subtle (1) and anything else: just the status bar line
_ => {}
};
let (color, pattern) = display_style;
Expand Down
4 changes: 2 additions & 2 deletions daemon/src/display/tmobile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use tokio_util::task::TaskTracker;

use std::time::Duration;

use crate::config;
use crate::config::{self, UiLevel};
use crate::display::DisplayState;

macro_rules! led {
Expand All @@ -31,7 +31,7 @@ pub fn update_ui(
mut ui_update_rx: mpsc::Receiver<DisplayState>,
) {
let mut invisible: bool = false;
if config.ui_level == 0 {
if config.ui_level == UiLevel::Invisible {
info!("Invisible mode, not spawning UI.");
invisible = true;
}
Expand Down
4 changes: 2 additions & 2 deletions daemon/src/display/tplink.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use tokio::sync::mpsc::Receiver;
use tokio_util::sync::CancellationToken;
use tokio_util::task::TaskTracker;

use crate::config;
use crate::config::{self, UiLevel};
use crate::display::{DisplayState, tplink_framebuffer, tplink_onebit};

use std::fs;
Expand All @@ -15,7 +15,7 @@ pub fn update_ui(
ui_update_rx: Receiver<DisplayState>,
) {
let display_level = config.ui_level;
if display_level == 0 {
if display_level == UiLevel::Invisible {
info!("Invisible mode, not spawning UI.");
}

Expand Down
6 changes: 3 additions & 3 deletions daemon/src/display/tplink_onebit.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/// Display module for the TP-Link M7350 oled one-bit display.
///
/// https://github.com/m0veax/tplink_m7350/tree/main/oled
use crate::config;
use crate::config::{self, UiLevel};
use crate::display::DisplayState;

use log::{error, info};
Expand Down Expand Up @@ -115,7 +115,7 @@ pub fn update_ui(
mut ui_update_rx: Receiver<DisplayState>,
) {
let display_level = config.ui_level;
if display_level == 0 {
if display_level == UiLevel::Invisible {
info!("Invisible mode, not spawning UI.");
}

Expand All @@ -140,7 +140,7 @@ pub fn update_ui(

// we write the status every second because it may have been overwritten through menu
// navigation.
if display_level != 0
if display_level != UiLevel::Invisible
&& let Err(e) = tokio::fs::write(OLED_PATH, pixels).await
{
error!("failed to write to display: {e}");
Expand Down
4 changes: 2 additions & 2 deletions daemon/src/display/uz801.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use tokio_util::task::TaskTracker;

use std::time::Duration;

use crate::config;
use crate::config::{self, UiLevel};
use crate::display::DisplayState;

macro_rules! led {
Expand All @@ -31,7 +31,7 @@ pub fn update_ui(
mut ui_update_rx: mpsc::Receiver<DisplayState>,
) {
let mut invisible: bool = false;
if config.ui_level == 0 {
if config.ui_level == UiLevel::Invisible {
info!("Invisible mode, not spawning UI.");
invisible = true;
}
Expand Down
Loading
Loading