False alarm GNSS-signal-loss seen for device of gnss-monitor ptp-instance
The false alarm seen with following GpsData, where lock_state is 0 and satellite_count and signal are positive value : GpsData(gpsd_running=1, lock_state=0, satellite_count=22, signal_quality_db=SignalQualityDb(min=28.0, max=36.0, avg=32.954)) SKY report of Gpsd data gives satellite count and signal_quality_db. TPV report of Gpsd data gives lock_state. The code was written with the assumption: SKY report always received only after TPV report. In long running system, it is observed the order is not guaranteed (5 out-of- order receipt in 2 days). This commit fixes the issue by handling out-of-order TPV and SKY report. Unit tests has been added to check out-of-order handling. TEST PLAN: PASS: Unit test with out-of-order TPV and SKY reports PASS: Deploy gnss-monitor instance and test functionality PASS: Run in loop to verify GpsData output sudo python /usr/rootdirs/opt/collectd/extensions/python/ptp_gnss_monitor_cli.py --devices /dev/ttyACM0 Closes-bug: 2127121 Change-Id: I80594f5a3a1210213c6f688822711b9c2e4e84a1 Signed-off-by: Tara Nath Subedi <tara.subedi@windriver.com>
This commit is contained in:
@@ -115,6 +115,12 @@ def get_gps_data_by_session(session, device_path):
|
|||||||
signal_quality_db=SignalQualityDb(min=0, max=0, avg=0),
|
signal_quality_db=SignalQualityDb(min=0, max=0, avg=0),
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
|
# - TPV and SKY report are independent information and could come in any order.
|
||||||
|
# - A GPS receiver might have satellite visibility data (a SKY report) but still not
|
||||||
|
# be able to calculate a usable position, hence sending a TPV report with mode: 0.
|
||||||
|
# - SKY report won't follow TPV, when GPS receiver is not functional.
|
||||||
|
tpv_report_scanned = False
|
||||||
|
sky_report_scanned = False
|
||||||
for report in session:
|
for report in session:
|
||||||
if report["class"] in ["VERSION", "WATCH", "DEVICE"]:
|
if report["class"] in ["VERSION", "WATCH", "DEVICE"]:
|
||||||
continue
|
continue
|
||||||
@@ -138,12 +144,17 @@ def get_gps_data_by_session(session, device_path):
|
|||||||
message = f"{PLUGIN} {device_path} have not achieved satellite lock: {report}"
|
message = f"{PLUGIN} {device_path} have not achieved satellite lock: {report}"
|
||||||
collectd.debug(message)
|
collectd.debug(message)
|
||||||
data.lock_state = 0
|
data.lock_state = 0
|
||||||
# reset satellite_count and signal_quality_db
|
# Do not change satellite_count and signal_quality_db in case
|
||||||
data.satellite_count = 0
|
# SKY already scanned
|
||||||
data.signal_quality_db = SignalQualityDb(min=0, max=0, avg=0)
|
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
data.lock_state = 1
|
data.lock_state = 1
|
||||||
|
if sky_report_scanned:
|
||||||
|
break
|
||||||
|
|
||||||
|
# Set TPV report scanned flag
|
||||||
|
tpv_report_scanned = True
|
||||||
|
|
||||||
# device key is optional in SKY class
|
# device key is optional in SKY class
|
||||||
elif (
|
elif (
|
||||||
report["class"] == "SKY"
|
report["class"] == "SKY"
|
||||||
@@ -153,14 +164,23 @@ def get_gps_data_by_session(session, device_path):
|
|||||||
# uSat key is optional in SKY class, Number of satellites used in navigation solution
|
# uSat key is optional in SKY class, Number of satellites used in navigation solution
|
||||||
if "uSat" in report:
|
if "uSat" in report:
|
||||||
data.satellite_count = report["uSat"]
|
data.satellite_count = report["uSat"]
|
||||||
|
else:
|
||||||
|
data.satellite_count = 0
|
||||||
# satellites key is optional in SKY class, List of satellite objects in skyview
|
# satellites key is optional in SKY class, List of satellite objects in skyview
|
||||||
if "satellites" in report:
|
if "satellites" in report:
|
||||||
data.signal_quality_db = get_signal_to_noise_ratio(
|
data.signal_quality_db = get_signal_to_noise_ratio(
|
||||||
report["satellites"]
|
report["satellites"]
|
||||||
)
|
)
|
||||||
|
else:
|
||||||
|
data.signal_quality_db = SignalQualityDb(min=0, max=0, avg=0)
|
||||||
|
|
||||||
# All reports collected, No more polling required.
|
# All reports collected, No more polling required.
|
||||||
break
|
if tpv_report_scanned:
|
||||||
|
break
|
||||||
|
|
||||||
|
# Set SKY report scanned flag
|
||||||
|
sky_report_scanned = True
|
||||||
|
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
# In case of parsing error, should be reported instead of throwing exception
|
# In case of parsing error, should be reported instead of throwing exception
|
||||||
message = f"{PLUGIN} Programming error occured: {type(exc)}:{exc}"
|
message = f"{PLUGIN} Programming error occured: {type(exc)}:{exc}"
|
||||||
|
@@ -321,6 +321,280 @@ class TestPtpMonitoring(unittest.TestCase):
|
|||||||
msg=f"actual {data} not equal to expected {expected_data} ",
|
msg=f"actual {data} not equal to expected {expected_data} ",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_get_gps_data_by_session_sky_before_tpv_mode_2_valid(self):
|
||||||
|
# out of order test: SKY before TPV (with mode:2)
|
||||||
|
device_path = "/dev/gnss0"
|
||||||
|
session = [
|
||||||
|
{
|
||||||
|
"class": "VERSION",
|
||||||
|
"release": "3.22",
|
||||||
|
"rev": "3.22",
|
||||||
|
"proto_major": 3,
|
||||||
|
"proto_minor": 14,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"class": "DEVICES",
|
||||||
|
"devices": [
|
||||||
|
{
|
||||||
|
"class": "DEVICE",
|
||||||
|
"path": "/dev/gnss0",
|
||||||
|
"activated": "2025-06-13T12:52:15.463Z",
|
||||||
|
"native": 0,
|
||||||
|
"bps": 9600,
|
||||||
|
"parity": "N",
|
||||||
|
"stopbits": 0,
|
||||||
|
"cycle": 1.0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"class": "DEVICE",
|
||||||
|
"path": "/dev/gnss1",
|
||||||
|
"activated": "2025-06-13T12:52:19.637Z",
|
||||||
|
"native": 0,
|
||||||
|
"bps": 9600,
|
||||||
|
"parity": "N",
|
||||||
|
"stopbits": 0,
|
||||||
|
"cycle": 1.0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"class": "WATCH",
|
||||||
|
"enable": True,
|
||||||
|
"json": True,
|
||||||
|
"nmea": False,
|
||||||
|
"raw": 0,
|
||||||
|
"scaled": False,
|
||||||
|
"timing": False,
|
||||||
|
"split24": False,
|
||||||
|
"pps": False,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"class": "DEVICE",
|
||||||
|
"path": "/dev/gnss0",
|
||||||
|
"driver": "NMEA0183",
|
||||||
|
"activated": "2025-06-13T12:52:19.637Z",
|
||||||
|
"native": 0,
|
||||||
|
"bps": 9600,
|
||||||
|
"parity": "N",
|
||||||
|
"stopbits": 0,
|
||||||
|
"cycle": 1.0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"class": "SKY",
|
||||||
|
"device": "/dev/gnss0",
|
||||||
|
"time": "2019-04-10T20:27:52.000Z",
|
||||||
|
"xdop": 0.69,
|
||||||
|
"ydop": 0.68,
|
||||||
|
"vdop": 1.33,
|
||||||
|
"tdop": 0.88,
|
||||||
|
"hdop": 0.97,
|
||||||
|
"gdop": 1.86,
|
||||||
|
"pdop": 1.64,
|
||||||
|
"nSat": 4,
|
||||||
|
"uSat": 3,
|
||||||
|
"satellites": [
|
||||||
|
{
|
||||||
|
"PRN": 5,
|
||||||
|
"el": 31.0,
|
||||||
|
"az": 86.0,
|
||||||
|
"ss": 45.2,
|
||||||
|
"used": True,
|
||||||
|
"gnssid": 0,
|
||||||
|
"svid": 5,
|
||||||
|
"health": 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"PRN": 10,
|
||||||
|
"el": 10.0,
|
||||||
|
"az": 278.0,
|
||||||
|
"ss": 40.0,
|
||||||
|
"used": False,
|
||||||
|
"gnssid": 0,
|
||||||
|
"svid": 10,
|
||||||
|
"health": 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"PRN": 13,
|
||||||
|
"el": 44.0,
|
||||||
|
"az": 53.0,
|
||||||
|
"ss": 47.4,
|
||||||
|
"used": True,
|
||||||
|
"gnssid": 0,
|
||||||
|
"svid": 13,
|
||||||
|
"health": 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"PRN": 15,
|
||||||
|
"el": 80.0,
|
||||||
|
"az": 68.0,
|
||||||
|
"ss": 48.8,
|
||||||
|
"used": True,
|
||||||
|
"gnssid": 0,
|
||||||
|
"svid": 15,
|
||||||
|
"health": 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{"class": "TPV", "device": "/dev/gnss0", "mode": 2},
|
||||||
|
]
|
||||||
|
snr = [45.2, 47.4, 48.8]
|
||||||
|
avg = sum(snr) / len(snr)
|
||||||
|
trunc_avg = int(avg * 1000) / 1000
|
||||||
|
expected_signal_quality_db = ptp_monitoring.SignalQualityDb(
|
||||||
|
min=min(snr), max=max(snr), avg=trunc_avg
|
||||||
|
)
|
||||||
|
expected_data = ptp_monitoring.GpsData(
|
||||||
|
gpsd_running=1,
|
||||||
|
lock_state=1,
|
||||||
|
satellite_count=3,
|
||||||
|
signal_quality_db=expected_signal_quality_db,
|
||||||
|
)
|
||||||
|
|
||||||
|
data = ptp_monitoring.get_gps_data_by_session(session, device_path)
|
||||||
|
mock_collectd.assert_not_called()
|
||||||
|
self.assertEqual(
|
||||||
|
data,
|
||||||
|
expected_data,
|
||||||
|
msg=f"actual {data} not equal to expected {expected_data} ",
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_get_gps_data_by_session_sky_before_tpv_mode_1_valid(self):
|
||||||
|
# out of order test: SKY before TPV (with mode:1)
|
||||||
|
device_path = "/dev/gnss0"
|
||||||
|
session = [
|
||||||
|
{
|
||||||
|
"class": "VERSION",
|
||||||
|
"release": "3.22",
|
||||||
|
"rev": "3.22",
|
||||||
|
"proto_major": 3,
|
||||||
|
"proto_minor": 14,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"class": "DEVICES",
|
||||||
|
"devices": [
|
||||||
|
{
|
||||||
|
"class": "DEVICE",
|
||||||
|
"path": "/dev/gnss0",
|
||||||
|
"activated": "2025-06-13T12:52:15.463Z",
|
||||||
|
"native": 0,
|
||||||
|
"bps": 9600,
|
||||||
|
"parity": "N",
|
||||||
|
"stopbits": 0,
|
||||||
|
"cycle": 1.0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"class": "DEVICE",
|
||||||
|
"path": "/dev/gnss1",
|
||||||
|
"activated": "2025-06-13T12:52:19.637Z",
|
||||||
|
"native": 0,
|
||||||
|
"bps": 9600,
|
||||||
|
"parity": "N",
|
||||||
|
"stopbits": 0,
|
||||||
|
"cycle": 1.0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"class": "WATCH",
|
||||||
|
"enable": True,
|
||||||
|
"json": True,
|
||||||
|
"nmea": False,
|
||||||
|
"raw": 0,
|
||||||
|
"scaled": False,
|
||||||
|
"timing": False,
|
||||||
|
"split24": False,
|
||||||
|
"pps": False,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"class": "DEVICE",
|
||||||
|
"path": "/dev/gnss0",
|
||||||
|
"driver": "NMEA0183",
|
||||||
|
"activated": "2025-06-13T12:52:19.637Z",
|
||||||
|
"native": 0,
|
||||||
|
"bps": 9600,
|
||||||
|
"parity": "N",
|
||||||
|
"stopbits": 0,
|
||||||
|
"cycle": 1.0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"class": "SKY",
|
||||||
|
"device": "/dev/gnss0",
|
||||||
|
"time": "2019-04-10T20:27:52.000Z",
|
||||||
|
"xdop": 0.69,
|
||||||
|
"ydop": 0.68,
|
||||||
|
"vdop": 1.33,
|
||||||
|
"tdop": 0.88,
|
||||||
|
"hdop": 0.97,
|
||||||
|
"gdop": 1.86,
|
||||||
|
"pdop": 1.64,
|
||||||
|
"nSat": 4,
|
||||||
|
"uSat": 3,
|
||||||
|
"satellites": [
|
||||||
|
{
|
||||||
|
"PRN": 5,
|
||||||
|
"el": 31.0,
|
||||||
|
"az": 86.0,
|
||||||
|
"ss": 45.2,
|
||||||
|
"used": True,
|
||||||
|
"gnssid": 0,
|
||||||
|
"svid": 5,
|
||||||
|
"health": 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"PRN": 10,
|
||||||
|
"el": 10.0,
|
||||||
|
"az": 278.0,
|
||||||
|
"ss": 40.0,
|
||||||
|
"used": False,
|
||||||
|
"gnssid": 0,
|
||||||
|
"svid": 10,
|
||||||
|
"health": 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"PRN": 13,
|
||||||
|
"el": 44.0,
|
||||||
|
"az": 53.0,
|
||||||
|
"ss": 47.4,
|
||||||
|
"used": True,
|
||||||
|
"gnssid": 0,
|
||||||
|
"svid": 13,
|
||||||
|
"health": 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"PRN": 15,
|
||||||
|
"el": 80.0,
|
||||||
|
"az": 68.0,
|
||||||
|
"ss": 48.8,
|
||||||
|
"used": True,
|
||||||
|
"gnssid": 0,
|
||||||
|
"svid": 15,
|
||||||
|
"health": 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{"class": "TPV", "device": "/dev/gnss0", "mode": 1},
|
||||||
|
]
|
||||||
|
snr = [45.2, 47.4, 48.8]
|
||||||
|
avg = sum(snr) / len(snr)
|
||||||
|
trunc_avg = int(avg * 1000) / 1000
|
||||||
|
expected_signal_quality_db = ptp_monitoring.SignalQualityDb(
|
||||||
|
min=min(snr), max=max(snr), avg=trunc_avg
|
||||||
|
)
|
||||||
|
expected_data = ptp_monitoring.GpsData(
|
||||||
|
gpsd_running=1,
|
||||||
|
lock_state=0,
|
||||||
|
satellite_count=3,
|
||||||
|
signal_quality_db=expected_signal_quality_db,
|
||||||
|
)
|
||||||
|
|
||||||
|
data = ptp_monitoring.get_gps_data_by_session(session, device_path)
|
||||||
|
mock_collectd.assert_not_called()
|
||||||
|
self.assertEqual(
|
||||||
|
data,
|
||||||
|
expected_data,
|
||||||
|
msg=f"actual {data} not equal to expected {expected_data} ",
|
||||||
|
)
|
||||||
|
|
||||||
def test_get_gps_data_by_session_with_garbase_data(self):
|
def test_get_gps_data_by_session_with_garbase_data(self):
|
||||||
device_path = "/dev/gnss0"
|
device_path = "/dev/gnss0"
|
||||||
session = [
|
session = [
|
||||||
|
Reference in New Issue
Block a user