Closed fohrloop closed 2 years ago
Added GSV signal_id processing to fix https://github.com/Knio/pynmea2/issues/108
The idea is the add custom __init__
method to GSV
class which allows for custom name_to_idx
and fields
for the GSV
instances. Also, there is custom __getattr__
for the GSV
class, which basically just makes the GSV
instances to use self.name_to_idx
and self.fields
instead of the t.name_to_idx
or t.fields
(t=type).
Some examples below: (adds signal_id
and removes the erroneus sv_prn_num_#
).
Same pattern could be used also for other messages which may be variable length, and which may contain additional identifiers added by GNSS receiver manufacturers.
In [1]: pynmea2.parse("$GPGSV,3,3,09,25,,,40,1*6E")
Out[1]: <GSV(num_messages='3', msg_num='3', num_sv_in_view='09', sv_prn_num_1='25', elevation_deg_1='', azimuth_1='', snr_1='40', sv_prn_num_2='1')>
In [2]: pynmea2.parse("$GPGSV,3,3,09,25,,,40,1*6E", GSV_signal_id=True)
Out[2]: <GSV(num_messages='3', msg_num='3', num_sv_in_view='09', sv_prn_num_1='25', elevation_deg_1='', azimuth_1='', snr_1='40', signal_id='1')>
In [1]: pynmea2.parse("$GPGSV,3,3,11,26,49,301,08,29,58,056,37,31,50,235,22,1*55")
Out[1]: <GSV(num_messages='3', msg_num='3', num_sv_in_view='11', sv_prn_num_1='26', elevation_deg_1='49', azimuth_1='301', snr_1='08', sv_prn_num_2='29', elevation_deg_2='58', azimuth_2='056', snr_2='37', sv_prn_num_3='31', elevation_deg_3='50', azimuth_3='235', snr_3='22', sv_prn_num_4='1')>
In [2]: pynmea2.parse("$GPGSV,3,3,11,26,49,301,08,29,58,056,37,31,50,235,22,1*55", GSV_signal_id=True)
Out[2]: <GSV(num_messages='3', msg_num='3', num_sv_in_view='11', sv_prn_num_1='26', elevation_deg_1='49', azimuth_1='301', snr_1='08', sv_prn_num_2='29', elevation_deg_2='58', azimuth_2='056', snr_2='37', sv_prn_num_3='31', elevation_deg_3='50', azimuth_3='235', snr_3='22', signal_id='1')>
In [1]: pynmea2.parse('$GAGSV,1,1,00,2*76\r\n')
Out[1]: <GSV(num_messages='1', msg_num='1', num_sv_in_view='00', sv_prn_num_1='2')>
In [2]: pynmea2.parse('$GAGSV,1,1,00,2*76\r\n', GSV_signal_id=True)
Out[2]: <GSV(num_messages='1', msg_num='1', num_sv_in_view='00', signal_id='2')>
Added support for reading the systemId and signalId from GRS NMEA 4.10+ messages.
In [1]: data = "$GNGRS,121519.00,1,0.2,-1.4,-1.9,3.0,-0.2,1.2,-0.8,-1.2,,,,,3,7*70"
# This is the default behaviour; the system_id and signal_id are in the data property
In [2]: msg = pynmea2.parse(data, GRS_ids=False)
In [3]: msg
Out[3]: <GRS(timestamp=datetime.time(12, 15, 19), residuals_mode=1, sv_res_01=0.2, sv_res_02=-1.4, sv_res_03=-1.9, sv_res_04=3.0, sv_res_05=-0.2, sv_res_06=1.2, sv_res_07=-0.8, sv_res_08=-1.2, sv_res_09=None, sv_res_10=None, sv_res_11=None, sv_res_12=None) data=['3', '7']>
In [4]: msg = pynmea2.parse(data, GRS_ids=True)
In [5]: msg
Out[5]: <GRS(timestamp=datetime.time(12, 15, 19), residuals_mode=1, sv_res_01=0.2, sv_res_02=-1.4, sv_res_03=-1.9, sv_res_04=3.0, sv_res_05=-0.2, sv_res_06=1.2, sv_res_07=-0.8, sv_res_08=-1.2, sv_res_09=None, sv_res_10=None, sv_res_11=None, sv_res_12=None, system_id='3', signal_id='7')>
If signal_id
and system_id
are standard, why not just add them to the field list of the messages that need them? If the receiver doesn't add them to the sentence (old hardware), the new fields will just remain empty.
Sorry. Didn't see that GSV
can have less satellites but still send signal_id
and system_id
.
No problem. I see that the original implementation uses a metaclass and the different NMEA Sentences are implemented as classes that are constructed using the metaclass. Now, solving the problem of variable length NMEA strings (with variable amount of commas) could probably be also solved using some extra arguments when creating the NMEA Sentence classes, by modifying the metaclass code, but I did not figure out an easy way to do that.
You're right that actually GRS
systemId and signalId could be read by just adding the two entries to the GRS.fields
.
The GSV
messages are tricky since at least uBlox outputs sometimes variable amount of commas in the message. Maybe this could be also solved by introducing "fields" that are read from end of the string but still it will probably need user given argument to parse()
.
The checksum checking was previously always on, even though the default value for
check
inparse()
wasFalse