mirror of
https://gitee.com/mirrors_PX4/PX4-Autopilot.git
synced 2026-07-03 06:40:35 +08:00
orb: add optional queuing of messages
This adds two uORB API calls: - orb_advertise_queue - orb_advertise_multi_queue Both add a queue_size parameter to define a maximum number of buffered item. The existing orb calls use all a queue size of one and thus their behavior is unchanged. If a writer publishes too fast, the oldest elements from the queue are silently dropped. The returned timestamp is always the one from the latest message in the queue. Queue size can be set via ioctl during advertisement phase. After that it cannot be changed anymore.
This commit is contained in:
@@ -61,7 +61,8 @@ uORB::DeviceNode::SubscriberData *uORB::DeviceNode::filp_to_sd(device::file_t *
|
||||
return sd;
|
||||
}
|
||||
|
||||
uORB::DeviceNode::DeviceNode(const struct orb_metadata *meta, const char *name, const char *path, int priority) :
|
||||
uORB::DeviceNode::DeviceNode(const struct orb_metadata *meta, const char *name, const char *path,
|
||||
int priority, unsigned int queue_size) :
|
||||
VDev(name, path),
|
||||
_meta(meta),
|
||||
_data(nullptr),
|
||||
@@ -70,6 +71,7 @@ uORB::DeviceNode::DeviceNode(const struct orb_metadata *meta, const char *name,
|
||||
_publisher(0),
|
||||
_priority(priority),
|
||||
_published(false),
|
||||
_queue_size(queue_size),
|
||||
_subscriber_count(0)
|
||||
{
|
||||
// enable debug() calls
|
||||
@@ -198,13 +200,26 @@ uORB::DeviceNode::read(device::file_t *filp, char *buffer, size_t buflen)
|
||||
*/
|
||||
lock();
|
||||
|
||||
/* if the caller doesn't want the data, don't give it to them */
|
||||
if (nullptr != buffer) {
|
||||
memcpy(buffer, _data, _meta->o_size);
|
||||
if (_generation > sd->generation + _queue_size) {
|
||||
/* Reader is too far behind: some messages are lost */
|
||||
sd->generation = _generation - _queue_size;
|
||||
}
|
||||
|
||||
/* track the last generation that the file has seen */
|
||||
sd->generation = _generation;
|
||||
if (_generation == sd->generation && sd->generation > 0) {
|
||||
/* The subscriber already read the latest message, but nothing new was published yet.
|
||||
* Return the previous message
|
||||
*/
|
||||
--sd->generation;
|
||||
}
|
||||
|
||||
/* if the caller doesn't want the data, don't give it to them */
|
||||
if (nullptr != buffer) {
|
||||
memcpy(buffer, _data + (_meta->o_size * (sd->generation % _queue_size)), _meta->o_size);
|
||||
}
|
||||
|
||||
if (sd->generation < _generation) {
|
||||
++sd->generation;
|
||||
}
|
||||
|
||||
/* set priority */
|
||||
sd->priority = _priority;
|
||||
@@ -238,7 +253,7 @@ uORB::DeviceNode::write(device::file_t *filp, const char *buffer, size_t buflen)
|
||||
|
||||
/* re-check size */
|
||||
if (nullptr == _data) {
|
||||
_data = new uint8_t[_meta->o_size];
|
||||
_data = new uint8_t[_meta->o_size * _queue_size];
|
||||
}
|
||||
|
||||
unlock();
|
||||
@@ -255,10 +270,11 @@ uORB::DeviceNode::write(device::file_t *filp, const char *buffer, size_t buflen)
|
||||
}
|
||||
|
||||
lock();
|
||||
memcpy(_data, buffer, _meta->o_size);
|
||||
memcpy(_data + (_meta->o_size * (_generation % _queue_size)), buffer, _meta->o_size);
|
||||
|
||||
/* update the timestamp and generation count */
|
||||
_last_update = hrt_absolute_time();
|
||||
/* wrap-around happens after ~49 days, assuming a publisher rate of 1 kHz */
|
||||
_generation++;
|
||||
|
||||
_published = true;
|
||||
@@ -305,6 +321,11 @@ uORB::DeviceNode::ioctl(device::file_t *filp, int cmd, unsigned long arg)
|
||||
*(int *)arg = sd->priority;
|
||||
return PX4_OK;
|
||||
|
||||
case ORBIOCSETQUEUESIZE:
|
||||
//no need for locking here, since this is used only during the advertisement call,
|
||||
//and only one advertiser is allowed to open the DeviceNode at the same time.
|
||||
return update_queue_size(arg);
|
||||
|
||||
default:
|
||||
/* give it to the superclass */
|
||||
return VDev::ioctl(filp, cmd, arg);
|
||||
@@ -527,6 +548,20 @@ bool uORB::DeviceNode::is_published()
|
||||
return _published;
|
||||
}
|
||||
|
||||
int uORB::DeviceNode::update_queue_size(unsigned int queue_size)
|
||||
{
|
||||
if (_queue_size == queue_size) {
|
||||
return PX4_OK;
|
||||
}
|
||||
|
||||
if (_data || _queue_size > queue_size) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
_queue_size = queue_size;
|
||||
return PX4_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
int16_t uORB::DeviceNode::process_add_subscription(int32_t rateInHz)
|
||||
|
||||
Reference in New Issue
Block a user