Dawn Framework 1.0
Universal data acquisition framework for embedded systems
config.cxx
1// dawn/src/io/config.cxx
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5
6#include "dawn/io/config.hxx"
7
8#include <alloca.h>
9#include <cstdint>
10#include <cstring>
11#include <vector>
12
13using namespace dawn;
14
15static size_t cfgDtypeSize(uint8_t dtype)
16{
17 int sz;
18
19 if (dtype == SObjectId::DTYPE_ANY)
20 {
21 return sizeof(uint32_t);
22 }
23
25 if (sz <= 0)
26 {
27 return sizeof(uint32_t);
28 }
29
30 return (size_t)sz;
31}
32
33static size_t cfgWordsPerValue(uint8_t dtype)
34{
35 size_t dsize = cfgDtypeSize(dtype);
36
37 if (dsize == sizeof(uint64_t))
38 {
39 return 0;
40 }
41
42 return 1;
43}
44
45static size_t cfgValueCount(uint32_t objcfg)
46{
47 size_t words = SObjectCfg::objectCfgGetSize(objcfg);
48 size_t step = cfgWordsPerValue(SObjectCfg::objectCfgGetDtype(objcfg));
49
50 if (step == 0 || words == 0 || words % step != 0)
51 {
52 return 0;
53 }
54
55 return words / step;
56}
57
58static int cfgWordsToTyped(uint8_t dtype,
59 const uint32_t *src,
60 size_t words,
61 void *dst,
62 size_t items)
63{
64 size_t i;
65 size_t step = cfgWordsPerValue(dtype);
66
67 if (step == 0 || src == nullptr || dst == nullptr || items * step != words)
68 {
69 return -EINVAL;
70 }
71
72 switch (dtype)
73 {
74#if defined(CONFIG_DAWN_DTYPE_BOOL) || defined(CONFIG_DAWN_DTYPE_UINT8) || \
75 defined(CONFIG_DAWN_DTYPE_CHAR)
76# ifdef CONFIG_DAWN_DTYPE_BOOL
78# endif
79# ifdef CONFIG_DAWN_DTYPE_UINT8
81# endif
82# ifdef CONFIG_DAWN_DTYPE_CHAR
84# endif
85 {
86 uint8_t *ptr = reinterpret_cast<uint8_t *>(dst);
87
88 for (i = 0; i < items; i++)
89 {
90 ptr[i] = static_cast<uint8_t>(src[i] & 0xff);
91 }
92
93 return OK;
94 }
95#endif
96
97#ifdef CONFIG_DAWN_DTYPE_INT8
99 {
100 int8_t *ptr = reinterpret_cast<int8_t *>(dst);
101
102 for (i = 0; i < items; i++)
103 {
104 ptr[i] = static_cast<int8_t>(src[i] & 0xff);
105 }
106
107 return OK;
108 }
109#endif
110
111#ifdef CONFIG_DAWN_DTYPE_UINT16
113 {
114 uint16_t *ptr = reinterpret_cast<uint16_t *>(dst);
115
116 for (i = 0; i < items; i++)
117 {
118 ptr[i] = static_cast<uint16_t>(src[i] & 0xffff);
119 }
120
121 return OK;
122 }
123#endif
124
125#ifdef CONFIG_DAWN_DTYPE_INT16
127 {
128 int16_t *ptr = reinterpret_cast<int16_t *>(dst);
129
130 for (i = 0; i < items; i++)
131 {
132 ptr[i] = static_cast<int16_t>(src[i] & 0xffff);
133 }
134
135 return OK;
136 }
137#endif
138
139#if defined(CONFIG_DAWN_DTYPE_INT32) || defined(CONFIG_DAWN_DTYPE_UINT32) || \
140 defined(CONFIG_DAWN_DTYPE_FLOAT) || defined(CONFIG_DAWN_DTYPE_B16) || \
141 defined(CONFIG_DAWN_DTYPE_UB16) || defined(CONFIG_DAWN_DTYPE_BLOCK)
142# ifdef CONFIG_DAWN_DTYPE_INT32
144# endif
145# ifdef CONFIG_DAWN_DTYPE_UINT32
147# endif
148# ifdef CONFIG_DAWN_DTYPE_FLOAT
150# endif
151# ifdef CONFIG_DAWN_DTYPE_B16
153# endif
154# ifdef CONFIG_DAWN_DTYPE_UB16
156# endif
158# ifdef CONFIG_DAWN_DTYPE_BLOCK
160# endif
161 {
162 std::memcpy(dst, src, items * sizeof(uint32_t));
163 return OK;
164 }
165#endif
166
167 default:
168 {
169 return -ENOTSUP;
170 }
171 }
172}
173
174static int cfgTypedToWords(uint8_t dtype,
175 const void *src,
176 size_t items,
177 uint32_t *dst,
178 size_t words)
179{
180 size_t i;
181 size_t step = cfgWordsPerValue(dtype);
182
183 if (step == 0 || src == nullptr || dst == nullptr || items * step != words)
184 {
185 return -EINVAL;
186 }
187
188 switch (dtype)
189 {
190#ifdef CONFIG_DAWN_DTYPE_BOOL
192 {
193 const uint8_t *ptr = reinterpret_cast<const uint8_t *>(src);
194
195 for (i = 0; i < items; i++)
196 {
197 dst[i] = ptr[i] ? 1 : 0;
198 }
199
200 return OK;
201 }
202#endif
203
204#if defined(CONFIG_DAWN_DTYPE_UINT8) || defined(CONFIG_DAWN_DTYPE_CHAR)
205# ifdef CONFIG_DAWN_DTYPE_UINT8
207# endif
208# ifdef CONFIG_DAWN_DTYPE_CHAR
210# endif
211 {
212 const uint8_t *ptr = reinterpret_cast<const uint8_t *>(src);
213
214 for (i = 0; i < items; i++)
215 {
216 dst[i] = ptr[i];
217 }
218
219 return OK;
220 }
221#endif
222
223#ifdef CONFIG_DAWN_DTYPE_INT8
225 {
226 const int8_t *ptr = reinterpret_cast<const int8_t *>(src);
227 int32_t v;
228
229 for (i = 0; i < items; i++)
230 {
231 v = ptr[i];
232 std::memcpy(&dst[i], &v, sizeof(v));
233 }
234
235 return OK;
236 }
237#endif
238
239#ifdef CONFIG_DAWN_DTYPE_UINT16
241 {
242 const uint16_t *ptr = reinterpret_cast<const uint16_t *>(src);
243
244 for (i = 0; i < items; i++)
245 {
246 dst[i] = ptr[i];
247 }
248
249 return OK;
250 }
251#endif
252
253#ifdef CONFIG_DAWN_DTYPE_INT16
255 {
256 const int16_t *ptr = reinterpret_cast<const int16_t *>(src);
257 int32_t v;
258
259 for (i = 0; i < items; i++)
260 {
261 v = ptr[i];
262 std::memcpy(&dst[i], &v, sizeof(v));
263 }
264
265 return OK;
266 }
267#endif
268
269#if defined(CONFIG_DAWN_DTYPE_INT32) || defined(CONFIG_DAWN_DTYPE_UINT32) || \
270 defined(CONFIG_DAWN_DTYPE_FLOAT) || defined(CONFIG_DAWN_DTYPE_B16) || \
271 defined(CONFIG_DAWN_DTYPE_UB16) || defined(CONFIG_DAWN_DTYPE_BLOCK)
272# ifdef CONFIG_DAWN_DTYPE_INT32
274# endif
275# ifdef CONFIG_DAWN_DTYPE_UINT32
277# endif
278# ifdef CONFIG_DAWN_DTYPE_FLOAT
280# endif
281# ifdef CONFIG_DAWN_DTYPE_B16
283# endif
284# ifdef CONFIG_DAWN_DTYPE_UB16
286# endif
288# ifdef CONFIG_DAWN_DTYPE_BLOCK
290# endif
291 {
292 std::memcpy(dst, src, items * sizeof(uint32_t));
293 return OK;
294 }
295#endif
296
297 default:
298 {
299 return -ENOTSUP;
300 }
301 }
302}
303
304void CIOConfig::configureDesc(const CDescObject &desc)
305{
307 size_t offset = 0;
308
309 for (size_t i = 0; i < desc.getSize(); i++)
310 {
311 item = desc.objectCfgItemAtOffset(offset);
312
313 if (item->cfgid.s.cls == CIOCommon::IO_CLASS_ANY)
314 {
315 offset += cfgCmnOffset(item);
316 continue;
317 }
318
319 if (item->cfgid.s.cls != CIOCommon::IO_CLASS_CONFIG)
320 {
321 DAWNERR("unsupported config cfg 0x%08" PRIx32 "\n", item->cfgid.v);
322 objcfg = 0;
323 return;
324 }
325
326 switch (item->cfgid.s.id)
327 {
328 case CIOConfig::IO_CONFIG_CFG_OBJCFG:
329 {
330 const uint32_t *tmp = reinterpret_cast<const uint32_t *>(&item->data);
331
332 objcfg = *tmp;
333 offset += 2;
334 break;
335 }
336
337 case CIOConfig::IO_CONFIG_CFG_OFFSET:
338 {
339 const uint32_t *tmp = reinterpret_cast<const uint32_t *>(&item->data);
340
341 cfg_offset = *tmp;
342 offset += 2;
343 break;
344 }
345
346 case CIOConfig::IO_CONFIG_CFG_SIZE:
347 {
348 const uint32_t *tmp = reinterpret_cast<const uint32_t *>(&item->data);
349
350 cfg_size = *tmp;
351 offset += 2;
352 break;
353 }
354
355 case CIOConfig::IO_CONFIG_CFG_ALLOC:
356 {
357 offset += 1;
358
359 for (size_t j = 0; j < item->cfgid.s.size; j++)
360 {
361 map.insert_or_assign(item->data[j], nullptr);
362
363 offset += 1;
364 }
365
366 break;
367 }
368
369 default:
370 {
371 DAWNERR("unsupported config cfg 0x%08" PRIx32 "\n", item->cfgid.v);
372 objcfg = 0;
373 return;
374 }
375 }
376 }
377
378 return;
379}
380
381CIOConfig::~CIOConfig()
382{
383}
384
386{
387 size_t cfg_words;
389 const CIOLimits *lim;
390 bool has_limits;
391
392 objcfg = 0;
393 cfg_offset = 0;
394 cfg_size = 0;
395
396 // Configure
397
398 configureDesc(getDesc());
399
400 if (objcfg == 0)
401 {
402 return -EINVAL;
403 }
404
406
407 if (cfg_size > 0 && cfg_offset + cfg_size > cfg_words)
408 {
409 DAWNERR("config: offset %" PRIu32 " + size %" PRIu32 " exceeds field size %zu\n",
410 cfg_offset,
411 cfg_size,
412 cfg_words);
413 return -EINVAL;
414 }
415
416 lim = &getCmnLimits();
417 has_limits = lim->isConfigured();
418
419 if (!has_limits)
420 {
421 return OK;
422 }
423
424 if (lim->getMin() == nullptr || lim->getMax() == nullptr || lim->getStep() == nullptr)
425 {
426 return -EINVAL;
427 }
428
429 cfg_words = cfg_size > 0 ? cfg_size : cfg_words;
431 if (cfg_words == 0 ||
432 (lim->getWords() != cfg_words && lim->getWords() != cfgWordsPerValue(cfg_dtype)))
433 {
434 return -EINVAL;
435 }
436 if (cfg_dtype != getDtype())
437 {
438 return -EINVAL;
439 }
440
441 return OK;
442}
443
445{
446 return OK;
447}
448
449int CIOConfig::getDataImpl(IODataCmn &data, size_t len)
450{
451 uint8_t dtype;
452 size_t cfg_words;
453 size_t effective_words;
454 size_t effective_items;
456 const uint32_t *src;
457 int ret;
458
459 DAWNASSERT(objcfg != 0, "invalid data");
460 UNUSED(len);
461
462 dtype = SObjectCfg::objectCfgGetDtype(objcfg);
464
465 effective_words = cfg_size > 0 ? cfg_size : cfg_words;
467
468 if (effective_items == 0 || data.getItems() < effective_items)
469 {
470 return -EINVAL;
471 }
472
473 if (cfg_size > 0 && cfg_offset + effective_words > cfg_words)
474 {
475 DAWNERR("config read out of bounds: offset %" PRIu32 " + %zu > %zu words\n",
476 cfg_offset,
478 cfg_words);
479 return -EINVAL;
480 }
481
482 cfg_tmp = reinterpret_cast<uint32_t *>(alloca(cfg_words * sizeof(uint32_t)));
483
484 for (auto &[id, obj] : map)
485 {
486 UNUSED(id);
487
488 if (obj == nullptr)
489 {
490 return -EACCES;
491 }
492
493 ret = obj->getObjConfig(objcfg, cfg_tmp, cfg_words);
494 if (ret < 0)
495 {
496 return ret;
497 }
498
499 src = (cfg_size > 0) ? &cfg_tmp[cfg_offset] : cfg_tmp;
500
501 ret = cfgWordsToTyped(dtype, src, effective_words, data.getDataPtr(), effective_items);
502 return ret;
503 }
504
505 return -EACCES;
506}
507
509{
510 uint8_t dtype;
511 size_t cfg_len;
512 size_t write_words;
513 size_t write_items;
515 uint32_t *full;
516 size_t idx;
517 size_t applied;
518 size_t rollback_idx;
519 int rollback_ret;
520 int ret;
521 std::vector<uint32_t> backups;
522
523 DAWNASSERT(objcfg != 0, "invalid data");
524
525 dtype = SObjectCfg::objectCfgGetDtype(objcfg);
527
528 write_words = cfg_size > 0 ? cfg_size : cfg_len;
530
531 if (data.getItems() < write_items)
532 {
533 return -EINVAL;
534 }
535
536 if (cfg_size > 0 && cfg_offset + write_words > cfg_len)
537 {
538 DAWNERR("config write out of bounds: offset %" PRIu32 " + %zu > %zu words\n",
539 cfg_offset,
541 cfg_len);
542 return -EINVAL;
543 }
544
545 // Convert user typed data to words (only the sub-range)
546 user_words = reinterpret_cast<uint32_t *>(alloca(write_words * sizeof(uint32_t)));
547 ret = cfgTypedToWords(dtype, data.getDataPtr(), write_items, user_words, write_words);
548 if (ret < 0)
549 {
550 return ret;
551 }
552
554 if (ret < 0)
555 {
556 return ret;
557 }
558
559 if (cfg_len == 0)
560 {
561 return -EINVAL;
562 }
563
564 if (map.empty())
565 {
566 return -EACCES;
567 }
568
569 for (auto &[id, obj] : map)
570 {
571 UNUSED(id);
572
573 if (obj == nullptr)
574 {
575 return -EACCES;
576 }
577 }
578
579 // Build the full config data to write
580 full = reinterpret_cast<uint32_t *>(alloca(cfg_len * sizeof(uint32_t)));
581
582 if (cfg_size > 0)
583 {
584 // Read-RMW: read full field, patch sub-range, write back
585 ret = map.begin()->second->getObjConfig(objcfg, full, cfg_len);
586 if (ret < 0)
587 {
588 return ret;
589 }
590
591 std::memcpy(&full[cfg_offset], user_words, write_words * sizeof(uint32_t));
592 }
593 else
594 {
595 std::memcpy(full, user_words, cfg_len * sizeof(uint32_t));
596 }
597
598 // Backup current state for all targets
599 backups.resize(map.size() * cfg_len);
600 idx = 0;
601 for (auto &[id, obj] : map)
602 {
603 UNUSED(id);
604 ret = obj->getObjConfig(objcfg, &backups[idx * cfg_len], cfg_len);
605 if (ret < 0)
606 {
607 return ret;
608 }
609
610 idx++;
611 }
612
613 // Apply to all targets with rollback
614 applied = 0;
615 idx = 0;
616 for (auto &[id, obj] : map)
617 {
618 UNUSED(id);
619
620 ret = obj->setObjConfig(objcfg, full, cfg_len);
621 if (ret < 0)
622 {
623 rollback_idx = 0;
624 for (auto &[rid, robj] : map)
625 {
626 UNUSED(rid);
627 if (rollback_idx >= applied)
628 {
629 break;
630 }
631
632 rollback_ret = robj->setObjConfig(objcfg, &backups[rollback_idx * cfg_len], cfg_len);
633 if (rollback_ret < 0)
634 {
635 DAWNERR("config rollback failed: %d\n", rollback_ret);
636 }
637
638 rollback_idx++;
639 }
640
641 return ret;
642 }
643
644 idx++;
645 applied = idx;
646 }
647
648 return OK;
649}
650
652{
653 uint8_t dtype;
654 size_t dsize;
655 size_t items;
656
657 if (objcfg == 0)
658 {
659 return sizeof(uint32_t);
660 }
661
662 dtype = SObjectCfg::objectCfgGetDtype(objcfg);
663 dsize = cfgDtypeSize(dtype);
664 items = cfg_size > 0 ? cfg_size : cfgValueCount(objcfg);
665 if (items == 0)
666 {
667 return sizeof(uint32_t);
668 }
669
670 return dsize * items;
671}
672
674{
675 if (objcfg == 0)
676 {
677 return 1;
678 }
679
680 return cfg_size > 0 ? cfg_size : cfgValueCount(objcfg);
681}
682
683int CIOConfig::bind(CObject *obj, uint32_t id)
684{
685 DAWNASSERT(obj->getIdV() == id, "something goes wrong!");
686 map.insert_or_assign(id, obj);
687
688 return OK;
689}
Descriptor wrapper for individual object configuration.
size_t getSize() const
Get number of configuration items for this object.
SObjectCfg::SObjectCfgItem * objectCfgItemAtOffset(size_t offset) const
Get configuration item at specified offset.
const CIOLimits & getCmnLimits() const
Get common IO limits container.
Definition common.hxx:843
size_t cfgCmnOffset(const SObjectCfg::SObjectCfgItem *cfg)
Get offset of configuration item in descriptor.
Definition common.cxx:144
@ IO_CLASS_ANY
Any I/O class.
Definition common.hxx:86
@ IO_CLASS_CONFIG
Configuration I/O.
Definition common.hxx:90
int getDataImpl(IODataCmn &data, size_t len)
Get data implementation (override in derived classes).
Definition config.cxx:449
int deinit()
De-initialize object.
Definition config.cxx:444
std::map< uint32_t, CObject * > map
Map of object ID to bound CObject pointers.
Definition config.hxx:125
int setDataImpl(IODataCmn &data)
Set data implementation (override in derived classes).
Definition config.cxx:508
int configure()
Configure object from descriptor data.
Definition config.cxx:385
size_t getDataSize() const
Get data size in bytes.
Definition config.cxx:651
size_t getDataDim() const
Get data vector dimension.
Definition config.cxx:673
Common IO runtime limits container and validator.
Definition limits.hxx:24
int validate(const uint32_t *data, size_t words, uint8_t dtype) const
Validate payload against configured limits.
Definition limits.hxx:177
Base class for all Dawn objects (IOs, Programs, Protocols).
Definition object.hxx:28
SObjectId::ObjectId getIdV() const
Get object identifier as raw 32-bit value.
Definition object.cxx:155
CDescObject & getDesc()
Get descriptor object for this object.
Definition object.cxx:190
uint8_t getDtype() const
Get data type field.
Definition object.cxx:175
static uint16_t objectCfgGetSize(const ObjectCfgId objcfg)
Extract configuration data size from ConfigID.
static uint8_t objectCfgGetDtype(const ObjectCfgId objcfg)
Extract data type from ConfigID.
Out-of-tree user-extension hooks for Dawn.
Definition bindable.hxx:13
Base interface for I/O data buffers (static and dynamic).
Definition idata.hxx:21
virtual size_t getItems()=0
Get number of items per batch.
virtual void * getDataPtr(size_t batch=0)=0
Get pointer to data only (skips timestamp if present).
Single configuration item within object.
EObjectDataType
Data types supported by Dawn framework.
Definition objectid.hxx:61
@ DTYPE_FLOAT
IEEE 754 single-precision floating point (32-bit).
Definition objectid.hxx:112
@ DTYPE_INT32
Signed 32-bit integer (-2147483648 to 2147483647).
Definition objectid.hxx:92
@ DTYPE_UINT8
Unsigned 8-bit integer (0 to 255).
Definition objectid.hxx:80
@ DTYPE_INT16
Signed 16-bit integer (-32768 to 32767).
Definition objectid.hxx:84
@ DTYPE_INT8
Signed 8-bit integer (-128 to 127).
Definition objectid.hxx:76
@ DTYPE_ANY
Wildcard data type (matches any actual type).
Definition objectid.hxx:68
@ DTYPE_BLOCK
Opaque block/byte-stream data type.
Definition objectid.hxx:153
@ DTYPE_UINT16
Unsigned 16-bit integer (0 to 65535).
Definition objectid.hxx:88
@ DTYPE_UB16
Unsigned 16.16 fixed-point (32-bit).
Definition objectid.hxx:132
@ DTYPE_CHAR
Character/string type (null-terminated, 4-byte aligned).
Definition objectid.hxx:144
@ DTYPE_UINT32
Unsigned 32-bit integer (0 to 4294967295).
Definition objectid.hxx:96
@ DTYPE_BOOL
Boolean data type (stored in 32-bit container).
Definition objectid.hxx:72
@ DTYPE_B16
Signed 16.16 fixed-point (32-bit).
Definition objectid.hxx:128
static int getDtypeSize_(const EObjectDataType dtype)
Get byte size for a specific data type.
Definition objectid.cxx:12