mirror of
https://github.com/apache/nuttx.git
synced 2025-01-13 13:18:50 +08:00
sensor/gps: support gps driver model
Signed-off-by: dongjiuzhu1 <dongjiuzhu1@xiaomi.com>
This commit is contained in:
parent
e503f86256
commit
2945252b71
4 changed files with 991 additions and 0 deletions
|
@ -24,6 +24,13 @@ config SENSORS_RPMSG
|
|||
---help---
|
||||
Allow application to read or control remote sensor device by rpmsg.
|
||||
|
||||
config SENSORS_GPS
|
||||
bool "GPS Support"
|
||||
default n
|
||||
depends on GPSUTILS_MINMEA_LIB
|
||||
---help---
|
||||
Allow application to use gps by /dev/uorb/gps or /dev/ttyGPS
|
||||
|
||||
config SENSORS_WTGAHRS2
|
||||
bool "Wtgahrs2 Sensor Support"
|
||||
default n
|
||||
|
|
|
@ -32,6 +32,10 @@ ifeq ($(CONFIG_SENSORS_RPMSG),y)
|
|||
CSRCS += sensor_rpmsg.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_SENSORS_GPS),y)
|
||||
CSRCS += gps.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_SENSORS_WTGAHRS2),y)
|
||||
CSRCS += wtgahrs2.c
|
||||
endif
|
||||
|
|
747
drivers/sensors/gps.c
Normal file
747
drivers/sensors/gps.c
Normal file
|
@ -0,0 +1,747 @@
|
|||
/****************************************************************************
|
||||
* drivers/sensors/gps.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 <nuttx/config.h>
|
||||
|
||||
#include <nuttx/kmalloc.h>
|
||||
#include <nuttx/mm/circbuf.h>
|
||||
#include <nuttx/sensors/sensor.h>
|
||||
#include <nuttx/sensors/gps.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
#include <debug.h>
|
||||
#include <minmea/minmea.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define GPS_PATH_FMT "/dev/ttyGPS%d"
|
||||
|
||||
#define GPS_IDX 0
|
||||
#define GPS_SATELLITE_IDX 1
|
||||
#define GPS_MAX_IDX 2
|
||||
|
||||
#define GPS_RECV_BUFFERSIZE 2048
|
||||
#define GPS_PARSE_BUFFERSIZE 256
|
||||
|
||||
#define GPS_KNOT_TO_KMH 1.852f
|
||||
#define GPS_KMH_TO_MPS 3.6f
|
||||
|
||||
#define GPS_FLAG_GGA (1 << 0)
|
||||
#define GPS_FLAG_RMC (1 << 1)
|
||||
#define GPS_FLAG_MARK (GPS_FLAG_GGA | GPS_FLAG_RMC)
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
/* This structure describes gps sensor info */
|
||||
|
||||
struct gps_sensor_s
|
||||
{
|
||||
struct sensor_lowerhalf_s lower;
|
||||
FAR void *upper;
|
||||
};
|
||||
|
||||
/* This structure describes user info of gps */
|
||||
|
||||
struct gps_user_s
|
||||
{
|
||||
FAR struct pollfd *fds;
|
||||
size_t pos;
|
||||
};
|
||||
|
||||
/* This structure describes the state of the upper half driver */
|
||||
|
||||
struct gps_upperhalf_s
|
||||
{
|
||||
struct gps_sensor_s dev[GPS_MAX_IDX];
|
||||
FAR struct gps_lowerhalf_s *lower;
|
||||
uint8_t crefs;
|
||||
uint8_t flags;
|
||||
mutex_t lock;
|
||||
sem_t buffersem;
|
||||
size_t parsenext;
|
||||
char parsebuffer[GPS_PARSE_BUFFERSIZE];
|
||||
struct circbuf_s buffer;
|
||||
struct sensor_gps gps;
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
static int gps_activate(FAR struct sensor_lowerhalf_s *lower,
|
||||
FAR struct file *filep, bool enable);
|
||||
static int gps_set_interval(FAR struct sensor_lowerhalf_s *lower,
|
||||
FAR struct file *filep,
|
||||
FAR unsigned long *interval);
|
||||
static int gps_control(FAR struct sensor_lowerhalf_s *lower,
|
||||
FAR struct file *filep, int cmd, unsigned long arg);
|
||||
|
||||
static int gps_open(FAR struct file *filep);
|
||||
static int gps_close(FAR struct file *filep);
|
||||
static ssize_t gps_read(FAR struct file *filep, FAR char *buffer,
|
||||
size_t buflen);
|
||||
static ssize_t gps_write(FAR struct file *filep,
|
||||
FAR const char *buffer, size_t buflen);
|
||||
static int gps_ioctl(FAR struct file *filep, int cmd,
|
||||
unsigned long arg);
|
||||
static int gps_poll(FAR struct file *filep, FAR struct pollfd *fds,
|
||||
bool setup);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static const struct sensor_ops_s g_gps_sensor_ops =
|
||||
{
|
||||
.activate = gps_activate,
|
||||
.set_interval = gps_set_interval,
|
||||
.control = gps_control,
|
||||
};
|
||||
|
||||
static const struct file_operations g_gps_fops =
|
||||
{
|
||||
gps_open, /* open */
|
||||
gps_close, /* close */
|
||||
gps_read, /* read */
|
||||
gps_write, /* write */
|
||||
NULL, /* seek */
|
||||
gps_ioctl, /* ioctl */
|
||||
NULL, /* mmap */
|
||||
NULL, /* truncate */
|
||||
gps_poll /* poll */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
static int gps_activate(FAR struct sensor_lowerhalf_s *lower,
|
||||
FAR struct file *filep, bool enable)
|
||||
{
|
||||
FAR struct gps_sensor_s *dev = (FAR struct gps_sensor_s *)lower;
|
||||
FAR struct gps_upperhalf_s *upper = dev->upper;
|
||||
int ret = OK;
|
||||
|
||||
nxmutex_lock(&upper->lock);
|
||||
if ((upper->crefs == 0 && enable) || (upper->crefs == 1 && !enable))
|
||||
{
|
||||
ret = upper->lower->ops->activate(upper->lower, filep, enable);
|
||||
if (ret >= 0)
|
||||
{
|
||||
upper->crefs += enable ? 1 : -1;
|
||||
}
|
||||
}
|
||||
|
||||
nxmutex_unlock(&upper->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int gps_set_interval(FAR struct sensor_lowerhalf_s *lower,
|
||||
FAR struct file *filep,
|
||||
FAR unsigned long *interval)
|
||||
{
|
||||
FAR struct gps_sensor_s *dev = (FAR struct gps_sensor_s *)lower;
|
||||
FAR struct gps_upperhalf_s *upper = dev->upper;
|
||||
|
||||
if (upper->lower->ops->set_interval == NULL)
|
||||
{
|
||||
return -ENOTTY;
|
||||
}
|
||||
|
||||
return upper->lower->ops->set_interval(upper->lower, filep, interval);
|
||||
}
|
||||
|
||||
static int gps_control(FAR struct sensor_lowerhalf_s *lower,
|
||||
FAR struct file *filep, int cmd, unsigned long arg)
|
||||
{
|
||||
FAR struct gps_sensor_s *dev = (FAR struct gps_sensor_s *)lower;
|
||||
FAR struct gps_upperhalf_s *upper = dev->upper;
|
||||
|
||||
if (upper->lower->ops->control == NULL)
|
||||
{
|
||||
return -ENOTTY;
|
||||
}
|
||||
|
||||
return upper->lower->ops->control(upper->lower, filep, cmd, arg);
|
||||
}
|
||||
|
||||
static int gps_open(FAR struct file *filep)
|
||||
{
|
||||
FAR struct gps_upperhalf_s *upper;
|
||||
FAR struct gps_user_s *user;
|
||||
int ret = OK;
|
||||
|
||||
DEBUGASSERT(filep != NULL && filep->f_inode != NULL);
|
||||
upper = filep->f_inode->i_private;
|
||||
|
||||
user = kmm_zalloc(sizeof(struct gps_user_s));
|
||||
if (user == NULL)
|
||||
{
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
nxmutex_lock(&upper->lock);
|
||||
if (upper->crefs >= 255)
|
||||
{
|
||||
ret = -EMFILE;
|
||||
kmm_free(user);
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (upper->crefs == 0)
|
||||
{
|
||||
ret = upper->lower->ops->activate(upper->lower, filep, true);
|
||||
if (ret < 0)
|
||||
{
|
||||
kmm_free(user);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
upper->crefs++;
|
||||
}
|
||||
|
||||
filep->f_priv = user;
|
||||
user->pos = upper->buffer.head;
|
||||
|
||||
out:
|
||||
nxmutex_unlock(&upper->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int gps_close(FAR struct file *filep)
|
||||
{
|
||||
FAR struct gps_upperhalf_s *upper;
|
||||
FAR struct gps_user_s *user;
|
||||
int ret = OK;
|
||||
|
||||
DEBUGASSERT(filep != NULL && filep->f_inode != NULL && filep->f_priv);
|
||||
upper = filep->f_inode->i_private;
|
||||
user = filep->f_priv;
|
||||
|
||||
nxmutex_lock(&upper->lock);
|
||||
if (upper->crefs > 0)
|
||||
{
|
||||
if (upper->crefs == 1)
|
||||
{
|
||||
ret = upper->lower->ops->activate(upper->lower, filep, false);
|
||||
if (ret < 0)
|
||||
{
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
upper->crefs--;
|
||||
}
|
||||
|
||||
kmm_free(user);
|
||||
|
||||
out:
|
||||
nxmutex_unlock(&upper->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t gps_read(FAR struct file *filep, FAR char *buffer,
|
||||
size_t buflen)
|
||||
{
|
||||
FAR struct gps_upperhalf_s *upper;
|
||||
FAR struct gps_user_s *user;
|
||||
ssize_t ret;
|
||||
|
||||
if (buffer == NULL || buflen == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEBUGASSERT(filep != NULL && filep->f_inode != NULL);
|
||||
upper = filep->f_inode->i_private;
|
||||
user = filep->f_priv;
|
||||
|
||||
nxmutex_lock(&upper->lock);
|
||||
if (user->pos < upper->buffer.tail)
|
||||
{
|
||||
user->pos = upper->buffer.tail;
|
||||
}
|
||||
|
||||
check:
|
||||
if (upper->buffer.head - user->pos == 0)
|
||||
{
|
||||
if (filep->f_oflags & O_NONBLOCK)
|
||||
{
|
||||
ret = -EAGAIN;
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
{
|
||||
nxmutex_unlock(&upper->lock);
|
||||
ret = nxsem_wait_uninterruptible(&upper->buffersem);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
nxmutex_lock(&upper->lock);
|
||||
goto check;
|
||||
}
|
||||
}
|
||||
|
||||
ret = circbuf_peekat(&upper->buffer, user->pos,
|
||||
buffer, buflen);
|
||||
user->pos += ret;
|
||||
|
||||
out:
|
||||
nxmutex_unlock(&upper->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t gps_write(FAR struct file *filep, FAR const char *buffer,
|
||||
size_t buflen)
|
||||
{
|
||||
FAR struct gps_upperhalf_s *upper;
|
||||
int ret = -ENOTSUP;
|
||||
|
||||
DEBUGASSERT(filep != NULL && filep->f_inode != NULL);
|
||||
upper = filep->f_inode->i_private;
|
||||
|
||||
nxmutex_lock(&upper->lock);
|
||||
if (upper->lower->ops->inject_data != NULL)
|
||||
{
|
||||
ret = upper->lower->ops->inject_data(upper->lower, filep,
|
||||
buffer, buflen);
|
||||
}
|
||||
|
||||
nxmutex_unlock(&upper->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int gps_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
||||
{
|
||||
FAR struct gps_upperhalf_s *upper;
|
||||
int ret = -ENOTTY;
|
||||
|
||||
DEBUGASSERT(filep != NULL && filep->f_inode != NULL);
|
||||
upper = filep->f_inode->i_private;
|
||||
|
||||
nxmutex_lock(&upper->lock);
|
||||
if (cmd == SNIOC_SET_INTERVAL)
|
||||
{
|
||||
if (upper->lower->ops->set_interval != NULL)
|
||||
{
|
||||
ret = upper->lower->ops->set_interval(upper->lower, filep,
|
||||
(FAR unsigned long *)(uintptr_t)arg);
|
||||
}
|
||||
}
|
||||
else if (upper->lower->ops->control != NULL)
|
||||
{
|
||||
ret = upper->lower->ops->control(upper->lower, filep, cmd, arg);
|
||||
}
|
||||
|
||||
nxmutex_unlock(&upper->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int gps_poll(FAR struct file *filep, FAR struct pollfd *fds,
|
||||
bool setup)
|
||||
{
|
||||
FAR struct gps_upperhalf_s *upper;
|
||||
FAR struct gps_user_s *user;
|
||||
ssize_t ret = OK;
|
||||
|
||||
DEBUGASSERT(filep != NULL && filep->f_inode != NULL);
|
||||
upper = filep->f_inode->i_private;
|
||||
user = filep->f_priv;
|
||||
|
||||
nxmutex_lock(&upper->lock);
|
||||
if (setup)
|
||||
{
|
||||
if (user->fds)
|
||||
{
|
||||
ret = -ENOSPC;
|
||||
goto out;
|
||||
}
|
||||
|
||||
user->fds = fds;
|
||||
fds->priv = filep;
|
||||
if (upper->buffer.head > user->pos)
|
||||
{
|
||||
poll_notify(&user->fds, 1, POLLIN);
|
||||
}
|
||||
}
|
||||
else if (user->fds)
|
||||
{
|
||||
user->fds = NULL;
|
||||
fds->priv = NULL;
|
||||
}
|
||||
|
||||
out:
|
||||
nxmutex_unlock(&upper->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void gps_init_data(FAR struct sensor_gps *gps)
|
||||
{
|
||||
gps->timestamp = ULONG_MAX;
|
||||
gps->time_utc = ULONG_MAX;
|
||||
gps->latitude = NAN;
|
||||
gps->longitude = NAN;
|
||||
gps->altitude = NAN;
|
||||
gps->altitude_ellipsoid = NAN;
|
||||
gps->eph = NAN;
|
||||
gps->epv = NAN;
|
||||
gps->hdop = NAN;
|
||||
gps->pdop = NAN;
|
||||
gps->vdop = NAN;
|
||||
gps->ground_speed = NAN;
|
||||
gps->course = NAN;
|
||||
gps->satellites_used = UINT_MAX;
|
||||
}
|
||||
|
||||
static void gps_parse_nmea(FAR struct gps_upperhalf_s *upper,
|
||||
FAR const char *nmea)
|
||||
{
|
||||
FAR struct sensor_lowerhalf_s *lower;
|
||||
|
||||
switch (minmea_sentence_id(nmea, false))
|
||||
{
|
||||
case MINMEA_SENTENCE_GGA:
|
||||
{
|
||||
struct minmea_sentence_gga frame;
|
||||
|
||||
if (minmea_parse_gga(&frame, nmea))
|
||||
{
|
||||
upper->gps.altitude = minmea_tofloat(&frame.altitude);
|
||||
upper->gps.altitude_ellipsoid =
|
||||
minmea_tofloat(&frame.height);
|
||||
upper->gps.hdop = minmea_tofloat(&frame.hdop);
|
||||
upper->gps.satellites_used = frame.satellites_tracked;
|
||||
upper->flags |= GPS_FLAG_GGA;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case MINMEA_SENTENCE_RMC:
|
||||
{
|
||||
struct minmea_sentence_rmc frame;
|
||||
struct tm t;
|
||||
|
||||
if (minmea_parse_rmc(&frame, nmea))
|
||||
{
|
||||
upper->gps.timestamp = sensor_get_timestamp();
|
||||
memset(&t, 0, sizeof(t));
|
||||
t.tm_sec = frame.time.seconds;
|
||||
t.tm_min = frame.time.minutes;
|
||||
t.tm_hour = frame.time.hours;
|
||||
t.tm_mday = frame.date.day;
|
||||
t.tm_mon = frame.date.month - 1;
|
||||
t.tm_year = frame.date.year + 2000 - 1900;
|
||||
t.tm_isdst = 0;
|
||||
upper->gps.time_utc = mktime(&t);
|
||||
upper->gps.latitude = minmea_tocoord(&frame.latitude);
|
||||
upper->gps.longitude = minmea_tocoord(&frame.longitude);
|
||||
upper->gps.ground_speed = minmea_tofloat(&frame.speed) *
|
||||
GPS_KNOT_TO_KMH / GPS_KMH_TO_MPS;
|
||||
upper->gps.course = minmea_tofloat(&frame.course);
|
||||
if (frame.valid)
|
||||
{
|
||||
upper->flags |= GPS_FLAG_RMC;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case MINMEA_SENTENCE_GST:
|
||||
{
|
||||
struct minmea_sentence_gst frame;
|
||||
float lat_err;
|
||||
float lon_err;
|
||||
|
||||
if (minmea_parse_gst(&frame, nmea))
|
||||
{
|
||||
lat_err = minmea_tofloat(
|
||||
&frame.latitude_error_deviation);
|
||||
lat_err *= lat_err;
|
||||
lon_err = minmea_tofloat(
|
||||
&frame.longitude_error_deviation);
|
||||
lon_err *= lon_err;
|
||||
upper->gps.eph = sqrtf(lat_err + lon_err);
|
||||
upper->gps.epv = minmea_tofloat(
|
||||
&frame.altitude_error_deviation);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case MINMEA_SENTENCE_GSV:
|
||||
{
|
||||
struct minmea_sentence_gsv frame;
|
||||
struct sensor_gps_satellite satellite;
|
||||
|
||||
memset(&satellite, 0, sizeof(satellite));
|
||||
if (minmea_parse_gsv(&frame, nmea))
|
||||
{
|
||||
satellite.timestamp = sensor_get_timestamp();
|
||||
satellite.count = frame.total_msgs;
|
||||
satellite.satellites = frame.total_sats;
|
||||
memcpy(satellite.info, frame.sats,
|
||||
sizeof(satellite.info[0]) * 4);
|
||||
lower = &upper->dev[GPS_SATELLITE_IDX].lower;
|
||||
lower->push_event(lower->priv, &satellite,
|
||||
sizeof(satellite));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (GPS_FLAG_MARK == upper->flags)
|
||||
{
|
||||
upper->flags &= ~GPS_FLAG_MARK;
|
||||
lower = &upper->dev[GPS_IDX].lower;
|
||||
lower->push_event(lower->priv, &upper->gps, sizeof(upper->gps));
|
||||
gps_init_data(&upper->gps);
|
||||
}
|
||||
}
|
||||
|
||||
static void gps_parse(FAR struct gps_upperhalf_s *upper,
|
||||
FAR const char *buffer, size_t bytes)
|
||||
{
|
||||
bool newline = upper->parsenext != 0;
|
||||
|
||||
for (; bytes > 0; buffer++, bytes--)
|
||||
{
|
||||
if (*buffer == '$')
|
||||
{
|
||||
newline = true;
|
||||
}
|
||||
|
||||
if (newline)
|
||||
{
|
||||
if (*buffer != '\r' && *buffer != '\n')
|
||||
{
|
||||
upper->parsebuffer[upper->parsenext++] = *buffer;
|
||||
continue;
|
||||
}
|
||||
|
||||
upper->parsebuffer[upper->parsenext] = '\0';
|
||||
gps_parse_nmea(upper, upper->parsebuffer);
|
||||
upper->parsenext = 0;
|
||||
newline = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void gps_push_data(FAR void *priv, FAR const void *data,
|
||||
size_t bytes, bool is_nmea)
|
||||
{
|
||||
FAR struct gps_upperhalf_s *upper = priv;
|
||||
int semcount;
|
||||
|
||||
if (data == NULL || bytes == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
nxmutex_lock(&upper->lock);
|
||||
if (is_nmea)
|
||||
{
|
||||
gps_parse(upper, data, bytes);
|
||||
}
|
||||
|
||||
circbuf_overwrite(&upper->buffer, data, bytes);
|
||||
nxmutex_unlock(&upper->lock);
|
||||
|
||||
nxsem_get_value(&upper->buffersem, &semcount);
|
||||
while (semcount++ <= 0)
|
||||
{
|
||||
nxsem_post(&upper->buffersem);
|
||||
}
|
||||
}
|
||||
|
||||
static void gps_push_event(FAR void *priv, FAR const void *data,
|
||||
size_t bytes, int type)
|
||||
{
|
||||
FAR struct gps_upperhalf_s *upper = priv;
|
||||
FAR struct sensor_lowerhalf_s *lower;
|
||||
|
||||
if (data == NULL || bytes == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
nxmutex_lock(&upper->lock);
|
||||
if (type == SENSOR_TYPE_GPS)
|
||||
{
|
||||
lower = &upper->dev[GPS_IDX].lower;
|
||||
lower->push_event(lower->priv, data, bytes);
|
||||
}
|
||||
else if (type == SENSOR_TYPE_GPS_SATELLITE)
|
||||
{
|
||||
lower = &upper->dev[GPS_SATELLITE_IDX].lower;
|
||||
lower->push_event(lower->priv, data, bytes);
|
||||
}
|
||||
|
||||
nxmutex_unlock(&upper->lock);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: gps_register
|
||||
*
|
||||
* Description:
|
||||
* This function binds an instance of a "lower half" gps driver with the
|
||||
* "upper half" gps device and registers that device so that can be used
|
||||
* by application code.
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - A pointer to an instance of lower half gps driver. This
|
||||
* instance is bound to the gps driver and must persist as long
|
||||
* as the driver persists.
|
||||
* devno - The user specifies which device of this type, from 0. If the
|
||||
* devno alerady exists, -EEXIST will be returned.
|
||||
* nbuffer - The number of events that the circular buffer can hold.
|
||||
*
|
||||
* Returned Value:
|
||||
* OK if the driver was successfully register; A negated errno value is
|
||||
* returned on any failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int gps_register(FAR struct gps_lowerhalf_s *lower, int devno,
|
||||
uint32_t nbuffer)
|
||||
{
|
||||
FAR struct gps_upperhalf_s *upper;
|
||||
FAR struct gps_sensor_s *dev;
|
||||
char path[PATH_MAX];
|
||||
int ret;
|
||||
|
||||
upper = kmm_zalloc(sizeof(struct gps_upperhalf_s));
|
||||
if (upper == NULL)
|
||||
{
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
lower->push_data = gps_push_data;
|
||||
lower->push_event = gps_push_event;
|
||||
lower->priv = upper;
|
||||
upper->lower = lower;
|
||||
|
||||
nxmutex_init(&upper->lock);
|
||||
nxsem_init(&upper->buffersem, 0, 0);
|
||||
gps_init_data(&upper->gps);
|
||||
|
||||
/* GPS register */
|
||||
|
||||
dev = &upper->dev[GPS_IDX];
|
||||
dev->lower.ops = &g_gps_sensor_ops;
|
||||
dev->lower.type = SENSOR_TYPE_GPS;
|
||||
dev->lower.nbuffer = nbuffer;
|
||||
dev->upper = upper;
|
||||
ret = sensor_register(&dev->lower, devno);
|
||||
if (ret < 0)
|
||||
{
|
||||
goto gps_err;
|
||||
}
|
||||
|
||||
/* Satellite register */
|
||||
|
||||
dev = &upper->dev[GPS_SATELLITE_IDX];
|
||||
dev->lower.ops = &g_gps_sensor_ops;
|
||||
dev->lower.type = SENSOR_TYPE_GPS_SATELLITE;
|
||||
dev->lower.nbuffer = nbuffer;
|
||||
dev->upper = upper;
|
||||
ret = sensor_register(&dev->lower, devno);
|
||||
if (ret < 0)
|
||||
{
|
||||
goto satellite_err;
|
||||
}
|
||||
|
||||
ret = circbuf_init(&upper->buffer, NULL, GPS_RECV_BUFFERSIZE);
|
||||
if (ret < 0)
|
||||
{
|
||||
goto circ_err;
|
||||
}
|
||||
|
||||
snprintf(path, PATH_MAX, GPS_PATH_FMT, devno);
|
||||
ret = register_driver(path, &g_gps_fops, 0666, upper);
|
||||
if (ret < 0)
|
||||
{
|
||||
goto driver_err;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
driver_err:
|
||||
circbuf_uninit(&upper->buffer);
|
||||
circ_err:
|
||||
sensor_unregister(&upper->dev[GPS_SATELLITE_IDX].lower, devno);
|
||||
satellite_err:
|
||||
sensor_unregister(&upper->dev[GPS_IDX].lower, devno);
|
||||
gps_err:
|
||||
nxmutex_destroy(&upper->lock);
|
||||
nxsem_destroy(&upper->buffersem);
|
||||
kmm_free(upper);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: gps_unregister
|
||||
*
|
||||
* Description:
|
||||
* This function unregisters character node and releases all resource from
|
||||
* upper half driver. This API corresponds to the gps_register.
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - A pointer to an instance of lower half gps driver. This
|
||||
* instance is bound to the gps driver and must persists as long
|
||||
* as the driver persists.
|
||||
* devno - The user specifies which device of this type, from 0.
|
||||
****************************************************************************/
|
||||
|
||||
void gps_unregister(FAR struct gps_lowerhalf_s *lower, int devno)
|
||||
{
|
||||
FAR struct gps_upperhalf_s *upper = lower->priv;
|
||||
char path[PATH_MAX];
|
||||
|
||||
sensor_unregister(&upper->dev[GPS_IDX].lower, devno);
|
||||
sensor_unregister(&upper->dev[GPS_SATELLITE_IDX].lower, devno);
|
||||
snprintf(path, PATH_MAX, GPS_PATH_FMT, devno);
|
||||
unregister_driver(path);
|
||||
nxsem_destroy(&upper->buffersem);
|
||||
circbuf_uninit(&upper->buffer);
|
||||
kmm_free(upper);
|
||||
}
|
233
include/nuttx/sensors/gps.h
Normal file
233
include/nuttx/sensors/gps.h
Normal file
|
@ -0,0 +1,233 @@
|
|||
/****************************************************************************
|
||||
* include/nuttx/sensors/gps.h
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __INCLUDE_NUTTX_SENSORS_GPS_H
|
||||
#define __INCLUDE_NUTTX_SENSORS_GPS_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/fs/fs.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
|
||||
/* The gps lower half driver interface */
|
||||
|
||||
struct gps_lowerhalf_s;
|
||||
struct gps_ops_s
|
||||
{
|
||||
/**************************************************************************
|
||||
* Name: activate
|
||||
*
|
||||
* Description:
|
||||
* Enable or disable gps device. when enable gps, gps will
|
||||
* work in current mode(if not set, use default mode). when disable
|
||||
* gps, it will disable sense path and stop work.
|
||||
*
|
||||
* Input Parameters:
|
||||
* lower - The instance of lower half gps driver
|
||||
* filep - The pointer of file, represents each user using the gps.
|
||||
* enable - true(enable) and false(disable)
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) or positive on success; a negated errno value on failure.
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
CODE int (*activate)(FAR struct gps_lowerhalf_s *lower,
|
||||
FAR struct file *filep, bool enable);
|
||||
|
||||
/**************************************************************************
|
||||
* Name: set_interval
|
||||
*
|
||||
* Description:
|
||||
* Set the gps output data period in microseconds for a given gps.
|
||||
* If *period_us > max_delay it will be truncated to max_delay and if
|
||||
* *period_us < min_delay it will be replaced by min_delay.
|
||||
*
|
||||
* The lower-half can update update *period_us to reflect the actual
|
||||
* period in case the value is rounded up to nearest supported value.
|
||||
*
|
||||
* Before changing the interval, you need to push the prepared data to
|
||||
* ensure that they are not lost.
|
||||
*
|
||||
* Input Parameters:
|
||||
* lower - The instance of lower half gps driver.
|
||||
* filep - The pointer of file, represents each user using gps.
|
||||
* period_us - the time between samples, in us, it may be overwrite by
|
||||
* lower half driver.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) or positive on success; a negated errno value on failure.
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
CODE int (*set_interval)(FAR struct gps_lowerhalf_s *lower,
|
||||
FAR struct file *filep,
|
||||
FAR unsigned long *period_us);
|
||||
|
||||
/**************************************************************************
|
||||
* Name: control
|
||||
*
|
||||
* With this method, the user can set some special config for the gps,
|
||||
* such as changing the custom mode, setting the custom resolution, reset,
|
||||
* etc, which are all parsed and implemented by lower half driver.
|
||||
*
|
||||
* Input Parameters:
|
||||
* lower - The instance of lower half gps driver.
|
||||
* filep - The pointer of file, represents each user using gps.
|
||||
* cmd - The special cmd for gps.
|
||||
* arg - The parameters associated with cmd.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) on success; a negated errno value on failure.
|
||||
* -ENOTTY - The cmd don't support.
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
CODE int (*control)(FAR struct gps_lowerhalf_s *lower,
|
||||
FAR struct file *filep,
|
||||
int cmd, unsigned long arg);
|
||||
|
||||
/**************************************************************************
|
||||
* Name: inject_data
|
||||
*
|
||||
* With this method, the user can inject some data to gps driver,
|
||||
* such as inject lto data, utc data, etc.
|
||||
*
|
||||
* Input Parameters:
|
||||
* lower - The instance of lower half gps driver.
|
||||
* filep - The pointer of file, represents each user using gps.
|
||||
* buffer - The buffer of inject data.
|
||||
* buflen - The length of buffer.
|
||||
*
|
||||
* Returned Value:
|
||||
* The written bytes returned on success;
|
||||
* A negated errno value on failure.
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
CODE ssize_t (*inject_data)(FAR struct gps_lowerhalf_s *lower,
|
||||
FAR struct file *filep,
|
||||
FAR const void *buffer, size_t buflen);
|
||||
};
|
||||
|
||||
/* This structure is the generic form of state structure used by lower half
|
||||
* gps driver.
|
||||
*/
|
||||
|
||||
typedef CODE void (*gps_push_data_t)(FAR void *priv, FAR const void *data,
|
||||
size_t bytes, bool is_nmea);
|
||||
|
||||
typedef CODE void (*gps_push_event_t)(FAR void *priv, FAR const void *data,
|
||||
size_t bytes, int type);
|
||||
|
||||
struct gps_lowerhalf_s
|
||||
{
|
||||
/* The lower half gps driver operations */
|
||||
|
||||
FAR const struct gps_ops_s *ops;
|
||||
|
||||
/* Lower half driver pushes raw data by calling this function.
|
||||
* It is provided by upper half driver to lower half driver,
|
||||
* if paramenter is_nmea is true, the data includes nmea message.
|
||||
*/
|
||||
|
||||
gps_push_data_t push_data;
|
||||
|
||||
/* Lower half driver pushes gps event by calling this function.
|
||||
* It is provided by upper half driver to lower half driver.
|
||||
* lower half can use type to description the data type, eg:
|
||||
* SENSOR_TYPE_GPS, SENSOR_TYPE_GPS_SATELLITE
|
||||
*/
|
||||
|
||||
gps_push_event_t push_event;
|
||||
|
||||
/* The private opaque pointer to be passed to upper-layer during callback */
|
||||
|
||||
FAR void *priv;
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define EXTERN extern "C"
|
||||
extern "C"
|
||||
{
|
||||
#else
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: gps_register
|
||||
*
|
||||
* Description:
|
||||
* This function binds an instance of a "lower half" gps driver with the
|
||||
* "upper half" gps device and registers that device so that can be used
|
||||
* by application code.
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - A pointer to an instance of lower half gps driver. This
|
||||
* instance is bound to the gps driver and must persist as long
|
||||
* as the driver persists.
|
||||
* devno - The user specifies which device of this type, from 0. If the
|
||||
* devno alerady exists, -EEXIST will be returned.
|
||||
* nbuffer - The number of events that the circular buffer can hold.
|
||||
*
|
||||
* Returned Value:
|
||||
* OK if the driver was successfully register; A negated errno value is
|
||||
* returned on any failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int gps_register(FAR struct gps_lowerhalf_s *dev, int devno,
|
||||
uint32_t nbuffer);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: gps_unregister
|
||||
*
|
||||
* Description:
|
||||
* This function unregisters character node and releases all resource from
|
||||
* upper half driver. This API corresponds to the gps_register.
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - A pointer to an instance of lower half gps driver. This
|
||||
* instance is bound to the gps driver and must persists as long
|
||||
* as the driver persists.
|
||||
* devno - The user specifies which device of this type, from 0.
|
||||
****************************************************************************/
|
||||
|
||||
void gps_unregister(FAR struct gps_lowerhalf_s *dev, int devno);
|
||||
|
||||
#undef EXTERN
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __INCLUDE_NUTTX_SENSORS_GPS_H */
|
Loading…
Reference in a new issue