CodexPadFrameDecoder Arduino Lib 1.0.3

Loading...
Searching...
No Matches
inputs_detection.ino
Go to the documentation of this file.
1/**
2 * @~Chinese
3 * @file ble_uno_or_nl_16_module/inputs_detection/inputs_detection.ino
4 * @example ble_uno_or_nl_16_module/inputs_detection/inputs_detection.ino
5 * @brief 演示如何检测已连接的 CodexPad 设备的实时按钮状态与摇杆移动。
6 * @details 本示例先通过 AT 指令与指定的 CodexPad 设备建立蓝牙连接，然后持续监控所有用户输入。
7 * 它展示了三种不同的按钮状态检测： **按下** (瞬间按下)、 **释放** (瞬间释放)和 **持续按住** 。
8 * 同时，它监控模拟摇杆轴，当检测到超过设定阈值的显著变化时打印其值，从而过滤微小抖动。
9 * @note 必须在主循环中尽可能频繁地调用 `Update()` 方法，且不得添加延时，以确保实时响应性并防止数据包丢失。
10 * @see CodexPadFrameDecoder::Update
11 * @see CodexPadFrameDecoder::pressed
12 * @see CodexPadFrameDecoder::released
13 * @see CodexPadFrameDecoder::holding
14 * @see CodexPadFrameDecoder::HasAxisValueChanged
15 * @see CodexPadFrameDecoder::axis_value
16 */
17/**
18 * @~English
19 * @file ble_uno_or_nl_16_module/inputs_detection/inputs_detection.ino
20 * @example ble_uno_or_nl_16_module/inputs_detection/inputs_detection.ino
21 * @brief Demonstrate how to detect real-time button status and joystick movement of connected CodexPad devices.
22 * @details This example first sends AT commands to establish a BLE connection to a CodexPad device (by Bluetooth Device Address), then continuously
23 * monitors all user inputs. It showcases the detection of three distinct button states: **pressed** (momentary press), **released** (momentary
24 * release), and **holding** (sustained press). It also monitors the analog joystick axes and prints their values when a significant change beyond a
25 * set threshold is detected, filtering out minor jitter.
26 * @note The `Update()` method must be called as frequently as possible within the main loop without delays to ensure real‑time
27 * responsiveness and prevent data packet loss.
28 * @see CodexPadFrameDecoder::Update
29 * @see CodexPadFrameDecoder::pressed
30 * @see CodexPadFrameDecoder::released
31 * @see CodexPadFrameDecoder::holding
32 * @see CodexPadFrameDecoder::HasAxisValueChanged
33 * @see CodexPadFrameDecoder::axis_value
34 */
35
36#include <SoftwareSerial.h>
37
38#include "codex_pad_frame_decoder.h"
39
40 namespace {
41// 调试串口引脚定义。
42// 将外部串口工具连接到这些引脚以查看调试输出。
43// Debug serial port pin definitions.
44// Connect external serial port tools to these pins to view debug output.
45 constexpr uint8_t kDebugSerialRxPin = 6; // 调试输出接收引脚 | RX pin for debug output
46 constexpr uint8_t kDebugSerialTxPin = 5; // 调试输出发送引脚 | TX pin for debug output
47
48// 摇杆轴变化检测的阈值。当前值与上一帧值的绝对差值达到此值（或到达边界0/255）时才被视为有效变化，用于过滤微小抖动。
49// Threshold for joystick axis change detection. Only when the absolute difference between the current and previous axis value reaches this value
50// (or the value hits boundaries 0/255) will it be reported as a significant change.
51 constexpr uint8_t kAxisThreshold = 2;
52
53// 替换为你的 CodexPad 的 Bluetooth device address。
54// Replace with your CodexPad device's Bluetooth device address.
55 const String kBluetoothDeviceAddress = "0C:3D:5E:9D:80:99";
56
57// 与蓝牙模块通信的串口波特率（请查阅模块数据手册，替换为模块对应的波特率）。
58// The serial port baud rate for communication with the Bluetooth module (please refer to the module data manual, replace with the corresponding baud
59// rate for the module).
60 constexpr uint32_t kBluetoothModuleSerialBaudRate = 115200;
61
62 const CodexPadFrameDecoder::Button kAllButtons[] = {CodexPadFrameDecoder::Button::kUp,
63 CodexPadFrameDecoder::Button::kDown,
64 CodexPadFrameDecoder::Button::kLeft,
65 CodexPadFrameDecoder::Button::kRight,
66 CodexPadFrameDecoder::Button::kSquareX,
67 CodexPadFrameDecoder::Button::kTriangleY,
68 CodexPadFrameDecoder::Button::kCrossA,
69 CodexPadFrameDecoder::Button::kCircleB,
70 CodexPadFrameDecoder::Button::kL1,
71 CodexPadFrameDecoder::Button::kL2,
72 CodexPadFrameDecoder::Button::kL3,
73 CodexPadFrameDecoder::Button::kR1,
74 CodexPadFrameDecoder::Button::kR2,
75 CodexPadFrameDecoder::Button::kR3,
76 CodexPadFrameDecoder::Button::kSelect,
77 CodexPadFrameDecoder::Button::kStart,
78 CodexPadFrameDecoder::Button::kHome};
79
80// 用于调试输出的软串口。
81// A soft serial port used for debugging output.
82SoftwareSerial g_debug_serial(kDebugSerialRxPin, kDebugSerialTxPin);
83
84// 此处解码器传入的串口实例，与 Connect() 中传入的为同一个串口实例。
85// The serial instance passed in by the decoder here is the same as the one passed in Connect().
86 CodexPadFrameDecoder g_codex_pad_frame_decoder(Serial);
87
88/**
89 * 将按钮枚举值转换为可读的字符串。
90 * Convert a Button enumeration value to a human-readable string.
91 */
92 const String ButtonToString(CodexPadFrameDecoder::Button button) {
93 switch (button) {
94 case CodexPadFrameDecoder::Button::kUp: {
95 return "Up"; // 上按钮 | UP button
96 }
97 case CodexPadFrameDecoder::Button::kDown: {
98 return "Down"; // 下按钮 | DOWN button
99 }
100 case CodexPadFrameDecoder::Button::kLeft: {
101 return "Left"; // 左按钮 | LEFT button
102 }
103 case CodexPadFrameDecoder::Button::kRight: {
104 return "Right"; // 右按钮 | RIGHT button
105 }
106 case CodexPadFrameDecoder::Button::kSquareX: {
107 return "Square(X)"; // 方形 或者 X 按钮 | SQUARE or X button
108 }
109 case CodexPadFrameDecoder::Button::kTriangleY: {
110 return "Triangle(Y)"; // 三角 或者 Y 按钮 | TRIANGLE or Y button
111 }
112 case CodexPadFrameDecoder::Button::kCrossA: {
113 return "Cross(A)"; // 叉形 或者 A 按钮 | CROSS or A button
114 }
115 case CodexPadFrameDecoder::Button::kCircleB: {
116 return "Circle(B)"; // 圆形 或者 B 按钮 | CIRCLE or B button
117 }
118 case CodexPadFrameDecoder::Button::kL1: {
119 return "L1"; // L1按钮 | L1 button
120 }
121 case CodexPadFrameDecoder::Button::kL2: {
122 return "L2"; // L2按钮 | L2 button
123 }
124 case CodexPadFrameDecoder::Button::kL3: {
125 return "L3"; // L3按钮 | L3 button
126 }
127 case CodexPadFrameDecoder::Button::kR1: {
128 return "R1"; // R1按钮 | R1 button
129 }
130 case CodexPadFrameDecoder::Button::kR2: {
131 return "R2"; // R2按钮 | R2 button
132 }
133 case CodexPadFrameDecoder::Button::kR3: {
134 return "R3"; // R3按钮 | R3 button
135 }
136 case CodexPadFrameDecoder::Button::kSelect: {
137 return "Select"; // 选择按钮 | SELECT button
138 }
139 case CodexPadFrameDecoder::Button::kStart: {
140 return "Start"; // 开始按钮 | START button
141 }
142 case CodexPadFrameDecoder::Button::kHome: {
143 return "Home"; // 首页按钮 | HOME button
144 }
145 default: {
146 return {}; // 未知按钮返回空字符串 | Unknown button returns empty string
147 }
148 }
149}
150
151/**
152 * @~Chinese
153 * @brief 向蓝牙模块发送 AT 指令以建立 BLE 连接。
154 * @details 依次执行 AT 指令序列，将蓝牙模块配置为主机模式并连接到指定 MAC 地址的目标设备。
155 * 指令顺序：AT+DISCON → AT+RESET → AT+ECHO=0 → AT+ROLE=0 → AT+AUTOCON=0 → AT+CON=<mac>。
156 * @param[in] bluetooth_stream 连接蓝牙模块的 Stream 对象。
157 * 注意：此对象必须与传入 CodexPadFrameDecoder 的 Stream 是同一个实例（如 Serial），
158 * 因为解码器正是从这同一个串口读取手柄发来的数据。
159 * @param[in] bluetooth_device_address 目标设备的 MAC 地址，格式为 "XX:XX:XX:XX:XX:XX"。
160 */
161/**
162 * @~English
163 * @brief Send AT commands to the Bluetooth module to establish a BLE connection.
164 * @details Executes a sequence of AT commands to configure the Bluetooth module as master and connect to the target device
165 * at the specified MAC address.
166 * Command order: AT+DISCON → AT+RESET → AT+ECHO=0 → AT+ROLE=0 → AT+AUTOCON=0 → AT+CON=<mac>.
167 * @param[in] bluetooth_stream Stream connected to the Bluetooth module.
168 * Note: This must be the same Stream instance that is passed to the CodexPadFrameDecoder
169 * (e.g., Serial), as the decoder reads incoming data from this same serial port.
170 * @param[in] bluetooth_device_address MAC address of the target device in format "XX:XX:XX:XX:XX:XX".
171 */
172 void Connect(Stream &bluetooth_stream, const String &bluetooth_device_address) {
173 if (bluetooth_device_address.length() != 17 || bluetooth_device_address[2] != ':' || bluetooth_device_address[5] != ':' ||
174 bluetooth_device_address[8] != ':' || bluetooth_device_address[11] != ':' || bluetooth_device_address[14] != ':') {
175 g_debug_serial.println("Error: Invalid MAC address format. Expected: XX:XX:XX:XX:XX:XX");
176 while (true);
177 }
178
179 g_debug_serial.print("Start to connect ");
180 g_debug_serial.println(kBluetoothDeviceAddress);
181
182 // 模块可能处于连接状态，先发送断开指令，确保模块是未连接状态。
183 // The module may be in a connected state. Send the disconnection command first to ensure the module is in an unconnected state.
184 bluetooth_stream.println("AT+DISCON");
185 delay(100);
186
187 // 软件复位蓝牙芯片，清除所有配对和配置数据。
188 // Software reset BLE chip, clear all pairing and configuration data.
189 bluetooth_stream.println("AT+RESET");
190 delay(100);
191
192 // 关闭AT信息回显。
193 // Close AT information echo.
194 bluetooth_stream.println("AT+ECHO=0");
195 delay(100);
196
197 // 设置模块为主机模式，使其能够主动连接从机蓝牙。
198 // Set the module to host mode so that it can actively connect to the BLE of the slave device.
199 bluetooth_stream.println("AT+ROLE=0");
200 delay(100);
201
202 // 关闭模块的蓝牙自动连接模式。
203 // Disable the module's automatic Bluetooth connection mode.
204 bluetooth_stream.println("AT+AUTOCON=0");
205 delay(100);
206
207 // 使用指定的MAC地址发起与从机蓝牙连接。
208 // Initiate BLE connection with the slave using the specified MAC address.
209 bluetooth_stream.print("AT+CON=");
210 bluetooth_stream.println(bluetooth_device_address);
211 delay(100);
212
213 g_debug_serial.println("Connected");
214}
215} // namespace
216
217 void setup() {
218 g_debug_serial.begin(115200);
219
220 Serial.begin(kBluetoothModuleSerialBaudRate);
221
222 Connect(Serial, kBluetoothDeviceAddress);
223}
224
225 void loop() {
226 // 重要：Update()方法必须在循环中尽可能频繁地调用，不能添加延时。
227 // 该方法负责处理所有接收到的蓝牙数据包，延时会导致数据丢失和响应延迟。
228 // 对于实时控制应用，必须保持高频率调用以确保及时响应手柄输入。
229 // Important: Update() method must be called as frequently as possible in the loop, no delays should be added.
230 // This method processes all received Bluetooth packets, delays will cause data loss and response lag.
231 // For real-time control applications, high-frequency calls are essential to ensure prompt response to gamepad input.
232 g_codex_pad_frame_decoder.Update();
233
234 for (auto button : kAllButtons) {
235 // 检测按钮是否刚刚按下（从弹起变为按下）。
236 // Check if button was just pressed (transition from released to pressed).
237 if (g_codex_pad_frame_decoder.pressed(button)) {
238 g_debug_serial.print("Button ");
239 g_debug_serial.print(ButtonToString(button));
240 g_debug_serial.println(": pressed");
241 }
242
243 // 检测按钮是否刚刚释放（从按下变为弹起）。
244 // Check if button was just released (transition from pressed to released).
245 else if (g_codex_pad_frame_decoder.released(button)) {
246 g_debug_serial.print("Button ");
247 g_debug_serial.print(ButtonToString(button));
248 g_debug_serial.println(": released");
249 }
250
251 // 检测按钮是否持续按下状态。
252 // Check if button is holding.
253 else if (g_codex_pad_frame_decoder.holding(button)) {
254 g_debug_serial.print("Button ");
255 g_debug_serial.print(ButtonToString(button));
256 g_debug_serial.println(": holding");
257 }
258 }
259
260 // 检测左右两个摇杆的X轴或Y轴是否有显著变化。
261 // Check if left and right sticks X or Y axes have significant changes.
262 if (g_codex_pad_frame_decoder.HasAxisValueChanged(CodexPadFrameDecoder::Axis::kLeftStickX, kAxisThreshold) ||
263 g_codex_pad_frame_decoder.HasAxisValueChanged(CodexPadFrameDecoder::Axis::kLeftStickY, kAxisThreshold) ||
264 g_codex_pad_frame_decoder.HasAxisValueChanged(CodexPadFrameDecoder::Axis::kRightStickX, kAxisThreshold) ||
265 g_codex_pad_frame_decoder.HasAxisValueChanged(CodexPadFrameDecoder::Axis::kRightStickY, kAxisThreshold)) {
266 // 打印摇杆轴的当前值（0-255）。
267 // Print current joystick axis values (0-255).
268 g_debug_serial.print("L(X:");
269 g_debug_serial.print(
270 g_codex_pad_frame_decoder.axis_value(CodexPadFrameDecoder::Axis::kLeftStickX)); // 左摇杆X轴当前值 | Left stick X axis current value
271 g_debug_serial.print(", Y:");
272 g_debug_serial.print(
273 g_codex_pad_frame_decoder.axis_value(CodexPadFrameDecoder::Axis::kLeftStickY)); // 左摇杆Y轴当前值 | Left stick Y axis current value
274 g_debug_serial.print("), R(X:");
275 g_debug_serial.print(
276 g_codex_pad_frame_decoder.axis_value(CodexPadFrameDecoder::Axis::kRightStickX)); // 右摇杆X轴当前值 | Right stick X axis current value
277 g_debug_serial.print(", Y:");
278 g_debug_serial.print(
279 g_codex_pad_frame_decoder.axis_value(CodexPadFrameDecoder::Axis::kRightStickY)); // 右摇杆Y轴当前值 | Right stick Y axis current value
280 g_debug_serial.println(")");
281 }
282}
CodexPadFrameDecoder
CodexPad controller data frame decoding main class.
Definition codex_pad_frame_decoder.h:29
CodexPadFrameDecoder::Button
Button
Gamepad button mask enumeration.
Definition codex_pad_frame_decoder.h:71
CodexPadFrameDecoder::Button::kSelect
@ kSelect
Select.
Definition codex_pad_frame_decoder.h:220
CodexPadFrameDecoder::Button::kStart
@ kStart
Start.
Definition codex_pad_frame_decoder.h:230
CodexPadFrameDecoder::Button::kL2
@ kL2
L2.
Definition codex_pad_frame_decoder.h:170
CodexPadFrameDecoder::Button::kL1
@ kL1
L1.
Definition codex_pad_frame_decoder.h:160
CodexPadFrameDecoder::Button::kCrossA
@ kCrossA
Cross or A.
Definition codex_pad_frame_decoder.h:140
CodexPadFrameDecoder::Button::kLeft
@ kLeft
Left.
Definition codex_pad_frame_decoder.h:100
CodexPadFrameDecoder::Button::kRight
@ kRight
Right.
Definition codex_pad_frame_decoder.h:110
CodexPadFrameDecoder::Button::kHome
@ kHome
Home.
Definition codex_pad_frame_decoder.h:240
CodexPadFrameDecoder::Button::kL3
@ kL3
L3.
Definition codex_pad_frame_decoder.h:180
CodexPadFrameDecoder::Button::kDown
@ kDown
Down.
Definition codex_pad_frame_decoder.h:90
CodexPadFrameDecoder::Button::kSquareX
@ kSquareX
Square or X.
Definition codex_pad_frame_decoder.h:120
CodexPadFrameDecoder::Button::kR3
@ kR3
R3.
Definition codex_pad_frame_decoder.h:210
CodexPadFrameDecoder::Button::kR2
@ kR2
R2.
Definition codex_pad_frame_decoder.h:200
CodexPadFrameDecoder::Button::kUp
@ kUp
Up.
Definition codex_pad_frame_decoder.h:80
CodexPadFrameDecoder::Button::kCircleB
@ kCircleB
Circle or B.
Definition codex_pad_frame_decoder.h:150
CodexPadFrameDecoder::Button::kR1
@ kR1
R1.
Definition codex_pad_frame_decoder.h:190
CodexPadFrameDecoder::Button::kTriangleY
@ kTriangleY
Triangle or Y.
Definition codex_pad_frame_decoder.h:130
CodexPadFrameDecoder::Axis::kLeftStickX
@ kLeftStickX
Left stick X axis.
Definition codex_pad_frame_decoder.h:262
CodexPadFrameDecoder::Axis::kRightStickY
@ kRightStickY
Right stick Y axis.
Definition codex_pad_frame_decoder.h:292
CodexPadFrameDecoder::Axis::kLeftStickY
@ kLeftStickY
Left stick Y axis.
Definition codex_pad_frame_decoder.h:272
CodexPadFrameDecoder::Axis::kRightStickX
@ kRightStickX
Right stick X axis.
Definition codex_pad_frame_decoder.h:282
codex_pad_frame_decoder.h