Dawn Framework 1.0
Universal data acquisition framework for embedded systems
pretty.cxx
1// dawn/src/proto/shell/pretty.cxx
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5
6#include "dawn/proto/shell/pretty.hxx"
7#include "dawn/dev/shutdown.hxx"
8
9#include <chrono>
10#include <climits>
11#include <cstdlib>
12#include <cstring>
13#include <iostream>
14#include <string>
15#include <thread>
16#include <vector>
17
18#include "dawn/io/common.hxx"
19#include "dawn/io/sdata.hxx"
20#include "dawn/prog/common.hxx"
21#include "system/readline.h"
22
23#ifdef CONFIG_DAWN_PROTO_SHELL_INSPECT
24# include "dawn/dev/inspector.hxx"
25#endif
26
27using namespace dawn;
28using namespace std::chrono_literals;
29
30#define DAWN_PROTO_SHELL_LINELEN 64
31#define SHELLPRINT printf
32
33#define GETANDPRINT_DIM_MAX 128
34#define SHELL_SEEK_CHUNK_SIZE 64
35#define SHELL_SEEK_LINE_BYTES 16
36
39
40static bool parseU32Token(const char *token, uint32_t *out)
41{
42 unsigned long parsed;
43 char *endptr = nullptr;
44
45 if (token == nullptr || out == nullptr || *token == '\0')
46 {
47 return false;
48 }
49
50 parsed = strtoul(token, &endptr, 0);
51 if (*endptr != '\0' || parsed > UINT32_MAX)
52 {
53 return false;
54 }
55
56 *out = static_cast<uint32_t>(parsed);
57 return true;
58}
59
60template<typename T>
61static void printTypedDataHelper(FILE *outstream,
62 CIOCommon *io,
63 size_t ddim,
64 const char *fmt,
65 const T *data_ptr,
66 uint64_t ts)
67{
68#ifdef CONFIG_DAWN_IO_TIMESTAMP
69 if (io->isTimestamp())
70 {
71 fprintf(outstream, " ts:%" PRId64 " ", ts);
72 }
73#endif
74
75 for (size_t i = 0; i < ddim; i++)
76 {
77 fprintf(outstream, fmt, data_ptr[i]);
78 }
79}
80
81#ifdef CONFIG_DAWN_DTYPE_CHAR
82static void printCharDataHelper(FILE *outstream,
83 CIOCommon *io,
84 size_t ddim,
85 const char *data_ptr,
86 uint64_t ts)
87{
88# ifdef CONFIG_DAWN_IO_TIMESTAMP
89 if (io->isTimestamp())
90 {
91 fprintf(outstream, " ts:%" PRId64 " ", ts);
92 }
93# endif
94
95 for (size_t i = 0; i < ddim; i++)
96 {
97 if (data_ptr[i] == '\0')
98 {
99 break;
100 }
101
102 fprintf(outstream, "%c", data_ptr[i]);
103 }
104}
105#endif
106
107template<typename T>
108static bool getAndPrintTyped(FILE *outstream, CIOCommon *io, size_t ddim, const char *fmt)
109{
111 if (data.getItems() < ddim)
112 {
113 fprintf(outstream, "Data dimension %zu exceeds buffer size %zu\n", ddim, data.getItems());
114 return false;
115 }
116
117 int ret = io->getData(data, 1);
118 if (ret < 0)
119 {
120 fprintf(outstream, "getio failed %d\n", ret);
121 return false;
122 }
123
124 printTypedDataHelper<T>(outstream, io, ddim, fmt, &data(0), data[0]);
125 return true;
126}
127
128#ifdef CONFIG_DAWN_DTYPE_CHAR
129static bool getAndPrintChar(FILE *outstream, CIOCommon *io, size_t ddim)
130{
132 if (data.getItems() < ddim)
133 {
134 fprintf(outstream, "Data dimension %zu exceeds buffer size %zu\n", ddim, data.getItems());
135 return false;
136 }
137
138 int ret = io->getData(data, 1);
139 if (ret < 0)
140 {
141 fprintf(outstream, "getio failed %d\n", ret);
142 return false;
143 }
144
145 printCharDataHelper(outstream, io, ddim, &data(0), data[0]);
146 return true;
147}
148#endif
149
150#ifdef CONFIG_DAWN_IO_NOTIFY
151int CProtoShellPretty::notifierCb(void *priv, io_ddata_t *data)
152{
153 CIOCommon *io = (CIOCommon *)priv;
154
155 if (io == nullptr)
156 {
157 DAWNERR("NULL io pointer in notifier callback\n");
158 return -EINVAL;
159 }
160
161 size_t ddim = io->getDataDim();
162 int dtype = io->getDtype();
163
164 fprintf(outstream_, "IO 0x%" PRIx32 " data:\n\t", io->getIdV());
165
166 uint64_t ts = 0;
167# ifdef CONFIG_DAWN_IO_TIMESTAMP
168 ts = (*data)[0];
169# endif
170 (void)ddim;
171 (void)ts;
172
173 switch (dtype)
174 {
175# ifdef CONFIG_DAWN_DTYPE_BOOL
177 printTypedDataHelper<bool>(outstream_, io, ddim, "%" PRId8 " ", &data->get<bool>(0), ts);
178 break;
179# endif
180
181# ifdef CONFIG_DAWN_DTYPE_INT8
183 printTypedDataHelper<int8_t>(
184 outstream_, io, ddim, "%" PRId8 " ", &data->get<int8_t>(0), ts);
185 break;
186# endif
187
188# ifdef CONFIG_DAWN_DTYPE_UINT8
190 printTypedDataHelper<uint8_t>(
191 outstream_, io, ddim, "%" PRId8 " ", &data->get<uint8_t>(0), ts);
192 break;
193# endif
194
195# ifdef CONFIG_DAWN_DTYPE_INT16
197 printTypedDataHelper<int16_t>(
198 outstream_, io, ddim, "%" PRId16 " ", &data->get<int16_t>(0), ts);
199 break;
200# endif
201
202# ifdef CONFIG_DAWN_DTYPE_UINT16
204 printTypedDataHelper<uint16_t>(
205 outstream_, io, ddim, "%" PRId16 " ", &data->get<uint16_t>(0), ts);
206 break;
207# endif
208
209# ifdef CONFIG_DAWN_DTYPE_INT32
211 printTypedDataHelper<int32_t>(
212 outstream_, io, ddim, "%" PRId32 " ", &data->get<int32_t>(0), ts);
213 break;
214# endif
215
216# ifdef CONFIG_DAWN_DTYPE_UINT32
218 printTypedDataHelper<uint32_t>(
219 outstream_, io, ddim, "%" PRId32 " ", &data->get<uint32_t>(0), ts);
220 break;
221# endif
222
223# ifdef CONFIG_DAWN_DTYPE_UINT64
225 printTypedDataHelper<uint64_t>(
226 outstream_, io, ddim, "%" PRId64 " ", &data->get<uint64_t>(0), ts);
227 break;
228# endif
229
230# ifdef CONFIG_DAWN_DTYPE_FLOAT
232 printTypedDataHelper<float>(outstream_, io, ddim, "%.4f ", &data->get<float>(0), ts);
233 break;
234# endif
235
236# ifdef CONFIG_DAWN_DTYPE_CHAR
238 printCharDataHelper(outstream_, io, ddim, &data->get<char>(0), ts);
239 break;
240# endif
241
242 default:
243 fprintf(outstream_, "missing print support for dtype=%d\n", dtype);
244 break;
245 }
246
247 fprintf(outstream_, "\n\n");
248
249 return OK;
250}
251#endif
252
253int CProtoShellPretty::configureDesc(const CDescObject &desc)
254{
255 SObjectCfg::SObjectCfgItem *item = nullptr;
256 size_t offset = 0;
257
258 for (size_t i = 0; i < desc.getSize(); i++)
259 {
260 item = desc.objectCfgItemNext(offset);
261
263 {
264 DAWNERR("Unsupported Shell config 0x%08" PRIx32 "\n", item->cfgid.v);
265 return -EINVAL;
266 }
267
268 switch (item->cfgid.s.id)
269 {
271 {
272 const size_t wpe = sizeof(SProtoShellIOBind) / 4;
273 size_t j;
274
275 for (j = 0; j < item->cfgid.s.size; j++)
276 {
277 const SProtoShellIOBind *tmp =
278 reinterpret_cast<SProtoShellIOBind *>(item->data + j * wpe);
279
280 allocObject(tmp->objid);
281 }
282
283 break;
284 }
285
287 {
288 path = reinterpret_cast<const char *>(&item->data);
289 break;
290 }
291
293 {
294 const char *tmp = reinterpret_cast<const char *>(&item->data);
295 setPrompt(tmp);
296 break;
297 }
298
299 default:
300 {
301 DAWNERR("Unsupported Shell config 0x%08" PRIx32 "\n", item->cfgid.v);
302 return -EINVAL;
303 }
304 }
305 }
306
307 return OK;
308};
309
310void CProtoShellPretty::allocObject(const SObjectId::UObjectId &obj)
311{
312 DAWNINFO("allocate object 0x%" PRIx32 "\n", obj.v);
313
314 // Allocate object in map
315
316 setObjectMapItem(obj.v, nullptr);
317};
318
319void CProtoShellPretty::setPrompt(const char *p)
320{
321 prompt = p;
322}
323
324void CProtoShellPretty::getAndPrintSeek(CIOCommon *io) const
325{
326 SObjectId::ObjectId objid = io->getIdV();
327 size_t total = io->getDataSize();
328 size_t offset = 0;
329 io_ddata_t *chunk;
330 int ret;
331
332 fprintf(outstream_, "IO 0x%" PRIx32 " seekable data (%zu bytes):\n", objid, total);
333
334 chunk = io->ddata_alloc(1, SHELL_SEEK_CHUNK_SIZE);
335 if (chunk == nullptr)
336 {
337 fprintf(outstream_, "ddata_alloc failed\n");
338 return;
339 }
340
341 while (offset < total)
342 {
343 const uint8_t *ptr;
344 size_t avail;
345 size_t chunk_bytes;
346 size_t i;
347
348 ret = io->getData(*chunk, 1, offset);
349 if (ret < 0)
350 {
351 fprintf(outstream_, "getio seek failed at offset %zu: %d\n", offset, ret);
352 break;
353 }
354
355 avail = total - offset;
356 chunk_bytes = chunk->getDataSize() < avail ? chunk->getDataSize() : avail;
357 ptr = static_cast<const uint8_t *>(chunk->getDataPtr());
358
359 for (i = 0; i < chunk_bytes; i += SHELL_SEEK_LINE_BYTES)
360 {
361 size_t line_len =
362 (chunk_bytes - i) < SHELL_SEEK_LINE_BYTES ? (chunk_bytes - i) : SHELL_SEEK_LINE_BYTES;
363 size_t j;
364
365 fprintf(outstream_, "%08zx: ", offset + i);
366
367 for (j = 0; j < SHELL_SEEK_LINE_BYTES; j++)
368 {
369 if (j < line_len)
370 {
371 fprintf(outstream_, "%02x ", ptr[i + j]);
372 }
373 else
374 {
375 fprintf(outstream_, " ");
376 }
377
378 if (j == 7)
379 {
380 fprintf(outstream_, " ");
381 }
382 }
383
384 fprintf(outstream_, " ");
385
386 for (j = 0; j < line_len; j++)
387 {
388 uint8_t c = ptr[i + j];
389 fprintf(outstream_, "%c", (c >= 0x20 && c < 0x7f) ? (char)c : '.');
390 }
391
392 fprintf(outstream_, "\n");
393 }
394
395 offset += chunk_bytes;
396 }
397
398 free(chunk);
399}
400
401void CProtoShellPretty::getAndPrint(CIOCommon *io) const
402{
403 SObjectId::ObjectId objid = io->getIdV();
404 size_t ddim = io->getDataDim();
405 int dtype = io->getDtype();
406 (void)ddim;
407
408 // Check if we can read
409
410 if (io->isRead() == false)
411 {
412 fprintf(outstream_, "IO 0x%" PRIx32 "is write-only\n", objid);
413 return;
414 }
415
416 // Seekable IOs use hex dump output
417
418 if (io->isSeekable())
419 {
420 getAndPrintSeek(io);
421 return;
422 }
423
424 fprintf(outstream_, "IO 0x%" PRIx32 " data:\n\t", objid);
425
426 switch (dtype)
427 {
428#ifdef CONFIG_DAWN_DTYPE_BOOL
430 getAndPrintTyped<bool>(outstream_, io, ddim, "%" PRId8 " ");
431 break;
432#endif
433#ifdef CONFIG_DAWN_DTYPE_INT8
435 getAndPrintTyped<int8_t>(outstream_, io, ddim, "%" PRId8 " ");
436 break;
437#endif
438#ifdef CONFIG_DAWN_DTYPE_UINT8
440 getAndPrintTyped<uint8_t>(outstream_, io, ddim, "%" PRId8 " ");
441 break;
442#endif
443#ifdef CONFIG_DAWN_DTYPE_INT16
445 getAndPrintTyped<int16_t>(outstream_, io, ddim, "%" PRId16 " ");
446 break;
447#endif
448#ifdef CONFIG_DAWN_DTYPE_UINT16
450 getAndPrintTyped<uint16_t>(outstream_, io, ddim, "%" PRId16 " ");
451 break;
452#endif
453#ifdef CONFIG_DAWN_DTYPE_INT32
455 getAndPrintTyped<int32_t>(outstream_, io, ddim, "%" PRId32 " ");
456 break;
457#endif
458#ifdef CONFIG_DAWN_DTYPE_UINT32
460 getAndPrintTyped<uint32_t>(outstream_, io, ddim, "%" PRId32 " ");
461 break;
462#endif
463#ifdef CONFIG_DAWN_DTYPE_UINT64
465 getAndPrintTyped<uint64_t>(outstream_, io, ddim, "%" PRId64 " ");
466 break;
467#endif
468#ifdef CONFIG_DAWN_DTYPE_FLOAT
470 getAndPrintTyped<float>(outstream_, io, ddim, "%.4f ");
471 break;
472#endif
473#ifdef CONFIG_DAWN_DTYPE_CHAR
475 getAndPrintChar(outstream_, io, ddim);
476 break;
477#endif
478 default:
479 fprintf(outstream_, "missing print support for dtype=%d\n", dtype);
480 break;
481 }
482
483 fprintf(outstream_, "\n");
484}
485
486void CProtoShellPretty::getcfgAndPrint(CObject *obj) const
487{
488 const CDescObject &desc = obj->getDesc();
489
490 for (size_t i = 0; i < desc.getSizeBytes() / 4; i++)
491 {
492 fprintf(outstream_, " 0x%08" PRIx32 "\n", desc.getAtOffset(i));
493 }
494}
495
496void CProtoShellPretty::cmdHelp()
497{
498 fprintf(outstream_, "Proto SHELL help:\n");
499 fprintf(outstream_, "\t help - print this message\n");
500 fprintf(outstream_, "\t exit - exit\n");
501 fprintf(outstream_, "\t info - show shell-bound IO inventory\n");
502 fprintf(outstream_, "\t getio <IO objectID> - get value for a given objectID\n");
503 fprintf(outstream_, "\t setio <IO objectID> <v1..vN> - set IO value words\n");
504 fprintf(outstream_, "\t getioloop - get all objects in loop\n");
505#ifdef CONFIG_DAWN_IO_NOTIFY
506 fprintf(outstream_, "\t getionotify <objectID> - get io with notification\n");
507#endif
508 fprintf(outstream_, "\t getcfg <objectID> [cfgID] - get object configuration\n");
509 fprintf(outstream_, "\t setcfg <objectID> <cfgID> <v1..vN> - set object config words\n");
510#ifdef CONFIG_DAWN_PROTO_SHELL_INSPECT
511 fprintf(outstream_, "\n Object Inspector:\n");
512 fprintf(outstream_, "\t list [io|prog|proto] [verbose] - show object inventory\n");
513 fprintf(outstream_, "\t inspect <objectID> - detailed object introspection\n");
514 fprintf(outstream_, "\t tree - show object hierarchy\n");
515 fprintf(outstream_, "\t stats - show runtime statistics\n");
516#endif
517 fprintf(outstream_, "\n\t NOTE: all values must be in hex format: 0xYYYYYYYY\n");
518}
519
520void CProtoShellPretty::cmdExit()
521{
523 workerThread().requestStop();
524}
525
526void CProtoShellPretty::cmdInfo()
527{
528 fprintf(outstream_, "INFO: shell IO bindings\n");
529 fprintf(outstream_, " Name ObjID DType[Dim] Flags\n");
530 fprintf(outstream_, " -------------- ---------- ---------- ------\n");
531
532 for (auto const &[id, io] : getIOMap())
533 {
534 if (io == nullptr)
535 {
536 fprintf(
537 outstream_, " %-14s 0x%08" PRIx32 " %-10s %s\n", "(unbound)", id, "-", "unbound");
538 continue;
539 }
540
541 fprintf(outstream_,
542 " %-14s 0x%08" PRIx32 " %s[%zu] %c%c%c%c%c\n",
543#ifdef CONFIG_DAWN_OBJECT_HAS_NAME
544 io->getName(),
545#else
546 "-",
547#endif
548 io->getIdV(),
550 io->getDataDim(),
551 io->isRead() ? 'R' : '-',
552 io->isWrite() ? 'W' : '-',
553 io->isNotify() ? 'N' : '-',
554 io->isTimestamp() ? 'T' : '-',
555 io->getCfgFlag() ? 'C' : '-');
556 }
557
558 fprintf(outstream_, "Flags: R=Read W=Write N=Notify T=Timestamp C=Config\n");
559#ifdef CONFIG_DAWN_PROTO_SHELL_INSPECT
560 fprintf(outstream_, "Use 'list io' for all runtime IOs or 'list verbose' for details.\n");
561#endif
562}
563
564void CProtoShellPretty::cmdSetio(const char *arg)
565{
566 SObjectId::ObjectId objid = 0;
567 CIOCommon *io = nullptr;
568 io_ddata_t *data = nullptr;
569 char argbuf[DAWN_PROTO_SHELL_LINELEN];
570 char *saveptr = nullptr;
571 char *token;
572 size_t words;
573 size_t data_size;
574 size_t elem_size;
575 size_t i;
576 int ret;
577
578 if (arg == nullptr || *arg == '\0')
579 {
580 fprintf(outstream_, "invalid argument\n");
581 return;
582 }
583
584 strncpy(argbuf, arg, sizeof(argbuf) - 1);
585 argbuf[sizeof(argbuf) - 1] = '\0';
586
587 token = strtok_r(argbuf, " \t", &saveptr);
588 if (!parseU32Token(token, &objid))
589 {
590 fprintf(outstream_, "invalid argument: %s\n", arg);
591 return;
592 }
593
594 token = strtok_r(nullptr, " \t", &saveptr);
595 if (token == nullptr)
596 {
597 fprintf(outstream_,
598 "invalid argument: %s."
599 " Must be string in 0xXXXXXXXX format\n",
600 arg);
601 return;
602 }
603
604 // Get IO
605
606 io = getIO(objid);
607 if (io == nullptr)
608 {
609 fprintf(outstream_, "no IO with objID = 0x%" PRIx32 "\n", objid);
610 return;
611 }
612
613 if (io->getIdV() != objid)
614 {
615 fprintf(outstream_,
616 "IO ID mismatch: expected 0x%" PRIx32 ", got 0x%" PRIx32 "\n",
617 objid,
618 io->getIdV());
619 return;
620 }
621
622 // Check if we can write
623
624 if (io->isWrite() == false)
625 {
626 fprintf(outstream_, "IO 0x%" PRIx32 "is read-only\n", objid);
627 return;
628 }
629
630 words = io->getDataDim();
631 if (words == 0 || words > GETANDPRINT_DIM_MAX)
632 {
633 fprintf(outstream_, "unsupported io dim %zu\n", words);
634 return;
635 }
636
637 data_size = io->getDataSize();
638 if (data_size == 0 || data_size % words != 0)
639 {
640 fprintf(outstream_, "unsupported io data shape size=%zu dim=%zu\n", data_size, words);
641 return;
642 }
643
644 elem_size = data_size / words;
645 if (elem_size == 0 || elem_size > 4)
646 {
647 fprintf(outstream_, "io set supported only for element size <= 4\n");
648 return;
649 }
650
651 data = io->ddata_alloc(1);
652 if (data == nullptr)
653 {
654 fprintf(outstream_, "setio buffer alloc failed\n");
655 return;
656 }
657
658 for (i = 0; i < words; i++)
659 {
660 uint32_t value;
661
662 if (i > 0)
663 {
664 token = strtok_r(nullptr, " \t", &saveptr);
665 }
666
667 if (!parseU32Token(token, &value))
668 {
669 fprintf(
670 outstream_, "invalid data: expected %zu words for IO 0x%" PRIx32 "\n", words, objid);
671 delete data;
672 return;
673 }
674
675 std::memcpy(static_cast<uint8_t *>(data->getDataPtr()) + i * elem_size, &value, elem_size);
676 }
677
678 if (strtok_r(nullptr, " \t", &saveptr) != nullptr)
679 {
680 fprintf(outstream_, "too many data words for IO 0x%" PRIx32 "\n", objid);
681 delete data;
682 return;
683 }
684
685 ret = io->setData(*data);
686 if (ret < 0)
687 {
688 fprintf(outstream_, "setio failed %d\n", ret);
689 }
690
691 delete data;
692}
693
694void CProtoShellPretty::cmdGetio(const char *arg)
695{
696 SObjectId::ObjectId objid = 0;
697 CIOCommon *io;
698
699 // Get objectid
700
701 if (!parseU32Token(arg, &objid))
702 {
703 fprintf(outstream_, "invalid argument: %s\n", arg);
704 return;
705 }
706
707 // Get IO
708
709 io = getIO(objid);
710 if (io == nullptr)
711 {
712 fprintf(outstream_, "no IO with objID = 0x%" PRIx32 "\n", objid);
713 return;
714 }
715
716 if (io->getIdV() != objid)
717 {
718 fprintf(outstream_,
719 "IO ID mismatch: expected 0x%" PRIx32 ", got 0x%" PRIx32 "\n",
720 objid,
721 io->getIdV());
722 return;
723 }
724
725 // Get data and print on stdout
726
727 getAndPrint(io);
728}
729
730void CProtoShellPretty::cmdGetioloop(const char *arg)
731{
732 int times = 10;
733
734 do
735 {
736 fprintf(outstream_, "\nProto 0x%" PRIx32 "\n", getIdV());
737
738 for (auto const &[id, io] : getIOMap())
739 {
740 if (io == nullptr)
741 {
742 fprintf(outstream_, "IO 0x%" PRIx32 " is not bound\n", id);
743 continue;
744 }
745
746 getAndPrint(io);
747 }
748
749 times--;
750 std::this_thread::sleep_for(1000ms);
751 }
752 while (times > 0);
753}
754
755#ifdef CONFIG_DAWN_IO_NOTIFY
756void CProtoShellPretty::cmdGetioNotify(const char *arg)
757{
758 SObjectId::ObjectId objid = 0;
759 CIOCommon *io;
760 int ret;
761
762 // Get objectid
763
764 if (!parseU32Token(arg, &objid))
765 {
766 fprintf(outstream_, "invalid argument: %s\n", arg);
767 return;
768 }
769
770 // Get IO
771
772 io = getIO(objid);
773 if (io == nullptr)
774 {
775 fprintf(outstream_, "no IO with objID = 0x%" PRIx32 "\n", objid);
776 return;
777 }
778
779 if (io->getIdV() != objid)
780 {
781 fprintf(outstream_,
782 "IO ID mismatch: expected 0x%" PRIx32 ", got 0x%" PRIx32 "\n",
783 objid,
784 io->getIdV());
785 return;
786 }
787
788 // Set notifier
789
790 ret = io->setNotifier(notifierCb, 0, io);
791 if (ret < 0)
792 {
793 fprintf(outstream_, "ERROR: set notifier failed for objId = 0x%" PRIx32 "\n", objid);
794 return;
795 }
796}
797#endif
798
799void CProtoShellPretty::cmdSetcfg(const char *arg)
800{
801 SObjectId::ObjectId objid = 0;
802 SObjectCfg::ObjectCfgId objcfg = 0;
803 CObject *obj;
804 std::vector<uint32_t> data;
805 char argbuf[DAWN_PROTO_SHELL_LINELEN];
806 char *saveptr = nullptr;
807 char *token;
808 size_t words;
809 size_t i;
810 int ret;
811
812 if (arg == nullptr || *arg == '\0')
813 {
814 fprintf(outstream_, "invalid arguments\n");
815 return;
816 }
817
818 strncpy(argbuf, arg, sizeof(argbuf) - 1);
819 argbuf[sizeof(argbuf) - 1] = '\0';
820
821 token = strtok_r(argbuf, " \t", &saveptr);
822 if (!parseU32Token(token, &objid))
823 {
824 fprintf(outstream_, "invalid object ID: %s\n", arg);
825 return;
826 }
827
828 token = strtok_r(nullptr, " \t", &saveptr);
829 if (!parseU32Token(token, &objcfg))
830 {
831 fprintf(outstream_, "invalid cfg ID: %s\n", arg);
832 return;
833 }
834
835 words = SObjectCfg::objectCfgGetSize(objcfg);
836 if (words == 0)
837 {
838 fprintf(outstream_, "invalid cfg word count for cfgID = 0x%" PRIx32 "\n", objcfg);
839 return;
840 }
841
842 data.resize(words);
843 for (i = 0; i < words; i++)
844 {
845 token = strtok_r(nullptr, " \t", &saveptr);
846 if (!parseU32Token(token, &data[i]))
847 {
848 fprintf(outstream_,
849 "invalid data: expected %zu words for cfgID 0x%" PRIx32 "\n",
850 words,
851 objcfg);
852 return;
853 }
854 }
855
856 if (strtok_r(nullptr, " \t", &saveptr) != nullptr)
857 {
858 fprintf(outstream_, "too many data words for cfgID 0x%" PRIx32 "\n", objcfg);
859 return;
860 }
861
862 obj = getObject(objid);
863 if (obj == nullptr)
864 {
865 fprintf(outstream_, "no object with objID = 0x%" PRIx32 "\n", objid);
866 return;
867 }
868
869 ret = obj->setObjConfig(objcfg, data.data(), words);
870 if (ret < 0)
871 {
872 fprintf(outstream_, "failed to update objectCfg = 0x%" PRIx32 "\n", objcfg);
873 return;
874 }
875}
876
877void CProtoShellPretty::cmdGetcfg(const char *arg)
878{
879 SObjectId::ObjectId objid = 0;
880 SObjectCfg::ObjectCfgId objcfg = 0;
881 CObject *obj;
882 std::vector<uint32_t> data;
883 char argbuf[DAWN_PROTO_SHELL_LINELEN];
884 char *saveptr = nullptr;
885 char *token;
886 size_t words;
887 size_t i;
888
889 if (arg == nullptr || *arg == '\0')
890 {
891 fprintf(outstream_, "invalid arguments\n");
892 return;
893 }
894
895 strncpy(argbuf, arg, sizeof(argbuf) - 1);
896 argbuf[sizeof(argbuf) - 1] = '\0';
897
898 token = strtok_r(argbuf, " \t", &saveptr);
899 if (!parseU32Token(token, &objid))
900 {
901 fprintf(outstream_, "invalid object ID: %s\n", arg);
902 return;
903 }
904
905 obj = getObject(objid);
906 if (obj == nullptr)
907 {
908 fprintf(outstream_, "no object with objID = 0x%" PRIx32 "\n", objid);
909 return;
910 }
911
912 token = strtok_r(nullptr, " \t", &saveptr);
913 if (token == nullptr)
914 {
915 getcfgAndPrint(obj);
916 return;
917 }
918
919 if (!parseU32Token(token, &objcfg))
920 {
921 fprintf(outstream_, "invalid cfg ID: %s\n", arg);
922 return;
923 }
924
925 if (strtok_r(nullptr, " \t", &saveptr) != nullptr)
926 {
927 fprintf(outstream_, "invalid argument: %s\n", arg);
928 return;
929 }
930
931 words = SObjectCfg::objectCfgGetSize(objcfg);
932 if (words == 0)
933 {
934 fprintf(outstream_, "invalid cfg word count for cfgID = 0x%" PRIx32 "\n", objcfg);
935 return;
936 }
937
938 data.resize(words);
939 if (obj->getObjConfig(objcfg, data.data(), words) < 0)
940 {
941 fprintf(outstream_, "failed to read objectCfg = 0x%" PRIx32 "\n", objcfg);
942 return;
943 }
944
945 fprintf(outstream_, "CFG 0x%" PRIx32 ":\n", objcfg);
946 for (i = 0; i < words; i++)
947 {
948 fprintf(outstream_, "\t0x%08" PRIx32 "\n", data[i]);
949 }
950}
951
952void CProtoShellPretty::cmdHandle(char *cmd, const char *arg)
953{
954 std::string scmd = cmd;
955
956 // fprintf(outstream_, "cmd = %s arg = %s\n", cmd, arg);
957
958 switch (cmdmap[scmd])
959 {
960 case PROTO_SHELL_CMDID_HELP:
961 {
962 cmdHelp();
963 break;
964 }
965
966 case PROTO_SHELL_CMDID_EXIT:
967 {
968 cmdExit();
969 break;
970 }
971
972 case PROTO_SHELL_CMDID_INFO:
973 {
974 cmdInfo();
975 break;
976 }
977
978 case PROTO_SHELL_CMDID_SETIO:
979 {
980 cmdSetio(arg);
981 break;
982 }
983
984 case PROTO_SHELL_CMDID_GETIO:
985 {
986 cmdGetio(arg);
987 break;
988 }
989
990#ifdef CONFIG_DAWN_IO_NOTIFY
991 case PROTO_SHELL_CMDID_GETIONOTIFY:
992 {
993 cmdGetioNotify(arg);
994 break;
995 }
996#endif
997
998 case PROTO_SHELL_CMDID_GETIOLOOP:
999 {
1000 cmdGetioloop(arg);
1001 break;
1002 }
1003
1004 case PROTO_SHELL_CMDID_SETCFG:
1005 {
1006 cmdSetcfg(arg);
1007 break;
1008 }
1009
1010 case PROTO_SHELL_CMDID_GETCFG:
1011 {
1012 cmdGetcfg(arg);
1013 break;
1014 }
1015
1016#ifdef CONFIG_DAWN_PROTO_SHELL_INSPECT
1017 case PROTO_SHELL_CMDID_LIST:
1018 {
1019 cmdList(arg);
1020 break;
1021 }
1022
1023 case PROTO_SHELL_CMDID_INSPECT:
1024 {
1025 cmdInspect(arg);
1026 break;
1027 }
1028
1029 case PROTO_SHELL_CMDID_TREE:
1030 {
1031 cmdTree(arg);
1032 break;
1033 }
1034
1035 case PROTO_SHELL_CMDID_STATS:
1036 {
1037 cmdStats(arg);
1038 break;
1039 }
1040#endif // CONFIG_DAWN_PROTO_SHELL_INSPECT
1041
1042 default:
1043 {
1044 fprintf(outstream_, "ERROR:invalid command %s\n", cmd);
1045 cmdHelp();
1046 break;
1047 }
1048 }
1049}
1050
1051void CProtoShellPretty::thread()
1052{
1053 char buffer[DAWN_PROTO_SHELL_LINELEN];
1054 char *cmd;
1055 char *arg;
1056
1057 // Initialize thread
1058
1059 fprintf(outstream_, "\n*Start DAWN Shell*\n\n");
1060
1061 // Loop until stop called
1062
1063 do
1064 {
1065 if (prompt)
1066 {
1067 fprintf(outstream, "%s", prompt);
1068 fflush(stdout);
1069 }
1070
1071 auto len = readline_stream(buffer, sizeof(buffer), instream, outstream);
1072 if (len > 0)
1073 {
1074 // Handle simple ENTER
1075
1076 if (len == 1)
1077 {
1078 continue;
1079 }
1080
1081 // Remove trailing line endings (\n, \r, or CRLF)
1082
1083 buffer[len] = '\0';
1084 while (len > 0 && (buffer[len - 1] == '\n' || buffer[len - 1] == '\r'))
1085 {
1086 buffer[len - 1] = '\0';
1087 len -= 1;
1088 }
1089
1090 if (len == 0)
1091 {
1092 continue;
1093 }
1094
1095 // Parse the command from the argument
1096
1097 cmd = strtok_r(buffer, " \r\n", &arg);
1098 if (cmd == nullptr)
1099 {
1100 continue;
1101 }
1102
1103 // Remove leading spaces from arg
1104
1105 while (*arg == ' ')
1106 {
1107 arg++;
1108 }
1109
1110 // Handle command
1111
1112 cmdHandle(cmd, arg);
1113 }
1114 }
1115 while (!workerThread().shouldQuit());
1116
1117 // Mark thread quit done
1118
1119 workerThread().markThreadFinished();
1120}
1121
1122CProtoShellPretty::~CProtoShellPretty()
1123{
1124 // Make sure that thread is stopped
1125
1127
1128 // Close streams
1129
1130 fclose(instream);
1131 fclose(outstream);
1132
1134 {
1136 }
1137}
1138
1140{
1141 int ret;
1142
1143 if (CProtoShellPretty::inst != 0)
1144 {
1145 DAWNERR("Only one shell instance is supported\n");
1146 return -EBUSY;
1147 }
1148
1150
1151 // Configure object
1152
1153 ret = configureDesc(getDesc());
1154 if (ret != OK)
1155 {
1156 DAWNERR("Shell configure failed (error %d)\n", ret);
1158 return ret;
1159 }
1160
1161 if (path)
1162 {
1163 DAWNINFO("CProtoShellPretty path= %s\n", path);
1164
1165 instream = fopen(path, "r");
1166 if (instream == nullptr)
1167 {
1168 DAWNERR("Failed to open input stream: %s\n", path);
1170 return -EIO;
1171 }
1172
1173 outstream = fopen(path, "w");
1174 if (outstream == nullptr)
1175 {
1176 DAWNERR("Failed to open output stream: %s\n", path);
1177 fclose(instream);
1178 instream = nullptr;
1180 return -EIO;
1181 }
1182 }
1183 else
1184 {
1185 // Default streams
1186
1187 instream = stdin;
1188 outstream = stdout;
1189 }
1190
1191 // Store reference to output stream
1192
1193 outstream_ = outstream;
1194
1195 return OK;
1196}
1197
1199{
1200 return startWorkerThread([this]() { thread(); });
1201};
1202
1204{
1205 return stopWorkerThread();
1206}
1207
1209{
1210 return workerThreadRunning();
1211}
CObject * getObject(SObjectId::ObjectId id)
Get an object by ID.
Definition bindable.cxx:52
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
const std::map< SObjectId::ObjectId, CIOCommon * > & getIOMap() const
Get the I/O map for this object.
Definition bindable.cxx:18
Descriptor wrapper for individual object configuration.
size_t getSizeBytes() const
Get total size in bytes for this object definition.
size_t getSize() const
Get number of configuration items for this object.
uint32_t getAtOffset(size_t offset) const
Get 32-bit word at specified offset.
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
virtual bool isWrite() const =0
Check if IO supports write operations.
int setData(IODataCmn &data, size_t offset=0)
Set data for I/O (public interface with stats tracking).
Definition common.hxx:392
int getData(IODataCmn &data, size_t len, size_t offset=0)
Get data from I/O (public interface with stats tracking).
Definition common.hxx:353
virtual bool isSeekable() const
Check if IO supports partial (seekable) access.
Definition common.hxx:502
bool isTimestamp() const
Check if I/O supports timestamp.
Definition common.cxx:189
virtual size_t getDataDim() const =0
Get data vector dimension.
io_ddata_t * ddata_alloc(size_t batch, size_t chunk_size=0)
Allocate data buffer for this I/O.
Definition common.cxx:247
virtual size_t getDataSize() const =0
Get data size in bytes.
virtual bool isRead() const =0
Check if IO supports read operations.
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
int getObjConfig(SObjectCfg::ObjectCfgId objcfg, uint32_t *data, size_t len)
Get object configuration item.
Definition object.cxx:240
int setObjConfig(SObjectCfg::ObjectCfgId objcfg, uint32_t *data, size_t len)
Set object configuration item.
Definition object.cxx:200
uint8_t getDtype() const
Get data type field.
Definition object.cxx:175
bool getCfgFlag() const
Check if configuration flag is set.
Definition object.cxx:160
@ PROTO_CLASS_SHELL_STD
Interactive shell on stdin/stdout.
Definition common.hxx:55
int doStart()
Start implementation hook.
Definition pretty.cxx:1198
@ PROTO_SHELL_CFG_PATH
Shell device path (TTY/serial).
Definition pretty.hxx:42
@ PROTO_SHELL_CFG_PROMPT
Custom prompt string.
Definition pretty.hxx:43
@ PROTO_SHELL_CFG_IOBIND
I/O object binding configuration.
Definition pretty.hxx:41
static int inst
Global instance counter for multiple shell instances.
Definition pretty.hxx:35
int doStop()
Stop implementation hook.
Definition pretty.cxx:1203
static FILE * outstream_
Global output stream for shell messages.
Definition pretty.hxx:36
bool hasThread() const
Check if a background thread is active.
Definition pretty.cxx:1208
int configure()
Configure object from descriptor data.
Definition pretty.cxx:1139
static void request()
Request application shutdown.
Definition shutdown.cxx:17
bool workerThreadRunning() const
Check if the worker thread is running.
Definition thread.hxx:269
int stopWorkerThread()
Stop the worker thread.
Definition thread.hxx:258
int startWorkerThread(Func &&func)
Start the worker thread with a given function.
Definition thread.hxx:246
CThreadedObject & workerThread()
Get a reference to this thread controller.
Definition thread.hxx:280
uint32_t ObjectCfgId
ConfigID type - single 32-bit value.
Definition objectcfg.hxx:60
static uint16_t objectCfgGetSize(const ObjectCfgId objcfg)
Extract configuration data size from ConfigID.
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).
static const char * dtypeToString(uint8_t dtype)
Convert data type to human-readable string.
Definition objectid.cxx:167
@ 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_UINT64
Unsigned 64-bit integer.
Definition objectid.hxx:104
@ DTYPE_UINT16
Unsigned 16-bit integer (0 to 65535).
Definition objectid.hxx:88
@ 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
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
T & get(size_t index, size_t batch=0)
Get data element by index and batch (type-safe).
Definition ddata.hxx:93
Static (compile-time) I/O data buffer (no timestamp).
Definition sdata.hxx:39
size_t getItems()
Get number of items per batch.
Definition sdata.hxx:89
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