halx
読み取り中…
検索中…
一致する文字列を見つけられません
fdcan.hpp
[詳解]
1#pragma once
2
3#include <algorithm>
4#include <cstdint>
5#include <iterator>
6#include <optional>
7#include <vector>
8
9#include "halx/core.hpp"
10
11namespace halx::peripheral {
12
13template <FDCAN_HandleTypeDef *Handle> class FdCan {
14public:
16 : rx_callbacks_(Handle->Init.StdFiltersNbr + Handle->Init.ExtFiltersNbr,
17 nullptr),
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;
24 CanMessage msg;
25
26 auto fdcan = stm32cubemx_helper::get_context<Handle, FdCan>();
27
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()) {
32 continue;
33 }
34 size_t filter_index = rx_header.FilterIndex;
35 if (rx_header.IdType == FDCAN_EXTENDED_ID) {
36 filter_index += Handle->Init.StdFiltersNbr;
37 }
38 auto rx_callback = fdcan->rx_callbacks_[filter_index];
39 if (rx_callback) {
40 update_rx_message(msg, rx_header);
41 rx_callback(msg, fdcan->rx_callback_contexts_[filter_index]);
42 }
43 }
44 });
45 }
46
48 HAL_FDCAN_UnRegisterRxFifo0Callback(Handle);
49 stm32cubemx_helper::set_context<Handle, FdCan>(nullptr);
50 }
51
52 bool start() {
53 if (HAL_FDCAN_ConfigGlobalFilter(Handle, FDCAN_REJECT, FDCAN_REJECT,
54 FDCAN_REJECT_REMOTE,
55 FDCAN_REJECT_REMOTE) != HAL_OK) {
56 return false;
57 }
58 if (HAL_FDCAN_ActivateNotification(Handle, FDCAN_IT_RX_FIFO0_NEW_MESSAGE,
59 0) != HAL_OK) {
60 return false;
61 }
62 return HAL_FDCAN_Start(Handle) == HAL_OK;
63 }
64
65 bool stop() {
66 if (HAL_FDCAN_Stop(Handle) != HAL_OK) {
67 return false;
68 }
69 return HAL_FDCAN_DeactivateNotification(
70 Handle, FDCAN_IT_RX_FIFO0_NEW_MESSAGE) == HAL_OK;
71 }
72
73 bool transmit(const CanMessage &msg, uint32_t timeout) {
74 FDCAN_TxHeaderTypeDef tx_header = create_tx_header(msg);
75 core::TimeoutHelper timeout_helper{timeout};
76 while (HAL_FDCAN_AddMessageToTxFifoQ(Handle, &tx_header, msg.data.data()) !=
77 HAL_OK) {
78 if (timeout_helper.is_timeout()) {
79 return false;
80 }
82 }
83 return true;
84 }
85
86 std::optional<size_t> attach_rx_filter(const CanFilter &filter,
87 void (*callback)(const CanMessage &msg,
88 void *context),
89 void *context) {
90 auto filter_index = find_rx_filter_index(filter);
91 if (!filter_index) {
92 return std::nullopt;
93 }
94 if (!enable_rx_filter(filter, *filter_index)) {
95 return std::nullopt;
96 }
97 rx_callbacks_[*filter_index] = callback;
98 rx_callback_contexts_[*filter_index] = context;
99 return filter_index;
100 }
101
102 bool detach_rx_filter(size_t filter_index) {
103 if (!disable_rx_filter(filter_index)) {
104 return false;
105 }
106 rx_callbacks_[filter_index] = nullptr;
107 return true;
108 }
109
110private:
111 std::vector<void (*)(const CanMessage &msg, void *context)> rx_callbacks_;
112 std::vector<void *> rx_callback_contexts_;
113
114 FdCan(const FdCan &) = delete;
115 FdCan &operator=(const FdCan &) = delete;
116
117 std::optional<size_t> find_rx_filter_index(const CanFilter &filter) {
118 if (filter.ide) {
119 auto it = std::find(rx_callbacks_.begin() + Handle->Init.StdFiltersNbr,
120 rx_callbacks_.end(), nullptr);
121 if (it == rx_callbacks_.end()) {
122 return std::nullopt;
123 }
124 return std::distance(rx_callbacks_.begin(), it);
125 } else {
126 auto it = std::find(rx_callbacks_.begin(),
127 rx_callbacks_.begin() + Handle->Init.StdFiltersNbr,
128 nullptr);
129 if (it == rx_callbacks_.begin() + Handle->Init.StdFiltersNbr) {
130 return std::nullopt;
131 }
132 return std::distance(rx_callbacks_.begin(), it);
133 }
134 }
135
136 static inline bool enable_rx_filter(const CanFilter &filter,
137 uint32_t filter_index) {
138 FDCAN_FilterTypeDef filter_config{};
139 if (filter.ide) {
140 filter_config.IdType = FDCAN_EXTENDED_ID;
141 filter_config.FilterIndex = filter_index - Handle->Init.StdFiltersNbr;
142 } else {
143 filter_config.IdType = FDCAN_STANDARD_ID;
144 filter_config.FilterIndex = filter_index;
145 }
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;
150
151 return HAL_FDCAN_ConfigFilter(Handle, &filter_config) == HAL_OK;
152 }
153
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;
159 } else {
160 filter_config.IdType = FDCAN_STANDARD_ID;
161 filter_config.FilterIndex = filter_index;
162 }
163 filter_config.FilterConfig = FDCAN_FILTER_DISABLE;
164
165 return HAL_FDCAN_ConfigFilter(Handle, &filter_config) == HAL_OK;
166 }
167
168 static inline FDCAN_TxHeaderTypeDef create_tx_header(const CanMessage &msg) {
169 FDCAN_TxHeaderTypeDef tx_header{};
170 tx_header.Identifier = msg.id;
171 if (msg.ide) {
172 tx_header.IdType = FDCAN_EXTENDED_ID;
173 } else {
174 tx_header.IdType = FDCAN_STANDARD_ID;
175 }
176 tx_header.TxFrameType = FDCAN_DATA_FRAME;
177 switch (msg.dlc) {
178 case 0:
179 tx_header.DataLength = FDCAN_DLC_BYTES_0;
180 break;
181 case 1:
182 tx_header.DataLength = FDCAN_DLC_BYTES_1;
183 break;
184 case 2:
185 tx_header.DataLength = FDCAN_DLC_BYTES_2;
186 break;
187 case 3:
188 tx_header.DataLength = FDCAN_DLC_BYTES_3;
189 break;
190 case 4:
191 tx_header.DataLength = FDCAN_DLC_BYTES_4;
192 break;
193 case 5:
194 tx_header.DataLength = FDCAN_DLC_BYTES_5;
195 break;
196 case 6:
197 tx_header.DataLength = FDCAN_DLC_BYTES_6;
198 break;
199 case 7:
200 tx_header.DataLength = FDCAN_DLC_BYTES_7;
201 break;
202 case 8:
203 tx_header.DataLength = FDCAN_DLC_BYTES_8;
204 break;
205 }
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;
211 return tx_header;
212 }
213
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) {
218 msg.ide = false;
219 } else if (rx_header.IdType == FDCAN_EXTENDED_ID) {
220 msg.ide = true;
221 }
222 switch (rx_header.DataLength) {
223 case FDCAN_DLC_BYTES_0:
224 msg.dlc = 0;
225 break;
226 case FDCAN_DLC_BYTES_1:
227 msg.dlc = 1;
228 break;
229 case FDCAN_DLC_BYTES_2:
230 msg.dlc = 2;
231 break;
232 case FDCAN_DLC_BYTES_3:
233 msg.dlc = 3;
234 break;
235 case FDCAN_DLC_BYTES_4:
236 msg.dlc = 4;
237 break;
238 case FDCAN_DLC_BYTES_5:
239 msg.dlc = 5;
240 break;
241 case FDCAN_DLC_BYTES_6:
242 msg.dlc = 6;
243 break;
244 case FDCAN_DLC_BYTES_7:
245 msg.dlc = 7;
246 break;
247 case FDCAN_DLC_BYTES_8:
248 msg.dlc = 8;
249 break;
250 }
251 }
252};
253
254} // namespace halx::peripheral
Definition timeout.hpp:9
Definition fdcan.hpp:13
bool start()
Definition fdcan.hpp:52
~FdCan()
Definition fdcan.hpp:47
bool transmit(const CanMessage &msg, uint32_t timeout)
Definition fdcan.hpp:73
bool stop()
Definition fdcan.hpp:65
bool detach_rx_filter(size_t filter_index)
Definition fdcan.hpp:102
std::optional< size_t > attach_rx_filter(const CanFilter &filter, void(*callback)(const CanMessage &msg, void *context), void *context)
Definition fdcan.hpp:86
FdCan()
Definition fdcan.hpp:15
void yield()
Definition common.hpp:46
Definition can.hpp:13
Definition common.hpp:12
bool ide
Definition common.hpp:15
Definition common.hpp:18
std::array< uint8_t, 8 > data
Definition common.hpp:22