/*
 * Common header file for ESP ("upstream") and FPGA ("downstream")
 * sides of link. This MUST contain only data structures!
 */
#ifndef ESPLINK_H
#define ESPLINK_H 1

#include <stdlib.h>
#include <stdbool.h>
#include <inttypes.h>

#define ESPLINK_HDR_ADDR	((const uint32_t *)0x40000000)

/*
 * Ring buffer descriptor structure; this should be setup time only
 * and is statically cached on the upstream side.
 */
struct esplink_ringbuf_desc {
    struct esplink_ringbuf {
	void *start;
	size_t size;		/* Power of 2 */
    } dstr, ustr;
};

/*
 * Upstream and downstream pointer blocks, with the pointers encoded as
 * offsets into the buffer.
 *
 * Note that the head and tail pointers are reversed between the two
 * directions to allow one to be copied to the other.
 */
struct esplink_ptrs_ustr {
    size_t head;
    size_t tail;
};
struct esplink_ptrs_dstr {
    size_t tail;
    size_t head;
};

struct esplink_timesync {
    struct esplink_timesync_buf {
	uint16_t update;
	uint16_t tick;
	union {
	    struct {
		unsigned int sec2     : 5;
		unsigned int min      : 6;
		unsigned int hour     : 5;
		unsigned int mday     : 5;
		unsigned int mon      : 4;
		unsigned int year     : 7;
	    } tm;
	    uint32_t td;
	};
    } get, set;
};

struct esplink_ota {
    const void *data;
    uint32_t len;
};

#define ESPLINK_CONFIG_BUFSIZE 16384
struct esplink_configbuf {
    volatile void *buf;	       /* Buffer for configuration and data */
    size_t buflen;	       /* Size of buffer */
};

#define ESPLINK_HEAD_MAGIC	0x3648dec4
#define MAX_SIGNATURE_LEN	64

struct esplink_head {
    volatile uint32_t magic;
    uint32_t          hlen;
    struct {
	union {
	    uint32_t    cfg;
	    struct {
		uint8_t fixes;
		uint8_t minor;
		uint8_t major;
		uint8_t fpga;
	    };
	};
    } board;

    volatile struct esplink_timesync *tsync;
    volatile struct esplink_ota *ota;
    struct esplink_configbuf cfg;

    struct esplink_ringbuf_head {
	uint32_t count;
	struct esplink_ringbuf_desc *desc;
	struct esplink_ptrs_dstr *dstr; /* Downstream (FPGA) side */
	struct esplink_ptrs_ustr *ustr; /* Upstream (ESP32) side */
    } rb;

    char signature[MAX_SIGNATURE_LEN]; /* Human-readable signature string */

    const void *board_info;	/* board_info structure pointer */
};

#define EL_DIRQ_UNDERRUN	0	/* Local interrupt/status bit */
#define EL_DIRQ_HELLO		1
#define EL_DIRQ_RINGBUF		2
#define EL_DIRQ_TIME		3
#define EL_DIRQ_DONE		4	/* Some operation completed */
#define EL_DIRQ_BOARDINFO	5	/* board_info structure updated */
#define EL_DIRQ_CONFIG		6	/* config_buf updated */

#define EL_UIRQ_WREN		0	/* Remote write enable bit, not IRQ */
#define EL_UIRQ_READY		1
#define EL_UIRQ_RINGBUF		2
#define EL_UIRQ_TIME		3
#define EL_UIRQ_OTA		4

/*
 * Well known ring buffer indicies; must match for both sides.
 * Currently assuming one link in each direction; if only a unidirectional
 * link is needed, leave the descriptor for the unused direction blank.
 */
enum esplink_ringbuf_user {
    EL_RB_CONFIG,

    EL_RB_COUNT
};

#endif	/* ESPLINK_H */
