#include #include #include #include #include #include "encoding.h" #include "platform.h" #include "eos.h" #include "msgq.h" #include "interrupt.h" #include "net.h" #include "spi.h" #define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)) #define MAX(X, Y) (((X) > (Y)) ? (X) : (Y)) #define SPI_BUFQ_IDX_MASK(IDX) ((IDX) & (SPI_SIZE_BUFQ - 1)) EOSMsgQ _eos_spi_send_q; static EOSMsgItem spi_sndq_array[SPI_SIZE_BUFQ]; SPIBufQ _eos_spi_buf_q; static unsigned char spi_bufq_array[SPI_SIZE_BUFQ][SPI_SIZE_BUF]; extern EOSMsgQ _eos_event_q; uint8_t _eos_spi_state_flags = 0; uint32_t _eos_spi_state_len = 0; uint32_t _eos_spi_state_len_tx = 0; uint32_t _eos_spi_state_len_rx = 0; uint32_t _eos_spi_state_idx_tx = 0; uint32_t _eos_spi_state_idx_rx = 0; unsigned char _eos_spi_state_cmd = 0; unsigned char *_eos_spi_state_buf = NULL; uint8_t _eos_spi_state_next_cnt = 0; unsigned char *_eos_spi_state_next_buf = NULL; static eos_evt_fptr_t evt_handler[EOS_NET_MAX_CMD]; static uint16_t evt_handler_flags_buf_free = 0; static uint16_t evt_handler_flags_buf_acq = 0; static int spi_bufq_push(unsigned char *buffer) { _eos_spi_buf_q.array[SPI_BUFQ_IDX_MASK(_eos_spi_buf_q.idx_w++)] = buffer; return EOS_OK; } static unsigned char *spi_bufq_pop(void) { if (_eos_spi_buf_q.idx_r == _eos_spi_buf_q.idx_w) return NULL; return _eos_spi_buf_q.array[SPI_BUFQ_IDX_MASK(_eos_spi_buf_q.idx_r++)]; } static void spi_xchg_reset(void) { _eos_spi_state_flags &= ~SPI_FLAG_CTS; _eos_spi_state_flags |= SPI_FLAG_RST; // before starting a transaction, set SPI peripheral to desired mode SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_HOLD; SPI1_REG(SPI_REG_TXFIFO) = 0; SPI1_REG(SPI_REG_RXCTRL) = SPI_RXWM(0); SPI1_REG(SPI_REG_IE) = SPI_IP_RXWM; } static void spi_xchg_start(unsigned char cmd, unsigned char *buffer, uint16_t len) { _eos_spi_state_flags &= ~SPI_FLAG_CTS; _eos_spi_state_flags |= SPI_FLAG_INIT; if (_eos_spi_state_next_cnt && (_eos_spi_state_next_buf == NULL)) cmd |= EOS_NET_CMD_FLAG_ONEW; if (cmd & EOS_NET_CMD_FLAG_ONEW) _eos_spi_state_flags |= SPI_FLAG_ONEW; _eos_spi_state_cmd = cmd; _eos_spi_state_buf = buffer; _eos_spi_state_len_tx = len; _eos_spi_state_len_rx = 0; _eos_spi_state_idx_tx = 0; _eos_spi_state_idx_rx = 0; // before starting a transaction, set SPI peripheral to desired mode SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_HOLD; SPI1_REG(SPI_REG_TXFIFO) = ((cmd << 3) | (len >> 8)) & 0xFF; SPI1_REG(SPI_REG_TXFIFO) = len & 0xFF; SPI1_REG(SPI_REG_RXCTRL) = SPI_RXWM(1); SPI1_REG(SPI_REG_IE) = SPI_IP_RXWM; } static int spi_xchg_next(unsigned char *_buffer) { unsigned char cmd; unsigned char *buffer = NULL; uint16_t len; eos_msgq_pop(&_eos_spi_send_q, &cmd, &buffer, &len); if (cmd) { spi_xchg_start(cmd, buffer, len); } else if (_eos_spi_state_flags & SPI_FLAG_RTS) { if (_buffer == NULL) _buffer = spi_bufq_pop(); if (_buffer) { spi_xchg_start(0, _buffer, 0); return 0; } } return 1; } static void spi_handler_xchg(void) { volatile uint32_t r1, r2; int i; if (_eos_spi_state_flags & SPI_FLAG_RST) { _eos_spi_state_flags &= ~SPI_FLAG_RST; r1 = SPI1_REG(SPI_REG_RXFIFO); SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_AUTO; SPI1_REG(SPI_REG_IE) = 0x0; return; } else if (_eos_spi_state_flags & SPI_FLAG_INIT) { _eos_spi_state_flags &= ~SPI_FLAG_INIT; SPI1_REG(SPI_REG_TXCTRL) = SPI_TXWM(SPI_SIZE_WM); SPI1_REG(SPI_REG_IE) = SPI_IP_TXWM; r1 = SPI1_REG(SPI_REG_RXFIFO); r2 = SPI1_REG(SPI_REG_RXFIFO); if (_eos_spi_state_cmd & EOS_NET_CMD_FLAG_ONEW) { r1 = 0; r2 = 0; } _eos_spi_state_cmd = ((r1 & 0xFF) >> 3); _eos_spi_state_len_rx = ((r1 & 0x07) << 8); _eos_spi_state_len_rx |= (r2 & 0xFF); _eos_spi_state_len = MAX(_eos_spi_state_len_tx, _eos_spi_state_len_rx); // Work around esp32 bug if (_eos_spi_state_len < 6) { _eos_spi_state_len = 6; } else if ((_eos_spi_state_len + 2) % 4 != 0) { _eos_spi_state_len = ((_eos_spi_state_len + 2)/4 + 1) * 4 - 2; } if (_eos_spi_state_len > SPI_SIZE_BUF) { SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_AUTO; SPI1_REG(SPI_REG_IE) = 0x0; } return; } uint16_t sz_chunk = MIN(_eos_spi_state_len - _eos_spi_state_idx_tx, SPI_SIZE_CHUNK); for (i=0; i EOS_NET_MAX_CMD) { eos_evtq_bad_handler(cmd, buffer, len); } else { unsigned char idx = (cmd & ~EOS_EVT_MASK) - 1; uint16_t buf_free = ((uint16_t)1 << idx) & evt_handler_flags_buf_free; uint16_t buf_acq = ((uint16_t)1 << idx) & evt_handler_flags_buf_acq; if (buf_free) { eos_net_free(buffer, buf_acq); buffer = NULL; len = 0; } evt_handler[idx](cmd, buffer, len); if (buf_free && buf_acq) eos_net_release(); } } void eos_net_set_handler(unsigned char cmd, eos_evt_fptr_t handler, uint8_t flags) { if (flags) { uint16_t flag = (uint16_t)1 << ((cmd & ~EOS_EVT_MASK) - 1); if (flags & EOS_NET_FLAG_BUF_FREE) evt_handler_flags_buf_free |= flag; if (flags & EOS_NET_FLAG_BUF_ACQ) evt_handler_flags_buf_acq |= flag; } evt_handler[(cmd & ~EOS_EVT_MASK) - 1] = handler; } void eos_net_init(void) { int i; _eos_spi_buf_q.idx_r = 0; _eos_spi_buf_q.idx_w = 0; for (i=0; i