コード例 #1
0
ssize_t
uORB::DeviceNode::read(struct file *filp, char *buffer, size_t buflen)
{
    SubscriberData *sd = (SubscriberData *)filp_to_sd(filp);

    /* if the object has not been written yet, return zero */
    if (_data == nullptr) {
        return 0;
    }

    /* if the caller's buffer is the wrong size, that's an error */
    if (buflen != _meta->o_size) {
        return -EIO;
    }

    /*
     * Perform an atomic copy & state update
     */
    irqstate_t flags = px4_enter_critical_section();

    if (_generation > sd->generation + _queue_size) {
        /* Reader is too far behind: some messages are lost */
        _lost_messages += _generation - (sd->generation + _queue_size);
        sd->generation = _generation - _queue_size;
    }

    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->set_priority(_priority);

    /*
     * Clear the flag that indicates that an update has been reported, as
     * we have just collected it.
     */
    sd->set_update_reported(false);

    px4_leave_critical_section(flags);

    return _meta->o_size;
}
コード例 #2
0
int
uORB::DeviceNode::open(struct file *filp)
{
    int ret;

    /* is this a publisher? */
    if (filp->f_oflags == O_WRONLY) {

        /* become the publisher if we can */
        lock();

        if (_publisher == 0) {
            _publisher = getpid();
            ret = OK;

        } else {
            ret = -EBUSY;
        }

        unlock();

        /* now complete the open */
        if (ret == OK) {
            ret = CDev::open(filp);

            /* open failed - not the publisher anymore */
            if (ret != OK) {
                _publisher = 0;
            }
        }

        return ret;
    }

    /* is this a new subscriber? */
    if (filp->f_oflags == O_RDONLY) {

        /* allocate subscriber data */
        SubscriberData *sd = new SubscriberData;

        if (nullptr == sd) {
            return -ENOMEM;
        }

        memset(sd, 0, sizeof(*sd));

        /* default to no pending update */
        sd->generation = _generation;

        /* set priority */
        sd->set_priority(_priority);

        filp->f_priv = (void *)sd;

        ret = CDev::open(filp);

        add_internal_subscriber();

        if (ret != OK) {
            delete sd;
        }

        return ret;
    }

    /* can only be pub or sub, not both */
    return -EINVAL;
}
コード例 #3
0
int
uORB::DeviceNode::ioctl(struct file *filp, int cmd, unsigned long arg)
{
    SubscriberData *sd = filp_to_sd(filp);

    switch (cmd) {
    case ORBIOCLASTUPDATE: {
        irqstate_t state = px4_enter_critical_section();
        *(hrt_abstime *)arg = _last_update;
        px4_leave_critical_section(state);
        return OK;
    }

    case ORBIOCUPDATED:
        *(bool *)arg = appears_updated(sd);
        return OK;

    case ORBIOCSETINTERVAL: {
        int ret = PX4_OK;
        lock();

        if (arg == 0) {
            if (sd->update_interval) {
                delete(sd->update_interval);
                sd->update_interval = nullptr;
            }

        } else {
            if (sd->update_interval) {
                sd->update_interval->interval = arg;

            } else {
                sd->update_interval = new UpdateIntervalData();

                if (sd->update_interval) {
                    memset(&sd->update_interval->update_call, 0, sizeof(hrt_call));
                    sd->update_interval->interval = arg;

                } else {
                    ret = -ENOMEM;
                }
            }
        }

        unlock();
        return ret;
    }

    case ORBIOCGADVERTISER:
        *(uintptr_t *)arg = (uintptr_t)this;
        return OK;

    case ORBIOCGPRIORITY:
        *(int *)arg = sd->priority();
        return 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);

    case ORBIOCGETINTERVAL:
        if (sd->update_interval) {
            *(unsigned *)arg = sd->update_interval->interval;

        } else {
            *(unsigned *)arg = 0;
        }

        return OK;

    default:
        /* give it to the superclass */
        return CDev::ioctl(filp, cmd, arg);
    }
}
コード例 #4
0
ファイル: uORBDeviceNode.cpp プロジェクト: igalloway/Firmware
int
uORB::DeviceNode::open(cdev::file_t *filp)
{
	int ret;

	/* is this a publisher? */
	if (FILE_FLAGS(filp) == PX4_F_WRONLY) {

		/* become the publisher if we can */
		lock();

		if (_publisher == 0) {
			_publisher = px4_getpid();
			ret = PX4_OK;

		} else {
			ret = -EBUSY;
		}

		unlock();

		/* now complete the open */
		if (ret == PX4_OK) {
			ret = CDev::open(filp);

			/* open failed - not the publisher anymore */
			if (ret != PX4_OK) {
				_publisher = 0;
			}
		}

		return ret;
	}

	/* is this a new subscriber? */
	if (FILE_FLAGS(filp) == PX4_F_RDONLY) {

		/* allocate subscriber data */
		SubscriberData *sd = new SubscriberData{};

		if (nullptr == sd) {
			return -ENOMEM;
		}

		/* If there were any previous publications, allow the subscriber to read them */
		sd->generation = _generation - (_queue_size < _generation ? _queue_size : _generation);

		/* set priority */
		sd->set_priority(_priority);

		FILE_PRIV(filp) = (void *)sd;

		ret = CDev::open(filp);

		add_internal_subscriber();

		if (ret != PX4_OK) {
			PX4_ERR("CDev::open failed");
			delete sd;
		}

		return ret;
	}

	if (FILE_FLAGS(filp) == 0) {
		return CDev::open(filp);
	}

	/* can only be pub or sub, not both */
	return -EINVAL;
}
コード例 #5
0
ファイル: uORBDeviceNode.cpp プロジェクト: igalloway/Firmware
int
uORB::DeviceNode::ioctl(cdev::file_t *filp, int cmd, unsigned long arg)
{
	SubscriberData *sd = filp_to_sd(filp);

	switch (cmd) {
	case ORBIOCLASTUPDATE: {
			ATOMIC_ENTER;
			*(hrt_abstime *)arg = _last_update;
			ATOMIC_LEAVE;
			return PX4_OK;
		}

	case ORBIOCUPDATED:
#ifndef __PX4_NUTTX
		lock();
#endif
		*(bool *)arg = appears_updated(sd);
#ifndef __PX4_NUTTX
		unlock();
#endif
		return PX4_OK;

	case ORBIOCSETINTERVAL: {
			int ret = PX4_OK;
			lock();

			if (arg == 0) {
				if (sd->update_interval) {
					delete (sd->update_interval);
					sd->update_interval = nullptr;
				}

			} else {
				if (sd->update_interval) {
					sd->update_interval->interval = arg;
#ifndef __PX4_NUTTX
					sd->update_interval->last_update = hrt_absolute_time();
#endif

				} else {
					sd->update_interval = new UpdateIntervalData();

					if (sd->update_interval) {
						memset(&sd->update_interval->update_call, 0, sizeof(hrt_call));
						sd->update_interval->interval = arg;
#ifndef __PX4_NUTTX
						sd->update_interval->last_update = hrt_absolute_time();
#endif

					} else {
						ret = -ENOMEM;
					}
				}
			}

			unlock();
			return ret;
		}

	case ORBIOCGADVERTISER:
		*(uintptr_t *)arg = (uintptr_t)this;
		return PX4_OK;

	case ORBIOCGPRIORITY:
		*(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);

	case ORBIOCGETINTERVAL:
		if (sd->update_interval) {
			*(unsigned *)arg = sd->update_interval->interval;

		} else {
			*(unsigned *)arg = 0;
		}

		return OK;

	case ORBIOCISPUBLISHED:
		*(unsigned long *)arg = _published;

		return OK;

	default:
		/* give it to the superclass */
		return CDev::ioctl(filp, cmd, arg);
	}
}