Dawn Framework 1.0
Universal data acquisition framework for embedded systems
virt.cxx
1// dawn/src/io/virt.cxx
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5
6#include "dawn/io/virt.hxx"
7
8#include <new>
9
10using namespace dawn;
11
12#ifdef CONFIG_DAWN_IO_NOTIFY
13void CIOVirt::sendNotify(io_ddata_t *data)
14{
15 pfdsLock.lock();
16
17 // Notify all consumers
18
19 for (auto v : vnote)
20 {
21 if (v.cb)
22 {
23 v.cb(v.priv, data);
24 }
25 }
26
27 pfdsLock.unlock();
28}
29#endif
30
31CIOVirt::~CIOVirt()
32{
33 // Free data buffer
34
35 if (iodata)
36 {
37 delete iodata;
38 }
39}
40
42{
43 return OK;
44}
45
47{
48 return OK;
49}
50
52{
53 return OK;
54}
55
56int CIOVirt::getDataImpl(IODataCmn &data, size_t len)
57{
58 size_t b;
59
60 // Not initialized yet
61
62 if (!iodata)
63 {
64 return -EACCES;
65 }
66
67 if (blen > 1 && len > blen)
68 {
69 return -EINVAL;
70 }
71
72 for (size_t i = 0; i < len; i++)
73 {
74 // Notify provider
75
76 if (get_cb)
77 {
78 get_cb(this, get_cb_priv);
79 }
80
81 // Copy data
82
83 mutex.lock();
84
85 // Single-batch storage replicates its value into every slot
86
87 b = blen > 1 ? i : 0;
88
89#ifdef CONFIG_DAWN_IO_TIMESTAMP
90 data.getTs(i) = iodata->hasTs ? iodata->getTs(b) : ts;
91#endif
92
93 std::memcpy(data.getDataPtr(i), iodata->getDataPtr(b), dlen * tlen);
94
95 mutex.unlock();
96 }
97
98 return OK;
99}
100
101void CIOVirt::copyBatches(uint8_t *dst,
102 size_t dstStride,
103 const uint8_t *src,
104 size_t srcStride,
105 size_t n)
106{
107 size_t size = dlen * tlen;
108
109 // Neither side padded (no timestamps) - one flat copy
110
111 if (dstStride == size && srcStride == size)
112 {
113 std::memcpy(dst, src, size * n);
114 return;
115 }
116
117 for (size_t b = 0; b < n; b++)
118 {
119 std::memcpy(dst + b * dstStride, src + b * srcStride, size);
120 }
121}
122
123size_t CIOVirt::batchStride(IODataCmn &data)
124{
125 if (data.getBatch() < 2)
126 {
127 return dlen * tlen;
128 }
129
130 return static_cast<uint8_t *>(data.getDataPtr(1)) - static_cast<uint8_t *>(data.getDataPtr(0));
131}
132
133int CIOVirt::store(const void *src, size_t stride, IODataCmn *tsSrc)
134{
135 size_t b;
136
137 mutex.lock();
138
139#ifdef CONFIG_DAWN_IO_TIMESTAMP
140 if (isTimestamp())
141 {
142 ts = getTimestamp();
143 }
144#endif
145
146 copyBatches(static_cast<uint8_t *>(iodata->getDataPtr(0)),
147 iodata->off,
148 static_cast<const uint8_t *>(src),
149 stride,
150 blen);
151
152 // Source timestamps are kept per batch, otherwise stamp with now
153
154 if (iodata->hasTs)
155 {
156 for (b = 0; b < blen; b++)
157 {
158 if (tsSrc != nullptr && tsSrc->hasTimestamp())
159 {
160 iodata->getTs(b) = tsSrc->getTs(b);
161 }
162#ifdef CONFIG_DAWN_IO_TIMESTAMP
163 else
164 {
165 iodata->getTs(b) = ts;
166 }
167#endif
168 }
169 }
170
171 mutex.unlock();
172
173#ifdef CONFIG_DAWN_IO_NOTIFY
174 sendNotify(iodata);
175#endif
176
177 return OK;
178}
179
181{
182 int ret;
183
184 // Not initialized yet
185
186 if (!iodata)
187 {
188 return -EACCES;
189 }
190
191 // A shorter source would be read past its end; a longer one (batched
192 // notifier buffer into a single-slot virt) stores its first blen batches
193
194 if (data.getBatch() < blen)
195 {
196 DAWNERR("virt batch mismatch: expected %zu got %zu\n", blen, data.getBatch());
197 return -EINVAL;
198 }
199
200 // Single-slot storage is stamped on write, batches keep the source stamps
201
202 ret = store(data.getDataPtr(0), batchStride(data), blen > 1 ? &data : nullptr);
203
204 // Notify provider
205
206 if (set_cb)
207 {
208 set_cb(this, set_cb_priv);
209 }
210
211 return ret;
212}
213
214#ifdef CONFIG_DAWN_IO_NOTIFY
215int CIOVirt::getFd() const
216{
217 // There is a custom pass-through notification mechanism impelemted for
218 // VirtIO, we don't use standard poll notifier here
219
220 return -1;
221};
222#endif
223
225{
226 // Size of a single data item (batches are handled in setVal/getVal)
227
228 return dlen * tlen;
229}
230
232{
233 // Data dimmention
234
235 return dlen;
236}
237
238// VirtIO specific implementation for IIONotifier
240{
241#ifdef CONFIG_DAWN_IO_NOTIFY
242 DAWNASSERT(n.io != nullptr, "nullptr pointer");
243
244 pfdsLock.lock();
245 if (n.cb == nullptr)
246 {
247 vnote.clear();
248 }
249 else
250 {
251 vnote.push_back(n);
252 }
253
254 pfdsLock.unlock();
255#endif
256
257 return OK;
258}
259
260int CIOVirt::unregNotifier(const SIONotifier &n)
261{
262#ifdef CONFIG_DAWN_IO_NOTIFY
263 DAWNASSERT(n.io != nullptr, "nullptr pointer");
264
265 pfdsLock.lock();
266
267 for (auto it = vnote.begin(); it != vnote.end(); ++it)
268 {
269 if (it->io == n.io && it->cb == n.cb && it->priv == n.priv)
270 {
271 vnote.erase(it);
272 pfdsLock.unlock();
273 return OK;
274 }
275 }
276
277 pfdsLock.unlock();
278 return -ENOENT;
279#else
280 UNUSED(n);
281 return -ENOTSUP;
282#endif
283}
284
285int CIOVirt::initialize(size_t dim, size_t batch, bool notify)
286{
287 io_ddata_t *data;
288
289 noteSupport = notify;
290 dlen = dim;
291 blen = batch;
292 data = new (std::nothrow) io_ddata_t(tlen, dim, batch, getDtype(), isTimestamp());
293 if (data == nullptr || !data->isAllocated())
294 {
295 delete data;
296 DAWNERR("failed to allocate data\n");
297 return -ENOMEM;
298 }
299
300 mutex.lock();
301 delete iodata;
302 iodata = data;
303 mutex.unlock();
304
305#ifdef CONFIG_DAWN_IO_NOTIFY
306 setNotifyBatch(batch);
307 bindNotifier(this);
308#endif
309
310 return OK;
311}
312
313// Set callback for setData. This is not for IO notifications!
314
315int CIOVirt::setCallbackSet(CIOVirt::virtCB cb, void *priv)
316{
317 set_cb = cb;
318 set_cb_priv = priv;
319
320 return OK;
321}
322
323// Set callback for getData. This is not for IO notifications!
324
325int CIOVirt::setCallbackGet(CIOVirt::virtCB cb, void *priv)
326{
327 get_cb = cb;
328 get_cb_priv = priv;
329
330 return OK;
331}
332
333int CIOVirt::getVal(void *v, size_t d)
334{
335 if (!iodata)
336 {
337 return -EACCES;
338 }
339
340 DAWNASSERT(dlen * tlen * blen == d, "invalid input");
341
342 mutex.lock();
343
344 copyBatches(static_cast<uint8_t *>(v),
345 dlen * tlen,
346 static_cast<const uint8_t *>(iodata->getDataPtr(0)),
347 iodata->off,
348 blen);
349
350 mutex.unlock();
351
352 return OK;
353}
354
355int CIOVirt::setVal(const void *v, size_t d)
356{
357 // Not initialized yet
358
359 if (!iodata)
360 {
361 return -EACCES;
362 }
363
364 DAWNASSERT(dlen * tlen * blen == d, "invalid input");
365
366 return store(v, dlen * tlen, nullptr);
367}
virtual int getFd() const
Get file descriptor for notifications.
Definition common.hxx:451
uint64_t getTimestamp()
Get current timestamp.
Definition common.cxx:194
bool isTimestamp() const
Check if I/O supports timestamp.
Definition common.cxx:189
size_t getDataSize() const
Get data size in bytes.
Definition virt.cxx:224
int regNotifier(SIONotifier n)
Register I/O notification callback.
Definition virt.cxx:239
int configure()
Configure object from descriptor data.
Definition virt.cxx:41
int setDataImpl(IODataCmn &data)
Set data implementation (override in derived classes).
Definition virt.cxx:180
int deinit()
De-initialize object.
Definition virt.cxx:51
size_t getDataDim() const
Get data vector dimension.
Definition virt.cxx:231
int getDataImpl(IODataCmn &data, size_t len)
Get data implementation (override in derived classes).
Definition virt.cxx:56
int init()
One-time initialize object after bindings are resolved.
Definition virt.cxx:46
uint8_t getDtype() const
Get data type field.
Definition object.cxx:175
Out-of-tree user-extension hooks for Dawn.
Definition bindable.hxx:13
Notifier registration structure.
Definition inotifier.hxx:46
CIOCommon * io
I/O object pointer.
Definition inotifier.hxx:62
int(* cb)(void *priv, io_ddata_t *data)
Notifier callback function type.
Definition inotifier.hxx:70
Base interface for I/O data buffers (static and dynamic).
Definition idata.hxx:21
virtual bool hasTimestamp()=0
Check if this data buffer has per-batch timestamp storage.
virtual size_t getBatch()=0
Get number of batches.
virtual void * getDataPtr(size_t batch=0)=0
Get pointer to data only (skips timestamp if present).
virtual uint64_t & getTs(size_t batch=0)=0
Get timestamp reference for batch.
Heap-allocated dynamic I/O data buffer.
Definition ddata.hxx:21
void * getDataPtr(size_t batch=0)
Get pointer to data only (skips timestamp if present).
Definition ddata.hxx:180
io_ts_t & getTs(size_t batch=0)
Get timestamp reference for batch.
Definition ddata.hxx:203