halx
読み取り中…
検索中…
一致する文字列を見つけられません
bxcan.hpp
[詳解]
1#pragma once
2
3#include <algorithm>
4#include <array>
5#include <cstdint>
6#include <iterator>
7#include <optional>
8
9#include "halx/core.hpp"
10
11namespace halx::peripheral {
12
13template <CAN_HandleTypeDef *Handle> class BxCan {
14public:
16 stm32cubemx_helper::set_context<Handle, BxCan>(this);
17 HAL_CAN_RegisterCallback(
18 Handle, HAL_CAN_RX_FIFO0_MSG_PENDING_CB_ID,
19 [](CAN_HandleTypeDef *hcan) {
20 CAN_RxHeaderTypeDef rx_header;
21 CanMessage msg;
22
23 auto bxcan = stm32cubemx_helper::get_context<Handle, BxCan>();
24
25 while (HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &rx_header,
26 msg.data.data()) == HAL_OK) {
27 if (rx_header.FilterMatchIndex >= BxCan::FILTER_BANK_SIZE) {
28 continue;
29 }
30 auto rx_callback = bxcan->rx_callbacks_[rx_header.FilterMatchIndex];
31 if (rx_callback) {
32 update_rx_message(msg, rx_header);
33 rx_callback(
34 msg,
35 bxcan->rx_callback_contexts_[rx_header.FilterMatchIndex]);
36 }
37 }
38 });
39 }
40
42 HAL_CAN_UnRegisterCallback(Handle, HAL_CAN_RX_FIFO0_MSG_PENDING_CB_ID);
43 stm32cubemx_helper::set_context<Handle, BxCan>(nullptr);
44 }
45
46 bool start() {
47 if (HAL_CAN_ActivateNotification(Handle, CAN_IT_RX_FIFO0_MSG_PENDING) !=
48 HAL_OK) {
49 return false;
50 }
51 return HAL_CAN_Start(Handle) == HAL_OK;
52 }
53
54 bool stop() {
55 if (HAL_CAN_Stop(Handle) != HAL_OK) {
56 return false;
57 }
58 return HAL_CAN_DeactivateNotification(
59 Handle, CAN_IT_RX_FIFO0_MSG_PENDING) == HAL_OK;
60 }
61
62 bool transmit(const CanMessage &msg, uint32_t timeout) {
63 CAN_TxHeaderTypeDef tx_header = create_tx_header(msg);
64 uint32_t tx_mailbox;
65 core::TimeoutHelper timeout_helper{timeout};
66 while (HAL_CAN_AddTxMessage(Handle, &tx_header, msg.data.data(),
67 &tx_mailbox) != HAL_OK) {
68 if (timeout_helper.is_timeout()) {
69 return false;
70 }
72 }
73 return true;
74 }
75
76 std::optional<size_t> attach_rx_filter(const CanFilter &filter,
77 void (*callback)(const CanMessage &msg,
78 void *context),
79 void *context) {
80 auto filter_index = find_rx_filter_index(filter);
81 if (!filter_index) {
82 return std::nullopt;
83 }
84 if (!enable_rx_filter(filter, *filter_index)) {
85 return std::nullopt;
86 }
87 rx_callbacks_[*filter_index] = callback;
88 rx_callback_contexts_[*filter_index] = context;
89 return filter_index;
90 }
91
92 bool detach_rx_filter(size_t filter_index) {
93 if (!disable_rx_filter(filter_index)) {
94 return false;
95 }
96 rx_callbacks_[filter_index] = nullptr;
97 return true;
98 }
99
100private:
101 static constexpr uint32_t FILTER_BANK_SIZE = 14;
102
103 std::array<void (*)(const CanMessage &msg, void *context), FILTER_BANK_SIZE>
104 rx_callbacks_{};
105 std::array<void *, FILTER_BANK_SIZE> rx_callback_contexts_{};
106
107 BxCan(const BxCan &) = delete;
108 BxCan &operator=(const BxCan &) = delete;
109
110 std::optional<size_t> find_rx_filter_index(const CanFilter &) {
111 auto it = std::find(rx_callbacks_.begin(), rx_callbacks_.end(), nullptr);
112 if (it == rx_callbacks_.end()) {
113 return std::nullopt;
114 }
115 return std::distance(rx_callbacks_.begin(), it);
116 }
117
118 static inline bool enable_rx_filter(const CanFilter &filter,
119 uint32_t filter_index) {
120 CAN_FilterTypeDef filter_config{};
121 if (filter.ide) {
122 filter_config.FilterIdHigh = filter.id >> 13;
123 filter_config.FilterIdLow = ((filter.id << 3) & 0xFFFF) | 0x4;
124 filter_config.FilterMaskIdHigh = filter.mask >> 13;
125 filter_config.FilterMaskIdLow = ((filter.mask << 3) & 0xFFFF) | 0x4;
126 } else {
127 filter_config.FilterIdHigh = filter.id << 5;
128 filter_config.FilterIdLow = 0x0;
129 filter_config.FilterMaskIdHigh = filter.mask << 5;
130 filter_config.FilterMaskIdLow = 0x0;
131 }
132 filter_config.FilterFIFOAssignment = CAN_FILTER_FIFO0;
133 filter_config.FilterBank = filter_index;
134#ifdef CAN2
135 if (Handle->Instance == CAN2) {
136 filter_config.FilterBank += FILTER_BANK_SIZE;
137 }
138#endif
139 filter_config.FilterMode = CAN_FILTERMODE_IDMASK;
140 filter_config.FilterScale = CAN_FILTERSCALE_32BIT;
141 filter_config.FilterActivation = ENABLE;
142 filter_config.SlaveStartFilterBank = FILTER_BANK_SIZE;
143
144 return HAL_CAN_ConfigFilter(Handle, &filter_config) == HAL_OK;
145 }
146
147 static inline bool disable_rx_filter(size_t filter_index) {
148 CAN_FilterTypeDef filter_config{};
149 filter_config.FilterBank = filter_index;
150#ifdef CAN2
151 if (Handle->Instance == CAN2) {
152 filter_config.FilterBank += FILTER_BANK_SIZE;
153 }
154#endif
155 filter_config.FilterActivation = DISABLE;
156
157 return HAL_CAN_ConfigFilter(Handle, &filter_config) == HAL_OK;
158 }
159
160 static inline CAN_TxHeaderTypeDef create_tx_header(const CanMessage &msg) {
161 CAN_TxHeaderTypeDef tx_header{};
162 if (msg.ide) {
163 tx_header.ExtId = msg.id;
164 tx_header.IDE = CAN_ID_EXT;
165 } else {
166 tx_header.StdId = msg.id;
167 tx_header.IDE = CAN_ID_STD;
168 }
169 tx_header.RTR = CAN_RTR_DATA;
170 tx_header.DLC = msg.dlc;
171 tx_header.TransmitGlobalTime = DISABLE;
172 return tx_header;
173 }
174
175 static inline void update_rx_message(CanMessage &msg,
176 const CAN_RxHeaderTypeDef &rx_header) {
177 switch (rx_header.IDE) {
178 case CAN_ID_STD:
179 msg.id = rx_header.StdId;
180 msg.ide = false;
181 break;
182 case CAN_ID_EXT:
183 msg.id = rx_header.ExtId;
184 msg.ide = true;
185 break;
186 }
187 msg.dlc = rx_header.DLC;
188 }
189};
190
191} // namespace halx::peripheral
Definition timeout.hpp:9
bool detach_rx_filter(size_t filter_index)
Definition bxcan.hpp:92
BxCan()
Definition bxcan.hpp:15
~BxCan()
Definition bxcan.hpp:41
bool transmit(const CanMessage &msg, uint32_t timeout)
Definition bxcan.hpp:62
std::optional< size_t > attach_rx_filter(const CanFilter &filter, void(*callback)(const CanMessage &msg, void *context), void *context)
Definition bxcan.hpp:76
bool start()
Definition bxcan.hpp:46
bool stop()
Definition bxcan.hpp:54
void yield()
Definition common.hpp:46
Definition can.hpp:13
Definition common.hpp:12
Definition common.hpp:18
std::array< uint8_t, 8 > data
Definition common.hpp:22