Dawn Framework 1.0
Universal data acquisition framework for embedded systems
regs.cxx
1// dawn/src/proto/can/regs.cxx
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5
6#include "can_internal.hxx"
7
8#include <new>
9
10#include "dawn/io/common.hxx"
11#include "dawn/porting/can.hxx"
12
13using namespace dawn;
14
15static constexpr size_t CAN_SEGMENT_TRANSFER_MAX = 0x380;
16static constexpr size_t CAN_SINGLE_ID_TRANSFER_MAX = 0x300;
17
18static size_t canIoDataBytes(CIOCommon *io)
19{
20 return io->getDataSize();
21}
22
23#ifdef CONFIG_DAWN_IO_NOTIFY
24int CProtoCan::notifierCb(void *priv, io_ddata_t *data)
25{
26 SCanIoData *canio = (SCanIoData *)priv;
27 CIOCommon *io;
29
30 if (canio == nullptr)
31 {
32 DAWNERR("NULL canio pointer in notifier callback\n");
33 return -EINVAL;
34 }
35
36 io = canio->io;
37 if (io == nullptr)
38 {
39 DAWNERR("NULL io pointer in notifier callback\n");
40 return -EINVAL;
41 }
42
43 msg.id = canio->canid;
44 msg.len = io->getDataSize();
45 msg.rtr = 0;
46 msg.extid = CAN_EXTID_FLAG;
47 msg._res = 0;
48
49 std::memcpy(msg.data, data->getDataPtr(), io->getDataSize());
50
51 return can_send(canio->proto->fd, &msg);
52}
53#endif
54
55int CProtoCan::validateCanIo(const SProtoCanIOBind *v, CIOCommon *io, SCanIoData *canio)
56{
57 switch (v->type)
58 {
59#ifdef CONFIG_DAWN_PROTO_CAN_SIMPLE
60# ifdef CONFIG_DAWN_IO_NOTIFY
61 case CAN_TYPE_PUSH:
62 {
63 if (io->isRead() == false)
64 {
65 DAWNERR("input reg doesn't support read\n");
66 return -EINVAL;
67 }
68
69 if (io->isNotify() == true)
70 {
71 int ret = io->setNotifier(notifierCb, 0, canio);
72 if (ret < 0)
73 {
74 DAWNERR("ERROR: set notifier failed for objId = "
75 "0x%" PRIx32 "\n",
76 io->getIdV());
77 }
78 }
79 else
80 {
81 DAWNERR("IO notify required\n");
82 return -EINVAL;
83 }
84
85 if (canio->data_len > 8)
86 {
87 DAWNERR("not supported\n");
88 return -EINVAL;
89 }
90
91 break;
92 }
93# endif
94
95 case CAN_TYPE_READ:
96 {
97# ifdef CONFIG_DAWN_PROTO_CAN_RTR
98 if (io->isRead() == false)
99 {
100 DAWNERR("input reg doesn't support read\n");
101 return -EINVAL;
102 }
103
104 if (canio->data_len > 8)
105 {
106 DAWNERR("not supported\n");
107 return -EINVAL;
108 }
109# else
110 DAWNERR("CAN RTR required\n");
111 return -EINVAL;
112# endif
113 break;
114 }
115
116 case CAN_TYPE_WRITE:
117 {
118 if (io->isWrite() == false)
119 {
120 DAWNERR("reg doesn't support write\n");
121 return -EINVAL;
122 }
123
124 if (canio->data_len > 8)
125 {
126 DAWNERR("not supported\n");
127 return -EINVAL;
128 }
129
130 break;
131 }
132#endif
133
134#ifdef CONFIG_DAWN_PROTO_CAN_SINGLE_ID
136 {
137 if (io->isRead() == false)
138 {
139 DAWNERR("input reg doesn't support read\n");
140 return -EINVAL;
141 }
142
143 break;
144 }
145
147 {
148 if (io->isWrite() == false)
149 {
150 DAWNERR("reg doesn't support write\n");
151 return -EINVAL;
152 }
153
154 break;
155 }
156#endif
157
158#ifdef CONFIG_DAWN_PROTO_CAN_SEG
160 {
161 if (io->isRead() == false)
162 {
163 DAWNERR("input reg doesn't support read\n");
164 return -EINVAL;
165 }
166
167 if (!io->isSeekable() && canio->data_len > CAN_SEGMENT_TRANSFER_MAX)
168 {
169 DAWNERR("not supported\n");
170 return -EINVAL;
171 }
172 break;
173 }
174
176 {
177 if (io->isWrite() == false)
178 {
179 DAWNERR("reg doesn't support write\n");
180 return -EINVAL;
181 }
182
183 if (canio->data_len > CAN_SEGMENT_TRANSFER_MAX)
184 {
185 DAWNERR("not supported\n");
186 return -EINVAL;
187 }
188
189 break;
190 }
191#endif
192
193 default:
194 {
195 DAWNERR("unsupported CAN access type\n");
196 return -EINVAL;
197 }
198 }
199
200 return OK;
201}
202
203int CProtoCan::createRegsForGroup(SProtoCanIOBind *v)
204{
205 SProtoCanRegs *tmp;
206 int ret;
207
208 tmp = new (std::nothrow) SProtoCanRegs();
209 if (!tmp)
210 {
211 DAWNERR("failed to allocate register handler\n");
212 return -ENOMEM;
213 }
214
215 vregs.push_back(tmp);
216
217 tmp->cfg = v;
218 tmp->ios = 0;
219
220#ifdef CONFIG_DAWN_PROTO_CAN_SINGLE_ID
221 if (v->type == CAN_TYPE_INDEXED_WRITE)
222 {
223 tmp->write_all = new (std::nothrow) SProtoCanWriteAll();
224 if (!tmp->write_all)
225 {
226 return -ENOMEM;
227 }
228
229 CIsoTp::initState(tmp->write_all->isotp);
230 tmp->write_all->io_idx = 0;
231 tmp->write_all->io_off = 0;
232 }
233 else
234 {
235 tmp->write_all = nullptr;
236 }
237#endif
238
239 tmp->io = new (std::nothrow) SCanIoData[v->size]();
240 if (!tmp->io)
241 {
242 return -ENOMEM;
243 }
244
245#ifdef CONFIG_DAWN_PROTO_CAN_SINGLE_ID
246 size_t group_total = 0;
247#endif
248
249 for (size_t i = 0; i < v->size; i++)
250 {
251 CIOCommon *io;
252 io_ddata_t *iobuffer;
253 SCanIoData *canio = &tmp->io[i];
254
255 canio->proto = this;
256
257 io = getIO(v->objid[i]);
258 if (io == nullptr)
259 {
260 DAWNERR("Failed to get IO 0x%08" PRIx32 "\n", v->objid[i]);
261 return -EIO;
262 }
263
264 if (io->isSeekable() && v->type != CAN_TYPE_READ_SEG && v->type != CAN_TYPE_WRITE_SEG)
265 {
266 DAWNERR("seekable IO is supported only for segmented read "
267 "or write types (objid=0x%08" PRIx32 ", type=%" PRIu32 ")\n",
268 io->getIdV(),
269 v->type);
270 return -ENOTSUP;
271 }
272
273 size_t chunk_size = 0;
274
275 if (io->isSeekable())
276 {
277 if (v->type == CAN_TYPE_READ_SEG)
278 {
279 chunk_size = 64;
280 }
281 else if (v->type == CAN_TYPE_WRITE_SEG)
282 {
283 chunk_size = CAN_SEGMENT_TRANSFER_MAX;
284 }
285 }
286
287 iobuffer = io->ddata_alloc(1, chunk_size);
288 if (!iobuffer)
289 {
290 DAWNERR("failed to allocate register buffer\n");
291 return -ENOMEM;
292 }
293
294 canio->iodata = iobuffer;
295 canio->io = io;
296 canio->data_len = canIoDataBytes(io);
297 if (io->isSeekable() && v->type == CAN_TYPE_WRITE_SEG)
298 {
299 canio->data_len = iobuffer->getDataSize();
300 }
301
302#ifdef CONFIG_DAWN_PROTO_CAN_SINGLE_ID
303 if (v->type == CAN_TYPE_INDEXED_READ || v->type == CAN_TYPE_INDEXED_WRITE)
304 {
305 canio->canid = nodeid + v->start;
306 }
307 else
308#endif
309 {
310 canio->canid = nodeid + v->start + tmp->ios;
311 }
312
313#ifdef DAWN_PROTO_HAS_ISOTP
314 if (v->type == CAN_TYPE_WRITE_SEG || v->type == CAN_TYPE_INDEXED_WRITE)
315 {
316 canio->isotp = new (std::nothrow) CIsoTp::State();
317 if (!canio->isotp)
318 {
319 return -ENOMEM;
320 }
321
322 CIsoTp::initState(*canio->isotp);
323 }
324 else
325 {
326 canio->isotp = nullptr;
327 }
328#endif
329
330#ifdef CONFIG_DAWN_PROTO_CAN_EXTID
331 if (canio->canid > CAN_MAX_EXTMSGID)
332 {
333 DAWNERR("CAN ID 0x%08" PRIx32 " exceeds extended ID max\n",
334 static_cast<uint32_t>(canio->canid));
335 return -EINVAL;
336 }
337#else
338 if (canio->canid > CAN_MAX_STDMSGID)
339 {
340 DAWNERR("CAN ID 0x%08" PRIx32 " exceeds standard ID max\n",
341 static_cast<uint32_t>(canio->canid));
342 return -EINVAL;
343 }
344#endif
345
346 ret = validateCanIo(v, io, canio);
347 if (ret < 0)
348 {
349 return ret;
350 }
351
352#ifdef CONFIG_DAWN_PROTO_CAN_SINGLE_ID
353 if (v->type == CAN_TYPE_INDEXED_READ || v->type == CAN_TYPE_INDEXED_WRITE)
354 {
355 if (v->size > 0xff)
356 {
357 DAWNERR("too many IOs for single ID\n");
358 return -EINVAL;
359 }
360
361 if (canio->data_len > CAN_SINGLE_ID_TRANSFER_MAX)
362 {
363 DAWNERR("not supported\n");
364 return -EINVAL;
365 }
366
367 group_total += canio->data_len;
368 if (group_total > CAN_SINGLE_ID_TRANSFER_MAX)
369 {
370 DAWNERR("not supported\n");
371 return -EINVAL;
372 }
373 }
374#endif
375
376 tmp->ios += 1;
377 }
378
379 return OK;
380}
381
382int CProtoCan::createRegs()
383{
384 int ret;
385
386 if (initialized)
387 {
388 return OK;
389 }
390
391 for (auto *v : valloc)
392 {
393 ret = createRegsForGroup(v);
394 if (ret < 0)
395 {
396 destroyRegs();
397 return ret;
398 }
399 }
400
401 initialized = true;
402 return OK;
403}
404
405int CProtoCan::destroyRegs()
406{
407 for (auto *v : vregs)
408 {
409 if (v == nullptr)
410 {
411 continue;
412 }
413
414 if (v->io)
415 {
416 for (size_t i = 0; i < v->ios; i++)
417 {
418 SCanIoData *canio = &v->io[i];
419
420#ifdef CONFIG_DAWN_IO_NOTIFY
421 if (canio->io && canio->io->isNotify())
422 {
423 canio->io->setNotifier(nullptr, 0, nullptr);
424 }
425#endif
426
427 if (canio->iodata)
428 {
429 delete canio->iodata;
430 canio->iodata = nullptr;
431 }
432
433#ifdef DAWN_PROTO_HAS_ISOTP
434 if (canio->isotp)
435 {
436 delete canio->isotp;
437 canio->isotp = nullptr;
438 }
439#endif
440 }
441
442 delete[] v->io;
443 v->io = nullptr;
444 }
445
446#ifdef CONFIG_DAWN_PROTO_CAN_SINGLE_ID
447 if (v->write_all)
448 {
449 delete v->write_all;
450 v->write_all = nullptr;
451 }
452#endif
453
454 delete v;
455 }
456
457 valloc.clear();
458 vregs.clear();
459 initialized = false;
460
461 return OK;
462}
463
464int CProtoCan::msgRecv(const dawn::porting::canmsg_s &msg)
465{
466 int ret;
467
468 for (auto v : vregs)
469 {
470#ifdef CONFIG_DAWN_PROTO_CAN_SINGLE_ID
471 if (v->cfg->type == CAN_TYPE_INDEXED_READ || v->cfg->type == CAN_TYPE_INDEXED_WRITE)
472 {
473 ret = handleSingleIdGroup(msg, v);
474 }
475 else
476#endif
477 {
478 ret = handleLegacyGroup(msg, v);
479 }
480
481 if (ret != -ENOMSG)
482 {
483 return ret;
484 }
485 }
486
487 return OK;
488}
489
490#ifdef DAWN_PROTO_HAS_ISOTP
491int CProtoCan::sendSegmented(uint16_t canid,
492 const uint8_t *data,
493 size_t len,
494 bool with_index,
495 uint8_t index)
496{
497 int ret;
498 size_t offset = 0;
499 uint8_t seg = 0;
500 size_t header = with_index ? 2 : 1;
501 size_t payload_max = with_index ? 6 : 7;
502
503 if (len > payload_max * 0x80)
504 {
505 return -EINVAL;
506 }
507
508 if (len == 0)
509 {
511
512 resp.id = canid;
513 resp.len = header;
514 resp.rtr = 0;
515 resp.extid = CAN_EXTID_FLAG;
516 resp._res = 0;
517 resp.data[0] = 0x80;
518 if (with_index)
519 {
520 resp.data[1] = index;
521 }
522
523 return can_send(fd, &resp);
524 }
525
526 while (offset < len)
527 {
529 size_t chunk = len - offset;
530 bool last = false;
531
532 if (chunk > payload_max)
533 {
534 chunk = payload_max;
535 }
536 else
537 {
538 last = true;
539 }
540
541 resp.id = canid;
542 resp.len = header + chunk;
543 resp.rtr = 0;
544 resp.extid = CAN_EXTID_FLAG;
545 resp._res = 0;
546
547 resp.data[0] = seg;
548 if (last)
549 {
550 resp.data[0] |= 0x80;
551 }
552
553 if (with_index)
554 {
555 resp.data[1] = index;
556 std::memcpy(resp.data + 2, data + offset, chunk);
557 }
558 else
559 {
560 std::memcpy(resp.data + 1, data + offset, chunk);
561 }
562
563 ret = can_send(fd, &resp);
564 if (ret < 0)
565 {
566 return ret;
567 }
568
569 offset += chunk;
570 seg += 1;
571 }
572
573 return OK;
574}
575
576int CProtoCan::sendSegmentedRead(SCanIoData *canio,
577 size_t len,
578 bool with_index,
579 uint8_t index,
580 size_t offset)
581{
582 int ret;
583 CIOCommon *io;
584 io_ddata_t *iodata;
585 size_t total_len;
586 size_t payload_max = with_index ? 6 : 7;
587 size_t max_window = payload_max * CAN_SEG_SEQ_MAX;
588
589 if (!canio || !canio->io || !canio->iodata)
590 {
591 return -EINVAL;
592 }
593
594 io = canio->io;
595 iodata = canio->iodata;
596 total_len = io->isSeekable() ? io->getDataSize() : canio->data_len;
597
598 if (!io->isSeekable())
599 {
600 return sendSegmented(
601 canio->canid, static_cast<const uint8_t *>(iodata->getDataPtr()), len, with_index, index);
602 }
603
604 if (offset >= total_len)
605 {
606 return -EINVAL;
607 }
608
609 if (offset + len > total_len)
610 {
611 len = total_len - offset;
612 }
613
614 if (len > max_window)
615 {
616 len = max_window;
617 }
618
619 size_t sent = 0;
620 uint8_t seg = 0;
621 size_t buf_off = 0;
622 size_t buf_len = 0;
623
624 while (sent < len)
625 {
627
628 if (buf_off >= buf_len)
629 {
630 // Buffer empty, read more
631
632 buf_len = len - sent;
633 if (buf_len > iodata->getDataSize())
634 {
635 buf_len = iodata->getDataSize();
636 }
637
638 ret = io->getData(*iodata, 1, offset + sent);
639 if (ret < 0)
640 {
641 return ret;
642 }
643
644 buf_off = 0;
645 }
646
647 size_t remaining = buf_len - buf_off;
648 size_t chunk = remaining;
649
650 if (chunk > payload_max)
651 {
652 chunk = payload_max;
653 }
654
655 resp.id = canio->canid;
656 resp.len = (with_index ? 2 : 1) + chunk;
657 resp.rtr = 0;
658 resp.extid = CAN_EXTID_FLAG;
659 resp._res = 0;
660 resp.data[0] = seg;
661
662 if ((sent + chunk) >= len)
663 {
664 resp.data[0] |= 0x80;
665 }
666
667 if (with_index)
668 {
669 resp.data[1] = index;
670 std::memcpy(resp.data + 2, (uint8_t *)iodata->getDataPtr() + buf_off, chunk);
671 }
672 else
673 {
674 std::memcpy(resp.data + 1, (uint8_t *)iodata->getDataPtr() + buf_off, chunk);
675 }
676
677 ret = can_send(fd, &resp);
678 if (ret < 0)
679 {
680 return ret;
681 }
682
683 sent += chunk;
684 buf_off += chunk;
685 seg += 1;
686 }
687
688 return OK;
689}
690#endif
691
692int CProtoCan::sendIoResponse(SCanIoData *canio, uint8_t index, bool segmented)
693{
694 int ret;
695 size_t data_len;
696
697 data_len = canio->data_len;
698 if (canio->io->isSeekable())
699 {
700 data_len = canio->io->getDataSize();
701 }
702
703 if (!segmented || !canio->io->isSeekable())
704 {
705 ret = canio->io->getData(*canio->iodata, 1);
706 if (ret < 0)
707 {
708 DAWNERR("failed to get IO\n");
709 return ret;
710 }
711 }
712
713 if (!segmented)
714 {
716
717 if (data_len > 8)
718 {
719 return -ENOSYS;
720 }
721
722 resp.id = canio->canid;
723 resp.len = data_len;
724 resp.rtr = 0;
725 resp.extid = CAN_EXTID_FLAG;
726 resp._res = 0;
727
728 std::memcpy(resp.data, canio->iodata->getDataPtr(), resp.len);
729
730 return can_send(fd, &resp);
731 }
732
733#ifdef DAWN_PROTO_HAS_ISOTP
734 return sendSegmentedRead(canio, data_len, index > 0, index);
735#else
736 return -ENOTSUP;
737#endif
738}
739
740#ifdef CONFIG_DAWN_PROTO_CAN_SINGLE_ID
741int CProtoCan::handleSingleIdReadAll(const dawn::porting::canmsg_s &msg,
742 SProtoCanRegs *v,
743 bool ignore_len)
744{
745 int ret;
746
747 if (!ignore_len && msg.len != 2)
748 {
749 return OK;
750 }
751
752 for (size_t i = 0; i < v->ios; i++)
753 {
754 SCanIoData *canio = &v->io[i];
755
756 ret = sendIoResponse(canio, static_cast<uint8_t>(i + 1), true);
757 if (ret < 0)
758 {
759 return ret;
760 }
761 }
762
763 return OK;
764}
765
766int CProtoCan::handleSingleIdWriteAll(const dawn::porting::canmsg_s &msg,
767 SProtoCanRegs *v,
768 uint8_t seg_no,
769 bool seg_last)
770{
771 int ret;
772 size_t payload_len = msg.len - 2;
773 size_t payload_off = 0;
774 uint64_t now = canTimestampUs();
775 uint64_t timeout = CONFIG_DAWN_PROTO_CAN_SEG_TIMEOUT_US;
776
777 if (!v->write_all->isotp.active)
778 {
779 if (seg_no != 0)
780 {
781 return -EINVAL;
782 }
783
784 v->write_all->isotp.active = true;
785 v->write_all->isotp.seq_next = 0;
786 v->write_all->io_idx = 0;
787 v->write_all->io_off = 0;
788 v->write_all->isotp.timestamp = now;
789 }
790 else if (timeout > 0 && (now - v->write_all->isotp.timestamp) > timeout)
791 {
792 v->write_all->isotp.active = false;
793 if (seg_no != 0)
794 {
795 return -ETIMEDOUT;
796 }
797
798 v->write_all->isotp.active = true;
799 v->write_all->isotp.seq_next = 0;
800 v->write_all->io_idx = 0;
801 v->write_all->io_off = 0;
802 v->write_all->isotp.timestamp = now;
803 }
804
805 if (seg_no != v->write_all->isotp.seq_next)
806 {
807 v->write_all->isotp.active = false;
808 return -EINVAL;
809 }
810
811 while (payload_off < payload_len && v->write_all->io_idx < v->ios)
812 {
813 SCanIoData *canio = &v->io[v->write_all->io_idx];
814 size_t need = canio->data_len - v->write_all->io_off;
815 size_t avail = payload_len - payload_off;
816 size_t chunk = (avail < need) ? avail : need;
817
818 std::memcpy((uint8_t *)canio->iodata->getDataPtr() + v->write_all->io_off,
819 msg.data + 2 + payload_off,
820 chunk);
821
822 v->write_all->io_off += chunk;
823 payload_off += chunk;
824
825 if (v->write_all->io_off == canio->data_len)
826 {
827 ret = canio->io->setData(*canio->iodata);
828 if (ret != OK)
829 {
830 DAWNERR("failed to set IO\n");
831 v->write_all->isotp.active = false;
832 return ret;
833 }
834
835 v->write_all->io_idx += 1;
836 v->write_all->io_off = 0;
837 }
838 }
839
840 if (payload_off != payload_len)
841 {
842 v->write_all->isotp.active = false;
843 return -EINVAL;
844 }
845
846 if (seg_last)
847 {
848 if (v->write_all->io_idx != v->ios)
849 {
850 v->write_all->isotp.active = false;
851 return -EINVAL;
852 }
853
854 CIsoTp::resetState(v->write_all->isotp);
855 v->write_all->io_idx = 0;
856 v->write_all->io_off = 0;
857
858 return OK;
859 }
860
861 v->write_all->isotp.timestamp = now;
862 v->write_all->isotp.seq_next += 1;
863 return OK;
864}
865
866int CProtoCan::handleSingleIdIndex(const dawn::porting::canmsg_s &msg,
867 SProtoCanRegs *v,
868 uint8_t index,
869 uint8_t seg_no,
870 bool seg_last)
871{
872 int ret;
873 SCanIoData *canio = &v->io[index - 1];
874
875 if (v->cfg->type == CAN_TYPE_INDEXED_WRITE)
876 {
877 uint64_t now = canTimestampUs();
878 uint64_t timeout = CONFIG_DAWN_PROTO_CAN_SEG_TIMEOUT_US;
879
880 ret = CIsoTp::receiveCustom(msg,
881 *canio->isotp,
882 canio->iodata->getDataPtr(),
883 canio->data_len,
884 seg_no,
885 seg_last,
886 now,
887 timeout);
888 if (ret < 0)
889 {
890 return ret;
891 }
892
893 if (ret == 1) // Complete
894 {
895 ret = canio->io->setData(*canio->iodata);
896 if (ret != OK)
897 {
898 DAWNERR("failed to set IO\n");
899 return ret;
900 }
901 }
902
903 return OK;
904 }
905
906 if (msg.len != 2)
907 {
908 return OK;
909 }
910
911 if (canio->io->isRead() == false)
912 {
913 DAWNERR("IO doesn't support read\n");
914 return -EINVAL;
915 }
916
917 return sendIoResponse(canio, index, true);
918}
919
920int CProtoCan::handleSingleIdGroup(const dawn::porting::canmsg_s &msg, SProtoCanRegs *v)
921{
922 if (v->cfg->type != CAN_TYPE_INDEXED_READ && v->cfg->type != CAN_TYPE_INDEXED_WRITE)
923 {
924 return -ENOMSG;
925 }
926
927 if (msg.id != nodeid + v->cfg->start)
928 {
929 return -ENOMSG;
930 }
931
932 if (msg.len < 2)
933 {
934 return OK;
935 }
936
937 uint8_t seg = msg.data[0];
938 uint8_t seg_no = seg & 0x7f;
939 bool seg_last = (seg & 0x80) != 0;
940 uint8_t index = msg.data[1];
941
942 if (seg_no != 0 && v->cfg->type == CAN_TYPE_INDEXED_READ)
943 {
944 return -ENOMSG;
945 }
946
947 if (v->cfg->type == CAN_TYPE_INDEXED_READ && msg.len != 2)
948 {
949 // Ignore loopback of our own indexed read response frames. They share
950 // the same CAN ID but are not request frames.
951 return -ENOMSG;
952 }
953
954 if (index == 0)
955 {
956 if (v->cfg->type == CAN_TYPE_INDEXED_READ)
957 {
958 return handleSingleIdReadAll(msg, v, true);
959 }
960
961 return handleSingleIdWriteAll(msg, v, seg_no, seg_last);
962 }
963
964 if (index > v->cfg->size)
965 {
966 return OK;
967 }
968
969 return handleSingleIdIndex(msg, v, index, seg_no, seg_last);
970}
971#endif
972
973int CProtoCan::handleLegacyGroup(const dawn::porting::canmsg_s &msg, SProtoCanRegs *v)
974{
975 int ret;
976
977 if (msg.id < nodeid + v->cfg->start || msg.id >= nodeid + v->cfg->start + v->cfg->size)
978 {
979 return -ENOMSG;
980 }
981
982 uint8_t idx = msg.id - nodeid - v->cfg->start;
983 SCanIoData *canio = &v->io[idx];
984
985 if (!canio->io)
986 {
987 return -EINVAL;
988 }
989
990#ifdef CONFIG_DAWN_PROTO_CAN_SIMPLE
991 if (v->cfg->type == CAN_TYPE_WRITE)
992 {
993 if (canio->io->isWrite() == false)
994 {
995 DAWNERR("IO doesn't support write\n");
996 return -EINVAL;
997 }
998
999 std::memcpy(canio->iodata->getDataPtr(), msg.data, msg.len);
1000
1001 ret = canio->io->setData(*canio->iodata);
1002 if (ret != OK)
1003 {
1004 DAWNERR("failed to set IO\n");
1005 return ret;
1006 }
1007
1008 return OK;
1009 }
1010#endif
1011
1012#ifdef CONFIG_DAWN_PROTO_CAN_SEG
1013 if (v->cfg->type == CAN_TYPE_READ_SEG && msg.rtr == 1)
1014 {
1015 // Segmented reads do not use RTR.
1016 return -ENOTSUP;
1017 }
1018
1019 if (v->cfg->type == CAN_TYPE_READ_SEG && msg.rtr == 0)
1020 {
1021 if (msg.len != 0)
1022 {
1023 return OK;
1024 }
1025
1026 if (canio->io->isRead() == false)
1027 {
1028 DAWNERR("IO doesn't support read\n");
1029 return -EINVAL;
1030 }
1031
1032 return sendIoResponse(canio, 0, true);
1033 }
1034
1035 if (v->cfg->type == CAN_TYPE_WRITE_SEG)
1036 {
1037 uint64_t now = canTimestampUs();
1038 uint64_t timeout = CONFIG_DAWN_PROTO_CAN_SEG_TIMEOUT_US;
1039 size_t payload_len;
1040
1041 // Allow other handlers (e.g. READ_SEG on same CAN ID) to process
1042 // non-write traffic.
1043 if (msg.rtr == 1)
1044 {
1045 return -ENOMSG;
1046 }
1047
1048 ret = CIsoTp::receive(
1049 msg, *canio->isotp, canio->iodata->getDataPtr(), canio->data_len, now, timeout);
1050 if (ret < 0)
1051 {
1052 return ret;
1053 }
1054
1055 if (ret == 1) // Complete
1056 {
1057 size_t old_size;
1058
1059 payload_len = canio->isotp->total_len;
1060
1061 if (canio->io->isSeekable())
1062 {
1063 // Reuse the staged segmented buffer, but clamp the logical size
1064 // to the received ISO-TP payload before writing.
1065 old_size = canio->iodata->N;
1066 canio->iodata->N = payload_len;
1067 ret = canio->io->setData(*canio->iodata);
1068 canio->iodata->N = old_size;
1069 }
1070 else
1071 {
1072 ret = canio->io->setData(*canio->iodata);
1073 }
1074
1075 CIsoTp::resetState(*canio->isotp);
1076 if (ret != OK)
1077 {
1078 DAWNERR("failed to set IO\n");
1079 return ret;
1080 }
1081 }
1082
1083 return OK;
1084 }
1085#endif
1086
1087#ifdef CONFIG_DAWN_PROTO_CAN_RTR
1088 if (msg.rtr == 1)
1089 {
1090# ifdef CONFIG_DAWN_PROTO_CAN_SIMPLE
1091 if (v->cfg->type == CAN_TYPE_READ)
1092 {
1093 if (canio->io->isRead() == false)
1094 {
1095 DAWNERR("IO doesn't support read\n");
1096 return -EINVAL;
1097 }
1098
1099 return sendIoResponse(canio, 0, false);
1100 }
1101# endif
1102
1103# ifdef CONFIG_DAWN_PROTO_CAN_SEG
1104 if (v->cfg->type == CAN_TYPE_READ_SEG)
1105 {
1106 return -ENOTSUP;
1107 }
1108# endif
1109 }
1110#endif
1111
1112 return OK;
1113}
CIOCommon * getIO(SObjectId::ObjectId id)
Get an I/O object by ID.
Definition bindable.cxx:41
Base class for all I/O objects.
Definition common.hxx:27
virtual bool isWrite() const =0
Check if IO supports write operations.
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 isNotify() const =0
Check if IO supports notifications.
virtual bool isSeekable() const
Check if IO supports partial (seekable) access.
Definition common.hxx:502
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.
static int receiveCustom(const porting::canmsg_s &msg, State &state, void *data_buf, size_t buf_size, uint8_t seg_no, bool seg_last, uint64_t now, uint64_t timeout)
Process incoming Custom Segmented frame (Dawn specific).
Definition isotp.cxx:242
static int receive(const porting::canmsg_s &msg, State &state, void *data_buf, size_t buf_size, uint64_t now, uint64_t timeout)
Process incoming ISO-TP frame.
Definition isotp.cxx:178
SObjectId::ObjectId getIdV() const
Get object identifier as raw 32-bit value.
Definition object.cxx:155
@ CAN_TYPE_READ_SEG
segmented response, requested by data frame
Definition can.hxx:54
@ CAN_TYPE_WRITE_SEG
segmented request
Definition can.hxx:55
@ CAN_TYPE_PUSH
device autonomously sends data
Definition can.hxx:49
@ CAN_TYPE_INDEXED_WRITE
indexed request/response
Definition can.hxx:53
@ CAN_TYPE_INDEXED_READ
indexed request/response
Definition can.hxx:52
@ CAN_TYPE_READ
request/response with RTR frame
Definition can.hxx:50
@ CAN_TYPE_WRITE
master sends command
Definition can.hxx:51
Out-of-tree user-extension hooks for Dawn.
Definition bindable.hxx:13
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
Common CAN message format for chardev and socketCAN.
Definition can.hxx:20