20template <>
class Can<CAN_HandleTypeDef *> :
public CanBase {
22 Can(CAN_HandleTypeDef *hcan) : hcan_{hcan} {
23 hal::set_bxcan_context(hcan_,
this);
24 HAL_CAN_RegisterCallback(
25 hcan_, HAL_CAN_RX_FIFO0_MSG_PENDING_CB_ID, [](CAN_HandleTypeDef *hcan) {
26 static CAN_RxHeaderTypeDef rx_header;
29 auto bxcan =
reinterpret_cast<Can *
>(hal::get_bxcan_context(hcan));
31 while (HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &rx_header,
32 msg.
data.data()) == HAL_OK) {
33 if (rx_header.FilterMatchIndex >= Can::FILTER_BANK_SIZE) {
37 bxcan->rx_queues_[rx_header.FilterMatchIndex];
39 update_rx_message(msg, rx_header);
40 rx_queue->
push(msg, 0);
47 HAL_CAN_UnRegisterCallback(hcan_, HAL_CAN_RX_FIFO0_MSG_PENDING_CB_ID);
48 hal::set_bxcan_context(hcan_,
nullptr);
52 if (HAL_CAN_ActivateNotification(hcan_, CAN_IT_RX_FIFO0_MSG_PENDING) !=
56 return HAL_CAN_Start(hcan_) == HAL_OK;
60 if (HAL_CAN_Stop(hcan_) != HAL_OK) {
63 return HAL_CAN_DeactivateNotification(hcan_, CAN_IT_RX_FIFO0_MSG_PENDING) ==
68 CAN_TxHeaderTypeDef tx_header = create_tx_header(msg);
71 while (HAL_CAN_AddTxMessage(hcan_, &tx_header, msg.
data.data(),
72 &tx_mailbox) != HAL_OK) {
83 size_t rx_queue_index = find_rx_queue_index(
nullptr);
84 if (rx_queue_index >= FILTER_BANK_SIZE) {
87 CAN_FilterTypeDef filter_config = create_filter_config(
88 filter, rx_queue_index_to_filter_index(hcan_, rx_queue_index));
89 if (HAL_CAN_ConfigFilter(hcan_, &filter_config) != HAL_OK) {
92 rx_queues_[rx_queue_index] = &queue;
97 size_t rx_queue_index = find_rx_queue_index(&queue);
98 if (rx_queue_index >= FILTER_BANK_SIZE) {
101 CAN_FilterTypeDef filter_config{};
102 filter_config.FilterBank =
103 rx_queue_index_to_filter_index(hcan_, rx_queue_index);
104 filter_config.FilterActivation = DISABLE;
105 if (HAL_CAN_ConfigFilter(hcan_, &filter_config) != HAL_OK) {
108 rx_queues_[rx_queue_index] =
nullptr;
113 static constexpr uint32_t FILTER_BANK_SIZE = 14;
115 CAN_HandleTypeDef *hcan_;
116 std::array<core::Queue<CanMessage> *, FILTER_BANK_SIZE> rx_queues_{};
118 Can(
const Can &) =
delete;
119 Can &operator=(
const Can &) =
delete;
122 return std::distance(
124 std::find(rx_queues_.begin(), rx_queues_.end(), queue));
127 static inline uint32_t
128 rx_queue_index_to_filter_index(
const CAN_HandleTypeDef *hcan,
129 size_t rx_queue_index) {
131 if (hcan->Instance == CAN2) {
132 return rx_queue_index + FILTER_BANK_SIZE;
135 return rx_queue_index;
138 static inline CAN_FilterTypeDef create_filter_config(
const CanFilter &filter,
139 uint32_t filter_index) {
140 CAN_FilterTypeDef filter_config{};
142 filter_config.FilterIdHigh = filter.id >> 13;
143 filter_config.FilterIdLow = ((filter.id << 3) & 0xFFFF) | 0x4;
144 filter_config.FilterMaskIdHigh = filter.mask >> 13;
145 filter_config.FilterMaskIdLow = ((filter.mask << 3) & 0xFFFF) | 0x4;
147 filter_config.FilterIdHigh = filter.id << 5;
148 filter_config.FilterIdLow = 0x0;
149 filter_config.FilterMaskIdHigh = filter.mask << 5;
150 filter_config.FilterMaskIdLow = 0x0;
152 filter_config.FilterFIFOAssignment = CAN_FILTER_FIFO0;
153 filter_config.FilterBank = filter_index;
154 filter_config.FilterMode = CAN_FILTERMODE_IDMASK;
155 filter_config.FilterScale = CAN_FILTERSCALE_32BIT;
156 filter_config.FilterActivation = ENABLE;
157 filter_config.SlaveStartFilterBank = FILTER_BANK_SIZE;
158 return filter_config;
161 static inline CAN_TxHeaderTypeDef create_tx_header(
const CanMessage &msg) {
162 CAN_TxHeaderTypeDef tx_header{};
164 tx_header.ExtId = msg.id;
165 tx_header.IDE = CAN_ID_EXT;
167 tx_header.StdId = msg.id;
168 tx_header.IDE = CAN_ID_STD;
170 tx_header.RTR = CAN_RTR_DATA;
171 tx_header.DLC = msg.dlc;
172 tx_header.TransmitGlobalTime = DISABLE;
176 static inline void update_rx_message(
CanMessage &msg,
177 const CAN_RxHeaderTypeDef &rx_header) {
178 switch (rx_header.IDE) {
180 msg.id = rx_header.StdId;
184 msg.id = rx_header.ExtId;
188 msg.dlc = rx_header.DLC;