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 "libxr_mem.hpp"
17#include "timebase.hpp"
18#include "usb/core/desc_cfg.hpp"
19
20namespace LibXR::USB
21{
22
29template <std::size_t CanChNum>
30class GsUsbClass : public DeviceClass
31{
32 public:
33 static_assert(CanChNum > 0 && CanChNum <= 255, "CanChNum must be in (0, 255]");
34 static constexpr uint8_t CAN_CH_NUM = static_cast<uint8_t>(CanChNum);
35 // GS USB 功能的默认接口字符串。
36 // Default interface string for the GS USB function.
37 static constexpr const char* DEFAULT_INTERFACE_STRING = "XRUSB GS USB";
38
39 private:
40 // ===== Linux gs_usb 线缆格式(固定 12 字节头) / Linux gs_usb wire format
41 // (fixed 12-byte header) =====
42#pragma pack(push, 1)
43
48 {
49 uint32_t echo_id;
50 uint32_t can_id;
51 uint8_t can_dlc;
52 uint8_t channel;
53 uint8_t flags;
54 uint8_t reserved;
55 };
56#pragma pack(pop)
57
58 static constexpr uint32_t ECHO_ID_RX =
59 0xFFFFFFFFu;
60
61 static constexpr std::size_t WIRE_HDR_SIZE =
62 sizeof(WireHeader);
63 static constexpr std::size_t WIRE_CLASSIC_DATA_SIZE =
64 8;
65 static constexpr std::size_t WIRE_FD_DATA_SIZE = 64;
66 static constexpr std::size_t WIRE_TS_SIZE =
67 4;
68
69 static constexpr std::size_t WIRE_CLASSIC_SIZE =
70 WIRE_HDR_SIZE + 8;
71 static constexpr std::size_t WIRE_CLASSIC_TS_SIZE =
72 WIRE_HDR_SIZE + 8 + 4;
73 static constexpr std::size_t WIRE_FD_SIZE =
74 WIRE_HDR_SIZE + 64;
75 static constexpr std::size_t WIRE_FD_TS_SIZE =
76 WIRE_HDR_SIZE + 64 + 4;
77 static constexpr std::size_t WIRE_MAX_SIZE =
79
80 public:
96 GsUsbClass(std::initializer_list<LibXR::CAN*> cans,
99 size_t rx_queue_size = 32, size_t echo_queue_size = 32,
100 LibXR::GPIO* identify_gpio = nullptr,
101 std::initializer_list<LibXR::GPIO*> termination_gpios = {},
102 LibXR::Database* database = nullptr,
103 const char* interface_string = DEFAULT_INTERFACE_STRING)
104 : data_in_ep_num_(data_in_ep_num),
105 data_out_ep_num_(data_out_ep_num),
106 identify_gpio_(identify_gpio),
107 database_(database),
108 rx_queue_(rx_queue_size),
109 echo_queue_(echo_queue_size),
110 interface_string_(interface_string)
111 {
112 ASSERT(cans.size() == CAN_CH_NUM);
113 std::size_t i = 0;
114 for (auto* p : cans)
115 {
116 cans_[i++] = p;
117 }
118
119 if (termination_gpios.size() == 0)
120 {
121 termination_gpios_.fill(nullptr);
122 }
123 else
124 {
125 ASSERT(termination_gpios.size() == CAN_CH_NUM);
126 i = 0;
127 for (auto* g : termination_gpios)
128 {
129 termination_gpios_[i++] = g;
130 }
131 }
132
134 }
135
136 const char* GetInterfaceString(size_t local_interface_index) const override
137 {
138 // GS USB 暴露一个 vendor-specific 接口。
139 // GS USB contributes one vendor-specific interface.
140 return (local_interface_index == 0u) ? interface_string_ : nullptr;
141 }
142
160 GsUsbClass(std::initializer_list<LibXR::FDCAN*> fd_cans,
163 size_t rx_queue_size = 32, size_t echo_queue_size = 32,
164 LibXR::GPIO* identify_gpio = nullptr,
165 std::initializer_list<LibXR::GPIO*> termination_gpios = {},
166 LibXR::Database* database = nullptr,
167 const char* interface_string = DEFAULT_INTERFACE_STRING)
168 : fd_supported_(true),
169 data_in_ep_num_(data_in_ep_num),
170 data_out_ep_num_(data_out_ep_num),
171 identify_gpio_(identify_gpio),
172 database_(database),
173 rx_queue_(rx_queue_size),
174 echo_queue_(echo_queue_size),
175 interface_string_(interface_string)
176 {
177 ASSERT(fd_cans.size() == CAN_CH_NUM);
178 std::size_t i = 0;
179 for (auto* p : fd_cans)
180 {
181 fdcans_[i] = p;
182 cans_[i] = p; // 向上转 CAN* / Upcast to CAN*
183 ++i;
184 }
185
186 if (termination_gpios.size() == 0)
187 {
188 termination_gpios_.fill(nullptr);
189 }
190 else
191 {
192 ASSERT(termination_gpios.size() == CAN_CH_NUM);
193 i = 0;
194 for (auto* g : termination_gpios)
195 {
196 termination_gpios_[i++] = g;
197 }
198 }
199
201 }
202
208 bool IsHostFormatOK() const { return host_format_ok_; }
209
210 protected:
217 void BindEndpoints(EndpointPool& endpoint_pool, uint8_t start_itf_num, bool) override
218 {
219 inited_ = false;
220 interface_num_ = start_itf_num;
221
222 auto ans = endpoint_pool.Get(ep_data_in_, Endpoint::Direction::IN, data_in_ep_num_);
223 ASSERT(ans == ErrorCode::OK);
224
226 ASSERT(ans == ErrorCode::OK);
227
228 // UINT16_MAX 只是上限,底层会选不超过该值的可用最大长度。
229 // UINT16_MAX is only an upper bound; the backend still chooses the largest valid length.
231 {Endpoint::Direction::IN, Endpoint::Type::BULK, UINT16_MAX, true});
234
235 desc_block_.intf = {9,
236 static_cast<uint8_t>(DescriptorType::INTERFACE),
238 0,
239 2,
240 0xFF,
241 0xFF,
242 0xFF,
244
245 desc_block_.ep_out = {7,
246 static_cast<uint8_t>(DescriptorType::ENDPOINT),
247 static_cast<uint8_t>(ep_data_out_->GetAddress()),
248 static_cast<uint8_t>(Endpoint::Type::BULK),
250 0};
251
252 desc_block_.ep_in = {7,
253 static_cast<uint8_t>(DescriptorType::ENDPOINT),
254 static_cast<uint8_t>(ep_data_in_->GetAddress()),
255 static_cast<uint8_t>(Endpoint::Type::BULK),
257 0};
258
259 SetData(RawData{reinterpret_cast<uint8_t*>(&desc_block_), sizeof(desc_block_)});
260
263
264 host_format_ok_ = false;
265
266 for (uint8_t i = 0; i < can_count_; ++i)
267 {
268 can_enabled_[i] = false;
269 berr_enabled_[i] = false;
270 fd_enabled_[i] = false;
271 term_state_[i] = GsUsb::TerminationState::OFF;
272 timestamps_enabled_ch_[i] = false;
273 }
274
275 // 注册 CAN RX 回调 / Register CAN RX callbacks
277 {
278 for (uint8_t ch = 0; ch < can_count_; ++ch)
279 {
280 if (!cans_[ch])
281 {
282 continue;
283 }
284
285 can_rx_ctx_[ch].self = this;
286 can_rx_ctx_[ch].ch = ch;
288
289 cans_[ch]->Register(can_rx_cb_[ch], LibXR::CAN::Type::STANDARD);
290 cans_[ch]->Register(can_rx_cb_[ch], LibXR::CAN::Type::EXTENDED);
293 cans_[ch]->Register(can_rx_cb_[ch], LibXR::CAN::Type::ERROR);
294 }
295 can_rx_registered_ = true;
296 }
297
299 {
300 for (uint8_t ch = 0; ch < can_count_; ++ch)
301 {
302 if (!fdcans_[ch])
303 {
304 continue;
305 }
306
307 fd_can_rx_ctx_[ch].self = this;
308 fd_can_rx_ctx_[ch].ch = ch;
309 fd_can_rx_cb_[ch] =
311
314 }
316 }
317
318 inited_ = true;
320 }
321
327 void UnbindEndpoints(EndpointPool& endpoint_pool, bool) override
328 {
329 inited_ = false;
330 host_format_ok_ = false;
331
332 for (uint8_t i = 0; i < can_count_; ++i)
333 {
334 can_enabled_[i] = false;
335 berr_enabled_[i] = false;
336 fd_enabled_[i] = false;
337 term_state_[i] = GsUsb::TerminationState::OFF;
338 timestamps_enabled_ch_[i] = false;
339 }
340
341 if (ep_data_in_)
342 {
345 endpoint_pool.Release(ep_data_in_);
346 ep_data_in_ = nullptr;
347 }
348
349 if (ep_data_out_)
350 {
353 endpoint_pool.Release(ep_data_out_);
354 ep_data_out_ = nullptr;
355 }
356 }
357
362 size_t GetInterfaceCount() override { return 1; }
363
369 bool HasIAD() override { return false; }
370
377 bool OwnsEndpoint(uint8_t ep_addr) const override
378 {
379 if (!inited_)
380 {
381 return false;
382 }
383
384 return (ep_data_in_ && ep_data_in_->GetAddress() == ep_addr) ||
385 (ep_data_out_ && ep_data_out_->GetAddress() == ep_addr);
386 }
387
392 size_t GetMaxConfigSize() override { return sizeof(desc_block_); }
393
399 ErrorCode OnClassRequest(bool, uint8_t, uint16_t, uint16_t, uint16_t,
401 {
403 }
404
415 ErrorCode OnVendorRequest(bool in_isr, uint8_t bRequest, uint16_t wValue,
416 uint16_t wLength, uint16_t wIndex,
417 DeviceClass::ControlTransferResult& result) override
418 {
419 UNUSED(in_isr);
420 UNUSED(wIndex);
421
422 auto req = static_cast<GsUsb::BReq>(bRequest);
423
424 switch (req)
425 {
426 // ===== Device -> Host =====
427 case GsUsb::BReq::BT_CONST:
428 {
429 if (wLength < sizeof(bt_const_))
430 {
431 return ErrorCode::ARG_ERR;
432 }
433 result.write_data =
434 ConstRawData{reinterpret_cast<const uint8_t*>(&bt_const_), sizeof(bt_const_)};
435 return ErrorCode::OK;
436 }
437
438 case GsUsb::BReq::BT_CONST_EXT:
439 {
440 if (!fd_supported_)
441 {
443 }
444 if (wLength < sizeof(bt_const_ext_))
445 {
446 return ErrorCode::ARG_ERR;
447 }
448 result.write_data = ConstRawData{reinterpret_cast<const uint8_t*>(&bt_const_ext_),
449 sizeof(bt_const_ext_)};
450 return ErrorCode::OK;
451 }
452
453 case GsUsb::BReq::DEVICE_CONFIG:
454 {
455 if (wLength < sizeof(dev_cfg_))
456 {
457 return ErrorCode::ARG_ERR;
458 }
459 result.write_data =
460 ConstRawData{reinterpret_cast<const uint8_t*>(&dev_cfg_), sizeof(dev_cfg_)};
461 return ErrorCode::OK;
462 }
463
464 case GsUsb::BReq::TIMESTAMP:
465 {
466 ctrl_buf_.timestamp_us = MakeTimestampUsGlobal();
467 if (wLength < sizeof(ctrl_buf_.timestamp_us))
468 {
469 return ErrorCode::ARG_ERR;
470 }
471
472 result.write_data =
473 ConstRawData{reinterpret_cast<const uint8_t*>(&ctrl_buf_.timestamp_us),
474 sizeof(ctrl_buf_.timestamp_us)};
475 return ErrorCode::OK;
476 }
477
478 case GsUsb::BReq::GET_TERMINATION:
479 {
480 if (wValue >= can_count_)
481 {
482 return ErrorCode::ARG_ERR;
483 }
484 ctrl_buf_.term.state = static_cast<uint32_t>(term_state_[wValue]);
485 if (wLength < sizeof(ctrl_buf_.term))
486 {
487 return ErrorCode::ARG_ERR;
488 }
489
490 result.write_data = ConstRawData{
491 reinterpret_cast<const uint8_t*>(&ctrl_buf_.term), sizeof(ctrl_buf_.term)};
492 return ErrorCode::OK;
493 }
494
495 case GsUsb::BReq::GET_STATE:
496 {
497 if (wValue >= can_count_)
498 {
499 return ErrorCode::ARG_ERR;
500 }
501
502 GsUsb::CanState st = GsUsb::CanState::ERROR_ACTIVE;
503 uint32_t rxerr = 0;
504 uint32_t txerr = 0;
505
506 auto* can = cans_[wValue];
507 if (can != nullptr)
508 {
510 if (can->GetErrorState(es) == ErrorCode::OK)
511 {
512 if (es.bus_off)
513 {
514 st = GsUsb::CanState::BUS_OFF;
515 }
516 else if (es.error_passive)
517 {
518 st = GsUsb::CanState::ERROR_PASSIVE;
519 }
520 else if (es.error_warning)
521 {
522 st = GsUsb::CanState::ERROR_WARNING;
523 }
524 else
525 {
526 st = GsUsb::CanState::ERROR_ACTIVE;
527 }
528
529 rxerr = es.rx_error_counter;
530 txerr = es.tx_error_counter;
531 }
532 }
533
534 ctrl_buf_.dev_state.state = static_cast<uint32_t>(st);
535 ctrl_buf_.dev_state.rxerr = rxerr;
536 ctrl_buf_.dev_state.txerr = txerr;
537
538 if (wLength < sizeof(ctrl_buf_.dev_state))
539 {
540 return ErrorCode::ARG_ERR;
541 }
542
543 result.write_data =
544 ConstRawData{reinterpret_cast<const uint8_t*>(&ctrl_buf_.dev_state),
545 sizeof(ctrl_buf_.dev_state)};
546 return ErrorCode::OK;
547 }
548
549 case GsUsb::BReq::GET_USER_ID:
550 {
552 if (wLength < sizeof(ctrl_buf_.user_id))
553 {
554 return ErrorCode::ARG_ERR;
555 }
556
557 result.write_data =
558 ConstRawData{reinterpret_cast<const uint8_t*>(&ctrl_buf_.user_id),
559 sizeof(ctrl_buf_.user_id)};
560 return ErrorCode::OK;
561 }
562
563 // ===== Host -> Device(有 DATA 阶段) / Host -> Device (with DATA stage) =====
564 case GsUsb::BReq::HOST_FORMAT:
565 {
566 if (wLength != sizeof(GsUsb::HostConfig))
567 {
568 return ErrorCode::ARG_ERR;
569 }
570 result.read_data = RawData{reinterpret_cast<uint8_t*>(&ctrl_buf_.host_cfg),
571 sizeof(GsUsb::HostConfig)};
572 return ErrorCode::OK;
573 }
574
575 case GsUsb::BReq::BITTIMING:
576 {
577 if (wLength != sizeof(GsUsb::DeviceBitTiming) || wValue >= can_count_)
578 {
579 return ErrorCode::ARG_ERR;
580 }
581 ctrl_target_channel_ = static_cast<uint8_t>(wValue);
582 result.read_data = RawData{reinterpret_cast<uint8_t*>(&ctrl_buf_.bt),
583 sizeof(GsUsb::DeviceBitTiming)};
584 return ErrorCode::OK;
585 }
586
587 case GsUsb::BReq::DATA_BITTIMING:
588 {
589 if (!fd_supported_)
590 {
592 }
593 if (wLength != sizeof(GsUsb::DeviceBitTiming) || wValue >= can_count_)
594 {
595 return ErrorCode::ARG_ERR;
596 }
597 ctrl_target_channel_ = static_cast<uint8_t>(wValue);
598 result.read_data = RawData{reinterpret_cast<uint8_t*>(&ctrl_buf_.bt),
599 sizeof(GsUsb::DeviceBitTiming)};
600 return ErrorCode::OK;
601 }
602
603 case GsUsb::BReq::MODE:
604 {
605 if (wLength != sizeof(GsUsb::DeviceMode) || wValue >= can_count_)
606 {
607 return ErrorCode::ARG_ERR;
608 }
609 ctrl_target_channel_ = static_cast<uint8_t>(wValue);
610 result.read_data = RawData{reinterpret_cast<uint8_t*>(&ctrl_buf_.mode),
611 sizeof(GsUsb::DeviceMode)};
612 return ErrorCode::OK;
613 }
614
615 case GsUsb::BReq::BERR:
616 {
617 if (wLength != sizeof(uint32_t) || wValue >= can_count_)
618 {
619 return ErrorCode::ARG_ERR;
620 }
621 ctrl_target_channel_ = static_cast<uint8_t>(wValue);
622 result.read_data =
623 RawData{reinterpret_cast<uint8_t*>(&ctrl_buf_.berr_on), sizeof(uint32_t)};
624 return ErrorCode::OK;
625 }
626
627 case GsUsb::BReq::IDENTIFY:
628 {
629 if (wLength != sizeof(GsUsb::Identify) || wValue >= can_count_)
630 {
631 return ErrorCode::ARG_ERR;
632 }
633 ctrl_target_channel_ = static_cast<uint8_t>(wValue);
634 result.read_data = RawData{reinterpret_cast<uint8_t*>(&ctrl_buf_.identify),
635 sizeof(GsUsb::Identify)};
636 return ErrorCode::OK;
637 }
638
639 case GsUsb::BReq::SET_TERMINATION:
640 {
641 if (wLength != sizeof(GsUsb::DeviceTerminationState) || wValue >= can_count_)
642 {
643 return ErrorCode::ARG_ERR;
644 }
645 ctrl_target_channel_ = static_cast<uint8_t>(wValue);
646 result.read_data = RawData{reinterpret_cast<uint8_t*>(&ctrl_buf_.term),
648 return ErrorCode::OK;
649 }
650
651 case GsUsb::BReq::SET_USER_ID:
652 {
653 if (wLength != sizeof(uint32_t))
654 {
655 return ErrorCode::ARG_ERR;
656 }
657 result.read_data =
658 RawData{reinterpret_cast<uint8_t*>(&ctrl_buf_.user_id), sizeof(uint32_t)};
659 return ErrorCode::OK;
660 }
661
662 default:
664 }
665 }
666
674 ErrorCode OnClassData(bool in_isr, uint8_t bRequest, LibXR::ConstRawData& data) override
675 {
676 UNUSED(in_isr);
677
678 auto req = static_cast<GsUsb::BReq>(bRequest);
679
680 switch (req)
681 {
682 case GsUsb::BReq::HOST_FORMAT:
683 if (data.size_ != sizeof(GsUsb::HostConfig))
684 {
685 return ErrorCode::ARG_ERR;
686 }
687 return HandleHostFormat(ctrl_buf_.host_cfg);
688
689 case GsUsb::BReq::BITTIMING:
690 if (data.size_ != sizeof(GsUsb::DeviceBitTiming))
691 {
692 return ErrorCode::ARG_ERR;
693 }
695
696 case GsUsb::BReq::DATA_BITTIMING:
697 if (!fd_supported_)
698 {
700 }
701 if (data.size_ != sizeof(GsUsb::DeviceBitTiming))
702 {
703 return ErrorCode::ARG_ERR;
704 }
706
707 case GsUsb::BReq::MODE:
708 if (data.size_ != sizeof(GsUsb::DeviceMode))
709 {
710 return ErrorCode::ARG_ERR;
711 }
713
714 case GsUsb::BReq::BERR:
715 if (data.size_ != sizeof(uint32_t))
716 {
717 return ErrorCode::ARG_ERR;
718 }
720
721 case GsUsb::BReq::IDENTIFY:
722 if (data.size_ != sizeof(GsUsb::Identify))
723 {
724 return ErrorCode::ARG_ERR;
725 }
727
728 case GsUsb::BReq::SET_TERMINATION:
729 if (data.size_ != sizeof(GsUsb::DeviceTerminationState))
730 {
731 return ErrorCode::ARG_ERR;
732 }
734
735 case GsUsb::BReq::SET_USER_ID:
736 if (data.size_ != sizeof(uint32_t))
737 {
738 return ErrorCode::ARG_ERR;
739 }
741 return ErrorCode::OK;
742
743 case GsUsb::BReq::DEVICE_CONFIG:
744 case GsUsb::BReq::BT_CONST:
745 case GsUsb::BReq::BT_CONST_EXT:
746 case GsUsb::BReq::TIMESTAMP:
747 case GsUsb::BReq::GET_TERMINATION:
748 case GsUsb::BReq::GET_STATE:
749 case GsUsb::BReq::GET_USER_ID:
750 return ErrorCode::OK;
751
752 default:
754 }
755 }
756
757 // ================= Bulk 端点回调 / Bulk endpoint callbacks =================
758
765 static void OnDataOutCompleteStatic(bool in_isr, GsUsbClass* self, ConstRawData& data)
766 {
767 if (self == nullptr || !self->inited_)
768 {
769 return;
770 }
771 self->OnDataOutComplete(in_isr, data);
772 }
773
780 static void OnDataInCompleteStatic(bool in_isr, GsUsbClass* self, ConstRawData& data)
781 {
782 if (self == nullptr || !self->inited_)
783 {
784 return;
785 }
786 self->OnDataInComplete(in_isr, data);
787 }
788
794 void OnDataOutComplete(bool in_isr, ConstRawData& data)
795 {
796 UNUSED(in_isr);
797
798 if (!ep_data_out_)
799 {
800 return;
801 }
802 if (!host_format_ok_)
803 {
805 return;
806 }
807
808 const std::size_t RXLEN = data.size_;
809 if (RXLEN < WIRE_CLASSIC_SIZE)
810 {
812 return;
813 }
814
815 // 解析 wire header / Parse wire header
816 const WireHeader& wh = *reinterpret_cast<const WireHeader*>(data.addr_);
817
818 const uint8_t CH = wh.channel;
819 if (CH >= can_count_ || !cans_[CH])
820 {
822 return;
823 }
824
825 const bool IS_FD = (wh.flags & GsUsb::CAN_FLAG_FD) != 0;
826 const uint8_t* payload = reinterpret_cast<const uint8_t*>(data.addr_) + WIRE_HDR_SIZE;
827
828 if (IS_FD)
829 {
830 if (!fd_supported_ || !fdcans_[CH] || !fd_enabled_[CH])
831 {
833 return;
834 }
835
836 if (RXLEN < WIRE_FD_SIZE)
837 {
839 return;
840 }
841
843 HostWireToFdPack(wh, payload, pack);
844 (void)fdcans_[CH]->AddMessage(pack);
845 }
846 else
847 {
848 if (!can_enabled_[CH])
849 {
851 return;
852 }
853
854 if (RXLEN < WIRE_CLASSIC_SIZE)
855 {
857 return;
858 }
859
861 HostWireToClassicPack(wh, payload, pack);
862 (void)cans_[CH]->AddMessage(pack);
863 }
864
865 // TX echo:host 通过 echo_id 跟踪 TX buffer;设备需回送 echo_id。
866 // TX echo: the host tracks TX buffers via echo_id, and the device should echo it back.
867 if (wh.echo_id != ECHO_ID_RX)
868 {
869 QueueItem qi;
870 qi.hdr = wh;
871 qi.is_fd = IS_FD;
872 qi.data_len = IS_FD ? 64u : 8u;
874 Memory::FastCopy(qi.data.data(), payload, qi.data_len);
875 (void)EnqueueFrame(qi, true, in_isr);
876 }
877
879 }
880
886 void OnDataInComplete(bool in_isr, ConstRawData& data)
887 {
888 UNUSED(in_isr);
889 UNUSED(data);
890 TryKickTx(false);
891 }
892
893 private:
894 // ================= 成员 / Members =================
895 std::array<LibXR::CAN*, CanChNum> cans_{};
896 std::array<LibXR::FDCAN*, CanChNum>
898 bool fd_supported_ = false;
899
900 uint8_t can_count_ = CAN_CH_NUM;
901
904
907
908 bool inited_ = false;
909 uint8_t interface_num_ = 0;
910 const char* interface_string_ = nullptr;
911
913 nullptr;
914 std::array<LibXR::GPIO*, CanChNum>
916
919 uint32_t user_id_ram_ = 0;
920
923 this);
924
927 this);
928
933
937 union
938 {
942 uint32_t berr_on;
944 uint32_t timestamp_us;
947 uint32_t user_id;
949
950 std::array<LibXR::CAN::Configuration, CanChNum>
952 std::array<LibXR::FDCAN::Configuration, CanChNum>
954
955 bool host_format_ok_ = false;
956
957 bool can_enabled_[CanChNum] = {
958 false};
959 bool berr_enabled_[CanChNum] = {false};
960 bool fd_enabled_[CanChNum] = {false};
961
962 bool timestamps_enabled_ch_[CanChNum] = {
963 false};
964 GsUsb::TerminationState term_state_[CanChNum] = {
965 GsUsb::TerminationState::OFF};
967 0;
968
969#pragma pack(push, 1)
979#pragma pack(pop)
980
982 std::array<uint8_t, WIRE_MAX_SIZE>
984
985 // ================= CAN RX 回调 & BULK IN 发送队列 / CAN RX callbacks & Bulk IN TX
986 // queues =================
987
991 struct CanRxCtx
992 {
994 uint8_t ch;
995 };
996
1001 {
1003 uint8_t ch;
1004 };
1005
1007 false;
1008 CanRxCtx can_rx_ctx_[CanChNum]{};
1010 can_rx_cb_[CanChNum]{};
1011
1013 false;
1016 fd_can_rx_cb_[CanChNum]{};
1017
1021 static void OnCanRxStatic(bool in_isr, CanRxCtx* ctx,
1022 const LibXR::CAN::ClassicPack& pack)
1023 {
1024 if (!ctx || !ctx->self || !ctx->self->inited_)
1025 {
1026 return;
1027 }
1028 ctx->self->OnCanRx(in_isr, ctx->ch, pack);
1029 }
1030
1034 static void OnFdCanRxStatic(bool in_isr, FdCanRxCtx* ctx,
1035 const LibXR::FDCAN::FDPack& pack)
1036 {
1037 if (!ctx || !ctx->self || !ctx->self->inited_)
1038 {
1039 return;
1040 }
1041 ctx->self->OnFdCanRx(in_isr, ctx->ch, pack);
1042 }
1043
1049 {
1051 bool is_fd;
1052 uint8_t data_len;
1053 uint32_t timestamp_us;
1054 std::array<uint8_t, 64> data;
1055 };
1056
1061
1065 void OnCanRx(bool in_isr, uint8_t ch, const LibXR::CAN::ClassicPack& pack)
1066 {
1067 if (ch >= can_count_ || !ep_data_in_)
1068 {
1069 return;
1070 }
1071
1072 if (pack.type == LibXR::CAN::Type::ERROR)
1073 {
1074 QueueItem qi;
1075 if (ErrorPackToHostErrorFrame(ch, pack, qi))
1076 {
1077 (void)EnqueueFrame(qi, false, in_isr);
1078 }
1079 return;
1080 }
1081
1082 if (!can_enabled_[ch])
1083 {
1084 return;
1085 }
1086
1087 QueueItem qi;
1088 ClassicPackToQueueItem(pack, ch, qi);
1089 (void)EnqueueFrame(qi, false, in_isr);
1090 }
1091
1095 void OnFdCanRx(bool in_isr, uint8_t ch, const LibXR::FDCAN::FDPack& pack)
1096 {
1097 if (!fd_supported_ || ch >= can_count_ || !fd_enabled_[ch] || !ep_data_in_)
1098 {
1099 return;
1100 }
1101
1102 QueueItem qi;
1103 FdPackToQueueItem(pack, ch, qi);
1104
1105 const auto& fd_cfg = fd_config_[ch];
1106 if (fd_cfg.fd_mode.brs)
1107 {
1108 qi.hdr.flags |= GsUsb::CAN_FLAG_BRS;
1109 }
1110 if (fd_cfg.fd_mode.esi)
1111 {
1112 qi.hdr.flags |= GsUsb::CAN_FLAG_ESI;
1113 }
1114
1115 (void)EnqueueFrame(qi, false, in_isr);
1116 }
1117
1126 bool EnqueueFrame(const QueueItem& qi, bool is_echo, bool in_isr)
1127 {
1128 UNUSED(in_isr);
1129
1130 const ErrorCode EC = is_echo ? echo_queue_.Push(qi) : rx_queue_.Push(qi);
1131 if (EC != ErrorCode::OK)
1132 {
1133 return false;
1134 }
1135
1136 TryKickTx(in_isr);
1138 return true;
1139 }
1140
1145 void TryKickTx(bool in_isr)
1146 {
1147 UNUSED(in_isr);
1148
1149 if (!ep_data_in_)
1150 {
1151 return;
1152 }
1154 {
1155 return;
1156 }
1157
1158 QueueItem qi;
1159 ErrorCode ec = echo_queue_.Pop(qi);
1160 if (ec != ErrorCode::OK)
1161 {
1162 ec = rx_queue_.Pop(qi);
1163 if (ec != ErrorCode::OK)
1164 {
1165 return;
1166 }
1167 }
1168
1169 const std::size_t SEND_LEN = PackQueueItemToWire(qi, tx_buf_.data(), tx_buf_.size());
1170 if (SEND_LEN == 0)
1171 {
1172 return;
1173 }
1174
1175 RawData tx_raw{tx_buf_.data(), SEND_LEN};
1176 (void)ep_data_in_->TransferMultiBulk(tx_raw);
1177
1179 }
1180
1185 {
1186 if (!ep_data_out_)
1187 {
1188 return;
1189 }
1191 {
1192 return;
1193 }
1194
1195 if (rx_queue_.EmptySize() == 0 || echo_queue_.EmptySize() == 0)
1196 {
1197 return;
1198 }
1199
1200 RawData rx_raw{rx_buf_, static_cast<size_t>(WIRE_MAX_SIZE)};
1201 (void)ep_data_out_->TransferMultiBulk(rx_raw);
1202 }
1203
1204 // ================= 业务处理函数 / Handlers =================
1205
1212 {
1213 for (uint8_t i = 0; i < can_count_; ++i)
1214 {
1215 if (termination_gpios_[i] != nullptr)
1216 {
1217 return true;
1218 }
1219 }
1220 return false;
1221 }
1222
1228 {
1229 can_count_ = CAN_CH_NUM;
1230 ASSERT(can_count_ > 0);
1231 ASSERT(cans_[0] != nullptr);
1232
1233 dev_cfg_.reserved1 = 0;
1234 dev_cfg_.reserved2 = 0;
1235 dev_cfg_.reserved3 = 0;
1236 dev_cfg_.icount = static_cast<uint8_t>(can_count_ - 1);
1237 dev_cfg_.sw_version = 2;
1238 dev_cfg_.hw_version = 1;
1239
1240 const uint32_t FCLK = cans_[0]->GetClockFreq();
1241
1242 bt_const_.feature = GsUsb::CAN_FEAT_LISTEN_ONLY | GsUsb::CAN_FEAT_LOOP_BACK |
1243 GsUsb::CAN_FEAT_TRIPLE_SAMPLE | GsUsb::CAN_FEAT_ONE_SHOT |
1244 GsUsb::CAN_FEAT_HW_TIMESTAMP | GsUsb::CAN_FEAT_BERR_REPORTING |
1245 GsUsb::CAN_FEAT_GET_STATE | GsUsb::CAN_FEAT_USER_ID;
1246
1247 if (identify_gpio_)
1248 {
1249 bt_const_.feature |= GsUsb::CAN_FEAT_IDENTIFY;
1250 }
1252 {
1253 bt_const_.feature |= GsUsb::CAN_FEAT_TERMINATION;
1254 }
1255
1256 bt_const_.fclk_can = FCLK;
1258 bt_const_.btc.tseg1_max = 16;
1261 bt_const_.btc.sjw_max = 4;
1262 bt_const_.btc.brp_min = 1;
1263 bt_const_.btc.brp_max = 1024;
1264 bt_const_.btc.brp_inc = 1;
1265
1267 bt_const_ext_.fclk_can = FCLK;
1270
1271 Memory::FastSet(config_.data(), 0, sizeof(config_));
1272 Memory::FastSet(fd_config_.data(), 0, sizeof(fd_config_));
1273 }
1274
1279 {
1280 can_count_ = CAN_CH_NUM;
1281 ASSERT(can_count_ > 0);
1282 ASSERT(cans_[0] != nullptr);
1283
1284 dev_cfg_.reserved1 = 0;
1285 dev_cfg_.reserved2 = 0;
1286 dev_cfg_.reserved3 = 0;
1287 dev_cfg_.icount = static_cast<uint8_t>(can_count_ - 1);
1288 dev_cfg_.sw_version = 2;
1289 dev_cfg_.hw_version = 1;
1290
1291 const uint32_t FCLK = cans_[0]->GetClockFreq();
1292
1293 bt_const_.feature = GsUsb::CAN_FEAT_LISTEN_ONLY | GsUsb::CAN_FEAT_LOOP_BACK |
1294 GsUsb::CAN_FEAT_TRIPLE_SAMPLE | GsUsb::CAN_FEAT_ONE_SHOT |
1295 GsUsb::CAN_FEAT_HW_TIMESTAMP | GsUsb::CAN_FEAT_BERR_REPORTING |
1296 GsUsb::CAN_FEAT_GET_STATE | GsUsb::CAN_FEAT_USER_ID |
1297 GsUsb::CAN_FEAT_FD | GsUsb::CAN_FEAT_BT_CONST_EXT;
1298
1299 if (identify_gpio_)
1300 {
1301 bt_const_.feature |= GsUsb::CAN_FEAT_IDENTIFY;
1302 }
1304 {
1305 bt_const_.feature |= GsUsb::CAN_FEAT_TERMINATION;
1306 }
1307
1308 bt_const_.fclk_can = FCLK;
1310 bt_const_.btc.tseg1_max = 16;
1313 bt_const_.btc.sjw_max = 4;
1314 bt_const_.btc.brp_min = 1;
1315 bt_const_.btc.brp_max = 1024;
1316 bt_const_.btc.brp_inc = 1;
1317
1319 bt_const_ext_.fclk_can = FCLK;
1322
1323 Memory::FastSet(config_.data(), 0, sizeof(config_));
1324 Memory::FastSet(fd_config_.data(), 0, sizeof(fd_config_));
1325 }
1326
1333 {
1334 host_format_ok_ = (cfg.byte_order == 0x0000beefu);
1335 return ErrorCode::OK;
1336 }
1337
1342 {
1343 if (!host_format_ok_ || ch >= can_count_ || !cans_[ch])
1344 {
1345 return ErrorCode::ARG_ERR;
1346 }
1347
1348 const uint32_t TSEG1 = bt.prop_seg + bt.phase_seg1;
1349 const uint32_t TSEG2 = bt.phase_seg2;
1350 const uint32_t TQ_NUM = 1u + TSEG1 + TSEG2;
1351
1352 const uint32_t FCLK = cans_[ch]->GetClockFreq();
1353
1354 auto& cfg = config_[ch];
1355 cfg.bit_timing.brp = bt.brp;
1356 cfg.bit_timing.prop_seg = bt.prop_seg;
1357 cfg.bit_timing.phase_seg1 = bt.phase_seg1;
1358 cfg.bit_timing.phase_seg2 = bt.phase_seg2;
1359 cfg.bit_timing.sjw = bt.sjw;
1360
1361 if (bt.brp != 0u && TQ_NUM != 0u)
1362 {
1363 cfg.bitrate = FCLK / (bt.brp * TQ_NUM);
1364 cfg.sample_point = static_cast<float>(1u + TSEG1) / static_cast<float>(TQ_NUM);
1365 }
1366 else
1367 {
1368 cfg.bitrate = 0;
1369 cfg.sample_point = 0.0f;
1370 }
1371
1372 if (fd_supported_ && fdcans_[ch])
1373 {
1374 auto& fd_cfg = fd_config_[ch];
1375 static_cast<CAN::Configuration&>(fd_cfg) = cfg;
1376 }
1377
1378 return cans_[ch]->SetConfig(cfg);
1379 }
1380
1385 {
1386 if (!host_format_ok_)
1387 {
1388 return ErrorCode::ARG_ERR;
1389 }
1390 if (!fd_supported_ || ch >= can_count_ || !fdcans_[ch])
1391 {
1393 }
1394
1395 const uint32_t TSEG1 = bt.prop_seg + bt.phase_seg1;
1396 const uint32_t TSEG2 = bt.phase_seg2;
1397 const uint32_t TQ_NUM = 1u + TSEG1 + TSEG2;
1398
1399 const uint32_t FCLK = fdcans_[ch]->GetClockFreq();
1400
1401 auto& fd_cfg = fd_config_[ch];
1402 static_cast<CAN::Configuration&>(fd_cfg) = config_[ch];
1403
1404 fd_cfg.data_timing.brp = bt.brp;
1405 fd_cfg.data_timing.prop_seg = bt.prop_seg;
1406 fd_cfg.data_timing.phase_seg1 = bt.phase_seg1;
1407 fd_cfg.data_timing.phase_seg2 = bt.phase_seg2;
1408 fd_cfg.data_timing.sjw = bt.sjw;
1409
1410 if (bt.brp != 0u && TQ_NUM != 0u)
1411 {
1412 fd_cfg.data_bitrate = FCLK / (bt.brp * TQ_NUM);
1413 fd_cfg.data_sample_point =
1414 static_cast<float>(1u + TSEG1) / static_cast<float>(TQ_NUM);
1415 }
1416 else
1417 {
1418 fd_cfg.data_bitrate = 0;
1419 fd_cfg.data_sample_point = 0.0f;
1420 }
1421
1422 return fdcans_[ch]->SetConfig(fd_cfg);
1423 }
1424
1429 {
1430 if (!host_format_ok_ || ch >= can_count_ || !cans_[ch])
1431 {
1432 return ErrorCode::ARG_ERR;
1433 }
1434
1435 switch (static_cast<GsUsb::CanMode>(mode.mode))
1436 {
1437 case GsUsb::CanMode::RESET:
1438 can_enabled_[ch] = false;
1439 fd_enabled_[ch] = false;
1440 break;
1441
1442 case GsUsb::CanMode::START:
1443 can_enabled_[ch] = true;
1444 if (fd_supported_ && fdcans_[ch] && (mode.flags & GsUsb::GSCAN_MODE_FD))
1445 {
1446 fd_enabled_[ch] = true;
1447 }
1448 break;
1449
1450 default:
1451 return ErrorCode::ARG_ERR;
1452 }
1453
1454 auto& cfg = config_[ch];
1455 cfg.mode.loopback = (mode.flags & GsUsb::GSCAN_MODE_LOOP_BACK) != 0;
1456 cfg.mode.listen_only = (mode.flags & GsUsb::GSCAN_MODE_LISTEN_ONLY) != 0;
1457 cfg.mode.triple_sampling = (mode.flags & GsUsb::GSCAN_MODE_TRIPLE_SAMPLE) != 0;
1458 cfg.mode.one_shot = (mode.flags & GsUsb::GSCAN_MODE_ONE_SHOT) != 0;
1459
1460 timestamps_enabled_ch_[ch] = (mode.flags & GsUsb::GSCAN_MODE_HW_TIMESTAMP) != 0;
1461 berr_enabled_[ch] = (mode.flags & GsUsb::GSCAN_MODE_BERR_REPORTING) != 0;
1462
1463 const ErrorCode EC = cans_[ch]->SetConfig(cfg);
1464
1465 if (fd_supported_ && fdcans_[ch])
1466 {
1467 auto& fd_cfg = fd_config_[ch];
1468 static_cast<CAN::Configuration&>(fd_cfg) = cfg;
1469 fd_cfg.fd_mode.fd_enabled = (mode.flags & GsUsb::GSCAN_MODE_FD) != 0;
1470 (void)fdcans_[ch]->SetConfig(fd_cfg);
1471 }
1472
1473 return EC;
1474 }
1475
1479 ErrorCode HandleBerr(uint8_t ch, uint32_t berr_on)
1480 {
1481 if (ch >= can_count_)
1482 {
1483 return ErrorCode::ARG_ERR;
1484 }
1485 berr_enabled_[ch] = (berr_on != 0);
1486 return ErrorCode::OK;
1487 }
1488
1493 {
1494 const bool ON = (id.mode == static_cast<uint32_t>(GsUsb::IdentifyMode::ON));
1495 if (identify_gpio_)
1496 {
1497 (void)identify_gpio_->Write(ON);
1498 }
1499 return ErrorCode::OK;
1500 }
1501
1506 {
1507 if (ch >= can_count_)
1508 {
1509 return ErrorCode::ARG_ERR;
1510 }
1511
1512 term_state_[ch] = static_cast<GsUsb::TerminationState>(
1513 st.state != 0 ? static_cast<uint32_t>(GsUsb::TerminationState::ON)
1514 : static_cast<uint32_t>(GsUsb::TerminationState::OFF));
1515
1516 if (termination_gpios_[ch])
1517 {
1518 const bool ON = (term_state_[ch] == GsUsb::TerminationState::ON);
1519 (void)termination_gpios_[ch]->Write(ON);
1520 }
1521
1522 return ErrorCode::OK;
1523 }
1524
1528 static void HostWireToClassicPack(const WireHeader& wh, const uint8_t* payload,
1530 {
1531 const uint32_t CID = wh.can_id;
1532 const bool IS_EFF = (CID & GsUsb::CAN_EFF_FLAG) != 0;
1533 const bool IS_RTR = (CID & GsUsb::CAN_RTR_FLAG) != 0;
1534
1535 if (IS_EFF)
1536 {
1537 pack.id = CID & GsUsb::CAN_EFF_MASK;
1539 }
1540 else
1541 {
1542 pack.id = CID & GsUsb::CAN_SFF_MASK;
1544 }
1545
1546 uint8_t dlc = wh.can_dlc;
1547 if (dlc > 8u)
1548 {
1549 dlc = 8u;
1550 }
1551 pack.dlc = dlc;
1552
1553 if (dlc > 0u)
1554 {
1555 Memory::FastCopy(pack.data, payload, dlc);
1556 }
1557 }
1558
1562 static void HostWireToFdPack(const WireHeader& wh, const uint8_t* payload,
1564 {
1565 const uint32_t CID = wh.can_id;
1566 const bool IS_EFF = (CID & GsUsb::CAN_EFF_FLAG) != 0;
1567 const bool IS_RTR = (CID & GsUsb::CAN_RTR_FLAG) != 0;
1568
1569 if (IS_EFF)
1570 {
1571 pack.id = CID & GsUsb::CAN_EFF_MASK;
1573 }
1574 else
1575 {
1576 pack.id = CID & GsUsb::CAN_SFF_MASK;
1578 }
1579
1580 uint8_t len = DlcToLen(wh.can_dlc);
1581 if (len > 64)
1582 {
1583 len = 64;
1584 }
1585 pack.len = len;
1586
1587 if (len > 0u)
1588 {
1589 Memory::FastCopy(pack.data, payload, len);
1590 }
1591 }
1592
1597 QueueItem& qi)
1598 {
1599 uint32_t cid = 0;
1600 switch (pack.type)
1601 {
1603 cid = (pack.id & GsUsb::CAN_SFF_MASK);
1604 break;
1606 cid = (pack.id & GsUsb::CAN_EFF_MASK) | GsUsb::CAN_EFF_FLAG;
1607 break;
1609 cid = (pack.id & GsUsb::CAN_SFF_MASK) | GsUsb::CAN_RTR_FLAG;
1610 break;
1612 cid = (pack.id & GsUsb::CAN_EFF_MASK) | GsUsb::CAN_EFF_FLAG | GsUsb::CAN_RTR_FLAG;
1613 break;
1614 default:
1615 cid = pack.id & GsUsb::CAN_SFF_MASK;
1616 break;
1617 }
1618
1619 qi.hdr.echo_id = ECHO_ID_RX;
1620 qi.hdr.can_id = cid;
1621 qi.hdr.can_dlc = (pack.dlc <= 8u) ? pack.dlc : 8u;
1622 qi.hdr.channel = ch;
1623 qi.hdr.flags = 0;
1624 qi.hdr.reserved = 0;
1625
1626 qi.is_fd = false;
1627 qi.data_len = 8;
1629
1630 Memory::FastSet(qi.data.data(), 0, 8);
1631 if (qi.hdr.can_dlc > 0u)
1632 {
1633 Memory::FastCopy(qi.data.data(), pack.data, qi.hdr.can_dlc);
1634 }
1635 }
1636
1640 void FdPackToQueueItem(const LibXR::FDCAN::FDPack& pack, uint8_t ch, QueueItem& qi)
1641 {
1642 uint32_t cid = 0;
1643 switch (pack.type)
1644 {
1646 cid = (pack.id & GsUsb::CAN_SFF_MASK);
1647 break;
1649 cid = (pack.id & GsUsb::CAN_EFF_MASK) | GsUsb::CAN_EFF_FLAG;
1650 break;
1652 cid = (pack.id & GsUsb::CAN_SFF_MASK) | GsUsb::CAN_RTR_FLAG;
1653 break;
1655 cid = (pack.id & GsUsb::CAN_EFF_MASK) | GsUsb::CAN_EFF_FLAG | GsUsb::CAN_RTR_FLAG;
1656 break;
1657 default:
1658 cid = pack.id & GsUsb::CAN_SFF_MASK;
1659 break;
1660 }
1661
1662 qi.hdr.echo_id = ECHO_ID_RX;
1663 qi.hdr.can_id = cid;
1664 qi.hdr.can_dlc = LenToDlc(pack.len);
1665 qi.hdr.channel = ch;
1666 qi.hdr.flags = GsUsb::CAN_FLAG_FD;
1667 qi.hdr.reserved = 0;
1668
1669 qi.is_fd = true;
1670 qi.data_len = 64;
1672
1673 const uint8_t LEN = (pack.len <= 64) ? pack.len : 64;
1674
1675 if (LEN > 0u)
1676 {
1677 Memory::FastCopy(qi.data.data(), pack.data, LEN);
1678 }
1679 if (LEN < 64u)
1680 {
1681 Memory::FastSet(qi.data.data() + LEN, 0, 64u - LEN);
1682 }
1683 }
1684
1692 std::size_t PackQueueItemToWire(const QueueItem& qi, uint8_t* out,
1693 std::size_t cap) const
1694 {
1695 if (cap < WIRE_HDR_SIZE)
1696 {
1697 return 0;
1698 }
1699
1700 const uint8_t CH = qi.hdr.channel;
1701 const bool TS = (CH < can_count_) ? timestamps_enabled_ch_[CH] : false;
1702 const std::size_t PAYLOAD = qi.is_fd ? WIRE_FD_DATA_SIZE : WIRE_CLASSIC_DATA_SIZE;
1703 const std::size_t TOTAL = WIRE_HDR_SIZE + PAYLOAD + (TS ? WIRE_TS_SIZE : 0);
1704
1705 if (TOTAL > cap)
1706 {
1707 return 0;
1708 }
1709
1711 Memory::FastCopy(out + WIRE_HDR_SIZE, qi.data.data(), PAYLOAD);
1712
1713 if (TS)
1714 {
1716 }
1717
1718 return TOTAL;
1719 }
1720
1730 bool ErrorPackToHostErrorFrame(uint8_t ch, const LibXR::CAN::ClassicPack& err_pack,
1731 QueueItem& qi)
1732 {
1733 if (ch >= can_count_ || !cans_[ch])
1734 {
1735 return false;
1736 }
1737 if (!berr_enabled_[ch])
1738 {
1739 return false;
1740 }
1741 if (!LibXR::CAN::IsErrorId(err_pack.id))
1742 {
1743 return false;
1744 }
1745
1746 // 与 Linux can/error.h 对齐(沿用之前版本的映射)。
1747 // Keep these definitions aligned with Linux can/error.h, matching the previous mapping.
1748 constexpr uint8_t LNX_CAN_ERR_CRTL_UNSPEC = 0x00;
1749 constexpr uint8_t LNX_CAN_ERR_CRTL_RX_WARNING = 0x04;
1750 constexpr uint8_t LNX_CAN_ERR_CRTL_TX_WARNING = 0x08;
1751 constexpr uint8_t LNX_CAN_ERR_CRTL_RX_PASSIVE = 0x10;
1752 constexpr uint8_t LNX_CAN_ERR_CRTL_TX_PASSIVE = 0x20;
1753
1754 constexpr uint8_t LNX_CAN_ERR_PROT_UNSPEC = 0x00;
1755 constexpr uint8_t LNX_CAN_ERR_PROT_FORM = 0x02;
1756 constexpr uint8_t LNX_CAN_ERR_PROT_STUFF = 0x04;
1757 constexpr uint8_t LNX_CAN_ERR_PROT_BIT0 = 0x08;
1758 constexpr uint8_t LNX_CAN_ERR_PROT_BIT1 = 0x10;
1759 constexpr uint8_t LNX_CAN_ERR_PROT_TX = 0x80;
1760
1761 constexpr uint8_t LNX_CAN_ERR_PROT_LOC_UNSPEC = 0x00;
1762 constexpr uint8_t LNX_CAN_ERR_PROT_LOC_ACK = 0x19;
1763
1764 constexpr uint32_t LNX_CAN_ERR_CNT = 0x00000200U;
1765
1766 bool ec_valid = false;
1767 uint32_t txerr = 0, rxerr = 0;
1768 {
1770 if (cans_[ch]->GetErrorState(es) == ErrorCode::OK)
1771 {
1772 ec_valid = true;
1773 txerr = es.tx_error_counter;
1774 rxerr = es.rx_error_counter;
1775 }
1776 }
1777
1778 const uint8_t TXERR_U8 = (txerr > 255U) ? 255U : static_cast<uint8_t>(txerr);
1779 const uint8_t RXERR_U8 = (rxerr > 255U) ? 255U : static_cast<uint8_t>(rxerr);
1780
1781 const auto EID = LibXR::CAN::ToErrorID(err_pack.id);
1782
1783 uint32_t cid = GsUsb::CAN_ERR_FLAG;
1784 std::array<uint8_t, 8> d{};
1785 switch (EID)
1786 {
1787 case LibXR::CAN::ErrorID::CAN_ERROR_ID_BUS_OFF:
1788 cid |= GsUsb::CAN_ERR_BUSOFF;
1789 break;
1790
1791 case LibXR::CAN::ErrorID::CAN_ERROR_ID_ERROR_WARNING:
1792 case LibXR::CAN::ErrorID::CAN_ERROR_ID_ERROR_PASSIVE:
1793 {
1794 cid |= GsUsb::CAN_ERR_CRTL;
1795 uint8_t ctrl = LNX_CAN_ERR_CRTL_UNSPEC;
1796
1797 if (ec_valid)
1798 {
1799 if (EID == LibXR::CAN::ErrorID::CAN_ERROR_ID_ERROR_PASSIVE)
1800 {
1801 if (txerr >= 128U)
1802 {
1803 ctrl |= LNX_CAN_ERR_CRTL_TX_PASSIVE;
1804 }
1805 if (rxerr >= 128U)
1806 {
1807 ctrl |= LNX_CAN_ERR_CRTL_RX_PASSIVE;
1808 }
1809 }
1810 else
1811 {
1812 if (txerr >= 96U)
1813 {
1814 ctrl |= LNX_CAN_ERR_CRTL_TX_WARNING;
1815 }
1816 if (rxerr >= 96U)
1817 {
1818 ctrl |= LNX_CAN_ERR_CRTL_RX_WARNING;
1819 }
1820 }
1821 }
1822
1823 if (ctrl == LNX_CAN_ERR_CRTL_UNSPEC)
1824 {
1825 ctrl = (EID == LibXR::CAN::ErrorID::CAN_ERROR_ID_ERROR_PASSIVE)
1826 ? static_cast<uint8_t>(LNX_CAN_ERR_CRTL_TX_PASSIVE |
1827 LNX_CAN_ERR_CRTL_RX_PASSIVE)
1828 : static_cast<uint8_t>(LNX_CAN_ERR_CRTL_TX_WARNING |
1829 LNX_CAN_ERR_CRTL_RX_WARNING);
1830 }
1831
1832 d[1] = ctrl;
1833 break;
1834 }
1835
1836 case LibXR::CAN::ErrorID::CAN_ERROR_ID_ACK:
1837 cid |= GsUsb::CAN_ERR_ACK;
1838 cid |= GsUsb::CAN_ERR_PROT;
1839 d[2] = static_cast<uint8_t>(LNX_CAN_ERR_PROT_UNSPEC | LNX_CAN_ERR_PROT_TX);
1840 d[3] = LNX_CAN_ERR_PROT_LOC_ACK;
1841 break;
1842
1843 case LibXR::CAN::ErrorID::CAN_ERROR_ID_STUFF:
1844 cid |= GsUsb::CAN_ERR_PROT;
1845 d[2] = static_cast<uint8_t>(LNX_CAN_ERR_PROT_STUFF | LNX_CAN_ERR_PROT_TX);
1846 d[3] = LNX_CAN_ERR_PROT_LOC_UNSPEC;
1847 break;
1848
1849 case LibXR::CAN::ErrorID::CAN_ERROR_ID_FORM:
1850 cid |= GsUsb::CAN_ERR_PROT;
1851 d[2] = static_cast<uint8_t>(LNX_CAN_ERR_PROT_FORM | LNX_CAN_ERR_PROT_TX);
1852 d[3] = LNX_CAN_ERR_PROT_LOC_UNSPEC;
1853 break;
1854
1855 case LibXR::CAN::ErrorID::CAN_ERROR_ID_BIT0:
1856 cid |= GsUsb::CAN_ERR_PROT;
1857 d[2] = static_cast<uint8_t>(LNX_CAN_ERR_PROT_BIT0 | LNX_CAN_ERR_PROT_TX);
1858 d[3] = LNX_CAN_ERR_PROT_LOC_UNSPEC;
1859 break;
1860
1861 case LibXR::CAN::ErrorID::CAN_ERROR_ID_BIT1:
1862 cid |= GsUsb::CAN_ERR_PROT;
1863 d[2] = static_cast<uint8_t>(LNX_CAN_ERR_PROT_BIT1 | LNX_CAN_ERR_PROT_TX);
1864 d[3] = LNX_CAN_ERR_PROT_LOC_UNSPEC;
1865 break;
1866
1867 default:
1868 cid |= GsUsb::CAN_ERR_PROT;
1869 d[2] = static_cast<uint8_t>(LNX_CAN_ERR_PROT_UNSPEC | LNX_CAN_ERR_PROT_TX);
1870 d[3] = LNX_CAN_ERR_PROT_LOC_UNSPEC;
1871 break;
1872 }
1873
1874 cid |= LNX_CAN_ERR_CNT;
1875 d[6] = TXERR_U8;
1876 d[7] = RXERR_U8;
1877
1878 qi.hdr.echo_id = ECHO_ID_RX;
1879 qi.hdr.can_id = cid;
1880 qi.hdr.can_dlc = GsUsb::CAN_ERR_DLC;
1881 qi.hdr.channel = ch;
1882 qi.hdr.flags = 0;
1883 qi.hdr.reserved = 0;
1884
1885 qi.is_fd = false;
1886 qi.data_len = 8;
1888
1889 Memory::FastCopy(qi.data.data(), d.data(), 8);
1890
1891 return true;
1892 }
1893
1894 // ================= 工具函数 / Utilities =================
1895
1901 uint32_t MakeTimestampUs(uint8_t ch) const
1902 {
1903 if (ch < can_count_ && timestamps_enabled_ch_[ch] &&
1904 LibXR::Timebase::timebase != nullptr)
1905 {
1906 return static_cast<uint32_t>(LibXR::Timebase::GetMicroseconds() & 0xFFFFFFFFu);
1907 }
1908 return 0u;
1909 }
1910
1915 uint32_t MakeTimestampUsGlobal() const
1916 {
1917 if (LibXR::Timebase::timebase != nullptr)
1918 {
1919 return static_cast<uint32_t>(LibXR::Timebase::GetMicroseconds() & 0xFFFFFFFFu);
1920 }
1921 return 0u;
1922 }
1923
1927 static uint8_t DlcToLen(uint8_t dlc)
1928 {
1929 static constexpr uint8_t TABLE[16] = {0, 1, 2, 3, 4, 5, 6, 7,
1930 8, 12, 16, 20, 24, 32, 48, 64};
1931 return (dlc < 16) ? TABLE[dlc] : 64;
1932 }
1933
1937 static uint8_t LenToDlc(uint8_t len)
1938 {
1939 if (len <= 8)
1940 {
1941 return len;
1942 }
1943 if (len <= 12)
1944 {
1945 return 9;
1946 }
1947 if (len <= 16)
1948 {
1949 return 10;
1950 }
1951 if (len <= 20)
1952 {
1953 return 11;
1954 }
1955 if (len <= 24)
1956 {
1957 return 12;
1958 }
1959 if (len <= 32)
1960 {
1961 return 13;
1962 }
1963 if (len <= 48)
1964 {
1965 return 14;
1966 }
1967 return 15;
1968 }
1969
1974 uint32_t GetUserIdFromStorage() const
1975 {
1976 if (database_ == nullptr)
1977 {
1978 return user_id_ram_;
1979 }
1980
1982 return static_cast<uint32_t>(key);
1983 }
1984
1989 void SetUserIdToStorage(uint32_t value)
1990 {
1991 user_id_ram_ = value;
1992
1993 if (database_ == nullptr)
1994 {
1995 return;
1996 }
1997
1998 LibXR::Database::Key<uint32_t> key(*database_, "user_id", 0u);
1999 (void)key.Set(value);
2000 }
2001};
2002
2003} // 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:142
static Callback Create(CallableType fun, BoundArgType arg)
Definition libxr_cb.hpp:159
常量原始数据封装类。 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:50
ErrorCode Set(Data data)
设置键的值并更新数据库 (Set the key's value and update the database).
Definition database.hpp:108
数据库接口,提供键值存储和管理功能 (Database interface providing key-value storage and management).
Definition database.hpp:22
通用输入输出(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:5
原始数据封装类。 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:193
USB 设备类接口基类 / USB device class interface base.
uint8_t GetInterfaceStringIndex(size_t local_interface_index) const
返回已分配的接口字符串索引 Return the assigned USB string index for a local interface.
USB 端点基类 / USB Endpoint base class.
Definition ep.hpp:24
EPNumber
端点号 Endpoint number
Definition ep.hpp:42
@ EP1
端点 1 / Endpoint 1
@ EP_AUTO
自动分配端点号 / Auto allocate
@ EP2
端点 2 / Endpoint 2
uint8_t GetAddress() const
获取端点地址(方向 + 号) / Get endpoint address (dir + num)
Definition ep.hpp:195
@ IN
输入方向 / IN direction
@ OUT
输出方向 / OUT direction
virtual ErrorCode TransferMultiBulk(RawData &data)
Bulk 多包传输辅助接口 / Helper for multi-packet bulk transfer.
Definition ep.hpp:321
void SetActiveLength(uint16_t len)
设置当前活动缓冲区有效长度 / Set active buffer valid length
Definition ep.hpp:271
void SetOnTransferCompleteCallback(Callback< ConstRawData & > cb)
设置传输完成回调 / Set transfer complete callback
Definition ep.hpp:262
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:226
State GetState() const
获取端点状态 / Get endpoint state
Definition ep.hpp:208
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:31
bool can_enabled_[CanChNum]
通道启用(classic) / Channel enabled (classic)
Definition gs_usb.hpp:957
void ClassicPackToQueueItem(const LibXR::CAN::ClassicPack &pack, uint8_t ch, QueueItem &qi)
ClassicPack -> QueueItem / Convert ClassicPack to QueueItem.
Definition gs_usb.hpp:1596
ErrorCode HandleBitTiming(uint8_t ch, const GsUsb::DeviceBitTiming &bt)
处理 BITTIMING(仲裁相位) / Handle BITTIMING (arbitration phase)
Definition gs_usb.hpp:1341
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:1730
void SetUserIdToStorage(uint32_t value)
写入 USER_ID(RAM 或 Database) / Write USER_ID (RAM or Database)
Definition gs_usb.hpp:1989
bool inited_
是否已初始化 / Initialized
Definition gs_usb.hpp:908
LibXR::LockFreeQueue< QueueItem > echo_queue_
Echo 队列(回送 echo_id) / Echo queue (echo back echo_id)
Definition gs_usb.hpp:1060
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:1021
static uint8_t LenToDlc(uint8_t len)
长度转 DLC(FD 表) / Length to DLC (FD table)
Definition gs_usb.hpp:1937
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, const char *interface_string=DEFAULT_INTERFACE_STRING)
构造:经典 CAN / Construct: Classic CAN
Definition gs_usb.hpp:96
GsUsb::DeviceBitTiming bt
BITTIMING / DATA_BITTIMING.
Definition gs_usb.hpp:940
ErrorCode HandleBerr(uint8_t ch, uint32_t berr_on)
处理 BERR 开关 / Handle BERR enable/disable
Definition gs_usb.hpp:1479
ErrorCode HandleMode(uint8_t ch, const GsUsb::DeviceMode &mode)
处理 MODE(启动/复位 + 标志位) / Handle MODE (start/reset + flags)
Definition gs_usb.hpp:1428
static constexpr std::size_t WIRE_FD_DATA_SIZE
FD 数据长度 / FD data size.
Definition gs_usb.hpp:65
const char * interface_string_
接口字符串 / Interface string
Definition gs_usb.hpp:910
bool fd_can_rx_registered_
FD RX 回调是否已注册 / FD RX callback registered.
Definition gs_usb.hpp:1012
uint8_t can_count_
实际通道数 / Actual channel count
Definition gs_usb.hpp:900
static constexpr std::size_t WIRE_CLASSIC_TS_SIZE
classic+ts 总长度 / Classic+ts total size
Definition gs_usb.hpp:71
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:1528
bool OwnsEndpoint(uint8_t ep_addr) const override
判断端点地址是否属于本类 / Check whether an endpoint belongs to this class
Definition gs_usb.hpp:377
GsUsb::Identify identify
IDENTIFY.
Definition gs_usb.hpp:943
LibXR::Callback< LibXR::ConstRawData & > on_data_out_cb_
OUT 回调 / OUT callback.
Definition gs_usb.hpp:921
std::array< LibXR::FDCAN *, CanChNum > fdcans_
FDCAN 通道列表 / FDCAN channel pointers.
Definition gs_usb.hpp:897
std::array< LibXR::CAN::Configuration, CanChNum > config_
经典 CAN 配置 / Classic CAN configuration
Definition gs_usb.hpp:951
GsUsb::DeviceTerminationState term
SET_TERMINATION / GET_TERMINATION.
Definition gs_usb.hpp:945
LibXR::LockFreeQueue< QueueItem > rx_queue_
RX 队列(Device->Host) / RX queue (Device->Host)
Definition gs_usb.hpp:1058
Endpoint::EPNumber data_out_ep_num_
Bulk OUT 端点号 / Bulk OUT endpoint number.
Definition gs_usb.hpp:903
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, const char *interface_string=DEFAULT_INTERFACE_STRING)
构造:FDCAN / Construct: FDCAN
Definition gs_usb.hpp:160
std::array< LibXR::CAN *, CanChNum > cans_
CAN 通道列表 / CAN channel pointers.
Definition gs_usb.hpp:895
bool berr_enabled_[CanChNum]
错误报告启用 / Bus error reporting enabled
Definition gs_usb.hpp:959
GsUsb::TerminationState term_state_[CanChNum]
终端电阻状态 / Termination state
Definition gs_usb.hpp:964
static constexpr std::size_t WIRE_HDR_SIZE
Header 长度 / Header size.
Definition gs_usb.hpp:61
bool can_rx_registered_
classic RX 回调是否已注册 / Classic RX callback registered
Definition gs_usb.hpp:1006
void UnbindEndpoints(EndpointPool &endpoint_pool, bool) override
释放端点资源并复位状态 / Release endpoint resources and reset state
Definition gs_usb.hpp:327
static constexpr std::size_t WIRE_FD_TS_SIZE
FD+ts 总长度 / FD+ts total size.
Definition gs_usb.hpp:75
GsUsb::HostConfig host_cfg
HOST_FORMAT.
Definition gs_usb.hpp:939
static uint8_t DlcToLen(uint8_t dlc)
DLC 转长度(FD 表) / DLC to length (FD table)
Definition gs_usb.hpp:1927
bool HasAnyTerminationGpio() const
是否存在任意 termination GPIO / Whether any termination GPIO exists
Definition gs_usb.hpp:1211
ErrorCode HandleHostFormat(const GsUsb::HostConfig &cfg)
处理 HOST_FORMAT / Handle HOST_FORMAT
Definition gs_usb.hpp:1332
LibXR::Callback< LibXR::ConstRawData & > on_data_in_cb_
IN 回调 / IN callback.
Definition gs_usb.hpp:925
const char * GetInterfaceString(size_t local_interface_index) const override
返回本类暴露的第 N 个接口字符串 Return the string for the Nth local interface exposed by this class.
Definition gs_usb.hpp:136
static constexpr std::size_t WIRE_TS_SIZE
时间戳字段长度 / Timestamp field size
Definition gs_usb.hpp:66
GsUsb::DeviceConfig dev_cfg_
设备配置 / Device configuration
Definition gs_usb.hpp:929
std::array< uint8_t, WIRE_MAX_SIZE > tx_buf_
IN 发送暂存区 / IN transmit staging buffer.
Definition gs_usb.hpp:983
void OnFdCanRx(bool in_isr, uint8_t ch, const LibXR::FDCAN::FDPack &pack)
FD CAN RX 处理 / Handle FD CAN RX.
Definition gs_usb.hpp:1095
LibXR::CAN::Callback can_rx_cb_[CanChNum]
classic RX 回调数组 / Classic RX callbacks
Definition gs_usb.hpp:1010
LibXR::Database * database_
Definition gs_usb.hpp:917
void OnDataInComplete(bool in_isr, ConstRawData &data)
Bulk IN 完成处理(Device->Host) / Handle Bulk IN completion (Device->Host)
Definition gs_usb.hpp:886
Endpoint * ep_data_in_
Bulk IN 端点对象 / Bulk IN endpoint object.
Definition gs_usb.hpp:905
static constexpr uint32_t ECHO_ID_RX
RX 帧 echo_id 固定值 / Fixed echo_id for RX frames.
Definition gs_usb.hpp:58
static constexpr std::size_t WIRE_FD_SIZE
FD 总长度 / FD total size.
Definition gs_usb.hpp:73
ErrorCode HandleDataBitTiming(uint8_t ch, const GsUsb::DeviceBitTiming &bt)
处理 DATA_BITTIMING(数据相位) / Handle DATA_BITTIMING (data phase)
Definition gs_usb.hpp:1384
static constexpr std::size_t WIRE_CLASSIC_SIZE
classic 总长度 / Classic total size
Definition gs_usb.hpp:69
GsUsb::DeviceBTConstExtended bt_const_ext_
BT 常量(扩展/FD) / BT constants (extended/FD)
Definition gs_usb.hpp:932
FdCanRxCtx fd_can_rx_ctx_[CanChNum]
FD RX 上下文数组 / FD RX contexts.
Definition gs_usb.hpp:1014
uint32_t user_id
GET_USER_ID / SET_USER_ID.
Definition gs_usb.hpp:947
void InitDeviceConfigFd()
初始化 FD 设备配置与能力位 / Initialize FD device config and feature bits
Definition gs_usb.hpp:1278
uint8_t rx_buf_[WIRE_MAX_SIZE]
OUT 接收缓冲区 / OUT receive buffer.
Definition gs_usb.hpp:981
bool HasIAD() override
是否包含 IAD / Whether class has IAD
Definition gs_usb.hpp:369
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:1562
ErrorCode HandleSetTermination(uint8_t ch, const GsUsb::DeviceTerminationState &st)
处理 SET_TERMINATION / Handle SET_TERMINATION
Definition gs_usb.hpp:1505
std::array< LibXR::GPIO *, CanChNum > termination_gpios_
终端电阻 GPIO(可选) / Termination GPIOs (optional)
Definition gs_usb.hpp:915
CanRxCtx can_rx_ctx_[CanChNum]
classic RX 上下文数组 / Classic RX contexts
Definition gs_usb.hpp:1008
std::array< LibXR::FDCAN::Configuration, CanChNum > fd_config_
FD 配置 / FD configuration.
Definition gs_usb.hpp:953
static void OnDataOutCompleteStatic(bool in_isr, GsUsbClass *self, ConstRawData &data)
Bulk OUT 完成静态回调包装 / Static wrapper for Bulk OUT completion.
Definition gs_usb.hpp:765
uint32_t GetUserIdFromStorage() const
读取 USER_ID(RAM 或 Database) / Read USER_ID (RAM or Database)
Definition gs_usb.hpp:1974
uint8_t ctrl_target_channel_
控制请求目标通道 / Control request target channel
Definition gs_usb.hpp:966
uint32_t berr_on
BERR.
Definition gs_usb.hpp:942
GsUsb::DeviceMode mode
MODE.
Definition gs_usb.hpp:941
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:674
bool timestamps_enabled_ch_[CanChNum]
通道时间戳启用 / Per-channel timestamp enabled
Definition gs_usb.hpp:962
bool IsHostFormatOK() const
Host 字节序协商是否通过 / Whether host format negotiation passed.
Definition gs_usb.hpp:208
GsUsb::DeviceBTConst bt_const_
BT 常量(classic) / BT constants (classic)
Definition gs_usb.hpp:930
uint32_t timestamp_us
TIMESTAMP.
Definition gs_usb.hpp:944
size_t GetInterfaceCount() override
返回接口数量(实现侧固定 1) / Return interface count (fixed to 1)
Definition gs_usb.hpp:362
static constexpr std::size_t WIRE_CLASSIC_DATA_SIZE
classic 数据长度 / Classic data size
Definition gs_usb.hpp:63
uint8_t interface_num_
接口号 / Interface number
Definition gs_usb.hpp:909
void TryKickTx(bool in_isr)
尝试启动 Bulk IN 发送 / Try to start Bulk IN transmit
Definition gs_usb.hpp:1145
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:415
bool fd_enabled_[CanChNum]
通道启用(FD) / Channel enabled (FD)
Definition gs_usb.hpp:960
void InitDeviceConfigClassic()
初始化 classic CAN 设备配置与能力位 / Initialize classic CAN device config and feature bits
Definition gs_usb.hpp:1227
bool EnqueueFrame(const QueueItem &qi, bool is_echo, bool in_isr)
入队并尝试触发发送 / Enqueue and try to trigger TX
Definition gs_usb.hpp:1126
LibXR::FDCAN::CallbackFD fd_can_rx_cb_[CanChNum]
FD RX 回调数组 / FD RX callbacks.
Definition gs_usb.hpp:1016
uint32_t MakeTimestampUs(uint8_t ch) const
获取通道时间戳(us, 32-bit) / Get per-channel timestamp (us, 32-bit)
Definition gs_usb.hpp:1901
Endpoint * ep_data_out_
Bulk OUT 端点对象 / Bulk OUT endpoint object.
Definition gs_usb.hpp:906
static void OnDataInCompleteStatic(bool in_isr, GsUsbClass *self, ConstRawData &data)
Bulk IN 完成静态回调包装 / Static wrapper for Bulk IN completion.
Definition gs_usb.hpp:780
ErrorCode HandleIdentify(uint8_t, const GsUsb::Identify &id)
处理 IDENTIFY / Handle IDENTIFY
Definition gs_usb.hpp:1492
size_t GetMaxConfigSize() override
返回描述符块最大长度 / Return max configuration descriptor block size
Definition gs_usb.hpp:392
void OnDataOutComplete(bool in_isr, ConstRawData &data)
Bulk OUT 完成处理(Host->Device) / Handle Bulk OUT completion (Host->Device)
Definition gs_usb.hpp:794
static constexpr std::size_t WIRE_MAX_SIZE
最大线缆帧长度 / Maximum wire frame size
Definition gs_usb.hpp:77
GsUsb::DeviceState dev_state
GET_STATE.
Definition gs_usb.hpp:946
LibXR::GPIO * identify_gpio_
Identify GPIO(可选) / Identify GPIO (optional)
Definition gs_usb.hpp:912
bool host_format_ok_
HOST_FORMAT 是否通过 / HOST_FORMAT OK.
Definition gs_usb.hpp:955
void OnCanRx(bool in_isr, uint8_t ch, const LibXR::CAN::ClassicPack &pack)
classic CAN RX 处理 / Handle classic CAN RX
Definition gs_usb.hpp:1065
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:1034
void FdPackToQueueItem(const LibXR::FDCAN::FDPack &pack, uint8_t ch, QueueItem &qi)
FDPack -> QueueItem / Convert FDPack to QueueItem.
Definition gs_usb.hpp:1640
void BindEndpoints(EndpointPool &endpoint_pool, uint8_t start_itf_num, bool) override
初始化接口与端点资源 / Initialize interface and endpoints
Definition gs_usb.hpp:217
Endpoint::EPNumber data_in_ep_num_
Bulk IN 端点号 / Bulk IN endpoint number.
Definition gs_usb.hpp:902
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:1692
uint32_t user_id_ram_
USER_ID 的 RAM 备份 / USER_ID RAM backup.
Definition gs_usb.hpp:919
void MaybeArmOutTransfer()
确保 Bulk OUT 保持挂起接收 / Ensure Bulk OUT is armed for receiving
Definition gs_usb.hpp:1184
bool fd_supported_
是否支持 FD / FD supported
Definition gs_usb.hpp:898
uint32_t MakeTimestampUsGlobal() const
获取全局时间戳(us, 32-bit) / Get global timestamp (us, 32-bit)
Definition gs_usb.hpp:1915
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:399
ErrorCode
定义错误码枚举
@ NOT_SUPPORT
不支持 | Not supported
@ OK
操作成功 | Operation successful
@ ARG_ERR
参数错误 | Argument error
经典 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:91
接口描述符(9 字节)/ Interface descriptor (9 bytes)
Definition desc_cfg.hpp:75
控制请求(Class/Vendor)处理结果 / Control request (Class/Vendor) handling result
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:992
uint8_t ch
通道号 / Channel index
Definition gs_usb.hpp:994
GsUsbClass * self
实例指针 / Instance pointer
Definition gs_usb.hpp:993
FDCAN RX 回调上下文 / FDCAN RX callback context.
Definition gs_usb.hpp:1001
GsUsbClass * self
实例指针 / Instance pointer
Definition gs_usb.hpp:1002
uint8_t ch
通道号 / Channel index
Definition gs_usb.hpp:1003
本类的接口与端点描述符块 / Descriptor block for interface and endpoints
Definition gs_usb.hpp:974
InterfaceDescriptor intf
Interface 描述符 / Interface descriptor.
Definition gs_usb.hpp:975
EndpointDescriptor ep_in
IN 端点描述符 / IN endpoint descriptor.
Definition gs_usb.hpp:977
EndpointDescriptor ep_out
OUT 端点描述符 / OUT endpoint descriptor.
Definition gs_usb.hpp:976
发送队列元素(包含 header/data/timestamp) / TX queue item (header/data/timestamp)
Definition gs_usb.hpp:1049
uint8_t data_len
payload 长度(8/64) / Payload length (8/64)
Definition gs_usb.hpp:1052
uint32_t timestamp_us
时间戳 / Timestamp
Definition gs_usb.hpp:1053
WireHeader hdr
线缆头 / Wire header
Definition gs_usb.hpp:1050
bool is_fd
是否 FD / Is FD
Definition gs_usb.hpp:1051
std::array< uint8_t, 64 > data
数据段 / Data bytes
Definition gs_usb.hpp:1054
gs_usb 线缆格式头(12 字节) / gs_usb wire-format header (12 bytes)
Definition gs_usb.hpp:48
uint8_t channel
通道号 / Channel index
Definition gs_usb.hpp:52
uint8_t reserved
保留 / Reserved
Definition gs_usb.hpp:54
uint32_t echo_id
回显 ID / Echo ID
Definition gs_usb.hpp:49
uint8_t flags
帧标志(GS_CAN_FLAG_*) / Frame flags (GS_CAN_FLAG_*)
Definition gs_usb.hpp:53
uint32_t can_id
CAN ID(含标志位) / CAN ID (with flags)
Definition gs_usb.hpp:50