Dawn Framework 1.0
Universal data acquisition framework for embedded systems
expression.cxx
1// dawn/src/prog/expression.cxx
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5
6#include "dawn/prog/expression.hxx"
7
8#include <climits>
9#include <cstring>
10#include <new>
11
12#include "dawn/debug.hxx"
13#include "dawn/io/common.hxx"
14#include "dawn/io/ddata.hxx"
15
16using namespace dawn;
17
18static constexpr uint32_t EXPRESSION_VALUE_BITS = sizeof(uint32_t) * CHAR_BIT;
19
20CProgExpression::CProgExpression(CDescObject &desc)
21 : CProgCommon(desc)
22 , opType(OP_SHIFT_LEFT)
23 , constant(0)
24 , active(false)
25 , registered(false)
26{
27}
28
29CProgExpression::~CProgExpression()
30{
31 deinit();
32}
33
34int CProgExpression::allocBind(SObjectId::ObjectId sourceId, SObjectId::ObjectId outputId)
35{
36 SExpressionBind *bind;
37
38 bind = new (std::nothrow) SExpressionBind();
39 if (!bind)
40 {
41 return -ENOMEM;
42 }
43
44 bind->owner = this;
45 bind->sourceId = sourceId;
46 bind->outputId = outputId;
47 bind->source = nullptr;
48 bind->output = nullptr;
49
50 binds.push_back(bind);
51 setObjectMapItem(sourceId, nullptr);
52 setObjectMapItem(outputId, nullptr);
53 return OK;
54}
55
56int CProgExpression::configureDesc(const CDescObject &desc)
57{
59 const SObjectId::UObjectId *ids;
61 size_t offset = 0;
62
63 for (size_t i = 0; i < desc.getSize(); i++)
64 {
65 item = desc.objectCfgItemNext(offset);
66
67 if (item->cfgid.s.cls != CProgCommon::PROG_CLASS_EXPRESSION)
68 {
69 DAWNERR("expression: unsupported cfg class 0x%" PRIx32 "\n", item->cfgid.v);
70 return -EINVAL;
71 }
72
73 switch (item->cfgid.s.id)
74 {
75 case PROG_EXPRESSION_CFG_IOBIND:
76 {
77 size_t nitems = static_cast<size_t>(item->cfgid.s.size);
78 if (nitems == 0 || nitems % 2 != 0)
79 {
80 DAWNERR("expression: invalid IOBIND size %zu\n", nitems);
81 return -EINVAL;
82 }
83
84 ids = reinterpret_cast<const SObjectId::UObjectId *>(item->data);
85 for (size_t b = 0; b < nitems / 2; b++)
86 {
87 int ret = allocBind(ids[b * 2].v, ids[b * 2 + 1].v);
88 if (ret != OK)
89 {
90 return ret;
91 }
92 }
93 break;
94 }
95
96 case PROG_EXPRESSION_CFG_OP:
97 {
98 if (item->cfgid.s.size != 2)
99 {
100 DAWNERR("expression: OP config must have exactly 2 entries\n");
101 return -EINVAL;
102 }
103
104 raw = reinterpret_cast<const SObjectCfg::ObjectCfgData_t *>(item->data);
105 opType = SObjectCfg::cfgToU32(raw[0]);
106 constant = SObjectCfg::cfgToU32(raw[1]);
107 break;
108 }
109
110 default:
111 {
112 DAWNERR("expression: unsupported cfg id %u\n", item->cfgid.s.id);
113 return -EINVAL;
114 }
115 }
116 }
117
118 if (binds.empty())
119 {
120 DAWNERR("expression: at least one IOBIND entry required\n");
121 return -EINVAL;
122 }
123
124 if (opType > OP_SUB)
125 {
126 DAWNERR("expression: invalid op type %" PRIu32 "\n", opType);
127 return -EINVAL;
128 }
129
130 if ((opType == OP_SHIFT_LEFT || opType == OP_SHIFT_RIGHT) && constant >= EXPRESSION_VALUE_BITS)
131 {
132 DAWNERR("expression: invalid shift constant %" PRIu32 "\n", constant);
133 return -EINVAL;
134 }
135
136 return OK;
137}
138
140{
141 return configureDesc(getDesc());
142}
143
145{
146 int ret;
147
148 for (auto bind : binds)
149 {
150 bind->source = getIO(bind->sourceId);
151 bind->output = getIO(bind->outputId);
152 if (!bind->source || !bind->output)
153 {
154 return -EIO;
155 }
156
157 ret = prepareWritableTarget(bind->output, 1, true);
158 if (ret != OK)
159 {
160 return ret;
161 }
162
163 if (!bind->source->isRead() || bind->source->getDtype() != SObjectId::DTYPE_UINT32 ||
164 bind->source->getDataDim() != 1 || !bind->output->isWrite() ||
165 bind->output->getDtype() != SObjectId::DTYPE_UINT32 || bind->output->getDataDim() != 1)
166 {
167 DAWNERR("expression: only scalar uint32 source/output IO is supported\n");
168 return -EINVAL;
169 }
170 }
171
172 return OK;
173}
174
176{
177 doStop();
178
179 for (auto bind : binds)
180 {
181 delete bind;
182 }
183
184 binds.clear();
185 return OK;
186}
187
188bool CProgExpression::compute(uint32_t input, uint32_t &result, const char *phase)
189{
190 switch (opType)
191 {
192 case OP_SHIFT_LEFT:
193 result = input << constant;
194 return true;
195 case OP_SHIFT_RIGHT:
196 result = input >> constant;
197 return true;
198 case OP_CONST_LEFT_SHIFT:
199 if (input >= EXPRESSION_VALUE_BITS)
200 {
201 DAWNERR("expression: invalid %s shift %" PRIu32 "\n", phase, input);
202 return false;
203 }
204 result = constant << input;
205 return true;
206 case OP_ADD:
207 result = input + constant;
208 return true;
209 case OP_SUB:
210 result = input - constant;
211 return true;
212 default:
213 return false;
214 }
215}
216
217void CProgExpression::refresh(SExpressionBind *bind, io_ddata_t *data, const char *phase)
218{
219 uint32_t input;
220 uint32_t result;
221 int ret;
222
223 if (data && data->getItems() >= 1)
224 {
225 std::memcpy(
226 bind->sourceData.getDataPtr(), data->getDataPtr(), bind->sourceData.getDataSize());
227 }
228 else if (bind->source->getData(bind->sourceData, 1) != OK)
229 {
230 return;
231 }
232
233 input = bind->sourceData(0);
234 if (!compute(input, result, phase))
235 {
236 return;
237 }
238
239 bind->outputData(0) = result;
240 ret = bind->output->setData(bind->outputData);
241 if (ret != OK)
242 {
243 DAWNERR("expression: setData failed %d\n", ret);
244 }
245}
246
247int CProgExpression::ioNotifierCb(void *priv, io_ddata_t *data)
248{
249 SExpressionBind *bind = static_cast<SExpressionBind *>(priv);
250
251 if (bind && bind->owner && bind->owner->active)
252 {
253 bind->owner->refresh(bind, data, "runtime");
254 }
255
256 return OK;
257}
258
260{
261 int ret;
262
263 if (!registered)
264 {
265 for (auto bind : binds)
266 {
267 if (!bind->source->isNotify())
268 {
269 continue;
270 }
271
272 ret = bind->source->setNotifier(ioNotifierCb, 0, bind);
273 if (ret != OK)
274 {
275 return ret;
276 }
277 }
278
279 registered = true;
280 }
281
282 active = true;
283
284 for (auto bind : binds)
285 {
286 refresh(bind, nullptr, "initial");
287 }
288
289 return OK;
290}
291
293{
294 if (registered)
295 {
296 for (auto bind : binds)
297 {
298 if (bind->source && bind->source->isNotify())
299 {
300 bind->source->setNotifier(nullptr, 0, nullptr);
301 }
302 }
303
304 registered = false;
305 }
306
307 active = false;
308 return OK;
309}
310
312{
313 return false;
314}
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
Base class for all PROG (processing) objects.
Definition common.hxx:27
int init()
One-time initialize object after bindings are resolved.
int configure()
Configure object from descriptor data.
int doStop()
Stop implementation hook.
int doStart()
Start implementation hook.
bool hasThread() const
Check if a background thread is active.
int deinit()
De-initialize object.
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).
@ 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
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