Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactored pprzlink python Ivy link interface to improve error reporting #117

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 17 additions & 12 deletions lib/v1.0/python/pprzlink/ivy.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,9 @@ def parse_pprz_msg(callback, ivy_msg):
msg_name = data.group(2)
payload = data.group(3)
# check which message class it is
msg_class, msg_name = messages_xml_map.find_msg_by_name(msg_name)
if msg_class is None:
try:
msg_class, msg_name = messages_xml_map.find_msg_by_name(msg_name)
except ValueError:
logger.error("Ignoring unknown message " + ivy_msg)
return

Expand Down Expand Up @@ -166,14 +167,16 @@ def send_raw_datalink(self, msg):
Send a PprzMessage of datalink msg_class embedded in RAW_DATALINK message

:param msg: PprzMessage
:returns: Number of clients the message sent to, None if msg was invalid
:returns: Number of clients the message was sent to
:raises: ValueError: if msg was invalid
:raises: RuntimeError: if the server is not running
"""
if not isinstance(msg, PprzMessage):
logger.error("Can only send PprzMessage")
return None
raise ValueError("Expected msg to be PprzMessage, got " + type(msg) + " instead.")

if "datalink" not in msg.msg_class:
logger.error("Message to embed in RAW_DATALINK needs to be of 'datalink' class")
return None
raise ValueError("Message to embed in RAW_DATALINK needs to be of 'datalink' class.")

raw = PprzMessage("ground", "RAW_DATALINK")
raw['ac_id'] = msg['ac_id']
raw['message'] = msg.to_csv()
Expand All @@ -185,16 +188,18 @@ def send(self, msg, ac_id=None):

:param msg: PprzMessage or simple string
:param ac_id: Needed if sending a PprzMessage of telemetry msg_class
:returns: Number of clients the message sent to, None if msg was invalid
:returns: Number of clients the message was sent to
:raises: ValueError: if msg was invalid or `ac_id` not provided for telemetry messages
:raises: RuntimeError: if the server is not running

"""
if not self._running:
logger.error("Ivy server not running!")
return
raise RuntimeError("Ivy server not running!")

if isinstance(msg, PprzMessage):
if "telemetry" in msg.msg_class:
if ac_id is None:
logger.error("ac_id needed to send telemetry message.")
return None
raise ValueError("ac_id needed to send telemetry message.")
else:
return IvySendMsg("%d %s %s" % (ac_id, msg.name, msg.payload_to_ivy_string()))
else:
Expand Down
93 changes: 45 additions & 48 deletions lib/v1.0/python/pprzlink/messages_xml_map.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from __future__ import absolute_import, print_function

import os
import logging

# if PAPARAZZI_HOME is set use $PAPARAZZI_HOME/var/messages.xml
# else assume this file is installed in var/lib/python/pprzlink
Expand All @@ -26,7 +25,6 @@
message_dictionary_name_id = {}
message_dictionary_broadcast = {}

logger = logging.getLogger("PprzLink")


class MessagesNotFound(Exception):
Expand Down Expand Up @@ -95,77 +93,76 @@ def _ensure_message_dictionary():

def find_msg_by_name(name):
_ensure_message_dictionary()
for msg_class in message_dictionary:
if name in message_dictionary[msg_class]:
for msg_class, msg_name in message_dictionary.items():
if name in msg_name:
#print("found msg name %s in class %s" % (name, msg_class))
return msg_class, name
logger.error("Error: msg_name %s not found." % name)
return None, None

raise ValueError("Error: msg_name %s not found." % name)


def get_msgs(msg_class):
_ensure_message_dictionary()
if msg_class in message_dictionary:
return message_dictionary[msg_class]
else:
logger.error("Error: msg_class %s not found." % msg_class)
return []
if msg_class not in message_dictionary:
raise ValueError("Error: msg_class %s not found." % msg_class)

return message_dictionary[msg_class]


def get_msg_name(msg_class, msg_id):
_ensure_message_dictionary()
if msg_class in message_dictionary:
if msg_id in message_dictionary_id_name[msg_class]:
return message_dictionary_id_name[msg_class][msg_id]
else:
logger.error("Error: msg_id %d not found in msg_class %s." % (msg_id, msg_class))
else:
logger.error("Error: msg_class %s not found." % msg_class)
return ""
if msg_class not in message_dictionary:
raise ValueError("Error: msg_class %s not found." % msg_class)

if msg_id not in message_dictionary_id_name[msg_class]:
raise ValueError("Error: msg_id %d not found in msg_class %s." % (msg_id, msg_class))

return message_dictionary_id_name[msg_class][msg_id]


def get_msg_fields(msg_class, msg_name):
_ensure_message_dictionary()
if msg_class in message_dictionary:
if msg_name in message_dictionary[msg_class]:
return message_dictionary[msg_class][msg_name]
else:
logger.error("Error: msg_name %s not found in msg_class %s." % (msg_name, msg_class))
else:
logger.error("Error: msg_class %s not found." % msg_class)
return []
if msg_class not in message_dictionary:
raise ValueError("Error: msg_class %s not found." % msg_class)

if msg_name not in message_dictionary[msg_class]:
raise ValueError("Error: msg_name %s not found in msg_class %s." % (msg_name, msg_class))

return message_dictionary[msg_class][msg_name]


def get_msg_id(msg_class, msg_name):
_ensure_message_dictionary()
try:
return message_dictionary_name_id[msg_class][msg_name]
except KeyError:
logger.error("Error: msg_name %s not found in msg_class %s." % (msg_name, msg_class))
return 0
if msg_class not in message_dictionary_name_id:
raise ValueError("Error: msg_class %s not found." % msg_class)

if msg_name not in message_dictionary_name_id[msg_class]:
raise ValueError("Error: msg_name %s not found in msg_class %s." % (msg_name, msg_class))

return message_dictionary_name_id[msg_class][msg_name]


def get_msg_fieldtypes(msg_class, msg_id):
_ensure_message_dictionary()
if msg_class in message_dictionary_types:
if msg_id in message_dictionary_types[msg_class]:
return message_dictionary_types[msg_class][msg_id]
else:
logger.error("Error: message with ID %d not found in msg_class %s." % (msg_id, msg_class))
else:
logger.error("Error: msg_class %s not found." % msg_class)
return []

if msg_class not in message_dictionary_types:
raise ValueError("Error: msg_class %s not found." % msg_class)

if msg_id not in message_dictionary_types[msg_class]:
raise ValueError("Error: message with ID %d not found in msg_class %s." % (msg_id, msg_class))

return message_dictionary_types[msg_class][msg_id]


def get_msg_fieldcoefs(msg_class, msg_id):
_ensure_message_dictionary()
if msg_class in message_dictionary_coefs:
if msg_id in message_dictionary_coefs[msg_class]:
return message_dictionary_coefs[msg_class][msg_id]
else:
logger.error("Error: message with ID %d not found in msg_class %s." % (msg_id, msg_class))
else:
logger.error("Error: msg_class %s not found." % msg_class)
return []
if msg_class not in message_dictionary_coefs:
raise ValueError("Error: msg_class %s not found." % msg_class)

if msg_id not in message_dictionary_coefs[msg_class]:
raise ValueError("Error: message with ID %d not found in msg_class %s." % (msg_id, msg_class))

return message_dictionary_coefs[msg_class][msg_id]


def test():
Expand Down
14 changes: 9 additions & 5 deletions lib/v1.0/python/pprzlink/serial.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,15 @@ def run(self):
c = self.ser.read(1)
if len(c) == 1:
if self.trans.parse_byte(c):
(sender_id, msg) = self.trans.unpack()
if self.verbose: # Can be replaced with the log level
logger.info("New incoming message '%s' from %i" % (msg.name, sender_id))
# Callback function on new message
self.callback(sender_id, msg)
try:
(sender_id, msg) = self.trans.unpack()
except ValueError as e:
logger.warning("Ignoring unknown message, %s" % e)
else:
if self.verbose: # Can be replaced with the log level
logger.info("New incoming message '%s' from %i" % (msg.name, sender_id))
# Callback function on new message
self.callback(sender_id, msg)

except StopIteration:
pass
Expand Down
14 changes: 9 additions & 5 deletions lib/v1.0/python/pprzlink/udp.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,15 @@ def run(self):
length = len(msg)
for c in msg:
if self.trans.parse_byte(c):
(sender_id, msg) = self.trans.unpack()
if self.verbose:
logger.info("New incoming message '%s' from %i (%s)" % (msg.name, sender_id, address))
# Callback function on new message
self.callback(sender_id, address, msg, length)
try:
(sender_id, msg) = self.trans.unpack()
except ValueError as e:
logger.warning("Ignoring unknown message, %s" % e)
else:
if self.verbose:
logger.info("New incoming message '%s' from %i (%s)" % (msg.name, sender_id, address))
# Callback function on new message
self.callback(sender_id, address, msg, length)
except socket.timeout:
pass

Expand Down
34 changes: 20 additions & 14 deletions lib/v2.0/python/pprzlink/ivy.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
else:
IVY_BUS = ""

logger = logging.getLogger("PpzLink")
logger = logging.getLogger("PprzLink")


class IvyMessagesInterface(object):
Expand Down Expand Up @@ -138,10 +138,12 @@ def parse_pprz_msg(callback, ivy_msg):
msg_name = data.group(2)
payload = data.group(3)
# check which message class it is
msg_class, msg_name = messages_xml_map.find_msg_by_name(msg_name)
if msg_class is None:
try:
msg_class, msg_name = messages_xml_map.find_msg_by_name(msg_name)
except ValueError:
logger.error("Ignoring unknown message " + ivy_msg)
return

msg = PprzMessage(msg_class, msg_name)
msg.ivy_string_to_payload(payload)
# pass non-telemetry messages with ac_id 0 or ac_id attrib value
Expand All @@ -167,14 +169,16 @@ def send_raw_datalink(self, msg):
Send a PprzMessage of datalink msg_class embedded in RAW_DATALINK message

:param msg: PprzMessage
:returns: Number of clients the message sent to, None if msg was invalid
:returns: Number of clients the message was sent to
:raises: ValueError: if msg was invalid
:raises: RuntimeError: if the server is not running
"""
if not isinstance(msg, PprzMessage):
logger.error("Can only send PprzMessage")
return None
raise ValueError("Expected msg to be PprzMessage, got " + type(msg) + " instead.")

if "datalink" not in msg.msg_class:
logger.error("Message to embed in RAW_DATALINK needs to be of 'datalink' class")
return None
raise ValueError("Message to embed in RAW_DATALINK needs to be of 'datalink' class.")

raw = PprzMessage("ground", "RAW_DATALINK")
raw['ac_id'] = msg['ac_id']
raw['message'] = msg.to_csv()
Expand All @@ -185,17 +189,19 @@ def send(self, msg, sender_id=None, receiver_id=None, component_id=None):
Send a message

:param msg: PprzMessage or simple string
:param sender_id: Needed if sending a PprzMessage of telemetry msg_class, otherwise message class might be used instead
:returns: Number of clients the message sent to, None if msg was invalid
:param sender_id: Needed if sending a PprzMessage of telemetry msg_class, otherwise
message class might be used instead
:returns: Number of clients the message was sent to
:raises: ValueError: if msg was invalid or `sender_id` not provided for telemetry messages
:raises: RuntimeError: if the server is not running
"""
if not self._running:
logger.error("Ivy server not running!")
return
raise RuntimeError("Ivy server not running!")

if isinstance(msg, PprzMessage):
if "telemetry" in msg.msg_class:
if sender_id is None:
logger.error("ac_id needed to send telemetry message.")
return None
raise ValueError("ac_id needed to send telemetry message.")
else:
return IvySendMsg("%d %s %s" % (sender_id, msg.name, msg.payload_to_ivy_string()))
else:
Expand Down
Loading