CodexPad Arduino 库 3.0.0
载入中...
搜索中...
未找到
codex_pad.h
1#pragma once
2
3#include <functional>
4#include <mutex>
5#include <optional>
6#include <queue>
7#include <string>
8#include <vector>
9
10#include "NimBLEDevice.h"
11#include "gamepad_input_tracker.h"
12
13/**
14 * @~English
15 * @class CodexPad
16 * @brief CodexPad main class
17 */
18/**
19 * @~Chinese
20 * @class CodexPad
21 * @brief CodexPad主类
22 */
23class CodexPad {
24 public:
25 /**
26 * @~English
27 * @enum CodexPad::TxPower
28 * @brief CodexPad transmission power levels
29 */
30 /**
31 * @~Chinese
32 * @enum CodexPad::TxPower
33 * @brief CodexPad发射功率等级
34 */
35 enum class TxPower : int8_t {
36 /**
37 * @~English
38 * @brief -16 dBm
39 */
40 /**
41 * @~Chinese
42 * @brief -16 dBm
43 */
45
46 /**
47 * @~English
48 * @brief -12 dBm
49 */
50 /**
51 * @~Chinese
52 * @brief -12 dBm
53 */
55
56 /**
57 * @~English
58 * @brief -8 dBm
59 */
60 /**
61 * @~Chinese
62 * @brief -8 dBm
63 */
65
66 /**
67 * @~English
68 * @brief -5 dBm
69 */
70 /**
71 * @~Chinese
72 * @brief -5 dBm
73 */
75
76 /**
77 * @~English
78 * @brief -3 dBm
79 */
80 /**
81 * @~Chinese
82 * @brief -3 dBm
83 */
85
86 /**
87 * @~English
88 * @brief -1 dBm
89 */
90 /**
91 * @~Chinese
92 * @brief -1 dBm
93 */
95
96 /**
97 * @~English
98 * @brief 0 dBm
99 */
100 /**
101 * @~Chinese
102 * @brief 0 dBm
103 */
104 k0dBm = 0,
105
106 /**
107 * @~English
108 * @brief 1 dBm
109 */
110 /**
111 * @~Chinese
112 * @brief 1 dBm
113 */
114 k1dBm = 1,
115
116 /**
117 * @~English
118 * @brief 2 dBm
119 */
120 /**
121 * @~Chinese
122 * @brief 2 dBm
123 */
124 k2dBm = 2,
125
126 /**
127 * @~English
128 * @brief 3 dBm
129 */
130 /**
131 * @~Chinese
132 * @brief 3 dBm
133 */
134 k3dBm = 3,
135
136 /**
137 * @~English
138 * @brief 4 dBm
139 */
140 /**
141 * @~Chinese
142 * @brief 4 dBm
143 */
144 k4dBm = 4,
145
146 /**
147 * @~English
148 * @brief 5 dBm
149 */
150 /**
151 * @~Chinese
152 * @brief 5 dBm
153 */
154 k5dBm = 5,
155
156 /**
157 * @~English
158 * @brief 6 dBm
159 */
160 /**
161 * @~Chinese
162 * @brief 6 dBm
163 */
165 };
166 /**
167 * @~English
168 * @brief Constructor
169 */
170 /**
171 * @~Chinese
172 * @brief 构造函数
173 */
174 CodexPad() noexcept;
175
176 /**
177 * @~English
178 * @brief Destructor
179 */
180 /**
181 * @~Chinese
182 * @brief 析构函数
183 */
184 ~CodexPad() noexcept;
185
186 /**
187 * @~English
188 * @brief Initialize
189 */
190 /**
191 * @~Chinese
192 * @brief 初始化
193 */
194 void Init() noexcept;
195
196 /**
197 * @~English
198 * @brief Connect
199 * @param[in] bluetooth_device_address The Bluetooth device address(BD_ADDR) of the CodexPad, formatted as
200 * "XX:XX:XX:XX:XX:XX", X is a number or uppercase letter, colon separated
201 * @param[in] timeout_ms Timeout in milliseconds
202 * @retval true if connected successfully
203 * @retval false if connection failed
204 * */
205 /**
206 * @~Chinese
207 * @brief 连接
208 * @param[in] bluetooth_device_address CodexPad的蓝牙设备地址(BD_ADDR),格式为"XX:XX:XX:XX:XX:XX",X为数字或者大写字母,
209 * 半角冒号分隔
210 * @param[in] timeout_ms 超时时间,单位毫秒
211 * @retval true 连接成功
212 * @retval false 连接失败
213 */
214 bool Connect(const std::string& bluetooth_device_address, uint32_t timeout_ms = 5000) noexcept;
215
216 /**
217 * @~English
218 * @brief Scans for nearby CodexPad devices and automatically connects to a device whose button state matches the specified
219 * mask.
220 * @details This method actively scans for Bluetooth devices. When it discovers one or more CodexPad devices whose current
221 * button states exactly match the provided `button_mask`, it will attempt to establish a connection. If multiple nearby
222 * devices match the button mask, the device with the strongest signal (highest RSSI) will be selected for connection.
223 * @param[in] button_mask A 32-bit button mask used to match the target device's button states.
224 * Use the `ButtonMask()` function to combine multiple @ref Button values.
225 * @retval true Connection successful (a device matching the button mask was found and connected).
226 * @retval false Connection failed (no matching device found or connection attempt failed).
227 * @note This is a blocking call. It will continuously scan until a matching device is found, a connection is established, or
228 * the internal timeout is reached.
229 * @warning **DO NOT** include `Button::kHome` in the button mask. Holding the Home button triggers a device reboot, which
230 * will interrupt the connection process. Example:
231 * @code
232 * CodexPad pad;
233 * pad.Init();
234 * // Continuously try to connect to a device where the Start and Cross/A buttons are pressed.
235 * while (!pad.ScanAndConnect(gamepad::input::Button::kStart | gamepad::input::Button::kStart)) {
236 * // Optional: Add a small delay or other operations between attempts.
237 * delay(100);
238 * }
239 * // Once the loop exits, connection is successful.
240 * Serial.println("CodexPad connected!");
241 * @endcode
242 */
243 /**
244 * @~Chinese
245 * @brief 扫描附近的 CodexPad 设备,并自动连接到一个按键状态与指定掩码匹配的设备。
246 * @details 此方法会主动扫描蓝牙设备。当发现一个或多个 CodexPad 设备,其当前按键状态与提供的 `button_mask`
247 * 完全匹配时,它将尝试建立连接。 如果附近有多个设备都符合按键掩码,则会选择信号最强(RSSI 值最大)的设备进行连接。
248 * @param[in] button_mask 用于匹配目标设备按键状态的32位按钮掩码。
249 * 使用 `ButtonMask()` 函数来组合多个 @ref Button 枚举值。
250 * @retval true 连接成功(找到了符合按键掩码的设备并成功连接)。
251 * @retval false 连接失败(未找到匹配设备或连接尝试失败)。
252 * @note 这是一个阻塞式调用。它会持续扫描,直到找到匹配的设备、连接建立或达到内部超时时间。
253 * @warning **请勿**在按钮掩码中包含 `Button::kHome`。按住 Home 键会触发设备重启,这将中断连接过程。
254 * 示例:
255 * @code
256 * CodexPad pad;
257 * pad.Init();
258 * // 持续尝试连接到 Start 和 Cross/A 按键被同时按下的设备。
259 * while (!pad.ScanAndConnect(gamepad::input::Button::kStart | gamepad::input::Button::kStart)) {
260 * // 可选:在尝试之间添加短暂延时或其他操作。
261 * delay(100);
262 * }
263 * // 循环退出,意味着连接成功。
264 * Serial.println("CodexPad 连接成功!");
265 * @endcode
266 */
267 bool ScanAndConnect(gamepad::input::Button buttons) noexcept;
268
269 /**
270 * @~English
271 * @brief Disconnect
272 */
273 /**
274 * @~Chinese
275 * @brief 断开连接
276 */
277 void Disconnect() noexcept { Reset(); }
278
279 /**
280 * @~English
281 * @brief Update, need to be called in Loop
282 */
283 /**
284 * @~Chinese
285 * @brief 更新,需要在Loop中不断调用
286 */
287 const gamepad::input::Tracker& Update() noexcept;
288
289 /**
290 * @~English
291 * @brief Is connected
292 * @retval true if connected
293 * @retval false if not
294 */
295 /**
296 * @~Chinese
297 * @brief 是否连接
298 * @retval true 已连接
299 * @retval false 未连接
300 */
301 bool is_connected() const noexcept;
302
303 /**
304 * @~English
305 * @brief Set transmission power, only effective when connected, immediately effective for current connection, effective for
306 * next connection
307 * @param[in] power Transmission power
308 * @retval true Success
309 * @retval false Fail
310 */
311 /**
312 * @~Chinese
313 * @brief 设置发射功率,连接状态下调用,立即生效于当前连接,下次连接生效
314 * @param[in] power 发射功率
315 * @retval true 成功
316 * @retval false 失败
317 */
318 bool set_remote_tx_power(TxPower power) noexcept;
319
320 /**
321 * @~English
322 * @brief Get model number of the CodexPad
323 * @return Model number of the CodexPad
324 */
325 /**
326 * @~Chinese
327 * @brief 获取CodexPad的型号
328 * @return CodexPad的型号
329 */
330 const std::string& remote_device_name() const noexcept { return remote_device_name_; }
331
332 /**
333 * @~English
334 * @brief Get model number of the CodexPad
335 * @return Model number of the CodexPad
336 */
337 /**
338 * @~Chinese
339 * @brief 获取CodexPad的型号
340 * @return CodexPad的型号
341 */
342 const std::string& remote_model_number() const noexcept { return remote_model_number_; }
343
344 /**
345 * @~English
346 * @brief Get firmware version of the CodexPad
347 * @return Firmware version of the CodexPad
348 */
349 /**
350 * @~Chinese
351 * @brief 获取CodexPad的固件版本
352 * @return CodexPad的固件版本
353 */
354 const std::array<uint8_t, 3>& remote_firmware_version() const noexcept { return remote_firmware_version_; }
355
356 /**
357 * @~English
358 * @brief Get the input tracker object
359 * @details This function returns a reference to the internal input tracker object.
360 * @return Input tracker object
361 */
362 /**
363 * @~Chinese
364 * @brief 获取输入跟踪器对象
365 * @details 此函数返回内部输入跟踪器对象的引用。
366 * @return 输入跟踪器对象
367 */
368 const gamepad::input::Tracker& input_tracker() const noexcept { return input_tracker_; }
369
370 /**
371 * @~English
372 * @brief Get the BLE client object
373 * @details This function returns a pointer to the internal BLE client object. The caller should not try and release/delete
374 * it.
375 * @return BLE client object
376 */
377 /**
378 * @~Chinese
379 * @brief 获取 BLE 客户端对象
380 * @details 此函数返回内部 BLE 客户端对象的指针。调用者不应尝试释放/删除它。
381 * @return BLE 客户端对象
382 */
383 NimBLEClient* ble_client() const noexcept { return ble_client_; }
384
385 private:
386 static constexpr size_t kInputsQueueMax = 10;
387
388 bool Connect(const NimBLEAddress& address, bool async_connect, const uint32_t timeout_ms);
389 void OnNotify(const NimBLERemoteCharacteristic* remote_characteristic, const uint8_t* data, const size_t length,
390 const bool is_notify);
391 void Reset();
392
393 mutable std::mutex mutex_;
394 NimBLEClient* ble_client_ = nullptr;
395 std::string remote_device_name_;
396 std::string remote_model_number_;
397 std::array<uint8_t, 3> remote_firmware_version_ = {0, 0, 0};
398 std::queue<gamepad::input::State> inputs_queue_;
399 gamepad::input::Tracker input_tracker_;
400};
CodexPad主类
CodexPad() noexcept
构造函数
bool Connect(const std::string &bluetooth_device_address, uint32_t timeout_ms=5000) noexcept
连接
bool is_connected() const noexcept
是否连接
const gamepad::input::Tracker & input_tracker() const noexcept
获取输入跟踪器对象
const std::array< uint8_t, 3 > & remote_firmware_version() const noexcept
获取CodexPad的固件版本
const gamepad::input::Tracker & Update() noexcept
更新,需要在Loop中不断调用
const std::string & remote_model_number() const noexcept
获取CodexPad的型号
void Init() noexcept
初始化
NimBLEClient * ble_client() const noexcept
获取 BLE 客户端对象
const std::string & remote_device_name() const noexcept
获取CodexPad的型号
void Disconnect() noexcept
断开连接
bool set_remote_tx_power(TxPower power) noexcept
设置发射功率,连接状态下调用,立即生效于当前连接,下次连接生效
bool ScanAndConnect(gamepad::input::Button buttons) noexcept
扫描附近的 CodexPad 设备,并自动连接到一个按键状态与指定掩码匹配的设备。