/*
 * @Date: 2025-06-26 10:32:57
 * @Author: mypx
 * @LastEditors: mypx mypx_coder@163.com
 * @LastEditTime: 2025-08-19 08:28:42
 * @FilePath: sv_common.h
 * @Description:
 * Copyright (c) 2025 by mypx, All Rights Reserved.
 */
#ifndef __SV_COMMON_H__
#define __SV_COMMON_H__
#include "nanomodbus.h"
#include <stddef.h>
#include <stdint.h>

#define SV630P_OK           0x00
#define SV630P_ERR          0x01
#define SV630P_TIMEOUT      0x02
#define SV630P_CHECKSUM_ERR 0x03
#define SV630P_NOT_INIT     0x04
#define SV630P_INDEX_ERR    0x05
#define SV630P_BUS_ERR      0x06
#define SV630P_PARAM_ERR    0x07
#define SV630P_MB_ERR       0x08


/**
 * @brief SV630P Servo Drive DIDO Input Function (FunIN) Enumeration
 *        Format: SV630P_FunIN_Code_Name
 */
typedef enum
{
    SV630P_FunIN_1_S_ON = 1,      ///< FunIN.1 - S-ON - Servo Enable
    SV630P_FunIN_2_ALM_RST,       ///< FunIN.2 - ALM-RST - Fault and Warning Reset
    SV630P_FunIN_3_GAIN_SEL,      ///< FunIN.3 - GAIN-SEL - Gain Switch
    SV630P_FunIN_4_CMD_SEL,       ///< FunIN.4 - CMD-SEL - Main Shaft Operation Command Switch
    SV630P_FunIN_5_DIR_SEL,       ///< FunIN.5 - DIR-SEL - Multi-speed DI Switch Running Direction Setting
    SV630P_FunIN_6_CMD1,          ///< FunIN.6 - CMD1 - Multi-segment Run Command Switch 1
    SV630P_FunIN_7_CMD2,          ///< FunIN.7 - CMD2 - Multi-segment Run Command Switch 2
    SV630P_FunIN_8_CMD3,          ///< FunIN.8 - CMD3 - Multi-segment Run Command Switch 3
    SV630P_FunIN_9_CMD4,          ///< FunIN.9 - CMD4 - Multi-segment Run Command Switch 4
    SV630P_FunIN_10_M1_SEL,       ///< FunIN.10 - M1-SEL - Mode Switch 1
    SV630P_FunIN_11_M2_SEL,       ///< FunIN.11 - M2-SEL - Mode Switch 2
    SV630P_FunIN_12_ZCLAMP,       ///< FunIN.12 - ZCLAMP - Zero Position Fixed Enable
    SV630P_FunIN_13_INHIBIT,      ///< FunIN.13 - INHIBIT - Position Command Inhibit
    SV630P_FunIN_14_P_OT,         ///< FunIN.14 - P-OT - Positive Overtravel Switch
    SV630P_FunIN_15_N_OT,         ///< FunIN.15 - N-OT - Negative Overtravel Switch
    SV630P_FunIN_16_P_CL,         ///< FunIN.16 - P-CL - Positive External Torque Limit
    SV630P_FunIN_17_N_CL,         ///< FunIN.17 - N-CL - Negative External Torque Limit
    SV630P_FunIN_18_JOGCMD_PLUS,  ///< FunIN.18 - JOGCMD+ - Positive Jog
    SV630P_FunIN_19_JOGCMD_MINUS, ///< FunIN.19 - JOGCMD- - Negative Jog
    SV630P_FunIN_20_POSSTEP,      ///< FunIN.20 - POSSTEP - Step enable
    SV630P_FunIN_21_HX1,          ///< FunIN.21 - HX1 - Handwheel ratio signal 1
    SV630P_FunIN_22_HX2,          ///< FunIN.22 - HX2 - Handwheel ratio signal 2
    SV630P_FunIN_23_HX_EN,        ///< FunIN.23 - HX_EN - Handwheel enable signal
    SV630P_FunIN_24_GEAR_SEL,     ///< FunIN.24 - GEAR_SEL - Electronic gear selection
    SV630P_FunIN_25_TOQDirSel,    ///< FunIN.25 - TOQDirSel - Torque command direction setting
    SV630P_FunIN_26_SPDDirSel,    ///< FunIN.26 - SPDDirSel - Speed command direction setting
    SV630P_FunIN_27_POSDirSel,    ///< FunIN.27 - POSDirSel - Position command direction setting
    SV630P_FunIN_28_PosinSen,     ///< FunIN.28 - PosinSen - Multi-segment position command enable
    SV630P_FunIN_29_XintFree,     ///< FunIN.29 - XintFree - Interrupted fixed-length state release
    SV630P_FunIN_31_HomeSwitch, ///< FunIN.31 - HomeSwitch - Origin switch (original table FunIN.31, if 30 exists it can be added)
    SV630P_FunIN_32_HomingStart,      ///< FunIN.32 - HomingStart - Homing enable
    SV630P_FunIN_33_XintInhibit,      ///< FunIN.33 - XintInhibit - Interrupted fixed-length prohibition
    SV630P_FunIN_34_EmergencyStop,    ///< FunIN.34 - EmergencyStop - Emergency shutdown
    SV630P_FunIN_35_ClrPosErr,        ///< FunIN.35 - ClrPosErr - Clear position error
    SV630P_FunIN_36_V_LmtSel,         ///< FunIN.36 - V_LmtSel - Internal speed limit source
    SV630P_FunIN_37_PulseInhibit,     ///< FunIN.37 - PulseInhibit - Pulse command inhibition
    SV630P_FunIN_38_MultiBlockTrig,   ///< FunIN.38 - MultiBlockTrig - Axis control write interrupt
    SV630P_FunIN_39_MultiBlockWr,     ///< FunIN.39 - MultiBlockWr - Axis control write without interrupt
    SV630P_FunIN_40_ClrCmdOkAndArrOk, ///< FunIN.40 - ClrCmdOkAndArrOk - Clear command and positioning completion
    SV630P_FunIN_41_HomeRecord,       ///< FunIN.41 - HomeRecord - Set current position as origin
} SV630P_DIDO_FunIN;

/**
 * @brief SV630P Servo Drive DIDO Output Function (FunOUT) Enumeration
 *        Format: SV630P_FunOUT_Code_Name
 */
typedef enum
{
    SV630P_FunOUT_1_S_RDY = 1001,     ///< FunOUT.1 - S-RDY - Servo ready
    SV630P_FunOUT_2_TGON,             ///< FunOUT.2 - TGON - Motor rotation output
    SV630P_FunOUT_3_ZERO,             ///< FunOUT.3 - ZERO - Zero speed
    SV630P_FunOUT_4_V_CMP,            ///< FunOUT.4 - V-CMP - Speed match
    SV630P_FunOUT_5_COIN,             ///< FunOUT.5 - COIN - Positioning complete
    SV630P_FunOUT_6_NEAR,             ///< FunOUT.6 - NEAR - Positioning near
    SV630P_FunOUT_7_C_LT,             ///< FunOUT.7 - C-LT - Torque limit
    SV630P_FunOUT_8_V_LT,             ///< FunOUT.8 - V-LT - Speed limit
    SV630P_FunOUT_9_BK,               ///< FunOUT.9 - BK - Brake output
    SV630P_FunOUT_10_WARN,            ///< FunOUT.10 - WARN - Warning output
    SV630P_FunOUT_11_ALM,             ///< FunOUT.11 - ALM - Fault output
    SV630P_FunOUT_12_ALM01,           ///< FunOUT.12 - ALM01 - Output 3-bit alarm code
    SV630P_FunOUT_13_ALM02,           ///< FunOUT.13 - ALM02 - Output 3-bit alarm code
    SV630P_FunOUT_14_ALM03,           ///< FunOUT.14 - ALM03 - Output 3-bit alarm code
    SV630P_FunOUT_15_Xintcoin,        ///< FunOUT.15 - Xintcoin - Interrupted fixed-length completion
    SV630P_FunOUT_16_HomeAttain,      ///< FunOUT.16 - HomeAttain - Homing completed
    SV630P_FunOUT_17_ElectHomeAttain, ///< FunOUT.17 - ElectHomeAttain - Electrical homing output
    SV630P_FunOUT_18_ToqReach,        ///< FunOUT.18 - ToqReach - Torque reached output
    SV630P_FunOUT_19_V_Arr,           ///< FunOUT.19 - V-Arr - Speed arrived output
    SV630P_FunOUT_20_AngIntRdy,       ///< FunOUT.20 - AngIntRdy - Angle identification output
    SV630P_FunOUT_21_DB,              ///< FunOUT.21 - DB - DB brake output
    SV630P_FunOUT_22_CmdOk,           ///< FunOUT.22 - CmdOk - Internal command output
    SV630P_FunOUT_23_WrNextBlockEn,   ///< FunOUT.23 - WrNextBlockEn - Allow next segment write output
    SV630P_FunOUT_24_McOk,            ///< FunOUT.24 - McOk - Motion control output
    SV630P_FunOUT_26_RefAllow,        ///< FunOUT.26 - RefAllow - Servo enable to receive reference command
    SV630P_FunOUT_27_AlmAndWarn,      ///< FunOUT.27 - AlmAndWarn - Fault or warning active output signal
} SV630P_DIDO_FunOUT;

typedef struct sv630_trace
{
    void (*debug)(const char *fmt, ...);
    void (*info)(const char *fmt, ...);
    void (*warn)(const char *fmt, ...);
    void (*error)(const char *fmt, ...);
} sv630_trace_t;


#define SV630_DEBUG(dev, fmt, ...)                  \
    do                                              \
    {                                               \
        if ((dev) && ((dev)->trace.debug))          \
        {                                           \
            (dev)->trace.debug(fmt, ##__VA_ARGS__); \
        }                                           \
    } while (0)

#define SV630_INFO(dev, fmt, ...)                  \
    do                                             \
    {                                              \
        if ((dev) && ((dev)->trace.info))          \
        {                                          \
            (dev)->trace.info(fmt, ##__VA_ARGS__); \
        }                                          \
    } while (0)

#define SV630_WARN(dev, fmt, ...)                  \
    do                                             \
    {                                              \
        if ((dev) && ((dev)->trace.warn))          \
        {                                          \
            (dev)->trace.warn(fmt, ##__VA_ARGS__); \
        }                                          \
    } while (0)

#define SV630_ERROR(dev, fmt, ...)                  \
    do                                              \
    {                                               \
        if ((dev) && ((dev)->trace.error))          \
        {                                           \
            (dev)->trace.error(fmt, ##__VA_ARGS__); \
        }                                           \
    } while (0)

#define SV630P_ARGS_CHECK(dev)                                   \
    do                                                           \
    {                                                            \
        if (dev == NULL || dev->init == false)                   \
        {                                                        \
            SV630_ERROR(dev, "sv630p device not initialized\n"); \
            return SV630P_NOT_INIT;                              \
        }                                                        \
    } while (0)


struct sv630p_handle;

// return SV630P_OK or SV630P_BUS_ERR for operate modbus device
typedef struct
{
    int (*read_holding_regs)(struct sv630p_handle *dev, uint16_t address, uint16_t quantity, uint16_t *data);
    int (*read_input_regs)(struct sv630p_handle *dev, uint16_t address, uint16_t quantity, uint16_t *data);
    int (*write_single_reg)(struct sv630p_handle *dev, uint16_t address, uint16_t data);
    int (*write_multiple_regs)(struct sv630p_handle *dev, uint16_t address, uint16_t quantity, uint16_t *data);
} sv630p_ops_t;

typedef enum
{
    SV630P_DIR_UNKNOWN = 0,
    SV630P_DIR_FORWARD,
    SV630P_DIR_BACKWARD,
    SV630P_DIR_STOP,
} SV630P_Dir;

typedef struct sv630p_handle
{
    sv630p_ops_t   *ops;              ///< Servo drive operation interface
    void           *mb_handle;        ///< Modbus communication handle
    sv630_trace_t   trace;            ///< Servo drive debug information output interface
    bool            init;             ///< Servo drive initialization status
    bool            is_error;         ///< 0: no error, 1: error occurred
    bool            is_timer_running; ///< Timer running status
    SV630P_Dir      dir;
    double          rpm;
    double          last_rpm;
} sv630p_handle_t;

int sv630p_init(sv630p_handle_t *dev, sv630p_ops_t *ops, void *mb);

#endif
