use crate::message::ParsedSentence;
use crate::types::{MessageType, TalkerId};
#[derive(Debug, Clone)]
pub struct GsvData {
pub talker_id: TalkerId,
pub num_messages: u8,
pub message_num: u8,
pub satellites_in_view: u8,
pub satellite_info: [Option<SatelliteInfo>; 4],
}
#[derive(Debug, Clone)]
pub struct SatelliteInfo {
pub prn: Option<u8>,
pub elevation: Option<u16>,
pub azimuth: Option<u16>,
pub snr: Option<u8>,
}
impl ParsedSentence {
pub fn as_gsv(&self) -> Option<GsvData> {
if self.message_type != MessageType::GSV {
return None;
}
let num_messages: u8 = self.parse_field(1)?;
let message_num: u8 = self.parse_field(2)?;
let satellites_in_view: u8 = self.parse_field(3)?;
let sat1 = if self.get_field_str(4).is_some() {
Some(SatelliteInfo {
prn: self.parse_field(4),
elevation: self.parse_field(5),
azimuth: self.parse_field(6),
snr: self.parse_field(7),
})
} else {
None
};
let sat2 = if self.get_field_str(8).is_some() {
Some(SatelliteInfo {
prn: self.parse_field(8),
elevation: self.parse_field(9),
azimuth: self.parse_field(10),
snr: self.parse_field(11),
})
} else {
None
};
let sat3 = if self.get_field_str(12).is_some() {
Some(SatelliteInfo {
prn: self.parse_field(12),
elevation: self.parse_field(13),
azimuth: self.parse_field(14),
snr: self.parse_field(15),
})
} else {
None
};
let sat4 = if self.get_field_str(16).is_some() {
Some(SatelliteInfo {
prn: self.parse_field(16),
elevation: self.parse_field(17),
azimuth: self.parse_field(18),
snr: self.parse_field(19),
})
} else {
None
};
Some(GsvData {
talker_id: self.talker_id,
num_messages,
message_num,
satellites_in_view,
satellite_info: [sat1, sat2, sat3, sat4],
})
}
}
#[cfg(test)]
mod tests {
use crate::NmeaParser;
#[test]
fn test_gsv_complete_message() {
let parser = NmeaParser::new();
let sentence = b"$GPGSV,2,1,08,01,40,083,46,02,17,308,41,12,07,344,39,14,22,228,45*75\r\n";
let result = parser.parse_sentence_complete(sentence);
assert!(result.is_some());
let msg = result.unwrap();
let gsv = msg.as_gsv();
assert!(gsv.is_some());
let gsv_data = gsv.unwrap();
assert_eq!(gsv_data.num_messages, 2);
assert_eq!(gsv_data.message_num, 1);
assert_eq!(gsv_data.satellites_in_view, 8);
assert!(gsv_data.satellite_info[0].is_some());
let sat1 = gsv_data.satellite_info[0].as_ref().unwrap();
assert_eq!(sat1.prn, Some(1));
assert_eq!(sat1.elevation, Some(40));
assert_eq!(sat1.azimuth, Some(83));
assert_eq!(sat1.snr, Some(46));
assert!(gsv_data.satellite_info[1].is_some());
let sat2 = gsv_data.satellite_info[1].as_ref().unwrap();
assert_eq!(sat2.prn, Some(2));
assert_eq!(sat2.elevation, Some(17));
assert_eq!(sat2.azimuth, Some(308));
assert_eq!(sat2.snr, Some(41));
}
#[test]
fn test_gsv_partial_satellites() {
let parser = NmeaParser::new();
let sentence = b"$GPGSV,1,1,02,01,40,083,46,02,17,308,*75\r\n";
let result = parser.parse_sentence_complete(sentence);
assert!(result.is_some());
let msg = result.unwrap();
let gsv = msg.as_gsv();
assert!(gsv.is_some());
let gsv_data = gsv.unwrap();
assert_eq!(gsv_data.satellites_in_view, 2);
assert!(gsv_data.satellite_info[0].is_some());
let sat1 = gsv_data.satellite_info[0].as_ref().unwrap();
assert_eq!(sat1.prn, Some(1));
assert!(gsv_data.satellite_info[1].is_some());
let sat2 = gsv_data.satellite_info[1].as_ref().unwrap();
assert_eq!(sat2.prn, Some(2));
assert_eq!(sat2.snr, None);
assert!(gsv_data.satellite_info[2].is_none());
assert!(gsv_data.satellite_info[3].is_none());
}
#[test]
fn test_gsv_single_satellite() {
let parser = NmeaParser::new();
let sentence = b"$GPGSV,1,1,01,01,40,083,46*75\r\n";
let result = parser.parse_sentence_complete(sentence);
assert!(result.is_some());
let msg = result.unwrap();
let gsv = msg.as_gsv();
assert!(gsv.is_some());
let gsv_data = gsv.unwrap();
assert_eq!(gsv_data.satellites_in_view, 1);
assert!(gsv_data.satellite_info[0].is_some());
assert!(gsv_data.satellite_info[1].is_none());
}
#[test]
fn test_gsv_missing_num_messages() {
let parser = NmeaParser::new();
let sentence = b"$GPGSV,,1,08,01,40,083,46,02,17,308,41,12,07,344,39,14,22,228,45*75\r\n";
let result = parser.parse_sentence_complete(sentence);
assert!(result.is_none());
}
#[test]
fn test_gsv_missing_message_num() {
let parser = NmeaParser::new();
let sentence = b"$GPGSV,2,,08,01,40,083,46,02,17,308,41,12,07,344,39,14,22,228,45*75\r\n";
let result = parser.parse_sentence_complete(sentence);
assert!(result.is_none());
}
#[test]
fn test_gsv_missing_satellites_in_view() {
let parser = NmeaParser::new();
let sentence = b"$GPGSV,2,1,,01,40,083,46,02,17,308,41,12,07,344,39,14,22,228,45*75\r\n";
let result = parser.parse_sentence_complete(sentence);
assert!(result.is_none());
}
#[test]
fn test_gsv_satellite_partial_info() {
let parser = NmeaParser::new();
let sentence = b"$GPGSV,1,1,01,01,,,*75\r\n";
let result = parser.parse_sentence_complete(sentence);
assert!(result.is_some());
let msg = result.unwrap();
let gsv = msg.as_gsv();
assert!(gsv.is_some());
let gsv_data = gsv.unwrap();
assert!(gsv_data.satellite_info[0].is_some());
let sat = gsv_data.satellite_info[0].as_ref().unwrap();
assert_eq!(sat.prn, Some(1));
assert_eq!(sat.elevation, None);
assert_eq!(sat.azimuth, None);
assert_eq!(sat.snr, None);
}
#[test]
fn test_gsv_zero_elevation_azimuth() {
let parser = NmeaParser::new();
let sentence = b"$GPGSV,1,1,01,01,0,0,46*75\r\n";
let result = parser.parse_sentence_complete(sentence);
assert!(result.is_some());
let msg = result.unwrap();
let gsv = msg.as_gsv();
assert!(gsv.is_some());
let gsv_data = gsv.unwrap();
let sat = gsv_data.satellite_info[0].as_ref().unwrap();
assert_eq!(sat.elevation, Some(0));
assert_eq!(sat.azimuth, Some(0));
}
#[test]
fn test_gsv_max_elevation() {
let parser = NmeaParser::new();
let sentence = b"$GPGSV,1,1,01,01,90,180,46*75\r\n";
let result = parser.parse_sentence_complete(sentence);
assert!(result.is_some());
let msg = result.unwrap();
let gsv = msg.as_gsv();
assert!(gsv.is_some());
let gsv_data = gsv.unwrap();
let sat = gsv_data.satellite_info[0].as_ref().unwrap();
assert_eq!(sat.elevation, Some(90));
}
#[test]
fn test_gsv_max_azimuth() {
let parser = NmeaParser::new();
let sentence = b"$GPGSV,1,1,01,01,45,359,46*75\r\n";
let result = parser.parse_sentence_complete(sentence);
assert!(result.is_some());
let msg = result.unwrap();
let gsv = msg.as_gsv();
assert!(gsv.is_some());
let gsv_data = gsv.unwrap();
let sat = gsv_data.satellite_info[0].as_ref().unwrap();
assert_eq!(sat.azimuth, Some(359));
}
#[test]
fn test_gsv_different_talker_id() {
let parser = NmeaParser::new();
let sentence = b"$GNGSV,2,1,08,01,40,083,46,02,17,308,41,12,07,344,39,14,22,228,45*75\r\n";
let result = parser.parse_sentence_complete(sentence);
assert!(result.is_some());
let msg = result.unwrap();
let gsv = msg.as_gsv();
assert!(gsv.is_some());
let gsv_data = gsv.unwrap();
assert_eq!(gsv_data.talker_id, crate::types::TalkerId::GN);
}
#[test]
fn test_gsv_satellites_from_different_constellations() {
let parser = NmeaParser::new();
let gp_sentence =
b"$GPGSV,2,1,08,01,40,083,46,02,17,308,41,12,07,344,39,14,22,228,45*75\r\n";
let gp_result = parser.parse_sentence_complete(gp_sentence);
assert!(gp_result.is_some());
let gp_msg = gp_result.unwrap();
let gp_gsv = gp_msg.as_gsv().unwrap();
assert_eq!(gp_gsv.talker_id, crate::types::TalkerId::GP);
assert_eq!(gp_gsv.satellites_in_view, 8);
let gl_sentence =
b"$GLGSV,2,1,08,65,40,083,46,66,17,308,41,75,07,344,39,76,22,228,45*75\r\n";
let gl_result = parser.parse_sentence_complete(gl_sentence);
assert!(gl_result.is_some());
let gl_msg = gl_result.unwrap();
let gl_gsv = gl_msg.as_gsv().unwrap();
assert_eq!(gl_gsv.talker_id, crate::types::TalkerId::GL);
let ga_sentence =
b"$GAGSV,2,1,08,01,40,083,46,02,17,308,41,12,07,344,39,14,22,228,45*75\r\n";
let ga_result = parser.parse_sentence_complete(ga_sentence);
assert!(ga_result.is_some());
let ga_msg = ga_result.unwrap();
let ga_gsv = ga_msg.as_gsv().unwrap();
assert_eq!(ga_gsv.talker_id, crate::types::TalkerId::GA);
}
#[test]
fn test_gsv_multiple_message_sequence() {
let parser = NmeaParser::new();
let sentence1 = b"$GPGSV,2,1,08,01,40,083,46,02,17,308,41,12,07,344,39,14,22,228,45*75\r\n";
let result1 = parser.parse_sentence_complete(sentence1);
assert!(result1.is_some());
let msg1 = result1.unwrap();
let gsv1_data = msg1.as_gsv().unwrap();
assert_eq!(gsv1_data.message_num, 1);
assert_eq!(gsv1_data.num_messages, 2);
let sentence2 = b"$GPGSV,2,2,08,20,35,073,44,21,25,210,42,25,15,120,40,32,10,045,38*75\r\n";
let result2 = parser.parse_sentence_complete(sentence2);
assert!(result2.is_some());
let msg2 = result2.unwrap();
let gsv2_data = msg2.as_gsv().unwrap();
assert_eq!(gsv2_data.message_num, 2);
assert_eq!(gsv2_data.num_messages, 2);
}
}