Skip to content

Commit

Permalink
Merge branch 'nmea_listener'
Browse files Browse the repository at this point in the history
  • Loading branch information
eriffon committed Oct 16, 2023
2 parents 1da13af + aaacc50 commit ea7f7da
Show file tree
Hide file tree
Showing 19 changed files with 517 additions and 24 deletions.
Binary file added docs/_static/ssm_nmea0183_input.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/ssm_nmea0183_listeners.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions docs/user_manual_setup.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ Setup
user_manual_setup_settings
user_manual_setup_sis_v4
user_manual_setup_sis_v5
user_manual_setup_nmea0183
30 changes: 30 additions & 0 deletions docs/user_manual_setup_nmea0183.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
.. _nmea0183:

Sound Speed Manager - NMEA-0183 interaction
===========================================

.. index:: NMEA-0183;

A rudimentary NMEA-0183 listener can be used to capture the current location via a UDP broadcast of NMEA-0183 $--GGA or $--GLL sentences. This feature can be used to associate the current position to the sound speed profile formats that cannot store location information.

Open in editing mode the Sound Speed Manager’s Setup Tab, then set the NMEA-0183 listen port the Listeners sub-tab (see :numref:`ssm_nmea0183_listeners_fig`).

.. _ssm_nmea0183_listeners_fig:
.. figure:: ./_static/ssm_nmea0183_listeners.png
:width: 618px
:align: center
:alt: figure with nmea0183 settings part 1
:figclass: align-center

*Sound Speed Manager Setup Listeners* dialog, with the *Listen Port* setting and incoming NMEA-0183 data highlighted in red.

Then, switch to the Input sub-tab (see :numref:`ssm_nmea0183_input_fig`) and select the True value for the Listen NMEA-0183 field. After a **restart**, the current position is displayed in the status bar.

.. _ssm_nmea0183_input_fig:
.. figure:: ./_static/ssm_nmea0183_input.png
:width: 618px
:align: center
:alt: figure with nmea0183 settings part 2
:figclass: align-center

*Input tab* in the Sound Speed Manager’s Setup.
7 changes: 7 additions & 0 deletions hyo2/soundspeed/base/callbacks/abstract_callbacks.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

if TYPE_CHECKING:
from hyo2.soundspeed.listener.sis.sis import Sis
from hyo2.soundspeed.listener.nmea.nmea import Nmea


logger = logging.getLogger(__name__)
Expand All @@ -15,6 +16,7 @@ class GeneralAbstractCallbacks(metaclass=ABCMeta):

def __init__(self) -> None:
self.sis_listener = None # type: Optional[Sis]
self.nmea_listener = None # type: Optional[Nmea]

@abstractmethod
def ask_number(self, title: Optional[str] = "", msg: Optional[str] = "Enter number", default: Optional[float] = 0.0,
Expand Down Expand Up @@ -73,6 +75,11 @@ def ask_location_from_sis(self) -> bool:
"""Ask user for location"""
pass

@abstractmethod
def ask_location_from_nmea(self) -> bool:
"""Ask user for location"""
pass

@abstractmethod
def ask_tss(self) -> Optional[float]:
"""Ask user for transducer sound speed"""
Expand Down
11 changes: 11 additions & 0 deletions hyo2/soundspeed/base/callbacks/cli_callbacks.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,17 @@ def ask_location_from_sis(self) -> bool:
return True
return False

def ask_location_from_nmea(self) -> bool:
"""Ask user whether retrieving location from NMEA-0183"""
bool_msg = "Geographic location required for pressure/depth conversion and atlas lookup.\n" \
"Use geographic position from NMEA-0183?\'y' for yes, other inputs to enter position manually."

raw = input(bool_msg)
# print(raw)
if (raw == "Y") or (raw == "y"):
return True
return False

def ask_tss(self) -> Optional[float]:
"""Ask user for transducer sound speed"""
tss = 1500.0
Expand Down
3 changes: 3 additions & 0 deletions hyo2/soundspeed/base/callbacks/fake_callbacks.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ def ask_directory(self, key_name: Optional[str] = None, default_path: Optional[s
def ask_location_from_sis(self) -> bool:
return True

def ask_location_from_nmea(self) -> bool:
return True

def ask_tss(self) -> Optional[float]:
return 1500.0

Expand Down
18 changes: 18 additions & 0 deletions hyo2/soundspeed/base/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ def __init__(self, release_folder, use_setup_name=None):
self.use_sis4 = None
self.use_sis5 = None
self.use_sippican = None
self.use_nmea = None
self.use_mvp = None

# output
Expand All @@ -78,6 +79,9 @@ def __init__(self, release_folder, use_setup_name=None):
# listeners - sippican
self.sippican_listen_port = None
self.sippican_listen_timeout = None
# listeners - nmea
self.nmea_listen_port = None
self.nmea_listen_timeout = None
# listeners - mvp
self.mvp_ip_address = None
self.mvp_listen_port = None
Expand Down Expand Up @@ -158,6 +162,7 @@ def load_from_db(self, db_path: Optional[str] = None):
self.use_sis4 = db.use_sis4
self.use_sis5 = db.use_sis5
self.use_sippican = db.use_sippican
self.use_nmea = db.use_nmea
self.use_mvp = db.use_mvp

# output
Expand All @@ -178,6 +183,10 @@ def load_from_db(self, db_path: Optional[str] = None):
self.sippican_listen_port = db.sippican_listen_port
self.sippican_listen_timeout = db.sippican_listen_timeout

# listeners - nmea
self.nmea_listen_port = db.nmea_listen_port
self.nmea_listen_timeout = db.nmea_listen_timeout

# listeners - mvp
self.mvp_ip_address = db.mvp_ip_address
self.mvp_listen_port = db.mvp_listen_port
Expand Down Expand Up @@ -243,6 +252,7 @@ def save_to_db(self):
db.use_sis4 = self.use_sis4
db.use_sis5 = self.use_sis5
db.use_sippican = self.use_sippican
db.use_nmea = self.use_nmea
db.use_mvp = self.use_mvp

# client list
Expand All @@ -264,6 +274,10 @@ def save_to_db(self):
db.sippican_listen_port = self.sippican_listen_port
db.sippican_listen_timeout = self.sippican_listen_timeout

# listeners - nmea
db.nmea_listen_port = self.nmea_listen_port
db.nmea_listen_timeout = self.nmea_listen_timeout

# listeners - mvp
db.mvp_ip_address = self.mvp_ip_address
db.mvp_listen_port = self.mvp_listen_port
Expand Down Expand Up @@ -322,6 +336,7 @@ def __repr__(self):
msg += " <use_sis4: %s>\n" % self.use_sis4
msg += " <use_sis5: %s>\n" % self.use_sis5
msg += " <use_sippican: %s>\n" % self.use_sippican
msg += " <use_nmea: %s>\n" % self.use_nmea
msg += " <use_mvp: %s>\n" % self.use_mvp
msg += " <output>\n"
msg += " <clients>\n"
Expand All @@ -334,6 +349,9 @@ def __repr__(self):
msg += " <listeners - sippican>\n"
msg += " <sippican_listen_port: %s>\n" % self.sippican_listen_port
msg += " <sippican_listen_timeout: %s>\n" % self.sippican_listen_timeout
msg += " <listeners - nmea>\n"
msg += " <nmea_listen_port: %s>\n" % self.nmea_listen_port
msg += " <nmea_listen_timeout: %s>\n" % self.nmea_listen_timeout
msg += " <listeners - mvp>\n"
msg += " <mvp_ip_address: %s>\n" % self.mvp_ip_address
msg += " <mvp_listen_port: %s>\n" % self.mvp_listen_port
Expand Down
27 changes: 27 additions & 0 deletions hyo2/soundspeed/base/setup_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,15 @@ def use_sippican(self):
def use_sippican(self, value):
self._setter_bool("use_sippican", value)

# --- use_nmea
@property
def use_nmea(self):
return self._getter_bool("use_nmea")

@use_nmea.setter
def use_nmea(self, value):
self._setter_bool("use_nmea", value)

# --- use_mvp
@property
def use_mvp(self):
Expand Down Expand Up @@ -527,6 +536,24 @@ def sippican_listen_timeout(self):
def sippican_listen_timeout(self, value):
self._setter_int("sippican_listen_timeout", value)

# --- nmea_listen_port
@property
def nmea_listen_port(self):
return self._getter_int("nmea_listen_port")

@nmea_listen_port.setter
def nmea_listen_port(self, value):
self._setter_int("nmea_listen_port", value)

# --- nmea_listen_timeout
@property
def nmea_listen_timeout(self):
return self._getter_int("nmea_listen_timeout")

@nmea_listen_timeout.setter
def nmea_listen_timeout(self, value):
self._setter_int("nmea_listen_timeout", value)

# --- mvp_ip_address
@property
def mvp_ip_address(self):
Expand Down
24 changes: 17 additions & 7 deletions hyo2/soundspeed/base/setup_sql.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
use_sis integer NOT NULL DEFAULT 1,
use_sis5 integer NOT NULL DEFAULT 0,
use_sippican integer NOT NULL DEFAULT 0,
use_nmea integer NOT NULL DEFAULT 0,
use_mvp integer NOT NULL DEFAULT 0,
/* listeners - sis4 */
sis_listen_port integer NOT NULL DEFAULT 16103,
Expand All @@ -90,6 +91,9 @@
/* listeners - sippican */
sippican_listen_port integer NOT NULL DEFAULT 2002,
sippican_listen_timeout integer NOT NULL DEFAULT 10,
/* listeners - nmea */
nmea_listen_port integer NOT NULL DEFAULT 2006,
nmea_listen_timeout integer NOT NULL DEFAULT 10,
/* listeners - mvp */
mvp_ip_address text NOT NULL DEFAULT "127.0.0.1",
mvp_listen_port integer NOT NULL DEFAULT 2006,
Expand Down Expand Up @@ -173,13 +177,13 @@
INSERT INTO general
(id, setup_name, setup_status, use_woa09, use_woa13, use_woa18, use_rtofs,
ssp_extension_source, ssp_salinity_source, ssp_temp_sal_source, ssp_up_or_down, rx_max_wait_time,
use_sis, use_sippican, use_mvp, sis_listen_port, sis_listen_timeout,
sis_auto_apply_manual_casts, sippican_listen_port, sippican_listen_timeout, mvp_ip_address,
mvp_listen_port, mvp_listen_timeout, mvp_transmission_protocol, mvp_format, mvp_winch_port,
mvp_fish_port, mvp_nav_port, mvp_system_port, mvp_sw_version, mvp_instrument_id, mvp_instrument,
server_source, server_apply_surface_sound_speed, current_project, custom_projects_folder,
custom_outputs_folder, custom_woa09_folder, custom_woa13_folder, noaa_tools, default_institution,
default_survey, default_vessel, auto_apply_default_metadata)
use_sis, use_sippican, use_nmea, use_mvp, sis_listen_port, sis_listen_timeout,
sis_auto_apply_manual_casts, sippican_listen_port, sippican_listen_timeout, nmea_listen_port,
nmea_listen_timeout, mvp_ip_address, mvp_listen_port, mvp_listen_timeout, mvp_transmission_protocol,
mvp_format, mvp_winch_port, mvp_fish_port, mvp_nav_port, mvp_system_port, mvp_sw_version,
mvp_instrument_id, mvp_instrument, server_source, server_apply_surface_sound_speed, current_project,
custom_projects_folder, custom_outputs_folder, custom_woa09_folder, custom_woa13_folder, noaa_tools,
default_institution, default_survey, default_vessel, auto_apply_default_metadata)
SELECT
id, setup_name, setup_status,
CASE WHEN typeof(use_woa09) == 'text' THEN
Expand Down Expand Up @@ -213,6 +217,11 @@
ELSE
use_sippican
END,
CASE WHEN typeof(use_nmea) == 'text' THEN
use_nmea == 'True'
ELSE
use_nmea
END,
CASE WHEN typeof(use_mvp) == 'text' THEN
use_mvp == 'True'
ELSE
Expand All @@ -225,6 +234,7 @@
sis_auto_apply_manual_casts
END,
sippican_listen_port, sippican_listen_timeout,
nmea_listen_port, nmea_listen_timeout,
mvp_ip_address, mvp_listen_port, mvp_listen_timeout, mvp_transmission_protocol, mvp_format, mvp_winch_port,
mvp_fish_port, mvp_nav_port, mvp_system_port, mvp_sw_version, mvp_instrument_id, mvp_instrument,
server_source,
Expand Down
94 changes: 94 additions & 0 deletions hyo2/soundspeed/formats/nmea0183.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import logging

logger = logging.getLogger(__name__)


class Nmea0183Nav:

def __init__(self, data):

self.data = data
self.msg = None

self.latitude = None
self.longitude = None

self.parse()

def parse(self) -> None:
self.msg = self.data.split(',')

def __str__(self):
return "Latitude: {0}, Longitude: {1}\n".format(self.latitude, self.longitude)



class Nmea0183GGA(Nmea0183Nav):

def __init__(self, data):
super(Nmea0183GGA, self).__init__(data)

self.timestamp = self.msg[1]
self.lat = self.msg[2]
self.lat_dir = self.msg[3]
self.lon = self.msg[4]
self.lon_dir = self.msg[5]
self.gps_qual = self.msg[6]
self.num_sats = self.msg[7]
self.horizontal_dil = self.msg[8]
self.altitude = self.msg[9]
self.altitude_units = self.msg[10]
self.geo_sep = self.msg[11]
self.geo_sep_units = self.msg[12]
self.age_gps_data = self.msg[13]
self.ref_station_id = self.msg[14]

try:
self.latitude = int(self.lat[:2]) + float(self.lat[2:])/60.
if self.lat_dir == 'S':
self.latitude = -1.0 * self.latitude
#logger.debug("NMEA-0183 $$GGA lat: {}".format(self.latitude))
except Exception as e:
logger.warning("unable to interpret latitude from {0} and {1}, {2}".format(self.lat, self.lat_dir, e))

try:
self.longitude = int(self.lon[:3]) + float(self.lon[3:])/60.
if self.lon_dir == 'W':
self.longitude = -1.0 * self.longitude
#logger.debug("NMEA-0183 $$GGA lon: {}".format(self.longitude))
except Exception as e:
logger.warning("unable to interpret longitude from {0} and {1}, {2}".format(self.lon, self.lon_dir, e))




class Nmea0183GLL(Nmea0183Nav):

def __init__(self, data):
super(Nmea0183GLL, self).__init__(data)

self.msg = self.data.split(',')

self.lat = self.msg[1]
self.lat_dir = self.msg[2]
self.lon = self.msg[3]
self.lon_dir = self.msg[4]
self.timestamp = self.msg[5]
self.status = self.msg[6]

try:
self.latitude = int(self.lat[:2]) + float(self.lat[2:])/60.
if self.lat_dir == 'S':
self.latitude = -1.0 * self.latitude
#logger.debug("NMEA-0183 $$GLL lat: {}".format(self.latitude))
except Exception as e:
logger.warning("unable to interpret latitude from {0} and {1}, {2}".format(self.lat, self.lat_dir, e))

try:
self.longitude = int(self.lon[:3]) + float(self.lon[3:])/60.
if self.lon_dir == 'W':
self.longitude = -1.0 * self.longitude
#logger.debug("NMEA-0183 $$GLL lon: {}".format(self.longitude))
except Exception as e:
logger.warning("unable to interpret longitude from {0} and {1}, {2}".format(self.lon, self.lon_dir, e))

Loading

0 comments on commit ea7f7da

Please sign in to comment.