| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259 | #include "compiler.h"#include "common.h"#include "io.h"#include "console.h"#include "esp.h"#include "boardinfo_fpga.h"#include "config.h"struct esplink_head __esplink_head esplink_head;static volatile __esplink struct esplink_timesync tsync;static volatile __esplink struct esplink_ota ota;volatile __esplink char board_info_esp[BOARDINFO_SIZE];IRQHANDLER(esp,0){    uint32_t irqstatus = ESP_CPU_IRQ;    ESP_CPU_IRQ_CLR = irqstatus;    if (irqstatus & (1 << EL_DIRQ_UNDERRUN)) {	con_printf("esp: ESP link memory underrun!!\n");	ESP_SPI_IRQ = (1 << EL_UIRQ_READY); /* Block writes, reinitialize! */	return;    }    if (irqstatus & (1 << EL_DIRQ_TIME)) {	if (tsync.set.update) {	    SYSCLOCK_TICK_HOLD = tsync.set.tick;	    SYSCLOCK_DATETIME  = tsync.set.td;	    tsync.set.update = 0;	    do_write_rtc = true;	} else {	    tsync.get.td   = SYSCLOCK_DATETIME;	    tsync.get.tick = SYSCLOCK_TICK_HOLD;	    ESP_SPI_IRQ_SET = 1 << EL_UIRQ_TIME;	}    }    if (irqstatus & (1 << EL_DIRQ_BOARDINFO))	do_update_boardinfo = true;    if (irqstatus & (1 << EL_DIRQ_HELLO)) {	con_printf("esp: Got hello, sending ready...\n");	/* Hello, are you there? Yes, I'm here, and you can write data now */	ESP_SPI_IRQ_SET = (1 << EL_UIRQ_READY)|(1 << EL_UIRQ_WREN);    }    if (irqstatus & (1 << EL_DIRQ_CONFIG))	do_update_config = true;    /*     * Check to see if we got hello after an OTA process was completed     * or aborted; ESP will send EL_DIRQ_DONE to wake us up.     */    if (!(ESP_SPI_IRQ & (1 << EL_UIRQ_OTA))) {	ota.data = NULL;	ota.len  = 0;    }}void esp_ota(const void *data, size_t len){    mask_irq(ESP_IRQ);    ota.data = data;    ota.len  = len;    ESP_SPI_IRQ_SET = 1 << EL_UIRQ_OTA;    unmask_irq(ESP_IRQ);    while (ota.data)	waitfor(ESP_IRQ);}#define RINGBUF_BUF_SIZE 4096	/* Must be a power of 2 */static __esplink uint8_t rb_buf[EL_RB_COUNT][2][RINGBUF_BUF_SIZE];static __esplink struct esplink_ringbuf_desc       rb_desc[EL_RB_COUNT];static volatile __esplink struct esplink_ptrs_dstr rb_dstr[EL_RB_COUNT];static volatile __esplink struct esplink_ptrs_ustr rb_ustr[EL_RB_COUNT];static void esplink_rb_init(void){    unsigned int i;    for (i = 0; i < EL_RB_COUNT; i++) {	rb_desc[i].dstr.start = rb_buf[i][0];	rb_desc[i].dstr.size  = RINGBUF_BUF_SIZE;	rb_desc[i].ustr.start = rb_buf[i][1];	rb_desc[i].ustr.size  = RINGBUF_BUF_SIZE;    }    esplink_head.rb.desc       = rb_desc;    esplink_head.rb.dstr       = (void *)rb_dstr;    esplink_head.rb.ustr       = (void *)rb_ustr;    esplink_head.rb.count      = EL_RB_COUNT;}/* * Read and write from ring buffers. These are atomic only; on failure * returns the amount of data/space available, but does NOT advance * any pointers nor copy any data. */size_t esp_rb_read(enum esplink_ringbuf_user ring, void *data, size_t len){    const size_t size          = rb_desc[ring].dstr.size;    const size_t sizemask      = size - 1;    const uint8_t * const base = rb_desc[ring].dstr.start;    size_t head                = rb_ustr[ring].head;    size_t tail                = rb_dstr[ring].tail;    size_t avail               = (head - tail) & sizemask;    uint8_t *p                 = data;    size_t xlen                = len;    if (!len)	return 0;    if (avail < xlen)	return avail;    if (tail + xlen > size) {	size_t left = size - tail;	memcpy(p, base + tail, left);	p += left;	xlen -= left;	tail = 0;    }    memcpy(p, base + tail, xlen);    tail = (tail + xlen) & sizemask;    rb_dstr[ring].tail = tail;    ESP_SPI_IRQ_SET = 1 << EL_UIRQ_RINGBUF;    return len;}size_t esp_rb_write(enum esplink_ringbuf_user ring,		    const void *data, size_t len){    const size_t size          = RINGBUF_BUF_SIZE;    const size_t sizemask      = size - 1;    uint8_t * const base       = rb_desc[ring].ustr.start;    size_t tail                = rb_ustr[ring].tail;    size_t head                = rb_dstr[ring].head;    size_t avail               = (tail - head - 1) & sizemask;    const uint8_t *p           = data;    size_t xlen                = len;    if (!len)	return 0;    if (avail < xlen)	return avail;    if (head + xlen > size) {	size_t left = size - head;	memcpy(base + head, p, left);	p += left;	xlen -= left;	head = 0;    }    memcpy(base + head, p, xlen);    head = (head + xlen) & sizemask;    rb_dstr[ring].head = head;    ESP_SPI_IRQ_SET = 1 << EL_UIRQ_RINGBUF;    return len;}/* * Faster/simpler versions for reading/writing a single byte at a time; * esp_rb_getc() returns -1 if the ring is empty. * * esp_rb_putc() returns -1 on failure, otherwise the number of * bytes still free in the ring (a nonnegative number.) */__hot int esp_rb_getc(enum esplink_ringbuf_user ring){    const size_t size          = RINGBUF_BUF_SIZE;    const size_t sizemask      = size - 1;    const uint8_t * const base = rb_desc[ring].dstr.start;    size_t head                = rb_ustr[ring].head;    size_t tail                = rb_dstr[ring].tail;    int data;    if (tail == head)	return -1;		/* Buffer empty */    data = base[tail];    tail = (tail + 1) & sizemask;    rb_dstr[ring].tail = tail;    ESP_SPI_IRQ_SET = 1 << EL_UIRQ_RINGBUF;    return data;}__hot int esp_rb_putc(enum esplink_ringbuf_user ring, uint8_t data){    const size_t size          = RINGBUF_BUF_SIZE;    const size_t sizemask      = size - 1;    uint8_t * const base       = rb_desc[ring].ustr.start;    size_t tail                = rb_ustr[ring].tail;    size_t head                = rb_dstr[ring].head;    int avail                  = (tail - head - 1) & sizemask;    if (avail--) {	base[head] = data;	head = (head + 1) & sizemask;	rb_dstr[ring].head = head;	ESP_SPI_IRQ_SET = 1 << EL_UIRQ_RINGBUF;    }    return avail;}__hot enum ringbuf_status esp_rb_status(enum esplink_ringbuf_user ring){    const size_t size          = RINGBUF_BUF_SIZE;    const size_t sizemask      = size - 1;    const size_t utail         = rb_ustr[ring].tail;    const size_t dhead         = rb_ustr[ring].head;    const size_t uhead         = rb_dstr[ring].head;    const size_t dtail         = rb_dstr[ring].tail;    enum ringbuf_status status = RB_CONNECTED;    if (dhead != dtail)	status |= RB_RXDATA;    if ((utail - uhead - 1) & sizemask)	status |= RB_TXFREE;    return status;}void esp_init(void){    static char __dram_data esp_signature[] = "Hej tomtebuggar slå i glasen!";    ESP_CPU_IRQ                = 0;    ESP_SPI_IRQ                = 0;    memset(&esplink_head, 0, sizeof esplink_head);    esplink_head.hlen          = sizeof esplink_head;    esplink_head.board.cfg     = SYS_BOARDCFG;    memcpy(esplink_head.signature, esp_signature, sizeof esp_signature);    esplink_head.board_info    = &board_info_raw;    esplink_head.tsync         = &tsync;    esplink_head.ota           = &ota;    esplink_head.cfg.buf       = config_buf;    esplink_head.cfg.buflen    = sizeof config_buf;    esplink_rb_init();    esplink_head.magic         = ESPLINK_HEAD_MAGIC;    ESP_SPI_IRQ                = (1 << EL_UIRQ_READY);    unmask_irq(ESP_IRQ);}
 |