/*
 * @Date: 2025-07-02 13:22:04
 * @Author: mypx
 * @LastEditors: mypx mypx_coder@163.com
 * @LastEditTime: 2025-09-12 13:59:23
 * @FilePath: sv_device.c
 * @Description: 
 * Copyright (c) 2025 by mypx, All Rights Reserved.
 */
#include "sv_device.h"
#include "etk_utils.h"
#include "et_log.h"
#include "h02_basic_control.h"
#include "h03_di_do.h"
#include "h05_pos_control.h"
#include "h06_speed_control.h"
#include "h0d_af.h"
#include "h31_comm_related_var.h"

// FIXME: this function is not debug
int sv630p_position_mode_init(sv630p_handle_t *dev)
{
    sv630p_h02_00_write_control_mode(dev, SV630P_CONTROL_MODE_POSITION);
    sv630p_h05_00_write_command_source(dev, SV630P_POS_CMD_STEP);
    // 关键DI配置
    sv630p_h03_01_write_power_on_di_func_assign2(dev, SV630P_FunIN_1_S_ON);
    sv630p_h03_01_write_power_on_di_func_assign2(dev, SV630P_FunIN_27_POSDirSel);
    sv630p_h03_02_write_di1_function_selection(dev, DI_FUNC_CLEAR_POS_ERROR);
    // 关键DO配置
    return 0;
}

int sv630p_speed_mode_init(sv630p_handle_t *dev)
{
    int ret = 0;

    dev->rpm = 0;
    dev->dir = SV630P_DIR_UNKNOWN;

    ret = sv630p_h02_00_write_control_mode(dev, SV630P_CONTROL_MODE_SPEED);
    ERR_CHECK_RET_NONZERO_ACT(ret, { goto err; });
    // ret = sv630p_h06_00_write_main_speed_cmd_a_src(dev, DIGITAL_VALUE_SPECIFIED_CMD_A);
    // ERR_CHECK_RET_NONZERO_ACT(ret, { goto err; });

    ret = sv630p_h06_02_write_speed_cmd_select(dev, SV630P_SPEED_CMD_COMMUNICATION);
    ERR_CHECK_RET_NONZERO_ACT(ret, { goto err; });

    return 0;
err:
    dev->is_error = true;
    ET_ERR("Failed to init speed mode: %d", ret);
    return -1;
}

int sv630p_speed_mode_start(sv630p_handle_t *dev, double rpm)
{
    int ret = 0;

    //ET_INFO("Start speed mode, rpm:%d", (int)rpm);
    ret = sv630p_h31_09_write_speed_command(dev, rpm);
    ERR_CHECK_RET_NONZERO_ACT(ret, { goto err; });

    ret = sv630p_h0d_17_write_force_output_mode(dev, SV630P_DIDO_FORCE_DI_ENABLE);
    ERR_CHECK_RET_NONZERO_ACT(ret, { goto err; });
    /* FIXME: The default function of DI5 is servo enabling. Please check the function selection 
    of the H03.10 - DI5 terminal and the logic selection of the H03.11 - DI5 terminal.*/
    ret = sv630p_h0d_18_write_force_input_bits(dev, NOT_CONCERN_BIT, DI5_BIT);
    ERR_CHECK_RET_NONZERO_ACT(ret, { goto err; });
    dev->last_rpm = rpm;
    dev->rpm      = rpm;
    dev->dir      = rpm > 0 ? SV630P_DIR_FORWARD : SV630P_DIR_BACKWARD;
    return 0;
err:
    ET_ERR("Failed to start speed mode: %d", ret);
    dev->is_error = true;
    return -1;
}

int sv630p_speed_mode_resume(sv630p_handle_t *dev)
{
    return sv630p_speed_mode_start(dev, dev->last_rpm);
}

int sv630p_speed_update(sv630p_handle_t *dev, double rpm)
{
    int ret = 0;

    SV630P_Dir dir = rpm > 0 ? SV630P_DIR_FORWARD : SV630P_DIR_BACKWARD;

    if (ETK_FLOAT_ALMOST_EQUAL(dev->rpm, rpm, 0.005))
    {
        //ET_DBG("rpm diff small %.2f", rpm);
        return 0;
    }
    dev->last_rpm = rpm;
    if (dev->dir != dir)
    {
        ret = sv630p_speed_mode_stop(dev);
        ERR_CHECK_RET_NONZERO_ACT(ret, { goto err; });
        rt_thread_mdelay(50); // 等待停止完成
        ret = sv630p_speed_mode_start(dev, rpm);
        ERR_CHECK_RET_NONZERO_ACT(ret, { goto err; });
    }
    else
    {
        ET_INFO("Update rpm: %.2f", rpm);
        ret = sv630p_h31_09_write_speed_command(dev, rpm);
        ERR_CHECK_RET_NONZERO_ACT(ret, { goto err; });
        dev->rpm = rpm;
        dev->dir = dir;
    }
    return 0;
err:
    dev->is_error = true;
    ET_ERR("Failed to start speed mode: %d", ret);
    return -1;
}

int sv630p_dir_change(sv630p_handle_t *dev)
{
    int ret = 0;

    double rpm = dev->last_rpm * -1.0;

    ET_INFO("Change dir, rpm:%d", (int)rpm);
    ret = sv630p_speed_mode_stop(dev);
    ERR_CHECK_RET_NONZERO_ACT(ret, { goto err; });
    rt_thread_mdelay(50); // 等待停止完成
    ret = sv630p_speed_mode_start(dev, rpm);
    ERR_CHECK_RET_NONZERO_ACT(ret, { goto err; });

    return 0;
err:
    dev->is_error = true;
    ET_ERR("Failed to change direction: %d", ret);
    return -1;
}


int sv630p_speed_mode_stop(sv630p_handle_t *dev)
{
    int ret = 0;

    ret = sv630p_h0d_17_write_force_output_mode(dev, SV630P_DIDO_FORCE_NONE);
    ERR_CHECK_RET_NONZERO_ACT(ret, { goto err; });
    /* FIXME: The default function of DI5 is servo enabling. Please check the function selection 
    of the H03.10 - DI5 terminal and the logic selection of the H03.11 - DI5 terminal.*/
    ret = sv630p_h0d_18_write_force_input_bits(dev, DI5_BIT, NOT_CONCERN_BIT);
    ERR_CHECK_RET_NONZERO_ACT(ret, { goto err; });
    //ET_DBG("Servo STOP from dir:%d", dev->dir);
    dev->rpm = 0;
    dev->dir = SV630P_DIR_STOP;

    return 0;
err:
    dev->is_error = true;
    ET_ERR("Failed to stop speed mode: %d", ret);
    return -1;
}

double sv630p_get_last_rpm(sv630p_handle_t *dev)
{
    return dev->last_rpm;
}

SV630P_Dir sv630p_get_dir(sv630p_handle_t *dev)
{
    return dev->dir;
}


