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