Dawn Framework 1.0
Universal data acquisition framework for embedded systems
bitsplit.cxx
1// dawn/src/prog/bitsplit.cxx
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5
6#include "dawn/prog/bitsplit.hxx"
7
8#include <cstring>
9#include <new>
10
11#include "bitwise.hxx"
12#include "dawn/debug.hxx"
13#include "dawn/io/common.hxx"
14#include "dawn/io/ddata.hxx"
15
16using namespace dawn;
17using namespace dawn::prog;
18
19CProgBitSplit::CProgBitSplit(CDescObject &desc)
20 : CProgCommon(desc)
21 , active(false)
22 , registered(false)
23{
24}
25
26CProgBitSplit::~CProgBitSplit()
27{
28 deinit();
29}
30
31int CProgBitSplit::allocBind(SObjectId::ObjectId sourceId, SObjectId::ObjectId outputId)
32{
33 SBitSplitBind *bind;
34
35 bind = new (std::nothrow) SBitSplitBind();
36 if (!bind)
37 {
38 return -ENOMEM;
39 }
40
41 bind->owner = this;
42 bind->sourceId = sourceId;
43 bind->outputId = outputId;
44 bind->source = nullptr;
45 bind->output = nullptr;
46 bind->sourceData = nullptr;
47 bind->outputData = nullptr;
48 bind->bit = 0;
49
50 binds.push_back(bind);
51 setObjectMapItem(sourceId, nullptr);
52 setObjectMapItem(outputId, nullptr);
53 return OK;
54}
55
56int CProgBitSplit::configureDesc(const CDescObject &desc)
57{
59 const SObjectId::UObjectId *ids;
61 size_t offset;
62 size_t ii;
63 size_t nitems;
64
65 offset = 0;
66 for (ii = 0; ii < desc.getSize(); ii++)
67 {
68 item = desc.objectCfgItemNext(offset);
69
70 if (item->cfgid.s.cls != CProgCommon::PROG_CLASS_BITSPLIT)
71 {
72 DAWNERR("bitsplit: unsupported cfg class 0x%" PRIx32 "\n", item->cfgid.v);
73 return -EINVAL;
74 }
75
76 switch (item->cfgid.s.id)
77 {
78 case PROG_BITSPLIT_CFG_IOBIND:
79 {
80 nitems = static_cast<size_t>(item->cfgid.s.size);
81 if (nitems == 0 || nitems % 2 != 0)
82 {
83 DAWNERR("bitsplit: invalid IOBIND size %zu\n", nitems);
84 return -EINVAL;
85 }
86
87 ids = reinterpret_cast<const SObjectId::UObjectId *>(item->data);
88 for (size_t b = 0; b < nitems / 2; b++)
89 {
90 int ret = allocBind(ids[b * 2].v, ids[b * 2 + 1].v);
91 if (ret != OK)
92 {
93 return ret;
94 }
95 }
96 break;
97 }
98
99 case PROG_BITSPLIT_CFG_BITS:
100 {
101 nitems = static_cast<size_t>(item->cfgid.s.size);
102 if (nitems == 0)
103 {
104 DAWNERR("bitsplit: BITS config must have at least one entry\n");
105 return -EINVAL;
106 }
107
108 raw = reinterpret_cast<const SObjectCfg::ObjectCfgData_t *>(item->data);
109 bitPositions.reserve(nitems);
110 for (size_t i = 0; i < nitems; i++)
111 {
112 bitPositions.push_back(SObjectCfg::cfgToU32(raw[i]));
113 }
114 break;
115 }
116
117 default:
118 {
119 DAWNERR("bitsplit: unsupported cfg id %u\n", item->cfgid.s.id);
120 return -EINVAL;
121 }
122 }
123 }
124
125 if (binds.empty())
126 {
127 DAWNERR("bitsplit: at least one IOBIND entry required\n");
128 return -EINVAL;
129 }
130
131 if (binds.size() != bitPositions.size())
132 {
133 DAWNERR(
134 "bitsplit: IOBIND count (%zu) != BITS count (%zu)\n", binds.size(), bitPositions.size());
135 return -EINVAL;
136 }
137
138 for (ii = 0; ii < binds.size(); ii++)
139 {
140 binds[ii]->bit = bitPositions[ii];
141 }
142
143 return OK;
144}
145
147{
148 return configureDesc(getDesc());
149}
150
152{
153 int ret;
154
155 for (auto bind : binds)
156 {
157 bind->source = getIO(bind->sourceId);
158 if (!bind->source)
159 {
160 DAWNERR("bitsplit: source IO 0x%" PRIx32 " not found\n", bind->sourceId);
161 return -EIO;
162 }
163
164 if (!bind->source->isRead() || !isBitwiseDtype(bind->source->getDtype()))
165 {
166 DAWNERR("bitsplit: source IO 0x%" PRIx32 " is not readable bitwise IO\n", bind->sourceId);
167 return -EINVAL;
168 }
169
170 bind->output = getIO(bind->outputId);
171 if (!bind->output)
172 {
173 DAWNERR("bitsplit: output IO 0x%" PRIx32 " not found\n", bind->outputId);
174 return -EIO;
175 }
176
177 if (!isBitwiseDtype(bind->output->getDtype()))
178 {
179 DAWNERR("bitsplit: output IO 0x%" PRIx32 " unsupported dtype %u\n",
180 bind->outputId,
181 bind->output->getDtype());
182 return -EINVAL;
183 }
184
185 ret = prepareWritableTarget(
186 bind->output, bind->output->getDataDim() == 0 ? 1 : bind->output->getDataDim(), true);
187 if (ret != OK)
188 {
189 DAWNERR("bitsplit: output target prepare failed %d\n", ret);
190 return ret;
191 }
192
193 bind->sourceData = bind->source->ddata_alloc(1);
194 bind->outputData = bind->output->ddata_alloc(1);
195 if (!bind->sourceData || !bind->outputData)
196 {
197 DAWNERR("bitsplit: data allocation failed\n");
198 return -ENOMEM;
199 }
200 }
201
202 return OK;
203}
204
206{
207 doStop();
208
209 for (auto bind : binds)
210 {
211 delete bind->sourceData;
212 delete bind->outputData;
213 delete bind;
214 }
215
216 binds.clear();
217 bitPositions.clear();
218 return OK;
219}
220
221int CProgBitSplit::ioNotifierCb(void *priv, io_ddata_t *data)
222{
223 SBitSplitBind *bind = static_cast<SBitSplitBind *>(priv);
224
225 if (!bind || !bind->owner || !bind->owner->active)
226 {
227 return OK;
228 }
229
230 if (data && data->getItems() >= 1)
231 {
232 bind->owner->refreshSource(bind->sourceId);
233 }
234
235 return OK;
236}
237
239{
240 int ret;
241
242 if (!registered)
243 {
244 for (auto bind : binds)
245 {
246 if (!bind->source->isNotify())
247 {
248 continue;
249 }
250
251 ret = bind->source->setNotifier(ioNotifierCb, 0, bind);
252 if (ret != OK)
253 {
254 DAWNERR(
255 "bitsplit: setNotifier failed for source 0x%" PRIx32 ": %d\n", bind->sourceId, ret);
256 return ret;
257 }
258 }
259
260 registered = true;
261 }
262
263 active = true;
264
265 for (auto bind : binds)
266 {
267 updateBind(bind, nullptr);
268 }
269
270 return OK;
271}
272
274{
275 if (registered)
276 {
277 for (auto bind : binds)
278 {
279 if (bind->source && bind->source->isNotify())
280 {
281 bind->source->setNotifier(nullptr, 0, nullptr);
282 }
283 }
284
285 registered = false;
286 }
287
288 active = false;
289 return OK;
290}
291
293{
294 return false;
295}
296
297void CProgBitSplit::refreshSource(SObjectId::ObjectId sourceId)
298{
299 for (auto bind : binds)
300 {
301 if (bind->sourceId == sourceId)
302 {
303 updateBind(bind, nullptr);
304 }
305 }
306}
307
308void CProgBitSplit::updateBind(SBitSplitBind *bind, io_ddata_t *data)
309{
310 size_t srcBits;
311 size_t dstBits;
312 size_t bit;
313 int ret;
314
315 if (!bind || !bind->source || !bind->output || !bind->sourceData || !bind->outputData)
316 {
317 return;
318 }
319
320 if (data && data->getItems() >= 1)
321 {
322 std::memcpy(
323 bind->sourceData->getDataPtr(), data->getDataPtr(), bind->sourceData->getDataSize());
324 }
325 else
326 {
327 ret = bind->source->getData(*bind->sourceData, 1);
328 if (ret != OK)
329 {
330 DAWNERR("bitsplit: getData failed for source 0x%" PRIx32 ": %d\n", bind->sourceId, ret);
331 return;
332 }
333 }
334
335 srcBits = getLogicalBits(bind->source);
336 dstBits = getLogicalBits(bind->output);
337
338 if (static_cast<size_t>(bind->bit) >= srcBits)
339 {
340 DAWNERR("bitsplit: start bit %" PRIu32 " out of range for 0x%" PRIx32 " (%zu bits)\n",
341 bind->bit,
342 bind->outputId,
343 srcBits);
344 return;
345 }
346
347 std::memset(bind->outputData->getDataPtr(), 0, bind->outputData->getDataSize());
348
349 for (bit = 0; bit < dstBits && static_cast<size_t>(bind->bit) + bit < srcBits; bit++)
350 {
351 if (readLogicalBit(
352 bind->source, bind->sourceData->getDataPtr(), static_cast<size_t>(bind->bit) + bit))
353 {
354 writeLogicalBit(bind->output, bind->outputData->getDataPtr(), bit, true);
355 }
356 }
357
358 ret = bind->output->setData(*bind->outputData);
359 if (ret != OK)
360 {
361 DAWNERR("bitsplit: setData failed %d\n", ret);
362 }
363}
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.
CDescObject & getDesc()
Get descriptor object for this object.
Definition object.cxx:190
int configure()
Configure object from descriptor data.
Definition bitsplit.cxx:146
int doStart()
Start implementation hook.
Definition bitsplit.cxx:238
int doStop()
Stop implementation hook.
Definition bitsplit.cxx:273
int init()
One-time initialize object after bindings are resolved.
Definition bitsplit.cxx:151
int deinit()
De-initialize object.
Definition bitsplit.cxx:205
bool hasThread() const
Check if a background thread is active.
Definition bitsplit.cxx:292
Base class for all PROG (processing) objects.
Definition common.hxx:27
uint32_t ObjectCfgData_t
Configuration data element - single 32-bit word.
Definition objectcfg.hxx:69
static uint32_t cfgToU32(ObjectCfgData_t x)
Convert ObjectCfgData_t to uint32_t.
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).
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
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