#pragma once

#define _GNU_SOURCE 1

#include "compiler.h"

/* Standard C headers */
#include <inttypes.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* Arduino headers */
#include <Arduino.h>
#include <FreeRTOS.h>

/* ESP-IDF headers */
#include <sdkconfig.h>
#include <esp_err.h>
#include <esp_event.h>
#include <esp_log.h>

#include "xmalloc.h"

#ifndef MODULE
# define MODULE ""
#endif

#if DEBUG
# define CMSG(...) printf(__VA_ARGS__)
#else
# define CMSG(...) ((void)0)
#endif
#define MSG(...)  CMSG(MODULE ": " __VA_ARGS__)

/*
 * Hack to deal with the lack of this information in FreeRTOS proper
 */
#define EVENT_BITS	(configUSE_16_BIT_TICKS ? 8 : 24)
#define EVENT_ALL_BITS	((1U << EVENT_BITS)-1)

/*
 * Common types for callbacks
 */
typedef void *token_t;
typedef int (*read_func_t)(token_t token, void *buf, size_t len);
typedef int (*write_func_t)(token_t token, const void *buf, size_t len);

/*
 * Bad SPIRAM memory?
 */
extern_c bool _spiram_broken;
static inline bool spiram_broken(void)
{
    return _spiram_broken;
}

/*
 * Sleep thread...
 */
static inline void suspend(void)
{
    vTaskSuspend(NULL);
}

/*
 * Kill thread; vTaskDelete(NULL) *should* never return...
 */
static inline no_return exit_task(void)
{
    vTaskDelete(NULL);
    while (1) {
	/* vTaskDelete() returned!? */
	vTaskSuspend(NULL);
    }
}

/*
 * Convert a NULL pointer string to ""
 */
static inline const char *notempty(const char *str)
{
    return str ? str : "";
}
static inline char *dupstr(const char *str)
{
    return strdup(notempty(str));
}

/*
 * Reboot system
 */
extern_c void reboot_now(void);
extern_c int reboot_delayed(void);

/*
 * Main MAC address from efuses
 */
extern_c uint8_t efuse_default_mac[6];
extern_c char serial_number[16];

/*
 * Time sync status
 */
extern_c volatile bool time_net_sync_status;
struct timeval;
extern_c void time_net_sync(const struct timeval *tv);
extern_c void print_time(const char *msg, const struct timeval *tv);

/*
 * Log output
 */
extern_c volatile bool do_log_config_status;
extern_c void __fmt_printf(2,3)
  logmsg(const char *module, const char *fmt, ...);
extern_c void heap_info(void);
