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