Skip to content

Commit e1786a3

Browse files
john-michaelburkeJason Mobarak
andauthored
Headless runner for console[CPP-318]. (#123)
* Headless runner for console. * Update console_backend/Cargo.toml Co-authored-by: Jason Mobarak <[email protected]> * Log messages. Co-authored-by: Jason Mobarak <[email protected]>
1 parent c1eeb4e commit e1786a3

30 files changed

+1344
-1166
lines changed

Cargo.lock

Lines changed: 9 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Makefile.toml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,18 @@ dependencies = [
152152
]
153153
run_task = "start-console"
154154

155+
[tasks.headless-run]
156+
command = "cargo"
157+
args = [
158+
"run",
159+
"--bin",
160+
"headless-console",
161+
"--features",
162+
"headless-console",
163+
"--no-default-features",
164+
"${@}",
165+
]
166+
155167
[tasks.store-version]
156168
script_runner = "@shell"
157169
script = '''

console_backend/Cargo.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ minreq = { version = "2.4.2", features = ["https"] }
4040
regex = { version = "1.5.4" }
4141
semver = { version = "1" }
4242
rust-ini = "0.17.0"
43+
snap = { version = "1", optional = true }
4344

4445
[dependencies.sbp]
4546
git = "https://github.com/swift-nav/libsbp.git"
@@ -80,8 +81,15 @@ path = "src/bin/fft_monitor.rs"
8081
bench = false
8182
required-features = ["fft"]
8283

84+
[[bin]]
85+
name = "headless-console"
86+
path = "src/bin/headless-console.rs"
87+
bench = false
88+
required-features = ["headless-console"]
89+
8390
[features]
8491
default = ["pyo3"]
8592
benches = []
8693
tests = []
8794
fft = ["serde-pickle"]
95+
headless-console = ["snap"]

console_backend/benches/cpu_benches.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ extern crate console_backend;
1414
use console_backend::{
1515
connection::Connection,
1616
process_messages,
17-
types::{ClientSender, RealtimeDelay, SharedState},
17+
shared_state::SharedState,
18+
types::{ClientSender, RealtimeDelay},
1819
};
1920

2021
const BENCH_FILEPATH: &str = "./tests/data/piksi-relay.sbp";

console_backend/src/advanced_ins_tab.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ use capnp::message::Builder;
66
use crate::constants::*;
77
use crate::errors::GET_MUT_OBJECT_FAILURE;
88
use crate::fusion_status_flags::FusionStatusFlags;
9-
use crate::types::{CapnProtoSender, Deque, SharedState};
9+
use crate::shared_state::SharedState;
10+
use crate::types::{CapnProtoSender, Deque};
1011
use crate::utils::serialize_capnproto_builder;
1112

1213
/// AdvancedInsTab struct.

console_backend/src/advanced_magnetometer_tab.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ use capnp::message::Builder;
44

55
use crate::constants::{MAGNETOMETER_Y_AXIS_PADDING_MULTIPLIER, NUM_POINTS};
66
use crate::errors::GET_MUT_OBJECT_FAILURE;
7-
use crate::types::{CapnProtoSender, Deque, SharedState};
7+
use crate::shared_state::SharedState;
8+
use crate::types::{CapnProtoSender, Deque};
89
use crate::utils::serialize_capnproto_builder;
910

1011
/// AdvancedMagnetometerTab struct.

console_backend/src/advanced_spectrum_analyzer_tab.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ use log::error;
33
use crate::constants::{AMPLITUDES, CHANNELS, FREQUENCIES};
44
use crate::errors::SHARED_STATE_LOCK_MUTEX_FAILURE;
55
use crate::fft_monitor::FftMonitor;
6-
use crate::types::{CapnProtoSender, SharedState, Specan};
6+
use crate::shared_state::SharedState;
7+
use crate::types::{CapnProtoSender, Specan};
78
use crate::utils::serialize_capnproto_builder;
89
use capnp::message::Builder;
910

console_backend/src/baseline_tab.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ use crate::constants::*;
1212
use crate::date_conv::*;
1313
use crate::output::BaselineLog;
1414
use crate::piksi_tools_constants::EMPTY_STR;
15+
use crate::shared_state::SharedState;
1516
use crate::types::{
16-
BaselineNED, CapnProtoSender, Deque, GnssModes, GpsTime, MsgSender, Result, SharedState,
17-
UtcDateTime,
17+
BaselineNED, CapnProtoSender, Deque, GnssModes, GpsTime, MsgSender, Result, UtcDateTime,
1818
};
1919
use crate::utils::*;
2020

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
use anyhow::Result;
2+
use chrono::prelude::*;
3+
use console_backend::{
4+
cli_options::{handle_cli, CliOptions},
5+
connection::ConnectionState,
6+
log_panel::setup_logging,
7+
server_recv_thread::server_recv_thread,
8+
shared_state::SharedState,
9+
types::ClientSender,
10+
utils::{refresh_loggingbar, refresh_navbar},
11+
};
12+
use crossbeam::channel;
13+
use std::fs::File;
14+
use std::io::{prelude::*, BufWriter};
15+
16+
fn main() -> Result<()> {
17+
let opt = CliOptions::from_filtered_cli();
18+
if opt.input.is_none() {
19+
eprintln!(
20+
r#"
21+
Running in headless mode only command line options work.
22+
Help:
23+
./headless-console --help
24+
Usage:
25+
./headless-console tcp piksi-relay-bb9f2b10e53143f4a816a11884e679cf.ce.swiftnav.com --port=55555
26+
"#
27+
);
28+
return Ok(());
29+
}
30+
let (client_send_, client_recv) = channel::unbounded::<Vec<u8>>();
31+
let (_server_send, server_recv) = channel::unbounded::<Vec<u8>>();
32+
let client_send = ClientSender::new(client_send_);
33+
setup_logging(client_send.clone(), true);
34+
let shared_state = SharedState::new();
35+
let connection_state = ConnectionState::new(client_send.clone(), shared_state.clone());
36+
handle_cli(opt, &connection_state, shared_state.clone());
37+
refresh_navbar(&mut client_send.clone(), shared_state.clone());
38+
refresh_loggingbar(&mut client_send.clone(), shared_state.clone());
39+
server_recv_thread(connection_state, client_send, server_recv, shared_state);
40+
41+
let local: DateTime<Local> = Local::now();
42+
let mut filename = format!("headless-console-{}.data", local);
43+
filename.retain(|c| !c.is_whitespace());
44+
let file_out = File::create(filename)?;
45+
let buf_out = BufWriter::new(file_out);
46+
let mut msg_count: usize = 0;
47+
let mut file_out = snap::write::FrameEncoder::new(buf_out);
48+
while let Ok(msg) = client_recv.recv() {
49+
match file_out.write_all(&msg) {
50+
Ok(_) => {
51+
msg_count += 1;
52+
if msg_count % 100 == 0 {
53+
println!("Messages received: {}", msg_count);
54+
}
55+
}
56+
Err(err) => {
57+
eprintln!("{}", err);
58+
}
59+
}
60+
}
61+
Ok(())
62+
}

console_backend/src/cli_options.rs

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,14 @@ use std::{
77
use strum::VariantNames;
88

99
use crate::constants::{AVAILABLE_BAUDRATES, AVAILABLE_REFRESH_RATES};
10+
use crate::errors::{CONVERT_TO_STR_FAILURE, SHARED_STATE_LOCK_MUTEX_FAILURE};
1011
use crate::log_panel::LogLevel;
11-
use crate::types::FlowControl;
12+
use crate::output::CsvLogging;
13+
use crate::shared_state::SharedState;
14+
use crate::types::{FlowControl, RealtimeDelay};
1215
use crate::{
1316
common_constants::{SbpLogging, Tabs},
14-
connection::Connection,
17+
connection::{Connection, ConnectionState},
1518
};
1619

1720
#[derive(Debug)]
@@ -233,3 +236,48 @@ fn is_baudrate(br: &str) -> Result<(), String> {
233236
AVAILABLE_BAUDRATES
234237
))
235238
}
239+
240+
/// Start connections based on CLI options.
241+
///
242+
/// # Parameters
243+
/// - `opt`: CLI Options to start specific connection type.
244+
/// - `connection_state`: The Server state to start a specific connection.
245+
/// - `client_send`: Client Sender channel for communication from backend to frontend.
246+
/// - `shared_state`: The shared state for validating another connection is not already running.
247+
pub fn handle_cli(opt: CliOptions, connection_state: &ConnectionState, shared_state: SharedState) {
248+
if let Some(opt_input) = opt.input {
249+
match opt_input {
250+
Input::Tcp { host, port } => {
251+
connection_state.connect_to_host(host, port);
252+
}
253+
Input::File { file_in } => {
254+
let filename = file_in.display().to_string();
255+
connection_state.connect_to_file(filename, RealtimeDelay::On, opt.exit_after);
256+
}
257+
Input::Serial {
258+
serialport,
259+
baudrate,
260+
flow_control,
261+
} => {
262+
let serialport = serialport.display().to_string();
263+
connection_state.connect_to_serial(serialport, baudrate, flow_control);
264+
}
265+
}
266+
}
267+
if let Some(folder) = opt.dirname {
268+
shared_state.set_logging_directory(PathBuf::from(folder));
269+
}
270+
let log_level = if let Some(log_level_) = opt.log_level {
271+
(*log_level_).clone()
272+
} else {
273+
LogLevel::INFO
274+
};
275+
shared_state.set_log_level(log_level);
276+
let mut shared_data = shared_state.lock().expect(SHARED_STATE_LOCK_MUTEX_FAILURE);
277+
(*shared_data).logging_bar.csv_logging = CsvLogging::from(opt.csv_log);
278+
if let Some(sbp_log) = opt.sbp_log {
279+
(*shared_data).logging_bar.sbp_logging =
280+
SbpLogging::from_str(&sbp_log.to_string()).expect(CONVERT_TO_STR_FAILURE);
281+
}
282+
log::logger().flush();
283+
}

console_backend/src/connection.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::constants::*;
22
use crate::errors::*;
33
use crate::process_messages::process_messages;
4+
use crate::shared_state::SharedState;
45
use crate::types::*;
56
use anyhow::anyhow;
67
use crossbeam::channel::{unbounded, Receiver, Sender};

console_backend/src/errors.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
pub(crate) const HEARTBEAT_LOCK_MUTEX_FAILURE: &str = "unable to lock heartbeat mutex";
2-
pub(crate) const SHARED_STATE_LOCK_MUTEX_FAILURE: &str = "unable to lock shared_state mutex";
2+
pub const SHARED_STATE_LOCK_MUTEX_FAILURE: &str = "unable to lock shared_state mutex";
33
pub(crate) const UPDATE_STATUS_LOCK_MUTEX_FAILURE: &str = "unable to lock update status mutex";
44
pub(crate) const CAP_N_PROTO_SERIALIZATION_FAILURE: &str = "unable to serialize capnproto message";
55
#[allow(dead_code)]
6-
pub(crate) const CAP_N_PROTO_DESERIALIZATION_FAILURE: &str =
7-
"unable to deserialize capnproto message";
8-
pub(crate) const CONVERT_TO_STR_FAILURE: &str = "error converting to str";
6+
pub const CAP_N_PROTO_DESERIALIZATION_FAILURE: &str = "unable to deserialize capnproto message";
7+
pub const CONVERT_TO_STR_FAILURE: &str = "error converting to str";
98
pub(crate) const GET_MUT_OBJECT_FAILURE: &str = "error trying to get mut object";
109
pub(crate) const UNABLE_TO_STOP_TIMER_THREAD_FAILURE: &str = "unable to kill running timer thread";
1110
pub(crate) const UNABLE_TO_SEND_INS_UPDATE_FAILURE: &str = "unable to send an ins status update";

console_backend/src/fusion_status_flags.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ use crate::errors::{
1414
THREAD_JOIN_FAILURE, UNABLE_TO_SEND_INS_UPDATE_FAILURE, UNABLE_TO_STOP_TIMER_THREAD_FAILURE,
1515
UPDATE_STATUS_LOCK_MUTEX_FAILURE,
1616
};
17-
use crate::types::ArcBool;
18-
use crate::types::{CapnProtoSender, SharedState};
17+
use crate::shared_state::SharedState;
18+
use crate::types::{ArcBool, CapnProtoSender};
1919
use crate::utils::serialize_capnproto_builder;
2020

2121
const STATUS_PERIOD: f64 = 1.0;

console_backend/src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ pub mod process_messages;
2525
#[cfg(not(test))]
2626
#[cfg(all(not(feature = "benches"), not(feature = "tests"), feature = "pyo3"))]
2727
pub mod server;
28+
pub mod server_recv_thread;
2829
pub mod settings_tab;
30+
pub mod shared_state;
2931
pub mod solution_tab;
3032
pub mod solution_velocity_tab;
3133
pub mod status_bar;
@@ -62,7 +64,7 @@ struct Tabs<'link, S: types::CapnProtoSender> {
6264

6365
impl<'link, S: types::CapnProtoSender> Tabs<'link, S> {
6466
fn new(
65-
shared_state: types::SharedState,
67+
shared_state: shared_state::SharedState,
6668
client_sender: S,
6769
msg_sender: types::MsgSender,
6870
link: sbp::link::Link<'link, ()>,

console_backend/src/log_panel.rs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use capnp::message::Builder;
66
use crate::common_constants as cc;
77
use crate::constants::LOG_WRITER_BUFFER_MESSAGE_COUNT;
88
use crate::errors::CONSOLE_LOG_JSON_TO_STRING_FAILURE;
9-
use crate::types::*;
9+
use crate::types::{CapnProtoSender, ClientSender};
1010
use crate::utils::serialize_capnproto_builder;
1111

1212
use async_logger::Writer;
@@ -96,8 +96,8 @@ pub fn handle_log_msg(msg: MsgLog) {
9696
}
9797
}
9898

99-
pub fn setup_logging(client_sender: ClientSender) {
100-
let log_panel = LogPanelWriter::new(client_sender);
99+
pub fn setup_logging(client_sender: ClientSender, debug: bool) {
100+
let log_panel = LogPanelWriter::new(client_sender, debug);
101101
let logger = Logger::builder()
102102
.buf_size(LOG_WRITER_BUFFER_MESSAGE_COUNT)
103103
.formatter(splitable_log_formatter)
@@ -111,11 +111,15 @@ pub fn setup_logging(client_sender: ClientSender) {
111111
#[derive(Debug)]
112112
pub struct LogPanelWriter<S: CapnProtoSender> {
113113
pub client_sender: S,
114+
pub debug: bool,
114115
}
115116

116117
impl<S: CapnProtoSender> LogPanelWriter<S> {
117-
pub fn new(client_sender: S) -> LogPanelWriter<S> {
118-
LogPanelWriter { client_sender }
118+
pub fn new(client_sender: S, debug: bool) -> LogPanelWriter<S> {
119+
LogPanelWriter {
120+
client_sender,
121+
debug,
122+
}
119123
}
120124
}
121125

@@ -132,6 +136,9 @@ impl<S: CapnProtoSender> Writer<Box<String>> for LogPanelWriter<S> {
132136
let mut entries = log_update.init_entries(slice.len() as u32);
133137

134138
for (idx, item) in slice.iter().enumerate() {
139+
if self.debug {
140+
eprintln!("{}", item);
141+
}
135142
let mut entry = entries.reborrow().get(idx as u32);
136143

137144
entry.set_line(&**item);

console_backend/src/main_tab.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,13 @@ use log::{debug, error};
55
use sbp::{messages::SBP, time::GpsTime};
66

77
use crate::common_constants::SbpLogging;
8-
use crate::constants::*;
9-
use crate::output::*;
10-
use crate::types::*;
8+
use crate::constants::{
9+
BASELINE_TIME_STR_FILEPATH, POS_LLH_TIME_STR_FILEPATH, SBP_FILEPATH, SBP_JSON_FILEPATH,
10+
VEL_TIME_STR_FILEPATH,
11+
};
12+
use crate::output::{CsvLogging, SbpLogger};
13+
use crate::shared_state::{create_directory, SharedState};
14+
use crate::types::CapnProtoSender;
1115
use crate::utils::refresh_loggingbar;
1216

1317
pub struct MainTab<S: CapnProtoSender> {
@@ -191,7 +195,7 @@ mod tests {
191195
use super::*;
192196
use crate::baseline_tab::BaselineTab;
193197
use crate::solution_tab::SolutionTab;
194-
use crate::types::{PosLLH, VelNED};
198+
use crate::types::{BaselineNED, MsgSender, PosLLH, TestSender, VelNED};
195199
use crate::utils::{mm_to_m, ms_to_sec};
196200
use glob::glob;
197201
use sbp::messages::navigation::{MsgBaselineNED, MsgPosLLH, MsgVelNED};

console_backend/src/observation_tab.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ use capnp::message::Builder;
33
use log::warn;
44
use std::collections::{BTreeMap, HashMap};
55

6-
use crate::types::*;
6+
use crate::shared_state::SharedState;
7+
use crate::types::{CapnProtoSender, ObservationMsg, SignalCodes};
78
use crate::utils::{compute_doppler, sec_to_ns};
89

910
use crate::utils::serialize_capnproto_builder;

0 commit comments

Comments
 (0)