smartknob状态机

254 2024-09-07 08:53

 用状态机优化下面代码

if (reading >= lower - (upper - lower) && reading < upper + (upper - lower) * 2)
        {
            long value = CLAMP(reading, lower, upper);
            press_value_unit = 1. * (value - lower) / (upper - lower);

            static bool pressed;
            static bool accumulatable;
            static uint8_t press_count;
            static uint8_t release_count;
            if (!pressed && accumulatable && press_value_unit > 0.75)
            {
                accumulatable = false;
                // snprintf(buf_, sizeof(buf_), "accumulatable: %d", accumulatable);
                // log(buf_);
            }
            else if (!pressed && !accumulatable && press_value_unit > 0.75)
            {
                pressed = true;
                accumulatable = true;
                motor_task_.playHaptic(true);
                // snprintf(buf_, sizeof(buf_), "pressed: %d \t accumulatable: %d", pressed, accumulatable);
                // log(buf_);
            }
            else if (pressed && accumulatable && press_value_unit > 0.75)
            {
                press_count++;
                // snprintf(buf_, sizeof(buf_), "press_count: %d", press_count);
                // log(buf_);
            }
            else if (pressed && accumulatable && press_value_unit < 0.25)
            {
                accumulatable = false;
            }
            else if (pressed && !accumulatable && press_value_unit < 0.25)
            {
                release_count++;
                // snprintf(buf_, sizeof(buf_), "release_count: %d", release_count);
                // log(buf_);
                if (press_count > 30 && release_count > 2)
                {
                    changeConfigToZero();
                    press_count = 0;
                    // snprintf(buf_, sizeof(buf_), "配置0");
                    // log(buf_);
                    motor_task_.playHaptic(false);
                    pressed = false;
                }
                else if (press_count > 2 && release_count > 2)
                {
                    changeConfig(true);
                    press_count = 0;
                    // snprintf(buf_, sizeof(buf_), "下一个配置");
                    // log(buf_);
                    motor_task_.playHaptic(false);
                    pressed = false;
                }
            }
            else
            {
                release_count = 0;
            }
        }

 

为了优化这段代码,我们可以使用一个状态机来管理不同的状态和事件。状态机可以帮助我们更清晰地管理状态转换,并且使代码更加模块化和易于维护。下面是一个简化的状态机实现的示例:

首先,我们定义状态和事件:

```c
enum State {
    STATE_IDLE,
    STATE_PRESSED,
    STATE_ACCUMULATING,
    STATE_RELEASED
};

enum Event {
    EVENT_PRESS,
    EVENT_ACCUMULATE,
    EVENT_RELEASE,
    EVENT_IDLE
};
```

然后,我们定义一个结构体来保存状态机的状态:

```c
struct StateMachine {
    State state;
    bool accumulatable;
    uint8_t press_count;
    uint8_t release_count;
};
```

接下来,我们定义状态转换函数:

```c
void handleEvent(StateMachine *sm, Event event, double press_value_unit, long lower, long upper) {
    long value = CLAMP(reading, lower, upper);
    double press_value_unit = 1. * (value - lower) / (upper - lower);

    switch (sm->state) {
        case STATE_IDLE:
            if (press_value_unit > 0.75) {
                sm->state = STATE_PRESSED;
                sm->accumulatable = true;
                // log("Pressed");
            }
            break;
        case STATE_PRESSED:
            if (press_value_unit > 0.75) {
                if (sm->accumulatable) {
                    sm->state = STATE_ACCUMULATING;
                    sm->press_count++;
                    // log("Accumulating");
                }
            } else if (press_value_unit < 0.25) {
                sm->state = STATE_RELEASED;
                sm->release_count++;
                // log("Released");
            }
            break;
        case STATE_ACCUMULATING:
            if (press_value_unit > 0.75) {
                sm->press_count++;
                // log("Press count: ", sm->press_count);
            } else if (press_value_unit < 0.25) {
                sm->state = STATE_RELEASED;
                sm->accumulatable = false;
                // log("Released");
            }
            break;
        case STATE_RELEASED:
            if (press_value_unit < 0.25) {
                if (sm->press_count > 30 && sm->release_count > 2) {
                    changeConfigToZero();
                    sm->press_count = 0;
                    // log("Config 0");
                    motor_task_.playHaptic(false);
                } else if (sm->press_count > 2 && sm->release_count > 2) {
                    changeConfig(true);
                    sm->press_count = 0;
                    // log("Next config");
                    motor_task_.playHaptic(false);
                }
                sm->state = STATE_IDLE;
            } else {
                sm->release_count = 0;
            }
            break;
    }
}
```

最后,我们在主循环中使用状态机:

```c
StateMachine sm = {STATE_IDLE, true, 0, 0};

while (true) {
    // 假设 reading 是从传感器读取的值
    double reading = getSensorReading();
    if (reading >= lower - (upper - lower) && reading < upper + (upper - lower) * 2) {
        handleEvent(&sm, EVENT_PRESS, reading, lower, upper);
    } else {
        handleEvent(&sm, EVENT_IDLE, 0, lower, upper);
    }
    // 其他循环逻辑...
}
```

这个状态机的实现将原始的 if-else 逻辑分解为不同的状态和事件处理函数,使得代码更加清晰和易于理解。每个状态和事件都有明确的定义,这有助于未来的维护和扩展。

 

全部评论

·