libxr
Embedded C++ framework for bare-metal, RTOS and Linux
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
47 struct WireHeader
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 =
78 WIRE_FD_TS_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
131 InitDeviceConfigClassic();
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
194 InitDeviceConfigFd();
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
219 ans = endpoint_pool.Get(ep_data_out_, Endpoint::Direction::OUT, data_out_ep_num_);
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.
225 ep_data_in_->Configure(
226 {Endpoint::Direction::IN, Endpoint::Type::BULK, UINT16_MAX, true});
227 ep_data_out_->Configure(
229
230 desc_block_.intf = {9,
231 static_cast<uint8_t>(DescriptorType::INTERFACE),
232 interface_num_,
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),
244 ep_data_out_->MaxPacketSize(),
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),
251 ep_data_in_->MaxPacketSize(),
252 0};
253
254 SetData(RawData{reinterpret_cast<uint8_t*>(&desc_block_), sizeof(desc_block_)});
255
256 ep_data_out_->SetOnTransferCompleteCallback(on_data_out_cb_);
257 ep_data_in_->SetOnTransferCompleteCallback(on_data_in_cb_);
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
271 if (!can_rx_registered_)
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;
282 can_rx_cb_[ch] = LibXR::CAN::Callback::Create(OnCanRxStatic, &can_rx_ctx_[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);
286 cans_[ch]->Register(can_rx_cb_[ch], LibXR::CAN::Type::REMOTE_STANDARD);
287 cans_[ch]->Register(can_rx_cb_[ch], LibXR::CAN::Type::REMOTE_EXTENDED);
288 cans_[ch]->Register(can_rx_cb_[ch], LibXR::CAN::Type::ERROR);
289 }
290 can_rx_registered_ = true;
291 }
292
293 if (fd_supported_ && !fd_can_rx_registered_)
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] =
305 LibXR::FDCAN::CallbackFD::Create(OnFdCanRxStatic, &fd_can_rx_ctx_[ch]);
306
307 fdcans_[ch]->Register(fd_can_rx_cb_[ch], LibXR::CAN::Type::STANDARD);
308 fdcans_[ch]->Register(fd_can_rx_cb_[ch], LibXR::CAN::Type::EXTENDED);
309 }
310 fd_can_rx_registered_ = true;
311 }
312
313 inited_ = true;
314 MaybeArmOutTransfer();
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 {
338 ep_data_in_->Close();
339 ep_data_in_->SetActiveLength(0);
340 endpoint_pool.Release(ep_data_in_);
341 ep_data_in_ = nullptr;
342 }
343
344 if (ep_data_out_)
345 {
346 ep_data_out_->Close();
347 ep_data_out_->SetActiveLength(0);
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 {
546 ctrl_buf_.user_id = GetUserIdFromStorage();
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 }
689 return HandleBitTiming(ctrl_target_channel_, ctrl_buf_.bt);
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 }
700 return HandleDataBitTiming(ctrl_target_channel_, ctrl_buf_.bt);
701
702 case GsUsb::BReq::MODE:
703 if (data.size_ != sizeof(GsUsb::DeviceMode))
704 {
705 return ErrorCode::ARG_ERR;
706 }
707 return HandleMode(ctrl_target_channel_, ctrl_buf_.mode);
708
709 case GsUsb::BReq::BERR:
710 if (data.size_ != sizeof(uint32_t))
711 {
712 return ErrorCode::ARG_ERR;
713 }
714 return HandleBerr(ctrl_target_channel_, ctrl_buf_.berr_on);
715
716 case GsUsb::BReq::IDENTIFY:
717 if (data.size_ != sizeof(GsUsb::Identify))
718 {
719 return ErrorCode::ARG_ERR;
720 }
721 return HandleIdentify(ctrl_target_channel_, ctrl_buf_.identify);
722
723 case GsUsb::BReq::SET_TERMINATION:
724 if (data.size_ != sizeof(GsUsb::DeviceTerminationState))
725 {
726 return ErrorCode::ARG_ERR;
727 }
728 return HandleSetTermination(ctrl_target_channel_, ctrl_buf_.term);
729
730 case GsUsb::BReq::SET_USER_ID:
731 if (data.size_ != sizeof(uint32_t))
732 {
733 return ErrorCode::ARG_ERR;
734 }
735 SetUserIdToStorage(ctrl_buf_.user_id);
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 {
799 MaybeArmOutTransfer();
800 return;
801 }
802
803 const std::size_t RXLEN = data.size_;
804 if (RXLEN < WIRE_CLASSIC_SIZE)
805 {
806 MaybeArmOutTransfer();
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 {
816 MaybeArmOutTransfer();
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 {
827 MaybeArmOutTransfer();
828 return;
829 }
830
831 if (RXLEN < WIRE_FD_SIZE)
832 {
833 MaybeArmOutTransfer();
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 {
845 MaybeArmOutTransfer();
846 return;
847 }
848
849 if (RXLEN < WIRE_CLASSIC_SIZE)
850 {
851 MaybeArmOutTransfer();
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;
869 qi.timestamp_us = MakeTimestampUs(CH);
870 Memory::FastCopy(qi.data.data(), payload, qi.data_len);
871 (void)EnqueueFrame(qi, true, in_isr);
872 }
873
874 MaybeArmOutTransfer();
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>
893 fdcans_{};
894 bool fd_supported_ = false;
895
896 uint8_t can_count_ = CAN_CH_NUM;
897
898 Endpoint::EPNumber data_in_ep_num_;
899 Endpoint::EPNumber data_out_ep_num_;
900
901 Endpoint* ep_data_in_ = nullptr;
902 Endpoint* ep_data_out_ = nullptr;
903
904 bool inited_ = false;
905 uint8_t interface_num_ = 0;
906 const char* interface_string_ = nullptr;
907
908 LibXR::GPIO* identify_gpio_ =
909 nullptr;
910 std::array<LibXR::GPIO*, CanChNum>
911 termination_gpios_{};
912
913 LibXR::Database* database_ = nullptr;
915 uint32_t user_id_ram_ = 0;
916
919 this);
920
923 this);
924
925 GsUsb::DeviceConfig dev_cfg_{};
926 GsUsb::DeviceBTConst bt_const_{};
927 GsUsb::DeviceBTConstExtended
928 bt_const_ext_{};
929
933 union
934 {
938 uint32_t berr_on;
940 uint32_t timestamp_us;
943 uint32_t user_id;
944 } ctrl_buf_{};
945
946 std::array<LibXR::CAN::Configuration, CanChNum>
947 config_{};
948 std::array<LibXR::FDCAN::Configuration, CanChNum>
949 fd_config_{};
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};
962 uint8_t ctrl_target_channel_ =
963 0;
964
965 LIBXR_PACKED_BEGIN
969 struct GsUsbDescBlock
970 {
971 InterfaceDescriptor intf;
972 EndpointDescriptor ep_out;
973 EndpointDescriptor ep_in;
974 } desc_block_{};
975 LIBXR_PACKED_END
976
977 uint8_t rx_buf_[WIRE_MAX_SIZE]{};
978 std::array<uint8_t, WIRE_MAX_SIZE>
979 tx_buf_{};
980
981 // ================= CAN RX 回调 & BULK IN 发送队列 / CAN RX callbacks & Bulk IN TX
982 // queues =================
983
987 struct CanRxCtx
988 {
989 GsUsbClass* self;
990 uint8_t ch;
991 };
992
996 struct FdCanRxCtx
997 {
998 GsUsbClass* self;
999 uint8_t ch;
1000 };
1001
1002 bool can_rx_registered_ =
1003 false;
1004 CanRxCtx can_rx_ctx_[CanChNum]{};
1006 can_rx_cb_[CanChNum]{};
1007
1008 bool fd_can_rx_registered_ =
1009 false;
1010 FdCanRxCtx fd_can_rx_ctx_[CanChNum]{};
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
1044 struct QueueItem
1045 {
1046 WireHeader hdr;
1047 bool is_fd;
1048 uint8_t data_len;
1049 uint32_t timestamp_us;
1050 std::array<uint8_t, 64> data;
1051 };
1052
1054 rx_queue_;
1056 echo_queue_;
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);
1133 MaybeArmOutTransfer();
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 }
1149 if (ep_data_in_->GetState() != Endpoint::State::IDLE)
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
1174 MaybeArmOutTransfer();
1175 }
1176
1180 void MaybeArmOutTransfer()
1181 {
1182 if (!ep_data_out_)
1183 {
1184 return;
1185 }
1186 if (ep_data_out_->GetState() != Endpoint::State::IDLE)
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
1207 bool HasAnyTerminationGpio() const
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
1223 void InitDeviceConfigClassic()
1224 {
1225 can_count_ = CAN_CH_NUM;
1226 ASSERT(cans_[0] != nullptr);
1227
1228 dev_cfg_.reserved1 = 0;
1229 dev_cfg_.reserved2 = 0;
1230 dev_cfg_.reserved3 = 0;
1231 dev_cfg_.icount = static_cast<uint8_t>(can_count_ - 1);
1232 dev_cfg_.sw_version = 2;
1233 dev_cfg_.hw_version = 1;
1234
1235 const uint32_t FCLK = cans_[0]->GetClockFreq();
1236
1237 bt_const_.feature = GsUsb::CAN_FEAT_LISTEN_ONLY | GsUsb::CAN_FEAT_LOOP_BACK |
1238 GsUsb::CAN_FEAT_TRIPLE_SAMPLE | GsUsb::CAN_FEAT_ONE_SHOT |
1239 GsUsb::CAN_FEAT_HW_TIMESTAMP | GsUsb::CAN_FEAT_BERR_REPORTING |
1240 GsUsb::CAN_FEAT_GET_STATE | GsUsb::CAN_FEAT_USER_ID;
1241
1242 if (identify_gpio_)
1243 {
1244 bt_const_.feature |= GsUsb::CAN_FEAT_IDENTIFY;
1245 }
1246 if (HasAnyTerminationGpio())
1247 {
1248 bt_const_.feature |= GsUsb::CAN_FEAT_TERMINATION;
1249 }
1250
1251 bt_const_.fclk_can = FCLK;
1252 bt_const_.btc.tseg1_min = 1;
1253 bt_const_.btc.tseg1_max = 16;
1254 bt_const_.btc.tseg2_min = 1;
1255 bt_const_.btc.tseg2_max = 8;
1256 bt_const_.btc.sjw_max = 4;
1257 bt_const_.btc.brp_min = 1;
1258 bt_const_.btc.brp_max = 1024;
1259 bt_const_.btc.brp_inc = 1;
1260
1261 bt_const_ext_.feature = bt_const_.feature;
1262 bt_const_ext_.fclk_can = FCLK;
1263 bt_const_ext_.btc = bt_const_.btc;
1264 bt_const_ext_.dbtc = bt_const_.btc;
1265
1266 Memory::FastSet(config_.data(), 0, sizeof(config_));
1267 Memory::FastSet(fd_config_.data(), 0, sizeof(fd_config_));
1268 }
1269
1273 void InitDeviceConfigFd()
1274 {
1275 can_count_ = CAN_CH_NUM;
1276 ASSERT(cans_[0] != nullptr);
1277
1278 dev_cfg_.reserved1 = 0;
1279 dev_cfg_.reserved2 = 0;
1280 dev_cfg_.reserved3 = 0;
1281 dev_cfg_.icount = static_cast<uint8_t>(can_count_ - 1);
1282 dev_cfg_.sw_version = 2;
1283 dev_cfg_.hw_version = 1;
1284
1285 const uint32_t FCLK = cans_[0]->GetClockFreq();
1286
1287 bt_const_.feature = GsUsb::CAN_FEAT_LISTEN_ONLY | GsUsb::CAN_FEAT_LOOP_BACK |
1288 GsUsb::CAN_FEAT_TRIPLE_SAMPLE | GsUsb::CAN_FEAT_ONE_SHOT |
1289 GsUsb::CAN_FEAT_HW_TIMESTAMP | GsUsb::CAN_FEAT_BERR_REPORTING |
1290 GsUsb::CAN_FEAT_GET_STATE | GsUsb::CAN_FEAT_USER_ID |
1291 GsUsb::CAN_FEAT_FD | GsUsb::CAN_FEAT_BT_CONST_EXT;
1292
1293 if (identify_gpio_)
1294 {
1295 bt_const_.feature |= GsUsb::CAN_FEAT_IDENTIFY;
1296 }
1297 if (HasAnyTerminationGpio())
1298 {
1299 bt_const_.feature |= GsUsb::CAN_FEAT_TERMINATION;
1300 }
1301
1302 bt_const_.fclk_can = FCLK;
1303 bt_const_.btc.tseg1_min = 1;
1304 bt_const_.btc.tseg1_max = 16;
1305 bt_const_.btc.tseg2_min = 1;
1306 bt_const_.btc.tseg2_max = 8;
1307 bt_const_.btc.sjw_max = 4;
1308 bt_const_.btc.brp_min = 1;
1309 bt_const_.btc.brp_max = 1024;
1310 bt_const_.btc.brp_inc = 1;
1311
1312 bt_const_ext_.feature = bt_const_.feature;
1313 bt_const_ext_.fclk_can = FCLK;
1314 bt_const_ext_.btc = bt_const_.btc;
1315 bt_const_ext_.dbtc = bt_const_.btc;
1316
1317 Memory::FastSet(config_.data(), 0, sizeof(config_));
1318 Memory::FastSet(fd_config_.data(), 0, sizeof(fd_config_));
1319 }
1320
1326 ErrorCode HandleHostFormat(const GsUsb::HostConfig& cfg)
1327 {
1328 host_format_ok_ = (cfg.byte_order == 0x0000beefu);
1329 return ErrorCode::OK;
1330 }
1331
1335 ErrorCode HandleBitTiming(uint8_t ch, const GsUsb::DeviceBitTiming& bt)
1336 {
1337 if (!host_format_ok_ || ch >= can_count_ || !cans_[ch])
1338 {
1339 return ErrorCode::ARG_ERR;
1340 }
1341
1342 const uint32_t TSEG1 = bt.prop_seg + bt.phase_seg1;
1343 const uint32_t TSEG2 = bt.phase_seg2;
1344 const uint32_t TQ_NUM = 1u + TSEG1 + TSEG2;
1345
1346 const uint32_t FCLK = cans_[ch]->GetClockFreq();
1347
1348 auto& cfg = config_[ch];
1349 cfg.bit_timing.brp = bt.brp;
1350 cfg.bit_timing.prop_seg = bt.prop_seg;
1351 cfg.bit_timing.phase_seg1 = bt.phase_seg1;
1352 cfg.bit_timing.phase_seg2 = bt.phase_seg2;
1353 cfg.bit_timing.sjw = bt.sjw;
1354
1355 if (bt.brp != 0u && TQ_NUM != 0u)
1356 {
1357 cfg.bitrate = FCLK / (bt.brp * TQ_NUM);
1358 cfg.sample_point = static_cast<float>(1u + TSEG1) / static_cast<float>(TQ_NUM);
1359 }
1360 else
1361 {
1362 cfg.bitrate = 0;
1363 cfg.sample_point = 0.0f;
1364 }
1365
1366 if (fd_supported_ && fdcans_[ch])
1367 {
1368 auto& fd_cfg = fd_config_[ch];
1369 static_cast<CAN::Configuration&>(fd_cfg) = cfg;
1370 }
1371
1372 return cans_[ch]->SetConfig(cfg);
1373 }
1374
1378 ErrorCode HandleDataBitTiming(uint8_t ch, const GsUsb::DeviceBitTiming& bt)
1379 {
1380 if (!host_format_ok_)
1381 {
1382 return ErrorCode::ARG_ERR;
1383 }
1384 if (!fd_supported_ || ch >= can_count_ || !fdcans_[ch])
1385 {
1387 }
1388
1389 const uint32_t TSEG1 = bt.prop_seg + bt.phase_seg1;
1390 const uint32_t TSEG2 = bt.phase_seg2;
1391 const uint32_t TQ_NUM = 1u + TSEG1 + TSEG2;
1392
1393 const uint32_t FCLK = fdcans_[ch]->GetClockFreq();
1394
1395 auto& fd_cfg = fd_config_[ch];
1396 static_cast<CAN::Configuration&>(fd_cfg) = config_[ch];
1397
1398 fd_cfg.data_timing.brp = bt.brp;
1399 fd_cfg.data_timing.prop_seg = bt.prop_seg;
1400 fd_cfg.data_timing.phase_seg1 = bt.phase_seg1;
1401 fd_cfg.data_timing.phase_seg2 = bt.phase_seg2;
1402 fd_cfg.data_timing.sjw = bt.sjw;
1403
1404 if (bt.brp != 0u && TQ_NUM != 0u)
1405 {
1406 fd_cfg.data_bitrate = FCLK / (bt.brp * TQ_NUM);
1407 fd_cfg.data_sample_point =
1408 static_cast<float>(1u + TSEG1) / static_cast<float>(TQ_NUM);
1409 }
1410 else
1411 {
1412 fd_cfg.data_bitrate = 0;
1413 fd_cfg.data_sample_point = 0.0f;
1414 }
1415
1416 return fdcans_[ch]->SetConfig(fd_cfg);
1417 }
1418
1422 ErrorCode HandleMode(uint8_t ch, const GsUsb::DeviceMode& mode)
1423 {
1424 if (!host_format_ok_ || ch >= can_count_ || !cans_[ch])
1425 {
1426 return ErrorCode::ARG_ERR;
1427 }
1428
1429 switch (static_cast<GsUsb::CanMode>(mode.mode))
1430 {
1431 case GsUsb::CanMode::RESET:
1432 can_enabled_[ch] = false;
1433 fd_enabled_[ch] = false;
1434 break;
1435
1436 case GsUsb::CanMode::START:
1437 can_enabled_[ch] = true;
1438 if (fd_supported_ && fdcans_[ch] && (mode.flags & GsUsb::GSCAN_MODE_FD))
1439 {
1440 fd_enabled_[ch] = true;
1441 }
1442 break;
1443
1444 default:
1445 return ErrorCode::ARG_ERR;
1446 }
1447
1448 auto& cfg = config_[ch];
1449 cfg.mode.loopback = (mode.flags & GsUsb::GSCAN_MODE_LOOP_BACK) != 0;
1450 cfg.mode.listen_only = (mode.flags & GsUsb::GSCAN_MODE_LISTEN_ONLY) != 0;
1451 cfg.mode.triple_sampling = (mode.flags & GsUsb::GSCAN_MODE_TRIPLE_SAMPLE) != 0;
1452 cfg.mode.one_shot = (mode.flags & GsUsb::GSCAN_MODE_ONE_SHOT) != 0;
1453
1454 timestamps_enabled_ch_[ch] = (mode.flags & GsUsb::GSCAN_MODE_HW_TIMESTAMP) != 0;
1455 berr_enabled_[ch] = (mode.flags & GsUsb::GSCAN_MODE_BERR_REPORTING) != 0;
1456
1457 const ErrorCode EC = cans_[ch]->SetConfig(cfg);
1458
1459 if (fd_supported_ && fdcans_[ch])
1460 {
1461 auto& fd_cfg = fd_config_[ch];
1462 static_cast<CAN::Configuration&>(fd_cfg) = cfg;
1463 fd_cfg.fd_mode.fd_enabled = (mode.flags & GsUsb::GSCAN_MODE_FD) != 0;
1464 (void)fdcans_[ch]->SetConfig(fd_cfg);
1465 }
1466
1467 return EC;
1468 }
1469
1473 ErrorCode HandleBerr(uint8_t ch, uint32_t berr_on)
1474 {
1475 if (ch >= can_count_)
1476 {
1477 return ErrorCode::ARG_ERR;
1478 }
1479 berr_enabled_[ch] = (berr_on != 0);
1480 return ErrorCode::OK;
1481 }
1482
1486 ErrorCode HandleIdentify(uint8_t, const GsUsb::Identify& id)
1487 {
1488 const bool ON = (id.mode == static_cast<uint32_t>(GsUsb::IdentifyMode::ON));
1489 if (identify_gpio_)
1490 {
1491 (void)identify_gpio_->Write(ON);
1492 }
1493 return ErrorCode::OK;
1494 }
1495
1499 ErrorCode HandleSetTermination(uint8_t ch, const GsUsb::DeviceTerminationState& st)
1500 {
1501 if (ch >= can_count_)
1502 {
1503 return ErrorCode::ARG_ERR;
1504 }
1505
1506 term_state_[ch] = static_cast<GsUsb::TerminationState>(
1507 st.state != 0 ? static_cast<uint32_t>(GsUsb::TerminationState::ON)
1508 : static_cast<uint32_t>(GsUsb::TerminationState::OFF));
1509
1510 if (termination_gpios_[ch])
1511 {
1512 const bool ON = (term_state_[ch] == GsUsb::TerminationState::ON);
1513 (void)termination_gpios_[ch]->Write(ON);
1514 }
1515
1516 return ErrorCode::OK;
1517 }
1518
1522 static void HostWireToClassicPack(const WireHeader& wh, const uint8_t* payload,
1524 {
1525 const uint32_t CID = wh.can_id;
1526 const bool IS_EFF = (CID & GsUsb::CAN_EFF_FLAG) != 0;
1527 const bool IS_RTR = (CID & GsUsb::CAN_RTR_FLAG) != 0;
1528
1529 if (IS_EFF)
1530 {
1531 pack.id = CID & GsUsb::CAN_EFF_MASK;
1533 }
1534 else
1535 {
1536 pack.id = CID & GsUsb::CAN_SFF_MASK;
1538 }
1539
1540 uint8_t dlc = wh.can_dlc;
1541 if (dlc > 8u)
1542 {
1543 dlc = 8u;
1544 }
1545 pack.dlc = dlc;
1546
1547 if (dlc > 0u)
1548 {
1549 Memory::FastCopy(pack.data, payload, dlc);
1550 }
1551 }
1552
1556 static void HostWireToFdPack(const WireHeader& wh, const uint8_t* payload,
1558 {
1559 const uint32_t CID = wh.can_id;
1560 const bool IS_EFF = (CID & GsUsb::CAN_EFF_FLAG) != 0;
1561 const bool IS_RTR = (CID & GsUsb::CAN_RTR_FLAG) != 0;
1562
1563 if (IS_EFF)
1564 {
1565 pack.id = CID & GsUsb::CAN_EFF_MASK;
1567 }
1568 else
1569 {
1570 pack.id = CID & GsUsb::CAN_SFF_MASK;
1572 }
1573
1574 uint8_t len = DlcToLen(wh.can_dlc);
1575 if (len > 64)
1576 {
1577 len = 64;
1578 }
1579 pack.len = len;
1580
1581 if (len > 0u)
1582 {
1583 Memory::FastCopy(pack.data, payload, len);
1584 }
1585 }
1586
1590 void ClassicPackToQueueItem(const LibXR::CAN::ClassicPack& pack, uint8_t ch,
1591 QueueItem& qi)
1592 {
1593 uint32_t cid = 0;
1594 switch (pack.type)
1595 {
1597 cid = (pack.id & GsUsb::CAN_SFF_MASK);
1598 break;
1600 cid = (pack.id & GsUsb::CAN_EFF_MASK) | GsUsb::CAN_EFF_FLAG;
1601 break;
1603 cid = (pack.id & GsUsb::CAN_SFF_MASK) | GsUsb::CAN_RTR_FLAG;
1604 break;
1606 cid = (pack.id & GsUsb::CAN_EFF_MASK) | GsUsb::CAN_EFF_FLAG | GsUsb::CAN_RTR_FLAG;
1607 break;
1608 default:
1609 cid = pack.id & GsUsb::CAN_SFF_MASK;
1610 break;
1611 }
1612
1613 qi.hdr.echo_id = ECHO_ID_RX;
1614 qi.hdr.can_id = cid;
1615 qi.hdr.can_dlc = (pack.dlc <= 8u) ? pack.dlc : 8u;
1616 qi.hdr.channel = ch;
1617 qi.hdr.flags = 0;
1618 qi.hdr.reserved = 0;
1619
1620 qi.is_fd = false;
1621 qi.data_len = 8;
1622 qi.timestamp_us = MakeTimestampUs(ch);
1623
1624 Memory::FastSet(qi.data.data(), 0, 8);
1625 if (qi.hdr.can_dlc > 0u)
1626 {
1627 Memory::FastCopy(qi.data.data(), pack.data, qi.hdr.can_dlc);
1628 }
1629 }
1630
1634 void FdPackToQueueItem(const LibXR::FDCAN::FDPack& pack, uint8_t ch, QueueItem& qi)
1635 {
1636 uint32_t cid = 0;
1637 switch (pack.type)
1638 {
1640 cid = (pack.id & GsUsb::CAN_SFF_MASK);
1641 break;
1643 cid = (pack.id & GsUsb::CAN_EFF_MASK) | GsUsb::CAN_EFF_FLAG;
1644 break;
1646 cid = (pack.id & GsUsb::CAN_SFF_MASK) | GsUsb::CAN_RTR_FLAG;
1647 break;
1649 cid = (pack.id & GsUsb::CAN_EFF_MASK) | GsUsb::CAN_EFF_FLAG | GsUsb::CAN_RTR_FLAG;
1650 break;
1651 default:
1652 cid = pack.id & GsUsb::CAN_SFF_MASK;
1653 break;
1654 }
1655
1656 qi.hdr.echo_id = ECHO_ID_RX;
1657 qi.hdr.can_id = cid;
1658 qi.hdr.can_dlc = LenToDlc(pack.len);
1659 qi.hdr.channel = ch;
1660 qi.hdr.flags = GsUsb::CAN_FLAG_FD;
1661 qi.hdr.reserved = 0;
1662
1663 qi.is_fd = true;
1664 qi.data_len = 64;
1665 qi.timestamp_us = MakeTimestampUs(ch);
1666
1667 const uint8_t LEN = (pack.len <= 64) ? pack.len : 64;
1668
1669 if (LEN > 0u)
1670 {
1671 Memory::FastCopy(qi.data.data(), pack.data, LEN);
1672 }
1673 if (LEN < 64u)
1674 {
1675 Memory::FastSet(qi.data.data() + LEN, 0, 64u - LEN);
1676 }
1677 }
1678
1686 std::size_t PackQueueItemToWire(const QueueItem& qi, uint8_t* out,
1687 std::size_t cap) const
1688 {
1689 if (cap < WIRE_HDR_SIZE)
1690 {
1691 return 0;
1692 }
1693
1694 const uint8_t CH = qi.hdr.channel;
1695 const bool TS = (CH < can_count_) ? timestamps_enabled_ch_[CH] : false;
1696 const std::size_t PAYLOAD = qi.is_fd ? WIRE_FD_DATA_SIZE : WIRE_CLASSIC_DATA_SIZE;
1697 const std::size_t TOTAL = WIRE_HDR_SIZE + PAYLOAD + (TS ? WIRE_TS_SIZE : 0);
1698
1699 if (TOTAL > cap)
1700 {
1701 return 0;
1702 }
1703
1704 Memory::FastCopy(out, &qi.hdr, WIRE_HDR_SIZE);
1705 Memory::FastCopy(out + WIRE_HDR_SIZE, qi.data.data(), PAYLOAD);
1706
1707 if (TS)
1708 {
1709 Memory::FastCopy(out + WIRE_HDR_SIZE + PAYLOAD, &qi.timestamp_us, WIRE_TS_SIZE);
1710 }
1711
1712 return TOTAL;
1713 }
1714
1724 bool ErrorPackToHostErrorFrame(uint8_t ch, const LibXR::CAN::ClassicPack& err_pack,
1725 QueueItem& qi)
1726 {
1727 if (ch >= can_count_ || !cans_[ch])
1728 {
1729 return false;
1730 }
1731 if (!berr_enabled_[ch])
1732 {
1733 return false;
1734 }
1735 if (!LibXR::CAN::IsErrorId(err_pack.id))
1736 {
1737 return false;
1738 }
1739
1740 // 与 Linux can/error.h 对齐(沿用之前版本的映射)。
1741 // Keep these definitions aligned with Linux can/error.h, matching the previous
1742 // mapping.
1743 constexpr uint8_t LNX_CAN_ERR_CRTL_UNSPEC = 0x00;
1744 constexpr uint8_t LNX_CAN_ERR_CRTL_RX_WARNING = 0x04;
1745 constexpr uint8_t LNX_CAN_ERR_CRTL_TX_WARNING = 0x08;
1746 constexpr uint8_t LNX_CAN_ERR_CRTL_RX_PASSIVE = 0x10;
1747 constexpr uint8_t LNX_CAN_ERR_CRTL_TX_PASSIVE = 0x20;
1748
1749 constexpr uint8_t LNX_CAN_ERR_PROT_UNSPEC = 0x00;
1750 constexpr uint8_t LNX_CAN_ERR_PROT_FORM = 0x02;
1751 constexpr uint8_t LNX_CAN_ERR_PROT_STUFF = 0x04;
1752 constexpr uint8_t LNX_CAN_ERR_PROT_BIT0 = 0x08;
1753 constexpr uint8_t LNX_CAN_ERR_PROT_BIT1 = 0x10;
1754 constexpr uint8_t LNX_CAN_ERR_PROT_TX = 0x80;
1755
1756 constexpr uint8_t LNX_CAN_ERR_PROT_LOC_UNSPEC = 0x00;
1757 constexpr uint8_t LNX_CAN_ERR_PROT_LOC_ACK = 0x19;
1758
1759 constexpr uint32_t LNX_CAN_ERR_CNT = 0x00000200U;
1760
1761 bool ec_valid = false;
1762 uint32_t txerr = 0, rxerr = 0;
1763 {
1765 if (cans_[ch]->GetErrorState(es) == ErrorCode::OK)
1766 {
1767 ec_valid = true;
1768 txerr = es.tx_error_counter;
1769 rxerr = es.rx_error_counter;
1770 }
1771 }
1772
1773 const uint8_t TXERR_U8 = (txerr > 255U) ? 255U : static_cast<uint8_t>(txerr);
1774 const uint8_t RXERR_U8 = (rxerr > 255U) ? 255U : static_cast<uint8_t>(rxerr);
1775
1776 const auto EID = LibXR::CAN::ToErrorID(err_pack.id);
1777
1778 uint32_t cid = GsUsb::CAN_ERR_FLAG;
1779 std::array<uint8_t, 8> d{};
1780 switch (EID)
1781 {
1782 case LibXR::CAN::ErrorID::CAN_ERROR_ID_BUS_OFF:
1783 cid |= GsUsb::CAN_ERR_BUSOFF;
1784 break;
1785
1786 case LibXR::CAN::ErrorID::CAN_ERROR_ID_ERROR_WARNING:
1787 case LibXR::CAN::ErrorID::CAN_ERROR_ID_ERROR_PASSIVE:
1788 {
1789 cid |= GsUsb::CAN_ERR_CRTL;
1790 uint8_t ctrl = LNX_CAN_ERR_CRTL_UNSPEC;
1791
1792 if (ec_valid)
1793 {
1794 if (EID == LibXR::CAN::ErrorID::CAN_ERROR_ID_ERROR_PASSIVE)
1795 {
1796 if (txerr >= 128U)
1797 {
1798 ctrl |= LNX_CAN_ERR_CRTL_TX_PASSIVE;
1799 }
1800 if (rxerr >= 128U)
1801 {
1802 ctrl |= LNX_CAN_ERR_CRTL_RX_PASSIVE;
1803 }
1804 }
1805 else
1806 {
1807 if (txerr >= 96U)
1808 {
1809 ctrl |= LNX_CAN_ERR_CRTL_TX_WARNING;
1810 }
1811 if (rxerr >= 96U)
1812 {
1813 ctrl |= LNX_CAN_ERR_CRTL_RX_WARNING;
1814 }
1815 }
1816 }
1817
1818 if (ctrl == LNX_CAN_ERR_CRTL_UNSPEC)
1819 {
1820 ctrl = (EID == LibXR::CAN::ErrorID::CAN_ERROR_ID_ERROR_PASSIVE)
1821 ? static_cast<uint8_t>(LNX_CAN_ERR_CRTL_TX_PASSIVE |
1822 LNX_CAN_ERR_CRTL_RX_PASSIVE)
1823 : static_cast<uint8_t>(LNX_CAN_ERR_CRTL_TX_WARNING |
1824 LNX_CAN_ERR_CRTL_RX_WARNING);
1825 }
1826
1827 d[1] = ctrl;
1828 break;
1829 }
1830
1831 case LibXR::CAN::ErrorID::CAN_ERROR_ID_ACK:
1832 cid |= GsUsb::CAN_ERR_ACK;
1833 cid |= GsUsb::CAN_ERR_PROT;
1834 d[2] = static_cast<uint8_t>(LNX_CAN_ERR_PROT_UNSPEC | LNX_CAN_ERR_PROT_TX);
1835 d[3] = LNX_CAN_ERR_PROT_LOC_ACK;
1836 break;
1837
1838 case LibXR::CAN::ErrorID::CAN_ERROR_ID_STUFF:
1839 cid |= GsUsb::CAN_ERR_PROT;
1840 d[2] = static_cast<uint8_t>(LNX_CAN_ERR_PROT_STUFF | LNX_CAN_ERR_PROT_TX);
1841 d[3] = LNX_CAN_ERR_PROT_LOC_UNSPEC;
1842 break;
1843
1844 case LibXR::CAN::ErrorID::CAN_ERROR_ID_FORM:
1845 cid |= GsUsb::CAN_ERR_PROT;
1846 d[2] = static_cast<uint8_t>(LNX_CAN_ERR_PROT_FORM | LNX_CAN_ERR_PROT_TX);
1847 d[3] = LNX_CAN_ERR_PROT_LOC_UNSPEC;
1848 break;
1849
1850 case LibXR::CAN::ErrorID::CAN_ERROR_ID_BIT0:
1851 cid |= GsUsb::CAN_ERR_PROT;
1852 d[2] = static_cast<uint8_t>(LNX_CAN_ERR_PROT_BIT0 | LNX_CAN_ERR_PROT_TX);
1853 d[3] = LNX_CAN_ERR_PROT_LOC_UNSPEC;
1854 break;
1855
1856 case LibXR::CAN::ErrorID::CAN_ERROR_ID_BIT1:
1857 cid |= GsUsb::CAN_ERR_PROT;
1858 d[2] = static_cast<uint8_t>(LNX_CAN_ERR_PROT_BIT1 | LNX_CAN_ERR_PROT_TX);
1859 d[3] = LNX_CAN_ERR_PROT_LOC_UNSPEC;
1860 break;
1861
1862 default:
1863 cid |= GsUsb::CAN_ERR_PROT;
1864 d[2] = static_cast<uint8_t>(LNX_CAN_ERR_PROT_UNSPEC | LNX_CAN_ERR_PROT_TX);
1865 d[3] = LNX_CAN_ERR_PROT_LOC_UNSPEC;
1866 break;
1867 }
1868
1869 cid |= LNX_CAN_ERR_CNT;
1870 d[6] = TXERR_U8;
1871 d[7] = RXERR_U8;
1872
1873 qi.hdr.echo_id = ECHO_ID_RX;
1874 qi.hdr.can_id = cid;
1875 qi.hdr.can_dlc = GsUsb::CAN_ERR_DLC;
1876 qi.hdr.channel = ch;
1877 qi.hdr.flags = 0;
1878 qi.hdr.reserved = 0;
1879
1880 qi.is_fd = false;
1881 qi.data_len = 8;
1882 qi.timestamp_us = MakeTimestampUs(ch);
1883
1884 Memory::FastCopy(qi.data.data(), d.data(), 8);
1885
1886 return true;
1887 }
1888
1889 // ================= 工具函数 / Utilities =================
1890
1896 uint32_t MakeTimestampUs(uint8_t ch) const
1897 {
1898 if (ch < can_count_ && timestamps_enabled_ch_[ch])
1899 {
1900 return static_cast<uint32_t>(LibXR::Timebase::GetMicroseconds() & 0xFFFFFFFFu);
1901 }
1902 return 0u;
1903 }
1904
1909 uint32_t MakeTimestampUsGlobal() const
1910 {
1911 return static_cast<uint32_t>(LibXR::Timebase::GetMicroseconds() & 0xFFFFFFFFu);
1912 }
1913
1917 static uint8_t DlcToLen(uint8_t dlc)
1918 {
1919 static constexpr uint8_t TABLE[16] = {0, 1, 2, 3, 4, 5, 6, 7,
1920 8, 12, 16, 20, 24, 32, 48, 64};
1921 return (dlc < 16) ? TABLE[dlc] : 64;
1922 }
1923
1927 static uint8_t LenToDlc(uint8_t len)
1928 {
1929 if (len <= 8)
1930 {
1931 return len;
1932 }
1933 if (len <= 12)
1934 {
1935 return 9;
1936 }
1937 if (len <= 16)
1938 {
1939 return 10;
1940 }
1941 if (len <= 20)
1942 {
1943 return 11;
1944 }
1945 if (len <= 24)
1946 {
1947 return 12;
1948 }
1949 if (len <= 32)
1950 {
1951 return 13;
1952 }
1953 if (len <= 48)
1954 {
1955 return 14;
1956 }
1957 return 15;
1958 }
1959
1964 uint32_t GetUserIdFromStorage() const
1965 {
1966 if (database_ == nullptr)
1967 {
1968 return user_id_ram_;
1969 }
1970
1971 LibXR::Database::Key<uint32_t> key(*database_, "user_id", user_id_ram_);
1972 return static_cast<uint32_t>(key);
1973 }
1974
1979 void SetUserIdToStorage(uint32_t value)
1980 {
1981 user_id_ram_ = value;
1982
1983 if (database_ == nullptr)
1984 {
1985 return;
1986 }
1987
1988 LibXR::Database::Key<uint32_t> key(*database_, "user_id", 0u);
1989 (void)key.Set(value);
1990 }
1991};
1992
1993} // namespace LibXR::USB
static constexpr bool IsErrorId(uint32_t id) noexcept
判断 id 是否处于错误 ID 空间 / Check if id is in error ID space.
Definition can.hpp:169
@ 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:175
通用回调包装,支持动态参数传递 / 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
数据库接口,提供键值存储和管理功能 Database interface providing key-value storage and management.
Definition interface.hpp:24
通用输入输出(GPIO)接口类。 General Purpose Input/Output (GPIO) interface class.
Definition gpio.hpp:14
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
ErrorCode Push(const Data &item)
推入一个强类型元素 / Push one typed element.
ErrorCode Pop(Data &item)
弹出一个强类型元素 / Pop one typed element.
可写原始数据视图 / Mutable raw data view
size_t EmptySize() const
获取剩余空槽数 / Get the current free-slot count
单生产者单消费者无锁队列 / Single-producer single-consumer lock-free queue.
static MicrosecondTimestamp GetMicroseconds()
获取当前时间的微秒级时间戳。 Gets the current timestamp in microseconds.
void SetData(RawData data)
设置内部数据缓存 / Set internal data cache
Definition desc_cfg.hpp:207
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.
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
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
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
GsUsb::DeviceBitTiming bt
BITTIMING / DATA_BITTIMING.
Definition gs_usb.hpp:936
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
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
GsUsb::DeviceTerminationState term
SET_TERMINATION / GET_TERMINATION.
Definition gs_usb.hpp:941
void UnbindEndpoints(EndpointPool &endpoint_pool, bool) override
释放端点资源并复位状态 / Release endpoint resources and reset state
Definition gs_usb.hpp:322
GsUsb::HostConfig host_cfg
HOST_FORMAT.
Definition gs_usb.hpp:935
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
void OnDataInComplete(bool in_isr, ConstRawData &data)
Bulk IN 完成处理(Device->Host) / Handle Bulk IN completion (Device->Host)
Definition gs_usb.hpp:882
uint32_t user_id
GET_USER_ID / SET_USER_ID.
Definition gs_usb.hpp:943
bool HasIAD() override
是否包含 IAD / Whether class has IAD
Definition gs_usb.hpp:364
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 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 IsHostFormatOK() const
Host 字节序协商是否通过 / Whether host format negotiation passed.
Definition gs_usb.hpp:202
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
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
static void OnDataInCompleteStatic(bool in_isr, GsUsbClass *self, ConstRawData &data)
Bulk IN 完成静态回调包装 / Static wrapper for Bulk IN completion.
Definition gs_usb.hpp:775
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
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
GsUsb::DeviceState dev_state
GET_STATE.
Definition gs_usb.hpp:942
void BindEndpoints(EndpointPool &endpoint_pool, uint8_t start_itf_num, bool) override
初始化接口与端点资源 / Initialize interface and endpoints
Definition gs_usb.hpp:211
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
定义错误码枚举 / Defines an enumeration for error codes
@ 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:132
uint8_t data[8]
数据载荷 / Data payload (up to 8 bytes).
Definition can.hpp:134
uint8_t dlc
有效数据长度(0~8) / Data length code (0–8).
Definition can.hpp:133
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:266
Type type
帧类型 / Frame type.
Definition can.hpp:268
uint32_t id
CAN ID / CAN ID.
Definition can.hpp:267
uint8_t len
数据长度(0~64) / Data length (0–64 bytes).
Definition can.hpp:269
uint8_t data[64]
数据载荷 / Data payload.
Definition can.hpp:270
控制请求(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.
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.
uint32_t fclk_can
CAN 时钟 / CAN clock.
CanBitTimingConst btc
定时常量 / Timing constants
比特定时参数 / Bit timing parameters
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