Dawn Framework 1.0
Universal data acquisition framework for embedded systems
iodemux.cxx
1// dawn/src/prog/iodemux.cxx
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5
6#include "dawn/prog/iodemux.hxx"
7
8#include <cstring>
9
10#include "dawn/debug.hxx"
11#include "dawn/io/common.hxx"
12#include "dawn/io/sdata.hxx"
13
14using namespace dawn;
15
16CProgIODemux::CProgIODemux(CDescObject &desc)
17 : CProgCommon(desc)
18 , control(nullptr)
19 , controlId(0)
20 , input(nullptr)
21 , inputId(0)
22 , dataBuf(nullptr)
23 , currentIndex(0)
24 , active(false)
25 , registered(false)
26{
27}
28
29CProgIODemux::~CProgIODemux()
30{
31 deinit();
32}
33
34int CProgIODemux::allocOutput(SObjectId::ObjectId ioId)
35{
36 outputIds.push_back(ioId);
37 outputs.push_back(nullptr);
38 setObjectMapItem(ioId, nullptr);
39 return OK;
40}
41
42int CProgIODemux::configureDesc(const CDescObject &desc)
43{
45 const SObjectId::UObjectId *ids;
46 size_t offset = 0;
47
48 for (size_t i = 0; i < desc.getSize(); i++)
49 {
50 item = desc.objectCfgItemNext(offset);
51
52 if (item->cfgid.s.cls != CProgCommon::PROG_CLASS_IODEMUX)
53 {
54 DAWNERR("iodemux: unsupported cfg class 0x%" PRIx32 "\n", item->cfgid.v);
55 return -EINVAL;
56 }
57
58 switch (item->cfgid.s.id)
59 {
60 case PROG_IODEMUX_CFG_CONTROL:
61 {
62 if (item->cfgid.s.size != 1)
63 {
64 DAWNERR("iodemux: CONTROL must have one item\n");
65 return -EINVAL;
66 }
67 ids = reinterpret_cast<const SObjectId::UObjectId *>(item->data);
68 controlId = ids[0].v;
69 setObjectMapItem(controlId, nullptr);
70 break;
71 }
72
73 case PROG_IODEMUX_CFG_INPUT:
74 {
75 if (item->cfgid.s.size != 1)
76 {
77 DAWNERR("iodemux: INPUT must have one item\n");
78 return -EINVAL;
79 }
80 ids = reinterpret_cast<const SObjectId::UObjectId *>(item->data);
81 inputId = ids[0].v;
82 setObjectMapItem(inputId, nullptr);
83 break;
84 }
85
86 case PROG_IODEMUX_CFG_OUTPUTS:
87 {
88 if (item->cfgid.s.size == 0)
89 {
90 DAWNERR("iodemux: OUTPUTS must not be empty\n");
91 return -EINVAL;
92 }
93 ids = reinterpret_cast<const SObjectId::UObjectId *>(item->data);
94 for (size_t j = 0; j < item->cfgid.s.size; j++)
95 {
96 int ret = allocOutput(ids[j].v);
97 if (ret != OK)
98 {
99 return ret;
100 }
101 }
102 break;
103 }
104
105 default:
106 DAWNERR("iodemux: unsupported cfg id %u\n", item->cfgid.s.id);
107 return -EINVAL;
108 }
109 }
110
111 if (controlId == 0 || inputId == 0 || outputs.empty())
112 {
113 DAWNERR("iodemux: control, input and outputs are required\n");
114 return -EINVAL;
115 }
116
117 return OK;
118}
119
121{
122 return configureDesc(getDesc());
123}
124
125int CProgIODemux::validateShape(CIOCommon *io) const
126{
127 if (io == nullptr || input == nullptr)
128 {
129 return -EIO;
130 }
131
132 if (io->getDtype() != input->getDtype() || io->getDataDim() != input->getDataDim() ||
133 io->isTimestamp() != input->isTimestamp() || io->getDataSize() != input->getDataSize())
134 {
135 return -EINVAL;
136 }
137
138 return OK;
139}
140
142{
143 control = getIO(controlId);
144 if (control == nullptr || !control->isRead() || !control->isNotify() ||
145 control->getDtype() != SObjectId::DTYPE_UINT32 || control->getDataDim() != 1)
146 {
147 DAWNERR("iodemux: control 0x%" PRIx32 " must be scalar uint32 notify IO\n", controlId);
148 return -EINVAL;
149 }
150
151 input = getIO(inputId);
152 if (input == nullptr || !input->isRead() || !input->isNotify())
153 {
154 DAWNERR("iodemux: input 0x%" PRIx32 " is not readable notify IO\n", inputId);
155 return -EINVAL;
156 }
157
158 for (size_t i = 0; i < outputIds.size(); i++)
159 {
160 outputs[i] = getIO(outputIds[i]);
161 if (outputs[i] == nullptr)
162 {
163 DAWNERR("iodemux: output IO 0x%" PRIx32 " not found\n", outputIds[i]);
164 return -EIO;
165 }
166
167 int ret = prepareWritableTarget(outputs[i], input->getDataDim(), true);
168 if (ret != OK)
169 {
170 DAWNERR("iodemux: output prepare failed %d\n", ret);
171 return ret;
172 }
173
174 ret = validateShape(outputs[i]);
175 if (ret != OK)
176 {
177 DAWNERR("iodemux: output 0x%" PRIx32 " incompatible\n", outputIds[i]);
178 return ret;
179 }
180 }
181
182 dataBuf = input->ddata_alloc(1);
183 if (dataBuf == nullptr)
184 {
185 return -ENOMEM;
186 }
187
188 return OK;
189}
190
192{
193 doStop();
194 delete dataBuf;
195 dataBuf = nullptr;
196 control = nullptr;
197 controlId = 0;
198 input = nullptr;
199 inputId = 0;
200 outputs.clear();
201 outputIds.clear();
202 return OK;
203}
204
205int CProgIODemux::controlNotifierCb(void *priv, io_ddata_t *data)
206{
207 CProgIODemux *self = static_cast<CProgIODemux *>(priv);
208 uint32_t index;
209
210 if (self == nullptr || !self->active || data == nullptr || data->getItems() < 1)
211 {
212 return OK;
213 }
214
215 std::memcpy(&index, data->getDataPtr(), sizeof(index));
216 self->routeIndex(index);
217 return OK;
218}
219
220int CProgIODemux::inputNotifierCb(void *priv, io_ddata_t *data)
221{
222 CProgIODemux *self = static_cast<CProgIODemux *>(priv);
223
224 UNUSED(data);
225
226 if (self == nullptr || !self->active)
227 {
228 return OK;
229 }
230
231 self->routeIndex(static_cast<uint32_t>(self->currentIndex));
232 return OK;
233}
234
236{
237 int ret;
238
239 if (!registered)
240 {
241 ret = control->setNotifier(controlNotifierCb, 0, this);
242 if (ret != OK)
243 {
244 DAWNERR("iodemux: control setNotifier failed %d\n", ret);
245 return ret;
246 }
247
248 ret = input->setNotifier(inputNotifierCb, 0, this);
249 if (ret != OK)
250 {
251 DAWNERR("iodemux: input setNotifier failed %d\n", ret);
252 return ret;
253 }
254
255 registered = true;
256 }
257
258 active = true;
260 if (control->getData(ctrlData, 1) == OK)
261 {
262 routeIndex(ctrlData(0));
263 }
264 return OK;
265}
266
268{
269 if (registered)
270 {
271 if (control != nullptr)
272 {
273 control->setNotifier(nullptr, 0, nullptr);
274 }
275 if (input != nullptr)
276 {
277 input->setNotifier(nullptr, 0, nullptr);
278 }
279 registered = false;
280 }
281
282 active = false;
283 return OK;
284}
285
287{
288 return false;
289}
290
291void CProgIODemux::routeIndex(uint32_t index)
292{
293 if (index >= outputs.size() || dataBuf == nullptr)
294 {
295 return;
296 }
297
298 currentIndex = index;
299 if (input->getData(*dataBuf, 1) != OK)
300 {
301 return;
302 }
303
304 int ret = outputs[index]->setData(*dataBuf);
305 if (ret != OK)
306 {
307 DAWNERR("iodemux: output setData failed %d\n", ret);
308 }
309}
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 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.
bool isTimestamp() const
Check if I/O supports timestamp.
Definition common.cxx:189
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.
Definition common.cxx:247
virtual size_t getDataSize() const =0
Get data size in bytes.
virtual bool isRead() const =0
Check if IO supports read operations.
CDescObject & getDesc()
Get descriptor object for this object.
Definition object.cxx:190
uint8_t getDtype() const
Get data type field.
Definition object.cxx:175
Base class for all PROG (processing) objects.
Definition common.hxx:27
IO demultiplexer: routes one input to the selected output.
Definition iodemux.hxx:22
int doStop()
Stop implementation hook.
Definition iodemux.cxx:267
int doStart()
Start implementation hook.
Definition iodemux.cxx:235
int configure()
Configure object from descriptor data.
Definition iodemux.cxx:120
int init()
One-time initialize object after bindings are resolved.
Definition iodemux.cxx:141
bool hasThread() const
Check if a background thread is active.
Definition iodemux.cxx:286
int deinit()
De-initialize object.
Definition iodemux.cxx:191
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
uint32_t ObjectId
ObjectID type - single 32-bit value.
Definition objectid.hxx:44
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