Skip to content

Commit

Permalink
Merge branch 'KD7TKJ-master'
Browse files Browse the repository at this point in the history
  • Loading branch information
Knio committed Mar 21, 2020
2 parents 5b01d7d + e77304e commit 4527cf4
Show file tree
Hide file tree
Showing 6 changed files with 242 additions and 6 deletions.
6 changes: 5 additions & 1 deletion pynmea2/nmea_utils.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
#pylint: disable=invalid-name
import datetime
import re

def valid(s):
return s == 'A'


def timestamp(s):
'''
Expand All @@ -25,7 +30,6 @@ def datestamp(s):
return datetime.datetime.strptime(s, '%d%m%y').date()


import re
def dm_to_sd(dm):
'''
Converts a geographic co-ordinate given in "degrees/minutes" dddmm.mmmm
Expand Down
2 changes: 2 additions & 0 deletions pynmea2/types/proprietary/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from . import ash
from . import grm
from . import kwd
from . import mgn
from . import rdi
from . import srf
from . import sxn
Expand Down
32 changes: 27 additions & 5 deletions pynmea2/types/proprietary/grm.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class GRME(GRM):
("Estimated Vert. Position Error", "vpe", Decimal),
("Estimated Vert. Position Error Unit (M)", "vpe_unit"),
("Estimated Horiz. Position Error", "osepe", Decimal),
("Overall Spherical Equiv. Position Error", "osepe_unit")
("Overall Spherical Equiv. Position Error", "osepe_unit"),
)


Expand All @@ -40,15 +40,37 @@ class GRMM(GRM):
)


class GRMW(GRM):
""" GARMIN Waypoint Information
https://www8.garmin.com/support/pdf/NMEA_0183.pdf
https://github.com/wb2osz/direwolf/blob/master/waypoint.c
$PGRMW,wname,alt,symbol,comment*99
Where,
wname is waypoint name. Must match existing waypoint.
alt is altitude in meters.
symbol is symbol code. Hexadecimal up to FFFF.
See Garmin Device Interface Specification
001-0063-00 for values of "symbol_type."
comment is comment for the waypoint.
*99 is checksum
"""
fields = (
("Subtype", "subtype"),
("Waypoint Name", "wname"),
("Altitude", "altitude", Decimal),
("Symbol", "symbol"),
("Comment", "comment"),
)


class GRMZ(GRM):
""" GARMIN Altitude Information
"""
fields = (
("Subtype", "subtype"),
("Altitude", "altitude", Decimal),
("Altitude Units (Feet)", "altitude_unit"),
("Positional Fix Dimension (2=user, 3=GPS)", "pos_fix_dim")
("Positional Fix Dimension (2=user, 3=GPS)", "pos_fix_dim"),
)



104 changes: 104 additions & 0 deletions pynmea2/types/proprietary/kwd.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# Kenwood

from decimal import Decimal
from datetime import date, time

from ... import nmea
from ... import nmea_utils


class KWD(nmea.ProprietarySentence):
sentence_types = {}

def __new__(_cls, manufacturer, data):
name = manufacturer + data[0]
cls = _cls.sentence_types.get(name, _cls)
return super(KWD, cls).__new__(cls)

def __init__(self, manufacturer, data):
self.sentence_type = manufacturer + data[0]
super(KWD, self).__init__(manufacturer, data)


class KWDWPL(KWD, nmea_utils.LatLonFix, nmea_utils.DatetimeFix, nmea_utils.ValidStatusFix):
""" Kenwood Waypoint Location
https://github.com/wb2osz/direwolf/blob/master/waypoint.c
$PKWDWPL,hhmmss,v,ddmm.mm,ns,dddmm.mm,ew,speed,course,ddmmyy,alt,wname,ts*99
Where,
hhmmss is time in UTC from the clock in the transceiver.
This will be bogus if the clock was not set properly.
It does not use the timestamp from a position
report which could be useful.
GPS Status A = active, V = void.
It looks like this might be modeled after the GPS status values
we see in $GPRMC. i.e. Does the transceiver know its location?
I don't see how that information would be relevant in this context.
I've observed this under various conditions (No GPS, GPS with/without
fix) and it has always been "V."
ddmm.mm,ns is latitude. N or S.
dddmm.mm,ew is longitude. E or W.
speed is speed over ground, knots.
course is course over ground, degrees.
ddmmyy is date. See comments for time.
alt is altitude, meters above mean sea level.
wname is the waypoint name. For an Object Report, the id is the object name.
For a position report, it is the call of the sending station.
An Object name can contain any printable characters.
What if object name contains , or * characters?
Those are field delimiter characters and it would be unfortunate
if they appeared in a NMEA sentence data field.
If there is a comma in the name, such as "test,5" the Kenwood TM-D710A displays
it fine but we end up with an extra field.
$PKWDWPL,150803,V,4237.14,N,07120.83,W,,,190316,,test,5,/'*30
If the name contains an asterisk, it doesn't show up on the
display and no waypoint sentence is generated.
Some other talkers substitute these two characters following the AvMap precedent.
$PKWDWPL,204714,V,4237.1400,N,07120.8300,W,,,200316,,test|5,/'*61
$PKWDWPL,204719,V,4237.1400,N,07120.8300,W,,,200316,,test~6,/'*6D
ts are the table and symbol.
What happens if the symbol is comma or asterisk?
, Boy Scouts / Girl Scouts
* SnowMobile / Snow
the D710A just pushes them thru without checking.
These would not be parsed properly:
$PKWDWPL,150753,V,4237.14,N,07120.83,W,,,190316,,test3,/,*1B
$PKWDWPL,150758,V,4237.14,N,07120.83,W,,,190316,,test4,/ **3B
Other talkers do the usual substitution and the other end would
need to change them back after extracting from NMEA sentence.
$PKWDWPL,204704,V,4237.1400,N,07120.8300,W,,,200316,,test3,/|*41
$PKWDWPL,204709,V,4237.1400,N,07120.8300,W,,,200316,,test4,/~*49
*99 is checksum
Oddly, there is no place for comment.
"""
fields = (
("Subtype", "subtype"),
("Time of Receipt", "timestamp", nmea_utils.timestamp),
("GPS Status (Void)","status"),
("Latitude", "lat"),
("Latitude Direction", "lat_dir"),
("Longitude", "lon"),
("Longitude Direction", "lon_dir"),
("Speed over Ground", "sog", float),
("Course over Ground", "cog", float),
("Date", "datestamp", nmea_utils.datestamp),
("Altitude", "altitude", Decimal),
("Waypoint Name", "wname"),
("Table and Symbol", "ts"),
)
52 changes: 52 additions & 0 deletions pynmea2/types/proprietary/mgn.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Magellan

from decimal import Decimal

from ... import nmea
from ... import nmea_utils


class MGN(nmea.ProprietarySentence):
sentence_types = {}

def __new__(_cls, manufacturer, data):
name = manufacturer + data[0]
cls = _cls.sentence_types.get(name, _cls)
return super(MGN, cls).__new__(cls)

def __init__(self, manufacturer, data):
self.sentence_type = manufacturer + data[0]
super(MGN, self).__init__(manufacturer, data)


class MGNWPL(MGN, nmea_utils.LatLonFix):
""" Magellan Waypoint Location
https://github.com/wb2osz/direwolf/blob/master/waypoint.c
$PMGNWPL,ddmm.mmmm,ns,dddmm.mmmm,ew,alt,unit,wname,comment,icon,xx*99
Where,
ddmm.mmmm,ns is latitude
dddmm.mmmm,ew is longitude
alt is altitude
unit is M for meters or F for feet
wname is the waypoint name
comment is message or comment
icon is one or two letters for icon code
xx is waypoint type which is optional, not well
defined, and not used in their example.
*99 is checksum
"""
fields = (
("Subtype", "subtype"),
("Latitude", "lat"),
("Latitude Direction", "lat_dir"),
("Longitude", "lon"),
("Longitude Direction", "lon_dir"),
("Altitude", "altitude", Decimal),
("Altitude Units (Feet/Meters)", "altitude_unit"),
("Waypoint Name", "wname"),
("Comment", "comment"),
("Icon", "icon"),
("Waypoint Type", "type")
)
52 changes: 52 additions & 0 deletions test/test_proprietary.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ def test_grm():
assert msg.osepe == 25.0
assert msg.osepe_unit == 'M'


def test_tnl():
data = '$PTNL,BPQ,224445.06,021207,3723.09383914,N,12200.32620132,W,EHT-5.923,M,5*60'
msg = pynmea2.parse(data)
Expand Down Expand Up @@ -195,3 +196,54 @@ def test_proprietary_VTX_0012():
assert msg.gain == 38.8
assert msg.render() == data


def test_proprietary_GRMW():
# A sample proprietary Garmin Waypoint sentence, generated by DIREWOLF
data = "$PGRMW,AC7FD-1,,000A,AC7FD local DIGI U=12.5V|T=23.9C*1A"
msg = pynmea2.parse(data)
assert msg.manufacturer == 'GRM'
assert msg.wname == 'AC7FD-1'
assert msg.altitude == None
assert msg.symbol == '000A'
assert msg.comment == 'AC7FD local DIGI U=12.5V|T=23.9C'


def test_proprietary_MGNWPL():
# A sample proprietary Magellan Waypoint sentence, generated by DIREWOLF
data = "$PMGNWPL,4531.7900,N,12253.4800,W,,M,AC7FD-1,AC7FD local DIGI U=12.5V|T=23.9C,c*46"
msg = pynmea2.parse(data)
assert msg.manufacturer == 'MGN'
assert msg.lat =='4531.7900'
assert msg.lat_dir == 'N'
assert msg.lon == '12253.4800'
assert msg.lon_dir == 'W'
assert msg.altitude == None
assert msg.altitude_unit == 'M'
assert msg.wname == 'AC7FD-1'
assert msg.comment == 'AC7FD local DIGI U=12.5V|T=23.9C'
assert msg.icon == 'c'
assert msg.latitude == 45.529833333333336
assert msg.longitude == -122.89133333333334


def test_KWDWPL():
# A sample proprietary Kenwood Waypoint sentence, generated by DIREWOLF
data = "$PKWDWPL,053125,V,4531.7900,N,12253.4800,W,,,200320,,AC7FD-1,/-*10"
msg = pynmea2.parse(data)
assert msg.manufacturer == "KWD"
assert msg.timestamp == datetime.time(5, 31, 25)
assert msg.status == 'V'
assert msg.is_valid == False
assert msg.lat == '4531.7900'
assert msg.lat_dir == 'N'
assert msg.lon == '12253.4800'
assert msg.lon_dir == 'W'
assert msg.sog == None
assert msg.cog == None
assert msg.datestamp == datetime.date(2020, 3, 20)
assert msg.datetime == datetime.datetime(2020, 3, 20, 5, 31, 25)
assert msg.altitude == None
assert msg.wname == 'AC7FD-1'
assert msg.ts == '/-'
assert msg.latitude == 45.529833333333336
assert msg.longitude == -122.89133333333334

0 comments on commit 4527cf4

Please sign in to comment.