This commit is contained in:
Attila Body 2020-02-10 15:06:45 +01:00
parent 90d89c7fbe
commit 49383b1b32
68 changed files with 3385 additions and 610 deletions

View file

@ -0,0 +1,190 @@
/*
* interrupt.c
*
* Created on: Aug 29, 2019
* Author: abody
*/
#include <f4ll_cpp/crcscheduler.h>
#include <string.h>
#if defined(HAVE_DIAG)
#include "diag.h"
#endif
#include "f4ll_cpp/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_StartNextTask(struct crcstatus_t *status);
CrcScheduler::CrcScheduler(CRC_TypeDef *crcUnit, DMA_TypeDef *dma, uint32_t stream) :
m_dma(dma, stream),
m_activeSlot(nullptr),
m_firstSlot(nullptr)
{
m_crcUnit = crcUnit;
LL_DMA_EnableIT_TC(dma, stream);
LL_DMA_EnableIT_TE(dma, stream);
LL_DMA_SetM2MDstAddress(dma, stream, (uint32_t)&crcUnit->DR);
}
void CrcScheduler::AttachTasks(struct crcslot_t *slot, struct crctask_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 = m_firstSlot;
m_firstSlot = slot;
__set_PRIMASK(prim);
}
uint8_t CrcScheduler::GetActiveTask(struct crcslot_t **slot_out)
{
uint8_t ret;
uint32_t prim = __get_PRIMASK();
__disable_irq();
ret = m_activeTask;
if(slot_out)
*slot_out = (struct crcslot_t *) m_activeSlot;
__set_PRIMASK(prim);
return ret;
}
bool CrcScheduler::IsTaskQueued(struct crcslot_t *slot, uint8_t task) {
return ((struct crctask_t volatile)slot->tasks[task]).address != NULL;
}
bool CrcScheduler::IsTaskBusy(struct crcslot_t *slot, uint8_t task) {
struct crctask_t volatile *taskPtr = &slot->tasks[task];
return taskPtr->callback != NULL || taskPtr->callbackParam != NULL;
}
void CrcScheduler::WaitResults(struct crcslot_t *slot, uint8_t task) {
while(IsTaskBusy(slot, task));
}
uint8_t CrcScheduler::Enqueue(struct crcslot_t *slot, uint8_t task, void *address, uint16_t len,
ICrcCallback* callback, void* callbackParam)
{
uint32_t prim = __get_PRIMASK();
bool need_start;
//struct crcstatus_t volatile *st = status;
while(IsTaskBusy(slot, task));
__disable_irq();
need_start = (m_activeSlot == nullptr);
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) {
m_activeSlot = slot;
m_activeTask = task;
}
__set_PRIMASK(prim);
if(need_start) {
DIAG_CRC_CALC_START();
m_crcUnit->CR = 1;
LL_DMA_SetM2MSrcAddress(m_dma.GetDma(), m_dma.GetStream(), (uint32_t)address);
LL_DMA_SetDataLength(m_dma.GetDma(), m_dma.GetStream(), (len+3)/4);
DIAG_CRC_CALC_START();
LL_DMA_EnableStream(m_dma.GetDma(), m_dma.GetStream());
}
return need_start;
}
uint32_t CrcScheduler::Compute(struct crcslot_t *slot, uint8_t task, void *address, uint16_t len)
{
uint32_t result;
Enqueue(slot, task, address, len, NULL, &result);
while((struct crcslot_t volatile *)slot->tasks[task].callbackParam);
return result;
}
// only called from ISR context
void CrcScheduler::StartNextTask()
{
char moreTasks;
uint8_t index = 0;
do {
struct crcslot_t *slot = m_firstSlot;
moreTasks = 0;
while(slot) {
if(index < slot->count) {
if(slot->tasks[index].address) {
DIAG_CRC_CALC_START();
m_activeSlot = slot;
m_activeTask = index;
m_crcUnit->CR = 1;
LL_DMA_SetM2MSrcAddress(m_dma.GetDma(), m_dma.GetStream(), (uint32_t)slot->tasks[index].address);
LL_DMA_SetDataLength(m_dma.GetDma(), m_dma.GetStream(), slot->tasks[index].wordCount);
LL_DMA_EnableStream(m_dma.GetDma(), m_dma.GetStream());
slot->tasks[index].address = nullptr; // marking as started
return;
}
if(index + 1 < slot->count)
moreTasks = 1;
}
slot = slot->next;
}
++index;
} while(moreTasks);
m_activeSlot = nullptr;
}
// !!!PORTABILITY WARNING!!! using registers and bits directly. should be reviewed extremely when porting to a different MCU
void CrcScheduler::_HandleDmaIrq()
{
uint8_t success = 1;
DIAG_INTERRUPT_IN();
if((*m_dma.GetIsReg() & m_dma.GetTcMask()) ||
(*m_dma.GetIsReg() & m_dma.GetTeMask())) {
if(*m_dma.GetIsReg() & m_dma.GetTeMask())
success = 0;
*m_dma.GetIfcReg() = *m_dma.GetIsReg() & (m_dma.GetTcMask() | m_dma.GetTeMask());
LL_DMA_DisableStream(m_dma.GetDma(), m_dma.GetStream());
if(m_activeSlot) {
crctask_t *tsk = &m_activeSlot->tasks[m_activeTask];
if(tsk->callback)
tsk->callback->CrcCalculationCompleted(tsk->callbackParam, m_crcUnit->DR, success);
else if(tsk->callbackParam)
*(uint32_t*)tsk->callbackParam = success ? m_crcUnit->DR : 0xffffffff;
tsk->callback = nullptr;
tsk->callbackParam = nullptr; // marking as inactive
DIAG_CRC_CALC_END();
StartNextTask();
}
}
DIAG_INTERRUPT_OUT();
}

View file

@ -0,0 +1,68 @@
/*
* interrupt.h
*
* Created on: Aug 29, 2019
* Author: abody
*/
#ifndef CRC_HANDLER_H_
#define CRC_HANDLER_H_
#include <inttypes.h>
#ifdef HAVE_CONFIG
#include "config.h"
#endif // HAVE_CONFIG
#include <platform/crc_ll.h>
#include <f4ll_cpp/dmahelper.h>
class CrcScheduler {
public:
struct ICrcCallback {
virtual void CrcCalculationCompleted(void*, uint32_t, uint8_t) = 0;
};
struct crctask_t {
void * volatile address;
uint16_t wordCount;
ICrcCallback* callback;
void *callbackParam;
};
struct crcslot_t {
uint16_t count;
struct crcslot_t *next;
struct crctask_t *tasks;
};
CrcScheduler(CRC_TypeDef *crcUnit, DMA_TypeDef *dma, uint32_t stream);
uint8_t GetActiveTask(struct crcslot_t **slot_out);
bool IsTaskQueued(struct crcslot_t *slot, uint8_t task);
bool IsTaskBusy(struct crcslot_t *slot, uint8_t task);
void WaitResults(struct crcslot_t *slot, uint8_t task);
void AttachTasks(struct crcslot_t *slot, struct crctask_t *tasks, uint8_t taskCount);
uint8_t Enqueue(struct crcslot_t *slot, uint8_t task, void *address, uint16_t len,
ICrcCallback* callback, void* callbackParam);
uint32_t Compute(struct crcslot_t *slot, uint8_t task, void *address, uint16_t len);
static void HandleDmaIrq(void *param) { reinterpret_cast<CrcScheduler*>(param)->_HandleDmaIrq(); }
void _HandleDmaIrq();
private:
void StartNextTask();
CRC_TypeDef *m_crcUnit;
DmaHelper m_dma;
volatile crcslot_t *m_activeSlot;
volatile uint8_t m_activeTask;
crcslot_t *m_firstSlot;
};
#endif /* CRC_HANDLER_H_ */

View file

@ -13,16 +13,16 @@ DmaHelper::DmaHelper(DMA_TypeDef *dma, uint32_t stream)
{
m_dma = dma;
m_stream = stream;
m_isReg = GetIsReg(dma, stream);
m_ifcReg = GetIfcReg(dma, stream);
m_feMask = GetFeMask(stream);
m_dmeMask = GetDmeMask(stream);
m_teMask = GetTeMask(stream);
m_htMask = GetHtMask(stream);
m_tcMask = GetTcMask(stream);
m_isReg = _GetIsReg(dma, stream);
m_ifcReg = _GetIfcReg(dma, stream);
m_feMask = _GetFeMask(stream);
m_dmeMask = _GetDmeMask(stream);
m_teMask = _GetTeMask(stream);
m_htMask = _GetHtMask(stream);
m_tcMask = _GetTcMask(stream);
}
volatile uint32_t* DmaHelper::GetIsReg(DMA_TypeDef *dma, uint32_t stream)
volatile uint32_t* DmaHelper::_GetIsReg(DMA_TypeDef *dma, uint32_t stream)
{
if(dma == DMA1)
return (stream < LL_DMA_STREAM_4) ? &DMA1->LISR : &DMA1->HISR;
@ -31,7 +31,7 @@ volatile uint32_t* DmaHelper::GetIsReg(DMA_TypeDef *dma, uint32_t stream)
}
volatile uint32_t* DmaHelper::GetIfcReg(DMA_TypeDef *dma, uint32_t stream)
volatile uint32_t* DmaHelper::_GetIfcReg(DMA_TypeDef *dma, uint32_t stream)
{
if(dma == DMA1)
return (stream < LL_DMA_STREAM_4) ? &DMA1->LIFCR : &DMA1->HIFCR;
@ -39,7 +39,7 @@ volatile uint32_t* DmaHelper::GetIfcReg(DMA_TypeDef *dma, uint32_t stream)
return (stream < LL_DMA_STREAM_4) ? &DMA2->LIFCR : &DMA2->HIFCR;
}
uint32_t DmaHelper::GetFeMask(uint32_t stream)
uint32_t DmaHelper::_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
@ -47,7 +47,7 @@ uint32_t DmaHelper::GetFeMask(uint32_t stream)
return feMasks[stream];
}
uint32_t DmaHelper::GetDmeMask(uint32_t stream)
uint32_t DmaHelper::_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
@ -55,7 +55,7 @@ uint32_t DmaHelper::GetDmeMask(uint32_t stream)
return dmeMasks[stream];
}
uint32_t DmaHelper::GetTeMask(uint32_t stream)
uint32_t DmaHelper::_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
@ -63,7 +63,7 @@ uint32_t DmaHelper::GetTeMask(uint32_t stream)
return teMasks[stream];
}
uint32_t DmaHelper::GetHtMask(uint32_t stream)
uint32_t DmaHelper::_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
@ -71,7 +71,7 @@ uint32_t DmaHelper::GetHtMask(uint32_t stream)
return htMasks[stream];
}
uint32_t DmaHelper::GetTcMask(uint32_t stream)
uint32_t DmaHelper::_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

View file

@ -17,13 +17,25 @@
class DmaHelper {
public:
DmaHelper(DMA_TypeDef *dma, uint32_t stream);
volatile uint32_t* GetIsReg(DMA_TypeDef *dma, uint32_t stream);
volatile uint32_t* GetIfcReg(DMA_TypeDef *dma, uint32_t stream);
uint32_t GetDmeMask(uint32_t stream);
uint32_t GetTeMask(uint32_t stream);
uint32_t GetHtMask(uint32_t stream);
uint32_t GetTcMask(uint32_t stream);
uint32_t GetFeMask(uint32_t stream);
DMA_TypeDef* GetDma() { return m_dma; }
uint32_t GetStream() { return m_stream; }
volatile uint32_t* GetIsReg() { return m_isReg; }
volatile uint32_t* GetIfcReg() { return m_ifcReg; }
uint32_t GetDmeMask() { return m_dmeMask; }
uint32_t GetTeMask() { return m_teMask; }
uint32_t GetHtMask() { return m_htMask; }
uint32_t GetTcMask() { return m_tcMask; }
uint32_t GetFeMask() { return m_feMask; }
private:
static volatile uint32_t* _GetIsReg(DMA_TypeDef *dma, uint32_t stream);
static volatile uint32_t* _GetIfcReg(DMA_TypeDef *dma, uint32_t stream);
static uint32_t _GetDmeMask(uint32_t stream);
static uint32_t _GetTeMask(uint32_t stream);
static uint32_t _GetHtMask(uint32_t stream);
static uint32_t _GetTcMask(uint32_t stream);
static uint32_t _GetFeMask(uint32_t stream);
private:
DMA_TypeDef *m_dma;

View file

@ -0,0 +1,35 @@
/*
* memcpy_dma.c
*
* Created on: Oct 1, 2019
* Author: abody
*/
#include <f4ll_cpp/dmahelper.h>
#include <f4ll_cpp/memcpydma.h>
MemcpyDma::MemcpyDma(DMA_TypeDef *dma, uint32_t stream) :
DmaHelper(dma, stream),
m_busy(false)
{
LL_DMA_EnableIT_TC(dma, stream);
}
void* MemcpyDma::Copy(void *dst, void const *src, size_t length)
{
while(m_busy);
LL_DMA_SetM2MSrcAddress(GetDma(), GetStream(), (uint32_t)src);
LL_DMA_SetM2MDstAddress(GetDma(), GetStream(), (uint32_t)dst);
LL_DMA_SetDataLength(GetDma(), GetStream(), (length+3)/4 );
m_busy = true;
LL_DMA_EnableStream(GetDma(), GetStream());
return dst;
}
void MemcpyDma::HandleDmaIrq(void)
{
if(*GetIsReg() & GetTcMask()) { // DMA transfer complete
*GetIfcReg() = GetTcMask();
LL_DMA_DisableStream(GetDma(), GetStream());
m_busy = false;
}
}

View file

@ -0,0 +1,30 @@
/*
* memcpy_dma.h
*
* Created on: Oct 1, 2019
* Author: abody
*/
#ifndef MEMCPY_DMA_H_
#define MEMCPY_DMA_H_
#include <inttypes.h>
#include <platform/dma_ll.h>
#include <f4ll_cpp/dmahelper.h>
#include <f4ll_cpp/singleton.h>
class MemcpyDma : public DmaHelper, public Singleton<MemcpyDma>
{
public:
MemcpyDma(DMA_TypeDef *dma, uint32_t stream);
void* Copy(void *dst, void const *src, size_t length);
static inline void HandleDmaIrq(void *param) { reinterpret_cast<MemcpyDma*>(param)->HandleDmaIrq(); }
private:
void HandleDmaIrq();
volatile bool m_busy;
};
#endif /* MEMCPY_DMA_H_ */

View file

@ -0,0 +1,282 @@
/*
* usart_handler.c
*
* Created on: Sep 16, 2019
* Author: abody
*/
#include <f4ll_cpp/memcpydma.h>
#include "f4ll_cpp/crcscheduler.h"
#include <f4ll_cpp/packetuart.h>
#include <string.h>
#include <platform/usart_ll.h>
#if defined(HAVE_DIAG)
#include "diag.h"
#endif
#ifndef MOCKABLE
#define MOCKABLE(x) x
#endif
#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;
}
#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,y)
#endif // USART_STATS_DISABLED
PacketUart::PacketUart(
USART_TypeDef *uart, DMA_TypeDef *dma, uint32_t stream_rx, uint32_t stream_tx, CrcScheduler *crcScheduler,
PacketUart::pku_packetreceivedcallback_t packetReceivedCallback, void * packetReceivedCallbackParam)
: UartBase(uart, dma, stream_rx, stream_tx)
, m_crcScheduler(crcScheduler)
{
uint32_t status = uart->SR;
volatile uint32_t tmpreg = uart->DR; // clearing some of the error/status bits in the USART
(void) tmpreg;
(void) status;
txBuffer.busy = 0;
txBuffer.error = 0;
txBuffer.requestedLength = 0;
rxBuffers[0].busy = 0;
rxBuffers[1].busy = 0;
rxBuffers[0].error = 0;
rxBuffers[1].error = 0;
rxBuffers[0].requestedLength = 0;
rxBuffers[1].requestedLength = 0;
packetReceivedCallback = packetReceivedCallback;
packetReceivedCallbackParam = packetReceivedCallbackParam;
rxSerial = -1;
txSerial = 0;
activeRxBuf = 0;
m_crcScheduler->AttachTasks( &crcSlot, crcTasks, 2);
#ifndef USART_STATS_DISABLED
memset(&st->stats, 0, sizeof(st->stats));
#endif
LL_USART_EnableIT_IDLE(uart);
}
uint8_t* PacketUart::GetTxBuffer()
{
return txBuffer.packet.payload;
}
uint8_t PacketUart::CheckHeader(Packet *packet)
{
return packet->header.startByte == STARTMARKER && (packet->header.startByte ^ packet->header.serial ^ packet->header.payloadLength) == packet->header.hash;
}
uint8_t PacketUart::Post(uint8_t const *payload, uint8_t length, uint8_t waitForCrcQueue)
{
struct Buffer *buffer = &txBuffer;
uint8_t hash = STARTMARKER;
buffer->packet.header.startByte = STARTMARKER;
buffer->packet.header.serial = txSerial;
hash ^= txSerial++;
buffer->packet.header.payloadLength = length;
hash ^= length;
buffer->packet.header.hash = hash;
uint16_t payloadLength = RoundUpTo4(length);
if(payload)
memcpy(txBuffer.packet.payload, payload, length);
txBuffer.requestedLength = sizeof(struct Header) + payloadLength + sizeof(uint32_t); // +4 for the hash
txBuffer.busy = 1;
txBuffer.error = 0;
m_crcScheduler->Enqueue(&crcSlot, 0, &txBuffer.packet, sizeof(txBuffer.packet.header) + payloadLength,
NULL, (uint32_t*)(txBuffer.packet.payload + payloadLength));
while(waitForCrcQueue && m_crcScheduler->IsTaskQueued(&crcSlot, 0));
SetupTransmit(&txBuffer.packet, txBuffer.requestedLength);
StatsIncSent(&status->stats);
return 0;
}
void PacketUart::SetupReceive()
{
uint8_t packetIndex = activeRxBuf;
rxBuffers[packetIndex].requestedLength = sizeof(rxBuffers[packetIndex].packet);
UartBase::SetupReceive(&rxBuffers[packetIndex], sizeof(rxBuffers[packetIndex].packet));
}
void PacketUart::ConsumePacket(uint8_t packetIndex)
{
Buffer *buffer = &rxBuffers[packetIndex];
if(buffer->busy) {
if(buffer->error)
StatsIncPayloadError(&status->stats, Buffer->errorInfo, *(uint32_t*) (Buffer->packet.payload + RoundUpTo4(Buffer->packet.header.payloadLength)));
else {
uint8_t diff = buffer->packet.header.serial - rxSerial;
if(diff > 1)
StatsAddSkiped(&status->stats, diff - 1);
rxSerial = buffer->packet.header.serial;
}
}
buffer->busy = buffer->error = 0;
}
void PacketUart::HandleRxDmaIrq()
{
DIAG_INTERRUPT_IN();
StatsIncRcvd(&status->stats);
if(*m_rxDma.GetIsReg() & m_rxDma.GetTcMask()) {
*m_rxDma.GetIfcReg() = m_rxDma.GetTcMask();
if(CheckHeader(&rxBuffers[activeRxBuf].packet)) {
m_crcScheduler->Enqueue(&crcSlot, 1, &rxBuffers[activeRxBuf].packet,
RoundUpTo4(rxBuffers[activeRxBuf].packet.header.payloadLength) + sizeof(struct Header),
this, &rxBuffers[activeRxBuf]);
} else {
StatsIncHdrError(&status->stats, *(uint32_t*)&status->rxBuffers[status->activeRxBuf].packet.header);
rxBuffers[activeRxBuf].error = 1;
}
}
if(*m_rxDma.GetIsReg() & m_rxDma.GetTeMask()) {
*m_rxDma.GetIfcReg() = m_rxDma.GetTeMask();
rxBuffers[activeRxBuf].error = 1;
}
activeRxBuf ^= 1;
DIAG_RX_BUFFER_SWITCH(status->activeRxBuf);
if(rxBuffers[activeRxBuf].busy)
StatsIncOverrun(&status->stats);
SetupReceive();
DIAG_INTERRUPT_OUT();
}
void PacketUart::CrcCalculationCompleted(void *callbackParm, uint32_t calculatedCrc, uint8_t success)
{
struct Buffer *ub = (struct Buffer*) callbackParm;
if(!success)
ub->error = 1;
else if(*(uint32_t*) (ub->packet.payload + RoundUpTo4(ub->packet.header.payloadLength)) == calculatedCrc)
ub->busy = 1;
else {
ub->error = ub->busy = 1;
ub->errorInfo = calculatedCrc;
}
if(packetReceivedCallback)
packetReceivedCallback(packetReceivedCallbackParam, ub);
}
void PacketUart::HandleTxDmaIrq()
{
DIAG_INTERRUPT_IN();
if(*m_txDma.GetIsReg() & m_txDma.GetTcMask()) { // DMA transfer complete
*m_txDma.GetIfcReg() = m_txDma.GetTcMask();
LL_USART_EnableIT_TC(m_uart);
LL_DMA_DisableStream(m_txDma.GetDma(), m_txDma.GetStream());
}
if(*m_txDma.GetIsReg() & m_txDma.GetTeMask()) {
*m_txDma.GetIfcReg() = m_txDma.GetTeMask();
txBuffer.error = 1;
LL_USART_EnableIT_TC(m_uart);
LL_DMA_DisableStream(m_txDma.GetDma(), m_txDma.GetStream());
StatsIncDmaError(&status->stats);
}
if(*m_txDma.GetIsReg() & m_txDma.GetFeMask())
*m_txDma.GetIfcReg() = m_txDma.GetFeMask();
if(*m_txDma.GetIsReg() & m_txDma.GetHtMask())
*m_txDma.GetIfcReg() = m_txDma.GetHtMask();
if(*m_txDma.GetIsReg() & m_txDma.GetDmeMask())
*m_txDma.GetIfcReg() = m_txDma.GetDmeMask();
DIAG_INTERRUPT_OUT();
}
void PacketUart::HandleUsartIrq()
{
DIAG_INTERRUPT_IN();
if(LL_USART_IsActiveFlag_IDLE(m_uart) && LL_USART_IsEnabledIT_IDLE(m_uart)) { // receiver idle
LL_USART_ClearFlag_IDLE(m_uart);
uint16_t rcvdLen = rxBuffers[activeRxBuf].requestedLength - LL_DMA_GetDataLength(m_rxDma.GetDma(), m_rxDma.GetStream());
if(rcvdLen >= sizeof(struct Header)) {
if(CheckHeader(&rxBuffers[activeRxBuf].packet)) {
if(rcvdLen >= sizeof(struct Header) + RoundUpTo4(rxBuffers[activeRxBuf].packet.header.payloadLength) + sizeof(uint32_t))
LL_DMA_DisableStream(m_rxDma.GetDma(), m_rxDma.GetStream());
else
StatsIncPremature_payload(&stats);
} else {
rxBuffers[activeRxBuf].error = 1;
rxBuffers[activeRxBuf].busy = 1;
LL_DMA_DisableStream(m_rxDma.GetDma(), m_rxDma.GetStream());
}
} else
StatsIncPremature_hdr(&status->stats);
}
if(LL_USART_IsActiveFlag_TC(m_uart) && LL_USART_IsEnabledIT_TC(m_uart)) { // transmission complete
LL_USART_DisableIT_TC(m_uart);
LL_USART_DisableDirectionTx(m_uart); // enforcing an idle frame
LL_USART_EnableDirectionTx(m_uart);
txBuffer.busy = 0;
}
DIAG_INTERRUPT_OUT();
}

View file

@ -0,0 +1,103 @@
/*
* usart_handler.h
*
* Created on: Sep 16, 2019
* Author: abody
*/
#ifndef USART_HANDLER_H_
#define USART_HANDLER_H_
#include <inttypes.h>
#include <platform/usart_ll.h>
#include <f4ll_cpp/uartbase.h>
#define USART_STATS_DISABLED
class PacketUart : public UartBase, public CrcScheduler::ICrcCallback
{
public:
struct Buffer;
struct IPacketUsartCallback {
virtual void PacketReceived(void *userParam, Buffer *buffer) = 0;
};
struct 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 Header {
uint8_t startByte;
uint8_t serial;
uint8_t payloadLength;
uint8_t hash;
};
struct Packet {
struct Header header;
//!!! should start on word offset !!!
uint8_t payload[256+sizeof(uint32_t)]; // extra room for crc32
} __attribute__((aligned));
struct Buffer {
Packet packet;
//transfer area ends here
volatile uint8_t busy;
volatile uint8_t error;
uint16_t requestedLength;
uint32_t errorInfo;
};
typedef void (*pku_packetreceivedcallback_t)(void *userParam, Buffer *Buffer);
PacketUart(
USART_TypeDef *uart, DMA_TypeDef *dma, uint32_t stream_rx, uint32_t stream_tx, CrcScheduler *crcScheduler,
PacketUart::pku_packetreceivedcallback_t packetReceivedCallback, void * packetReceivedCallbackParam);
uint8_t* GetTxBuffer();
uint8_t Post(uint8_t const *payload, uint8_t length, uint8_t waitForCrcQueue);
void SetupReceive();
void ConsumePacket(uint8_t packetIndex);
static void HandleRxDmaIrq(void* param) { reinterpret_cast<PacketUart*>(param)->HandleRxDmaIrq(); }
static void HandleTxDmaIrq(void* param) { reinterpret_cast<PacketUart*>(param)->HandleTxDmaIrq(); }
static void HandleUsartIrq(void* param) { reinterpret_cast<PacketUart*>(param)->HandleUsartIrq(); }
uint8_t CheckHeader(struct Packet *packet);
protected:
private:
void HandleRxDmaIrq();
void HandleTxDmaIrq();
void HandleUsartIrq();
virtual void CrcCalculationCompleted(void*, uint32_t, uint8_t);
CrcScheduler *m_crcScheduler;
CrcScheduler::crcslot_t crcSlot;
CrcScheduler::crctask_t crcTasks[2];
uint8_t rxSerial;
uint8_t txSerial;
Stats stats;
uint8_t activeRxBuf;
pku_packetreceivedcallback_t packetReceivedCallback;
void *packetReceivedCallbackParam;
Buffer txBuffer;
Buffer rxBuffers[2];
};
#endif /* UART_HANDLER_H_ */

View file

@ -0,0 +1,161 @@
/*
* interrupt.h
*
* Created on: Aug 29, 2019
* Author: abody
*/
#ifndef CONSOLEHANDLER_H_
#define CONSOLEHANDLER_H_
#include <cstring>
#include "usart.h"
#include <f4ll_cpp/dmahelper.h>
#include <f4ll_cpp/uartbase.h>
template<unsigned int bufSize> class SerialConsole : protected UartBase
{
public:
struct Buffer {
volatile bool busy = false;
volatile bool error = false;
uint8_t len;
char buffer[bufSize];
};
struct ISerialConsoleCallback {
virtual void LineReceived(void *userParam, Buffer *buffer) = 0;
virtual void TransmissionComplete(void *userParam, Buffer *buffer) = 0;
};
SerialConsole(USART_TypeDef *uart, DMA_TypeDef *dma, uint32_t stream_rx, uint32_t stream_tx,
ISerialConsoleCallback *callback, void *callbackUserParam);
void Send(char const *buffer, uint8_t length = 0);
void SendLine(char const *buffer, uint8_t length = 0);
void HandleRxDmaIrq();
void HandleTxDmaIrq();
void HandleUsartIrq();
private:
bool m_activeRxBuffer = false;
Buffer m_rxBuffers[2];
Buffer m_txBuffer;
ISerialConsoleCallback *m_callback;
void *m_callbackUserParam;
};
template<unsigned int bufSize> SerialConsole<bufSize>::SerialConsole(
USART_TypeDef *uart, DMA_TypeDef *dma, uint32_t stream_rx, uint32_t stream_tx,
ISerialConsoleCallback *callback, void *callbackUserParam
)
: UartBase(uart, dma, stream_rx, stream_tx)
, m_callback(callback), m_callbackUserParam(callbackUserParam)
{
LL_USART_EnableIT_IDLE(uart);
SetupReceive(m_rxBuffers[m_activeRxBuffer].buffer, bufSize);
}
template<unsigned int bufSize> void SerialConsole<bufSize>::HandleRxDmaIrq()
{
if(*m_rxDma.GetIsReg() & m_rxDma.GetTcMask()) {
*m_rxDma.GetIfcReg() = m_rxDma.GetTcMask();
m_rxBuffers[m_activeRxBuffer].busy = true;
if(m_callback)
m_callback->LineReceived(m_callbackUserParam, &m_rxBuffers[m_activeRxBuffer]);
}
if(*m_rxDma.GetIsReg() & m_rxDma.GetTeMask()) {
*m_rxDma.GetIfcReg() = m_rxDma.GetTeMask();
}
m_activeRxBuffer = !m_activeRxBuffer;
SetupReceive(m_rxBuffers[m_activeRxBuffer].buffer, bufSize);
}
template<unsigned int bufSize> void SerialConsole<bufSize>::HandleTxDmaIrq()
{
if(*m_txDma.GetIsReg() & m_txDma.GetTcMask()) { // DMA transfer complete
*m_txDma.GetIfcReg() = m_txDma.GetTcMask();
LL_USART_EnableIT_TC(m_uart);
LL_DMA_DisableStream(m_txDma.GetDma(), m_txDma.GetStream());
}
if(*m_txDma.GetIsReg() & m_txDma.GetTeMask()) {
*m_txDma.GetIfcReg() = m_txDma.GetTeMask();
m_txBuffer.error = true;
LL_USART_EnableIT_TC(m_uart);
LL_DMA_DisableStream(m_txDma.GetDma(), m_txDma.GetStream());
}
}
template<unsigned int bufSize> void SerialConsole<bufSize>::HandleUsartIrq()
{
if(LL_USART_IsActiveFlag_IDLE(m_uart) && LL_USART_IsEnabledIT_IDLE(m_uart)) { // receiver idle
// we assume that new line marker will arrive without an idle cycle even if it is CRLF
LL_USART_ClearFlag_IDLE(m_uart);
uint16_t rcvdLen = bufSize - LL_DMA_GetDataLength(m_rxDma.GetDma(), m_rxDma.GetStream());
if(rcvdLen ) {
bool newLine = false;;
do {
auto lastChar = m_rxBuffers[m_activeRxBuffer].buffer[rcvdLen-1];
if( lastChar == '\r' || lastChar == '\n')
newLine = true;
else
break;
} while(--rcvdLen);
if(newLine) {
m_rxBuffers[m_activeRxBuffer].buffer[rcvdLen] = 0;
m_rxBuffers[m_activeRxBuffer].len = rcvdLen;
LL_DMA_DisableStream(m_rxDma.GetDma(), m_rxDma.GetStream());
}
}
}
if(LL_USART_IsActiveFlag_TC(m_uart) && LL_USART_IsEnabledIT_TC(m_uart)) { // transmission complete
LL_USART_DisableIT_TC(m_uart);
LL_USART_DisableDirectionTx(m_uart); // enforcing an idle frame
LL_USART_EnableDirectionTx(m_uart);
m_txBuffer.busy = false;
if(m_callback)
m_callback->TransmissionComplete(m_callbackUserParam, &m_txBuffer);
}
}
template<unsigned int bufSize> void SerialConsole<bufSize>::Send(char const *buffer, uint8_t length)
{
if(!length) {
auto computedLength = strlen(buffer);
if(computedLength <= (uint8_t)-1)
length = computedLength;
}
if(length) {
while( m_txBuffer.busy );
memcpy(m_txBuffer.buffer, buffer, length);
SetupTransmit(m_txBuffer.buffer, length);
}
}
template<unsigned int bufSize> void SerialConsole<bufSize>::SendLine(char const *buffer, uint8_t length)
{
if(!length) {
auto computedLength = strlen(buffer);
if(computedLength <= (uint8_t)-1)
length = computedLength;
}
if(length) {
while( m_txBuffer.busy );
memcpy(m_txBuffer.buffer, buffer, length);
if(m_txBuffer.buffer[length-1 != '\n']) {
m_txBuffer.buffer[length++] = '\r';
m_txBuffer.buffer[length++] = '\n';
}
SetupTransmit(m_txBuffer.buffer, length);
}
}
#endif /* CONSOLEHANDLER_H_ */

View file

@ -0,0 +1,35 @@
/*
* singleton.h
*
* Created on: Sep 11, 2019
* Author: compi
*/
#ifndef SINGLETON_H_
#define SINGLETON_H_
#include <utility>
template<typename T> class Singleton {
public:
static T &Instance() { return *m_instance; }
template<typename ... Args>
static T &Init(Args &&... args)
{
static T instance{ std::forward<Args>(args)... };
if(!m_instance)
m_instance = &instance;
return instance;
}
protected:
Singleton() = default;
Singleton(const Singleton &) = delete;
Singleton &operator=(const Singleton &) = delete;
virtual ~Singleton() = default;
static T *m_instance;
};
template<typename T> T* Singleton<T>::m_instance = nullptr;
#endif /* SINGLETON_H_ */

View file

@ -0,0 +1,110 @@
#include <stdint.h>
#include <f4ll_cpp/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);
}

View file

@ -0,0 +1,31 @@
/*
* strutil.h
*
* Created on: Feb 11, 2017
* Author: compi
*/
#ifndef _STM32PLUS_STRUTIL_H_
#define _STM32PLUS_STRUTIL_H_
#include <stddef.h>
#include <inttypes.h>
#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_ */

View file

@ -0,0 +1,46 @@
/*
* UartBase.cpp
*
* Created on: Feb 4, 2020
* Author: abody
*/
#include <f4ll_cpp/uartbase.h>
UartBase::UartBase(USART_TypeDef *uart, DMA_TypeDef *dma, uint32_t stream_rx, uint32_t stream_tx)
: m_uart(uart)
, m_rxDma(dma, stream_rx)
, m_txDma(dma, stream_tx)
{
*m_rxDma.GetIfcReg() =
m_rxDma.GetTcMask() | m_rxDma.GetHtMask() |
m_rxDma.GetTeMask() | m_rxDma.GetFeMask() | m_rxDma.GetDmeMask();
*m_txDma.GetIfcReg() =
m_txDma.GetTcMask() | m_txDma.GetHtMask() |
m_txDma.GetTeMask() | m_txDma.GetFeMask() | m_txDma.GetDmeMask();
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);
}
void UartBase::SetupReceive(void *buffer, uint16_t length)
{
LL_DMA_ConfigAddresses(m_rxDma.GetDma(), m_rxDma.GetStream(), LL_USART_DMA_GetRegAddr(m_uart),
(uint32_t)buffer, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
LL_DMA_SetDataLength(m_rxDma.GetDma(), m_rxDma.GetStream(), length); // payload already have extra room for hash
LL_USART_EnableDMAReq_RX(m_uart);
LL_USART_ClearFlag_ORE(m_uart);
LL_DMA_EnableStream(m_rxDma.GetDma(), m_rxDma.GetStream());
}
void UartBase::SetupTransmit(void *buffer, uint16_t length)
{
LL_DMA_ConfigAddresses(m_txDma.GetDma(), m_txDma.GetStream(), (uint32_t)buffer, LL_USART_DMA_GetRegAddr(m_uart), LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
LL_DMA_SetDataLength(m_txDma.GetDma(), m_txDma.GetStream(), length);
LL_USART_EnableDMAReq_TX(m_uart);
LL_DMA_EnableStream(m_txDma.GetDma(), m_txDma.GetStream());
}

View file

@ -0,0 +1,27 @@
/*
* UartBase.h
*
* Created on: Feb 4, 2020
* Author: abody
*/
#ifndef F4LL_CPP_UARTBASE_H_
#define F4LL_CPP_UARTBASE_H_
#include <platform/usart_ll.h>
#include <f4ll_cpp/dmahelper.h>
class UartBase
{
public:
UartBase() = delete;
protected:
UartBase(USART_TypeDef *uart, DMA_TypeDef *dma, uint32_t stream_rx, uint32_t stream_tx);
void SetupTransmit(void *buffer, uint16_t length);
void SetupReceive(void *buffer, uint16_t length);
USART_TypeDef *m_uart;
DmaHelper m_rxDma;
DmaHelper m_txDma;
};
#endif /* F4LL_CPP_UARTBASE_H_ */