CodexPad Arduino Lib 2.2.1
Loading...
Searching...
No Matches
scan_and_connect.ino
Go to the documentation of this file.
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) alone to set the button mask. Pressing and holding the Home button will trigger a
38// device shutdown. If you need to use the Home button, it is recommended to use it in combination with other buttons (e.g., Home + Cross).
39// 【重要警告】请勿单独使用 `Button::kHome` (Home键) 来设置按钮掩码。因为按住Home键会触发设备关机。如需使用Home键,建议采用组合按键方式(例如 Home +
40// Cross)。
41
42// Example 1: The button mask to match - Only the Start button
43// 示例 1:需要匹配的按钮掩码 - 仅Start按钮
44// constexpr auto kExpectedButtonMask = CodexPad::ButtonMask(CodexPad::Button::kStart);
45
46// Example 2: The button mask to match - Start and CrossA buttons
47// 示例 2:需要匹配的按钮掩码 - Start 和 CrossA 按钮
48constexpr auto kExpectedButtonMask = CodexPad::ButtonMask(CodexPad::Button::kStart, CodexPad::Button::kCrossA);
49
50// Example 3: The button mask to match - Start, CrossA, and SquareX buttons
51// 示例 3:需要匹配的按钮掩码 - Start、CrossA 和 SquareX 按钮
52// constexpr auto kExpectedButtonMask = CodexPad::ButtonMask(CodexPad::Button::kStart, CodexPad::Button::kCrossA, CodexPad::Button::kSquareX);
53
54CodexPad g_codex_pad;
55
56/**
57 * Convert button constant to readable string name
58 * 将按钮枚举转换为可读的字符串名称
59 */
60std::string ButtonToString(CodexPad::Button button) {
61 switch (button) {
63 return "Up"; // 上按钮 | UP button
64 }
66 return "Down"; // 下按钮 | DOWN button
67 }
69 return "Left"; // 左按钮 | LEFT button
70 }
72 return "Right"; // 右按钮 | RIGHT button
73 }
75 return "Square(X)"; // 方形 或者 X 按钮 | SQUARE or X button
76 }
78 return "Triangle(Y)"; // 三角 或者 Y 按钮 | TRIANGLE or Y button
79 }
81 return "Cross(A)"; // 叉型 或者 A 按钮 | CROSS or A button
82 }
84 return "Circle(B)"; // 圆形 或者 B 按钮 | CIRCLE or B button
85 }
87 return "L1"; // L1按钮 | L1 button
88 }
90 return "L2"; // L2按钮 | L2 button
91 }
93 return "L3"; // L3按钮 | L3 button
94 }
96 return "R1"; // R1按钮 | R1 button
97 }
99 return "R2"; // R2按钮 | R2 button
100 }
102 return "R3"; // R3按钮 | R3 button
103 }
105 return "Select"; // 选择按钮 | SELECT button
106 }
108 return "Start"; // 开始按钮 | START button
109 }
111 return "Home"; // 首页按钮 | HOME button
112 }
113 default: {
114 return {}; // 未知按钮返回空字符串 | Unknown button returns empty string
115 }
116 }
117}
118
119void Connect() {
120 printf("Start to scan and connect, button mask: 0x%08X\n", kExpectedButtonMask);
121
122 while (!g_codex_pad.ScanAndConnect(kExpectedButtonMask)) {
123 printf("Retry to scan and connect, button mask: 0x%08X\n", kExpectedButtonMask);
124 }
125
126 printf("Remote device name: %s\n", g_codex_pad.remote_device_name().c_str());
127 printf("Remote model number: %s\n", g_codex_pad.remote_model_number().c_str());
128 printf("Remote firmware revision: %u.%u.%u\n", g_codex_pad.remote_firmware_version()[0], g_codex_pad.remote_firmware_version()[1],
129 g_codex_pad.remote_firmware_version()[2]);
130
131 if (const auto ble_client = g_codex_pad.ble_client(); ble_client != nullptr) {
132 printf("Remote Bluetooth Device Address: %s\n", ble_client->getPeerAddress().toString().c_str());
133 } else {
134 printf("Remote Bluetooth Device Address: unknown\n");
135 }
136
137 // Set transmission power to 0dBm
138 // Transmission power affects communication range and power consumption:
139 // Higher power provides longer range but consumes more battery
140 // Choose appropriate power level based on your application to balance range and battery life
141 // 设置发射功率为0dBm
142 // 发射功率影响通信距离和功耗:功率越高,通信距离越远,但功耗也越大
143 // 建议根据实际应用场景选择合适的功率等级以平衡距离和电池寿命
145 printf("Set remote tx power to 0dBm successfully\n");
146 }
147
148 printf("Connected\n");
149}
150} // namespace
151
152void setup() {
153 Serial.begin(115200);
154
155 printf("Init\n");
156 g_codex_pad.Init();
157
158 Connect();
159}
160
161void loop() {
162 // Important: Update() method must be called as frequently as possible in the loop, no delays should be added
163 // This method processes all received Bluetooth packets, delays will cause data loss and response lag
164 // For real-time control applications, high-frequency calls are essential to ensure prompt response to gamepad input
165 // 重要:Update()方法必须在循环中尽可能频繁地调用,不能添加延时
166 // 该方法负责处理所有接收到的蓝牙数据包,延时会导致数据丢失和响应延迟
167 // 对于实时控制应用,必须保持高频率调用以确保及时响应手柄输入
168 g_codex_pad.Update();
169
170 if (!g_codex_pad.is_connected()) {
171 printf("Disconnected, start to reconnect\n");
172 Connect();
173 return;
174 }
175
176 // Detect state changes for all buttons
177 // Use pressed(), released(), holding() methods to detect different button states
178 // 检测所有按钮的状态变化
179 // 使用pressed(), released(), holding()方法检测按钮的不同状态
184 // Check if button was just pressed (transition from released to pressed)
185 // 检测按钮是否刚刚按下(从弹起变为按下)
186 if (g_codex_pad.pressed(button)) {
187 printf("Button %s: pressed\n", ButtonToString(button).c_str());
188 }
189
190 // Check if button was just released (transition from pressed to released)
191 // 检测按钮是否刚刚释放(从按下变为弹起)
192 else if (g_codex_pad.released(button)) {
193 printf("Button %s: released\n", ButtonToString(button).c_str());
194 }
195
196 // Check if button is holding
197 // 检测按钮是否持续按下状态
198 else if (g_codex_pad.holding(button)) {
199 printf("Button %s: holding\n", ButtonToString(button).c_str());
200 }
201 }
202
203 // Check if joystick axis values have changed significantly (using threshold to avoid minor jitter)
204 // Threshold is set to 2, only consider changes equal to or greater than 2 units as significant
205 // 检测摇杆轴值是否发生了有效变化(使用阈值避免微小抖动)
206 // 阈值设置为2,只有当摇杆值变化达到或超过2个单位时才认为是有效变化
207 constexpr uint8_t kAxisValueChangeThreshold = 2;
208
209 // Check if left stick X or Y axis has significant change
210 // 检测左摇杆X轴或Y轴是否有显著变化
211 if (g_codex_pad.HasAxisValueChanged(CodexPad::Axis::kLeftStickX, kAxisValueChangeThreshold) ||
212 g_codex_pad.HasAxisValueChanged(CodexPad::Axis::kLeftStickY, kAxisValueChangeThreshold) ||
213 g_codex_pad.HasAxisValueChanged(CodexPad::Axis::kRightStickX, kAxisValueChangeThreshold) ||
214 g_codex_pad.HasAxisValueChanged(CodexPad::Axis::kRightStickY, kAxisValueChangeThreshold)) {
215 // Print current joystick axis values (0-255)
216 // 打印摇杆轴的当前值(0-255)
217 printf("L(X: %3" PRIu8 ", Y: %3" PRIu8 "), R(X: %3" PRIu8 ", Y: %3" PRIu8 ")\n",
218 g_codex_pad.axis_value(CodexPad::Axis::kLeftStickX), // 左摇杆X轴当前值 | Left stick X axis current value
219 g_codex_pad.axis_value(CodexPad::Axis::kLeftStickY), // 左摇杆Y轴当前值 | Left stick Y axis current value
220 g_codex_pad.axis_value(CodexPad::Axis::kRightStickX), // 右摇杆X轴当前值 | Right stick X axis current value
221 g_codex_pad.axis_value(CodexPad::Axis::kRightStickY) // 右摇杆Y轴当前值 | Right stick Y axis current value
222 );
223 }
224}
CodexPad main class.
Definition codex_pad.h:46
const std::array< uint8_t, 3 > remote_firmware_version() const
Get firmware version of the CodexPad.
Definition codex_pad.h:734
const std::string & remote_model_number() const
Get model number of the CodexPad.
Definition codex_pad.h:722
bool ScanAndConnect(const uint32_t button_mask)
Scans for nearby CodexPad devices and automatically connects to a device whose button state matches t...
Definition codex_pad.cpp:51
@ kLeftStickX
Left stick X axis.
Definition codex_pad.h:411
@ kRightStickY
Right stick Y axis.
Definition codex_pad.h:441
@ kLeftStickY
Left stick Y axis.
Definition codex_pad.h:421
@ kRightStickX
Right stick X axis.
Definition codex_pad.h:431
bool pressed(const Button button) const
check if a button is pressed
@ kSelect
Select.
Definition codex_pad.h:369
@ kCrossA
Cross or A.
Definition codex_pad.h:289
@ kSquareX
Square or X.
Definition codex_pad.h:269
@ kCircleB
Circle or B.
Definition codex_pad.h:299
@ kTriangleY
Triangle or Y.
Definition codex_pad.h:279
const std::string & remote_device_name() const
Get model number of the CodexPad.
Definition codex_pad.h:710
NimBLEClient * ble_client() const
Get the BLE client object.
Definition codex_pad.h:903
uint8_t axis_value(const Axis axis) const
Get axis value.
bool HasAxisValueChanged(const Axis axis, const uint8_t threshold) const
check if an axis value has changed
bool set_remote_tx_power(const TxPower power)
Set transmission power, only effective when connected, immediately effective for current connection,...
bool is_connected() const
Is connected.
bool released(const Button button) const
check if a button is released
void Init()
Initialize.
Definition codex_pad.cpp:34
void Update()
Update, need to be called in Loop.
bool holding(const Button button) const
check if a button is held