26 stm32cubemx_helper::set_context<Handle, Can>(
this);
27 HAL_CAN_RegisterCallback(
28 Handle, HAL_CAN_RX_FIFO0_MSG_PENDING_CB_ID,
29 [](CAN_HandleTypeDef *hcan) {
30 static CAN_RxHeaderTypeDef rx_header;
33 auto bxcan = stm32cubemx_helper::get_context<Handle, Can>();
35 while (HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &rx_header,
36 msg.
data.data()) == HAL_OK) {
37 if (rx_header.FilterMatchIndex >= Can::FILTER_BANK_SIZE) {
41 bxcan->rx_queues_[rx_header.FilterMatchIndex];
43 update_rx_message(msg, rx_header);
44 rx_queue->
push(msg, 0);
51 HAL_CAN_UnRegisterCallback(Handle, HAL_CAN_RX_FIFO0_MSG_PENDING_CB_ID);
52 stm32cubemx_helper::set_context<Handle, Can>(
nullptr);
56 if (HAL_CAN_ActivateNotification(Handle, CAN_IT_RX_FIFO0_MSG_PENDING) !=
60 return HAL_CAN_Start(Handle) == HAL_OK;
64 if (HAL_CAN_Stop(Handle) != HAL_OK) {
67 return HAL_CAN_DeactivateNotification(
68 Handle, CAN_IT_RX_FIFO0_MSG_PENDING) == HAL_OK;
72 CAN_TxHeaderTypeDef tx_header = create_tx_header(msg);
75 while (HAL_CAN_AddTxMessage(Handle, &tx_header, msg.
data.data(),
76 &tx_mailbox) != HAL_OK) {
87 size_t rx_queue_index = find_rx_queue_index(
nullptr);
88 if (rx_queue_index >= FILTER_BANK_SIZE) {
91 CAN_FilterTypeDef filter_config = create_filter_config(
92 filter, rx_queue_index_to_filter_index(Handle, rx_queue_index));
93 if (HAL_CAN_ConfigFilter(Handle, &filter_config) != HAL_OK) {
96 rx_queues_[rx_queue_index] = &queue;
101 size_t rx_queue_index = find_rx_queue_index(&queue);
102 if (rx_queue_index >= FILTER_BANK_SIZE) {
105 CAN_FilterTypeDef filter_config{};
106 filter_config.FilterBank =
107 rx_queue_index_to_filter_index(Handle, rx_queue_index);
108 filter_config.FilterActivation = DISABLE;
109 if (HAL_CAN_ConfigFilter(Handle, &filter_config) != HAL_OK) {
112 rx_queues_[rx_queue_index] =
nullptr;
117 static constexpr uint32_t FILTER_BANK_SIZE = 14;
119 std::array<core::Queue<CanMessage> *, FILTER_BANK_SIZE> rx_queues_{};
121 Can(
const Can &) =
delete;
122 Can &operator=(
const Can &) =
delete;
125 return std::distance(
127 std::find(rx_queues_.begin(), rx_queues_.end(), queue));
130 static inline uint32_t
131 rx_queue_index_to_filter_index(
const CAN_HandleTypeDef *hcan,
132 size_t rx_queue_index) {
134 if (hcan->Instance == CAN2) {
135 return rx_queue_index + FILTER_BANK_SIZE;
138 return rx_queue_index;
141 static inline CAN_FilterTypeDef create_filter_config(
const CanFilter &filter,
142 uint32_t filter_index) {
143 CAN_FilterTypeDef filter_config{};
145 filter_config.FilterIdHigh = filter.id >> 13;
146 filter_config.FilterIdLow = ((filter.id << 3) & 0xFFFF) | 0x4;
147 filter_config.FilterMaskIdHigh = filter.mask >> 13;
148 filter_config.FilterMaskIdLow = ((filter.mask << 3) & 0xFFFF) | 0x4;
150 filter_config.FilterIdHigh = filter.id << 5;
151 filter_config.FilterIdLow = 0x0;
152 filter_config.FilterMaskIdHigh = filter.mask << 5;
153 filter_config.FilterMaskIdLow = 0x0;
155 filter_config.FilterFIFOAssignment = CAN_FILTER_FIFO0;
156 filter_config.FilterBank = filter_index;
157 filter_config.FilterMode = CAN_FILTERMODE_IDMASK;
158 filter_config.FilterScale = CAN_FILTERSCALE_32BIT;
159 filter_config.FilterActivation = ENABLE;
160 filter_config.SlaveStartFilterBank = FILTER_BANK_SIZE;
161 return filter_config;
164 static inline CAN_TxHeaderTypeDef create_tx_header(
const CanMessage &msg) {
165 CAN_TxHeaderTypeDef tx_header{};
167 tx_header.ExtId = msg.id;
168 tx_header.IDE = CAN_ID_EXT;
170 tx_header.StdId = msg.id;
171 tx_header.IDE = CAN_ID_STD;
173 tx_header.RTR = CAN_RTR_DATA;
174 tx_header.DLC = msg.dlc;
175 tx_header.TransmitGlobalTime = DISABLE;
179 static inline void update_rx_message(
CanMessage &msg,
180 const CAN_RxHeaderTypeDef &rx_header) {
181 switch (rx_header.IDE) {
183 msg.id = rx_header.StdId;
187 msg.id = rx_header.ExtId;
191 msg.dlc = rx_header.DLC;