diff --git a/generator/sbpg/targets/rust.py b/generator/sbpg/targets/rust.py index 6bd958b955..6f0e4f48ea 100644 --- a/generator/sbpg/targets/rust.py +++ b/generator/sbpg/targets/rust.py @@ -114,7 +114,7 @@ def render_source(output_dir, package_spec): if 'types' in includes: del includes[includes.index('types')] with open(destination_filename, 'w') as f: - f.write(py_template.render(msgs=sorted(package_spec.definitions, key=lambda msg: msg.sbp_id), + f.write(py_template.render(msgs=sorted(package_spec.definitions, key=lambda msg: msg.identifier), pkg_name=name, filepath="/".join(package_spec.filepath) + ".yaml", description=package_spec.description, diff --git a/rust/sbp/src/messages/acquisition.rs b/rust/sbp/src/messages/acquisition.rs index d17bb86a95..6499638ed9 100644 --- a/rust/sbp/src/messages/acquisition.rs +++ b/rust/sbp/src/messages/acquisition.rs @@ -162,39 +162,42 @@ impl AcqSvProfileDep { } } -/// Deprecated +/// Satellite acquisition result /// -/// Deprecated. +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgAcqResultDepB { +pub struct MsgAcqResult { 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, + /// 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, + pub sid: GnssSignal, } -impl MsgAcqResultDepB { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgAcqResultDepB { +impl MsgAcqResult { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgAcqResult { sender_id: None, - snr: _buf.read_f32::()?, + cn0: _buf.read_f32::()?, cp: _buf.read_f32::()?, cf: _buf.read_f32::()?, - sid: GnssSignalDep::parse(_buf)?, + sid: GnssSignal::parse(_buf)?, }) } } -impl super::SBPMessage for MsgAcqResultDepB { - const MSG_ID: u16 = 20; +impl super::SBPMessage for MsgAcqResult { + const MSG_ID: u16 = 47; fn get_sender_id(&self) -> Option { self.sender_id @@ -249,29 +252,39 @@ impl super::SBPMessage for MsgAcqResultDepA { } } -/// Deprecated. +/// Deprecated /// /// Deprecated. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgAcqSvProfileDep { +pub struct MsgAcqResultDepB { pub sender_id: Option, - /// SV profiles during acquisition time - pub acq_sv_profile: Vec, + /// 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 MsgAcqSvProfileDep { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgAcqSvProfileDep { +impl MsgAcqResultDepB { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgAcqResultDepB { sender_id: None, - acq_sv_profile: AcqSvProfileDep::parse_array(_buf)?, + snr: _buf.read_f32::()?, + cp: _buf.read_f32::()?, + cf: _buf.read_f32::()?, + sid: GnssSignalDep::parse(_buf)?, }) } } -impl super::SBPMessage for MsgAcqSvProfileDep { - const MSG_ID: u16 = 30; +impl super::SBPMessage for MsgAcqResultDepB { + const MSG_ID: u16 = 20; fn get_sender_id(&self) -> Option { self.sender_id @@ -358,42 +371,29 @@ impl super::SBPMessage for MsgAcqSvProfile { } } -/// Satellite acquisition result +/// Deprecated. /// -/// 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. +/// Deprecated. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgAcqResult { +pub struct MsgAcqSvProfileDep { 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, + /// SV profiles during acquisition time + pub acq_sv_profile: Vec, } -impl MsgAcqResult { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgAcqResult { +impl MsgAcqSvProfileDep { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgAcqSvProfileDep { sender_id: None, - cn0: _buf.read_f32::()?, - cp: _buf.read_f32::()?, - cf: _buf.read_f32::()?, - sid: GnssSignal::parse(_buf)?, + acq_sv_profile: AcqSvProfileDep::parse_array(_buf)?, }) } } -impl super::SBPMessage for MsgAcqResult { - const MSG_ID: u16 = 47; +impl super::SBPMessage for MsgAcqSvProfileDep { + const MSG_ID: u16 = 30; fn get_sender_id(&self) -> Option { self.sender_id diff --git a/rust/sbp/src/messages/bootload.rs b/rust/sbp/src/messages/bootload.rs index 764a2c7a0f..7bb5721436 100644 --- a/rust/sbp/src/messages/bootload.rs +++ b/rust/sbp/src/messages/bootload.rs @@ -58,39 +58,6 @@ impl super::SBPMessage for MsgBootloaderHandshakeDepA { } } -/// Bootloader jump to application (host => device) -/// -/// The host initiates the bootloader to jump to the application. -/// -#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] -#[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); - } -} - /// Bootloading handshake request (host => device) /// /// The handshake message request from the host establishes a @@ -161,34 +128,29 @@ impl super::SBPMessage for MsgBootloaderHandshakeResp { } } -/// Read FPGA device ID over UART response (host <= device) +/// Bootloader jump to application (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. +/// The host initiates the bootloader to jump to the application. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgNapDeviceDnaResp { +pub struct MsgBootloaderJumpToApp { pub sender_id: Option, - /// 57-bit SwiftNAP FPGA Device ID. Remaining bits are padded on the right. - pub dna: Vec, + /// Ignored by the device + pub jump: u8, } -impl MsgNapDeviceDnaResp { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgNapDeviceDnaResp { +impl MsgBootloaderJumpToApp { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgBootloaderJumpToApp { sender_id: None, - dna: crate::parser::read_u8_array_limit(_buf, 8)?, + jump: _buf.read_u8()?, }) } } -impl super::SBPMessage for MsgNapDeviceDnaResp { - const MSG_ID: u16 = 221; +impl super::SBPMessage for MsgBootloaderJumpToApp { + const MSG_ID: u16 = 177; fn get_sender_id(&self) -> Option { self.sender_id @@ -231,3 +193,41 @@ impl super::SBPMessage for MsgNapDeviceDnaReq { 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. +/// +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +#[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: crate::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); + } +} diff --git a/rust/sbp/src/messages/file_io.rs b/rust/sbp/src/messages/file_io.rs index 6328e57904..a9e91925c2 100644 --- a/rust/sbp/src/messages/file_io.rs +++ b/rust/sbp/src/messages/file_io.rs @@ -28,36 +28,32 @@ use self::byteorder::{LittleEndian, ReadBytesExt}; #[cfg(feature = "serialize")] use serde::{Deserialize, Serialize}; -/// File read from the file system (host <= device) +/// Request advice on the optimal configuration for FileIO. /// -/// 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. +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgFileioReadResp { +pub struct MsgFileioConfigReq { pub sender_id: Option, - /// Read sequence number + /// Advice sequence number pub sequence: u32, - /// Contents of read file - pub contents: Vec, } -impl MsgFileioReadResp { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgFileioReadResp { +impl MsgFileioConfigReq { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgFileioConfigReq { sender_id: None, sequence: _buf.read_u32::()?, - contents: crate::parser::read_u8_array(_buf)?, }) } } -impl super::SBPMessage for MsgFileioReadResp { - const MSG_ID: u16 = 163; +impl super::SBPMessage for MsgFileioConfigReq { + const MSG_ID: u16 = 4097; fn get_sender_id(&self) -> Option { self.sender_id @@ -68,45 +64,42 @@ impl super::SBPMessage for MsgFileioReadResp { } } -/// Read file from the file system (host => device) +/// Response with advice on the optimal configuration for FileIO. + /// -/// 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. +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgFileioReadReq { +pub struct MsgFileioConfigResp { pub sender_id: Option, - /// Read sequence number + /// Advice 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, + /// 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 MsgFileioReadReq { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgFileioReadReq { +impl MsgFileioConfigResp { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgFileioConfigResp { sender_id: None, sequence: _buf.read_u32::()?, - offset: _buf.read_u32::()?, - chunk_size: _buf.read_u8()?, - filename: crate::parser::read_string(_buf)?, + window_size: _buf.read_u32::()?, + batch_size: _buf.read_u32::()?, + fileio_version: _buf.read_u32::()?, }) } } -impl super::SBPMessage for MsgFileioReadReq { - const MSG_ID: u16 = 168; +impl super::SBPMessage for MsgFileioConfigResp { + const MSG_ID: u16 = 4098; fn get_sender_id(&self) -> Option { self.sender_id @@ -206,33 +199,85 @@ impl super::SBPMessage for MsgFileioReadDirResp { } } -/// File written to (host <= device) +/// Read file from the file system (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. +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgFileioWriteResp { +pub struct MsgFileioReadReq { pub sender_id: Option, - /// Write sequence number + /// 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 MsgFileioWriteResp { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgFileioWriteResp { +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: crate::parser::read_string(_buf)?, }) } } -impl super::SBPMessage for MsgFileioWriteResp { - const MSG_ID: u16 = 171; +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. +/// +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +#[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: crate::parser::read_u8_array(_buf)?, + }) + } +} +impl super::SBPMessage for MsgFileioReadResp { + const MSG_ID: u16 = 163; fn get_sender_id(&self) -> Option { self.sender_id @@ -328,78 +373,33 @@ impl super::SBPMessage for MsgFileioWriteReq { } } -/// 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. -/// -#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] -#[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. - +/// File written to (host <= device) /// -/// 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. +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgFileioConfigResp { +pub struct MsgFileioWriteResp { pub sender_id: Option, - /// Advice sequence number + /// Write 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 { +impl MsgFileioWriteResp { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgFileioWriteResp { 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; +impl super::SBPMessage for MsgFileioWriteResp { + const MSG_ID: u16 = 171; fn get_sender_id(&self) -> Option { self.sender_id diff --git a/rust/sbp/src/messages/flash.rs b/rust/sbp/src/messages/flash.rs index f02a56c7b5..494015d12e 100644 --- a/rust/sbp/src/messages/flash.rs +++ b/rust/sbp/src/messages/flash.rs @@ -61,41 +61,36 @@ impl super::SBPMessage for MsgFlashDone { } } -/// Read STM or M25 flash address response (host <= device). +/// Erase sector of device flash memory (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. +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgFlashReadResp { +pub struct MsgFlashErase { 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, + /// Flash sector number to erase (0-11 for the STM, 0-15 for the M25) + pub sector_num: u32, } -impl MsgFlashReadResp { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgFlashReadResp { +impl MsgFlashErase { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgFlashErase { sender_id: None, target: _buf.read_u8()?, - addr_start: crate::parser::read_u8_array_limit(_buf, 3)?, - addr_len: _buf.read_u8()?, + sector_num: _buf.read_u32::()?, }) } } -impl super::SBPMessage for MsgFlashReadResp { - const MSG_ID: u16 = 225; +impl super::SBPMessage for MsgFlashErase { + const MSG_ID: u16 = 226; fn get_sender_id(&self) -> Option { self.sender_id @@ -106,36 +101,43 @@ impl super::SBPMessage for MsgFlashReadResp { } } -/// Erase sector of device flash memory (host => device). +/// Program flash addresses /// -/// 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. +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgFlashErase { +pub struct MsgFlashProgram { 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, + /// 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 MsgFlashErase { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgFlashErase { +impl MsgFlashProgram { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgFlashProgram { sender_id: None, target: _buf.read_u8()?, - sector_num: _buf.read_u32::()?, + addr_start: crate::parser::read_u8_array_limit(_buf, 3)?, + addr_len: _buf.read_u8()?, + data: crate::parser::read_u8_array(_buf)?, }) } } -impl super::SBPMessage for MsgFlashErase { - const MSG_ID: u16 = 226; +impl super::SBPMessage for MsgFlashProgram { + const MSG_ID: u16 = 230; fn get_sender_id(&self) -> Option { self.sender_id @@ -146,30 +148,41 @@ impl super::SBPMessage for MsgFlashErase { } } -/// Lock sector of STM flash memory (host => device) +/// Read STM or M25 flash address request (host => device). /// -/// The flash lock message locks a sector of the STM flash -/// memory. The device replies with a MSG_FLASH_DONE message. +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgStmFlashLockSector { +pub struct MsgFlashReadReq { pub sender_id: Option, - /// Flash sector number to lock - pub sector: u32, + /// 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 MsgStmFlashLockSector { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgStmFlashLockSector { +impl MsgFlashReadReq { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgFlashReadReq { sender_id: None, - sector: _buf.read_u32::()?, + target: _buf.read_u8()?, + addr_start: crate::parser::read_u8_array_limit(_buf, 3)?, + addr_len: _buf.read_u8()?, }) } } -impl super::SBPMessage for MsgStmFlashLockSector { - const MSG_ID: u16 = 227; +impl super::SBPMessage for MsgFlashReadReq { + const MSG_ID: u16 = 231; fn get_sender_id(&self) -> Option { self.sender_id @@ -180,30 +193,41 @@ impl super::SBPMessage for MsgStmFlashLockSector { } } -/// Unlock sector of STM flash memory (host => device) +/// Read STM or M25 flash address response (host <= device). /// -/// The flash unlock message unlocks a sector of the STM flash -/// memory. The device replies with a MSG_FLASH_DONE message. +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgStmFlashUnlockSector { +pub struct MsgFlashReadResp { pub sender_id: Option, - /// Flash sector number to unlock - pub sector: u32, + /// 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 MsgStmFlashUnlockSector { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgStmFlashUnlockSector { +impl MsgFlashReadResp { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgFlashReadResp { sender_id: None, - sector: _buf.read_u32::()?, + target: _buf.read_u8()?, + addr_start: crate::parser::read_u8_array_limit(_buf, 3)?, + addr_len: _buf.read_u8()?, }) } } -impl super::SBPMessage for MsgStmFlashUnlockSector { - const MSG_ID: u16 = 228; +impl super::SBPMessage for MsgFlashReadResp { + const MSG_ID: u16 = 225; fn get_sender_id(&self) -> Option { self.sender_id @@ -214,33 +238,30 @@ impl super::SBPMessage for MsgStmFlashUnlockSector { } } -/// Read device's hardcoded unique ID response (host <= device) - +/// Write M25 flash status register (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.. +/// The flash status message writes to the 8-bit M25 flash status +/// register. The device replies with a MSG_FLASH_DONE message. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgStmUniqueIdResp { +pub struct MsgM25FlashWriteStatus { pub sender_id: Option, - /// Device unique ID - pub stm_id: Vec, + /// Byte to write to the M25 flash status register + pub status: Vec, } -impl MsgStmUniqueIdResp { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgStmUniqueIdResp { +impl MsgM25FlashWriteStatus { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgM25FlashWriteStatus { sender_id: None, - stm_id: crate::parser::read_u8_array_limit(_buf, 12)?, + status: crate::parser::read_u8_array_limit(_buf, 1)?, }) } } -impl super::SBPMessage for MsgStmUniqueIdResp { - const MSG_ID: u16 = 229; +impl super::SBPMessage for MsgM25FlashWriteStatus { + const MSG_ID: u16 = 243; fn get_sender_id(&self) -> Option { self.sender_id @@ -251,43 +272,30 @@ impl super::SBPMessage for MsgStmUniqueIdResp { } } -/// Program flash addresses +/// Lock sector of STM flash memory (host => device) /// -/// 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. +/// The flash lock message locks a sector of the STM flash +/// memory. The device replies with a MSG_FLASH_DONE message. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgFlashProgram { +pub struct MsgStmFlashLockSector { 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, + /// Flash sector number to lock + pub sector: u32, } -impl MsgFlashProgram { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgFlashProgram { +impl MsgStmFlashLockSector { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgStmFlashLockSector { sender_id: None, - target: _buf.read_u8()?, - addr_start: crate::parser::read_u8_array_limit(_buf, 3)?, - addr_len: _buf.read_u8()?, - data: crate::parser::read_u8_array(_buf)?, + sector: _buf.read_u32::()?, }) } } -impl super::SBPMessage for MsgFlashProgram { - const MSG_ID: u16 = 230; +impl super::SBPMessage for MsgStmFlashLockSector { + const MSG_ID: u16 = 227; fn get_sender_id(&self) -> Option { self.sender_id @@ -298,41 +306,30 @@ impl super::SBPMessage for MsgFlashProgram { } } -/// Read STM or M25 flash address request (host => device). +/// Unlock sector of STM flash memory (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. +/// The flash unlock message unlocks a sector of the STM flash +/// memory. The device replies with a MSG_FLASH_DONE message. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgFlashReadReq { +pub struct MsgStmFlashUnlockSector { 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, + /// Flash sector number to unlock + pub sector: u32, } -impl MsgFlashReadReq { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgFlashReadReq { +impl MsgStmFlashUnlockSector { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgStmFlashUnlockSector { sender_id: None, - target: _buf.read_u8()?, - addr_start: crate::parser::read_u8_array_limit(_buf, 3)?, - addr_len: _buf.read_u8()?, + sector: _buf.read_u32::()?, }) } } -impl super::SBPMessage for MsgFlashReadReq { - const MSG_ID: u16 = 231; +impl super::SBPMessage for MsgStmFlashUnlockSector { + const MSG_ID: u16 = 228; fn get_sender_id(&self) -> Option { self.sender_id @@ -375,30 +372,33 @@ impl super::SBPMessage for MsgStmUniqueIdReq { } } -/// Write M25 flash status register (host => device) +/// Read device's hardcoded unique ID response (host <= device) + /// -/// The flash status message writes to the 8-bit M25 flash status -/// register. The device replies with a MSG_FLASH_DONE message. +/// 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.. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgM25FlashWriteStatus { +pub struct MsgStmUniqueIdResp { pub sender_id: Option, - /// Byte to write to the M25 flash status register - pub status: Vec, + /// Device unique ID + pub stm_id: Vec, } -impl MsgM25FlashWriteStatus { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgM25FlashWriteStatus { +impl MsgStmUniqueIdResp { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgStmUniqueIdResp { sender_id: None, - status: crate::parser::read_u8_array_limit(_buf, 1)?, + stm_id: crate::parser::read_u8_array_limit(_buf, 12)?, }) } } -impl super::SBPMessage for MsgM25FlashWriteStatus { - const MSG_ID: u16 = 243; +impl super::SBPMessage for MsgStmUniqueIdResp { + const MSG_ID: u16 = 229; fn get_sender_id(&self) -> Option { self.sender_id diff --git a/rust/sbp/src/messages/gnss.rs b/rust/sbp/src/messages/gnss.rs index 076228f140..4b5c98e914 100644 --- a/rust/sbp/src/messages/gnss.rs +++ b/rust/sbp/src/messages/gnss.rs @@ -20,125 +20,87 @@ use self::byteorder::{LittleEndian, ReadBytesExt}; #[cfg(feature = "serialize")] use serde::{Deserialize, Serialize}; -/// Represents all the relevant information about the signal -/// -/// Signal identifier containing constellation, band, and satellite identifier -/// -#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] -#[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, crate::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, crate::Error> { - let mut v = Vec::new(); - for _ in 0..n { - v.push(GnssSignal::parse(buf)?); - } - Ok(v) - } -} - -/// Space vehicle identifier +/// GNSS carrier phase measurement. /// -/// A (Constellation ID, satellite ID) tuple that uniquely identifies -/// a space vehicle +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[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, +pub struct CarrierPhase { + /// Carrier phase whole cycles + pub i: i32, + /// Carrier phase fractional part + pub f: u8, } -impl SvId { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(SvId { - satId: _buf.read_u8()?, - constellation: _buf.read_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, crate::Error> { + pub fn parse_array(buf: &mut &[u8]) -> Result, crate::Error> { let mut v = Vec::new(); while buf.len() > 0 { - v.push(SvId::parse(buf)?); + v.push(CarrierPhase::parse(buf)?); } Ok(v) } - pub fn parse_array_limit(buf: &mut &[u8], n: usize) -> Result, crate::Error> { + pub fn parse_array_limit(buf: &mut &[u8], n: usize) -> Result, crate::Error> { let mut v = Vec::new(); for _ in 0..n { - v.push(SvId::parse(buf)?); + v.push(CarrierPhase::parse(buf)?); } Ok(v) } } -/// Deprecated +/// Nanosecond-accurate receiver clock time /// -/// Deprecated. +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[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, +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 GnssSignalDep { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(GnssSignalDep { - sat: _buf.read_u16::()?, - code: _buf.read_u8()?, - reserved: _buf.read_u8()?, +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, crate::Error> { + pub fn parse_array(buf: &mut &[u8]) -> Result, crate::Error> { let mut v = Vec::new(); while buf.len() > 0 { - v.push(GnssSignalDep::parse(buf)?); + v.push(GPSTime::parse(buf)?); } Ok(v) } - pub fn parse_array_limit( - buf: &mut &[u8], - n: usize, - ) -> Result, crate::Error> { + pub fn parse_array_limit(buf: &mut &[u8], n: usize) -> Result, crate::Error> { let mut v = Vec::new(); for _ in 0..n { - v.push(GnssSignalDep::parse(buf)?); + v.push(GPSTime::parse(buf)?); } Ok(v) } @@ -224,87 +186,125 @@ impl GPSTimeSec { } } -/// Nanosecond-accurate receiver clock time +/// Represents all the relevant information about the signal /// -/// 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. +/// Signal identifier containing constellation, band, and satellite identifier /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[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, +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 GPSTime { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(GPSTime { - tow: _buf.read_u32::()?, - ns_residual: _buf.read_i32::()?, - wn: _buf.read_u16::()?, +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, crate::Error> { + pub fn parse_array(buf: &mut &[u8]) -> Result, crate::Error> { let mut v = Vec::new(); while buf.len() > 0 { - v.push(GPSTime::parse(buf)?); + v.push(GnssSignal::parse(buf)?); } Ok(v) } - pub fn parse_array_limit(buf: &mut &[u8], n: usize) -> Result, crate::Error> { + pub fn parse_array_limit(buf: &mut &[u8], n: usize) -> Result, crate::Error> { let mut v = Vec::new(); for _ in 0..n { - v.push(GPSTime::parse(buf)?); + v.push(GnssSignal::parse(buf)?); } Ok(v) } } -/// GNSS carrier phase measurement. +/// Deprecated /// -/// 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. +/// Deprecated. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct CarrierPhase { - /// Carrier phase whole cycles - pub i: i32, - /// Carrier phase fractional part - pub f: u8, +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 CarrierPhase { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(CarrierPhase { - i: _buf.read_i32::()?, - f: _buf.read_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, crate::Error> { + pub fn parse_array(buf: &mut &[u8]) -> Result, crate::Error> { let mut v = Vec::new(); while buf.len() > 0 { - v.push(CarrierPhase::parse(buf)?); + v.push(GnssSignalDep::parse(buf)?); } Ok(v) } - pub fn parse_array_limit(buf: &mut &[u8], n: usize) -> Result, crate::Error> { + pub fn parse_array_limit( + buf: &mut &[u8], + n: usize, + ) -> Result, crate::Error> { let mut v = Vec::new(); for _ in 0..n { - v.push(CarrierPhase::parse(buf)?); + v.push(GnssSignalDep::parse(buf)?); + } + Ok(v) + } +} + +/// Space vehicle identifier +/// +/// A (Constellation ID, satellite ID) tuple that uniquely identifies +/// a space vehicle +/// +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +#[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, crate::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, crate::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(SvId::parse(buf)?); } Ok(v) } diff --git a/rust/sbp/src/messages/imu.rs b/rust/sbp/src/messages/imu.rs index fe105f9feb..ffbcdb1de9 100644 --- a/rust/sbp/src/messages/imu.rs +++ b/rust/sbp/src/messages/imu.rs @@ -20,6 +20,47 @@ use self::byteorder::{LittleEndian, ReadBytesExt}; #[cfg(feature = "serialize")] use serde::{Deserialize, Serialize}; +/// 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`. +/// +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +#[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); + } +} + /// Raw IMU data /// /// Raw data from the Inertial Measurement Unit, containing accelerometer and @@ -77,44 +118,3 @@ impl super::SBPMessage for MsgImuRaw { 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`. -/// -#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] -#[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 index 16c44fe909..ab900c2eb3 100644 --- a/rust/sbp/src/messages/linux.rs +++ b/rust/sbp/src/messages/linux.rs @@ -113,44 +113,78 @@ impl super::SBPMessage for MsgLinuxMemState { } } -/// CPU, Memory and Process Starts/Stops +/// Summary of processes with large amounts of open file descriptors /// -/// This presents a summary of CPU and memory utilization. +/// Top 10 list of processes with a large number of open file descriptors. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgLinuxSysState { +pub struct MsgLinuxProcessFdCount { 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, + /// 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 MsgLinuxSysState { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgLinuxSysState { +impl MsgLinuxProcessFdCount { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgLinuxProcessFdCount { 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::()?, + index: _buf.read_u8()?, + pid: _buf.read_u16::()?, + fd_count: _buf.read_u16::()?, + cmdline: crate::parser::read_string(_buf)?, }) } } -impl super::SBPMessage for MsgLinuxSysState { - const MSG_ID: u16 = 32514; +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. +/// +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +#[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: crate::parser::read_string(_buf)?, + }) + } +} +impl super::SBPMessage for MsgLinuxProcessFdSummary { + const MSG_ID: u16 = 32519; fn get_sender_id(&self) -> Option { self.sender_id @@ -318,78 +352,44 @@ impl super::SBPMessage for MsgLinuxSocketUsage { } } -/// Summary of processes with large amounts of open file descriptors -/// -/// Top 10 list of processes with a large number of open file descriptors. -/// -#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] -#[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: crate::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 +/// CPU, Memory and Process Starts/Stops /// -/// Summary of open file descriptors on the system. +/// This presents a summary of CPU and memory utilization. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgLinuxProcessFdSummary { +pub struct MsgLinuxSysState { 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, + /// 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 MsgLinuxProcessFdSummary { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgLinuxProcessFdSummary { +impl MsgLinuxSysState { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgLinuxSysState { sender_id: None, - sys_fd_count: _buf.read_u32::()?, - most_opened: crate::parser::read_string(_buf)?, + 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 MsgLinuxProcessFdSummary { - const MSG_ID: u16 = 32519; +impl super::SBPMessage for MsgLinuxSysState { + const MSG_ID: u16 = 32514; fn get_sender_id(&self) -> Option { self.sender_id diff --git a/rust/sbp/src/messages/logging.rs b/rust/sbp/src/messages/logging.rs index bd800ed18b..a722cd7708 100644 --- a/rust/sbp/src/messages/logging.rs +++ b/rust/sbp/src/messages/logging.rs @@ -21,29 +21,41 @@ use self::byteorder::{LittleEndian, ReadBytesExt}; #[cfg(feature = "serialize")] use serde::{Deserialize, Serialize}; -/// Deprecated +/// Wrapper for FWD a separate stream of information over SBP /// -/// Deprecated. +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgPrintDep { +pub struct MsgFwd { pub sender_id: Option, - /// Human-readable string - pub text: String, + /// source identifier + pub source: u8, + /// protocol identifier + pub protocol: u8, + /// variable length wrapped binary message + pub fwd_payload: String, } -impl MsgPrintDep { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgPrintDep { +impl MsgFwd { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgFwd { sender_id: None, - text: crate::parser::read_string(_buf)?, + source: _buf.read_u8()?, + protocol: _buf.read_u8()?, + fwd_payload: crate::parser::read_string(_buf)?, }) } } -impl super::SBPMessage for MsgPrintDep { - const MSG_ID: u16 = 16; +impl super::SBPMessage for MsgFwd { + const MSG_ID: u16 = 1026; fn get_sender_id(&self) -> Option { self.sender_id @@ -92,41 +104,29 @@ impl super::SBPMessage for MsgLog { } } -/// 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. +/// Deprecated /// -/// 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. +/// Deprecated. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgFwd { +pub struct MsgPrintDep { pub sender_id: Option, - /// source identifier - pub source: u8, - /// protocol identifier - pub protocol: u8, - /// variable length wrapped binary message - pub fwd_payload: String, + /// Human-readable string + pub text: String, } -impl MsgFwd { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgFwd { +impl MsgPrintDep { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgPrintDep { sender_id: None, - source: _buf.read_u8()?, - protocol: _buf.read_u8()?, - fwd_payload: crate::parser::read_string(_buf)?, + text: crate::parser::read_string(_buf)?, }) } } -impl super::SBPMessage for MsgFwd { - const MSG_ID: u16 = 1026; +impl super::SBPMessage for MsgPrintDep { + const MSG_ID: u16 = 16; fn get_sender_id(&self) -> Option { self.sender_id diff --git a/rust/sbp/src/messages/navigation.rs b/rust/sbp/src/messages/navigation.rs index 0f2c94539f..9714d97fc1 100644 --- a/rust/sbp/src/messages/navigation.rs +++ b/rust/sbp/src/messages/navigation.rs @@ -38,51 +38,33 @@ use self::byteorder::{LittleEndian, ReadBytesExt}; #[cfg(feature = "serialize")] use serde::{Deserialize, Serialize}; -/// 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. +/// Age of corrections /// -/// 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. +/// This message reports the Age of the corrections used for the current +/// Differential solution /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgGPSTimeDepA { +pub struct MsgAgeCorrections { pub sender_id: Option, - /// GPS week number - pub wn: u16, - /// GPS time of week rounded to the nearest millisecond + /// GPS Time of Week pub tow: u32, - /// Nanosecond residual of millisecond-rounded TOW (ranges from -500000 to - /// 500000) - pub ns_residual: i32, - /// Status flags (reserved) - pub flags: u8, + /// Age of the corrections (0xFFFF indicates invalid) + pub age: u16, } -impl MsgGPSTimeDepA { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgGPSTimeDepA { +impl MsgAgeCorrections { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgAgeCorrections { sender_id: None, - wn: _buf.read_u16::()?, tow: _buf.read_u32::()?, - ns_residual: _buf.read_i32::()?, - flags: _buf.read_u8()?, + age: _buf.read_u16::()?, }) } } -impl super::SBPMessage for MsgGPSTimeDepA { - const MSG_ID: u16 = 256; +impl super::SBPMessage for MsgAgeCorrections { + const MSG_ID: u16 = 528; fn get_sender_id(&self) -> Option { self.sender_id @@ -93,51 +75,51 @@ impl super::SBPMessage for MsgGPSTimeDepA { } } -/// 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. +/// Baseline Position in ECEF /// -/// 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. +/// 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). /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgGPSTime { +pub struct MsgBaselineECEF { pub sender_id: Option, - /// GPS week number - pub wn: u16, - /// GPS time of week rounded to the nearest millisecond + /// GPS Time of Week pub tow: u32, - /// Nanosecond residual of millisecond-rounded TOW (ranges from -500000 to - /// 500000) - pub ns_residual: i32, - /// Status flags (reserved) + /// 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 MsgGPSTime { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgGPSTime { +impl MsgBaselineECEF { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgBaselineECEF { sender_id: None, - wn: _buf.read_u16::()?, tow: _buf.read_u32::()?, - ns_residual: _buf.read_i32::()?, + 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 MsgGPSTime { - const MSG_ID: u16 = 258; +impl super::SBPMessage for MsgBaselineECEF { + const MSG_ID: u16 = 523; fn get_sender_id(&self) -> Option { self.sender_id @@ -148,54 +130,51 @@ impl super::SBPMessage for MsgGPSTime { } } -/// UTC Time +/// Baseline Position in ECEF /// -/// 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. +/// 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). /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgUtcTime { +pub struct MsgBaselineECEFDepA { pub sender_id: Option, - /// Indicates source and time validity - pub flags: u8, - /// GPS time of week rounded to the nearest millisecond + /// GPS Time of Week 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, + /// 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 MsgUtcTime { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgUtcTime { +impl MsgBaselineECEFDepA { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgBaselineECEFDepA { 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::()?, + 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 MsgUtcTime { - const MSG_ID: u16 = 259; +impl super::SBPMessage for MsgBaselineECEFDepA { + const MSG_ID: u16 = 514; fn get_sender_id(&self) -> Option { self.sender_id @@ -206,54 +185,40 @@ impl super::SBPMessage for MsgUtcTime { } } -/// Single-point position in ECEF +/// Heading relative to True North /// -/// 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). +/// 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). /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgPosECEFDepA { +pub struct MsgBaselineHeadingDepA { 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, + /// Heading + pub heading: u32, /// 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 { +impl MsgBaselineHeadingDepA { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgBaselineHeadingDepA { sender_id: None, tow: _buf.read_u32::()?, - x: _buf.read_f64::()?, - y: _buf.read_f64::()?, - z: _buf.read_f64::()?, - accuracy: _buf.read_u16::()?, + heading: _buf.read_u32::()?, n_sats: _buf.read_u8()?, flags: _buf.read_u8()?, }) } } -impl super::SBPMessage for MsgPosECEFDepA { - const MSG_ID: u16 = 512; +impl super::SBPMessage for MsgBaselineHeadingDepA { + const MSG_ID: u16 = 519; fn get_sender_id(&self) -> Option { self.sender_id @@ -264,48 +229,46 @@ impl super::SBPMessage for MsgPosECEFDepA { } } -/// Geodetic Position +/// Baseline in NED /// -/// 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). +/// 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). /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgPosLLHDepA { +pub struct MsgBaselineNED { 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. + /// 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 accuracy estimate (not implemented). Defaults to 0. + /// Vertical position estimated standard deviation pub v_accuracy: u16, - /// Number of satellites used in solution. + /// 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 { +impl MsgBaselineNED { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgBaselineNED { sender_id: None, tow: _buf.read_u32::()?, - lat: _buf.read_f64::()?, - lon: _buf.read_f64::()?, - height: _buf.read_f64::()?, + 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()?, @@ -313,63 +276,8 @@ impl MsgPosLLHDepA { }) } } -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). -/// -#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] -#[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; +impl super::SBPMessage for MsgBaselineNED { + const MSG_ID: u16 = 524; fn get_sender_id(&self) -> Option { self.sender_id @@ -439,106 +347,50 @@ impl super::SBPMessage for MsgBaselineNEDDepA { } } -/// 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). -/// -#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] -#[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 +/// Dilution of Precision /// -/// 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 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgVelNEDDepA { +pub struct MsgDops { 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) + /// 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 MsgVelNEDDepA { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgVelNEDDepA { +impl MsgDops { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgDops { 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()?, + 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 MsgVelNEDDepA { - const MSG_ID: u16 = 517; +impl super::SBPMessage for MsgDops { + const MSG_ID: u16 = 520; fn get_sender_id(&self) -> Option { self.sender_id @@ -599,40 +451,51 @@ impl super::SBPMessage for MsgDopsDepA { } } -/// Heading relative to True North +/// GPS Time /// -/// 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). +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgBaselineHeadingDepA { +pub struct MsgGPSTime { pub sender_id: Option, - /// GPS Time of Week + /// GPS week number + pub wn: u16, + /// GPS time of week rounded to the nearest millisecond pub tow: u32, - /// Heading - pub heading: u32, - /// Number of satellites used in solution - pub n_sats: u8, - /// Status flags + /// Nanosecond residual of millisecond-rounded TOW (ranges from -500000 to + /// 500000) + pub ns_residual: i32, + /// Status flags (reserved) pub flags: u8, } -impl MsgBaselineHeadingDepA { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgBaselineHeadingDepA { +impl MsgGPSTime { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgGPSTime { sender_id: None, + wn: _buf.read_u16::()?, tow: _buf.read_u32::()?, - heading: _buf.read_u32::()?, - n_sats: _buf.read_u8()?, + ns_residual: _buf.read_i32::()?, flags: _buf.read_u8()?, }) } } -impl super::SBPMessage for MsgBaselineHeadingDepA { - const MSG_ID: u16 = 519; +impl super::SBPMessage for MsgGPSTime { + const MSG_ID: u16 = 258; fn get_sender_id(&self) -> Option { self.sender_id @@ -643,50 +506,51 @@ impl super::SBPMessage for MsgBaselineHeadingDepA { } } -/// Dilution of Precision +/// GPS Time (v1.0) /// -/// 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. +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgDops { +pub struct MsgGPSTimeDepA { pub sender_id: Option, - /// GPS Time of Week + /// GPS week number + pub wn: u16, + /// GPS time of week rounded to the nearest millisecond 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 + /// Nanosecond residual of millisecond-rounded TOW (ranges from -500000 to + /// 500000) + pub ns_residual: i32, + /// Status flags (reserved) pub flags: u8, } -impl MsgDops { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgDops { +impl MsgGPSTimeDepA { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgGPSTimeDepA { sender_id: None, + wn: _buf.read_u16::()?, tow: _buf.read_u32::()?, - gdop: _buf.read_u16::()?, - pdop: _buf.read_u16::()?, - tdop: _buf.read_u16::()?, - hdop: _buf.read_u16::()?, - vdop: _buf.read_u16::()?, + ns_residual: _buf.read_i32::()?, flags: _buf.read_u8()?, }) } } -impl super::SBPMessage for MsgDops { - const MSG_ID: u16 = 520; +impl super::SBPMessage for MsgGPSTimeDepA { + const MSG_ID: u16 = 256; fn get_sender_id(&self) -> Option { self.sender_id @@ -755,57 +619,70 @@ impl super::SBPMessage for MsgPosECEF { } } -/// Geodetic Position +/// Single-point position in ECEF /// -/// 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). +/// 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). /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgPosLLH { +pub struct MsgPosECEFCov { 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. + /// 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 MsgPosLLH { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgPosLLH { +impl MsgPosECEFCov { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgPosECEFCov { 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::()?, + 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 MsgPosLLH { - const MSG_ID: u16 = 522; +impl super::SBPMessage for MsgPosECEFCov { + const MSG_ID: u16 = 532; fn get_sender_id(&self) -> Option { self.sender_id @@ -816,28 +693,31 @@ impl super::SBPMessage for MsgPosLLH { } } -/// Baseline Position in ECEF +/// Single-point 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). +/// 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). /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgBaselineECEF { +pub struct MsgPosECEFDepA { 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 + /// 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, @@ -845,22 +725,22 @@ pub struct MsgBaselineECEF { pub flags: u8, } -impl MsgBaselineECEF { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgBaselineECEF { +impl MsgPosECEFDepA { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgPosECEFDepA { sender_id: None, tow: _buf.read_u32::()?, - x: _buf.read_i32::()?, - y: _buf.read_i32::()?, - z: _buf.read_i32::()?, + 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 MsgBaselineECEF { - const MSG_ID: u16 = 523; +impl super::SBPMessage for MsgPosECEFDepA { + const MSG_ID: u16 = 512; fn get_sender_id(&self) -> Option { self.sender_id @@ -871,46 +751,48 @@ impl super::SBPMessage for MsgBaselineECEF { } } -/// Baseline in NED +/// Geodetic Position /// -/// 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). +/// 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). /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgBaselineNED { +pub struct MsgPosLLH { 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, + /// 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 + /// 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 { +impl MsgPosLLH { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgPosLLH { sender_id: None, tow: _buf.read_u32::()?, - n: _buf.read_i32::()?, - e: _buf.read_i32::()?, - d: _buf.read_i32::()?, + 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()?, @@ -918,8 +800,8 @@ impl MsgBaselineNED { }) } } -impl super::SBPMessage for MsgBaselineNED { - const MSG_ID: u16 = 524; +impl super::SBPMessage for MsgPosLLH { + const MSG_ID: u16 = 522; fn get_sender_id(&self) -> Option { self.sender_id @@ -930,49 +812,69 @@ impl super::SBPMessage for MsgBaselineNED { } } -/// Velocity in ECEF +/// Geodetic Position /// -/// 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). +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgVelECEF { +pub struct MsgPosLLHCov { 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 + /// 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 MsgVelECEF { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgVelECEF { +impl MsgPosLLHCov { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgPosLLHCov { sender_id: None, tow: _buf.read_u32::()?, - x: _buf.read_i32::()?, - y: _buf.read_i32::()?, - z: _buf.read_i32::()?, - accuracy: _buf.read_u16::()?, + 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 MsgVelECEF { - const MSG_ID: u16 = 525; +impl super::SBPMessage for MsgPosLLHCov { + const MSG_ID: u16 = 529; fn get_sender_id(&self) -> Option { self.sender_id @@ -983,44 +885,48 @@ impl super::SBPMessage for MsgVelECEF { } } -/// Velocity in NED +/// Geodetic Position /// -/// 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 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). /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgVelNED { +pub struct MsgPosLLHDepA { 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 + /// 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 velocity estimated standard deviation + /// Vertical position accuracy estimate (not implemented). Defaults to 0. pub v_accuracy: u16, - /// Number of satellites used in solution + /// 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 { +impl MsgPosLLHDepA { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgPosLLHDepA { sender_id: None, tow: _buf.read_u32::()?, - n: _buf.read_i32::()?, - e: _buf.read_i32::()?, - d: _buf.read_i32::()?, + 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()?, @@ -1028,45 +934,8 @@ impl MsgVelNED { }) } } -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); - } -} - -/// Age of corrections -/// -/// This message reports the Age of the corrections used for the current -/// Differential solution -/// -#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] -#[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; +impl super::SBPMessage for MsgPosLLHDepA { + const MSG_ID: u16 = 513; fn get_sender_id(&self) -> Option { self.sender_id @@ -1077,69 +946,49 @@ impl super::SBPMessage for MsgAgeCorrections { } } -/// Geodetic Position +/// Computed Position and Protection Level /// -/// 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. +/// This message reports the local vertical and horizontal protection levels +/// associated with a given LLH position solution. The full GPS time is given +/// by the preceding MSG_GPS_TIME with the matching time-of-week (tow). /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgPosLLHCov { +pub struct MsgProtectionLevel { pub sender_id: Option, /// GPS Time of Week pub tow: u32, + /// Vertical protection level + pub vpl: u16, + /// Horizontal protection level + pub hpl: u16, /// Latitude pub lat: f64, /// Longitude pub lon: f64, - /// Height above WGS84 ellipsoid + /// Height 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 { +impl MsgProtectionLevel { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgProtectionLevel { sender_id: None, tow: _buf.read_u32::()?, + vpl: _buf.read_u16::()?, + hpl: _buf.read_u16::()?, 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; +impl super::SBPMessage for MsgProtectionLevel { + const MSG_ID: u16 = 534; fn get_sender_id(&self) -> Option { self.sender_id @@ -1150,67 +999,54 @@ impl super::SBPMessage for MsgPosLLHCov { } } -/// Velocity in NED +/// UTC Time /// -/// 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. +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgVelNEDCov { +pub struct MsgUtcTime { 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 + /// 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 MsgVelNEDCov { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgVelNEDCov { +impl MsgUtcTime { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgUtcTime { 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()?, + 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 MsgVelNEDCov { - const MSG_ID: u16 = 530; +impl super::SBPMessage for MsgUtcTime { + const MSG_ID: u16 = 259; fn get_sender_id(&self) -> Option { self.sender_id @@ -1294,70 +1130,49 @@ impl super::SBPMessage for MsgVelBody { } } -/// Single-point position in ECEF +/// Velocity 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 +/// 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). /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgPosECEFCov { +pub struct MsgVelECEF { 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 { + /// 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_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::()?, + 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 MsgPosECEFCov { - const MSG_ID: u16 = 532; +impl super::SBPMessage for MsgVelECEF { + const MSG_ID: u16 = 525; fn get_sender_id(&self) -> Option { self.sender_id @@ -1436,49 +1251,234 @@ impl super::SBPMessage for MsgVelECEFCov { } } -/// Computed Position and Protection Level +/// Velocity in ECEF /// -/// This message reports the local vertical and horizontal protection levels -/// associated with a given LLH position solution. The full GPS time is given -/// by the preceding MSG_GPS_TIME with the matching time-of-week (tow). +/// 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). /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgProtectionLevel { +pub struct MsgVelECEFDepA { pub sender_id: Option, /// GPS Time of Week pub tow: u32, - /// Vertical protection level - pub vpl: u16, - /// Horizontal protection level - pub hpl: u16, - /// Latitude - pub lat: f64, - /// Longitude - pub lon: f64, - /// Height - pub height: f64, + /// 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). +/// +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +#[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 MsgProtectionLevel { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgProtectionLevel { +impl MsgVelNED { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgVelNED { sender_id: None, tow: _buf.read_u32::()?, - vpl: _buf.read_u16::()?, - hpl: _buf.read_u16::()?, - lat: _buf.read_f64::()?, - lon: _buf.read_f64::()?, - height: _buf.read_f64::()?, + 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 MsgProtectionLevel { - const MSG_ID: u16 = 534; +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. +/// +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +#[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 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). +/// +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +#[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 diff --git a/rust/sbp/src/messages/observation.rs b/rust/sbp/src/messages/observation.rs index efa8e3e645..9b1b0563d9 100644 --- a/rust/sbp/src/messages/observation.rs +++ b/rust/sbp/src/messages/observation.rs @@ -21,32 +21,48 @@ use super::gnss::*; #[cfg(feature = "serialize")] use serde::{Deserialize, Serialize}; -/// Header for observation message. -/// -/// Header of a GNSS observation message. -/// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[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, +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 ObservationHeader { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(ObservationHeader { - t: GPSTime::parse(_buf)?, - n_obs: _buf.read_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, crate::Error> { + pub fn parse_array(buf: &mut &[u8]) -> Result, crate::Error> { let mut v = Vec::new(); while buf.len() > 0 { - v.push(ObservationHeader::parse(buf)?); + v.push(AlmanacCommonContent::parse(buf)?); } Ok(v) } @@ -54,109 +70,102 @@ impl ObservationHeader { pub fn parse_array_limit( buf: &mut &[u8], n: usize, - ) -> Result, crate::Error> { + ) -> Result, crate::Error> { let mut v = Vec::new(); for _ in 0..n { - v.push(ObservationHeader::parse(buf)?); + v.push(AlmanacCommonContent::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. -/// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct Doppler { - /// Doppler whole Hz - pub i: i16, - /// Doppler fractional part - pub f: u8, +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 Doppler { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(Doppler { - i: _buf.read_i16::()?, - f: _buf.read_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, crate::Error> { + pub fn parse_array(buf: &mut &[u8]) -> Result, crate::Error> { let mut v = Vec::new(); while buf.len() > 0 { - v.push(Doppler::parse(buf)?); + v.push(AlmanacCommonContentDep::parse(buf)?); } Ok(v) } - pub fn parse_array_limit(buf: &mut &[u8], n: usize) -> Result, crate::Error> { + pub fn parse_array_limit( + buf: &mut &[u8], + n: usize, + ) -> Result, crate::Error> { let mut v = Vec::new(); for _ in 0..n { - v.push(Doppler::parse(buf)?); + v.push(AlmanacCommonContentDep::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. +/// GPS carrier phase measurement. /// -/// 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. +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[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, +pub struct CarrierPhaseDepA { + /// Carrier phase whole cycles + pub i: i32, + /// Carrier phase fractional part + pub f: u8, } -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)?, +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, crate::Error> { + pub fn parse_array(buf: &mut &[u8]) -> Result, crate::Error> { let mut v = Vec::new(); while buf.len() > 0 { - v.push(PackedObsContent::parse(buf)?); + v.push(CarrierPhaseDepA::parse(buf)?); } Ok(v) } @@ -164,74 +173,51 @@ impl PackedObsContent { pub fn parse_array_limit( buf: &mut &[u8], n: usize, - ) -> Result, crate::Error> { + ) -> Result, crate::Error> { let mut v = Vec::new(); for _ in 0..n { - v.push(PackedObsContent::parse(buf)?); + v.push(CarrierPhaseDepA::parse(buf)?); } Ok(v) } } -/// Network correction for a particular satellite signal. +/// GNSS doppler measurement. /// -/// Pseudorange and carrier phase network corrections for a satellite signal. +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[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, +pub struct Doppler { + /// Doppler whole Hz + pub i: i16, + /// Doppler fractional part + pub f: u8, } -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::()?, +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, crate::Error> { + pub fn parse_array(buf: &mut &[u8]) -> Result, crate::Error> { let mut v = Vec::new(); while buf.len() > 0 { - v.push(PackedOsrContent::parse(buf)?); + v.push(Doppler::parse(buf)?); } Ok(v) } - pub fn parse_array_limit( - buf: &mut &[u8], - n: usize, - ) -> Result, crate::Error> { + pub fn parse_array_limit(buf: &mut &[u8], n: usize) -> Result, crate::Error> { let mut v = Vec::new(); for _ in 0..n { - v.push(PackedOsrContent::parse(buf)?); + v.push(Doppler::parse(buf)?); } Ok(v) } @@ -290,37 +276,37 @@ impl EphemerisCommonContent { #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct EphemerisCommonContentDepB { - /// GNSS signal identifier (16 bit) - pub sid: GnssSignal, +pub struct EphemerisCommonContentDepA { + /// GNSS signal identifier + pub sid: GnssSignalDep, /// Time of Ephemerides - pub toe: GPSTimeSec, + 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 Others: - /// 0 = valid, non-zero = invalid + /// 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 EphemerisCommonContentDepB { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(EphemerisCommonContentDepB { - sid: GnssSignal::parse(_buf)?, - toe: GPSTimeSec::parse(_buf)?, - ura: _buf.read_f64::()?, +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, crate::Error> { + pub fn parse_array(buf: &mut &[u8]) -> Result, crate::Error> { let mut v = Vec::new(); while buf.len() > 0 { - v.push(EphemerisCommonContentDepB::parse(buf)?); + v.push(EphemerisCommonContentDepA::parse(buf)?); } Ok(v) } @@ -328,10 +314,10 @@ impl EphemerisCommonContentDepB { pub fn parse_array_limit( buf: &mut &[u8], n: usize, - ) -> Result, crate::Error> { + ) -> Result, crate::Error> { let mut v = Vec::new(); for _ in 0..n { - v.push(EphemerisCommonContentDepB::parse(buf)?); + v.push(EphemerisCommonContentDepA::parse(buf)?); } Ok(v) } @@ -340,37 +326,37 @@ impl EphemerisCommonContentDepB { #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct EphemerisCommonContentDepA { - /// GNSS signal identifier - pub sid: GnssSignalDep, +pub struct EphemerisCommonContentDepB { + /// GNSS signal identifier (16 bit) + pub sid: GnssSignal, /// Time of Ephemerides - pub toe: GPSTimeDep, + 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 SBAS: 0 - /// = valid, non-zero = invalid GLO: 0 = valid, non-zero = invalid + /// 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 EphemerisCommonContentDepA { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(EphemerisCommonContentDepA { - sid: GnssSignalDep::parse(_buf)?, - toe: GPSTimeDep::parse(_buf)?, +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, crate::Error> { + pub fn parse_array(buf: &mut &[u8]) -> Result, crate::Error> { let mut v = Vec::new(); while buf.len() > 0 { - v.push(EphemerisCommonContentDepA::parse(buf)?); + v.push(EphemerisCommonContentDepB::parse(buf)?); } Ok(v) } @@ -378,522 +364,283 @@ impl EphemerisCommonContentDepA { pub fn parse_array_limit( buf: &mut &[u8], n: usize, - ) -> Result, crate::Error> { + ) -> Result, crate::Error> { let mut v = Vec::new(); for _ in 0..n { - v.push(EphemerisCommonContentDepA::parse(buf)?); + v.push(EphemerisCommonContentDepB::parse(buf)?); } Ok(v) } } -/// Header for observation message. -/// -/// Header of a GPS observation message. -/// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[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, +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 ObservationHeaderDep { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(ObservationHeaderDep { - t: GPSTimeDep::parse(_buf)?, - n_obs: _buf.read_u8()?, +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, crate::Error> { + pub fn parse_array(buf: &mut &[u8]) -> Result, crate::Error> { let mut v = Vec::new(); while buf.len() > 0 { - v.push(ObservationHeaderDep::parse(buf)?); + v.push(GnssCapb::parse(buf)?); } Ok(v) } - pub fn parse_array_limit( - buf: &mut &[u8], - n: usize, - ) -> Result, crate::Error> { + pub fn parse_array_limit(buf: &mut &[u8], n: usize) -> Result, crate::Error> { let mut v = Vec::new(); for _ in 0..n { - v.push(ObservationHeaderDep::parse(buf)?); + v.push(GnssCapb::parse(buf)?); } Ok(v) } } -/// GPS carrier phase measurement. +/// Satellite broadcast ephemeris for GLO /// -/// 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. +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct CarrierPhaseDepA { - /// Carrier phase whole cycles - pub i: i32, - /// Carrier phase fractional part - pub f: u8, +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 CarrierPhaseDepA { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(CarrierPhaseDepA { - i: _buf.read_i32::()?, - f: _buf.read_u8()?, +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::()?, }) } - pub fn parse_array(buf: &mut &[u8]) -> Result, crate::Error> { - let mut v = Vec::new(); - while buf.len() > 0 { - v.push(CarrierPhaseDepA::parse(buf)?); - } - Ok(v) +} +impl super::SBPMessage for MsgAlmanacGlo { + const MSG_ID: u16 = 115; + + fn get_sender_id(&self) -> Option { + self.sender_id } - pub fn parse_array_limit( - buf: &mut &[u8], - n: usize, - ) -> Result, crate::Error> { - let mut v = Vec::new(); - for _ in 0..n { - v.push(CarrierPhaseDepA::parse(buf)?); - } - Ok(v) + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); } } -/// Deprecated +/// Satellite broadcast ephemeris for GLO /// -/// Deprecated. +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[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, +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 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()?, +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::()?, }) } - pub fn parse_array(buf: &mut &[u8]) -> Result, crate::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, crate::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. -/// -#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] -#[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 super::SBPMessage for MsgAlmanacGloDep { + const MSG_ID: u16 = 113; -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, crate::Error> { - let mut v = Vec::new(); - while buf.len() > 0 { - v.push(PackedObsContentDepB::parse(buf)?); - } - Ok(v) + fn get_sender_id(&self) -> Option { + self.sender_id } - pub fn parse_array_limit( - buf: &mut &[u8], - n: usize, - ) -> Result, crate::Error> { - let mut v = Vec::new(); - for _ in 0..n { - v.push(PackedObsContentDepB::parse(buf)?); - } - Ok(v) + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); } } -/// GPS observations for a particular satellite signal. +/// Satellite broadcast ephemeris for GPS /// -/// 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. +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[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, crate::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, crate::Error> { - let mut v = Vec::new(); - for _ in 0..n { - v.push(PackedObsContentDepC::parse(buf)?); - } - Ok(v) - } -} - -#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] -#[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, crate::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, crate::Error> { - let mut v = Vec::new(); - for _ in 0..n { - v.push(GnssCapb::parse(buf)?); - } - Ok(v) - } -} - -#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] -#[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, crate::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, crate::Error> { - let mut v = Vec::new(); - for _ in 0..n { - v.push(AlmanacCommonContent::parse(buf)?); - } - Ok(v) - } -} - -#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] -#[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, +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 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()?, +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::()?, }) } - pub fn parse_array(buf: &mut &[u8]) -> Result, crate::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, crate::Error> { - let mut v = Vec::new(); - for _ in 0..n { - v.push(AlmanacCommonContentDep::parse(buf)?); - } - Ok(v) - } -} - -/// Satellite azimuth and elevation. -/// -/// Satellite azimuth and elevation. -/// -#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] -#[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 super::SBPMessage for MsgAlmanacGPS { + const MSG_ID: u16 = 114; -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, crate::Error> { - let mut v = Vec::new(); - while buf.len() > 0 { - v.push(SvAzEl::parse(buf)?); - } - Ok(v) + fn get_sender_id(&self) -> Option { + self.sender_id } - pub fn parse_array_limit(buf: &mut &[u8], n: usize) -> Result, crate::Error> { - let mut v = Vec::new(); - for _ in 0..n { - v.push(SvAzEl::parse(buf)?); - } - Ok(v) + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); } } -/// Deprecated +/// Satellite broadcast ephemeris for GPS /// -/// Deprecated. +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgEphemerisDepA { +pub struct MsgAlmanacGPSDep { 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, + /// Values common for all almanac types + pub common: AlmanacCommonContentDep, /// Mean anomaly at reference time pub m0: f64, /// Eccentricity of satellite orbit @@ -905,45 +652,20 @@ pub struct MsgEphemerisDepA { /// 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, + 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 MsgEphemerisDepA { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgEphemerisDepA { +impl MsgAlmanacGPSDep { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgAlmanacGPSDep { 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::()?, + common: AlmanacCommonContentDep::parse(_buf)?, m0: _buf.read_f64::()?, ecc: _buf.read_f64::()?, sqrta: _buf.read_f64::()?, @@ -951,22 +673,13 @@ impl MsgEphemerisDepA { 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; +impl super::SBPMessage for MsgAlmanacGPSDep { + const MSG_ID: u16 = 112; fn get_sender_id(&self) -> Option { self.sender_id @@ -977,37 +690,40 @@ impl super::SBPMessage for MsgEphemerisDepA { } } -/// Deprecated +/// Base station position in ECEF /// -/// 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. +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgObsDepB { +pub struct MsgBasePosECEF { 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, + /// ECEF X coodinate + pub x: f64, + /// ECEF Y coordinate + pub y: f64, + /// ECEF Z coordinate + pub z: f64, } -impl MsgObsDepB { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgObsDepB { +impl MsgBasePosECEF { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgBasePosECEF { sender_id: None, - header: ObservationHeaderDep::parse(_buf)?, - obs: PackedObsContentDepB::parse_array(_buf)?, + x: _buf.read_f64::()?, + y: _buf.read_f64::()?, + z: _buf.read_f64::()?, }) } } -impl super::SBPMessage for MsgObsDepB { - const MSG_ID: u16 = 67; +impl super::SBPMessage for MsgBasePosECEF { + const MSG_ID: u16 = 72; fn get_sender_id(&self) -> Option { self.sender_id @@ -1061,6 +777,115 @@ impl super::SBPMessage for MsgBasePosLLH { } } +/// 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. +/// +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +#[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 /// /// Deprecated. @@ -1068,25 +893,101 @@ impl super::SBPMessage for MsgBasePosLLH { #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgObsDepA { +pub struct MsgEphemerisDepA { 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, + /// 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 MsgObsDepA { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgObsDepA { +impl MsgEphemerisDepA { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgEphemerisDepA { sender_id: None, - header: ObservationHeaderDep::parse(_buf)?, - obs: PackedObsContentDepA::parse_array(_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::()?, + 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 MsgObsDepA { - const MSG_ID: u16 = 69; +impl super::SBPMessage for MsgEphemerisDepA { + const MSG_ID: u16 = 26; fn get_sender_id(&self) -> Option { self.sender_id @@ -1337,82 +1238,121 @@ impl super::SBPMessage for MsgEphemerisDepC { } } -/// 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. -/// -#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] -#[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); - } -} - -/// Deprecated +/// Satellite broadcast ephemeris /// -/// 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. +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgObsDepC { +pub struct MsgEphemerisDepD { 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, + /// 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 MsgObsDepC { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgObsDepC { +impl MsgEphemerisDepD { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgEphemerisDepD { sender_id: None, - header: ObservationHeaderDep::parse(_buf)?, - obs: PackedObsContentDepC::parse_array(_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::()?, + 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 MsgObsDepC { - const MSG_ID: u16 = 73; +impl super::SBPMessage for MsgEphemerisDepD { + const MSG_ID: u16 = 128; fn get_sender_id(&self) -> Option { self.sender_id @@ -1423,38 +1363,108 @@ impl super::SBPMessage for MsgObsDepC { } } -/// GPS satellite observations +/// Satellite broadcast ephemeris for Galileo /// -/// 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. +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgObs { +pub struct MsgEphemerisGal { 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, + /// 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 MsgObs { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgObs { +impl MsgEphemerisGal { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgEphemerisGal { sender_id: None, - header: ObservationHeader::parse(_buf)?, - obs: PackedObsContent::parse_array(_buf)?, + 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 MsgObs { - const MSG_ID: u16 = 74; +impl super::SBPMessage for MsgEphemerisGal { + const MSG_ID: u16 = 141; fn get_sender_id(&self) -> Option { self.sender_id @@ -1465,20 +1475,40 @@ impl super::SBPMessage for MsgObs { } } -/// Satellite broadcast ephemeris for GPS +/// Deprecated /// -/// 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. +/// This observation message has been deprecated in favor of +/// an ephemeris message with explicit source of NAV data. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgAlmanacGPSDep { +pub struct MsgEphemerisGalDepA { pub sender_id: Option, - /// Values common for all almanac types - pub common: AlmanacCommonContentDep, + /// 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 @@ -1493,17 +1523,36 @@ pub struct MsgAlmanacGPSDep { 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 MsgAlmanacGPSDep { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgAlmanacGPSDep { +impl MsgEphemerisGalDepA { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgEphemerisGalDepA { sender_id: None, - common: AlmanacCommonContentDep::parse(_buf)?, + 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::()?, @@ -1511,13 +1560,18 @@ impl MsgAlmanacGPSDep { 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 MsgAlmanacGPSDep { - const MSG_ID: u16 = 112; +impl super::SBPMessage for MsgEphemerisGalDepA { + const MSG_ID: u16 = 149; fn get_sender_id(&self) -> Option { self.sender_id @@ -1530,52 +1584,159 @@ impl super::SBPMessage for MsgAlmanacGPSDep { /// 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. +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgAlmanacGloDep { +pub struct MsgEphemerisGlo { 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, + /// 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: crate::parser::read_double_array_limit(_buf, 3)?, + vel: crate::parser::read_double_array_limit(_buf, 3)?, + acc: crate::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 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. +/// +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +#[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: crate::parser::read_double_array_limit(_buf, 3)?, + vel: crate::parser::read_double_array_limit(_buf, 3)?, + acc: crate::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); + } +} + +/// 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. +/// +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +#[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 MsgAlmanacGloDep { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgAlmanacGloDep { +impl MsgEphemerisGloDepB { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgEphemerisGloDepB { 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::()?, + common: EphemerisCommonContentDepB::parse(_buf)?, + gamma: _buf.read_f64::()?, + tau: _buf.read_f64::()?, + pos: crate::parser::read_double_array_limit(_buf, 3)?, + vel: crate::parser::read_double_array_limit(_buf, 3)?, + acc: crate::parser::read_double_array_limit(_buf, 3)?, }) } } -impl super::SBPMessage for MsgAlmanacGloDep { - const MSG_ID: u16 = 113; +impl super::SBPMessage for MsgEphemerisGloDepB { + const MSG_ID: u16 = 133; fn get_sender_id(&self) -> Option { self.sender_id @@ -1586,59 +1747,54 @@ impl super::SBPMessage for MsgAlmanacGloDep { } } -/// Satellite broadcast ephemeris for GPS +/// 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 Navstar GPS Space Segment/Navigation user interfaces -/// (ICD-GPS-200, Chapter 20.3.3.5.1.2 Almanac Data) for more details. +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgAlmanacGPS { +pub struct MsgEphemerisGloDepC { 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, + /// 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 MsgAlmanacGPS { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgAlmanacGPS { +impl MsgEphemerisGloDepC { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgEphemerisGloDepC { 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::()?, + common: EphemerisCommonContentDepB::parse(_buf)?, + gamma: _buf.read_f64::()?, + tau: _buf.read_f64::()?, + d_tau: _buf.read_f64::()?, + pos: crate::parser::read_double_array_limit(_buf, 3)?, + vel: crate::parser::read_double_array_limit(_buf, 3)?, + acc: crate::parser::read_double_array_limit(_buf, 3)?, + fcn: _buf.read_u8()?, }) } } -impl super::SBPMessage for MsgAlmanacGPS { - const MSG_ID: u16 = 114; +impl super::SBPMessage for MsgEphemerisGloDepC { + const MSG_ID: u16 = 135; fn get_sender_id(&self) -> Option { self.sender_id @@ -1649,54 +1805,54 @@ impl super::SBPMessage for MsgAlmanacGPS { } } -/// Satellite broadcast ephemeris for GLO +/// Deprecated /// -/// 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. +/// This observation message has been deprecated in favor of +/// ephemeris message using floats for size reduction. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgAlmanacGlo { +pub struct MsgEphemerisGloDepD { 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, + /// 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 MsgAlmanacGlo { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgAlmanacGlo { +impl MsgEphemerisGloDepD { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgEphemerisGloDepD { 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::()?, + common: EphemerisCommonContentDepB::parse(_buf)?, + gamma: _buf.read_f64::()?, + tau: _buf.read_f64::()?, + d_tau: _buf.read_f64::()?, + pos: crate::parser::read_double_array_limit(_buf, 3)?, + vel: crate::parser::read_double_array_limit(_buf, 3)?, + acc: crate::parser::read_double_array_limit(_buf, 3)?, + fcn: _buf.read_u8()?, + iod: _buf.read_u8()?, }) } } -impl super::SBPMessage for MsgAlmanacGlo { - const MSG_ID: u16 = 115; +impl super::SBPMessage for MsgEphemerisGloDepD { + const MSG_ID: u16 = 136; fn get_sender_id(&self) -> Option { self.sender_id @@ -1707,44 +1863,103 @@ impl super::SBPMessage for MsgAlmanacGlo { } } -/// GLONASS L1/L2 Code-Phase biases +/// Satellite broadcast ephemeris for GPS /// -/// 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) +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgGloBiases { +pub struct MsgEphemerisGPS { 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, + /// 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 MsgGloBiases { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgGloBiases { +impl MsgEphemerisGPS { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgEphemerisGPS { 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::()?, + 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 MsgGloBiases { - const MSG_ID: u16 = 117; +impl super::SBPMessage for MsgEphemerisGPS { + const MSG_ID: u16 = 138; fn get_sender_id(&self) -> Option { self.sender_id @@ -1755,7 +1970,7 @@ impl super::SBPMessage for MsgGloBiases { } } -/// Satellite broadcast ephemeris +/// Satellite broadcast ephemeris for GPS /// /// The ephemeris message returns a set of satellite orbit /// parameters that is used to calculate GPS satellite position, @@ -1766,8 +1981,10 @@ impl super::SBPMessage for MsgGloBiases { #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgEphemerisDepD { +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 @@ -1810,32 +2027,19 @@ pub struct MsgEphemerisDepD { 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, + /// Clock reference + pub toc: GPSTimeDep, /// 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 { +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::()?, @@ -1855,21 +2059,14 @@ impl MsgEphemerisDepD { 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)?, + toc: GPSTimeDep::parse(_buf)?, iode: _buf.read_u8()?, iodc: _buf.read_u16::()?, - reserved: _buf.read_u32::()?, }) } } -impl super::SBPMessage for MsgEphemerisDepD { - const MSG_ID: u16 = 128; +impl super::SBPMessage for MsgEphemerisGPSDepE { + const MSG_ID: u16 = 129; fn get_sender_id(&self) -> Option { self.sender_id @@ -1880,21 +2077,18 @@ impl super::SBPMessage for MsgEphemerisDepD { } } -/// Satellite broadcast ephemeris for GPS +/// Deprecated /// -/// 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. +/// This observation message has been deprecated in favor of +/// ephemeris message using floats for size reduction. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgEphemerisGPSDepE { +pub struct MsgEphemerisGPSDepF { pub sender_id: Option, /// Values common for all ephemeris types - pub common: EphemerisCommonContentDepA, + pub common: EphemerisCommonContentDepB, /// Group delay differential between L1 and L2 pub tgd: f64, /// Amplitude of the sine harmonic correction term to the orbit radius @@ -1938,18 +2132,18 @@ pub struct MsgEphemerisGPSDepE { /// Polynomial clock correction coefficient (rate of clock drift) pub af2: f64, /// Clock reference - pub toc: GPSTimeDep, + pub toc: GPSTimeSec, /// 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 { +impl MsgEphemerisGPSDepF { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgEphemerisGPSDepF { sender_id: None, - common: EphemerisCommonContentDepA::parse(_buf)?, + common: EphemerisCommonContentDepB::parse(_buf)?, tgd: _buf.read_f64::()?, c_rs: _buf.read_f64::()?, c_rc: _buf.read_f64::()?, @@ -1969,14 +2163,14 @@ impl MsgEphemerisGPSDepE { af0: _buf.read_f64::()?, af1: _buf.read_f64::()?, af2: _buf.read_f64::()?, - toc: GPSTimeDep::parse(_buf)?, + toc: GPSTimeSec::parse(_buf)?, iode: _buf.read_u8()?, iodc: _buf.read_u16::()?, }) } } -impl super::SBPMessage for MsgEphemerisGPSDepE { - const MSG_ID: u16 = 129; +impl super::SBPMessage for MsgEphemerisGPSDepF { + const MSG_ID: u16 = 134; fn get_sender_id(&self) -> Option { self.sender_id @@ -1987,40 +2181,145 @@ impl super::SBPMessage for MsgEphemerisGPSDepE { } } +/// 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. +/// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgEphemerisSbasDepA { +pub struct MsgEphemerisQzss { pub sender_id: Option, /// Values common for all ephemeris types - pub common: EphemerisCommonContentDepA, + 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); + } +} + +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +#[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, + pub vel: Vec, /// Acceleration of the GEO at time toe - pub acc: Vec, + pub acc: Vec, /// Time offset of the GEO clock w.r.t. SBAS Network Time - pub a_gf0: f64, + pub a_gf0: f32, /// Drift of the GEO clock w.r.t. SBAS Network Time - pub a_gf1: f64, + pub a_gf1: f32, } -impl MsgEphemerisSbasDepA { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgEphemerisSbasDepA { +impl MsgEphemerisSbas { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgEphemerisSbas { sender_id: None, - common: EphemerisCommonContentDepA::parse(_buf)?, + common: EphemerisCommonContent::parse(_buf)?, pos: crate::parser::read_double_array_limit(_buf, 3)?, - vel: crate::parser::read_double_array_limit(_buf, 3)?, - acc: crate::parser::read_double_array_limit(_buf, 3)?, - a_gf0: _buf.read_f64::()?, - a_gf1: _buf.read_f64::()?, + vel: crate::parser::read_float_array_limit(_buf, 3)?, + acc: crate::parser::read_float_array_limit(_buf, 3)?, + a_gf0: _buf.read_f32::()?, + a_gf1: _buf.read_f32::()?, }) } -} -impl super::SBPMessage for MsgEphemerisSbasDepA { - const MSG_ID: u16 = 130; +} +impl super::SBPMessage for MsgEphemerisSbas { + const MSG_ID: u16 = 140; fn get_sender_id(&self) -> Option { self.sender_id @@ -2031,48 +2330,40 @@ impl super::SBPMessage for MsgEphemerisSbasDepA { } } -/// 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. -/// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgEphemerisGloDepA { +pub struct MsgEphemerisSbasDepA { 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 + /// Position of the GEO at time toe pub pos: Vec, - /// Velocity vector of the SV at tb in PZ-90.02 coordinates system + /// Velocity of the GEO at time toe pub vel: Vec, - /// Acceleration vector of the SV at tb in PZ-90.02 coordinates sys + /// 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 MsgEphemerisGloDepA { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgEphemerisGloDepA { +impl MsgEphemerisSbasDepA { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgEphemerisSbasDepA { sender_id: None, common: EphemerisCommonContentDepA::parse(_buf)?, - gamma: _buf.read_f64::()?, - tau: _buf.read_f64::()?, pos: crate::parser::read_double_array_limit(_buf, 3)?, vel: crate::parser::read_double_array_limit(_buf, 3)?, acc: crate::parser::read_double_array_limit(_buf, 3)?, + a_gf0: _buf.read_f64::()?, + a_gf1: _buf.read_f64::()?, }) } } -impl super::SBPMessage for MsgEphemerisGloDepA { - const MSG_ID: u16 = 131; +impl super::SBPMessage for MsgEphemerisSbasDepA { + const MSG_ID: u16 = 130; fn get_sender_id(&self) -> Option { self.sender_id @@ -2132,152 +2423,44 @@ impl super::SBPMessage for MsgEphemerisSbasDepB { } } -/// 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. -/// -#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] -#[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: crate::parser::read_double_array_limit(_buf, 3)?, - vel: crate::parser::read_double_array_limit(_buf, 3)?, - acc: crate::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); - } -} - -/// Deprecated +/// GLONASS L1/L2 Code-Phase biases /// -/// This observation message has been deprecated in favor of -/// ephemeris message using floats for size reduction. +/// 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) /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgEphemerisGPSDepF { +pub struct MsgGloBiases { 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, + /// 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 MsgEphemerisGPSDepF { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgEphemerisGPSDepF { +impl MsgGloBiases { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgGloBiases { 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::()?, + 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 MsgEphemerisGPSDepF { - const MSG_ID: u16 = 134; +impl super::SBPMessage for MsgGloBiases { + const MSG_ID: u16 = 117; fn get_sender_id(&self) -> Option { self.sender_id @@ -2288,54 +2471,28 @@ impl super::SBPMessage for MsgEphemerisGPSDepF { } } -/// 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. -/// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgEphemerisGloDepC { +pub struct MsgGnssCapb { 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, + /// Navigation Message Correction Table Validity Time + pub t_nmct: GPSTimeSec, + /// GNSS capabilities masks + pub gc: GnssCapb, } -impl MsgEphemerisGloDepC { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgEphemerisGloDepC { +impl MsgGnssCapb { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgGnssCapb { sender_id: None, - common: EphemerisCommonContentDepB::parse(_buf)?, - gamma: _buf.read_f64::()?, - tau: _buf.read_f64::()?, - d_tau: _buf.read_f64::()?, - pos: crate::parser::read_double_array_limit(_buf, 3)?, - vel: crate::parser::read_double_array_limit(_buf, 3)?, - acc: crate::parser::read_double_array_limit(_buf, 3)?, - fcn: _buf.read_u8()?, + t_nmct: GPSTimeSec::parse(_buf)?, + gc: GnssCapb::parse(_buf)?, }) } } -impl super::SBPMessage for MsgEphemerisGloDepC { - const MSG_ID: u16 = 135; +impl super::SBPMessage for MsgGnssCapb { + const MSG_ID: u16 = 150; fn get_sender_id(&self) -> Option { self.sender_id @@ -2346,54 +2503,42 @@ impl super::SBPMessage for MsgEphemerisGloDepC { } } -/// Deprecated -/// -/// This observation message has been deprecated in favor of -/// ephemeris message using floats for size reduction. +/// Group Delay +/// +/// Please see ICD-GPS-200 (30.3.3.3.1.1) for more details. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgEphemerisGloDepD { +pub struct MsgGroupDelay { 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, + /// 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 MsgEphemerisGloDepD { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgEphemerisGloDepD { +impl MsgGroupDelay { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgGroupDelay { sender_id: None, - common: EphemerisCommonContentDepB::parse(_buf)?, - gamma: _buf.read_f64::()?, - tau: _buf.read_f64::()?, - d_tau: _buf.read_f64::()?, - pos: crate::parser::read_double_array_limit(_buf, 3)?, - vel: crate::parser::read_double_array_limit(_buf, 3)?, - acc: crate::parser::read_double_array_limit(_buf, 3)?, - fcn: _buf.read_u8()?, - iod: _buf.read_u8()?, + 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 MsgEphemerisGloDepD { - const MSG_ID: u16 = 136; +impl super::SBPMessage for MsgGroupDelay { + const MSG_ID: u16 = 148; fn get_sender_id(&self) -> Option { self.sender_id @@ -2404,105 +2549,42 @@ impl super::SBPMessage for MsgEphemerisGloDepD { } } -/// Satellite broadcast ephemeris for BDS +/// Group Delay /// -/// 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. +/// Please see ICD-GPS-200 (30.3.3.3.1.1) for more details. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgEphemerisBds { +pub struct MsgGroupDelayDepA { 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, + /// 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 MsgEphemerisBds { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgEphemerisBds { +impl MsgGroupDelayDepA { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgGroupDelayDepA { 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::()?, + 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 MsgEphemerisBds { - const MSG_ID: u16 = 137; +impl super::SBPMessage for MsgGroupDelayDepA { + const MSG_ID: u16 = 146; fn get_sender_id(&self) -> Option { self.sender_id @@ -2513,103 +2595,93 @@ impl super::SBPMessage for MsgEphemerisBds { } } -/// Satellite broadcast ephemeris for GPS +/// Group Delay /// -/// 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. +/// Please see ICD-GPS-200 (30.3.3.3.1.1) for more details. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgEphemerisGPS { +pub struct MsgGroupDelayDepB { 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, + /// 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); + } } -impl MsgEphemerisGPS { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgEphemerisGPS { +/// 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. +/// +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +#[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, - 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::()?, + 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 MsgEphemerisGPS { - const MSG_ID: u16 = 138; +impl super::SBPMessage for MsgIono { + const MSG_ID: u16 = 144; fn get_sender_id(&self) -> Option { self.sender_id @@ -2620,57 +2692,38 @@ impl super::SBPMessage for MsgEphemerisGPS { } } -/// Satellite broadcast ephemeris for GLO +/// GPS satellite observations /// -/// 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. +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgEphemerisGlo { +pub struct MsgObs { 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, + /// Header of a GPS observation message + pub header: ObservationHeader, + /// Pseudorange and carrier phase observation for a satellite being tracked. + pub obs: Vec, } -impl MsgEphemerisGlo { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgEphemerisGlo { +impl MsgObs { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgObs { sender_id: None, - common: EphemerisCommonContent::parse(_buf)?, - gamma: _buf.read_f32::()?, - tau: _buf.read_f32::()?, - d_tau: _buf.read_f32::()?, - pos: crate::parser::read_double_array_limit(_buf, 3)?, - vel: crate::parser::read_double_array_limit(_buf, 3)?, - acc: crate::parser::read_float_array_limit(_buf, 3)?, - fcn: _buf.read_u8()?, - iod: _buf.read_u8()?, + header: ObservationHeader::parse(_buf)?, + obs: PackedObsContent::parse_array(_buf)?, }) } } -impl super::SBPMessage for MsgEphemerisGlo { - const MSG_ID: u16 = 139; +impl super::SBPMessage for MsgObs { + const MSG_ID: u16 = 74; fn get_sender_id(&self) -> Option { self.sender_id @@ -2681,40 +2734,32 @@ impl super::SBPMessage for MsgEphemerisGlo { } } +/// Deprecated +/// +/// Deprecated. +/// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgEphemerisSbas { +pub struct MsgObsDepA { 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, + /// Header of a GPS observation message + pub header: ObservationHeaderDep, + /// Pseudorange and carrier phase observation for a satellite being tracked. + pub obs: Vec, } -impl MsgEphemerisSbas { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgEphemerisSbas { +impl MsgObsDepA { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgObsDepA { sender_id: None, - common: EphemerisCommonContent::parse(_buf)?, - pos: crate::parser::read_double_array_limit(_buf, 3)?, - vel: crate::parser::read_float_array_limit(_buf, 3)?, - acc: crate::parser::read_float_array_limit(_buf, 3)?, - a_gf0: _buf.read_f32::()?, - a_gf1: _buf.read_f32::()?, + header: ObservationHeaderDep::parse(_buf)?, + obs: PackedObsContentDepA::parse_array(_buf)?, }) } } -impl super::SBPMessage for MsgEphemerisSbas { - const MSG_ID: u16 = 140; +impl super::SBPMessage for MsgObsDepA { + const MSG_ID: u16 = 69; fn get_sender_id(&self) -> Option { self.sender_id @@ -2725,108 +2770,79 @@ impl super::SBPMessage for MsgEphemerisSbas { } } -/// Satellite broadcast ephemeris for Galileo +/// Deprecated /// -/// 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. +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgEphemerisGal { +pub struct MsgObsDepB { 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, + /// 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); + } } -impl MsgEphemerisGal { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgEphemerisGal { +/// 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. +/// +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +#[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, - 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()?, + header: ObservationHeaderDep::parse(_buf)?, + obs: PackedObsContentDepC::parse_array(_buf)?, }) } } -impl super::SBPMessage for MsgEphemerisGal { - const MSG_ID: u16 = 141; +impl super::SBPMessage for MsgObsDepC { + const MSG_ID: u16 = 73; fn get_sender_id(&self) -> Option { self.sender_id @@ -2837,101 +2853,32 @@ impl super::SBPMessage for MsgEphemerisGal { } } -/// Satellite broadcast ephemeris for QZSS +/// OSR corrections /// -/// The ephemeris message returns a set of satellite orbit -/// parameters that is used to calculate QZSS satellite position, -/// velocity, and clock offset. +/// The OSR message contains network corrections in an observation-like format /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgEphemerisQzss { +pub struct MsgOsr { 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, + /// Header of a GPS observation message + pub header: ObservationHeader, + /// Network correction for a satellite signal. + pub obs: Vec, } -impl MsgEphemerisQzss { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgEphemerisQzss { +impl MsgOsr { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgOsr { 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::()?, + header: ObservationHeader::parse(_buf)?, + obs: PackedOsrContent::parse_array(_buf)?, }) } } -impl super::SBPMessage for MsgEphemerisQzss { - const MSG_ID: u16 = 142; +impl super::SBPMessage for MsgOsr { + const MSG_ID: u16 = 1600; fn get_sender_id(&self) -> Option { self.sender_id @@ -2942,47 +2889,30 @@ impl super::SBPMessage for MsgEphemerisQzss { } } -/// Iono corrections +/// Satellite azimuths and elevations /// -/// 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. +/// Azimuth and elevation angles of all the visible satellites +/// that the device does have ephemeris or almanac for. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgIono { +pub struct MsgSvAzEl { 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, + /// Azimuth and elevation per satellite + pub azel: Vec, } -impl MsgIono { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgIono { +impl MsgSvAzEl { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgSvAzEl { 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::()?, + azel: SvAzEl::parse_array(_buf)?, }) } } -impl super::SBPMessage for MsgIono { - const MSG_ID: u16 = 144; +impl super::SBPMessage for MsgSvAzEl { + const MSG_ID: u16 = 151; fn get_sender_id(&self) -> Option { self.sender_id @@ -3029,349 +2959,419 @@ impl super::SBPMessage for MsgSvConfigurationGPSDep { } } -/// Group Delay +/// Header for observation message. /// -/// Please see ICD-GPS-200 (30.3.3.3.1.1) for more details. +/// Header of a GNSS observation message. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[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, +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 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 ObservationHeader { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(ObservationHeader { + t: GPSTime::parse(_buf)?, + n_obs: _buf.read_u8()?, }) } -} -impl super::SBPMessage for MsgGroupDelayDepA { - const MSG_ID: u16 = 146; - - fn get_sender_id(&self) -> Option { - self.sender_id + pub fn parse_array(buf: &mut &[u8]) -> Result, crate::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(ObservationHeader::parse(buf)?); + } + Ok(v) } - - fn set_sender_id(&mut self, new_id: u16) { - self.sender_id = Some(new_id); + + pub fn parse_array_limit( + buf: &mut &[u8], + n: usize, + ) -> Result, crate::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(ObservationHeader::parse(buf)?); + } + Ok(v) } } -/// Group Delay +/// Header for observation message. /// -/// Please see ICD-GPS-200 (30.3.3.3.1.1) for more details. +/// Header of a GPS observation message. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[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, +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 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 ObservationHeaderDep { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(ObservationHeaderDep { + t: GPSTimeDep::parse(_buf)?, + n_obs: _buf.read_u8()?, }) } -} -impl super::SBPMessage for MsgGroupDelayDepB { - const MSG_ID: u16 = 147; - - fn get_sender_id(&self) -> Option { - self.sender_id + pub fn parse_array(buf: &mut &[u8]) -> Result, crate::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(ObservationHeaderDep::parse(buf)?); + } + Ok(v) } - fn set_sender_id(&mut self, new_id: u16) { - self.sender_id = Some(new_id); + pub fn parse_array_limit( + buf: &mut &[u8], + n: usize, + ) -> Result, crate::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(ObservationHeaderDep::parse(buf)?); + } + Ok(v) } } -/// Group Delay +/// GNSS observations for a particular satellite signal. /// -/// Please see ICD-GPS-200 (30.3.3.3.1.1) for more details. +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[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 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, - /// 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)?, +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)?, - 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 + pub fn parse_array(buf: &mut &[u8]) -> Result, crate::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(PackedObsContent::parse(buf)?); + } + Ok(v) } - fn set_sender_id(&mut self, new_id: u16) { - self.sender_id = Some(new_id); + pub fn parse_array_limit( + buf: &mut &[u8], + n: usize, + ) -> Result, crate::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(PackedObsContent::parse(buf)?); + } + Ok(v) } } /// Deprecated /// -/// This observation message has been deprecated in favor of -/// an ephemeris message with explicit source of NAV data. +/// Deprecated. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[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, +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 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 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()?, }) } -} -impl super::SBPMessage for MsgEphemerisGalDepA { - const MSG_ID: u16 = 149; - - fn get_sender_id(&self) -> Option { - self.sender_id + pub fn parse_array(buf: &mut &[u8]) -> Result, crate::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(PackedObsContentDepA::parse(buf)?); + } + Ok(v) } - fn set_sender_id(&mut self, new_id: u16) { - self.sender_id = Some(new_id); + pub fn parse_array_limit( + buf: &mut &[u8], + n: usize, + ) -> Result, crate::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. +/// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[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, +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 MsgGnssCapb { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgGnssCapb { - sender_id: None, - t_nmct: GPSTimeSec::parse(_buf)?, - gc: GnssCapb::parse(_buf)?, +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)?, }) } -} -impl super::SBPMessage for MsgGnssCapb { - const MSG_ID: u16 = 150; - - fn get_sender_id(&self) -> Option { - self.sender_id + pub fn parse_array(buf: &mut &[u8]) -> Result, crate::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(PackedObsContentDepB::parse(buf)?); + } + Ok(v) } - fn set_sender_id(&mut self, new_id: u16) { - self.sender_id = Some(new_id); + pub fn parse_array_limit( + buf: &mut &[u8], + n: usize, + ) -> Result, crate::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(PackedObsContentDepB::parse(buf)?); + } + Ok(v) } } -/// Satellite azimuths and elevations +/// GPS observations for a particular satellite signal. /// -/// Azimuth and elevation angles of all the visible satellites -/// that the device does have ephemeris or almanac for. +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgSvAzEl { - pub sender_id: Option, - /// Azimuth and elevation per satellite - pub azel: Vec, +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 MsgSvAzEl { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgSvAzEl { - sender_id: None, - azel: SvAzEl::parse_array(_buf)?, +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)?, }) } -} -impl super::SBPMessage for MsgSvAzEl { - const MSG_ID: u16 = 151; - - fn get_sender_id(&self) -> Option { - self.sender_id + pub fn parse_array(buf: &mut &[u8]) -> Result, crate::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(PackedObsContentDepC::parse(buf)?); + } + Ok(v) } - fn set_sender_id(&mut self, new_id: u16) { - self.sender_id = Some(new_id); + pub fn parse_array_limit( + buf: &mut &[u8], + n: usize, + ) -> Result, crate::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(PackedObsContentDepC::parse(buf)?); + } + Ok(v) } } -/// OSR corrections +/// Network correction for a particular satellite signal. /// -/// The OSR message contains network corrections in an observation-like format +/// Pseudorange and carrier phase network corrections for a satellite signal. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[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, +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 MsgOsr { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgOsr { - sender_id: None, - header: ObservationHeader::parse(_buf)?, - obs: PackedOsrContent::parse_array(_buf)?, +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, crate::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, crate::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(PackedOsrContent::parse(buf)?); + } + Ok(v) + } } -impl super::SBPMessage for MsgOsr { - const MSG_ID: u16 = 1600; - fn get_sender_id(&self) -> Option { - self.sender_id +/// Satellite azimuth and elevation. +/// +/// Satellite azimuth and elevation. +/// +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +#[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, crate::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(SvAzEl::parse(buf)?); + } + Ok(v) } - fn set_sender_id(&mut self, new_id: u16) { - self.sender_id = Some(new_id); + pub fn parse_array_limit(buf: &mut &[u8], n: usize) -> Result, crate::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(SvAzEl::parse(buf)?); + } + Ok(v) } } diff --git a/rust/sbp/src/messages/orientation.rs b/rust/sbp/src/messages/orientation.rs index b6cec022be..6916959826 100644 --- a/rust/sbp/src/messages/orientation.rs +++ b/rust/sbp/src/messages/orientation.rs @@ -20,41 +20,49 @@ use self::byteorder::{LittleEndian, ReadBytesExt}; #[cfg(feature = "serialize")] use serde::{Deserialize, Serialize}; -/// Heading relative to True North +/// Vehicle Body Frame instantaneous angular rates /// -/// 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. +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgBaselineHeading { +pub struct MsgAngularRate { 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, + /// 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 MsgBaselineHeading { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgBaselineHeading { +impl MsgAngularRate { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgAngularRate { sender_id: None, tow: _buf.read_u32::()?, - heading: _buf.read_u32::()?, - n_sats: _buf.read_u8()?, + x: _buf.read_i32::()?, + y: _buf.read_i32::()?, + z: _buf.read_i32::()?, flags: _buf.read_u8()?, }) } } -impl super::SBPMessage for MsgBaselineHeading { - const MSG_ID: u16 = 527; +impl super::SBPMessage for MsgAngularRate { + const MSG_ID: u16 = 546; fn get_sender_id(&self) -> Option { self.sender_id @@ -65,60 +73,41 @@ impl super::SBPMessage for MsgBaselineHeading { } } -/// Quaternion 4 component vector +/// Heading relative to True North /// -/// 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. +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgOrientQuat { +pub struct MsgBaselineHeading { 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, + /// Heading + pub heading: u32, + /// Number of satellites used in solution + pub n_sats: u8, /// Status flags pub flags: u8, } -impl MsgOrientQuat { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgOrientQuat { +impl MsgBaselineHeading { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgBaselineHeading { 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::()?, + heading: _buf.read_u32::()?, + n_sats: _buf.read_u8()?, flags: _buf.read_u8()?, }) } } -impl super::SBPMessage for MsgOrientQuat { - const MSG_ID: u16 = 544; +impl super::SBPMessage for MsgBaselineHeading { + const MSG_ID: u16 = 527; fn get_sender_id(&self) -> Option { self.sender_id @@ -187,49 +176,60 @@ impl super::SBPMessage for MsgOrientEuler { } } -/// Vehicle Body Frame instantaneous angular rates +/// Quaternion 4 component vector /// -/// 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. +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgAngularRate { +pub struct MsgOrientQuat { pub sender_id: Option, /// GPS Time of Week pub tow: u32, - /// angular rate about x axis + /// Real component + pub w: i32, + /// 1st imaginary component pub x: i32, - /// angular rate about y axis + /// 2nd imaginary component pub y: i32, - /// angular rate about z axis + /// 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 MsgAngularRate { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgAngularRate { +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 MsgAngularRate { - const MSG_ID: u16 = 546; +impl super::SBPMessage for MsgOrientQuat { + const MSG_ID: u16 = 544; fn get_sender_id(&self) -> Option { self.sender_id diff --git a/rust/sbp/src/messages/piksi.rs b/rust/sbp/src/messages/piksi.rs index c74a056c03..1eb57c3631 100644 --- a/rust/sbp/src/messages/piksi.rs +++ b/rust/sbp/src/messages/piksi.rs @@ -24,107 +24,6 @@ use super::gnss::*; #[cfg(feature = "serialize")] use serde::{Deserialize, Serialize}; -/// 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. -/// -#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] -#[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, crate::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, crate::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. -/// -#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] -#[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, crate::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, crate::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 @@ -173,90 +72,66 @@ impl Latency { } } -/// Bandwidth usage measurement for a single interface. +/// Legacy message to load satellite almanac (host => Piksi) /// -/// 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. +/// This is a legacy message for sending and loading a satellite +/// alamanac onto the Piksi's flash memory from the host. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[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, +pub struct MsgAlmanac { + pub sender_id: Option, } -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: crate::parser::read_string_limit(_buf, 16)?, - }) +impl MsgAlmanac { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgAlmanac { sender_id: None }) } - pub fn parse_array(buf: &mut &[u8]) -> Result, crate::Error> { - let mut v = Vec::new(); - while buf.len() > 0 { - v.push(NetworkUsage::parse(buf)?); - } - Ok(v) +} +impl super::SBPMessage for MsgAlmanac { + const MSG_ID: u16 = 105; + + fn get_sender_id(&self) -> Option { + self.sender_id } - pub fn parse_array_limit(buf: &mut &[u8], n: usize) -> Result, crate::Error> { - let mut v = Vec::new(); - for _ in 0..n { - v.push(NetworkUsage::parse(buf)?); - } - Ok(v) + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); } } -/// State of an RTOS thread +/// Cell modem information update message /// -/// 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. +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgThreadState { +pub struct MsgCellModemStatus { 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, + /// 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 MsgThreadState { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgThreadState { +impl MsgCellModemStatus { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgCellModemStatus { sender_id: None, - name: crate::parser::read_string_limit(_buf, 20)?, - cpu: _buf.read_u16::()?, - stack_free: _buf.read_u32::()?, + signal_strength: _buf.read_i8()?, + signal_error_rate: _buf.read_f32::()?, + reserved: crate::parser::read_u8_array(_buf)?, }) } } -impl super::SBPMessage for MsgThreadState { - const MSG_ID: u16 = 23; +impl super::SBPMessage for MsgCellModemStatus { + const MSG_ID: u16 = 190; fn get_sender_id(&self) -> Option { self.sender_id @@ -267,38 +142,35 @@ impl super::SBPMessage for MsgThreadState { } } -/// Deprecated +/// Command output /// -/// Deprecated +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgUartStateDepa { +pub struct MsgCommandOutput { 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, + /// Sequence number + pub sequence: u32, + /// Line of standard output or standard error + pub line: String, } -impl MsgUartStateDepa { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgUartStateDepa { +impl MsgCommandOutput { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgCommandOutput { sender_id: None, - uart_a: UARTChannel::parse(_buf)?, - uart_b: UARTChannel::parse(_buf)?, - uart_ftdi: UARTChannel::parse(_buf)?, - latency: Latency::parse(_buf)?, + sequence: _buf.read_u32::()?, + line: crate::parser::read_string(_buf)?, }) } } -impl super::SBPMessage for MsgUartStateDepa { - const MSG_ID: u16 = 24; +impl super::SBPMessage for MsgCommandOutput { + const MSG_ID: u16 = 188; fn get_sender_id(&self) -> Option { self.sender_id @@ -309,32 +181,34 @@ impl super::SBPMessage for MsgUartStateDepa { } } -/// State of the Integer Ambiguity Resolution (IAR) process +/// Execute a command (host => device) /// -/// 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. +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgIarState { +pub struct MsgCommandReq { pub sender_id: Option, - /// Number of integer ambiguity hypotheses remaining - pub num_hyps: u32, + /// Sequence number + pub sequence: u32, + /// Command line to execute + pub command: String, } -impl MsgIarState { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgIarState { +impl MsgCommandReq { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgCommandReq { sender_id: None, - num_hyps: _buf.read_u32::()?, + sequence: _buf.read_u32::()?, + command: crate::parser::read_string(_buf)?, }) } } -impl super::SBPMessage for MsgIarState { - const MSG_ID: u16 = 25; +impl super::SBPMessage for MsgCommandReq { + const MSG_ID: u16 = 184; fn get_sender_id(&self) -> Option { self.sender_id @@ -345,32 +219,33 @@ impl super::SBPMessage for MsgIarState { } } -/// Deprecated +/// Exit code from executed command (device => host) /// -/// Deprecated. +/// The response to MSG_COMMAND_REQ with the return code of +/// the command. A return code of zero indicates success. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgMaskSatelliteDep { +pub struct MsgCommandResp { 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, + /// Sequence number + pub sequence: u32, + /// Exit code + pub code: i32, } -impl MsgMaskSatelliteDep { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgMaskSatelliteDep { +impl MsgCommandResp { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgCommandResp { sender_id: None, - mask: _buf.read_u8()?, - sid: GnssSignalDep::parse(_buf)?, + sequence: _buf.read_u32::()?, + code: _buf.read_i32::()?, }) } } -impl super::SBPMessage for MsgMaskSatelliteDep { - const MSG_ID: u16 = 27; +impl super::SBPMessage for MsgCommandResp { + const MSG_ID: u16 = 185; fn get_sender_id(&self) -> Option { self.sender_id @@ -381,49 +256,26 @@ impl super::SBPMessage for MsgMaskSatelliteDep { } } -/// State of the UART channels +/// Legacy message for CW interference channel (Piksi => host) /// -/// 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. +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgUartState { +pub struct MsgCwResults { 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 MsgCwResults { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgCwResults { sender_id: None }) } } -impl super::SBPMessage for MsgUartState { - const MSG_ID: u16 = 29; +impl super::SBPMessage for MsgCwResults { + const MSG_ID: u16 = 192; fn get_sender_id(&self) -> Option { self.sender_id @@ -434,30 +286,26 @@ impl super::SBPMessage for MsgUartState { } } -/// Reset IAR filters (host => Piksi) +/// Legacy message for CW interference channel (host => Piksi) /// -/// This message resets either the DGNSS Kalman filters or Integer -/// Ambiguity Resolution (IAR) process. +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgResetFilters { +pub struct MsgCwStart { 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 MsgCwStart { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgCwStart { sender_id: None }) } } -impl super::SBPMessage for MsgResetFilters { - const MSG_ID: u16 = 34; +impl super::SBPMessage for MsgCwStart { + const MSG_ID: u16 = 193; fn get_sender_id(&self) -> Option { self.sender_id @@ -468,24 +316,43 @@ impl super::SBPMessage for MsgResetFilters { } } -/// Deprecated +/// Device temperature and voltage levels /// -/// Deprecated +/// This message contains temperature and voltage level measurements from the +/// processor's monitoring system and the RF frontend die temperature if +/// available. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgInitBaseDep { +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 MsgInitBaseDep { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgInitBaseDep { sender_id: None }) +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 MsgInitBaseDep { - const MSG_ID: u16 = 35; +impl super::SBPMessage for MsgDeviceMonitor { + const MSG_ID: u16 = 181; fn get_sender_id(&self) -> Option { self.sender_id @@ -496,33 +363,37 @@ impl super::SBPMessage for MsgInitBaseDep { } } -/// Mask a satellite from use in Piksi subsystems +/// RF AGC status /// -/// This message allows setting a mask to prevent a particular satellite -/// from being used in various Piksi subsystems. +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgMaskSatellite { +pub struct MsgFrontEndGain { 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, + /// RF gain for each frontend channel + pub rf_gain: Vec, + /// Intermediate frequency gain for each frontend channel + pub if_gain: Vec, } -impl MsgMaskSatellite { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgMaskSatellite { +impl MsgFrontEndGain { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgFrontEndGain { sender_id: None, - mask: _buf.read_u8()?, - sid: GnssSignal::parse(_buf)?, + rf_gain: crate::parser::read_s8_array_limit(_buf, 8)?, + if_gain: crate::parser::read_s8_array_limit(_buf, 8)?, }) } } -impl super::SBPMessage for MsgMaskSatellite { - const MSG_ID: u16 = 43; +impl super::SBPMessage for MsgFrontEndGain { + const MSG_ID: u16 = 191; fn get_sender_id(&self) -> Option { self.sender_id @@ -533,47 +404,32 @@ impl super::SBPMessage for MsgMaskSatellite { } } -/// Deprecated +/// State of the Integer Ambiguity Resolution (IAR) process /// -/// Deprecated. +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgSpecanDep { +pub struct MsgIarState { 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, + /// Number of integer ambiguity hypotheses remaining + pub num_hyps: u32, } -impl MsgSpecanDep { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgSpecanDep { +impl MsgIarState { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgIarState { 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: crate::parser::read_u8_array(_buf)?, + num_hyps: _buf.read_u32::()?, }) } } -impl super::SBPMessage for MsgSpecanDep { - const MSG_ID: u16 = 80; +impl super::SBPMessage for MsgIarState { + const MSG_ID: u16 = 25; fn get_sender_id(&self) -> Option { self.sender_id @@ -584,47 +440,24 @@ impl super::SBPMessage for MsgSpecanDep { } } -/// Spectrum analyzer +/// Deprecated /// -/// Spectrum analyzer packet. +/// Deprecated /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgSpecan { +pub struct MsgInitBaseDep { 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: crate::parser::read_u8_array(_buf)?, - }) +impl MsgInitBaseDep { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgInitBaseDep { sender_id: None }) } } -impl super::SBPMessage for MsgSpecan { - const MSG_ID: u16 = 81; +impl super::SBPMessage for MsgInitBaseDep { + const MSG_ID: u16 = 35; fn get_sender_id(&self) -> Option { self.sender_id @@ -635,25 +468,33 @@ impl super::SBPMessage for MsgSpecan { } } -/// Send GPS time from host (host => Piksi) +/// Mask a satellite from use in Piksi subsystems /// -/// This message sets up timing functionality using a coarse GPS -/// time estimate sent by the host. +/// This message allows setting a mask to prevent a particular satellite +/// from being used in various Piksi subsystems. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgSetTime { +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 MsgSetTime { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgSetTime { sender_id: None }) +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 MsgSetTime { - const MSG_ID: u16 = 104; +impl super::SBPMessage for MsgMaskSatellite { + const MSG_ID: u16 = 43; fn get_sender_id(&self) -> Option { self.sender_id @@ -664,25 +505,32 @@ impl super::SBPMessage for MsgSetTime { } } -/// Legacy message to load satellite almanac (host => Piksi) +/// Deprecated /// -/// This is a legacy message for sending and loading a satellite -/// alamanac onto the Piksi's flash memory from the host. +/// Deprecated. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgAlmanac { +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 MsgAlmanac { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgAlmanac { sender_id: None }) +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 MsgAlmanac { - const MSG_ID: u16 = 105; +impl super::SBPMessage for MsgMaskSatelliteDep { + const MSG_ID: u16 = 27; fn get_sender_id(&self) -> Option { self.sender_id @@ -693,25 +541,29 @@ impl super::SBPMessage for MsgAlmanac { } } -/// Reset the device (host => Piksi) +/// Bandwidth usage reporting message /// -/// This message from the host resets the Piksi back into the -/// bootloader. +/// The bandwidth usage, a list of usage by interface. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgResetDep { +pub struct MsgNetworkBandwidthUsage { pub sender_id: Option, + /// Usage measurement array + pub interfaces: Vec, } -impl MsgResetDep { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgResetDep { sender_id: None }) +impl MsgNetworkBandwidthUsage { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgNetworkBandwidthUsage { + sender_id: None, + interfaces: NetworkUsage::parse_array(_buf)?, + }) } } -impl super::SBPMessage for MsgResetDep { - const MSG_ID: u16 = 178; +impl super::SBPMessage for MsgNetworkBandwidthUsage { + const MSG_ID: u16 = 189; fn get_sender_id(&self) -> Option { self.sender_id @@ -722,43 +574,81 @@ impl super::SBPMessage for MsgResetDep { } } -/// Device temperature and voltage levels +/// Request state of Piksi network interfaces /// -/// This message contains temperature and voltage level measurements from the -/// processor's monitoring system and the RF frontend die temperature if -/// available. +/// Request state of Piksi network interfaces. +/// Output will be sent in MSG_NETWORK_STATE_RESP messages /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgDeviceMonitor { +pub struct MsgNetworkStateReq { 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 { +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. +/// +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +#[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, - 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::()?, + ipv4_address: crate::parser::read_u8_array_limit(_buf, 4)?, + ipv4_mask_size: _buf.read_u8()?, + ipv6_address: crate::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: crate::parser::read_string_limit(_buf, 16)?, + flags: _buf.read_u32::()?, }) } } -impl super::SBPMessage for MsgDeviceMonitor { - const MSG_ID: u16 = 181; +impl super::SBPMessage for MsgNetworkStateResp { + const MSG_ID: u16 = 187; fn get_sender_id(&self) -> Option { self.sender_id @@ -803,34 +693,25 @@ impl super::SBPMessage for MsgReset { } } -/// Execute a command (host => device) +/// Reset the device (host => Piksi) /// -/// 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. +/// This message from the host resets the Piksi back into the +/// bootloader. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgCommandReq { +pub struct MsgResetDep { 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: crate::parser::read_string(_buf)?, - }) +impl MsgResetDep { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgResetDep { sender_id: None }) } } -impl super::SBPMessage for MsgCommandReq { - const MSG_ID: u16 = 184; +impl super::SBPMessage for MsgResetDep { + const MSG_ID: u16 = 178; fn get_sender_id(&self) -> Option { self.sender_id @@ -841,33 +722,30 @@ impl super::SBPMessage for MsgCommandReq { } } -/// Exit code from executed command (device => host) +/// Reset IAR filters (host => Piksi) /// -/// The response to MSG_COMMAND_REQ with the return code of -/// the command. A return code of zero indicates success. +/// This message resets either the DGNSS Kalman filters or Integer +/// Ambiguity Resolution (IAR) process. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgCommandResp { +pub struct MsgResetFilters { pub sender_id: Option, - /// Sequence number - pub sequence: u32, - /// Exit code - pub code: i32, + /// Filter flags + pub filter: u8, } -impl MsgCommandResp { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgCommandResp { +impl MsgResetFilters { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgResetFilters { sender_id: None, - sequence: _buf.read_u32::()?, - code: _buf.read_i32::()?, + filter: _buf.read_u8()?, }) } } -impl super::SBPMessage for MsgCommandResp { - const MSG_ID: u16 = 185; +impl super::SBPMessage for MsgResetFilters { + const MSG_ID: u16 = 34; fn get_sender_id(&self) -> Option { self.sender_id @@ -878,25 +756,25 @@ impl super::SBPMessage for MsgCommandResp { } } -/// Request state of Piksi network interfaces +/// Send GPS time from host (host => Piksi) /// -/// Request state of Piksi network interfaces. -/// Output will be sent in MSG_NETWORK_STATE_RESP messages +/// This message sets up timing functionality using a coarse GPS +/// time estimate sent by the host. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgNetworkStateReq { +pub struct MsgSetTime { pub sender_id: Option, } -impl MsgNetworkStateReq { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgNetworkStateReq { sender_id: None }) +impl MsgSetTime { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgSetTime { sender_id: None }) } } -impl super::SBPMessage for MsgNetworkStateReq { - const MSG_ID: u16 = 186; +impl super::SBPMessage for MsgSetTime { + const MSG_ID: u16 = 104; fn get_sender_id(&self) -> Option { self.sender_id @@ -907,52 +785,47 @@ impl super::SBPMessage for MsgNetworkStateReq { } } -/// State of network interface +/// Spectrum analyzer /// -/// The state of a network interface on the Piksi. -/// Data is made to reflect output of ifaddrs struct returned by getifaddrs -/// in c. +/// Spectrum analyzer packet. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgNetworkStateResp { +pub struct MsgSpecan { 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 { + /// 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, - ipv4_address: crate::parser::read_u8_array_limit(_buf, 4)?, - ipv4_mask_size: _buf.read_u8()?, - ipv6_address: crate::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: crate::parser::read_string_limit(_buf, 16)?, - flags: _buf.read_u32::()?, + 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: crate::parser::read_u8_array(_buf)?, }) } } -impl super::SBPMessage for MsgNetworkStateResp { - const MSG_ID: u16 = 187; +impl super::SBPMessage for MsgSpecan { + const MSG_ID: u16 = 81; fn get_sender_id(&self) -> Option { self.sender_id @@ -963,35 +836,47 @@ impl super::SBPMessage for MsgNetworkStateResp { } } -/// Command output +/// Deprecated /// -/// 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. +/// Deprecated. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgCommandOutput { +pub struct MsgSpecanDep { pub sender_id: Option, - /// Sequence number - pub sequence: u32, - /// Line of standard output or standard error - pub line: String, + /// 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 MsgCommandOutput { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgCommandOutput { +impl MsgSpecanDep { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgSpecanDep { sender_id: None, - sequence: _buf.read_u32::()?, - line: crate::parser::read_string(_buf)?, + 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: crate::parser::read_u8_array(_buf)?, }) } } -impl super::SBPMessage for MsgCommandOutput { - const MSG_ID: u16 = 188; +impl super::SBPMessage for MsgSpecanDep { + const MSG_ID: u16 = 80; fn get_sender_id(&self) -> Option { self.sender_id @@ -1002,29 +887,38 @@ impl super::SBPMessage for MsgCommandOutput { } } -/// Bandwidth usage reporting message +/// State of an RTOS thread /// -/// The bandwidth usage, a list of usage by interface. +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgNetworkBandwidthUsage { +pub struct MsgThreadState { pub sender_id: Option, - /// Usage measurement array - pub interfaces: Vec, + /// 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 MsgNetworkBandwidthUsage { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgNetworkBandwidthUsage { +impl MsgThreadState { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgThreadState { sender_id: None, - interfaces: NetworkUsage::parse_array(_buf)?, + name: crate::parser::read_string_limit(_buf, 20)?, + cpu: _buf.read_u16::()?, + stack_free: _buf.read_u32::()?, }) } } -impl super::SBPMessage for MsgNetworkBandwidthUsage { - const MSG_ID: u16 = 189; +impl super::SBPMessage for MsgThreadState { + const MSG_ID: u16 = 23; fn get_sender_id(&self) -> Option { self.sender_id @@ -1035,37 +929,49 @@ impl super::SBPMessage for MsgNetworkBandwidthUsage { } } -/// Cell modem information update message +/// State of the UART channels /// -/// 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. +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgCellModemStatus { +pub struct MsgUartState { 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, + /// 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 MsgCellModemStatus { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgCellModemStatus { +impl MsgUartState { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgUartState { sender_id: None, - signal_strength: _buf.read_i8()?, - signal_error_rate: _buf.read_f32::()?, - reserved: crate::parser::read_u8_array(_buf)?, + 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 MsgCellModemStatus { - const MSG_ID: u16 = 190; +impl super::SBPMessage for MsgUartState { + const MSG_ID: u16 = 29; fn get_sender_id(&self) -> Option { self.sender_id @@ -1076,37 +982,38 @@ impl super::SBPMessage for MsgCellModemStatus { } } -/// RF AGC status +/// Deprecated /// -/// 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. +/// Deprecated /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgFrontEndGain { +pub struct MsgUartStateDepa { 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, + /// 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 MsgFrontEndGain { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgFrontEndGain { +impl MsgUartStateDepa { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgUartStateDepa { sender_id: None, - rf_gain: crate::parser::read_s8_array_limit(_buf, 8)?, - if_gain: crate::parser::read_s8_array_limit(_buf, 8)?, + uart_a: UARTChannel::parse(_buf)?, + uart_b: UARTChannel::parse(_buf)?, + uart_ftdi: UARTChannel::parse(_buf)?, + latency: Latency::parse(_buf)?, }) } } -impl super::SBPMessage for MsgFrontEndGain { - const MSG_ID: u16 = 191; +impl super::SBPMessage for MsgUartStateDepa { + const MSG_ID: u16 = 24; fn get_sender_id(&self) -> Option { self.sender_id @@ -1117,62 +1024,155 @@ impl super::SBPMessage for MsgFrontEndGain { } } -/// Legacy message for CW interference channel (Piksi => host) +/// Bandwidth usage measurement for a single interface. /// -/// 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. +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgCwResults { - pub sender_id: Option, +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 MsgCwResults { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgCwResults { sender_id: None }) +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: crate::parser::read_string_limit(_buf, 16)?, + }) } -} -impl super::SBPMessage for MsgCwResults { - const MSG_ID: u16 = 192; - - fn get_sender_id(&self) -> Option { - self.sender_id + pub fn parse_array(buf: &mut &[u8]) -> Result, crate::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(NetworkUsage::parse(buf)?); + } + Ok(v) } - fn set_sender_id(&mut self, new_id: u16) { - self.sender_id = Some(new_id); + pub fn parse_array_limit(buf: &mut &[u8], n: usize) -> Result, crate::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(NetworkUsage::parse(buf)?); + } + Ok(v) } } -/// Legacy message for CW interference channel (host => Piksi) +/// base station observation message receipt period /// -/// 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. +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgCwStart { - pub sender_id: Option, +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 MsgCwStart { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgCwStart { sender_id: None }) +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, crate::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, crate::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(Period::parse(buf)?); + } + Ok(v) } } -impl super::SBPMessage for MsgCwStart { - const MSG_ID: u16 = 193; - fn get_sender_id(&self) -> Option { - self.sender_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. +/// +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +#[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, crate::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(UARTChannel::parse(buf)?); + } + Ok(v) } - fn set_sender_id(&mut self, new_id: u16) { - self.sender_id = Some(new_id); + pub fn parse_array_limit(buf: &mut &[u8], n: usize) -> Result, crate::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(UARTChannel::parse(buf)?); + } + Ok(v) } } diff --git a/rust/sbp/src/messages/settings.rs b/rust/sbp/src/messages/settings.rs index 19e76e6c76..a45b8363e3 100644 --- a/rust/sbp/src/messages/settings.rs +++ b/rust/sbp/src/messages/settings.rs @@ -46,36 +46,24 @@ use self::byteorder::{LittleEndian, ReadBytesExt}; #[cfg(feature = "serialize")] use serde::{Deserialize, Serialize}; -/// Write device configuration settings (host => device) +/// Finished reading 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". +/// The settings message for indicating end of the settings values. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgSettingsWrite { +pub struct MsgSettingsReadByIndexDone { 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: crate::parser::read_string(_buf)?, - }) +impl MsgSettingsReadByIndexDone { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgSettingsReadByIndexDone { sender_id: None }) } } -impl super::SBPMessage for MsgSettingsWrite { - const MSG_ID: u16 = 160; +impl super::SBPMessage for MsgSettingsReadByIndexDone { + const MSG_ID: u16 = 166; fn get_sender_id(&self) -> Option { self.sender_id @@ -86,25 +74,32 @@ impl super::SBPMessage for MsgSettingsWrite { } } -/// Save settings to flash (host => device) +/// Read setting by direct index (host => device) /// -/// The save settings message persists the device's current settings -/// configuration to its onboard flash memory file system. +/// The settings message for iterating through the settings +/// values. A device will respond to this message with a +/// "MSG_SETTINGS_READ_BY_INDEX_RESP". /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgSettingsSave { +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 MsgSettingsSave { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgSettingsSave { sender_id: None }) +impl MsgSettingsReadByIndexReq { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgSettingsReadByIndexReq { + sender_id: None, + index: _buf.read_u16::()?, + }) } } -impl super::SBPMessage for MsgSettingsSave { - const MSG_ID: u16 = 161; +impl super::SBPMessage for MsgSettingsReadByIndexReq { + const MSG_ID: u16 = 162; fn get_sender_id(&self) -> Option { self.sender_id @@ -115,32 +110,43 @@ impl super::SBPMessage for MsgSettingsSave { } } -/// Read setting by direct index (host => device) +/// 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". +/// 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" /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgSettingsReadByIndexReq { +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 MsgSettingsReadByIndexReq { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgSettingsReadByIndexReq { +impl MsgSettingsReadByIndexResp { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgSettingsReadByIndexResp { sender_id: None, index: _buf.read_u16::()?, + setting: crate::parser::read_string(_buf)?, }) } } -impl super::SBPMessage for MsgSettingsReadByIndexReq { - const MSG_ID: u16 = 162; +impl super::SBPMessage for MsgSettingsReadByIndexResp { + const MSG_ID: u16 = 167; fn get_sender_id(&self) -> Option { self.sender_id @@ -232,24 +238,32 @@ impl super::SBPMessage for MsgSettingsReadResp { } } -/// Finished reading settings (host <= device) +/// Register setting and default value (device => host) /// -/// The settings message for indicating end of the settings values. +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgSettingsReadByIndexDone { +pub struct MsgSettingsRegister { pub sender_id: Option, + /// A NULL-terminated and delimited string with contents + /// "SECTION_SETTING\0SETTING\0VALUE". + pub setting: String, } -impl MsgSettingsReadByIndexDone { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgSettingsReadByIndexDone { sender_id: None }) +impl MsgSettingsRegister { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgSettingsRegister { + sender_id: None, + setting: crate::parser::read_string(_buf)?, + }) } } -impl super::SBPMessage for MsgSettingsReadByIndexDone { - const MSG_ID: u16 = 166; +impl super::SBPMessage for MsgSettingsRegister { + const MSG_ID: u16 = 174; fn get_sender_id(&self) -> Option { self.sender_id @@ -260,43 +274,37 @@ impl super::SBPMessage for MsgSettingsReadByIndexDone { } } -/// Read setting by direct index (host <= device) -/// -/// The settings message that reports the value of a setting at an index. +/// Register setting and default value (device <= host) /// -/// 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" +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgSettingsReadByIndexResp { +pub struct MsgSettingsRegisterResp { pub sender_id: Option, - /// An index into the device settings, with values ranging from 0 to - /// length(settings) - pub index: u16, + /// Register status + pub status: u8, /// A NULL-terminated and delimited string with contents - /// "SECTION_SETTING\0SETTING\0VALUE\0FORMAT_TYPE\0" + /// "SECTION_SETTING\0SETTING\0VALUE". The meaning of value is defined + /// according to the status field. pub setting: String, } -impl MsgSettingsReadByIndexResp { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgSettingsReadByIndexResp { +impl MsgSettingsRegisterResp { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgSettingsRegisterResp { sender_id: None, - index: _buf.read_u16::()?, + status: _buf.read_u8()?, setting: crate::parser::read_string(_buf)?, }) } } -impl super::SBPMessage for MsgSettingsReadByIndexResp { - const MSG_ID: u16 = 167; +impl super::SBPMessage for MsgSettingsRegisterResp { + const MSG_ID: u16 = 431; fn get_sender_id(&self) -> Option { self.sender_id @@ -307,32 +315,25 @@ impl super::SBPMessage for MsgSettingsReadByIndexResp { } } -/// Register setting and default value (device => host) +/// Save settings to flash (host => device) /// -/// 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. +/// The save settings message persists the device's current settings +/// configuration to its onboard flash memory file system. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgSettingsRegister { +pub struct MsgSettingsSave { 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: crate::parser::read_string(_buf)?, - }) +impl MsgSettingsSave { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgSettingsSave { sender_id: None }) } } -impl super::SBPMessage for MsgSettingsRegister { - const MSG_ID: u16 = 174; +impl super::SBPMessage for MsgSettingsSave { + const MSG_ID: u16 = 161; fn get_sender_id(&self) -> Option { self.sender_id @@ -343,39 +344,36 @@ impl super::SBPMessage for MsgSettingsRegister { } } -/// Acknowledgement with status of MSG_SETTINGS_WRITE +/// Write device configuration settings (host => device) /// -/// 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 +/// 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". /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgSettingsWriteResp { +pub struct MsgSettingsWrite { pub sender_id: Option, - /// Write status - pub status: u8, - /// A NULL-terminated and delimited string with contents + /// A NULL-terminated and NULL-delimited string with contents /// "SECTION_SETTING\0SETTING\0VALUE\0" pub setting: String, } -impl MsgSettingsWriteResp { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgSettingsWriteResp { +impl MsgSettingsWrite { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgSettingsWrite { sender_id: None, - status: _buf.read_u8()?, setting: crate::parser::read_string(_buf)?, }) } } -impl super::SBPMessage for MsgSettingsWriteResp { - const MSG_ID: u16 = 175; +impl super::SBPMessage for MsgSettingsWrite { + const MSG_ID: u16 = 160; fn get_sender_id(&self) -> Option { self.sender_id @@ -386,37 +384,39 @@ impl super::SBPMessage for MsgSettingsWriteResp { } } -/// Register setting and default value (device <= host) +/// Acknowledgement with status of MSG_SETTINGS_WRITE /// -/// 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. +/// 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". /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgSettingsRegisterResp { +pub struct MsgSettingsWriteResp { pub sender_id: Option, - /// Register status + /// Write 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. + /// "SECTION_SETTING\0SETTING\0VALUE\0" pub setting: String, } -impl MsgSettingsRegisterResp { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgSettingsRegisterResp { +impl MsgSettingsWriteResp { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgSettingsWriteResp { sender_id: None, status: _buf.read_u8()?, setting: crate::parser::read_string(_buf)?, }) } } -impl super::SBPMessage for MsgSettingsRegisterResp { - const MSG_ID: u16 = 431; +impl super::SBPMessage for MsgSettingsWriteResp { + const MSG_ID: u16 = 175; fn get_sender_id(&self) -> Option { self.sender_id diff --git a/rust/sbp/src/messages/ssr.rs b/rust/sbp/src/messages/ssr.rs index 5c1996a99d..71d810131f 100644 --- a/rust/sbp/src/messages/ssr.rs +++ b/rust/sbp/src/messages/ssr.rs @@ -63,42 +63,46 @@ impl CodeBiasesContent { } } -/// SSR phase biases corrections for a particular satellite. +/// Defines the grid for MSG_SSR_GRIDDED_CORRECTION messages. /// -/// Phase biases are to be added to carrier phase measurements. -/// The corrections conform with typical RTCMv3 MT1059 and 1065. +/// Defines the grid for MSG_SSR_GRIDDED_CORRECTION messages. +/// Also includes an RLE encoded validity list. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[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, +pub struct GridDefinitionHeader { + /// region_size (deg) = 10 / region_size_inverse 0 is an invalid value. + pub region_size_inverse: u8, + /// grid height (deg) = grid idth (deg) = area_width / region_size 0 is an + /// invalid value. + pub area_width: u16, + /// North-West corner latitdue (deg) = region_size * lat_nw_corner_enc - 90 + pub lat_nw_corner_enc: u16, + /// North-West corner longtitude (deg) = region_size * lon_nw_corner_enc - + /// 180 + 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 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::()?, +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, crate::Error> { + pub fn parse_array(buf: &mut &[u8]) -> Result, crate::Error> { let mut v = Vec::new(); while buf.len() > 0 { - v.push(PhaseBiasesContent::parse(buf)?); + v.push(GridDefinitionHeader::parse(buf)?); } Ok(v) } @@ -106,60 +110,52 @@ impl PhaseBiasesContent { pub fn parse_array_limit( buf: &mut &[u8], n: usize, - ) -> Result, crate::Error> { + ) -> Result, crate::Error> { let mut v = Vec::new(); for _ in 0..n { - v.push(PhaseBiasesContent::parse(buf)?); + v.push(GridDefinitionHeader::parse(buf)?); } Ok(v) } } -/// Header for MSG_SSR_STEC_CORRECTION message +/// Correction data for a single grid point. /// -/// 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. +/// Contains one tropo delay, plus STEC residuals for each satellite at the +/// grid point. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[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 atmospheric correction - pub iod_atmo: u8, +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 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_atmo: _buf.read_u8()?, +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, crate::Error> { + pub fn parse_array(buf: &mut &[u8]) -> Result, crate::Error> { let mut v = Vec::new(); while buf.len() > 0 { - v.push(STECHeader::parse(buf)?); + v.push(GridElement::parse(buf)?); } Ok(v) } - pub fn parse_array_limit(buf: &mut &[u8], n: usize) -> Result, crate::Error> { + pub fn parse_array_limit(buf: &mut &[u8], n: usize) -> Result, crate::Error> { let mut v = Vec::new(); for _ in 0..n { - v.push(STECHeader::parse(buf)?); + v.push(GridElement::parse(buf)?); } Ok(v) } @@ -222,225 +218,130 @@ impl GriddedCorrectionHeader { } } -/// None +/// Precise code biases correction /// -/// STEC polynomial for the given satellite. +/// 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 /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[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 - /// in units of 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, +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 STECSatElement { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(STECSatElement { - sv_id: SvId::parse(_buf)?, - stec_quality_indicator: _buf.read_u8()?, - stec_coeff: crate::parser::read_s16_array_limit(_buf, 4)?, +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)?, }) } - pub fn parse_array(buf: &mut &[u8]) -> Result, crate::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, crate::Error> { - let mut v = Vec::new(); - for _ in 0..n { - v.push(STECSatElement::parse(buf)?); - } - Ok(v) - } -} - -/// None -/// -/// Troposphere vertical delays at the grid point. -/// -#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] -#[derive(Debug)] -#[allow(non_snake_case)] -pub struct TroposphericDelayCorrection { - /// Hydrostatic vertical delay - pub hydro: i16, - /// Wet vertical delay - pub wet: i8, } +impl super::SBPMessage for MsgSsrCodeBiases { + const MSG_ID: u16 = 1505; -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, crate::Error> { - let mut v = Vec::new(); - while buf.len() > 0 { - v.push(TroposphericDelayCorrection::parse(buf)?); - } - Ok(v) + fn get_sender_id(&self) -> Option { + self.sender_id } - pub fn parse_array_limit( - buf: &mut &[u8], - n: usize, - ) -> Result, crate::Error> { - let mut v = Vec::new(); - for _ in 0..n { - v.push(TroposphericDelayCorrection::parse(buf)?); - } - Ok(v) + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); } } -/// None +/// Gridded troposphere and STEC residuals /// -/// STEC residual for the given satellite at the grid point. +/// STEC residuals are per space vehicle, tropo is not. +/// It is typically equivalent to the QZSS CLAS Sub Type 9 messages /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct STECResidual { - /// space vehicle identifier - pub sv_id: SvId, - /// STEC residual - pub residual: i16, +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 STECResidual { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(STECResidual { - sv_id: SvId::parse(_buf)?, - residual: _buf.read_i16::()?, +impl MsgSsrGriddedCorrection { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgSsrGriddedCorrection { + sender_id: None, + header: GriddedCorrectionHeader::parse(_buf)?, + element: GridElement::parse(_buf)?, }) } - pub fn parse_array(buf: &mut &[u8]) -> Result, crate::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, crate::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. -/// -#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] -#[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 super::SBPMessage for MsgSsrGriddedCorrection { + const MSG_ID: u16 = 1520; -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, crate::Error> { - let mut v = Vec::new(); - while buf.len() > 0 { - v.push(GridElement::parse(buf)?); - } - Ok(v) + fn get_sender_id(&self) -> Option { + self.sender_id } - pub fn parse_array_limit(buf: &mut &[u8], n: usize) -> Result, crate::Error> { - let mut v = Vec::new(); - for _ in 0..n { - v.push(GridElement::parse(buf)?); - } - Ok(v) + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); } } -/// Defines the grid for MSG_SSR_GRIDDED_CORRECTION messages. +/// Definition of the grid for STEC and tropo messages /// -/// Defines the grid for MSG_SSR_GRIDDED_CORRECTION messages. -/// Also includes an RLE encoded validity list. +/// Based on the 3GPP proposal R2-1906781 which is in turn based on +/// OMA-LPPe-ValidityArea from OMA-TS-LPPe-V2_0-20141202-C /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct GridDefinitionHeader { - /// region_size (deg) = 10 / region_size_inverse 0 is an invalid value. - pub region_size_inverse: u8, - /// grid height (deg) = grid idth (deg) = area_width / region_size 0 is an - /// invalid value. - pub area_width: u16, - /// North-West corner latitdue (deg) = region_size * lat_nw_corner_enc - 90 - pub lat_nw_corner_enc: u16, - /// North-West corner longtitude (deg) = region_size * lon_nw_corner_enc - - /// 180 - 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, +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 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()?, +impl MsgSsrGridDefinition { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgSsrGridDefinition { + sender_id: None, + header: GridDefinitionHeader::parse(_buf)?, + rle_list: crate::parser::read_u8_array(_buf)?, }) } - pub fn parse_array(buf: &mut &[u8]) -> Result, crate::Error> { - let mut v = Vec::new(); - while buf.len() > 0 { - v.push(GridDefinitionHeader::parse(buf)?); - } - Ok(v) +} +impl super::SBPMessage for MsgSsrGridDefinition { + const MSG_ID: u16 = 1525; + + fn get_sender_id(&self) -> Option { + self.sender_id } - pub fn parse_array_limit( - buf: &mut &[u8], - n: usize, - ) -> Result, crate::Error> { - let mut v = Vec::new(); - for _ in 0..n { - v.push(GridDefinitionHeader::parse(buf)?); - } - Ok(v) + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); } } @@ -454,7 +355,7 @@ impl GridDefinitionHeader { #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgSsrOrbitClockDepA { +pub struct MsgSsrOrbitClock { pub sender_id: Option, /// GNSS reference time of the correction pub time: GPSTimeSec, @@ -466,8 +367,8 @@ pub struct MsgSsrOrbitClockDepA { /// 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, + /// Issue of broadcast ephemeris data or IODCRC (Beidou) + pub iod: u32, /// Orbit radial delta correction pub radial: i32, /// Orbit along delta correction @@ -488,15 +389,15 @@ pub struct MsgSsrOrbitClockDepA { pub c2: i32, } -impl MsgSsrOrbitClockDepA { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgSsrOrbitClockDepA { +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_u8()?, + iod: _buf.read_u32::()?, radial: _buf.read_i32::()?, along: _buf.read_i32::()?, cross: _buf.read_i32::()?, @@ -509,8 +410,8 @@ impl MsgSsrOrbitClockDepA { }) } } -impl super::SBPMessage for MsgSsrOrbitClockDepA { - const MSG_ID: u16 = 1500; +impl super::SBPMessage for MsgSsrOrbitClock { + const MSG_ID: u16 = 1501; fn get_sender_id(&self) -> Option { self.sender_id @@ -531,7 +432,7 @@ impl super::SBPMessage for MsgSsrOrbitClockDepA { #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgSsrOrbitClock { +pub struct MsgSsrOrbitClockDepA { pub sender_id: Option, /// GNSS reference time of the correction pub time: GPSTimeSec, @@ -543,8 +444,8 @@ pub struct MsgSsrOrbitClock { /// 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, + /// Issue of broadcast ephemeris data + pub iod: u8, /// Orbit radial delta correction pub radial: i32, /// Orbit along delta correction @@ -565,79 +466,29 @@ pub struct MsgSsrOrbitClock { 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 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 -/// -#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] -#[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 { +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()?, - biases: CodeBiasesContent::parse_array(_buf)?, + 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 MsgSsrCodeBiases { - const MSG_ID: u16 = 1505; +impl super::SBPMessage for MsgSsrOrbitClockDepA { + const MSG_ID: u16 = 1500; fn get_sender_id(&self) -> Option { self.sender_id @@ -751,79 +602,228 @@ impl super::SBPMessage for MsgSsrStecCorrection { } } -/// Gridded troposphere and STEC residuals +/// SSR phase biases corrections for a particular satellite. /// -/// STEC residuals are per space vehicle, tropo is not. -/// It is typically equivalent to the QZSS CLAS Sub Type 9 messages +/// Phase biases are to be added to carrier phase measurements. +/// The corrections conform with typical RTCMv3 MT1059 and 1065. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[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, +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 MsgSsrGriddedCorrection { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgSsrGriddedCorrection { - sender_id: None, - header: GriddedCorrectionHeader::parse(_buf)?, - element: GridElement::parse(_buf)?, +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, crate::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, crate::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(PhaseBiasesContent::parse(buf)?); + } + Ok(v) + } } -impl super::SBPMessage for MsgSsrGriddedCorrection { - const MSG_ID: u16 = 1520; - fn get_sender_id(&self) -> Option { - self.sender_id +/// 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. +/// +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +#[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 atmospheric correction + pub iod_atmo: 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_atmo: _buf.read_u8()?, + }) + } + pub fn parse_array(buf: &mut &[u8]) -> Result, crate::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(STECHeader::parse(buf)?); + } + Ok(v) } - fn set_sender_id(&mut self, new_id: u16) { - self.sender_id = Some(new_id); + pub fn parse_array_limit(buf: &mut &[u8], n: usize) -> Result, crate::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(STECHeader::parse(buf)?); + } + Ok(v) } } -/// Definition of the grid for STEC and tropo messages +/// None /// -/// Based on the 3GPP proposal R2-1906781 which is in turn based on -/// OMA-LPPe-ValidityArea from OMA-TS-LPPe-V2_0-20141202-C +/// STEC residual for the given satellite at the grid point. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[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, +pub struct STECResidual { + /// space vehicle identifier + pub sv_id: SvId, + /// STEC residual + pub residual: i16, } -impl MsgSsrGridDefinition { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgSsrGridDefinition { - sender_id: None, - header: GridDefinitionHeader::parse(_buf)?, - rle_list: crate::parser::read_u8_array(_buf)?, +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, crate::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, crate::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(STECResidual::parse(buf)?); + } + Ok(v) + } } -impl super::SBPMessage for MsgSsrGridDefinition { - const MSG_ID: u16 = 1525; - fn get_sender_id(&self) -> Option { - self.sender_id +/// None +/// +/// STEC polynomial for the given satellite. +/// +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +#[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 + /// in units of 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: crate::parser::read_s16_array_limit(_buf, 4)?, + }) + } + pub fn parse_array(buf: &mut &[u8]) -> Result, crate::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(STECSatElement::parse(buf)?); + } + Ok(v) } - fn set_sender_id(&mut self, new_id: u16) { - self.sender_id = Some(new_id); + pub fn parse_array_limit( + buf: &mut &[u8], + n: usize, + ) -> Result, crate::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(STECSatElement::parse(buf)?); + } + Ok(v) + } +} + +/// None +/// +/// Troposphere vertical delays at the grid point. +/// +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +#[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, crate::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, crate::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(TroposphericDelayCorrection::parse(buf)?); + } + Ok(v) } } diff --git a/rust/sbp/src/messages/system.rs b/rust/sbp/src/messages/system.rs index f7351c5342..ebcdf1fc11 100644 --- a/rust/sbp/src/messages/system.rs +++ b/rust/sbp/src/messages/system.rs @@ -20,38 +20,74 @@ use self::byteorder::{LittleEndian, ReadBytesExt}; #[cfg(feature = "serialize")] use serde::{Deserialize, Serialize}; -/// System start-up message +/// Experimental telemetry 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. +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgStartup { +pub struct MsgCsacTelemetry { pub sender_id: Option, - /// Cause of startup - pub cause: u8, - /// Startup type - pub startup_type: u8, - /// Reserved - pub reserved: u16, + /// 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 MsgStartup { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgStartup { +impl MsgCsacTelemetry { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgCsacTelemetry { sender_id: None, - cause: _buf.read_u8()?, - startup_type: _buf.read_u8()?, - reserved: _buf.read_u16::()?, + id: _buf.read_u8()?, + telemetry: crate::parser::read_string(_buf)?, }) } } -impl super::SBPMessage for MsgStartup { - const MSG_ID: u16 = 65280; +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. +/// +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +#[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: crate::parser::read_string(_buf)?, + }) + } +} +impl super::SBPMessage for MsgCsacTelemetryLabels { + const MSG_ID: u16 = 65285; fn get_sender_id(&self) -> Option { self.sender_id @@ -106,69 +142,38 @@ impl super::SBPMessage for MsgDgnssStatus { } } -/// Inertial Navigation System status message +/// System heartbeat message /// -/// The INS status message describes the state of the operation -/// and initialization of the inertial navigation system. +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgInsStatus { +pub struct MsgHeartbeat { pub sender_id: Option, /// Status flags pub flags: u32, } -impl MsgInsStatus { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgInsStatus { +impl MsgHeartbeat { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgHeartbeat { 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. -/// -#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] -#[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: crate::parser::read_string(_buf)?, - }) - } -} -impl super::SBPMessage for MsgCsacTelemetry { - const MSG_ID: u16 = 65284; +impl super::SBPMessage for MsgHeartbeat { + const MSG_ID: u16 = 65535; fn get_sender_id(&self) -> Option { self.sender_id @@ -179,35 +184,30 @@ impl super::SBPMessage for MsgCsacTelemetry { } } -/// Experimental telemetry message labels +/// Inertial Navigation System status message /// -/// 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. +/// The INS status message describes the state of the operation +/// and initialization of the inertial navigation system. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgCsacTelemetryLabels { +pub struct MsgInsStatus { 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, + /// Status flags + pub flags: u32, } -impl MsgCsacTelemetryLabels { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgCsacTelemetryLabels { +impl MsgInsStatus { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgInsStatus { sender_id: None, - id: _buf.read_u8()?, - telemetry_labels: crate::parser::read_string(_buf)?, + flags: _buf.read_u32::()?, }) } } -impl super::SBPMessage for MsgCsacTelemetryLabels { - const MSG_ID: u16 = 65285; +impl super::SBPMessage for MsgInsStatus { + const MSG_ID: u16 = 65283; fn get_sender_id(&self) -> Option { self.sender_id @@ -218,38 +218,38 @@ impl super::SBPMessage for MsgCsacTelemetryLabels { } } -/// 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. +/// System start-up message /// -/// 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. +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgHeartbeat { +pub struct MsgStartup { pub sender_id: Option, - /// Status flags - pub flags: u32, + /// Cause of startup + pub cause: u8, + /// Startup type + pub startup_type: u8, + /// Reserved + pub reserved: u16, } -impl MsgHeartbeat { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgHeartbeat { +impl MsgStartup { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgStartup { sender_id: None, - flags: _buf.read_u32::()?, + cause: _buf.read_u8()?, + startup_type: _buf.read_u8()?, + reserved: _buf.read_u16::()?, }) } } -impl super::SBPMessage for MsgHeartbeat { - const MSG_ID: u16 = 65535; +impl super::SBPMessage for MsgStartup { + const MSG_ID: u16 = 65280; fn get_sender_id(&self) -> Option { self.sender_id diff --git a/rust/sbp/src/messages/tracking.rs b/rust/sbp/src/messages/tracking.rs index c2b5d030b8..8a6204fee3 100644 --- a/rust/sbp/src/messages/tracking.rs +++ b/rust/sbp/src/messages/tracking.rs @@ -22,222 +22,225 @@ use super::gnss::*; #[cfg(feature = "serialize")] use serde::{Deserialize, Serialize}; -/// Signal tracking channel state +/// Measurement Engine signal tracking channel states /// -/// Tracking channel state for a specific satellite signal and -/// measured signal power. +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[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, +pub struct MsgMeasurementState { + pub sender_id: Option, + /// ME signal tracking channel state + pub states: Vec, } -impl TrackingChannelState { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(TrackingChannelState { - sid: GnssSignal::parse(_buf)?, - fcn: _buf.read_u8()?, - cn0: _buf.read_u8()?, +impl MsgMeasurementState { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgMeasurementState { + sender_id: None, + states: MeasurementState::parse_array(_buf)?, }) } - pub fn parse_array(buf: &mut &[u8]) -> Result, crate::Error> { - let mut v = Vec::new(); - while buf.len() > 0 { - v.push(TrackingChannelState::parse(buf)?); - } - Ok(v) +} +impl super::SBPMessage for MsgMeasurementState { + const MSG_ID: u16 = 97; + + fn get_sender_id(&self) -> Option { + self.sender_id } - pub fn parse_array_limit( - buf: &mut &[u8], - n: usize, - ) -> Result, crate::Error> { - let mut v = Vec::new(); - for _ in 0..n { - v.push(TrackingChannelState::parse(buf)?); - } - Ok(v) + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); } } -/// Measurement Engine signal tracking channel state +/// Tracking channel correlations /// -/// 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) +/// When enabled, a tracking channel can output the correlations at each +/// update interval. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[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, +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 MeasurementState { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MeasurementState { - mesid: GnssSignal::parse(_buf)?, - cn0: _buf.read_u8()?, +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)?, }) } - pub fn parse_array(buf: &mut &[u8]) -> Result, crate::Error> { - let mut v = Vec::new(); - while buf.len() > 0 { - v.push(MeasurementState::parse(buf)?); - } - Ok(v) +} +impl super::SBPMessage for MsgTrackingIq { + const MSG_ID: u16 = 45; + + fn get_sender_id(&self) -> Option { + self.sender_id } - pub fn parse_array_limit( - buf: &mut &[u8], - n: usize, - ) -> Result, crate::Error> { - let mut v = Vec::new(); - for _ in 0..n { - v.push(MeasurementState::parse(buf)?); - } - Ok(v) + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); } } -/// Complex correlation structure +/// Deprecated /// -/// Structure containing in-phase and quadrature correlation components. +/// Deprecated. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct TrackingChannelCorrelation { - /// In-phase correlation - pub I: i16, - /// Quadrature correlation - pub Q: i16, +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 TrackingChannelCorrelation { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(TrackingChannelCorrelation { - I: _buf.read_i16::()?, - Q: _buf.read_i16::()?, +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)?, }) } - pub fn parse_array(buf: &mut &[u8]) -> Result, crate::Error> { - let mut v = Vec::new(); - while buf.len() > 0 { - v.push(TrackingChannelCorrelation::parse(buf)?); - } - Ok(v) +} +impl super::SBPMessage for MsgTrackingIqDepA { + const MSG_ID: u16 = 28; + + fn get_sender_id(&self) -> Option { + self.sender_id } - pub fn parse_array_limit( - buf: &mut &[u8], - n: usize, - ) -> Result, crate::Error> { - let mut v = Vec::new(); - for _ in 0..n { - v.push(TrackingChannelCorrelation::parse(buf)?); - } - Ok(v) + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); } } -/// Complex correlation structure +/// Tracking channel correlations /// -/// Structure containing in-phase and quadrature correlation components. +/// When enabled, a tracking channel can output the correlations at each +/// update interval. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct TrackingChannelCorrelationDep { - /// In-phase correlation - pub I: i32, - /// Quadrature correlation - pub Q: i32, +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 TrackingChannelCorrelationDep { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(TrackingChannelCorrelationDep { - I: _buf.read_i32::()?, - Q: _buf.read_i32::()?, +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)?, }) } - pub fn parse_array( - buf: &mut &[u8], - ) -> Result, crate::Error> { - let mut v = Vec::new(); - while buf.len() > 0 { - v.push(TrackingChannelCorrelationDep::parse(buf)?); - } - Ok(v) +} +impl super::SBPMessage for MsgTrackingIqDepB { + const MSG_ID: u16 = 44; + + fn get_sender_id(&self) -> Option { + self.sender_id } - pub fn parse_array_limit( - buf: &mut &[u8], - n: usize, - ) -> Result, crate::Error> { - let mut v = Vec::new(); - for _ in 0..n { - v.push(TrackingChannelCorrelationDep::parse(buf)?); - } - Ok(v) + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); } } -/// Deprecated +/// Signal tracking channel states /// -/// Deprecated. +/// 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. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[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, +pub struct MsgTrackingState { + pub sender_id: Option, + /// Signal tracking channel state + pub states: Vec, } -impl TrackingChannelStateDepA { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(TrackingChannelStateDepA { - state: _buf.read_u8()?, - prn: _buf.read_u8()?, - cn0: _buf.read_f32::()?, +impl MsgTrackingState { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgTrackingState { + sender_id: None, + states: TrackingChannelState::parse_array(_buf)?, }) } - pub fn parse_array(buf: &mut &[u8]) -> Result, crate::Error> { - let mut v = Vec::new(); - while buf.len() > 0 { - v.push(TrackingChannelStateDepA::parse(buf)?); - } - Ok(v) - } +} +impl super::SBPMessage for MsgTrackingState { + const MSG_ID: u16 = 65; - pub fn parse_array_limit( - buf: &mut &[u8], - n: usize, - ) -> Result, crate::Error> { - let mut v = Vec::new(); - for _ in 0..n { - v.push(TrackingChannelStateDepA::parse(buf)?); - } - Ok(v) + 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. +/// +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +#[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); } } @@ -248,40 +251,29 @@ impl TrackingChannelStateDepA { #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[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, +pub struct MsgTrackingStateDepB { + pub sender_id: Option, + /// Signal tracking channel state + pub states: Vec, } -impl TrackingChannelStateDepB { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(TrackingChannelStateDepB { - state: _buf.read_u8()?, - sid: GnssSignalDep::parse(_buf)?, - cn0: _buf.read_f32::()?, +impl MsgTrackingStateDepB { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MsgTrackingStateDepB { + sender_id: None, + states: TrackingChannelStateDepB::parse_array(_buf)?, }) } - pub fn parse_array(buf: &mut &[u8]) -> Result, crate::Error> { - let mut v = Vec::new(); - while buf.len() > 0 { - v.push(TrackingChannelStateDepB::parse(buf)?); - } - Ok(v) +} +impl super::SBPMessage for MsgTrackingStateDepB { + const MSG_ID: u16 = 19; + + fn get_sender_id(&self) -> Option { + self.sender_id } - pub fn parse_array_limit( - buf: &mut &[u8], - n: usize, - ) -> Result, crate::Error> { - let mut v = Vec::new(); - for _ in 0..n { - v.push(TrackingChannelStateDepB::parse(buf)?); - } - Ok(v) + fn set_sender_id(&mut self, new_id: u16) { + self.sender_id = Some(new_id); } } @@ -384,111 +376,6 @@ impl super::SBPMessage for MsgTrackingStateDetailedDep { } } -/// Deprecated. -/// -/// Deprecated. -/// -#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] -#[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); - } -} - -/// Deprecated -/// -/// Deprecated. -/// -#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] -#[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. -/// -#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] -#[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); - } -} - /// Detailed signal tracking channel states. DEPRECATED. /// /// The tracking message returns a set tracking channel parameters for a @@ -589,152 +476,265 @@ impl super::SBPMessage for MsgTrackingStateDetailedDepA { } } -/// Tracking channel correlations +/// Measurement Engine signal tracking channel state /// -/// When enabled, a tracking channel can output the correlations at each -/// update interval. +/// 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) /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[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, +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 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 MeasurementState { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(MeasurementState { + mesid: GnssSignal::parse(_buf)?, + cn0: _buf.read_u8()?, }) } -} -impl super::SBPMessage for MsgTrackingIqDepB { - const MSG_ID: u16 = 44; - - fn get_sender_id(&self) -> Option { - self.sender_id + pub fn parse_array(buf: &mut &[u8]) -> Result, crate::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(MeasurementState::parse(buf)?); + } + Ok(v) } - fn set_sender_id(&mut self, new_id: u16) { - self.sender_id = Some(new_id); + pub fn parse_array_limit( + buf: &mut &[u8], + n: usize, + ) -> Result, crate::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(MeasurementState::parse(buf)?); + } + Ok(v) } } -/// Tracking channel correlations +/// Complex correlation structure /// -/// When enabled, a tracking channel can output the correlations at each -/// update interval. +/// Structure containing in-phase and quadrature correlation components. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[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, +pub struct TrackingChannelCorrelation { + /// In-phase correlation + pub I: i16, + /// Quadrature correlation + pub Q: i16, } -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 TrackingChannelCorrelation { + pub fn parse(_buf: &mut &[u8]) -> Result { + Ok(TrackingChannelCorrelation { + I: _buf.read_i16::()?, + Q: _buf.read_i16::()?, }) } -} -impl super::SBPMessage for MsgTrackingIq { - const MSG_ID: u16 = 45; - - fn get_sender_id(&self) -> Option { - self.sender_id + pub fn parse_array(buf: &mut &[u8]) -> Result, crate::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(TrackingChannelCorrelation::parse(buf)?); + } + Ok(v) } - fn set_sender_id(&mut self, new_id: u16) { - self.sender_id = Some(new_id); + pub fn parse_array_limit( + buf: &mut &[u8], + n: usize, + ) -> Result, crate::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(TrackingChannelCorrelation::parse(buf)?); + } + Ok(v) } } -/// Signal tracking channel states +/// Complex correlation structure /// -/// 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. +/// Structure containing in-phase and quadrature correlation components. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgTrackingState { - pub sender_id: Option, - /// Signal tracking channel state - pub states: Vec, +pub struct TrackingChannelCorrelationDep { + /// In-phase correlation + pub I: i32, + /// Quadrature correlation + pub Q: i32, } -impl MsgTrackingState { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgTrackingState { - sender_id: None, - states: TrackingChannelState::parse_array(_buf)?, +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, crate::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, crate::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(TrackingChannelCorrelationDep::parse(buf)?); + } + Ok(v) + } } -impl super::SBPMessage for MsgTrackingState { - const MSG_ID: u16 = 65; - fn get_sender_id(&self) -> Option { - self.sender_id +/// Signal tracking channel state +/// +/// Tracking channel state for a specific satellite signal and +/// measured signal power. +/// +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +#[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, crate::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(TrackingChannelState::parse(buf)?); + } + Ok(v) } - fn set_sender_id(&mut self, new_id: u16) { - self.sender_id = Some(new_id); + pub fn parse_array_limit( + buf: &mut &[u8], + n: usize, + ) -> Result, crate::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(TrackingChannelState::parse(buf)?); + } + Ok(v) } } -/// Measurement Engine signal tracking channel states +/// Deprecated /// -/// 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. +/// Deprecated. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] #[allow(non_snake_case)] -pub struct MsgMeasurementState { - pub sender_id: Option, - /// ME signal tracking channel state - pub states: Vec, +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 MsgMeasurementState { - pub fn parse(_buf: &mut &[u8]) -> Result { - Ok(MsgMeasurementState { - sender_id: None, - states: MeasurementState::parse_array(_buf)?, +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, crate::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, crate::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(TrackingChannelStateDepA::parse(buf)?); + } + Ok(v) + } } -impl super::SBPMessage for MsgMeasurementState { - const MSG_ID: u16 = 97; - fn get_sender_id(&self) -> Option { - self.sender_id +/// Deprecated. +/// +/// Deprecated. +/// +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +#[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, crate::Error> { + let mut v = Vec::new(); + while buf.len() > 0 { + v.push(TrackingChannelStateDepB::parse(buf)?); + } + Ok(v) } - fn set_sender_id(&mut self, new_id: u16) { - self.sender_id = Some(new_id); + pub fn parse_array_limit( + buf: &mut &[u8], + n: usize, + ) -> Result, crate::Error> { + let mut v = Vec::new(); + for _ in 0..n { + v.push(TrackingChannelStateDepB::parse(buf)?); + } + Ok(v) } }