CodexPad Arduino 库 2.1.3
载入中...
搜索中...
未找到
scan_and_connect.ino
浏览该文件的文档.
1/**
2 * @~English
3 * @file scan_and_connect.ino
4 * @example scan_and_connect.ino
5 * @brief Demonstrates how to scan for and connect to a CodexPad device by matching specific button presses.
6 * @details This example shows the usage of the `ScanAndConnect()` function. The device will scan for nearby CodexPad devices and automatically
7 * connect to one where the operator is holding down the predefined combination of buttons (the *button mask*). The button mask is defined by the
8 * `kExpectedButtonMask` constant. You must physically press and hold the corresponding button(s) on the target CodexPad for the connection to
9 * succeed.
10 * @warning **Important:** The button mask must NOT include `Button::kHome`. Pressing and holding the Home button causes the device to
11 * reboot, which will interrupt or prevent connection.
12 * @see CodexPad::ScanAndConnect
13 * @see CodexPad::ButtonMask
14 */
15/**
16 * @~Chinese
17 * @file scan_and_connect.ino
18 * @example scan_and_connect.ino
19 * @brief 演示如何通过匹配特定按键按压来扫描并连接 CodexPad 设备。
20 * @details 本示例展示了 `ScanAndConnect()` 函数的使用方法。设备将扫描附近的 CodexPad
21 * 设备,并自动连接到操作者正按住预定义按键组合(*按钮掩码*)的那一个。 按钮掩码由常量 `kExpectedButtonMask` 定义。您必须在目标 CodexPad
22 * 手柄上物理按住对应的按键,连接才能成功。
23 * @warning **重要:** 按钮掩码中 **不得** 包含 `Button::kHome`。按住 Home 键会导致设备重启,从而中断或阻止连接。
24 * @see CodexPad::ScanAndConnect
25 * @see CodexPad::ButtonMask
26 */
27
28#include "codex_pad.h"
29
30namespace {
31// You can set a button mask to automatically connect when a target device is scanned and its button state matches this mask.
32// For example, you can set it to connect only when a specific button is pressed, or when multiple specified buttons are pressed simultaneously on the
33// device.
34// 你可以设置一个按钮掩码,当扫描到目标设备并检测到其按键状态与该掩码匹配时,自动进行连接。
35// 例如,可以设置为当设备上某个特定按键被按下,或多个指定按键被同时按下时才建立连接。
36
37// 【Important Warning】DO NOT use `Button::kHome` (Home button) to set the button mask. Pressing and holding the Home button will trigger a device
38// reboot, which will interrupt the connection process or put the device into an unexpected state.
39// 【重要警告】请勿使用 `Button::kHome` (Home键) 来设置按钮掩码。因为按住Home键会触发设备重启,这将导致连接过程中断或设备进入不可预期的状态。
40
41// Example: The button mask to match - Only the Start button
42// 示例:需要匹配的按钮掩码 - 仅Start按钮
43// constexpr auto kExpectedButtonMask = CodexPad::ButtonMask(CodexPad::Button::kStart);
44
45// Example: The button mask to match - Start and CrossA buttons
46// 示例:需要匹配的按钮掩码 - Start 和 CrossA 按钮
47constexpr auto kExpectedButtonMask = CodexPad::ButtonMask(CodexPad::Button::kStart, CodexPad::Button::kCrossA);
48
49// Example: The button mask to match - Start, CrossA, and SquareX buttons
50// 示例:需要匹配的按钮掩码 - Start、CrossA 和 SquareX 按钮
51// constexpr auto kExpectedButtonMask = CodexPad::ButtonMask(CodexPad::Button::kStart, CodexPad::Button::kCrossA, CodexPad::Button::kSquareX);
52
53CodexPad g_codex_pad;
54
55/**
56 * Convert button constant to readable string name
57 * 将按钮枚举转换为可读的字符串名称
58 */
59std::string ButtonToString(CodexPad::Button button) {
60 switch (button) {
62 return "Up"; // 上按钮 | UP button
63 }
65 return "Down"; // 下按钮 | DOWN button
66 }
68 return "Left"; // 左按钮 | LEFT button
69 }
71 return "Right"; // 右按钮 | RIGHT button
72 }
74 return "Square(X)"; // 方形 或者 X 按钮 | SQUARE or X button
75 }
77 return "Triangle(Y)"; // 三角 或者 Y 按钮 | TRIANGLE or Y button
78 }
80 return "Cross(A)"; // 叉型 或者 A 按钮 | CROSS or A button
81 }
83 return "Circle(B)"; // 圆形 或者 B 按钮 | CIRCLE or B button
84 }
86 return "L1"; // L1按钮 | L1 button
87 }
89 return "L2"; // L2按钮 | L2 button
90 }
92 return "L3"; // L3按钮 | L3 button
93 }
95 return "R1"; // R1按钮 | R1 button
96 }
98 return "R2"; // R2按钮 | R2 button
99 }
101 return "R3"; // R3按钮 | R3 button
102 }
104 return "Select"; // 选择按钮 | SELECT button
105 }
107 return "Start"; // 开始按钮 | START button
108 }
110 return "Home"; // 首页按钮 | HOME button
111 }
112 default: {
113 return {}; // 未知按钮返回空字符串 | Unknown button returns empty string
114 }
115 }
116}
117
118void Connect() {
119 printf("Start to scan and connect, button mask: 0x%08X\n", kExpectedButtonMask);
120
121 while (!g_codex_pad.ScanAndConnect(kExpectedButtonMask)) {
122 printf("Retry to scan and connect, button mask: 0x%08X\n", kExpectedButtonMask);
123 }
124
125 printf("Remote device name: %s\n", g_codex_pad.remote_device_name().c_str());
126 printf("Remote model number: %s\n", g_codex_pad.remote_model_number().c_str());
127 printf("Remote firmware revision: %u.%u.%u\n",
128 g_codex_pad.remote_firmware_version()[0],
129 g_codex_pad.remote_firmware_version()[1],
130 g_codex_pad.remote_firmware_version()[2]);
131
132 if (const auto ble_client = g_codex_pad.ble_client(); ble_client != nullptr) {
133 printf("Remote Bluetooth Device Address: %s\n", ble_client->getPeerAddress().toString().c_str());
134 } else {
135 printf("Remote Bluetooth Device Address: unknown\n");
136 }
137
138 // Set transmission power to 0dBm
139 // Transmission power affects communication range and power consumption:
140 // Higher power provides longer range but consumes more battery
141 // Choose appropriate power level based on your application to balance range and battery life
142 // 设置发射功率为0dBm
143 // 发射功率影响通信距离和功耗:功率越高,通信距离越远,但功耗也越大
144 // 建议根据实际应用场景选择合适的功率等级以平衡距离和电池寿命
146 printf("Set remote tx power to 0dBm successfully\n");
147 }
148
149 printf("Connected\n");
150}
151} // namespace
152
153void setup() {
154 Serial.begin(115200);
155
156 printf("Init\n");
157 g_codex_pad.Init();
158
159 Connect();
160}
161
162void loop() {
163 // Important: Update() method must be called as frequently as possible in the loop, no delays should be added
164 // This method processes all received Bluetooth packets, delays will cause data loss and response lag
165 // For real-time control applications, high-frequency calls are essential to ensure prompt response to gamepad input
166 // 重要:Update()方法必须在循环中尽可能频繁地调用,不能添加延时
167 // 该方法负责处理所有接收到的蓝牙数据包,延时会导致数据丢失和响应延迟
168 // 对于实时控制应用,必须保持高频率调用以确保及时响应手柄输入
169 g_codex_pad.Update();
170
171 if (!g_codex_pad.is_connected()) {
172 printf("Disconnected, start to reconnect\n");
173 Connect();
174 return;
175 }
176
177 // Detect state changes for all buttons
178 // Use pressed(), released(), holding() methods to detect different button states
179 // 检测所有按钮的状态变化
180 // 使用pressed(), released(), holding()方法检测按钮的不同状态
181 for (const auto button : {CodexPad::Button::kUp,
198 // Check if button was just pressed (transition from released to pressed)
199 // 检测按钮是否刚刚按下(从弹起变为按下)
200 if (g_codex_pad.pressed(button)) {
201 printf("Button %s: pressed\n", ButtonToString(button).c_str());
202 }
203
204 // Check if button was just released (transition from pressed to released)
205 // 检测按钮是否刚刚释放(从按下变为弹起)
206 else if (g_codex_pad.released(button)) {
207 printf("Button %s: released\n", ButtonToString(button).c_str());
208 }
209
210 // Check if button is holding
211 // 检测按钮是否持续按下状态
212 else if (g_codex_pad.holding(button)) {
213 printf("Button %s: holding\n", ButtonToString(button).c_str());
214 }
215 }
216
217 // Check if joystick axis values have changed significantly (using threshold to avoid minor jitter)
218 // Threshold is set to 2, only consider changes equal to or greater than 2 units as significant
219 // 检测摇杆轴值是否发生了有效变化(使用阈值避免微小抖动)
220 // 阈值设置为2,只有当摇杆值变化达到或超过2个单位时才认为是有效变化
221 constexpr uint8_t kAxisValueChangeThreshold = 2;
222
223 // Check if left stick X or Y axis has significant change
224 // 检测左摇杆X轴或Y轴是否有显著变化
225 if (g_codex_pad.HasAxisValueChanged(CodexPad::Axis::kLeftStickX, kAxisValueChangeThreshold) ||
226 g_codex_pad.HasAxisValueChanged(CodexPad::Axis::kLeftStickY, kAxisValueChangeThreshold) ||
227 g_codex_pad.HasAxisValueChanged(CodexPad::Axis::kRightStickX, kAxisValueChangeThreshold) ||
228 g_codex_pad.HasAxisValueChanged(CodexPad::Axis::kRightStickY, kAxisValueChangeThreshold)) {
229 // Print current joystick axis values (0-255)
230 // 打印摇杆轴的当前值(0-255)
231 printf("L(X: %3" PRIu8 ", Y: %3" PRIu8 "), R(X: %3" PRIu8 ", Y: %3" PRIu8 ")\n",
232 g_codex_pad.axis_value(CodexPad::Axis::kLeftStickX), // 左摇杆X轴当前值 | Left stick X axis current value
233 g_codex_pad.axis_value(CodexPad::Axis::kLeftStickY), // 左摇杆Y轴当前值 | Left stick Y axis current value
234 g_codex_pad.axis_value(CodexPad::Axis::kRightStickX), // 右摇杆X轴当前值 | Right stick X axis current value
235 g_codex_pad.axis_value(CodexPad::Axis::kRightStickY) // 右摇杆Y轴当前值 | Right stick Y axis current value
236 );
237 }
238}
CodexPad主类
const std::array< uint8_t, 3 > remote_firmware_version() const
获取CodexPad的固件版本
const std::string & remote_model_number() const
获取CodexPad的型号
bool ScanAndConnect(const uint32_t button_mask)
扫描附近的 CodexPad 设备,并自动连接到一个按键状态与指定掩码匹配的设备。
@ kLeftStickX
左摇杆X轴
@ kRightStickY
右摇杆Y轴
@ kLeftStickY
左摇杆Y轴
@ kRightStickX
右摇杆X轴
bool pressed(const Button button) const
查询按键是否被按下
@ kSquareX
方形或者X
@ kCircleB
圆形或者B
@ kTriangleY
三角形或者Y
const std::string & remote_device_name() const
获取CodexPad的型号
NimBLEClient * ble_client() const
获取 BLE 客户端对象
uint8_t axis_value(const Axis axis) const
获取轴值
bool HasAxisValueChanged(const Axis axis, const uint8_t threshold) const
查询轴值是否发生变化
bool set_remote_tx_power(const TxPower power)
设置发射功率,连接状态下调用,立即生效于当前连接,下次连接生效
bool is_connected() const
是否连接
bool released(const Button button) const
查询按键是否被释放
void Init()
初始化
void Update()
更新,需要在Loop中不断调用
bool holding(const Button button) const
查询按键是否被持续按下