/*
 * @Date: 2025-07-01 09:47:13
 * @Author: mypx
 * @LastEditors: mypx mypx_coder@163.com
 * @LastEditTime: 2025-07-22 10:18:57
 * @FilePath: h0c_comm.c
 * @Description: 
 * Copyright (c) 2025 by mypx, All Rights Reserved.
 */
#include "h0c_comm.h"

extern nmbs_t servo_nmbs;

/*==========================
 * H0C Group - Communication Parameters (200C-xxh)
 *==========================*/

/**
 * @brief H0C.00 Read Drive Axis Address (16-bit)
 * @param value Pointer to store the axis address (1-247)
 * @return nmbs_error
 * @note The drive axis address must be consistent with the host configuration
 */
nmbs_error sv630p_read_axis_address(uint16_t *value)
{
    return nmbs_read_holding_registers(&servo_nmbs, REG_H0C_00_AXIS_ADDR, 1, value);
}

/**
 * @brief H0C.00 Write Drive Axis Address (16-bit)
 * @param value Axis address to write (1-247)
 * @return nmbs_error
 * @note Change when stopped, takes effect immediately
 */
nmbs_error sv630p_write_axis_address(uint16_t value)
{
    if (value < H0C_00_MIN || value > H0C_00_MAX)
        return NMBS_ERROR_INVALID_ARGUMENT;
    return nmbs_write_single_register(&servo_nmbs, REG_H0C_00_AXIS_ADDR, value);
}

/**
 * @brief H0C.02 Read Serial Baud Rate Setting (16-bit)
 * @param value Pointer to store the baud rate setting (0-6)
 * @return nmbs_error
 * @note 0:2400bps, 1:4800bps, 2:9600bps, 3:19200bps, 4:38400bps, 5:57600bps, 6:115200bps
 */
nmbs_error sv630p_read_baud_rate(SV630P_BaudRate *baud_rate)
{
    nmbs_error err;
    uint16_t   value;
    err = nmbs_read_holding_registers(&servo_nmbs, REG_H0C_02_BAUD_RATE, 1, &value);
    if (err == NMBS_ERROR_NONE)
    {
        if (value > SV630P_BAUD_115200)
            err = NMBS_ERROR_INVALID_ARGUMENT;
        else
            *baud_rate = value;
    }
    return err;
}

/**
 * @brief H0C.02 Write Serial Baud Rate Setting (16-bit)
 * @param value Baud rate setting to write (0-6)
 * @return nmbs_error
 * @note Communication will be interrupted after modification, serial port needs to be re-initialized
 */
nmbs_error sv630p_write_baud_rate(SV630P_BaudRate baud_rate)
{
    uint16_t value = (uint16_t)baud_rate;
    return nmbs_write_single_register(&servo_nmbs, REG_H0C_02_BAUD_RATE, value);
}

/**
 * @brief H0C.03 Read Modbus Communication Data Format (16-bit)
 * @param value Pointer to store the data format (0-3)
 * @return nmbs_error
 * @note 0:No parity+2 stop bits, 1:Even parity+1 stop bit, 2:Odd parity+1 stop bit, 3:No parity+1 stop bit
 */
nmbs_error sv630p_read_modbus_data_format(SV630P_ModbusFormat *fmt)
{
    nmbs_error err;
    uint16_t   value;
    err = nmbs_read_holding_registers(&servo_nmbs, REG_H0C_03_DATA_FORMAT, 1, &value);
    if (err == NMBS_ERROR_NONE)
    {
        if (value > SV630P_MODBUS_ODD_1STOP)
            err = NMBS_ERROR_INVALID_ARGUMENT;
        else
            *fmt = value;
    }
    return err;
}

/**
 * @brief H0C.03 Write Modbus Communication Data Format (16-bit)
 * @param value Data format to write (0-3)
 * @return nmbs_error
 * @note Must be consistent with the host computer, otherwise communication will fail. Takes effect immediately.
 */
nmbs_error sv630p_write_modbus_data_format(SV630P_ModbusFormat fmt)
{
    if (fmt < SV630P_MODBUS_NONE_1STOP || fmt > SV630P_MODBUS_ODD_1STOP)
        return NMBS_ERROR_INVALID_ARGUMENT;
    return nmbs_write_single_register(&servo_nmbs, REG_H0C_03_DATA_FORMAT, (uint16_t)fmt);
}

/**
 * @brief H0C.08 Read CAN Communication Rate (16-bit)
 * @param value Pointer to store the CAN rate setting (0-7)
 * @return nmbs_error
 * @note 0:20K, 1:50K, 2:100K, 3:125K, 4:250K, 5:500K, 6:1M(80% sample), 7:1M(70% sample)
 */
nmbs_error sv630p_read_can_rate(uint16_t *value)
{
    return nmbs_read_holding_registers(&servo_nmbs, REG_H0C_08_CAN_RATE, 1, value);
}

/**
 * @brief H0C.08 Write CAN Communication Rate (16-bit)
 * @param value CAN rate setting to write (0-7)
 * @return nmbs_error
 * @note Only supports CANlink/CANopen communication, must be consistent with the host
 */
nmbs_error sv630p_write_can_rate(uint16_t value)
{
    return nmbs_write_single_register(&servo_nmbs, REG_H0C_08_CAN_RATE, value);
}

/**
 * @brief Read communication VDI enable status
 * @param[out] value 0=disable, 1=enable
 * @return nmbs_error
 * @note After enabling VDI, DI function must be defined with H17 group parameters
 */
nmbs_error sv630p_read_vdi_enable(uint16_t *value)
{
    return nmbs_read_holding_registers(&servo_nmbs, REG_H0C_09_VDI_ENABLE, 1, value);
}

/**
 * @brief Set communication VDI enable status
 * @param[in] value 0=disable, 1=enable
 * @return nmbs_error
 * @note Value range: H0C_09_MIN ~ H0C_09_MAX
 */
nmbs_error sv630p_write_vdi_enable(VDI_StatusTypeDef status)
{
    uint16_t value = status;
    return nmbs_write_single_register(&servo_nmbs, REG_H0C_09_VDI_ENABLE, value);
}

/*==========================
 * H0C.10: Default VDI value after power-on (200C-0Bh)
 *==========================*/
/**
 * @brief Read default VDI value after power-on
 * @param[out] value Default VDI level configuration, bit0 corresponds to VDI1
 * @return nmbs_error
 */
nmbs_error sv630p_read_vdi_default(uint16_t *value)
{
    return nmbs_read_holding_registers(&servo_nmbs, REG_H0C_10_VDI_DEFAULT, 1, value);
}

/**
 * @brief Set default VDI value after power-on
 * @param[in] value Default VDI level configuration, bit0 corresponds to VDI1
 * @return nmbs_error
 * @note Value range: H0C_10_MIN ~ H0C_10_MAX
 */
nmbs_error sv630p_write_vdi_default(uint16_t value)
{
    return nmbs_write_single_register(&servo_nmbs, REG_H0C_10_VDI_DEFAULT, value);
}

/*==========================
 * H0C.11: Communication VDO Enable (200C-0Ch)
 *==========================*/
/**
 * @brief Read communication VDO enable status
 * @param[out] value 0=disable, 1=enable
 * @return nmbs_error
 * @note After enabling VDO, DO function must be defined with H31 group parameters
 */
nmbs_error sv630p_read_vdo_enable(uint16_t *value)
{
    return nmbs_read_holding_registers(&servo_nmbs, REG_H0C_11_VDO_ENABLE, 1, value);
}

/**
 * @brief Set communication VDO enable status
 * @param[in] value 0=disable, 1=enable
 * @return nmbs_error
 * @note Value range: H0C_11_MIN ~ H0C_11_MAX
 */
nmbs_error sv630p_write_vdo_enable(uint16_t value)
{
    // if (value < H0C_11_MIN || value > H0C_11_MAX) {
    //     return NMBS_ERROR_INVALID_ARGUMENT;
    // }
    return nmbs_write_single_register(&servo_nmbs, REG_H0C_11_VDO_ENABLE, value);
}

/*==========================
 * H0C.12: Default VDO level when function is disabled (200C-0Dh)
 *==========================*/
/**
 * @brief Read default output level when VDO function is disabled
 * @param[out] value Default output level
 * @return nmbs_error
 */
nmbs_error sv630p_read_vdo_default_level(uint16_t *value)
{
    return nmbs_read_holding_registers(&servo_nmbs, REG_H0C_12_VDO_DEFAULT_LEVEL, 1, value);
}

/**
 * @brief Set default output level when VDO function is disabled
 * @param[in] value Default output level
 * @return nmbs_error
 * @note Value range: H0C_12_MIN ~ H0C_12_MAX
 */
nmbs_error sv630p_write_vdo_default_level(uint16_t value)
{
    // if (value < H0C_12_MIN || value > H0C_12_MAX) {
    //     return NMBS_ERROR_INVALID_ARGUMENT;
    // }
    return nmbs_write_single_register(&servo_nmbs, REG_H0C_12_VDO_DEFAULT_LEVEL, value);
}

/*==========================
 * H0C.13: Communication function code EEPROM update (200C-0Eh)
 *==========================*/
/**
 * @brief Read whether communication function code is updated to EEPROM
 * @param[out] value 0=not updated, 1=updated
 * @return nmbs_error
 */
nmbs_error sv630p_read_func_code_eeprom(uint16_t *value)
{
    return nmbs_read_holding_registers(&servo_nmbs, REG_H0C_13_FUNC_CODE_EEPROM, 1, value);
}

/**
 * @brief Set whether communication function code is updated to EEPROM
 * @param[in] value 0=not updated, 1=updated
 * @return nmbs_error
 * @note Value range: H0C_13_MIN ~ H0C_13_MAX
 */
nmbs_error sv630p_write_func_code_eeprom(uint16_t value)
{
    // if (value < H0C_13_MIN || value > H0C_13_MAX) {
    //     return NMBS_ERROR_INVALID_ARGUMENT;
    // }
    return nmbs_write_single_register(&servo_nmbs, REG_H0C_13_FUNC_CODE_EEPROM, value);
}
