#pragma once

#ifdef __cplusplus
extern "C"
{
#endif

#include <stdint.h>
#include <stdio.h>
#include <time.h>

#define RX_BURST_MAX 32
#define MAX_THREAD_NUM 256 // limit by snowflake

#define ATOMIC_INC(x) __atomic_fetch_add(x, 1, __ATOMIC_RELAXED)
#define ATOMIC_DEC(x) __atomic_fetch_sub(x, 1, __ATOMIC_RELAXED)
#define ATOMIC_READ(x) __atomic_load_n(x, __ATOMIC_RELAXED)
#define ATOMIC_ZERO(x) __atomic_fetch_and(x, 0, __ATOMIC_RELAXED)
#define ATOMIC_ADD(x, y) __atomic_fetch_add(x, y, __ATOMIC_RELAXED)
#define ATOMIC_SET(x, y) __atomic_store_n(x, y, __ATOMIC_RELAXED)
#define MIN(x, y) ((x) < (y) ? (x) : (y))

#define likely(expr) __builtin_expect((expr), 1)
#define unlikely(expr) __builtin_expect((expr), 0)

/*
 * The maximum number of seconds that can be stored in the time_t value is 2147483647 –- a little over 68 years.
 *
 * struct timespec
 * {
 *     time_t tv_sec; // seconds
 *     long tv_nsec;  // nanoseconds
 * };
 *
 * 1  s = 1000 ms
 * 1 ms = 1000 us
 * 1 us = 1000 ns
 */

#define TIMESPEC_TO_MSEC(ts) ((ts).tv_sec * 1000 + (ts).tv_nsec / 1000000)

static inline uint64_t clock_get_real_time_ms()
{
    struct timespec now;
    clock_gettime(CLOCK_REALTIME_COARSE, &now);

    return TIMESPEC_TO_MSEC(now);
}

static inline void hexdump_to_fd(int fd, uint32_t idx, const char *data, uint16_t len)
{
    uint16_t i = 0;
    uint16_t used = 0;
    uint16_t offset = 0;

#define LINE_LEN 80
    char line[LINE_LEN]; /* space needed 8+16*3+3+16 == 75 */
    while (offset < len)
    {
        used = snprintf(line, LINE_LEN, "%08X ", idx + offset);

        // hexdump
        for (i = 0; ((offset + i) < len) && (i < 16); i++)
        {
            if (i == 8)
            {
                used += snprintf(line + used, LINE_LEN - used, " ");
            }
            used += snprintf(line + used, LINE_LEN - used, " %02x", (data[offset + i] & 0xff));
        }

        // padding
        for (; i <= 16; i++)
        {
            if (i == 8)
            {
                used += snprintf(line + used, LINE_LEN - used, " ");
            }
            used += snprintf(line + used, LINE_LEN - used, "   ");
        }

        // ascii
        for (i = 0; (offset < len) && (i < 16); i++, offset++)
        {
            unsigned char c = data[offset];
            if ((c < ' ') || (c > '~'))
            {
                c = '.';
            }
            if (i == 8)
            {
                used += snprintf(line + used, LINE_LEN - used, " ");
            }
            used += snprintf(line + used, LINE_LEN - used, "%c", c);
        }
        dprintf(fd, "%s\n", line);
    }
}

#ifdef __cplusplus
}
#endif
