#ifndef __QUEUE_H
#define __QUEUE_H
#include "stdio.h"

#define MAX_QSIZE (60u) /* 最大队列长度 */

typedef unsigned long long u64;

typedef struct
{
    struct
    {
        uint8_t ide;
        uint8_t rtr;
        uint8_t dlc;
    } reg;
    union
    {
        uint32_t r;
        struct
        {
            uint8_t sa : 8;
            uint8_t ps : 8;
            uint8_t pf : 8;
            uint8_t dp : 1;
            uint8_t r  : 1;
            uint8_t p  : 3;
        } b;
    } id;
    union
    {
        uint8_t  u8_buf[8];
        uint16_t u16_buf[4];
        uint32_t u32_buf[2];
        u64      u64_buf;
    } data;
} pdu_tag, *p_pdu_tag;

typedef struct
{
    uint8_t  buf[8];
    uint32_t can_id;
} CanData_TypeDef;

typedef struct
{
    uint16_t head;
    uint16_t tail;
    uint16_t count;
    pdu_tag  can_message[MAX_QSIZE];
} can_queue_tag, *p_can_queue_tag;

typedef enum
{
    Q_OK,
    Q_ERR,
    Q_FULL,
    Q_EMPTY,
} QUEUE_STATUS;

#define QUEUE_ENTRY(type, size) \
    struct                      \
    {                           \
        uint8_t head;           \
        uint8_t tail;           \
        uint8_t count;          \
        type    message[size];  \
    }

#define QUEUE_INIT(name)                 \
    {                                    \
        (name)->head = (name)->tail = 0; \
        (name)->count               = 0; \
    }

/* List functions. */
#define QUEUE_EMPTY(name) ((name)->count == 0)
#define QUEUE_MAX(name)   ((sizeof((name)->message)) / (sizeof((name)->message[0])))
#define QUEUE_FULL(name)  ((name)->count == ((sizeof((name)->message)) / (sizeof((name)->message[0]))))
#define EN_QUEUE(name, field, ret)                                                \
    do                                                                            \
    {                                                                             \
        if (QUEUE_FULL(name))                                                     \
        {                                                                         \
            ret = Q_FULL;                                                         \
        }                                                                         \
        else                                                                      \
        {                                                                         \
            (name)->count++;                                                      \
            (name)->message[(name)->head] = field;                                \
            (name)->head                  = ((name)->head + 1) % QUEUE_MAX(name); \
            ret                           = Q_OK;                                 \
        }                                                                         \
    } while (0)

#define DE_QUEUE(name, field, ret)                               \
    do                                                           \
    {                                                            \
        if (QUEUE_EMPTY(name))                                   \
        {                                                        \
            ret = Q_EMPTY;                                       \
        }                                                        \
        else                                                     \
        {                                                        \
            field        = (name)->message[(name)->tail];        \
            (name)->tail = ((name)->tail + 1) % QUEUE_MAX(name); \
            (name)->count--;                                     \
            ret = Q_OK;                                          \
        }                                                        \
    } while (0)

void         queue_init(p_can_queue_tag);  // 初始化队列
uint8_t      queue_empty(p_can_queue_tag); // 查询队列是否为空
uint8_t      queue_full(p_can_queue_tag);
uint8_t      get_head(can_queue_tag *p_queue, pdu_tag *data); // 获取对头数据
QUEUE_STATUS en_queue(p_can_queue_tag, pdu_tag);              // 队列插入数据
QUEUE_STATUS de_queue(p_can_queue_tag, pdu_tag);
#endif
