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 LIBXR_PACKED_BEGIN
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 LIBXR_PACKED_END
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(Endpoint::EPNumber data_in_ep_num, Endpoint::EPNumber data_out_ep_num,
97 std::initializer_list<LibXR::CAN*> cans, size_t rx_queue_size = 32,
98 size_t echo_queue_size = 32, LibXR::GPIO* identify_gpio = nullptr,
99 std::initializer_list<LibXR::GPIO*> termination_gpios = {},
100 LibXR::Database* database = nullptr,
101 const char* interface_string = DEFAULT_INTERFACE_STRING)
102 : data_in_ep_num_(data_in_ep_num),
103 data_out_ep_num_(data_out_ep_num),
104 identify_gpio_(identify_gpio),
105 database_(database),
106 rx_queue_(rx_queue_size),
107 echo_queue_(echo_queue_size),
108 interface_string_(interface_string)
109 {
110 ASSERT(cans.size() == CAN_CH_NUM);
111 std::size_t i = 0;
112 for (auto* p : cans)
113 {
114 cans_[i++] = p;
115 }
116
117 if (termination_gpios.size() == 0)
118 {
119 termination_gpios_.fill(nullptr);
120 }
121 else
122 {
123 ASSERT(termination_gpios.size() == CAN_CH_NUM);
124 i = 0;
125 for (auto* g : termination_gpios)
126 {
127 termination_gpios_[i++] = g;
128 }
129 }
130
132 }
133
134 const char* GetInterfaceString(size_t local_interface_index) const override
135 {
136 // GS USB 暴露一个 vendor-specific 接口。
137 // GS USB contributes one vendor-specific interface.
138 return (local_interface_index == 0u) ? interface_string_ : nullptr;
139 }
140
156 GsUsbClass(Endpoint::EPNumber data_in_ep_num, Endpoint::EPNumber data_out_ep_num,
157 std::initializer_list<LibXR::FDCAN*> fd_cans, size_t rx_queue_size = 32,
158 size_t echo_queue_size = 32, LibXR::GPIO* identify_gpio = nullptr,
159 std::initializer_list<LibXR::GPIO*> termination_gpios = {},
160 LibXR::Database* database = nullptr,
161 const char* interface_string = DEFAULT_INTERFACE_STRING)
162 : fd_supported_(true),
163 data_in_ep_num_(data_in_ep_num),
164 data_out_ep_num_(data_out_ep_num),
165 identify_gpio_(identify_gpio),
166 database_(database),
167 rx_queue_(rx_queue_size),
168 echo_queue_(echo_queue_size),
169 interface_string_(interface_string)
170 {
171 ASSERT(fd_cans.size() == CAN_CH_NUM);
172 std::size_t i = 0;
173 for (auto* p : fd_cans)
174 {
175 fdcans_[i] = p;
176 cans_[i] = p; // 向上转 CAN* / Upcast to CAN*
177 ++i;
178 }
179
180 if (termination_gpios.size() == 0)
181 {
182 termination_gpios_.fill(nullptr);
183 }
184 else
185 {
186 ASSERT(termination_gpios.size() == CAN_CH_NUM);
187 i = 0;
188 for (auto* g : termination_gpios)
189 {
190 termination_gpios_[i++] = g;
191 }
192 }
193
195 }
196
202 bool IsHostFormatOK() const { return host_format_ok_; }
203
204 protected:
211 void BindEndpoints(EndpointPool& endpoint_pool, uint8_t start_itf_num, bool) override
212 {
213 inited_ = false;
214 interface_num_ = start_itf_num;
215
216 auto ans = endpoint_pool.Get(ep_data_in_, Endpoint::Direction::IN, data_in_ep_num_);
217 ASSERT(ans == ErrorCode::OK);
218
220 ASSERT(ans == ErrorCode::OK);
221
222 // UINT16_MAX 只是上限,底层会选不超过该值的可用最大长度。
223 // UINT16_MAX is only an upper bound; the backend still chooses the largest valid
224 // length.
226 {Endpoint::Direction::IN, Endpoint::Type::BULK, UINT16_MAX, true});
229
230 desc_block_.intf = {9,
231 static_cast<uint8_t>(DescriptorType::INTERFACE),
233 0,
234 2,
235 0xFF,
236 0xFF,
237 0xFF,
239
240 desc_block_.ep_out = {7,
241 static_cast<uint8_t>(DescriptorType::ENDPOINT),
242 static_cast<uint8_t>(ep_data_out_->GetAddress()),
243 static_cast<uint8_t>(Endpoint::Type::BULK),
245 0};
246
247 desc_block_.ep_in = {7,
248 static_cast<uint8_t>(DescriptorType::ENDPOINT),
249 static_cast<uint8_t>(ep_data_in_->GetAddress()),
250 static_cast<uint8_t>(Endpoint::Type::BULK),
252 0};
253
254 SetData(RawData{reinterpret_cast<uint8_t*>(&desc_block_), sizeof(desc_block_)});
255
258
259 host_format_ok_ = false;
260
261 for (uint8_t i = 0; i < can_count_; ++i)
262 {
263 can_enabled_[i] = false;
264 berr_enabled_[i] = false;
265 fd_enabled_[i] = false;
266 term_state_[i] = GsUsb::TerminationState::OFF;
267 timestamps_enabled_ch_[i] = false;
268 }
269
270 // 注册 CAN RX 回调 / Register CAN RX callbacks
272 {
273 for (uint8_t ch = 0; ch < can_count_; ++ch)
274 {
275 if (!cans_[ch])
276 {
277 continue;
278 }
279
280 can_rx_ctx_[ch].self = this;
281 can_rx_ctx_[ch].ch = ch;
283
284 cans_[ch]->Register(can_rx_cb_[ch], LibXR::CAN::Type::STANDARD);
285 cans_[ch]->Register(can_rx_cb_[ch], LibXR::CAN::Type::EXTENDED);
288 cans_[ch]->Register(can_rx_cb_[ch], LibXR::CAN::Type::ERROR);
289 }
290 can_rx_registered_ = true;
291 }
292
294 {
295 for (uint8_t ch = 0; ch < can_count_; ++ch)
296 {
297 if (!fdcans_[ch])
298 {
299 continue;
300 }
301
302 fd_can_rx_ctx_[ch].self = this;
303 fd_can_rx_ctx_[ch].ch = ch;
304 fd_can_rx_cb_[ch] =
306
309 }
311 }
312
313 inited_ = true;
315 }
316
322 void UnbindEndpoints(EndpointPool& endpoint_pool, bool) override
323 {
324 inited_ = false;
325 host_format_ok_ = false;
326
327 for (uint8_t i = 0; i < can_count_; ++i)
328 {
329 can_enabled_[i] = false;
330 berr_enabled_[i] = false;
331 fd_enabled_[i] = false;
332 term_state_[i] = GsUsb::TerminationState::OFF;
333 timestamps_enabled_ch_[i] = false;
334 }
335
336 if (ep_data_in_)
337 {
340 endpoint_pool.Release(ep_data_in_);
341 ep_data_in_ = nullptr;
342 }
343
344 if (ep_data_out_)
345 {
348 endpoint_pool.Release(ep_data_out_);
349 ep_data_out_ = nullptr;
350 }
351 }
352
357 size_t GetInterfaceCount() override { return 1; }
358
364 bool HasIAD() override { return false; }
365
372 bool OwnsEndpoint(uint8_t ep_addr) const override
373 {
374 if (!inited_)
375 {
376 return false;
377 }
378
379 return (ep_data_in_ && ep_data_in_->GetAddress() == ep_addr) ||
380 (ep_data_out_ && ep_data_out_->GetAddress() == ep_addr);
381 }
382
387 size_t GetMaxConfigSize() override { return sizeof(desc_block_); }
388
394 ErrorCode OnClassRequest(bool, uint8_t, uint16_t, uint16_t, uint16_t,
396 {
398 }
399
410 ErrorCode OnVendorRequest(bool in_isr, uint8_t bRequest, uint16_t wValue,
411 uint16_t wLength, uint16_t wIndex,
412 DeviceClass::ControlTransferResult& result) override
413 {
414 UNUSED(in_isr);
415 UNUSED(wIndex);
416
417 auto req = static_cast<GsUsb::BReq>(bRequest);
418
419 switch (req)
420 {
421 // ===== Device -> Host =====
422 case GsUsb::BReq::BT_CONST:
423 {
424 if (wLength < sizeof(bt_const_))
425 {
426 return ErrorCode::ARG_ERR;
427 }
428 result.write_data =
429 ConstRawData{reinterpret_cast<const uint8_t*>(&bt_const_), sizeof(bt_const_)};
430 return ErrorCode::OK;
431 }
432
433 case GsUsb::BReq::BT_CONST_EXT:
434 {
435 if (!fd_supported_)
436 {
438 }
439 if (wLength < sizeof(bt_const_ext_))
440 {
441 return ErrorCode::ARG_ERR;
442 }
443 result.write_data = ConstRawData{reinterpret_cast<const uint8_t*>(&bt_const_ext_),
444 sizeof(bt_const_ext_)};
445 return ErrorCode::OK;
446 }
447
448 case GsUsb::BReq::DEVICE_CONFIG:
449 {
450 if (wLength < sizeof(dev_cfg_))
451 {
452 return ErrorCode::ARG_ERR;
453 }
454 result.write_data =
455 ConstRawData{reinterpret_cast<const uint8_t*>(&dev_cfg_), sizeof(dev_cfg_)};
456 return ErrorCode::OK;
457 }
458
459 case GsUsb::BReq::TIMESTAMP:
460 {
461 ctrl_buf_.timestamp_us = MakeTimestampUsGlobal();
462 if (wLength < sizeof(ctrl_buf_.timestamp_us))
463 {
464 return ErrorCode::ARG_ERR;
465 }
466
467 result.write_data =
468 ConstRawData{reinterpret_cast<const uint8_t*>(&ctrl_buf_.timestamp_us),
469 sizeof(ctrl_buf_.timestamp_us)};
470 return ErrorCode::OK;
471 }
472
473 case GsUsb::BReq::GET_TERMINATION:
474 {
475 if (wValue >= can_count_)
476 {
477 return ErrorCode::ARG_ERR;
478 }
479 ctrl_buf_.term.state = static_cast<uint32_t>(term_state_[wValue]);
480 if (wLength < sizeof(ctrl_buf_.term))
481 {
482 return ErrorCode::ARG_ERR;
483 }
484
485 result.write_data = ConstRawData{
486 reinterpret_cast<const uint8_t*>(&ctrl_buf_.term), sizeof(ctrl_buf_.term)};
487 return ErrorCode::OK;
488 }
489
490 case GsUsb::BReq::GET_STATE:
491 {
492 if (wValue >= can_count_)
493 {
494 return ErrorCode::ARG_ERR;
495 }
496
497 GsUsb::CanState st = GsUsb::CanState::ERROR_ACTIVE;
498 uint32_t rxerr = 0;
499 uint32_t txerr = 0;
500
501 auto* can = cans_[wValue];
502 if (can != nullptr)
503 {
505 if (can->GetErrorState(es) == ErrorCode::OK)
506 {
507 if (es.bus_off)
508 {
509 st = GsUsb::CanState::BUS_OFF;
510 }
511 else if (es.error_passive)
512 {
513 st = GsUsb::CanState::ERROR_PASSIVE;
514 }
515 else if (es.error_warning)
516 {
517 st = GsUsb::CanState::ERROR_WARNING;
518 }
519 else
520 {
521 st = GsUsb::CanState::ERROR_ACTIVE;
522 }
523
524 rxerr = es.rx_error_counter;
525 txerr = es.tx_error_counter;
526 }
527 }
528
529 ctrl_buf_.dev_state.state = static_cast<uint32_t>(st);
530 ctrl_buf_.dev_state.rxerr = rxerr;
531 ctrl_buf_.dev_state.txerr = txerr;
532
533 if (wLength < sizeof(ctrl_buf_.dev_state))
534 {
535 return ErrorCode::ARG_ERR;
536 }
537
538 result.write_data =
539 ConstRawData{reinterpret_cast<const uint8_t*>(&ctrl_buf_.dev_state),
540 sizeof(ctrl_buf_.dev_state)};
541 return ErrorCode::OK;
542 }
543
544 case GsUsb::BReq::GET_USER_ID:
545 {
547 if (wLength < sizeof(ctrl_buf_.user_id))
548 {
549 return ErrorCode::ARG_ERR;
550 }
551
552 result.write_data =
553 ConstRawData{reinterpret_cast<const uint8_t*>(&ctrl_buf_.user_id),
554 sizeof(ctrl_buf_.user_id)};
555 return ErrorCode::OK;
556 }
557
558 // ===== Host -> Device(有 DATA 阶段) / Host -> Device (with DATA stage) =====
559 case GsUsb::BReq::HOST_FORMAT:
560 {
561 if (wLength != sizeof(GsUsb::HostConfig))
562 {
563 return ErrorCode::ARG_ERR;
564 }
565 result.read_data = RawData{reinterpret_cast<uint8_t*>(&ctrl_buf_.host_cfg),
566 sizeof(GsUsb::HostConfig)};
567 return ErrorCode::OK;
568 }
569
570 case GsUsb::BReq::BITTIMING:
571 {
572 if (wLength != sizeof(GsUsb::DeviceBitTiming) || wValue >= can_count_)
573 {
574 return ErrorCode::ARG_ERR;
575 }
576 ctrl_target_channel_ = static_cast<uint8_t>(wValue);
577 result.read_data = RawData{reinterpret_cast<uint8_t*>(&ctrl_buf_.bt),
578 sizeof(GsUsb::DeviceBitTiming)};
579 return ErrorCode::OK;
580 }
581
582 case GsUsb::BReq::DATA_BITTIMING:
583 {
584 if (!fd_supported_)
585 {
587 }
588 if (wLength != sizeof(GsUsb::DeviceBitTiming) || wValue >= can_count_)
589 {
590 return ErrorCode::ARG_ERR;
591 }
592 ctrl_target_channel_ = static_cast<uint8_t>(wValue);
593 result.read_data = RawData{reinterpret_cast<uint8_t*>(&ctrl_buf_.bt),
594 sizeof(GsUsb::DeviceBitTiming)};
595 return ErrorCode::OK;
596 }
597
598 case GsUsb::BReq::MODE:
599 {
600 if (wLength != sizeof(GsUsb::DeviceMode) || wValue >= can_count_)
601 {
602 return ErrorCode::ARG_ERR;
603 }
604 ctrl_target_channel_ = static_cast<uint8_t>(wValue);
605 result.read_data = RawData{reinterpret_cast<uint8_t*>(&ctrl_buf_.mode),
606 sizeof(GsUsb::DeviceMode)};
607 return ErrorCode::OK;
608 }
609
610 case GsUsb::BReq::BERR:
611 {
612 if (wLength != sizeof(uint32_t) || wValue >= can_count_)
613 {
614 return ErrorCode::ARG_ERR;
615 }
616 ctrl_target_channel_ = static_cast<uint8_t>(wValue);
617 result.read_data =
618 RawData{reinterpret_cast<uint8_t*>(&ctrl_buf_.berr_on), sizeof(uint32_t)};
619 return ErrorCode::OK;
620 }
621
622 case GsUsb::BReq::IDENTIFY:
623 {
624 if (wLength != sizeof(GsUsb::Identify) || wValue >= can_count_)
625 {
626 return ErrorCode::ARG_ERR;
627 }
628 ctrl_target_channel_ = static_cast<uint8_t>(wValue);
629 result.read_data = RawData{reinterpret_cast<uint8_t*>(&ctrl_buf_.identify),
630 sizeof(GsUsb::Identify)};
631 return ErrorCode::OK;
632 }
633
634 case GsUsb::BReq::SET_TERMINATION:
635 {
636 if (wLength != sizeof(GsUsb::DeviceTerminationState) || wValue >= can_count_)
637 {
638 return ErrorCode::ARG_ERR;
639 }
640 ctrl_target_channel_ = static_cast<uint8_t>(wValue);
641 result.read_data = RawData{reinterpret_cast<uint8_t*>(&ctrl_buf_.term),
643 return ErrorCode::OK;
644 }
645
646 case GsUsb::BReq::SET_USER_ID:
647 {
648 if (wLength != sizeof(uint32_t))
649 {
650 return ErrorCode::ARG_ERR;
651 }
652 result.read_data =
653 RawData{reinterpret_cast<uint8_t*>(&ctrl_buf_.user_id), sizeof(uint32_t)};
654 return ErrorCode::OK;
655 }
656
657 default:
659 }
660 }
661
669 ErrorCode OnClassData(bool in_isr, uint8_t bRequest, LibXR::ConstRawData& data) override
670 {
671 UNUSED(in_isr);
672
673 auto req = static_cast<GsUsb::BReq>(bRequest);
674
675 switch (req)
676 {
677 case GsUsb::BReq::HOST_FORMAT:
678 if (data.size_ != sizeof(GsUsb::HostConfig))
679 {
680 return ErrorCode::ARG_ERR;
681 }
682 return HandleHostFormat(ctrl_buf_.host_cfg);
683
684 case GsUsb::BReq::BITTIMING:
685 if (data.size_ != sizeof(GsUsb::DeviceBitTiming))
686 {
687 return ErrorCode::ARG_ERR;
688 }
690
691 case GsUsb::BReq::DATA_BITTIMING:
692 if (!fd_supported_)
693 {
695 }
696 if (data.size_ != sizeof(GsUsb::DeviceBitTiming))
697 {
698 return ErrorCode::ARG_ERR;
699 }
701
702 case GsUsb::BReq::MODE:
703 if (data.size_ != sizeof(GsUsb::DeviceMode))
704 {
705 return ErrorCode::ARG_ERR;
706 }
708
709 case GsUsb::BReq::BERR:
710 if (data.size_ != sizeof(uint32_t))
711 {
712 return ErrorCode::ARG_ERR;
713 }
715
716 case GsUsb::BReq::IDENTIFY:
717 if (data.size_ != sizeof(GsUsb::Identify))
718 {
719 return ErrorCode::ARG_ERR;
720 }
722
723 case GsUsb::BReq::SET_TERMINATION:
724 if (data.size_ != sizeof(GsUsb::DeviceTerminationState))
725 {
726 return ErrorCode::ARG_ERR;
727 }
729
730 case GsUsb::BReq::SET_USER_ID:
731 if (data.size_ != sizeof(uint32_t))
732 {
733 return ErrorCode::ARG_ERR;
734 }
736 return ErrorCode::OK;
737
738 case GsUsb::BReq::DEVICE_CONFIG:
739 case GsUsb::BReq::BT_CONST:
740 case GsUsb::BReq::BT_CONST_EXT:
741 case GsUsb::BReq::TIMESTAMP:
742 case GsUsb::BReq::GET_TERMINATION:
743 case GsUsb::BReq::GET_STATE:
744 case GsUsb::BReq::GET_USER_ID:
745 return ErrorCode::OK;
746
747 default:
749 }
750 }
751
752 // ================= Bulk 端点回调 / Bulk endpoint callbacks =================
753
760 static void OnDataOutCompleteStatic(bool in_isr, GsUsbClass* self, ConstRawData& data)
761 {
762 if (self == nullptr || !self->inited_)
763 {
764 return;
765 }
766 self->OnDataOutComplete(in_isr, data);
767 }
768
775 static void OnDataInCompleteStatic(bool in_isr, GsUsbClass* self, ConstRawData& data)
776 {
777 if (self == nullptr || !self->inited_)
778 {
779 return;
780 }
781 self->OnDataInComplete(in_isr, data);
782 }
783
789 void OnDataOutComplete(bool in_isr, ConstRawData& data)
790 {
791 UNUSED(in_isr);
792
793 if (!ep_data_out_)
794 {
795 return;
796 }
797 if (!host_format_ok_)
798 {
800 return;
801 }
802
803 const std::size_t RXLEN = data.size_;
804 if (RXLEN < WIRE_CLASSIC_SIZE)
805 {
807 return;
808 }
809
810 // 解析 wire header / Parse wire header
811 const WireHeader& wh = *reinterpret_cast<const WireHeader*>(data.addr_);
812
813 const uint8_t CH = wh.channel;
814 if (CH >= can_count_ || !cans_[CH])
815 {
817 return;
818 }
819
820 const bool IS_FD = (wh.flags & GsUsb::CAN_FLAG_FD) != 0;
821 const uint8_t* payload = reinterpret_cast<const uint8_t*>(data.addr_) + WIRE_HDR_SIZE;
822
823 if (IS_FD)
824 {
825 if (!fd_supported_ || !fdcans_[CH] || !fd_enabled_[CH])
826 {
828 return;
829 }
830
831 if (RXLEN < WIRE_FD_SIZE)
832 {
834 return;
835 }
836
838 HostWireToFdPack(wh, payload, pack);
839 (void)fdcans_[CH]->AddMessage(pack);
840 }
841 else
842 {
843 if (!can_enabled_[CH])
844 {
846 return;
847 }
848
849 if (RXLEN < WIRE_CLASSIC_SIZE)
850 {
852 return;
853 }
854
856 HostWireToClassicPack(wh, payload, pack);
857 (void)cans_[CH]->AddMessage(pack);
858 }
859
860 // TX echo:host 通过 echo_id 跟踪 TX buffer;设备需回送 echo_id。
861 // TX echo: the host tracks TX buffers via echo_id, and the device should echo it
862 // back.
863 if (wh.echo_id != ECHO_ID_RX)
864 {
865 QueueItem qi;
866 qi.hdr = wh;
867 qi.is_fd = IS_FD;
868 qi.data_len = IS_FD ? 64u : 8u;
870 Memory::FastCopy(qi.data.data(), payload, qi.data_len);
871 (void)EnqueueFrame(qi, true, in_isr);
872 }
873
875 }
876
882 void OnDataInComplete(bool in_isr, ConstRawData& data)
883 {
884 UNUSED(in_isr);
885 UNUSED(data);
886 TryKickTx(false);
887 }
888
889 private:
890 // ================= 成员 / Members =================
891 std::array<LibXR::CAN*, CanChNum> cans_{};
892 std::array<LibXR::FDCAN*, CanChNum>
894 bool fd_supported_ = false;
895
896 uint8_t can_count_ = CAN_CH_NUM;
897
900
903
904 bool inited_ = false;
905 uint8_t interface_num_ = 0;
906 const char* interface_string_ = nullptr;
907
909 nullptr;
910 std::array<LibXR::GPIO*, CanChNum>
912
915 uint32_t user_id_ram_ = 0;
916
919 this);
920
923 this);
924
929
933 union
934 {
938 uint32_t berr_on;
940 uint32_t timestamp_us;
943 uint32_t user_id;
945
946 std::array<LibXR::CAN::Configuration, CanChNum>
948 std::array<LibXR::FDCAN::Configuration, CanChNum>
950
951 bool host_format_ok_ = false;
952
953 bool can_enabled_[CanChNum] = {
954 false};
955 bool berr_enabled_[CanChNum] = {false};
956 bool fd_enabled_[CanChNum] = {false};
957
958 bool timestamps_enabled_ch_[CanChNum] = {
959 false};
960 GsUsb::TerminationState term_state_[CanChNum] = {
961 GsUsb::TerminationState::OFF};
963 0;
964
965 LIBXR_PACKED_BEGIN
975 LIBXR_PACKED_END
976
978 std::array<uint8_t, WIRE_MAX_SIZE>
980
981 // ================= CAN RX 回调 & BULK IN 发送队列 / CAN RX callbacks & Bulk IN TX
982 // queues =================
983
987 struct CanRxCtx
988 {
990 uint8_t ch;
991 };
992
997 {
999 uint8_t ch;
1000 };
1001
1003 false;
1004 CanRxCtx can_rx_ctx_[CanChNum]{};
1006 can_rx_cb_[CanChNum]{};
1007
1009 false;
1012 fd_can_rx_cb_[CanChNum]{};
1013
1017 static void OnCanRxStatic(bool in_isr, CanRxCtx* ctx,
1018 const LibXR::CAN::ClassicPack& pack)
1019 {
1020 if (!ctx || !ctx->self || !ctx->self->inited_)
1021 {
1022 return;
1023 }
1024 ctx->self->OnCanRx(in_isr, ctx->ch, pack);
1025 }
1026
1030 static void OnFdCanRxStatic(bool in_isr, FdCanRxCtx* ctx,
1031 const LibXR::FDCAN::FDPack& pack)
1032 {
1033 if (!ctx || !ctx->self || !ctx->self->inited_)
1034 {
1035 return;
1036 }
1037 ctx->self->OnFdCanRx(in_isr, ctx->ch, pack);
1038 }
1039
1045 {
1047 bool is_fd;
1048 uint8_t data_len;
1049 uint32_t timestamp_us;
1050 std::array<uint8_t, 64> data;
1051 };
1052
1057
1061 void OnCanRx(bool in_isr, uint8_t ch, const LibXR::CAN::ClassicPack& pack)
1062 {
1063 if (ch >= can_count_ || !ep_data_in_)
1064 {
1065 return;
1066 }
1067
1068 if (pack.type == LibXR::CAN::Type::ERROR)
1069 {
1070 QueueItem qi;
1071 if (ErrorPackToHostErrorFrame(ch, pack, qi))
1072 {
1073 (void)EnqueueFrame(qi, false, in_isr);
1074 }
1075 return;
1076 }
1077
1078 if (!can_enabled_[ch])
1079 {
1080 return;
1081 }
1082
1083 QueueItem qi;
1084 ClassicPackToQueueItem(pack, ch, qi);
1085 (void)EnqueueFrame(qi, false, in_isr);
1086 }
1087
1091 void OnFdCanRx(bool in_isr, uint8_t ch, const LibXR::FDCAN::FDPack& pack)
1092 {
1093 if (!fd_supported_ || ch >= can_count_ || !fd_enabled_[ch] || !ep_data_in_)
1094 {
1095 return;
1096 }
1097
1098 QueueItem qi;
1099 FdPackToQueueItem(pack, ch, qi);
1100
1101 const auto& fd_cfg = fd_config_[ch];
1102 if (fd_cfg.fd_mode.brs)
1103 {
1104 qi.hdr.flags |= GsUsb::CAN_FLAG_BRS;
1105 }
1106 if (fd_cfg.fd_mode.esi)
1107 {
1108 qi.hdr.flags |= GsUsb::CAN_FLAG_ESI;
1109 }
1110
1111 (void)EnqueueFrame(qi, false, in_isr);
1112 }
1113
1122 bool EnqueueFrame(const QueueItem& qi, bool is_echo, bool in_isr)
1123 {
1124 UNUSED(in_isr);
1125
1126 const ErrorCode EC = is_echo ? echo_queue_.Push(qi) : rx_queue_.Push(qi);
1127 if (EC != ErrorCode::OK)
1128 {
1129 return false;
1130 }
1131
1132 TryKickTx(in_isr);
1134 return true;
1135 }
1136
1141 void TryKickTx(bool in_isr)
1142 {
1143 UNUSED(in_isr);
1144
1145 if (!ep_data_in_)
1146 {
1147 return;
1148 }
1150 {
1151 return;
1152 }
1153
1154 QueueItem qi;
1155 ErrorCode ec = echo_queue_.Pop(qi);
1156 if (ec != ErrorCode::OK)
1157 {
1158 ec = rx_queue_.Pop(qi);
1159 if (ec != ErrorCode::OK)
1160 {
1161 return;
1162 }
1163 }
1164
1165 const std::size_t SEND_LEN = PackQueueItemToWire(qi, tx_buf_.data(), tx_buf_.size());
1166 if (SEND_LEN == 0)
1167 {
1168 return;
1169 }
1170
1171 RawData tx_raw{tx_buf_.data(), SEND_LEN};
1172 (void)ep_data_in_->TransferMultiBulk(tx_raw);
1173
1175 }
1176
1181 {
1182 if (!ep_data_out_)
1183 {
1184 return;
1185 }
1187 {
1188 return;
1189 }
1190
1191 if (rx_queue_.EmptySize() == 0 || echo_queue_.EmptySize() == 0)
1192 {
1193 return;
1194 }
1195
1196 RawData rx_raw{rx_buf_, static_cast<size_t>(WIRE_MAX_SIZE)};
1197 (void)ep_data_out_->TransferMultiBulk(rx_raw);
1198 }
1199
1200 // ================= 业务处理函数 / Handlers =================
1201
1208 {
1209 for (uint8_t i = 0; i < can_count_; ++i)
1210 {
1211 if (termination_gpios_[i] != nullptr)
1212 {
1213 return true;
1214 }
1215 }
1216 return false;
1217 }
1218
1224 {
1225 can_count_ = CAN_CH_NUM;
1226 ASSERT(can_count_ > 0);
1227 ASSERT(cans_[0] != nullptr);
1228
1229 dev_cfg_.reserved1 = 0;
1230 dev_cfg_.reserved2 = 0;
1231 dev_cfg_.reserved3 = 0;
1232 dev_cfg_.icount = static_cast<uint8_t>(can_count_ - 1);
1233 dev_cfg_.sw_version = 2;
1234 dev_cfg_.hw_version = 1;
1235
1236 const uint32_t FCLK = cans_[0]->GetClockFreq();
1237
1238 bt_const_.feature = GsUsb::CAN_FEAT_LISTEN_ONLY | GsUsb::CAN_FEAT_LOOP_BACK |
1239 GsUsb::CAN_FEAT_TRIPLE_SAMPLE | GsUsb::CAN_FEAT_ONE_SHOT |
1240 GsUsb::CAN_FEAT_HW_TIMESTAMP | GsUsb::CAN_FEAT_BERR_REPORTING |
1241 GsUsb::CAN_FEAT_GET_STATE | GsUsb::CAN_FEAT_USER_ID;
1242
1243 if (identify_gpio_)
1244 {
1245 bt_const_.feature |= GsUsb::CAN_FEAT_IDENTIFY;
1246 }
1248 {
1249 bt_const_.feature |= GsUsb::CAN_FEAT_TERMINATION;
1250 }
1251
1252 bt_const_.fclk_can = FCLK;
1254 bt_const_.btc.tseg1_max = 16;
1257 bt_const_.btc.sjw_max = 4;
1258 bt_const_.btc.brp_min = 1;
1259 bt_const_.btc.brp_max = 1024;
1260 bt_const_.btc.brp_inc = 1;
1261
1263 bt_const_ext_.fclk_can = FCLK;
1266
1267 Memory::FastSet(config_.data(), 0, sizeof(config_));
1268 Memory::FastSet(fd_config_.data(), 0, sizeof(fd_config_));
1269 }
1270
1275 {
1276 can_count_ = CAN_CH_NUM;
1277 ASSERT(can_count_ > 0);
1278 ASSERT(cans_[0] != nullptr);
1279
1280 dev_cfg_.reserved1 = 0;
1281 dev_cfg_.reserved2 = 0;
1282 dev_cfg_.reserved3 = 0;
1283 dev_cfg_.icount = static_cast<uint8_t>(can_count_ - 1);
1284 dev_cfg_.sw_version = 2;
1285 dev_cfg_.hw_version = 1;
1286
1287 const uint32_t FCLK = cans_[0]->GetClockFreq();
1288
1289 bt_const_.feature = GsUsb::CAN_FEAT_LISTEN_ONLY | GsUsb::CAN_FEAT_LOOP_BACK |
1290 GsUsb::CAN_FEAT_TRIPLE_SAMPLE | GsUsb::CAN_FEAT_ONE_SHOT |
1291 GsUsb::CAN_FEAT_HW_TIMESTAMP | GsUsb::CAN_FEAT_BERR_REPORTING |
1292 GsUsb::CAN_FEAT_GET_STATE | GsUsb::CAN_FEAT_USER_ID |
1293 GsUsb::CAN_FEAT_FD | GsUsb::CAN_FEAT_BT_CONST_EXT;
1294
1295 if (identify_gpio_)
1296 {
1297 bt_const_.feature |= GsUsb::CAN_FEAT_IDENTIFY;
1298 }
1300 {
1301 bt_const_.feature |= GsUsb::CAN_FEAT_TERMINATION;
1302 }
1303
1304 bt_const_.fclk_can = FCLK;
1306 bt_const_.btc.tseg1_max = 16;
1309 bt_const_.btc.sjw_max = 4;
1310 bt_const_.btc.brp_min = 1;
1311 bt_const_.btc.brp_max = 1024;
1312 bt_const_.btc.brp_inc = 1;
1313
1315 bt_const_ext_.fclk_can = FCLK;
1318
1319 Memory::FastSet(config_.data(), 0, sizeof(config_));
1320 Memory::FastSet(fd_config_.data(), 0, sizeof(fd_config_));
1321 }
1322
1329 {
1330 host_format_ok_ = (cfg.byte_order == 0x0000beefu);
1331 return ErrorCode::OK;
1332 }
1333
1338 {
1339 if (!host_format_ok_ || ch >= can_count_ || !cans_[ch])
1340 {
1341 return ErrorCode::ARG_ERR;
1342 }
1343
1344 const uint32_t TSEG1 = bt.prop_seg + bt.phase_seg1;
1345 const uint32_t TSEG2 = bt.phase_seg2;
1346 const uint32_t TQ_NUM = 1u + TSEG1 + TSEG2;
1347
1348 const uint32_t FCLK = cans_[ch]->GetClockFreq();
1349
1350 auto& cfg = config_[ch];
1351 cfg.bit_timing.brp = bt.brp;
1352 cfg.bit_timing.prop_seg = bt.prop_seg;
1353 cfg.bit_timing.phase_seg1 = bt.phase_seg1;
1354 cfg.bit_timing.phase_seg2 = bt.phase_seg2;
1355 cfg.bit_timing.sjw = bt.sjw;
1356
1357 if (bt.brp != 0u && TQ_NUM != 0u)
1358 {
1359 cfg.bitrate = FCLK / (bt.brp * TQ_NUM);
1360 cfg.sample_point = static_cast<float>(1u + TSEG1) / static_cast<float>(TQ_NUM);
1361 }
1362 else
1363 {
1364 cfg.bitrate = 0;
1365 cfg.sample_point = 0.0f;
1366 }
1367
1368 if (fd_supported_ && fdcans_[ch])
1369 {
1370 auto& fd_cfg = fd_config_[ch];
1371 static_cast<CAN::Configuration&>(fd_cfg) = cfg;
1372 }
1373
1374 return cans_[ch]->SetConfig(cfg);
1375 }
1376
1381 {
1382 if (!host_format_ok_)
1383 {
1384 return ErrorCode::ARG_ERR;
1385 }
1386 if (!fd_supported_ || ch >= can_count_ || !fdcans_[ch])
1387 {
1389 }
1390
1391 const uint32_t TSEG1 = bt.prop_seg + bt.phase_seg1;
1392 const uint32_t TSEG2 = bt.phase_seg2;
1393 const uint32_t TQ_NUM = 1u + TSEG1 + TSEG2;
1394
1395 const uint32_t FCLK = fdcans_[ch]->GetClockFreq();
1396
1397 auto& fd_cfg = fd_config_[ch];
1398 static_cast<CAN::Configuration&>(fd_cfg) = config_[ch];
1399
1400 fd_cfg.data_timing.brp = bt.brp;
1401 fd_cfg.data_timing.prop_seg = bt.prop_seg;
1402 fd_cfg.data_timing.phase_seg1 = bt.phase_seg1;
1403 fd_cfg.data_timing.phase_seg2 = bt.phase_seg2;
1404 fd_cfg.data_timing.sjw = bt.sjw;
1405
1406 if (bt.brp != 0u && TQ_NUM != 0u)
1407 {
1408 fd_cfg.data_bitrate = FCLK / (bt.brp * TQ_NUM);
1409 fd_cfg.data_sample_point =
1410 static_cast<float>(1u + TSEG1) / static_cast<float>(TQ_NUM);
1411 }
1412 else
1413 {
1414 fd_cfg.data_bitrate = 0;
1415 fd_cfg.data_sample_point = 0.0f;
1416 }
1417
1418 return fdcans_[ch]->SetConfig(fd_cfg);
1419 }
1420
1425 {
1426 if (!host_format_ok_ || ch >= can_count_ || !cans_[ch])
1427 {
1428 return ErrorCode::ARG_ERR;
1429 }
1430
1431 switch (static_cast<GsUsb::CanMode>(mode.mode))
1432 {
1433 case GsUsb::CanMode::RESET:
1434 can_enabled_[ch] = false;
1435 fd_enabled_[ch] = false;
1436 break;
1437
1438 case GsUsb::CanMode::START:
1439 can_enabled_[ch] = true;
1440 if (fd_supported_ && fdcans_[ch] && (mode.flags & GsUsb::GSCAN_MODE_FD))
1441 {
1442 fd_enabled_[ch] = true;
1443 }
1444 break;
1445
1446 default:
1447 return ErrorCode::ARG_ERR;
1448 }
1449
1450 auto& cfg = config_[ch];
1451 cfg.mode.loopback = (mode.flags & GsUsb::GSCAN_MODE_LOOP_BACK) != 0;
1452 cfg.mode.listen_only = (mode.flags & GsUsb::GSCAN_MODE_LISTEN_ONLY) != 0;
1453 cfg.mode.triple_sampling = (mode.flags & GsUsb::GSCAN_MODE_TRIPLE_SAMPLE) != 0;
1454 cfg.mode.one_shot = (mode.flags & GsUsb::GSCAN_MODE_ONE_SHOT) != 0;
1455
1456 timestamps_enabled_ch_[ch] = (mode.flags & GsUsb::GSCAN_MODE_HW_TIMESTAMP) != 0;
1457 berr_enabled_[ch] = (mode.flags & GsUsb::GSCAN_MODE_BERR_REPORTING) != 0;
1458
1459 const ErrorCode EC = cans_[ch]->SetConfig(cfg);
1460
1461 if (fd_supported_ && fdcans_[ch])
1462 {
1463 auto& fd_cfg = fd_config_[ch];
1464 static_cast<CAN::Configuration&>(fd_cfg) = cfg;
1465 fd_cfg.fd_mode.fd_enabled = (mode.flags & GsUsb::GSCAN_MODE_FD) != 0;
1466 (void)fdcans_[ch]->SetConfig(fd_cfg);
1467 }
1468
1469 return EC;
1470 }
1471
1475 ErrorCode HandleBerr(uint8_t ch, uint32_t berr_on)
1476 {
1477 if (ch >= can_count_)
1478 {
1479 return ErrorCode::ARG_ERR;
1480 }
1481 berr_enabled_[ch] = (berr_on != 0);
1482 return ErrorCode::OK;
1483 }
1484
1489 {
1490 const bool ON = (id.mode == static_cast<uint32_t>(GsUsb::IdentifyMode::ON));
1491 if (identify_gpio_)
1492 {
1493 (void)identify_gpio_->Write(ON);
1494 }
1495 return ErrorCode::OK;
1496 }
1497
1502 {
1503 if (ch >= can_count_)
1504 {
1505 return ErrorCode::ARG_ERR;
1506 }
1507
1508 term_state_[ch] = static_cast<GsUsb::TerminationState>(
1509 st.state != 0 ? static_cast<uint32_t>(GsUsb::TerminationState::ON)
1510 : static_cast<uint32_t>(GsUsb::TerminationState::OFF));
1511
1512 if (termination_gpios_[ch])
1513 {
1514 const bool ON = (term_state_[ch] == GsUsb::TerminationState::ON);
1515 (void)termination_gpios_[ch]->Write(ON);
1516 }
1517
1518 return ErrorCode::OK;
1519 }
1520
1524 static void HostWireToClassicPack(const WireHeader& wh, const uint8_t* payload,
1526 {
1527 const uint32_t CID = wh.can_id;
1528 const bool IS_EFF = (CID & GsUsb::CAN_EFF_FLAG) != 0;
1529 const bool IS_RTR = (CID & GsUsb::CAN_RTR_FLAG) != 0;
1530
1531 if (IS_EFF)
1532 {
1533 pack.id = CID & GsUsb::CAN_EFF_MASK;
1535 }
1536 else
1537 {
1538 pack.id = CID & GsUsb::CAN_SFF_MASK;
1540 }
1541
1542 uint8_t dlc = wh.can_dlc;
1543 if (dlc > 8u)
1544 {
1545 dlc = 8u;
1546 }
1547 pack.dlc = dlc;
1548
1549 if (dlc > 0u)
1550 {
1551 Memory::FastCopy(pack.data, payload, dlc);
1552 }
1553 }
1554
1558 static void HostWireToFdPack(const WireHeader& wh, const uint8_t* payload,
1560 {
1561 const uint32_t CID = wh.can_id;
1562 const bool IS_EFF = (CID & GsUsb::CAN_EFF_FLAG) != 0;
1563 const bool IS_RTR = (CID & GsUsb::CAN_RTR_FLAG) != 0;
1564
1565 if (IS_EFF)
1566 {
1567 pack.id = CID & GsUsb::CAN_EFF_MASK;
1569 }
1570 else
1571 {
1572 pack.id = CID & GsUsb::CAN_SFF_MASK;
1574 }
1575
1576 uint8_t len = DlcToLen(wh.can_dlc);
1577 if (len > 64)
1578 {
1579 len = 64;
1580 }
1581 pack.len = len;
1582
1583 if (len > 0u)
1584 {
1585 Memory::FastCopy(pack.data, payload, len);
1586 }
1587 }
1588
1593 QueueItem& qi)
1594 {
1595 uint32_t cid = 0;
1596 switch (pack.type)
1597 {
1599 cid = (pack.id & GsUsb::CAN_SFF_MASK);
1600 break;
1602 cid = (pack.id & GsUsb::CAN_EFF_MASK) | GsUsb::CAN_EFF_FLAG;
1603 break;
1605 cid = (pack.id & GsUsb::CAN_SFF_MASK) | GsUsb::CAN_RTR_FLAG;
1606 break;
1608 cid = (pack.id & GsUsb::CAN_EFF_MASK) | GsUsb::CAN_EFF_FLAG | GsUsb::CAN_RTR_FLAG;
1609 break;
1610 default:
1611 cid = pack.id & GsUsb::CAN_SFF_MASK;
1612 break;
1613 }
1614
1615 qi.hdr.echo_id = ECHO_ID_RX;
1616 qi.hdr.can_id = cid;
1617 qi.hdr.can_dlc = (pack.dlc <= 8u) ? pack.dlc : 8u;
1618 qi.hdr.channel = ch;
1619 qi.hdr.flags = 0;
1620 qi.hdr.reserved = 0;
1621
1622 qi.is_fd = false;
1623 qi.data_len = 8;
1625
1626 Memory::FastSet(qi.data.data(), 0, 8);
1627 if (qi.hdr.can_dlc > 0u)
1628 {
1629 Memory::FastCopy(qi.data.data(), pack.data, qi.hdr.can_dlc);
1630 }
1631 }
1632
1636 void FdPackToQueueItem(const LibXR::FDCAN::FDPack& pack, uint8_t ch, QueueItem& qi)
1637 {
1638 uint32_t cid = 0;
1639 switch (pack.type)
1640 {
1642 cid = (pack.id & GsUsb::CAN_SFF_MASK);
1643 break;
1645 cid = (pack.id & GsUsb::CAN_EFF_MASK) | GsUsb::CAN_EFF_FLAG;
1646 break;
1648 cid = (pack.id & GsUsb::CAN_SFF_MASK) | GsUsb::CAN_RTR_FLAG;
1649 break;
1651 cid = (pack.id & GsUsb::CAN_EFF_MASK) | GsUsb::CAN_EFF_FLAG | GsUsb::CAN_RTR_FLAG;
1652 break;
1653 default:
1654 cid = pack.id & GsUsb::CAN_SFF_MASK;
1655 break;
1656 }
1657
1658 qi.hdr.echo_id = ECHO_ID_RX;
1659 qi.hdr.can_id = cid;
1660 qi.hdr.can_dlc = LenToDlc(pack.len);
1661 qi.hdr.channel = ch;
1662 qi.hdr.flags = GsUsb::CAN_FLAG_FD;
1663 qi.hdr.reserved = 0;
1664
1665 qi.is_fd = true;
1666 qi.data_len = 64;
1668
1669 const uint8_t LEN = (pack.len <= 64) ? pack.len : 64;
1670
1671 if (LEN > 0u)
1672 {
1673 Memory::FastCopy(qi.data.data(), pack.data, LEN);
1674 }
1675 if (LEN < 64u)
1676 {
1677 Memory::FastSet(qi.data.data() + LEN, 0, 64u - LEN);
1678 }
1679 }
1680
1688 std::size_t PackQueueItemToWire(const QueueItem& qi, uint8_t* out,
1689 std::size_t cap) const
1690 {
1691 if (cap < WIRE_HDR_SIZE)
1692 {
1693 return 0;
1694 }
1695
1696 const uint8_t CH = qi.hdr.channel;
1697 const bool TS = (CH < can_count_) ? timestamps_enabled_ch_[CH] : false;
1698 const std::size_t PAYLOAD = qi.is_fd ? WIRE_FD_DATA_SIZE : WIRE_CLASSIC_DATA_SIZE;
1699 const std::size_t TOTAL = WIRE_HDR_SIZE + PAYLOAD + (TS ? WIRE_TS_SIZE : 0);
1700
1701 if (TOTAL > cap)
1702 {
1703 return 0;
1704 }
1705
1707 Memory::FastCopy(out + WIRE_HDR_SIZE, qi.data.data(), PAYLOAD);
1708
1709 if (TS)
1710 {
1712 }
1713
1714 return TOTAL;
1715 }
1716
1726 bool ErrorPackToHostErrorFrame(uint8_t ch, const LibXR::CAN::ClassicPack& err_pack,
1727 QueueItem& qi)
1728 {
1729 if (ch >= can_count_ || !cans_[ch])
1730 {
1731 return false;
1732 }
1733 if (!berr_enabled_[ch])
1734 {
1735 return false;
1736 }
1737 if (!LibXR::CAN::IsErrorId(err_pack.id))
1738 {
1739 return false;
1740 }
1741
1742 // 与 Linux can/error.h 对齐(沿用之前版本的映射)。
1743 // Keep these definitions aligned with Linux can/error.h, matching the previous
1744 // mapping.
1745 constexpr uint8_t LNX_CAN_ERR_CRTL_UNSPEC = 0x00;
1746 constexpr uint8_t LNX_CAN_ERR_CRTL_RX_WARNING = 0x04;
1747 constexpr uint8_t LNX_CAN_ERR_CRTL_TX_WARNING = 0x08;
1748 constexpr uint8_t LNX_CAN_ERR_CRTL_RX_PASSIVE = 0x10;
1749 constexpr uint8_t LNX_CAN_ERR_CRTL_TX_PASSIVE = 0x20;
1750
1751 constexpr uint8_t LNX_CAN_ERR_PROT_UNSPEC = 0x00;
1752 constexpr uint8_t LNX_CAN_ERR_PROT_FORM = 0x02;
1753 constexpr uint8_t LNX_CAN_ERR_PROT_STUFF = 0x04;
1754 constexpr uint8_t LNX_CAN_ERR_PROT_BIT0 = 0x08;
1755 constexpr uint8_t LNX_CAN_ERR_PROT_BIT1 = 0x10;
1756 constexpr uint8_t LNX_CAN_ERR_PROT_TX = 0x80;
1757
1758 constexpr uint8_t LNX_CAN_ERR_PROT_LOC_UNSPEC = 0x00;
1759 constexpr uint8_t LNX_CAN_ERR_PROT_LOC_ACK = 0x19;
1760
1761 constexpr uint32_t LNX_CAN_ERR_CNT = 0x00000200U;
1762
1763 bool ec_valid = false;
1764 uint32_t txerr = 0, rxerr = 0;
1765 {
1767 if (cans_[ch]->GetErrorState(es) == ErrorCode::OK)
1768 {
1769 ec_valid = true;
1770 txerr = es.tx_error_counter;
1771 rxerr = es.rx_error_counter;
1772 }
1773 }
1774
1775 const uint8_t TXERR_U8 = (txerr > 255U) ? 255U : static_cast<uint8_t>(txerr);
1776 const uint8_t RXERR_U8 = (rxerr > 255U) ? 255U : static_cast<uint8_t>(rxerr);
1777
1778 const auto EID = LibXR::CAN::ToErrorID(err_pack.id);
1779
1780 uint32_t cid = GsUsb::CAN_ERR_FLAG;
1781 std::array<uint8_t, 8> d{};
1782 switch (EID)
1783 {
1784 case LibXR::CAN::ErrorID::CAN_ERROR_ID_BUS_OFF:
1785 cid |= GsUsb::CAN_ERR_BUSOFF;
1786 break;
1787
1788 case LibXR::CAN::ErrorID::CAN_ERROR_ID_ERROR_WARNING:
1789 case LibXR::CAN::ErrorID::CAN_ERROR_ID_ERROR_PASSIVE:
1790 {
1791 cid |= GsUsb::CAN_ERR_CRTL;
1792 uint8_t ctrl = LNX_CAN_ERR_CRTL_UNSPEC;
1793
1794 if (ec_valid)
1795 {
1796 if (EID == LibXR::CAN::ErrorID::CAN_ERROR_ID_ERROR_PASSIVE)
1797 {
1798 if (txerr >= 128U)
1799 {
1800 ctrl |= LNX_CAN_ERR_CRTL_TX_PASSIVE;
1801 }
1802 if (rxerr >= 128U)
1803 {
1804 ctrl |= LNX_CAN_ERR_CRTL_RX_PASSIVE;
1805 }
1806 }
1807 else
1808 {
1809 if (txerr >= 96U)
1810 {
1811 ctrl |= LNX_CAN_ERR_CRTL_TX_WARNING;
1812 }
1813 if (rxerr >= 96U)
1814 {
1815 ctrl |= LNX_CAN_ERR_CRTL_RX_WARNING;
1816 }
1817 }
1818 }
1819
1820 if (ctrl == LNX_CAN_ERR_CRTL_UNSPEC)
1821 {
1822 ctrl = (EID == LibXR::CAN::ErrorID::CAN_ERROR_ID_ERROR_PASSIVE)
1823 ? static_cast<uint8_t>(LNX_CAN_ERR_CRTL_TX_PASSIVE |
1824 LNX_CAN_ERR_CRTL_RX_PASSIVE)
1825 : static_cast<uint8_t>(LNX_CAN_ERR_CRTL_TX_WARNING |
1826 LNX_CAN_ERR_CRTL_RX_WARNING);
1827 }
1828
1829 d[1] = ctrl;
1830 break;
1831 }
1832
1833 case LibXR::CAN::ErrorID::CAN_ERROR_ID_ACK:
1834 cid |= GsUsb::CAN_ERR_ACK;
1835 cid |= GsUsb::CAN_ERR_PROT;
1836 d[2] = static_cast<uint8_t>(LNX_CAN_ERR_PROT_UNSPEC | LNX_CAN_ERR_PROT_TX);
1837 d[3] = LNX_CAN_ERR_PROT_LOC_ACK;
1838 break;
1839
1840 case LibXR::CAN::ErrorID::CAN_ERROR_ID_STUFF:
1841 cid |= GsUsb::CAN_ERR_PROT;
1842 d[2] = static_cast<uint8_t>(LNX_CAN_ERR_PROT_STUFF | LNX_CAN_ERR_PROT_TX);
1843 d[3] = LNX_CAN_ERR_PROT_LOC_UNSPEC;
1844 break;
1845
1846 case LibXR::CAN::ErrorID::CAN_ERROR_ID_FORM:
1847 cid |= GsUsb::CAN_ERR_PROT;
1848 d[2] = static_cast<uint8_t>(LNX_CAN_ERR_PROT_FORM | LNX_CAN_ERR_PROT_TX);
1849 d[3] = LNX_CAN_ERR_PROT_LOC_UNSPEC;
1850 break;
1851
1852 case LibXR::CAN::ErrorID::CAN_ERROR_ID_BIT0:
1853 cid |= GsUsb::CAN_ERR_PROT;
1854 d[2] = static_cast<uint8_t>(LNX_CAN_ERR_PROT_BIT0 | LNX_CAN_ERR_PROT_TX);
1855 d[3] = LNX_CAN_ERR_PROT_LOC_UNSPEC;
1856 break;
1857
1858 case LibXR::CAN::ErrorID::CAN_ERROR_ID_BIT1:
1859 cid |= GsUsb::CAN_ERR_PROT;
1860 d[2] = static_cast<uint8_t>(LNX_CAN_ERR_PROT_BIT1 | LNX_CAN_ERR_PROT_TX);
1861 d[3] = LNX_CAN_ERR_PROT_LOC_UNSPEC;
1862 break;
1863
1864 default:
1865 cid |= GsUsb::CAN_ERR_PROT;
1866 d[2] = static_cast<uint8_t>(LNX_CAN_ERR_PROT_UNSPEC | LNX_CAN_ERR_PROT_TX);
1867 d[3] = LNX_CAN_ERR_PROT_LOC_UNSPEC;
1868 break;
1869 }
1870
1871 cid |= LNX_CAN_ERR_CNT;
1872 d[6] = TXERR_U8;
1873 d[7] = RXERR_U8;
1874
1875 qi.hdr.echo_id = ECHO_ID_RX;
1876 qi.hdr.can_id = cid;
1877 qi.hdr.can_dlc = GsUsb::CAN_ERR_DLC;
1878 qi.hdr.channel = ch;
1879 qi.hdr.flags = 0;
1880 qi.hdr.reserved = 0;
1881
1882 qi.is_fd = false;
1883 qi.data_len = 8;
1885
1886 Memory::FastCopy(qi.data.data(), d.data(), 8);
1887
1888 return true;
1889 }
1890
1891 // ================= 工具函数 / Utilities =================
1892
1898 uint32_t MakeTimestampUs(uint8_t ch) const
1899 {
1900 if (ch < can_count_ && timestamps_enabled_ch_[ch])
1901 {
1902 return static_cast<uint32_t>(LibXR::Timebase::GetMicroseconds() & 0xFFFFFFFFu);
1903 }
1904 return 0u;
1905 }
1906
1911 uint32_t MakeTimestampUsGlobal() const
1912 {
1913 return static_cast<uint32_t>(LibXR::Timebase::GetMicroseconds() & 0xFFFFFFFFu);
1914 }
1915
1919 static uint8_t DlcToLen(uint8_t dlc)
1920 {
1921 static constexpr uint8_t TABLE[16] = {0, 1, 2, 3, 4, 5, 6, 7,
1922 8, 12, 16, 20, 24, 32, 48, 64};
1923 return (dlc < 16) ? TABLE[dlc] : 64;
1924 }
1925
1929 static uint8_t LenToDlc(uint8_t len)
1930 {
1931 if (len <= 8)
1932 {
1933 return len;
1934 }
1935 if (len <= 12)
1936 {
1937 return 9;
1938 }
1939 if (len <= 16)
1940 {
1941 return 10;
1942 }
1943 if (len <= 20)
1944 {
1945 return 11;
1946 }
1947 if (len <= 24)
1948 {
1949 return 12;
1950 }
1951 if (len <= 32)
1952 {
1953 return 13;
1954 }
1955 if (len <= 48)
1956 {
1957 return 14;
1958 }
1959 return 15;
1960 }
1961
1966 uint32_t GetUserIdFromStorage() const
1967 {
1968 if (database_ == nullptr)
1969 {
1970 return user_id_ram_;
1971 }
1972
1974 return static_cast<uint32_t>(key);
1975 }
1976
1981 void SetUserIdToStorage(uint32_t value)
1982 {
1983 user_id_ram_ = value;
1984
1985 if (database_ == nullptr)
1986 {
1987 return;
1988 }
1989
1990 LibXR::Database::Key<uint32_t> key(*database_, "user_id", 0u);
1991 (void)key.Set(value);
1992 }
1993};
1994
1995} // 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:143
static Callback Create(CallableType fun, BoundArgType arg)
Definition libxr_cb.hpp:166
只读原始数据视图 / Immutable raw data view
size_t size_
数据字节数 / Data size in bytes
const void * addr_
数据起始地址 / Data start address
模板类,表示数据库中的具体键 (Template class representing a specific key in the database).
Definition interface.hpp:52
ErrorCode Set(Data data)
设置键的值并更新数据库 (Set the key's value and update the database).
数据库接口,提供键值存储和管理功能 (Database interface providing key-value storage and management).
Definition interface.hpp:24
通用输入输出(GPIO)接口类。General Purpose Input/Output (GPIO) interface class.
Definition gpio.hpp:13
virtual void Write(bool value)=0
写入 GPIO 引脚状态。Writes the GPIO pin state.
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
可写原始数据视图 / Mutable raw data view
单生产者单消费者无锁队列。
static MicrosecondTimestamp GetMicroseconds()
获取当前时间的微秒级时间戳。 Gets the current timestamp in microseconds.
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
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:29
ErrorCode Release(Endpoint *ep_info)
回收端点 / Release endpoint
Definition ep_pool.cpp:93
ErrorCode Get(Endpoint *&ep_info, Endpoint::Direction direction, Endpoint::EPNumber ep_num)
分配端点 / Allocate endpoint
Definition ep_pool.cpp:52
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:953
void ClassicPackToQueueItem(const LibXR::CAN::ClassicPack &pack, uint8_t ch, QueueItem &qi)
ClassicPack -> QueueItem / Convert ClassicPack to QueueItem.
Definition gs_usb.hpp:1592
ErrorCode HandleBitTiming(uint8_t ch, const GsUsb::DeviceBitTiming &bt)
处理 BITTIMING(仲裁相位) / Handle BITTIMING (arbitration phase)
Definition gs_usb.hpp:1337
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:1726
void SetUserIdToStorage(uint32_t value)
写入 USER_ID(RAM 或 Database) / Write USER_ID (RAM or Database)
Definition gs_usb.hpp:1981
bool inited_
是否已初始化 / Initialized
Definition gs_usb.hpp:904
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:1017
static uint8_t LenToDlc(uint8_t len)
长度转 DLC(FD 表) / Length to DLC (FD table)
Definition gs_usb.hpp:1929
GsUsb::DeviceBitTiming bt
BITTIMING / DATA_BITTIMING.
Definition gs_usb.hpp:936
ErrorCode HandleBerr(uint8_t ch, uint32_t berr_on)
处理 BERR 开关 / Handle BERR enable/disable
Definition gs_usb.hpp:1475
ErrorCode HandleMode(uint8_t ch, const GsUsb::DeviceMode &mode)
处理 MODE(启动/复位 + 标志位) / Handle MODE (start/reset + flags)
Definition gs_usb.hpp:1424
GsUsbClass(Endpoint::EPNumber data_in_ep_num, Endpoint::EPNumber data_out_ep_num, std::initializer_list< LibXR::FDCAN * > fd_cans, 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:156
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:906
bool fd_can_rx_registered_
FD RX 回调是否已注册 / FD RX callback registered.
Definition gs_usb.hpp:1008
uint8_t can_count_
实际通道数 / Actual channel count
Definition gs_usb.hpp:896
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:1524
bool OwnsEndpoint(uint8_t ep_addr) const override
判断端点地址是否属于本类 / Check whether an endpoint belongs to this class
Definition gs_usb.hpp:372
GsUsb::Identify identify
IDENTIFY.
Definition gs_usb.hpp:939
LibXR::Callback< LibXR::ConstRawData & > on_data_out_cb_
OUT 回调 / OUT callback.
Definition gs_usb.hpp:917
std::array< LibXR::FDCAN *, CanChNum > fdcans_
FDCAN 通道列表 / FDCAN channel pointers.
Definition gs_usb.hpp:893
std::array< LibXR::CAN::Configuration, CanChNum > config_
经典 CAN 配置 / Classic CAN configuration
Definition gs_usb.hpp:947
LibXR::SPSCQueue< QueueItem > echo_queue_
Echo 队列(回送 echo_id) / Echo queue (echo back echo_id)
Definition gs_usb.hpp:1056
GsUsb::DeviceTerminationState term
SET_TERMINATION / GET_TERMINATION.
Definition gs_usb.hpp:941
Endpoint::EPNumber data_out_ep_num_
Bulk OUT 端点号 / Bulk OUT endpoint number.
Definition gs_usb.hpp:899
std::array< LibXR::CAN *, CanChNum > cans_
CAN 通道列表 / CAN channel pointers.
Definition gs_usb.hpp:891
bool berr_enabled_[CanChNum]
错误报告启用 / Bus error reporting enabled
Definition gs_usb.hpp:955
GsUsb::TerminationState term_state_[CanChNum]
终端电阻状态 / Termination state
Definition gs_usb.hpp:960
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:1002
void UnbindEndpoints(EndpointPool &endpoint_pool, bool) override
释放端点资源并复位状态 / Release endpoint resources and reset state
Definition gs_usb.hpp:322
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:935
static uint8_t DlcToLen(uint8_t dlc)
DLC 转长度(FD 表) / DLC to length (FD table)
Definition gs_usb.hpp:1919
bool HasAnyTerminationGpio() const
是否存在任意 termination GPIO / Whether any termination GPIO exists
Definition gs_usb.hpp:1207
ErrorCode HandleHostFormat(const GsUsb::HostConfig &cfg)
处理 HOST_FORMAT / Handle HOST_FORMAT
Definition gs_usb.hpp:1328
LibXR::Callback< LibXR::ConstRawData & > on_data_in_cb_
IN 回调 / IN callback.
Definition gs_usb.hpp:921
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:134
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:925
std::array< uint8_t, WIRE_MAX_SIZE > tx_buf_
IN 发送暂存区 / IN transmit staging buffer.
Definition gs_usb.hpp:979
void OnFdCanRx(bool in_isr, uint8_t ch, const LibXR::FDCAN::FDPack &pack)
FD CAN RX 处理 / Handle FD CAN RX.
Definition gs_usb.hpp:1091
LibXR::CAN::Callback can_rx_cb_[CanChNum]
classic RX 回调数组 / Classic RX callbacks
Definition gs_usb.hpp:1006
LibXR::Database * database_
Definition gs_usb.hpp:913
void OnDataInComplete(bool in_isr, ConstRawData &data)
Bulk IN 完成处理(Device->Host) / Handle Bulk IN completion (Device->Host)
Definition gs_usb.hpp:882
Endpoint * ep_data_in_
Bulk IN 端点对象 / Bulk IN endpoint object.
Definition gs_usb.hpp:901
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:1380
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:928
LIBXR_PACKED_END uint8_t rx_buf_[WIRE_MAX_SIZE]
OUT 接收缓冲区 / OUT receive buffer.
Definition gs_usb.hpp:977
FdCanRxCtx fd_can_rx_ctx_[CanChNum]
FD RX 上下文数组 / FD RX contexts.
Definition gs_usb.hpp:1010
LibXR::SPSCQueue< QueueItem > rx_queue_
RX 队列(Device->Host) / RX queue (Device->Host)
Definition gs_usb.hpp:1054
uint32_t user_id
GET_USER_ID / SET_USER_ID.
Definition gs_usb.hpp:943
void InitDeviceConfigFd()
初始化 FD 设备配置与能力位 / Initialize FD device config and feature bits
Definition gs_usb.hpp:1274
bool HasIAD() override
是否包含 IAD / Whether class has IAD
Definition gs_usb.hpp:364
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:1558
ErrorCode HandleSetTermination(uint8_t ch, const GsUsb::DeviceTerminationState &st)
处理 SET_TERMINATION / Handle SET_TERMINATION
Definition gs_usb.hpp:1501
std::array< LibXR::GPIO *, CanChNum > termination_gpios_
终端电阻 GPIO(可选) / Termination GPIOs (optional)
Definition gs_usb.hpp:911
CanRxCtx can_rx_ctx_[CanChNum]
classic RX 上下文数组 / Classic RX contexts
Definition gs_usb.hpp:1004
std::array< LibXR::FDCAN::Configuration, CanChNum > fd_config_
FD 配置 / FD configuration.
Definition gs_usb.hpp:949
static void OnDataOutCompleteStatic(bool in_isr, GsUsbClass *self, ConstRawData &data)
Bulk OUT 完成静态回调包装 / Static wrapper for Bulk OUT completion.
Definition gs_usb.hpp:760
uint32_t GetUserIdFromStorage() const
读取 USER_ID(RAM 或 Database) / Read USER_ID (RAM or Database)
Definition gs_usb.hpp:1966
uint8_t ctrl_target_channel_
控制请求目标通道 / Control request target channel
Definition gs_usb.hpp:962
uint32_t berr_on
BERR.
Definition gs_usb.hpp:938
GsUsb::DeviceMode mode
MODE.
Definition gs_usb.hpp:937
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:669
bool timestamps_enabled_ch_[CanChNum]
通道时间戳启用 / Per-channel timestamp enabled
Definition gs_usb.hpp:958
bool IsHostFormatOK() const
Host 字节序协商是否通过 / Whether host format negotiation passed.
Definition gs_usb.hpp:202
GsUsb::DeviceBTConst bt_const_
BT 常量(classic) / BT constants (classic)
Definition gs_usb.hpp:926
uint32_t timestamp_us
TIMESTAMP.
Definition gs_usb.hpp:940
size_t GetInterfaceCount() override
返回接口数量(实现侧固定 1) / Return interface count (fixed to 1)
Definition gs_usb.hpp:357
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:905
void TryKickTx(bool in_isr)
尝试启动 Bulk IN 发送 / Try to start Bulk IN transmit
Definition gs_usb.hpp:1141
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:410
bool fd_enabled_[CanChNum]
通道启用(FD) / Channel enabled (FD)
Definition gs_usb.hpp:956
void InitDeviceConfigClassic()
初始化 classic CAN 设备配置与能力位 / Initialize classic CAN device config and feature bits
Definition gs_usb.hpp:1223
bool EnqueueFrame(const QueueItem &qi, bool is_echo, bool in_isr)
入队并尝试触发发送 / Enqueue and try to trigger TX
Definition gs_usb.hpp:1122
LibXR::FDCAN::CallbackFD fd_can_rx_cb_[CanChNum]
FD RX 回调数组 / FD RX callbacks.
Definition gs_usb.hpp:1012
uint32_t MakeTimestampUs(uint8_t ch) const
获取通道时间戳(us, 32-bit) / Get per-channel timestamp (us, 32-bit)
Definition gs_usb.hpp:1898
Endpoint * ep_data_out_
Bulk OUT 端点对象 / Bulk OUT endpoint object.
Definition gs_usb.hpp:902
static void OnDataInCompleteStatic(bool in_isr, GsUsbClass *self, ConstRawData &data)
Bulk IN 完成静态回调包装 / Static wrapper for Bulk IN completion.
Definition gs_usb.hpp:775
ErrorCode HandleIdentify(uint8_t, const GsUsb::Identify &id)
处理 IDENTIFY / Handle IDENTIFY
Definition gs_usb.hpp:1488
size_t GetMaxConfigSize() override
返回描述符块最大长度 / Return max configuration descriptor block size
Definition gs_usb.hpp:387
void OnDataOutComplete(bool in_isr, ConstRawData &data)
Bulk OUT 完成处理(Host->Device) / Handle Bulk OUT completion (Host->Device)
Definition gs_usb.hpp:789
static LIBXR_PACKED_END constexpr uint32_t ECHO_ID_RX
RX 帧 echo_id 固定值 / Fixed echo_id for RX frames.
Definition gs_usb.hpp:58
GsUsbClass(Endpoint::EPNumber data_in_ep_num, Endpoint::EPNumber data_out_ep_num, std::initializer_list< LibXR::CAN * > cans, 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
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:942
LibXR::GPIO * identify_gpio_
Identify GPIO(可选) / Identify GPIO (optional)
Definition gs_usb.hpp:908
bool host_format_ok_
HOST_FORMAT 是否通过 / HOST_FORMAT OK.
Definition gs_usb.hpp:951
void OnCanRx(bool in_isr, uint8_t ch, const LibXR::CAN::ClassicPack &pack)
classic CAN RX 处理 / Handle classic CAN RX
Definition gs_usb.hpp:1061
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:1030
void FdPackToQueueItem(const LibXR::FDCAN::FDPack &pack, uint8_t ch, QueueItem &qi)
FDPack -> QueueItem / Convert FDPack to QueueItem.
Definition gs_usb.hpp:1636
void BindEndpoints(EndpointPool &endpoint_pool, uint8_t start_itf_num, bool) override
初始化接口与端点资源 / Initialize interface and endpoints
Definition gs_usb.hpp:211
Endpoint::EPNumber data_in_ep_num_
Bulk IN 端点号 / Bulk IN endpoint number.
Definition gs_usb.hpp:898
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:1688
uint32_t user_id_ram_
USER_ID 的 RAM 备份 / USER_ID RAM backup.
Definition gs_usb.hpp:915
void MaybeArmOutTransfer()
确保 Bulk OUT 保持挂起接收 / Ensure Bulk OUT is armed for receiving
Definition gs_usb.hpp:1180
bool fd_supported_
是否支持 FD / FD supported
Definition gs_usb.hpp:894
uint32_t MakeTimestampUsGlobal() const
获取全局时间戳(us, 32-bit) / Get global timestamp (us, 32-bit)
Definition gs_usb.hpp:1911
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:394
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:988
uint8_t ch
通道号 / Channel index
Definition gs_usb.hpp:990
GsUsbClass * self
实例指针 / Instance pointer
Definition gs_usb.hpp:989
FDCAN RX 回调上下文 / FDCAN RX callback context.
Definition gs_usb.hpp:997
GsUsbClass * self
实例指针 / Instance pointer
Definition gs_usb.hpp:998
uint8_t ch
通道号 / Channel index
Definition gs_usb.hpp:999
本类的接口与端点描述符块 / Descriptor block for interface and endpoints
Definition gs_usb.hpp:970
InterfaceDescriptor intf
Interface 描述符 / Interface descriptor.
Definition gs_usb.hpp:971
EndpointDescriptor ep_in
IN 端点描述符 / IN endpoint descriptor.
Definition gs_usb.hpp:973
EndpointDescriptor ep_out
OUT 端点描述符 / OUT endpoint descriptor.
Definition gs_usb.hpp:972
发送队列元素(包含 header/data/timestamp) / TX queue item (header/data/timestamp)
Definition gs_usb.hpp:1045
uint8_t data_len
payload 长度(8/64) / Payload length (8/64)
Definition gs_usb.hpp:1048
uint32_t timestamp_us
时间戳 / Timestamp
Definition gs_usb.hpp:1049
WireHeader hdr
线缆头 / Wire header
Definition gs_usb.hpp:1046
bool is_fd
是否 FD / Is FD
Definition gs_usb.hpp:1047
std::array< uint8_t, 64 > data
数据段 / Data bytes
Definition gs_usb.hpp:1050
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