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