| /**************************************************************************** |
| * 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; |
| } |