diff --git a/.gitignore b/.gitignore index 25821343c8..56d8e18ef5 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ .DS_Store *.*~ limbo/ +.idea/ # Byte-compiled / optimized / DLL files __pycache__/ @@ -71,4 +72,7 @@ sbp_out.* .stack-work/ .build/ +# rust +Cargo.lock + python/sbp/_version.py diff --git a/.travis.yml b/.travis.yml index 8f1fe6e03f..008126ec4e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -75,6 +75,12 @@ matrix: - make test-c after_success: bash <(curl -s https://codecov.io/bash) -s c/build || echo "Codecov did not collect coverage reports"; + - env: + language: rust + rust: + - stable + script: + - make test-rust deploy: provider: releases diff --git a/Makefile b/Makefile index c27c0fa654..bf2e612d2a 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ SBP_PATCH_VERSION := $(word 3, $(subst ., , $(SBP_VERSION))) CHANGELOG_MAX_ISSUES := 100 -.PHONY: help test release dist clean all docs pdf html c deps-c gen-c test-c python deps-python gen-python test-python javascript deps-javascript gen-javascript test-javascript java deps-java gen-java test-java haskell deps-haskell gen-haskell test-haskell haskell deps-protobuf gen-protobuf test-protobuf verify-prereq-generator verify-prereq-c verify-prereq-javascript verify-prereq-python verify-prereq-java verify-prereq-haskell verify-prereq-protobuf mapping +.PHONY: help test release dist clean all docs pdf html c deps-c gen-c test-c python deps-python gen-python test-python javascript deps-javascript gen-javascript test-javascript java deps-java gen-java test-java haskell deps-haskell gen-haskell test-haskell haskell deps-protobuf gen-protobuf test-protobuf verify-prereq-generator verify-prereq-c verify-prereq-javascript verify-prereq-python verify-prereq-java verify-prereq-haskell verify-prereq-protobuf mapping rust deps-rust gen-rust test-rust # Functions define announce-begin @@ -53,12 +53,13 @@ help: @echo " pythonNG to make Python (JIT) bindings" @echo " haskell to make Haskell bindings" @echo " java to make Java bindings" + @echo " rust to make Rust bindings" @echo " protobuf to make Protocol Buffer bindings" @echo " release to handle some release tasks" @echo " test to run all tests" @echo -all: c python pythonNG javascript java docs haskell protobuf +all: c python pythonNG javascript java docs haskell protobuf rust clean: @echo "Removing the ./c/build directory..." rm -r $(SWIFTNAV_ROOT)/c/build @@ -70,6 +71,7 @@ pythonNG: deps-python gen-pythonNG javascript: deps-javascript gen-javascript test-javascript java: deps-java gen-java test-java haskell: deps-haskell gen-haskell test-haskell +rust: deps-rust gen-rust test-rust protobuf: deps-protobuf gen-protobuf test-protobuf # Prerequisite verification @@ -100,7 +102,9 @@ verify-prereq-java: verify-prereq-generator verify-prereq-haskell: verify-prereq-generator -verify-prereq-protobuf: verify-prereq-generator +verify-prereq-rust: ; + +verify-prereq-protobuf: verify-prereq-protobuf verify-prereq-docs: verify-prereq-generator @command -v pdflatex 1>/dev/null 2>/dev/null || { echo >&2 -e "I require \`pdflatex\` but it's not installed. Aborting.\n\nHave you installed pdflatex? See the generator readme (Installing instructions) at \`generator/README.md\` for setup instructions.\n"; exit 1; } @@ -122,6 +126,8 @@ deps-java: verify-prereq-java deps-haskell: verify-prereq-haskell +deps-rust: verify-prereq-rust + deps-protobuf: verify-prereq-protobuf # Generators @@ -192,6 +198,16 @@ gen-haskell: --haskell $(call announce-begin,"Finished generating Haskell bindings") +gen-rust: + $(call announce-begin,"Generating Rust bindings") + cd $(SWIFTNAV_ROOT)/generator; \ + $(SBP_GEN_BIN) -i $(SBP_SPEC_DIR) \ + -o $(SWIFTNAV_ROOT)/rust/ \ + -r $(SBP_MAJOR_VERSION).$(SBP_MINOR_VERSION).$(SBP_PATCH_VERSION) \ + --rust + cd $(SWIFTNAV_ROOT)/rust/sbp && cargo fmt + $(call announce-begin,"Finished generating Rust bindings") + gen-protobuf: $(call announce-begin,"Generating Protocol Buffers bindings") cd $(SWIFTNAV_ROOT)/generator; \ @@ -201,10 +217,9 @@ gen-protobuf: --protobuf $(call announce-begin,"Finished generating Protocol Buffers bindings") - # Testers -test: test-all-begin test-c test-java test-python test-haskell test-javascript test-all-end +test: test-all-begin test-c test-java test-python test-haskell test-javascript test-rust test-all-end test-all-begin: $(call announce-begin,"Running all tests") @@ -245,6 +260,11 @@ test-haskell: cd $(SWIFTNAV_ROOT)/haskell/ && stack build --test --allow-different-user $(call announce-end,"Finished running Haskell tests") +test-rust: + $(call announce-begin,"Running Rust tests") + cd $(SWIFTNAV_ROOT)/rust/sbp && cargo test --verbose + $(call announce-end,"Finished running Rust tests") + test-protobuf: $(call announce-begin,"Running Protocol Buffer tests") $(call announce-end,"Finished running Protocol Buffer tests") diff --git a/generator/sbpg/generator.py b/generator/sbpg/generator.py index 49cf7ac13b..e5da3aa883 100755 --- a/generator/sbpg/generator.py +++ b/generator/sbpg/generator.py @@ -27,6 +27,7 @@ import sbpg.targets.python as py import sbpg.targets.pythonNG as pyNG import sbpg.targets.javascript as js +import sbpg.targets.rust as rs def get_args(): parser = argparse.ArgumentParser(description='Swift Navigation SBP generator.') @@ -61,6 +62,9 @@ def get_args(): parser.add_argument('--java', action="store_true", help='Target language: Java!') + parser.add_argument('--rust', + action="store_true", + help='Target language: Rust.') parser.add_argument('--latex', action="store_true", help='Target language: LaTeX.') @@ -84,7 +88,7 @@ def main(): # Parse and validate arguments. args = get_args().parse_args() verbose = args.verbose - assert args.pythonNG or args.python or args.javascript or args.c or args.test_c or args.haskell or args.latex or args.protobuf or args.java, \ + assert args.pythonNG or args.python or args.javascript or args.c or args.test_c or args.haskell or args.latex or args.protobuf or args.java or args.rust, \ "Please specify a target language." input_file = os.path.abspath(args.input_file[0]) assert len(args.input_file) == 1 @@ -138,6 +142,8 @@ def main(): hs.render_source(output_dir, parsed) elif args.java: java.render_source(output_dir, parsed) + elif args.rust: + rs.render_source(output_dir, parsed) elif args.protobuf: pb.render_source(output_dir, parsed) if args.c: @@ -151,6 +157,9 @@ def main(): elif args.java: parsed = [yaml.parse_spec(spec) for _, spec in file_index_items] java.render_table(output_dir, parsed) + elif args.rust: + parsed = [yaml.parse_spec(spec) for spec in file_index.values()] + rs.render_mod(output_dir, parsed) elif args.test_c: test_c.render_check_suites(output_dir, all_specs) test_c.render_check_main(output_dir, all_specs) diff --git a/generator/sbpg/targets/resources/sbp_messages_mod.rs b/generator/sbpg/targets/resources/sbp_messages_mod.rs new file mode 100644 index 0000000000..b0da99a4c9 --- /dev/null +++ b/generator/sbpg/targets/resources/sbp_messages_mod.rs @@ -0,0 +1,55 @@ +// Copyright (C) 2015-2018 Swift Navigation Inc. +// Contact: Swift Navigation +// +// This source is subject to the license found in the file 'LICENSE' which must +// be be distributed together with this source. All other rights reserved. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. + +((*- for m in mods *)) +pub mod (((m))); +((*- endfor *)) + +((*- for p in packages *)) +((*- for m in p.definitions *)) +((*- if m.sbp_id *)) +use self::(((p.identifier|mod_name)))::(((m.identifier|camel_case))); +((*- endif *)) +((*- endfor *)) +((*- endfor *)) + +trait SBPMessage { + const MSG_ID: u16; + + fn get_sender_id(&self) -> Option; + fn set_sender_id(&mut self, new_id: u16); +} + +#[derive(Debug)] +pub enum SBP { + Unknown { msg_id: u16, sender_id: u16, payload: Vec }, + ((*- for m in msgs *)) + (((m.identifier|camel_case)))( (((m.identifier|camel_case))) ), + ((*- endfor *)) +} + +impl SBP { + pub fn parse(msg_id: u16, sender_id: u16, payload: &mut &[u8]) -> Result { + let x: Result = match msg_id { + ((*- for m in msgs *)) + (((m.sbp_id))) => { + let mut msg = (((m.identifier|camel_case)))::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::(((m.identifier|camel_case)))(msg)) + }, + ((*- endfor *)) + _ => Ok(SBP::Unknown { msg_id: msg_id, sender_id: sender_id, payload: payload.to_vec() }) + }; + match x { + Ok(x) => Ok(x), + Err(_) => Err(::Error::ParseError), + } + } +} diff --git a/generator/sbpg/targets/resources/sbp_messages_template.rs b/generator/sbpg/targets/resources/sbp_messages_template.rs new file mode 100644 index 0000000000..ec85a42473 --- /dev/null +++ b/generator/sbpg/targets/resources/sbp_messages_template.rs @@ -0,0 +1,92 @@ +// Copyright (C) 2015-2018 Swift Navigation Inc. +// Contact: Swift Navigation +// +// This source is subject to the license found in the file 'LICENSE' which must +// be be distributed together with this source. All other rights reserved. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. + +//**************************************************************************** +// Automatically generated from yaml/(((filepath))) +// with generate.py. Please do not hand edit! +//****************************************************************************/ + +//! (((description | replace("\n", "\n//! ")))) + +extern crate byteorder; +#[allow(unused_imports)] +use self::byteorder::{LittleEndian,ReadBytesExt}; + +((*- for i in includes *)) +use super::(((i)))::*; +((*- endfor *)) + +((* for m in msgs *)) +((*- if m.desc *)) +/// (((m.short_desc))) +/// +(((m.desc|commentify))) +/// +((*- endif *)) +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct (((m.identifier|camel_case))) { + ((*- if m.sbp_id *)) + pub sender_id: Option, + ((*- endif *)) + ((*- for f in m.fields *)) + ((*- if f.desc *)) + /// (((f.desc | replace("\n", " ") | wordwrap(width=72, wrapstring="\n /// ")))) + ((*- endif *)) + pub (((f.identifier))): (((f|type_map))), + ((*- endfor *)) +} + +impl (((m.identifier|camel_case))) { + pub fn parse(_buf: &mut &[u8]) -> Result<(((m.identifier|camel_case))), ::Error> { + Ok( (((m.identifier|camel_case))){ + ((*- if m.sbp_id *)) + sender_id: None, + ((*- endif *)) + ((*- for f in m.fields *)) + (((f.identifier))): (((f|parse_type)))?, + ((*- endfor *)) + } ) + } + + ((*- if not m.sbp_id *)) + pub fn parse_array(buf: &mut &[u8]) -> Result, ::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push( (((m.identifier|camel_case)))::parse(buf)? ); + } + Ok(v) + } + + pub fn parse_array_limit(buf: &mut &[u8], n: usize) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push( (((m.identifier|camel_case)))::parse(buf)? ); + } + Ok(v) + } + ((*- endif *)) +} + +((*- if m.sbp_id *)) +impl super::SBPMessage for (((m.identifier|camel_case))) { + const MSG_ID: u16 = (((m.sbp_id))); + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} +((*- endif *)) + +((* endfor *)) diff --git a/generator/sbpg/targets/rust.py b/generator/sbpg/targets/rust.py new file mode 100644 index 0000000000..11acb1877b --- /dev/null +++ b/generator/sbpg/targets/rust.py @@ -0,0 +1,141 @@ +#!/usr/bin/env python +# Copyright (C) 2018 Swift Navigation Inc. +# Contact: Gareth McMullin +# +# This source is subject to the license found in the file 'LICENSE' which must +# be be distributed together with this source. All other rights reserved. +# +# THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +# EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. + +""" +Generator for rust target. +""" + +from sbpg.targets.templating import * +from sbpg.utils import markdown_links + +MESSAGES_TEMPLATE_NAME = "sbp_messages_template.rs" +MESSAGES_MOD_TEMPLATE_NAME = "sbp_messages_mod.rs" + +import re +def camel_case(s): + """ + Makes a classname. + """ + if '_' not in s: return s + s = re.sub('([a-z])([A-Z])', r'\1_\2', s) + return ''.join(w if w in ACRONYMS else w.title() for w in s.split('_')) + +def commentify(value): + """ + Builds a comment. + """ + value = markdown_links(value) + if value is None: + return + if len(value.split('\n')) == 1: + return "/// " + value + else: + return '\n'.join(['/// ' + l for l in value.split('\n')[:-1]]) + +TYPE_MAP = {'u8': 'u8', + 'u16': 'u16', + 'u32': 'u32', + 'u64': 'u64', + 's8': 'i8', + 's16': 'i16', + 's32': 'i32', + 's64': 'i64', + 'float': 'f32', + 'double': 'f64', + 'string': 'String'} + +def type_map(field): + if TYPE_MAP.has_key(field.type_id): + return TYPE_MAP[field.type_id] + elif field.type_id == 'array': + t = field.options['fill'].value + return "Vec<{}>".format(TYPE_MAP.get(t, t)) + else: + return field.type_id + +def mod_name(x): + return x.split('.', 2)[2] + +def parse_type(field): + """ + Function to pull a type from the binary payload. + """ + if field.type_id == 'string': + if field.options.has_key('size'): + return "::parser::read_string_limit(_buf, %s)" % field.options['size'].value + else: + return "::parser::read_string(_buf)" + elif field.type_id == 'u8': + return '_buf.read_u8()' + elif field.type_id == 's8': + return '_buf.read_i8()' + elif field.type_id in TYPE_MAP.keys(): + # Primitive java types have extractor methods in SBPMessage.Parser + return '_buf.read_%s::()' % TYPE_MAP[field.type_id] + if field.type_id == 'array': + # Call function to build array + t = field.options['fill'].value + if t in TYPE_MAP.keys(): + if field.options.has_key('size'): + return '::parser::read_%s_array_limit(_buf, %d)' % (t, field.options['size'].value) + else: + return '::parser::read_%s_array(_buf)' % t + else: + if field.options.has_key('size'): + return '%s::parse_array_limit(_buf, %d)' % (t, field.options['size'].value) + else: + return '%s::parse_array(_buf)' % t + else: + # This is an inner class, call default constructor + return "%s::parse(_buf)" % field.type_id + +JENV.filters['camel_case'] = camel_case +JENV.filters['commentify'] = commentify +JENV.filters['type_map'] = type_map +JENV.filters['mod_name'] = mod_name +JENV.filters['parse_type'] = parse_type + +def render_source(output_dir, package_spec): + """ + Render and output to a directory given a package specification. + """ + path, name = package_spec.filepath + destination_filename = "%s/sbp/src/messages/%s.rs" % (output_dir, name) + py_template = JENV.get_template(MESSAGES_TEMPLATE_NAME) + includes = [x.rsplit('.', 1)[0] for x in package_spec.includes] + if 'types' in includes: + del includes[includes.index('types')] + with open(destination_filename, 'w') as f: + f.write(py_template.render(msgs=package_spec.definitions, + pkg_name=name, + filepath="/".join(package_spec.filepath) + ".yaml", + description=package_spec.description, + timestamp=package_spec.creation_timestamp, + includes=includes)) + +def render_mod(output_dir, package_specs): + msgs = [] + mods = [] + for package_spec in package_specs: + if not package_spec.render_source: + continue + name = package_spec.identifier.split('.', 2)[2] + if name != 'types': + mods.append(name) + for m in package_spec.definitions: + if m.static and m.sbp_id: + msgs.append(m) + destination_filename = "%s/sbp/src/messages/mod.rs" % output_dir + py_template = JENV.get_template(MESSAGES_MOD_TEMPLATE_NAME) + with open(destination_filename, 'w') as f: + f.write(py_template.render(packages=package_specs, + mods=mods, + msgs=sorted(msgs))) diff --git a/rust/example/Cargo.toml b/rust/example/Cargo.toml new file mode 100644 index 0000000000..f67a97b85e --- /dev/null +++ b/rust/example/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "example" +version = "0.1.0" +authors = ["Gareth McMullin "] + +[dependencies] +serialport = "2.1.0" + +[dependencies.sbp] +path = "../sbp" diff --git a/rust/example/src/main.rs b/rust/example/src/main.rs new file mode 100644 index 0000000000..1c5489e5b5 --- /dev/null +++ b/rust/example/src/main.rs @@ -0,0 +1,41 @@ +extern crate serialport; +extern crate sbp; + +use serialport::prelude::*; +use std::time::Duration; +use sbp::messages::SBP; +use sbp::Error; + +fn main() { + let s = SerialPortSettings { + baud_rate: BaudRate::Baud115200, + data_bits: DataBits::Eight, + flow_control: FlowControl::None, + parity: Parity::None, + stop_bits: StopBits::One, + timeout: Duration::from_millis(1000), + }; + + let mut port = serialport::open_with_settings("/dev/ttyUSB0", &s) + .expect("open failed"); + + loop { + match sbp::client::parser::parse(&mut port) { + Ok(SBP::MsgLog(x)) => + println!("{}", x.text), + Ok(SBP::MsgPosLLH(x)) => + println!("{} {} {}", x.lat, x.lon, x.height), + Ok(_) => (), + + Err(Error::InvalidPreamble) => (), + Err(Error::CRCMismatch) => (), + Err(Error::ParseError) => (), + Err(Error::IoError(ref x)) if x.kind() == std::io::ErrorKind::TimedOut => (), + + Err(e) => { + println!("{:?}", e); + break; + } + } + } +} diff --git a/rust/sbp/Cargo.toml b/rust/sbp/Cargo.toml new file mode 100644 index 0000000000..53484564a6 --- /dev/null +++ b/rust/sbp/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "sbp" +version = "0.1.0" +description = "Rust native implementation of SBP (Swift Binary Protocol) for communicating with devices made by Swift Navigation" +authors = ["Swift Navigation "] +repository = "https://github.com/swift-nav/libsbp" +license = "LGPL-3.0" +categories = ["parsing"] + +[dependencies] +byteorder = "1.2.1" +crc16 = "*" +nom = "5.0.0" + +[badges] +travis-ci = { repository = "swift-nav/libsbp" } diff --git a/rust/sbp/src/lib.rs b/rust/sbp/src/lib.rs new file mode 100644 index 0000000000..bf4ffcd29b --- /dev/null +++ b/rust/sbp/src/lib.rs @@ -0,0 +1,113 @@ +pub mod messages; +pub mod parser; + +#[derive(Debug)] +pub enum Error { + ParseError, + NotEnoughData, + UnrecoverableFailure, + IoError(std::io::Error), +} + +#[cfg(test)] +mod tests { + #[test] + fn baseline_ecef() { + let baseline_ecef_payload = [ + 0x28u8, 0xf4, 0x7a, 0x13, 0x96, 0x62, 0xee, 0xff, 0xbe, 0x40, 0x14, 0x00, 0xf6, 0xa3, + 0x09, 0x00, 0x00, 0x00, 0x0e, 0x00, + ]; + let baseline_ecef_expectation = ::messages::navigation::MsgBaselineECEF { + sender_id: Some(1234), + accuracy: 0, + flags: 0, + n_sats: 14, + tow: 326825000, + x: -1154410, + y: 1327294, + z: 631798, + }; + let sbp_result = ::messages::SBP::parse(0x20b, 1234, &mut &baseline_ecef_payload[..]); + assert!(sbp_result.is_ok()); + if let ::messages::SBP::MsgBaselineECEF(msg) = sbp_result.unwrap() { + assert_eq!(msg.sender_id, baseline_ecef_expectation.sender_id); + assert_eq!(msg.accuracy, baseline_ecef_expectation.accuracy); + assert_eq!(msg.flags, baseline_ecef_expectation.flags); + assert_eq!(msg.n_sats, baseline_ecef_expectation.n_sats); + assert_eq!(msg.tow, baseline_ecef_expectation.tow); + assert_eq!(msg.x, baseline_ecef_expectation.x); + assert_eq!(msg.y, baseline_ecef_expectation.y); + assert_eq!(msg.z, baseline_ecef_expectation.z); + } else { + assert!(false); + } + } + + #[test] + fn frame() { + let packet = [ + 0x55u8, 0x0b, 0x02, 0xd3, 0x88, 0x14, 0x28, 0xf4, 0x7a, 0x13, 0x96, 0x62, 0xee, 0xff, + 0xbe, 0x40, 0x14, 0x00, 0xf6, 0xa3, 0x09, 0x00, 0x00, 0x00, 0x0e, 0x00, 0xdb, 0xbf, + ]; + let baseline_ecef_expectation = ::messages::navigation::MsgBaselineECEF { + sender_id: Some(0x88d3), + accuracy: 0, + flags: 0, + n_sats: 14, + tow: 326825000, + x: -1154410, + y: 1327294, + z: 631798, + }; + let (sbp_result, _remaining_data) = ::parser::frame(&packet[..]); + assert!(sbp_result.is_ok()); + if let ::messages::SBP::MsgBaselineECEF(msg) = sbp_result.unwrap() { + assert_eq!(msg.sender_id, baseline_ecef_expectation.sender_id); + assert_eq!(msg.accuracy, baseline_ecef_expectation.accuracy); + assert_eq!(msg.flags, baseline_ecef_expectation.flags); + assert_eq!(msg.n_sats, baseline_ecef_expectation.n_sats); + assert_eq!(msg.tow, baseline_ecef_expectation.tow); + assert_eq!(msg.x, baseline_ecef_expectation.x); + assert_eq!(msg.y, baseline_ecef_expectation.y); + assert_eq!(msg.z, baseline_ecef_expectation.z); + } else { + assert!(false); + } + } + + #[test] + fn parser() { + let packet = vec![ + 0x00, 0x11, 0x22, 0x55u8, 0x0b, 0x02, 0xd3, 0x88, 0x14, 0x28, 0xf4, 0x7a, 0x13, 0x96, + 0x62, 0xee, 0xff, 0xbe, 0x40, 0x14, 0x00, 0xf6, 0xa3, 0x09, 0x00, 0x00, 0x00, 0x0e, + 0x00, 0xdb, 0xbf, 0xde, 0xad, 0xbe, 0xef, + ]; + let mut reader = std::io::Cursor::new(packet); + let baseline_ecef_expectation = ::messages::navigation::MsgBaselineECEF { + sender_id: Some(0x88d3), + accuracy: 0, + flags: 0, + n_sats: 14, + tow: 326825000, + x: -1154410, + y: 1327294, + z: 631798, + }; + let mut parser = ::parser::Parser::new(); + // Iterate through the data until we hit something that is parsable + let sbp_result = parser.parse(&mut reader); + assert!(sbp_result.is_ok()); + if let ::messages::SBP::MsgBaselineECEF(msg) = sbp_result.unwrap() { + assert_eq!(msg.sender_id, baseline_ecef_expectation.sender_id); + assert_eq!(msg.accuracy, baseline_ecef_expectation.accuracy); + assert_eq!(msg.flags, baseline_ecef_expectation.flags); + assert_eq!(msg.n_sats, baseline_ecef_expectation.n_sats); + assert_eq!(msg.tow, baseline_ecef_expectation.tow); + assert_eq!(msg.x, baseline_ecef_expectation.x); + assert_eq!(msg.y, baseline_ecef_expectation.y); + assert_eq!(msg.z, baseline_ecef_expectation.z); + } else { + assert!(false); + } + } +} diff --git a/rust/sbp/src/messages/acquisition.rs b/rust/sbp/src/messages/acquisition.rs new file mode 100644 index 0000000000..e16bff45e5 --- /dev/null +++ b/rust/sbp/src/messages/acquisition.rs @@ -0,0 +1,392 @@ +// Copyright (C) 2015-2018 Swift Navigation Inc. +// Contact: Swift Navigation +// +// This source is subject to the license found in the file 'LICENSE' which must +// be be distributed together with this source. All other rights reserved. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. + +//**************************************************************************** +// Automatically generated from yaml/swiftnav/sbp/acquisition.yaml +// with generate.py. Please do not hand edit! +//****************************************************************************/ +//! Satellite acquisition messages from the device. + +extern crate byteorder; +#[allow(unused_imports)] +use self::byteorder::{LittleEndian, ReadBytesExt}; +use super::gnss::*; + +/// Satellite acquisition result +/// +/// This message describes the results from an attempted GPS signal +/// acquisition search for a satellite PRN over a code phase/carrier +/// frequency range. It contains the parameters of the point in the +/// acquisition search space with the best carrier-to-noise (CN/0) +/// ratio. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgAcqResult { + pub sender_id: Option, + /// CN/0 of best point + pub cn0: f32, + /// Code phase of best point + pub cp: f32, + /// Carrier frequency of best point + pub cf: f32, + /// GNSS signal for which acquisition was attempted + pub sid: GnssSignal, +} + +impl MsgAcqResult { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgAcqResult { + sender_id: None, + cn0: _buf.read_f32::()?, + cp: _buf.read_f32::()?, + cf: _buf.read_f32::()?, + sid: GnssSignal::parse(_buf)?, + }) + } +} +impl super::SBPMessage for MsgAcqResult { + const MSG_ID: u16 = 47; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Deprecated +/// +/// Deprecated. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgAcqResultDepC { + pub sender_id: Option, + /// CN/0 of best point + pub cn0: f32, + /// Code phase of best point + pub cp: f32, + /// Carrier frequency of best point + pub cf: f32, + /// GNSS signal for which acquisition was attempted + pub sid: GnssSignalDep, +} + +impl MsgAcqResultDepC { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgAcqResultDepC { + sender_id: None, + cn0: _buf.read_f32::()?, + cp: _buf.read_f32::()?, + cf: _buf.read_f32::()?, + sid: GnssSignalDep::parse(_buf)?, + }) + } +} +impl super::SBPMessage for MsgAcqResultDepC { + const MSG_ID: u16 = 31; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Deprecated +/// +/// Deprecated. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgAcqResultDepB { + pub sender_id: Option, + /// SNR of best point. Currently in arbitrary SNR points, but will be in + /// units of dB Hz in a later revision of this message. + pub snr: f32, + /// Code phase of best point + pub cp: f32, + /// Carrier frequency of best point + pub cf: f32, + /// GNSS signal for which acquisition was attempted + pub sid: GnssSignalDep, +} + +impl MsgAcqResultDepB { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgAcqResultDepB { + sender_id: None, + snr: _buf.read_f32::()?, + cp: _buf.read_f32::()?, + cf: _buf.read_f32::()?, + sid: GnssSignalDep::parse(_buf)?, + }) + } +} +impl super::SBPMessage for MsgAcqResultDepB { + const MSG_ID: u16 = 20; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Deprecated +/// +/// Deprecated. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgAcqResultDepA { + pub sender_id: Option, + /// SNR of best point. Currently dimensonless, but will have units of dB Hz + /// in the revision of this message. + pub snr: f32, + /// Code phase of best point + pub cp: f32, + /// Carrier frequency of best point + pub cf: f32, + /// PRN-1 identifier of the satellite signal for which acquisition was + /// attempted + pub prn: u8, +} + +impl MsgAcqResultDepA { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgAcqResultDepA { + sender_id: None, + snr: _buf.read_f32::()?, + cp: _buf.read_f32::()?, + cf: _buf.read_f32::()?, + prn: _buf.read_u8()?, + }) + } +} +impl super::SBPMessage for MsgAcqResultDepA { + const MSG_ID: u16 = 21; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Acq perfomance measurement and debug +/// +/// Profile for a specific SV for debugging purposes +/// The message describes SV profile during acquisition time. +/// The message is used to debug and measure the performance. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct AcqSvProfile { + /// SV search job type (deep, fallback, etc) + pub job_type: u8, + /// Acquisition status 1 is Success, 0 is Failure + pub status: u8, + /// CN0 value. Only valid if status is '1' + pub cn0: u16, + /// Acquisition integration time + pub int_time: u8, + /// GNSS signal for which acquisition was attempted + pub sid: GnssSignal, + /// Acq frequency bin width + pub bin_width: u16, + /// Timestamp of the job complete event + pub timestamp: u32, + /// Time spent to search for sid.code + pub time_spent: u32, + /// Doppler range lowest frequency + pub cf_min: i32, + /// Doppler range highest frequency + pub cf_max: i32, + /// Doppler value of detected peak. Only valid if status is '1' + pub cf: i32, + /// Codephase of detected peak. Only valid if status is '1' + pub cp: u32, +} + +impl AcqSvProfile { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(AcqSvProfile { + job_type: _buf.read_u8()?, + status: _buf.read_u8()?, + cn0: _buf.read_u16::()?, + int_time: _buf.read_u8()?, + sid: GnssSignal::parse(_buf)?, + bin_width: _buf.read_u16::()?, + timestamp: _buf.read_u32::()?, + time_spent: _buf.read_u32::()?, + cf_min: _buf.read_i32::()?, + cf_max: _buf.read_i32::()?, + cf: _buf.read_i32::()?, + cp: _buf.read_u32::()?, + }) + } + pub fn parse_array(buf: &mut &[u8]) -> Result, ::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(AcqSvProfile::parse(buf)?); + } + Ok(v) + } + + pub fn parse_array_limit(buf: &mut &[u8], n: usize) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(AcqSvProfile::parse(buf)?); + } + Ok(v) + } +} + +/// Deprecated +/// +/// Deprecated. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct AcqSvProfileDep { + /// SV search job type (deep, fallback, etc) + pub job_type: u8, + /// Acquisition status 1 is Success, 0 is Failure + pub status: u8, + /// CN0 value. Only valid if status is '1' + pub cn0: u16, + /// Acquisition integration time + pub int_time: u8, + /// GNSS signal for which acquisition was attempted + pub sid: GnssSignalDep, + /// Acq frequency bin width + pub bin_width: u16, + /// Timestamp of the job complete event + pub timestamp: u32, + /// Time spent to search for sid.code + pub time_spent: u32, + /// Doppler range lowest frequency + pub cf_min: i32, + /// Doppler range highest frequency + pub cf_max: i32, + /// Doppler value of detected peak. Only valid if status is '1' + pub cf: i32, + /// Codephase of detected peak. Only valid if status is '1' + pub cp: u32, +} + +impl AcqSvProfileDep { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(AcqSvProfileDep { + job_type: _buf.read_u8()?, + status: _buf.read_u8()?, + cn0: _buf.read_u16::()?, + int_time: _buf.read_u8()?, + sid: GnssSignalDep::parse(_buf)?, + bin_width: _buf.read_u16::()?, + timestamp: _buf.read_u32::()?, + time_spent: _buf.read_u32::()?, + cf_min: _buf.read_i32::()?, + cf_max: _buf.read_i32::()?, + cf: _buf.read_i32::()?, + cp: _buf.read_u32::()?, + }) + } + pub fn parse_array(buf: &mut &[u8]) -> Result, ::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(AcqSvProfileDep::parse(buf)?); + } + Ok(v) + } + + pub fn parse_array_limit(buf: &mut &[u8], n: usize) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(AcqSvProfileDep::parse(buf)?); + } + Ok(v) + } +} + +/// Acquisition perfomance measurement and debug +/// +/// The message describes all SV profiles during acquisition time. +/// The message is used to debug and measure the performance. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgAcqSvProfile { + pub sender_id: Option, + /// SV profiles during acquisition time + pub acq_sv_profile: Vec, +} + +impl MsgAcqSvProfile { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgAcqSvProfile { + sender_id: None, + acq_sv_profile: AcqSvProfile::parse_array(_buf)?, + }) + } +} +impl super::SBPMessage for MsgAcqSvProfile { + const MSG_ID: u16 = 46; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Deprecated. +/// +/// Deprecated. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgAcqSvProfileDep { + pub sender_id: Option, + /// SV profiles during acquisition time + pub acq_sv_profile: Vec, +} + +impl MsgAcqSvProfileDep { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgAcqSvProfileDep { + sender_id: None, + acq_sv_profile: AcqSvProfileDep::parse_array(_buf)?, + }) + } +} +impl super::SBPMessage for MsgAcqSvProfileDep { + const MSG_ID: u16 = 30; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} diff --git a/rust/sbp/src/messages/bootload.rs b/rust/sbp/src/messages/bootload.rs new file mode 100644 index 0000000000..290080c43b --- /dev/null +++ b/rust/sbp/src/messages/bootload.rs @@ -0,0 +1,225 @@ +// Copyright (C) 2015-2018 Swift Navigation Inc. +// Contact: Swift Navigation +// +// This source is subject to the license found in the file 'LICENSE' which must +// be be distributed together with this source. All other rights reserved. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. + +//**************************************************************************** +// Automatically generated from yaml/swiftnav/sbp/bootload.yaml +// with generate.py. Please do not hand edit! +//****************************************************************************/ +//! Messages for the bootloading configuration of a Piksi 2.3.1. This message +//! group does not apply to Piksi Multi. +//! +//! Note that some of these messages share the same message type ID for both the +//! host request and the device response. +//! + +extern crate byteorder; +#[allow(unused_imports)] +use self::byteorder::{LittleEndian, ReadBytesExt}; + +/// Bootloading handshake request (host => device) +/// +/// The handshake message request from the host establishes a +/// handshake between the device bootloader and the host. The +/// response from the device is MSG_BOOTLOADER_HANDSHAKE_RESP. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgBootloaderHandshakeReq { + pub sender_id: Option, +} + +impl MsgBootloaderHandshakeReq { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgBootloaderHandshakeReq { sender_id: None }) + } +} +impl super::SBPMessage for MsgBootloaderHandshakeReq { + const MSG_ID: u16 = 179; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Bootloading handshake response (host <= device) +/// +/// The handshake message response from the device establishes a +/// handshake between the device bootloader and the host. The +/// request from the host is MSG_BOOTLOADER_HANDSHAKE_REQ. The +/// payload contains the bootloader version number and the SBP +/// protocol version number. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgBootloaderHandshakeResp { + pub sender_id: Option, + /// Bootloader flags + pub flags: u32, + /// Bootloader version number + pub version: String, +} + +impl MsgBootloaderHandshakeResp { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgBootloaderHandshakeResp { + sender_id: None, + flags: _buf.read_u32::()?, + version: ::parser::read_string(_buf)?, + }) + } +} +impl super::SBPMessage for MsgBootloaderHandshakeResp { + const MSG_ID: u16 = 180; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Bootloader jump to application (host => device) +/// +/// The host initiates the bootloader to jump to the application. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgBootloaderJumpToApp { + pub sender_id: Option, + /// Ignored by the device + pub jump: u8, +} + +impl MsgBootloaderJumpToApp { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgBootloaderJumpToApp { + sender_id: None, + jump: _buf.read_u8()?, + }) + } +} +impl super::SBPMessage for MsgBootloaderJumpToApp { + const MSG_ID: u16 = 177; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Read FPGA device ID over UART request (host => device) +/// +/// The device message from the host reads a unique device +/// identifier from the SwiftNAP, an FPGA. The host requests the ID +/// by sending a MSG_NAP_DEVICE_DNA_REQ message. The device +/// responds with a MSG_NAP_DEVICE_DNA_RESP message with the +/// device ID in the payload. Note that this ID is tied to the FPGA, +/// and not related to the Piksi's serial number. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgNapDeviceDnaReq { + pub sender_id: Option, +} + +impl MsgNapDeviceDnaReq { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgNapDeviceDnaReq { sender_id: None }) + } +} +impl super::SBPMessage for MsgNapDeviceDnaReq { + const MSG_ID: u16 = 222; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Read FPGA device ID over UART response (host <= device) +/// +/// The device message from the host reads a unique device +/// identifier from the SwiftNAP, an FPGA. The host requests the ID +/// by sending a MSG_NAP_DEVICE_DNA_REQ message. The device +/// responds with a MSG_NAP_DEVICE_DNA_RESP messagage with the +/// device ID in the payload. Note that this ID is tied to the FPGA, +/// and not related to the Piksi's serial number. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgNapDeviceDnaResp { + pub sender_id: Option, + /// 57-bit SwiftNAP FPGA Device ID. Remaining bits are padded on the right. + pub dna: Vec, +} + +impl MsgNapDeviceDnaResp { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgNapDeviceDnaResp { + sender_id: None, + dna: ::parser::read_u8_array_limit(_buf, 8)?, + }) + } +} +impl super::SBPMessage for MsgNapDeviceDnaResp { + const MSG_ID: u16 = 221; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Deprecated +/// +/// Deprecated. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgBootloaderHandshakeDepA { + pub sender_id: Option, + /// Version number string (not NULL terminated) + pub handshake: Vec, +} + +impl MsgBootloaderHandshakeDepA { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgBootloaderHandshakeDepA { + sender_id: None, + handshake: ::parser::read_u8_array(_buf)?, + }) + } +} +impl super::SBPMessage for MsgBootloaderHandshakeDepA { + const MSG_ID: u16 = 176; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} diff --git a/rust/sbp/src/messages/ext_events.rs b/rust/sbp/src/messages/ext_events.rs new file mode 100644 index 0000000000..0005a4df6a --- /dev/null +++ b/rust/sbp/src/messages/ext_events.rs @@ -0,0 +1,67 @@ +// Copyright (C) 2015-2018 Swift Navigation Inc. +// Contact: Swift Navigation +// +// This source is subject to the license found in the file 'LICENSE' which must +// be be distributed together with this source. All other rights reserved. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. + +//**************************************************************************** +// Automatically generated from yaml/swiftnav/sbp/ext_events.yaml +// with generate.py. Please do not hand edit! +//****************************************************************************/ +//! Messages reporting accurately-timestamped external events, +//! e.g. camera shutter time. +//! + +extern crate byteorder; +#[allow(unused_imports)] +use self::byteorder::{LittleEndian, ReadBytesExt}; + +/// Reports timestamped external pin event +/// +/// Reports detection of an external event, the GPS time it occurred, +/// which pin it was and whether it was rising or falling. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgExtEvent { + pub sender_id: Option, + /// GPS week number + pub wn: u16, + /// GPS time of week rounded to the nearest millisecond + pub tow: u32, + /// Nanosecond residual of millisecond-rounded TOW (ranges from -500000 to + /// 500000) + pub ns_residual: i32, + /// Flags + pub flags: u8, + /// Pin number. 0..9 = DEBUG0..9. + pub pin: u8, +} + +impl MsgExtEvent { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgExtEvent { + sender_id: None, + wn: _buf.read_u16::()?, + tow: _buf.read_u32::()?, + ns_residual: _buf.read_i32::()?, + flags: _buf.read_u8()?, + pin: _buf.read_u8()?, + }) + } +} +impl super::SBPMessage for MsgExtEvent { + const MSG_ID: u16 = 257; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} diff --git a/rust/sbp/src/messages/file_io.rs b/rust/sbp/src/messages/file_io.rs new file mode 100644 index 0000000000..0a40b73e9f --- /dev/null +++ b/rust/sbp/src/messages/file_io.rs @@ -0,0 +1,400 @@ +// Copyright (C) 2015-2018 Swift Navigation Inc. +// Contact: Swift Navigation +// +// This source is subject to the license found in the file 'LICENSE' which must +// be be distributed together with this source. All other rights reserved. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. + +//**************************************************************************** +// Automatically generated from yaml/swiftnav/sbp/file_io.yaml +// with generate.py. Please do not hand edit! +//****************************************************************************/ +//! Messages for using device's onboard flash filesystem +//! functionality. This allows data to be stored persistently in the +//! device's program flash with wear-levelling using a simple filesystem +//! interface. The file system interface (CFS) defines an abstract API +//! for reading directories and for reading and writing files. +//! +//! Note that some of these messages share the same message type ID for both the +//! host request and the device response. +//! + +extern crate byteorder; +#[allow(unused_imports)] +use self::byteorder::{LittleEndian, ReadBytesExt}; + +/// Read file from the file system (host => device) +/// +/// The file read message reads a certain length (up to 255 bytes) +/// from a given offset into a file, and returns the data in a +/// MSG_FILEIO_READ_RESP message where the message length field +/// indicates how many bytes were succesfully read.The sequence +/// number in the request will be returned in the response. +/// If the message is invalid, a followup MSG_PRINT message will +/// print "Invalid fileio read message". A device will only respond +/// to this message when it is received from sender ID 0x42. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgFileioReadReq { + pub sender_id: Option, + /// Read sequence number + pub sequence: u32, + /// File offset + pub offset: u32, + /// Chunk size to read + pub chunk_size: u8, + /// Name of the file to read from + pub filename: String, +} + +impl MsgFileioReadReq { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgFileioReadReq { + sender_id: None, + sequence: _buf.read_u32::()?, + offset: _buf.read_u32::()?, + chunk_size: _buf.read_u8()?, + filename: ::parser::read_string(_buf)?, + }) + } +} +impl super::SBPMessage for MsgFileioReadReq { + const MSG_ID: u16 = 168; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// File read from the file system (host <= device) +/// +/// The file read message reads a certain length (up to 255 bytes) +/// from a given offset into a file, and returns the data in a +/// message where the message length field indicates how many bytes +/// were succesfully read. The sequence number in the response is +/// preserved from the request. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgFileioReadResp { + pub sender_id: Option, + /// Read sequence number + pub sequence: u32, + /// Contents of read file + pub contents: Vec, +} + +impl MsgFileioReadResp { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgFileioReadResp { + sender_id: None, + sequence: _buf.read_u32::()?, + contents: ::parser::read_u8_array(_buf)?, + }) + } +} +impl super::SBPMessage for MsgFileioReadResp { + const MSG_ID: u16 = 163; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// List files in a directory (host => device) +/// +/// The read directory message lists the files in a directory on the +/// device's onboard flash file system. The offset parameter can be +/// used to skip the first n elements of the file list. Returns a +/// MSG_FILEIO_READ_DIR_RESP message containing the directory +/// listings as a NULL delimited list. The listing is chunked over +/// multiple SBP packets. The sequence number in the request will be +/// returned in the response. If message is invalid, a followup +/// MSG_PRINT message will print "Invalid fileio read message". +/// A device will only respond to this message when it is received +/// from sender ID 0x42. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgFileioReadDirReq { + pub sender_id: Option, + /// Read sequence number + pub sequence: u32, + /// The offset to skip the first n elements of the file list + pub offset: u32, + /// Name of the directory to list + pub dirname: String, +} + +impl MsgFileioReadDirReq { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgFileioReadDirReq { + sender_id: None, + sequence: _buf.read_u32::()?, + offset: _buf.read_u32::()?, + dirname: ::parser::read_string(_buf)?, + }) + } +} +impl super::SBPMessage for MsgFileioReadDirReq { + const MSG_ID: u16 = 169; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Files listed in a directory (host <= device) +/// +/// The read directory message lists the files in a directory on the +/// device's onboard flash file system. Message contains the directory +/// listings as a NULL delimited list. The listing is chunked over +/// multiple SBP packets and the end of the list is identified by an +/// entry containing just the character 0xFF. The sequence number in +/// the response is preserved from the request. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgFileioReadDirResp { + pub sender_id: Option, + /// Read sequence number + pub sequence: u32, + /// Contents of read directory + pub contents: Vec, +} + +impl MsgFileioReadDirResp { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgFileioReadDirResp { + sender_id: None, + sequence: _buf.read_u32::()?, + contents: ::parser::read_u8_array(_buf)?, + }) + } +} +impl super::SBPMessage for MsgFileioReadDirResp { + const MSG_ID: u16 = 170; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Delete a file from the file system (host => device) +/// +/// The file remove message deletes a file from the file system. +/// If the message is invalid, a followup MSG_PRINT message will +/// print "Invalid fileio remove message". A device will only +/// process this message when it is received from sender ID 0x42. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgFileioRemove { + pub sender_id: Option, + /// Name of the file to delete + pub filename: String, +} + +impl MsgFileioRemove { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgFileioRemove { + sender_id: None, + filename: ::parser::read_string(_buf)?, + }) + } +} +impl super::SBPMessage for MsgFileioRemove { + const MSG_ID: u16 = 172; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Write to file (host => device) +/// +/// The file write message writes a certain length (up to 255 bytes) +/// of data to a file at a given offset. Returns a copy of the +/// original MSG_FILEIO_WRITE_RESP message to check integrity of +/// the write. The sequence number in the request will be returned +/// in the response. If message is invalid, a followup MSG_PRINT +/// message will print "Invalid fileio write message". A device will +/// only process this message when it is received from sender ID +/// 0x42. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgFileioWriteReq { + pub sender_id: Option, + /// Write sequence number + pub sequence: u32, + /// Offset into the file at which to start writing in bytes + pub offset: u32, + /// Name of the file to write to + pub filename: String, + /// Variable-length array of data to write + pub data: Vec, +} + +impl MsgFileioWriteReq { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgFileioWriteReq { + sender_id: None, + sequence: _buf.read_u32::()?, + offset: _buf.read_u32::()?, + filename: ::parser::read_string(_buf)?, + data: ::parser::read_u8_array(_buf)?, + }) + } +} +impl super::SBPMessage for MsgFileioWriteReq { + const MSG_ID: u16 = 173; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// File written to (host <= device) +/// +/// The file write message writes a certain length (up to 255 bytes) +/// of data to a file at a given offset. The message is a copy of the +/// original MSG_FILEIO_WRITE_REQ message to check integrity of the +/// write. The sequence number in the response is preserved from the +/// request. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgFileioWriteResp { + pub sender_id: Option, + /// Write sequence number + pub sequence: u32, +} + +impl MsgFileioWriteResp { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgFileioWriteResp { + sender_id: None, + sequence: _buf.read_u32::()?, + }) + } +} +impl super::SBPMessage for MsgFileioWriteResp { + const MSG_ID: u16 = 171; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Request advice on the optimal configuration for FileIO. +/// +/// Requests advice on the optimal configuration for a FileIO +/// transfer. Newer version of FileIO can support greater +/// throughput by supporting a large window of FileIO data +/// that can be in-flight during read or write operations. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgFileioConfigReq { + pub sender_id: Option, + /// Advice sequence number + pub sequence: u32, +} + +impl MsgFileioConfigReq { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgFileioConfigReq { + sender_id: None, + sequence: _buf.read_u32::()?, + }) + } +} +impl super::SBPMessage for MsgFileioConfigReq { + const MSG_ID: u16 = 4097; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Response with advice on the optimal configuration for FileIO. + +/// +/// The advice on the optimal configuration for a FileIO +/// transfer. Newer version of FileIO can support greater +/// throughput by supporting a large window of FileIO data +/// that can be in-flight during read or write operations. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgFileioConfigResp { + pub sender_id: Option, + /// Advice sequence number + pub sequence: u32, + /// The number of SBP packets in the data in-flight window + pub window_size: u32, + /// The number of SBP packets sent in one PDU + pub batch_size: u32, + /// The version of FileIO that is supported + pub fileio_version: u32, +} + +impl MsgFileioConfigResp { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgFileioConfigResp { + sender_id: None, + sequence: _buf.read_u32::()?, + window_size: _buf.read_u32::()?, + batch_size: _buf.read_u32::()?, + fileio_version: _buf.read_u32::()?, + }) + } +} +impl super::SBPMessage for MsgFileioConfigResp { + const MSG_ID: u16 = 4098; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} diff --git a/rust/sbp/src/messages/flash.rs b/rust/sbp/src/messages/flash.rs new file mode 100644 index 0000000000..709543bf29 --- /dev/null +++ b/rust/sbp/src/messages/flash.rs @@ -0,0 +1,398 @@ +// Copyright (C) 2015-2018 Swift Navigation Inc. +// Contact: Swift Navigation +// +// This source is subject to the license found in the file 'LICENSE' which must +// be be distributed together with this source. All other rights reserved. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. + +//**************************************************************************** +// Automatically generated from yaml/swiftnav/sbp/flash.yaml +// with generate.py. Please do not hand edit! +//****************************************************************************/ +//! Messages for reading/writing the device's onboard flash memory. Many +//! of these messages target specific flash memory peripherals used in +//! Swift Navigation devices: the STM32 flash and the M25Pxx FPGA +//! configuration flash from Piksi 2.3.1. This module does not apply +//! to Piksi Multi. +//! + +extern crate byteorder; +#[allow(unused_imports)] +use self::byteorder::{LittleEndian, ReadBytesExt}; + +/// Program flash addresses +/// +/// The flash program message programs a set of addresses of either +/// the STM or M25 flash. The device replies with either a +/// MSG_FLASH_DONE message containing the return code FLASH_OK (0) +/// on success, or FLASH_INVALID_LEN (2) if the maximum write size +/// is exceeded. Note that the sector-containing addresses must be +/// erased before addresses can be programmed. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgFlashProgram { + pub sender_id: Option, + /// Target flags + pub target: u8, + /// Starting address offset to program + pub addr_start: Vec, + /// Length of set of addresses to program, counting up from starting address + pub addr_len: u8, + /// Data to program addresses with, with length N=addr_len + pub data: Vec, +} + +impl MsgFlashProgram { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgFlashProgram { + sender_id: None, + target: _buf.read_u8()?, + addr_start: ::parser::read_u8_array_limit(_buf, 3)?, + addr_len: _buf.read_u8()?, + data: ::parser::read_u8_array(_buf)?, + }) + } +} +impl super::SBPMessage for MsgFlashProgram { + const MSG_ID: u16 = 230; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Flash response message (host <= device). +/// +/// This message defines success or failure codes for a variety of +/// flash memory requests from the host to the device. Flash read +/// and write messages, such as MSG_FLASH_READ_REQ, or +/// MSG_FLASH_PROGRAM, may return this message on failure. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgFlashDone { + pub sender_id: Option, + /// Response flags + pub response: u8, +} + +impl MsgFlashDone { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgFlashDone { + sender_id: None, + response: _buf.read_u8()?, + }) + } +} +impl super::SBPMessage for MsgFlashDone { + const MSG_ID: u16 = 224; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Read STM or M25 flash address request (host => device). +/// +/// The flash read message reads a set of addresses of either the +/// STM or M25 onboard flash. The device replies with a +/// MSG_FLASH_READ_RESP message containing either the read data on +/// success or a MSG_FLASH_DONE message containing the return code +/// FLASH_INVALID_LEN (2) if the maximum read size is exceeded or +/// FLASH_INVALID_ADDR (3) if the address is outside of the allowed +/// range. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgFlashReadReq { + pub sender_id: Option, + /// Target flags + pub target: u8, + /// Starting address offset to read from + pub addr_start: Vec, + /// Length of set of addresses to read, counting up from starting address + pub addr_len: u8, +} + +impl MsgFlashReadReq { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgFlashReadReq { + sender_id: None, + target: _buf.read_u8()?, + addr_start: ::parser::read_u8_array_limit(_buf, 3)?, + addr_len: _buf.read_u8()?, + }) + } +} +impl super::SBPMessage for MsgFlashReadReq { + const MSG_ID: u16 = 231; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Read STM or M25 flash address response (host <= device). +/// +/// The flash read message reads a set of addresses of either the +/// STM or M25 onboard flash. The device replies with a +/// MSG_FLASH_READ_RESP message containing either the read data on +/// success or a MSG_FLASH_DONE message containing the return code +/// FLASH_INVALID_LEN (2) if the maximum read size is exceeded or +/// FLASH_INVALID_ADDR (3) if the address is outside of the allowed +/// range. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgFlashReadResp { + pub sender_id: Option, + /// Target flags + pub target: u8, + /// Starting address offset to read from + pub addr_start: Vec, + /// Length of set of addresses to read, counting up from starting address + pub addr_len: u8, +} + +impl MsgFlashReadResp { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgFlashReadResp { + sender_id: None, + target: _buf.read_u8()?, + addr_start: ::parser::read_u8_array_limit(_buf, 3)?, + addr_len: _buf.read_u8()?, + }) + } +} +impl super::SBPMessage for MsgFlashReadResp { + const MSG_ID: u16 = 225; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Erase sector of device flash memory (host => device). +/// +/// The flash erase message from the host erases a sector of either +/// the STM or M25 onboard flash memory. The device will reply with a +/// MSG_FLASH_DONE message containing the return code - FLASH_OK (0) +/// on success or FLASH_INVALID_FLASH (1) if the flash specified is +/// invalid. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgFlashErase { + pub sender_id: Option, + /// Target flags + pub target: u8, + /// Flash sector number to erase (0-11 for the STM, 0-15 for the M25) + pub sector_num: u32, +} + +impl MsgFlashErase { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgFlashErase { + sender_id: None, + target: _buf.read_u8()?, + sector_num: _buf.read_u32::()?, + }) + } +} +impl super::SBPMessage for MsgFlashErase { + const MSG_ID: u16 = 226; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Lock sector of STM flash memory (host => device) +/// +/// The flash lock message locks a sector of the STM flash +/// memory. The device replies with a MSG_FLASH_DONE message. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgStmFlashLockSector { + pub sender_id: Option, + /// Flash sector number to lock + pub sector: u32, +} + +impl MsgStmFlashLockSector { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgStmFlashLockSector { + sender_id: None, + sector: _buf.read_u32::()?, + }) + } +} +impl super::SBPMessage for MsgStmFlashLockSector { + const MSG_ID: u16 = 227; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Unlock sector of STM flash memory (host => device) +/// +/// The flash unlock message unlocks a sector of the STM flash +/// memory. The device replies with a MSG_FLASH_DONE message. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgStmFlashUnlockSector { + pub sender_id: Option, + /// Flash sector number to unlock + pub sector: u32, +} + +impl MsgStmFlashUnlockSector { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgStmFlashUnlockSector { + sender_id: None, + sector: _buf.read_u32::()?, + }) + } +} +impl super::SBPMessage for MsgStmFlashUnlockSector { + const MSG_ID: u16 = 228; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Read device's hardcoded unique ID request (host => device) + +/// +/// This message reads the device's hardcoded unique ID. The host +/// requests the ID by sending a MSG_STM_UNIQUE_ID_REQ. The device +/// responds with a MSG_STM_UNIQUE_ID_RESP with the 12-byte unique +/// ID in the payload. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgStmUniqueIdReq { + pub sender_id: Option, +} + +impl MsgStmUniqueIdReq { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgStmUniqueIdReq { sender_id: None }) + } +} +impl super::SBPMessage for MsgStmUniqueIdReq { + const MSG_ID: u16 = 232; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Read device's hardcoded unique ID response (host <= device) + +/// +/// This message reads the device's hardcoded unique ID. The host +/// requests the ID by sending a MSG_STM_UNIQUE_ID_REQ. The device +/// responds with a MSG_STM_UNIQUE_ID_RESP with the 12-byte unique +/// ID in the payload.. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgStmUniqueIdResp { + pub sender_id: Option, + /// Device unique ID + pub stm_id: Vec, +} + +impl MsgStmUniqueIdResp { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgStmUniqueIdResp { + sender_id: None, + stm_id: ::parser::read_u8_array_limit(_buf, 12)?, + }) + } +} +impl super::SBPMessage for MsgStmUniqueIdResp { + const MSG_ID: u16 = 229; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Write M25 flash status register (host => device) +/// +/// The flash status message writes to the 8-bit M25 flash status +/// register. The device replies with a MSG_FLASH_DONE message. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgM25FlashWriteStatus { + pub sender_id: Option, + /// Byte to write to the M25 flash status register + pub status: Vec, +} + +impl MsgM25FlashWriteStatus { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgM25FlashWriteStatus { + sender_id: None, + status: ::parser::read_u8_array_limit(_buf, 1)?, + }) + } +} +impl super::SBPMessage for MsgM25FlashWriteStatus { + const MSG_ID: u16 = 243; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} diff --git a/rust/sbp/src/messages/gnss.rs b/rust/sbp/src/messages/gnss.rs new file mode 100644 index 0000000000..3a5a9971ef --- /dev/null +++ b/rust/sbp/src/messages/gnss.rs @@ -0,0 +1,299 @@ +// Copyright (C) 2015-2018 Swift Navigation Inc. +// Contact: Swift Navigation +// +// This source is subject to the license found in the file 'LICENSE' which must +// be be distributed together with this source. All other rights reserved. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. + +//**************************************************************************** +// Automatically generated from yaml/swiftnav/sbp/gnss.yaml +// with generate.py. Please do not hand edit! +//****************************************************************************/ +//! Various structs shared between modules + +extern crate byteorder; +#[allow(unused_imports)] +use self::byteorder::{LittleEndian, ReadBytesExt}; + +/// Represents all the relevant information about the signal +/// +/// Signal identifier containing constellation, band, and satellite identifier +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct GnssSignal { + /// Constellation-specific satellite identifier. This field for Glonass can + /// either be (100+FCN) where FCN is in [-7,+6] or the Slot ID in [1,28] + pub sat: u8, + /// Signal constellation, band and code + pub code: u8, +} + +impl GnssSignal { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(GnssSignal { + sat: _buf.read_u8()?, + code: _buf.read_u8()?, + }) + } + pub fn parse_array(buf: &mut &[u8]) -> Result, ::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(GnssSignal::parse(buf)?); + } + Ok(v) + } + + pub fn parse_array_limit(buf: &mut &[u8], n: usize) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(GnssSignal::parse(buf)?); + } + Ok(v) + } +} + +/// Space vehicle identifier +/// +/// A (Constellation ID, satellite ID) tuple that uniquely identifies +/// a space vehicle +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct SvId { + /// ID of the space vehicle within its constellation + pub satId: u8, + /// Constellation ID to which the SV belongs + pub constellation: u8, +} + +impl SvId { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(SvId { + satId: _buf.read_u8()?, + constellation: _buf.read_u8()?, + }) + } + pub fn parse_array(buf: &mut &[u8]) -> Result, ::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(SvId::parse(buf)?); + } + Ok(v) + } + + pub fn parse_array_limit(buf: &mut &[u8], n: usize) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(SvId::parse(buf)?); + } + Ok(v) + } +} + +/// Deprecated +/// +/// Deprecated. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct GnssSignalDep { + /// Constellation-specific satellite identifier. Note: unlike GnssSignal, + /// GPS satellites are encoded as (PRN - 1). Other constellations do not + /// have this offset. + pub sat: u16, + /// Signal constellation, band and code + pub code: u8, + /// Reserved + pub reserved: u8, +} + +impl GnssSignalDep { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(GnssSignalDep { + sat: _buf.read_u16::()?, + code: _buf.read_u8()?, + reserved: _buf.read_u8()?, + }) + } + pub fn parse_array(buf: &mut &[u8]) -> Result, ::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(GnssSignalDep::parse(buf)?); + } + Ok(v) + } + + pub fn parse_array_limit(buf: &mut &[u8], n: usize) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(GnssSignalDep::parse(buf)?); + } + Ok(v) + } +} + +/// Millisecond-accurate GPS time +/// +/// A wire-appropriate GPS time, defined as the number of +/// milliseconds since beginning of the week on the Saturday/Sunday +/// transition. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct GPSTimeDep { + /// Milliseconds since start of GPS week + pub tow: u32, + /// GPS week number + pub wn: u16, +} + +impl GPSTimeDep { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(GPSTimeDep { + tow: _buf.read_u32::()?, + wn: _buf.read_u16::()?, + }) + } + pub fn parse_array(buf: &mut &[u8]) -> Result, ::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(GPSTimeDep::parse(buf)?); + } + Ok(v) + } + + pub fn parse_array_limit(buf: &mut &[u8], n: usize) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(GPSTimeDep::parse(buf)?); + } + Ok(v) + } +} + +/// Whole second accurate GPS time +/// +/// A GPS time, defined as the number of +/// seconds since beginning of the week on the Saturday/Sunday +/// transition. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct GPSTimeSec { + /// Seconds since start of GPS week + pub tow: u32, + /// GPS week number + pub wn: u16, +} + +impl GPSTimeSec { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(GPSTimeSec { + tow: _buf.read_u32::()?, + wn: _buf.read_u16::()?, + }) + } + pub fn parse_array(buf: &mut &[u8]) -> Result, ::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(GPSTimeSec::parse(buf)?); + } + Ok(v) + } + + pub fn parse_array_limit(buf: &mut &[u8], n: usize) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(GPSTimeSec::parse(buf)?); + } + Ok(v) + } +} + +/// Nanosecond-accurate receiver clock time +/// +/// A wire-appropriate receiver clock time, defined as the time +/// since the beginning of the week on the Saturday/Sunday +/// transition. In most cases, observations are epoch aligned +/// so ns field will be 0. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct GPSTime { + /// Milliseconds since start of GPS week + pub tow: u32, + /// Nanosecond residual of millisecond-rounded TOW (ranges from -500000 to + /// 500000) + pub ns_residual: i32, + /// GPS week number + pub wn: u16, +} + +impl GPSTime { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(GPSTime { + tow: _buf.read_u32::()?, + ns_residual: _buf.read_i32::()?, + wn: _buf.read_u16::()?, + }) + } + pub fn parse_array(buf: &mut &[u8]) -> Result, ::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(GPSTime::parse(buf)?); + } + Ok(v) + } + + pub fn parse_array_limit(buf: &mut &[u8], n: usize) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(GPSTime::parse(buf)?); + } + Ok(v) + } +} + +/// GNSS carrier phase measurement. +/// +/// Carrier phase measurement in cycles represented as a 40-bit +/// fixed point number with Q32.8 layout, i.e. 32-bits of whole +/// cycles and 8-bits of fractional cycles. This phase has the +/// same sign as the pseudorange. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct CarrierPhase { + /// Carrier phase whole cycles + pub i: i32, + /// Carrier phase fractional part + pub f: u8, +} + +impl CarrierPhase { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(CarrierPhase { + i: _buf.read_i32::()?, + f: _buf.read_u8()?, + }) + } + pub fn parse_array(buf: &mut &[u8]) -> Result, ::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(CarrierPhase::parse(buf)?); + } + Ok(v) + } + + pub fn parse_array_limit(buf: &mut &[u8], n: usize) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(CarrierPhase::parse(buf)?); + } + Ok(v) + } +} diff --git a/rust/sbp/src/messages/imu.rs b/rust/sbp/src/messages/imu.rs new file mode 100644 index 0000000000..1215e038e7 --- /dev/null +++ b/rust/sbp/src/messages/imu.rs @@ -0,0 +1,116 @@ +// Copyright (C) 2015-2018 Swift Navigation Inc. +// Contact: Swift Navigation +// +// This source is subject to the license found in the file 'LICENSE' which must +// be be distributed together with this source. All other rights reserved. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. + +//**************************************************************************** +// Automatically generated from yaml/swiftnav/sbp/imu.yaml +// with generate.py. Please do not hand edit! +//****************************************************************************/ +//! Inertial Measurement Unit (IMU) messages. + +extern crate byteorder; +#[allow(unused_imports)] +use self::byteorder::{LittleEndian, ReadBytesExt}; + +/// Raw IMU data +/// +/// Raw data from the Inertial Measurement Unit, containing accelerometer and +/// gyroscope readings. The sense of the measurements are to be aligned with +/// the indications on the device itself. Measurement units, which are specific to the +/// device hardware and settings, are communicated via the MSG_IMU_AUX message. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgImuRaw { + pub sender_id: Option, + /// Milliseconds since start of GPS week. If the high bit is set, the time + /// is unknown or invalid. + pub tow: u32, + /// Milliseconds since start of GPS week, fractional part + pub tow_f: u8, + /// Acceleration in the IMU frame X axis + pub acc_x: i16, + /// Acceleration in the IMU frame Y axis + pub acc_y: i16, + /// Acceleration in the IMU frame Z axis + pub acc_z: i16, + /// Angular rate around IMU frame X axis + pub gyr_x: i16, + /// Angular rate around IMU frame Y axis + pub gyr_y: i16, + /// Angular rate around IMU frame Z axis + pub gyr_z: i16, +} + +impl MsgImuRaw { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgImuRaw { + sender_id: None, + tow: _buf.read_u32::()?, + tow_f: _buf.read_u8()?, + acc_x: _buf.read_i16::()?, + acc_y: _buf.read_i16::()?, + acc_z: _buf.read_i16::()?, + gyr_x: _buf.read_i16::()?, + gyr_y: _buf.read_i16::()?, + gyr_z: _buf.read_i16::()?, + }) + } +} +impl super::SBPMessage for MsgImuRaw { + const MSG_ID: u16 = 2304; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Auxiliary IMU data +/// +/// Auxiliary data specific to a particular IMU. The `imu_type` field will +/// always be consistent but the rest of the payload is device specific and +/// depends on the value of `imu_type`. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgImuAux { + pub sender_id: Option, + /// IMU type + pub imu_type: u8, + /// Raw IMU temperature + pub temp: i16, + /// IMU configuration + pub imu_conf: u8, +} + +impl MsgImuAux { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgImuAux { + sender_id: None, + imu_type: _buf.read_u8()?, + temp: _buf.read_i16::()?, + imu_conf: _buf.read_u8()?, + }) + } +} +impl super::SBPMessage for MsgImuAux { + const MSG_ID: u16 = 2305; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} diff --git a/rust/sbp/src/messages/linux.rs b/rust/sbp/src/messages/linux.rs new file mode 100644 index 0000000000..d797d1abc8 --- /dev/null +++ b/rust/sbp/src/messages/linux.rs @@ -0,0 +1,391 @@ +// Copyright (C) 2015-2018 Swift Navigation Inc. +// Contact: Swift Navigation +// +// This source is subject to the license found in the file 'LICENSE' which must +// be be distributed together with this source. All other rights reserved. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. + +//**************************************************************************** +// Automatically generated from yaml/swiftnav/sbp/linux.yaml +// with generate.py. Please do not hand edit! +//****************************************************************************/ +//! Linux state monitoring. +//! + +extern crate byteorder; +#[allow(unused_imports)] +use self::byteorder::{LittleEndian, ReadBytesExt}; + +/// List CPU state on the system +/// +/// This message indicates the process state of the top 10 heaviest +/// consumers of CPU on the system. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgLinuxCpuState { + pub sender_id: Option, + /// sequence of this status message, values from 0-9 + pub index: u8, + /// the PID of the process + pub pid: u16, + /// percent of cpu used, expressed as a fraction of 256 + pub pcpu: u8, + /// fixed length string representing the thread name + pub tname: String, + /// the command line (as much as it fits in the remaining packet) + pub cmdline: String, +} + +impl MsgLinuxCpuState { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgLinuxCpuState { + sender_id: None, + index: _buf.read_u8()?, + pid: _buf.read_u16::()?, + pcpu: _buf.read_u8()?, + tname: ::parser::read_string_limit(_buf, 15)?, + cmdline: ::parser::read_string(_buf)?, + }) + } +} +impl super::SBPMessage for MsgLinuxCpuState { + const MSG_ID: u16 = 32512; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// List CPU state on the system +/// +/// This message indicates the process state of the top 10 heaviest +/// consumers of memory on the system. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgLinuxMemState { + pub sender_id: Option, + /// sequence of this status message, values from 0-9 + pub index: u8, + /// the PID of the process + pub pid: u16, + /// percent of memory used, expressed as a fraction of 256 + pub pmem: u8, + /// fixed length string representing the thread name + pub tname: String, + /// the command line (as much as it fits in the remaining packet) + pub cmdline: String, +} + +impl MsgLinuxMemState { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgLinuxMemState { + sender_id: None, + index: _buf.read_u8()?, + pid: _buf.read_u16::()?, + pmem: _buf.read_u8()?, + tname: ::parser::read_string_limit(_buf, 15)?, + cmdline: ::parser::read_string(_buf)?, + }) + } +} +impl super::SBPMessage for MsgLinuxMemState { + const MSG_ID: u16 = 32513; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// CPU, Memory and Process Starts/Stops +/// +/// This presents a summary of CPU and memory utilization. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgLinuxSysState { + pub sender_id: Option, + /// total system memory + pub mem_total: u16, + /// percent of total cpu currently utilized + pub pcpu: u8, + /// percent of total memory currently utilized + pub pmem: u8, + /// number of processes that started during collection phase + pub procs_starting: u16, + /// number of processes that stopped during collection phase + pub procs_stopping: u16, + /// the count of processes on the system + pub pid_count: u16, +} + +impl MsgLinuxSysState { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgLinuxSysState { + sender_id: None, + mem_total: _buf.read_u16::()?, + pcpu: _buf.read_u8()?, + pmem: _buf.read_u8()?, + procs_starting: _buf.read_u16::()?, + procs_stopping: _buf.read_u16::()?, + pid_count: _buf.read_u16::()?, + }) + } +} +impl super::SBPMessage for MsgLinuxSysState { + const MSG_ID: u16 = 32514; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// A list of processes with high socket counts +/// +/// Top 10 list of processes with high socket counts. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgLinuxProcessSocketCounts { + pub sender_id: Option, + /// sequence of this status message, values from 0-9 + pub index: u8, + /// the PID of the process in question + pub pid: u16, + /// the number of sockets the process is using + pub socket_count: u16, + /// A bitfield indicating the socket types used: 0x1 (tcp), 0x2 (udp), 0x4 + /// (unix stream), 0x8 (unix dgram), 0x10 (netlink), and 0x8000 (unknown) + pub socket_types: u16, + /// A bitfield indicating the socket states: 0x1 (established), 0x2 (syn- + /// sent), 0x4 (syn-recv), 0x8 (fin-wait-1), 0x10 (fin-wait-2), 0x20 + /// (time-wait), 0x40 (closed), 0x80 (close-wait), 0x100 (last-ack), 0x200 + /// (listen), 0x400 (closing), 0x800 (unconnected), and 0x8000 (unknown) + pub socket_states: u16, + /// the command line of the process in question + pub cmdline: String, +} + +impl MsgLinuxProcessSocketCounts { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgLinuxProcessSocketCounts { + sender_id: None, + index: _buf.read_u8()?, + pid: _buf.read_u16::()?, + socket_count: _buf.read_u16::()?, + socket_types: _buf.read_u16::()?, + socket_states: _buf.read_u16::()?, + cmdline: ::parser::read_string(_buf)?, + }) + } +} +impl super::SBPMessage for MsgLinuxProcessSocketCounts { + const MSG_ID: u16 = 32515; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// A list of processes with deep socket queues +/// +/// Top 10 list of sockets with deep queues. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgLinuxProcessSocketQueues { + pub sender_id: Option, + /// sequence of this status message, values from 0-9 + pub index: u8, + /// the PID of the process in question + pub pid: u16, + /// the total amount of receive data queued for this process + pub recv_queued: u16, + /// the total amount of send data queued for this process + pub send_queued: u16, + /// A bitfield indicating the socket types used: 0x1 (tcp), 0x2 (udp), 0x4 + /// (unix stream), 0x8 (unix dgram), 0x10 (netlink), and 0x8000 (unknown) + pub socket_types: u16, + /// A bitfield indicating the socket states: 0x1 (established), 0x2 (syn- + /// sent), 0x4 (syn-recv), 0x8 (fin-wait-1), 0x10 (fin-wait-2), 0x20 + /// (time-wait), 0x40 (closed), 0x80 (close-wait), 0x100 (last-ack), 0x200 + /// (listen), 0x400 (closing), 0x800 (unconnected), and 0x8000 (unknown) + pub socket_states: u16, + /// Address of the largest queue, remote or local depending on the + /// directionality of the connection. + pub address_of_largest: String, + /// the command line of the process in question + pub cmdline: String, +} + +impl MsgLinuxProcessSocketQueues { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgLinuxProcessSocketQueues { + sender_id: None, + index: _buf.read_u8()?, + pid: _buf.read_u16::()?, + recv_queued: _buf.read_u16::()?, + send_queued: _buf.read_u16::()?, + socket_types: _buf.read_u16::()?, + socket_states: _buf.read_u16::()?, + address_of_largest: ::parser::read_string_limit(_buf, 64)?, + cmdline: ::parser::read_string(_buf)?, + }) + } +} +impl super::SBPMessage for MsgLinuxProcessSocketQueues { + const MSG_ID: u16 = 32516; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Summary of socket usage across the system +/// +/// Summaries the socket usage across the system. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgLinuxSocketUsage { + pub sender_id: Option, + /// average socket queue depths across all sockets on the system + pub avg_queue_depth: u32, + /// the max queue depth seen within the reporting period + pub max_queue_depth: u32, + /// A count for each socket type reported in the `socket_types_reported` + /// field, the first entry corresponds to the first enabled bit in + /// `types_reported`. + pub socket_state_counts: Vec, + /// A count for each socket type reported in the `socket_types_reported` + /// field, the first entry corresponds to the first enabled bit in + /// `types_reported`. + pub socket_type_counts: Vec, +} + +impl MsgLinuxSocketUsage { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgLinuxSocketUsage { + sender_id: None, + avg_queue_depth: _buf.read_u32::()?, + max_queue_depth: _buf.read_u32::()?, + socket_state_counts: ::parser::read_u16_array_limit(_buf, 16)?, + socket_type_counts: ::parser::read_u16_array_limit(_buf, 16)?, + }) + } +} +impl super::SBPMessage for MsgLinuxSocketUsage { + const MSG_ID: u16 = 32517; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Summary of processes with large amounts of open file descriptors +/// +/// Top 10 list of processes with a large number of open file descriptors. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgLinuxProcessFdCount { + pub sender_id: Option, + /// sequence of this status message, values from 0-9 + pub index: u8, + /// the PID of the process in question + pub pid: u16, + /// a count of the number of file descriptors opened by the process + pub fd_count: u16, + /// the command line of the process in question + pub cmdline: String, +} + +impl MsgLinuxProcessFdCount { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgLinuxProcessFdCount { + sender_id: None, + index: _buf.read_u8()?, + pid: _buf.read_u16::()?, + fd_count: _buf.read_u16::()?, + cmdline: ::parser::read_string(_buf)?, + }) + } +} +impl super::SBPMessage for MsgLinuxProcessFdCount { + const MSG_ID: u16 = 32518; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Summary of open file descriptors on the system +/// +/// Summary of open file descriptors on the system. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgLinuxProcessFdSummary { + pub sender_id: Option, + /// count of total FDs open on the system + pub sys_fd_count: u32, + /// A null delimited list of strings which alternates between a string + /// representation of the process count and the file name whose count it + /// being reported. That is, in C string syntax + /// "32\0/var/log/syslog\012\0/tmp/foo\0" with the end of the list being 2 + /// NULL terminators in a row. + pub most_opened: String, +} + +impl MsgLinuxProcessFdSummary { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgLinuxProcessFdSummary { + sender_id: None, + sys_fd_count: _buf.read_u32::()?, + most_opened: ::parser::read_string(_buf)?, + }) + } +} +impl super::SBPMessage for MsgLinuxProcessFdSummary { + const MSG_ID: u16 = 32519; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} diff --git a/rust/sbp/src/messages/logging.rs b/rust/sbp/src/messages/logging.rs new file mode 100644 index 0000000000..b21969b440 --- /dev/null +++ b/rust/sbp/src/messages/logging.rs @@ -0,0 +1,133 @@ +// Copyright (C) 2015-2018 Swift Navigation Inc. +// Contact: Swift Navigation +// +// This source is subject to the license found in the file 'LICENSE' which must +// be be distributed together with this source. All other rights reserved. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. + +//**************************************************************************** +// Automatically generated from yaml/swiftnav/sbp/logging.yaml +// with generate.py. Please do not hand edit! +//****************************************************************************/ +//! Logging and debugging messages from the device. +//! + +extern crate byteorder; +#[allow(unused_imports)] +use self::byteorder::{LittleEndian, ReadBytesExt}; + +/// Plaintext logging messages with levels +/// +/// This message contains a human-readable payload string from the +/// device containing errors, warnings and informational messages at +/// ERROR, WARNING, DEBUG, INFO logging levels. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgLog { + pub sender_id: Option, + /// Logging level + pub level: u8, + /// Human-readable string + pub text: String, +} + +impl MsgLog { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgLog { + sender_id: None, + level: _buf.read_u8()?, + text: ::parser::read_string(_buf)?, + }) + } +} +impl super::SBPMessage for MsgLog { + const MSG_ID: u16 = 1025; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Wrapper for FWD a separate stream of information over SBP +/// +/// This message provides the ability to forward messages over SBP. This may take the form +/// of wrapping up SBP messages received by Piksi for logging purposes or wrapping +/// another protocol with SBP. +/// +/// The source identifier indicates from what interface a forwarded stream derived. +/// The protocol identifier identifies what the expected protocol the forwarded msg contains. +/// Protocol 0 represents SBP and the remaining values are implementation defined. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgFwd { + pub sender_id: Option, + /// source identifier + pub source: u8, + /// protocol identifier + pub protocol: u8, + /// variable length wrapped binary message + pub fwd_payload: String, +} + +impl MsgFwd { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgFwd { + sender_id: None, + source: _buf.read_u8()?, + protocol: _buf.read_u8()?, + fwd_payload: ::parser::read_string(_buf)?, + }) + } +} +impl super::SBPMessage for MsgFwd { + const MSG_ID: u16 = 1026; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Deprecated +/// +/// Deprecated. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgPrintDep { + pub sender_id: Option, + /// Human-readable string + pub text: String, +} + +impl MsgPrintDep { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgPrintDep { + sender_id: None, + text: ::parser::read_string(_buf)?, + }) + } +} +impl super::SBPMessage for MsgPrintDep { + const MSG_ID: u16 = 16; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} diff --git a/rust/sbp/src/messages/mag.rs b/rust/sbp/src/messages/mag.rs new file mode 100644 index 0000000000..23d7e266a9 --- /dev/null +++ b/rust/sbp/src/messages/mag.rs @@ -0,0 +1,64 @@ +// Copyright (C) 2015-2018 Swift Navigation Inc. +// Contact: Swift Navigation +// +// This source is subject to the license found in the file 'LICENSE' which must +// be be distributed together with this source. All other rights reserved. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. + +//**************************************************************************** +// Automatically generated from yaml/swiftnav/sbp/mag.yaml +// with generate.py. Please do not hand edit! +//****************************************************************************/ +//! Magnetometer (mag) messages. + +extern crate byteorder; +#[allow(unused_imports)] +use self::byteorder::{LittleEndian, ReadBytesExt}; + +/// Raw magnetometer data +/// +/// Raw data from the magnetometer. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgMagRaw { + pub sender_id: Option, + /// Milliseconds since start of GPS week. If the high bit is set, the time + /// is unknown or invalid. + pub tow: u32, + /// Milliseconds since start of GPS week, fractional part + pub tow_f: u8, + /// Magnetic field in the body frame X axis + pub mag_x: i16, + /// Magnetic field in the body frame Y axis + pub mag_y: i16, + /// Magnetic field in the body frame Z axis + pub mag_z: i16, +} + +impl MsgMagRaw { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgMagRaw { + sender_id: None, + tow: _buf.read_u32::()?, + tow_f: _buf.read_u8()?, + mag_x: _buf.read_i16::()?, + mag_y: _buf.read_i16::()?, + mag_z: _buf.read_i16::()?, + }) + } +} +impl super::SBPMessage for MsgMagRaw { + const MSG_ID: u16 = 2306; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} diff --git a/rust/sbp/src/messages/mod.rs b/rust/sbp/src/messages/mod.rs new file mode 100644 index 0000000000..5b46461445 --- /dev/null +++ b/rust/sbp/src/messages/mod.rs @@ -0,0 +1,1274 @@ +// Copyright (C) 2015-2018 Swift Navigation Inc. +// Contact: Swift Navigation +// +// This source is subject to the license found in the file 'LICENSE' which must +// be be distributed together with this source. All other rights reserved. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. +pub mod acquisition; +pub mod bootload; +pub mod ext_events; +pub mod file_io; +pub mod flash; +pub mod gnss; +pub mod imu; +pub mod linux; +pub mod logging; +pub mod mag; +pub mod navigation; +pub mod ndb; +pub mod observation; +pub mod orientation; +pub mod piksi; +pub mod sbas; +pub mod settings; +pub mod ssr; +pub mod system; +pub mod tracking; +pub mod user; +pub mod vehicle; +use self::acquisition::MsgAcqResult; +use self::acquisition::MsgAcqResultDepA; +use self::acquisition::MsgAcqResultDepB; +use self::acquisition::MsgAcqResultDepC; +use self::acquisition::MsgAcqSvProfile; +use self::acquisition::MsgAcqSvProfileDep; +use self::bootload::MsgBootloaderHandshakeDepA; +use self::bootload::MsgBootloaderHandshakeReq; +use self::bootload::MsgBootloaderHandshakeResp; +use self::bootload::MsgBootloaderJumpToApp; +use self::bootload::MsgNapDeviceDnaReq; +use self::bootload::MsgNapDeviceDnaResp; +use self::ext_events::MsgExtEvent; +use self::file_io::MsgFileioConfigReq; +use self::file_io::MsgFileioConfigResp; +use self::file_io::MsgFileioReadDirReq; +use self::file_io::MsgFileioReadDirResp; +use self::file_io::MsgFileioReadReq; +use self::file_io::MsgFileioReadResp; +use self::file_io::MsgFileioRemove; +use self::file_io::MsgFileioWriteReq; +use self::file_io::MsgFileioWriteResp; +use self::flash::MsgFlashDone; +use self::flash::MsgFlashErase; +use self::flash::MsgFlashProgram; +use self::flash::MsgFlashReadReq; +use self::flash::MsgFlashReadResp; +use self::flash::MsgM25FlashWriteStatus; +use self::flash::MsgStmFlashLockSector; +use self::flash::MsgStmFlashUnlockSector; +use self::flash::MsgStmUniqueIdReq; +use self::flash::MsgStmUniqueIdResp; +use self::imu::MsgImuAux; +use self::imu::MsgImuRaw; +use self::linux::MsgLinuxCpuState; +use self::linux::MsgLinuxMemState; +use self::linux::MsgLinuxProcessFdCount; +use self::linux::MsgLinuxProcessFdSummary; +use self::linux::MsgLinuxProcessSocketCounts; +use self::linux::MsgLinuxProcessSocketQueues; +use self::linux::MsgLinuxSocketUsage; +use self::linux::MsgLinuxSysState; +use self::logging::MsgFwd; +use self::logging::MsgLog; +use self::logging::MsgPrintDep; +use self::mag::MsgMagRaw; +use self::navigation::MsgAgeCorrections; +use self::navigation::MsgBaselineECEF; +use self::navigation::MsgBaselineECEFDepA; +use self::navigation::MsgBaselineHeadingDepA; +use self::navigation::MsgBaselineNED; +use self::navigation::MsgBaselineNEDDepA; +use self::navigation::MsgDops; +use self::navigation::MsgDopsDepA; +use self::navigation::MsgGPSTime; +use self::navigation::MsgGPSTimeDepA; +use self::navigation::MsgPosECEF; +use self::navigation::MsgPosECEFCov; +use self::navigation::MsgPosECEFDepA; +use self::navigation::MsgPosLLH; +use self::navigation::MsgPosLLHCov; +use self::navigation::MsgPosLLHDepA; +use self::navigation::MsgUtcTime; +use self::navigation::MsgVelBody; +use self::navigation::MsgVelECEF; +use self::navigation::MsgVelECEFCov; +use self::navigation::MsgVelECEFDepA; +use self::navigation::MsgVelNED; +use self::navigation::MsgVelNEDCov; +use self::navigation::MsgVelNEDDepA; +use self::ndb::MsgNdbEvent; +use self::observation::MsgAlmanacGPS; +use self::observation::MsgAlmanacGPSDep; +use self::observation::MsgAlmanacGlo; +use self::observation::MsgAlmanacGloDep; +use self::observation::MsgBasePosECEF; +use self::observation::MsgBasePosLLH; +use self::observation::MsgEphemerisBds; +use self::observation::MsgEphemerisDepA; +use self::observation::MsgEphemerisDepB; +use self::observation::MsgEphemerisDepC; +use self::observation::MsgEphemerisDepD; +use self::observation::MsgEphemerisGPS; +use self::observation::MsgEphemerisGPSDepE; +use self::observation::MsgEphemerisGPSDepF; +use self::observation::MsgEphemerisGal; +use self::observation::MsgEphemerisGalDepA; +use self::observation::MsgEphemerisGlo; +use self::observation::MsgEphemerisGloDepA; +use self::observation::MsgEphemerisGloDepB; +use self::observation::MsgEphemerisGloDepC; +use self::observation::MsgEphemerisGloDepD; +use self::observation::MsgEphemerisQzss; +use self::observation::MsgEphemerisSbas; +use self::observation::MsgEphemerisSbasDepA; +use self::observation::MsgEphemerisSbasDepB; +use self::observation::MsgGloBiases; +use self::observation::MsgGnssCapb; +use self::observation::MsgGroupDelay; +use self::observation::MsgGroupDelayDepA; +use self::observation::MsgGroupDelayDepB; +use self::observation::MsgIono; +use self::observation::MsgObs; +use self::observation::MsgObsDepA; +use self::observation::MsgObsDepB; +use self::observation::MsgObsDepC; +use self::observation::MsgOsr; +use self::observation::MsgSvAzEl; +use self::observation::MsgSvConfigurationGPSDep; +use self::orientation::MsgAngularRate; +use self::orientation::MsgBaselineHeading; +use self::orientation::MsgOrientEuler; +use self::orientation::MsgOrientQuat; +use self::piksi::MsgAlmanac; +use self::piksi::MsgCellModemStatus; +use self::piksi::MsgCommandOutput; +use self::piksi::MsgCommandReq; +use self::piksi::MsgCommandResp; +use self::piksi::MsgCwResults; +use self::piksi::MsgCwStart; +use self::piksi::MsgDeviceMonitor; +use self::piksi::MsgFrontEndGain; +use self::piksi::MsgIarState; +use self::piksi::MsgInitBaseDep; +use self::piksi::MsgMaskSatellite; +use self::piksi::MsgMaskSatelliteDep; +use self::piksi::MsgNetworkBandwidthUsage; +use self::piksi::MsgNetworkStateReq; +use self::piksi::MsgNetworkStateResp; +use self::piksi::MsgReset; +use self::piksi::MsgResetDep; +use self::piksi::MsgResetFilters; +use self::piksi::MsgSetTime; +use self::piksi::MsgSpecan; +use self::piksi::MsgSpecanDep; +use self::piksi::MsgThreadState; +use self::piksi::MsgUartState; +use self::piksi::MsgUartStateDepa; +use self::sbas::MsgSbasRaw; +use self::settings::MsgSettingsReadByIndexDone; +use self::settings::MsgSettingsReadByIndexReq; +use self::settings::MsgSettingsReadByIndexResp; +use self::settings::MsgSettingsReadReq; +use self::settings::MsgSettingsReadResp; +use self::settings::MsgSettingsRegister; +use self::settings::MsgSettingsRegisterResp; +use self::settings::MsgSettingsSave; +use self::settings::MsgSettingsWrite; +use self::settings::MsgSettingsWriteResp; +use self::ssr::MsgSsrCodeBiases; +use self::ssr::MsgSsrGridDefinition; +use self::ssr::MsgSsrGriddedCorrection; +use self::ssr::MsgSsrOrbitClock; +use self::ssr::MsgSsrOrbitClockDepA; +use self::ssr::MsgSsrPhaseBiases; +use self::ssr::MsgSsrStecCorrection; +use self::system::MsgCsacTelemetry; +use self::system::MsgCsacTelemetryLabels; +use self::system::MsgDgnssStatus; +use self::system::MsgHeartbeat; +use self::system::MsgInsStatus; +use self::system::MsgStartup; +use self::tracking::MsgMeasurementState; +use self::tracking::MsgTrackingIq; +use self::tracking::MsgTrackingIqDepA; +use self::tracking::MsgTrackingIqDepB; +use self::tracking::MsgTrackingState; +use self::tracking::MsgTrackingStateDepA; +use self::tracking::MsgTrackingStateDepB; +use self::tracking::MsgTrackingStateDetailedDep; +use self::tracking::MsgTrackingStateDetailedDepA; +use self::user::MsgUserData; +use self::vehicle::MsgOdometry; + +trait SBPMessage { + const MSG_ID: u16; + + fn get_sender_id(&self) -> Option; + fn set_sender_id(&mut self, new_id: u16); +} + +#[derive(Debug)] +pub enum SBP { + Unknown { + msg_id: u16, + sender_id: u16, + payload: Vec, + }, + MsgUartState(MsgUartState), + MsgUartStateDepa(MsgUartStateDepa), + MsgResetDep(MsgResetDep), + MsgCwResults(MsgCwResults), + MsgCwStart(MsgCwStart), + MsgResetFilters(MsgResetFilters), + MsgInitBaseDep(MsgInitBaseDep), + MsgThreadState(MsgThreadState), + MsgCommandOutput(MsgCommandOutput), + MsgNetworkStateReq(MsgNetworkStateReq), + MsgNetworkStateResp(MsgNetworkStateResp), + MsgSpecan(MsgSpecan), + MsgFrontEndGain(MsgFrontEndGain), + MsgLinuxCpuState(MsgLinuxCpuState), + MsgNetworkBandwidthUsage(MsgNetworkBandwidthUsage), + MsgCellModemStatus(MsgCellModemStatus), + MsgSpecanDep(MsgSpecanDep), + MsgLinuxProcessSocketCounts(MsgLinuxProcessSocketCounts), + MsgLinuxProcessSocketQueues(MsgLinuxProcessSocketQueues), + MsgLinuxSocketUsage(MsgLinuxSocketUsage), + MsgLinuxMemState(MsgLinuxMemState), + MsgLinuxSysState(MsgLinuxSysState), + MsgLinuxProcessFdCount(MsgLinuxProcessFdCount), + MsgLinuxProcessFdSummary(MsgLinuxProcessFdSummary), + MsgStartup(MsgStartup), + MsgDgnssStatus(MsgDgnssStatus), + MsgHeartbeat(MsgHeartbeat), + MsgIarState(MsgIarState), + MsgMaskSatellite(MsgMaskSatellite), + MsgMaskSatelliteDep(MsgMaskSatelliteDep), + MsgDeviceMonitor(MsgDeviceMonitor), + MsgCommandReq(MsgCommandReq), + MsgCommandResp(MsgCommandResp), + MsgNdbEvent(MsgNdbEvent), + MsgAlmanac(MsgAlmanac), + MsgSetTime(MsgSetTime), + MsgReset(MsgReset), + MsgObs(MsgObs), + MsgBasePosLLH(MsgBasePosLLH), + MsgBasePosECEF(MsgBasePosECEF), + MsgInsStatus(MsgInsStatus), + MsgCsacTelemetry(MsgCsacTelemetry), + MsgCsacTelemetryLabels(MsgCsacTelemetryLabels), + MsgExtEvent(MsgExtEvent), + MsgEphemerisGPSDepE(MsgEphemerisGPSDepE), + MsgEphemerisGPSDepF(MsgEphemerisGPSDepF), + MsgEphemerisGPS(MsgEphemerisGPS), + MsgEphemerisQzss(MsgEphemerisQzss), + MsgEphemerisBds(MsgEphemerisBds), + MsgEphemerisGalDepA(MsgEphemerisGalDepA), + MsgEphemerisGal(MsgEphemerisGal), + MsgEphemerisSbasDepA(MsgEphemerisSbasDepA), + MsgEphemerisGloDepA(MsgEphemerisGloDepA), + MsgEphemerisSbasDepB(MsgEphemerisSbasDepB), + MsgEphemerisSbas(MsgEphemerisSbas), + MsgEphemerisGloDepB(MsgEphemerisGloDepB), + MsgEphemerisGloDepC(MsgEphemerisGloDepC), + MsgEphemerisGloDepD(MsgEphemerisGloDepD), + MsgAcqResultDepB(MsgAcqResultDepB), + MsgAcqResultDepA(MsgAcqResultDepA), + MsgAcqSvProfile(MsgAcqSvProfile), + MsgAcqSvProfileDep(MsgAcqSvProfileDep), + MsgSbasRaw(MsgSbasRaw), + MsgSettingsSave(MsgSettingsSave), + MsgSettingsWrite(MsgSettingsWrite), + MsgSettingsWriteResp(MsgSettingsWriteResp), + MsgSettingsReadReq(MsgSettingsReadReq), + MsgSettingsReadResp(MsgSettingsReadResp), + MsgSettingsReadByIndexReq(MsgSettingsReadByIndexReq), + MsgSettingsReadByIndexResp(MsgSettingsReadByIndexResp), + MsgSettingsReadByIndexDone(MsgSettingsReadByIndexDone), + MsgSettingsRegister(MsgSettingsRegister), + MsgSettingsRegisterResp(MsgSettingsRegisterResp), + MsgBootloaderHandshakeReq(MsgBootloaderHandshakeReq), + MsgBootloaderHandshakeResp(MsgBootloaderHandshakeResp), + MsgBootloaderJumpToApp(MsgBootloaderJumpToApp), + MsgNapDeviceDnaReq(MsgNapDeviceDnaReq), + MsgNapDeviceDnaResp(MsgNapDeviceDnaResp), + MsgBootloaderHandshakeDepA(MsgBootloaderHandshakeDepA), + MsgFileioReadReq(MsgFileioReadReq), + MsgFileioReadResp(MsgFileioReadResp), + MsgFileioReadDirReq(MsgFileioReadDirReq), + MsgFileioReadDirResp(MsgFileioReadDirResp), + MsgFileioRemove(MsgFileioRemove), + MsgFileioWriteReq(MsgFileioWriteReq), + MsgFileioWriteResp(MsgFileioWriteResp), + MsgFileioConfigReq(MsgFileioConfigReq), + MsgFileioConfigResp(MsgFileioConfigResp), + MsgTrackingIq(MsgTrackingIq), + MsgTrackingIqDepB(MsgTrackingIqDepB), + MsgTrackingIqDepA(MsgTrackingIqDepA), + MsgTrackingStateDepA(MsgTrackingStateDepA), + MsgTrackingStateDepB(MsgTrackingStateDepB), + MsgLog(MsgLog), + MsgFwd(MsgFwd), + MsgPrintDep(MsgPrintDep), + MsgImuRaw(MsgImuRaw), + MsgImuAux(MsgImuAux), + MsgMagRaw(MsgMagRaw), + MsgSsrOrbitClock(MsgSsrOrbitClock), + MsgSsrOrbitClockDepA(MsgSsrOrbitClockDepA), + MsgSsrCodeBiases(MsgSsrCodeBiases), + MsgSsrPhaseBiases(MsgSsrPhaseBiases), + MsgSsrStecCorrection(MsgSsrStecCorrection), + MsgSsrGriddedCorrection(MsgSsrGriddedCorrection), + MsgSsrGridDefinition(MsgSsrGridDefinition), + MsgUserData(MsgUserData), + MsgAcqResult(MsgAcqResult), + MsgAcqResultDepC(MsgAcqResultDepC), + MsgVelECEFDepA(MsgVelECEFDepA), + MsgVelNEDDepA(MsgVelNEDDepA), + MsgBaselineHeadingDepA(MsgBaselineHeadingDepA), + MsgOdometry(MsgOdometry), + MsgBaselineHeading(MsgBaselineHeading), + MsgOrientQuat(MsgOrientQuat), + MsgOrientEuler(MsgOrientEuler), + MsgAngularRate(MsgAngularRate), + MsgTrackingStateDetailedDepA(MsgTrackingStateDetailedDepA), + MsgTrackingStateDetailedDep(MsgTrackingStateDetailedDep), + MsgTrackingState(MsgTrackingState), + MsgMeasurementState(MsgMeasurementState), + MsgPosECEF(MsgPosECEF), + MsgPosECEFCov(MsgPosECEFCov), + MsgPosLLH(MsgPosLLH), + MsgPosLLHCov(MsgPosLLHCov), + MsgBaselineECEF(MsgBaselineECEF), + MsgBaselineNED(MsgBaselineNED), + MsgVelECEF(MsgVelECEF), + MsgVelECEFCov(MsgVelECEFCov), + MsgVelNED(MsgVelNED), + MsgVelNEDCov(MsgVelNEDCov), + MsgVelBody(MsgVelBody), + MsgAgeCorrections(MsgAgeCorrections), + MsgGPSTimeDepA(MsgGPSTimeDepA), + MsgDopsDepA(MsgDopsDepA), + MsgPosECEFDepA(MsgPosECEFDepA), + MsgPosLLHDepA(MsgPosLLHDepA), + MsgBaselineECEFDepA(MsgBaselineECEFDepA), + MsgBaselineNEDDepA(MsgBaselineNEDDepA), + MsgGnssCapb(MsgGnssCapb), + MsgGroupDelayDepA(MsgGroupDelayDepA), + MsgGroupDelayDepB(MsgGroupDelayDepB), + MsgGroupDelay(MsgGroupDelay), + MsgAlmanacGPSDep(MsgAlmanacGPSDep), + MsgAlmanacGPS(MsgAlmanacGPS), + MsgAlmanacGloDep(MsgAlmanacGloDep), + MsgAlmanacGlo(MsgAlmanacGlo), + MsgGloBiases(MsgGloBiases), + MsgSvAzEl(MsgSvAzEl), + MsgOsr(MsgOsr), + MsgFlashProgram(MsgFlashProgram), + MsgFlashDone(MsgFlashDone), + MsgFlashReadReq(MsgFlashReadReq), + MsgFlashReadResp(MsgFlashReadResp), + MsgFlashErase(MsgFlashErase), + MsgStmFlashLockSector(MsgStmFlashLockSector), + MsgStmFlashUnlockSector(MsgStmFlashUnlockSector), + MsgStmUniqueIdReq(MsgStmUniqueIdReq), + MsgStmUniqueIdResp(MsgStmUniqueIdResp), + MsgM25FlashWriteStatus(MsgM25FlashWriteStatus), + MsgGPSTime(MsgGPSTime), + MsgUtcTime(MsgUtcTime), + MsgDops(MsgDops), + MsgEphemerisGlo(MsgEphemerisGlo), + MsgEphemerisDepD(MsgEphemerisDepD), + MsgEphemerisDepA(MsgEphemerisDepA), + MsgEphemerisDepB(MsgEphemerisDepB), + MsgEphemerisDepC(MsgEphemerisDepC), + MsgObsDepA(MsgObsDepA), + MsgObsDepB(MsgObsDepB), + MsgObsDepC(MsgObsDepC), + MsgIono(MsgIono), + MsgSvConfigurationGPSDep(MsgSvConfigurationGPSDep), +} + +impl SBP { + pub fn parse(msg_id: u16, sender_id: u16, payload: &mut &[u8]) -> Result { + let x: Result = match msg_id { + 29 => { + let mut msg = MsgUartState::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgUartState(msg)) + } + 24 => { + let mut msg = MsgUartStateDepa::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgUartStateDepa(msg)) + } + 178 => { + let mut msg = MsgResetDep::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgResetDep(msg)) + } + 192 => { + let mut msg = MsgCwResults::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgCwResults(msg)) + } + 193 => { + let mut msg = MsgCwStart::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgCwStart(msg)) + } + 34 => { + let mut msg = MsgResetFilters::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgResetFilters(msg)) + } + 35 => { + let mut msg = MsgInitBaseDep::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgInitBaseDep(msg)) + } + 23 => { + let mut msg = MsgThreadState::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgThreadState(msg)) + } + 188 => { + let mut msg = MsgCommandOutput::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgCommandOutput(msg)) + } + 186 => { + let mut msg = MsgNetworkStateReq::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgNetworkStateReq(msg)) + } + 187 => { + let mut msg = MsgNetworkStateResp::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgNetworkStateResp(msg)) + } + 81 => { + let mut msg = MsgSpecan::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgSpecan(msg)) + } + 191 => { + let mut msg = MsgFrontEndGain::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgFrontEndGain(msg)) + } + 32512 => { + let mut msg = MsgLinuxCpuState::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgLinuxCpuState(msg)) + } + 189 => { + let mut msg = MsgNetworkBandwidthUsage::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgNetworkBandwidthUsage(msg)) + } + 190 => { + let mut msg = MsgCellModemStatus::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgCellModemStatus(msg)) + } + 80 => { + let mut msg = MsgSpecanDep::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgSpecanDep(msg)) + } + 32515 => { + let mut msg = MsgLinuxProcessSocketCounts::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgLinuxProcessSocketCounts(msg)) + } + 32516 => { + let mut msg = MsgLinuxProcessSocketQueues::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgLinuxProcessSocketQueues(msg)) + } + 32517 => { + let mut msg = MsgLinuxSocketUsage::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgLinuxSocketUsage(msg)) + } + 32513 => { + let mut msg = MsgLinuxMemState::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgLinuxMemState(msg)) + } + 32514 => { + let mut msg = MsgLinuxSysState::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgLinuxSysState(msg)) + } + 32518 => { + let mut msg = MsgLinuxProcessFdCount::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgLinuxProcessFdCount(msg)) + } + 32519 => { + let mut msg = MsgLinuxProcessFdSummary::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgLinuxProcessFdSummary(msg)) + } + 65280 => { + let mut msg = MsgStartup::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgStartup(msg)) + } + 65282 => { + let mut msg = MsgDgnssStatus::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgDgnssStatus(msg)) + } + 65535 => { + let mut msg = MsgHeartbeat::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgHeartbeat(msg)) + } + 25 => { + let mut msg = MsgIarState::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgIarState(msg)) + } + 43 => { + let mut msg = MsgMaskSatellite::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgMaskSatellite(msg)) + } + 27 => { + let mut msg = MsgMaskSatelliteDep::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgMaskSatelliteDep(msg)) + } + 181 => { + let mut msg = MsgDeviceMonitor::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgDeviceMonitor(msg)) + } + 184 => { + let mut msg = MsgCommandReq::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgCommandReq(msg)) + } + 185 => { + let mut msg = MsgCommandResp::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgCommandResp(msg)) + } + 1024 => { + let mut msg = MsgNdbEvent::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgNdbEvent(msg)) + } + 105 => { + let mut msg = MsgAlmanac::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgAlmanac(msg)) + } + 104 => { + let mut msg = MsgSetTime::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgSetTime(msg)) + } + 182 => { + let mut msg = MsgReset::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgReset(msg)) + } + 74 => { + let mut msg = MsgObs::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgObs(msg)) + } + 68 => { + let mut msg = MsgBasePosLLH::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgBasePosLLH(msg)) + } + 72 => { + let mut msg = MsgBasePosECEF::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgBasePosECEF(msg)) + } + 65283 => { + let mut msg = MsgInsStatus::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgInsStatus(msg)) + } + 65284 => { + let mut msg = MsgCsacTelemetry::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgCsacTelemetry(msg)) + } + 65285 => { + let mut msg = MsgCsacTelemetryLabels::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgCsacTelemetryLabels(msg)) + } + 257 => { + let mut msg = MsgExtEvent::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgExtEvent(msg)) + } + 129 => { + let mut msg = MsgEphemerisGPSDepE::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgEphemerisGPSDepE(msg)) + } + 134 => { + let mut msg = MsgEphemerisGPSDepF::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgEphemerisGPSDepF(msg)) + } + 138 => { + let mut msg = MsgEphemerisGPS::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgEphemerisGPS(msg)) + } + 142 => { + let mut msg = MsgEphemerisQzss::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgEphemerisQzss(msg)) + } + 137 => { + let mut msg = MsgEphemerisBds::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgEphemerisBds(msg)) + } + 149 => { + let mut msg = MsgEphemerisGalDepA::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgEphemerisGalDepA(msg)) + } + 141 => { + let mut msg = MsgEphemerisGal::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgEphemerisGal(msg)) + } + 130 => { + let mut msg = MsgEphemerisSbasDepA::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgEphemerisSbasDepA(msg)) + } + 131 => { + let mut msg = MsgEphemerisGloDepA::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgEphemerisGloDepA(msg)) + } + 132 => { + let mut msg = MsgEphemerisSbasDepB::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgEphemerisSbasDepB(msg)) + } + 140 => { + let mut msg = MsgEphemerisSbas::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgEphemerisSbas(msg)) + } + 133 => { + let mut msg = MsgEphemerisGloDepB::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgEphemerisGloDepB(msg)) + } + 135 => { + let mut msg = MsgEphemerisGloDepC::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgEphemerisGloDepC(msg)) + } + 136 => { + let mut msg = MsgEphemerisGloDepD::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgEphemerisGloDepD(msg)) + } + 20 => { + let mut msg = MsgAcqResultDepB::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgAcqResultDepB(msg)) + } + 21 => { + let mut msg = MsgAcqResultDepA::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgAcqResultDepA(msg)) + } + 46 => { + let mut msg = MsgAcqSvProfile::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgAcqSvProfile(msg)) + } + 30 => { + let mut msg = MsgAcqSvProfileDep::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgAcqSvProfileDep(msg)) + } + 30583 => { + let mut msg = MsgSbasRaw::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgSbasRaw(msg)) + } + 161 => { + let mut msg = MsgSettingsSave::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgSettingsSave(msg)) + } + 160 => { + let mut msg = MsgSettingsWrite::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgSettingsWrite(msg)) + } + 175 => { + let mut msg = MsgSettingsWriteResp::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgSettingsWriteResp(msg)) + } + 164 => { + let mut msg = MsgSettingsReadReq::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgSettingsReadReq(msg)) + } + 165 => { + let mut msg = MsgSettingsReadResp::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgSettingsReadResp(msg)) + } + 162 => { + let mut msg = MsgSettingsReadByIndexReq::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgSettingsReadByIndexReq(msg)) + } + 167 => { + let mut msg = MsgSettingsReadByIndexResp::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgSettingsReadByIndexResp(msg)) + } + 166 => { + let mut msg = MsgSettingsReadByIndexDone::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgSettingsReadByIndexDone(msg)) + } + 174 => { + let mut msg = MsgSettingsRegister::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgSettingsRegister(msg)) + } + 431 => { + let mut msg = MsgSettingsRegisterResp::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgSettingsRegisterResp(msg)) + } + 179 => { + let mut msg = MsgBootloaderHandshakeReq::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgBootloaderHandshakeReq(msg)) + } + 180 => { + let mut msg = MsgBootloaderHandshakeResp::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgBootloaderHandshakeResp(msg)) + } + 177 => { + let mut msg = MsgBootloaderJumpToApp::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgBootloaderJumpToApp(msg)) + } + 222 => { + let mut msg = MsgNapDeviceDnaReq::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgNapDeviceDnaReq(msg)) + } + 221 => { + let mut msg = MsgNapDeviceDnaResp::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgNapDeviceDnaResp(msg)) + } + 176 => { + let mut msg = MsgBootloaderHandshakeDepA::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgBootloaderHandshakeDepA(msg)) + } + 168 => { + let mut msg = MsgFileioReadReq::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgFileioReadReq(msg)) + } + 163 => { + let mut msg = MsgFileioReadResp::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgFileioReadResp(msg)) + } + 169 => { + let mut msg = MsgFileioReadDirReq::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgFileioReadDirReq(msg)) + } + 170 => { + let mut msg = MsgFileioReadDirResp::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgFileioReadDirResp(msg)) + } + 172 => { + let mut msg = MsgFileioRemove::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgFileioRemove(msg)) + } + 173 => { + let mut msg = MsgFileioWriteReq::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgFileioWriteReq(msg)) + } + 171 => { + let mut msg = MsgFileioWriteResp::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgFileioWriteResp(msg)) + } + 4097 => { + let mut msg = MsgFileioConfigReq::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgFileioConfigReq(msg)) + } + 4098 => { + let mut msg = MsgFileioConfigResp::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgFileioConfigResp(msg)) + } + 45 => { + let mut msg = MsgTrackingIq::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgTrackingIq(msg)) + } + 44 => { + let mut msg = MsgTrackingIqDepB::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgTrackingIqDepB(msg)) + } + 28 => { + let mut msg = MsgTrackingIqDepA::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgTrackingIqDepA(msg)) + } + 22 => { + let mut msg = MsgTrackingStateDepA::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgTrackingStateDepA(msg)) + } + 19 => { + let mut msg = MsgTrackingStateDepB::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgTrackingStateDepB(msg)) + } + 1025 => { + let mut msg = MsgLog::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgLog(msg)) + } + 1026 => { + let mut msg = MsgFwd::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgFwd(msg)) + } + 16 => { + let mut msg = MsgPrintDep::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgPrintDep(msg)) + } + 2304 => { + let mut msg = MsgImuRaw::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgImuRaw(msg)) + } + 2305 => { + let mut msg = MsgImuAux::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgImuAux(msg)) + } + 2306 => { + let mut msg = MsgMagRaw::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgMagRaw(msg)) + } + 1501 => { + let mut msg = MsgSsrOrbitClock::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgSsrOrbitClock(msg)) + } + 1500 => { + let mut msg = MsgSsrOrbitClockDepA::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgSsrOrbitClockDepA(msg)) + } + 1505 => { + let mut msg = MsgSsrCodeBiases::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgSsrCodeBiases(msg)) + } + 1510 => { + let mut msg = MsgSsrPhaseBiases::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgSsrPhaseBiases(msg)) + } + 1515 => { + let mut msg = MsgSsrStecCorrection::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgSsrStecCorrection(msg)) + } + 1520 => { + let mut msg = MsgSsrGriddedCorrection::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgSsrGriddedCorrection(msg)) + } + 1525 => { + let mut msg = MsgSsrGridDefinition::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgSsrGridDefinition(msg)) + } + 2048 => { + let mut msg = MsgUserData::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgUserData(msg)) + } + 47 => { + let mut msg = MsgAcqResult::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgAcqResult(msg)) + } + 31 => { + let mut msg = MsgAcqResultDepC::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgAcqResultDepC(msg)) + } + 516 => { + let mut msg = MsgVelECEFDepA::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgVelECEFDepA(msg)) + } + 517 => { + let mut msg = MsgVelNEDDepA::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgVelNEDDepA(msg)) + } + 519 => { + let mut msg = MsgBaselineHeadingDepA::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgBaselineHeadingDepA(msg)) + } + 2307 => { + let mut msg = MsgOdometry::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgOdometry(msg)) + } + 527 => { + let mut msg = MsgBaselineHeading::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgBaselineHeading(msg)) + } + 544 => { + let mut msg = MsgOrientQuat::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgOrientQuat(msg)) + } + 545 => { + let mut msg = MsgOrientEuler::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgOrientEuler(msg)) + } + 546 => { + let mut msg = MsgAngularRate::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgAngularRate(msg)) + } + 33 => { + let mut msg = MsgTrackingStateDetailedDepA::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgTrackingStateDetailedDepA(msg)) + } + 17 => { + let mut msg = MsgTrackingStateDetailedDep::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgTrackingStateDetailedDep(msg)) + } + 65 => { + let mut msg = MsgTrackingState::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgTrackingState(msg)) + } + 97 => { + let mut msg = MsgMeasurementState::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgMeasurementState(msg)) + } + 521 => { + let mut msg = MsgPosECEF::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgPosECEF(msg)) + } + 532 => { + let mut msg = MsgPosECEFCov::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgPosECEFCov(msg)) + } + 522 => { + let mut msg = MsgPosLLH::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgPosLLH(msg)) + } + 529 => { + let mut msg = MsgPosLLHCov::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgPosLLHCov(msg)) + } + 523 => { + let mut msg = MsgBaselineECEF::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgBaselineECEF(msg)) + } + 524 => { + let mut msg = MsgBaselineNED::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgBaselineNED(msg)) + } + 525 => { + let mut msg = MsgVelECEF::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgVelECEF(msg)) + } + 533 => { + let mut msg = MsgVelECEFCov::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgVelECEFCov(msg)) + } + 526 => { + let mut msg = MsgVelNED::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgVelNED(msg)) + } + 530 => { + let mut msg = MsgVelNEDCov::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgVelNEDCov(msg)) + } + 531 => { + let mut msg = MsgVelBody::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgVelBody(msg)) + } + 528 => { + let mut msg = MsgAgeCorrections::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgAgeCorrections(msg)) + } + 256 => { + let mut msg = MsgGPSTimeDepA::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgGPSTimeDepA(msg)) + } + 518 => { + let mut msg = MsgDopsDepA::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgDopsDepA(msg)) + } + 512 => { + let mut msg = MsgPosECEFDepA::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgPosECEFDepA(msg)) + } + 513 => { + let mut msg = MsgPosLLHDepA::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgPosLLHDepA(msg)) + } + 514 => { + let mut msg = MsgBaselineECEFDepA::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgBaselineECEFDepA(msg)) + } + 515 => { + let mut msg = MsgBaselineNEDDepA::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgBaselineNEDDepA(msg)) + } + 150 => { + let mut msg = MsgGnssCapb::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgGnssCapb(msg)) + } + 146 => { + let mut msg = MsgGroupDelayDepA::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgGroupDelayDepA(msg)) + } + 147 => { + let mut msg = MsgGroupDelayDepB::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgGroupDelayDepB(msg)) + } + 148 => { + let mut msg = MsgGroupDelay::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgGroupDelay(msg)) + } + 112 => { + let mut msg = MsgAlmanacGPSDep::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgAlmanacGPSDep(msg)) + } + 114 => { + let mut msg = MsgAlmanacGPS::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgAlmanacGPS(msg)) + } + 113 => { + let mut msg = MsgAlmanacGloDep::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgAlmanacGloDep(msg)) + } + 115 => { + let mut msg = MsgAlmanacGlo::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgAlmanacGlo(msg)) + } + 117 => { + let mut msg = MsgGloBiases::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgGloBiases(msg)) + } + 151 => { + let mut msg = MsgSvAzEl::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgSvAzEl(msg)) + } + 1600 => { + let mut msg = MsgOsr::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgOsr(msg)) + } + 230 => { + let mut msg = MsgFlashProgram::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgFlashProgram(msg)) + } + 224 => { + let mut msg = MsgFlashDone::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgFlashDone(msg)) + } + 231 => { + let mut msg = MsgFlashReadReq::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgFlashReadReq(msg)) + } + 225 => { + let mut msg = MsgFlashReadResp::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgFlashReadResp(msg)) + } + 226 => { + let mut msg = MsgFlashErase::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgFlashErase(msg)) + } + 227 => { + let mut msg = MsgStmFlashLockSector::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgStmFlashLockSector(msg)) + } + 228 => { + let mut msg = MsgStmFlashUnlockSector::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgStmFlashUnlockSector(msg)) + } + 232 => { + let mut msg = MsgStmUniqueIdReq::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgStmUniqueIdReq(msg)) + } + 229 => { + let mut msg = MsgStmUniqueIdResp::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgStmUniqueIdResp(msg)) + } + 243 => { + let mut msg = MsgM25FlashWriteStatus::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgM25FlashWriteStatus(msg)) + } + 258 => { + let mut msg = MsgGPSTime::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgGPSTime(msg)) + } + 259 => { + let mut msg = MsgUtcTime::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgUtcTime(msg)) + } + 520 => { + let mut msg = MsgDops::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgDops(msg)) + } + 139 => { + let mut msg = MsgEphemerisGlo::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgEphemerisGlo(msg)) + } + 128 => { + let mut msg = MsgEphemerisDepD::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgEphemerisDepD(msg)) + } + 26 => { + let mut msg = MsgEphemerisDepA::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgEphemerisDepA(msg)) + } + 70 => { + let mut msg = MsgEphemerisDepB::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgEphemerisDepB(msg)) + } + 71 => { + let mut msg = MsgEphemerisDepC::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgEphemerisDepC(msg)) + } + 69 => { + let mut msg = MsgObsDepA::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgObsDepA(msg)) + } + 67 => { + let mut msg = MsgObsDepB::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgObsDepB(msg)) + } + 73 => { + let mut msg = MsgObsDepC::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgObsDepC(msg)) + } + 144 => { + let mut msg = MsgIono::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgIono(msg)) + } + 145 => { + let mut msg = MsgSvConfigurationGPSDep::parse(payload)?; + msg.set_sender_id(sender_id); + Ok(SBP::MsgSvConfigurationGPSDep(msg)) + } + _ => Ok(SBP::Unknown { + msg_id: msg_id, + sender_id: sender_id, + payload: payload.to_vec(), + }), + }; + match x { + Ok(x) => Ok(x), + Err(_) => Err(::Error::ParseError), + } + } +} diff --git a/rust/sbp/src/messages/navigation.rs b/rust/sbp/src/messages/navigation.rs new file mode 100644 index 0000000000..6f5f60fc09 --- /dev/null +++ b/rust/sbp/src/messages/navigation.rs @@ -0,0 +1,1411 @@ +// Copyright (C) 2015-2018 Swift Navigation Inc. +// Contact: Swift Navigation +// +// This source is subject to the license found in the file 'LICENSE' which must +// be be distributed together with this source. All other rights reserved. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. + +//**************************************************************************** +// Automatically generated from yaml/swiftnav/sbp/navigation.yaml +// with generate.py. Please do not hand edit! +//****************************************************************************/ +//! Geodetic navigation messages reporting GPS time, position, velocity, +//! and baseline position solutions. For position solutions, these +//! messages define several different position solutions: single-point +//! (SPP), RTK, and pseudo-absolute position solutions. +//! +//! The SPP is the standalone, absolute GPS position solution using only +//! a single receiver. The RTK solution is the differential GPS +//! solution, which can use either a fixed/integer or floating carrier +//! phase ambiguity. The pseudo-absolute position solution uses a +//! user-provided, well-surveyed base station position (if available) +//! and the RTK solution in tandem. +//! +//! When the inertial navigation mode indicates that the IMU is used, +//! all messages are reported in the vehicle body frame as defined by +//! device settings. By default, the vehicle body frame is configured to be +//! coincident with the antenna phase center. When there is no inertial +//! navigation, the solution will be reported at the phase center of the antenna. +//! There is no inertial navigation capability on Piksi Multi or Duro. +//! + +extern crate byteorder; +#[allow(unused_imports)] +use self::byteorder::{LittleEndian, ReadBytesExt}; + +/// GPS Time +/// +/// This message reports the GPS time, representing the time since +/// the GPS epoch began on midnight January 6, 1980 UTC. GPS time +/// counts the weeks and seconds of the week. The weeks begin at the +/// Saturday/Sunday transition. GPS week 0 began at the beginning of +/// the GPS time scale. +/// +/// Within each week number, the GPS time of the week is between +/// between 0 and 604800 seconds (=60*60*24*7). Note that GPS time +/// does not accumulate leap seconds, and as of now, has a small +/// offset from UTC. In a message stream, this message precedes a +/// set of other navigation messages referenced to the same time +/// (but lacking the ns field) and indicates a more precise time of +/// these messages. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgGPSTime { + pub sender_id: Option, + /// GPS week number + pub wn: u16, + /// GPS time of week rounded to the nearest millisecond + pub tow: u32, + /// Nanosecond residual of millisecond-rounded TOW (ranges from -500000 to + /// 500000) + pub ns_residual: i32, + /// Status flags (reserved) + pub flags: u8, +} + +impl MsgGPSTime { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgGPSTime { + sender_id: None, + wn: _buf.read_u16::()?, + tow: _buf.read_u32::()?, + ns_residual: _buf.read_i32::()?, + flags: _buf.read_u8()?, + }) + } +} +impl super::SBPMessage for MsgGPSTime { + const MSG_ID: u16 = 258; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// UTC Time +/// +/// This message reports the Universal Coordinated Time (UTC). Note the flags +/// which indicate the source of the UTC offset value and source of the time fix. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgUtcTime { + pub sender_id: Option, + /// Indicates source and time validity + pub flags: u8, + /// GPS time of week rounded to the nearest millisecond + pub tow: u32, + /// Year + pub year: u16, + /// Month (range 1 .. 12) + pub month: u8, + /// days in the month (range 1-31) + pub day: u8, + /// hours of day (range 0-23) + pub hours: u8, + /// minutes of hour (range 0-59) + pub minutes: u8, + /// seconds of minute (range 0-60) rounded down + pub seconds: u8, + /// nanoseconds of second (range 0-999999999) + pub ns: u32, +} + +impl MsgUtcTime { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgUtcTime { + sender_id: None, + flags: _buf.read_u8()?, + tow: _buf.read_u32::()?, + year: _buf.read_u16::()?, + month: _buf.read_u8()?, + day: _buf.read_u8()?, + hours: _buf.read_u8()?, + minutes: _buf.read_u8()?, + seconds: _buf.read_u8()?, + ns: _buf.read_u32::()?, + }) + } +} +impl super::SBPMessage for MsgUtcTime { + const MSG_ID: u16 = 259; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Dilution of Precision +/// +/// This dilution of precision (DOP) message describes the effect of +/// navigation satellite geometry on positional measurement +/// precision. The flags field indicated whether the DOP reported +/// corresponds to differential or SPP solution. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgDops { + pub sender_id: Option, + /// GPS Time of Week + pub tow: u32, + /// Geometric Dilution of Precision + pub gdop: u16, + /// Position Dilution of Precision + pub pdop: u16, + /// Time Dilution of Precision + pub tdop: u16, + /// Horizontal Dilution of Precision + pub hdop: u16, + /// Vertical Dilution of Precision + pub vdop: u16, + /// Indicates the position solution with which the DOPS message corresponds + pub flags: u8, +} + +impl MsgDops { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgDops { + sender_id: None, + tow: _buf.read_u32::()?, + gdop: _buf.read_u16::()?, + pdop: _buf.read_u16::()?, + tdop: _buf.read_u16::()?, + hdop: _buf.read_u16::()?, + vdop: _buf.read_u16::()?, + flags: _buf.read_u8()?, + }) + } +} +impl super::SBPMessage for MsgDops { + const MSG_ID: u16 = 520; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Single-point position in ECEF +/// +/// The position solution message reports absolute Earth Centered +/// Earth Fixed (ECEF) coordinates and the status (single point vs +/// pseudo-absolute RTK) of the position solution. If the rover +/// receiver knows the surveyed position of the base station and has +/// an RTK solution, this reports a pseudo-absolute position +/// solution using the base station position and the rover's RTK +/// baseline vector. The full GPS time is given by the preceding +/// MSG_GPS_TIME with the matching time-of-week (tow). +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgPosECEF { + pub sender_id: Option, + /// GPS Time of Week + pub tow: u32, + /// ECEF X coordinate + pub x: f64, + /// ECEF Y coordinate + pub y: f64, + /// ECEF Z coordinate + pub z: f64, + /// Position estimated standard deviation + pub accuracy: u16, + /// Number of satellites used in solution + pub n_sats: u8, + /// Status flags + pub flags: u8, +} + +impl MsgPosECEF { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgPosECEF { + sender_id: None, + tow: _buf.read_u32::()?, + x: _buf.read_f64::()?, + y: _buf.read_f64::()?, + z: _buf.read_f64::()?, + accuracy: _buf.read_u16::()?, + n_sats: _buf.read_u8()?, + flags: _buf.read_u8()?, + }) + } +} +impl super::SBPMessage for MsgPosECEF { + const MSG_ID: u16 = 521; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Single-point position in ECEF +/// +/// The position solution message reports absolute Earth Centered +/// Earth Fixed (ECEF) coordinates and the status (single point vs +/// pseudo-absolute RTK) of the position solution. The message also +/// reports the upper triangular portion of the 3x3 covariance matrix. +/// If the receiver knows the surveyed position of the base station and has +/// an RTK solution, this reports a pseudo-absolute position +/// solution using the base station position and the rover's RTK +/// baseline vector. The full GPS time is given by the preceding +/// MSG_GPS_TIME with the matching time-of-week (tow). +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgPosECEFCov { + pub sender_id: Option, + /// GPS Time of Week + pub tow: u32, + /// ECEF X coordinate + pub x: f64, + /// ECEF Y coordinate + pub y: f64, + /// ECEF Z coordinate + pub z: f64, + /// Estimated variance of x + pub cov_x_x: f32, + /// Estimated covariance of x and y + pub cov_x_y: f32, + /// Estimated covariance of x and z + pub cov_x_z: f32, + /// Estimated variance of y + pub cov_y_y: f32, + /// Estimated covariance of y and z + pub cov_y_z: f32, + /// Estimated variance of z + pub cov_z_z: f32, + /// Number of satellites used in solution + pub n_sats: u8, + /// Status flags + pub flags: u8, +} + +impl MsgPosECEFCov { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgPosECEFCov { + sender_id: None, + tow: _buf.read_u32::()?, + x: _buf.read_f64::()?, + y: _buf.read_f64::()?, + z: _buf.read_f64::()?, + cov_x_x: _buf.read_f32::()?, + cov_x_y: _buf.read_f32::()?, + cov_x_z: _buf.read_f32::()?, + cov_y_y: _buf.read_f32::()?, + cov_y_z: _buf.read_f32::()?, + cov_z_z: _buf.read_f32::()?, + n_sats: _buf.read_u8()?, + flags: _buf.read_u8()?, + }) + } +} +impl super::SBPMessage for MsgPosECEFCov { + const MSG_ID: u16 = 532; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Geodetic Position +/// +/// This position solution message reports the absolute geodetic +/// coordinates and the status (single point vs pseudo-absolute RTK) +/// of the position solution. If the rover receiver knows the +/// surveyed position of the base station and has an RTK solution, +/// this reports a pseudo-absolute position solution using the base +/// station position and the rover's RTK baseline vector. The full +/// GPS time is given by the preceding MSG_GPS_TIME with the +/// matching time-of-week (tow). +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgPosLLH { + pub sender_id: Option, + /// GPS Time of Week + pub tow: u32, + /// Latitude + pub lat: f64, + /// Longitude + pub lon: f64, + /// Height above WGS84 ellipsoid + pub height: f64, + /// Horizontal position estimated standard deviation + pub h_accuracy: u16, + /// Vertical position estimated standard deviation + pub v_accuracy: u16, + /// Number of satellites used in solution. + pub n_sats: u8, + /// Status flags + pub flags: u8, +} + +impl MsgPosLLH { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgPosLLH { + sender_id: None, + tow: _buf.read_u32::()?, + lat: _buf.read_f64::()?, + lon: _buf.read_f64::()?, + height: _buf.read_f64::()?, + h_accuracy: _buf.read_u16::()?, + v_accuracy: _buf.read_u16::()?, + n_sats: _buf.read_u8()?, + flags: _buf.read_u8()?, + }) + } +} +impl super::SBPMessage for MsgPosLLH { + const MSG_ID: u16 = 522; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Geodetic Position +/// +/// This position solution message reports the absolute geodetic +/// coordinates and the status (single point vs pseudo-absolute RTK) +/// of the position solution as well as the upper triangle of the 3x3 +/// covariance matrix. The position information and Fix Mode flags should +/// follow the MSG_POS_LLH message. Since the covariance matrix is computed +/// in the local-level North, East, Down frame, the covariance terms follow +/// with that convention. Thus, covariances are reported against the "downward" +/// measurement and care should be taken with the sign convention. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgPosLLHCov { + pub sender_id: Option, + /// GPS Time of Week + pub tow: u32, + /// Latitude + pub lat: f64, + /// Longitude + pub lon: f64, + /// Height above WGS84 ellipsoid + pub height: f64, + /// Estimated variance of northing + pub cov_n_n: f32, + /// Covariance of northing and easting + pub cov_n_e: f32, + /// Covariance of northing and downward measurement + pub cov_n_d: f32, + /// Estimated variance of easting + pub cov_e_e: f32, + /// Covariance of easting and downward measurement + pub cov_e_d: f32, + /// Estimated variance of downward measurement + pub cov_d_d: f32, + /// Number of satellites used in solution. + pub n_sats: u8, + /// Status flags + pub flags: u8, +} + +impl MsgPosLLHCov { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgPosLLHCov { + sender_id: None, + tow: _buf.read_u32::()?, + lat: _buf.read_f64::()?, + lon: _buf.read_f64::()?, + height: _buf.read_f64::()?, + cov_n_n: _buf.read_f32::()?, + cov_n_e: _buf.read_f32::()?, + cov_n_d: _buf.read_f32::()?, + cov_e_e: _buf.read_f32::()?, + cov_e_d: _buf.read_f32::()?, + cov_d_d: _buf.read_f32::()?, + n_sats: _buf.read_u8()?, + flags: _buf.read_u8()?, + }) + } +} +impl super::SBPMessage for MsgPosLLHCov { + const MSG_ID: u16 = 529; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Baseline Position in ECEF +/// +/// This message reports the baseline solution in Earth Centered +/// Earth Fixed (ECEF) coordinates. This baseline is the relative +/// vector distance from the base station to the rover receiver. The +/// full GPS time is given by the preceding MSG_GPS_TIME with the +/// matching time-of-week (tow). +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgBaselineECEF { + pub sender_id: Option, + /// GPS Time of Week + pub tow: u32, + /// Baseline ECEF X coordinate + pub x: i32, + /// Baseline ECEF Y coordinate + pub y: i32, + /// Baseline ECEF Z coordinate + pub z: i32, + /// Position estimated standard deviation + pub accuracy: u16, + /// Number of satellites used in solution + pub n_sats: u8, + /// Status flags + pub flags: u8, +} + +impl MsgBaselineECEF { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgBaselineECEF { + sender_id: None, + tow: _buf.read_u32::()?, + x: _buf.read_i32::()?, + y: _buf.read_i32::()?, + z: _buf.read_i32::()?, + accuracy: _buf.read_u16::()?, + n_sats: _buf.read_u8()?, + flags: _buf.read_u8()?, + }) + } +} +impl super::SBPMessage for MsgBaselineECEF { + const MSG_ID: u16 = 523; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Baseline in NED +/// +/// This message reports the baseline solution in North East Down +/// (NED) coordinates. This baseline is the relative vector distance +/// from the base station to the rover receiver, and NED coordinate +/// system is defined at the local WGS84 tangent plane centered at the +/// base station position. The full GPS time is given by the +/// preceding MSG_GPS_TIME with the matching time-of-week (tow). +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgBaselineNED { + pub sender_id: Option, + /// GPS Time of Week + pub tow: u32, + /// Baseline North coordinate + pub n: i32, + /// Baseline East coordinate + pub e: i32, + /// Baseline Down coordinate + pub d: i32, + /// Horizontal position estimated standard deviation + pub h_accuracy: u16, + /// Vertical position estimated standard deviation + pub v_accuracy: u16, + /// Number of satellites used in solution + pub n_sats: u8, + /// Status flags + pub flags: u8, +} + +impl MsgBaselineNED { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgBaselineNED { + sender_id: None, + tow: _buf.read_u32::()?, + n: _buf.read_i32::()?, + e: _buf.read_i32::()?, + d: _buf.read_i32::()?, + h_accuracy: _buf.read_u16::()?, + v_accuracy: _buf.read_u16::()?, + n_sats: _buf.read_u8()?, + flags: _buf.read_u8()?, + }) + } +} +impl super::SBPMessage for MsgBaselineNED { + const MSG_ID: u16 = 524; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Velocity in ECEF +/// +/// This message reports the velocity in Earth Centered Earth Fixed +/// (ECEF) coordinates. The full GPS time is given by the preceding +/// MSG_GPS_TIME with the matching time-of-week (tow). +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgVelECEF { + pub sender_id: Option, + /// GPS Time of Week + pub tow: u32, + /// Velocity ECEF X coordinate + pub x: i32, + /// Velocity ECEF Y coordinate + pub y: i32, + /// Velocity ECEF Z coordinate + pub z: i32, + /// Velocity estimated standard deviation + pub accuracy: u16, + /// Number of satellites used in solution + pub n_sats: u8, + /// Status flags + pub flags: u8, +} + +impl MsgVelECEF { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgVelECEF { + sender_id: None, + tow: _buf.read_u32::()?, + x: _buf.read_i32::()?, + y: _buf.read_i32::()?, + z: _buf.read_i32::()?, + accuracy: _buf.read_u16::()?, + n_sats: _buf.read_u8()?, + flags: _buf.read_u8()?, + }) + } +} +impl super::SBPMessage for MsgVelECEF { + const MSG_ID: u16 = 525; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Velocity in ECEF +/// +/// This message reports the velocity in Earth Centered Earth Fixed +/// (ECEF) coordinates. The full GPS time is given by the preceding +/// MSG_GPS_TIME with the matching time-of-week (tow). +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgVelECEFCov { + pub sender_id: Option, + /// GPS Time of Week + pub tow: u32, + /// Velocity ECEF X coordinate + pub x: i32, + /// Velocity ECEF Y coordinate + pub y: i32, + /// Velocity ECEF Z coordinate + pub z: i32, + /// Estimated variance of x + pub cov_x_x: f32, + /// Estimated covariance of x and y + pub cov_x_y: f32, + /// Estimated covariance of x and z + pub cov_x_z: f32, + /// Estimated variance of y + pub cov_y_y: f32, + /// Estimated covariance of y and z + pub cov_y_z: f32, + /// Estimated variance of z + pub cov_z_z: f32, + /// Number of satellites used in solution + pub n_sats: u8, + /// Status flags + pub flags: u8, +} + +impl MsgVelECEFCov { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgVelECEFCov { + sender_id: None, + tow: _buf.read_u32::()?, + x: _buf.read_i32::()?, + y: _buf.read_i32::()?, + z: _buf.read_i32::()?, + cov_x_x: _buf.read_f32::()?, + cov_x_y: _buf.read_f32::()?, + cov_x_z: _buf.read_f32::()?, + cov_y_y: _buf.read_f32::()?, + cov_y_z: _buf.read_f32::()?, + cov_z_z: _buf.read_f32::()?, + n_sats: _buf.read_u8()?, + flags: _buf.read_u8()?, + }) + } +} +impl super::SBPMessage for MsgVelECEFCov { + const MSG_ID: u16 = 533; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Velocity in NED +/// +/// This message reports the velocity in local North East Down (NED) +/// coordinates. The NED coordinate system is defined as the local WGS84 +/// tangent plane centered at the current position. The full GPS time is +/// given by the preceding MSG_GPS_TIME with the matching time-of-week (tow). +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgVelNED { + pub sender_id: Option, + /// GPS Time of Week + pub tow: u32, + /// Velocity North coordinate + pub n: i32, + /// Velocity East coordinate + pub e: i32, + /// Velocity Down coordinate + pub d: i32, + /// Horizontal velocity estimated standard deviation + pub h_accuracy: u16, + /// Vertical velocity estimated standard deviation + pub v_accuracy: u16, + /// Number of satellites used in solution + pub n_sats: u8, + /// Status flags + pub flags: u8, +} + +impl MsgVelNED { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgVelNED { + sender_id: None, + tow: _buf.read_u32::()?, + n: _buf.read_i32::()?, + e: _buf.read_i32::()?, + d: _buf.read_i32::()?, + h_accuracy: _buf.read_u16::()?, + v_accuracy: _buf.read_u16::()?, + n_sats: _buf.read_u8()?, + flags: _buf.read_u8()?, + }) + } +} +impl super::SBPMessage for MsgVelNED { + const MSG_ID: u16 = 526; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Velocity in NED +/// +/// This message reports the velocity in local North East Down (NED) +/// coordinates. The NED coordinate system is defined as the local WGS84 +/// tangent plane centered at the current position. The full GPS time is +/// given by the preceding MSG_GPS_TIME with the matching time-of-week (tow). +/// This message is similar to the MSG_VEL_NED, but it includes the upper triangular +/// portion of the 3x3 covariance matrix. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgVelNEDCov { + pub sender_id: Option, + /// GPS Time of Week + pub tow: u32, + /// Velocity North coordinate + pub n: i32, + /// Velocity East coordinate + pub e: i32, + /// Velocity Down coordinate + pub d: i32, + /// Estimated variance of northward measurement + pub cov_n_n: f32, + /// Covariance of northward and eastward measurement + pub cov_n_e: f32, + /// Covariance of northward and downward measurement + pub cov_n_d: f32, + /// Estimated variance of eastward measurement + pub cov_e_e: f32, + /// Covariance of eastward and downward measurement + pub cov_e_d: f32, + /// Estimated variance of downward measurement + pub cov_d_d: f32, + /// Number of satellites used in solution + pub n_sats: u8, + /// Status flags + pub flags: u8, +} + +impl MsgVelNEDCov { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgVelNEDCov { + sender_id: None, + tow: _buf.read_u32::()?, + n: _buf.read_i32::()?, + e: _buf.read_i32::()?, + d: _buf.read_i32::()?, + cov_n_n: _buf.read_f32::()?, + cov_n_e: _buf.read_f32::()?, + cov_n_d: _buf.read_f32::()?, + cov_e_e: _buf.read_f32::()?, + cov_e_d: _buf.read_f32::()?, + cov_d_d: _buf.read_f32::()?, + n_sats: _buf.read_u8()?, + flags: _buf.read_u8()?, + }) + } +} +impl super::SBPMessage for MsgVelNEDCov { + const MSG_ID: u16 = 530; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Velocity in User Frame +/// +/// This message reports the velocity in the Vehicle Body Frame. By convention, +/// the x-axis should point out the nose of the vehicle and represent the forward +/// direction, while as the y-axis should point out the right hand side of the vehicle. +/// Since this is a right handed system, z should point out the bottom of the vehicle. +/// The orientation and origin of the Vehicle Body Frame are specified via the device settings. +/// The full GPS time is given by the preceding MSG_GPS_TIME with the +/// matching time-of-week (tow). This message is only produced by inertial versions of Swift +/// products and is not available from Piksi Multi or Duro. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgVelBody { + pub sender_id: Option, + /// GPS Time of Week + pub tow: u32, + /// Velocity in x direction + pub x: i32, + /// Velocity in y direction + pub y: i32, + /// Velocity in z direction + pub z: i32, + /// Estimated variance of x + pub cov_x_x: f32, + /// Covariance of x and y + pub cov_x_y: f32, + /// Covariance of x and z + pub cov_x_z: f32, + /// Estimated variance of y + pub cov_y_y: f32, + /// Covariance of y and z + pub cov_y_z: f32, + /// Estimated variance of z + pub cov_z_z: f32, + /// Number of satellites used in solution + pub n_sats: u8, + /// Status flags + pub flags: u8, +} + +impl MsgVelBody { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgVelBody { + sender_id: None, + tow: _buf.read_u32::()?, + x: _buf.read_i32::()?, + y: _buf.read_i32::()?, + z: _buf.read_i32::()?, + cov_x_x: _buf.read_f32::()?, + cov_x_y: _buf.read_f32::()?, + cov_x_z: _buf.read_f32::()?, + cov_y_y: _buf.read_f32::()?, + cov_y_z: _buf.read_f32::()?, + cov_z_z: _buf.read_f32::()?, + n_sats: _buf.read_u8()?, + flags: _buf.read_u8()?, + }) + } +} +impl super::SBPMessage for MsgVelBody { + const MSG_ID: u16 = 531; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Age of corrections +/// +/// This message reports the Age of the corrections used for the current +/// Differential solution +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgAgeCorrections { + pub sender_id: Option, + /// GPS Time of Week + pub tow: u32, + /// Age of the corrections (0xFFFF indicates invalid) + pub age: u16, +} + +impl MsgAgeCorrections { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgAgeCorrections { + sender_id: None, + tow: _buf.read_u32::()?, + age: _buf.read_u16::()?, + }) + } +} +impl super::SBPMessage for MsgAgeCorrections { + const MSG_ID: u16 = 528; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// GPS Time (v1.0) +/// +/// This message reports the GPS time, representing the time since +/// the GPS epoch began on midnight January 6, 1980 UTC. GPS time +/// counts the weeks and seconds of the week. The weeks begin at the +/// Saturday/Sunday transition. GPS week 0 began at the beginning of +/// the GPS time scale. +/// +/// Within each week number, the GPS time of the week is between +/// between 0 and 604800 seconds (=60*60*24*7). Note that GPS time +/// does not accumulate leap seconds, and as of now, has a small +/// offset from UTC. In a message stream, this message precedes a +/// set of other navigation messages referenced to the same time +/// (but lacking the ns field) and indicates a more precise time of +/// these messages. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgGPSTimeDepA { + pub sender_id: Option, + /// GPS week number + pub wn: u16, + /// GPS time of week rounded to the nearest millisecond + pub tow: u32, + /// Nanosecond residual of millisecond-rounded TOW (ranges from -500000 to + /// 500000) + pub ns_residual: i32, + /// Status flags (reserved) + pub flags: u8, +} + +impl MsgGPSTimeDepA { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgGPSTimeDepA { + sender_id: None, + wn: _buf.read_u16::()?, + tow: _buf.read_u32::()?, + ns_residual: _buf.read_i32::()?, + flags: _buf.read_u8()?, + }) + } +} +impl super::SBPMessage for MsgGPSTimeDepA { + const MSG_ID: u16 = 256; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Dilution of Precision +/// +/// This dilution of precision (DOP) message describes the effect of +/// navigation satellite geometry on positional measurement +/// precision. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgDopsDepA { + pub sender_id: Option, + /// GPS Time of Week + pub tow: u32, + /// Geometric Dilution of Precision + pub gdop: u16, + /// Position Dilution of Precision + pub pdop: u16, + /// Time Dilution of Precision + pub tdop: u16, + /// Horizontal Dilution of Precision + pub hdop: u16, + /// Vertical Dilution of Precision + pub vdop: u16, +} + +impl MsgDopsDepA { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgDopsDepA { + sender_id: None, + tow: _buf.read_u32::()?, + gdop: _buf.read_u16::()?, + pdop: _buf.read_u16::()?, + tdop: _buf.read_u16::()?, + hdop: _buf.read_u16::()?, + vdop: _buf.read_u16::()?, + }) + } +} +impl super::SBPMessage for MsgDopsDepA { + const MSG_ID: u16 = 518; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Single-point position in ECEF +/// +/// The position solution message reports absolute Earth Centered +/// Earth Fixed (ECEF) coordinates and the status (single point vs +/// pseudo-absolute RTK) of the position solution. If the rover +/// receiver knows the surveyed position of the base station and has +/// an RTK solution, this reports a pseudo-absolute position +/// solution using the base station position and the rover's RTK +/// baseline vector. The full GPS time is given by the preceding +/// MSG_GPS_TIME with the matching time-of-week (tow). +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgPosECEFDepA { + pub sender_id: Option, + /// GPS Time of Week + pub tow: u32, + /// ECEF X coordinate + pub x: f64, + /// ECEF Y coordinate + pub y: f64, + /// ECEF Z coordinate + pub z: f64, + /// Position accuracy estimate (not implemented). Defaults to 0. + pub accuracy: u16, + /// Number of satellites used in solution + pub n_sats: u8, + /// Status flags + pub flags: u8, +} + +impl MsgPosECEFDepA { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgPosECEFDepA { + sender_id: None, + tow: _buf.read_u32::()?, + x: _buf.read_f64::()?, + y: _buf.read_f64::()?, + z: _buf.read_f64::()?, + accuracy: _buf.read_u16::()?, + n_sats: _buf.read_u8()?, + flags: _buf.read_u8()?, + }) + } +} +impl super::SBPMessage for MsgPosECEFDepA { + const MSG_ID: u16 = 512; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Geodetic Position +/// +/// This position solution message reports the absolute geodetic +/// coordinates and the status (single point vs pseudo-absolute RTK) +/// of the position solution. If the rover receiver knows the +/// surveyed position of the base station and has an RTK solution, +/// this reports a pseudo-absolute position solution using the base +/// station position and the rover's RTK baseline vector. The full +/// GPS time is given by the preceding MSG_GPS_TIME with the +/// matching time-of-week (tow). +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgPosLLHDepA { + pub sender_id: Option, + /// GPS Time of Week + pub tow: u32, + /// Latitude + pub lat: f64, + /// Longitude + pub lon: f64, + /// Height + pub height: f64, + /// Horizontal position accuracy estimate (not implemented). Defaults to 0. + pub h_accuracy: u16, + /// Vertical position accuracy estimate (not implemented). Defaults to 0. + pub v_accuracy: u16, + /// Number of satellites used in solution. + pub n_sats: u8, + /// Status flags + pub flags: u8, +} + +impl MsgPosLLHDepA { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgPosLLHDepA { + sender_id: None, + tow: _buf.read_u32::()?, + lat: _buf.read_f64::()?, + lon: _buf.read_f64::()?, + height: _buf.read_f64::()?, + h_accuracy: _buf.read_u16::()?, + v_accuracy: _buf.read_u16::()?, + n_sats: _buf.read_u8()?, + flags: _buf.read_u8()?, + }) + } +} +impl super::SBPMessage for MsgPosLLHDepA { + const MSG_ID: u16 = 513; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Baseline Position in ECEF +/// +/// This message reports the baseline solution in Earth Centered +/// Earth Fixed (ECEF) coordinates. This baseline is the relative +/// vector distance from the base station to the rover receiver. The +/// full GPS time is given by the preceding MSG_GPS_TIME with the +/// matching time-of-week (tow). +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgBaselineECEFDepA { + pub sender_id: Option, + /// GPS Time of Week + pub tow: u32, + /// Baseline ECEF X coordinate + pub x: i32, + /// Baseline ECEF Y coordinate + pub y: i32, + /// Baseline ECEF Z coordinate + pub z: i32, + /// Position accuracy estimate + pub accuracy: u16, + /// Number of satellites used in solution + pub n_sats: u8, + /// Status flags + pub flags: u8, +} + +impl MsgBaselineECEFDepA { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgBaselineECEFDepA { + sender_id: None, + tow: _buf.read_u32::()?, + x: _buf.read_i32::()?, + y: _buf.read_i32::()?, + z: _buf.read_i32::()?, + accuracy: _buf.read_u16::()?, + n_sats: _buf.read_u8()?, + flags: _buf.read_u8()?, + }) + } +} +impl super::SBPMessage for MsgBaselineECEFDepA { + const MSG_ID: u16 = 514; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Baseline in NED +/// +/// This message reports the baseline solution in North East Down +/// (NED) coordinates. This baseline is the relative vector distance +/// from the base station to the rover receiver, and NED coordinate +/// system is defined at the local WGS84 tangent plane centered at the +/// base station position. The full GPS time is given by the +/// preceding MSG_GPS_TIME with the matching time-of-week (tow). +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgBaselineNEDDepA { + pub sender_id: Option, + /// GPS Time of Week + pub tow: u32, + /// Baseline North coordinate + pub n: i32, + /// Baseline East coordinate + pub e: i32, + /// Baseline Down coordinate + pub d: i32, + /// Horizontal position accuracy estimate (not implemented). Defaults to 0. + pub h_accuracy: u16, + /// Vertical position accuracy estimate (not implemented). Defaults to 0. + pub v_accuracy: u16, + /// Number of satellites used in solution + pub n_sats: u8, + /// Status flags + pub flags: u8, +} + +impl MsgBaselineNEDDepA { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgBaselineNEDDepA { + sender_id: None, + tow: _buf.read_u32::()?, + n: _buf.read_i32::()?, + e: _buf.read_i32::()?, + d: _buf.read_i32::()?, + h_accuracy: _buf.read_u16::()?, + v_accuracy: _buf.read_u16::()?, + n_sats: _buf.read_u8()?, + flags: _buf.read_u8()?, + }) + } +} +impl super::SBPMessage for MsgBaselineNEDDepA { + const MSG_ID: u16 = 515; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Velocity in ECEF +/// +/// This message reports the velocity in Earth Centered Earth Fixed +/// (ECEF) coordinates. The full GPS time is given by the preceding +/// MSG_GPS_TIME with the matching time-of-week (tow). +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgVelECEFDepA { + pub sender_id: Option, + /// GPS Time of Week + pub tow: u32, + /// Velocity ECEF X coordinate + pub x: i32, + /// Velocity ECEF Y coordinate + pub y: i32, + /// Velocity ECEF Z coordinate + pub z: i32, + /// Velocity accuracy estimate (not implemented). Defaults to 0. + pub accuracy: u16, + /// Number of satellites used in solution + pub n_sats: u8, + /// Status flags (reserved) + pub flags: u8, +} + +impl MsgVelECEFDepA { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgVelECEFDepA { + sender_id: None, + tow: _buf.read_u32::()?, + x: _buf.read_i32::()?, + y: _buf.read_i32::()?, + z: _buf.read_i32::()?, + accuracy: _buf.read_u16::()?, + n_sats: _buf.read_u8()?, + flags: _buf.read_u8()?, + }) + } +} +impl super::SBPMessage for MsgVelECEFDepA { + const MSG_ID: u16 = 516; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Velocity in NED +/// +/// This message reports the velocity in local North East Down (NED) +/// coordinates. The NED coordinate system is defined as the local WGS84 +/// tangent plane centered at the current position. The full GPS time is +/// given by the preceding MSG_GPS_TIME with the matching time-of-week (tow). +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgVelNEDDepA { + pub sender_id: Option, + /// GPS Time of Week + pub tow: u32, + /// Velocity North coordinate + pub n: i32, + /// Velocity East coordinate + pub e: i32, + /// Velocity Down coordinate + pub d: i32, + /// Horizontal velocity accuracy estimate (not implemented). Defaults to 0. + pub h_accuracy: u16, + /// Vertical velocity accuracy estimate (not implemented). Defaults to 0. + pub v_accuracy: u16, + /// Number of satellites used in solution + pub n_sats: u8, + /// Status flags (reserved) + pub flags: u8, +} + +impl MsgVelNEDDepA { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgVelNEDDepA { + sender_id: None, + tow: _buf.read_u32::()?, + n: _buf.read_i32::()?, + e: _buf.read_i32::()?, + d: _buf.read_i32::()?, + h_accuracy: _buf.read_u16::()?, + v_accuracy: _buf.read_u16::()?, + n_sats: _buf.read_u8()?, + flags: _buf.read_u8()?, + }) + } +} +impl super::SBPMessage for MsgVelNEDDepA { + const MSG_ID: u16 = 517; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Heading relative to True North +/// +/// This message reports the baseline heading pointing from the base station +/// to the rover relative to True North. The full GPS time is given by the +/// preceding MSG_GPS_TIME with the matching time-of-week (tow). +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgBaselineHeadingDepA { + pub sender_id: Option, + /// GPS Time of Week + pub tow: u32, + /// Heading + pub heading: u32, + /// Number of satellites used in solution + pub n_sats: u8, + /// Status flags + pub flags: u8, +} + +impl MsgBaselineHeadingDepA { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgBaselineHeadingDepA { + sender_id: None, + tow: _buf.read_u32::()?, + heading: _buf.read_u32::()?, + n_sats: _buf.read_u8()?, + flags: _buf.read_u8()?, + }) + } +} +impl super::SBPMessage for MsgBaselineHeadingDepA { + const MSG_ID: u16 = 519; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} diff --git a/rust/sbp/src/messages/ndb.rs b/rust/sbp/src/messages/ndb.rs new file mode 100644 index 0000000000..936b045c48 --- /dev/null +++ b/rust/sbp/src/messages/ndb.rs @@ -0,0 +1,81 @@ +// Copyright (C) 2015-2018 Swift Navigation Inc. +// Contact: Swift Navigation +// +// This source is subject to the license found in the file 'LICENSE' which must +// be be distributed together with this source. All other rights reserved. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. + +//**************************************************************************** +// Automatically generated from yaml/swiftnav/sbp/ndb.yaml +// with generate.py. Please do not hand edit! +//****************************************************************************/ +//! Messages for logging NDB events. +//! + +extern crate byteorder; +#[allow(unused_imports)] +use self::byteorder::{LittleEndian, ReadBytesExt}; +use super::gnss::*; + +/// Navigation DataBase Event +/// +/// This message is sent out when an object is stored into NDB. If needed +/// message could also be sent out when fetching an object from NDB. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgNdbEvent { + pub sender_id: Option, + /// HW time in milliseconds. + pub recv_time: u64, + /// Event type. + pub event: u8, + /// Event object type. + pub object_type: u8, + /// Event result. + pub result: u8, + /// Data source for STORE event, reserved for other events. + pub data_source: u8, + /// GNSS signal identifier, If object_type is Ephemeris OR Almanac, sid + /// indicates for which signal the object belongs to. Reserved in other + /// cases. + pub object_sid: GnssSignal, + /// GNSS signal identifier, If object_type is Almanac, Almanac WN, Iono OR + /// L2C capabilities AND data_source is NDB_DS_RECEIVER sid indicates from + /// which SV data was decoded. Reserved in other cases. + pub src_sid: GnssSignal, + /// A unique identifier of the sending hardware. For v1.0, set to the 2 + /// least significant bytes of the device serial number, valid only if + /// data_source is NDB_DS_SBP. Reserved in case of other data_source. + pub original_sender: u16, +} + +impl MsgNdbEvent { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgNdbEvent { + sender_id: None, + recv_time: _buf.read_u64::()?, + event: _buf.read_u8()?, + object_type: _buf.read_u8()?, + result: _buf.read_u8()?, + data_source: _buf.read_u8()?, + object_sid: GnssSignal::parse(_buf)?, + src_sid: GnssSignal::parse(_buf)?, + original_sender: _buf.read_u16::()?, + }) + } +} +impl super::SBPMessage for MsgNdbEvent { + const MSG_ID: u16 = 1024; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} diff --git a/rust/sbp/src/messages/observation.rs b/rust/sbp/src/messages/observation.rs new file mode 100644 index 0000000000..54be91f833 --- /dev/null +++ b/rust/sbp/src/messages/observation.rs @@ -0,0 +1,3309 @@ +// Copyright (C) 2015-2018 Swift Navigation Inc. +// Contact: Swift Navigation +// +// This source is subject to the license found in the file 'LICENSE' which must +// be be distributed together with this source. All other rights reserved. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. + +//**************************************************************************** +// Automatically generated from yaml/swiftnav/sbp/observation.yaml +// with generate.py. Please do not hand edit! +//****************************************************************************/ +//! Satellite observation messages from the device. + +extern crate byteorder; +#[allow(unused_imports)] +use self::byteorder::{LittleEndian, ReadBytesExt}; +use super::gnss::*; + +/// Header for observation message. +/// +/// Header of a GNSS observation message. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct ObservationHeader { + /// GNSS time of this observation + pub t: GPSTime, + /// Total number of observations. First nibble is the size of the sequence + /// (n), second nibble is the zero-indexed counter (ith packet of n) + pub n_obs: u8, +} + +impl ObservationHeader { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(ObservationHeader { + t: GPSTime::parse(_buf)?, + n_obs: _buf.read_u8()?, + }) + } + pub fn parse_array(buf: &mut &[u8]) -> Result, ::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(ObservationHeader::parse(buf)?); + } + Ok(v) + } + + pub fn parse_array_limit(buf: &mut &[u8], n: usize) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(ObservationHeader::parse(buf)?); + } + Ok(v) + } +} + +/// GNSS doppler measurement. +/// +/// Doppler measurement in Hz represented as a 24-bit +/// fixed point number with Q16.8 layout, i.e. 16-bits of whole +/// doppler and 8-bits of fractional doppler. This doppler is defined +/// as positive for approaching satellites. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct Doppler { + /// Doppler whole Hz + pub i: i16, + /// Doppler fractional part + pub f: u8, +} + +impl Doppler { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(Doppler { + i: _buf.read_i16::()?, + f: _buf.read_u8()?, + }) + } + pub fn parse_array(buf: &mut &[u8]) -> Result, ::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(Doppler::parse(buf)?); + } + Ok(v) + } + + pub fn parse_array_limit(buf: &mut &[u8], n: usize) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(Doppler::parse(buf)?); + } + Ok(v) + } +} + +/// GNSS observations for a particular satellite signal. +/// +/// Pseudorange and carrier phase observation for a satellite being tracked. +/// The observations are interoperable with 3rd party receivers and conform with +/// typical RTCM 3.1 message GPS/GLO observations. +/// +/// Carrier phase observations are not guaranteed to be aligned to the RINEX 3 +/// or RTCM 3.3 MSM reference signal and no 1/4 cycle adjustments are currently +/// peformed. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct PackedObsContent { + /// Pseudorange observation + pub P: u32, + /// Carrier phase observation with typical sign convention. + pub L: CarrierPhase, + /// Doppler observation with typical sign convention. + pub D: Doppler, + /// Carrier-to-Noise density. Zero implies invalid cn0. + pub cn0: u8, + /// Lock timer. This value gives an indication of the time for which a + /// signal has maintained continuous phase lock. Whenever a signal has lost + /// and regained lock, this value is reset to zero. It is encoded according + /// to DF402 from the RTCM 10403.2 Amendment 2 specification. Valid values + /// range from 0 to 15 and the most significant nibble is reserved for + /// future use. + pub lock: u8, + /// Measurement status flags. A bit field of flags providing the status of + /// this observation. If this field is 0 it means only the Cn0 estimate for + /// the signal is valid. + pub flags: u8, + /// GNSS signal identifier (16 bit) + pub sid: GnssSignal, +} + +impl PackedObsContent { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(PackedObsContent { + P: _buf.read_u32::()?, + L: CarrierPhase::parse(_buf)?, + D: Doppler::parse(_buf)?, + cn0: _buf.read_u8()?, + lock: _buf.read_u8()?, + flags: _buf.read_u8()?, + sid: GnssSignal::parse(_buf)?, + }) + } + pub fn parse_array(buf: &mut &[u8]) -> Result, ::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(PackedObsContent::parse(buf)?); + } + Ok(v) + } + + pub fn parse_array_limit(buf: &mut &[u8], n: usize) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(PackedObsContent::parse(buf)?); + } + Ok(v) + } +} + +/// Network correction for a particular satellite signal. +/// +/// Pseudorange and carrier phase network corrections for a satellite signal. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct PackedOsrContent { + /// Pseudorange observation + pub P: u32, + /// Carrier phase observation with typical sign convention. + pub L: CarrierPhase, + /// Lock timer. This value gives an indication of the time for which a + /// signal has maintained continuous phase lock. Whenever a signal has lost + /// and regained lock, this value is reset to zero. It is encoded according + /// to DF402 from the RTCM 10403.2 Amendment 2 specification. Valid values + /// range from 0 to 15 and the most significant nibble is reserved for + /// future use. + pub lock: u8, + /// Correction flags. + pub flags: u8, + /// GNSS signal identifier (16 bit) + pub sid: GnssSignal, + /// Slant ionospheric correction standard deviation + pub iono_std: u16, + /// Slant tropospheric correction standard deviation + pub tropo_std: u16, + /// Orbit/clock/bias correction projected on range standard deviation + pub range_std: u16, +} + +impl PackedOsrContent { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(PackedOsrContent { + P: _buf.read_u32::()?, + L: CarrierPhase::parse(_buf)?, + lock: _buf.read_u8()?, + flags: _buf.read_u8()?, + sid: GnssSignal::parse(_buf)?, + iono_std: _buf.read_u16::()?, + tropo_std: _buf.read_u16::()?, + range_std: _buf.read_u16::()?, + }) + } + pub fn parse_array(buf: &mut &[u8]) -> Result, ::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(PackedOsrContent::parse(buf)?); + } + Ok(v) + } + + pub fn parse_array_limit(buf: &mut &[u8], n: usize) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(PackedOsrContent::parse(buf)?); + } + Ok(v) + } +} + +/// GPS satellite observations +/// +/// The GPS observations message reports all the raw pseudorange and +/// carrier phase observations for the satellites being tracked by +/// the device. Carrier phase observation here is represented as a +/// 40-bit fixed point number with Q32.8 layout (i.e. 32-bits of +/// whole cycles and 8-bits of fractional cycles). The observations +/// are be interoperable with 3rd party receivers and conform +/// with typical RTCMv3 GNSS observations. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgObs { + pub sender_id: Option, + /// Header of a GPS observation message + pub header: ObservationHeader, + /// Pseudorange and carrier phase observation for a satellite being tracked. + pub obs: Vec, +} + +impl MsgObs { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgObs { + sender_id: None, + header: ObservationHeader::parse(_buf)?, + obs: PackedObsContent::parse_array(_buf)?, + }) + } +} +impl super::SBPMessage for MsgObs { + const MSG_ID: u16 = 74; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Base station position +/// +/// The base station position message is the position reported by +/// the base station itself. It is used for pseudo-absolute RTK +/// positioning, and is required to be a high-accuracy surveyed +/// location of the base station. Any error here will result in an +/// error in the pseudo-absolute position output. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgBasePosLLH { + pub sender_id: Option, + /// Latitude + pub lat: f64, + /// Longitude + pub lon: f64, + /// Height + pub height: f64, +} + +impl MsgBasePosLLH { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgBasePosLLH { + sender_id: None, + lat: _buf.read_f64::()?, + lon: _buf.read_f64::()?, + height: _buf.read_f64::()?, + }) + } +} +impl super::SBPMessage for MsgBasePosLLH { + const MSG_ID: u16 = 68; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Base station position in ECEF +/// +/// The base station position message is the position reported by +/// the base station itself in absolute Earth Centered Earth Fixed +/// coordinates. It is used for pseudo-absolute RTK positioning, and +/// is required to be a high-accuracy surveyed location of the base +/// station. Any error here will result in an error in the +/// pseudo-absolute position output. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgBasePosECEF { + pub sender_id: Option, + /// ECEF X coodinate + pub x: f64, + /// ECEF Y coordinate + pub y: f64, + /// ECEF Z coordinate + pub z: f64, +} + +impl MsgBasePosECEF { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgBasePosECEF { + sender_id: None, + x: _buf.read_f64::()?, + y: _buf.read_f64::()?, + z: _buf.read_f64::()?, + }) + } +} +impl super::SBPMessage for MsgBasePosECEF { + const MSG_ID: u16 = 72; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct EphemerisCommonContent { + /// GNSS signal identifier (16 bit) + pub sid: GnssSignal, + /// Time of Ephemerides + pub toe: GPSTimeSec, + /// User Range Accuracy + pub ura: f32, + /// Curve fit interval + pub fit_interval: u32, + /// Status of ephemeris, 1 = valid, 0 = invalid + pub valid: u8, + /// Satellite health status. GPS: ICD-GPS-200, chapter 20.3.3.3.1.4 SBAS: 0 + /// = valid, non-zero = invalid GLO: 0 = valid, non-zero = invalid + pub health_bits: u8, +} + +impl EphemerisCommonContent { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(EphemerisCommonContent { + sid: GnssSignal::parse(_buf)?, + toe: GPSTimeSec::parse(_buf)?, + ura: _buf.read_f32::()?, + fit_interval: _buf.read_u32::()?, + valid: _buf.read_u8()?, + health_bits: _buf.read_u8()?, + }) + } + pub fn parse_array(buf: &mut &[u8]) -> Result, ::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(EphemerisCommonContent::parse(buf)?); + } + Ok(v) + } + + pub fn parse_array_limit( + buf: &mut &[u8], + n: usize, + ) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(EphemerisCommonContent::parse(buf)?); + } + Ok(v) + } +} + +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct EphemerisCommonContentDepB { + /// GNSS signal identifier (16 bit) + pub sid: GnssSignal, + /// Time of Ephemerides + pub toe: GPSTimeSec, + /// User Range Accuracy + pub ura: f64, + /// Curve fit interval + pub fit_interval: u32, + /// Status of ephemeris, 1 = valid, 0 = invalid + pub valid: u8, + /// Satellite health status. GPS: ICD-GPS-200, chapter 20.3.3.3.1.4 Others: + /// 0 = valid, non-zero = invalid + pub health_bits: u8, +} + +impl EphemerisCommonContentDepB { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(EphemerisCommonContentDepB { + sid: GnssSignal::parse(_buf)?, + toe: GPSTimeSec::parse(_buf)?, + ura: _buf.read_f64::()?, + fit_interval: _buf.read_u32::()?, + valid: _buf.read_u8()?, + health_bits: _buf.read_u8()?, + }) + } + pub fn parse_array(buf: &mut &[u8]) -> Result, ::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(EphemerisCommonContentDepB::parse(buf)?); + } + Ok(v) + } + + pub fn parse_array_limit( + buf: &mut &[u8], + n: usize, + ) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(EphemerisCommonContentDepB::parse(buf)?); + } + Ok(v) + } +} + +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct EphemerisCommonContentDepA { + /// GNSS signal identifier + pub sid: GnssSignalDep, + /// Time of Ephemerides + pub toe: GPSTimeDep, + /// User Range Accuracy + pub ura: f64, + /// Curve fit interval + pub fit_interval: u32, + /// Status of ephemeris, 1 = valid, 0 = invalid + pub valid: u8, + /// Satellite health status. GPS: ICD-GPS-200, chapter 20.3.3.3.1.4 SBAS: 0 + /// = valid, non-zero = invalid GLO: 0 = valid, non-zero = invalid + pub health_bits: u8, +} + +impl EphemerisCommonContentDepA { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(EphemerisCommonContentDepA { + sid: GnssSignalDep::parse(_buf)?, + toe: GPSTimeDep::parse(_buf)?, + ura: _buf.read_f64::()?, + fit_interval: _buf.read_u32::()?, + valid: _buf.read_u8()?, + health_bits: _buf.read_u8()?, + }) + } + pub fn parse_array(buf: &mut &[u8]) -> Result, ::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(EphemerisCommonContentDepA::parse(buf)?); + } + Ok(v) + } + + pub fn parse_array_limit( + buf: &mut &[u8], + n: usize, + ) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(EphemerisCommonContentDepA::parse(buf)?); + } + Ok(v) + } +} + +/// Satellite broadcast ephemeris for GPS +/// +/// The ephemeris message returns a set of satellite orbit +/// parameters that is used to calculate GPS satellite position, +/// velocity, and clock offset. Please see the Navstar GPS +/// Space Segment/Navigation user interfaces (ICD-GPS-200, Table +/// 20-III) for more details. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgEphemerisGPSDepE { + pub sender_id: Option, + /// Values common for all ephemeris types + pub common: EphemerisCommonContentDepA, + /// Group delay differential between L1 and L2 + pub tgd: f64, + /// Amplitude of the sine harmonic correction term to the orbit radius + pub c_rs: f64, + /// Amplitude of the cosine harmonic correction term to the orbit radius + pub c_rc: f64, + /// Amplitude of the cosine harmonic correction term to the argument of + /// latitude + pub c_uc: f64, + /// Amplitude of the sine harmonic correction term to the argument of + /// latitude + pub c_us: f64, + /// Amplitude of the cosine harmonic correction term to the angle of + /// inclination + pub c_ic: f64, + /// Amplitude of the sine harmonic correction term to the angle of + /// inclination + pub c_is: f64, + /// Mean motion difference + pub dn: f64, + /// Mean anomaly at reference time + pub m0: f64, + /// Eccentricity of satellite orbit + pub ecc: f64, + /// Square root of the semi-major axis of orbit + pub sqrta: f64, + /// Longitude of ascending node of orbit plane at weekly epoch + pub omega0: f64, + /// Rate of right ascension + pub omegadot: f64, + /// Argument of perigee + pub w: f64, + /// Inclination + pub inc: f64, + /// Inclination first derivative + pub inc_dot: f64, + /// Polynomial clock correction coefficient (clock bias) + pub af0: f64, + /// Polynomial clock correction coefficient (clock drift) + pub af1: f64, + /// Polynomial clock correction coefficient (rate of clock drift) + pub af2: f64, + /// Clock reference + pub toc: GPSTimeDep, + /// Issue of ephemeris data + pub iode: u8, + /// Issue of clock data + pub iodc: u16, +} + +impl MsgEphemerisGPSDepE { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgEphemerisGPSDepE { + sender_id: None, + common: EphemerisCommonContentDepA::parse(_buf)?, + tgd: _buf.read_f64::()?, + c_rs: _buf.read_f64::()?, + c_rc: _buf.read_f64::()?, + c_uc: _buf.read_f64::()?, + c_us: _buf.read_f64::()?, + c_ic: _buf.read_f64::()?, + c_is: _buf.read_f64::()?, + dn: _buf.read_f64::()?, + m0: _buf.read_f64::()?, + ecc: _buf.read_f64::()?, + sqrta: _buf.read_f64::()?, + omega0: _buf.read_f64::()?, + omegadot: _buf.read_f64::()?, + w: _buf.read_f64::()?, + inc: _buf.read_f64::()?, + inc_dot: _buf.read_f64::()?, + af0: _buf.read_f64::()?, + af1: _buf.read_f64::()?, + af2: _buf.read_f64::()?, + toc: GPSTimeDep::parse(_buf)?, + iode: _buf.read_u8()?, + iodc: _buf.read_u16::()?, + }) + } +} +impl super::SBPMessage for MsgEphemerisGPSDepE { + const MSG_ID: u16 = 129; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Deprecated +/// +/// This observation message has been deprecated in favor of +/// ephemeris message using floats for size reduction. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgEphemerisGPSDepF { + pub sender_id: Option, + /// Values common for all ephemeris types + pub common: EphemerisCommonContentDepB, + /// Group delay differential between L1 and L2 + pub tgd: f64, + /// Amplitude of the sine harmonic correction term to the orbit radius + pub c_rs: f64, + /// Amplitude of the cosine harmonic correction term to the orbit radius + pub c_rc: f64, + /// Amplitude of the cosine harmonic correction term to the argument of + /// latitude + pub c_uc: f64, + /// Amplitude of the sine harmonic correction term to the argument of + /// latitude + pub c_us: f64, + /// Amplitude of the cosine harmonic correction term to the angle of + /// inclination + pub c_ic: f64, + /// Amplitude of the sine harmonic correction term to the angle of + /// inclination + pub c_is: f64, + /// Mean motion difference + pub dn: f64, + /// Mean anomaly at reference time + pub m0: f64, + /// Eccentricity of satellite orbit + pub ecc: f64, + /// Square root of the semi-major axis of orbit + pub sqrta: f64, + /// Longitude of ascending node of orbit plane at weekly epoch + pub omega0: f64, + /// Rate of right ascension + pub omegadot: f64, + /// Argument of perigee + pub w: f64, + /// Inclination + pub inc: f64, + /// Inclination first derivative + pub inc_dot: f64, + /// Polynomial clock correction coefficient (clock bias) + pub af0: f64, + /// Polynomial clock correction coefficient (clock drift) + pub af1: f64, + /// Polynomial clock correction coefficient (rate of clock drift) + pub af2: f64, + /// Clock reference + pub toc: GPSTimeSec, + /// Issue of ephemeris data + pub iode: u8, + /// Issue of clock data + pub iodc: u16, +} + +impl MsgEphemerisGPSDepF { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgEphemerisGPSDepF { + sender_id: None, + common: EphemerisCommonContentDepB::parse(_buf)?, + tgd: _buf.read_f64::()?, + c_rs: _buf.read_f64::()?, + c_rc: _buf.read_f64::()?, + c_uc: _buf.read_f64::()?, + c_us: _buf.read_f64::()?, + c_ic: _buf.read_f64::()?, + c_is: _buf.read_f64::()?, + dn: _buf.read_f64::()?, + m0: _buf.read_f64::()?, + ecc: _buf.read_f64::()?, + sqrta: _buf.read_f64::()?, + omega0: _buf.read_f64::()?, + omegadot: _buf.read_f64::()?, + w: _buf.read_f64::()?, + inc: _buf.read_f64::()?, + inc_dot: _buf.read_f64::()?, + af0: _buf.read_f64::()?, + af1: _buf.read_f64::()?, + af2: _buf.read_f64::()?, + toc: GPSTimeSec::parse(_buf)?, + iode: _buf.read_u8()?, + iodc: _buf.read_u16::()?, + }) + } +} +impl super::SBPMessage for MsgEphemerisGPSDepF { + const MSG_ID: u16 = 134; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Satellite broadcast ephemeris for GPS +/// +/// The ephemeris message returns a set of satellite orbit +/// parameters that is used to calculate GPS satellite position, +/// velocity, and clock offset. Please see the Navstar GPS +/// Space Segment/Navigation user interfaces (ICD-GPS-200, Table +/// 20-III) for more details. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgEphemerisGPS { + pub sender_id: Option, + /// Values common for all ephemeris types + pub common: EphemerisCommonContent, + /// Group delay differential between L1 and L2 + pub tgd: f32, + /// Amplitude of the sine harmonic correction term to the orbit radius + pub c_rs: f32, + /// Amplitude of the cosine harmonic correction term to the orbit radius + pub c_rc: f32, + /// Amplitude of the cosine harmonic correction term to the argument of + /// latitude + pub c_uc: f32, + /// Amplitude of the sine harmonic correction term to the argument of + /// latitude + pub c_us: f32, + /// Amplitude of the cosine harmonic correction term to the angle of + /// inclination + pub c_ic: f32, + /// Amplitude of the sine harmonic correction term to the angle of + /// inclination + pub c_is: f32, + /// Mean motion difference + pub dn: f64, + /// Mean anomaly at reference time + pub m0: f64, + /// Eccentricity of satellite orbit + pub ecc: f64, + /// Square root of the semi-major axis of orbit + pub sqrta: f64, + /// Longitude of ascending node of orbit plane at weekly epoch + pub omega0: f64, + /// Rate of right ascension + pub omegadot: f64, + /// Argument of perigee + pub w: f64, + /// Inclination + pub inc: f64, + /// Inclination first derivative + pub inc_dot: f64, + /// Polynomial clock correction coefficient (clock bias) + pub af0: f32, + /// Polynomial clock correction coefficient (clock drift) + pub af1: f32, + /// Polynomial clock correction coefficient (rate of clock drift) + pub af2: f32, + /// Clock reference + pub toc: GPSTimeSec, + /// Issue of ephemeris data + pub iode: u8, + /// Issue of clock data + pub iodc: u16, +} + +impl MsgEphemerisGPS { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgEphemerisGPS { + sender_id: None, + common: EphemerisCommonContent::parse(_buf)?, + tgd: _buf.read_f32::()?, + c_rs: _buf.read_f32::()?, + c_rc: _buf.read_f32::()?, + c_uc: _buf.read_f32::()?, + c_us: _buf.read_f32::()?, + c_ic: _buf.read_f32::()?, + c_is: _buf.read_f32::()?, + dn: _buf.read_f64::()?, + m0: _buf.read_f64::()?, + ecc: _buf.read_f64::()?, + sqrta: _buf.read_f64::()?, + omega0: _buf.read_f64::()?, + omegadot: _buf.read_f64::()?, + w: _buf.read_f64::()?, + inc: _buf.read_f64::()?, + inc_dot: _buf.read_f64::()?, + af0: _buf.read_f32::()?, + af1: _buf.read_f32::()?, + af2: _buf.read_f32::()?, + toc: GPSTimeSec::parse(_buf)?, + iode: _buf.read_u8()?, + iodc: _buf.read_u16::()?, + }) + } +} +impl super::SBPMessage for MsgEphemerisGPS { + const MSG_ID: u16 = 138; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Satellite broadcast ephemeris for QZSS +/// +/// The ephemeris message returns a set of satellite orbit +/// parameters that is used to calculate QZSS satellite position, +/// velocity, and clock offset. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgEphemerisQzss { + pub sender_id: Option, + /// Values common for all ephemeris types + pub common: EphemerisCommonContent, + /// Group delay differential between L1 and L2 + pub tgd: f32, + /// Amplitude of the sine harmonic correction term to the orbit radius + pub c_rs: f32, + /// Amplitude of the cosine harmonic correction term to the orbit radius + pub c_rc: f32, + /// Amplitude of the cosine harmonic correction term to the argument of + /// latitude + pub c_uc: f32, + /// Amplitude of the sine harmonic correction term to the argument of + /// latitude + pub c_us: f32, + /// Amplitude of the cosine harmonic correction term to the angle of + /// inclination + pub c_ic: f32, + /// Amplitude of the sine harmonic correction term to the angle of + /// inclination + pub c_is: f32, + /// Mean motion difference + pub dn: f64, + /// Mean anomaly at reference time + pub m0: f64, + /// Eccentricity of satellite orbit + pub ecc: f64, + /// Square root of the semi-major axis of orbit + pub sqrta: f64, + /// Longitude of ascending node of orbit plane at weekly epoch + pub omega0: f64, + /// Rate of right ascension + pub omegadot: f64, + /// Argument of perigee + pub w: f64, + /// Inclination + pub inc: f64, + /// Inclination first derivative + pub inc_dot: f64, + /// Polynomial clock correction coefficient (clock bias) + pub af0: f32, + /// Polynomial clock correction coefficient (clock drift) + pub af1: f32, + /// Polynomial clock correction coefficient (rate of clock drift) + pub af2: f32, + /// Clock reference + pub toc: GPSTimeSec, + /// Issue of ephemeris data + pub iode: u8, + /// Issue of clock data + pub iodc: u16, +} + +impl MsgEphemerisQzss { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgEphemerisQzss { + sender_id: None, + common: EphemerisCommonContent::parse(_buf)?, + tgd: _buf.read_f32::()?, + c_rs: _buf.read_f32::()?, + c_rc: _buf.read_f32::()?, + c_uc: _buf.read_f32::()?, + c_us: _buf.read_f32::()?, + c_ic: _buf.read_f32::()?, + c_is: _buf.read_f32::()?, + dn: _buf.read_f64::()?, + m0: _buf.read_f64::()?, + ecc: _buf.read_f64::()?, + sqrta: _buf.read_f64::()?, + omega0: _buf.read_f64::()?, + omegadot: _buf.read_f64::()?, + w: _buf.read_f64::()?, + inc: _buf.read_f64::()?, + inc_dot: _buf.read_f64::()?, + af0: _buf.read_f32::()?, + af1: _buf.read_f32::()?, + af2: _buf.read_f32::()?, + toc: GPSTimeSec::parse(_buf)?, + iode: _buf.read_u8()?, + iodc: _buf.read_u16::()?, + }) + } +} +impl super::SBPMessage for MsgEphemerisQzss { + const MSG_ID: u16 = 142; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Satellite broadcast ephemeris for BDS +/// +/// The ephemeris message returns a set of satellite orbit +/// parameters that is used to calculate BDS satellite position, +/// velocity, and clock offset. Please see the BeiDou Navigation +/// Satellite System SIS-ICD Version 2.1, Table 5-9 for more details. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgEphemerisBds { + pub sender_id: Option, + /// Values common for all ephemeris types + pub common: EphemerisCommonContent, + /// Group delay differential for B1 + pub tgd1: f32, + /// Group delay differential for B2 + pub tgd2: f32, + /// Amplitude of the sine harmonic correction term to the orbit radius + pub c_rs: f32, + /// Amplitude of the cosine harmonic correction term to the orbit radius + pub c_rc: f32, + /// Amplitude of the cosine harmonic correction term to the argument of + /// latitude + pub c_uc: f32, + /// Amplitude of the sine harmonic correction term to the argument of + /// latitude + pub c_us: f32, + /// Amplitude of the cosine harmonic correction term to the angle of + /// inclination + pub c_ic: f32, + /// Amplitude of the sine harmonic correction term to the angle of + /// inclination + pub c_is: f32, + /// Mean motion difference + pub dn: f64, + /// Mean anomaly at reference time + pub m0: f64, + /// Eccentricity of satellite orbit + pub ecc: f64, + /// Square root of the semi-major axis of orbit + pub sqrta: f64, + /// Longitude of ascending node of orbit plane at weekly epoch + pub omega0: f64, + /// Rate of right ascension + pub omegadot: f64, + /// Argument of perigee + pub w: f64, + /// Inclination + pub inc: f64, + /// Inclination first derivative + pub inc_dot: f64, + /// Polynomial clock correction coefficient (clock bias) + pub af0: f64, + /// Polynomial clock correction coefficient (clock drift) + pub af1: f32, + /// Polynomial clock correction coefficient (rate of clock drift) + pub af2: f32, + /// Clock reference + pub toc: GPSTimeSec, + /// Issue of ephemeris data + pub iode: u8, + /// Issue of clock data + pub iodc: u16, +} + +impl MsgEphemerisBds { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgEphemerisBds { + sender_id: None, + common: EphemerisCommonContent::parse(_buf)?, + tgd1: _buf.read_f32::()?, + tgd2: _buf.read_f32::()?, + c_rs: _buf.read_f32::()?, + c_rc: _buf.read_f32::()?, + c_uc: _buf.read_f32::()?, + c_us: _buf.read_f32::()?, + c_ic: _buf.read_f32::()?, + c_is: _buf.read_f32::()?, + dn: _buf.read_f64::()?, + m0: _buf.read_f64::()?, + ecc: _buf.read_f64::()?, + sqrta: _buf.read_f64::()?, + omega0: _buf.read_f64::()?, + omegadot: _buf.read_f64::()?, + w: _buf.read_f64::()?, + inc: _buf.read_f64::()?, + inc_dot: _buf.read_f64::()?, + af0: _buf.read_f64::()?, + af1: _buf.read_f32::()?, + af2: _buf.read_f32::()?, + toc: GPSTimeSec::parse(_buf)?, + iode: _buf.read_u8()?, + iodc: _buf.read_u16::()?, + }) + } +} +impl super::SBPMessage for MsgEphemerisBds { + const MSG_ID: u16 = 137; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Deprecated +/// +/// This observation message has been deprecated in favor of +/// an ephemeris message with explicit source of NAV data. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgEphemerisGalDepA { + pub sender_id: Option, + /// Values common for all ephemeris types + pub common: EphemerisCommonContent, + /// E1-E5a Broadcast Group Delay + pub bgd_e1e5a: f32, + /// E1-E5b Broadcast Group Delay + pub bgd_e1e5b: f32, + /// Amplitude of the sine harmonic correction term to the orbit radius + pub c_rs: f32, + /// Amplitude of the cosine harmonic correction term to the orbit radius + pub c_rc: f32, + /// Amplitude of the cosine harmonic correction term to the argument of + /// latitude + pub c_uc: f32, + /// Amplitude of the sine harmonic correction term to the argument of + /// latitude + pub c_us: f32, + /// Amplitude of the cosine harmonic correction term to the angle of + /// inclination + pub c_ic: f32, + /// Amplitude of the sine harmonic correction term to the angle of + /// inclination + pub c_is: f32, + /// Mean motion difference + pub dn: f64, + /// Mean anomaly at reference time + pub m0: f64, + /// Eccentricity of satellite orbit + pub ecc: f64, + /// Square root of the semi-major axis of orbit + pub sqrta: f64, + /// Longitude of ascending node of orbit plane at weekly epoch + pub omega0: f64, + /// Rate of right ascension + pub omegadot: f64, + /// Argument of perigee + pub w: f64, + /// Inclination + pub inc: f64, + /// Inclination first derivative + pub inc_dot: f64, + /// Polynomial clock correction coefficient (clock bias) + pub af0: f64, + /// Polynomial clock correction coefficient (clock drift) + pub af1: f64, + /// Polynomial clock correction coefficient (rate of clock drift) + pub af2: f32, + /// Clock reference + pub toc: GPSTimeSec, + /// Issue of ephemeris data + pub iode: u16, + /// Issue of clock data + pub iodc: u16, +} + +impl MsgEphemerisGalDepA { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgEphemerisGalDepA { + sender_id: None, + common: EphemerisCommonContent::parse(_buf)?, + bgd_e1e5a: _buf.read_f32::()?, + bgd_e1e5b: _buf.read_f32::()?, + c_rs: _buf.read_f32::()?, + c_rc: _buf.read_f32::()?, + c_uc: _buf.read_f32::()?, + c_us: _buf.read_f32::()?, + c_ic: _buf.read_f32::()?, + c_is: _buf.read_f32::()?, + dn: _buf.read_f64::()?, + m0: _buf.read_f64::()?, + ecc: _buf.read_f64::()?, + sqrta: _buf.read_f64::()?, + omega0: _buf.read_f64::()?, + omegadot: _buf.read_f64::()?, + w: _buf.read_f64::()?, + inc: _buf.read_f64::()?, + inc_dot: _buf.read_f64::()?, + af0: _buf.read_f64::()?, + af1: _buf.read_f64::()?, + af2: _buf.read_f32::()?, + toc: GPSTimeSec::parse(_buf)?, + iode: _buf.read_u16::()?, + iodc: _buf.read_u16::()?, + }) + } +} +impl super::SBPMessage for MsgEphemerisGalDepA { + const MSG_ID: u16 = 149; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Satellite broadcast ephemeris for Galileo +/// +/// The ephemeris message returns a set of satellite orbit +/// parameters that is used to calculate Galileo satellite position, +/// velocity, and clock offset. Please see the Signal In Space ICD +/// OS SIS ICD, Issue 1.3, December 2016 for more details. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgEphemerisGal { + pub sender_id: Option, + /// Values common for all ephemeris types + pub common: EphemerisCommonContent, + /// E1-E5a Broadcast Group Delay + pub bgd_e1e5a: f32, + /// E1-E5b Broadcast Group Delay + pub bgd_e1e5b: f32, + /// Amplitude of the sine harmonic correction term to the orbit radius + pub c_rs: f32, + /// Amplitude of the cosine harmonic correction term to the orbit radius + pub c_rc: f32, + /// Amplitude of the cosine harmonic correction term to the argument of + /// latitude + pub c_uc: f32, + /// Amplitude of the sine harmonic correction term to the argument of + /// latitude + pub c_us: f32, + /// Amplitude of the cosine harmonic correction term to the angle of + /// inclination + pub c_ic: f32, + /// Amplitude of the sine harmonic correction term to the angle of + /// inclination + pub c_is: f32, + /// Mean motion difference + pub dn: f64, + /// Mean anomaly at reference time + pub m0: f64, + /// Eccentricity of satellite orbit + pub ecc: f64, + /// Square root of the semi-major axis of orbit + pub sqrta: f64, + /// Longitude of ascending node of orbit plane at weekly epoch + pub omega0: f64, + /// Rate of right ascension + pub omegadot: f64, + /// Argument of perigee + pub w: f64, + /// Inclination + pub inc: f64, + /// Inclination first derivative + pub inc_dot: f64, + /// Polynomial clock correction coefficient (clock bias) + pub af0: f64, + /// Polynomial clock correction coefficient (clock drift) + pub af1: f64, + /// Polynomial clock correction coefficient (rate of clock drift) + pub af2: f32, + /// Clock reference + pub toc: GPSTimeSec, + /// Issue of ephemeris data + pub iode: u16, + /// Issue of clock data + pub iodc: u16, + /// 0=I/NAV, 1=F/NAV, ... + pub source: u8, +} + +impl MsgEphemerisGal { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgEphemerisGal { + sender_id: None, + common: EphemerisCommonContent::parse(_buf)?, + bgd_e1e5a: _buf.read_f32::()?, + bgd_e1e5b: _buf.read_f32::()?, + c_rs: _buf.read_f32::()?, + c_rc: _buf.read_f32::()?, + c_uc: _buf.read_f32::()?, + c_us: _buf.read_f32::()?, + c_ic: _buf.read_f32::()?, + c_is: _buf.read_f32::()?, + dn: _buf.read_f64::()?, + m0: _buf.read_f64::()?, + ecc: _buf.read_f64::()?, + sqrta: _buf.read_f64::()?, + omega0: _buf.read_f64::()?, + omegadot: _buf.read_f64::()?, + w: _buf.read_f64::()?, + inc: _buf.read_f64::()?, + inc_dot: _buf.read_f64::()?, + af0: _buf.read_f64::()?, + af1: _buf.read_f64::()?, + af2: _buf.read_f32::()?, + toc: GPSTimeSec::parse(_buf)?, + iode: _buf.read_u16::()?, + iodc: _buf.read_u16::()?, + source: _buf.read_u8()?, + }) + } +} +impl super::SBPMessage for MsgEphemerisGal { + const MSG_ID: u16 = 141; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgEphemerisSbasDepA { + pub sender_id: Option, + /// Values common for all ephemeris types + pub common: EphemerisCommonContentDepA, + /// Position of the GEO at time toe + pub pos: Vec, + /// Velocity of the GEO at time toe + pub vel: Vec, + /// Acceleration of the GEO at time toe + pub acc: Vec, + /// Time offset of the GEO clock w.r.t. SBAS Network Time + pub a_gf0: f64, + /// Drift of the GEO clock w.r.t. SBAS Network Time + pub a_gf1: f64, +} + +impl MsgEphemerisSbasDepA { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgEphemerisSbasDepA { + sender_id: None, + common: EphemerisCommonContentDepA::parse(_buf)?, + pos: ::parser::read_double_array_limit(_buf, 3)?, + vel: ::parser::read_double_array_limit(_buf, 3)?, + acc: ::parser::read_double_array_limit(_buf, 3)?, + a_gf0: _buf.read_f64::()?, + a_gf1: _buf.read_f64::()?, + }) + } +} +impl super::SBPMessage for MsgEphemerisSbasDepA { + const MSG_ID: u16 = 130; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Satellite broadcast ephemeris for GLO +/// +/// The ephemeris message returns a set of satellite orbit +/// parameters that is used to calculate GLO satellite position, +/// velocity, and clock offset. Please see the GLO ICD 5.1 "Table 4.5 +/// Characteristics of words of immediate information (ephemeris parameters)" +/// for more details. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgEphemerisGloDepA { + pub sender_id: Option, + /// Values common for all ephemeris types + pub common: EphemerisCommonContentDepA, + /// Relative deviation of predicted carrier frequency from nominal + pub gamma: f64, + /// Correction to the SV time + pub tau: f64, + /// Position of the SV at tb in PZ-90.02 coordinates system + pub pos: Vec, + /// Velocity vector of the SV at tb in PZ-90.02 coordinates system + pub vel: Vec, + /// Acceleration vector of the SV at tb in PZ-90.02 coordinates sys + pub acc: Vec, +} + +impl MsgEphemerisGloDepA { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgEphemerisGloDepA { + sender_id: None, + common: EphemerisCommonContentDepA::parse(_buf)?, + gamma: _buf.read_f64::()?, + tau: _buf.read_f64::()?, + pos: ::parser::read_double_array_limit(_buf, 3)?, + vel: ::parser::read_double_array_limit(_buf, 3)?, + acc: ::parser::read_double_array_limit(_buf, 3)?, + }) + } +} +impl super::SBPMessage for MsgEphemerisGloDepA { + const MSG_ID: u16 = 131; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Deprecated +/// +/// This observation message has been deprecated in favor of +/// ephemeris message using floats for size reduction. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgEphemerisSbasDepB { + pub sender_id: Option, + /// Values common for all ephemeris types + pub common: EphemerisCommonContentDepB, + /// Position of the GEO at time toe + pub pos: Vec, + /// Velocity of the GEO at time toe + pub vel: Vec, + /// Acceleration of the GEO at time toe + pub acc: Vec, + /// Time offset of the GEO clock w.r.t. SBAS Network Time + pub a_gf0: f64, + /// Drift of the GEO clock w.r.t. SBAS Network Time + pub a_gf1: f64, +} + +impl MsgEphemerisSbasDepB { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgEphemerisSbasDepB { + sender_id: None, + common: EphemerisCommonContentDepB::parse(_buf)?, + pos: ::parser::read_double_array_limit(_buf, 3)?, + vel: ::parser::read_double_array_limit(_buf, 3)?, + acc: ::parser::read_double_array_limit(_buf, 3)?, + a_gf0: _buf.read_f64::()?, + a_gf1: _buf.read_f64::()?, + }) + } +} +impl super::SBPMessage for MsgEphemerisSbasDepB { + const MSG_ID: u16 = 132; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgEphemerisSbas { + pub sender_id: Option, + /// Values common for all ephemeris types + pub common: EphemerisCommonContent, + /// Position of the GEO at time toe + pub pos: Vec, + /// Velocity of the GEO at time toe + pub vel: Vec, + /// Acceleration of the GEO at time toe + pub acc: Vec, + /// Time offset of the GEO clock w.r.t. SBAS Network Time + pub a_gf0: f32, + /// Drift of the GEO clock w.r.t. SBAS Network Time + pub a_gf1: f32, +} + +impl MsgEphemerisSbas { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgEphemerisSbas { + sender_id: None, + common: EphemerisCommonContent::parse(_buf)?, + pos: ::parser::read_double_array_limit(_buf, 3)?, + vel: ::parser::read_float_array_limit(_buf, 3)?, + acc: ::parser::read_float_array_limit(_buf, 3)?, + a_gf0: _buf.read_f32::()?, + a_gf1: _buf.read_f32::()?, + }) + } +} +impl super::SBPMessage for MsgEphemerisSbas { + const MSG_ID: u16 = 140; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Satellite broadcast ephemeris for GLO +/// +/// The ephemeris message returns a set of satellite orbit +/// parameters that is used to calculate GLO satellite position, +/// velocity, and clock offset. Please see the GLO ICD 5.1 "Table 4.5 +/// Characteristics of words of immediate information (ephemeris parameters)" +/// for more details. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgEphemerisGloDepB { + pub sender_id: Option, + /// Values common for all ephemeris types + pub common: EphemerisCommonContentDepB, + /// Relative deviation of predicted carrier frequency from nominal + pub gamma: f64, + /// Correction to the SV time + pub tau: f64, + /// Position of the SV at tb in PZ-90.02 coordinates system + pub pos: Vec, + /// Velocity vector of the SV at tb in PZ-90.02 coordinates system + pub vel: Vec, + /// Acceleration vector of the SV at tb in PZ-90.02 coordinates sys + pub acc: Vec, +} + +impl MsgEphemerisGloDepB { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgEphemerisGloDepB { + sender_id: None, + common: EphemerisCommonContentDepB::parse(_buf)?, + gamma: _buf.read_f64::()?, + tau: _buf.read_f64::()?, + pos: ::parser::read_double_array_limit(_buf, 3)?, + vel: ::parser::read_double_array_limit(_buf, 3)?, + acc: ::parser::read_double_array_limit(_buf, 3)?, + }) + } +} +impl super::SBPMessage for MsgEphemerisGloDepB { + const MSG_ID: u16 = 133; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Satellite broadcast ephemeris for GLO +/// +/// The ephemeris message returns a set of satellite orbit +/// parameters that is used to calculate GLO satellite position, +/// velocity, and clock offset. Please see the GLO ICD 5.1 "Table 4.5 +/// Characteristics of words of immediate information (ephemeris parameters)" +/// for more details. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgEphemerisGloDepC { + pub sender_id: Option, + /// Values common for all ephemeris types + pub common: EphemerisCommonContentDepB, + /// Relative deviation of predicted carrier frequency from nominal + pub gamma: f64, + /// Correction to the SV time + pub tau: f64, + /// Equipment delay between L1 and L2 + pub d_tau: f64, + /// Position of the SV at tb in PZ-90.02 coordinates system + pub pos: Vec, + /// Velocity vector of the SV at tb in PZ-90.02 coordinates system + pub vel: Vec, + /// Acceleration vector of the SV at tb in PZ-90.02 coordinates sys + pub acc: Vec, + /// Frequency slot. FCN+8 (that is [1..14]). 0 or 0xFF for invalid + pub fcn: u8, +} + +impl MsgEphemerisGloDepC { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgEphemerisGloDepC { + sender_id: None, + common: EphemerisCommonContentDepB::parse(_buf)?, + gamma: _buf.read_f64::()?, + tau: _buf.read_f64::()?, + d_tau: _buf.read_f64::()?, + pos: ::parser::read_double_array_limit(_buf, 3)?, + vel: ::parser::read_double_array_limit(_buf, 3)?, + acc: ::parser::read_double_array_limit(_buf, 3)?, + fcn: _buf.read_u8()?, + }) + } +} +impl super::SBPMessage for MsgEphemerisGloDepC { + const MSG_ID: u16 = 135; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Deprecated +/// +/// This observation message has been deprecated in favor of +/// ephemeris message using floats for size reduction. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgEphemerisGloDepD { + pub sender_id: Option, + /// Values common for all ephemeris types + pub common: EphemerisCommonContentDepB, + /// Relative deviation of predicted carrier frequency from nominal + pub gamma: f64, + /// Correction to the SV time + pub tau: f64, + /// Equipment delay between L1 and L2 + pub d_tau: f64, + /// Position of the SV at tb in PZ-90.02 coordinates system + pub pos: Vec, + /// Velocity vector of the SV at tb in PZ-90.02 coordinates system + pub vel: Vec, + /// Acceleration vector of the SV at tb in PZ-90.02 coordinates sys + pub acc: Vec, + /// Frequency slot. FCN+8 (that is [1..14]). 0 or 0xFF for invalid + pub fcn: u8, + /// Issue of ephemeris data + pub iod: u8, +} + +impl MsgEphemerisGloDepD { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgEphemerisGloDepD { + sender_id: None, + common: EphemerisCommonContentDepB::parse(_buf)?, + gamma: _buf.read_f64::()?, + tau: _buf.read_f64::()?, + d_tau: _buf.read_f64::()?, + pos: ::parser::read_double_array_limit(_buf, 3)?, + vel: ::parser::read_double_array_limit(_buf, 3)?, + acc: ::parser::read_double_array_limit(_buf, 3)?, + fcn: _buf.read_u8()?, + iod: _buf.read_u8()?, + }) + } +} +impl super::SBPMessage for MsgEphemerisGloDepD { + const MSG_ID: u16 = 136; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Satellite broadcast ephemeris for GLO +/// +/// The ephemeris message returns a set of satellite orbit +/// parameters that is used to calculate GLO satellite position, +/// velocity, and clock offset. Please see the GLO ICD 5.1 "Table 4.5 +/// Characteristics of words of immediate information (ephemeris parameters)" +/// for more details. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgEphemerisGlo { + pub sender_id: Option, + /// Values common for all ephemeris types + pub common: EphemerisCommonContent, + /// Relative deviation of predicted carrier frequency from nominal + pub gamma: f32, + /// Correction to the SV time + pub tau: f32, + /// Equipment delay between L1 and L2 + pub d_tau: f32, + /// Position of the SV at tb in PZ-90.02 coordinates system + pub pos: Vec, + /// Velocity vector of the SV at tb in PZ-90.02 coordinates system + pub vel: Vec, + /// Acceleration vector of the SV at tb in PZ-90.02 coordinates sys + pub acc: Vec, + /// Frequency slot. FCN+8 (that is [1..14]). 0 or 0xFF for invalid + pub fcn: u8, + /// Issue of ephemeris data + pub iod: u8, +} + +impl MsgEphemerisGlo { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgEphemerisGlo { + sender_id: None, + common: EphemerisCommonContent::parse(_buf)?, + gamma: _buf.read_f32::()?, + tau: _buf.read_f32::()?, + d_tau: _buf.read_f32::()?, + pos: ::parser::read_double_array_limit(_buf, 3)?, + vel: ::parser::read_double_array_limit(_buf, 3)?, + acc: ::parser::read_float_array_limit(_buf, 3)?, + fcn: _buf.read_u8()?, + iod: _buf.read_u8()?, + }) + } +} +impl super::SBPMessage for MsgEphemerisGlo { + const MSG_ID: u16 = 139; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Satellite broadcast ephemeris +/// +/// The ephemeris message returns a set of satellite orbit +/// parameters that is used to calculate GPS satellite position, +/// velocity, and clock offset. Please see the Navstar GPS +/// Space Segment/Navigation user interfaces (ICD-GPS-200, Table +/// 20-III) for more details. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgEphemerisDepD { + pub sender_id: Option, + /// Group delay differential between L1 and L2 + pub tgd: f64, + /// Amplitude of the sine harmonic correction term to the orbit radius + pub c_rs: f64, + /// Amplitude of the cosine harmonic correction term to the orbit radius + pub c_rc: f64, + /// Amplitude of the cosine harmonic correction term to the argument of + /// latitude + pub c_uc: f64, + /// Amplitude of the sine harmonic correction term to the argument of + /// latitude + pub c_us: f64, + /// Amplitude of the cosine harmonic correction term to the angle of + /// inclination + pub c_ic: f64, + /// Amplitude of the sine harmonic correction term to the angle of + /// inclination + pub c_is: f64, + /// Mean motion difference + pub dn: f64, + /// Mean anomaly at reference time + pub m0: f64, + /// Eccentricity of satellite orbit + pub ecc: f64, + /// Square root of the semi-major axis of orbit + pub sqrta: f64, + /// Longitude of ascending node of orbit plane at weekly epoch + pub omega0: f64, + /// Rate of right ascension + pub omegadot: f64, + /// Argument of perigee + pub w: f64, + /// Inclination + pub inc: f64, + /// Inclination first derivative + pub inc_dot: f64, + /// Polynomial clock correction coefficient (clock bias) + pub af0: f64, + /// Polynomial clock correction coefficient (clock drift) + pub af1: f64, + /// Polynomial clock correction coefficient (rate of clock drift) + pub af2: f64, + /// Time of week + pub toe_tow: f64, + /// Week number + pub toe_wn: u16, + /// Clock reference time of week + pub toc_tow: f64, + /// Clock reference week number + pub toc_wn: u16, + /// Is valid? + pub valid: u8, + /// Satellite is healthy? + pub healthy: u8, + /// GNSS signal identifier + pub sid: GnssSignalDep, + /// Issue of ephemeris data + pub iode: u8, + /// Issue of clock data + pub iodc: u16, + /// Reserved field + pub reserved: u32, +} + +impl MsgEphemerisDepD { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgEphemerisDepD { + sender_id: None, + tgd: _buf.read_f64::()?, + c_rs: _buf.read_f64::()?, + c_rc: _buf.read_f64::()?, + c_uc: _buf.read_f64::()?, + c_us: _buf.read_f64::()?, + c_ic: _buf.read_f64::()?, + c_is: _buf.read_f64::()?, + dn: _buf.read_f64::()?, + m0: _buf.read_f64::()?, + ecc: _buf.read_f64::()?, + sqrta: _buf.read_f64::()?, + omega0: _buf.read_f64::()?, + omegadot: _buf.read_f64::()?, + w: _buf.read_f64::()?, + inc: _buf.read_f64::()?, + inc_dot: _buf.read_f64::()?, + af0: _buf.read_f64::()?, + af1: _buf.read_f64::()?, + af2: _buf.read_f64::()?, + toe_tow: _buf.read_f64::()?, + toe_wn: _buf.read_u16::()?, + toc_tow: _buf.read_f64::()?, + toc_wn: _buf.read_u16::()?, + valid: _buf.read_u8()?, + healthy: _buf.read_u8()?, + sid: GnssSignalDep::parse(_buf)?, + iode: _buf.read_u8()?, + iodc: _buf.read_u16::()?, + reserved: _buf.read_u32::()?, + }) + } +} +impl super::SBPMessage for MsgEphemerisDepD { + const MSG_ID: u16 = 128; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Deprecated +/// +/// Deprecated. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgEphemerisDepA { + pub sender_id: Option, + /// Group delay differential between L1 and L2 + pub tgd: f64, + /// Amplitude of the sine harmonic correction term to the orbit radius + pub c_rs: f64, + /// Amplitude of the cosine harmonic correction term to the orbit radius + pub c_rc: f64, + /// Amplitude of the cosine harmonic correction term to the argument of + /// latitude + pub c_uc: f64, + /// Amplitude of the sine harmonic correction term to the argument of + /// latitude + pub c_us: f64, + /// Amplitude of the cosine harmonic correction term to the angle of + /// inclination + pub c_ic: f64, + /// Amplitude of the sine harmonic correction term to the angle of + /// inclination + pub c_is: f64, + /// Mean motion difference + pub dn: f64, + /// Mean anomaly at reference time + pub m0: f64, + /// Eccentricity of satellite orbit + pub ecc: f64, + /// Square root of the semi-major axis of orbit + pub sqrta: f64, + /// Longitude of ascending node of orbit plane at weekly epoch + pub omega0: f64, + /// Rate of right ascension + pub omegadot: f64, + /// Argument of perigee + pub w: f64, + /// Inclination + pub inc: f64, + /// Inclination first derivative + pub inc_dot: f64, + /// Polynomial clock correction coefficient (clock bias) + pub af0: f64, + /// Polynomial clock correction coefficient (clock drift) + pub af1: f64, + /// Polynomial clock correction coefficient (rate of clock drift) + pub af2: f64, + /// Time of week + pub toe_tow: f64, + /// Week number + pub toe_wn: u16, + /// Clock reference time of week + pub toc_tow: f64, + /// Clock reference week number + pub toc_wn: u16, + /// Is valid? + pub valid: u8, + /// Satellite is healthy? + pub healthy: u8, + /// PRN being tracked + pub prn: u8, +} + +impl MsgEphemerisDepA { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgEphemerisDepA { + sender_id: None, + tgd: _buf.read_f64::()?, + c_rs: _buf.read_f64::()?, + c_rc: _buf.read_f64::()?, + c_uc: _buf.read_f64::()?, + c_us: _buf.read_f64::()?, + c_ic: _buf.read_f64::()?, + c_is: _buf.read_f64::()?, + dn: _buf.read_f64::()?, + m0: _buf.read_f64::()?, + ecc: _buf.read_f64::()?, + sqrta: _buf.read_f64::()?, + omega0: _buf.read_f64::()?, + omegadot: _buf.read_f64::()?, + w: _buf.read_f64::()?, + inc: _buf.read_f64::()?, + inc_dot: _buf.read_f64::()?, + af0: _buf.read_f64::()?, + af1: _buf.read_f64::()?, + af2: _buf.read_f64::()?, + toe_tow: _buf.read_f64::()?, + toe_wn: _buf.read_u16::()?, + toc_tow: _buf.read_f64::()?, + toc_wn: _buf.read_u16::()?, + valid: _buf.read_u8()?, + healthy: _buf.read_u8()?, + prn: _buf.read_u8()?, + }) + } +} +impl super::SBPMessage for MsgEphemerisDepA { + const MSG_ID: u16 = 26; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Deprecated +/// +/// Deprecated. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgEphemerisDepB { + pub sender_id: Option, + /// Group delay differential between L1 and L2 + pub tgd: f64, + /// Amplitude of the sine harmonic correction term to the orbit radius + pub c_rs: f64, + /// Amplitude of the cosine harmonic correction term to the orbit radius + pub c_rc: f64, + /// Amplitude of the cosine harmonic correction term to the argument of + /// latitude + pub c_uc: f64, + /// Amplitude of the sine harmonic correction term to the argument of + /// latitude + pub c_us: f64, + /// Amplitude of the cosine harmonic correction term to the angle of + /// inclination + pub c_ic: f64, + /// Amplitude of the sine harmonic correction term to the angle of + /// inclination + pub c_is: f64, + /// Mean motion difference + pub dn: f64, + /// Mean anomaly at reference time + pub m0: f64, + /// Eccentricity of satellite orbit + pub ecc: f64, + /// Square root of the semi-major axis of orbit + pub sqrta: f64, + /// Longitude of ascending node of orbit plane at weekly epoch + pub omega0: f64, + /// Rate of right ascension + pub omegadot: f64, + /// Argument of perigee + pub w: f64, + /// Inclination + pub inc: f64, + /// Inclination first derivative + pub inc_dot: f64, + /// Polynomial clock correction coefficient (clock bias) + pub af0: f64, + /// Polynomial clock correction coefficient (clock drift) + pub af1: f64, + /// Polynomial clock correction coefficient (rate of clock drift) + pub af2: f64, + /// Time of week + pub toe_tow: f64, + /// Week number + pub toe_wn: u16, + /// Clock reference time of week + pub toc_tow: f64, + /// Clock reference week number + pub toc_wn: u16, + /// Is valid? + pub valid: u8, + /// Satellite is healthy? + pub healthy: u8, + /// PRN being tracked + pub prn: u8, + /// Issue of ephemeris data + pub iode: u8, +} + +impl MsgEphemerisDepB { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgEphemerisDepB { + sender_id: None, + tgd: _buf.read_f64::()?, + c_rs: _buf.read_f64::()?, + c_rc: _buf.read_f64::()?, + c_uc: _buf.read_f64::()?, + c_us: _buf.read_f64::()?, + c_ic: _buf.read_f64::()?, + c_is: _buf.read_f64::()?, + dn: _buf.read_f64::()?, + m0: _buf.read_f64::()?, + ecc: _buf.read_f64::()?, + sqrta: _buf.read_f64::()?, + omega0: _buf.read_f64::()?, + omegadot: _buf.read_f64::()?, + w: _buf.read_f64::()?, + inc: _buf.read_f64::()?, + inc_dot: _buf.read_f64::()?, + af0: _buf.read_f64::()?, + af1: _buf.read_f64::()?, + af2: _buf.read_f64::()?, + toe_tow: _buf.read_f64::()?, + toe_wn: _buf.read_u16::()?, + toc_tow: _buf.read_f64::()?, + toc_wn: _buf.read_u16::()?, + valid: _buf.read_u8()?, + healthy: _buf.read_u8()?, + prn: _buf.read_u8()?, + iode: _buf.read_u8()?, + }) + } +} +impl super::SBPMessage for MsgEphemerisDepB { + const MSG_ID: u16 = 70; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Satellite broadcast ephemeris +/// +/// The ephemeris message returns a set of satellite orbit +/// parameters that is used to calculate GPS satellite position, +/// velocity, and clock offset. Please see the Navstar GPS +/// Space Segment/Navigation user interfaces (ICD-GPS-200, Table +/// 20-III) for more details. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgEphemerisDepC { + pub sender_id: Option, + /// Group delay differential between L1 and L2 + pub tgd: f64, + /// Amplitude of the sine harmonic correction term to the orbit radius + pub c_rs: f64, + /// Amplitude of the cosine harmonic correction term to the orbit radius + pub c_rc: f64, + /// Amplitude of the cosine harmonic correction term to the argument of + /// latitude + pub c_uc: f64, + /// Amplitude of the sine harmonic correction term to the argument of + /// latitude + pub c_us: f64, + /// Amplitude of the cosine harmonic correction term to the angle of + /// inclination + pub c_ic: f64, + /// Amplitude of the sine harmonic correction term to the angle of + /// inclination + pub c_is: f64, + /// Mean motion difference + pub dn: f64, + /// Mean anomaly at reference time + pub m0: f64, + /// Eccentricity of satellite orbit + pub ecc: f64, + /// Square root of the semi-major axis of orbit + pub sqrta: f64, + /// Longitude of ascending node of orbit plane at weekly epoch + pub omega0: f64, + /// Rate of right ascension + pub omegadot: f64, + /// Argument of perigee + pub w: f64, + /// Inclination + pub inc: f64, + /// Inclination first derivative + pub inc_dot: f64, + /// Polynomial clock correction coefficient (clock bias) + pub af0: f64, + /// Polynomial clock correction coefficient (clock drift) + pub af1: f64, + /// Polynomial clock correction coefficient (rate of clock drift) + pub af2: f64, + /// Time of week + pub toe_tow: f64, + /// Week number + pub toe_wn: u16, + /// Clock reference time of week + pub toc_tow: f64, + /// Clock reference week number + pub toc_wn: u16, + /// Is valid? + pub valid: u8, + /// Satellite is healthy? + pub healthy: u8, + /// GNSS signal identifier + pub sid: GnssSignalDep, + /// Issue of ephemeris data + pub iode: u8, + /// Issue of clock data + pub iodc: u16, + /// Reserved field + pub reserved: u32, +} + +impl MsgEphemerisDepC { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgEphemerisDepC { + sender_id: None, + tgd: _buf.read_f64::()?, + c_rs: _buf.read_f64::()?, + c_rc: _buf.read_f64::()?, + c_uc: _buf.read_f64::()?, + c_us: _buf.read_f64::()?, + c_ic: _buf.read_f64::()?, + c_is: _buf.read_f64::()?, + dn: _buf.read_f64::()?, + m0: _buf.read_f64::()?, + ecc: _buf.read_f64::()?, + sqrta: _buf.read_f64::()?, + omega0: _buf.read_f64::()?, + omegadot: _buf.read_f64::()?, + w: _buf.read_f64::()?, + inc: _buf.read_f64::()?, + inc_dot: _buf.read_f64::()?, + af0: _buf.read_f64::()?, + af1: _buf.read_f64::()?, + af2: _buf.read_f64::()?, + toe_tow: _buf.read_f64::()?, + toe_wn: _buf.read_u16::()?, + toc_tow: _buf.read_f64::()?, + toc_wn: _buf.read_u16::()?, + valid: _buf.read_u8()?, + healthy: _buf.read_u8()?, + sid: GnssSignalDep::parse(_buf)?, + iode: _buf.read_u8()?, + iodc: _buf.read_u16::()?, + reserved: _buf.read_u32::()?, + }) + } +} +impl super::SBPMessage for MsgEphemerisDepC { + const MSG_ID: u16 = 71; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Header for observation message. +/// +/// Header of a GPS observation message. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct ObservationHeaderDep { + /// GPS time of this observation + pub t: GPSTimeDep, + /// Total number of observations. First nibble is the size of the sequence + /// (n), second nibble is the zero-indexed counter (ith packet of n) + pub n_obs: u8, +} + +impl ObservationHeaderDep { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(ObservationHeaderDep { + t: GPSTimeDep::parse(_buf)?, + n_obs: _buf.read_u8()?, + }) + } + pub fn parse_array(buf: &mut &[u8]) -> Result, ::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(ObservationHeaderDep::parse(buf)?); + } + Ok(v) + } + + pub fn parse_array_limit( + buf: &mut &[u8], + n: usize, + ) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(ObservationHeaderDep::parse(buf)?); + } + Ok(v) + } +} + +/// GPS carrier phase measurement. +/// +/// Carrier phase measurement in cycles represented as a 40-bit +/// fixed point number with Q32.8 layout, i.e. 32-bits of whole +/// cycles and 8-bits of fractional cycles. This has the opposite +/// sign convention than a typical GPS receiver and the phase has +/// the opposite sign as the pseudorange. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct CarrierPhaseDepA { + /// Carrier phase whole cycles + pub i: i32, + /// Carrier phase fractional part + pub f: u8, +} + +impl CarrierPhaseDepA { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(CarrierPhaseDepA { + i: _buf.read_i32::()?, + f: _buf.read_u8()?, + }) + } + pub fn parse_array(buf: &mut &[u8]) -> Result, ::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(CarrierPhaseDepA::parse(buf)?); + } + Ok(v) + } + + pub fn parse_array_limit(buf: &mut &[u8], n: usize) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(CarrierPhaseDepA::parse(buf)?); + } + Ok(v) + } +} + +/// Deprecated +/// +/// Deprecated. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct PackedObsContentDepA { + /// Pseudorange observation + pub P: u32, + /// Carrier phase observation with opposite sign from typical convention + pub L: CarrierPhaseDepA, + /// Carrier-to-Noise density + pub cn0: u8, + /// Lock indicator. This value changes whenever a satellite signal has lost + /// and regained lock, indicating that the carrier phase ambiguity may have + /// changed. + pub lock: u16, + /// PRN-1 identifier of the satellite signal + pub prn: u8, +} + +impl PackedObsContentDepA { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(PackedObsContentDepA { + P: _buf.read_u32::()?, + L: CarrierPhaseDepA::parse(_buf)?, + cn0: _buf.read_u8()?, + lock: _buf.read_u16::()?, + prn: _buf.read_u8()?, + }) + } + pub fn parse_array(buf: &mut &[u8]) -> Result, ::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(PackedObsContentDepA::parse(buf)?); + } + Ok(v) + } + + pub fn parse_array_limit( + buf: &mut &[u8], + n: usize, + ) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(PackedObsContentDepA::parse(buf)?); + } + Ok(v) + } +} + +/// GPS observations for a particular satellite signal. +/// +/// Pseudorange and carrier phase observation for a satellite being +/// tracked. Pseudoranges are referenced to a nominal pseudorange. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct PackedObsContentDepB { + /// Pseudorange observation + pub P: u32, + /// Carrier phase observation with opposite sign from typical convention. + pub L: CarrierPhaseDepA, + /// Carrier-to-Noise density + pub cn0: u8, + /// Lock indicator. This value changes whenever a satellite signal has lost + /// and regained lock, indicating that the carrier phase ambiguity may have + /// changed. + pub lock: u16, + /// GNSS signal identifier + pub sid: GnssSignalDep, +} + +impl PackedObsContentDepB { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(PackedObsContentDepB { + P: _buf.read_u32::()?, + L: CarrierPhaseDepA::parse(_buf)?, + cn0: _buf.read_u8()?, + lock: _buf.read_u16::()?, + sid: GnssSignalDep::parse(_buf)?, + }) + } + pub fn parse_array(buf: &mut &[u8]) -> Result, ::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(PackedObsContentDepB::parse(buf)?); + } + Ok(v) + } + + pub fn parse_array_limit( + buf: &mut &[u8], + n: usize, + ) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(PackedObsContentDepB::parse(buf)?); + } + Ok(v) + } +} + +/// GPS observations for a particular satellite signal. +/// +/// Pseudorange and carrier phase observation for a satellite being +/// tracked. The observations are be interoperable with 3rd party +/// receivers and conform with typical RTCMv3 GNSS observations. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct PackedObsContentDepC { + /// Pseudorange observation + pub P: u32, + /// Carrier phase observation with typical sign convention. + pub L: CarrierPhase, + /// Carrier-to-Noise density + pub cn0: u8, + /// Lock indicator. This value changes whenever a satellite signal has lost + /// and regained lock, indicating that the carrier phase ambiguity may have + /// changed. + pub lock: u16, + /// GNSS signal identifier + pub sid: GnssSignalDep, +} + +impl PackedObsContentDepC { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(PackedObsContentDepC { + P: _buf.read_u32::()?, + L: CarrierPhase::parse(_buf)?, + cn0: _buf.read_u8()?, + lock: _buf.read_u16::()?, + sid: GnssSignalDep::parse(_buf)?, + }) + } + pub fn parse_array(buf: &mut &[u8]) -> Result, ::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(PackedObsContentDepC::parse(buf)?); + } + Ok(v) + } + + pub fn parse_array_limit( + buf: &mut &[u8], + n: usize, + ) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(PackedObsContentDepC::parse(buf)?); + } + Ok(v) + } +} + +/// Deprecated +/// +/// Deprecated. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgObsDepA { + pub sender_id: Option, + /// Header of a GPS observation message + pub header: ObservationHeaderDep, + /// Pseudorange and carrier phase observation for a satellite being tracked. + pub obs: Vec, +} + +impl MsgObsDepA { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgObsDepA { + sender_id: None, + header: ObservationHeaderDep::parse(_buf)?, + obs: PackedObsContentDepA::parse_array(_buf)?, + }) + } +} +impl super::SBPMessage for MsgObsDepA { + const MSG_ID: u16 = 69; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Deprecated +/// +/// This observation message has been deprecated in favor of +/// observations that are more interoperable. This message +/// should be used for observations referenced to +/// a nominal pseudorange which are not interoperable with +/// most 3rd party GNSS receievers or typical RTCMv3 +/// observations. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgObsDepB { + pub sender_id: Option, + /// Header of a GPS observation message + pub header: ObservationHeaderDep, + /// Pseudorange and carrier phase observation for a satellite being tracked. + pub obs: Vec, +} + +impl MsgObsDepB { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgObsDepB { + sender_id: None, + header: ObservationHeaderDep::parse(_buf)?, + obs: PackedObsContentDepB::parse_array(_buf)?, + }) + } +} +impl super::SBPMessage for MsgObsDepB { + const MSG_ID: u16 = 67; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Deprecated +/// +/// The GPS observations message reports all the raw pseudorange and +/// carrier phase observations for the satellites being tracked by +/// the device. Carrier phase observation here is represented as a +/// 40-bit fixed point number with Q32.8 layout (i.e. 32-bits of +/// whole cycles and 8-bits of fractional cycles). The observations +/// are interoperable with 3rd party receivers and conform +/// with typical RTCMv3 GNSS observations. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgObsDepC { + pub sender_id: Option, + /// Header of a GPS observation message + pub header: ObservationHeaderDep, + /// Pseudorange and carrier phase observation for a satellite being tracked. + pub obs: Vec, +} + +impl MsgObsDepC { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgObsDepC { + sender_id: None, + header: ObservationHeaderDep::parse(_buf)?, + obs: PackedObsContentDepC::parse_array(_buf)?, + }) + } +} +impl super::SBPMessage for MsgObsDepC { + const MSG_ID: u16 = 73; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Iono corrections +/// +/// The ionospheric parameters which allow the "L1 only" or "L2 only" user to +/// utilize the ionospheric model for computation of the ionospheric delay. +/// Please see ICD-GPS-200 (Chapter 20.3.3.5.1.7) for more details. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgIono { + pub sender_id: Option, + /// Navigation Message Correction Table Valitidy Time + pub t_nmct: GPSTimeSec, + pub a0: f64, + pub a1: f64, + pub a2: f64, + pub a3: f64, + pub b0: f64, + pub b1: f64, + pub b2: f64, + pub b3: f64, +} + +impl MsgIono { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgIono { + sender_id: None, + t_nmct: GPSTimeSec::parse(_buf)?, + a0: _buf.read_f64::()?, + a1: _buf.read_f64::()?, + a2: _buf.read_f64::()?, + a3: _buf.read_f64::()?, + b0: _buf.read_f64::()?, + b1: _buf.read_f64::()?, + b2: _buf.read_f64::()?, + b3: _buf.read_f64::()?, + }) + } +} +impl super::SBPMessage for MsgIono { + const MSG_ID: u16 = 144; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// L2C capability mask +/// +/// Please see ICD-GPS-200 (Chapter 20.3.3.5.1.4) for more details. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgSvConfigurationGPSDep { + pub sender_id: Option, + /// Navigation Message Correction Table Valitidy Time + pub t_nmct: GPSTimeSec, + /// L2C capability mask, SV32 bit being MSB, SV1 bit being LSB + pub l2c_mask: u32, +} + +impl MsgSvConfigurationGPSDep { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgSvConfigurationGPSDep { + sender_id: None, + t_nmct: GPSTimeSec::parse(_buf)?, + l2c_mask: _buf.read_u32::()?, + }) + } +} +impl super::SBPMessage for MsgSvConfigurationGPSDep { + const MSG_ID: u16 = 145; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct GnssCapb { + /// GPS SV active mask + pub gps_active: u64, + /// GPS L2C active mask + pub gps_l2c: u64, + /// GPS L5 active mask + pub gps_l5: u64, + /// GLO active mask + pub glo_active: u32, + /// GLO L2OF active mask + pub glo_l2of: u32, + /// GLO L3 active mask + pub glo_l3: u32, + /// SBAS active mask (PRNs 120..158, AN 7/62.2.2-18/18 Table B-23, + /// https://www.caat.or.th/wp-content/uploads/2018/03/SL-2018.18.E-1.pdf) + pub sbas_active: u64, + /// SBAS L5 active mask (PRNs 120..158, AN 7/62.2.2-18/18 Table B-23, + /// https://www.caat.or.th/wp-content/uploads/2018/03/SL-2018.18.E-1.pdf) + pub sbas_l5: u64, + /// BDS active mask + pub bds_active: u64, + /// BDS D2NAV active mask + pub bds_d2nav: u64, + /// BDS B2 active mask + pub bds_b2: u64, + /// BDS B2A active mask + pub bds_b2a: u64, + /// QZSS active mask + pub qzss_active: u32, + /// GAL active mask + pub gal_active: u64, + /// GAL E5 active mask + pub gal_e5: u64, +} + +impl GnssCapb { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(GnssCapb { + gps_active: _buf.read_u64::()?, + gps_l2c: _buf.read_u64::()?, + gps_l5: _buf.read_u64::()?, + glo_active: _buf.read_u32::()?, + glo_l2of: _buf.read_u32::()?, + glo_l3: _buf.read_u32::()?, + sbas_active: _buf.read_u64::()?, + sbas_l5: _buf.read_u64::()?, + bds_active: _buf.read_u64::()?, + bds_d2nav: _buf.read_u64::()?, + bds_b2: _buf.read_u64::()?, + bds_b2a: _buf.read_u64::()?, + qzss_active: _buf.read_u32::()?, + gal_active: _buf.read_u64::()?, + gal_e5: _buf.read_u64::()?, + }) + } + pub fn parse_array(buf: &mut &[u8]) -> Result, ::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(GnssCapb::parse(buf)?); + } + Ok(v) + } + + pub fn parse_array_limit(buf: &mut &[u8], n: usize) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(GnssCapb::parse(buf)?); + } + Ok(v) + } +} + +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgGnssCapb { + pub sender_id: Option, + /// Navigation Message Correction Table Validity Time + pub t_nmct: GPSTimeSec, + /// GNSS capabilities masks + pub gc: GnssCapb, +} + +impl MsgGnssCapb { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgGnssCapb { + sender_id: None, + t_nmct: GPSTimeSec::parse(_buf)?, + gc: GnssCapb::parse(_buf)?, + }) + } +} +impl super::SBPMessage for MsgGnssCapb { + const MSG_ID: u16 = 150; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Group Delay +/// +/// Please see ICD-GPS-200 (30.3.3.3.1.1) for more details. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgGroupDelayDepA { + pub sender_id: Option, + /// Data Predict Time of Week + pub t_op: GPSTimeDep, + /// Satellite number + pub prn: u8, + /// bit-field indicating validity of the values, LSB indicating tgd validity + /// etc. 1 = value is valid, 0 = value is not valid. + pub valid: u8, + pub tgd: i16, + pub isc_l1ca: i16, + pub isc_l2c: i16, +} + +impl MsgGroupDelayDepA { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgGroupDelayDepA { + sender_id: None, + t_op: GPSTimeDep::parse(_buf)?, + prn: _buf.read_u8()?, + valid: _buf.read_u8()?, + tgd: _buf.read_i16::()?, + isc_l1ca: _buf.read_i16::()?, + isc_l2c: _buf.read_i16::()?, + }) + } +} +impl super::SBPMessage for MsgGroupDelayDepA { + const MSG_ID: u16 = 146; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Group Delay +/// +/// Please see ICD-GPS-200 (30.3.3.3.1.1) for more details. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgGroupDelayDepB { + pub sender_id: Option, + /// Data Predict Time of Week + pub t_op: GPSTimeSec, + /// GNSS signal identifier + pub sid: GnssSignalDep, + /// bit-field indicating validity of the values, LSB indicating tgd validity + /// etc. 1 = value is valid, 0 = value is not valid. + pub valid: u8, + pub tgd: i16, + pub isc_l1ca: i16, + pub isc_l2c: i16, +} + +impl MsgGroupDelayDepB { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgGroupDelayDepB { + sender_id: None, + t_op: GPSTimeSec::parse(_buf)?, + sid: GnssSignalDep::parse(_buf)?, + valid: _buf.read_u8()?, + tgd: _buf.read_i16::()?, + isc_l1ca: _buf.read_i16::()?, + isc_l2c: _buf.read_i16::()?, + }) + } +} +impl super::SBPMessage for MsgGroupDelayDepB { + const MSG_ID: u16 = 147; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Group Delay +/// +/// Please see ICD-GPS-200 (30.3.3.3.1.1) for more details. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgGroupDelay { + pub sender_id: Option, + /// Data Predict Time of Week + pub t_op: GPSTimeSec, + /// GNSS signal identifier + pub sid: GnssSignal, + /// bit-field indicating validity of the values, LSB indicating tgd validity + /// etc. 1 = value is valid, 0 = value is not valid. + pub valid: u8, + pub tgd: i16, + pub isc_l1ca: i16, + pub isc_l2c: i16, +} + +impl MsgGroupDelay { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgGroupDelay { + sender_id: None, + t_op: GPSTimeSec::parse(_buf)?, + sid: GnssSignal::parse(_buf)?, + valid: _buf.read_u8()?, + tgd: _buf.read_i16::()?, + isc_l1ca: _buf.read_i16::()?, + isc_l2c: _buf.read_i16::()?, + }) + } +} +impl super::SBPMessage for MsgGroupDelay { + const MSG_ID: u16 = 148; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct AlmanacCommonContent { + /// GNSS signal identifier + pub sid: GnssSignal, + /// Reference time of almanac + pub toa: GPSTimeSec, + /// User Range Accuracy + pub ura: f64, + /// Curve fit interval + pub fit_interval: u32, + /// Status of almanac, 1 = valid, 0 = invalid + pub valid: u8, + /// Satellite health status for GPS: - bits 5-7: NAV data health status. + /// See IS-GPS-200H Table 20-VII: NAV Data Health Indications. - bits + /// 0-4: Signal health status. See IS-GPS-200H Table 20-VIII. Codes for + /// Health of SV Signal Components. Satellite health status for GLO: + /// See GLO ICD 5.1 table 5.1 for details - bit 0: C(n), "unhealthy" flag + /// that is transmitted within non-immediate data and indicates overall + /// constellation status at the moment of almanac uploading. '0' + /// indicates malfunction of n-satellite. '1' indicates that n-satellite + /// is operational. - bit 1: Bn(ln), '0' indicates the satellite is + /// operational and suitable for navigation. + pub health_bits: u8, +} + +impl AlmanacCommonContent { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(AlmanacCommonContent { + sid: GnssSignal::parse(_buf)?, + toa: GPSTimeSec::parse(_buf)?, + ura: _buf.read_f64::()?, + fit_interval: _buf.read_u32::()?, + valid: _buf.read_u8()?, + health_bits: _buf.read_u8()?, + }) + } + pub fn parse_array(buf: &mut &[u8]) -> Result, ::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(AlmanacCommonContent::parse(buf)?); + } + Ok(v) + } + + pub fn parse_array_limit( + buf: &mut &[u8], + n: usize, + ) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(AlmanacCommonContent::parse(buf)?); + } + Ok(v) + } +} + +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct AlmanacCommonContentDep { + /// GNSS signal identifier + pub sid: GnssSignalDep, + /// Reference time of almanac + pub toa: GPSTimeSec, + /// User Range Accuracy + pub ura: f64, + /// Curve fit interval + pub fit_interval: u32, + /// Status of almanac, 1 = valid, 0 = invalid + pub valid: u8, + /// Satellite health status for GPS: - bits 5-7: NAV data health status. + /// See IS-GPS-200H Table 20-VII: NAV Data Health Indications. - bits + /// 0-4: Signal health status. See IS-GPS-200H Table 20-VIII. Codes for + /// Health of SV Signal Components. Satellite health status for GLO: + /// See GLO ICD 5.1 table 5.1 for details - bit 0: C(n), "unhealthy" flag + /// that is transmitted within non-immediate data and indicates overall + /// constellation status at the moment of almanac uploading. '0' + /// indicates malfunction of n-satellite. '1' indicates that n-satellite + /// is operational. - bit 1: Bn(ln), '0' indicates the satellite is + /// operational and suitable for navigation. + pub health_bits: u8, +} + +impl AlmanacCommonContentDep { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(AlmanacCommonContentDep { + sid: GnssSignalDep::parse(_buf)?, + toa: GPSTimeSec::parse(_buf)?, + ura: _buf.read_f64::()?, + fit_interval: _buf.read_u32::()?, + valid: _buf.read_u8()?, + health_bits: _buf.read_u8()?, + }) + } + pub fn parse_array(buf: &mut &[u8]) -> Result, ::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(AlmanacCommonContentDep::parse(buf)?); + } + Ok(v) + } + + pub fn parse_array_limit( + buf: &mut &[u8], + n: usize, + ) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(AlmanacCommonContentDep::parse(buf)?); + } + Ok(v) + } +} + +/// Satellite broadcast ephemeris for GPS +/// +/// The almanac message returns a set of satellite orbit parameters. Almanac +/// data is not very precise and is considered valid for up to several months. +/// Please see the Navstar GPS Space Segment/Navigation user interfaces +/// (ICD-GPS-200, Chapter 20.3.3.5.1.2 Almanac Data) for more details. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgAlmanacGPSDep { + pub sender_id: Option, + /// Values common for all almanac types + pub common: AlmanacCommonContentDep, + /// Mean anomaly at reference time + pub m0: f64, + /// Eccentricity of satellite orbit + pub ecc: f64, + /// Square root of the semi-major axis of orbit + pub sqrta: f64, + /// Longitude of ascending node of orbit plane at weekly epoch + pub omega0: f64, + /// Rate of right ascension + pub omegadot: f64, + /// Argument of perigee + pub w: f64, + /// Inclination + pub inc: f64, + /// Polynomial clock correction coefficient (clock bias) + pub af0: f64, + /// Polynomial clock correction coefficient (clock drift) + pub af1: f64, +} + +impl MsgAlmanacGPSDep { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgAlmanacGPSDep { + sender_id: None, + common: AlmanacCommonContentDep::parse(_buf)?, + m0: _buf.read_f64::()?, + ecc: _buf.read_f64::()?, + sqrta: _buf.read_f64::()?, + omega0: _buf.read_f64::()?, + omegadot: _buf.read_f64::()?, + w: _buf.read_f64::()?, + inc: _buf.read_f64::()?, + af0: _buf.read_f64::()?, + af1: _buf.read_f64::()?, + }) + } +} +impl super::SBPMessage for MsgAlmanacGPSDep { + const MSG_ID: u16 = 112; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Satellite broadcast ephemeris for GPS +/// +/// The almanac message returns a set of satellite orbit parameters. Almanac +/// data is not very precise and is considered valid for up to several months. +/// Please see the Navstar GPS Space Segment/Navigation user interfaces +/// (ICD-GPS-200, Chapter 20.3.3.5.1.2 Almanac Data) for more details. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgAlmanacGPS { + pub sender_id: Option, + /// Values common for all almanac types + pub common: AlmanacCommonContent, + /// Mean anomaly at reference time + pub m0: f64, + /// Eccentricity of satellite orbit + pub ecc: f64, + /// Square root of the semi-major axis of orbit + pub sqrta: f64, + /// Longitude of ascending node of orbit plane at weekly epoch + pub omega0: f64, + /// Rate of right ascension + pub omegadot: f64, + /// Argument of perigee + pub w: f64, + /// Inclination + pub inc: f64, + /// Polynomial clock correction coefficient (clock bias) + pub af0: f64, + /// Polynomial clock correction coefficient (clock drift) + pub af1: f64, +} + +impl MsgAlmanacGPS { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgAlmanacGPS { + sender_id: None, + common: AlmanacCommonContent::parse(_buf)?, + m0: _buf.read_f64::()?, + ecc: _buf.read_f64::()?, + sqrta: _buf.read_f64::()?, + omega0: _buf.read_f64::()?, + omegadot: _buf.read_f64::()?, + w: _buf.read_f64::()?, + inc: _buf.read_f64::()?, + af0: _buf.read_f64::()?, + af1: _buf.read_f64::()?, + }) + } +} +impl super::SBPMessage for MsgAlmanacGPS { + const MSG_ID: u16 = 114; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Satellite broadcast ephemeris for GLO +/// +/// The almanac message returns a set of satellite orbit parameters. Almanac +/// data is not very precise and is considered valid for up to several months. +/// Please see the GLO ICD 5.1 "Chapter 4.5 Non-immediate information and +/// almanac" for details. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgAlmanacGloDep { + pub sender_id: Option, + /// Values common for all almanac types + pub common: AlmanacCommonContentDep, + /// Longitude of the first ascending node of the orbit in PZ-90.02 + /// coordinate system + pub lambda_na: f64, + /// Time of the first ascending node passage + pub t_lambda_na: f64, + /// Value of inclination at instant of t_lambda + pub i: f64, + /// Value of Draconian period at instant of t_lambda + pub t: f64, + /// Rate of change of the Draconian period + pub t_dot: f64, + /// Eccentricity at instant of t_lambda + pub epsilon: f64, + /// Argument of perigee at instant of t_lambda + pub omega: f64, +} + +impl MsgAlmanacGloDep { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgAlmanacGloDep { + sender_id: None, + common: AlmanacCommonContentDep::parse(_buf)?, + lambda_na: _buf.read_f64::()?, + t_lambda_na: _buf.read_f64::()?, + i: _buf.read_f64::()?, + t: _buf.read_f64::()?, + t_dot: _buf.read_f64::()?, + epsilon: _buf.read_f64::()?, + omega: _buf.read_f64::()?, + }) + } +} +impl super::SBPMessage for MsgAlmanacGloDep { + const MSG_ID: u16 = 113; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Satellite broadcast ephemeris for GLO +/// +/// The almanac message returns a set of satellite orbit parameters. Almanac +/// data is not very precise and is considered valid for up to several months. +/// Please see the GLO ICD 5.1 "Chapter 4.5 Non-immediate information and +/// almanac" for details. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgAlmanacGlo { + pub sender_id: Option, + /// Values common for all almanac types + pub common: AlmanacCommonContent, + /// Longitude of the first ascending node of the orbit in PZ-90.02 + /// coordinate system + pub lambda_na: f64, + /// Time of the first ascending node passage + pub t_lambda_na: f64, + /// Value of inclination at instant of t_lambda + pub i: f64, + /// Value of Draconian period at instant of t_lambda + pub t: f64, + /// Rate of change of the Draconian period + pub t_dot: f64, + /// Eccentricity at instant of t_lambda + pub epsilon: f64, + /// Argument of perigee at instant of t_lambda + pub omega: f64, +} + +impl MsgAlmanacGlo { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgAlmanacGlo { + sender_id: None, + common: AlmanacCommonContent::parse(_buf)?, + lambda_na: _buf.read_f64::()?, + t_lambda_na: _buf.read_f64::()?, + i: _buf.read_f64::()?, + t: _buf.read_f64::()?, + t_dot: _buf.read_f64::()?, + epsilon: _buf.read_f64::()?, + omega: _buf.read_f64::()?, + }) + } +} +impl super::SBPMessage for MsgAlmanacGlo { + const MSG_ID: u16 = 115; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// GLONASS L1/L2 Code-Phase biases +/// +/// The GLONASS L1/L2 Code-Phase biases allows to perform +/// GPS+GLONASS integer ambiguity resolution for baselines +/// with mixed receiver types (e.g. receiver of different +/// manufacturers) +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgGloBiases { + pub sender_id: Option, + /// GLONASS FDMA signals mask + pub mask: u8, + /// GLONASS L1 C/A Code-Phase Bias + pub l1ca_bias: i16, + /// GLONASS L1 P Code-Phase Bias + pub l1p_bias: i16, + /// GLONASS L2 C/A Code-Phase Bias + pub l2ca_bias: i16, + /// GLONASS L2 P Code-Phase Bias + pub l2p_bias: i16, +} + +impl MsgGloBiases { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgGloBiases { + sender_id: None, + mask: _buf.read_u8()?, + l1ca_bias: _buf.read_i16::()?, + l1p_bias: _buf.read_i16::()?, + l2ca_bias: _buf.read_i16::()?, + l2p_bias: _buf.read_i16::()?, + }) + } +} +impl super::SBPMessage for MsgGloBiases { + const MSG_ID: u16 = 117; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Satellite azimuth and elevation. +/// +/// Satellite azimuth and elevation. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct SvAzEl { + /// GNSS signal identifier + pub sid: GnssSignal, + /// Azimuth angle (range 0..179) + pub az: u8, + /// Elevation angle (range -90..90) + pub el: i8, +} + +impl SvAzEl { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(SvAzEl { + sid: GnssSignal::parse(_buf)?, + az: _buf.read_u8()?, + el: _buf.read_i8()?, + }) + } + pub fn parse_array(buf: &mut &[u8]) -> Result, ::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(SvAzEl::parse(buf)?); + } + Ok(v) + } + + pub fn parse_array_limit(buf: &mut &[u8], n: usize) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(SvAzEl::parse(buf)?); + } + Ok(v) + } +} + +/// Satellite azimuths and elevations +/// +/// Azimuth and elevation angles of all the visible satellites +/// that the device does have ephemeris or almanac for. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgSvAzEl { + pub sender_id: Option, + /// Azimuth and elevation per satellite + pub azel: Vec, +} + +impl MsgSvAzEl { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgSvAzEl { + sender_id: None, + azel: SvAzEl::parse_array(_buf)?, + }) + } +} +impl super::SBPMessage for MsgSvAzEl { + const MSG_ID: u16 = 151; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// OSR corrections +/// +/// The OSR message contains network corrections in an observation-like format +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgOsr { + pub sender_id: Option, + /// Header of a GPS observation message + pub header: ObservationHeader, + /// Network correction for a satellite signal. + pub obs: Vec, +} + +impl MsgOsr { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgOsr { + sender_id: None, + header: ObservationHeader::parse(_buf)?, + obs: PackedOsrContent::parse_array(_buf)?, + }) + } +} +impl super::SBPMessage for MsgOsr { + const MSG_ID: u16 = 1600; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} diff --git a/rust/sbp/src/messages/orientation.rs b/rust/sbp/src/messages/orientation.rs new file mode 100644 index 0000000000..0959160fd7 --- /dev/null +++ b/rust/sbp/src/messages/orientation.rs @@ -0,0 +1,235 @@ +// Copyright (C) 2015-2018 Swift Navigation Inc. +// Contact: Swift Navigation +// +// This source is subject to the license found in the file 'LICENSE' which must +// be be distributed together with this source. All other rights reserved. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. + +//**************************************************************************** +// Automatically generated from yaml/swiftnav/sbp/orientation.yaml +// with generate.py. Please do not hand edit! +//****************************************************************************/ +//! Orientation Messages + +extern crate byteorder; +#[allow(unused_imports)] +use self::byteorder::{LittleEndian, ReadBytesExt}; + +/// Heading relative to True North +/// +/// This message reports the baseline heading pointing from the base station +/// to the rover relative to True North. The full GPS time is given by the +/// preceding MSG_GPS_TIME with the matching time-of-week (tow). It is intended +/// that time-matched RTK mode is used when the base station is moving. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgBaselineHeading { + pub sender_id: Option, + /// GPS Time of Week + pub tow: u32, + /// Heading + pub heading: u32, + /// Number of satellites used in solution + pub n_sats: u8, + /// Status flags + pub flags: u8, +} + +impl MsgBaselineHeading { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgBaselineHeading { + sender_id: None, + tow: _buf.read_u32::()?, + heading: _buf.read_u32::()?, + n_sats: _buf.read_u8()?, + flags: _buf.read_u8()?, + }) + } +} +impl super::SBPMessage for MsgBaselineHeading { + const MSG_ID: u16 = 527; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Quaternion 4 component vector +/// +/// This message reports the quaternion vector describing the vehicle body frame's orientation +/// with respect to a local-level NED frame. The components of the vector should sum to a unit +/// vector assuming that the LSB of each component as a value of 2^-31. This message will only +/// be available in future INS versions of Swift Products and is not produced by Piksi Multi +/// or Duro. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgOrientQuat { + pub sender_id: Option, + /// GPS Time of Week + pub tow: u32, + /// Real component + pub w: i32, + /// 1st imaginary component + pub x: i32, + /// 2nd imaginary component + pub y: i32, + /// 3rd imaginary component + pub z: i32, + /// Estimated standard deviation of w + pub w_accuracy: f32, + /// Estimated standard deviation of x + pub x_accuracy: f32, + /// Estimated standard deviation of y + pub y_accuracy: f32, + /// Estimated standard deviation of z + pub z_accuracy: f32, + /// Status flags + pub flags: u8, +} + +impl MsgOrientQuat { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgOrientQuat { + sender_id: None, + tow: _buf.read_u32::()?, + w: _buf.read_i32::()?, + x: _buf.read_i32::()?, + y: _buf.read_i32::()?, + z: _buf.read_i32::()?, + w_accuracy: _buf.read_f32::()?, + x_accuracy: _buf.read_f32::()?, + y_accuracy: _buf.read_f32::()?, + z_accuracy: _buf.read_f32::()?, + flags: _buf.read_u8()?, + }) + } +} +impl super::SBPMessage for MsgOrientQuat { + const MSG_ID: u16 = 544; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Euler angles +/// +/// This message reports the yaw, pitch, and roll angles of the vehicle body frame. +/// The rotations should applied intrinsically in the order yaw, pitch, and roll +/// in order to rotate the from a frame aligned with the local-level NED frame +/// to the vehicle body frame. This message will only be available in future +/// INS versions of Swift Products and is not produced by Piksi Multi or Duro. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgOrientEuler { + pub sender_id: Option, + /// GPS Time of Week + pub tow: u32, + /// rotation about the forward axis of the vehicle + pub roll: i32, + /// rotation about the rightward axis of the vehicle + pub pitch: i32, + /// rotation about the downward axis of the vehicle + pub yaw: i32, + /// Estimated standard deviation of roll + pub roll_accuracy: f32, + /// Estimated standard deviation of pitch + pub pitch_accuracy: f32, + /// Estimated standard deviation of yaw + pub yaw_accuracy: f32, + /// Status flags + pub flags: u8, +} + +impl MsgOrientEuler { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgOrientEuler { + sender_id: None, + tow: _buf.read_u32::()?, + roll: _buf.read_i32::()?, + pitch: _buf.read_i32::()?, + yaw: _buf.read_i32::()?, + roll_accuracy: _buf.read_f32::()?, + pitch_accuracy: _buf.read_f32::()?, + yaw_accuracy: _buf.read_f32::()?, + flags: _buf.read_u8()?, + }) + } +} +impl super::SBPMessage for MsgOrientEuler { + const MSG_ID: u16 = 545; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Vehicle Body Frame instantaneous angular rates +/// +/// This message reports the orientation rates in the vehicle body frame. +/// The values represent the measurements a strapped down gyroscope would +/// make and are not equivalent to the time derivative of the Euler angles. +/// The orientation and origin of the user frame is specified via device settings. +/// By convention, the vehicle x-axis is expected to be aligned with the forward +/// direction, while the vehicle y-axis is expected to be aligned with the right +/// direction, and the vehicle z-axis should be aligned with the down direction. +/// This message will only be available in future INS versions of Swift Products +/// and is not produced by Piksi Multi or Duro. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgAngularRate { + pub sender_id: Option, + /// GPS Time of Week + pub tow: u32, + /// angular rate about x axis + pub x: i32, + /// angular rate about y axis + pub y: i32, + /// angular rate about z axis + pub z: i32, + /// Status flags + pub flags: u8, +} + +impl MsgAngularRate { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgAngularRate { + sender_id: None, + tow: _buf.read_u32::()?, + x: _buf.read_i32::()?, + y: _buf.read_i32::()?, + z: _buf.read_i32::()?, + flags: _buf.read_u8()?, + }) + } +} +impl super::SBPMessage for MsgAngularRate { + const MSG_ID: u16 = 546; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} diff --git a/rust/sbp/src/messages/piksi.rs b/rust/sbp/src/messages/piksi.rs new file mode 100644 index 0000000000..efb11802fe --- /dev/null +++ b/rust/sbp/src/messages/piksi.rs @@ -0,0 +1,1147 @@ +// Copyright (C) 2015-2018 Swift Navigation Inc. +// Contact: Swift Navigation +// +// This source is subject to the license found in the file 'LICENSE' which must +// be be distributed together with this source. All other rights reserved. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. + +//**************************************************************************** +// Automatically generated from yaml/swiftnav/sbp/piksi.yaml +// with generate.py. Please do not hand edit! +//****************************************************************************/ +//! System health, configuration, and diagnostic messages specific to +//! the Piksi L1 receiver, including a variety of legacy messages that +//! may no longer be used. +//! + +extern crate byteorder; +#[allow(unused_imports)] +use self::byteorder::{LittleEndian, ReadBytesExt}; +use super::gnss::*; + +/// Legacy message to load satellite almanac (host => Piksi) +/// +/// This is a legacy message for sending and loading a satellite +/// alamanac onto the Piksi's flash memory from the host. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgAlmanac { + pub sender_id: Option, +} + +impl MsgAlmanac { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgAlmanac { sender_id: None }) + } +} +impl super::SBPMessage for MsgAlmanac { + const MSG_ID: u16 = 105; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Send GPS time from host (host => Piksi) +/// +/// This message sets up timing functionality using a coarse GPS +/// time estimate sent by the host. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgSetTime { + pub sender_id: Option, +} + +impl MsgSetTime { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgSetTime { sender_id: None }) + } +} +impl super::SBPMessage for MsgSetTime { + const MSG_ID: u16 = 104; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Reset the device (host => Piksi) +/// +/// This message from the host resets the Piksi back into the +/// bootloader. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgReset { + pub sender_id: Option, + /// Reset flags + pub flags: u32, +} + +impl MsgReset { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgReset { + sender_id: None, + flags: _buf.read_u32::()?, + }) + } +} +impl super::SBPMessage for MsgReset { + const MSG_ID: u16 = 182; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Reset the device (host => Piksi) +/// +/// This message from the host resets the Piksi back into the +/// bootloader. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgResetDep { + pub sender_id: Option, +} + +impl MsgResetDep { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgResetDep { sender_id: None }) + } +} +impl super::SBPMessage for MsgResetDep { + const MSG_ID: u16 = 178; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Legacy message for CW interference channel (Piksi => host) +/// +/// This is an unused legacy message for result reporting from the +/// CW interference channel on the SwiftNAP. This message will be +/// removed in a future release. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgCwResults { + pub sender_id: Option, +} + +impl MsgCwResults { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgCwResults { sender_id: None }) + } +} +impl super::SBPMessage for MsgCwResults { + const MSG_ID: u16 = 192; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Legacy message for CW interference channel (host => Piksi) +/// +/// This is an unused legacy message from the host for starting +/// the CW interference channel on the SwiftNAP. This message will +/// be removed in a future release. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgCwStart { + pub sender_id: Option, +} + +impl MsgCwStart { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgCwStart { sender_id: None }) + } +} +impl super::SBPMessage for MsgCwStart { + const MSG_ID: u16 = 193; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Reset IAR filters (host => Piksi) +/// +/// This message resets either the DGNSS Kalman filters or Integer +/// Ambiguity Resolution (IAR) process. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgResetFilters { + pub sender_id: Option, + /// Filter flags + pub filter: u8, +} + +impl MsgResetFilters { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgResetFilters { + sender_id: None, + filter: _buf.read_u8()?, + }) + } +} +impl super::SBPMessage for MsgResetFilters { + const MSG_ID: u16 = 34; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Deprecated +/// +/// Deprecated +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgInitBaseDep { + pub sender_id: Option, +} + +impl MsgInitBaseDep { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgInitBaseDep { sender_id: None }) + } +} +impl super::SBPMessage for MsgInitBaseDep { + const MSG_ID: u16 = 35; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// State of an RTOS thread +/// +/// The thread usage message from the device reports real-time +/// operating system (RTOS) thread usage statistics for the named +/// thread. The reported percentage values must be normalized. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgThreadState { + pub sender_id: Option, + /// Thread name (NULL terminated) + pub name: String, + /// Percentage cpu use for this thread. Values range from 0 - 1000 and needs + /// to be renormalized to 100 + pub cpu: u16, + /// Free stack space for this thread + pub stack_free: u32, +} + +impl MsgThreadState { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgThreadState { + sender_id: None, + name: ::parser::read_string_limit(_buf, 20)?, + cpu: _buf.read_u16::()?, + stack_free: _buf.read_u32::()?, + }) + } +} +impl super::SBPMessage for MsgThreadState { + const MSG_ID: u16 = 23; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// State of the UART channel +/// +/// Throughput, utilization, and error counts on the RX/TX buffers +/// of this UART channel. The reported percentage values must +/// be normalized. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct UARTChannel { + /// UART transmit throughput + pub tx_throughput: f32, + /// UART receive throughput + pub rx_throughput: f32, + /// UART CRC error count + pub crc_error_count: u16, + /// UART IO error count + pub io_error_count: u16, + /// UART transmit buffer percentage utilization (ranges from 0 to 255) + pub tx_buffer_level: u8, + /// UART receive buffer percentage utilization (ranges from 0 to 255) + pub rx_buffer_level: u8, +} + +impl UARTChannel { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(UARTChannel { + tx_throughput: _buf.read_f32::()?, + rx_throughput: _buf.read_f32::()?, + crc_error_count: _buf.read_u16::()?, + io_error_count: _buf.read_u16::()?, + tx_buffer_level: _buf.read_u8()?, + rx_buffer_level: _buf.read_u8()?, + }) + } + pub fn parse_array(buf: &mut &[u8]) -> Result, ::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(UARTChannel::parse(buf)?); + } + Ok(v) + } + + pub fn parse_array_limit(buf: &mut &[u8], n: usize) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(UARTChannel::parse(buf)?); + } + Ok(v) + } +} + +/// base station observation message receipt period +/// +/// Statistics on the period of observations received from the base +/// station. As complete observation sets are received, their time +/// of reception is compared with the prior set''s time of reception. +/// This measurement provides a proxy for link quality as incomplete +/// or missing sets will increase the period. Long periods +/// can cause momentary RTK solution outages. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct Period { + /// Average period + pub avg: i32, + /// Minimum period + pub pmin: i32, + /// Maximum period + pub pmax: i32, + /// Smoothed estimate of the current period + pub current: i32, +} + +impl Period { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(Period { + avg: _buf.read_i32::()?, + pmin: _buf.read_i32::()?, + pmax: _buf.read_i32::()?, + current: _buf.read_i32::()?, + }) + } + pub fn parse_array(buf: &mut &[u8]) -> Result, ::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(Period::parse(buf)?); + } + Ok(v) + } + + pub fn parse_array_limit(buf: &mut &[u8], n: usize) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(Period::parse(buf)?); + } + Ok(v) + } +} + +/// Receiver-to-base station latency +/// +/// Statistics on the latency of observations received from the base +/// station. As observation packets are received their GPS time is +/// compared to the current GPS time calculated locally by the +/// receiver to give a precise measurement of the end-to-end +/// communication latency in the system. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct Latency { + /// Average latency + pub avg: i32, + /// Minimum latency + pub lmin: i32, + /// Maximum latency + pub lmax: i32, + /// Smoothed estimate of the current latency + pub current: i32, +} + +impl Latency { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(Latency { + avg: _buf.read_i32::()?, + lmin: _buf.read_i32::()?, + lmax: _buf.read_i32::()?, + current: _buf.read_i32::()?, + }) + } + pub fn parse_array(buf: &mut &[u8]) -> Result, ::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(Latency::parse(buf)?); + } + Ok(v) + } + + pub fn parse_array_limit(buf: &mut &[u8], n: usize) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(Latency::parse(buf)?); + } + Ok(v) + } +} + +/// State of the UART channels +/// +/// The UART message reports data latency and throughput of the UART +/// channels providing SBP I/O. On the default Piksi configuration, +/// UARTs A and B are used for telemetry radios, but can also be +/// host access ports for embedded hosts, or other interfaces in +/// future. The reported percentage values must be normalized. +/// Observations latency and period can be used to assess the +/// health of the differential corrections link. Latency provides +/// the timeliness of received base observations while the +/// period indicates their likelihood of transmission. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgUartState { + pub sender_id: Option, + /// State of UART A + pub uart_a: UARTChannel, + /// State of UART B + pub uart_b: UARTChannel, + /// State of UART FTDI (USB logger) + pub uart_ftdi: UARTChannel, + /// UART communication latency + pub latency: Latency, + /// Observation receipt period + pub obs_period: Period, +} + +impl MsgUartState { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgUartState { + sender_id: None, + uart_a: UARTChannel::parse(_buf)?, + uart_b: UARTChannel::parse(_buf)?, + uart_ftdi: UARTChannel::parse(_buf)?, + latency: Latency::parse(_buf)?, + obs_period: Period::parse(_buf)?, + }) + } +} +impl super::SBPMessage for MsgUartState { + const MSG_ID: u16 = 29; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Deprecated +/// +/// Deprecated +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgUartStateDepa { + pub sender_id: Option, + /// State of UART A + pub uart_a: UARTChannel, + /// State of UART B + pub uart_b: UARTChannel, + /// State of UART FTDI (USB logger) + pub uart_ftdi: UARTChannel, + /// UART communication latency + pub latency: Latency, +} + +impl MsgUartStateDepa { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgUartStateDepa { + sender_id: None, + uart_a: UARTChannel::parse(_buf)?, + uart_b: UARTChannel::parse(_buf)?, + uart_ftdi: UARTChannel::parse(_buf)?, + latency: Latency::parse(_buf)?, + }) + } +} +impl super::SBPMessage for MsgUartStateDepa { + const MSG_ID: u16 = 24; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// State of the Integer Ambiguity Resolution (IAR) process +/// +/// This message reports the state of the Integer Ambiguity +/// Resolution (IAR) process, which resolves unknown integer +/// ambiguities from double-differenced carrier-phase measurements +/// from satellite observations. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgIarState { + pub sender_id: Option, + /// Number of integer ambiguity hypotheses remaining + pub num_hyps: u32, +} + +impl MsgIarState { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgIarState { + sender_id: None, + num_hyps: _buf.read_u32::()?, + }) + } +} +impl super::SBPMessage for MsgIarState { + const MSG_ID: u16 = 25; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Mask a satellite from use in Piksi subsystems +/// +/// This message allows setting a mask to prevent a particular satellite +/// from being used in various Piksi subsystems. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgMaskSatellite { + pub sender_id: Option, + /// Mask of systems that should ignore this satellite. + pub mask: u8, + /// GNSS signal for which the mask is applied + pub sid: GnssSignal, +} + +impl MsgMaskSatellite { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgMaskSatellite { + sender_id: None, + mask: _buf.read_u8()?, + sid: GnssSignal::parse(_buf)?, + }) + } +} +impl super::SBPMessage for MsgMaskSatellite { + const MSG_ID: u16 = 43; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Deprecated +/// +/// Deprecated. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgMaskSatelliteDep { + pub sender_id: Option, + /// Mask of systems that should ignore this satellite. + pub mask: u8, + /// GNSS signal for which the mask is applied + pub sid: GnssSignalDep, +} + +impl MsgMaskSatelliteDep { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgMaskSatelliteDep { + sender_id: None, + mask: _buf.read_u8()?, + sid: GnssSignalDep::parse(_buf)?, + }) + } +} +impl super::SBPMessage for MsgMaskSatelliteDep { + const MSG_ID: u16 = 27; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Device temperature and voltage levels +/// +/// This message contains temperature and voltage level measurements from the +/// processor's monitoring system and the RF frontend die temperature if +/// available. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgDeviceMonitor { + pub sender_id: Option, + /// Device V_in + pub dev_vin: i16, + /// Processor V_int + pub cpu_vint: i16, + /// Processor V_aux + pub cpu_vaux: i16, + /// Processor temperature + pub cpu_temperature: i16, + /// Frontend temperature (if available) + pub fe_temperature: i16, +} + +impl MsgDeviceMonitor { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgDeviceMonitor { + sender_id: None, + dev_vin: _buf.read_i16::()?, + cpu_vint: _buf.read_i16::()?, + cpu_vaux: _buf.read_i16::()?, + cpu_temperature: _buf.read_i16::()?, + fe_temperature: _buf.read_i16::()?, + }) + } +} +impl super::SBPMessage for MsgDeviceMonitor { + const MSG_ID: u16 = 181; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Execute a command (host => device) +/// +/// Request the recipient to execute an command. +/// Output will be sent in MSG_LOG messages, and the exit +/// code will be returned with MSG_COMMAND_RESP. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgCommandReq { + pub sender_id: Option, + /// Sequence number + pub sequence: u32, + /// Command line to execute + pub command: String, +} + +impl MsgCommandReq { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgCommandReq { + sender_id: None, + sequence: _buf.read_u32::()?, + command: ::parser::read_string(_buf)?, + }) + } +} +impl super::SBPMessage for MsgCommandReq { + const MSG_ID: u16 = 184; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Exit code from executed command (device => host) +/// +/// The response to MSG_COMMAND_REQ with the return code of +/// the command. A return code of zero indicates success. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgCommandResp { + pub sender_id: Option, + /// Sequence number + pub sequence: u32, + /// Exit code + pub code: i32, +} + +impl MsgCommandResp { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgCommandResp { + sender_id: None, + sequence: _buf.read_u32::()?, + code: _buf.read_i32::()?, + }) + } +} +impl super::SBPMessage for MsgCommandResp { + const MSG_ID: u16 = 185; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Command output +/// +/// Returns the standard output and standard error of the +/// command requested by MSG_COMMAND_REQ. +/// The sequence number can be used to filter for filtering +/// the correct command. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgCommandOutput { + pub sender_id: Option, + /// Sequence number + pub sequence: u32, + /// Line of standard output or standard error + pub line: String, +} + +impl MsgCommandOutput { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgCommandOutput { + sender_id: None, + sequence: _buf.read_u32::()?, + line: ::parser::read_string(_buf)?, + }) + } +} +impl super::SBPMessage for MsgCommandOutput { + const MSG_ID: u16 = 188; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Request state of Piksi network interfaces +/// +/// Request state of Piksi network interfaces. +/// Output will be sent in MSG_NETWORK_STATE_RESP messages +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgNetworkStateReq { + pub sender_id: Option, +} + +impl MsgNetworkStateReq { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgNetworkStateReq { sender_id: None }) + } +} +impl super::SBPMessage for MsgNetworkStateReq { + const MSG_ID: u16 = 186; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// State of network interface +/// +/// The state of a network interface on the Piksi. +/// Data is made to reflect output of ifaddrs struct returned by getifaddrs +/// in c. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgNetworkStateResp { + pub sender_id: Option, + /// IPv4 address (all zero when unavailable) + pub ipv4_address: Vec, + /// IPv4 netmask CIDR notation + pub ipv4_mask_size: u8, + /// IPv6 address (all zero when unavailable) + pub ipv6_address: Vec, + /// IPv6 netmask CIDR notation + pub ipv6_mask_size: u8, + /// Number of Rx bytes + pub rx_bytes: u32, + /// Number of Tx bytes + pub tx_bytes: u32, + /// Interface Name + pub interface_name: String, + /// Interface flags from SIOCGIFFLAGS + pub flags: u32, +} + +impl MsgNetworkStateResp { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgNetworkStateResp { + sender_id: None, + ipv4_address: ::parser::read_u8_array_limit(_buf, 4)?, + ipv4_mask_size: _buf.read_u8()?, + ipv6_address: ::parser::read_u8_array_limit(_buf, 16)?, + ipv6_mask_size: _buf.read_u8()?, + rx_bytes: _buf.read_u32::()?, + tx_bytes: _buf.read_u32::()?, + interface_name: ::parser::read_string_limit(_buf, 16)?, + flags: _buf.read_u32::()?, + }) + } +} +impl super::SBPMessage for MsgNetworkStateResp { + const MSG_ID: u16 = 187; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Bandwidth usage measurement for a single interface. +/// +/// The bandwidth usage for each interface can be reported +/// within this struct and utilize multiple fields to fully +/// specify the type of traffic that is being tracked. As +/// either the interval of collection or the collection time +/// may vary, both a timestamp and period field is provided, +/// though may not necessarily be populated with a value. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct NetworkUsage { + /// Duration over which the measurement was collected + pub duration: u64, + /// Number of bytes handled in total within period + pub total_bytes: u64, + /// Number of bytes transmitted within period + pub rx_bytes: u32, + /// Number of bytes received within period + pub tx_bytes: u32, + /// Interface Name + pub interface_name: String, +} + +impl NetworkUsage { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(NetworkUsage { + duration: _buf.read_u64::()?, + total_bytes: _buf.read_u64::()?, + rx_bytes: _buf.read_u32::()?, + tx_bytes: _buf.read_u32::()?, + interface_name: ::parser::read_string_limit(_buf, 16)?, + }) + } + pub fn parse_array(buf: &mut &[u8]) -> Result, ::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(NetworkUsage::parse(buf)?); + } + Ok(v) + } + + pub fn parse_array_limit(buf: &mut &[u8], n: usize) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(NetworkUsage::parse(buf)?); + } + Ok(v) + } +} + +/// Bandwidth usage reporting message +/// +/// The bandwidth usage, a list of usage by interface. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgNetworkBandwidthUsage { + pub sender_id: Option, + /// Usage measurement array + pub interfaces: Vec, +} + +impl MsgNetworkBandwidthUsage { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgNetworkBandwidthUsage { + sender_id: None, + interfaces: NetworkUsage::parse_array(_buf)?, + }) + } +} +impl super::SBPMessage for MsgNetworkBandwidthUsage { + const MSG_ID: u16 = 189; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Cell modem information update message +/// +/// If a cell modem is present on a piksi device, this message +/// will be send periodically to update the host on the status +/// of the modem and its various parameters. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgCellModemStatus { + pub sender_id: Option, + /// Received cell signal strength in dBm, zero translates to unknown + pub signal_strength: i8, + /// BER as reported by the modem, zero translates to unknown + pub signal_error_rate: f32, + /// Unspecified data TBD for this schema + pub reserved: Vec, +} + +impl MsgCellModemStatus { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgCellModemStatus { + sender_id: None, + signal_strength: _buf.read_i8()?, + signal_error_rate: _buf.read_f32::()?, + reserved: ::parser::read_u8_array(_buf)?, + }) + } +} +impl super::SBPMessage for MsgCellModemStatus { + const MSG_ID: u16 = 190; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Deprecated +/// +/// Deprecated. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgSpecanDep { + pub sender_id: Option, + /// Channel ID + pub channel_tag: u16, + /// Receiver time of this observation + pub t: GPSTimeDep, + /// Reference frequency of this packet + pub freq_ref: f32, + /// Frequency step of points in this packet + pub freq_step: f32, + /// Reference amplitude of this packet + pub amplitude_ref: f32, + /// Amplitude unit value of points in this packet + pub amplitude_unit: f32, + /// Amplitude values (in the above units) of points in this packet + pub amplitude_value: Vec, +} + +impl MsgSpecanDep { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgSpecanDep { + sender_id: None, + channel_tag: _buf.read_u16::()?, + t: GPSTimeDep::parse(_buf)?, + freq_ref: _buf.read_f32::()?, + freq_step: _buf.read_f32::()?, + amplitude_ref: _buf.read_f32::()?, + amplitude_unit: _buf.read_f32::()?, + amplitude_value: ::parser::read_u8_array(_buf)?, + }) + } +} +impl super::SBPMessage for MsgSpecanDep { + const MSG_ID: u16 = 80; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Spectrum analyzer +/// +/// Spectrum analyzer packet. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgSpecan { + pub sender_id: Option, + /// Channel ID + pub channel_tag: u16, + /// Receiver time of this observation + pub t: GPSTime, + /// Reference frequency of this packet + pub freq_ref: f32, + /// Frequency step of points in this packet + pub freq_step: f32, + /// Reference amplitude of this packet + pub amplitude_ref: f32, + /// Amplitude unit value of points in this packet + pub amplitude_unit: f32, + /// Amplitude values (in the above units) of points in this packet + pub amplitude_value: Vec, +} + +impl MsgSpecan { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgSpecan { + sender_id: None, + channel_tag: _buf.read_u16::()?, + t: GPSTime::parse(_buf)?, + freq_ref: _buf.read_f32::()?, + freq_step: _buf.read_f32::()?, + amplitude_ref: _buf.read_f32::()?, + amplitude_unit: _buf.read_f32::()?, + amplitude_value: ::parser::read_u8_array(_buf)?, + }) + } +} +impl super::SBPMessage for MsgSpecan { + const MSG_ID: u16 = 81; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// RF AGC status +/// +/// This message describes the gain of each channel in the receiver frontend. Each +/// gain is encoded as a non-dimensional percentage relative to the maximum range +/// possible for the gain stage of the frontend. By convention, each gain array +/// has 8 entries and the index of the array corresponding to the index of the rf channel +/// in the frontend. A gain of 127 percent encodes that rf channel is not present in the hardware. +/// A negative value implies an error for the particular gain stage as reported by the frontend. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgFrontEndGain { + pub sender_id: Option, + /// RF gain for each frontend channel + pub rf_gain: Vec, + /// Intermediate frequency gain for each frontend channel + pub if_gain: Vec, +} + +impl MsgFrontEndGain { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgFrontEndGain { + sender_id: None, + rf_gain: ::parser::read_s8_array_limit(_buf, 8)?, + if_gain: ::parser::read_s8_array_limit(_buf, 8)?, + }) + } +} +impl super::SBPMessage for MsgFrontEndGain { + const MSG_ID: u16 = 191; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} diff --git a/rust/sbp/src/messages/sbas.rs b/rust/sbp/src/messages/sbas.rs new file mode 100644 index 0000000000..8b8e74350e --- /dev/null +++ b/rust/sbp/src/messages/sbas.rs @@ -0,0 +1,62 @@ +// Copyright (C) 2015-2018 Swift Navigation Inc. +// Contact: Swift Navigation +// +// This source is subject to the license found in the file 'LICENSE' which must +// be be distributed together with this source. All other rights reserved. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. + +//**************************************************************************** +// Automatically generated from yaml/swiftnav/sbp/sbas.yaml +// with generate.py. Please do not hand edit! +//****************************************************************************/ +//! SBAS data + +extern crate byteorder; +#[allow(unused_imports)] +use self::byteorder::{LittleEndian, ReadBytesExt}; +use super::gnss::*; + +/// Raw SBAS data +/// +/// This message is sent once per second per SBAS satellite. ME checks the +/// parity of the data block and sends only blocks that pass the check. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgSbasRaw { + pub sender_id: Option, + /// GNSS signal identifier. + pub sid: GnssSignal, + /// GPS time-of-week at the start of the data block. + pub tow: u32, + /// SBAS message type (0-63) + pub message_type: u8, + /// Raw SBAS data field of 212 bits (last byte padded with zeros). + pub data: Vec, +} + +impl MsgSbasRaw { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgSbasRaw { + sender_id: None, + sid: GnssSignal::parse(_buf)?, + tow: _buf.read_u32::()?, + message_type: _buf.read_u8()?, + data: ::parser::read_u8_array_limit(_buf, 27)?, + }) + } +} +impl super::SBPMessage for MsgSbasRaw { + const MSG_ID: u16 = 30583; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} diff --git a/rust/sbp/src/messages/settings.rs b/rust/sbp/src/messages/settings.rs new file mode 100644 index 0000000000..93138f71f2 --- /dev/null +++ b/rust/sbp/src/messages/settings.rs @@ -0,0 +1,416 @@ +// Copyright (C) 2015-2018 Swift Navigation Inc. +// Contact: Swift Navigation +// +// This source is subject to the license found in the file 'LICENSE' which must +// be be distributed together with this source. All other rights reserved. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. + +//**************************************************************************** +// Automatically generated from yaml/swiftnav/sbp/settings.yaml +// with generate.py. Please do not hand edit! +//****************************************************************************/ +//! +//! Messages for reading, writing, and discovering device settings. Settings +//! with a "string" field have multiple values in this field delimited with a +//! null character (the c style null terminator). For instance, when querying +//! the 'firmware_version' setting in the 'system_info' section, the following +//! array of characters needs to be sent for the string field in +//! MSG_SETTINGS_READ: "system_info\0firmware_version\0", where the delimiting +//! null characters are specified with the escape sequence '\0' and all +//! quotation marks should be omitted. +//! +//! +//! In the message descriptions below, the generic strings SECTION_SETTING and +//! SETTING are used to refer to the two strings that comprise the identifier +//! of an individual setting.In firmware_version example above, SECTION_SETTING +//! is the 'system_info', and the SETTING portion is 'firmware_version'. +//! +//! See the "Software Settings Manual" on support.swiftnav.com for detailed +//! documentation about all settings and sections available for each Swift +//! firmware version. Settings manuals are available for each firmware version +//! at the following link: @@https://support.swiftnav.com/customer/en/portal/articles/2628580-piksi-multi-specifications#settings[Piksi Multi Specifications]. +//! The latest settings document is also available at the following link: +//! @@http://swiftnav.com/latest/piksi-multi-settings[Latest settings document] . +//! See lastly @@https://github.com/swift-nav/piksi_tools/blob/master/piksi_tools/settings.py[settings.py] , +//! the open source python command line utility for reading, writing, and +//! saving settings in the piksi_tools repository on github as a helpful +//! reference and example. +//! + +extern crate byteorder; +#[allow(unused_imports)] +use self::byteorder::{LittleEndian, ReadBytesExt}; + +/// Save settings to flash (host => device) +/// +/// The save settings message persists the device's current settings +/// configuration to its onboard flash memory file system. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgSettingsSave { + pub sender_id: Option, +} + +impl MsgSettingsSave { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgSettingsSave { sender_id: None }) + } +} +impl super::SBPMessage for MsgSettingsSave { + const MSG_ID: u16 = 161; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Write device configuration settings (host => device) +/// +/// The setting message writes the device configuration for a particular +/// setting via A NULL-terminated and NULL-delimited string with contents +/// "SECTION_SETTING\0SETTING\0VALUE\0" where the '\0' escape sequence denotes +/// the NULL character and where quotation marks are omitted. A device will +/// only process to this message when it is received from sender ID 0x42. +/// An example string that could be sent to a device is +/// "solution\0soln_freq\010\0". +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgSettingsWrite { + pub sender_id: Option, + /// A NULL-terminated and NULL-delimited string with contents + /// "SECTION_SETTING\0SETTING\0VALUE\0" + pub setting: String, +} + +impl MsgSettingsWrite { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgSettingsWrite { + sender_id: None, + setting: ::parser::read_string(_buf)?, + }) + } +} +impl super::SBPMessage for MsgSettingsWrite { + const MSG_ID: u16 = 160; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Acknowledgement with status of MSG_SETTINGS_WRITE +/// +/// Return the status of a write request with the new value of the +/// setting. If the requested value is rejected, the current value +/// will be returned. The string field is a NULL-terminated and NULL-delimited +/// string with contents "SECTION_SETTING\0SETTING\0VALUE\0" where the '\0' +/// escape sequence denotes the NULL character and where quotation marks +/// are omitted. An example string that could be sent from device is +/// "solution\0soln_freq\010\0". +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgSettingsWriteResp { + pub sender_id: Option, + /// Write status + pub status: u8, + /// A NULL-terminated and delimited string with contents + /// "SECTION_SETTING\0SETTING\0VALUE\0" + pub setting: String, +} + +impl MsgSettingsWriteResp { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgSettingsWriteResp { + sender_id: None, + status: _buf.read_u8()?, + setting: ::parser::read_string(_buf)?, + }) + } +} +impl super::SBPMessage for MsgSettingsWriteResp { + const MSG_ID: u16 = 175; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Read device configuration settings (host => device) +/// +/// The setting message that reads the device configuration. The string +/// field is a NULL-terminated and NULL-delimited string with contents +/// "SECTION_SETTING\0SETTING\0" where the '\0' escape sequence denotes the +/// NULL character and where quotation marks are omitted. An example +/// string that could be sent to a device is "solution\0soln_freq\0". A +/// device will only respond to this message when it is received from +/// sender ID 0x42. A device should respond with a MSG_SETTINGS_READ_RESP +/// message (msg_id 0x00A5). +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgSettingsReadReq { + pub sender_id: Option, + /// A NULL-terminated and NULL-delimited string with contents + /// "SECTION_SETTING\0SETTING\0" + pub setting: String, +} + +impl MsgSettingsReadReq { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgSettingsReadReq { + sender_id: None, + setting: ::parser::read_string(_buf)?, + }) + } +} +impl super::SBPMessage for MsgSettingsReadReq { + const MSG_ID: u16 = 164; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Read device configuration settings (host <= device) +/// +/// The setting message wich which the device responds after a +/// MSG_SETTING_READ_REQ is sent to device. The string field is a +/// NULL-terminated and NULL-delimited string with contents +/// "SECTION_SETTING\0SETTING\0VALUE\0" where the '\0' escape sequence +/// denotes the NULL character and where quotation marks are omitted. An +/// example string that could be sent from device is +/// "solution\0soln_freq\010\0". +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgSettingsReadResp { + pub sender_id: Option, + /// A NULL-terminated and NULL-delimited string with contents + /// "SECTION_SETTING\0SETTING\0VALUE\0" + pub setting: String, +} + +impl MsgSettingsReadResp { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgSettingsReadResp { + sender_id: None, + setting: ::parser::read_string(_buf)?, + }) + } +} +impl super::SBPMessage for MsgSettingsReadResp { + const MSG_ID: u16 = 165; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Read setting by direct index (host => device) +/// +/// The settings message for iterating through the settings +/// values. A device will respond to this message with a +/// "MSG_SETTINGS_READ_BY_INDEX_RESP". +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgSettingsReadByIndexReq { + pub sender_id: Option, + /// An index into the device settings, with values ranging from 0 to + /// length(settings) + pub index: u16, +} + +impl MsgSettingsReadByIndexReq { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgSettingsReadByIndexReq { + sender_id: None, + index: _buf.read_u16::()?, + }) + } +} +impl super::SBPMessage for MsgSettingsReadByIndexReq { + const MSG_ID: u16 = 162; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Read setting by direct index (host <= device) +/// +/// The settings message that reports the value of a setting at an index. +/// +/// In the string field, it reports NULL-terminated and delimited string +/// with contents "SECTION_SETTING\0SETTING\0VALUE\0FORMAT_TYPE\0". where +/// the '\0' escape sequence denotes the NULL character and where quotation +/// marks are omitted. The FORMAT_TYPE field is optional and denotes +/// possible string values of the setting as a hint to the user. If +/// included, the format type portion of the string has the format +/// "enum:value1,value2,value3". An example string that could be sent from +/// the device is "simulator\0enabled\0True\0enum:True,False\0" +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgSettingsReadByIndexResp { + pub sender_id: Option, + /// An index into the device settings, with values ranging from 0 to + /// length(settings) + pub index: u16, + /// A NULL-terminated and delimited string with contents + /// "SECTION_SETTING\0SETTING\0VALUE\0FORMAT_TYPE\0" + pub setting: String, +} + +impl MsgSettingsReadByIndexResp { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgSettingsReadByIndexResp { + sender_id: None, + index: _buf.read_u16::()?, + setting: ::parser::read_string(_buf)?, + }) + } +} +impl super::SBPMessage for MsgSettingsReadByIndexResp { + const MSG_ID: u16 = 167; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Finished reading settings (host <= device) +/// +/// The settings message for indicating end of the settings values. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgSettingsReadByIndexDone { + pub sender_id: Option, +} + +impl MsgSettingsReadByIndexDone { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgSettingsReadByIndexDone { sender_id: None }) + } +} +impl super::SBPMessage for MsgSettingsReadByIndexDone { + const MSG_ID: u16 = 166; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Register setting and default value (device => host) +/// +/// This message registers the presence and default value of a setting +/// with a settings daemon. The host should reply with MSG_SETTINGS_WRITE +/// for this setting to set the initial value. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgSettingsRegister { + pub sender_id: Option, + /// A NULL-terminated and delimited string with contents + /// "SECTION_SETTING\0SETTING\0VALUE". + pub setting: String, +} + +impl MsgSettingsRegister { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgSettingsRegister { + sender_id: None, + setting: ::parser::read_string(_buf)?, + }) + } +} +impl super::SBPMessage for MsgSettingsRegister { + const MSG_ID: u16 = 174; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Register setting and default value (device <= host) +/// +/// This message responds to setting registration with the effective value. +/// The effective value shall differ from the given default value if setting +/// was already registered or is available in the permanent setting storage +/// and had a different value. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgSettingsRegisterResp { + pub sender_id: Option, + /// Register status + pub status: u8, + /// A NULL-terminated and delimited string with contents + /// "SECTION_SETTING\0SETTING\0VALUE". The meaning of value is defined + /// according to the status field. + pub setting: String, +} + +impl MsgSettingsRegisterResp { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgSettingsRegisterResp { + sender_id: None, + status: _buf.read_u8()?, + setting: ::parser::read_string(_buf)?, + }) + } +} +impl super::SBPMessage for MsgSettingsRegisterResp { + const MSG_ID: u16 = 431; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} diff --git a/rust/sbp/src/messages/ssr.rs b/rust/sbp/src/messages/ssr.rs new file mode 100644 index 0000000000..f49b1ee9e2 --- /dev/null +++ b/rust/sbp/src/messages/ssr.rs @@ -0,0 +1,804 @@ +// Copyright (C) 2015-2018 Swift Navigation Inc. +// Contact: Swift Navigation +// +// This source is subject to the license found in the file 'LICENSE' which must +// be be distributed together with this source. All other rights reserved. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. + +//**************************************************************************** +// Automatically generated from yaml/swiftnav/sbp/ssr.yaml +// with generate.py. Please do not hand edit! +//****************************************************************************/ +//! Precise State Space Representation (SSR) corrections format + +extern crate byteorder; +#[allow(unused_imports)] +use self::byteorder::{LittleEndian, ReadBytesExt}; +use super::gnss::*; + +/// SSR code biases corrections for a particular satellite. +/// +/// Code biases are to be added to pseudorange. +/// The corrections conform with typical RTCMv3 MT1059 and 1065. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct CodeBiasesContent { + /// Signal constellation, band and code + pub code: u8, + /// Code bias value + pub value: i16, +} + +impl CodeBiasesContent { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(CodeBiasesContent { + code: _buf.read_u8()?, + value: _buf.read_i16::()?, + }) + } + pub fn parse_array(buf: &mut &[u8]) -> Result, ::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(CodeBiasesContent::parse(buf)?); + } + Ok(v) + } + + pub fn parse_array_limit(buf: &mut &[u8], n: usize) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(CodeBiasesContent::parse(buf)?); + } + Ok(v) + } +} + +/// SSR phase biases corrections for a particular satellite. +/// +/// Phase biases are to be added to carrier phase measurements. +/// The corrections conform with typical RTCMv3 MT1059 and 1065. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct PhaseBiasesContent { + /// Signal constellation, band and code + pub code: u8, + /// Indicator for integer property + pub integer_indicator: u8, + /// Indicator for two groups of Wide-Lane(s) integer property + pub widelane_integer_indicator: u8, + /// Signal phase discontinuity counter. Increased for every discontinuity in + /// phase. + pub discontinuity_counter: u8, + /// Phase bias for specified signal + pub bias: i32, +} + +impl PhaseBiasesContent { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(PhaseBiasesContent { + code: _buf.read_u8()?, + integer_indicator: _buf.read_u8()?, + widelane_integer_indicator: _buf.read_u8()?, + discontinuity_counter: _buf.read_u8()?, + bias: _buf.read_i32::()?, + }) + } + pub fn parse_array(buf: &mut &[u8]) -> Result, ::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(PhaseBiasesContent::parse(buf)?); + } + Ok(v) + } + + pub fn parse_array_limit( + buf: &mut &[u8], + n: usize, + ) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(PhaseBiasesContent::parse(buf)?); + } + Ok(v) + } +} + +/// Header for MSG_SSR_STEC_CORRECTION message +/// +/// A full set of STEC information will likely span multiple SBP +/// messages, since SBP message a limited to 255 bytes. The header +/// is used to tie multiple SBP messages into a sequence. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct STECHeader { + /// GNSS reference time of the correction + pub time: GPSTimeSec, + /// Number of messages in the dataset + pub num_msgs: u8, + /// Position of this message in the dataset + pub seq_num: u8, + /// Update interval between consecutive corrections. Encoded following RTCM + /// DF391 specification. + pub update_interval: u8, + /// IOD of the SSR correction. A change of Issue Of Data SSR is used to + /// indicate a change in the SSR generating configuration. + pub iod_ssr: u8, +} + +impl STECHeader { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(STECHeader { + time: GPSTimeSec::parse(_buf)?, + num_msgs: _buf.read_u8()?, + seq_num: _buf.read_u8()?, + update_interval: _buf.read_u8()?, + iod_ssr: _buf.read_u8()?, + }) + } + pub fn parse_array(buf: &mut &[u8]) -> Result, ::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(STECHeader::parse(buf)?); + } + Ok(v) + } + + pub fn parse_array_limit(buf: &mut &[u8], n: usize) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(STECHeader::parse(buf)?); + } + Ok(v) + } +} + +/// Header for MSG_SSR_GRIDDED_CORRECTION +/// +/// The 3GPP message contains nested variable length arrays +/// which are not suppported in SBP, so each grid point will +/// be identified by the index. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct GriddedCorrectionHeader { + /// GNSS reference time of the correction + pub time: GPSTimeSec, + /// Number of messages in the dataset + pub num_msgs: u16, + /// Position of this message in the dataset + pub seq_num: u16, + /// Update interval between consecutive corrections. Encoded following RTCM + /// DF391 specification. + pub update_interval: u8, + /// IOD of the SSR correction. A change of Issue Of Data SSR is used to + /// indicate a change in the SSR generating configuration. + pub iod_ssr: u8, + /// Quality of the troposphere data. Encoded following RTCM DF389 + /// specifcation but as TECU instead of m. + pub tropo_quality_indicator: u8, +} + +impl GriddedCorrectionHeader { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(GriddedCorrectionHeader { + time: GPSTimeSec::parse(_buf)?, + num_msgs: _buf.read_u16::()?, + seq_num: _buf.read_u16::()?, + update_interval: _buf.read_u8()?, + iod_ssr: _buf.read_u8()?, + tropo_quality_indicator: _buf.read_u8()?, + }) + } + pub fn parse_array(buf: &mut &[u8]) -> Result, ::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(GriddedCorrectionHeader::parse(buf)?); + } + Ok(v) + } + + pub fn parse_array_limit( + buf: &mut &[u8], + n: usize, + ) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(GriddedCorrectionHeader::parse(buf)?); + } + Ok(v) + } +} + +/// None +/// +/// STEC polynomial for the given satellite. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct STECSatElement { + /// Unique space vehicle identifier + pub sv_id: SvId, + /// Quality of the STEC data. Encoded following RTCM DF389 specifcation but + /// as TECU instead of m. + pub stec_quality_indicator: u8, + /// Coefficents of the STEC polynomial in the order of C00, C01, C10, C11 + pub stec_coeff: Vec, +} + +impl STECSatElement { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(STECSatElement { + sv_id: SvId::parse(_buf)?, + stec_quality_indicator: _buf.read_u8()?, + stec_coeff: ::parser::read_s16_array_limit(_buf, 4)?, + }) + } + pub fn parse_array(buf: &mut &[u8]) -> Result, ::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(STECSatElement::parse(buf)?); + } + Ok(v) + } + + pub fn parse_array_limit(buf: &mut &[u8], n: usize) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(STECSatElement::parse(buf)?); + } + Ok(v) + } +} + +/// None +/// +/// Troposphere delays at the grid point. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct TroposphericDelayCorrection { + /// Hydrostatic vertical delay + pub hydro: i16, + /// Wet vertical delay + pub wet: i8, +} + +impl TroposphericDelayCorrection { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(TroposphericDelayCorrection { + hydro: _buf.read_i16::()?, + wet: _buf.read_i8()?, + }) + } + pub fn parse_array(buf: &mut &[u8]) -> Result, ::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(TroposphericDelayCorrection::parse(buf)?); + } + Ok(v) + } + + pub fn parse_array_limit( + buf: &mut &[u8], + n: usize, + ) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(TroposphericDelayCorrection::parse(buf)?); + } + Ok(v) + } +} + +/// None +/// +/// STEC residual for the given satellite at the grid point. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct STECResidual { + /// space vehicle identifier + pub sv_id: SvId, + /// STEC residual + pub residual: i16, +} + +impl STECResidual { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(STECResidual { + sv_id: SvId::parse(_buf)?, + residual: _buf.read_i16::()?, + }) + } + pub fn parse_array(buf: &mut &[u8]) -> Result, ::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(STECResidual::parse(buf)?); + } + Ok(v) + } + + pub fn parse_array_limit(buf: &mut &[u8], n: usize) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(STECResidual::parse(buf)?); + } + Ok(v) + } +} + +/// Correction data for a single grid point. +/// +/// Contains one tropo delay, plus STEC residuals for each satellite at the +/// grid point. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct GridElement { + /// Index of the grid point + pub index: u16, + /// Wet and hydrostatic vertical delays + pub tropo_delay_correction: TroposphericDelayCorrection, + /// STEC residuals for each satellite + pub stec_residuals: Vec, +} + +impl GridElement { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(GridElement { + index: _buf.read_u16::()?, + tropo_delay_correction: TroposphericDelayCorrection::parse(_buf)?, + stec_residuals: STECResidual::parse_array(_buf)?, + }) + } + pub fn parse_array(buf: &mut &[u8]) -> Result, ::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(GridElement::parse(buf)?); + } + Ok(v) + } + + pub fn parse_array_limit(buf: &mut &[u8], n: usize) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(GridElement::parse(buf)?); + } + Ok(v) + } +} + +/// Defines the grid for MSG_SSR_GRIDDED_CORRECTION messages. +/// +/// Defines the grid for MSG_SSR_GRIDDED_CORRECTION messages. +/// Also includes an RLE encoded validity list. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct GridDefinitionHeader { + /// inverse of region size + pub region_size_inverse: u8, + /// area width; see spec for details + pub area_width: u16, + /// encoded latitude of the northwest corner of the grid + pub lat_nw_corner_enc: u16, + /// encoded longitude of the northwest corner of the grid + pub lon_nw_corner_enc: u16, + /// Number of messages in the dataset + pub num_msgs: u8, + /// Postion of this message in the dataset + pub seq_num: u8, +} + +impl GridDefinitionHeader { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(GridDefinitionHeader { + region_size_inverse: _buf.read_u8()?, + area_width: _buf.read_u16::()?, + lat_nw_corner_enc: _buf.read_u16::()?, + lon_nw_corner_enc: _buf.read_u16::()?, + num_msgs: _buf.read_u8()?, + seq_num: _buf.read_u8()?, + }) + } + pub fn parse_array(buf: &mut &[u8]) -> Result, ::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(GridDefinitionHeader::parse(buf)?); + } + Ok(v) + } + + pub fn parse_array_limit( + buf: &mut &[u8], + n: usize, + ) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(GridDefinitionHeader::parse(buf)?); + } + Ok(v) + } +} + +/// Precise orbit and clock correction +/// +/// The precise orbit and clock correction message is +/// to be applied as a delta correction to broadcast +/// ephemeris and is typically an equivalent to the 1060 +/// and 1066 RTCM message types +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgSsrOrbitClock { + pub sender_id: Option, + /// GNSS reference time of the correction + pub time: GPSTimeSec, + /// GNSS signal identifier (16 bit) + pub sid: GnssSignal, + /// Update interval between consecutive corrections. Encoded following RTCM + /// DF391 specification. + pub update_interval: u8, + /// IOD of the SSR correction. A change of Issue Of Data SSR is used to + /// indicate a change in the SSR generating configuration + pub iod_ssr: u8, + /// Issue of broadcast ephemeris data or IODCRC (Beidou) + pub iod: u32, + /// Orbit radial delta correction + pub radial: i32, + /// Orbit along delta correction + pub along: i32, + /// Orbit along delta correction + pub cross: i32, + /// Velocity of orbit radial delta correction + pub dot_radial: i32, + /// Velocity of orbit along delta correction + pub dot_along: i32, + /// Velocity of orbit cross delta correction + pub dot_cross: i32, + /// C0 polynomial coefficient for correction of broadcast satellite clock + pub c0: i32, + /// C1 polynomial coefficient for correction of broadcast satellite clock + pub c1: i32, + /// C2 polynomial coefficient for correction of broadcast satellite clock + pub c2: i32, +} + +impl MsgSsrOrbitClock { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgSsrOrbitClock { + sender_id: None, + time: GPSTimeSec::parse(_buf)?, + sid: GnssSignal::parse(_buf)?, + update_interval: _buf.read_u8()?, + iod_ssr: _buf.read_u8()?, + iod: _buf.read_u32::()?, + radial: _buf.read_i32::()?, + along: _buf.read_i32::()?, + cross: _buf.read_i32::()?, + dot_radial: _buf.read_i32::()?, + dot_along: _buf.read_i32::()?, + dot_cross: _buf.read_i32::()?, + c0: _buf.read_i32::()?, + c1: _buf.read_i32::()?, + c2: _buf.read_i32::()?, + }) + } +} +impl super::SBPMessage for MsgSsrOrbitClock { + const MSG_ID: u16 = 1501; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Precise orbit and clock correction +/// +/// The precise orbit and clock correction message is +/// to be applied as a delta correction to broadcast +/// ephemeris and is typically an equivalent to the 1060 +/// and 1066 RTCM message types +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgSsrOrbitClockDepA { + pub sender_id: Option, + /// GNSS reference time of the correction + pub time: GPSTimeSec, + /// GNSS signal identifier (16 bit) + pub sid: GnssSignal, + /// Update interval between consecutive corrections. Encoded following RTCM + /// DF391 specification. + pub update_interval: u8, + /// IOD of the SSR correction. A change of Issue Of Data SSR is used to + /// indicate a change in the SSR generating configuration + pub iod_ssr: u8, + /// Issue of broadcast ephemeris data + pub iod: u8, + /// Orbit radial delta correction + pub radial: i32, + /// Orbit along delta correction + pub along: i32, + /// Orbit along delta correction + pub cross: i32, + /// Velocity of orbit radial delta correction + pub dot_radial: i32, + /// Velocity of orbit along delta correction + pub dot_along: i32, + /// Velocity of orbit cross delta correction + pub dot_cross: i32, + /// C0 polynomial coefficient for correction of broadcast satellite clock + pub c0: i32, + /// C1 polynomial coefficient for correction of broadcast satellite clock + pub c1: i32, + /// C2 polynomial coefficient for correction of broadcast satellite clock + pub c2: i32, +} + +impl MsgSsrOrbitClockDepA { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgSsrOrbitClockDepA { + sender_id: None, + time: GPSTimeSec::parse(_buf)?, + sid: GnssSignal::parse(_buf)?, + update_interval: _buf.read_u8()?, + iod_ssr: _buf.read_u8()?, + iod: _buf.read_u8()?, + radial: _buf.read_i32::()?, + along: _buf.read_i32::()?, + cross: _buf.read_i32::()?, + dot_radial: _buf.read_i32::()?, + dot_along: _buf.read_i32::()?, + dot_cross: _buf.read_i32::()?, + c0: _buf.read_i32::()?, + c1: _buf.read_i32::()?, + c2: _buf.read_i32::()?, + }) + } +} +impl super::SBPMessage for MsgSsrOrbitClockDepA { + const MSG_ID: u16 = 1500; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Precise code biases correction +/// +/// The precise code biases message is to be added +/// to the pseudorange of the corresponding signal +/// to get corrected pseudorange. It is typically +/// an equivalent to the 1059 and 1065 RTCM message types +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgSsrCodeBiases { + pub sender_id: Option, + /// GNSS reference time of the correction + pub time: GPSTimeSec, + /// GNSS signal identifier (16 bit) + pub sid: GnssSignal, + /// Update interval between consecutive corrections. Encoded following RTCM + /// DF391 specification. + pub update_interval: u8, + /// IOD of the SSR correction. A change of Issue Of Data SSR is used to + /// indicate a change in the SSR generating configuration + pub iod_ssr: u8, + /// Code biases for the different satellite signals + pub biases: Vec, +} + +impl MsgSsrCodeBiases { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgSsrCodeBiases { + sender_id: None, + time: GPSTimeSec::parse(_buf)?, + sid: GnssSignal::parse(_buf)?, + update_interval: _buf.read_u8()?, + iod_ssr: _buf.read_u8()?, + biases: CodeBiasesContent::parse_array(_buf)?, + }) + } +} +impl super::SBPMessage for MsgSsrCodeBiases { + const MSG_ID: u16 = 1505; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Precise phase biases correction +/// +/// The precise phase biases message contains the biases +/// to be added to the carrier phase of the corresponding +/// signal to get corrected carrier phase measurement, as +/// well as the satellite yaw angle to be applied to compute +/// the phase wind-up correction. +/// It is typically an equivalent to the 1265 RTCM message types +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgSsrPhaseBiases { + pub sender_id: Option, + /// GNSS reference time of the correction + pub time: GPSTimeSec, + /// GNSS signal identifier (16 bit) + pub sid: GnssSignal, + /// Update interval between consecutive corrections. Encoded following RTCM + /// DF391 specification. + pub update_interval: u8, + /// IOD of the SSR correction. A change of Issue Of Data SSR is used to + /// indicate a change in the SSR generating configuration + pub iod_ssr: u8, + /// Indicator for the dispersive phase biases property. + pub dispersive_bias: u8, + /// Consistency indicator for Melbourne-Wubbena linear combinations + pub mw_consistency: u8, + /// Satellite yaw angle + pub yaw: u16, + /// Satellite yaw angle rate + pub yaw_rate: i8, + /// Phase biases corrections for a satellite being tracked. + pub biases: Vec, +} + +impl MsgSsrPhaseBiases { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgSsrPhaseBiases { + sender_id: None, + time: GPSTimeSec::parse(_buf)?, + sid: GnssSignal::parse(_buf)?, + update_interval: _buf.read_u8()?, + iod_ssr: _buf.read_u8()?, + dispersive_bias: _buf.read_u8()?, + mw_consistency: _buf.read_u8()?, + yaw: _buf.read_u16::()?, + yaw_rate: _buf.read_i8()?, + biases: PhaseBiasesContent::parse_array(_buf)?, + }) + } +} +impl super::SBPMessage for MsgSsrPhaseBiases { + const MSG_ID: u16 = 1510; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Slant Total Electron Content +/// +/// The STEC per space vehicle, given as polynomial approximation for +/// a given grid. This should be combined with MSG_SSR_GRIDDED_CORRECTION +/// message to get the state space representation of the atmospheric +/// delay. It is typically equivalent to the QZSS CLAS Sub Type 8 messages +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgSsrStecCorrection { + pub sender_id: Option, + /// Header of a STEC message + pub header: STECHeader, + /// Array of STEC information for each space vehicle + pub stec_sat_list: Vec, +} + +impl MsgSsrStecCorrection { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgSsrStecCorrection { + sender_id: None, + header: STECHeader::parse(_buf)?, + stec_sat_list: STECSatElement::parse_array(_buf)?, + }) + } +} +impl super::SBPMessage for MsgSsrStecCorrection { + const MSG_ID: u16 = 1515; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Gridded troposphere and STEC residuals +/// +/// STEC residuals are per space vehicle, tropo is not. +/// It is typically equivalent to the QZSS CLAS Sub Type 9 messages +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgSsrGriddedCorrection { + pub sender_id: Option, + /// Header of a Gridded Correction message + pub header: GriddedCorrectionHeader, + /// Tropo and STEC residuals for the given grid point + pub element: GridElement, +} + +impl MsgSsrGriddedCorrection { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgSsrGriddedCorrection { + sender_id: None, + header: GriddedCorrectionHeader::parse(_buf)?, + element: GridElement::parse(_buf)?, + }) + } +} +impl super::SBPMessage for MsgSsrGriddedCorrection { + const MSG_ID: u16 = 1520; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// None +/// +/// Definition of the grid for STEC and tropo messages +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgSsrGridDefinition { + pub sender_id: Option, + /// Header of a Gridded Correction message + pub header: GridDefinitionHeader, + /// Run Length Encode list of quadrants that contain valid data. The spec + /// describes the encoding scheme in detail, but essentially the index of + /// the quadrants that contain transitions between valid and invalid (and + /// vice versa) are encoded as u8 integers. + pub rle_list: Vec, +} + +impl MsgSsrGridDefinition { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgSsrGridDefinition { + sender_id: None, + header: GridDefinitionHeader::parse(_buf)?, + rle_list: ::parser::read_u8_array(_buf)?, + }) + } +} +impl super::SBPMessage for MsgSsrGridDefinition { + const MSG_ID: u16 = 1525; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} diff --git a/rust/sbp/src/messages/system.rs b/rust/sbp/src/messages/system.rs new file mode 100644 index 0000000000..dcb53310c5 --- /dev/null +++ b/rust/sbp/src/messages/system.rs @@ -0,0 +1,253 @@ +// Copyright (C) 2015-2018 Swift Navigation Inc. +// Contact: Swift Navigation +// +// This source is subject to the license found in the file 'LICENSE' which must +// be be distributed together with this source. All other rights reserved. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. + +//**************************************************************************** +// Automatically generated from yaml/swiftnav/sbp/system.yaml +// with generate.py. Please do not hand edit! +//****************************************************************************/ +//! Standardized system messages from Swift Navigation devices. + +extern crate byteorder; +#[allow(unused_imports)] +use self::byteorder::{LittleEndian, ReadBytesExt}; + +/// System start-up message +/// +/// The system start-up message is sent once on system +/// start-up. It notifies the host or other attached devices that +/// the system has started and is now ready to respond to commands +/// or configuration requests. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgStartup { + pub sender_id: Option, + /// Cause of startup + pub cause: u8, + /// Startup type + pub startup_type: u8, + /// Reserved + pub reserved: u16, +} + +impl MsgStartup { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgStartup { + sender_id: None, + cause: _buf.read_u8()?, + startup_type: _buf.read_u8()?, + reserved: _buf.read_u16::()?, + }) + } +} +impl super::SBPMessage for MsgStartup { + const MSG_ID: u16 = 65280; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Status of received corrections +/// +/// This message provides information about the receipt of Differential +/// corrections. It is expected to be sent with each receipt of a complete +/// corrections packet. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgDgnssStatus { + pub sender_id: Option, + /// Status flags + pub flags: u8, + /// Latency of observation receipt + pub latency: u16, + /// Number of signals from base station + pub num_signals: u8, + /// Corrections source string + pub source: String, +} + +impl MsgDgnssStatus { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgDgnssStatus { + sender_id: None, + flags: _buf.read_u8()?, + latency: _buf.read_u16::()?, + num_signals: _buf.read_u8()?, + source: ::parser::read_string(_buf)?, + }) + } +} +impl super::SBPMessage for MsgDgnssStatus { + const MSG_ID: u16 = 65282; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// System heartbeat message +/// +/// The heartbeat message is sent periodically to inform the host +/// or other attached devices that the system is running. It is +/// used to monitor system malfunctions. It also contains status +/// flags that indicate to the host the status of the system and +/// whether it is operating correctly. Currently, the expected +/// heartbeat interval is 1 sec. +/// +/// The system error flag is used to indicate that an error has +/// occurred in the system. To determine the source of the error, +/// the remaining error flags should be inspected. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgHeartbeat { + pub sender_id: Option, + /// Status flags + pub flags: u32, +} + +impl MsgHeartbeat { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgHeartbeat { + sender_id: None, + flags: _buf.read_u32::()?, + }) + } +} +impl super::SBPMessage for MsgHeartbeat { + const MSG_ID: u16 = 65535; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Inertial Navigation System status message +/// +/// The INS status message describes the state of the operation +/// and initialization of the inertial navigation system. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgInsStatus { + pub sender_id: Option, + /// Status flags + pub flags: u32, +} + +impl MsgInsStatus { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgInsStatus { + sender_id: None, + flags: _buf.read_u32::()?, + }) + } +} +impl super::SBPMessage for MsgInsStatus { + const MSG_ID: u16 = 65283; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Experimental telemetry message +/// +/// The CSAC telemetry message has an implementation defined telemetry string +/// from a device. It is not produced or available on general Swift Products. +/// It is intended to be a low rate message for status purposes. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgCsacTelemetry { + pub sender_id: Option, + /// Index representing the type of telemetry in use. It is implemention + /// defined. + pub id: u8, + /// Comma separated list of values as defined by the index + pub telemetry: String, +} + +impl MsgCsacTelemetry { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgCsacTelemetry { + sender_id: None, + id: _buf.read_u8()?, + telemetry: ::parser::read_string(_buf)?, + }) + } +} +impl super::SBPMessage for MsgCsacTelemetry { + const MSG_ID: u16 = 65284; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Experimental telemetry message labels +/// +/// The CSAC telemetry message provides labels for each member of the string +/// produced by MSG_CSAC_TELEMETRY. It should be provided by a device at a lower +/// rate than the MSG_CSAC_TELEMETRY. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgCsacTelemetryLabels { + pub sender_id: Option, + /// Index representing the type of telemetry in use. It is implemention + /// defined. + pub id: u8, + /// Comma separated list of telemetry field values + pub telemetry_labels: String, +} + +impl MsgCsacTelemetryLabels { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgCsacTelemetryLabels { + sender_id: None, + id: _buf.read_u8()?, + telemetry_labels: ::parser::read_string(_buf)?, + }) + } +} +impl super::SBPMessage for MsgCsacTelemetryLabels { + const MSG_ID: u16 = 65285; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} diff --git a/rust/sbp/src/messages/tracking.rs b/rust/sbp/src/messages/tracking.rs new file mode 100644 index 0000000000..15a05325f9 --- /dev/null +++ b/rust/sbp/src/messages/tracking.rs @@ -0,0 +1,718 @@ +// Copyright (C) 2015-2018 Swift Navigation Inc. +// Contact: Swift Navigation +// +// This source is subject to the license found in the file 'LICENSE' which must +// be be distributed together with this source. All other rights reserved. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. + +//**************************************************************************** +// Automatically generated from yaml/swiftnav/sbp/tracking.yaml +// with generate.py. Please do not hand edit! +//****************************************************************************/ +//! Satellite code and carrier-phase tracking messages from the device. +//! + +extern crate byteorder; +#[allow(unused_imports)] +use self::byteorder::{LittleEndian, ReadBytesExt}; +use super::gnss::*; + +/// Detailed signal tracking channel states. DEPRECATED. +/// +/// The tracking message returns a set tracking channel parameters for a +/// single tracking channel useful for debugging issues. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgTrackingStateDetailedDepA { + pub sender_id: Option, + /// Receiver clock time. + pub recv_time: u64, + /// Time of transmission of signal from satellite. TOW only valid when TOW + /// status is decoded or propagated. WN only valid when week number valid + /// flag is set. + pub tot: GPSTime, + /// Pseudorange observation. Valid only when pseudorange valid flag is set. + pub P: u32, + /// Pseudorange observation standard deviation. Valid only when pseudorange + /// valid flag is set. + pub P_std: u16, + /// Carrier phase observation with typical sign convention. Valid only when + /// PLL pessimistic lock is achieved. + pub L: CarrierPhase, + /// Carrier-to-Noise density + pub cn0: u8, + /// Lock time. It is encoded according to DF402 from the RTCM 10403.2 + /// Amendment 2 specification. Valid values range from 0 to 15. + pub lock: u16, + /// GNSS signal identifier. + pub sid: GnssSignal, + /// Carrier Doppler frequency. + pub doppler: i32, + /// Carrier Doppler frequency standard deviation. + pub doppler_std: u16, + /// Number of seconds of continuous tracking. Specifies how much time signal + /// is in continuous track. + pub uptime: u32, + /// TCXO clock offset. Valid only when valid clock valid flag is set. + pub clock_offset: i16, + /// TCXO clock drift. Valid only when valid clock valid flag is set. + pub clock_drift: i16, + /// Early-Prompt (EP) and Prompt-Late (PL) correlators spacing. + pub corr_spacing: u16, + /// Acceleration. Valid only when acceleration valid flag is set. + pub acceleration: i8, + /// Synchronization status flags. + pub sync_flags: u8, + /// TOW status flags. + pub tow_flags: u8, + /// Tracking loop status flags. + pub track_flags: u8, + /// Navigation data status flags. + pub nav_flags: u8, + /// Parameters sets flags. + pub pset_flags: u8, + /// Miscellaneous flags. + pub misc_flags: u8, +} + +impl MsgTrackingStateDetailedDepA { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgTrackingStateDetailedDepA { + sender_id: None, + recv_time: _buf.read_u64::()?, + tot: GPSTime::parse(_buf)?, + P: _buf.read_u32::()?, + P_std: _buf.read_u16::()?, + L: CarrierPhase::parse(_buf)?, + cn0: _buf.read_u8()?, + lock: _buf.read_u16::()?, + sid: GnssSignal::parse(_buf)?, + doppler: _buf.read_i32::()?, + doppler_std: _buf.read_u16::()?, + uptime: _buf.read_u32::()?, + clock_offset: _buf.read_i16::()?, + clock_drift: _buf.read_i16::()?, + corr_spacing: _buf.read_u16::()?, + acceleration: _buf.read_i8()?, + sync_flags: _buf.read_u8()?, + tow_flags: _buf.read_u8()?, + track_flags: _buf.read_u8()?, + nav_flags: _buf.read_u8()?, + pset_flags: _buf.read_u8()?, + misc_flags: _buf.read_u8()?, + }) + } +} +impl super::SBPMessage for MsgTrackingStateDetailedDepA { + const MSG_ID: u16 = 33; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Deprecated +/// +/// Deprecated. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgTrackingStateDetailedDep { + pub sender_id: Option, + /// Receiver clock time. + pub recv_time: u64, + /// Time of transmission of signal from satellite. TOW only valid when TOW + /// status is decoded or propagated. WN only valid when week number valid + /// flag is set. + pub tot: GPSTimeDep, + /// Pseudorange observation. Valid only when pseudorange valid flag is set. + pub P: u32, + /// Pseudorange observation standard deviation. Valid only when pseudorange + /// valid flag is set. + pub P_std: u16, + /// Carrier phase observation with typical sign convention. Valid only when + /// PLL pessimistic lock is achieved. + pub L: CarrierPhase, + /// Carrier-to-Noise density + pub cn0: u8, + /// Lock time. It is encoded according to DF402 from the RTCM 10403.2 + /// Amendment 2 specification. Valid values range from 0 to 15. + pub lock: u16, + /// GNSS signal identifier. + pub sid: GnssSignalDep, + /// Carrier Doppler frequency. + pub doppler: i32, + /// Carrier Doppler frequency standard deviation. + pub doppler_std: u16, + /// Number of seconds of continuous tracking. Specifies how much time signal + /// is in continuous track. + pub uptime: u32, + /// TCXO clock offset. Valid only when valid clock valid flag is set. + pub clock_offset: i16, + /// TCXO clock drift. Valid only when valid clock valid flag is set. + pub clock_drift: i16, + /// Early-Prompt (EP) and Prompt-Late (PL) correlators spacing. + pub corr_spacing: u16, + /// Acceleration. Valid only when acceleration valid flag is set. + pub acceleration: i8, + /// Synchronization status flags. + pub sync_flags: u8, + /// TOW status flags. + pub tow_flags: u8, + /// Tracking loop status flags. + pub track_flags: u8, + /// Navigation data status flags. + pub nav_flags: u8, + /// Parameters sets flags. + pub pset_flags: u8, + /// Miscellaneous flags. + pub misc_flags: u8, +} + +impl MsgTrackingStateDetailedDep { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgTrackingStateDetailedDep { + sender_id: None, + recv_time: _buf.read_u64::()?, + tot: GPSTimeDep::parse(_buf)?, + P: _buf.read_u32::()?, + P_std: _buf.read_u16::()?, + L: CarrierPhase::parse(_buf)?, + cn0: _buf.read_u8()?, + lock: _buf.read_u16::()?, + sid: GnssSignalDep::parse(_buf)?, + doppler: _buf.read_i32::()?, + doppler_std: _buf.read_u16::()?, + uptime: _buf.read_u32::()?, + clock_offset: _buf.read_i16::()?, + clock_drift: _buf.read_i16::()?, + corr_spacing: _buf.read_u16::()?, + acceleration: _buf.read_i8()?, + sync_flags: _buf.read_u8()?, + tow_flags: _buf.read_u8()?, + track_flags: _buf.read_u8()?, + nav_flags: _buf.read_u8()?, + pset_flags: _buf.read_u8()?, + misc_flags: _buf.read_u8()?, + }) + } +} +impl super::SBPMessage for MsgTrackingStateDetailedDep { + const MSG_ID: u16 = 17; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Signal tracking channel state +/// +/// Tracking channel state for a specific satellite signal and +/// measured signal power. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct TrackingChannelState { + /// GNSS signal being tracked + pub sid: GnssSignal, + /// Frequency channel number (GLONASS only) + pub fcn: u8, + /// Carrier-to-Noise density. Zero implies invalid cn0. + pub cn0: u8, +} + +impl TrackingChannelState { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(TrackingChannelState { + sid: GnssSignal::parse(_buf)?, + fcn: _buf.read_u8()?, + cn0: _buf.read_u8()?, + }) + } + pub fn parse_array(buf: &mut &[u8]) -> Result, ::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(TrackingChannelState::parse(buf)?); + } + Ok(v) + } + + pub fn parse_array_limit( + buf: &mut &[u8], + n: usize, + ) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(TrackingChannelState::parse(buf)?); + } + Ok(v) + } +} + +/// Signal tracking channel states +/// +/// The tracking message returns a variable-length array of tracking +/// channel states. It reports status and carrier-to-noise density +/// measurements for all tracked satellites. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgTrackingState { + pub sender_id: Option, + /// Signal tracking channel state + pub states: Vec, +} + +impl MsgTrackingState { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgTrackingState { + sender_id: None, + states: TrackingChannelState::parse_array(_buf)?, + }) + } +} +impl super::SBPMessage for MsgTrackingState { + const MSG_ID: u16 = 65; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Measurement Engine signal tracking channel state +/// +/// Measurement Engine tracking channel state for a specific satellite signal +/// and measured signal power. +/// The mesid field for Glonass can either +/// carry the FCN as 100 + FCN where FCN is in [-7, +6] or +/// the Slot ID (from 1 to 28) +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MeasurementState { + /// Measurement Engine GNSS signal being tracked (carries either Glonass FCN + /// or SLOT) + pub mesid: GnssSignal, + /// Carrier-to-Noise density. Zero implies invalid cn0. + pub cn0: u8, +} + +impl MeasurementState { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MeasurementState { + mesid: GnssSignal::parse(_buf)?, + cn0: _buf.read_u8()?, + }) + } + pub fn parse_array(buf: &mut &[u8]) -> Result, ::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(MeasurementState::parse(buf)?); + } + Ok(v) + } + + pub fn parse_array_limit(buf: &mut &[u8], n: usize) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(MeasurementState::parse(buf)?); + } + Ok(v) + } +} + +/// Measurement Engine signal tracking channel states +/// +/// The tracking message returns a variable-length array of tracking +/// channel states. It reports status and carrier-to-noise density +/// measurements for all tracked satellites. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgMeasurementState { + pub sender_id: Option, + /// ME signal tracking channel state + pub states: Vec, +} + +impl MsgMeasurementState { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgMeasurementState { + sender_id: None, + states: MeasurementState::parse_array(_buf)?, + }) + } +} +impl super::SBPMessage for MsgMeasurementState { + const MSG_ID: u16 = 97; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Complex correlation structure +/// +/// Structure containing in-phase and quadrature correlation components. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct TrackingChannelCorrelation { + /// In-phase correlation + pub I: i16, + /// Quadrature correlation + pub Q: i16, +} + +impl TrackingChannelCorrelation { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(TrackingChannelCorrelation { + I: _buf.read_i16::()?, + Q: _buf.read_i16::()?, + }) + } + pub fn parse_array(buf: &mut &[u8]) -> Result, ::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(TrackingChannelCorrelation::parse(buf)?); + } + Ok(v) + } + + pub fn parse_array_limit( + buf: &mut &[u8], + n: usize, + ) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(TrackingChannelCorrelation::parse(buf)?); + } + Ok(v) + } +} + +/// Tracking channel correlations +/// +/// When enabled, a tracking channel can output the correlations at each +/// update interval. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgTrackingIq { + pub sender_id: Option, + /// Tracking channel of origin + pub channel: u8, + /// GNSS signal identifier + pub sid: GnssSignal, + /// Early, Prompt and Late correlations + pub corrs: Vec, +} + +impl MsgTrackingIq { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgTrackingIq { + sender_id: None, + channel: _buf.read_u8()?, + sid: GnssSignal::parse(_buf)?, + corrs: TrackingChannelCorrelation::parse_array_limit(_buf, 3)?, + }) + } +} +impl super::SBPMessage for MsgTrackingIq { + const MSG_ID: u16 = 45; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Complex correlation structure +/// +/// Structure containing in-phase and quadrature correlation components. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct TrackingChannelCorrelationDep { + /// In-phase correlation + pub I: i32, + /// Quadrature correlation + pub Q: i32, +} + +impl TrackingChannelCorrelationDep { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(TrackingChannelCorrelationDep { + I: _buf.read_i32::()?, + Q: _buf.read_i32::()?, + }) + } + pub fn parse_array(buf: &mut &[u8]) -> Result, ::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(TrackingChannelCorrelationDep::parse(buf)?); + } + Ok(v) + } + + pub fn parse_array_limit( + buf: &mut &[u8], + n: usize, + ) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(TrackingChannelCorrelationDep::parse(buf)?); + } + Ok(v) + } +} + +/// Tracking channel correlations +/// +/// When enabled, a tracking channel can output the correlations at each +/// update interval. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgTrackingIqDepB { + pub sender_id: Option, + /// Tracking channel of origin + pub channel: u8, + /// GNSS signal identifier + pub sid: GnssSignal, + /// Early, Prompt and Late correlations + pub corrs: Vec, +} + +impl MsgTrackingIqDepB { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgTrackingIqDepB { + sender_id: None, + channel: _buf.read_u8()?, + sid: GnssSignal::parse(_buf)?, + corrs: TrackingChannelCorrelationDep::parse_array_limit(_buf, 3)?, + }) + } +} +impl super::SBPMessage for MsgTrackingIqDepB { + const MSG_ID: u16 = 44; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Deprecated +/// +/// Deprecated. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgTrackingIqDepA { + pub sender_id: Option, + /// Tracking channel of origin + pub channel: u8, + /// GNSS signal identifier + pub sid: GnssSignalDep, + /// Early, Prompt and Late correlations + pub corrs: Vec, +} + +impl MsgTrackingIqDepA { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgTrackingIqDepA { + sender_id: None, + channel: _buf.read_u8()?, + sid: GnssSignalDep::parse(_buf)?, + corrs: TrackingChannelCorrelationDep::parse_array_limit(_buf, 3)?, + }) + } +} +impl super::SBPMessage for MsgTrackingIqDepA { + const MSG_ID: u16 = 28; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Deprecated +/// +/// Deprecated. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct TrackingChannelStateDepA { + /// Status of tracking channel + pub state: u8, + /// PRN-1 being tracked + pub prn: u8, + /// Carrier-to-noise density + pub cn0: f32, +} + +impl TrackingChannelStateDepA { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(TrackingChannelStateDepA { + state: _buf.read_u8()?, + prn: _buf.read_u8()?, + cn0: _buf.read_f32::()?, + }) + } + pub fn parse_array(buf: &mut &[u8]) -> Result, ::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(TrackingChannelStateDepA::parse(buf)?); + } + Ok(v) + } + + pub fn parse_array_limit( + buf: &mut &[u8], + n: usize, + ) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(TrackingChannelStateDepA::parse(buf)?); + } + Ok(v) + } +} + +/// Deprecated +/// +/// Deprecated. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgTrackingStateDepA { + pub sender_id: Option, + /// Satellite tracking channel state + pub states: Vec, +} + +impl MsgTrackingStateDepA { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgTrackingStateDepA { + sender_id: None, + states: TrackingChannelStateDepA::parse_array(_buf)?, + }) + } +} +impl super::SBPMessage for MsgTrackingStateDepA { + const MSG_ID: u16 = 22; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} + +/// Deprecated. +/// +/// Deprecated. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct TrackingChannelStateDepB { + /// Status of tracking channel + pub state: u8, + /// GNSS signal being tracked + pub sid: GnssSignalDep, + /// Carrier-to-noise density + pub cn0: f32, +} + +impl TrackingChannelStateDepB { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(TrackingChannelStateDepB { + state: _buf.read_u8()?, + sid: GnssSignalDep::parse(_buf)?, + cn0: _buf.read_f32::()?, + }) + } + pub fn parse_array(buf: &mut &[u8]) -> Result, ::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(TrackingChannelStateDepB::parse(buf)?); + } + Ok(v) + } + + pub fn parse_array_limit( + buf: &mut &[u8], + n: usize, + ) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(TrackingChannelStateDepB::parse(buf)?); + } + Ok(v) + } +} + +/// Deprecated. +/// +/// Deprecated. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgTrackingStateDepB { + pub sender_id: Option, + /// Signal tracking channel state + pub states: Vec, +} + +impl MsgTrackingStateDepB { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgTrackingStateDepB { + sender_id: None, + states: TrackingChannelStateDepB::parse_array(_buf)?, + }) + } +} +impl super::SBPMessage for MsgTrackingStateDepB { + const MSG_ID: u16 = 19; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} diff --git a/rust/sbp/src/messages/user.rs b/rust/sbp/src/messages/user.rs new file mode 100644 index 0000000000..41cf4dec65 --- /dev/null +++ b/rust/sbp/src/messages/user.rs @@ -0,0 +1,53 @@ +// Copyright (C) 2015-2018 Swift Navigation Inc. +// Contact: Swift Navigation +// +// This source is subject to the license found in the file 'LICENSE' which must +// be be distributed together with this source. All other rights reserved. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. + +//**************************************************************************** +// Automatically generated from yaml/swiftnav/sbp/user.yaml +// with generate.py. Please do not hand edit! +//****************************************************************************/ +//! Messages reserved for use by the user. +//! + +extern crate byteorder; +#[allow(unused_imports)] +use self::byteorder::{LittleEndian, ReadBytesExt}; + +/// User data +/// +/// This message can contain any application specific user data up to a +/// maximum length of 255 bytes per message. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgUserData { + pub sender_id: Option, + /// User data payload + pub contents: Vec, +} + +impl MsgUserData { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgUserData { + sender_id: None, + contents: ::parser::read_u8_array(_buf)?, + }) + } +} +impl super::SBPMessage for MsgUserData { + const MSG_ID: u16 = 2048; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} diff --git a/rust/sbp/src/messages/vehicle.rs b/rust/sbp/src/messages/vehicle.rs new file mode 100644 index 0000000000..311fb4bc55 --- /dev/null +++ b/rust/sbp/src/messages/vehicle.rs @@ -0,0 +1,63 @@ +// Copyright (C) 2015-2018 Swift Navigation Inc. +// Contact: Swift Navigation +// +// This source is subject to the license found in the file 'LICENSE' which must +// be be distributed together with this source. All other rights reserved. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. + +//**************************************************************************** +// Automatically generated from yaml/swiftnav/sbp/vehicle.yaml +// with generate.py. Please do not hand edit! +//****************************************************************************/ +//! Messages from a vehicle. + +extern crate byteorder; +#[allow(unused_imports)] +use self::byteorder::{LittleEndian, ReadBytesExt}; + +/// Vehicle forward (x-axis) velocity +/// +/// Message representing the x component of vehicle velocity in the user frame at the odometry +/// reference point(s) specified by the user. The offset for the odometry reference point and +/// the definition and origin of the user frame are defined through the device settings interface. +/// There are 4 possible user-defined sources of this message which are labeled arbitrarily +/// source 0 through 3. +/// +#[derive(Debug)] +#[allow(non_snake_case)] +pub struct MsgOdometry { + pub sender_id: Option, + /// Time field representing either milliseconds in the GPS Week or local CPU + /// time from the producing system in milliseconds. See the tow_source flag + /// for the exact source of this timestamp. + pub tow: u32, + /// The signed forward component of vehicle velocity. + pub velocity: i32, + /// Status flags + pub flags: u8, +} + +impl MsgOdometry { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgOdometry { + sender_id: None, + tow: _buf.read_u32::()?, + velocity: _buf.read_i32::()?, + flags: _buf.read_u8()?, + }) + } +} +impl super::SBPMessage for MsgOdometry { + const MSG_ID: u16 = 2307; + + fn get_sender_id(&self) -> Option { + self.sender_id + } + + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); + } +} diff --git a/rust/sbp/src/parser/mod.rs b/rust/sbp/src/parser/mod.rs new file mode 100644 index 0000000000..f6c6217fbb --- /dev/null +++ b/rust/sbp/src/parser/mod.rs @@ -0,0 +1,184 @@ +//! Simple parsing functionality for extracting SBP messages from binary streams + +extern crate byteorder; +extern crate nom; +use self::byteorder::{LittleEndian, ReadBytesExt}; +use self::nom::bytes::complete::is_a; +use self::nom::multi::length_data; +use self::nom::number::complete::{le_u16, le_u8}; +use self::nom::sequence::tuple; +use messages::SBP; +use std::io::{self, Read}; + +/// Attempts to extract a single SBP message from a data slice +/// +/// This function returns a tuple of a result and the number of bytes processed +/// from the slice. In regardless of the result the processed bytes should be +/// removed from the slice before calling `frame()` again. If the result is a +/// success then the SBP message has been fully validated. +pub fn frame(input: &[u8]) -> (Result, usize) { + let original_size = input.len(); + let preamble = is_a("\x55"); + let payload = length_data(le_u8); + + let result = tuple((preamble, le_u16, le_u16, payload, le_u16))(input); + + match result { + Ok((o, (_preamble, msg_type, sender_id, payload, _crc))) => { + let mut crc = crc16::State::::new(); + crc.update(&msg_type.to_le_bytes()); + crc.update(&sender_id.to_le_bytes()); + crc.update(&[payload.len() as u8]); + crc.update(payload); + if crc.get() == _crc { + let bytes_read = original_size - o.len(); + ( + SBP::parse(msg_type, sender_id, &mut &payload[..]), + bytes_read, + ) + } else { + (Err(::Error::ParseError), 1) + } + } + // Act like we didn't read anything + Err(self::nom::Err::Incomplete(_)) => (Err(::Error::NotEnoughData), 0), + // Act like we only read a single byte + Err(self::nom::Err::Error((_, _))) => (Err(::Error::ParseError), 1), + // Act like we didn't read anything + Err(self::nom::Err::Failure((_, _))) => (Err(::Error::UnrecoverableFailure), 0), + } +} + +/// A basic parser for SBP messages +/// +/// This object reads data from a source and attempts to read SBP messages from +/// the stream. A Parser buffers some data locally to reduce the number of +/// calls to read data. +pub struct Parser { + buffer: Vec, +} + +impl Parser { + const BUF_SIZE: usize = 1024usize; + + /// Creates a new Parser object + pub fn new() -> Parser { + Parser { buffer: vec![0; 0] } + } + + /// Attempts to read a single SBP message from the input stream + /// + /// This function will read data from the input source as needed + /// until either a message is successfully parsed or an error occurs + pub fn parse(&mut self, input: &mut R) -> Result { + if self.buffer.len() == 0 { + self.read_more(input)?; + } + + let result = loop { + match self.parse_remaining() { + Ok(msg) => break Ok(msg), + Err(::Error::NotEnoughData) => { + if let Err(e) = self.read_more(input) { + break Err(::Error::IoError(e)); + } + } + Err(e) => break Err(e), + }; + }; + + result + } + + fn read_more(&mut self, input: &mut R) -> Result { + let mut local_buffer = vec![0; Parser::BUF_SIZE]; + let read_bytes = input.read(local_buffer.as_mut())?; + self.buffer.extend_from_slice(&local_buffer[..read_bytes]); + Ok(read_bytes) + } + + fn parse_remaining(&mut self) -> Result { + loop { + let result = frame(&self.buffer); + + match result { + (Ok(msg), bytes_read) => { + self.buffer = self.buffer[bytes_read..].to_vec(); + break Ok(msg); + } + (Err(::Error::ParseError), bytes_read) => { + self.buffer = self.buffer[bytes_read..].to_vec(); + } + (Err(e), _bytes_read) => break Err(e), + } + } + } +} + +impl From for ::Error { + fn from(error: io::Error) -> Self { + ::Error::IoError(error) + } +} + +pub fn read_string(buf: &mut Read) -> Result { + let mut s = String::new(); + buf.read_to_string(&mut s)?; + Ok(s) +} + +pub fn read_string_limit(buf: &mut Read, n: u64) -> Result { + read_string(&mut buf.take(n)) +} + +pub fn read_u8_array(buf: &mut &[u8]) -> Result, ::Error> { + Ok(buf.to_vec()) +} + +pub fn read_u8_array_limit(buf: &mut &[u8], n: usize) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(buf.read_u8()?); + } + Ok(v) +} + +pub fn read_s8_array_limit(buf: &mut &[u8], n: usize) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(buf.read_i8()?); + } + Ok(v) +} + +pub fn read_s16_array_limit(buf: &mut &[u8], n: usize) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(buf.read_i16::()?); + } + Ok(v) +} + +pub fn read_u16_array_limit(buf: &mut &[u8], n: usize) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(buf.read_u16::()?); + } + Ok(v) +} + +pub fn read_float_array_limit(buf: &mut &[u8], n: usize) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(buf.read_f32::()?); + } + Ok(v) +} + +pub fn read_double_array_limit(buf: &mut &[u8], n: usize) -> Result, ::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(buf.read_f64::()?); + } + Ok(v) +}