add system/adcscope - streaming tool for ADC

add adcscope app allowing to stream data from ADC device with logging/nxscope.
Useful for testing ADC drivers.

Signed-off-by: raiden00pl <raiden00@railab.me>
This commit is contained in:
raiden00pl 2024-09-01 11:38:23 +02:00 committed by Alan C. Assis
parent 7b42dfc53e
commit faea03f1fd
5 changed files with 679 additions and 0 deletions

View file

@ -0,0 +1,31 @@
# ##############################################################################
# apps/system/adcscope/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_ADCSCOPE)
nuttx_add_application(
NAME
${CONFIG_SYSTEM_ADCSCOPE_PROGNAME}
SRCS
adcscope_main.c
STACKSIZE
${CONFIG_SYSTEM_ADCSCOPE_STACKSIZE}
PRIORITY
${CONFIG_SYSTEM_ADCSCOPE_PRIORITY})
endif()

109
system/adcscope/Kconfig Normal file
View file

@ -0,0 +1,109 @@
#
# For a description of the syntax of this configuration file,
# see the file kconfig-language.txt in the NuttX tools repository.
#
menuconfig SYSTEM_ADCSCOPE
bool "NxScope ADC stream app"
default n
depends on ADC && LOGGING_NXSCOPE
if SYSTEM_ADCSCOPE
config SYSTEM_ADCSCOPE_PROGNAME
string "Program name"
default "adcscope"
config SYSTEM_ADCSCOPE_PRIORITY
int "adcscope task priority"
default 100
config SYSTEM_ADCSCOPE_STACKSIZE
int "adcscope stack size"
default DEFAULT_TASK_STACKSIZE
config SYSTEM_ADCSCOPE_SERIAL_PATH
string "adcscope serial device path"
default "/dev/ttyUSB0"
config SYSTEM_ADCSCOPE_SERIAL_BAUD
int "adcscope serial baud"
default 115200
---help---
Ignored if set to 0 (for example for RTT interface)
config SYSTEM_ADCSCOPE_CDCACM
bool "adcscope CDCACM device support"
depends on CDCACM
default n
config SYSTEM_ADCSCOPE_FORCE_ENABLE
bool "adcscope force enable"
default n
config SYSTEM_ADCSCOPE_STREAMBUF_LEN
int "adcscope stream buffer length"
default 512
config SYSTEM_ADCSCOPE_RXBUF_LEN
int "adcscope RX buffer length"
default 32
config SYSTEM_ADCSCOPE_RX_PADDING
int "adcscope RX padding"
default 0
---help---
This value is returned by NxScope protocol to the client and can
be used to optimize RX transfers when the target supports DMA transfers.
In this case this value should be equal to the DMA RX buffer length.
config SYSTEM_ADCSCOPE_MAIN_INTERVAL
int "adcscope 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_ADCSCOPE_FETCH_INTERVAL
int "adcscope fetch interval (microseconds)"
default 1000
---help---
This value is responsible for the frequency at which the ADC
samples are read. If set to 0, then samples are read at maximum rate.
config SYSTEM_ADCSCOPE_ADC_PATH
string "adcscope ADC device path"
default "/dev/adc0"
config SYSTEM_ADCSCOPE_ADCBUF_LEN
int "adcscope buffer length"
default ADC_FIFOSIZE
---help---
The number of samples in the buffer used to read from the ADC device.
This is the maximum number of samples that can be read from the ADC
device during one read() operation.
config SYSTEM_ADCSCOPE_SWTRIG
bool "adcscope uses software trigger"
default n
---help---
When this option is set, all read() operations on the ADC device will
be preceded by an ioctl(ANIOC_TRIGGER) call.
choice
prompt "adcscope data type"
default SYSTEM_ADCSCOPE_INT16
config SYSTEM_ADCSCOPE_INT16
bool "pack ADC data as int16_t"
---help---
NxScope send ADC samples as int16_t data.
config SYSTEM_ADCSCOPE_INT32
bool "pack ADC data as int32_t"
---help---
NxScope send ADC samples as int32_t data.
endchoice # "adcscope data type"
endif # SYSTEM_ADCSCOPE

23
system/adcscope/Make.defs Normal file
View file

@ -0,0 +1,23 @@
############################################################################
# apps/systen/adcscope/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_ADCSCOPE),)
CONFIGURED_APPS += $(APPDIR)/system/adcscope
endif

34
system/adcscope/Makefile Normal file
View file

@ -0,0 +1,34 @@
############################################################################
# apps/system/adcscope/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
# adcscope built-in application info
PROGNAME = $(CONFIG_SYSTEM_ADCSCOPE_PROGNAME)
PRIORITY = $(CONFIG_SYSTEM_ADCSCOPE_PRIORITY)
STACKSIZE = $(CONFIG_SYSTEM_ADCSCOPE_STACKSIZE)
MODULE = $(CONFIG_SYSTEM_ADCSCOPE)
MAINSRC = adcscope_main.c
CSRCS =
include $(APPDIR)/Application.mk

View file

@ -0,0 +1,482 @@
/****************************************************************************
* apps/system/adcscope/adcscope_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/ioctl.h>
#include <assert.h>
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <nuttx/analog/adc.h>
#include <nuttx/analog/ioctl.h>
#include "logging/nxscope/nxscope.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Channel name length */
#define CHNAME_MAX 8
/* ADC data type */
#ifdef CONFIG_SYSTEM_ADCSCOPE_INT16
# define ADATA_PUT nxscope_put_int16
# define ADATA_DTYPE NXSCOPE_TYPE_INT16
#elif defined(CONFIG_SYSTEM_ADCSCOPE_INT32)
# define ADATA_PUT nxscope_put_int32
# define ADATA_DTYPE NXSCOPE_TYPE_INT32
#else
# error ADC data type not selected
#endif
/****************************************************************************
* Private Type Definition
****************************************************************************/
struct adcscope_thr_env_s
{
/* NxScope data */
struct nxscope_s nxs;
struct nxscope_cfg_s nxs_cfg;
struct nxscope_intf_s intf;
struct nxscope_proto_s proto;
struct nxscope_callbacks_s cbs;
struct nxscope_ser_cfg_s nxs_ser_cfg;
/* ADC data */
int fd;
size_t channels;
size_t data_size;
FAR struct adc_msg_s *data;
FAR char *chname;
};
/****************************************************************************
* Private Data
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: adcscope_env_init
****************************************************************************/
static int adcscope_env_init(FAR struct adcscope_thr_env_s *envp)
{
int ret = OK;
/* Open ADC device */
envp->fd = open(CONFIG_SYSTEM_ADCSCOPE_ADC_PATH, O_RDWR);
if (envp->fd <= 0)
{
printf("ERROR: failed to open %s\n", CONFIG_SYSTEM_ADCSCOPE_ADC_PATH);
ret = -errno;
goto errout;
}
/* Get number of channels */
envp->channels = ioctl(envp->fd, ANIOC_GET_NCHANNELS, 0);
if (envp->channels <= 0)
{
printf("ANIOC_GET_NCHANNELS ioctl failed: %d\n", envp->channels);
ret = -errno;
goto errout;
}
/* Allocate data buffer */
envp->data_size = sizeof(struct adc_msg_s) * envp->channels *
CONFIG_SYSTEM_ADCSCOPE_ADCBUF_LEN;
envp->data = zalloc(envp->data_size);
if (!envp->data)
{
printf("ERROR: zalloc failed %d\n", -errno);
ret = -errno;
goto errout;
}
/* Allocate channels name buffer */
envp->chname = zalloc(envp->channels * CHNAME_MAX);
if (!envp->chname)
{
printf("ERROR: zalloc failed %d\n", -errno);
ret = -errno;
goto errout;
}
errout:
return ret;
}
/****************************************************************************
* Name: adcscope_env_clean
****************************************************************************/
static void adcscope_env_clean(FAR struct adcscope_thr_env_s *envp)
{
/* Free buffers */
free(envp->data);
free(envp->chname);
}
/****************************************************************************
* 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;
}
/****************************************************************************
* Name: adcscope_nxscope_init
****************************************************************************/
static int adcscope_nxscope_init(FAR struct adcscope_thr_env_s *envp)
{
int ret;
/* Default serial protocol */
ret = nxscope_proto_ser_init(&envp->proto, NULL);
if (ret < 0)
{
printf("ERROR: nxscope_proto_ser_init failed %d\n", ret);
goto errout_noproto;
}
/* Configuration */
envp->nxs_ser_cfg.path = CONFIG_SYSTEM_ADCSCOPE_SERIAL_PATH;
envp->nxs_ser_cfg.nonblock = true;
envp->nxs_ser_cfg.baud = CONFIG_SYSTEM_ADCSCOPE_SERIAL_BAUD;
/* Initialize serial interface */
ret = nxscope_ser_init(&envp->intf, &envp->nxs_ser_cfg);
if (ret < 0)
{
printf("ERROR: nxscope_ser_init failed %d\n", ret);
goto errout_nointf;
}
/* Connect callbacks */
envp->cbs.start_priv = NULL;
envp->cbs.start = nxscope_cb_start;
/* Initialize nxscope */
envp->nxs_cfg.intf_cmd = &envp->intf;
envp->nxs_cfg.intf_stream = &envp->intf;
envp->nxs_cfg.proto_cmd = &envp->proto;
envp->nxs_cfg.proto_stream = &envp->proto;
envp->nxs_cfg.callbacks = &envp->cbs;
envp->nxs_cfg.channels = envp->channels;
envp->nxs_cfg.streambuf_len = CONFIG_SYSTEM_ADCSCOPE_STREAMBUF_LEN;
envp->nxs_cfg.rxbuf_len = CONFIG_SYSTEM_ADCSCOPE_RXBUF_LEN;
envp->nxs_cfg.rx_padding = CONFIG_SYSTEM_ADCSCOPE_RX_PADDING;
ret = nxscope_init(&envp->nxs, &envp->nxs_cfg);
if (ret < 0)
{
printf("ERROR: nxscope_init failed %d\n", ret);
goto errout_nonxscope;
}
return OK;
errout_nonxscope:
nxscope_proto_ser_deinit(&envp->proto);
errout_nointf:
nxscope_ser_deinit(&envp->intf);
errout_noproto:
return ret;
}
/****************************************************************************
* Name: adcscope_nxscope_clean
****************************************************************************/
static void adcscope_nxscope_clean(FAR struct adcscope_thr_env_s *envp)
{
/* Deinit nxscope */
nxscope_deinit(&envp->nxs);
/* Deinit protocol */
nxscope_proto_ser_deinit(&envp->proto);
/* Deinit interface */
nxscope_ser_deinit(&envp->intf);
}
/****************************************************************************
* Name: adcscope_samples_thr
****************************************************************************/
static FAR void *adcscope_samples_thr(FAR void *arg)
{
FAR struct adcscope_thr_env_s *envp = arg;
int ret;
size_t ptr;
size_t i;
DEBUGASSERT(envp);
printf("adcscope_samples_thr\n");
while (1)
{
#ifdef CONFIG_SYSTEM_ADCSCOPE_SWTRIG
/* Issue the software trigger to start ADC conversion */
ret = ioctl(envp->fd, ANIOC_TRIGGER, 0);
if (ret < 0)
{
printf("ERROR: ANIOC_TRIGGER ioctl failed: %d\n", -errno);
return NULL;
}
#endif
/* Read data from ADC */
ret = read(envp->fd, envp->data, envp->data_size);
if (ret < 0)
{
printf("ERROR: read failed %d\n", -errno);
}
else
{
/* Feed data to nxscope */
for (ptr = 0; ptr < ret / sizeof(struct adc_msg_s); )
{
for (i = 0; i < envp->channels; i++)
{
ADATA_PUT(&envp->nxs, i, envp->data[ptr].am_data);
ptr += 1;
}
}
}
#if CONFIG_SYSTEM_ADCSCOPE_FETCH_INTERVAL > 0
usleep(CONFIG_SYSTEM_ADCSCOPE_FETCH_INTERVAL);
#endif
}
return NULL;
}
#ifdef CONFIG_SYSTEM_ADCSCOPE_CDCACM
/****************************************************************************
* Name: adcscope_cdcacm_init
****************************************************************************/
static int adcscope_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: adcscope_channels
****************************************************************************/
static int adcscope_channels(FAR struct adcscope_thr_env_s *envp)
{
union nxscope_chinfo_type_u u;
FAR char *chname;
size_t i;
for (i = 0; i < envp->channels; i++)
{
/* Get channel name */
chname = &envp->chname[i * CHNAME_MAX];
snprintf(chname, CHNAME_MAX, "chan%d", i);
/* Register nxscope channel */
u.s.dtype = ADATA_DTYPE;
u.s._res = 0;
u.s.cri = 0;
nxscope_chan_init(&envp->nxs, i, chname, u.u8, 1, 0);
}
return OK;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: adcscope_main
****************************************************************************/
int main(int argc, FAR char *argv[])
{
struct adcscope_thr_env_s env;
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_ADCSCOPE_CDCACM
/* Initialize the USB CDCACM device */
ret = adcscope_cdcacm_init();
if (ret < 0)
{
printf("ERROR: adcscope_cdcacm_init failed %d\n", ret);
goto errout_noenv;
}
#endif
/* Initialize environment */
ret = adcscope_env_init(&env);
if (ret < 0)
{
printf("ERROR: failed to open %s\n", CONFIG_SYSTEM_ADCSCOPE_ADC_PATH);
goto errout_nonxscope;
}
/* Initialize NxScope */
ret = adcscope_nxscope_init(&env);
if (ret < 0)
{
printf("ERROR: failed to init nxscope\n");
goto errout_nonxscope;
}
/* Create channels */
ret = adcscope_channels(&env);
if (ret != OK)
{
printf("ERROR: adcscope_channels failed %d\n", ret);
goto errout;
}
/* Create samples thread */
ret = pthread_create(&thread, NULL, adcscope_samples_thr, &env);
if (ret != OK)
{
printf("ERROR: pthread_create failed %d\n", ret);
goto errout;
}
#ifdef CONFIG_SYSTEM_ADCSCOPE_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_ADCSCOPE_MAIN_INTERVAL);
}
errout:
adcscope_nxscope_clean(&env);
errout_nonxscope:
adcscope_env_clean(&env);
#ifdef CONFIG_SYSTEM_ADCSCOPE_CDCACM
errout_noenv:
#endif
return 0;
}