13template <FDCAN_HandleTypeDef *Handle>
class FdCan {
16 : rx_callbacks_(Handle->Init.StdFiltersNbr + Handle->Init.ExtFiltersNbr,
18 rx_callback_contexts_(
19 Handle->Init.StdFiltersNbr + Handle->Init.ExtFiltersNbr, nullptr) {
20 stm32cubemx_helper::set_context<Handle, FdCan>(
this);
21 HAL_FDCAN_RegisterRxFifo0Callback(
22 Handle, [](FDCAN_HandleTypeDef *hfdcan, uint32_t) {
23 FDCAN_RxHeaderTypeDef rx_header;
26 auto fdcan = stm32cubemx_helper::get_context<Handle, FdCan>();
28 while (HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &rx_header,
29 msg.
data.data()) == HAL_OK) {
30 if (rx_header.IsFilterMatchingFrame == 1 ||
31 rx_header.FilterIndex >= fdcan->rx_callbacks_.size()) {
34 size_t filter_index = rx_header.FilterIndex;
35 if (rx_header.IdType == FDCAN_EXTENDED_ID) {
36 filter_index += Handle->Init.StdFiltersNbr;
38 auto rx_callback = fdcan->rx_callbacks_[filter_index];
40 update_rx_message(msg, rx_header);
41 rx_callback(msg, fdcan->rx_callback_contexts_[filter_index]);
48 HAL_FDCAN_UnRegisterRxFifo0Callback(Handle);
49 stm32cubemx_helper::set_context<Handle, FdCan>(
nullptr);
53 if (HAL_FDCAN_ConfigGlobalFilter(Handle, FDCAN_REJECT, FDCAN_REJECT,
55 FDCAN_REJECT_REMOTE) != HAL_OK) {
58 if (HAL_FDCAN_ActivateNotification(Handle, FDCAN_IT_RX_FIFO0_NEW_MESSAGE,
62 return HAL_FDCAN_Start(Handle) == HAL_OK;
66 if (HAL_FDCAN_Stop(Handle) != HAL_OK) {
69 return HAL_FDCAN_DeactivateNotification(
70 Handle, FDCAN_IT_RX_FIFO0_NEW_MESSAGE) == HAL_OK;
74 FDCAN_TxHeaderTypeDef tx_header = create_tx_header(msg);
76 while (HAL_FDCAN_AddMessageToTxFifoQ(Handle, &tx_header, msg.
data.data()) !=
78 if (timeout_helper.is_timeout()) {
90 auto filter_index = find_rx_filter_index(filter);
94 if (!enable_rx_filter(filter, *filter_index)) {
97 rx_callbacks_[*filter_index] = callback;
98 rx_callback_contexts_[*filter_index] = context;
103 if (!disable_rx_filter(filter_index)) {
106 rx_callbacks_[filter_index] =
nullptr;
111 std::vector<void (*)(
const CanMessage &msg,
void *context)> rx_callbacks_;
112 std::vector<void *> rx_callback_contexts_;
117 std::optional<size_t> find_rx_filter_index(
const CanFilter &filter) {
119 auto it = std::find(rx_callbacks_.begin() + Handle->Init.StdFiltersNbr,
120 rx_callbacks_.end(),
nullptr);
121 if (it == rx_callbacks_.end()) {
124 return std::distance(rx_callbacks_.begin(), it);
126 auto it = std::find(rx_callbacks_.begin(),
127 rx_callbacks_.begin() + Handle->Init.StdFiltersNbr,
129 if (it == rx_callbacks_.begin() + Handle->Init.StdFiltersNbr) {
132 return std::distance(rx_callbacks_.begin(), it);
136 static inline bool enable_rx_filter(
const CanFilter &filter,
137 uint32_t filter_index) {
138 FDCAN_FilterTypeDef filter_config{};
140 filter_config.IdType = FDCAN_EXTENDED_ID;
141 filter_config.FilterIndex = filter_index - Handle->Init.StdFiltersNbr;
143 filter_config.IdType = FDCAN_STANDARD_ID;
144 filter_config.FilterIndex = filter_index;
146 filter_config.FilterType = FDCAN_FILTER_MASK;
147 filter_config.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
148 filter_config.FilterID1 = filter.id;
149 filter_config.FilterID2 = filter.mask;
151 return HAL_FDCAN_ConfigFilter(Handle, &filter_config) == HAL_OK;
154 static inline bool disable_rx_filter(
size_t filter_index) {
155 FDCAN_FilterTypeDef filter_config{};
156 if (filter_index >= Handle->Init.StdFiltersNbr) {
157 filter_config.IdType = FDCAN_EXTENDED_ID;
158 filter_config.FilterIndex = filter_index - Handle->Init.StdFiltersNbr;
160 filter_config.IdType = FDCAN_STANDARD_ID;
161 filter_config.FilterIndex = filter_index;
163 filter_config.FilterConfig = FDCAN_FILTER_DISABLE;
165 return HAL_FDCAN_ConfigFilter(Handle, &filter_config) == HAL_OK;
168 static inline FDCAN_TxHeaderTypeDef create_tx_header(
const CanMessage &msg) {
169 FDCAN_TxHeaderTypeDef tx_header{};
170 tx_header.Identifier = msg.id;
172 tx_header.IdType = FDCAN_EXTENDED_ID;
174 tx_header.IdType = FDCAN_STANDARD_ID;
176 tx_header.TxFrameType = FDCAN_DATA_FRAME;
179 tx_header.DataLength = FDCAN_DLC_BYTES_0;
182 tx_header.DataLength = FDCAN_DLC_BYTES_1;
185 tx_header.DataLength = FDCAN_DLC_BYTES_2;
188 tx_header.DataLength = FDCAN_DLC_BYTES_3;
191 tx_header.DataLength = FDCAN_DLC_BYTES_4;
194 tx_header.DataLength = FDCAN_DLC_BYTES_5;
197 tx_header.DataLength = FDCAN_DLC_BYTES_6;
200 tx_header.DataLength = FDCAN_DLC_BYTES_7;
203 tx_header.DataLength = FDCAN_DLC_BYTES_8;
206 tx_header.ErrorStateIndicator = FDCAN_ESI_ACTIVE;
207 tx_header.BitRateSwitch = FDCAN_BRS_OFF;
208 tx_header.FDFormat = FDCAN_CLASSIC_CAN;
209 tx_header.TxEventFifoControl = FDCAN_NO_TX_EVENTS;
210 tx_header.MessageMarker = 0;
214 static inline void update_rx_message(CanMessage &msg,
215 const FDCAN_RxHeaderTypeDef &rx_header) {
216 msg.id = rx_header.Identifier;
217 if (rx_header.IdType == FDCAN_STANDARD_ID) {
219 }
else if (rx_header.IdType == FDCAN_EXTENDED_ID) {
222 switch (rx_header.DataLength) {
223 case FDCAN_DLC_BYTES_0:
226 case FDCAN_DLC_BYTES_1:
229 case FDCAN_DLC_BYTES_2:
232 case FDCAN_DLC_BYTES_3:
235 case FDCAN_DLC_BYTES_4:
238 case FDCAN_DLC_BYTES_5:
241 case FDCAN_DLC_BYTES_6:
244 case FDCAN_DLC_BYTES_7:
247 case FDCAN_DLC_BYTES_8: