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