6#include "dawn/proto/nxscope/nxscope.hxx"
13#include "dawn/io/common.hxx"
14#include "dawn/io/ddata.hxx"
18#if defined(CONFIG_DAWN_PROTO_NXSCOPE_SAMPLE_THREAD) + defined(CONFIG_DAWN_IO_NOTIFY) != 1
19# error one sampling method can be supported
24static_assert(NXSCOPE_RECV_NONBLOCK == 1,
"doStop() relies on non-blocking recv");
28#define NXSCOPE_SAMPLE_INTERVAL (1000000)
30static inline uint16_t nxscopeU16Le(
const uint8_t *p)
32 return (uint16_t)p[0] | ((uint16_t)p[1] << 8);
35static inline uint32_t nxscopeU32Le(
const uint8_t *p)
37 return (uint32_t)p[0] | ((uint32_t)p[1] << 8) | ((uint32_t)p[2] << 16) | ((uint32_t)p[3] << 24);
40#ifdef CONFIG_DAWN_IO_NOTIFY
41int CProtoNxscope::ioNotifierCb(
void *priv,
io_ddata_t *data)
43 SProtoNxscopeIochan *chan = (SProtoNxscopeIochan *)priv;
46 if (!chan || !chan->obj || !data || !chan->put)
52 std::lock_guard<std::recursive_mutex> lock(chan->obj->streamLock);
54 ret = chan->put(&chan->obj->nxs, chan->chan, data, chan->dim);
59 sem_post(&chan->obj->streamSem);
65int CProtoNxscope::sendAck(
int ret)
69 if (nxs.proto_cmd ==
nullptr || nxs.intf_cmd ==
nullptr)
74 if (nxs.proto_cmd->ops ==
nullptr || nxs.intf_cmd->ops ==
nullptr)
79 if (nxs.proto_cmd->ops->frame_final ==
nullptr || nxs.intf_cmd->ops->send ==
nullptr)
84 if (nxs.txbuf ==
nullptr)
89 if (nxs.txbuf_len < nxs.proto_cmd->hdrlen +
sizeof(ret) + nxs.proto_cmd->footlen)
94 len = nxs.proto_cmd->hdrlen;
95 std::memcpy(&nxs.txbuf[len], &ret,
sizeof(ret));
98 ret = nxs.proto_cmd->ops->frame_final(nxs.proto_cmd, NXSCOPE_HDRID_ACK, nxs.txbuf, &len);
104 return nxs.intf_cmd->ops->send(nxs.intf_cmd, nxs.txbuf, (
int)len);
107int CProtoNxscope::userIdCb(
void *priv, uint8_t
id, uint8_t *buff)
114 if (obj ==
nullptr || buff ==
nullptr)
119 handled = (
id == NXSCOPE_USER_SET_IO ||
id == NXSCOPE_USER_SET_IO_SEEK ||
120 id == NXSCOPE_USER_GET_IO ||
id == NXSCOPE_USER_GET_IO_SEEK);
129 ret = obj->handleUserCommand(
id, buff);
131#ifdef CONFIG_LOGGING_NXSCOPE_ACKFRAMES
135 ack = obj->sendAck(ret);
138 DAWNERR(
"nxscope user ack failed: %d\n", ack);
147int CProtoNxscope::handleUserCommand(uint8_t
id, uint8_t *buff)
151 case NXSCOPE_USER_SET_IO:
153 return userSetIO(buff);
156 case NXSCOPE_USER_SET_IO_SEEK:
158 return userSetIOSeek(buff);
161 case NXSCOPE_USER_GET_IO:
163 return userGetIO(buff);
166 case NXSCOPE_USER_GET_IO_SEEK:
168 return userGetIOSeek(buff);
180 for (
auto &iochan : vio)
182 if (iochan.io !=
nullptr && iochan.io->getIdV() == objid)
191int CProtoNxscope::userSetIO(uint8_t *buff)
195 SProtoNxscopeIochan *iochan;
201 objid = nxscopeU32Le(buff);
202 size = nxscopeU16Le(&buff[4]);
204 iochan = findIochan(objid);
205 if (iochan ==
nullptr || iochan->io ==
nullptr)
216 iodata = iochan->setData;
217 if (iodata ==
nullptr)
229 std::memcpy(iodata->
getDataPtr(), &buff[6], size);
239 std::memcpy(iodata->
getDataPtr(), &buff[6], size);
250int CProtoNxscope::userSetIOSeek(uint8_t *buff)
255 SProtoNxscopeIochan *iochan;
261 objid = nxscopeU32Le(buff);
262 offset = nxscopeU32Le(&buff[4]);
263 size = nxscopeU16Le(&buff[8]);
265 iochan = findIochan(objid);
266 if (iochan ==
nullptr || iochan->io ==
nullptr)
282 iodata = iochan->setData;
283 if (iodata ==
nullptr)
293 std::memcpy(iodata->
getDataPtr(), &buff[10], size);
297 ret = io->
setData(*iodata, offset);
303int CProtoNxscope::userGetIO(uint8_t *buff)
306 SProtoNxscopeIochan *iochan;
311 objid = nxscopeU32Le(buff);
313 iochan = findIochan(objid);
314 if (iochan ==
nullptr || iochan->io ==
nullptr)
330 if (iochan->getData ==
nullptr)
333 if (iochan->getData ==
nullptr)
339 iodata = iochan->getData;
358int CProtoNxscope::userGetIOSeek(uint8_t *buff)
363 SProtoNxscopeIochan *iochan;
368 objid = nxscopeU32Le(buff);
369 offset = nxscopeU32Le(&buff[4]);
370 size = nxscopeU16Le(&buff[8]);
372 iochan = findIochan(objid);
373 if (iochan ==
nullptr || iochan->io ==
nullptr)
389 if (iochan->getData ==
nullptr)
392 if (iochan->getData ==
nullptr)
398 iodata = iochan->getData;
411 ret = io->
getData(*iodata, 1, offset);
417 ret = sendUserData(objid, iodata->
getDataPtr(), size);
433 if (nxs.proto_cmd ==
nullptr || nxs.intf_cmd ==
nullptr || nxs.proto_cmd->ops ==
nullptr ||
434 nxs.intf_cmd->ops ==
nullptr || nxs.proto_cmd->ops->frame_final ==
nullptr ||
435 nxs.intf_cmd->ops->send ==
nullptr || userTxBuf ==
nullptr)
440 if (userTxLen < nxs.proto_cmd->hdrlen + NXSCOPE_USER_DATA_HDR + size + nxs.proto_cmd->footlen)
445 len = nxs.proto_cmd->hdrlen;
446 userTxBuf[len++] = (uint8_t)(objid & 0xff);
447 userTxBuf[len++] = (uint8_t)((objid >> 8) & 0xff);
448 userTxBuf[len++] = (uint8_t)((objid >> 16) & 0xff);
449 userTxBuf[len++] = (uint8_t)((objid >> 24) & 0xff);
450 userTxBuf[len++] = (uint8_t)(size & 0xff);
451 userTxBuf[len++] = (uint8_t)((size >> 8) & 0xff);
452 std::memcpy(&userTxBuf[len], data, size);
455 ret = nxs.proto_cmd->ops->frame_final(nxs.proto_cmd, NXSCOPE_USER_GET_IO, userTxBuf, &len);
461 return nxs.intf_cmd->ops->send(nxs.intf_cmd, userTxBuf, (
int)len);
464int CProtoNxscope::configureNxscope()
470 ret = nxscope_proto_ser_init(&nxsProto,
nullptr);
473 DAWNERR(
"nxscope_proto_ser_init failed: %d\n", ret);
479 nxsCbs.userid_priv =
this;
480 nxsCbs.userid = userIdCb;
481 nxsCbs.start_priv =
nullptr;
482 nxsCbs.start =
nullptr;
486 nxsCfg.streambuf_len = CONFIG_DAWN_PROTO_NXSCOPE_STREAMBUF_LEN;
487 nxsCfg.rxbuf_len = CONFIG_DAWN_PROTO_NXSCOPE_RXBUF_LEN;
488 nxsCfg.rx_padding = CONFIG_DAWN_PROTO_NXSCOPE_RX_PADDING;
489#ifdef CONFIG_LOGGING_NXSCOPE_CRICHANNELS
490 nxsCfg.cribuf_len = CONFIG_DAWN_PROTO_NXSCOPE_CRIBUF_LEN;
495 nxsCfg.proto_cmd = &nxsProto;
496 nxsCfg.proto_stream = &nxsProto;
497 nxsCfg.callbacks = &nxsCbs;
498 nxsCfg.channels = vchannels.size();
500 ret = nxscope_init(&nxs, &nxsCfg);
503 DAWNERR(
"nxscope_init failed: %d\n", ret);
510int CProtoNxscope::allocObject(SProtoNxscopeIOBind *alloc)
512 DAWNINFO(
"allocate object 0x%" PRIx32
"\n", alloc->objid.v);
520 vchannels.push_back(alloc);
525int CProtoNxscope::allocNames(
size_t j, SProtoNxscopeNames *alloc)
527 DAWNINFO(
"channel %zu with name %s\n", j, alloc->name);
531 vnames.push_back(alloc);
536uint8_t CProtoNxscope::getChannelDim(
const CIOCommon &io)
541uint8_t CProtoNxscope::getChannelDtype(
const CIOCommon &io)
547#ifdef CONFIG_DAWN_DTYPE_UINT8
550 return NXSCOPE_TYPE_UINT8;
554#ifdef CONFIG_DAWN_DTYPE_INT8
557 return NXSCOPE_TYPE_INT8;
561#ifdef CONFIG_DAWN_DTYPE_UINT16
564 return NXSCOPE_TYPE_UINT16;
568#ifdef CONFIG_DAWN_DTYPE_INT16
571 return NXSCOPE_TYPE_INT16;
575#ifdef CONFIG_DAWN_DTYPE_INT32
578 return NXSCOPE_TYPE_INT32;
582#ifdef CONFIG_DAWN_DTYPE_UINT32
585 return NXSCOPE_TYPE_UINT32;
589#ifdef CONFIG_DAWN_DTYPE_UINT64
592 return NXSCOPE_TYPE_UINT64;
596#ifdef CONFIG_DAWN_DTYPE_FLOAT
599 return NXSCOPE_TYPE_FLOAT;
603#ifdef CONFIG_DAWN_DTYPE_B16
606 return NXSCOPE_TYPE_B16;
610#ifdef CONFIG_DAWN_DTYPE_UB16
613 return NXSCOPE_TYPE_UB16;
617#ifdef CONFIG_DAWN_DTYPE_CHAR
620 return NXSCOPE_TYPE_CHAR;
626 DAWNERR(
"unsuported nxscope type %d\n", dtype);
627 return NXSCOPE_TYPE_NONE;
632int CProtoNxscope::nxscopeChannelsCreate()
634 union nxscope_chinfo_type_u u;
635 const SProtoNxscopeIOBind *alloc;
641 hasStreamChannels =
false;
643 for (bindidx = 0; bindidx < vchannels.size(); bindidx++)
645 alloc = vchannels[bindidx];
650 SProtoNxscopeIochan iochan;
653 if (bindidx < vnames.size())
655 name = vnames[bindidx]->name;
662 DAWNINFO(
"nxscope channel %s %p 0x%x\n", name, io, alloc->objid.v);
666 iochan.chan = chanid;
667 iochan.dim = getChannelDim(*io);
668 iochan.stream = io->
isRead();
671 iochan.setData =
nullptr;
672 iochan.getData =
nullptr;
673#ifdef CONFIG_DAWN_IO_NOTIFY
674 iochan.put =
nullptr;
676#ifdef CONFIG_DAWN_PROTO_NXSCOPE_SAMPLE_THREAD
677 iochan.sample =
nullptr;
678 iochan.data =
nullptr;
683 DAWNERR(
"IO 0x%" PRIx32
" has neither read nor write support\n", alloc->objid.v);
695 n = std::min(n, (
size_t)CONFIG_DAWN_PROTO_NXSCOPE_RXBUF_LEN);
698 getmax = std::max(getmax, n);
701 if (iochan.io->isWrite())
703 if (iochan.io->isSeekable())
705 iochan.setData = iochan.io->ddata_alloc(1, CONFIG_DAWN_PROTO_NXSCOPE_RXBUF_LEN);
709 iochan.setData = iochan.io->ddata_alloc(1);
712 if (iochan.setData ==
nullptr)
714 DAWNERR(
"failed to allocate set buffer for objid=0x%" PRIx32
"\n",
716#ifdef CONFIG_DAWN_PROTO_NXSCOPE_SAMPLE_THREAD
718 iochan.data =
nullptr;
726 ret = bindChannelCallbacks(iochan, io->
getDtype());
729 if (iochan.io->isWrite())
731 DAWNINFO(
"set-only nxscope channel for objid=0x%" PRIx32
"\n",
733 iochan.stream =
false;
737 DAWNERR(
"Unsupported data type %d for objid=0x%" PRIx32
"\n",
740#ifdef CONFIG_DAWN_PROTO_NXSCOPE_SAMPLE_THREAD
742 iochan.data =
nullptr;
744 delete iochan.setData;
745 iochan.setData =
nullptr;
751#ifdef CONFIG_DAWN_IO_NOTIFY
752 if (iochan.stream && iochan.io->isNotify() ==
false)
756 DAWNWARN(
"%s-only nxscope channel (no notify) for objid=0x%" PRIx32
"\n",
757 iochan.io->isWrite() ?
"set" :
"get",
759 iochan.stream =
false;
763#ifdef CONFIG_DAWN_PROTO_NXSCOPE_SAMPLE_THREAD
764 if (iochan.stream && iochan.io->isSeekable())
766 if (iochan.io->isWrite())
768 DAWNINFO(
"set-only nxscope channel (seekable) for "
769 "objid=0x%" PRIx32
"\n",
771 iochan.stream =
false;
775 DAWNERR(
"seekable IO not supported by NXScope "
776 "(objid=0x%08" PRIx32
")\n",
777 iochan.io->getIdV());
778 delete iochan.setData;
779 iochan.setData =
nullptr;
786 iochan.data = iochan.io->ddata_alloc(1);
787 if (iochan.data ==
nullptr)
789 DAWNERR(
"failed to allocate sample buffer for objid=0x%" PRIx32
"\n",
791 delete iochan.setData;
792 iochan.setData =
nullptr;
801 u.s.dtype = getChannelDtype(*io);
807 nxscope_chan_init(&nxs, chanid,
const_cast<char *
>(name), u.u8, iochan.dim, 0);
808 iochan.chan = chanid;
810 hasStreamChannels =
true;
817 vio.push_back(iochan);
821 DAWNERR(
"IO not found for objid=0x%" PRIx32
"\n", alloc->objid.v);
829 userTxLen = nxsProto.hdrlen + NXSCOPE_USER_DATA_HDR + getmax + nxsProto.footlen;
830 userTxBuf =
new (std::nothrow) uint8_t[userTxLen];
831 if (userTxBuf ==
nullptr)
840#ifdef CONFIG_DAWN_IO_NOTIFY
841template<
typename T, CProtoNxscope::nxscope_put_t<T> Put>
842int CProtoNxscope::putBatch(
struct nxscope_s *nxs, uint8_t chan,
io_ddata_t *data, uint8_t dim)
848 for (
size_t i = 0; i < data->
getBatch() && ret >= 0; i++)
850 ret = Put(nxs, chan,
static_cast<T *
>(data->
getDataPtr(i)), dim);
857#ifdef CONFIG_DAWN_PROTO_NXSCOPE_SAMPLE_THREAD
858template<
typename T, CProtoNxscope::nxscope_put_t<T> Put>
859int CProtoNxscope::sampleTyped(
CProtoNxscope *obj, SProtoNxscopeIochan *iochan)
863 if (!iochan || !iochan->data)
868 ret = iochan->io->getData(*iochan->data, 1);
871 ret = Put(&obj->nxs, iochan->chan,
static_cast<T *
>(iochan->data->getDataPtr()), iochan->dim);
878template<
typename T, CProtoNxscope::nxscope_put_t<T> Put>
879void CProtoNxscope::bindTyped(SProtoNxscopeIochan &iochan)
881#ifdef CONFIG_DAWN_IO_NOTIFY
882 iochan.put = &putBatch<T, Put>;
884#ifdef CONFIG_DAWN_PROTO_NXSCOPE_SAMPLE_THREAD
885 iochan.sample = &sampleTyped<T, Put>;
889int CProtoNxscope::bindChannelCallbacks(SProtoNxscopeIochan &iochan, uint8_t dtype)
893#ifdef CONFIG_DAWN_DTYPE_UINT8
896 bindTyped<uint8_t, nxscope_put_vuint8>(iochan);
901#ifdef CONFIG_DAWN_DTYPE_INT8
904 bindTyped<int8_t, nxscope_put_vint8>(iochan);
909#ifdef CONFIG_DAWN_DTYPE_UINT16
912 bindTyped<uint16_t, nxscope_put_vuint16>(iochan);
917#ifdef CONFIG_DAWN_DTYPE_INT16
920 bindTyped<int16_t, nxscope_put_vint16>(iochan);
925#ifdef CONFIG_DAWN_DTYPE_INT32
928 bindTyped<int32_t, nxscope_put_vint32>(iochan);
933#ifdef CONFIG_DAWN_DTYPE_UINT32
936 bindTyped<uint32_t, nxscope_put_vuint32>(iochan);
941#ifdef CONFIG_DAWN_DTYPE_UINT64
944 bindTyped<uint64_t, nxscope_put_vuint64>(iochan);
949#ifdef CONFIG_DAWN_DTYPE_FLOAT
952 bindTyped<float, nxscope_put_vfloat>(iochan);
966#ifdef CONFIG_DAWN_PROTO_NXSCOPE_SAMPLE_THREAD
967void CProtoNxscope::getAndPut(SProtoNxscopeIochan *iochan)
971 if (!iochan || !iochan->sample)
976 std::lock_guard<std::recursive_mutex> lock(streamLock);
978 ret = iochan->sample(
this, iochan);
979 if (ret < 0 && ret != -EAGAIN)
981 DAWNERR(
"sampling failed for chan=%d ret=%d\n", iochan->chan, ret);
986void CProtoNxscope::threadRecv()
995 if (hasStreamChannels)
997#ifdef CONFIG_DAWN_IO_NOTIFY
1005 clock_gettime(CLOCK_MONOTONIC, &ts);
1006 ts.tv_nsec += CONFIG_DAWN_PROTO_NXSCOPE_RECV_INTERVAL * 1000L;
1007 ts.tv_sec += ts.tv_nsec / 1000000000L;
1008 ts.tv_nsec %= 1000000000L;
1010 sem_clockwait(&streamSem, CLOCK_MONOTONIC, &ts);
1015 while (sem_trywait(&streamSem) == 0)
1022 std::lock_guard<std::recursive_mutex> lock(streamLock);
1024 ret = nxscope_stream(&nxs);
1027 DAWNERR(
"ERROR: nxscope_stream failed %d\n", ret);
1036 std::lock_guard<std::recursive_mutex> lock(streamLock);
1038 ret = nxscope_recv(&nxs);
1043 DAWNERR(
"ERROR: nxscope_recv failed %d\n", ret);
1050 usleep(CONFIG_DAWN_PROTO_NXSCOPE_RECV_INTERVAL);
1053 while (!threadRecvMember.shouldQuit());
1057 threadRecvMember.markThreadFinished();
1060#ifdef CONFIG_DAWN_PROTO_NXSCOPE_SAMPLE_THREAD
1061void CProtoNxscope::threadSample()
1067 for (
auto &io : vio)
1076 usleep(NXSCOPE_SAMPLE_INTERVAL);
1078 while (!threadSampleMember.shouldQuit());
1082 threadSampleMember.markThreadFinished();
1087CProtoNxscope::~CProtoNxscope()
1089 for (
auto &io : vio)
1091#ifdef CONFIG_DAWN_PROTO_NXSCOPE_SAMPLE_THREAD
1106 userTxBuf =
nullptr;
1108#ifdef CONFIG_DAWN_IO_NOTIFY
1109 sem_destroy(&streamSem);
1114 nxscope_deinit(&nxs);
1133 return nxscopeChannelsCreate();
1153#ifdef CONFIG_DAWN_IO_NOTIFY
1157 for (
auto &io : vio)
1163 ret = io.io->setNotifier(ioNotifierCb, 0, (
void *)&io);
1166 DAWNERR(
"set notifier failed for objId = 0x%" PRIx32
" (%d)\n", io.io->
getIdV(), ret);
1187#ifdef CONFIG_DAWN_PROTO_NXSCOPE_SAMPLE_THREAD
1190 threadSampleMember.setThreadFunc([
this]() { threadSample(); });
1191 ret = threadSampleMember.threadStart();
1210#ifdef CONFIG_DAWN_PROTO_NXSCOPE_SAMPLE_THREAD
1213 threadSampleMember.threadStop();
1225#ifdef CONFIG_DAWN_PROTO_NXSCOPE_SAMPLE_THREAD
1226 return !(threadRecvMember.isStopped() & threadSampleMember.isStopped());
1228 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).
int getData(IODataCmn &data, size_t len, size_t offset=0)
Get data from 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.
io_ddata_t * ddata_alloc(size_t batch, size_t chunk_size=0)
Allocate data buffer for this I/O.
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_UINT8
Unsigned 8-bit integer (0 to 255).
@ DTYPE_INT16
Signed 16-bit integer (-32768 to 32767).
@ DTYPE_INT8
Signed 8-bit integer (-128 to 127).
@ DTYPE_UINT64
Unsigned 64-bit integer.
@ DTYPE_UINT16
Unsigned 16-bit integer (0 to 65535).
@ 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 getBatch()
Get number of batches.