6#include "dawn/proto/nxscope/nxscope.hxx"
10#include "dawn/io/common.hxx"
11#include "dawn/io/ddata.hxx"
15#if defined(CONFIG_DAWN_PROTO_NXSCOPE_SAMPLE_THREAD) + defined(CONFIG_DAWN_IO_NOTIFY) != 1
16# error one sampling method can be supported
21#define NXSCOPE_RECV_INTERVAL (10000)
25#define NXSCOPE_SAMPLE_INTERVAL (1000000)
27static inline uint16_t nxscopeU16Le(
const uint8_t *p)
29 return (uint16_t)p[0] | ((uint16_t)p[1] << 8);
32static inline uint32_t nxscopeU32Le(
const uint8_t *p)
34 return (uint32_t)p[0] | ((uint32_t)p[1] << 8) | ((uint32_t)p[2] << 16) | ((uint32_t)p[3] << 24);
37#ifdef CONFIG_DAWN_IO_NOTIFY
38int CProtoNxscope::ioNotifierCb(
void *priv,
io_ddata_t *data)
40 SProtoNxscopeIochan *chan = (SProtoNxscopeIochan *)priv;
42 if (!chan || !chan->obj || !data || !chan->put)
51int CProtoNxscope::sendAck(
int ret)
55 if (nxs.proto_cmd ==
nullptr || nxs.intf_cmd ==
nullptr)
60 if (nxs.proto_cmd->ops ==
nullptr || nxs.intf_cmd->ops ==
nullptr)
65 if (nxs.proto_cmd->ops->frame_final ==
nullptr || nxs.intf_cmd->ops->send ==
nullptr)
70 if (nxs.txbuf ==
nullptr)
75 if (nxs.txbuf_len < nxs.proto_cmd->hdrlen +
sizeof(ret) + nxs.proto_cmd->footlen)
80 len = nxs.proto_cmd->hdrlen;
81 std::memcpy(&nxs.txbuf[len], &ret,
sizeof(ret));
84 ret = nxs.proto_cmd->ops->frame_final(nxs.proto_cmd, NXSCOPE_HDRID_ACK, nxs.txbuf, &len);
90 return nxs.intf_cmd->ops->send(nxs.intf_cmd, nxs.txbuf, (
int)len);
93int CProtoNxscope::userIdCb(
void *priv, uint8_t
id, uint8_t *buff)
100 if (obj ==
nullptr || buff ==
nullptr)
105 handled = (
id == NXSCOPE_USER_SET_IO ||
id == NXSCOPE_USER_SET_IO_SEEK);
114 ret = obj->handleUserCommand(
id, buff);
116#ifdef CONFIG_LOGGING_NXSCOPE_ACKFRAMES
120 ack = obj->sendAck(ret);
123 DAWNERR(
"nxscope user ack failed: %d\n", ack);
132int CProtoNxscope::handleUserCommand(uint8_t
id, uint8_t *buff)
136 case NXSCOPE_USER_SET_IO:
138 return userSetIO(buff);
141 case NXSCOPE_USER_SET_IO_SEEK:
143 return userSetIOSeek(buff);
155 for (
auto &iochan : vio)
157 if (iochan.io !=
nullptr && iochan.io->getIdV() == objid)
166int CProtoNxscope::userSetIO(uint8_t *buff)
170 SProtoNxscopeIochan *iochan;
176 objid = nxscopeU32Le(buff);
177 size = nxscopeU16Le(&buff[4]);
179 iochan = findIochan(objid);
180 if (iochan ==
nullptr || iochan->io ==
nullptr)
191 iodata = iochan->setData;
192 if (iodata ==
nullptr)
204 std::memcpy(iodata->
getDataPtr(), &buff[6], size);
214 std::memcpy(iodata->
getDataPtr(), &buff[6], size);
225int CProtoNxscope::userSetIOSeek(uint8_t *buff)
230 SProtoNxscopeIochan *iochan;
236 objid = nxscopeU32Le(buff);
237 offset = nxscopeU32Le(&buff[4]);
238 size = nxscopeU16Le(&buff[8]);
240 iochan = findIochan(objid);
241 if (iochan ==
nullptr || iochan->io ==
nullptr)
257 iodata = iochan->setData;
258 if (iodata ==
nullptr)
268 std::memcpy(iodata->
getDataPtr(), &buff[10], size);
272 ret = io->
setData(*iodata, offset);
278int CProtoNxscope::configureNxscope()
284 ret = nxscope_proto_ser_init(&nxsProto,
nullptr);
287 DAWNERR(
"nxscope_proto_ser_init failed: %d\n", ret);
293 nxsCbs.userid_priv =
this;
294 nxsCbs.userid = userIdCb;
295 nxsCbs.start_priv =
nullptr;
296 nxsCbs.start =
nullptr;
300 nxsCfg.streambuf_len = CONFIG_DAWN_PROTO_NXSCOPE_STREAMBUF_LEN;
301 nxsCfg.rxbuf_len = CONFIG_DAWN_PROTO_NXSCOPE_RXBUF_LEN;
302 nxsCfg.rx_padding = CONFIG_DAWN_PROTO_NXSCOPE_RX_PADDING;
303#ifdef CONFIG_LOGGING_NXSCOPE_CRICHANNELS
304 nxsCfg.cribuf_len = CONFIG_DAWN_PROTO_NXSCOPE_CRIBUF_LEN;
309 nxsCfg.proto_cmd = &nxsProto;
310 nxsCfg.proto_stream = &nxsProto;
311 nxsCfg.callbacks = &nxsCbs;
312 nxsCfg.channels = vchannels.size();
314 ret = nxscope_init(&nxs, &nxsCfg);
317 DAWNERR(
"nxscope_init failed: %d\n", ret);
324int CProtoNxscope::allocObject(SProtoNxscopeIOBind *alloc)
326 DAWNINFO(
"allocate object 0x%" PRIx32
"\n", alloc->objid.v);
334 vchannels.push_back(alloc);
339int CProtoNxscope::allocNames(
size_t j, SProtoNxscopeNames *alloc)
341 DAWNINFO(
"channel %zu with name %s\n", j, alloc->name);
345 vnames.push_back(alloc);
350uint8_t CProtoNxscope::getChannelDim(
const CIOCommon &io)
355uint8_t CProtoNxscope::getChannelDtype(
const CIOCommon &io)
361#ifdef CONFIG_DAWN_DTYPE_INT32
364 return NXSCOPE_TYPE_INT32;
368#ifdef CONFIG_DAWN_DTYPE_UINT32
371 return NXSCOPE_TYPE_UINT32;
375#ifdef CONFIG_DAWN_DTYPE_UINT64
378 return NXSCOPE_TYPE_UINT64;
382#ifdef CONFIG_DAWN_DTYPE_FLOAT
385 return NXSCOPE_TYPE_FLOAT;
389#ifdef CONFIG_DAWN_DTYPE_B16
392 return NXSCOPE_TYPE_B16;
396#ifdef CONFIG_DAWN_DTYPE_UB16
399 return NXSCOPE_TYPE_UB16;
403#ifdef CONFIG_DAWN_DTYPE_CHAR
406 return NXSCOPE_TYPE_CHAR;
412 DAWNERR(
"unsuported nxscope type %d\n", dtype);
413 return NXSCOPE_TYPE_NONE;
418int CProtoNxscope::nxscopeChannelsCreate()
420 union nxscope_chinfo_type_u u;
421 const SProtoNxscopeIOBind *alloc;
426 hasStreamChannels =
false;
428 for (bindidx = 0; bindidx < vchannels.size(); bindidx++)
430 alloc = vchannels[bindidx];
435 SProtoNxscopeIochan iochan;
438 if (bindidx < vnames.size())
440 name = vnames[bindidx]->name;
447 DAWNINFO(
"nxscope channel %s %p 0x%x\n", name, io, alloc->objid.v);
451 iochan.chan = chanid;
452 iochan.dim = getChannelDim(*io);
453 iochan.stream = io->
isRead();
456 iochan.setData =
nullptr;
457#ifdef CONFIG_DAWN_IO_NOTIFY
458 iochan.put =
nullptr;
460#ifdef CONFIG_DAWN_PROTO_NXSCOPE_SAMPLE_THREAD
461 iochan.sample =
nullptr;
462 iochan.data =
nullptr;
467 DAWNERR(
"IO 0x%" PRIx32
" has neither read nor write support\n", alloc->objid.v);
471 if (iochan.io->isWrite())
473 if (iochan.io->isSeekable())
475 iochan.setData = iochan.io->ddata_alloc(1, CONFIG_DAWN_PROTO_NXSCOPE_RXBUF_LEN);
479 iochan.setData = iochan.io->ddata_alloc(1);
482 if (iochan.setData ==
nullptr)
484 DAWNERR(
"failed to allocate set buffer for objid=0x%" PRIx32
"\n",
486#ifdef CONFIG_DAWN_PROTO_NXSCOPE_SAMPLE_THREAD
488 iochan.data =
nullptr;
496 ret = bindChannelCallbacks(iochan, io->
getDtype());
499 if (iochan.io->isWrite())
501 DAWNINFO(
"set-only nxscope channel for objid=0x%" PRIx32
"\n",
503 iochan.stream =
false;
507 DAWNERR(
"Unsupported data type %d for objid=0x%" PRIx32
"\n",
510#ifdef CONFIG_DAWN_PROTO_NXSCOPE_SAMPLE_THREAD
512 iochan.data =
nullptr;
514 delete iochan.setData;
515 iochan.setData =
nullptr;
521#ifdef CONFIG_DAWN_IO_NOTIFY
522 if (iochan.stream && iochan.io->isNotify() ==
false)
524 if (iochan.io->isWrite())
526 DAWNINFO(
"set-only nxscope channel (no notify) for "
527 "objid=0x%" PRIx32
"\n",
529 iochan.stream =
false;
533 DAWNERR(
"notify not supported for objid=0x%" PRIx32
"\n", alloc->objid.v);
534 delete iochan.setData;
535 iochan.setData =
nullptr;
541#ifdef CONFIG_DAWN_PROTO_NXSCOPE_SAMPLE_THREAD
542 if (iochan.stream && iochan.io->isSeekable())
544 if (iochan.io->isWrite())
546 DAWNINFO(
"set-only nxscope channel (seekable) for "
547 "objid=0x%" PRIx32
"\n",
549 iochan.stream =
false;
553 DAWNERR(
"seekable IO not supported by NXScope "
554 "(objid=0x%08" PRIx32
")\n",
555 iochan.io->getIdV());
556 delete iochan.setData;
557 iochan.setData =
nullptr;
564 iochan.data = iochan.io->ddata_alloc(1);
565 if (iochan.data ==
nullptr)
567 DAWNERR(
"failed to allocate sample buffer for objid=0x%" PRIx32
"\n",
569 delete iochan.setData;
570 iochan.setData =
nullptr;
579 u.s.dtype = getChannelDtype(*io);
585 nxscope_chan_init(&nxs, chanid,
const_cast<char *
>(name), u.u8, iochan.dim, 0);
586 iochan.chan = chanid;
588 hasStreamChannels =
true;
595 vio.push_back(iochan);
599 DAWNERR(
"IO not found for objid=0x%" PRIx32
"\n", alloc->objid.v);
607#ifdef CONFIG_DAWN_IO_NOTIFY
608int CProtoNxscope::putInt32(
struct nxscope_s *nxs, uint8_t chan,
void *data, uint8_t dim)
610 return nxscope_put_vint32(nxs, chan,
static_cast<int32_t *
>(data), dim);
613int CProtoNxscope::putUint32(
struct nxscope_s *nxs, uint8_t chan,
void *data, uint8_t dim)
615 return nxscope_put_vuint32(nxs, chan,
static_cast<uint32_t *
>(data), dim);
618int CProtoNxscope::putUint64(
struct nxscope_s *nxs, uint8_t chan,
void *data, uint8_t dim)
620 return nxscope_put_vuint64(nxs, chan,
static_cast<uint64_t *
>(data), dim);
623int CProtoNxscope::putFloat(
struct nxscope_s *nxs, uint8_t chan,
void *data, uint8_t dim)
625 return nxscope_put_vfloat(nxs, chan,
static_cast<float *
>(data), dim);
629#ifdef CONFIG_DAWN_PROTO_NXSCOPE_SAMPLE_THREAD
630int CProtoNxscope::sampleInt32(
CProtoNxscope *obj, SProtoNxscopeIochan *iochan)
634 if (!iochan || !iochan->data)
639 ret = iochan->io->getData(*iochan->data, 1);
642 ret = nxscope_put_vint32(
643 &obj->nxs, iochan->chan,
static_cast<int32_t *
>(iochan->data->getDataPtr()), iochan->dim);
649int CProtoNxscope::sampleUint32(
CProtoNxscope *obj, SProtoNxscopeIochan *iochan)
653 if (!iochan || !iochan->data)
658 ret = iochan->io->getData(*iochan->data, 1);
661 ret = nxscope_put_vuint32(
662 &obj->nxs, iochan->chan,
static_cast<uint32_t *
>(iochan->data->getDataPtr()), iochan->dim);
668int CProtoNxscope::sampleUint64(
CProtoNxscope *obj, SProtoNxscopeIochan *iochan)
672 if (!iochan || !iochan->data)
677 ret = iochan->io->getData(*iochan->data, 1);
680 ret = nxscope_put_vuint64(
681 &obj->nxs, iochan->chan,
static_cast<uint64_t *
>(iochan->data->getDataPtr()), iochan->dim);
687int CProtoNxscope::sampleFloat(
CProtoNxscope *obj, SProtoNxscopeIochan *iochan)
691 if (!iochan || !iochan->data)
696 ret = iochan->io->getData(*iochan->data, 1);
699 ret = nxscope_put_vfloat(
700 &obj->nxs, iochan->chan,
static_cast<float *
>(iochan->data->getDataPtr()), iochan->dim);
707int CProtoNxscope::bindChannelCallbacks(SProtoNxscopeIochan &iochan, uint8_t dtype)
711#ifdef CONFIG_DAWN_DTYPE_INT32
714# ifdef CONFIG_DAWN_IO_NOTIFY
715 iochan.put = &putInt32;
717# ifdef CONFIG_DAWN_PROTO_NXSCOPE_SAMPLE_THREAD
718 iochan.sample = &sampleInt32;
724#ifdef CONFIG_DAWN_DTYPE_UINT32
727# ifdef CONFIG_DAWN_IO_NOTIFY
728 iochan.put = &putUint32;
730# ifdef CONFIG_DAWN_PROTO_NXSCOPE_SAMPLE_THREAD
731 iochan.sample = &sampleUint32;
737#ifdef CONFIG_DAWN_DTYPE_UINT64
740# ifdef CONFIG_DAWN_IO_NOTIFY
741 iochan.put = &putUint64;
743# ifdef CONFIG_DAWN_PROTO_NXSCOPE_SAMPLE_THREAD
744 iochan.sample = &sampleUint64;
750#ifdef CONFIG_DAWN_DTYPE_FLOAT
753# ifdef CONFIG_DAWN_IO_NOTIFY
754 iochan.put = &putFloat;
756# ifdef CONFIG_DAWN_PROTO_NXSCOPE_SAMPLE_THREAD
757 iochan.sample = &sampleFloat;
772#ifdef CONFIG_DAWN_PROTO_NXSCOPE_SAMPLE_THREAD
773void CProtoNxscope::getAndPut(SProtoNxscopeIochan *iochan)
777 if (!iochan || !iochan->sample)
782 ret = iochan->sample(
this, iochan);
783 if (ret < 0 && ret != -EAGAIN)
785 DAWNERR(
"sampling failed for chan=%d ret=%d\n", iochan->chan, ret);
790void CProtoNxscope::threadRecv()
800 if (hasStreamChannels)
802 ret = nxscope_stream(&nxs);
805 DAWNERR(
"ERROR: nxscope_stream failed %d\n", ret);
811 ret = nxscope_recv(&nxs);
814 DAWNERR(
"ERROR: nxscope_recv failed %d\n", ret);
817#if NXSCOPE_RECV_NONBLOCK == 1
820 usleep(NXSCOPE_RECV_INTERVAL);
823 while (!threadRecvMember.shouldQuit());
827 threadRecvMember.markThreadFinished();
830#ifdef CONFIG_DAWN_PROTO_NXSCOPE_SAMPLE_THREAD
831void CProtoNxscope::threadSample()
846 usleep(NXSCOPE_SAMPLE_INTERVAL);
848 while (!threadSampleMember.shouldQuit());
852 threadSampleMember.markThreadFinished();
857CProtoNxscope::~CProtoNxscope()
861#ifdef CONFIG_DAWN_PROTO_NXSCOPE_SAMPLE_THREAD
875 nxscope_deinit(&nxs);
894 return nxscopeChannelsCreate();
929#ifdef CONFIG_DAWN_PROTO_NXSCOPE_SAMPLE_THREAD
932 threadSampleMember.setThreadFunc([
this]() { threadSample(); });
933 ret = threadSampleMember.threadStart();
948 ret = io.io->setNotifier(ioNotifierCb, 0, (
void *)&io);
953 DAWNINFO(
"set notifier failed for writable objId = 0x%" PRIx32
954 ", fallback to set-only (%d)\n",
961 DAWNERR(
"set notifier failed for objId = 0x%" PRIx32
"\n", io.io->
getIdV());
982#ifdef CONFIG_DAWN_PROTO_NXSCOPE_SAMPLE_THREAD
985 threadSampleMember.threadStop();
993#ifdef CONFIG_DAWN_PROTO_NXSCOPE_SAMPLE_THREAD
994 return !(threadRecvMember.isStopped() & threadSampleMember.isStopped());
996 return !threadRecvMember.isStopped();
CIOCommon * getIO(SObjectId::ObjectId id)
Get an I/O object by ID.
void setObjectMapItem(SObjectId::ObjectId id, CObject *obj)
Set an item in the object map.
Base class for all I/O objects.
virtual bool isWrite() const =0
Check if IO supports write operations.
int setData(IODataCmn &data, size_t offset=0)
Set data for I/O (public interface with stats tracking).
virtual bool isSeekable() const
Check if IO supports partial (seekable) access.
virtual size_t getDataDim() const =0
Get data vector dimension.
virtual size_t getDataSize() const =0
Get data size in bytes.
virtual bool isRead() const =0
Check if IO supports read operations.
SObjectId::ObjectId getIdV() const
Get object identifier as raw 32-bit value.
uint8_t getDtype() const
Get data type field.
Real-time data visualization protocol (base class).
int doStop()
Stop implementation hook.
bool hasThread() const
Check if a background thread is active.
struct nxscope_intf_s nxsIntf
NXScope interface structure (from logging library).
int configure()
Configure object from descriptor data.
int doStart()
Start implementation hook.
int init()
One-time initialize object after bindings are resolved.
int deinit()
De-initialize object.
int threadStop()
Stop the worker thread.
int threadStart()
Start the worker thread.
void setThreadFunc(Func &&func)
Assign the function executed by threadStart().
Out-of-tree user-extension hooks for Dawn.
@ DTYPE_FLOAT
IEEE 754 single-precision floating point (32-bit).
@ DTYPE_INT32
Signed 32-bit integer (-2147483648 to 2147483647).
@ DTYPE_UINT64
Unsigned 64-bit integer.
@ DTYPE_UB16
Unsigned 16.16 fixed-point (32-bit).
@ DTYPE_CHAR
Character/string type (null-terminated, 4-byte aligned).
@ DTYPE_UINT32
Unsigned 32-bit integer (0 to 4294967295).
@ DTYPE_B16
Signed 16.16 fixed-point (32-bit).
uint32_t ObjectId
ObjectID type - single 32-bit value.
Heap-allocated dynamic I/O data buffer.
size_t getDataSize()
Get data size in bytes.
void * getDataPtr(size_t batch=0)
Get pointer to data only (skips timestamp if present).
size_t getItems()
Get number of items per batch.