system: add sensor streaming tool based on nxscope
This tool allows you to send sensor data via the nxscope interface.
Useful when we test sensors or when we just need a tool to visualize
data from sensors.
Works only with the new sensor framework.
diff --git a/system/sensorscope/CMakeLists.txt b/system/sensorscope/CMakeLists.txt
new file mode 100644
index 0000000..554114f
--- /dev/null
+++ b/system/sensorscope/CMakeLists.txt
@@ -0,0 +1,31 @@
+# ##############################################################################
+# apps/system/sensorscope/CMakeLists.txt
+#
+# 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.
+#
+# ##############################################################################
+
+if(CONFIG_SYSTEM_SENSORSCOPE)
+ nuttx_add_application(
+ NAME
+ ${CONFIG_SYSTEM_SENSORSCOPE_PROGNAME}
+ SRCS
+ sensorscope_main.c
+ STACKSIZE
+ ${CONFIG_SYSTEM_SENSORSCOPE_STACKSIZE}
+ PRIORITY
+ ${CONFIG_SYSTEM_SENSORSCOPE_PRIORITY})
+endif()
diff --git a/system/sensorscope/Kconfig b/system/sensorscope/Kconfig
new file mode 100644
index 0000000..a8dd84e
--- /dev/null
+++ b/system/sensorscope/Kconfig
@@ -0,0 +1,72 @@
+#
+# For a description of the syntax of this configuration file,
+# see the file kconfig-language.txt in the NuttX tools repository.
+#
+
+menuconfig SYSTEM_SENSORSCOPE
+ bool "NxScope sensors stream app"
+ default n
+ depends on LOGGING_NXSCOPE
+ select LOGGING_NXSCOPE_INTF_SERIAL
+ select LOGGING_NXSCOPE_PROTO_SER
+
+if SYSTEM_SENSORSCOPE
+
+config SYSTEM_SENSORSCOPE_PROGNAME
+ string "Program name"
+ default "sensorscope"
+
+config SYSTEM_SENSORSCOPE_PRIORITY
+ int "nxscope task priority"
+ default 100
+
+config SYSTEM_SENSORSCOPE_STACKSIZE
+ int "nxscope stack size"
+ default DEFAULT_TASK_STACKSIZE
+
+config SYSTEM_SENSORSCOPE_SERIAL_PATH
+ string "nxscope serial path"
+ default "/dev/ttyUSB0"
+
+config SYSTEM_SENSORSCOPE_SERIAL_BAUD
+ int "nxscope serial baud"
+ default 115200
+ ---help---
+ Ignored if set to 0 (for example for RTT interface)
+
+config SYSTEM_SENSORSCOPE_CDCACM
+ bool "nxscope CDCACM device support"
+ depends on CDCACM
+ default n
+
+config SYSTEM_SENSORSCOPE_FORCE_ENABLE
+ bool "nxscope force enable"
+ default n
+
+config SYSTEM_SENSORSCOPE_STREAMBUF_LEN
+ int "nxscope stream buffer length"
+ default 512
+
+config SYSTEM_SENSORSCOPE_RXBUF_LEN
+ int "nxscope RX buffer length"
+ default 32
+
+config SYSTEM_SENSORSCOPE_RX_PADDING
+ int "nxscope RX padding"
+ default 0
+
+config SYSTEM_SENSORSCOPE_MAIN_INTERVAL
+ int "nxscope main interval (microseconds)"
+ default 100000
+ ---help---
+ This value is responsible for the frequency at which stream
+ frames will be sent and incoming frames will be received.
+
+config SYSTEM_SENSORSCOPE_FETCH_INTERVAL
+ int "nxscope sensor fetch interval (microseconds)"
+ default 1000
+ ---help---
+ This value is responsible for the frequency at which the sensors
+ are read
+
+endif # SYSTEM_SENSORSCOPE
diff --git a/system/sensorscope/Make.defs b/system/sensorscope/Make.defs
new file mode 100644
index 0000000..2e76647
--- /dev/null
+++ b/system/sensorscope/Make.defs
@@ -0,0 +1,23 @@
+############################################################################
+# apps/systen/sensorscope/Make.defs
+#
+# 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.
+#
+############################################################################
+
+ifneq ($(CONFIG_SYSTEM_SENSORSCOPE),)
+CONFIGURED_APPS += $(APPDIR)/system/sensorscope
+endif
diff --git a/system/sensorscope/Makefile b/system/sensorscope/Makefile
new file mode 100644
index 0000000..18ee631
--- /dev/null
+++ b/system/sensorscope/Makefile
@@ -0,0 +1,34 @@
+############################################################################
+# apps/system/sensorscope/Makefile
+#
+# 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.
+#
+############################################################################
+
+include $(APPDIR)/Make.defs
+
+# sensorscope built-in application info
+
+PROGNAME = $(CONFIG_SYSTEM_SENSORSCOPE_PROGNAME)
+PRIORITY = $(CONFIG_SYSTEM_SENSORSCOPE_PRIORITY)
+STACKSIZE = $(CONFIG_SYSTEM_SENSORSCOPE_STACKSIZE)
+MODULE = $(CONFIG_SYSTEM_SENSORSCOPE)
+
+MAINSRC = sensorscope_main.c
+
+CSRCS =
+
+include $(APPDIR)/Application.mk
diff --git a/system/sensorscope/sensorscope_main.c b/system/sensorscope/sensorscope_main.c
new file mode 100644
index 0000000..ab80be5
--- /dev/null
+++ b/system/sensorscope/sensorscope_main.c
@@ -0,0 +1,555 @@
+/****************************************************************************
+ * apps/system/sensorscope/sensorscope_main.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 <sys/boardctl.h>
+#include <sys/param.h>
+
+#include <assert.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <libgen.h>
+
+#include <nuttx/sensors/sensor.h>
+
+#include "logging/nxscope/nxscope.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define SENSOR_PATH "/dev/uorb/"
+#define SENSOR_PATH_MAX 62
+#define SENSOR_CHNAME_MAX 16
+
+/****************************************************************************
+ * Private Type Definition
+ ****************************************************************************/
+
+struct nxsensor_info_s
+{
+ FAR const char *name;
+ size_t data_size; /* Sensor read data size */
+ size_t data_offset; /* Read data offset (no timestamp) */
+ size_t dim; /* Data vector dimenstion */
+ int dtype; /* Data vector type */
+};
+
+struct listen_object_s
+{
+ /* Node of object info list */
+
+ struct list_node node;
+
+ /* Sensor data */
+
+ int fd;
+ FAR uint8_t *data;
+
+ /* Sensor info */
+
+ FAR struct nxsensor_info_s *info;
+
+ /* nxscope channel data */
+
+ int chanid;
+ char chname[SENSOR_CHNAME_MAX];
+};
+
+struct nxscope_thr_env_s
+{
+ struct nxscope_s nxs;
+ struct list_node objlist;
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* This array defines supported sensors. */
+
+struct nxsensor_info_s g_nxsensor[] =
+{
+ {"accel", sizeof(struct sensor_accel), 0, 3, NXSCOPE_TYPE_FLOAT},
+ {"mag", sizeof(struct sensor_mag), 0, 3, NXSCOPE_TYPE_FLOAT},
+ {"gyro", sizeof(struct sensor_gyro), 0, 3, NXSCOPE_TYPE_FLOAT},
+ {"light", sizeof(struct sensor_light), 0, 2, NXSCOPE_TYPE_FLOAT},
+ {"baro", sizeof(struct sensor_baro), 0, 2, NXSCOPE_TYPE_FLOAT},
+ {"prox", sizeof(struct sensor_prox), 0, 1, NXSCOPE_TYPE_FLOAT},
+ {"humi", sizeof(struct sensor_humi), 0, 1, NXSCOPE_TYPE_FLOAT},
+ {"temp", sizeof(struct sensor_temp), 0, 1, NXSCOPE_TYPE_FLOAT},
+ {"rgb", sizeof(struct sensor_rgb), 0, 3, NXSCOPE_TYPE_FLOAT},
+ {"hall", sizeof(struct sensor_hall), 0, 1, NXSCOPE_TYPE_INT32},
+ {"ir", sizeof(struct sensor_ir), 0, 1, NXSCOPE_TYPE_FLOAT},
+ {"gas", sizeof(struct sensor_gas), 0, 1, NXSCOPE_TYPE_FLOAT},
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nxscope_samples_thr
+ ****************************************************************************/
+
+static FAR void *nxscope_samples_thr(FAR void *arg)
+{
+ FAR struct nxscope_thr_env_s *envp = arg;
+ FAR struct listen_object_s *tmp;
+ FAR float *data;
+ int ret;
+ size_t offset;
+
+ DEBUGASSERT(envp);
+
+ printf("nxscope_samples_thr\n");
+
+ while (1)
+ {
+ list_for_every_entry(&envp->objlist, tmp, struct listen_object_s, node)
+ {
+ /* Read data from sensor */
+
+ ret = read(tmp->fd, tmp->data, tmp->info->data_size);
+ if (ret < 0)
+ {
+ printf("ERROR: read failed %d\n", -errno);
+ }
+ else
+ {
+ /* Get vector from a given offset */
+
+ offset = tmp->info->data_offset + sizeof(uint64_t);
+ data = (float *)&tmp->data[offset];
+
+ nxscope_put_vfloat(&envp->nxs, tmp->chanid, data,
+ tmp->info->dim);
+ }
+ }
+
+ usleep(CONFIG_SYSTEM_SENSORSCOPE_FETCH_INTERVAL);
+ }
+
+ return NULL;
+}
+
+#ifdef CONFIG_SYSTEM_SENSORSCOPE_CDCACM
+/****************************************************************************
+ * Name: nxscope_cdcacm_init
+ ****************************************************************************/
+
+static int nxscope_cdcacm_init(void)
+{
+ struct boardioc_usbdev_ctrl_s ctrl;
+ FAR void *handle;
+ int ret;
+
+ ctrl.usbdev = BOARDIOC_USBDEV_CDCACM;
+ ctrl.action = BOARDIOC_USBDEV_CONNECT;
+ ctrl.instance = 0;
+ ctrl.handle = &handle;
+
+ ret = boardctl(BOARDIOC_USBDEV_CONTROL, (uintptr_t)&ctrl);
+ if (ret < 0)
+ {
+ printf("ERROR: BOARDIOC_USBDEV_CONTROL failed %d\n", ret);
+ goto errout;
+ }
+
+errout:
+ return ret;
+}
+#endif
+
+/****************************************************************************
+ * Name: listener_add_object
+ ****************************************************************************/
+
+static FAR struct listen_object_s *
+listener_add_object(FAR struct list_node *objlist,
+ FAR struct nxsensor_info_s *info,
+ int fd, int chanid, FAR char *chname)
+{
+ FAR struct listen_object_s *tmp;
+
+ tmp = malloc(sizeof(struct listen_object_s));
+ if (tmp == NULL)
+ {
+ return NULL;
+ }
+
+ /* Initialize object */
+
+ strncpy(tmp->chname, chname, SENSOR_CHNAME_MAX);
+
+ tmp->info = info;
+ tmp->chanid = chanid;
+ tmp->fd = fd;
+
+ /* Allocate space for data */
+
+ tmp->data = malloc(info->data_size);
+
+ /* Add node to list */
+
+ list_add_tail(objlist, &tmp->node);
+
+ return tmp;
+}
+
+/****************************************************************************
+ * Name: listener_delete_object_list
+ ****************************************************************************/
+
+static void listener_delete_object_list(FAR struct list_node *objlist)
+{
+ FAR struct listen_object_s *tmp;
+ FAR struct listen_object_s *next;
+
+ list_for_every_entry_safe(objlist, tmp, next, struct listen_object_s, node)
+ {
+ free(tmp->data);
+ list_delete(&tmp->node);
+ free(tmp);
+ }
+
+ list_initialize(objlist);
+}
+
+/****************************************************************************
+ * Name: sensorscope_chinfo
+ ****************************************************************************/
+
+static int sensorscope_chinfo(FAR char *path,
+ FAR struct nxsensor_info_s **info)
+{
+ int i;
+
+ for (i = 0; i < nitems(g_nxsensor); i++)
+ {
+ if (strstr(path, g_nxsensor[i].name) != NULL)
+ {
+ *info = &g_nxsensor[i];
+ return OK;
+ }
+ }
+
+ return -EINVAL;
+}
+
+/****************************************************************************
+ * Name: nxscope_channels_num
+ ****************************************************************************/
+
+static int nxscope_channels_num(void)
+{
+ FAR struct dirent *entry;
+ FAR DIR *dir;
+ int i = 0;
+
+ dir = opendir(SENSOR_PATH);
+ if (!dir)
+ {
+ return 0;
+ }
+
+ while ((entry = readdir(dir)) != NULL)
+ {
+ if (entry->d_type == DT_CHR)
+ {
+ i++;
+ }
+ }
+
+ closedir(dir);
+
+ return i;
+}
+
+/****************************************************************************
+ * Name: nxscope_channels
+ ****************************************************************************/
+
+static int nxscope_channels(FAR struct nxscope_thr_env_s *envp)
+{
+ union nxscope_chinfo_type_u u;
+ FAR struct nxsensor_info_s *info;
+ FAR struct dirent *entry;
+ FAR struct listen_object_s *obj;
+ FAR DIR *dir;
+ int chanid;
+ int ret;
+ int fd;
+ char path[SENSOR_PATH_MAX];
+
+ /* Initialize objects list */
+
+ list_initialize(&envp->objlist);
+
+ /* Open sensors direcotry */
+
+ dir = opendir(SENSOR_PATH);
+ if (!dir)
+ {
+ return 0;
+ }
+
+ /* Get available sensors */
+
+ chanid = 0;
+ while ((entry = readdir(dir)) != NULL)
+ {
+ if (entry->d_type != DT_CHR)
+ {
+ continue;
+ }
+
+ /* Get sensor info */
+
+ ret = sensorscope_chinfo(entry->d_name, &info);
+ if (ret != OK)
+ {
+ printf("ERROR: not supported sensor %s\n", entry->d_name);
+ }
+ else
+ {
+ snprintf(path, SENSOR_PATH_MAX, SENSOR_PATH"%s", entry->d_name);
+ fd = open(path, O_CLOEXEC | O_RDWR | O_NONBLOCK);
+ if (fd < 0)
+ {
+ printf("ERROR: failed to open %s %d\n", entry->d_name, -errno);
+ }
+ else
+ {
+ /* Add new object */
+
+ obj = listener_add_object(&envp->objlist,
+ info, fd, chanid,
+ basename(entry->d_name));
+ if (obj == NULL)
+ {
+ printf("ERROR: failed to add listener object %d\n",
+ chanid);
+ return -ENOMEM;
+ }
+
+ /* Register nxscope channel */
+
+ u.s.dtype = NXSCOPE_TYPE_FLOAT;
+ u.s._res = 0;
+ u.s.cri = 0;
+
+ nxscope_chan_init(&envp->nxs, obj->chanid, obj->chname,
+ u.u8, obj->info->dim, 0);
+
+ /* Next channel */
+
+ chanid++;
+ }
+ }
+ }
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: nxscope_cb_start
+ ****************************************************************************/
+
+static int nxscope_cb_start(FAR void *priv, bool start)
+{
+ UNUSED(priv);
+
+ printf("--> nxscope_cb_start: start=%d\n", start);
+
+ return OK;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nxscope_main
+ ****************************************************************************/
+
+int main(int argc, FAR char *argv[])
+{
+ struct nxscope_thr_env_s env;
+ struct nxscope_cfg_s nxs_cfg;
+ struct nxscope_intf_s intf;
+ struct nxscope_proto_s proto;
+ struct nxscope_ser_cfg_s nxs_ser_cfg;
+ struct nxscope_callbacks_s cbs;
+ pthread_t thread;
+ int ret;
+
+#ifndef CONFIG_NSH_ARCHINIT
+ /* Perform architecture-specific initialization (if configured) */
+
+ boardctl(BOARDIOC_INIT, 0);
+
+# ifdef CONFIG_BOARDCTL_FINALINIT
+ /* Perform architecture-specific final-initialization (if configured) */
+
+ boardctl(BOARDIOC_FINALINIT, 0);
+# endif
+#endif
+
+#ifdef CONFIG_SYSTEM_SENSORSCOPE_CDCACM
+ /* Initialize the USB CDCACM device */
+
+ ret = nxscope_cdcacm_init();
+ if (ret < 0)
+ {
+ printf("ERROR: nxscope_cdcacm_init failed %d\n", ret);
+ goto errout_noproto;
+ }
+#endif
+
+ /* Default serial protocol */
+
+ ret = nxscope_proto_ser_init(&proto, NULL);
+ if (ret < 0)
+ {
+ printf("ERROR: nxscope_proto_ser_init failed %d\n", ret);
+ goto errout_noproto;
+ }
+
+ /* Configuration */
+
+ nxs_ser_cfg.path = CONFIG_SYSTEM_SENSORSCOPE_SERIAL_PATH;
+ nxs_ser_cfg.nonblock = true;
+ nxs_ser_cfg.baud = CONFIG_SYSTEM_SENSORSCOPE_SERIAL_BAUD;
+
+ /* Initialize serial interface */
+
+ ret = nxscope_ser_init(&intf, &nxs_ser_cfg);
+ if (ret < 0)
+ {
+ printf("ERROR: nxscope_ser_init failed %d\n", ret);
+ goto errout_nointf;
+ }
+
+ /* Connect callbacks */
+
+ cbs.start_priv = NULL;
+ cbs.start = nxscope_cb_start;
+
+ /* Initialize nxscope */
+
+ nxs_cfg.intf_cmd = &intf;
+ nxs_cfg.intf_stream = &intf;
+ nxs_cfg.proto_cmd = &proto;
+ nxs_cfg.proto_stream = &proto;
+ nxs_cfg.callbacks = &cbs;
+ nxs_cfg.channels = nxscope_channels_num();
+ nxs_cfg.streambuf_len = CONFIG_SYSTEM_SENSORSCOPE_STREAMBUF_LEN;
+ nxs_cfg.rxbuf_len = CONFIG_SYSTEM_SENSORSCOPE_RXBUF_LEN;
+ nxs_cfg.rx_padding = CONFIG_SYSTEM_SENSORSCOPE_RX_PADDING;
+
+ ret = nxscope_init(&env.nxs, &nxs_cfg);
+ if (ret < 0)
+ {
+ printf("ERROR: nxscope_init failed %d\n", ret);
+ goto errout_nonxscope;
+ }
+
+ /* Create channels */
+
+ ret = nxscope_channels(&env);
+ if (ret != OK)
+ {
+ printf("ERROR: nxscope_channels failed %d\n", ret);
+ goto errout;
+ }
+
+ /* Create samples thread */
+
+ ret = pthread_create(&thread, NULL, nxscope_samples_thr, &env);
+ if (ret != OK)
+ {
+ printf("ERROR: pthread_create failed %d\n", ret);
+ goto errout;
+ }
+
+#ifdef CONFIG_SYSTEM_SENSORSCOPE_FORCE_ENABLE
+ /* Enable channels and enable stream */
+
+ nxscope_chan_all_en(&nxs, true);
+ nxscope_stream_start(&nxs, true);
+#endif
+
+ /* Main loop */
+
+ while (1)
+ {
+ /* Flush stream data */
+
+ ret = nxscope_stream(&env.nxs);
+ if (ret < 0)
+ {
+ printf("ERROR: nxscope_stream failed %d\n", ret);
+ }
+
+ /* Handle recv data */
+
+ ret = nxscope_recv(&env.nxs);
+ if (ret < 0)
+ {
+ printf("ERROR: nxscope_recv failed %d\n", ret);
+ }
+
+ usleep(CONFIG_SYSTEM_SENSORSCOPE_MAIN_INTERVAL);
+ }
+
+errout:
+
+ /* Delete objects */
+
+ listener_delete_object_list(&env.objlist);
+
+ /* Deinit nxscope */
+
+ nxscope_deinit(&env.nxs);
+
+errout_nonxscope:
+
+ /* Deinit interface */
+
+ nxscope_ser_deinit(&intf);
+
+errout_nointf:
+
+ /* Deinit protocol */
+
+ nxscope_proto_ser_deinit(&proto);
+
+errout_noproto:
+ return 0;
+}