This is an automated email from the ASF dual-hosted git repository. protobits pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git
commit a3f978da025e91bb44344b89a3026548d8c494eb Author: dongjiuzhu <dongjiuz...@xiaomi.com> AuthorDate: Mon Oct 19 21:30:22 2020 +0800 sensor/driver: wtgahrs2 by serial interface follow sensor.c/sensor.h Wtgahrs2 integrates multiple sensor: accel, gyro, mag, baro and gps. Signed-off-by: dongjiuzhu <dongjiuz...@xiaomi.com> --- drivers/sensors/Kconfig | 8 + drivers/sensors/Make.defs | 4 + drivers/sensors/wtgahrs2.c | 578 +++++++++++++++++++++++++++++++++++++++ include/nuttx/sensors/wtgahrs2.h | 64 +++++ 4 files changed, 654 insertions(+) diff --git a/drivers/sensors/Kconfig b/drivers/sensors/Kconfig index f9bad12..2a9bac5 100644 --- a/drivers/sensors/Kconfig +++ b/drivers/sensors/Kconfig @@ -11,6 +11,14 @@ menuconfig SENSORS if SENSORS +config SENSORS_WTGAHRS2 + bool "Wtgahrs2 Sensor Support" + default n + ---help--- + We can read sensor data by serial interface. It need the hardware sensor + wtgashrs2(JY901) as data source. This sensor can generate accelerometer, + gyroscope, magnetic, barometer and gps data. + config SENSORS_APDS9960 bool "Avago APDS-9960 Gesture Sensor support" default n diff --git a/drivers/sensors/Make.defs b/drivers/sensors/Make.defs index bf87397..a22909f 100644 --- a/drivers/sensors/Make.defs +++ b/drivers/sensors/Make.defs @@ -39,6 +39,10 @@ ifeq ($(CONFIG_SENSORS),y) CSRCS += sensor.c +ifeq ($(CONFIG_SENSORS_WTGAHRS2),y) + CSRCS += wtgahrs2.c +endif + ifeq ($(CONFIG_SENSORS_HCSR04),y) CSRCS += hc_sr04.c endif diff --git a/drivers/sensors/wtgahrs2.c b/drivers/sensors/wtgahrs2.c new file mode 100644 index 0000000..d3311b9 --- /dev/null +++ b/drivers/sensors/wtgahrs2.c @@ -0,0 +1,578 @@ +/**************************************************************************** + * drivers/sensors/wtgahrs2.c + * Driver for the Wit-Motion WTGAHRS2 accelerometer, gyroscope, magnetic, + * angle, barometer, temperature, gps sensors by serial interface with host + * + * 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/sensors/wtgahrs2.h> +#include <nuttx/kthread.h> +#include <nuttx/kmalloc.h> + +#include <termios.h> +#include <math.h> +#include <fcntl.h> +#include <stdio.h> + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define WTGAHRS2_ARRAYSIZE(a) (sizeof((a))/sizeof(a[0])) + +#define WTGAHRS2_ACCEL_IDX 0 +#define WTGAHRS2_GYRO_IDX 1 +#define WTGAHRS2_MAG_IDX 2 +#define WTGAHRS2_BARO_IDX 3 +#define WTGAHRS2_GPS_IDX 4 +#define WTGAHRS2_MAX_IDX 5 + +#define WTGAHRS2_GPS0_MASK (1 << 0) /* Time */ +#define WTGAHRS2_GPS1_MASK (1 << 1) /* Longitude, Latitude */ +#define WTGAHRS2_GPS2_MASK (1 << 2) /* Ground speed, Height, Yaw */ +#define WTGAHRS2_GPS_MASK (7 << 0) + +#define WTGAHRS2_GPS0_INFO 0x50 +#define WTGAHRS2_ACCEL_INFO 0x51 +#define WTGAHRS2_GYRO_INFO 0x52 +#define WTGAHRS2_MAG_INFO 0x54 +#define WTGAHRS2_BARO_INFO 0x56 +#define WTGAHRS2_GPS1_INFO 0x57 +#define WTGAHRS2_GPS2_INFO 0x58 + +#define WTGAHRS2_RSP_HEADER 0x55 +#define WTGAHRS2_RSP_LENGTH 11 +#define WTGAHRS2_CMD_LENGTH 5 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct wtgahrs2_sensor_s +{ + struct sensor_lowerhalf_s lower; + unsigned int interval; + unsigned int last_update; + bool enable; +}; + +struct wtgahrs2_dev_s +{ + struct wtgahrs2_sensor_s dev[WTGAHRS2_MAX_IDX]; + struct file file; + + struct sensor_event_gps gps; + unsigned char gps_mask; +}; + +/**************************************************************************** + * Private + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int wtgahrs2_activate(FAR struct sensor_lowerhalf_s *lower, bool sw); +static int wtgahrs2_set_interval(FAR struct sensor_lowerhalf_s *lower, + FAR unsigned int *interval); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* in microseconds */ + +static const unsigned int g_wtgahrs2_interval[] = +{ + 10000000, /* 0.1 hz */ + 2000000, /* 0.5 hz */ + 1000000, /* 1 hz */ + 500000, /* 2 hz */ + 200000, /* 5 hz */ + 100000, /* 10 hz */ + 50000, /* 20 hz */ + 20000, /* 50 hz */ + 10000, /* 100 hz */ + 5000, /* 200 hz */ +}; + +static const uint8_t g_wtgahrs2_unlock[] = +{ + 0xff, 0xaa, 0x69, 0x88, 0xb5 +}; + +static const uint8_t g_wtgahrs2_odr_200hz[] = +{ + 0xff, 0xaa, 0x03, 0x0b, 0x00 +}; + +static const uint8_t g_wtgahrs2_enable_sensor[] = +{ + 0xff, 0xaa, 0x02, 0xd7, 0x05 +}; + +static const struct sensor_ops_s g_wtgahrs2_ops = +{ + .activate = wtgahrs2_activate, + .set_interval = wtgahrs2_set_interval, + .batch = NULL, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void wtgahrs2_sendcmd(FAR struct wtgahrs2_dev_s *rtdata, + const void *cmd) +{ + file_write(&rtdata->file, cmd, WTGAHRS2_CMD_LENGTH); + usleep(10000); +} + +static int wtgahrs2_activate(FAR struct sensor_lowerhalf_s *lower, bool sw) +{ + FAR struct wtgahrs2_sensor_s *dev = (FAR struct wtgahrs2_sensor_s *)lower; + dev->enable = sw; + + return 0; +} + +static int wtgahrs2_set_interval(FAR struct sensor_lowerhalf_s *lower, + FAR unsigned int *interval) +{ + FAR struct wtgahrs2_sensor_s *dev = (FAR struct wtgahrs2_sensor_s *)lower; + int idx = 0; + + for (; idx < WTGAHRS2_ARRAYSIZE(g_wtgahrs2_interval) - 1; idx++) + { + if (*interval >= g_wtgahrs2_interval[idx]) + { + break; + } + } + + *interval = g_wtgahrs2_interval[idx]; + dev->interval = *interval; + + return 0; +} + +static void wtgahrs2_accel_data(FAR struct wtgahrs2_dev_s *rtdata, + FAR unsigned char *buffer) +{ + FAR struct wtgahrs2_sensor_s *dev = &rtdata->dev[WTGAHRS2_ACCEL_IDX]; + FAR struct sensor_lowerhalf_s *lower = &dev->lower; + uint64_t now = sensor_get_timestamp(); + struct sensor_event_accel accel; + + if (!dev->enable || now - dev->last_update < dev->interval) + { + return; + } + + dev->last_update = now; + + accel.timestamp = now; + accel.x = (short)(buffer[1] << 8 | buffer[0]) * (16 * 9.8f / 32768); + accel.y = (short)(buffer[3] << 8 | buffer[2]) * (16 * 9.8f / 32768); + accel.z = (short)(buffer[5] << 8 | buffer[4]) * (16 * 9.8f / 32768); + accel.temperature = (short)(buffer[7] << 8 | buffer[6]) / 100.0f; + + lower->push_event(lower->priv, &accel, sizeof(accel)); + sninfo("Accel: %.3fm/s^2 %.3fm/s^2 %.3fm/s^2, t:%.1f\r\n", + accel.x, accel.y, accel.z, accel.temperature); +} + +static void wtgahrs2_gyro_data(FAR struct wtgahrs2_dev_s *rtdata, + FAR unsigned char *buffer) +{ + FAR struct wtgahrs2_sensor_s *dev = &rtdata->dev[WTGAHRS2_GYRO_IDX]; + FAR struct sensor_lowerhalf_s *lower = &dev->lower; + uint64_t now = sensor_get_timestamp(); + struct sensor_event_gyro gyro; + + if (!dev->enable || now - dev->last_update < dev->interval) + { + return; + } + + dev->last_update = now; + + gyro.timestamp = now; + gyro.x = (short)(buffer[1] << 8 | buffer[0]) * (2000 * M_PI / 180 / 32768); + gyro.y = (short)(buffer[3] << 8 | buffer[2]) * (2000 * M_PI / 180 / 32768); + gyro.z = (short)(buffer[5] << 8 | buffer[4]) * (2000 * M_PI / 180 / 32768); + gyro.temperature = (short)(buffer[7] << 8 | buffer[6]) / 100.0f; + + lower->push_event(lower->priv, &gyro, sizeof(gyro)); + sninfo("Gyro: %.3frad/s %.3frad/s %.3frad/s, t:%.1f\r\n", + gyro.x, gyro.y, gyro.z, gyro.temperature); +} + +static void wtgahrs2_mag_data(FAR struct wtgahrs2_dev_s *rtdata, + FAR unsigned char *buffer) +{ + FAR struct wtgahrs2_sensor_s *dev = &rtdata->dev[WTGAHRS2_MAG_IDX]; + FAR struct sensor_lowerhalf_s *lower = &dev->lower; + uint64_t now = sensor_get_timestamp(); + struct sensor_event_mag mag; + + if (!dev->enable || now - dev->last_update < dev->interval) + { + return; + } + + dev->last_update = now; + + mag.timestamp = now; + mag.x = (short)(buffer[1] << 8 | buffer[0]) * 0.16f; + mag.y = (short)(buffer[3] << 8 | buffer[2]) * 0.16f; + mag.z = (short)(buffer[5] << 8 | buffer[4]) * 0.16f; + mag.temperature = (short)(buffer[7] << 8 | buffer[6]) / 100.0f; + + lower->push_event(lower->priv, &mag, sizeof(mag)); + sninfo("Mag: %.3fuT %.3fuT %.3fuT, t:%.1f\r\n", + mag.x, mag.y, mag.z, mag.temperature); +} + +static void wtgahrs2_baro_data(FAR struct wtgahrs2_dev_s *rtdata, + FAR unsigned char *buffer) +{ + FAR struct wtgahrs2_sensor_s *dev = &rtdata->dev[WTGAHRS2_BARO_IDX]; + FAR struct sensor_lowerhalf_s *lower = &dev->lower; + uint64_t now = sensor_get_timestamp(); + struct sensor_event_baro baro; + + if (!dev->enable || now - dev->last_update < dev->interval) + { + return; + } + + dev->last_update = now; + + baro.timestamp = now; + baro.pressure = (long)(buffer[3] << 24 | buffer[2] << 16 | + buffer[1] << 8 | buffer[0]) / 100.0f; + baro.temperature = NAN; + + lower->push_event(lower->priv, &baro, sizeof(baro)); + sninfo("Pressure : %.3fhPa\r\n", baro.pressure); +} + +static void wtgahrs2_gps_data(FAR struct wtgahrs2_dev_s *rtdata, + FAR unsigned char *buffer, int info_type) +{ + FAR struct wtgahrs2_sensor_s *dev = &rtdata->dev[WTGAHRS2_GPS_IDX]; + FAR struct sensor_lowerhalf_s *lower = &dev->lower; + uint64_t now = sensor_get_timestamp(); + + if (!dev->enable || now - dev->last_update < dev->interval) + { + return; + } + + if (rtdata->gps_mask == 0) + { + dev->last_update = now; + } + + switch (info_type) + { + case WTGAHRS2_GPS0_INFO: + rtdata->gps_mask |= WTGAHRS2_GPS0_MASK; + rtdata->gps.year = 2000 + buffer[0]; + rtdata->gps.month = buffer[1]; + rtdata->gps.day = buffer[2]; + rtdata->gps.hour = buffer[3]; + rtdata->gps.min = buffer[4]; + rtdata->gps.sec = buffer[5]; + rtdata->gps.msec = (buffer[7] << 8) | buffer[6]; + break; + + case WTGAHRS2_GPS1_INFO: + rtdata->gps_mask |= WTGAHRS2_GPS1_MASK; + rtdata->gps.longitude = (long)(buffer[3] << 8 + | buffer[2] << 8 + | buffer[1] << 8 + | buffer[0]) / 10000000.0f; + rtdata->gps.latitude = (long)(buffer[7] << 8 + | buffer[6] << 8 + | buffer[5] << 8 + | buffer[4]) / 10000000.0f; + break; + + case WTGAHRS2_GPS2_INFO: + rtdata->gps_mask |= WTGAHRS2_GPS2_MASK; + rtdata->gps.height = (short)(buffer[1] << 8 | buffer[0]) / 10.0f; + rtdata->gps.yaw = (short)(buffer[3] << 8 | buffer[2]) / 10.0f; + rtdata->gps.speed = (long)(buffer[7] << 8 | buffer[6] << 8 + | buffer[5] << 8 | buffer[4]) / 3600.0f; + break; + } + + if (rtdata->gps_mask == WTGAHRS2_GPS_MASK) + { + rtdata->gps_mask = 0; + lower->push_event(lower->priv, &rtdata->gps, sizeof(rtdata->gps)); + sninfo("Time : %d/%d/%d-%d:%d:%d\r\n", rtdata->gps.year, + rtdata->gps.month, rtdata->gps.day, rtdata->gps.hour, + rtdata->gps.min, rtdata->gps.sec); + sninfo("GPS longitude : %fdegree, latitude:%fdegree\r\n", + rtdata->gps.longitude, rtdata->gps.latitude); + sninfo("GPS speed: %fm/s, yaw:%fdegrees, height:%fm \r\n", + rtdata->gps.speed, rtdata->gps.yaw, rtdata->gps.height); + } +} + +static bool wtgahrs2_process_data(FAR struct wtgahrs2_dev_s *rtdata, + FAR unsigned char *buffer) +{ + unsigned char sum = 0; + int i; + + /* calculate sum and verify checksum */ + + for (i = 0; i < WTGAHRS2_RSP_LENGTH - 1; i++) + { + sum += buffer[i]; + } + + if (sum != buffer[WTGAHRS2_RSP_LENGTH - 1]) + { + return false; + } + + switch (buffer[1]) + { + case WTGAHRS2_ACCEL_INFO: + wtgahrs2_accel_data(rtdata, &buffer[2]); + break; + + case WTGAHRS2_GYRO_INFO: + wtgahrs2_gyro_data(rtdata, &buffer[2]); + break; + + case WTGAHRS2_MAG_INFO: + wtgahrs2_mag_data(rtdata, &buffer[2]); + break; + + case WTGAHRS2_BARO_INFO: + wtgahrs2_baro_data(rtdata, &buffer[2]); + break; + + case WTGAHRS2_GPS0_INFO: + case WTGAHRS2_GPS1_INFO: + case WTGAHRS2_GPS2_INFO: + wtgahrs2_gps_data(rtdata, &buffer[2], buffer[1]); + break; + } + + return true; +} + +static int wtgahrs2_thread(int argc, FAR char *argv[]) +{ + FAR struct wtgahrs2_dev_s *rtdata = (FAR struct wtgahrs2_dev_s *) + ((uintptr_t)strtoul(argv[1], NULL, 0)); + unsigned char buffer[8 * WTGAHRS2_RSP_LENGTH]; + ssize_t count = 0; + ssize_t pos; + + while (1) + { + count += file_read(&rtdata->file, buffer + count, + sizeof(buffer) - count); + for (pos = 0; pos < count; pos++) + { + if (buffer[pos] != WTGAHRS2_RSP_HEADER) + { + continue; + } + + if (count - pos < WTGAHRS2_RSP_LENGTH) + { + memmove(buffer, buffer + pos, count - pos); + break; + } + + if (wtgahrs2_process_data(rtdata, &buffer[pos])) + { + pos += WTGAHRS2_RSP_LENGTH - 1; + } + } + + count -= pos; + } + + return 0; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int wtgahrs2_initialize(FAR const char *path) +{ + FAR struct wtgahrs2_dev_s *rtdata; + FAR struct wtgahrs2_sensor_s *tmp; +#if CONFIG_SERIAL_TERMIOS + struct termios opt; +#endif + FAR char *argv[2]; + char arg1[16]; + int ret; + + if (!path) + { + snerr("Invaild path for serial interface\n"); + return -EINVAL; + } + + rtdata = kmm_zalloc(sizeof(struct wtgahrs2_dev_s)); + if (!rtdata) + { + snerr("Memory cannot be allocated for wtgahrs2\n"); + return -ENOMEM; + } + + /* Open serial tty port and set baud rate */ + + ret = file_open(&rtdata->file, path, O_RDWR); + if (ret < 0) + { + snerr("Failed to open wtgahrs2 serial:%s, err:%d", path, ret); + goto open_err; + } + +#if CONFIG_SERIAL_TERMIOS + file_ioctl(&rtdata->file, TCGETS, &opt); + cfmakeraw(&opt); + cfsetispeed(&opt, B115200); + cfsetospeed(&opt, B115200); + file_ioctl(&rtdata->file, TCSETS, &opt); +#endif + + /* Accelerometer register */ + + tmp = &rtdata->dev[WTGAHRS2_ACCEL_IDX]; + tmp->lower.ops = &g_wtgahrs2_ops; + tmp->lower.type = SENSOR_TYPE_ACCELEROMETER; + tmp->lower.buffer_bytes = sizeof(struct sensor_event_accel); + ret = sensor_register(&tmp->lower); + if (ret < 0) + { + goto accel_err; + } + + /* Gyroscope register */ + + tmp = &rtdata->dev[WTGAHRS2_GYRO_IDX]; + tmp->lower.ops = &g_wtgahrs2_ops; + tmp->lower.type = SENSOR_TYPE_GYROSCOPE; + tmp->lower.buffer_bytes = sizeof(struct sensor_event_gyro); + ret = sensor_register(&tmp->lower); + if (ret < 0) + { + goto gyro_err; + } + + /* Magnetic register */ + + tmp = &rtdata->dev[WTGAHRS2_MAG_IDX]; + tmp->lower.ops = &g_wtgahrs2_ops; + tmp->lower.type = SENSOR_TYPE_MAGNETIC_FIELD; + tmp->lower.buffer_bytes = sizeof(struct sensor_event_mag); + ret = sensor_register(&tmp->lower); + if (ret < 0) + { + goto mag_err; + } + + /* Barometer register */ + + tmp = &rtdata->dev[WTGAHRS2_BARO_IDX]; + tmp->lower.ops = &g_wtgahrs2_ops; + tmp->lower.type = SENSOR_TYPE_BAROMETER; + tmp->lower.buffer_bytes = sizeof(struct sensor_event_baro); + ret = sensor_register(&tmp->lower); + if (ret < 0) + { + goto baro_err; + } + + /* GPS register */ + + tmp = &rtdata->dev[WTGAHRS2_GPS_IDX]; + tmp->lower.ops = &g_wtgahrs2_ops; + tmp->lower.type = SENSOR_TYPE_GPS; + tmp->lower.buffer_bytes = sizeof(struct sensor_event_gps); + ret = sensor_register(&tmp->lower); + if (ret < 0) + { + goto gps_err; + } + + /* Set sensor default attributes and enter unlock mode */ + + wtgahrs2_sendcmd(rtdata, g_wtgahrs2_unlock); + + /* Set sensor default odr 200hz */ + + wtgahrs2_sendcmd(rtdata, g_wtgahrs2_odr_200hz); + + /* Enable all sensor */ + + wtgahrs2_sendcmd(rtdata, g_wtgahrs2_enable_sensor); + + snprintf(arg1, 16, "0x%" PRIxPTR, (uintptr_t)rtdata); + argv[0] = arg1; + argv[1] = NULL; + + ret = kthread_create("wtgahrs2_thread", SCHED_PRIORITY_DEFAULT, + CONFIG_DEFAULT_TASK_STACKSIZE, + wtgahrs2_thread, argv); + if (ret < 0) + { + goto thr_err; + } + + return ret; + +thr_err: + sensor_unregister(&rtdata->dev[WTGAHRS2_GPS_IDX].lower); +gps_err: + sensor_unregister(&rtdata->dev[WTGAHRS2_BARO_IDX].lower); +baro_err: + sensor_unregister(&rtdata->dev[WTGAHRS2_MAG_IDX].lower); +mag_err: + sensor_unregister(&rtdata->dev[WTGAHRS2_GYRO_IDX].lower); +gyro_err: + sensor_unregister(&rtdata->dev[WTGAHRS2_ACCEL_IDX].lower); +accel_err: + file_close(&rtdata->file); +open_err: + kmm_free(rtdata); + return ret; +} diff --git a/include/nuttx/sensors/wtgahrs2.h b/include/nuttx/sensors/wtgahrs2.h new file mode 100644 index 0000000..7d86254 --- /dev/null +++ b/include/nuttx/sensors/wtgahrs2.h @@ -0,0 +1,64 @@ +/**************************************************************************** + * include/nuttx/sensors/wtgahrs2.h + * Driver for the Wit-Motion WTGAHRS2 accelerometer, gyroscope, magnetic, + * angle, barometer, temperature, gps sensors by serial interface with host + * + * 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_WTGAHRS2_H +#define __INCLUDE_NUTTX_SENSORS_WTGAHRS2_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> +#include <nuttx/sensors/sensor.h> +#include <nuttx/sensors/ioctl.h> + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef __cplusplus +extern "C" +{ +#endif + +/**************************************************************************** + * Name: wtgahrs2_initialize + * + * Description: + * Initialize wrgahrs2 sensor module, it will create accelerometer, + * gyroscope, magnetic, barometer, gps character device. + * + * Input Parameters: + * devpath - The full path to the driver to read data source by serial tty. + * + * Returned Value: + * OK if the driver was successfully initialize; A negated errno value is + * returned on any failure. + ****************************************************************************/ + +int wtgahrs2_initialize(FAR const char *path); + +#ifdef __cplusplus +} +#endif + +#endif