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

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];
        uint64_t u64_buf;
    } data;
} pdu_tag, *p_pdu_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)

#endif
