/*
 * @Author: mypx
 * @Date: 2025-08-11 08:30:45
 * @LastEditTime: 2025-10-27 15:06:18
 * @LastEditors: mypx mypx_coder@163.com
 * @Description: 
 */
#include "pm_meas.h"
#include "data_process.h"
#include "data_sampling.h"
#include "et_waveform_analysis.h"
#include "servo.h"
#include <float.h>
#include <rtthread.h>
#include <stdio.h>


static pm_fsm_t *pm_fsm = NULL;

pm_fsm_t *get_pm_fsm(void)
{
    return pm_fsm;
}

void fsm_state_toggle(void)
{
    pm_fsm_t *fsm = get_pm_fsm();
    if (!fsm)
        return;
    fsm->fz_fsm_state = !fsm->fz_fsm_state;
}
MSH_CMD_EXPORT_ALIAS(fsm_state_toggle, fsm, calculate state toggle);

void calibrate_mode_toggle(void)
{
    pm_fsm_t *fsm = get_pm_fsm();
    if (!fsm)
        return;
    fsm->fz_fsm_state = false;
    fsm->meas_mode    = fsm->meas_mode == PM_MEAS_NORMAL_Mode ? PM_MEAS_TEST_Mode : PM_MEAS_NORMAL_Mode;
}
MSH_CMD_EXPORT_ALIAS(calibrate_mode_toggle, cali, calibrate mode toggle);

void trend_handle_init(trend_handle_t *handle)
{
    handle->last_val = NAN;
    handle->inc_cnt  = 0;
    handle->dec_cnt  = 0;
}

TrendStatus get_data_trend(trend_handle_t *handle, double new_val)
{
    const double EPS = 1e-6; // 浮点数比较精度（避免误差）

    // 1. 首次调用：无历史数据，返回“未知”并初始化上次值
    if (isnan(handle->last_val))
    {
        handle->last_val = new_val;
        return TREND_UNKNOWN;
    }

    // 2. 比较本次与上次数据，更新计数
    if (new_val > handle->last_val + EPS)
    {
        // 数据上升
        handle->inc_cnt++;
        handle->dec_cnt = 0;
    }
    else if (new_val < handle->last_val - EPS)
    {
        // 数据下降
        handle->dec_cnt++;
        handle->inc_cnt = 0;
    }

    handle->last_val = new_val;
    // 3. 判断是否达到“连续6次”的触发阈值（原逻辑：cnt > 5）
    if (handle->inc_cnt > TREND_MAX_CNT)
    {
        //inc_cnt  = 0; // 触发后清零，重新开始计数
        return TREND_INCREASE;
    }
    if (handle->dec_cnt > TREND_MAX_CNT)
    {
        //dec_cnt  = 0; // 触发后清零，重新开始计数
        return TREND_DECREASE;
    }
    return TREND_STABLE;
}

void trend_handle_reset(trend_handle_t *handle)
{
    handle->last_val = NAN;
    handle->inc_cnt  = 0;
    handle->dec_cnt  = 0;
}

void measurement_info_print(pm_meas_t *fz)
{
    ET_WARN("------------------------Calibration Info Start----------------------------");
    ET_INFO("Find zero time: %lu ms", fz->calib_info[0].end_time - fz->calib_info[0].start_time);
    float min_angle = FLT_MAX;
    float max_angle = -FLT_MAX;

    for (int i = 0; i < fz->calib_cnt; i++)
    {
#if (ENABLE_CALIB_DOUBLE_DIR == 1)
        if (fz->calib_info[i].m_dir == -1)
            fz->calib_info[i].cali_angle = fz->calib_info[i].angle - CALIB_OFFSET;
        else
#endif
            fz->calib_info[i].cali_angle = fz->calib_info[i].angle;
        if (fz->calib_info[i].cali_angle < min_angle)
        {
            min_angle = fz->calib_info[i].cali_angle;
        }
        if (fz->calib_info[i].cali_angle > max_angle)
        {
            max_angle = fz->calib_info[i].cali_angle;
        }
        // ET_INFO("[%d]: Used time:%d ms, start:%.3f, end zero pos:%.3f, cali_angle:%.2f, power:%.3f", i,
        //         fz->calib_info[i].end_time - fz->calib_info[i].start_time, fz->calib_info[i].target_angle,
        //         fz->calib_info[i].angle, fz->calib_info[i].cali_angle, fz->calib_info[i].power);
        ET_INFO("[%d]: Used time:%d ms, start:%.3f, end zero pos:%.3f, power:%.3f", i,
                fz->calib_info[i].end_time - fz->calib_info[i].start_time, fz->calib_info[i].target_angle,
                fz->calib_info[i].angle, fz->calib_info[i].power);
    }
    ET_INFO("Final min_angle: %.3f, max_angle: %.3f", min_angle, max_angle);
    if (min_angle != FLT_MAX && max_angle != FLT_MIN)
    {
        float accuracy = (max_angle - min_angle) / ENCODER_TO_POLARIZER_RATIO;
        ET_INFO("Accuracy: %.3f (max_angle-min_angle=%.3f, ratio=%d)", accuracy, max_angle - min_angle,
                ENCODER_TO_POLARIZER_RATIO);
    }
    else
    {
        ET_WARN("Accuracy not calculated: min_angle=%.3f, max_angle=%.3f", min_angle, max_angle);
    }
    ET_WARN("------------------------Calibration Info End----------------------------");
}

void accuracy_auto_measurement_once(pm_meas_t *fz, float angle)
{
    ET_INFO("Start to calibrate again:%d", fz->calib_cnt);

#if (CALIB_TO_FIX_STAGE == 1)
    float diff = angle - fz->stage_info[ZF_PREPARE_ENTER_STAGE].angle;
#else
    float diff = CALIB_OSCI_ANGLE;
#endif
    ET_INFO("diff:%.2f", diff);
    float target_angle = 0.0f;
#if (ENABLE_CALIB_DOUBLE_DIR == 1)
    if (fz->calib_cnt % 2 == 0)
    {
        target_angle = angle - diff;
        ET_INFO("Odd times, turn back");
    }
    else
    {
        target_angle = angle + diff;
        ET_INFO("Even times, turn forward");
    }
#else
    target_angle = angle + diff * CALIB_ONE_DIR;
#endif
    uint32_t delay = convert_encoder_angle_rpm_to_to_time(diff, RUN_OFFSET_ANGLE_RPM);
    ET_DBG("wait %d ms to target:%.2f", delay, target_angle);
    int speed = (target_angle > angle) ? (RUN_OFFSET_ANGLE_RPM * ENCODER_MOTOR_DIR_FACTOR)
                                       : (-RUN_OFFSET_ANGLE_RPM * ENCODER_MOTOR_DIR_FACTOR); // FIXME:note encoder dir and motor dir
    sv630p_speed_mode_start(&sv630p_handle, speed);
    fz->target_dir = (speed > 0) ? -1 : 1;
    ET_WARN("SPEED:%d", speed);
    uint32_t start_time = rt_tick_get_millisecond();
    while (1)
    {
        angle = get_real_time_angle_degree();
        //ET_DBG("angle:%.2f", angle);
        // 根据方向判断是否达到目标角度，处理负数角度情况
        if (((speed > 0) && (target_angle > angle)) || ((speed < 0) && (target_angle < angle))) //1000, -183,1124
        {
            sv630p_speed_mode_stop(&sv630p_handle);
            ET_INFO("Set angle:%.3f, reached:%.3f", target_angle, angle);
#if (CALIB_TO_FIX_STAGE == 1)
            fz->state = ZF_PREPARE_ENTER_STAGE;
            ET_WARN("Back to ZF_PREPARE_ENTER_STAGE state");
#else
            fz->state = ZF_FAST_CLOSE_STAGE;
            ET_WARN("Back to ZF_FAST_CLOSE_STAGE state");
#endif
            uint8_t index                      = fz->calib_cnt % FZ_CALI_MAX_COUNT;
            fz->calib_info[index].target_angle = target_angle;
            ET_INFO("update start calib index:%d", index);
            fz->calib_info[index].start_time = rt_tick_get_millisecond();
            //fz->target_dir                   *= -1; // reverse dir

            break;
        }
        else if (rt_tick_get_millisecond() - start_time > delay)
        {
            ET_WARN("Timeout, set angle:%.3f, reached:%.3f, speed:%d", target_angle, angle, speed);
            sv630p_speed_mode_stop(&sv630p_handle);
            break;
        }
    }
}

// 饱和高噪声状态判断，不会误判为其他状态，任何情形都无需从这个状态反转
StageResult is_saturate_starting(pm_meas_t *fz)
{
    if (fabs(fz->slope) < FZ_SATURATED_SLOPE_MAX && fz->p50 < FZ_SATURATED_POWER_MAX && (fz->freq < 10))
    {
        //fz->state       = ZF_SATURATED_STAGE;
        return STAGE_RESULT_OK;
    }
    else
        return STAGE_RESULT_NO;
}

int goto_saturated_stage(pm_meas_t *fz)
{
    fz->state = ZF_SATURATED_STAGE;
    ET_WARN("power state: ZF_SATURATED_STAGE");
    return sv630p_speed_update(&sv630p_handle, FZ_SATURATED_STAGE_RPM * fz->target_dir);
}

StageResult is_wave_enter_stage(pm_meas_t *fz)
{
    if (fz->slope > 100000)
        return STAGE_RESULT_OK;
    else
        return STAGE_RESULT_NO;
}

StageResult is_prepare_enter_stage(pm_meas_t *fz)
{
    if (fz->p50 > 100000 && fz->trend == TREND_DECREASE && fz->state != ZF_WAVE_LEAVE_STAGE)
        return STAGE_RESULT_OK;
    else
        return STAGE_RESULT_NO;
}

int goto_prepare_enter_stage(pm_meas_t *fz, double p50, double slope, float freq, double angle)
{
    fz->state = ZF_PREPARE_ENTER_STAGE;
    if (fz->stage_info[ZF_PREPARE_ENTER_STAGE].is_updated == 0)
    {
        fz->stage_info[ZF_PREPARE_ENTER_STAGE].angle      = angle;
        fz->stage_info[ZF_PREPARE_ENTER_STAGE].time       = rt_tick_get_millisecond();
        fz->stage_info[ZF_PREPARE_ENTER_STAGE].p50        = p50;
        fz->stage_info[ZF_PREPARE_ENTER_STAGE].slope      = slope;
        fz->stage_info[ZF_PREPARE_ENTER_STAGE].freq       = freq;
        fz->stage_info[ZF_PREPARE_ENTER_STAGE].is_updated = 1;
    }
    ET_WARN("enter ZF_PREPARE_ENTER_STAGE angle:%.3f", angle);
    return sv630p_speed_update(&sv630p_handle, FZ_PREPARE_STAGE_RPM * fz->target_dir);
}

int goto_prepare_leave_stage(pm_meas_t *fz, double angle)
{
    fz->target_dir = fz->target_dir * -1;
    if (fz->stage_info[ZF_PREPARE_LEAVE_STAGE].is_updated == 0)
    {
        fz->stage_info[ZF_PREPARE_LEAVE_STAGE].is_updated = 1;
        fz->stage_info[ZF_PREPARE_LEAVE_STAGE].angle      = angle;
        fz->stage_info[ZF_PREPARE_LEAVE_STAGE].time       = rt_tick_get_millisecond();
        fz->stage_info[ZF_PREPARE_LEAVE_STAGE].p50        = fz->p50;
        fz->stage_info[ZF_PREPARE_LEAVE_STAGE].slope      = fz->slope;
        fz->stage_info[ZF_PREPARE_LEAVE_STAGE].freq       = fz->freq;
    }
    ET_WARN("ZF_PREPARE_LEAVE_STAGE, angle:%.3f", angle);
    return sv630p_speed_update(&sv630p_handle, FZ_PREPARE_STAGE_RPM * fz->target_dir);
}

StageResult is_fast_close_enter(pm_meas_t *fz)
{
    if (fz->p50 <= 100000 && fz->trend == TREND_DECREASE && fz->state == ZF_PREPARE_ENTER_STAGE)
        return STAGE_RESULT_OK;
    else
        return STAGE_RESULT_NO;
}

int goto_fast_close_stage(pm_meas_t *fz, double p50, double slope, float freq, double angle)
{
    fz->state = ZF_FAST_CLOSE_STAGE;
    if (fz->stage_info[ZF_FAST_CLOSE_STAGE].is_updated == 0)
    {
        fz->stage_info[ZF_FAST_CLOSE_STAGE].is_updated = 1;
        fz->stage_info[ZF_FAST_CLOSE_STAGE].angle      = angle;
        fz->stage_info[ZF_FAST_CLOSE_STAGE].time       = rt_tick_get_millisecond();
        fz->stage_info[ZF_FAST_CLOSE_STAGE].p50        = p50;
        fz->stage_info[ZF_FAST_CLOSE_STAGE].slope      = slope;
        fz->stage_info[ZF_FAST_CLOSE_STAGE].freq       = freq;
    }
    ET_WARN("FAST_CLOSE, angle:%.3f\r\n", angle);
    return sv630p_speed_update(&sv630p_handle, FZ_FAST_CLOSE_STAGE_RPM * fz->target_dir);
}

StageResult is_zero_stage(pm_meas_t *fz)
{
    if (fabs(fz->slope) < 0.5 && fz->p50 < ZERO_POS_THRESHOLD && (fz->freq >= 99.95 && fz->freq < 100.3f)
        && fz->trend == TREND_STABLE)
        return STAGE_RESULT_OK;
    else
        return STAGE_RESULT_NO;
}

StageResult is_fast_leave_stage(pm_meas_t *fz)
{
    if ((fz->p50 <= 100000) && (fz->slope > 10000)
        && (fz->freq > FZ_FAST_CLOSE_ENTER_FREQ_MIN && fz->freq < FZ_FAST_CLOSE_ENTER_FREQ_MAX)
        && fz->state != ZF_SATURATED_STAGE)
        return STAGE_RESULT_OK;
    else
        return STAGE_RESULT_NO;
}

StageResult is_prepare_leave_stage(pm_meas_t *fz)
{
    if (fz->p50 >= 100000 && fz->trend == TREND_INCREASE
        && (fz->state == ZF_FAST_CLOSE_STAGE || fz->state == ZF_ZERO_STAGE))
        return STAGE_RESULT_OK;
    else
        return STAGE_RESULT_NO;
}

StageResult is_wave_leave_stage(pm_meas_t *fz)
{
    // if ((fz->slope < -100000) || (fz->freq > 52 && fz->freq < 98 && fz->p50 < 1000 && fz->trend == TREND_DECREASE)
    //     || (fz->freq < 1.0 && fz->trend == TREND_DECREASE)) // old version parameter
    // if ((fz->slope < -200 && (fz->freq < 48 || fz->freq > 102) && fz->p50 < 1000 && fz->trend == TREND_DECREASE)
    //     || (fz->freq < 1.0 && fz->trend == TREND_DECREASE))
    //     return STAGE_RESULT_OK;
    // else
        return STAGE_RESULT_NO;
}

ZeroFindState get_find_zero_state(pm_meas_t *fz)
{
    return fz->state;
}

void calculate_stage(pm_meas_t *fz)
{
    if (is_saturate_starting(fz) == STAGE_RESULT_OK && fz->stage_info[ZF_SATURATED_STAGE].is_print == false)
    {
        ET_WARN("enter saturated");
        fz->stage_info[ZF_SATURATED_STAGE].is_print = true;
        fz->state                                   = ZF_SATURATED_STAGE;
    }
    if (is_wave_enter_stage(fz) == STAGE_RESULT_OK && fz->stage_info[ZF_WAVE_ENTER_STAGE].is_print == false)
    {
        ET_WARN("enter 50hz started");
        fz->stage_info[ZF_WAVE_ENTER_STAGE].is_print = true;
        fz->stage_info[ZF_SATURATED_STAGE].is_print  = false;
        fz->state                                    = ZF_WAVE_ENTER_STAGE;
    }
    if (is_prepare_enter_stage(fz) == STAGE_RESULT_OK && fz->stage_info[ZF_PREPARE_ENTER_STAGE].is_print == false)
    {
        ET_WARN("enter prepare stage");
        fz->stage_info[ZF_PREPARE_ENTER_STAGE].is_print = true;
        fz->state                                       = ZF_PREPARE_ENTER_STAGE;
        fz->stage_info[ZF_WAVE_ENTER_STAGE].is_print    = false;
    }
    if (is_fast_close_enter(fz) == STAGE_RESULT_OK && fz->stage_info[ZF_FAST_CLOSE_STAGE].is_print == false)
    {
        ET_WARN("enter fast close stage, dir:%d, target dir :%d", sv630p_get_dir(&sv630p_handle), fz->target_dir);
        fz->stage_info[ZF_FAST_CLOSE_STAGE].is_print    = true;
        fz->stage_info[ZF_PREPARE_ENTER_STAGE].is_print = false;
        fz->state                                       = ZF_FAST_CLOSE_STAGE;
    }

    if (is_zero_stage(fz) == STAGE_RESULT_OK && fz->stage_info[ZF_ZERO_STAGE].is_print == false)
    {
        ET_WARN("enter zero state");
        fz->stage_info[ZF_ZERO_STAGE].is_print = true;
        if (fz->state == ZF_UNKNOWN_STAGE)
            fz->state = ZF_ZERO_STAGE; // 开机判断
    }
    else
    {
        fz->stage_info[ZF_ZERO_STAGE].is_print = false;
    }

    if (is_fast_leave_stage(fz) == STAGE_RESULT_OK && fz->stage_info[ZF_FAST_LEAVE_STAGE].is_print == false)
    {
        ET_WARN("fast leave stage");
        fz->stage_info[ZF_FAST_LEAVE_STAGE].is_print = true;
        //fz->stage_info[ZF_PRECISE_ADJUST_LEAVE_STAGE].is_print = false;
        fz->state = ZF_FAST_LEAVE_STAGE;
    }
    if (is_prepare_leave_stage(fz) == STAGE_RESULT_OK && fz->stage_info[ZF_PREPARE_LEAVE_STAGE].is_print == false)
    {
        ET_WARN("prepare leave stage");
        fz->stage_info[ZF_PREPARE_LEAVE_STAGE].is_print = true;
        fz->stage_info[ZF_FAST_LEAVE_STAGE].is_print    = false;
        fz->stage_info[ZF_WAVE_LEAVE_STAGE].is_print    = false;
        fz->state                                       = ZF_PREPARE_LEAVE_STAGE;
    }
    if (is_wave_leave_stage(fz) == STAGE_RESULT_OK && fz->stage_info[ZF_WAVE_LEAVE_STAGE].is_print == false)
    {
        ET_WARN("small 50hz leave stage");
        fz->stage_info[ZF_WAVE_LEAVE_STAGE].is_print    = true;
        fz->stage_info[ZF_PREPARE_LEAVE_STAGE].is_print = false;
        fz->state                                       = ZF_WAVE_LEAVE_STAGE;
    }
}

int find_zero_process(pm_meas_t *fz, const uint16_t *adc_buf, uint32_t len)
{
    pm_fsm_t *fsm = get_pm_fsm();
    if (!fsm)
    {
        ET_ERR("fsm is not init");
        return 0;
    }
    double rpm = 0.0;
    //static uint8_t wait_time = 0;
    float angle;

    fz->p50   = et_goertzel_compute_power_u16(&fz->cfg, adc_buf);
    fz->slope = etk_slope_update_slope(&fz->slope_handle, fz->p50);

    // if (wait_time++ < BUFFER_SIZE)
    //     return 0;
    angle = get_real_time_angle_degree();

    fz->freq  = et_zero_cross_freq_u16(&fz->zc, adc_buf, len, sampling_rate, DC_OFFSET_ADC_VALUE);
    fz->trend = get_data_trend(&fz->trend_handle, fz->p50);
    calculate_stage(fz);

    ET_DBG("[%d]tr:%d, s:%.2f, p50:%.2f, freq:%.2f, angle:%.2f", fz->state, fz->trend, fz->slope, fz->p50, fz->freq,
           angle);
    if (fsm->fz_fsm_state)
    {
        return 0;
    }
    if (fz->calib_info[0].start_time == 0)
    {
        fz->calib_info[0].start_time   = rt_tick_get_millisecond();
        fz->calib_info[0].angle        = 0;
        fz->calib_info[0].target_angle = 0;
    }
    switch (fz->state)
    {
    case ZF_UNKNOWN_STAGE:
    case ZF_SATURATED_STAGE:
        fz->target_dir = MEASURE_DEF_DIR;
        sv630p_speed_update(&sv630p_handle, FZ_UNKNOWN_STAGE_RPM * fz->target_dir);
        break;
    case ZF_WAVE_ENTER_STAGE:
        sv630p_speed_update(&sv630p_handle, FZ_WAVE_ENTER_STAGE_RPM * fz->target_dir);
        break;
    case ZF_PREPARE_ENTER_STAGE:
        sv630p_speed_update(&sv630p_handle, FZ_PREPARE_STAGE_RPM * fz->target_dir);
        break;
    case ZF_FAST_CLOSE_STAGE:
        // 优化方向反转逻辑，减少过零点超调
        if (get_data_trend(&fz->trend_handle, fz->p50) == TREND_INCREASE && fz->slope > 200 && fz->p50 < 40000)
        {
            fz->target_dir *= -1;
            etk_position_pid_reset(&fz->pid);      // 重置PID避免累积误差影响
            trend_handle_reset(&fz->trend_handle); // 防止很快的重复进来
            ET_WARN("passed the zero point and rotated in the opposite direction (slope=%.1f, p50=%.0f)", fz->slope,
                    fz->p50);
        }

        if (fz->p50 < ZERO_POS_THRESHOLD)
        {
            fz->zero_stable_count++;
            if (fz->zero_stable_count > ZC_COUNT_STABLE_TIMES || fz->p50 < 0.03)
            {
                fz->state                           = ZF_ZERO_STAGE;
                fz->calib_info[fz->calib_cnt].m_dir = sv630p_get_last_rpm(&sv630p_handle) > 0 ? 1 : -1;
                sv630p_speed_mode_stop(&sv630p_handle);
                uint8_t index                  = fz->calib_cnt % FZ_CALI_MAX_COUNT;
                fz->calib_info[index].angle    = angle;
                fz->calib_info[index].end_time = rt_tick_get_millisecond();
                fz->calib_info[index].power    = fz->p50;
                ET_INFO("update END calib index:%d", index);
                ET_WARN("Find zero done:%.3f", angle);
                fz->calib_cnt++;
                etk_position_pid_reset(&fz->pid);
                fz->target_dir = MEASURE_DEF_DIR;
            }
        }
        else
        {
            fz->zero_stable_count = 0;
#if 1
            // 根据p50值大小采用三级控制策略，优化不同阶段的控制效果
            if (fz->p50 > 40000)
            {
                rpm = 850.0f;
                rpm = rpm * (fz->target_dir);
            }
            else if (fz->p50 > 10000)
            {
                rpm = etk_position_pid_update(&fz->pid, fz->p50, 0.535, 0.7f);
                rpm = rpm * fz->target_dir;
            }
            else
#endif
            {
                // p50较小时使用保守PID控制，降低微分滤波系数以提高稳定性
                rpm = etk_position_pid_update(&fz->pid, fz->p50, 0.535, 0.9f);
                if (rpm > 350.0f)
                    rpm = 350.0f;
                if (rpm < -350.0f)
                    rpm = -350.0f;
                rpm = rpm * fz->target_dir;
            }

            if (fabs(rpm) < FZ_PRECISE_ADJUST_MIN_RPM)
            {
                rpm = (rpm >= 0) ? FZ_PRECISE_ADJUST_MIN_RPM : -FZ_PRECISE_ADJUST_MIN_RPM;
            }
            ET_DBG("rpm:%.2f", rpm);
            sv630p_speed_update(&sv630p_handle, rpm);
        }
        break;
    case ZF_ZERO_STAGE:
        if (fsm->meas_mode == PM_MEAS_TEST_Mode && fz->calib_cnt < FZ_CALI_MAX_COUNT)
        {
            fz->calib_info[fz->calib_cnt].start_time = rt_tick_get_millisecond();
            accuracy_auto_measurement_once(fz, angle);
        }
        else
        {
            sv630p_speed_mode_stop(&sv630p_handle);
            measurement_info_print(fz);
            fsm->fz_fsm_state = true; // test use
            fz->calib_cnt     = 0;
            fsm->meas_mode    = PM_MEAS_NORMAL_Mode;
            fz->target_dir    = MEASURE_DEF_DIR;
            //ET_WARN("Mesaure time:%d ms", rt_tick_get_millisecond() - fz->calib_start_time);
        }
        break;
    case ZF_FAST_LEAVE_STAGE:
        fz->target_dir *= -1;
        fz->state       = ZF_FAST_CLOSE_STAGE;
        sv630p_speed_update(&sv630p_handle, FZ_FAST_CLOSE_STAGE_RPM * fz->target_dir);
        break;
    case ZF_PREPARE_LEAVE_STAGE:
        goto_prepare_leave_stage(fz, angle);
        fz->state = ZF_PREPARE_ENTER_STAGE;
        break;
    case ZF_WAVE_LEAVE_STAGE:
        fz->target_dir *= -1;
        fz->state       = ZF_WAVE_ENTER_STAGE;
        break;
    case ZF_STATE_MAX:
        break;
    default:
        ET_INFO("not process state %d", fz->state);
        break;
    }
    return 0;
}

int pm_fsm_init(pm_fsm_t *fsm)
{
    pm_fsm            = fsm;
    fsm->fz_fsm_state = true;
    return 0;
}
