/*
 * @file hv_vos_Conn.h
 * @brief Header file of connect.
 *
 * @verbatim
 * ==============================================================================
 *                        ##### How to use #####
 * ==============================================================================
 * (+) Use ()
 *
 * @endverbatim
 * @author HiView SoC Software Team
 * @version 1.0.0
 * @date 2023-03-01
 */

/** @file vos_conn.h
 *  @brief VOS board connection functions
*/


#ifndef _HV_VOS_CONN_H
#define _HV_VOS_CONN_H

#include "hv_vos_Types.h"
#include "hv_vos_Macro.h"
#include "hv_vos_Endian.h"
#include "hv_vos_Log.h"

VOS_EXTERN_C_BEGIN


/** @brief forward declaration of connection type */
typedef struct _HV_VOS_CONN_S Hv_Vos_CONN_S;

/** @defgroup VOS_CONN VOS_CONN
 *  VOS board connection functions
 *  @{
 */

/** @brief board connection type */
typedef enum _HV_VOS_CONN_TYPE_E {
    HV_VOS_CONN_SIM,        //!< simulate connection
    HV_VOS_CONN_ETHERNET,   //!< connect via ETHERNET

    HV_VOS_CONN_I2C,        //!< connect via I2C, need unlock
    HV_VOS_CONN_DSUI2C,     //!< connect via normal I2C

    HV_VOS_CONN_AUTO,       //<! got connection from ChipDebugger.ini
    HV_VOS_CONN_DSUSPI,     //!< connect via debug spi
} Hv_Vos_CONN_TYPE_E;


/// debug flag
typedef enum _HV_VOS_CONN_DEBUG_FLAG {
    HV_VOS_CONN_DEBUG_NONE        = 0,
    HV_VOS_CONN_DEBUG_READ        = 1,
    HV_VOS_CONN_DEBUG_WRITE       = 2,
    HV_VOS_CONN_DEBUG_READ_WRITE  = 3,
} HV_VOS_CONN_DEBUG_FLAG;


#define Hv_Vos_CONN_Open(type, connectString) (NULL)
#define Hv_Vos_CONN_Close(self)
#define Hv_Vos_CONN_IsConnected(self) (HV_TRUE)
#define Hv_Vos_CONN_SetDebug(self, flag)




#ifndef HV_PHY_ADDR
    #define HV_PHY_ADDR(addr) ((intptr_t)(addr))
#endif

/* little endian functions */
#define HV_R8(addr)             (*(volatile UCHAR8*)(HV_PHY_ADDR(addr)))
#define HV_W8(addr, value)      (*(volatile UCHAR8*)(HV_PHY_ADDR(addr)) = (value))

INLINE void HV_W8_MASK(UINT32 addr, UCHAR8 mask, UCHAR8 value){
    UCHAR8 val = HV_R8(addr);
    val = HV_MASK_ASSIGN(val, mask, value);
    HV_W8(addr, val);
}

/* big endian functions */
#define HV_R8_BE(addr)                      HV_R8(addr)
#define HV_W8_BE(addr, value)               HV_W8_BE(addr, value)
#define HV_W8_BE_MASK(addr, mask, value)    HV_W8_MASK(addr, mask, value)


#ifdef HV_CONFIG_ENDIAN_LITTLE

/* Access LE registers on LE CPU */
#define HV_R16(addr)                        (*(volatile USHORT16*)(HV_PHY_ADDR(addr)))
#define HV_W16(addr, value)                 (*(volatile USHORT16*)(HV_PHY_ADDR(addr)) = (value))

/* Access BE registers on LE CPU */
#define HV_R16_BE(addr)                     HV_SWAP16(*(volatile USHORT16*)(HV_PHY_ADDR(addr)))
#define HV_W16_BE(addr, value)              (*(volatile USHORT16*)(HV_PHY_ADDR(addr)) = HV_SWAP16(value))

#else

/* Access LE registers on BE CPU */
#define HV_R16(addr)                        HV_SWAP16((*(volatile USHORT16*)(HV_PHY_ADDR(addr))))
#define HV_W16(addr, value)                 (*(volatile USHORT16*)(HV_PHY_ADDR(addr)) = HV_SWAP16(value))

/* Access BE registers on BE CPU */
#define HV_R16_BE(addr)                     (*(volatile USHORT16*)(HV_PHY_ADDR(addr)))
#define HV_W16_BE(addr, value)              (*(volatile USHORT16*)(HV_PHY_ADDR(addr)) = (value))

#endif

INLINE void HV_W16_MASK(USHORT16 addr, USHORT16 mask, USHORT16 value){
    USHORT16 val = HV_R16(addr);
    val = HV_MASK_ASSIGN(val, mask, value);
    HV_W16(addr, val);
}


INLINE void HV_W16_BE_MASK(USHORT16 addr, USHORT16 mask, USHORT16 value){
    USHORT16 val = HV_R16_BE(addr);
    val = HV_MASK_ASSIGN(val, mask, value);
    HV_W16_BE(addr, val);
}



#ifdef HV_CONFIG_ENDIAN_LITTLE

/* Access LE registers on LE CPU */
#define HV_R32(addr)        (*(volatile UINT32*)(HV_PHY_ADDR(addr)))
#define HV_W32(addr, value) (*(volatile UINT32*)(HV_PHY_ADDR(addr)) = (value))

/* Access BE registers on LE CPU */
#define HV_R32_BE(addr)         HV_SWAP32(*(volatile UINT32*)(HV_PHY_ADDR(addr)))
#define HV_W32_BE(addr, value) (*(volatile UINT32*)(HV_PHY_ADDR(addr)) = HV_SWAP32(value))

#else

/* Access LE registers on BE CPU */

#define HV_R32(addr)        (HV_SWAP32(*(volatile UINT32*)(addr)))
#define HV_W32(addr, value) (*(volatile UINT32*)(addr)) = HV_SWAP32(value)



/* Access BE registers on BE CPU */
#define HV_R32_BE(addr)         (*(volatile UINT32*)(HV_PHY_ADDR(addr)))
#define HV_W32_BE(addr, value) (*(volatile UINT32*)(HV_PHY_ADDR(addr)) = (value))

#endif

INLINE void HV_W32_MASK(UINT32 addr, UINT32 mask, UINT32 value){
    UINT32 val = HV_R32(addr);
    val = HV_MASK_ASSIGN(val, mask, value);
    HV_W32(addr, val);
}

INLINE void HV_W32_BE_MASK(UINT32 addr, UINT32 mask, UINT32 value){
    UINT32 val = HV_R32_BE(addr);
    val = HV_MASK_ASSIGN(val, mask, value);
    HV_W32_BE(addr, val);
}


void HV_WRITE_MEM(UINT32 addr, const UCHAR8 *data, UINT32 size);

void HV_READ_MEM(UINT32 addr, UCHAR8 *data, UINT32 size);



/// define a variable for HV_R8_FIELD
#define HV_R8_DECL_VAR() UCHAR8 _reg_val

/// read register field, need HV_R8_DECL_VAR first
#define HV_R8_FIELD(addr, field)                            \
    (_reg_val = HV_R8(addr), ((addr##_struct*)(void*)&(_reg_val))->field)

/// read register field
#define HV_R8_FIELD_EX(addr, base, field)                   \
    (_reg_val = HV_R8(addr + base), ((addr##_struct*)&(_reg_val))->field)
    
#define HV_W8_FIELD(addr, field, value) do {                \
    UCHAR8 _val = HV_R8(addr);                               \
    ((addr##_struct*)&(_val))->field = value;               \
    HV_W8(addr, _val);                                      \
} while (0)

#define HV_W8_FIELD_EX(addr, base, field, value) do {       \
        UCHAR8 _val = HV_R8(addr + base);                    \
        ((addr##_struct*)&(_val))->field = value;           \
        HV_W8(addr + base, _val);                           \
} while (0)


/// read register field, need HV_R8_DECL_VAR first
#define HV_R8_BE_FIELD(addr, field)                         \
    (_reg_val = HV_R8_BE(addr), ((addr##_struct*)(void*)&(_reg_val))->field)

/// read register field
#define HV_R8_BE_FIELD_EX(addr, base, field)                \
    (_reg_val = HV_R8_BE(addr + base), ((addr##_struct*)&(_reg_val))->field)
    
#define HV_W8_BE_FIELD(addr, field, value) do {             \
    UCHAR8 _val = HV_R8_BE(addr);                            \
    ((addr##_struct*)&(_val))->field = value;               \
    HV_W8_BE(addr, _val);                                   \
} while (0)

#define HV_W8_FIELD_EX(addr, base, field, value) do {       \
        UCHAR8 _val = HV_R8(addr + base);                    \
        ((addr##_struct*)&(_val))->field = value;           \
        HV_W8(addr + base, _val);                           \
} while (0)


/// define a variable for HV_R16_FIELD
#define HV_R16_DECL_VAR() USHORT16 _reg_val

/// read register field, need HV_R16_DECL_VAR first
#define HV_R16_FIELD(addr, field)                           \
    (_reg_val = HV_R16(addr), ((addr##_struct*)(void*)&(_reg_val))->field)

/// read register field
#define HV_R16_FIELD_EX(addr, base, field)                  \
    (_reg_val = HV_R16(addr + base), ((addr##_struct*)&(_reg_val))->field)
    
#define HV_W16_FIELD(addr, field, value) do {               \
    UCHAR8 _val = HV_R16(addr);                              \
    ((addr##_struct*)&(_val))->field = value;               \
    HV_W16(addr, _val);                                     \
} while (0)

#define HV_W16_FIELD_EX(addr, base, field, value) do {      \
        USHORT16 _val = HV_R16(addr + base);                  \
        ((addr##_struct*)&(_val))->field = value;           \
        HV_W16(addr + base, _val);                          \
} while (0)


/// read register field, need HV_R16_DECL_VAR first
#define HV_R16_BE_FIELD(addr, field)                        \
    (_reg_val = HV_R16_BE(addr), ((addr##_struct*)(void*)&(_reg_val))->field)

/// read register field
#define HV_R16_BE_FIELD_EX(addr, base, field)               \
    (_reg_val = HV_R16_BE(addr + base), ((addr##_struct*)&(_reg_val))->field)
    
#define HV_W16_BE_FIELD(addr, field, value) do {            \
    UCHAR8 _val = HV_R16_BE(addr);                           \
    ((addr##_struct*)&(_val))->field = value;               \
    HV_W16_BE(addr, _val);                                  \
} while (0)

#define HV_W16_BE_FIELD_EX(addr, base, field, value) do {   \
        USHORT16 _val = HV_R16_BE(addr + base);               \
        ((addr##_struct*)&(_val))->field = value;           \
        HV_W16_BE(addr + base, _val);                       \
} while (0)




/// define a variable for HV_R32_FIELD
#define HV_R32_DECL_VAR() UINT32 _reg_val

/// read register field, need HV_R32_DECL_VAR first
#define HV_R32_FIELD(addr, field)                           \
    (_reg_val = HV_R32(addr), ((addr##_struct*)(void*)&(_reg_val))->field)

/// read register field
#define HV_R32_FIELD_EX(addr, base, field)                  \
    (_reg_val = HV_R32(addr + base), ((addr##_struct*)&(_reg_val))->field)
    
#define HV_W32_FIELD(addr, field, value) do {               \
    UINT32 _val = HV_R32(addr);                             \
    ((addr##_struct*)&(_val))->field = value;               \
    HV_W32(addr, _val);                                     \
} while (0)

#define HV_W32_FIELD_EX(addr, base, field, value) do {      \
        UINT32 _val = HV_R32(addr + base);                  \
        ((addr##_struct*)&(_val))->field = value;           \
        HV_W32(addr + base, _val);                          \
    } while (0)


/// read register field, need HV_R32_DECL_VAR first
#define HV_R32_BE_FIELD(addr, field)                       \
    (_reg_val = HV_R32_BE(addr), ((addr##_struct*)(void*)&(_reg_val))->field)

/// read register field
#define HV_R32_BE_FIELD_EX(addr, base, field)              \
    (_reg_val = HV_R32_BE(addr + base), ((addr##_struct*)&(_reg_val))->field)
    
#define HV_W32_BE_FIELD(addr, field, value) do {           \
    UINT32 _val = HV_R32_BE(addr);                         \
    ((addr##_struct*)&(_val))->field = value;              \
    HV_W32_BE(addr, _val);                                 \
} while (0)

#define HV_W32_BE_FIELD_EX(addr, base, field, value) do {     \
        UINT32 _val = HV_R32_BE(addr + base);                 \
        ((addr##_struct*)&(_val))->field = value;          \
        HV_W32_BE(addr + base, _val);                         \
    } while (0)



/// convert register structure to UINT32
#define HV_REG_VAL(reg) (*(UINT32*)&(reg))

/// express way to write a register struct data value
#define HV_W32_REG(addr, reg) HV_W32(addr, HV_REG_VAL(reg))

#define HV_W32_BE_REG(addr, reg) HV_W32_BE(addr, HV_REG_VAL(reg))

/// express way to read register to struct data value
#define HV_R32_REG(addr, reg) HV_REG_VAL(reg) = HV_R32(addr)

#define HV_R32_BE_REG(addr, reg) HV_REG_VAL(reg) = HV_R32_BE(addr)


#define HV_W32_SET_BIT(addr, bit) HV_W32_MASK(addr, 1 << (bit), 1 << (bit))

#define HV_W32_CLR_BIT(addr, bit) HV_W32_MASK(addr, 1 << (bit), 0x00000000)

#define HV_R32_GET_BIT(addr, bit) ((HV_R32(addr) >> bit) & 1)

#define HV_W_FEILD_REG(addr, startbit,endbit, reg) do{   \
    UINT32 _val = HV_R32(addr);                         \
    if((endbit-startbit) != 31)                         \
    {                                                   \
    UINT32 _mask = ~(0xFFFFFFFF << (endbit - startbit + 1)) << startbit;\
    _val &= ~_mask;                                          \
    _val |= (reg<<startbit)&_mask;                              \
    HV_W32(addr,_val);                                  \
    }                                                   \
    else                                                \
    {                                                   \
        HV_W32(addr,reg);                                  \
    }                                                       \
} while (0)



/** @} */
VOS_EXTERN_C_END

#endif



