diff options
Diffstat (limited to 'fw/src/packet_interface.c')
-rw-r--r-- | fw/src/packet_interface.c | 98 |
1 files changed, 98 insertions, 0 deletions
diff --git a/fw/src/packet_interface.c b/fw/src/packet_interface.c new file mode 100644 index 0000000..98a1ef2 --- /dev/null +++ b/fw/src/packet_interface.c @@ -0,0 +1,98 @@ + +#include "packet_interface.h" +#include "noise.h" +#include "cobs.h" +#include "tracing.h" + +#include <libopencm3/stm32/usart.h> +#include <libopencm3/stm32/dma.h> +#include <libopencm3/cm3/nvic.h> +#include <libopencmsis/core_cm3.h> + +volatile struct { + struct dma_buf dma; + uint8_t data[256]; +} usart2_buf = { .dma = { .len = sizeof(usart2_buf.data) } }; + +struct dma_usart_file usart2_out_s = { + .usart = USART2, + .baudrate = 115200, + .dma = DMA1, + .stream = 6, + .channel = 4, + .irqn = NVIC_DMA_IRQ(1, 6), + .buf = &usart2_buf.dma +}; +struct dma_usart_file *usart2_out = &usart2_out_s; + +void dma1_stream6_isr(void) { + TRACING_SET(TR_HOST_IF_DMA_IRQ); + static unsigned int fifo_errors = 0; /* debug */ + if (dma_get_interrupt_flag(usart2_out->dma, usart2_out->stream, DMA_FEIF)) { + /* Ignore FIFO errors as they're 100% non-critical for UART applications */ + dma_clear_interrupt_flags(usart2_out->dma, usart2_out->stream, DMA_FEIF); + fifo_errors++; + TRACING_CLEAR(TR_HOST_IF_DMA_IRQ); + return; + } + + /* Transfer complete interrupt */ + dma_clear_interrupt_flags(usart2_out->dma, usart2_out->stream, DMA_TCIF); + + if (usart2_out->buf->wr_pos != usart2_out->buf->xfr_end) /* buffer not empty */ + schedule_dma(usart2_out); + TRACING_CLEAR(TR_HOST_IF_DMA_IRQ); +} + +void usart2_isr(void) { + TRACING_SET(TR_HOST_IF_USART_IRQ); + static struct cobs_decode_state host_cobs_state = {0}; + if (USART2_SR & USART_SR_ORE) { /* Overrun handling */ + LOG_PRINTF("USART2 data register overrun\n"); + /* Clear interrupt flag */ + (void)USART2_DR; /* FIXME make sure this read is not optimized out */ + host_packet_length = -1; + TRACING_CLEAR(TR_HOST_IF_USART_IRQ); + return; + } + + uint8_t data = USART2_DR; /* This automatically acknowledges the IRQ */ + + if (host_packet_length) { + LOG_PRINTF("USART2 COBS buffer overrun\n"); + host_packet_length = -1; + TRACING_CLEAR(TR_HOST_IF_USART_IRQ); + return; + } + + ssize_t rv = cobs_decode_incremental(&host_cobs_state, (char *)host_packet_buf, sizeof(host_packet_buf), data); + if (rv == 0) { + /* good, empty frame */ + LOG_PRINTF("Got empty frame from host\n"); + host_packet_length = -1; + } else if (rv == -1) { + /* Decoding frame, wait for next byte */ + } else if (rv == -2) { + LOG_PRINTF("Host interface COBS framing error\n"); + host_packet_length = -1; + } else if (rv == -3) { + /* invalid empty frame */ + LOG_PRINTF("Got double null byte from host\n"); + host_packet_length = -1; + } else if (rv == -4) { + /* frame too large */ + LOG_PRINTF("Got too large frame from host\n"); + host_packet_length = -1; + } else if (rv > 0) { + /* Good, non-empty frame */ + host_packet_length = rv; + } + TRACING_CLEAR(TR_HOST_IF_USART_IRQ); +} + +void send_packet(struct dma_usart_file *f, const uint8_t *data, size_t len) { + /* ignore return value as putf is blocking and always succeeds */ + (void)cobs_encode_incremental(f, putf, (char *)data, len); + flush(f); +} + |