Skip to content

Commit 64e92df

Browse files
authored
Develop (#263)
* Improve Readme * Improve fops/ definitions * CSV export * Working on RTK opmode and interfacing * Definitions for rtk * Orbit Upgrade * RTK upgrade --------- Signed-off-by: Guillaume W. Bres <guillaume.bressaix@gmail.com>
1 parent 99994db commit 64e92df

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1473
-896
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ test_resources/
66

77
Cargo.lock
88

9+
*.csv
910
*.png
1011
*.jpg
1112
*.html

rinex-cli/Cargo.toml

+4-3
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ serde = { version = "1.0", default-features = false, features = ["derive"] }
3434

3535
kml = { version = "0.8", optional = true }
3636
gpx = { version = "0.10", optional = true }
37+
csv = { version = "1.3.0", optional = true }
3738

3839
plotly = "0.9"
3940
# plotly = { path = "../../plotly-rs/plotly" }
@@ -44,9 +45,9 @@ hifitime = { version = "4.0.0-alpha", features = ["serde", "std"] }
4445

4546
gnss-rs = { version = "2.2.1", features = ["serde"] }
4647

47-
# gnss-rtk = { version = "0.6.0", features = ["serde"] }
48-
# gnss-rtk = { path = "../../rtk-rs/gnss-rtk", features = ["serde"] }
49-
gnss-rtk = { git = "https://github.com/rtk-rs/gnss-rtk", branch = "main", features = ["serde"] }
48+
gnss-rtk = { version = "0.7.0", features = ["serde"] }
49+
# gnss-rtk = { path = "../../rtk-rs/gnss-rtk", features = ["serde"] }
50+
# gnss-rtk = { git = "https://github.com/rtk-rs/gnss-rtk", branch = "main", features = ["serde"] }
5051

5152
cggtts = { version = "4.1.5", features = ["serde", "scheduler"], optional = true }
5253
# cggtts = { path = "../../cggtts/cggtts", features = ["serde", "scheduler"], optional = true }

rinex-cli/src/cli/fops/filegen.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ pub fn subcommand() -> Command {
88
.long_flag("filegen")
99
.arg_required_else_help(false)
1010
.about(
11-
"Parse, preprocess and generate data while preserving input format. See --filegen --help."
11+
"Parse, preprocess and generate new RINEX and/or SP3 data. Input forms are preserved. See --filegen --help."
1212
)
1313
.long_about("
1414
Use this mode to generate all file formats we support after preprocessing them.

rinex-cli/src/cli/fops/mod.rs

+54
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,58 @@ use rinex::prod::{DataSource, FFU, PPU};
1414
* Arguments that are shared by all file operations.
1515
* Mainly [ProductionAttributes] (re)definition opts
1616
*/
17+
#[cfg(not(feature = "csv"))]
18+
lazy_static! {
19+
pub static ref SHARED_GENERAL_ARGS : Vec<Arg> = vec![
20+
Arg::new("batch")
21+
.short('b')
22+
.long("batch")
23+
.required(false)
24+
.value_parser(value_parser!(u8))
25+
.help("Set # (number ID) in case this file is part of a file serie"),
26+
Arg::new("short")
27+
.short('s')
28+
.long("short")
29+
.action(ArgAction::SetTrue)
30+
.help("Prefer (deprecated) short filenames as historically used.
31+
Otherwise, this ecosystem prefers modern (longer) filenames that contain more information."),
32+
Arg::new("gzip")
33+
.long("gzip")
34+
.action(ArgAction::SetTrue)
35+
.help("Force .gzip compressed file generation, even if input data is not."),
36+
Arg::new("unzip")
37+
.long("unzip")
38+
.action(ArgAction::SetTrue)
39+
.help("Force plain/readable file generation. By default, if input data is gzip compressed, we will preserve
40+
the input compression. Use this to bypass."),
41+
Arg::new("csv")
42+
.long("csv")
43+
.action(ArgAction::SetTrue)
44+
.help("[NOT AVAILABLE] requires `csv` compilation option"),
45+
Arg::new("agency")
46+
.short('a')
47+
.long("agency")
48+
.required(false)
49+
.help("Define a custom agency name, possibly overwriting
50+
what the original filename did define (according to conventions)."),
51+
Arg::new("country")
52+
.short('c')
53+
.long("country")
54+
.required(false)
55+
.help("Define a custom (3 letter) country code.
56+
This code should represent where the Agency is located."),
57+
Arg::new("source")
58+
.long("src")
59+
.required(false)
60+
.value_name("[RCVR,STREAM]")
61+
.value_parser(value_parser!(DataSource))
62+
.help("Define the data source.
63+
In RINEX standards, we use \"RCVR\" when data was sampled from a hardware receiver.
64+
Use \"STREAM\" for other stream data source, like RTCM for example.")
65+
];
66+
}
67+
68+
#[cfg(feature = "csv")]
1769
lazy_static! {
1870
pub static ref SHARED_GENERAL_ARGS : Vec<Arg> = vec![
1971
Arg::new("batch")
@@ -64,7 +116,9 @@ This code should represent where the Agency is located."),
64116
In RINEX standards, we use \"RCVR\" when data was sampled from a hardware receiver.
65117
Use \"STREAM\" for other stream data source, like RTCM for example.")
66118
];
119+
}
67120

121+
lazy_static! {
68122
pub static ref SHARED_DATA_ARGS : Vec<Arg> = vec![
69123
Arg::new("PPU")
70124
.long("ppu")

rinex-cli/src/cli/mod.rs

+51-29
Original file line numberDiff line numberDiff line change
@@ -30,16 +30,21 @@ impl Default for Cli {
3030
}
3131
}
3232

33+
pub struct RemoteReferenceSite {
34+
pub data: QcContext,
35+
pub rx_ecef: Option<(f64, f64, f64)>,
36+
}
37+
3338
/// Context defined by User.
3439
pub struct Context {
3540
/// Quiet option
3641
pub quiet: bool,
3742
/// Data context defined by user.
3843
/// In differential opmode, this is the ROVER.
3944
pub data: QcContext,
40-
/// Secondary dataset defined by user
41-
/// serves as BASE in differential opmodes.
42-
pub station_data: Option<QcContext>,
45+
/// Remote reference site (secondary dataset) defined by User.
46+
/// Serves as reference point in differential techniques.
47+
pub reference_site: Option<RemoteReferenceSite>,
4348
/// Context name is derived from the primary file loaded in Self,
4449
/// and mostly used in output products generation.
4550
pub name: String,
@@ -83,13 +88,23 @@ impl Context {
8388
panic!("failed to create {}: {:?}", path.display(), e);
8489
})
8590
}
91+
// Returns True if this context is compatible with RTK positioning
92+
pub fn rtk_compatible(&self) -> bool {
93+
if let Some(remote) = &self.reference_site {
94+
self.data.observation().is_some()
95+
&& self.rx_ecef.is_some()
96+
&& remote.data.observation().is_some()
97+
&& remote.rx_ecef.is_some()
98+
} else {
99+
false
100+
}
101+
}
86102
}
87103

88104
impl Cli {
89105
/// Build new command line interface
90106
pub fn new() -> Self {
91-
Self {
92-
matches: {
107+
let cmd =
93108
Command::new("rinex-cli")
94109
.author("Guillaume W. Bres, <guillaume.bressaix@gmail.com>")
95110
.version(env!("CARGO_PKG_VERSION"))
@@ -167,6 +182,14 @@ but you can extend that with --depth. Refer to -f for more information."))
167182
By default the $RINEX_WORKSPACE variable is prefered if it is defined.
168183
You can also use this flag to customize it.
169184
If none are defined, we will then try to create a local directory named \"WORKSPACE\" like it is possible in this very repo."))
185+
.next_help_heading("Output customization")
186+
.arg(
187+
Arg::new("output-name")
188+
.short('o')
189+
.action(ArgAction::Set)
190+
.help("Customize output file or report name.
191+
In analysis opmode, report is named index.html by default, this will redefine that.
192+
In file operations (filegen, etc..) we can manually define output filenames with this option."))
170193
.next_help_heading("Report customization")
171194
.arg(
172195
Arg::new("report-sum")
@@ -183,12 +206,6 @@ If none are defined, we will then try to create a local directory named \"WORKSP
183206
By default, report synthesis happens once per input set (file combnation and cli options).
184207
Use this option to force report regeneration.
185208
This has no effect on file operations that do not synthesize a report."))
186-
.arg(
187-
Arg::new("report-name")
188-
.short('o')
189-
.action(ArgAction::Set)
190-
.help("Custom report name, otherwise, report is named index.html")
191-
)
192209
.arg(
193210
Arg::new("report-brdc-sky")
194211
.long("brdc-sky")
@@ -268,15 +285,17 @@ Otherwise it gets automatically picked up."))
268285
.value_name("\"lat,lon,alt\" coordinates in ddeg [°]")
269286
.help("Define the (RX) antenna position manualy, in decimal degrees."))
270287
.next_help_heading("Exclusive Opmodes: you can only run one at a time.")
271-
.subcommand(filegen::subcommand())
272-
.subcommand(merge::subcommand())
273-
.subcommand(positioning::ppp_subcommand())
274-
.subcommand(positioning::rtk_subcommand())
275-
.subcommand(split::subcommand())
276-
.subcommand(diff::subcommand())
277-
.subcommand(time_binning::subcommand())
278-
.get_matches()
279-
},
288+
.subcommand(filegen::subcommand());
289+
290+
let cmd = cmd
291+
.subcommand(merge::subcommand())
292+
.subcommand(positioning::ppp_subcommand())
293+
.subcommand(positioning::rtk_subcommand())
294+
.subcommand(split::subcommand())
295+
.subcommand(diff::subcommand())
296+
.subcommand(time_binning::subcommand());
297+
Self {
298+
matches: cmd.get_matches(),
280299
}
281300
}
282301
/// Recursive browser depth
@@ -404,11 +423,14 @@ Otherwise it gets automatically picked up."))
404423
}
405424
/// True if File Operations to generate data is being deployed
406425
pub fn has_fops_output_product(&self) -> bool {
407-
match self.matches.subcommand() {
408-
Some(("filegen", _)) | Some(("merge", _)) | Some(("split", _)) | Some(("tbin", _))
409-
| Some(("diff", _)) => true,
410-
_ => false,
411-
}
426+
matches!(
427+
self.matches.subcommand(),
428+
Some(("filegen", _))
429+
| Some(("merge", _))
430+
| Some(("split", _))
431+
| Some(("tbin", _))
432+
| Some(("diff", _))
433+
)
412434
}
413435
/// True if forced report synthesis is requested
414436
pub fn force_report_synthesis(&self) -> bool {
@@ -428,7 +450,7 @@ Otherwise it gets automatically picked up."))
428450
.chain(self.rover_files().into_iter().sorted())
429451
.chain(self.preprocessing().into_iter().sorted())
430452
.join(",");
431-
if let Some(custom) = self.custom_report_name() {
453+
if let Some(custom) = self.custom_output_name() {
432454
string.push_str(custom);
433455
}
434456
if let Some(geo) = self.manual_geodetic() {
@@ -456,8 +478,8 @@ Otherwise it gets automatically picked up."))
456478
force_brdc_skyplot: self.matches.get_flag("report-brdc-sky"),
457479
}
458480
}
459-
/// Report to be generated for this session
460-
pub fn custom_report_name(&self) -> Option<&String> {
461-
self.matches.get_one::<String>("report-name")
481+
/// Customized / manually defined output to be generated
482+
pub fn custom_output_name(&self) -> Option<&String> {
483+
self.matches.get_one::<String>("output-name")
462484
}
463485
}

0 commit comments

Comments
 (0)