nuttx-apps/system/uorb/uORB/uORB.c

325 lines
8.1 KiB
C
Raw Normal View History

/****************************************************************************
* apps/system/uorb/uORB/uORB.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <uORB/uORB.h>
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: orb_advsub_open
*
* Description:
* Open device node as advertiser / subscriber, regist node and save meta
* in driver for first user, set buffer number for advertisers.
*
* Input Parameters:
* meta The uORB metadata (usually from the ORB_ID() macro)
* flag The open flag.
* instance Instance number to open.
* queue_size Maximum number of buffered elements.
*
* Returned Value:
* fd on success, otherwise returns negative value and set errno.
****************************************************************************/
static int orb_advsub_open(FAR const struct orb_metadata *meta, int flags,
int instance, unsigned int queue_size)
{
char path[ORB_PATH_MAX];
int fd;
int ret;
int err;
snprintf(path, ORB_PATH_MAX, ORB_SENSOR_PATH"%s%d", meta->o_name,
instance);
/* Check existance before open */
flags |= O_CLOEXEC;
fd = open(path, flags);
if (fd < 0)
{
struct sensor_reginfo_s reginfo;
reginfo.path = path;
reginfo.esize = meta->o_size;
reginfo.nbuffer = queue_size;
reginfo.persist = !!(flags & SENSOR_PERSIST);
fd = open(ORB_USENSOR_PATH, O_WRONLY);
if (fd < 0)
{
return fd;
}
/* Register new device node */
ret = ioctl(fd, SNIOC_REGISTER, (unsigned long)(uintptr_t)&reginfo);
err = errno;
close(fd);
if (ret < 0 && err != EEXIST)
{
return ret;
}
fd = open(path, flags);
if (fd < 0)
{
return fd;
}
if (err != EEXIST)
{
ioctl(fd, SNIOC_SET_USERPRIV, (unsigned long)(uintptr_t)meta);
}
}
/* Only first advertiser can successfully set buffer number */
if (queue_size)
{
ioctl(fd, SNIOC_SET_BUFFER_NUMBER, (unsigned long)queue_size);
}
return fd;
}
static int
orb_advertise_multi_queue_flags(FAR const struct orb_metadata *meta,
FAR const void *data, FAR int *instance,
unsigned int queue_size, int flags)
{
int inst;
int fd;
/* Open the node as an advertiser */
inst = instance ? *instance : orb_group_count(meta);
fd = orb_advsub_open(meta, flags, inst, queue_size);
if (fd < 0)
{
uorberr("%s advertise failed (%i)", meta->o_name, fd);
return -1;
}
/* The advertiser may perform an initial publish to initialise the object */
if (data != NULL)
{
int ret;
ret = orb_publish_multi(fd, data, meta->o_size);
if (ret != meta->o_size)
{
uorberr("%s publish %d, expect %d",
meta->o_name, ret, meta->o_size);
close(fd);
return -1;
}
}
return fd;
}
/****************************************************************************
* Public Functions
****************************************************************************/
int orb_open(FAR const char *name, int instance, int flags)
{
char path[ORB_PATH_MAX];
snprintf(path, ORB_PATH_MAX, ORB_SENSOR_PATH"%s%d", name, instance);
return open(path, O_CLOEXEC | flags);
}
int orb_close(int fd)
{
return close(fd);
}
int orb_advertise_multi_queue(FAR const struct orb_metadata *meta,
FAR const void *data, FAR int *instance,
unsigned int queue_size)
{
return orb_advertise_multi_queue_flags(meta, data, instance,
queue_size, O_WRONLY);
}
int orb_advertise_multi_queue_persist(FAR const struct orb_metadata *meta,
FAR const void *data,
FAR int *instance,
unsigned int queue_size)
{
return orb_advertise_multi_queue_flags(meta, data, instance, queue_size,
O_WRONLY | SENSOR_PERSIST);
}
ssize_t orb_publish_multi(int fd, const void *data, size_t len)
{
return write(fd, data, len);
}
int orb_subscribe_multi(FAR const struct orb_metadata *meta,
unsigned instance)
{
return orb_advsub_open(meta, O_RDONLY, instance, 0);
}
ssize_t orb_copy_multi(int fd, FAR void *buffer, size_t len)
{
return read(fd, buffer, len);
}
int orb_get_state(int fd, FAR struct orb_state *state)
{
struct sensor_state_s tmp;
int ret;
if (!state)
{
return -EINVAL;
}
ret = ioctl(fd, SNIOC_GET_STATE, (unsigned long)(uintptr_t)&tmp);
if (ret < 0)
{
return ret;
}
state->max_frequency = tmp.min_interval ?
1000000 / tmp.min_interval : 0;
state->min_batch_interval = tmp.min_latency;
state->queue_size = tmp.nbuffer;
state->nsubscribers = tmp.nsubscribers;
state->generation = tmp.generation;
return ret;
}
int orb_check(int fd, FAR bool *updated)
{
return ioctl(fd, SNIOC_UPDATED, (unsigned long)(uintptr_t)updated);
}
int orb_ioctl(int fd, int cmd, unsigned long arg)
{
return ioctl(fd, cmd, arg);
}
int orb_set_interval(int fd, unsigned interval)
{
return ioctl(fd, SNIOC_SET_INTERVAL, (unsigned long)interval);
}
int orb_get_interval(int fd, FAR unsigned *interval)
{
struct sensor_state_s tmp;
int ret;
ret = ioctl(fd, SNIOC_GET_STATE, (unsigned long)(uintptr_t)&tmp);
if (ret < 0)
{
return ret;
}
*interval = tmp.min_interval;
return ret;
}
int orb_set_batch_interval(int fd, unsigned batch_interval)
{
return ioctl(fd, SNIOC_BATCH, (unsigned long)batch_interval);
}
int orb_get_batch_interval(int fd, FAR unsigned *batch_interval)
{
struct sensor_state_s tmp;
int ret;
ret = ioctl(fd, SNIOC_GET_STATE, (unsigned long)(uintptr_t)&tmp);
if (ret < 0)
{
return ret;
}
*batch_interval = tmp.min_latency;
return ret;
}
orb_abstime orb_absolute_time(void)
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return 1000000ull * ts.tv_sec + ts.tv_nsec / 1000;
}
int orb_exists(FAR const struct orb_metadata *meta, int instance)
{
struct sensor_state_s state;
char path[ORB_PATH_MAX];
int ret;
int fd;
snprintf(path, ORB_PATH_MAX, ORB_SENSOR_PATH"%s%d", meta->o_name,
instance);
fd = open(path, 0);
if (fd < 0)
{
return -1;
}
ret = ioctl(fd, SNIOC_GET_STATE, (unsigned long)(uintptr_t)&state);
close(fd);
if (ret < 0)
{
return -1;
}
return state.nadvertisers > 0 ? 0 : -1;
}
int orb_group_count(FAR const struct orb_metadata *meta)
{
unsigned instance = 0;
while (orb_exists(meta, instance) == 0)
{
++instance;
}
return instance;
}