#ifndef LIP_PTP_PROTO_DEFS_H
#define LIP_PTP_PROTO_DEFS_H

#include <stdint.h>
#include "lcspec.h"

#define LIP_PTP_CLOCK_IDENTITY_SIZE         8
#define LIP_PTP_PORT_IDENTITY_SIZE          10
#define LIP_PTP_SYSTEM_IDENTITY_SIZE        14
#define LIP_PTP_BMCA_PRIO_VECTOR_SIZE       28
#define LIP_PTP_PKT_TSTMP_SIZE              10
#define LIP_PTP_PKT_SCALEDNS_SIZE           12
#define LIP_PTP_AS_PTP_TLV_TOTAL_SIZE       32 /* полный размер Follow_Up information TLV для IEEE 802.1AS-2020 11.4.4.1  */

#define LIP_PTP_PROTO_VER_MJ     2
#define LIP_PTP_PROTO_VER_MN     1

#define LIP_PTP_SEC_NS_MUL 1000000000
#define LIP_PTP_FNS_SHIFT  16
#define LIP_PTP_FNS_FRACT_MAX  ((1UL << LIP_PTP_FNS_SHIFT))
#define LIP_PTP_FNS_FRACT_MASK (LIP_PTP_FNS_FRACT_MAX - 1)



#define LIP_PTP_MSGTYPE_IS_EVENT(msgtype)   (((msgtype) & 0x8) == 0)

typedef  enum {
    /* Event */
    LIP_PTP_MSGTYPE_SYNC                    = 0,
    LIP_PTP_MSGTYPE_DELAY_REQ               = 1,
    LIP_PTP_MSGTYPE_PDELAY_REQ              = 2,
    LIP_PTP_MSGTYPE_PDELAY_RESP             = 3,
    /* General */
    LIP_PTP_MSGTYPE_FOLLOW_UP               = 8,
    LIP_PTP_MSGTYPE_DELAY_RESP              = 9,
    LIP_PTP_MSGTYPE_PDELAY_RESP_FOLLOW_UP   = 10,
    LIP_PTP_MSGTYPE_ANNOUNCE                = 11,
    LIP_PTP_MSGTYPE_SIGNALING               = 12,
    LIP_PTP_MSGTYPE_MANAGEMENT              = 13,
} t_lip_ptp_msg_type;

typedef enum {
    LIP_PTP_MSGFLAG0_ALT_MASTER         =  1 << 0, /* Alternate Master Flag */
    LIP_PTP_MSGFLAG0_TWO_STEP           =  1 << 1, /* Two Step (Sync or PDelay_Req) */
    LIP_PTP_MSGFLAG0_UNICAST            =  1 << 2, /* Unicast address */
    LIP_PTP_MSGFLAG0_PROFILE_SPEC1      =  1 << 5, /* Profile Specific 1 */
    LIP_PTP_MSGFLAG0_PROFILE_SPEC2      =  1 << 6, /* Profile Specific 2 */
} t_lip_ptp_msg_flags0;

typedef enum {
    LIP_PTP_MSGFLAG1_LEAP_61            =  1 << 0,
    LIP_PTP_MSGFLAG1_LEAP_59            =  1 << 1,
    LIP_PTP_MSGFLAG1_CUR_UTC_OFFS_VALID =  1 << 2,
    LIP_PTP_MSGFLAG1_PTP_TIMESCALE      =  1 << 3,
    LIP_PTP_MSGFLAG1_TIME_TRACEABLE     =  1 << 4,
    LIP_PTP_MSGFLAG1_FREQ_TRACEABLE     =  1 << 5,
    LIP_PTP_MSGFLAG1_SYNC_UNCERTAIN     =  1 << 6,
} t_lip_ptp_msg_flags1;

typedef enum {
    LIP_PTP_TLV_CODE_MNGMNT                 = 0x0001,
    LIP_PTP_TLV_CODE_MNGMNT_ERR_STATUS      = 0x0002,
    LIP_PTP_TLV_CODE_ORG_EXT                = 0x0003,
    LIP_PTP_TLV_CODE_REQ_UNICAST_TX         = 0x0004,
    LIP_PTP_TLV_CODE_GRANT_UNICAST_TX       = 0x0005,
    LIP_PTP_TLV_CODE_CANCEL_UNICAST_TX      = 0x0006,
    LIP_PTP_TLV_CODE_ACK_CANCEL_UNICAST_TX  = 0x0005,
    LIP_PTP_TLV_CODE_PATH_TRACE             = 0x0008, /**< Path trace, propogate, 16.2 of IEEE 1588-2019 */
    LIP_PTP_TLV_CODE_ALT_TIME_OFFS_IND      = 0x0009, /**< Alternate Time Offset indicator, propogate, 16.3 of IEEE 1588-2019 */
    LIP_PTP_TLV_CODE_ORG_EXT_PROP           = 0x4000, /**< Organization Extension, porpagate, 14.3 of IEEE 1588-2019 */
    LIP_PTP_TLV_CODE_ENH_ACCUR_METRICS      = 0x4001, /**< Enchanced Accuracy Metrics, porpagate, 16.12 of IEEE 1588-2019 */
    LIP_PTP_TLV_CODE_ORG_EXT_NOT_PROP       = 0x8000,
    LIP_PTP_TLV_CODE_L1_SYNC                = 0x8001,
    LIP_PTP_TLV_CODE_PORT_COMM_AV           = 0x8002,
    LIP_PTP_TLV_CODE_PROTO_ADDR             = 0x8003,
    LIP_PTP_TLV_CODE_SLAVE_RX_SYNC_TIMING   = 0x8004,
    LIP_PTP_TLV_CODE_SLAVE_RX_SYNC_COMPUTE  = 0x8005,
    LIP_PTP_TLV_CODE_SLAVE_TX_EVT_TSTMP     = 0x8006,
    LIP_PTP_TLV_CODE_CUMUL_RATE_RATIO       = 0x8007,
    LIP_PTP_TLV_CODE_PAD                    = 0x8008,
    LIP_PTP_TLV_CODE_AUTH                   = 0x8009,
} t_lip_ptp_tlv_code;

#define LIP_PTP_TLV_PROP_INTERVAL_FIRST     0x4000
#define LIP_PTP_TLV_PROP_INTERVAL_LAST      0x7EFF
#define LIP_PTP_TLV_PROP_EXPERIMENTAL_FIRST 0x7FF0
#define LIP_PTP_TLV_PROP_EXPERIMENTAL_LAST  0x7FFF

#define LIP_PTP_MSGFLD_TYPESDOID_MSGTYPE    (0x0FUL << 0U)
#define LIP_PTP_MSGFLD_TYPESDOID_SDOID_MJ   (0x0FUL << 4U)

#define LIP_PTP_MSGFLD_VER_PTPVER_MJ        (0x0FUL << 0U)
#define LIP_PTP_MSGFLD_VER_PTPVER_MN        (0x0FUL << 4U)

#define LIP_PTP_SDOID_MJ_GENERAL            0
#define LIP_PTP_SDOID_MJ_GPTP               1
#define LIP_PTP_SDOID_MJ_CMLDS              2

#define LIP_PTP_LOGINT_INVALID              0x7F

#define LIP_PTP_TLV_ORG_HDR_SIZE                    6
#define LIP_PTP_ORGID_CODE_GPTP                     0x0080C2
#define LIP_PTP_ORG_GPTP_SUBTYPE_FUP                1 /* FullowUP TLV */
#define LIP_PTP_ORG_GPTP_SUBTYPE_GPTPCAP            4
#define LIP_PTP_ORG_GPTP_SUBTYPE_GPTPCAP_INT_REQ    5

#define LIP_PTP_LOG_INTERVAL_VAL_DISABLE            127
#define LIP_PTP_LOG_INTERVAL_VAL_DEFAULT            126
#define LIP_PTP_LOG_INTERVAL_VAL_NOT_CHANGE         -128

#include "lcspec_pack_start.h"

typedef uint8_t t_lip_ptp_clock_identity[LIP_PTP_CLOCK_IDENTITY_SIZE];
typedef struct {
    t_lip_ptp_clock_identity clockIdentity;
    uint16_t portNum;
} LATTRIBUTE_PACKED t_lip_ptp_port_identity;

typedef union {
    struct {
        uint16_t sec_h;
        uint32_t sec_l;
        uint32_t ns;
    } LATTRIBUTE_PACKED;
    uint8_t raw[LIP_PTP_PKT_TSTMP_SIZE];
} LATTRIBUTE_PACKED t_lip_ptp_pkt_tstmp;

typedef union {
    struct {
        int16_t nsec_h;
        int64_t nsec_l;
        uint16_t fract_ns;
    } LATTRIBUTE_PACKED tstmp;
    uint8_t raw[LIP_PTP_PKT_SCALEDNS_SIZE];
} LATTRIBUTE_PACKED t_lip_ptp_pkt_scaled_ns;

typedef struct {
    uint16_t tlvType;
    uint16_t lengthField;
} LATTRIBUTE_PACKED t_lip_ptp_tlv_hdr;

typedef struct {
    uint8_t msgType_mjSdoId;
    uint8_t ptpVer; /** PTP Version (major = 2, minor = 1) */
    uint16_t msgLen;
    uint8_t domainNum;
    uint8_t miSdoId;
    uint8_t flags0;
    uint8_t flags1;
    uint64_t corField;
    uint32_t msgTypeSpec;
    t_lip_ptp_port_identity srcPortIdentity;
    uint16_t seqId;
    uint8_t ctlField;
    int8_t logMsgInterval;
} LATTRIBUTE_PACKED t_lip_ptp_msg_hdr;


typedef struct {
    t_lip_ptp_msg_hdr           hdr;
    uint8_t                     reserved1[10];
    uint16_t                    currentUtcOffset;
    uint8_t                     reserved2;
    uint8_t                     grandmasterPriority1;
    uint32_t                    grandmasterClockQuality;
    uint8_t                     grandmasterPriority2;
    t_lip_ptp_clock_identity    grandmasterIdentity;
    uint16_t                    stepsRemoved;
    uint8_t                     timeSource;
} LATTRIBUTE_PACKED t_lip_ptp_msg_announce;

typedef struct {
    t_lip_ptp_msg_hdr           hdr;
    t_lip_ptp_port_identity     targetPortIdentity;
} LATTRIBUTE_PACKED t_lip_ptp_msg_signaling;


typedef struct {
    t_lip_ptp_msg_hdr           hdr;
    t_lip_ptp_pkt_tstmp         originTstmp;
} LATTRIBUTE_PACKED t_lip_ptp_msg_sync, t_lip_ptp_msg_delay_req;

typedef struct {
    t_lip_ptp_msg_hdr           hdr;
    t_lip_ptp_pkt_tstmp         precOriginTstmp;
} LATTRIBUTE_PACKED t_lip_ptp_msg_follow_up;

typedef struct {
    t_lip_ptp_msg_hdr           hdr;
    t_lip_ptp_pkt_tstmp         recvTstmp;
    t_lip_ptp_port_identity     reqPortIdentity;
} LATTRIBUTE_PACKED t_lip_ptp_msg_delay_resp;

typedef struct {
    t_lip_ptp_msg_hdr           hdr;
    t_lip_ptp_pkt_tstmp         originTstmp;
    uint8_t reserved[10];
} LATTRIBUTE_PACKED t_lip_ptp_msg_pdelay_req;

typedef struct {
    t_lip_ptp_msg_hdr           hdr;
    t_lip_ptp_pkt_tstmp         reqReceiptTstmp;
    t_lip_ptp_port_identity     reqPortIdentity;
} LATTRIBUTE_PACKED t_lip_ptp_msg_pdelay_resp;

typedef struct {
    t_lip_ptp_msg_hdr           hdr;
    t_lip_ptp_pkt_tstmp         respOriginTstmp;
    t_lip_ptp_port_identity     reqPortIdentity;
} LATTRIBUTE_PACKED t_lip_ptp_msg_pdelay_resp_follow_up;


typedef struct {
    int8_t logGptpCapableMessageInterval;
    uint8_t flags;
    uint32_t reserved;
} LATTRIBUTE_PACKED t_lip_ptp_orgtlv_gptp_cap;


typedef struct {
    uint16_t gmTimeBaseIndicator;
    t_lip_ptp_pkt_scaled_ns lastGmPhaseChange;
    int32_t scaledLastGmFreqChange;
} LATTRIBUTE_PACKED t_lip_ptp_last_time_change_info;


typedef struct {
    int32_t cumulativeScaledRateOffset;
    t_lip_ptp_last_time_change_info lastChange;
} LATTRIBUTE_PACKED t_lip_ptp_orgtlv_gptp_fup;



/* Варианты поля priority1 из таблицы 8-1 IEEE 802.1AS-2020 */
#define LIP_PTP_SYSTEM_PRIO1_CRITICAL           246 /* центаральная часть сети, от которой зависят остальные узлы */
#define LIP_PTP_SYSTEM_PRIO1_PERSIST            248 /* может отключаться, но при нормальной работе долен присутствовать */
#define LIP_PTP_SYSTEM_PRIO1_TRANSIENT          250 /* может отключиться в любой момент */
#define LIP_PTP_SYSTEM_PRIO1_NOT_GMCAP          255 /* не может быть GM */

/* Варианты ClockClass из таблицы 4 IEEE 1588-2019 */
#define LIP_PTP_SYSTEM_CLOCK_CLASS_PRISRC           6 /* прямое подключение к primary time source (не может быть slave) */
#define LIP_PTP_SYSTEM_CLOCK_CLASS_PRISRC_HOLDOVER  7
#define LIP_PTP_SYSTEM_CLOCK_CLASS_APPSRC           13 /* прямое подключение к application-specific источнику времени (не может быть slave) */
#define LIP_PTP_SYSTEM_CLOCK_CLASS_APPSRC_HOLDOVER  14
#define LIP_PTP_SYSTEM_CLOCK_CLASS_PRISRC_DEGR_A    52
#define LIP_PTP_SYSTEM_CLOCK_CLASS_APPSRC_DEGR_A    58
#define LIP_PTP_SYSTEM_CLOCK_CLASS_PRISRC_DEGR_B    187
#define LIP_PTP_SYSTEM_CLOCK_CLASS_APPSRC_DEGR_B    193
#define LIP_PTP_SYSTEM_CLOCK_CLASS_DEFAULT          248 /* ClockClass для GM-capable, но не определенный */
#define LIP_PTP_SYSTEM_CLOCK_CLASS_NOT_GMCAP        255 /* не может быть GM */
/* Варианты clockAccuracy из таблицы 5 IEEE 1588-2019 */
#define LIP_PTP_SYSTEM_CLOCK_ACCUR_UNKNOWN          254

#define LIP_PTP_SYSTEM_OFFS_LOGVAR_UNKNOWN          0x436A /* значение offsetScaledLogVariance, если не вычисляется (8.6.2.4 b из IEEE 802.1AS-2020) */

/* Варианты поля priority2 из 8.6.2.5  IEEE 802.1AS-2020 */
#define LIP_PTP_SYSTEM_PRIO2_RELAY_INST_DEFAULT     247 /* priority2 для relay (boundary clock) */
#define LIP_PTP_SYSTEM_PRIO2_END_INST_DEFAULT       248 /* priority2 для end instance (ordinary clock) */

/* Варианты timeSource из таблицы 6 IEEE 1588-2019 */
#define LIP_PTP_TIME_SRC_ATOMIC                     0x10
#define LIP_PTP_TIME_SRC_GNSS                       0x20
#define LIP_PTP_TIME_SRC_TERRESTRIAL_RADIO          0x30
#define LIP_PTP_TIME_SRC_SERIAL_TIME                0x39 /* IRIG-B */
#define LIP_PTP_TIME_SRC_PTP                        0x40
#define LIP_PTP_TIME_SRC_NTP                        0x50
#define LIP_PTP_TIME_SRC_HAND_SET                   0x60
#define LIP_PTP_TIME_SRC_OTHER                      0x90
#define LIP_PTP_TIME_SRC_INTERNAL_OSC               0xA0


/* System Identity - IEEE 802.1AS-2020 10.3.2 */
typedef union {
    uint8_t raw[LIP_PTP_SYSTEM_IDENTITY_SIZE];
    struct {
        uint8_t                     priority1;
        uint8_t                     clockClass;
        uint8_t                     clockAccuracy;
        uint16_t                    offsetScaledLogVariance;
        uint8_t                     priority2;
        t_lip_ptp_clock_identity    clockIdentity;
    } LATTRIBUTE_PACKED;
} LATTRIBUTE_PACKED t_lip_ptp_system_identity;



/* BCMA priority vector - IEEE 802.1AS-2020 10.3.4 */
typedef union {
    uint8_t raw[LIP_PTP_BMCA_PRIO_VECTOR_SIZE];
    struct {
        t_lip_ptp_system_identity   rootSystemIdentity;
        uint16_t                    stepsRemoved;
        t_lip_ptp_port_identity     sourcePortIdentity;
        uint16_t                    portNum;
    } LATTRIBUTE_PACKED;
} LATTRIBUTE_PACKED t_lip_ptp_bmca_prio_vector;


#include "lcspec_pack_restore.h"

#endif // LIP_PTP_PROTO_DEFS_H
