nuttx-apps/logging/nxscope/nxscope.c

1169 lines
26 KiB
C

/****************************************************************************
* apps/logging/nxscope/nxscope.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 <assert.h>
#include <debug.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <logging/nxscope/nxscope.h>
#include "nxscope_internals.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* NOTE: channel name is always terminated with a null-character */
#define CHINFO_DATA_SIZE_MAX (sizeof(struct nxscope_chinfo_s) - \
sizeof(char *) + CHAN_NAMELEN_MAX + 1)
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: nxscope_frame_send
*
* NOTE: This function assumes that we have exclusive access to the nxscope
* instance
*
****************************************************************************/
static int nxscope_frame_send(FAR struct nxscope_s *s, uint8_t id,
FAR uint8_t *data, size_t dlen)
{
size_t tx_i = 0;
int ret = OK;
DEBUGASSERT(s);
DEBUGASSERT(data);
#ifdef CONFIG_DEBUG_FEATURES
/* Validate TX buffer space */
if (s->txbuf_len < dlen + s->proto_cmd->footlen + s->proto_cmd->hdrlen)
{
ret = -ENOBUFS;
_err("ERROR: no space in txbuf %d\n", ret);
goto errout;
}
#endif
/* Offset for hdr */
tx_i = s->proto_cmd->hdrlen;
/* Copy data */
memcpy(&s->txbuf[tx_i], data, dlen);
tx_i += dlen;
/* Finalize a new frame */
ret = PROTO_FRAME_FINAL(s, s->proto_cmd, id, s->txbuf, &tx_i);
if (ret < 0)
{
_err("ERROR: PROTO_FRAME_FINAL failed %d\n", ret);
goto errout;
}
/* Send frame */
ret = INTF_SEND(s, s->intf_cmd, s->txbuf, tx_i);
if (ret < 0)
{
_err("ERROR: INTF_SEND failed %d\n", ret);
}
errout:
return ret;
}
/****************************************************************************
* Name: nxscope_cmninfo_send
*
* NOTE: This function assumes that we have exclusive access to the nxscope
* instance
*
****************************************************************************/
static int nxscope_cmninfo_send(FAR struct nxscope_s *s)
{
DEBUGASSERT(s);
return nxscope_frame_send(s,
NXSCOPE_HDRID_CMNINFO,
(FAR uint8_t *)&s->cmninfo,
sizeof(struct nxscope_info_cmn_s));
}
/****************************************************************************
* Name: nxscope_chinfo_send
*
* NOTE: This function assumes that we have exclusive access to the nxscope
* instance
*
****************************************************************************/
static int nxscope_chinfo_send(FAR struct nxscope_s *s, uint8_t ch)
{
uint8_t data[CHINFO_DATA_SIZE_MAX];
size_t namelen = 0;
size_t txlen = 0;
size_t tmp = 0;
DEBUGASSERT(s);
/* Copy channel info */
tmp = sizeof(struct nxscope_chinfo_s) - sizeof(char *);
memcpy(data, &s->chinfo[ch], tmp);
namelen = strnlen(s->chinfo[ch].name, CHAN_NAMELEN_MAX);
memcpy(&data[tmp], s->chinfo[ch].name, namelen);
/* Treminate name wit a null-character */
txlen = tmp + namelen + 1;
data[txlen - 1] = '\0';
/* Send frame */
return nxscope_frame_send(s, NXSCOPE_HDRID_CHINFO, data, txlen);
}
/****************************************************************************
* Name: nxscope_enable_req
*
* NOTE: This function assumes that we have exclusive access to the nxscope
* instance
*
****************************************************************************/
static int nxscope_enable_req(FAR struct nxscope_s *s,
FAR struct nxscope_set_frame_s *set,
uint16_t dlen)
{
FAR struct nxscope_enable_data_s *data = NULL;
int ret = OK;
int i = 0;
DEBUGASSERT(s);
DEBUGASSERT(set);
/* Get data */
data = (FAR struct nxscope_enable_data_s *) set->data;
/* Handle set request */
switch (set->req)
{
case NXSCOPE_SET_REQ_SINGLE:
{
/* Verify request length */
if (dlen != (sizeof(struct nxscope_set_frame_s) +
NXSCOPE_ENABLE_LEN - 1))
{
_err("ERROR: invalid enable single dlen = %d\n", dlen);
ret = -EINVAL;
goto errout;
}
/* Validate data */
if (data->ch[0].en != 0 && data->ch[0].en != 1)
{
ret = -EINVAL;
goto errout;
}
if (set->chan > s->cmninfo.chmax)
{
ret = -EINVAL;
goto errout;
}
/* Write configuration */
s->chinfo[set->chan].enable = data->ch[0].en;
break;
}
case NXSCOPE_SET_REQ_BULK:
{
/* Verify request length */
if (dlen != (sizeof(struct nxscope_set_frame_s) +
NXSCOPE_ENABLE_LEN * s->cmninfo.chmax - 1))
{
_err("ERROR: invalid enable bulk dlen = %d\n", dlen);
ret = -EINVAL;
goto errout;
}
/* Validate data */
for (i = 0; i < s->cmninfo.chmax; i++)
{
if (data->ch[i].en != 0 && data->ch[i].en != 1)
{
ret = -EINVAL;
goto errout;
}
}
/* Write configuration */
for (i = 0; i < s->cmninfo.chmax; i++)
{
s->chinfo[i].enable = data->ch[i].en;
}
break;
}
case NXSCOPE_SET_REQ_ALL:
{
/* Verify request length */
if (dlen != (sizeof(struct nxscope_set_frame_s) +
NXSCOPE_ENABLE_LEN - 1))
{
_err("ERROR: invalid enable all dlen = %d\n", dlen);
ret = -EINVAL;
goto errout;
}
if (data->ch[0].en != 0 && data->ch[0].en != 1)
{
ret = -EINVAL;
goto errout;
}
/* Write configuration */
for (i = 0; i < s->cmninfo.chmax; i++)
{
s->chinfo[i].enable = data->ch[0].en;
}
break;
}
default:
{
_err("ERROR: invalid set->req=%d\n", set->req);
ret = -EINVAL;
break;
}
}
errout:
return ret;
}
#ifdef CONFIG_LOGGING_NXSCOPE_DIVIDER
/****************************************************************************
* Name: nxscope_div_req
*
* NOTE: This function assumes that we have exclusive access to the nxscope
* instance
*
****************************************************************************/
static int nxscope_div_req(FAR struct nxscope_s *s,
FAR struct nxscope_set_frame_s *set,
uint16_t dlen)
{
FAR struct nxscope_div_data_s *data = NULL;
int ret = OK;
int i = 0;
DEBUGASSERT(s);
DEBUGASSERT(set);
/* Get data */
data = (FAR struct nxscope_div_data_s *)set->data;
/* Handle set request */
switch (set->req)
{
case NXSCOPE_SET_REQ_SINGLE:
{
/* Verify request length */
if (dlen != (sizeof(struct nxscope_set_frame_s) +
NXSCOPE_DIV_LEN - 1))
{
_err("ERROR: invalid div single dlen = %d\n", dlen);
ret = -EINVAL;
goto errout;
}
if (set->chan > s->cmninfo.chmax)
{
ret = -EINVAL;
goto errout;
}
/* Write configuration */
s->chinfo[set->chan].div = data->ch[0].div;
break;
}
case NXSCOPE_SET_REQ_BULK:
{
/* Verify request length */
if (dlen != (sizeof(struct nxscope_set_frame_s) +
NXSCOPE_DIV_LEN * s->cmninfo.chmax - 1))
{
_err("ERROR: invalid div bulk dlen = %d\n", dlen);
ret = -EINVAL;
goto errout;
}
/* Write configuration */
for (i = 0; i < s->cmninfo.chmax; i++)
{
s->chinfo[i].div = data->ch[i].div;
}
break;
}
case NXSCOPE_SET_REQ_ALL:
{
/* Verify request length */
if (dlen != (sizeof(struct nxscope_set_frame_s) +
NXSCOPE_DIV_LEN - 1))
{
_err("ERROR: invalid div all dlen = %d\n", dlen);
ret = -EINVAL;
goto errout;
}
/* Write configuration */
for (i = 0; i < s->cmninfo.chmax; i++)
{
s->chinfo[i].div = data->ch[0].div;
}
break;
}
default:
{
_err("ERROR: invalid set->req=%d\n", set->req);
ret = -EINVAL;
break;
}
}
errout:
return ret;
}
#endif
/****************************************************************************
* Name: nxscope_start_set
*
* NOTE: This function assumes that we have exclusive access to the nxscope
* instance
*
****************************************************************************/
static int nxscope_start_set(FAR struct nxscope_s *s, bool start)
{
int ret = OK;
s->start = start;
/* User specific callback */
if (s->callbacks != NULL && s->callbacks->start != NULL)
{
ret = s->callbacks->start(s->callbacks->start_priv, start);
if (ret < 0)
{
_err("ERROR: s->callbacks->start failed %d\n", ret);
}
}
return ret;
}
/****************************************************************************
* Name: nxscope_start_req
*
* NOTE: This function assumes that we have exclusive access to the nxscope
* instance
*
****************************************************************************/
static int nxscope_start_req(FAR struct nxscope_s *s,
FAR struct nxscope_start_data_s *data)
{
int ret = -EINVAL;
DEBUGASSERT(s);
DEBUGASSERT(data);
if (data->start == 0 || data->start == 1)
{
_info("data->start=%d\n", data->start);
ret = nxscope_start_set(s, data->start);
}
return ret;
}
/****************************************************************************
* Name: nxscope_stream_reset
*
* NOTE: This function assumes that we have exclusive access to the nxscope
* instance
*
****************************************************************************/
static void nxscope_stream_reset(FAR struct nxscope_s *s)
{
DEBUGASSERT(s);
/* Offset for hdr + 1 byte for flags */
s->stream_i = s->proto_stream->hdrlen + 1;
/* Reset flags */
s->streambuf[s->proto_stream->hdrlen] = 0;
}
/****************************************************************************
* Name: nxscope_stream_empty
*
* NOTE: This function assumes that we have exclusive access to the nxscope
* instance
*
****************************************************************************/
static bool nxscope_stream_empty(FAR struct nxscope_s *s)
{
DEBUGASSERT(s);
if (s->stream_i > s->proto_stream->hdrlen + 1)
{
return false;
}
else
{
return true;
}
}
#ifdef CONFIG_LOGGING_NXSCOPE_ACKFRAMES
/****************************************************************************
* Name: nxscope_ack
*
* NOTE: This function assumes that we have exclusive access to the nxscope
* instance
*
****************************************************************************/
static void nxscope_ack(FAR struct nxscope_s *s, int ret)
{
DEBUGASSERT(s);
nxscope_frame_send(s, NXSCOPE_HDRID_ACK, (FAR uint8_t *)&ret, 4);
}
#endif
/****************************************************************************
* Name: nxscope_recv_handle
****************************************************************************/
static int nxscope_recv_handle(FAR struct nxscope_s *s, uint8_t id,
uint16_t dlen, FAR uint8_t *buf)
{
int ret = OK;
DEBUGASSERT(s);
DEBUGASSERT(buf);
nxscope_lock(s);
switch (id)
{
case NXSCOPE_HDRID_CMNINFO:
{
_info("NXSCOPE_HDRID_CMNINFO\n");
/* Verify request length */
if (dlen != 0)
{
_err("ERROR: cmninfo request invalid dlen = %d\n", dlen);
goto errout;
}
/* Send cmninfo response */
ret = nxscope_cmninfo_send(s);
break;
}
case NXSCOPE_HDRID_CHINFO:
{
FAR uint8_t *ch = buf;
_info("NXSCOPE_HDRID_CHINFO %d\n", *ch);
/* Verify request length */
if (dlen != 1)
{
_err("ERROR: chinfo request invalid dlen = %d\n", dlen);
goto errout;
}
/* Send chinfo response */
ret = nxscope_chinfo_send(s, *ch);
break;
}
case NXSCOPE_HDRID_START:
{
FAR struct nxscope_start_data_s *data =
(FAR struct nxscope_start_data_s *)buf;
_info("NXSCOPE_HDRID_START\n");
/* Verify request length */
if (dlen != NXSCOPE_START_LEN)
{
_err("ERROR: start request invalid dlen = %d\n", dlen);
goto errout;
}
/* Start request */
ret = nxscope_start_req(s, data);
#ifdef CONFIG_LOGGING_NXSCOPE_ACKFRAMES
/* Send ACK */
nxscope_ack(s, ret);
#endif
break;
}
case NXSCOPE_HDRID_ENABLE:
{
FAR struct nxscope_set_frame_s *data =
(FAR struct nxscope_set_frame_s *)buf;
_info("NXSCOPE_HDRID_ENABLE\n");
/* Enable request */
ret = nxscope_enable_req(s, data, dlen);
#ifdef CONFIG_LOGGING_NXSCOPE_ACKFRAMES
/* Send ACK */
nxscope_ack(s, ret);
#endif
break;
}
case NXSCOPE_HDRID_DIV:
{
#ifdef CONFIG_LOGGING_NXSCOPE_DIVIDER
FAR struct nxscope_set_frame_s *data =
(FAR struct nxscope_set_frame_s *)buf;
_info("NXSCOPE_HDRID_DIV\n");
/* Divider request */
ret = nxscope_div_req(s, data, dlen);
#else
ret = -EPERM;
#endif
#ifdef CONFIG_LOGGING_NXSCOPE_ACKFRAMES
/* Send ACK */
nxscope_ack(s, ret);
#endif
break;
}
default:
{
/* User specific commands */
if (s->callbacks != NULL && s->callbacks->userid != NULL)
{
ret = s->callbacks->userid(s->callbacks->userid_priv, id, buf);
if (ret < 0)
{
_err("ERROR: s->callbacks->userid failed %d\n", ret);
}
}
else
{
_err("ERROR: unsupported id %d\n", id);
ret = -EINVAL;
}
}
}
errout:
nxscope_unlock(s);
return ret;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: nxscope_init
*
* Description:
* Initialize a nxscope instance
*
* Input Parameters:
* s - a pointer to a nxscope instance
* cfg - a pointer to a nxscope configuration data
*
****************************************************************************/
int nxscope_init(FAR struct nxscope_s *s, FAR struct nxscope_cfg_s *cfg)
{
int ret = OK;
int i = 0;
DEBUGASSERT(s);
DEBUGASSERT(cfg);
/* Reset structure */
memset(s, 0, sizeof(struct nxscope_s));
/* Connect command interface */
DEBUGASSERT(cfg->intf_cmd);
DEBUGASSERT(cfg->intf_cmd->ops->send);
DEBUGASSERT(cfg->intf_cmd->ops->recv);
/* Must be initialized */
if (!cfg->intf_cmd->initialized)
{
ret = -EINVAL;
goto errout;
}
s->intf_cmd = cfg->intf_cmd;
/* Connect command protocol handler */
DEBUGASSERT(cfg->proto_cmd);
DEBUGASSERT(cfg->proto_cmd->ops->frame_get);
DEBUGASSERT(cfg->proto_cmd->ops->frame_final);
/* Must be initialized */
if (!cfg->proto_cmd->initialized)
{
ret = -EINVAL;
goto errout;
}
s->proto_cmd = cfg->proto_cmd;
/* Connect stream interface */
DEBUGASSERT(cfg->intf_stream);
DEBUGASSERT(cfg->intf_stream->ops->send);
DEBUGASSERT(cfg->intf_stream->ops->recv);
/* Must be initialized */
if (!cfg->intf_stream->initialized)
{
ret = -EINVAL;
goto errout;
}
s->intf_stream = cfg->intf_stream;
/* Connect stream protocol handler */
DEBUGASSERT(cfg->proto_stream);
DEBUGASSERT(cfg->proto_stream->ops->frame_get);
DEBUGASSERT(cfg->proto_stream->ops->frame_final);
/* Must be initialized */
if (!cfg->proto_stream->initialized)
{
ret = -EINVAL;
goto errout;
}
s->proto_stream = cfg->proto_stream;
/* Connect callbacks (optional) */
s->callbacks = cfg->callbacks;
/* Allocate memory for stream buffer */
DEBUGASSERT(cfg->streambuf_len > 0);
s->streambuf = zalloc(cfg->streambuf_len);
if (s->streambuf == NULL)
{
ret = -errno;
_err("ERROR: streambuf zalloc failed %d\n", ret);
goto errout;
}
s->streambuf_len = cfg->streambuf_len;
/* Allocate memory for nxscope channels info */
DEBUGASSERT(cfg->channels > 0);
s->chinfo_size = cfg->channels * sizeof(struct nxscope_chinfo_s);
s->chinfo = zalloc(s->chinfo_size);
if (s->chinfo == NULL)
{
ret = -errno;
_err("ERROR: chinfo zalloc failed %d\n", ret);
goto errout;
}
#ifdef CONFIG_LOGGING_NXSCOPE_DIVIDER
/* Allocate memory for divider counters */
s->cntr = zalloc(cfg->channels * sizeof(uint32_t));
if (s->cntr == NULL)
{
ret = -errno;
_err("ERROR: cntr zalloc failed %d\n", ret);
goto errout;
}
#endif
/* Allocate memory for RX buffer */
DEBUGASSERT(cfg->rxbuf_len > 0);
s->rxbuf_len = cfg->rxbuf_len;
s->rxbuf = zalloc(s->rxbuf_len);
if (s->rxbuf == NULL)
{
ret = -errno;
_err("ERROR: rxbuf zalloc failed %d\n", ret);
goto errout;
}
/* Allocate memory for TX buffer.
* We must fit the longest possible CHINFO response.
*/
s->txbuf_len = (CHINFO_DATA_SIZE_MAX + s->proto_cmd->footlen +
s->proto_cmd->hdrlen);
s->txbuf = zalloc(s->txbuf_len);
if (s->txbuf == NULL)
{
ret = -errno;
_err("ERROR: txbuf zalloc failed %d\n", ret);
goto errout;
}
#ifdef CONFIG_LOGGING_NXSCOPE_CRICHANNELS
/* Allocate memory for critical channels buffer */
s->cribuf_len = cfg->cribuf_len;
s->cribuf = zalloc(s->cribuf_len);
if (s->cribuf == NULL)
{
ret = -errno;
_err("ERROR: cribuf zalloc failed %d\n", ret);
goto errout;
}
#endif
/* Initialize lock */
ret = pthread_mutex_init(&s->lock, NULL);
if (ret != 0)
{
_err("ERROR: pthread_mutex_init failed %d\n", errno);
goto errout;
}
/* Reset stream buffer */
nxscope_stream_reset(s);
/* Initialize info data */
s->cmninfo.chmax = cfg->channels;
s->cmninfo.flags = 0;
#ifdef CONFIG_LOGGING_NXSCOPE_DIVIDER
s->cmninfo.flags |= NXSCOPE_FLAGS_DIVIDER_SUPPORT;
#endif
#ifdef CONFIG_LOGGING_NXSCOPE_ACKFRAMES
s->cmninfo.flags |= NXSCOPE_FLAGS_ACK_SUPPORT;
#endif
s->cmninfo.rx_padding = cfg->rx_padding;
/* Initialize channels */
for (i = 0; i < cfg->channels; i++)
{
s->chinfo[i].name = "\0";
}
return OK;
errout:
if (s->streambuf != NULL)
{
free(s->streambuf);
}
if (s->chinfo != NULL)
{
free(s->chinfo);
}
#ifdef CONFIG_LOGGING_NXSCOPE_DIVIDER
if (s->cntr != NULL)
{
free(s->cntr);
}
#endif
if (s->rxbuf != NULL)
{
free(s->rxbuf);
}
if (s->txbuf != NULL)
{
free(s->txbuf);
}
#ifdef CONFIG_LOGGING_NXSCOPE_CRICHANNELS
if (s->cribuf != NULL)
{
free(s->cribuf);
}
#endif
return ret;
}
/****************************************************************************
* Name: nxscope_deinit
*
* Description:
* De-initialize a nxscope instance
*
* Input Parameters:
* s - a pointer to a nxscope instance
*
****************************************************************************/
void nxscope_deinit(FAR struct nxscope_s *s)
{
DEBUGASSERT(s);
/* Free mutex */
pthread_mutex_destroy(&s->lock);
/* Free allocated memory */
if (s->streambuf != NULL)
{
free(s->streambuf);
}
if (s->chinfo != NULL)
{
free(s->chinfo);
}
#ifdef CONFIG_LOGGING_NXSCOPE_DIVIDER
if (s->cntr != NULL)
{
free(s->cntr);
}
#endif
#ifdef CONFIG_LOGGING_NXSCOPE_CRICHANNELS
if (s->cribuf != NULL)
{
free(s->cribuf);
}
#endif
if (s->txbuf != NULL)
{
free(s->txbuf);
}
}
/****************************************************************************
* Name: nxscope_lock
*
* Description:
* Lock a nxscope instance
*
* Input Parameters:
* s - a pointer to a nxscope instance
*
****************************************************************************/
void nxscope_lock(FAR struct nxscope_s *s)
{
DEBUGASSERT(s);
pthread_mutex_lock(&s->lock);
}
/****************************************************************************
* Name: nxscope_unlock
*
* Description:
* Unlock a nxscope instance
*
* Input Parameters:
* s - a pointer to a nxscope instance
*
****************************************************************************/
void nxscope_unlock(FAR struct nxscope_s *s)
{
DEBUGASSERT(s);
pthread_mutex_unlock(&s->lock);
}
/****************************************************************************
* Name: nxscope_stream
*
* Description:
* Send nxscope stream data.
*
* NOTE: It's the user's responsibility to periodically call this function.
*
* Input Parameters:
* s - a pointer to a nxscope instance
*
****************************************************************************/
int nxscope_stream(FAR struct nxscope_s *s)
{
int ret = OK;
DEBUGASSERT(s);
nxscope_lock(s);
/* Do nothing if stream not started */
if (!s->start)
{
ret = OK;
goto errout;
}
/* Do nothing if no data */
if (nxscope_stream_empty(s))
{
goto errout;
}
/* Send stream data */
ret = nxscope_stream_send(s, s->streambuf, &s->stream_i);
if (ret < 0)
{
_err("ERROR: nxscope_stream_send failed %d\n", ret);
goto errout;
}
/* Reset stream buffer */
nxscope_stream_reset(s);
errout:
nxscope_unlock(s);
return ret;
}
/****************************************************************************
* Name: nxscope_recv
*
* Description:
* Receive and handle nxscope protocol data.
*
* NOTE: It's the user's responsibility to periodically call this function.
*
* Input Parameters:
* s - a pointer to a nxscope instance
*
****************************************************************************/
int nxscope_recv(FAR struct nxscope_s *s)
{
int ret = OK;
size_t size_left = 0;
size_t bytes_left = 0;
struct nxscope_frame_s frame;
DEBUGASSERT(s);
do
{
/* Accumulate data until buffer empty */
size_left = s->rxbuf_len - s->rxbuf_i;
ret = INTF_RECV(s, s->intf_cmd, &s->rxbuf[s->rxbuf_i], size_left);
if (ret <= 0)
{
break;
}
s->rxbuf_i += ret;
}
while (1);
/* Return if no data */
if (s->rxbuf_i == 0)
{
goto errout;
}
/* Get frame */
ret = PROTO_FRAME_GET(s, s->proto_cmd, s->rxbuf, s->rxbuf_i, &frame);
if (ret < 0)
{
/* Do not pass err further */
ret = OK;
goto errout;
}
/* Handle frame */
ret = nxscope_recv_handle(s, frame.id, frame.dlen, frame.data);
if (ret < 0)
{
_err("ERROR: nxscope_recv_handle failed %d\n", ret);
goto errout;
}
/* Keep the remaining data */
bytes_left = s->rxbuf_i - frame.drop;
if (bytes_left > 0)
{
memmove(s->rxbuf, &s->rxbuf[frame.drop], bytes_left);
}
errout:
s->rxbuf_i = bytes_left;
return ret;
}
/****************************************************************************
* Name: nxscope_stream_start
*
* Description:
* Start/stop data stream
*
* Input Parameters:
* s - a pointer to a nxscope instance
* start - start/stop
*
****************************************************************************/
int nxscope_stream_start(FAR struct nxscope_s *s, bool start)
{
int ret = OK;
DEBUGASSERT(s);
nxscope_lock(s);
_info("force stream_start=%d\n", start);
ret = nxscope_start_set(s, start);
nxscope_unlock(s);
return ret;
}