Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 18 additions & 9 deletions bits_button.c
Original file line number Diff line number Diff line change
Expand Up @@ -447,15 +447,6 @@ int32_t bits_button_init(const bits_btn_config_t *config)
return BITS_BTN_ERR_TOO_MANY_BUTTONS;
}

memset(button, 0, sizeof(bits_button_t));

button->btns = config->btns;
button->btns_cnt = config->btns_cnt;
button->btns_combo = config->btns_combo;
button->btns_combo_cnt = config->btns_combo_cnt;
button->_read_button_level = config->read_button_level_func;
button->bits_btn_result_cb = config->bits_btn_result_cb;

if (config->btns_combo_cnt > BITS_BTN_MAX_COMBO_BUTTONS)
{
if (debug_printf)
Expand Down Expand Up @@ -503,6 +494,17 @@ int32_t bits_button_init(const bits_btn_config_t *config)
}
}

// All validations passed, now modify global state
memset(button, 0, sizeof(bits_button_t));

button->btns = config->btns;
button->btns_cnt = config->btns_cnt;
button->btns_combo = config->btns_combo;
button->btns_combo_cnt = config->btns_combo_cnt;
button->_read_button_level = config->read_button_level_func;
button->bits_btn_result_cb = config->bits_btn_result_cb;

// Calculate combo_mask after btns_combo is assigned
for(uint16_t i = 0; i < config->btns_combo_cnt; i++)
{
button_obj_combo_t *combo = &button->btns_combo[i];
Expand Down Expand Up @@ -578,6 +580,9 @@ void bits_button_reset_states(void)
{
bits_button_t *button = &bits_btn_entity;

if (button->_read_button_level == NULL || button->btns == NULL)
return;

if (debug_printf)
debug_printf("Resetting all button states\n");

Expand Down Expand Up @@ -910,6 +915,10 @@ static void dispatch_unsuppressed_buttons(bits_button_t *button, button_mask_typ
void bits_button_ticks(void)
{
bits_button_t *button = &bits_btn_entity;

if (button->_read_button_level == NULL || button->btns == NULL)
return;

uint32_t current_time = get_button_tick();

button->btn_tick++;
Expand Down
20 changes: 15 additions & 5 deletions docs/buffer_modes.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ BitsButton库支持三种不同的缓冲区模式,以满足不同应用场景

### 1. C11原子缓冲区模式(默认)

这是默认模式,适用于多线程环境,提供高性能和线程安全的特性
这是默认模式,使用C11原子操作提供高性能的无锁缓冲区

**启用方式:**
```c
Expand All @@ -17,8 +17,8 @@ gcc -c -std=c11 bits_button.c

**特性:**
- 使用C11原子操作实现SPSC(单生产者单消费者)环形缓冲区
- 线程安全,无锁设计
- 高性能,适用于多线程环境
- 无锁设计,适用于单生产者单消费者场景
- 缓冲区满时采用覆写策略(丢弃最旧事件),通过 `get_bits_btn_buffer_overwrite_count()` 可查询覆写次数
- 需要C11编译器支持

### 2. 禁用缓冲区模式
Expand Down Expand Up @@ -135,7 +135,7 @@ void setup_custom_buffer(void) {
|------|-------------|----------------|----------------|
| 内存占用 | 中等 | 最小 | 可控 |
| 性能 | 高 | 高 | 取决于实现 |
| 线程安全 | | N/A | 取决于实现 |
| 线程安全 | SPSC(见注意事项) | N/A | 取决于实现 |
| 轮询支持 | 是 | 否 | 是 |
| 回调支持 | 是 | 是 | 是 |
| 编译器要求 | C11 | C89+ | C89+ |
Expand All @@ -146,4 +146,14 @@ void setup_custom_buffer(void) {
1. 禁用缓冲区模式下,`bits_button_get_key_result()` 函数将不可用
2. 用户自定义模式需要谨慎实现线程安全性
3. C11模式提供最佳的性能和安全性平衡
4. 在资源受限环境中,禁用缓冲区模式可能是最佳选择
4. 在资源受限环境中,禁用缓冲区模式可能是最佳选择
5. **C11 缓冲区的线程安全约束**:默认 C11 缓冲区基于 SPSC(单生产者单消费者)模型,
要求 `bits_button_ticks()`(生产者)和 `bits_button_get_key_result()` / `bits_button_peek_key_result()`(消费者)
不会并发访问同一个缓冲区槽位。在以下场景中请注意:
- **裸机主循环**:两者在同一循环中顺序调用,天然安全
- **中断 + 主循环**:`bits_button_ticks()` 在定时器中断中调用时,
若缓冲区满触发覆写,可能与主循环中的读取产生竞态。
建议确保缓冲区容量足够(通过 `BITS_BTN_BUFFER_SIZE` 宏调整),避免满溢
- **RTOS 多线程**:若生产者和消费者在不同线程,建议使用 `BITS_BTN_USE_USER_BUFFER`
模式,提供带互斥保护的自定义缓冲区实现
- 无论哪种场景,**回调函数**(`bits_btn_result_cb`)始终会被同步调用,不经过缓冲区,不受此约束影响
Loading