CodexPadFrameDecoder Arduino Lib 1.0.3
Loading...
Searching...
No Matches
codex_pad_frame_decoder.h
Go to the documentation of this file.
1#pragma once
2
3#ifndef _CODEX_PAD_FRAME_DECODER_H_
4#define _CODEX_PAD_FRAME_DECODER_H_
5
6#include <Stream.h>
7
8#include "robust_frame.h"
9
10/**
11 * @file codex_pad_frame_decoder.h
12 */
13
14/**
15 * @~Chinese
16 * @class CodexPadFrameDecoder
17 * @brief CodexPad 手柄数据帧解码主类。
18 * @details 通过外部传入的 Stream 对象获取原始字节流,内部使用 robust_frame 协议解析器完成帧同步、转义还原和 CRC
19 * 校验,成功接收完整的有效载荷后,输出按键状态和摇杆轴值。
20 */
21/**
22 * @~English
23 * @class CodexPadFrameDecoder
24 * @brief CodexPad controller data frame decoding main class.
25 * @details It takes a Stream object as input to read the raw byte stream, and internally uses the robust_frame protocol parser for frame
26 * synchronization, escape sequence restoration, and CRC validation. Upon successfully receiving a complete and valid payload, it outputs
27 * button states and joystick axis values.
28 */
30 public:
31 /**
32 * @~Chinese
33 * @brief 摇杆轴值的数量。
34 */
35 /**
36 * @~English
37 * @brief Number of axis values.
38 */
39 static constexpr size_t kAxisValueNum = 4;
40
41 /**
42 * @~Chinese
43 * @brief 摇杆轴的中心值(静止时的典型值)。
44 */
45 /**
46 * @~English
47 * @brief Center value of joystick axes (typical value at rest).
48 */
49 static constexpr uint8_t kAxisCenter = 0x80;
50
51 /**
52 * @~Chinese
53 * @brief 手柄输入报告的类型标识(有效载荷的第一个字节)。
54 */
55 /**
56 * @~English
57 * @brief Input report type identifier for the gamepad (the first byte of the payload).
58 */
59 static constexpr uint8_t kPayloadType = 0x01;
60
61 /**
62 * @~Chinese
63 * @enum Button
64 * @brief 手柄按键掩码枚举。
65 */
66 /**
67 * @~English
68 * @enum Button
69 * @brief Gamepad button mask enumeration.
70 */
71 enum class Button : uint32_t {
72 /**
73 * @~Chinese
74 * @brief 上。
75 */
76 /**
77 * @~English
78 * @brief Up.
79 */
80 kUp = uint32_t{1} << 0,
81
82 /**
83 * @~Chinese
84 * @brief 下。
85 */
86 /**
87 * @~English
88 * @brief Down.
89 */
90 kDown = uint32_t{1} << 1,
91
92 /**
93 * @~Chinese
94 * @brief 左。
95 */
96 /**
97 * @~English
98 * @brief Left.
99 */
100 kLeft = uint32_t{1} << 2,
101
102 /**
103 * @~Chinese
104 * @brief 右。
105 */
106 /**
107 * @~English
108 * @brief Right.
109 */
110 kRight = uint32_t{1} << 3,
111
112 /**
113 * @~Chinese
114 * @brief 方形 或者 X。
115 */
116 /**
117 * @~English
118 * @brief Square or X.
119 */
120 kSquareX = uint32_t{1} << 4,
121
122 /**
123 * @~Chinese
124 * @brief 三角形 或者 Y。
125 */
126 /**
127 * @~English
128 * @brief Triangle or Y.
129 */
130 kTriangleY = uint32_t{1} << 5,
131
132 /**
133 * @~Chinese
134 * @brief 叉形 或者 A。
135 */
136 /**
137 * @~English
138 * @brief Cross or A.
139 */
140 kCrossA = uint32_t{1} << 6,
141
142 /**
143 * @~Chinese
144 * @brief 圆形 或者 B。
145 */
146 /**
147 * @~English
148 * @brief Circle or B.
149 */
150 kCircleB = uint32_t{1} << 7,
151
152 /**
153 * @~Chinese
154 * @brief L1。
155 */
156 /**
157 * @~English
158 * @brief L1.
159 */
160 kL1 = uint32_t{1} << 8,
161
162 /**
163 * @~Chinese
164 * @brief L2。
165 */
166 /**
167 * @~English
168 * @brief L2.
169 */
170 kL2 = uint32_t{1} << 9,
171
172 /**
173 * @~Chinese
174 * @brief L3。
175 */
176 /**
177 * @~English
178 * @brief L3.
179 */
180 kL3 = uint32_t{1} << 10,
181
182 /**
183 * @~Chinese
184 * @brief R1。
185 */
186 /**
187 * @~English
188 * @brief R1.
189 */
190 kR1 = uint32_t{1} << 11,
191
192 /**
193 * @~Chinese
194 * @brief R2。
195 */
196 /**
197 * @~English
198 * @brief R2.
199 */
200 kR2 = uint32_t{1} << 12,
201
202 /**
203 * @~Chinese
204 * @brief R3。
205 */
206 /**
207 * @~English
208 * @brief R3.
209 */
210 kR3 = uint32_t{1} << 13,
211
212 /**
213 * @~Chinese
214 * @brief 选择。
215 */
216 /**
217 * @~English
218 * @brief Select.
219 */
220 kSelect = uint32_t{1} << 14,
221
222 /**
223 * @~Chinese
224 * @brief 开始。
225 */
226 /**
227 * @~English
228 * @brief Start.
229 */
230 kStart = uint32_t{1} << 15,
231
232 /**
233 * @~Chinese
234 * @brief 首页。
235 */
236 /**
237 * @~English
238 * @brief Home.
239 */
240 kHome = uint32_t{1} << 16,
241 };
242
243 /**
244 * @~Chinese
245 * @enum Axis
246 * @brief 摇杆轴索引枚举。
247 */
248 /**
249 * @~English
250 * @enum Axis
251 * @brief Joystick axis index enumeration.
252 */
253 enum class Axis : size_t {
254 /**
255 * @~Chinese
256 * @brief 左摇杆X轴。
257 */
258 /**
259 * @~English
260 * @brief Left stick X axis.
261 */
263
264 /**
265 * @~Chinese
266 * @brief 左摇杆Y轴。
267 */
268 /**
269 * @~English
270 * @brief Left stick Y axis.
271 */
273
274 /**
275 * @~Chinese
276 * @brief 右摇杆X轴。
277 */
278 /**
279 * @~English
280 * @brief Right stick X axis.
281 */
283
284 /**
285 * @~Chinese
286 * @brief 右摇杆Y轴。
287 */
288 /**
289 * @~English
290 * @brief Right stick Y axis.
291 */
293 };
294
295 /**
296 * @~Chinese
297 * @brief 构造函数。
298 * @param[in] stream 用于读取数据字节流的 Stream 对象引用。
299 */
300 /**
301 * @~English
302 * @brief Constructor.
303 * @param[in] stream Reference to a Stream object for reading data byte stream.
304 */
305 CodexPadFrameDecoder(Stream &stream);
306
307 /**
308 * @~Chinese
309 * @brief 更新解码器状态。需要在主循环中不断调用此函数,以喂入并解析字节流。
310 */
311 /**
312 * @~English
313 * @brief Update the decoder state. This function must be called continuously in the main loop
314 * to feed and parse the byte stream.
315 */
316 void Update();
317
318 /**
319 * @~Chinese
320 * @brief 查询按键是否被按下。
321 * @retval true 按键被按下。
322 * @retval false 按键没有被按下。
323 */
324 /**
325 * @~English
326 * @brief check if a button is pressed.
327 * @retval true if the button is pressed.
328 * @retval false if the button is not pressed.
329 */
330 bool pressed(const Button button) const;
331
332 /**
333 * @~Chinese
334 * @brief 查询按键是否被释放。
335 * @retval true 按键被释放。
336 * @retval false 按键没有被释放。
337 */
338 /**
339 * @~English
340 * @brief check if a button is released.
341 * @retval true if the button is released.
342 * @retval false if the button is not released.
343 */
344 bool released(const Button button) const;
345
346 /**
347 * @~Chinese
348 * @brief 查询按键是否被持续按下。
349 * @retval true 按键被持续按下。
350 * @retval false 按键没有被持续按下。
351 */
352 /**
353 * @~English
354 * @brief check if a button is held.
355 * @retval true if the button is held.
356 * @retval false if the button is not held.
357 */
358 bool holding(const Button button) const;
359
360 /**
361 * @~Chinese
362 * @brief 查询按键是否被按下或持续按下。
363 * @retval true 按键被按下或持续按下。
364 * @retval false 按键没有被按下或持续按下。
365 */
366 /**
367 * @~English
368 * @brief check if a button is pressed or held.
369 * @retval true if the button is pressed or held.
370 * @retval false if the button is not pressed or held.
371 */
372 bool button_state(const Button button) const;
373
374 /**
375 * @~Chinese
376 * @brief 以位掩码形式获取所有按键的当前状态。
377 * @return 一个32位无符号整数,每一位(bit)表示 @ref Button 枚举中对应按键的状态(1为按下,0为未按下)。
378 * 位的分配从最低有效位(LSB,第0位)开始,依次对应 @ref Button 中的各个值。
379 * 可使用位与操作 (&) 配合具体的 @ref Button 枚举值来检查特定按键状态。
380 * 示例:
381 * @code
382 * const uint32_t button_states = g_codex_pad_frame_decoder.button_states();
383 * if ((button_states & CodexPadFrameDecoder::Button::kUp)) != 0) {
384 * // 方向上按键被按下
385 * }
386 * @endcode
387 */
388 /**
389 * @~English
390 * @brief Get all button states, return a 32-bit unsigned integer where each bit represents the state of a specific button.
391 * @return A 32-bit unsigned integer where each bit represents the state of a specific button.
392 * The bits are from the least significant bit (LSB, bit 0) to the most significant bit (MSB, bit 31).
393 * You can use bit-and (&) operator to check specific button states.
394 * Example:
395 * @code
396 * const uint32_t button_states = g_codex_pad_frame_decoder.button_states();
397 * if ((button_states & CodexPadFrameDecoder::Button::kUp) != 0) {
398 * // Up button is pressed
399 * }
400 * @endcode
401 */
402 uint32_t button_states() const;
403
404 /**
405 * @~Chinese
406 * @brief 获取指定摇杆轴的原始值(0~255)。
407 * @param[in] axis 要读取的轴。
408 * @return 该轴的当前值,中心为 0x80。
409 */
410 /**
411 * @~English
412 * @brief Get the raw value (0~255) of a specified joystick axis.
413 * @param[in] axis The axis to read.
414 * @return The current value of the axis, with center at 0x80.
415 */
416 uint8_t axis_value(const Axis axis) const;
417
418 /**
419 * @~Chinese
420 * @brief 获取所有模拟轴的当前值(返回只读数组指针)。
421 * @details 返回指向内部 4 字节数组的 const 指针,索引与 Axis 枚举对应关系:
422 * - 索引 0:左摇杆 X 轴 (Axis::kLeftStickX)
423 * - 索引 1:左摇杆 Y 轴 (Axis::kLeftStickY)
424 * - 索引 2:右摇杆 X 轴 (Axis::kRightStickX)
425 * - 索引 3:右摇杆 Y 轴 (Axis::kRightStickY)
426 * 每个值的范围 0~255,中心位置为 128 (0x80)。
427 * @return const uint8_t* 指向 4 字节轴值数组的只读指针。
428 * @note 返回的指针在 CodexPadFrameDecoder 对象生命周期内有效,下次调用 Update() 后内容会更新。
429 *
430 * 示例:
431 * @code
432 * const uint8_t *axes = g_codex_pad_frame_decoder.axis_values();
433 * uint8_t left_stick_x = axes[static_cast<size_t>(CodexPadFrameDecoder::Axis::kLeftStickX)];
434 * uint8_t left_stick_y = axes[static_cast<size_t>(CodexPadFrameDecoder::Axis::kLeftStickY)];
435 * @endcode
436 */
437 /**
438 * @~English
439 * @brief Get current values of all analog axes (returns a read-only array pointer).
440 * @details Returns a const pointer to the internal 4-byte array. Indices correspond to the Axis enumeration:
441 * - Index 0: Left stick X axis (Axis::kLeftStickX)
442 * - Index 1: Left stick Y axis (Axis::kLeftStickY)
443 * - Index 2: Right stick X axis (Axis::kRightStickX)
444 * - Index 3: Right stick Y axis (Axis::kRightStickY)
445 * Each value ranges from 0 to 255, with the neutral center at 128 (0x80).
446 * @return const uint8_t* Read-only pointer to the 4-byte axis value array.
447 * @note The returned pointer is valid for the lifetime of the CodexPadFrameDecoder object.
448 * Content will be updated after the next call to Update().
449 *
450 * Example:
451 * @code
452 * const uint8_t *axes = g_codex_pad_frame_decoder.axis_values();
453 * uint8_t left_stick_x = axes[static_cast<size_t>(CodexPadFrameDecoder::Axis::kLeftStickX)];
454 * uint8_t left_stick_y = axes[static_cast<size_t>(CodexPadFrameDecoder::Axis::kLeftStickY)];
455 * @endcode
456 */
457 const uint8_t *axis_values() const;
458
459 /**
460 * @~Chinese
461 * @brief 查询轴值是否发生变化。
462 * @param[in] axis 轴。
463 * @param[in] threshold 阈值。
464 * @retval true 轴值发生变化。
465 * @retval false 轴值未发生变化。
466 */
467 /**
468 * @~English
469 * @brief check if an axis value has changed.
470 * @param[in] axis Axis.
471 * @param[in] threshold Threshold.
472 * @retval true if the axis value has changed.
473 * @retval false if the axis value has not changed.
474 */
475 bool HasAxisValueChanged(const Axis axis, const uint8_t threshold) const;
476
477 private:
479 CodexPadFrameDecoder &operator=(const CodexPadFrameDecoder &) = delete;
480
481 struct Inputs {
482 uint32_t button_states = 0;
483 uint8_t axis_values[kAxisValueNum] = {kAxisCenter, kAxisCenter, kAxisCenter, kAxisCenter};
484 };
485
486 void OnFrame(const uint8_t *data);
487
488 static void OnFrameReceived(const uint8_t *data, void *user_data);
489
490 Inputs prev_inputs_;
491 Inputs current_inputs_;
492
493 robust_frame::Parser parser_;
494
495 Stream &stream_;
496};
497
498#endif // _CODEX_PAD_FRAME_DECODER_H_
CodexPad controller data frame decoding main class.
void Update()
Update the decoder state. This function must be called continuously in the main loop to feed and pars...
uint32_t button_states() const
Get all button states, return a 32-bit unsigned integer where each bit represents the state of a spec...
const uint8_t * axis_values() const
Get current values of all analog axes (returns a read-only array pointer).
bool holding(const Button button) const
check if a button is held.
bool HasAxisValueChanged(const Axis axis, const uint8_t threshold) const
check if an axis value has changed.
uint8_t axis_value(const Axis axis) const
Get the raw value (0~255) of a specified joystick axis.
static constexpr size_t kAxisValueNum
Number of axis values.
static constexpr uint8_t kAxisCenter
Center value of joystick axes (typical value at rest).
static constexpr uint8_t kPayloadType
Input report type identifier for the gamepad (the first byte of the payload).
bool released(const Button button) const
check if a button is released.
bool pressed(const Button button) const
check if a button is pressed.
Button
Gamepad button mask enumeration.
CodexPadFrameDecoder(Stream &stream)
Constructor.
Axis
Joystick axis index enumeration.
bool button_state(const Button button) const
check if a button is pressed or held.