libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
gs_usb.hpp
1#pragma once
2
3#include <algorithm>
4#include <array>
5#include <cstddef>
6#include <cstdint>
7#include <cstring>
8#include <initializer_list>
9#include <type_traits>
10
11#include "can.hpp"
12#include "dev_core.hpp"
13#include "gpio.hpp"
14#include "gs_usb_protocol.hpp"
15#include "libxr_def.hpp"
16#include "timebase.hpp"
17#include "usb/core/desc_cfg.hpp"
18
19namespace LibXR::USB
20{
21
28template <std::size_t CanChNum>
29class GsUsbClass : public DeviceClass
30{
31 static_assert(CanChNum > 0 && CanChNum <= 255, "CanChNum must be in (0, 255]");
32 static constexpr uint8_t CAN_CH_NUM = static_cast<uint8_t>(CanChNum);
33
34 // ===== Linux gs_usb 线缆格式(header 固定 12 字节) / Linux gs_usb wire format
35 // (12-byte header) =====
36#pragma pack(push, 1)
37
42 {
43 uint32_t echo_id;
44 uint32_t can_id;
45 uint8_t can_dlc;
46 uint8_t channel;
47 uint8_t flags;
48 uint8_t reserved;
49 };
50#pragma pack(pop)
51
52 static constexpr uint32_t ECHO_ID_RX =
53 0xFFFFFFFFu;
54
55 static constexpr std::size_t WIRE_HDR_SIZE =
56 sizeof(WireHeader);
57 static constexpr std::size_t WIRE_CLASSIC_DATA_SIZE =
58 8;
59 static constexpr std::size_t WIRE_FD_DATA_SIZE = 64;
60 static constexpr std::size_t WIRE_TS_SIZE =
61 4;
62
63 static constexpr std::size_t WIRE_CLASSIC_SIZE =
64 WIRE_HDR_SIZE + 8;
65 static constexpr std::size_t WIRE_CLASSIC_TS_SIZE =
66 WIRE_HDR_SIZE + 8 + 4;
67 static constexpr std::size_t WIRE_FD_SIZE =
68 WIRE_HDR_SIZE + 64;
69 static constexpr std::size_t WIRE_FD_TS_SIZE =
70 WIRE_HDR_SIZE + 64 + 4;
71 static constexpr std::size_t WIRE_MAX_SIZE =
73
74 public:
89 GsUsbClass(std::initializer_list<LibXR::CAN*> cans,
92 size_t rx_queue_size = 32, size_t echo_queue_size = 32,
93 LibXR::GPIO* identify_gpio = nullptr,
94 std::initializer_list<LibXR::GPIO*> termination_gpios = {},
95 LibXR::Database* database = nullptr)
96 : data_in_ep_num_(data_in_ep_num),
97 data_out_ep_num_(data_out_ep_num),
98 identify_gpio_(identify_gpio),
99 database_(database),
100 rx_queue_(rx_queue_size),
101 echo_queue_(echo_queue_size)
102 {
103 ASSERT(cans.size() == CAN_CH_NUM);
104 std::size_t i = 0;
105 for (auto* p : cans)
106 {
107 cans_[i++] = p;
108 }
109
110 if (termination_gpios.size() == 0)
111 {
112 termination_gpios_.fill(nullptr);
113 }
114 else
115 {
116 ASSERT(termination_gpios.size() == CAN_CH_NUM);
117 i = 0;
118 for (auto* g : termination_gpios)
119 {
120 termination_gpios_[i++] = g;
121 }
122 }
123
125 }
126
143 GsUsbClass(std::initializer_list<LibXR::FDCAN*> fd_cans,
146 size_t rx_queue_size = 32, size_t echo_queue_size = 32,
147 LibXR::GPIO* identify_gpio = nullptr,
148 std::initializer_list<LibXR::GPIO*> termination_gpios = {},
149 LibXR::Database* database = nullptr)
150 : fd_supported_(true),
151 data_in_ep_num_(data_in_ep_num),
152 data_out_ep_num_(data_out_ep_num),
153 identify_gpio_(identify_gpio),
154 database_(database),
155 rx_queue_(rx_queue_size),
156 echo_queue_(echo_queue_size)
157 {
158 ASSERT(fd_cans.size() == CAN_CH_NUM);
159 std::size_t i = 0;
160 for (auto* p : fd_cans)
161 {
162 fdcans_[i] = p;
163 cans_[i] = p; // 向上转 CAN* / Upcast to CAN*
164 ++i;
165 }
166
167 if (termination_gpios.size() == 0)
168 {
169 termination_gpios_.fill(nullptr);
170 }
171 else
172 {
173 ASSERT(termination_gpios.size() == CAN_CH_NUM);
174 i = 0;
175 for (auto* g : termination_gpios)
176 {
177 termination_gpios_[i++] = g;
178 }
179 }
180
182 }
183
189 bool IsHostFormatOK() const { return host_format_ok_; }
190
191 protected:
198 void BindEndpoints(EndpointPool& endpoint_pool, uint8_t start_itf_num, bool) override
199 {
200 inited_ = false;
201 interface_num_ = start_itf_num;
202
203 auto ans = endpoint_pool.Get(ep_data_in_, Endpoint::Direction::IN, data_in_ep_num_);
204 ASSERT(ans == ErrorCode::OK);
205
207 ASSERT(ans == ErrorCode::OK);
208
209 // UINT16_MAX 只是上限,底层会选不超过该值的可用最大长度
211 {Endpoint::Direction::IN, Endpoint::Type::BULK, UINT16_MAX, true});
214
215 desc_block_.intf = {9,
216 static_cast<uint8_t>(DescriptorType::INTERFACE),
218 0,
219 2,
220 0xFF,
221 0xFF,
222 0xFF,
223 0};
224
225 desc_block_.ep_out = {7,
226 static_cast<uint8_t>(DescriptorType::ENDPOINT),
227 static_cast<uint8_t>(ep_data_out_->GetAddress()),
228 static_cast<uint8_t>(Endpoint::Type::BULK),
230 0};
231
232 desc_block_.ep_in = {7,
233 static_cast<uint8_t>(DescriptorType::ENDPOINT),
234 static_cast<uint8_t>(ep_data_in_->GetAddress()),
235 static_cast<uint8_t>(Endpoint::Type::BULK),
237 0};
238
239 SetData(RawData{reinterpret_cast<uint8_t*>(&desc_block_), sizeof(desc_block_)});
240
243
244 host_format_ok_ = false;
245
246 for (uint8_t i = 0; i < can_count_; ++i)
247 {
248 can_enabled_[i] = false;
249 berr_enabled_[i] = false;
250 fd_enabled_[i] = false;
251 term_state_[i] = GsUsb::TerminationState::OFF;
252 timestamps_enabled_ch_[i] = false;
253 }
254
255 // 注册 CAN RX 回调 / Register CAN RX callbacks
257 {
258 for (uint8_t ch = 0; ch < can_count_; ++ch)
259 {
260 if (!cans_[ch])
261 {
262 continue;
263 }
264
265 can_rx_ctx_[ch].self = this;
266 can_rx_ctx_[ch].ch = ch;
268
269 cans_[ch]->Register(can_rx_cb_[ch], LibXR::CAN::Type::STANDARD);
270 cans_[ch]->Register(can_rx_cb_[ch], LibXR::CAN::Type::EXTENDED);
273 cans_[ch]->Register(can_rx_cb_[ch], LibXR::CAN::Type::ERROR);
274 }
275 can_rx_registered_ = true;
276 }
277
279 {
280 for (uint8_t ch = 0; ch < can_count_; ++ch)
281 {
282 if (!fdcans_[ch])
283 {
284 continue;
285 }
286
287 fd_can_rx_ctx_[ch].self = this;
288 fd_can_rx_ctx_[ch].ch = ch;
289 fd_can_rx_cb_[ch] =
291
294 }
296 }
297
298 inited_ = true;
300 }
301
307 void UnbindEndpoints(EndpointPool& endpoint_pool, bool) override
308 {
309 inited_ = false;
310 host_format_ok_ = false;
311
312 for (uint8_t i = 0; i < can_count_; ++i)
313 {
314 can_enabled_[i] = false;
315 berr_enabled_[i] = false;
316 fd_enabled_[i] = false;
317 term_state_[i] = GsUsb::TerminationState::OFF;
318 timestamps_enabled_ch_[i] = false;
319 }
320
321 if (ep_data_in_)
322 {
325 endpoint_pool.Release(ep_data_in_);
326 ep_data_in_ = nullptr;
327 }
328
329 if (ep_data_out_)
330 {
333 endpoint_pool.Release(ep_data_out_);
334 ep_data_out_ = nullptr;
335 }
336 }
337
342 size_t GetInterfaceCount() override { return 1; }
343
349 bool HasIAD() override { return false; }
350
357 bool OwnsEndpoint(uint8_t ep_addr) const override
358 {
359 if (!inited_)
360 {
361 return false;
362 }
363
364 return (ep_data_in_ && ep_data_in_->GetAddress() == ep_addr) ||
365 (ep_data_out_ && ep_data_out_->GetAddress() == ep_addr);
366 }
367
372 size_t GetMaxConfigSize() override { return sizeof(desc_block_); }
373
379 ErrorCode OnClassRequest(bool, uint8_t, uint16_t, uint16_t, uint16_t,
381 {
382 return ErrorCode::NOT_SUPPORT;
383 }
384
395 ErrorCode OnVendorRequest(bool in_isr, uint8_t bRequest, uint16_t wValue,
396 uint16_t wLength, uint16_t wIndex,
397 DeviceClass::ControlTransferResult& result) override
398 {
399 UNUSED(in_isr);
400 UNUSED(wIndex);
401
402 auto req = static_cast<GsUsb::BReq>(bRequest);
403
404 switch (req)
405 {
406 // ===== Device -> Host =====
407 case GsUsb::BReq::BT_CONST:
408 {
409 if (wLength < sizeof(bt_const_))
410 {
411 return ErrorCode::ARG_ERR;
412 }
413 result.write_data =
414 ConstRawData{reinterpret_cast<const uint8_t*>(&bt_const_), sizeof(bt_const_)};
415 return ErrorCode::OK;
416 }
417
418 case GsUsb::BReq::BT_CONST_EXT:
419 {
420 if (!fd_supported_)
421 {
422 return ErrorCode::NOT_SUPPORT;
423 }
424 if (wLength < sizeof(bt_const_ext_))
425 {
426 return ErrorCode::ARG_ERR;
427 }
428 result.write_data = ConstRawData{reinterpret_cast<const uint8_t*>(&bt_const_ext_),
429 sizeof(bt_const_ext_)};
430 return ErrorCode::OK;
431 }
432
433 case GsUsb::BReq::DEVICE_CONFIG:
434 {
435 if (wLength < sizeof(dev_cfg_))
436 {
437 return ErrorCode::ARG_ERR;
438 }
439 result.write_data =
440 ConstRawData{reinterpret_cast<const uint8_t*>(&dev_cfg_), sizeof(dev_cfg_)};
441 return ErrorCode::OK;
442 }
443
444 case GsUsb::BReq::TIMESTAMP:
445 {
446 ctrl_buf_.timestamp_us = MakeTimestampUsGlobal();
447 if (wLength < sizeof(ctrl_buf_.timestamp_us))
448 {
449 return ErrorCode::ARG_ERR;
450 }
451
452 result.write_data =
453 ConstRawData{reinterpret_cast<const uint8_t*>(&ctrl_buf_.timestamp_us),
454 sizeof(ctrl_buf_.timestamp_us)};
455 return ErrorCode::OK;
456 }
457
458 case GsUsb::BReq::GET_TERMINATION:
459 {
460 if (wValue >= can_count_)
461 {
462 return ErrorCode::ARG_ERR;
463 }
464 ctrl_buf_.term.state = static_cast<uint32_t>(term_state_[wValue]);
465 if (wLength < sizeof(ctrl_buf_.term))
466 {
467 return ErrorCode::ARG_ERR;
468 }
469
470 result.write_data = ConstRawData{
471 reinterpret_cast<const uint8_t*>(&ctrl_buf_.term), sizeof(ctrl_buf_.term)};
472 return ErrorCode::OK;
473 }
474
475 case GsUsb::BReq::GET_STATE:
476 {
477 if (wValue >= can_count_)
478 {
479 return ErrorCode::ARG_ERR;
480 }
481
482 GsUsb::CanState st = GsUsb::CanState::ERROR_ACTIVE;
483 uint32_t rxerr = 0;
484 uint32_t txerr = 0;
485
486 auto* can = cans_[wValue];
487 if (can != nullptr)
488 {
490 if (can->GetErrorState(es) == ErrorCode::OK)
491 {
492 if (es.bus_off)
493 {
494 st = GsUsb::CanState::BUS_OFF;
495 }
496 else if (es.error_passive)
497 {
498 st = GsUsb::CanState::ERROR_PASSIVE;
499 }
500 else if (es.error_warning)
501 {
502 st = GsUsb::CanState::ERROR_WARNING;
503 }
504 else
505 {
506 st = GsUsb::CanState::ERROR_ACTIVE;
507 }
508
509 rxerr = es.rx_error_counter;
510 txerr = es.tx_error_counter;
511 }
512 }
513
514 ctrl_buf_.dev_state.state = static_cast<uint32_t>(st);
515 ctrl_buf_.dev_state.rxerr = rxerr;
516 ctrl_buf_.dev_state.txerr = txerr;
517
518 if (wLength < sizeof(ctrl_buf_.dev_state))
519 {
520 return ErrorCode::ARG_ERR;
521 }
522
523 result.write_data =
524 ConstRawData{reinterpret_cast<const uint8_t*>(&ctrl_buf_.dev_state),
525 sizeof(ctrl_buf_.dev_state)};
526 return ErrorCode::OK;
527 }
528
529 case GsUsb::BReq::GET_USER_ID:
530 {
532 if (wLength < sizeof(ctrl_buf_.user_id))
533 {
534 return ErrorCode::ARG_ERR;
535 }
536
537 result.write_data =
538 ConstRawData{reinterpret_cast<const uint8_t*>(&ctrl_buf_.user_id),
539 sizeof(ctrl_buf_.user_id)};
540 return ErrorCode::OK;
541 }
542
543 // ===== Host -> Device(有 DATA 阶段) / Host -> Device (with DATA stage) =====
544 case GsUsb::BReq::HOST_FORMAT:
545 {
546 if (wLength != sizeof(GsUsb::HostConfig))
547 {
548 return ErrorCode::ARG_ERR;
549 }
550 result.read_data = RawData{reinterpret_cast<uint8_t*>(&ctrl_buf_.host_cfg),
551 sizeof(GsUsb::HostConfig)};
552 return ErrorCode::OK;
553 }
554
555 case GsUsb::BReq::BITTIMING:
556 {
557 if (wLength != sizeof(GsUsb::DeviceBitTiming) || wValue >= can_count_)
558 {
559 return ErrorCode::ARG_ERR;
560 }
561 ctrl_target_channel_ = static_cast<uint8_t>(wValue);
562 result.read_data = RawData{reinterpret_cast<uint8_t*>(&ctrl_buf_.bt),
563 sizeof(GsUsb::DeviceBitTiming)};
564 return ErrorCode::OK;
565 }
566
567 case GsUsb::BReq::DATA_BITTIMING:
568 {
569 if (!fd_supported_)
570 {
571 return ErrorCode::NOT_SUPPORT;
572 }
573 if (wLength != sizeof(GsUsb::DeviceBitTiming) || wValue >= can_count_)
574 {
575 return ErrorCode::ARG_ERR;
576 }
577 ctrl_target_channel_ = static_cast<uint8_t>(wValue);
578 result.read_data = RawData{reinterpret_cast<uint8_t*>(&ctrl_buf_.bt),
579 sizeof(GsUsb::DeviceBitTiming)};
580 return ErrorCode::OK;
581 }
582
583 case GsUsb::BReq::MODE:
584 {
585 if (wLength != sizeof(GsUsb::DeviceMode) || wValue >= can_count_)
586 {
587 return ErrorCode::ARG_ERR;
588 }
589 ctrl_target_channel_ = static_cast<uint8_t>(wValue);
590 result.read_data = RawData{reinterpret_cast<uint8_t*>(&ctrl_buf_.mode),
591 sizeof(GsUsb::DeviceMode)};
592 return ErrorCode::OK;
593 }
594
595 case GsUsb::BReq::BERR:
596 {
597 if (wLength != sizeof(uint32_t) || wValue >= can_count_)
598 {
599 return ErrorCode::ARG_ERR;
600 }
601 ctrl_target_channel_ = static_cast<uint8_t>(wValue);
602 result.read_data =
603 RawData{reinterpret_cast<uint8_t*>(&ctrl_buf_.berr_on), sizeof(uint32_t)};
604 return ErrorCode::OK;
605 }
606
607 case GsUsb::BReq::IDENTIFY:
608 {
609 if (wLength != sizeof(GsUsb::Identify) || wValue >= can_count_)
610 {
611 return ErrorCode::ARG_ERR;
612 }
613 ctrl_target_channel_ = static_cast<uint8_t>(wValue);
614 result.read_data = RawData{reinterpret_cast<uint8_t*>(&ctrl_buf_.identify),
615 sizeof(GsUsb::Identify)};
616 return ErrorCode::OK;
617 }
618
619 case GsUsb::BReq::SET_TERMINATION:
620 {
621 if (wLength != sizeof(GsUsb::DeviceTerminationState) || wValue >= can_count_)
622 {
623 return ErrorCode::ARG_ERR;
624 }
625 ctrl_target_channel_ = static_cast<uint8_t>(wValue);
626 result.read_data = RawData{reinterpret_cast<uint8_t*>(&ctrl_buf_.term),
628 return ErrorCode::OK;
629 }
630
631 case GsUsb::BReq::SET_USER_ID:
632 {
633 if (wLength != sizeof(uint32_t))
634 {
635 return ErrorCode::ARG_ERR;
636 }
637 result.read_data =
638 RawData{reinterpret_cast<uint8_t*>(&ctrl_buf_.user_id), sizeof(uint32_t)};
639 return ErrorCode::OK;
640 }
641
642 default:
643 return ErrorCode::NOT_SUPPORT;
644 }
645 }
646
654 ErrorCode OnClassData(bool in_isr, uint8_t bRequest, LibXR::ConstRawData& data) override
655 {
656 UNUSED(in_isr);
657
658 auto req = static_cast<GsUsb::BReq>(bRequest);
659
660 switch (req)
661 {
662 case GsUsb::BReq::HOST_FORMAT:
663 if (data.size_ != sizeof(GsUsb::HostConfig))
664 {
665 return ErrorCode::ARG_ERR;
666 }
667 return HandleHostFormat(ctrl_buf_.host_cfg);
668
669 case GsUsb::BReq::BITTIMING:
670 if (data.size_ != sizeof(GsUsb::DeviceBitTiming))
671 {
672 return ErrorCode::ARG_ERR;
673 }
675
676 case GsUsb::BReq::DATA_BITTIMING:
677 if (!fd_supported_)
678 {
679 return ErrorCode::NOT_SUPPORT;
680 }
681 if (data.size_ != sizeof(GsUsb::DeviceBitTiming))
682 {
683 return ErrorCode::ARG_ERR;
684 }
686
687 case GsUsb::BReq::MODE:
688 if (data.size_ != sizeof(GsUsb::DeviceMode))
689 {
690 return ErrorCode::ARG_ERR;
691 }
693
694 case GsUsb::BReq::BERR:
695 if (data.size_ != sizeof(uint32_t))
696 {
697 return ErrorCode::ARG_ERR;
698 }
700
701 case GsUsb::BReq::IDENTIFY:
702 if (data.size_ != sizeof(GsUsb::Identify))
703 {
704 return ErrorCode::ARG_ERR;
705 }
707
708 case GsUsb::BReq::SET_TERMINATION:
709 if (data.size_ != sizeof(GsUsb::DeviceTerminationState))
710 {
711 return ErrorCode::ARG_ERR;
712 }
714
715 case GsUsb::BReq::SET_USER_ID:
716 if (data.size_ != sizeof(uint32_t))
717 {
718 return ErrorCode::ARG_ERR;
719 }
721 return ErrorCode::OK;
722
723 case GsUsb::BReq::DEVICE_CONFIG:
724 case GsUsb::BReq::BT_CONST:
725 case GsUsb::BReq::BT_CONST_EXT:
726 case GsUsb::BReq::TIMESTAMP:
727 case GsUsb::BReq::GET_TERMINATION:
728 case GsUsb::BReq::GET_STATE:
729 case GsUsb::BReq::GET_USER_ID:
730 return ErrorCode::OK;
731
732 default:
733 return ErrorCode::NOT_SUPPORT;
734 }
735 }
736
737 // ================= Bulk 端点回调 / Bulk endpoint callbacks =================
738
745 static void OnDataOutCompleteStatic(bool in_isr, GsUsbClass* self, ConstRawData& data)
746 {
747 if (!self->inited_)
748 {
749 return;
750 }
751 self->OnDataOutComplete(in_isr, data);
752 }
753
760 static void OnDataInCompleteStatic(bool in_isr, GsUsbClass* self, ConstRawData& data)
761 {
762 if (!self->inited_)
763 {
764 return;
765 }
766 self->OnDataInComplete(in_isr, data);
767 }
768
774 void OnDataOutComplete(bool in_isr, ConstRawData& data)
775 {
776 UNUSED(in_isr);
777
778 if (!ep_data_out_)
779 {
780 return;
781 }
782
783 const std::size_t RXLEN = data.size_;
784 if (RXLEN < WIRE_CLASSIC_SIZE)
785 {
787 return;
788 }
789
790 // 解析 wire header / Parse wire header
791 const WireHeader& wh = *reinterpret_cast<const WireHeader*>(data.addr_);
792
793 const uint8_t CH = wh.channel;
794 if (CH >= can_count_ || !cans_[CH])
795 {
797 return;
798 }
799
800 const bool IS_FD = (wh.flags & GsUsb::CAN_FLAG_FD) != 0;
801 const uint8_t* payload = reinterpret_cast<const uint8_t*>(data.addr_) + WIRE_HDR_SIZE;
802
803 if (IS_FD)
804 {
805 if (!fd_supported_ || !fdcans_[CH] || !fd_enabled_[CH])
806 {
808 return;
809 }
810
811 if (RXLEN < WIRE_FD_SIZE)
812 {
814 return;
815 }
816
818 HostWireToFdPack(wh, payload, pack);
819 (void)fdcans_[CH]->AddMessage(pack);
820 }
821 else
822 {
823 if (!can_enabled_[CH])
824 {
826 return;
827 }
828
829 if (RXLEN < WIRE_CLASSIC_SIZE)
830 {
832 return;
833 }
834
836 HostWireToClassicPack(wh, payload, pack);
837 (void)cans_[CH]->AddMessage(pack);
838 }
839
840 // TX echo:Host 通过 echo_id 跟踪 TX buffer;设备需回送 echo_id
841 // TX echo: host tracks TX buffer via echo_id; device should echo it back
842 if (wh.echo_id != ECHO_ID_RX)
843 {
844 QueueItem qi;
845 qi.hdr = wh;
846 qi.is_fd = IS_FD;
847 qi.data_len = IS_FD ? 64u : 8u;
849 Memory::FastCopy(qi.data.data(), payload, qi.data_len);
850 (void)EnqueueFrame(qi, true, in_isr);
851 }
852
854 }
855
861 void OnDataInComplete(bool in_isr, ConstRawData& data)
862 {
863 UNUSED(in_isr);
864 UNUSED(data);
865 TryKickTx(false);
866 }
867
868 private:
869 // ================= 成员 / Members =================
870 std::array<LibXR::CAN*, CanChNum> cans_{};
871 std::array<LibXR::FDCAN*, CanChNum>
873 bool fd_supported_ = false;
874
875 uint8_t can_count_ = CAN_CH_NUM;
876
879
882
883 bool inited_ = false;
884 uint8_t interface_num_ = 0;
885
887 nullptr;
888 std::array<LibXR::GPIO*, CanChNum>
890
893 uint32_t user_id_ram_ = 0;
894
897 this);
898
901 this);
902
907
911 union
912 {
916 uint32_t berr_on;
918 uint32_t timestamp_us;
921 uint32_t user_id;
923
924 std::array<LibXR::CAN::Configuration, CanChNum>
926 std::array<LibXR::FDCAN::Configuration, CanChNum>
928
929 bool host_format_ok_ = false;
930
931 bool can_enabled_[CanChNum] = {
932 false};
933 bool berr_enabled_[CanChNum] = {false};
934 bool fd_enabled_[CanChNum] = {false};
935
936 bool timestamps_enabled_ch_[CanChNum] = {
937 false};
938 GsUsb::TerminationState term_state_[CanChNum] = {
939 GsUsb::TerminationState::OFF};
941 0;
942
943#pragma pack(push, 1)
953#pragma pack(pop)
954
956 std::array<uint8_t, WIRE_MAX_SIZE>
958
959 // ================= CAN RX 回调 & BULK IN 发送队列 / CAN RX callbacks & Bulk IN TX
960 // queues =================
961
965 struct CanRxCtx
966 {
968 uint8_t ch;
969 };
970
975 {
977 uint8_t ch;
978 };
979
981 false;
982 CanRxCtx can_rx_ctx_[CanChNum]{};
984 can_rx_cb_[CanChNum]{};
985
987 false;
990 fd_can_rx_cb_[CanChNum]{};
991
995 static void OnCanRxStatic(bool in_isr, CanRxCtx* ctx,
996 const LibXR::CAN::ClassicPack& pack)
997 {
998 if (!ctx || !ctx->self || !ctx->self->inited_)
999 {
1000 return;
1001 }
1002 ctx->self->OnCanRx(in_isr, ctx->ch, pack);
1003 }
1004
1008 static void OnFdCanRxStatic(bool in_isr, FdCanRxCtx* ctx,
1009 const LibXR::FDCAN::FDPack& pack)
1010 {
1011 if (!ctx || !ctx->self || !ctx->self->inited_)
1012 {
1013 return;
1014 }
1015 ctx->self->OnFdCanRx(in_isr, ctx->ch, pack);
1016 }
1017
1023 {
1025 bool is_fd;
1026 uint8_t data_len;
1027 uint32_t timestamp_us;
1028 std::array<uint8_t, 64> data;
1029 };
1030
1035
1039 void OnCanRx(bool in_isr, uint8_t ch, const LibXR::CAN::ClassicPack& pack)
1040 {
1041 if (ch >= can_count_ || !ep_data_in_)
1042 {
1043 return;
1044 }
1045
1046 if (pack.type == LibXR::CAN::Type::ERROR)
1047 {
1048 QueueItem qi;
1049 if (ErrorPackToHostErrorFrame(ch, pack, qi))
1050 {
1051 (void)EnqueueFrame(qi, false, in_isr);
1052 }
1053 return;
1054 }
1055
1056 if (!can_enabled_[ch])
1057 {
1058 return;
1059 }
1060
1061 QueueItem qi;
1062 ClassicPackToQueueItem(pack, ch, qi);
1063 (void)EnqueueFrame(qi, false, in_isr);
1064 }
1065
1069 void OnFdCanRx(bool in_isr, uint8_t ch, const LibXR::FDCAN::FDPack& pack)
1070 {
1071 if (!fd_supported_ || ch >= can_count_ || !fd_enabled_[ch] || !ep_data_in_)
1072 {
1073 return;
1074 }
1075
1076 QueueItem qi;
1077 FdPackToQueueItem(pack, ch, qi);
1078
1079 const auto& fd_cfg = fd_config_[ch];
1080 if (fd_cfg.fd_mode.brs)
1081 {
1082 qi.hdr.flags |= GsUsb::CAN_FLAG_BRS;
1083 }
1084 if (fd_cfg.fd_mode.esi)
1085 {
1086 qi.hdr.flags |= GsUsb::CAN_FLAG_ESI;
1087 }
1088
1089 (void)EnqueueFrame(qi, false, in_isr);
1090 }
1091
1100 bool EnqueueFrame(const QueueItem& qi, bool is_echo, bool in_isr)
1101 {
1102 UNUSED(in_isr);
1103
1104 const ErrorCode EC = is_echo ? echo_queue_.Push(qi) : rx_queue_.Push(qi);
1105 if (EC != ErrorCode::OK)
1106 {
1107 return false;
1108 }
1109
1110 TryKickTx(in_isr);
1112 return true;
1113 }
1114
1119 void TryKickTx(bool in_isr)
1120 {
1121 UNUSED(in_isr);
1122
1123 if (!ep_data_in_)
1124 {
1125 return;
1126 }
1128 {
1129 return;
1130 }
1131
1132 QueueItem qi;
1133 ErrorCode ec = echo_queue_.Pop(qi);
1134 if (ec != ErrorCode::OK)
1135 {
1136 ec = rx_queue_.Pop(qi);
1137 if (ec != ErrorCode::OK)
1138 {
1139 return;
1140 }
1141 }
1142
1143 const std::size_t SEND_LEN = PackQueueItemToWire(qi, tx_buf_.data(), tx_buf_.size());
1144 if (SEND_LEN == 0)
1145 {
1146 return;
1147 }
1148
1149 RawData tx_raw{tx_buf_.data(), SEND_LEN};
1150 (void)ep_data_in_->TransferMultiBulk(tx_raw);
1151
1153 }
1154
1159 {
1160 if (!ep_data_out_)
1161 {
1162 return;
1163 }
1165 {
1166 return;
1167 }
1168
1169 if (rx_queue_.EmptySize() == 0 || echo_queue_.EmptySize() == 0)
1170 {
1171 return;
1172 }
1173
1174 RawData rx_raw{rx_buf_, static_cast<size_t>(WIRE_MAX_SIZE)};
1175 (void)ep_data_out_->TransferMultiBulk(rx_raw);
1176 }
1177
1178 // ================= 业务处理函数 / Handlers =================
1179
1186 {
1187 for (uint8_t i = 0; i < can_count_; ++i)
1188 {
1189 if (termination_gpios_[i] != nullptr)
1190 {
1191 return true;
1192 }
1193 }
1194 return false;
1195 }
1196
1202 {
1203 can_count_ = CAN_CH_NUM;
1204 ASSERT(can_count_ > 0);
1205 ASSERT(cans_[0] != nullptr);
1206
1207 dev_cfg_.reserved1 = 0;
1208 dev_cfg_.reserved2 = 0;
1209 dev_cfg_.reserved3 = 0;
1210 dev_cfg_.icount = static_cast<uint8_t>(can_count_ - 1);
1211 dev_cfg_.sw_version = 2;
1212 dev_cfg_.hw_version = 1;
1213
1214 const uint32_t FCLK = cans_[0]->GetClockFreq();
1215
1216 bt_const_.feature = GsUsb::CAN_FEAT_LISTEN_ONLY | GsUsb::CAN_FEAT_LOOP_BACK |
1217 GsUsb::CAN_FEAT_TRIPLE_SAMPLE | GsUsb::CAN_FEAT_ONE_SHOT |
1218 GsUsb::CAN_FEAT_HW_TIMESTAMP | GsUsb::CAN_FEAT_BERR_REPORTING |
1219 GsUsb::CAN_FEAT_GET_STATE | GsUsb::CAN_FEAT_USER_ID;
1220
1221 if (identify_gpio_)
1222 {
1223 bt_const_.feature |= GsUsb::CAN_FEAT_IDENTIFY;
1224 }
1226 {
1227 bt_const_.feature |= GsUsb::CAN_FEAT_TERMINATION;
1228 }
1229
1230 bt_const_.fclk_can = FCLK;
1232 bt_const_.btc.tseg1_max = 16;
1235 bt_const_.btc.sjw_max = 4;
1236 bt_const_.btc.brp_min = 1;
1237 bt_const_.btc.brp_max = 1024;
1238 bt_const_.btc.brp_inc = 1;
1239
1241 bt_const_ext_.fclk_can = FCLK;
1244
1245 Memory::FastSet(config_.data(), 0, sizeof(config_));
1246 Memory::FastSet(fd_config_.data(), 0, sizeof(fd_config_));
1247 }
1248
1253 {
1254 can_count_ = CAN_CH_NUM;
1255 ASSERT(can_count_ > 0);
1256 ASSERT(cans_[0] != nullptr);
1257
1258 dev_cfg_.reserved1 = 0;
1259 dev_cfg_.reserved2 = 0;
1260 dev_cfg_.reserved3 = 0;
1261 dev_cfg_.icount = static_cast<uint8_t>(can_count_ - 1);
1262 dev_cfg_.sw_version = 2;
1263 dev_cfg_.hw_version = 1;
1264
1265 const uint32_t FCLK = cans_[0]->GetClockFreq();
1266
1267 bt_const_.feature = GsUsb::CAN_FEAT_LISTEN_ONLY | GsUsb::CAN_FEAT_LOOP_BACK |
1268 GsUsb::CAN_FEAT_TRIPLE_SAMPLE | GsUsb::CAN_FEAT_ONE_SHOT |
1269 GsUsb::CAN_FEAT_HW_TIMESTAMP | GsUsb::CAN_FEAT_BERR_REPORTING |
1270 GsUsb::CAN_FEAT_GET_STATE | GsUsb::CAN_FEAT_USER_ID |
1271 GsUsb::CAN_FEAT_FD | GsUsb::CAN_FEAT_BT_CONST_EXT;
1272
1273 if (identify_gpio_)
1274 {
1275 bt_const_.feature |= GsUsb::CAN_FEAT_IDENTIFY;
1276 }
1278 {
1279 bt_const_.feature |= GsUsb::CAN_FEAT_TERMINATION;
1280 }
1281
1282 bt_const_.fclk_can = FCLK;
1284 bt_const_.btc.tseg1_max = 16;
1287 bt_const_.btc.sjw_max = 4;
1288 bt_const_.btc.brp_min = 1;
1289 bt_const_.btc.brp_max = 1024;
1290 bt_const_.btc.brp_inc = 1;
1291
1293 bt_const_ext_.fclk_can = FCLK;
1296
1297 Memory::FastSet(config_.data(), 0, sizeof(config_));
1298 Memory::FastSet(fd_config_.data(), 0, sizeof(fd_config_));
1299 }
1300
1307 {
1308 host_format_ok_ = (cfg.byte_order == 0x0000beefu);
1309 return ErrorCode::OK;
1310 }
1311
1315 ErrorCode HandleBitTiming(uint8_t ch, const GsUsb::DeviceBitTiming& bt)
1316 {
1317 if (!host_format_ok_ || ch >= can_count_ || !cans_[ch])
1318 {
1319 return ErrorCode::ARG_ERR;
1320 }
1321
1322 const uint32_t TSEG1 = bt.prop_seg + bt.phase_seg1;
1323 const uint32_t TSEG2 = bt.phase_seg2;
1324 const uint32_t TQ_NUM = 1u + TSEG1 + TSEG2;
1325
1326 const uint32_t FCLK = cans_[ch]->GetClockFreq();
1327
1328 auto& cfg = config_[ch];
1329 cfg.bit_timing.brp = bt.brp;
1330 cfg.bit_timing.prop_seg = bt.prop_seg;
1331 cfg.bit_timing.phase_seg1 = bt.phase_seg1;
1332 cfg.bit_timing.phase_seg2 = bt.phase_seg2;
1333 cfg.bit_timing.sjw = bt.sjw;
1334
1335 if (bt.brp != 0u && TQ_NUM != 0u)
1336 {
1337 cfg.bitrate = FCLK / (bt.brp * TQ_NUM);
1338 cfg.sample_point = static_cast<float>(1u + TSEG1) / static_cast<float>(TQ_NUM);
1339 }
1340 else
1341 {
1342 cfg.bitrate = 0;
1343 cfg.sample_point = 0.0f;
1344 }
1345
1346 if (fd_supported_ && fdcans_[ch])
1347 {
1348 auto& fd_cfg = fd_config_[ch];
1349 static_cast<CAN::Configuration&>(fd_cfg) = cfg;
1350 }
1351
1352 return cans_[ch]->SetConfig(cfg);
1353 }
1354
1358 ErrorCode HandleDataBitTiming(uint8_t ch, const GsUsb::DeviceBitTiming& bt)
1359 {
1360 if (!host_format_ok_)
1361 {
1362 return ErrorCode::ARG_ERR;
1363 }
1364 if (!fd_supported_ || ch >= can_count_ || !fdcans_[ch])
1365 {
1366 return ErrorCode::NOT_SUPPORT;
1367 }
1368
1369 const uint32_t TSEG1 = bt.prop_seg + bt.phase_seg1;
1370 const uint32_t TSEG2 = bt.phase_seg2;
1371 const uint32_t TQ_NUM = 1u + TSEG1 + TSEG2;
1372
1373 const uint32_t FCLK = fdcans_[ch]->GetClockFreq();
1374
1375 auto& fd_cfg = fd_config_[ch];
1376 static_cast<CAN::Configuration&>(fd_cfg) = config_[ch];
1377
1378 fd_cfg.data_timing.brp = bt.brp;
1379 fd_cfg.data_timing.prop_seg = bt.prop_seg;
1380 fd_cfg.data_timing.phase_seg1 = bt.phase_seg1;
1381 fd_cfg.data_timing.phase_seg2 = bt.phase_seg2;
1382 fd_cfg.data_timing.sjw = bt.sjw;
1383
1384 if (bt.brp != 0u && TQ_NUM != 0u)
1385 {
1386 fd_cfg.data_bitrate = FCLK / (bt.brp * TQ_NUM);
1387 fd_cfg.data_sample_point =
1388 static_cast<float>(1u + TSEG1) / static_cast<float>(TQ_NUM);
1389 }
1390 else
1391 {
1392 fd_cfg.data_bitrate = 0;
1393 fd_cfg.data_sample_point = 0.0f;
1394 }
1395
1396 return fdcans_[ch]->SetConfig(fd_cfg);
1397 }
1398
1402 ErrorCode HandleMode(uint8_t ch, const GsUsb::DeviceMode& mode)
1403 {
1404 if (!host_format_ok_ || ch >= can_count_ || !cans_[ch])
1405 {
1406 return ErrorCode::ARG_ERR;
1407 }
1408
1409 switch (static_cast<GsUsb::CanMode>(mode.mode))
1410 {
1411 case GsUsb::CanMode::RESET:
1412 can_enabled_[ch] = false;
1413 fd_enabled_[ch] = false;
1414 break;
1415
1416 case GsUsb::CanMode::START:
1417 can_enabled_[ch] = true;
1418 if (fd_supported_ && fdcans_[ch] && (mode.flags & GsUsb::GSCAN_MODE_FD))
1419 {
1420 fd_enabled_[ch] = true;
1421 }
1422 break;
1423
1424 default:
1425 return ErrorCode::ARG_ERR;
1426 }
1427
1428 auto& cfg = config_[ch];
1429 cfg.mode.loopback = (mode.flags & GsUsb::GSCAN_MODE_LOOP_BACK) != 0;
1430 cfg.mode.listen_only = (mode.flags & GsUsb::GSCAN_MODE_LISTEN_ONLY) != 0;
1431 cfg.mode.triple_sampling = (mode.flags & GsUsb::GSCAN_MODE_TRIPLE_SAMPLE) != 0;
1432 cfg.mode.one_shot = (mode.flags & GsUsb::GSCAN_MODE_ONE_SHOT) != 0;
1433
1434 timestamps_enabled_ch_[ch] = (mode.flags & GsUsb::GSCAN_MODE_HW_TIMESTAMP) != 0;
1435 berr_enabled_[ch] = (mode.flags & GsUsb::GSCAN_MODE_BERR_REPORTING) != 0;
1436
1437 const ErrorCode EC = cans_[ch]->SetConfig(cfg);
1438
1439 if (fd_supported_ && fdcans_[ch])
1440 {
1441 auto& fd_cfg = fd_config_[ch];
1442 static_cast<CAN::Configuration&>(fd_cfg) = cfg;
1443 fd_cfg.fd_mode.fd_enabled = (mode.flags & GsUsb::GSCAN_MODE_FD) != 0;
1444 (void)fdcans_[ch]->SetConfig(fd_cfg);
1445 }
1446
1447 return EC;
1448 }
1449
1453 ErrorCode HandleBerr(uint8_t ch, uint32_t berr_on)
1454 {
1455 if (ch >= can_count_)
1456 {
1457 return ErrorCode::ARG_ERR;
1458 }
1459 berr_enabled_[ch] = (berr_on != 0);
1460 return ErrorCode::OK;
1461 }
1462
1466 ErrorCode HandleIdentify(uint8_t, const GsUsb::Identify& id)
1467 {
1468 const bool ON = (id.mode == static_cast<uint32_t>(GsUsb::IdentifyMode::ON));
1469 if (identify_gpio_)
1470 {
1471 (void)identify_gpio_->Write(ON);
1472 }
1473 return ErrorCode::OK;
1474 }
1475
1480 {
1481 if (ch >= can_count_)
1482 {
1483 return ErrorCode::ARG_ERR;
1484 }
1485
1486 term_state_[ch] = static_cast<GsUsb::TerminationState>(
1487 st.state != 0 ? static_cast<uint32_t>(GsUsb::TerminationState::ON)
1488 : static_cast<uint32_t>(GsUsb::TerminationState::OFF));
1489
1490 if (termination_gpios_[ch])
1491 {
1492 const bool ON = (term_state_[ch] == GsUsb::TerminationState::ON);
1493 (void)termination_gpios_[ch]->Write(ON);
1494 }
1495
1496 return ErrorCode::OK;
1497 }
1498
1502 static void HostWireToClassicPack(const WireHeader& wh, const uint8_t* payload,
1504 {
1505 const uint32_t CID = wh.can_id;
1506 const bool IS_EFF = (CID & GsUsb::CAN_EFF_FLAG) != 0;
1507 const bool IS_RTR = (CID & GsUsb::CAN_RTR_FLAG) != 0;
1508
1509 if (IS_EFF)
1510 {
1511 pack.id = CID & GsUsb::CAN_EFF_MASK;
1513 }
1514 else
1515 {
1516 pack.id = CID & GsUsb::CAN_SFF_MASK;
1518 }
1519
1520 uint8_t dlc = wh.can_dlc;
1521 if (dlc > 8u)
1522 {
1523 dlc = 8u;
1524 }
1525 pack.dlc = dlc;
1526
1527 if (dlc > 0u)
1528 {
1529 Memory::FastCopy(pack.data, payload, dlc);
1530 }
1531 }
1532
1536 static void HostWireToFdPack(const WireHeader& wh, const uint8_t* payload,
1538 {
1539 const uint32_t CID = wh.can_id;
1540 const bool IS_EFF = (CID & GsUsb::CAN_EFF_FLAG) != 0;
1541 const bool IS_RTR = (CID & GsUsb::CAN_RTR_FLAG) != 0;
1542
1543 if (IS_EFF)
1544 {
1545 pack.id = CID & GsUsb::CAN_EFF_MASK;
1547 }
1548 else
1549 {
1550 pack.id = CID & GsUsb::CAN_SFF_MASK;
1552 }
1553
1554 uint8_t len = DlcToLen(wh.can_dlc);
1555 if (len > 64)
1556 {
1557 len = 64;
1558 }
1559 pack.len = len;
1560
1561 if (len > 0u)
1562 {
1563 Memory::FastCopy(pack.data, payload, len);
1564 }
1565 }
1566
1571 QueueItem& qi)
1572 {
1573 uint32_t cid = 0;
1574 switch (pack.type)
1575 {
1577 cid = (pack.id & GsUsb::CAN_SFF_MASK);
1578 break;
1580 cid = (pack.id & GsUsb::CAN_EFF_MASK) | GsUsb::CAN_EFF_FLAG;
1581 break;
1583 cid = (pack.id & GsUsb::CAN_SFF_MASK) | GsUsb::CAN_RTR_FLAG;
1584 break;
1586 cid = (pack.id & GsUsb::CAN_EFF_MASK) | GsUsb::CAN_EFF_FLAG | GsUsb::CAN_RTR_FLAG;
1587 break;
1588 default:
1589 cid = pack.id & GsUsb::CAN_SFF_MASK;
1590 break;
1591 }
1592
1593 qi.hdr.echo_id = ECHO_ID_RX;
1594 qi.hdr.can_id = cid;
1595 qi.hdr.can_dlc = (pack.dlc <= 8u) ? pack.dlc : 8u;
1596 qi.hdr.channel = ch;
1597 qi.hdr.flags = 0;
1598 qi.hdr.reserved = 0;
1599
1600 qi.is_fd = false;
1601 qi.data_len = 8;
1603
1604 Memory::FastSet(qi.data.data(), 0, 8);
1605 if (qi.hdr.can_dlc > 0u)
1606 {
1607 Memory::FastCopy(qi.data.data(), pack.data, qi.hdr.can_dlc);
1608 }
1609 }
1610
1614 void FdPackToQueueItem(const LibXR::FDCAN::FDPack& pack, uint8_t ch, QueueItem& qi)
1615 {
1616 uint32_t cid = 0;
1617 switch (pack.type)
1618 {
1620 cid = (pack.id & GsUsb::CAN_SFF_MASK);
1621 break;
1623 cid = (pack.id & GsUsb::CAN_EFF_MASK) | GsUsb::CAN_EFF_FLAG;
1624 break;
1626 cid = (pack.id & GsUsb::CAN_SFF_MASK) | GsUsb::CAN_RTR_FLAG;
1627 break;
1629 cid = (pack.id & GsUsb::CAN_EFF_MASK) | GsUsb::CAN_EFF_FLAG | GsUsb::CAN_RTR_FLAG;
1630 break;
1631 default:
1632 cid = pack.id & GsUsb::CAN_SFF_MASK;
1633 break;
1634 }
1635
1636 qi.hdr.echo_id = ECHO_ID_RX;
1637 qi.hdr.can_id = cid;
1638 qi.hdr.can_dlc = LenToDlc(pack.len);
1639 qi.hdr.channel = ch;
1640 qi.hdr.flags = GsUsb::CAN_FLAG_FD;
1641 qi.hdr.reserved = 0;
1642
1643 qi.is_fd = true;
1644 qi.data_len = 64;
1646
1647 const uint8_t LEN = (pack.len <= 64) ? pack.len : 64;
1648
1649 if (LEN > 0u)
1650 {
1651 Memory::FastCopy(qi.data.data(), pack.data, LEN);
1652 }
1653 if (LEN < 64u)
1654 {
1655 Memory::FastSet(qi.data.data() + LEN, 0, 64u - LEN);
1656 }
1657 }
1658
1666 std::size_t PackQueueItemToWire(const QueueItem& qi, uint8_t* out,
1667 std::size_t cap) const
1668 {
1669 if (cap < WIRE_HDR_SIZE)
1670 {
1671 return 0;
1672 }
1673
1674 const uint8_t CH = qi.hdr.channel;
1675 const bool TS = (CH < can_count_) ? timestamps_enabled_ch_[CH] : false;
1676 const std::size_t PAYLOAD = qi.is_fd ? WIRE_FD_DATA_SIZE : WIRE_CLASSIC_DATA_SIZE;
1677 const std::size_t TOTAL = WIRE_HDR_SIZE + PAYLOAD + (TS ? WIRE_TS_SIZE : 0);
1678
1679 if (TOTAL > cap)
1680 {
1681 return 0;
1682 }
1683
1685 Memory::FastCopy(out + WIRE_HDR_SIZE, qi.data.data(), PAYLOAD);
1686
1687 if (TS)
1688 {
1690 }
1691
1692 return TOTAL;
1693 }
1694
1704 bool ErrorPackToHostErrorFrame(uint8_t ch, const LibXR::CAN::ClassicPack& err_pack,
1705 QueueItem& qi)
1706 {
1707 if (ch >= can_count_ || !cans_[ch])
1708 {
1709 return false;
1710 }
1711 if (!berr_enabled_[ch])
1712 {
1713 return false;
1714 }
1715 if (!LibXR::CAN::IsErrorId(err_pack.id))
1716 {
1717 return false;
1718 }
1719
1720 // Linux can/error.h 对齐(同你之前版本)
1721 constexpr uint8_t LNX_CAN_ERR_CRTL_UNSPEC = 0x00;
1722 constexpr uint8_t LNX_CAN_ERR_CRTL_RX_WARNING = 0x04;
1723 constexpr uint8_t LNX_CAN_ERR_CRTL_TX_WARNING = 0x08;
1724 constexpr uint8_t LNX_CAN_ERR_CRTL_RX_PASSIVE = 0x10;
1725 constexpr uint8_t LNX_CAN_ERR_CRTL_TX_PASSIVE = 0x20;
1726
1727 constexpr uint8_t LNX_CAN_ERR_PROT_UNSPEC = 0x00;
1728 constexpr uint8_t LNX_CAN_ERR_PROT_FORM = 0x02;
1729 constexpr uint8_t LNX_CAN_ERR_PROT_STUFF = 0x04;
1730 constexpr uint8_t LNX_CAN_ERR_PROT_BIT0 = 0x08;
1731 constexpr uint8_t LNX_CAN_ERR_PROT_BIT1 = 0x10;
1732 constexpr uint8_t LNX_CAN_ERR_PROT_TX = 0x80;
1733
1734 constexpr uint8_t LNX_CAN_ERR_PROT_LOC_UNSPEC = 0x00;
1735 constexpr uint8_t LNX_CAN_ERR_PROT_LOC_ACK = 0x19;
1736
1737 constexpr uint32_t LNX_CAN_ERR_CNT = 0x00000200U;
1738
1739 bool ec_valid = false;
1740 uint32_t txerr = 0, rxerr = 0;
1741 {
1743 if (cans_[ch]->GetErrorState(es) == ErrorCode::OK)
1744 {
1745 ec_valid = true;
1746 txerr = es.tx_error_counter;
1747 rxerr = es.rx_error_counter;
1748 }
1749 }
1750
1751 const uint8_t TXERR_U8 = (txerr > 255U) ? 255U : static_cast<uint8_t>(txerr);
1752 const uint8_t RXERR_U8 = (rxerr > 255U) ? 255U : static_cast<uint8_t>(rxerr);
1753
1754 const auto EID = LibXR::CAN::ToErrorID(err_pack.id);
1755
1756 uint32_t cid = GsUsb::CAN_ERR_FLAG;
1757 std::array<uint8_t, 8> d{};
1758 switch (EID)
1759 {
1760 case LibXR::CAN::ErrorID::CAN_ERROR_ID_BUS_OFF:
1761 cid |= GsUsb::CAN_ERR_BUSOFF;
1762 break;
1763
1764 case LibXR::CAN::ErrorID::CAN_ERROR_ID_ERROR_WARNING:
1765 case LibXR::CAN::ErrorID::CAN_ERROR_ID_ERROR_PASSIVE:
1766 {
1767 cid |= GsUsb::CAN_ERR_CRTL;
1768 uint8_t ctrl = LNX_CAN_ERR_CRTL_UNSPEC;
1769
1770 if (ec_valid)
1771 {
1772 if (EID == LibXR::CAN::ErrorID::CAN_ERROR_ID_ERROR_PASSIVE)
1773 {
1774 if (txerr >= 128U)
1775 {
1776 ctrl |= LNX_CAN_ERR_CRTL_TX_PASSIVE;
1777 }
1778 if (rxerr >= 128U)
1779 {
1780 ctrl |= LNX_CAN_ERR_CRTL_RX_PASSIVE;
1781 }
1782 }
1783 else
1784 {
1785 if (txerr >= 96U)
1786 {
1787 ctrl |= LNX_CAN_ERR_CRTL_TX_WARNING;
1788 }
1789 if (rxerr >= 96U)
1790 {
1791 ctrl |= LNX_CAN_ERR_CRTL_RX_WARNING;
1792 }
1793 }
1794 }
1795
1796 if (ctrl == LNX_CAN_ERR_CRTL_UNSPEC)
1797 {
1798 ctrl = (EID == LibXR::CAN::ErrorID::CAN_ERROR_ID_ERROR_PASSIVE)
1799 ? static_cast<uint8_t>(LNX_CAN_ERR_CRTL_TX_PASSIVE |
1800 LNX_CAN_ERR_CRTL_RX_PASSIVE)
1801 : static_cast<uint8_t>(LNX_CAN_ERR_CRTL_TX_WARNING |
1802 LNX_CAN_ERR_CRTL_RX_WARNING);
1803 }
1804
1805 d[1] = ctrl;
1806 break;
1807 }
1808
1809 case LibXR::CAN::ErrorID::CAN_ERROR_ID_ACK:
1810 cid |= GsUsb::CAN_ERR_ACK;
1811 cid |= GsUsb::CAN_ERR_PROT;
1812 d[2] = static_cast<uint8_t>(LNX_CAN_ERR_PROT_UNSPEC | LNX_CAN_ERR_PROT_TX);
1813 d[3] = LNX_CAN_ERR_PROT_LOC_ACK;
1814 break;
1815
1816 case LibXR::CAN::ErrorID::CAN_ERROR_ID_STUFF:
1817 cid |= GsUsb::CAN_ERR_PROT;
1818 d[2] = static_cast<uint8_t>(LNX_CAN_ERR_PROT_STUFF | LNX_CAN_ERR_PROT_TX);
1819 d[3] = LNX_CAN_ERR_PROT_LOC_UNSPEC;
1820 break;
1821
1822 case LibXR::CAN::ErrorID::CAN_ERROR_ID_FORM:
1823 cid |= GsUsb::CAN_ERR_PROT;
1824 d[2] = static_cast<uint8_t>(LNX_CAN_ERR_PROT_FORM | LNX_CAN_ERR_PROT_TX);
1825 d[3] = LNX_CAN_ERR_PROT_LOC_UNSPEC;
1826 break;
1827
1828 case LibXR::CAN::ErrorID::CAN_ERROR_ID_BIT0:
1829 cid |= GsUsb::CAN_ERR_PROT;
1830 d[2] = static_cast<uint8_t>(LNX_CAN_ERR_PROT_BIT0 | LNX_CAN_ERR_PROT_TX);
1831 d[3] = LNX_CAN_ERR_PROT_LOC_UNSPEC;
1832 break;
1833
1834 case LibXR::CAN::ErrorID::CAN_ERROR_ID_BIT1:
1835 cid |= GsUsb::CAN_ERR_PROT;
1836 d[2] = static_cast<uint8_t>(LNX_CAN_ERR_PROT_BIT1 | LNX_CAN_ERR_PROT_TX);
1837 d[3] = LNX_CAN_ERR_PROT_LOC_UNSPEC;
1838 break;
1839
1840 default:
1841 cid |= GsUsb::CAN_ERR_PROT;
1842 d[2] = static_cast<uint8_t>(LNX_CAN_ERR_PROT_UNSPEC | LNX_CAN_ERR_PROT_TX);
1843 d[3] = LNX_CAN_ERR_PROT_LOC_UNSPEC;
1844 break;
1845 }
1846
1847 cid |= LNX_CAN_ERR_CNT;
1848 d[6] = TXERR_U8;
1849 d[7] = RXERR_U8;
1850
1851 qi.hdr.echo_id = ECHO_ID_RX;
1852 qi.hdr.can_id = cid;
1853 qi.hdr.can_dlc = GsUsb::CAN_ERR_DLC;
1854 qi.hdr.channel = ch;
1855 qi.hdr.flags = 0;
1856 qi.hdr.reserved = 0;
1857
1858 qi.is_fd = false;
1859 qi.data_len = 8;
1861
1862 Memory::FastCopy(qi.data.data(), d.data(), 8);
1863
1864 return true;
1865 }
1866
1867 // ================= 工具函数 / Utilities =================
1868
1874 uint32_t MakeTimestampUs(uint8_t ch) const
1875 {
1876 if (ch < can_count_ && timestamps_enabled_ch_[ch] &&
1877 LibXR::Timebase::timebase != nullptr)
1878 {
1879 return static_cast<uint32_t>(LibXR::Timebase::GetMicroseconds() & 0xFFFFFFFFu);
1880 }
1881 return 0u;
1882 }
1883
1888 uint32_t MakeTimestampUsGlobal() const
1889 {
1890 if (LibXR::Timebase::timebase != nullptr)
1891 {
1892 return static_cast<uint32_t>(LibXR::Timebase::GetMicroseconds() & 0xFFFFFFFFu);
1893 }
1894 return 0u;
1895 }
1896
1900 static uint8_t DlcToLen(uint8_t dlc)
1901 {
1902 static constexpr uint8_t TABLE[16] = {0, 1, 2, 3, 4, 5, 6, 7,
1903 8, 12, 16, 20, 24, 32, 48, 64};
1904 return (dlc < 16) ? TABLE[dlc] : 64;
1905 }
1906
1910 static uint8_t LenToDlc(uint8_t len)
1911 {
1912 if (len <= 8)
1913 {
1914 return len;
1915 }
1916 if (len <= 12)
1917 {
1918 return 9;
1919 }
1920 if (len <= 16)
1921 {
1922 return 10;
1923 }
1924 if (len <= 20)
1925 {
1926 return 11;
1927 }
1928 if (len <= 24)
1929 {
1930 return 12;
1931 }
1932 if (len <= 32)
1933 {
1934 return 13;
1935 }
1936 if (len <= 48)
1937 {
1938 return 14;
1939 }
1940 return 15;
1941 }
1942
1947 uint32_t GetUserIdFromStorage() const
1948 {
1949 if (database_ == nullptr)
1950 {
1951 return user_id_ram_;
1952 }
1953
1955 return static_cast<uint32_t>(key);
1956 }
1957
1962 void SetUserIdToStorage(uint32_t value)
1963 {
1964 user_id_ram_ = value;
1965
1966 if (database_ == nullptr)
1967 {
1968 return;
1969 }
1970
1971 LibXR::Database::Key<uint32_t> key(*database_, "user_id", 0u);
1972 (void)key.Set(value);
1973 }
1974};
1975
1976} // namespace LibXR::USB
static constexpr bool IsErrorId(uint32_t id) noexcept
判断 id 是否处于错误 ID 空间。Check if id is in error ID space.
Definition can.hpp:168
@ EXTENDED
扩展数据帧(29-bit ID)。Extended data frame (29-bit ID).
@ REMOTE_EXTENDED
扩展远程帧。Extended remote frame.
@ STANDARD
标准数据帧(11-bit ID)。Standard data frame (11-bit ID).
@ REMOTE_STANDARD
标准远程帧。Standard remote frame.
@ ERROR
错误帧(虚拟事件)。Error frame (virtual event).
static constexpr ErrorID ToErrorID(uint32_t id) noexcept
将 id 解释为 ErrorID。Interpret id as ErrorID.
Definition can.hpp:174
通用回调包装,支持动态参数传递 / Generic callback wrapper supporting dynamic argument passing
Definition libxr_cb.hpp:150
static Callback Create(FunType fun, ArgType arg)
Definition libxr_cb.hpp:167
常量原始数据封装类。 A class for encapsulating constant raw data.
size_t size_
数据大小(字节)。 The size of the data (in bytes).
const void * addr_
数据存储地址(常量)。 The storage address of the data (constant).
模板类,表示数据库中的具体键 (Template class representing a specific key in the database).
Definition database.hpp:49
ErrorCode Set(Data data)
设置键的值并更新数据库 (Set the key's value and update the database).
Definition database.hpp:107
数据库接口,提供键值存储和管理功能 (Database interface providing key-value storage and management).
Definition database.hpp:21
通用输入输出(GPIO)接口类。General Purpose Input/Output (GPIO) interface class.
Definition gpio.hpp:13
virtual void Write(bool value)=0
写入 GPIO 引脚状态。Writes the GPIO pin state.
无锁队列实现 / Lock-free queue implementation
static void FastSet(void *dst, uint8_t value, size_t size)
快速内存填充 / Fast memory fill
static void FastCopy(void *dst, const void *src, size_t size)
快速内存拷贝 / Fast memory copy
Definition libxr_mem.cpp:3
原始数据封装类。 A class for encapsulating raw data.
static Timebase * timebase
静态指针,用于存储全局时间基对象。 Static pointer storing the global timebase instance.
Definition timebase.hpp:119
static MicrosecondTimestamp GetMicroseconds()
获取当前时间的微秒级时间戳。 Gets the current timestamp in microseconds.
Definition timebase.hpp:49
void SetData(RawData data)
设置内部数据缓存 / Set internal data cache
Definition desc_cfg.hpp:194
USB 设备类接口基类 / USB device class interface base.
Definition dev_core.hpp:26
USB 端点基类 / USB Endpoint base class.
Definition ep.hpp:23
EPNumber
端点号 Endpoint number
Definition ep.hpp:41
@ EP1
端点 1 / Endpoint 1
@ EP_AUTO
自动分配端点号 / Auto allocate
@ EP2
端点 2 / Endpoint 2
uint8_t GetAddress() const
获取端点地址(方向 + 号) / Get endpoint address (dir + num)
Definition ep.hpp:194
@ IN
输入方向 / IN direction
@ OUT
输出方向 / OUT direction
virtual ErrorCode TransferMultiBulk(RawData &data)
Bulk 多包传输辅助接口 / Helper for multi-packet bulk transfer.
Definition ep.hpp:320
void SetActiveLength(uint16_t len)
设置当前活动缓冲区有效长度 / Set active buffer valid length
Definition ep.hpp:270
void SetOnTransferCompleteCallback(Callback< ConstRawData & > cb)
设置传输完成回调 / Set transfer complete callback
Definition ep.hpp:261
virtual void Configure(const Config &cfg)=0
配置端点协议参数 / Configure endpoint protocol parameters
@ BULK
批量端点 / Bulk
virtual void Close()=0
关闭端点 / Close endpoint
uint16_t MaxPacketSize() const
获取最大包长 / Get max packet size
Definition ep.hpp:225
State GetState() const
获取端点状态 / Get endpoint state
Definition ep.hpp:207
USB端点池类 / USB endpoint pool class.
Definition ep_pool.hpp:23
ErrorCode Get(Endpoint *&ep_info, Endpoint::Direction direction, Endpoint::EPNumber ep_num=Endpoint::EPNumber::EP_AUTO)
分配端点 / Allocate endpoint
Definition ep_pool.cpp:11
ErrorCode Release(Endpoint *ep_info)
回收端点 / Release endpoint
Definition ep_pool.cpp:37
GsUsb 设备类,实现 Linux gs_usb 协议(经典 CAN + CAN FD) / GsUsb device class implementing Linux gs_usb protocol...
Definition gs_usb.hpp:30
bool can_enabled_[CanChNum]
通道启用(classic) / Channel enabled (classic)
Definition gs_usb.hpp:931
void ClassicPackToQueueItem(const LibXR::CAN::ClassicPack &pack, uint8_t ch, QueueItem &qi)
ClassicPack -> QueueItem / Convert ClassicPack to QueueItem.
Definition gs_usb.hpp:1570
ErrorCode HandleBitTiming(uint8_t ch, const GsUsb::DeviceBitTiming &bt)
处理 BITTIMING(仲裁相位) / Handle BITTIMING (arbitration phase)
Definition gs_usb.hpp:1315
union LibXR::USB::GsUsbClass::@14 ctrl_buf_
控制传输复用缓冲区 / Union buffer for control transfers
bool ErrorPackToHostErrorFrame(uint8_t ch, const LibXR::CAN::ClassicPack &err_pack, QueueItem &qi)
将 LibXR 错误帧转换为 Host 错误帧(SocketCAN 语义) / Convert LibXR error pack to host error frame (SocketCAN seman...
Definition gs_usb.hpp:1704
void SetUserIdToStorage(uint32_t value)
写入 USER_ID(RAM 或 Database) / Write USER_ID (RAM or Database)
Definition gs_usb.hpp:1962
bool inited_
是否已初始化 / Initialized
Definition gs_usb.hpp:883
LibXR::LockFreeQueue< QueueItem > echo_queue_
Echo 队列(回送 echo_id) / Echo queue (echo back echo_id)
Definition gs_usb.hpp:1034
static void OnCanRxStatic(bool in_isr, CanRxCtx *ctx, const LibXR::CAN::ClassicPack &pack)
classic CAN RX 静态回调入口 / Static entry for classic CAN RX callback
Definition gs_usb.hpp:995
static uint8_t LenToDlc(uint8_t len)
长度转 DLC(FD 表) / Length to DLC (FD table)
Definition gs_usb.hpp:1910
GsUsb::DeviceBitTiming bt
BITTIMING / DATA_BITTIMING.
Definition gs_usb.hpp:914
ErrorCode HandleBerr(uint8_t ch, uint32_t berr_on)
处理 BERR 开关 / Handle BERR enable/disable
Definition gs_usb.hpp:1453
ErrorCode HandleMode(uint8_t ch, const GsUsb::DeviceMode &mode)
处理 MODE(启动/复位 + 标志位) / Handle MODE (start/reset + flags)
Definition gs_usb.hpp:1402
GsUsbClass(std::initializer_list< LibXR::CAN * > cans, Endpoint::EPNumber data_in_ep_num=Endpoint::EPNumber::EP1, Endpoint::EPNumber data_out_ep_num=Endpoint::EPNumber::EP2, size_t rx_queue_size=32, size_t echo_queue_size=32, LibXR::GPIO *identify_gpio=nullptr, std::initializer_list< LibXR::GPIO * > termination_gpios={}, LibXR::Database *database=nullptr)
构造:经典 CAN / Construct: Classic CAN
Definition gs_usb.hpp:89
static constexpr std::size_t WIRE_FD_DATA_SIZE
FD 数据长度 / FD data size.
Definition gs_usb.hpp:59
bool fd_can_rx_registered_
FD RX 回调是否已注册 / FD RX callback registered.
Definition gs_usb.hpp:986
uint8_t can_count_
实际通道数 / Actual channel count
Definition gs_usb.hpp:875
static constexpr std::size_t WIRE_CLASSIC_TS_SIZE
classic+ts 总长度 / Classic+ts total size
Definition gs_usb.hpp:65
static void HostWireToClassicPack(const WireHeader &wh, const uint8_t *payload, LibXR::CAN::ClassicPack &pack)
wire -> ClassicPack / Convert wire frame to ClassicPack
Definition gs_usb.hpp:1502
bool OwnsEndpoint(uint8_t ep_addr) const override
判断端点地址是否属于本类 / Check whether an endpoint belongs to this class
Definition gs_usb.hpp:357
GsUsb::Identify identify
IDENTIFY.
Definition gs_usb.hpp:917
GsUsbClass(std::initializer_list< LibXR::FDCAN * > fd_cans, Endpoint::EPNumber data_in_ep_num=Endpoint::EPNumber::EP_AUTO, Endpoint::EPNumber data_out_ep_num=Endpoint::EPNumber::EP_AUTO, size_t rx_queue_size=32, size_t echo_queue_size=32, LibXR::GPIO *identify_gpio=nullptr, std::initializer_list< LibXR::GPIO * > termination_gpios={}, LibXR::Database *database=nullptr)
构造:FDCAN / Construct: FDCAN
Definition gs_usb.hpp:143
LibXR::Callback< LibXR::ConstRawData & > on_data_out_cb_
OUT 回调 / OUT callback.
Definition gs_usb.hpp:895
std::array< LibXR::FDCAN *, CanChNum > fdcans_
FDCAN 通道列表 / FDCAN channel pointers.
Definition gs_usb.hpp:872
std::array< LibXR::CAN::Configuration, CanChNum > config_
经典 CAN 配置 / Classic CAN configuration
Definition gs_usb.hpp:925
GsUsb::DeviceTerminationState term
SET_TERMINATION / GET_TERMINATION.
Definition gs_usb.hpp:919
LibXR::LockFreeQueue< QueueItem > rx_queue_
RX 队列(Device->Host) / RX queue (Device->Host)
Definition gs_usb.hpp:1032
Endpoint::EPNumber data_out_ep_num_
Bulk OUT 端点号 / Bulk OUT endpoint number.
Definition gs_usb.hpp:878
std::array< LibXR::CAN *, CanChNum > cans_
CAN 通道列表 / CAN channel pointers.
Definition gs_usb.hpp:870
bool berr_enabled_[CanChNum]
错误报告启用 / Bus error reporting enabled
Definition gs_usb.hpp:933
GsUsb::TerminationState term_state_[CanChNum]
终端电阻状态 / Termination state
Definition gs_usb.hpp:938
static constexpr std::size_t WIRE_HDR_SIZE
Header 长度 / Header size.
Definition gs_usb.hpp:55
bool can_rx_registered_
classic RX 回调是否已注册 / Classic RX callback registered
Definition gs_usb.hpp:980
void UnbindEndpoints(EndpointPool &endpoint_pool, bool) override
释放端点资源并复位状态 / Release endpoint resources and reset state
Definition gs_usb.hpp:307
static constexpr std::size_t WIRE_FD_TS_SIZE
FD+ts 总长度 / FD+ts total size.
Definition gs_usb.hpp:69
GsUsb::HostConfig host_cfg
HOST_FORMAT.
Definition gs_usb.hpp:913
static uint8_t DlcToLen(uint8_t dlc)
DLC 转长度(FD 表) / DLC to length (FD table)
Definition gs_usb.hpp:1900
bool HasAnyTerminationGpio() const
是否存在任意 termination GPIO / Whether any termination GPIO exists
Definition gs_usb.hpp:1185
ErrorCode HandleHostFormat(const GsUsb::HostConfig &cfg)
处理 HOST_FORMAT / Handle HOST_FORMAT
Definition gs_usb.hpp:1306
LibXR::Callback< LibXR::ConstRawData & > on_data_in_cb_
IN 回调 / IN callback.
Definition gs_usb.hpp:899
static constexpr std::size_t WIRE_TS_SIZE
时间戳字段长度 / Timestamp field size
Definition gs_usb.hpp:60
GsUsb::DeviceConfig dev_cfg_
设备配置 / Device configuration
Definition gs_usb.hpp:903
std::array< uint8_t, WIRE_MAX_SIZE > tx_buf_
IN 发送暂存区 / IN transmit staging buffer.
Definition gs_usb.hpp:957
void OnFdCanRx(bool in_isr, uint8_t ch, const LibXR::FDCAN::FDPack &pack)
FD CAN RX 处理 / Handle FD CAN RX.
Definition gs_usb.hpp:1069
LibXR::CAN::Callback can_rx_cb_[CanChNum]
classic RX 回调数组 / Classic RX callbacks
Definition gs_usb.hpp:984
LibXR::Database * database_
Definition gs_usb.hpp:891
void OnDataInComplete(bool in_isr, ConstRawData &data)
Bulk IN 完成处理(Device->Host) / Handle Bulk IN completion (Device->Host)
Definition gs_usb.hpp:861
Endpoint * ep_data_in_
Bulk IN 端点对象 / Bulk IN endpoint object.
Definition gs_usb.hpp:880
static constexpr uint32_t ECHO_ID_RX
RX 帧 echo_id 固定值 / Fixed echo_id for RX frames.
Definition gs_usb.hpp:52
static constexpr std::size_t WIRE_FD_SIZE
FD 总长度 / FD total size.
Definition gs_usb.hpp:67
ErrorCode HandleDataBitTiming(uint8_t ch, const GsUsb::DeviceBitTiming &bt)
处理 DATA_BITTIMING(数据相位) / Handle DATA_BITTIMING (data phase)
Definition gs_usb.hpp:1358
static constexpr std::size_t WIRE_CLASSIC_SIZE
classic 总长度 / Classic total size
Definition gs_usb.hpp:63
GsUsb::DeviceBTConstExtended bt_const_ext_
BT 常量(扩展/FD) / BT constants (extended/FD)
Definition gs_usb.hpp:906
FdCanRxCtx fd_can_rx_ctx_[CanChNum]
FD RX 上下文数组 / FD RX contexts.
Definition gs_usb.hpp:988
uint32_t user_id
GET_USER_ID / SET_USER_ID.
Definition gs_usb.hpp:921
void InitDeviceConfigFd()
初始化 FD 设备配置与能力位 / Initialize FD device config and feature bits
Definition gs_usb.hpp:1252
uint8_t rx_buf_[WIRE_MAX_SIZE]
OUT 接收缓冲区 / OUT receive buffer.
Definition gs_usb.hpp:955
bool HasIAD() override
是否包含 IAD / Whether class has IAD
Definition gs_usb.hpp:349
static void HostWireToFdPack(const WireHeader &wh, const uint8_t *payload, LibXR::FDCAN::FDPack &pack)
wire -> FDPack / Convert wire frame to FDPack
Definition gs_usb.hpp:1536
ErrorCode HandleSetTermination(uint8_t ch, const GsUsb::DeviceTerminationState &st)
处理 SET_TERMINATION / Handle SET_TERMINATION
Definition gs_usb.hpp:1479
std::array< LibXR::GPIO *, CanChNum > termination_gpios_
终端电阻 GPIO(可选) / Termination GPIOs (optional)
Definition gs_usb.hpp:889
CanRxCtx can_rx_ctx_[CanChNum]
classic RX 上下文数组 / Classic RX contexts
Definition gs_usb.hpp:982
std::array< LibXR::FDCAN::Configuration, CanChNum > fd_config_
FD 配置 / FD configuration.
Definition gs_usb.hpp:927
static void OnDataOutCompleteStatic(bool in_isr, GsUsbClass *self, ConstRawData &data)
Bulk OUT 完成静态回调包装 / Static wrapper for Bulk OUT completion.
Definition gs_usb.hpp:745
uint32_t GetUserIdFromStorage() const
读取 USER_ID(RAM 或 Database) / Read USER_ID (RAM or Database)
Definition gs_usb.hpp:1947
uint8_t ctrl_target_channel_
控制请求目标通道 / Control request target channel
Definition gs_usb.hpp:940
uint32_t berr_on
BERR.
Definition gs_usb.hpp:916
GsUsb::DeviceMode mode
MODE.
Definition gs_usb.hpp:915
ErrorCode OnClassData(bool in_isr, uint8_t bRequest, LibXR::ConstRawData &data) override
Vendor Request 的 DATA 阶段处理 / Handle DATA stage for vendor requests.
Definition gs_usb.hpp:654
bool timestamps_enabled_ch_[CanChNum]
通道时间戳启用 / Per-channel timestamp enabled
Definition gs_usb.hpp:936
bool IsHostFormatOK() const
Host 字节序协商是否通过 / Whether host format negotiation passed.
Definition gs_usb.hpp:189
GsUsb::DeviceBTConst bt_const_
BT 常量(classic) / BT constants (classic)
Definition gs_usb.hpp:904
uint32_t timestamp_us
TIMESTAMP.
Definition gs_usb.hpp:918
size_t GetInterfaceCount() override
返回接口数量(实现侧固定 1) / Return interface count (fixed to 1)
Definition gs_usb.hpp:342
static constexpr std::size_t WIRE_CLASSIC_DATA_SIZE
classic 数据长度 / Classic data size
Definition gs_usb.hpp:57
uint8_t interface_num_
接口号 / Interface number
Definition gs_usb.hpp:884
void TryKickTx(bool in_isr)
尝试启动 Bulk IN 发送 / Try to start Bulk IN transmit
Definition gs_usb.hpp:1119
ErrorCode OnVendorRequest(bool in_isr, uint8_t bRequest, uint16_t wValue, uint16_t wLength, uint16_t wIndex, DeviceClass::ControlTransferResult &result) override
Vendor Request(gs_usb BREQ)处理 / Handle vendor requests (gs_usb BREQ)
Definition gs_usb.hpp:395
bool fd_enabled_[CanChNum]
通道启用(FD) / Channel enabled (FD)
Definition gs_usb.hpp:934
void InitDeviceConfigClassic()
初始化 classic CAN 设备配置与能力位 / Initialize classic CAN device config and feature bits
Definition gs_usb.hpp:1201
bool EnqueueFrame(const QueueItem &qi, bool is_echo, bool in_isr)
入队并尝试触发发送 / Enqueue and try to trigger TX
Definition gs_usb.hpp:1100
LibXR::FDCAN::CallbackFD fd_can_rx_cb_[CanChNum]
FD RX 回调数组 / FD RX callbacks.
Definition gs_usb.hpp:990
uint32_t MakeTimestampUs(uint8_t ch) const
获取通道时间戳(us, 32-bit) / Get per-channel timestamp (us, 32-bit)
Definition gs_usb.hpp:1874
Endpoint * ep_data_out_
Bulk OUT 端点对象 / Bulk OUT endpoint object.
Definition gs_usb.hpp:881
static void OnDataInCompleteStatic(bool in_isr, GsUsbClass *self, ConstRawData &data)
Bulk IN 完成静态回调包装 / Static wrapper for Bulk IN completion.
Definition gs_usb.hpp:760
ErrorCode HandleIdentify(uint8_t, const GsUsb::Identify &id)
处理 IDENTIFY / Handle IDENTIFY
Definition gs_usb.hpp:1466
size_t GetMaxConfigSize() override
返回描述符块最大长度 / Return max configuration descriptor block size
Definition gs_usb.hpp:372
void OnDataOutComplete(bool in_isr, ConstRawData &data)
Bulk OUT 完成处理(Host->Device) / Handle Bulk OUT completion (Host->Device)
Definition gs_usb.hpp:774
static constexpr std::size_t WIRE_MAX_SIZE
最大线缆帧长度 / Maximum wire frame size
Definition gs_usb.hpp:71
GsUsb::DeviceState dev_state
GET_STATE.
Definition gs_usb.hpp:920
LibXR::GPIO * identify_gpio_
Identify GPIO(可选) / Identify GPIO (optional)
Definition gs_usb.hpp:886
bool host_format_ok_
HOST_FORMAT 是否通过 / HOST_FORMAT OK.
Definition gs_usb.hpp:929
void OnCanRx(bool in_isr, uint8_t ch, const LibXR::CAN::ClassicPack &pack)
classic CAN RX 处理 / Handle classic CAN RX
Definition gs_usb.hpp:1039
static void OnFdCanRxStatic(bool in_isr, FdCanRxCtx *ctx, const LibXR::FDCAN::FDPack &pack)
FD CAN RX 静态回调入口 / Static entry for FD CAN RX callback.
Definition gs_usb.hpp:1008
void FdPackToQueueItem(const LibXR::FDCAN::FDPack &pack, uint8_t ch, QueueItem &qi)
FDPack -> QueueItem / Convert FDPack to QueueItem.
Definition gs_usb.hpp:1614
void BindEndpoints(EndpointPool &endpoint_pool, uint8_t start_itf_num, bool) override
初始化接口与端点资源 / Initialize interface and endpoints
Definition gs_usb.hpp:198
Endpoint::EPNumber data_in_ep_num_
Bulk IN 端点号 / Bulk IN endpoint number.
Definition gs_usb.hpp:877
std::size_t PackQueueItemToWire(const QueueItem &qi, uint8_t *out, std::size_t cap) const
QueueItem -> wire bytes / Convert QueueItem to wire bytes.
Definition gs_usb.hpp:1666
uint32_t user_id_ram_
USER_ID 的 RAM 备份 / USER_ID RAM backup.
Definition gs_usb.hpp:893
void MaybeArmOutTransfer()
确保 Bulk OUT 保持挂起接收 / Ensure Bulk OUT is armed for receiving
Definition gs_usb.hpp:1158
bool fd_supported_
是否支持 FD / FD supported
Definition gs_usb.hpp:873
uint32_t MakeTimestampUsGlobal() const
获取全局时间戳(us, 32-bit) / Get global timestamp (us, 32-bit)
Definition gs_usb.hpp:1888
ErrorCode OnClassRequest(bool, uint8_t, uint16_t, uint16_t, uint16_t, DeviceClass::ControlTransferResult &) override
标准 Class Request 处理(此类不支持) / Handle standard class request (not supported)
Definition gs_usb.hpp:379
经典 CAN 帧数据结构。Classic CAN frame structure.
Definition can.hpp:129
Type type
帧类型。Frame type.
Definition can.hpp:131
uint32_t id
CAN ID(11/29 bit 或 ErrorID)。CAN ID (11/29 bits or ErrorID).
Definition can.hpp:130
uint8_t data[8]
数据载荷。Data payload (up to 8 bytes).
Definition can.hpp:133
uint8_t dlc
有效数据长度(0~8)。Data length code (0–8).
Definition can.hpp:132
CAN 配置参数。CAN configuration parameters.
Definition can.hpp:62
CAN 当前错误状态快照(来自硬件计数器/状态机)。 Snapshot of current CAN controller error state (from HW counters/state).
Definition can.hpp:88
bool bus_off
是否处于 BUS-OFF。True if controller is bus-off.
Definition can.hpp:92
bool error_passive
是否处于 Error Passive。True if error-passive.
Definition can.hpp:93
uint8_t tx_error_counter
发送错误计数 TEC。Transmit error counter (TEC).
Definition can.hpp:89
bool error_warning
是否处于 Error Warning。True if error-warning.
Definition can.hpp:94
uint8_t rx_error_counter
接收错误计数 REC。Receive error counter (REC).
Definition can.hpp:90
CAN FD 帧数据结构。CAN FD frame structure.
Definition can.hpp:265
Type type
帧类型。Frame type.
Definition can.hpp:267
uint32_t id
CAN ID。CAN ID.
Definition can.hpp:266
uint8_t len
数据长度(0~64)。Data length (0–64 bytes).
Definition can.hpp:268
uint8_t data[64]
数据载荷。Data payload.
Definition can.hpp:269
端点描述符(7 字节)/ Endpoint descriptor (7 bytes)
Definition desc_cfg.hpp:92
接口描述符(9 字节)/ Interface descriptor (9 bytes)
Definition desc_cfg.hpp:76
控制请求(Class/Vendor)处理结果 / Control request (Class/Vendor) handling result
Definition dev_core.hpp:51
uint32_t tseg1_min
TSEG1 最小 / Min TSEG1.
uint32_t tseg2_min
TSEG2 最小 / Min TSEG2.
uint32_t brp_min
BRP 最小 / Min BRP.
uint32_t tseg2_max
TSEG2 最大 / Max TSEG2.
uint32_t brp_max
BRP 最大 / Max BRP.
uint32_t sjw_max
SJW 最大 / Max SJW.
uint32_t tseg1_max
TSEG1 最大 / Max TSEG1.
uint32_t brp_inc
BRP 步进 / BRP increment.
扩展比特定时能力(含 FD 数据相位) / Extended timing capabilities (with FD data phase)
CanBitTimingConst btc
仲裁相位 / Arbitration phase
CanBitTimingConst dbtc
数据相位 / Data phase
uint32_t feature
CAN_FEAT_*(含 FD) / CAN_FEAT_* (with FD)
uint32_t fclk_can
CAN 时钟 / CAN clock.
设备比特定时能力(经典/仲裁) / Device bit timing capabilities (classic/arbitration)
uint32_t fclk_can
CAN 时钟 / CAN clock.
CanBitTimingConst btc
定时常量 / Timing constants
比特定时参数 / Bit timing parameters
设备配置(per-device) / Device configuration (per-device)
uint32_t sw_version
软件版本 / Software version
uint8_t reserved2
保留 / Reserved
uint32_t hw_version
硬件版本 / Hardware version
uint8_t reserved3
保留 / Reserved
uint8_t icount
CAN 通道数 - 1 / CAN channel count minus 1.
uint8_t reserved1
保留 / Reserved
通道模式设置(per-channel) / Channel mode configuration (per-channel)
通道状态(per-channel) / Channel state (per-channel)
终端电阻控制 / Termination control
主机配置(字节序协商) / Host configuration (byte order negotiation)
识别控制 / Identify control
CAN RX 回调上下文 / CAN RX callback context.
Definition gs_usb.hpp:966
uint8_t ch
通道号 / Channel index
Definition gs_usb.hpp:968
GsUsbClass * self
实例指针 / Instance pointer
Definition gs_usb.hpp:967
FDCAN RX 回调上下文 / FDCAN RX callback context.
Definition gs_usb.hpp:975
GsUsbClass * self
实例指针 / Instance pointer
Definition gs_usb.hpp:976
uint8_t ch
通道号 / Channel index
Definition gs_usb.hpp:977
本类的接口与端点描述符块 / Descriptor block for interface and endpoints
Definition gs_usb.hpp:948
InterfaceDescriptor intf
Interface 描述符 / Interface descriptor.
Definition gs_usb.hpp:949
EndpointDescriptor ep_in
IN 端点描述符 / IN endpoint descriptor.
Definition gs_usb.hpp:951
EndpointDescriptor ep_out
OUT 端点描述符 / OUT endpoint descriptor.
Definition gs_usb.hpp:950
发送队列元素(包含 header/data/timestamp) / TX queue item (header/data/timestamp)
Definition gs_usb.hpp:1023
uint8_t data_len
payload 长度(8/64) / Payload length (8/64)
Definition gs_usb.hpp:1026
uint32_t timestamp_us
时间戳 / Timestamp
Definition gs_usb.hpp:1027
WireHeader hdr
线缆头 / Wire header
Definition gs_usb.hpp:1024
bool is_fd
是否 FD / Is FD
Definition gs_usb.hpp:1025
std::array< uint8_t, 64 > data
数据段 / Data bytes
Definition gs_usb.hpp:1028
gs_usb 线缆格式头(12 字节) / gs_usb wire-format header (12 bytes)
Definition gs_usb.hpp:42
uint8_t channel
通道号 / Channel index
Definition gs_usb.hpp:46
uint8_t reserved
保留 / Reserved
Definition gs_usb.hpp:48
uint32_t echo_id
回显 ID / Echo ID
Definition gs_usb.hpp:43
uint8_t flags
帧标志(GS_CAN_FLAG_*) / Frame flags (GS_CAN_FLAG_*)
Definition gs_usb.hpp:47
uint32_t can_id
CAN ID(含标志位) / CAN ID (with flags)
Definition gs_usb.hpp:44