Dawn Framework 1.0
Universal data acquisition framework for embedded systems
switch.cxx
1// dawn/src/prog/switch.cxx
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5
6#include "dawn/prog/switch.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#include "dawn/io/sdata.hxx"
15
16using namespace dawn;
17
18static const size_t INPUT_WORDS = 2;
19
20CProgSwitch::CProgSwitch(CDescObject &desc)
21 : CProgCommon(desc)
22 , target(nullptr)
23 , targetId(0)
24 , iodata(nullptr)
25 , onCmd(1)
26 , offCmd(0)
27 , lastAndState(false)
28 , active(false)
29 , registered(false)
30{
31}
32
33CProgSwitch::~CProgSwitch()
34{
35 deinit();
36}
37
38int CProgSwitch::allocInput(SObjectId::ObjectId ioId, uint32_t match)
39{
40 SSwitchInput inp;
41
42 inp.owner = this;
43 inp.io = nullptr;
44 inp.ioId = ioId;
45 inp.match = match;
46 inp.current = 0;
47
48 inputs.push_back(inp);
49 setObjectMapItem(ioId, nullptr);
50 return OK;
51}
52
53int CProgSwitch::configureDesc(const CDescObject &desc)
54{
56 const SObjectId::UObjectId *ids;
57 const uint32_t *vals;
58 size_t offset;
59 size_t ii;
60 size_t n;
61
62 offset = 0;
63 for (ii = 0; ii < desc.getSize(); ii++)
64 {
65 item = desc.objectCfgItemNext(offset);
66
67 if (item->cfgid.s.cls != CProgCommon::PROG_CLASS_SWITCH)
68 {
69 DAWNERR("switch: unsupported cfg class 0x%" PRIx32 "\n", item->cfgid.v);
70 return -EINVAL;
71 }
72
73 switch (item->cfgid.s.id)
74 {
75 case PROG_SWITCH_CFG_INPUTS:
76 {
77 n = static_cast<size_t>(item->cfgid.s.size);
78 if (n == 0 || n % INPUT_WORDS != 0)
79 {
80 DAWNERR("switch: invalid INPUTS size %zu\n", n);
81 return -EINVAL;
82 }
83
84 vals = reinterpret_cast<const uint32_t *>(item->data);
85 for (size_t j = 0; j < n; j += INPUT_WORDS)
86 {
87 ids = reinterpret_cast<const SObjectId::UObjectId *>(&vals[j]);
88 int ret = allocInput(ids[0].v, vals[j + 1]);
89 if (ret != OK)
90 {
91 return ret;
92 }
93 }
94 break;
95 }
96
97 case PROG_SWITCH_CFG_TARGET:
98 {
99 n = static_cast<size_t>(item->cfgid.s.size);
100 if (n != 3)
101 {
102 DAWNERR("switch: invalid TARGET size %zu\n", n);
103 return -EINVAL;
104 }
105
106 ids = reinterpret_cast<const SObjectId::UObjectId *>(item->data);
107 vals = reinterpret_cast<const uint32_t *>(item->data);
108 targetId = ids[0].v;
109 onCmd = static_cast<uint8_t>(vals[1]);
110 offCmd = static_cast<uint8_t>(vals[2]);
111 setObjectMapItem(targetId, nullptr);
112 break;
113 }
114
115 default:
116 {
117 DAWNERR("switch: unsupported cfg id %u\n", item->cfgid.s.id);
118 return -EINVAL;
119 }
120 }
121 }
122
123 if (inputs.empty())
124 {
125 DAWNERR("switch: at least one input required\n");
126 return -EINVAL;
127 }
128
129 if (targetId == 0)
130 {
131 DAWNERR("switch: target IO not configured\n");
132 return -EINVAL;
133 }
134
135 return OK;
136}
137
139{
140 return configureDesc(getDesc());
141}
142
144{
145 size_t i;
146 CIOCommon *io;
147 int ret;
148
149 for (i = 0; i < inputs.size(); i++)
150 {
151 io = getIO(inputs[i].ioId);
152 if (!io)
153 {
154 DAWNERR("switch: input IO 0x%" PRIx32 " not found\n", inputs[i].ioId);
155 return -EIO;
156 }
157
158 if (!io->isRead())
159 {
160 DAWNERR("switch: input 0x%" PRIx32 " is not readable\n", inputs[i].ioId);
161 return -EINVAL;
162 }
163
164 if (io->getDtype() != SObjectId::DTYPE_UINT32 || io->getDataDim() != 1)
165 {
166 DAWNERR("switch: input 0x%" PRIx32 " must be scalar uint32, got dtype=%u dim=%zu\n",
167 inputs[i].ioId,
168 io->getDtype(),
169 io->getDataDim());
170 return -EINVAL;
171 }
172
173 inputs[i].io = io;
174 }
175
176 target = getIO(targetId);
177 if (!target)
178 {
179 DAWNERR("switch: target 0x%" PRIx32 " not found\n", targetId);
180 return -EIO;
181 }
182
183 ret = prepareWritableTarget(target, 1, true);
184 if (ret != OK)
185 {
186 DAWNERR("switch: target prepare failed %d\n", ret);
187 return ret;
188 }
189
190 iodata = new (std::nothrow) io_ddata_t(target->getDataSize(), 1, 1, target->getDtype());
191 if (!iodata || !iodata->isAllocated())
192 {
193 delete iodata;
194 iodata = nullptr;
195 DAWNERR("switch: iodata allocation failed\n");
196 return -ENOMEM;
197 }
198
199 return OK;
200}
201
203{
204 doStop();
205 delete iodata;
206 iodata = nullptr;
207 target = nullptr;
208 inputs.clear();
209 return OK;
210}
211
212int CProgSwitch::ioNotifierCb(void *priv, io_ddata_t *data)
213{
214 SSwitchInput *inp = static_cast<SSwitchInput *>(priv);
215
216 if (data && data->getItems() >= 1)
217 {
218 std::memcpy(&inp->current, data->getDataPtr(), sizeof(inp->current));
219 }
220
221 if (inp->owner && inp->owner->active)
222 {
223 inp->owner->evaluate();
224 }
225
226 return OK;
227}
228
230{
231 size_t i;
232 int ret;
233
234 if (registered)
235 {
236 active = true;
237
238 for (i = 0; i < inputs.size(); i++)
239 {
241
242 ret = inputs[i].io->getData(inputData, 1);
243 if (ret != OK)
244 {
245 DAWNERR("switch: getData failed on input %zu: %d\n", i, ret);
246 return ret;
247 }
248 inputs[i].current = inputData(0);
249 }
250
251 lastAndState = !allInputsMatch();
252 evaluate();
253 return OK;
254 }
255
256 active = true;
257
258 for (i = 0; i < inputs.size(); i++)
259 {
260 if (!inputs[i].io->isNotify())
261 {
262 continue;
263 }
264
265 ret = inputs[i].io->setNotifier(ioNotifierCb, 0, &inputs[i]);
266 if (ret != OK)
267 {
268 DAWNERR("switch: setNotifier failed on input %zu: %d\n", i, ret);
269 return ret;
270 }
271 }
272
273 registered = true;
274
275 // Read current values and force the first write unconditionally.
276 for (i = 0; i < inputs.size(); i++)
277 {
279
280 ret = inputs[i].io->getData(inputData, 1);
281 if (ret != OK)
282 {
283 DAWNERR("switch: getData failed on input %zu: %d\n", i, ret);
284 return ret;
285 }
286 inputs[i].current = inputData(0);
287 }
288 lastAndState = !allInputsMatch();
289 evaluate();
290
291 return OK;
292}
293
295{
296 if (registered)
297 {
298 for (size_t i = 0; i < inputs.size(); i++)
299 {
300 if (inputs[i].io && inputs[i].io->isNotify())
301 {
302 inputs[i].io->setNotifier(nullptr, 0, nullptr);
303 }
304 }
305
306 registered = false;
307 }
308
309 active = false;
310 return OK;
311}
312
314{
315 return false;
316}
317
318bool CProgSwitch::allInputsMatch() const
319{
320 for (size_t i = 0; i < inputs.size(); i++)
321 {
322 if (inputs[i].current != inputs[i].match)
323 {
324 return false;
325 }
326 }
327
328 return true;
329}
330
331void CProgSwitch::evaluate()
332{
333 bool allMatch;
334 uint8_t cmd;
335 int ret;
336
337 for (size_t i = 0; i < inputs.size(); i++)
338 {
340
341 if (inputs[i].io == nullptr)
342 {
343 return;
344 }
345
346 ret = inputs[i].io->getData(inputData, 1);
347 if (ret != OK)
348 {
349 DAWNERR("switch: getData failed on input %zu: %d\n", i, ret);
350 return;
351 }
352
353 inputs[i].current = inputData(0);
354 }
355
356 allMatch = allInputsMatch();
357
358 if (allMatch == lastAndState)
359 {
360 return;
361 }
362
363 lastAndState = allMatch;
364 cmd = allMatch ? onCmd : offCmd;
365
366 if (!iodata || !target)
367 {
368 return;
369 }
370
371 std::memset(iodata->getDataPtr(), 0, iodata->getDataSize());
372 std::memcpy(iodata->getDataPtr(), &cmd, sizeof(cmd));
373
374 ret = target->setData(*iodata);
375 if (ret != OK)
376 {
377 DAWNERR("switch: setData to target failed %d\n", ret);
378 }
379}
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
virtual size_t getDataDim() const =0
Get data vector dimension.
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
int deinit()
De-initialize object.
Definition switch.cxx:202
bool hasThread() const
Check if a background thread is active.
Definition switch.cxx:313
int init()
One-time initialize object after bindings are resolved.
Definition switch.cxx:143
int doStart()
Start implementation hook.
Definition switch.cxx:229
int doStop()
Stop implementation hook.
Definition switch.cxx:294
int configure()
Configure object from descriptor data.
Definition switch.cxx:138
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
size_t getDataSize()
Get data size in bytes.
Definition ddata.hxx:153
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