Dawn Framework 1.0
Universal data acquisition framework for embedded systems
selector.cxx
1// dawn/src/prog/selector.cxx
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5
6#include "dawn/prog/selector.hxx"
7
8#include <cstring>
9#include <new>
10
11#include "dawn/debug.hxx"
12#include "dawn/io/common.hxx"
13#include "dawn/io/ddata.hxx"
14#include "dawn/io/sdata.hxx"
15
16using namespace dawn;
17
18CProgSelector::CProgSelector(CDescObject &desc)
19 : CProgCommon(desc)
20 , ctrlIo(nullptr)
21 , target(nullptr)
22 , ctrlId(0)
23 , targetId(0)
24 , iodata(nullptr)
25 , currentIndex(0)
26 , active(false)
27 , registered(false)
28{
29}
30
31CProgSelector::~CProgSelector()
32{
33 deinit();
34}
35
36int CProgSelector::configureDesc(const CDescObject &desc)
37{
39 const SObjectId::UObjectId *ids;
40 size_t offset;
41 size_t ii;
42 size_t n;
43
44 offset = 0;
45 for (ii = 0; ii < desc.getSize(); ii++)
46 {
47 item = desc.objectCfgItemNext(offset);
48
49 if (item->cfgid.s.cls != CProgCommon::PROG_CLASS_SELECTOR)
50 {
51 DAWNERR("selector: unsupported cfg class 0x%" PRIx32 "\n", item->cfgid.v);
52 return -EINVAL;
53 }
54
55 switch (item->cfgid.s.id)
56 {
57 case PROG_SELECTOR_CFG_CONTROL:
58 {
59 if (item->cfgid.s.size != 1)
60 {
61 DAWNERR("selector: CONTROL must have 1 entry\n");
62 return -EINVAL;
63 }
64 ids = reinterpret_cast<const SObjectId::UObjectId *>(item->data);
65 ctrlId = ids[0].v;
66 setObjectMapItem(ctrlId, nullptr);
67 break;
68 }
69
70 case PROG_SELECTOR_CFG_DATA:
71 {
72 n = static_cast<size_t>(item->cfgid.s.size);
73 if (n == 0)
74 {
75 DAWNERR("selector: DATA must have at least 1 entry\n");
76 return -EINVAL;
77 }
78 ids = reinterpret_cast<const SObjectId::UObjectId *>(item->data);
79 for (size_t j = 0; j < n; j++)
80 {
81 dataIds.push_back(ids[j].v);
82 dataIos.push_back(nullptr);
83 SDataBind db;
84 db.owner = this;
85 db.index = j;
86 dataBinds.push_back(db);
87 setObjectMapItem(ids[j].v, nullptr);
88 }
89 break;
90 }
91
92 case PROG_SELECTOR_CFG_TARGET:
93 {
94 if (item->cfgid.s.size != 1)
95 {
96 DAWNERR("selector: TARGET must have 1 entry\n");
97 return -EINVAL;
98 }
99 ids = reinterpret_cast<const SObjectId::UObjectId *>(item->data);
100 targetId = ids[0].v;
101 setObjectMapItem(targetId, nullptr);
102 break;
103 }
104
105 default:
106 {
107 DAWNERR("selector: unsupported cfg id %u\n", item->cfgid.s.id);
108 return -EINVAL;
109 }
110 }
111 }
112
113 if (ctrlId == 0 || dataIds.empty() || targetId == 0)
114 {
115 DAWNERR("selector: missing control, data, or target config\n");
116 return -EINVAL;
117 }
118
119 return OK;
120}
121
123{
124 return configureDesc(getDesc());
125}
126
128{
129 CIOCommon *io;
130 size_t i;
131 size_t dataDim;
132 size_t dataSize;
133 uint8_t dataDtype;
134 int ret;
135
136 io = getIO(ctrlId);
137 if (!io)
138 {
139 DAWNERR("selector: control IO 0x%" PRIx32 " not found\n", ctrlId);
140 return -EIO;
141 }
142 if (!io->isRead())
143 {
144 DAWNERR("selector: control IO 0x%" PRIx32 " is not readable\n", ctrlId);
145 return -EINVAL;
146 }
147 if (io->getDtype() != SObjectId::DTYPE_UINT32 || io->getDataDim() != 1)
148 {
149 DAWNERR("selector: control IO 0x%" PRIx32 " must be scalar uint32\n", ctrlId);
150 return -EINVAL;
151 }
152 ctrlIo = io;
153
154 for (i = 0; i < dataIds.size(); i++)
155 {
156 io = getIO(dataIds[i]);
157 if (!io)
158 {
159 DAWNERR("selector: data IO 0x%" PRIx32 " not found\n", dataIds[i]);
160 return -EIO;
161 }
162 if (!io->isRead())
163 {
164 DAWNERR("selector: data IO 0x%" PRIx32 " is not readable\n", dataIds[i]);
165 return -EINVAL;
166 }
167 dataIos[i] = io;
168 }
169
170 dataDim = dataIos[0]->getDataDim();
171 dataSize = dataIos[0]->getDtypeSize();
172 dataDtype = dataIos[0]->getDtype();
173
174 for (i = 1; i < dataIos.size(); i++)
175 {
176 if (dataIos[i]->getDataDim() != dataDim || dataIos[i]->getDtypeSize() != dataSize ||
177 dataIos[i]->getDtype() != dataDtype)
178 {
179 DAWNERR("selector: data IO 0x%" PRIx32 " shape mismatch with first data input\n",
180 dataIds[i]);
181 return -EINVAL;
182 }
183 }
184
185 target = getIO(targetId);
186 if (!target)
187 {
188 DAWNERR("selector: target 0x%" PRIx32 " not found\n", targetId);
189 return -EIO;
190 }
191
192 ret = prepareWritableTarget(target, dataDim, true);
193 if (ret != OK)
194 {
195 DAWNERR("selector: target prepare failed %d\n", ret);
196 return ret;
197 }
198
199 iodata = new (std::nothrow) io_ddata_t(dataSize, dataDim, 1, dataDtype);
200 if (!iodata || !iodata->isAllocated())
201 {
202 delete iodata;
203 iodata = nullptr;
204 DAWNERR("selector: iodata allocation failed\n");
205 return -ENOMEM;
206 }
207
208 return OK;
209}
210
212{
213 doStop();
214 delete iodata;
215 iodata = nullptr;
216 target = nullptr;
217 ctrlIo = nullptr;
218 dataIos.clear();
219 dataIds.clear();
220 dataBinds.clear();
221 return OK;
222}
223
224int CProgSelector::ctrlNotifierCb(void *priv, io_ddata_t *data)
225{
226 CProgSelector *sel = static_cast<CProgSelector *>(priv);
227 uint32_t idx;
228
229 if (!data || data->getItems() < 1 || !sel->active)
230 {
231 return OK;
232 }
233
234 std::memcpy(&idx, data->getDataPtr(), sizeof(idx));
235 sel->applyRoute(idx);
236 return OK;
237}
238
239int CProgSelector::dataNotifierCb(void *priv, io_ddata_t *data)
240{
241 SDataBind *bind = static_cast<SDataBind *>(priv);
242 uint32_t index;
243
244 (void)data;
245
246 if (!bind->owner || !bind->owner->active)
247 {
248 return OK;
249 }
250
251 if (bind->owner->ctrlIo)
252 {
254
255 if (bind->owner->ctrlIo->getData(ctrlData, 1) == OK)
256 {
257 index = ctrlData(0);
258 if (index < bind->owner->dataIos.size())
259 {
260 bind->owner->currentIndex = static_cast<size_t>(index);
261 }
262 }
263 }
264
265 // Re-route only if this data input is the currently selected one.
266 if (bind->index == bind->owner->currentIndex)
267 {
268 bind->owner->applyRoute(static_cast<uint32_t>(bind->index));
269 }
270
271 return OK;
272}
273
275{
276 size_t i;
277 int ret;
278 uint32_t index;
279
280 if (!registered)
281 {
282 if (ctrlIo && ctrlIo->isNotify())
283 {
284 ret = ctrlIo->setNotifier(ctrlNotifierCb, 0, this);
285 if (ret != OK)
286 {
287 DAWNERR("selector: setNotifier on control failed %d\n", ret);
288 return ret;
289 }
290 }
291
292 // Register notifiers on data IOs that support them.
293 for (i = 0; i < dataIos.size(); i++)
294 {
295 if (dataIos[i] && dataIos[i]->isNotify())
296 {
297 ret = dataIos[i]->setNotifier(dataNotifierCb, 0, &dataBinds[i]);
298 if (ret != OK)
299 {
300 DAWNERR("selector: setNotifier on data[%zu] failed %d\n", i, ret);
301 return ret;
302 }
303 }
304 }
305
306 registered = true;
307 }
308
309 active = true;
310
311 if (ctrlIo)
312 {
314
315 if (ctrlIo->getData(ctrlData, 1) == OK)
316 {
317 index = ctrlData(0);
318 applyRoute(index);
319 }
320 }
321
322 return OK;
323}
324
326{
327 if (registered)
328 {
329 if (ctrlIo && ctrlIo->isNotify())
330 {
331 ctrlIo->setNotifier(nullptr, 0, nullptr);
332 }
333
334 for (size_t i = 0; i < dataIos.size(); i++)
335 {
336 if (dataIos[i] && dataIos[i]->isNotify())
337 {
338 dataIos[i]->setNotifier(nullptr, 0, nullptr);
339 }
340 }
341
342 registered = false;
343 }
344
345 active = false;
346 return OK;
347}
348
350{
351 return false;
352}
353
354void CProgSelector::applyRoute(uint32_t index)
355{
356 int ret;
357
358 if (index >= dataIos.size() || !dataIos[index] || !iodata || !target)
359 {
360 return;
361 }
362
363 currentIndex = static_cast<size_t>(index);
364
365 ret = dataIos[index]->getData(*iodata, 1);
366 if (ret != OK)
367 {
368 DAWNERR("selector: getData from data[%" PRIu32 "] failed %d\n", index, ret);
369 return;
370 }
371
372 ret = target->setData(*iodata);
373 if (ret != OK)
374 {
375 DAWNERR("selector: setData to target failed %d\n", ret);
376 }
377}
CIOCommon * getIO(SObjectId::ObjectId id)
Get an I/O object by ID.
Definition bindable.cxx:41
void setObjectMapItem(SObjectId::ObjectId id, CObject *obj)
Set an item in the object map.
Definition bindable.cxx:23
Descriptor wrapper for individual object configuration.
size_t getSize() const
Get number of configuration items for this object.
SObjectCfg::SObjectCfgItem * objectCfgItemNext(size_t &offset) const
Get config item at current offset and advance past it.
Base class for all I/O objects.
Definition common.hxx:27
int setData(IODataCmn &data, size_t offset=0)
Set data for I/O (public interface with stats tracking).
Definition common.hxx:392
int getData(IODataCmn &data, size_t len, size_t offset=0)
Get data from I/O (public interface with stats tracking).
Definition common.hxx:353
virtual bool isNotify() const =0
Check if IO supports notifications.
virtual size_t getDataDim() const =0
Get data vector dimension.
virtual bool isRead() const =0
Check if IO supports read operations.
CDescObject & getDesc()
Get descriptor object for this object.
Definition object.cxx:190
size_t getDtypeSize() const
Get size of this object's data type.
Definition object.cxx:195
uint8_t getDtype() const
Get data type field.
Definition object.cxx:175
Base class for all PROG (processing) objects.
Definition common.hxx:27
Data selector: routes one of N data inputs to a target IO based on the value of a control input.
Definition selector.hxx:31
int init()
One-time initialize object after bindings are resolved.
Definition selector.cxx:127
int configure()
Configure object from descriptor data.
Definition selector.cxx:122
int deinit()
De-initialize object.
Definition selector.cxx:211
int doStop()
Stop implementation hook.
Definition selector.cxx:325
int doStart()
Start implementation hook.
Definition selector.cxx:274
bool hasThread() const
Check if a background thread is active.
Definition selector.cxx:349
Out-of-tree user-extension hooks for Dawn.
Definition bindable.hxx:13
Single configuration item within object.
ObjectCfgData_t data[]
Configuration data array (flexible, size from cfgid.s.size).
UObjectCfgId cfgid
Configuration ID header (type, class, id, size, rw, dtype).
@ DTYPE_UINT32
Unsigned 32-bit integer (0 to 4294967295).
Definition objectid.hxx:96
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
size_t getItems()
Get number of items per batch.
Definition ddata.hxx:128
Static (compile-time) I/O data buffer (no timestamp).
Definition sdata.hxx:39
ObjectCfgId v
Raw 32-bit ConfigID value (for storage, comparison).
Definition objectcfg.hxx:82
uint32_t cls
Object class (bits 21-29, max 511).
uint32_t id
Configuration identifier (bits 0-4, max 31).
Definition objectcfg.hxx:94
uint32_t size
Configuration data size in 32-bit words (bits 5-14, max 1023).
struct dawn::SObjectCfg::UObjectCfgId::@10 s
Bit-field structure for named member access.
32-bit encoded object identifier (union with bit field).
Definition objectid.hxx:218
ObjectId v
Raw 32-bit ObjectID value (for comparison, hashing, storage).
Definition objectid.hxx:221