#ifndef _IEC104_QUEUE_H
#define _IEC104_QUEUE_H

#include "iec104_conf.h"
#include "iec104_types.h"
#include <stdio.h>
#include <string.h>

/*
 * IEC104配置
 * */
#define IEC104LOCK
#define PRIO_QUEUE

#define IEC10X_PRIO_MAX      7
#define IEC10X_HEADER_LENGTH 1

/*
 * PRIO
 * */
#define IEC10X_PRIO_INITLINK  0
#define IEC10X_PRIO_CALLALL   1
#define IEC10X_PRIO_CALLGROUP 2
#define IEC10X_PRIO_CLOCK     3
#define IEC10X_PRIO_DELAY     3
#define IEC10X_PRIO_PULSE     0
#define IEC10X_PRIO_SPON      0

/*
 *  Transmission  Priority Queue.
 */
typedef struct iec104_callback_arg
{
    iec_8u *value;
    iec_32u pic_sn;
    iec_32u FramSerialNum;
} iec104_callback_arg_t;

typedef struct iec104_node
{
    iec_16u             Length;
    struct iec104_node *Next;
    void (*CallBack)(iec104_callback_arg_t *Arg);
    iec104_callback_arg_t CallBackArg;
    iec_8u                value[1];
} iec104_prio_node_t;

typedef struct iec104_queue
{
    struct iec104_node *header;
    struct iec104_node *tail;
    unsigned char       element_num;
} iec104_prio_queue_t;

/*
*********************************************************************************************************
*                                           BLOCK SIZE AND NUMBER
*
* if add part, please change OS_MAX_MEM_PART in ucosii.h.
*********************************************************************************************************
*/

/* IEC10X_PARTITION 1   size==256*8 */
#define IEC10X_PARTITION_NUM_1  5
#define IEC10X_PARTITION_SIZE_1 512
#define IEC10X_PARTITION_1      (IEC10X_PARTITION_SIZE_1 - 16)

/* IEC10X_PARTITION 2   size==(1300+16)*1 */
#define IEC10X_PARTITION_NUM_2  20
#define IEC10X_PARTITION_2      128
#define IEC10X_PARTITION_SIZE_2 (IEC10X_PARTITION_2 + sizeof(Iec10x_PrioNode_T))

/* IEC10X_PARTITION 1   size==64*20 */
#define IEC10X_PARTITION_NUM_3  10
#define IEC10X_PARTITION_3      32
#define IEC10X_PARTITION_SIZE_3 (IEC10X_PARTITION_3 + sizeof(Iec10x_PrioNode_T))

/*
*********************************************************************************************************
*                                           ASDU
*********************************************************************************************************
*/

/*
 * ASDU TYPE
 * */
#define Iec10x_M_EI_NA_1 0X46
#define IEC10X_C_IC_NA_1 0X64 /*CALL*/
#define IEC10X_C_CS_NA_1 103
#define IEC10X_C_CD_NA_1 106 /*CALL*/

/*Set data*/
#define IEC10X_C_SE_NA_1 48
#define IEC10X_C_SE_NC_1 50

/*
 * ASDU REASON
 * */
#define IEC10X_ASDU_REASON_INIT    0X04
#define IEC10X_ASDU_REASON_ACT     0X06
#define IEC10X_ASDU_REASON_ACTCON  0X07 /*CALL*/
#define IEC10X_ASDU_REASON_ACTFIN  0X08 /*CALL FINISH*/
#define IEC10X_ASDU_REASON_ACTTERM 0X0a /*CALL Terminal*/
#define IEC10X_ASDU_COT_UNKNOW     45

/*
 * INFO addr
 * */
#define IEC10X_INFO_addr_NONE 0X00

/*
*********************************************************************************************************
*                           REMOTE SIGNAL
*********************************************************************************************************
*/
/*
 * Asdu type (TI)
 * */
#define IEC10X_M_SP_NA_1 0X01
#define IEC10X_M_DP_NA_1 0X03
#define IEC10X_M_SP_TB_1 30
#define IEC10X_M_DP_TB_1 31
/*
 * Asdu reason (COT)
 * */
#define IEC10X_COT_BACK     2
#define IEC10X_COT_SPONT    3
#define IEC10X_COT_ACT      6
#define IEC10X_COT_ACTCON   7
#define IEC10X_COT_REQ      5
#define IEC10X_COT_RETREM   11
#define IEC10X_COT_RETLOC   12
#define IEC10X_COT_INTROGEN 20
#define IEC10X_COT_INTRO1   21
#define IEC10X_COT_INTRO2   22

/*
 * Asdu addr
 * */
#define IEC10X_INFO_ADDR_SIG_BASE        0X0001
#define IEC10X_INFO_ADDR_SIG_TEMP_HX_OFF 0x1000

/*
*********************************************************************************************************
*                           REMOTE DECTET
*********************************************************************************************************
*/
/*
 * Asdu type (TI)
 * */
#define IEC10X_M_ME_NA_1 9
#define IEC10X_M_ME_NC_1 13
#define IEC10X_M_ME_TD_1 34
#define IEC10X_M_ME_TF_1 36

/*
 * Asdu reason (COT)
 * */
#define IEC10X_COT_PER_CYC  1
#define IEC10X_COT_BACK     2
#define IEC10X_COT_SPONT    3
#define IEC10X_COT_REQ      5
#define IEC10X_COT_INTROGEN 20
#define IEC10X_COT_INTRO9   29
#define IEC10X_COT_INTRO10  30

/*
 * Asdu addr
 * */
#define IEC10X_INFO_addr_DET             0X4001
#define IEC10X_INFO_addr_DET_TEMP_HX_OFF 0x1000

/*
*********************************************************************************************************
*                           CALL QOI
*********************************************************************************************************
*/

#define IEC10X_CALL_QOI_TOTAL   20
#define IEC10X_CALL_QOI_GROUP1  21
#define IEC10X_CALL_QOI_GROUP2  22
#define IEC10X_CALL_QOI_GROUP9  29
#define IEC10X_CALL_QOI_GROUP10 30

/*
*********************************************************************************************************
*                           INFO addrEST
*               TD -- temprature device
*               PD -- pullotion device
*********************************************************************************************************
*/
#define IEC10X_SET_TD_UPCYCLE      0X100001
#define IEC10X_SET_TD_MAXIMUM      0X100002
#define IEC10X_SET_TD_MINIMUM      0X100003
#define IEC10X_SET_TD_DETCYCLE     0X100004
#define IEC10X_SET_TD_TEMPRISE     0X100005
#define IEC10X_SET_PD_DETCYCLE     0X100006
#define IEC10X_SET_PD_PULPSE       0X100007
#define IEC10X_SET_PD_SELFDETCYCLE 0X100008
/*
*********************************************************************************************************
*                           Fujian Huixing Add
*********************************************************************************************************
*/
/* TI. */
#define IEC10X_TI_FIRM_UPDATE     128
#define IEC10X_TI_AP_FIRM_BACKOFF 129
#define IEC10X_TI_AP_BASE_INFO    130

/* COT. */
#define IEC10X_COT_ACT_TERMINAL     8
#define IEC10X_COT_ACT_TERMINAL_ACK 9

#define IEC10X_COT_DATA         14
#define IEC10X_COT_DATA_ACK     15
#define IEC10X_COT_DATA_FIN     16
#define IEC10X_COT_DATA_FIN_ACK 17
#define IEC10X_COT_DATA_NEEDACK 0X100E

#pragma pack(1)

/*
 *  asdu number
 * */
typedef struct
{

    iec_8u _num : 7;
    iec_8u _sq  : 1;

} ASDU_NUM_T;
/*
 *  asdu reason
 * */
typedef struct
{
    iec_16u _reason : 14;
    iec_16u _pn     : 1;
    iec_16u _test   : 1;
} ASDU_REASON_T;
/*
 *  asdu
 * */
typedef struct
{

    iec_8u        _type;
    ASDU_NUM_T    _num;
    ASDU_REASON_T _reason;
    iec_16u       _addr;
    iec_8u        _info[1];
} iec10x_asdu_t, *p_iec10x_asdu_t;
/*
 *  asdu info
 * */
typedef struct
{
    iec_8u _addr[3];
    iec_8u _element[1];
} asdu_info_t, *p_asdu_info_t;

/*
 *  asdu info remote signal with time flag
 * */
typedef struct
{

    iec_8u _signal;
    iec_8u _time;
} SIGNAL_TIME_T, *PSIGNAL_TIME_T;

/*
 *  asdu info remote detect with time flag
 * */
/*int */
typedef struct
{

    iec_16s _detect;
    iec_8u  _qds;

} IEC10X_DETECT_T, *PIEC10X_DETECT_T;
/*float*/
typedef struct
{

    float  _detect;
    iec_8u _qds;

} IEC10X_DETECT_F_T, *PIEC10X_DETECT_F_T;

/*int  sq=0 */
typedef struct
{
    iec_8u  _addr[3];
    iec_16s _detect;
    iec_8u  _qds;

} IEC10X_DETECT_SQ0_T, *PIEC10X_DETECT_SQ0_T;
/*float sq=0*/
typedef struct
{

    iec_8u _addr[3];
    float  _detect;
    iec_8u _qds;

} IEC10X_DETECT_SQ0_F_T, *PIEC10X_DETECT_SQ0_F_T;

/*
 *  asdu info CP56Time2a
 * */
typedef struct
{

    iec_8u _minutes : 6;
    iec_8u _res     : 1;
    iec_8u _iv      : 1;
} iec10x_time_min_t, *p_iec10x_time_min_t;

typedef struct
{

    iec_8u _hours : 5;
    iec_8u _res   : 2;
    iec_8u _su    : 1;
} iec10x_time_hour_t, *p_iec10x_time_hour_t;
typedef struct
{

    iec_8u _dayofmonth : 5;
    iec_8u _dayofweek  : 3;
} IEC10X_Time_Day_T, *PIEC10X_Time_Day_T;
typedef struct
{

    iec_8u _month : 4;
    iec_8u _res   : 3;
} IEC10X_Time_Month_T, *PIEC10X_Time_Month_T;
typedef struct
{

    iec_8u _year : 7;
    iec_8u _res  : 1;
} IEC10X_Time_Year_T, *PIEC10X_Time_Year_T;
typedef struct
{

    iec_16u             _milliseconds;
    iec10x_time_min_t   _min;
    iec10x_time_hour_t  _hour;
    IEC10X_Time_Day_T   _day;
    IEC10X_Time_Month_T _month;
    IEC10X_Time_Year_T  _year;

} CP56Time2a_T, *PCP56Time2a_T;

/*
 *  asdu info remote detect with time flag
 * */
typedef struct
{

    iec_16u      _detect;
    iec_8u       _qds;
    CP56Time2a_T _time;
} DETECT_TIME_T, *PDETECT_TIME_T;

#pragma pack()

/*
 * Iec10x init
 */
typedef struct _iec104
{

    char *name;
    int (*init)(void);
    void (*delay_ms)(iec_16u);
    void (*close_link)(void);
    void *(*malloc)(iec_8u nbyte);
    void (*free)(void *buffer);
    iec_8u (*enqueue)(iec104_prio_queue_t *queue_hdr, iec104_prio_node_t *newnode);
    iec104_prio_node_t *(*dequeue)(iec104_prio_queue_t *queue_hdr);
    iec104_prio_node_t *(*find_qhead)(iec104_prio_queue_t *queue_hdr);
    iec_8u (*get_prio)(void);
    void (*queue_init)(iec104_prio_queue_t *PrioQueue);
    void (*queue_clear)(iec104_prio_queue_t *queue_hdr);
    iec_8u (*send)(int socketfd, char *data, int len);
    iec_32u (*set_time)(PCP56Time2a_T time);
    iec_32u (*get_time)(PCP56Time2a_T time);
    iec_8s (*get_station_state)(iec_16u addr, iec_8u dev_type);
    float (*get_sta_value)(iec_16u addr, iec_8u dev_type);
    iec_16u (*get_link_addr)(void);
    iec_8s (*get_info_num)(iec_8u *info_num, iec_8u dev_type);
    iec_8s (*set_config)(long value, iec_32u addr);
    iec_8s (*save_firmware)(iec_8u firm_len, iec_8u *buf, iec_32u firmware_type, iec_32u iec104_update_seek_addr);
    iec_8s (*check_firmware)(iec_32u firmware_type, iec_32u total_len);
    iec_8s (*update_firmware)(iec_32u firmware_type);
    iec_8s (*backoff_firmware)(iec_32u firmware_type);

#ifdef IEC104LOCK
    void (*lock)(void);
    void (*unlock)(void);
#endif

} *p_iec104_t, iec104_t;

/*
 * BIG ENDIAN
 * */
#ifdef BIG_ENDIAN
#define n2hs(x) (x)
#define h2ns(x) (x)

#define n2hl(x) (x)
#define h2nl(x) (x)
/* LITTLE ENDIAN */
#else
#define n2hs(x) ((((x) >> 8) & 0xFF) | (((x)&0xFF) << 8))
#define h2ns(x) ((((x) >> 8) & 0xFF) | (((x)&0xFF) << 8))

#define n2hl(x) ((((x) >> 24) & 0xFF) | (((x) >> 8) & 0xFF00) | \
                 (((x)&0xFF00) << 8) | (((x)&0xFF) << 24))
#define h2nl(x) ((((x) >> 24) & 0xFF) | (((x) >> 8) & 0xFF00) | \
                 (((x)&0xFF00) << 8) | (((x)&0xFF) << 24))
#endif /* BIG_ENDIAN */

/*
*********************************************************************************************************
*                                           EXTERN VARIABLE
*********************************************************************************************************
*/
extern p_iec104_t iec104;
extern iec_16u    iec104_state_addr;
extern iec_32s    iec104_build_send_sn;
extern iec_32s    iec104_build_recv_sn;

extern iec_16u      IEC10X_Cp16time2a;
extern iec_16u      IEC10X_Cp16time2a_V;
extern CP56Time2a_T IEC10X_Cp56time2a;
extern iec_8u       Iec10x_FirmwareUpdateFlag;

/*
 * Prio
 * */
iec_8u              iec104_prio_enqueue(iec104_prio_queue_t *queue_hdr, iec104_prio_node_t *new_p);
iec104_prio_node_t *iec104_prio_dequeue(iec104_prio_queue_t *queue_hdr);
iec_8u              iec10x_prio_highest(void);
void                iec104_prio_queue_init(iec104_prio_queue_t *PrioQueue);
void                iec104_prio_queue_clear(iec104_prio_queue_t *queue_hdr);
iec104_prio_node_t *iec104_prio_queue_find_head(iec104_prio_queue_t *queue_hdr);

/*
 * iec104 队列
 * */
void                iec104_queue_init(void);
void                iec104_queue_clear(void);
iec_8u              iec104_prio_get(iec_8u State);
void                iec104_enqueue(iec_8u *enq_buf, iec_16u Length, iec_8u Prio,
                                   void (*IEC10XCallBack)(iec104_callback_arg_t *Arg), iec104_callback_arg_t *CallbackArg);
void                iec104_scheduled(int socketfd);
iec104_prio_node_t *iec104_dequeue(void);
iec_32s             iec104_module_register(void *p_iec10x);
void                iec104_lock(void);
void                iec104_unlock(void);

#endif /*_IEC10X_H*/
