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

QoS - Expose the assert_liveliness API for Publishers and Nodes #313

Merged
merged 2 commits into from
May 3, 2019
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
9 changes: 9 additions & 0 deletions rclpy/rclpy/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -835,3 +835,12 @@ def count_subscribers(self, topic_name: str) -> int:
:return: the number of subscribers on the topic.
"""
return self._count_publishers_or_subscribers(topic_name, _rclpy.rclpy_count_subscribers)

def assert_liveliness(self) -> None:
"""
Manually assert that this Node is alive.

If the QoS Liveliness policy is set to RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_NODE, the
application must call this at least as often as ``QoSProfile.liveliness_lease_duration``.
"""
_rclpy.rclpy_assert_liveliness(self.node_handle)
9 changes: 9 additions & 0 deletions rclpy/rclpy/publisher.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,12 @@ def handle(self):

def destroy(self):
self.handle.destroy()

def assert_liveliness(self) -> None:
"""
Manually assert that this Publisher is alive.

If the QoS Liveliness policy is set to RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_TOPIC, the
application must call this at least as often as ``QoSProfile.liveliness_lease_duration``.
"""
_rclpy.rclpy_assert_liveliness(self.publisher_handle)
51 changes: 51 additions & 0 deletions rclpy/src/rclpy/_rclpy.c
Original file line number Diff line number Diff line change
Expand Up @@ -3604,6 +3604,53 @@ rclpy_get_rmw_qos_profile(PyObject * Py_UNUSED(self), PyObject * args)
return pyqos_profile;
}

/// Manually assert that an entity is alive.
/**
* When using RMW_QOS_POLICY_MANUAL_BY_*, the application must call this function at least as
* often as the qos policy liveliness_lease_duration.
* The passed entity can be a Publisher or a Node.
*
* Raises RuntimeError on failure to assert liveliness
* Raises TypeError if passed object is not a valid Publisher or Node
*
* \param[in] pyentity A capsule containing an rcl_node_t or rcl_publisher_t
* \return None
*/
static PyObject *
rclpy_assert_liveliness(PyObject * Py_UNUSED(self), PyObject * args)
{
PyObject * pyentity;

if (!PyArg_ParseTuple(args, "O", &pyentity)) {
return NULL;
}

if (PyCapsule_IsValid(pyentity, "rcl_node_t")) {
rcl_node_t * node = (rcl_node_t *)PyCapsule_GetPointer(pyentity, "rcl_node_t");
if (RCL_RET_OK != rcl_node_assert_liveliness(node)) {
PyErr_Format(PyExc_RuntimeError,
"Failed assert liveliness on the Node: %s", rcl_get_error_string().str);
rcl_reset_error();
return NULL;
}
} else if (PyCapsule_IsValid(pyentity, "rclpy_publisher_t")) {
rcl_publisher_t * publisher = (rcl_publisher_t *)PyCapsule_GetPointer(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This works because rcl_publisher_t is the first member of rclpy_publisher_t, but it would be nice to be more explicit about it

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't disagree - do we want to block merging for that? Or can we follow up afterwards?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll merge this one.

pyentity, "rclpy_publisher_t");
if (RCL_RET_OK != rcl_publisher_assert_liveliness(publisher)) {
PyErr_Format(PyExc_RuntimeError,
"Failed to assert liveliness on the Publisher: %s", rcl_get_error_string().str);
rcl_reset_error();
return NULL;
}
} else {
PyErr_Format(PyExc_TypeError,
"Passed capsule is not a valid Node or Publisher.");
return NULL;
}

Py_RETURN_NONE;
}

/// Destructor for a time point
void
_rclpy_destroy_time_point(PyObject * pycapsule)
Expand Down Expand Up @@ -4784,6 +4831,10 @@ static PyMethodDef rclpy_methods[] = {
"rclpy_get_rmw_qos_profile", rclpy_get_rmw_qos_profile, METH_VARARGS,
"Get QOS profile."
},
{
"rclpy_assert_liveliness", rclpy_assert_liveliness, METH_VARARGS,
"Assert the liveliness of an entity."
},

{
"rclpy_create_time_point", rclpy_create_time_point, METH_VARARGS,
Expand Down