From 7570c78a802a8a9300e9747beda701cc8f7e16c1 Mon Sep 17 00:00:00 2001 From: Attila BODY Date: Wed, 20 Nov 2019 21:13:52 +0100 Subject: [PATCH] initial commit --- component.mk | 10 ++ consolehandler.c | 68 ++++++++++++ consolehandler.h | 20 ++++ crcscheduler.c | 179 ++++++++++++++++++++++++++++++++ crcscheduler.h | 62 +++++++++++ dmahelper.c | 78 ++++++++++++++ dmahelper.h | 35 +++++++ f4ll_c | 1 + memcpydma.c | 48 +++++++++ memcpydma.h | 18 ++++ packetusart.c | 265 +++++++++++++++++++++++++++++++++++++++++++++++ packetusart.h | 142 +++++++++++++++++++++++++ strutil.c | 110 ++++++++++++++++++++ strutil.h | 31 ++++++ 14 files changed, 1067 insertions(+) create mode 100644 component.mk create mode 100644 consolehandler.c create mode 100644 consolehandler.h create mode 100644 crcscheduler.c create mode 100644 crcscheduler.h create mode 100644 dmahelper.c create mode 100644 dmahelper.h create mode 120000 f4ll_c create mode 100644 memcpydma.c create mode 100644 memcpydma.h create mode 100644 packetusart.c create mode 100644 packetusart.h create mode 100644 strutil.c create mode 100644 strutil.h diff --git a/component.mk b/component.mk new file mode 100644 index 0000000..ebed01c --- /dev/null +++ b/component.mk @@ -0,0 +1,10 @@ +#encoder +SELF_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) +REL_DIR := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST)))) +ifeq ($(MKDBG), 1) + $(info >>> $(REL_DIR)/component.mk) +endif +$(eval C_SOURCES += $(wildcard $(REL_DIR)/*.c)) +ifeq ($(MKDBG), 1) + $(info <<<) +endif diff --git a/consolehandler.c b/consolehandler.c new file mode 100644 index 0000000..7b6e944 --- /dev/null +++ b/consolehandler.c @@ -0,0 +1,68 @@ +/* + * interrupt.c + * + * Created on: Aug 29, 2019 + * Author: abody + */ +#include "main.h" +#include "globals.h" +#include "f4ll_c/packetusart.h" +#include "f4ll_c/strutil.h" + +#ifndef DIAG_INTERRUPT_IN +# define DIAG_INTERRUPT_IN() +#endif + +#ifndef DIAG_INTERRUPT_OUT +# define DIAG_INTERRUPT_OUT() +#endif + +void Con_HandleTxDmaIrq(DMAINFO *info, USART_TypeDef *usart) // debug usart +{ + DIAG_INTERRUPT_IN(); + if(*info->isReg & info->tcMask) { // DMA transfer complete + *info->ifcReg = info->tcMask; + LL_USART_EnableIT_TC(usart); + LL_DMA_DisableStream(info->dma, info->stream); + } + DIAG_INTERRUPT_OUT(); +} + +void Con_HandleUsartIrq(USART_TypeDef *usart) +{ + DIAG_INTERRUPT_IN(); + if(LL_USART_IsActiveFlag_TC(usart) && LL_USART_IsEnabledIT_TC(usart)) // transmission complete + LL_USART_DisableIT_TC(usart); + DIAG_INTERRUPT_OUT(); +} + +#define ADDINFO(b,s,u) \ + b += strcpy_ex(b,s); \ + b += uitodec(b,u); + +void Con_PrintStats(char *buffer, uint8_t id, struct usart_stats *stats, USART_TypeDef *usart, DMAINFO *dmaInfo) +{ + char ids[] = " : "; + char *bs = buffer; + + ids[0] = id + '0'; + buffer += strcpy_ex(buffer, ids); + ADDINFO(buffer, " s: ", stats->sent); + ADDINFO(buffer, " r: ", stats->rcvd); + ADDINFO(buffer, " sk: ", stats->skiped); + ADDINFO(buffer, " or: ", stats->overrun); + ADDINFO(buffer, " he: ", stats->hdrError); + buffer += strcpy_ex(buffer,",0x"); + buffer += uitohex(buffer, stats->lastErrHdr, 8); + ADDINFO(buffer, " pe: ", stats->payloadErrror); + buffer += strcpy_ex(buffer,",0x"); + buffer += uitohex(buffer, stats->pep1, 8); + buffer += strcpy_ex(buffer,",0x"); + buffer += uitohex(buffer, stats->pep2, 8); + ADDINFO(buffer, " de: ", stats->dmaError); + ADDINFO(buffer, " pmh: ", stats->premature_hdr); + ADDINFO(buffer, " pmp: ", stats->premature_payload); + buffer += strcpy_ex(buffer, "\r\n"); + + Pku_SetupTransmit(usart, dmaInfo->dma, dmaInfo->stream, bs, buffer - bs + 1); +} diff --git a/consolehandler.h b/consolehandler.h new file mode 100644 index 0000000..cbb9207 --- /dev/null +++ b/consolehandler.h @@ -0,0 +1,20 @@ +/* + * interrupt.h + * + * Created on: Aug 29, 2019 + * Author: abody + */ + +#ifndef INTERRUPT_HANDLERS_H_ +#define INTERRUPT_HANDLERS_H_ + +#include "usart.h" +#include "f4ll_c/dmahelper.h" +#include "f4ll_c/packetusart.h" + +void Con_HandleTxDmaIrq(DMAINFO *info, USART_TypeDef *usart); +void Con_HandleUsartIrq(USART_TypeDef *usart); + +void Con_PrintStats(char *buffer, uint8_t id, struct usart_stats *stats, USART_TypeDef *usart, DMAINFO *dmaInfo); + +#endif /* INTERRUPT_HANDLERS_H_ */ diff --git a/crcscheduler.c b/crcscheduler.c new file mode 100644 index 0000000..87d4d45 --- /dev/null +++ b/crcscheduler.c @@ -0,0 +1,179 @@ +/* + * interrupt.c + * + * Created on: Aug 29, 2019 + * Author: abody + */ +#include +#include "main.h" +#include +#include +#include "diag.h" +#include "f4ll_c/dmahelper.h" + +#ifndef DIAG_CRC_CALC_START +# define DIAG_CRC_CALC_START() +#endif + +#ifndef DIAG_CRC_CALC_END +# define DIAG_CRC_CALC_END() +#endif + +#ifndef DIAG_INTERRUPT_IN +# define DIAG_INTERRUPT_IN() +#endif + +#ifndef DIAG_INTERRUPT_OUT +# define DIAG_INTERRUPT_OUT() +#endif + +void Crc_InitStatus(struct crcstatus_t *st, DMA_TypeDef *dma, uint32_t stream) +{ + Dma_Init(&st->dmaInfo, dma, stream); + LL_DMA_EnableIT_TC(dma, stream); + LL_DMA_EnableIT_TE(dma, stream); + LL_DMA_SetM2MDstAddress(dma, stream, (uint32_t)&CRC->DR); + st->activeSlot = NULL; + st->first = NULL; +} + +void Crc_AttachTask(struct crcstatus_t *status, struct crcslotlistitem_t *slot, struct crcslottask_t *tasks, uint8_t taskCount) +{ + slot->count = taskCount; + slot->tasks = tasks; + memset(tasks, 0, sizeof(*tasks)*taskCount); + + uint32_t prim = __get_PRIMASK(); + __disable_irq(); + slot->next = status->first; + status->first = slot; + __set_PRIMASK(prim); +} + +uint8_t Crc_GetActiveTask(struct crcslotlistitem_t **slot_out, struct crcstatus_t volatile *status) +{ + uint8_t ret; + + uint32_t prim = __get_PRIMASK(); + + __disable_irq(); + ret = status->activeTask; + if(slot_out) + *slot_out = (struct crcslotlistitem_t *) status->activeSlot; + __set_PRIMASK(prim); + return ret; +} + + +uint8_t Crc_Enqueue(struct crcstatus_t *status, struct crcslotlistitem_t *slot, uint8_t task, + uint8_t *address, uint16_t len, void (*callback)(void*, uint32_t, uint8_t), void* callbackParam) +{ + uint32_t prim = __get_PRIMASK(); + uint16_t need_start; + struct crcstatus_t volatile *st = status; + + while(st->activeSlot == slot && st->activeTask == task); + __disable_irq(); + need_start = (st->activeSlot == NULL); + slot->tasks[task].address = need_start ? NULL : address; + slot->tasks[task].wordCount = (len+3)/4; + slot->tasks[task].callback = callback; + slot->tasks[task].callbackParam = callbackParam; + if(need_start) { + status->activeSlot = slot; + status->activeTask = task; + } + __set_PRIMASK(prim); + + if(need_start) { + CRC->CR = 1; + LL_DMA_SetM2MSrcAddress(status->dmaInfo.dma, status->dmaInfo.stream, (uint32_t)address); + LL_DMA_SetDataLength(status->dmaInfo.dma, status->dmaInfo.stream, (len+3)/4); + DIAG_CRC_CALC_START(); + LL_DMA_EnableStream(status->dmaInfo.dma, status->dmaInfo.stream); + } + return need_start; +} + +void Crc_WaitResults(struct crcstatus_t *status, struct crcslotlistitem_t *slot, uint8_t task) +{ + struct crcslotlistitem_t *slotQueued; + + while(Crc_IsSlotQueued(slot, task)); + while(Crc_GetActiveTask(&slotQueued, status) == task && slotQueued == slot); +} + + +uint32_t Crc_Compute(struct crcstatus_t *status, struct crcslotlistitem_t *slot, uint8_t task, uint8_t *address, uint16_t len) +{ + uint32_t result; + Crc_Enqueue(status, slot, task, address, len, NULL, &result); + while((struct crcslotlistitem_t volatile *)slot->tasks[task].callbackParam); + return result; +} + +// only called from ISR context +static void StartNextCrcTask(struct crcstatus_t *status) +{ + char moreTasks; + uint8_t index = 0; + + do { + struct crcslotlistitem_t *slot = status->first; + moreTasks = 0; + while(slot) { + if(index < slot->count) { + if(slot->tasks[index].address) { + status->activeSlot = slot; + status->activeTask = index; + CRC->CR = 1; + LL_DMA_SetM2MSrcAddress(status->dmaInfo.dma, status->dmaInfo.stream, (uint32_t)slot->tasks[index].address); + LL_DMA_SetDataLength(status->dmaInfo.dma, status->dmaInfo.stream, slot->tasks[index].wordCount); + LL_DMA_EnableStream(status->dmaInfo.dma, status->dmaInfo.stream); + slot->tasks[index].address = NULL; // marking as started + return; + } + if(index + 1 < slot->count) + moreTasks = 1; + } + slot = slot->next; + } + ++index; + } while(moreTasks); + status->activeSlot = NULL; +} + +void Crc_HandleDmaIrq(struct crcstatus_t *status) +{ + DIAG_INTERRUPT_IN(); + if(*status->dmaInfo.isReg & status->dmaInfo.tcMask) { // DMA transfer complete + *status->dmaInfo.ifcReg = status->dmaInfo.tcMask; + LL_DMA_DisableStream(status->dmaInfo.dma, status->dmaInfo.stream); + if(status->activeSlot) { + struct crcslottask_t *tsk = &status->activeSlot->tasks[status->activeTask]; + if(tsk->callback) + tsk->callback(tsk->callbackParam, CRC->DR, 1); + else if(tsk->callbackParam) + *(uint32_t*)tsk->callbackParam = CRC->DR; + tsk->callback = tsk->callbackParam = NULL; // marking as inactive + DIAG_CRC_CALC_END(); + StartNextCrcTask(status); + } + } + else if(*status->dmaInfo.isReg & status->dmaInfo.teMask) { + *status->dmaInfo.ifcReg = status->dmaInfo.teMask; + LL_DMA_DisableStream(status->dmaInfo.dma, status->dmaInfo.stream); + if(status->activeSlot) { + struct crcslottask_t *tsk = &status->activeSlot->tasks[status->activeTask]; + if(tsk->callback) + tsk->callback(tsk->callbackParam, CRC->DR, 0); + else if(tsk->callbackParam) + *(uint32_t*)tsk->callbackParam = 0xffffffff; + tsk->callback = tsk->callbackParam = NULL; // marking as inactive + DIAG_CRC_CALC_END(); + StartNextCrcTask(status); + } + } + DIAG_INTERRUPT_OUT(); +} + diff --git a/crcscheduler.h b/crcscheduler.h new file mode 100644 index 0000000..b82a1e0 --- /dev/null +++ b/crcscheduler.h @@ -0,0 +1,62 @@ +/* + * interrupt.h + * + * Created on: Aug 29, 2019 + * Author: abody + */ + +#ifndef CRC_HANDLER_H_ +#define CRC_HANDLER_H_ + +#include + +#ifdef HAVE_CONFIG +#include "config.h" +#endif // HAVE_CONFIG + +#include + +struct crcslottask_t { + void * volatile address; + uint16_t wordCount; + void (*callback)(void*, uint32_t, uint8_t); + void *callbackParam; +}; + +struct crcslotlistitem_t { + uint16_t count; + struct crcslotlistitem_t *next; + struct crcslottask_t *tasks; +}; + +struct crcstatus_t { + DMAINFO dmaInfo; + struct crcslotlistitem_t *activeSlot; + uint8_t activeTask; + struct crcslotlistitem_t *first; +}; + +void Crc_InitStatus(struct crcstatus_t *status, DMA_TypeDef *dma, uint32_t stream); + +uint8_t Crc_GetActiveTask(struct crcslotlistitem_t **slot_out, struct crcstatus_t volatile *status); + +static inline uint8_t Crc_IsSlotQueued(struct crcslotlistitem_t volatile *slot, uint8_t task) { + return slot->tasks[task].address != NULL; +} + +static inline uint8_t Crc_IsSlotActive(struct crcslotlistitem_t volatile *slot, uint8_t task) { + return slot->tasks[task].callback != NULL || slot->tasks[task].callbackParam != NULL; +} + +void Crc_AttachTask(struct crcstatus_t *status, struct crcslotlistitem_t *slot, struct crcslottask_t *tasks, uint8_t taskCount); + +uint8_t Crc_Enqueue(struct crcstatus_t *status, struct crcslotlistitem_t *slot, uint8_t task, + uint8_t *address, uint16_t len, void (*callback)(void*, uint32_t, uint8_t), void* callbackParam); +void Crc_WaitResults(struct crcstatus_t *status, struct crcslotlistitem_t *slot, uint8_t task); +uint32_t Crc_Compute(struct crcstatus_t *status, struct crcslotlistitem_t *slot, uint8_t task, uint8_t *address, uint16_t len); +void Crc_ComputeAsync(struct crcstatus_t *status, uint8_t slot, + uint8_t *address, uint16_t len, + void (*callback)(void*, uint32_t, uint8_t), void* callbackParam); +void Crc_HandleDmaIrq(struct crcstatus_t *status); + +#endif /* CRC_HANDLER_H_ */ diff --git a/dmahelper.c b/dmahelper.c new file mode 100644 index 0000000..b516d43 --- /dev/null +++ b/dmahelper.c @@ -0,0 +1,78 @@ +/* + * dma_helper.c + * + * Created on: Sep 18, 2019 + * Author: abody + */ +#include + + +volatile uint32_t* Dma_GetIsReg(DMA_TypeDef *dma, uint32_t stream) +{ + if(dma == DMA1) + return (stream < LL_DMA_STREAM_4) ? &DMA1->LISR : &DMA1->HISR; + else + return (stream < LL_DMA_STREAM_4) ? &DMA2->LISR : &DMA2->HISR; +} + +volatile uint32_t* Dma_GetIfcReg(DMA_TypeDef *dma, uint32_t stream) +{ + if(dma == DMA1) + return (stream < LL_DMA_STREAM_4) ? &DMA1->LIFCR : &DMA1->HIFCR; + else + return (stream < LL_DMA_STREAM_4) ? &DMA2->LIFCR : &DMA2->HIFCR; +} + +uint32_t Dma_GetFeMask(uint32_t stream) +{ + static const uint32_t feMasks[8] = { + DMA_LISR_FEIF0, DMA_LISR_FEIF1, DMA_LISR_FEIF2, DMA_LISR_FEIF3, DMA_HISR_FEIF4, DMA_HISR_FEIF5, DMA_HISR_FEIF6, DMA_HISR_FEIF7 + }; + return feMasks[stream]; +} + +uint32_t Dma_GetDmeMask(uint32_t stream) +{ + static const uint32_t dmeMasks[8] = { + DMA_LISR_DMEIF0, DMA_LISR_DMEIF1, DMA_LISR_DMEIF2, DMA_LISR_DMEIF3, DMA_HISR_DMEIF4, DMA_HISR_DMEIF5, DMA_HISR_DMEIF6, DMA_HISR_DMEIF7 + }; + return dmeMasks[stream]; +} + +uint32_t Dma_GetTeMask(uint32_t stream) +{ + static const uint32_t teMasks[8] = { + DMA_LISR_TEIF0, DMA_LISR_TEIF1, DMA_LISR_TEIF2, DMA_LISR_TEIF3, DMA_HISR_TEIF4, DMA_HISR_TEIF5, DMA_HISR_TEIF6, DMA_HISR_TEIF7 + }; + return teMasks[stream]; +} + +uint32_t Dma_GetHtMask(uint32_t stream) +{ + static const uint32_t htMasks[8] = { + DMA_LISR_HTIF0, DMA_LISR_HTIF1, DMA_LISR_HTIF2, DMA_LISR_HTIF3, DMA_HISR_HTIF4, DMA_HISR_HTIF5, DMA_HISR_HTIF6, DMA_HISR_HTIF7 + }; + return htMasks[stream]; +} + +uint32_t Dma_GetTcMask(uint32_t stream) +{ + static const uint32_t tcMasks[8] = { + DMA_LISR_TCIF0, DMA_LISR_TCIF1, DMA_LISR_TCIF2, DMA_LISR_TCIF3, DMA_HISR_TCIF4, DMA_HISR_TCIF5, DMA_HISR_TCIF6, DMA_HISR_TCIF7 + }; + + return tcMasks[stream]; +} + +void Dma_Init(DMAINFO *info, DMA_TypeDef *dma, uint32_t stream) +{ + info->dma = dma; + info->stream = stream; + info->isReg = Dma_GetIsReg(dma, stream); + info->ifcReg = Dma_GetIfcReg(dma, stream); + info->feMask = Dma_GetFeMask(stream); + info->dmeMask = Dma_GetDmeMask(stream); + info->teMask = Dma_GetTeMask(stream); + info->htMask = Dma_GetHtMask(stream); + info->tcMask = Dma_GetTcMask(stream); +} diff --git a/dmahelper.h b/dmahelper.h new file mode 100644 index 0000000..d54e22c --- /dev/null +++ b/dmahelper.h @@ -0,0 +1,35 @@ +/* + * dma_helper.h + * + * Created on: Sep 18, 2019 + * Author: abody + */ + +#ifndef DMA_HELPER_H_ +#define DMA_HELPER_H_ +#include +#include + +typedef struct { + DMA_TypeDef *dma; + uint32_t stream; + volatile uint32_t *isReg; + volatile uint32_t *ifcReg; + uint32_t feMask; + uint32_t dmeMask; + uint32_t teMask; + uint32_t htMask; + uint32_t tcMask; +} DMAINFO; + +volatile uint32_t* Dma_GetIsReg(DMA_TypeDef *dma, uint32_t stream); +volatile uint32_t* Dma_GetIfcReg(DMA_TypeDef *dma, uint32_t stream); +uint32_t Dma_GetDmeMask(uint32_t stream); +uint32_t Dma_GetTeMask(uint32_t stream); +uint32_t Dma_GetHtMask(uint32_t stream); +uint32_t Dma_GetTcMask(uint32_t stream); +uint32_t Dma_GetFeMask(uint32_t stream); + +void Dma_Init(DMAINFO *info, DMA_TypeDef *dma, uint32_t stream); + +#endif /* DMA_HELPER_H_ */ diff --git a/f4ll_c b/f4ll_c new file mode 120000 index 0000000..945c9b4 --- /dev/null +++ b/f4ll_c @@ -0,0 +1 @@ +. \ No newline at end of file diff --git a/memcpydma.c b/memcpydma.c new file mode 100644 index 0000000..68b725e --- /dev/null +++ b/memcpydma.c @@ -0,0 +1,48 @@ +/* + * memcpy_dma.c + * + * Created on: Oct 1, 2019 + * Author: abody + */ +#include +#include + +#ifndef DIAG_INTERRUPT_IN +# define DIAG_INTERRUPT_IN() +#endif + +#ifndef DIAG_INTERRUPT_OUT +# define DIAG_INTERRUPT_OUT() +#endif + +volatile uint8_t g_memcpyDmaBusy = 0; + +static DMAINFO g_memcpyDmaInfo; + +void Mcd_Init(DMA_TypeDef *dma, uint32_t stream) +{ + Dma_Init(&g_memcpyDmaInfo, dma, stream); + LL_DMA_EnableIT_TC(dma, stream); +} + +void * Mcd_Copy(void *dst, void const *src, size_t length) +{ + LL_DMA_SetM2MSrcAddress(g_memcpyDmaInfo.dma, g_memcpyDmaInfo.stream, (uint32_t)src); + LL_DMA_SetM2MDstAddress(g_memcpyDmaInfo.dma, g_memcpyDmaInfo.stream, (uint32_t)dst); + LL_DMA_SetDataLength(g_memcpyDmaInfo.dma, g_memcpyDmaInfo.stream, (length+3)/4 ); + g_memcpyDmaBusy = 1; + LL_DMA_EnableStream(g_memcpyDmaInfo.dma, g_memcpyDmaInfo.stream); + while(g_memcpyDmaBusy); + return dst; +} + +void Mcd_HandleDmaIrq() +{ + DIAG_INTERRUPT_IN(); + if(*g_memcpyDmaInfo.isReg & g_memcpyDmaInfo.tcMask) { // DMA transfer complete + *g_memcpyDmaInfo.ifcReg = g_memcpyDmaInfo.tcMask; + LL_DMA_DisableStream(g_memcpyDmaInfo.dma, g_memcpyDmaInfo.stream); + g_memcpyDmaBusy = 0; + } + DIAG_INTERRUPT_OUT(); +} diff --git a/memcpydma.h b/memcpydma.h new file mode 100644 index 0000000..b67573e --- /dev/null +++ b/memcpydma.h @@ -0,0 +1,18 @@ +/* + * memcpy_dma.h + * + * Created on: Oct 1, 2019 + * Author: abody + */ + +#ifndef MEMCPY_DMA_H_ +#define MEMCPY_DMA_H_ + +#include +#include + +void Mcd_Init(DMA_TypeDef *dma, uint32_t stream); +void * Mcd_Copy(void *dst, void const *src, size_t length); +void Mcd_HandleDmaIrq(); + +#endif /* MEMCPY_DMA_H_ */ diff --git a/packetusart.c b/packetusart.c new file mode 100644 index 0000000..4f10d42 --- /dev/null +++ b/packetusart.c @@ -0,0 +1,265 @@ +/* + * usart_handler.c + * + * Created on: Sep 16, 2019 + * Author: abody + */ + +#include +#include +#include +#include +#include "diag.h" +#include "f4ll_c/dmahelper.h" +#include "f4ll_c/crcscheduler.h" + +#ifndef DIAG_RX_BUFFER_SWITCH +# define DIAG_RX_BUFFER_SWITCH(x) +#endif +#ifndef DIAG_INTERRUPT_IN +# define DIAG_INTERRUPT_IN() +#endif +#ifndef DIAG_INTERRUPT_OUT +# define DIAG_INTERRUPT_OUT() +#endif + +#define STARTMARKER 0x95 + +static inline uint32_t RoundUpTo4(uint32_t inp) +{ + return (inp + 3) & 0xfffc; +} + +void Pku_Init( + struct usartstatus_t *st, USART_TypeDef *usart, DMA_TypeDef *dma, + uint32_t stream_rx, uint32_t stream_tx, + struct crcstatus_t *crcStatus, + pku_packetreceivedcallback_t packetReceivedCallback, void * packetReceivedCallbackParam) +{ + uint32_t status = usart->SR; + volatile uint32_t tmpreg = usart->DR; // clearing some of the error/status bits in the USART + (void) tmpreg; + (void) status; + + st->usart = usart; + Dma_Init(&st->rxDmaInfo, dma, stream_rx); + Dma_Init(&st->txDmaInfo, dma, stream_tx); + st->txBuffer.busy = 0; + st->txBuffer.error = 0; + st->txBuffer.requestedLength = 0; + st->rxBuffers[0].busy = 0; + st->rxBuffers[1].busy = 0; + st->rxBuffers[0].error = 0; + st->rxBuffers[1].error = 0; + st->rxBuffers[0].requestedLength = 0; + st->rxBuffers[1].requestedLength = 0; + st->txBuffer.usartStatus = st; + st->rxBuffers[0].usartStatus = st; + st->rxBuffers[1].usartStatus = st; + st->packetReceivedCallback = packetReceivedCallback; + st->packetReceivedCallbacParam = packetReceivedCallbackParam; + st->rxSerial = -1; + st->txSerial = 0; + st->activeRxBuf = 0; + st->crcStatus = crcStatus; + Crc_AttachTask(crcStatus, &st->crcSlot, st->crcTasks, 2); + memset(&st->stats, 0, sizeof(st->stats)); + + *Dma_GetIfcReg(dma, stream_rx) = + Dma_GetTcMask(stream_rx) | Dma_GetHtMask(stream_rx) | + Dma_GetTeMask(stream_rx) | Dma_GetFeMask(stream_rx) | Dma_GetDmeMask(stream_rx); + *Dma_GetIfcReg(dma, stream_tx) = + Dma_GetTcMask(stream_tx) | Dma_GetHtMask(stream_tx) | + Dma_GetTeMask(stream_tx) | Dma_GetFeMask(stream_tx) | Dma_GetDmeMask(stream_tx); + + LL_DMA_EnableIT_TC(dma, stream_rx); + LL_DMA_EnableIT_TE(dma, stream_rx); + LL_DMA_EnableIT_TC(dma, stream_tx); + LL_DMA_EnableIT_TE(dma, stream_tx); + LL_USART_EnableIT_IDLE(usart); +} + + +uint8_t* Pku_GetTxBuffer(struct usartstatus_t *status) +{ + return status->txBuffer.packet.payload; +} + + +static inline void BuildHeader(struct usart_buffer_t *buffer, uint8_t serial, uint8_t length) +{ + uint8_t hash = STARTMARKER; + buffer->packet.header.startByte = STARTMARKER; + buffer->packet.header.serial = serial; + hash ^= serial; + buffer->packet.header.payloadLength = length - 1; + hash ^= length - 1; + buffer->packet.header.hash = hash; +} + +static inline uint8_t CheckHeader(struct usartpacket_t *packet) +{ + return packet->header.startByte == STARTMARKER && (packet->header.startByte ^ packet->header.serial ^ packet->header.payloadLength) == packet->header.hash; +} + + +uint8_t Pku_Post(struct usartstatus_t *status, uint8_t const *payload, uint16_t length, struct crcstatus_t *crcStatus, uint8_t waitForCrcQueue) +{ +// static uint32_t count = 0; +// ITM->PORT[1].u32 = count++; + + if(length > 256) + return 1; + + + BuildHeader(&status->txBuffer, status->txSerial++, length); + uint16_t payloadLength = RoundUpTo4(length); + if(payload) + memcpy(status->txBuffer.packet.payload, payload, length); + status->txBuffer.requestedLength = sizeof(struct usartpacketheader_t) + payloadLength + sizeof(uint32_t); // +4 for the hash + status->txBuffer.busy = 1; + status->txBuffer.error = 0; + Crc_Enqueue(status->crcStatus, &status->crcSlot, 0, status->txBuffer.packet.payload, length, + NULL, (uint32_t*)(status->txBuffer.packet.payload + payloadLength)); + while(waitForCrcQueue && Crc_IsSlotQueued(&status->crcSlot, 0)); + Pku_SetupTransmit(status->usart, status->txDmaInfo.dma, status->txDmaInfo.stream, &status->txBuffer.packet, status->txBuffer.requestedLength); + + StatsIncSent(&status->stats); + return 0; +} + + +void Pku_SetupReceive(struct usartstatus_t *status) +{ + uint8_t packetIndex = status->activeRxBuf; + + LL_DMA_ConfigAddresses(status->rxDmaInfo.dma, status->rxDmaInfo.stream, LL_USART_DMA_GetRegAddr(status->usart), (uint32_t)&status->rxBuffers[packetIndex], + LL_DMA_DIRECTION_PERIPH_TO_MEMORY); + status->rxBuffers[packetIndex].requestedLength = sizeof(status->rxBuffers[packetIndex].packet); + LL_DMA_SetDataLength(status->rxDmaInfo.dma, status->rxDmaInfo.stream, status->rxBuffers[packetIndex].requestedLength); // payload already have extra room for hash + LL_USART_EnableDMAReq_RX(status->usart); + LL_USART_ClearFlag_ORE(status->usart); + LL_DMA_EnableStream(status->rxDmaInfo.dma, status->rxDmaInfo.stream); +} + + +void Pku_ConsumePacket(struct usartstatus_t *status, uint8_t packetIndex) +{ + struct usart_buffer_t *buffer = &status->rxBuffers[packetIndex]; + if(buffer->busy) { + if(buffer->error) + StatsIncPayloadError(&status->stats, buffer->errorInfo, *(uint32_t*) (buffer->packet.payload + RoundUpTo4(buffer->packet.header.payloadLength + 1))); + else { + uint8_t diff = buffer->packet.header.serial - status->rxSerial; + if(diff > 1) + StatsAddSkiped(&status->stats, diff - 1); + status->rxSerial = buffer->packet.header.serial; + } + } + + buffer->busy = buffer->error = 0; +} + + +void Pku_SetupTransmit(USART_TypeDef *usart, DMA_TypeDef* dma, uint32_t stream, void *buffer, uint32_t length) +{ + LL_DMA_ConfigAddresses(dma, stream, (uint32_t)buffer, LL_USART_DMA_GetRegAddr(usart), LL_DMA_DIRECTION_MEMORY_TO_PERIPH); + LL_DMA_SetDataLength(dma, stream, length); + LL_USART_EnableDMAReq_TX(usart); + LL_DMA_EnableStream(dma, stream); +} + +void RxCrcComputedCallback(void *callbackParm, uint32_t calculatedCrc, uint8_t success) +{ + struct usart_buffer_t *ub = (struct usart_buffer_t*) callbackParm; + if(!success) + ub->error = 1; + else if(*(uint32_t*) (ub->packet.payload + RoundUpTo4(ub->packet.header.payloadLength + 1)) == calculatedCrc) + ub->busy = 1; + else { + ub->error = ub->busy = 1; + ub->errorInfo = calculatedCrc; + } + if(ub->usartStatus->packetReceivedCallback) + ub->usartStatus->packetReceivedCallback(ub->usartStatus->packetReceivedCallbacParam, ub); +} + +void Pku_HandleRxDmaIrq(struct usartstatus_t *status) +{ + DIAG_INTERRUPT_IN(); + StatsIncRcvd(&status->stats); + if(*status->rxDmaInfo.isReg & status->rxDmaInfo.tcMask) { + *status->rxDmaInfo.ifcReg = status->rxDmaInfo.tcMask; + if(CheckHeader(&status->rxBuffers[status->activeRxBuf].packet)) + Crc_Enqueue(status->crcStatus, &status->crcSlot, 1, + status->rxBuffers[status->activeRxBuf].packet.payload, + status->rxBuffers[status->activeRxBuf].packet.header.payloadLength +1, + RxCrcComputedCallback, &status->rxBuffers[status->activeRxBuf]); + else { + StatsIncHdrError(&status->stats, *(uint32_t*)&status->rxBuffers[status->activeRxBuf].packet.header); + status->rxBuffers[status->activeRxBuf].error = 1; + } + } else if(*status->rxDmaInfo.isReg & status->rxDmaInfo.teMask) { + *status->rxDmaInfo.ifcReg = status->rxDmaInfo.teMask; + status->rxBuffers[status->activeRxBuf].error = 1; + } + + status->activeRxBuf ^= 1; + + DIAG_RX_BUFFER_SWITCH(status->activeRxBuf); + if(status->rxBuffers[status->activeRxBuf].busy) + StatsIncOverrun(&status->stats); + Pku_SetupReceive(status); + DIAG_INTERRUPT_OUT(); +} + +void Pku_HandleTxDmaIrq(struct usartstatus_t *status) +{ + DIAG_INTERRUPT_IN(); + if(*status->txDmaInfo.isReg & status->txDmaInfo.tcMask) { // DMA transfer complete + *status->txDmaInfo.ifcReg = status->txDmaInfo.tcMask; + LL_USART_EnableIT_TC(status->usart); + LL_DMA_DisableStream(status->txDmaInfo.dma, status->txDmaInfo.stream); + } + else if(*status->txDmaInfo.isReg & status->txDmaInfo.teMask) { + *status->txDmaInfo.ifcReg = status->txDmaInfo.teMask; + status->txBuffer.error = 1; + StatsIncDmaError(&status->stats); + } + if(*status->txDmaInfo.isReg & status->txDmaInfo.feMask) + *status->txDmaInfo.ifcReg = status->txDmaInfo.feMask; + if(*status->txDmaInfo.isReg & status->txDmaInfo.htMask) + *status->txDmaInfo.ifcReg = status->txDmaInfo.htMask; + if(*status->txDmaInfo.isReg & status->txDmaInfo.dmeMask) + *status->txDmaInfo.ifcReg = status->txDmaInfo.dmeMask; + DIAG_INTERRUPT_OUT(); +} + +void Pku_HandleUsartIrq(struct usartstatus_t *status) +{ + DIAG_INTERRUPT_IN(); + if(LL_USART_IsActiveFlag_IDLE(status->usart) && LL_USART_IsEnabledIT_IDLE(status->usart)) { // receiver idle + LL_USART_ClearFlag_IDLE(status->usart); + uint16_t rcvdLen = status->rxBuffers[status->activeRxBuf].requestedLength - LL_DMA_GetDataLength(status->rxDmaInfo.dma, status->rxDmaInfo.stream); + if(rcvdLen >= sizeof(struct usartpacketheader_t)) { + if(CheckHeader(&status->rxBuffers[status->activeRxBuf].packet)) { + if(rcvdLen >= sizeof(struct usartpacketheader_t) + RoundUpTo4(status->rxBuffers[status->activeRxBuf].packet.header.payloadLength + 1) + sizeof(uint32_t)) + LL_DMA_DisableStream(status->rxDmaInfo.dma, status->rxDmaInfo.stream); + else + StatsIncPremature_payload(&status->stats); + } else { + status->rxBuffers[status->activeRxBuf].error = 1; + LL_DMA_DisableStream(status->rxDmaInfo.dma, status->rxDmaInfo.stream); + } + } else + StatsIncPremature_hdr(&status->stats); + } + else if(LL_USART_IsActiveFlag_TC(status->usart) && LL_USART_IsEnabledIT_TC(status->usart)) { // transmission complete + LL_USART_DisableIT_TC(status->usart); + LL_USART_DisableDirectionTx(status->usart); // enforcing an idle frame + LL_USART_EnableDirectionTx(status->usart); + status->txBuffer.busy = 0; + } + DIAG_INTERRUPT_OUT(); +} + diff --git a/packetusart.h b/packetusart.h new file mode 100644 index 0000000..c980a8b --- /dev/null +++ b/packetusart.h @@ -0,0 +1,142 @@ +/* + * usart_handler.h + * + * Created on: Sep 16, 2019 + * Author: abody + */ + +#ifndef USART_HANDLER_H_ +#define USART_HANDLER_H_ +#include +#include + +#include "f4ll_c/dmahelper.h" + +struct usart_buffer_t; +struct usartstatus_t; + +typedef void (*pku_packetreceivedcallback_t)(void *userParam, struct usart_buffer_t *buffer); + +void Pku_Init( + struct usartstatus_t *st, USART_TypeDef *usart, DMA_TypeDef *dma, + uint32_t stream_rx, uint32_t stream_tx, + struct crcstatus_t *crcStatus, + pku_packetreceivedcallback_t packetReceivedCallback, void * packetReceivedCallbackParam); + +uint8_t* Pku_GetTxBuffer(struct usartstatus_t *status); + +uint8_t Pku_Post(struct usartstatus_t *status, uint8_t const *payload, uint16_t length, struct crcstatus_t *crcStatus, uint8_t waitForCrcQueue); +void Pku_SetupReceive(struct usartstatus_t *status); +void Pku_SetupTransmit(USART_TypeDef *usart, DMA_TypeDef* dma, uint32_t stream, void *buffer, uint32_t length); +void Pku_ConsumePacket(struct usartstatus_t *status, uint8_t packetIndex); + +void Pku_HandleRxDmaIrq(struct usartstatus_t *status); +void Pku_HandleTxDmaIrq(struct usartstatus_t *status); +void Pku_HandleUsartIrq(struct usartstatus_t *status); + +/****************************************************************************************** + * + * + * + */ + +struct usart_stats { + uint32_t overrun; + uint32_t hdrError; + uint32_t lastErrHdr; + uint32_t payloadErrror; + uint32_t pep1, pep2; + uint32_t dmaError; + uint32_t rcvd; + uint32_t premature_hdr; + uint32_t premature_payload; + uint32_t sent; + uint32_t skiped; +}; + +struct usartpacketheader_t { + uint8_t startByte; + uint8_t serial; + uint8_t payloadLength; + uint8_t hash; +}; + +struct usartpacket_t { + struct usartpacketheader_t header; + //!!! should start on word offset !!! + uint8_t payload[256+sizeof(uint32_t)]; // extra room for crc32 +} __attribute__((aligned)); + +struct usart_buffer_t { + struct usartpacket_t packet; + //transfer area ends here + volatile uint8_t busy; + volatile uint8_t error; + uint16_t requestedLength; + uint32_t errorInfo; + struct usartstatus_t *usartStatus; +}; + +struct usartstatus_t { + USART_TypeDef *usart; + DMAINFO rxDmaInfo; + DMAINFO txDmaInfo; + struct crcstatus_t *crcStatus; + struct crcslotlistitem_t crcSlot; + struct crcslottask_t crcTasks[2]; + + uint8_t rxSerial; + uint8_t txSerial; + struct usart_stats stats; + uint8_t activeRxBuf; + pku_packetreceivedcallback_t packetReceivedCallback; + void *packetReceivedCallbacParam; + struct usart_buffer_t txBuffer; + struct usart_buffer_t rxBuffers[2]; +}; + +#ifndef USART_STATS_DISABLED +static inline void StatsIncOverrun(struct usart_stats *s) { + ++s->overrun; +} +static inline void StatsIncHdrError(struct usart_stats *s, uint32_t hdr) { + ++s->hdrError; + s->lastErrHdr = hdr; +} +static inline void StatsIncPayloadError(struct usart_stats *s, uint32_t pep1, uint32_t pep2) { + ++s->payloadErrror; + s->pep1 = pep1; + s->pep2 = pep2; +} +static inline void StatsIncDmaError(struct usart_stats *s) { + ++s->dmaError; +} +static inline void StatsIncRcvd(struct usart_stats *s) { + ++s->rcvd; +} +static inline void StatsIncPremature_hdr(struct usart_stats *s) { + ++s->premature_hdr; +} +static inline void StatsIncPremature_payload(struct usart_stats *s) { + ++s->premature_payload; +} +static inline void StatsIncSent(struct usart_stats *s) { + ++s->sent; +} +static inline void StatsAddSkiped(struct usart_stats *s, uint8_t cnt) { + s->skiped += s->rcvd > 2 ? cnt : 0; +} + +#else // USART_STATS_DISABLED +#define StatsIncOverrun(x) +#define StatsIncHdrError(x,y) +#define StatsIncPayloadError(x,y,z) +#define StatsIncDmaError(x) +#define StatsIncRcvd(x) +#define StatsIncPremature_hdr(x) +#define StatsIncPremature_payload(x) +#define StatsIncSent(x) +#define StatsAddSkiped(x) +#endif // USART_STATS_DISABLED + +#endif /* UART_HANDLER_H_ */ diff --git a/strutil.c b/strutil.c new file mode 100644 index 0000000..c41e16e --- /dev/null +++ b/strutil.c @@ -0,0 +1,110 @@ +#include +#include "f4ll_c/strutil.h" + +////////////////////////////////////////////////////////////////////////////// +size_t strcpy_ex(char *dst, char const *src) +{ + size_t ret = 0; + do { + *dst++ = *src; + ++ret; + } while(*src++); + return ret - 1; +} + +////////////////////////////////////////////////////////////////////////////// +void strrev(char *first, char *last) +{ + char tmp; + while(last > first) { + tmp = *first; + *first++ = *last; + *last-- = tmp; + } +} + +////////////////////////////////////////////////////////////////////////////// +char tochr(const uint8_t in, const uint8_t upper) +{ + return in + ((in < 10) ? '0' : (upper ? 'A' : 'a') - 10); +} + +////////////////////////////////////////////////////////////////////////////// +size_t uitodec(char* buffer, uint32_t data) +{ + char *b2 = buffer; + if(!data) { + *b2++ = '0'; + *b2 = '\0'; + return 1; + } + + while(data) { + *b2++ = (data % 10) + '0'; + data /= 10; + } + size_t ret = b2 - buffer; + + *b2-- = 0; + + strrev(buffer, b2); + return ret; +} + +////////////////////////////////////////////////////////////////////////////// +size_t uitohex(char* buffer, uint32_t data, uint8_t chars) +{ + char *b2 = buffer; + size_t ret = 0; + + if(chars == 0xff || !chars) + { + if(!data) { + *b2++ = '0'; + *b2 = '\0'; + return 1; + } + + while(data) { + uint8_t curval = data & 0x0f; + *b2++ = tochr(curval, 1); + data >>= 4; + } + ret = b2 - buffer; + + } + else + { + ret = chars; + for(uint8_t pos = 0; pos < (uint8_t)ret; ++pos) { + *b2++ = tochr(data & 0x0f, 1); + data >>= 4; + } + + } + *b2-- = 0; + strrev(buffer, b2); + return ret; +} + + +////////////////////////////////////////////////////////////////////////////// +size_t itodec(char* buffer, int data) +{ + if(data < 0) { + *buffer++ = '-'; + return uitodec(buffer, -data) + 1; + } + + return uitodec(buffer, data); +} + +////////////////////////////////////////////////////////////////////////////// +size_t itohex(char* buffer, int data) +{ + if(data < 0) { + *buffer++ = '-'; + return uitohex(buffer, -data, 0) + 1; + } + return uitohex(buffer, data, 0); +} diff --git a/strutil.h b/strutil.h new file mode 100644 index 0000000..49ddc39 --- /dev/null +++ b/strutil.h @@ -0,0 +1,31 @@ +/* + * strutil.h + * + * Created on: Feb 11, 2017 + * Author: compi + */ + +#ifndef _STM32PLUS_STRUTIL_H_ +#define _STM32PLUS_STRUTIL_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +////////////////////////////////////////////////////////////////////////////// +size_t strcpy_ex(char *dst, char const *src); +size_t uitodec(char* buffer, uint32_t data); +size_t uitohex(char* buffer, uint32_t data, uint8_t chars); +size_t itodec(char* buffer, int data); +size_t itohex(char* buffer, int data); +void strrev(char *first, char *last); +char tochr(const uint8_t in, const uint8_t upper); + +#ifdef __cplusplus +} +#endif + +#endif /* _STM32PLUS_STRUTIL_H_ */