From f0c2ad69c9a923f2b0d7c26fa71d510389c8d51f Mon Sep 17 00:00:00 2001 From: abody Date: Thu, 7 Nov 2019 08:33:48 +0100 Subject: [PATCH] Divided USART communication into core and protocol classes --- Src/stm32f4xx_it.c | 2 +- app/ll_testbed.cpp | 5 +- lib/ll_dmahelper.h | 14 +++- lib/ll_hsusart.cpp | 161 ++++++++++++++++++++----------------------- lib/ll_hsusart.h | 59 ++++++++-------- lib/ll_usartcore.cpp | 116 +++++++++++++++++++++++++++++++ lib/ll_usartcore.h | 51 ++++++++++++++ 7 files changed, 287 insertions(+), 121 deletions(-) create mode 100644 lib/ll_usartcore.cpp create mode 100644 lib/ll_usartcore.h diff --git a/Src/stm32f4xx_it.c b/Src/stm32f4xx_it.c index c18a418..9d33022 100644 --- a/Src/stm32f4xx_it.c +++ b/Src/stm32f4xx_it.c @@ -223,7 +223,7 @@ void SysTick_Handler(void) void DMA1_Stream1_IRQHandler(void) { /* USER CODE BEGIN DMA1_Stream1_IRQn 0 */ - f4ll::LL_HsUsart::HandleRxDmaIrq(g_usarts[USART3_OFFSET]); + f4ll::LL_UsartCore::HandleRxDmaIrq(g_usarts[USART3_OFFSET]); /* USER CODE END DMA1_Stream1_IRQn 0 */ /* USER CODE BEGIN DMA1_Stream1_IRQn 1 */ diff --git a/app/ll_testbed.cpp b/app/ll_testbed.cpp index 309846b..c45be5d 100644 --- a/app/ll_testbed.cpp +++ b/app/ll_testbed.cpp @@ -46,7 +46,8 @@ void _PrintStats(char *buffer, uint8_t id, f4ll::LL_HsUsart &handler, USART_Type buffer += uitohex(buffer, stats.pep1, 8); buffer += strcpy_ex(buffer,",0x"); buffer += uitohex(buffer, stats.pep2, 8); - ADDINFO(buffer, " de: ", stats.dmaError); + ADDINFO(buffer, " rde: ", stats.rxDmaError); + ADDINFO(buffer, " tde: ", stats.txDmaError); ADDINFO(buffer, " pmh: ", stats.premature_hdr); ADDINFO(buffer, " pmp: ", stats.premature_payload); buffer += strcpy_ex(buffer, "\r\n"); @@ -69,7 +70,7 @@ extern "C" void MainLoop() f4ll::LL_HsUsart u3{ USART3, DMA1, LL_DMA_STREAM_1, LL_DMA_STREAM_3 }; f4ll::LL_HsUsart u6{ USART6, DMA2, LL_DMA_STREAM_1, LL_DMA_STREAM_6 }; - f4ll::LL_HsUsart * usarts[] = { & u1, &u2, &u3, &u6 }; + f4ll::LL_HsUsart * usarts[] = { &u1, &u2, &u3, &u6 }; for(unsigned int i=0; i < sizeof(usarts) / sizeof(usarts[0]); ++i) g_usarts[i] = usarts[i]; diff --git a/lib/ll_dmahelper.h b/lib/ll_dmahelper.h index 04070d8..345ad64 100644 --- a/lib/ll_dmahelper.h +++ b/lib/ll_dmahelper.h @@ -28,9 +28,21 @@ public: inline uint32_t GetHtMask() const { return m_HTMasks[m_stream]; } inline uint32_t GetTcMask() const { return m_TCMasks[m_stream]; } + inline bool IsEnabledIt_HT() { return LL_DMA_IsEnabledIT_HT(m_dma, m_stream) != 0; } + inline bool IsEnabledIt_TE() { return LL_DMA_IsEnabledIT_TE(m_dma, m_stream) != 0; } + inline bool IsEnabledIt_TC() { return LL_DMA_IsEnabledIT_TC(m_dma, m_stream) != 0; } + inline bool IsEnabledIt_DME() { return LL_DMA_IsEnabledIT_DME(m_dma, m_stream) != 0; } + inline bool IsEnabledIt_FE() { return LL_DMA_IsEnabledIT_FE(m_dma, m_stream) != 0; } + + enum class DmaErrorType { + Transfer, + DirectMode, + Fifo + }; + private: DMA_TypeDef *m_dma; - uint32_t m_stream; + uint32_t m_stream; volatile uint32_t *m_isReg; volatile uint32_t *m_ifcReg; diff --git a/lib/ll_hsusart.cpp b/lib/ll_hsusart.cpp index 477dddf..64deee4 100644 --- a/lib/ll_hsusart.cpp +++ b/lib/ll_hsusart.cpp @@ -14,19 +14,11 @@ template static inline T RoundUpTo4(T input) return (input + 3) & (((T)-1) - 3); } + LL_HsUsart::LL_HsUsart(USART_TypeDef *usart, DMA_TypeDef *dma, uint32_t streamRx, uint32_t streamTx) -: m_usart(usart) -, m_rxDma(dma, streamRx) -, m_txDma(dma, streamTx) +: LL_UsartCore(usart, dma, streamRx, streamTx) { LL_CrcHandler::Instance().AttachSlot(m_crcSlot); - LL_DMA_EnableIT_TC(dma, streamRx); - LL_DMA_EnableIT_TE(dma, streamRx); - LL_DMA_EnableIT_TC(dma, streamTx); - LL_DMA_EnableIT_TE(dma, streamTx); - LL_USART_EnableIT_IDLE(usart); - - memset(&m_stats, 0, sizeof(m_stats)); } @@ -119,11 +111,7 @@ void LL_HsUsart::PostPacket(uint8_t const *payload, uint8_t length, bool waitFor while(waitForCrcQueue && LL_CrcHandler::Instance().IsQueued(m_crcSlot, 0)); - LL_DMA_ConfigAddresses(m_txDma.GetDma(), m_txDma.GetStream(), reinterpret_cast(&m_txBuffer.packet), - LL_USART_DMA_GetRegAddr(m_usart), LL_DMA_DIRECTION_MEMORY_TO_PERIPH); - LL_DMA_SetDataLength(m_txDma.GetDma(), m_txDma.GetStream(), m_txBuffer.requestedLength); - LL_USART_EnableDMAReq_TX(m_usart); - LL_DMA_EnableStream(m_txDma.GetDma(), m_txDma.GetStream()); + SetupTransmit(&m_txBuffer.packet, m_txBuffer.requestedLength); ++m_stats.sent; } @@ -131,67 +119,87 @@ void LL_HsUsart::PostPacket(uint8_t const *payload, uint8_t length, bool waitFor void LL_HsUsart::SetupReceive() { - int packetIndex = m_rxBufferSelector; - - LL_DMA_ConfigAddresses(m_rxDma.GetDma(), m_rxDma.GetStream(), LL_USART_DMA_GetRegAddr(m_usart), - reinterpret_cast(&m_rxBuffers[packetIndex]), LL_DMA_DIRECTION_PERIPH_TO_MEMORY); - m_rxBuffers[packetIndex].requestedLength = sizeof(m_rxBuffers[packetIndex].packet); - LL_DMA_SetDataLength(m_rxDma.GetDma(), m_rxDma.GetStream(), m_rxBuffers[packetIndex].requestedLength); // payload already have extra room for hash - LL_USART_EnableDMAReq_RX(m_usart); - LL_USART_ClearFlag_ORE(m_usart); - LL_DMA_EnableStream(m_rxDma.GetDma(), m_rxDma.GetStream()); + m_rxBuffers[m_rxBufferSelector].requestedLength = sizeof(m_rxBuffers[m_rxBufferSelector].packet); + LL_UsartCore::SetupReceive(&m_rxBuffers[m_rxBufferSelector], sizeof(m_rxBuffers[m_rxBufferSelector].packet)); } -void LL_HsUsart::UsartIrq(void) +void LL_HsUsart::ReceiverIdle(void) { - if(LL_USART_IsActiveFlag_IDLE(m_usart) && LL_USART_IsEnabledIT_IDLE(m_usart)) { // receiver idle - LL_USART_ClearFlag_IDLE(m_usart); - uint16_t rcvdLen = m_rxBuffers[m_rxBufferSelector].requestedLength - LL_DMA_GetDataLength(m_rxDma.GetDma(), m_rxDma.GetStream()); - if(rcvdLen >= sizeof(PacketHeader)) { - if(CheckHeader(m_rxBuffers[m_rxBufferSelector].packet.header)) { - if(rcvdLen >= sizeof(PacketHeader) + - RoundUpTo4((uint16_t)m_rxBuffers[m_rxBufferSelector].packet.header.payloadLength) - + sizeof(uint32_t)) - LL_DMA_DisableStream(m_rxDma.GetDma(), m_rxDma.GetStream()); - else - ++m_stats.premature_payload; - } else { - m_rxBuffers[m_rxBufferSelector].error = 1; + uint16_t rcvdLen = m_rxBuffers[m_rxBufferSelector].requestedLength - LL_DMA_GetDataLength(m_rxDma.GetDma(), m_rxDma.GetStream()); + if(rcvdLen >= sizeof(PacketHeader)) { + if(CheckHeader(m_rxBuffers[m_rxBufferSelector].packet.header)) { + if(rcvdLen >= sizeof(PacketHeader) + + RoundUpTo4((uint16_t)m_rxBuffers[m_rxBufferSelector].packet.header.payloadLength) + + sizeof(uint32_t)) LL_DMA_DisableStream(m_rxDma.GetDma(), m_rxDma.GetStream()); - } - } else - ++m_stats.premature_hdr; - } - else if(LL_USART_IsActiveFlag_TC(m_usart) && LL_USART_IsEnabledIT_TC(m_usart)) { // transmission complete - LL_USART_DisableIT_TC(m_usart); - LL_USART_DisableDirectionTx(m_usart); // enforcing an idle frame - LL_USART_EnableDirectionTx(m_usart); - m_txBuffer.busy = 0; - } + else + ++m_stats.premature_payload; + } else { + m_rxBuffers[m_rxBufferSelector].error = 1; + LL_DMA_DisableStream(m_rxDma.GetDma(), m_rxDma.GetStream()); + } + } else + ++m_stats.premature_hdr; } -void LL_HsUsart::RxDmaIrq() +void LL_HsUsart::TransmissionComplete(void) +{ + LL_USART_DisableDirectionTx(m_usart); // enforcing an idle frame + LL_USART_EnableDirectionTx(m_usart); + m_txBuffer.busy = 0; +} + + +void LL_HsUsart::RxDmaTransferComplete(void) +{ + if(CheckHeader(m_rxBuffers[m_rxBufferSelector].packet.header)) + LL_CrcHandler::Instance().Enqueue(m_crcSlot, 1, + &m_rxBuffers[m_rxBufferSelector].packet, + sizeof(PacketHeader) + RoundUpTo4((uint16_t)m_rxBuffers[m_rxBufferSelector].packet.header.payloadLength), + this, m_rxBufferSelector); + else { + ++m_stats.hdrError; + m_rxBuffers[m_rxBufferSelector].error = true; + } + SwitchRxBuffers(); +} + +void LL_HsUsart::RxDmaHalfTransfer(void) +{ +} + + +void LL_HsUsart::RxDmaError(LL_DmaHelper::DmaErrorType reason) +{ + m_rxBuffers[m_rxBufferSelector].error = 1; + ++m_stats.rxDmaError; + SwitchRxBuffers(); +} + +void LL_HsUsart::TxDmaTransferComplete(void) +{ + LL_USART_EnableIT_TC(m_usart); + LL_DMA_DisableStream(m_txDma.GetDma(), m_txDma.GetStream()); +} + + +void LL_HsUsart::TxDmaHalfTransfer(void) +{ +} + + +void LL_HsUsart::TxDmaError(LL_DmaHelper::DmaErrorType reason) +{ + m_txBuffer.error = 1; + ++m_stats.txDmaError; +} + + +void LL_HsUsart::SwitchRxBuffers(void) { ++m_stats.rcvd; - if(*m_rxDma.GetIsReg() & m_rxDma.GetTcMask()) { - *m_rxDma.GetIfcReg() = m_rxDma.GetTcMask(); - if(CheckHeader(m_rxBuffers[m_rxBufferSelector].packet.header)) - LL_CrcHandler::Instance().Enqueue(m_crcSlot, 1, - &m_rxBuffers[m_rxBufferSelector].packet, - sizeof(PacketHeader) + RoundUpTo4((uint16_t)m_rxBuffers[m_rxBufferSelector].packet.header.payloadLength), - this, m_rxBufferSelector); - else { - ++m_stats.hdrError; - m_rxBuffers[m_rxBufferSelector].error = true; - } - } else if(*m_rxDma.GetIsReg() & m_rxDma.GetTeMask()) { - *m_rxDma.GetIfcReg() = m_rxDma.GetTeMask(); - m_rxBuffers[m_rxBufferSelector].error = 1; - ++m_stats.dmaError; - } - m_rxBufferSelector = !m_rxBufferSelector; if(m_rxBuffers[m_rxBufferSelector].busy) @@ -226,25 +234,4 @@ void LL_HsUsart::CrcFailed(uintptr_t callbackParam, uint32_t crc, int prio) } -void LL_HsUsart::TxDmaIrq() -{ - if(*m_txDma.GetIsReg() & m_txDma.GetTcMask()) { // DMA transfer complete - *m_txDma.GetIfcReg() = m_txDma.GetTcMask(); - LL_USART_EnableIT_TC(m_usart); - LL_DMA_DisableStream(m_txDma.GetDma(), m_txDma.GetStream()); - } - else if(*m_txDma.GetIsReg() & m_txDma.GetTeMask()) { - *m_txDma.GetIfcReg() = m_txDma.GetTeMask(); - m_txBuffer.error = 1; - ++m_stats.dmaError; - } - 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(); -} - - } // namespace f4ll diff --git a/lib/ll_hsusart.h b/lib/ll_hsusart.h index 6c13953..20f32e4 100644 --- a/lib/ll_hsusart.h +++ b/lib/ll_hsusart.h @@ -8,13 +8,14 @@ #ifndef LL_HSUSART_H_ #define LL_HSUSART_H_ #include +#include #include namespace f4ll { struct DMAINFO; -class LL_HsUsart : public LL_CrcHandler::ICallback +class LL_HsUsart : public LL_CrcHandler::ICallback, public LL_UsartCore { public: LL_HsUsart(USART_TypeDef *usart, DMA_TypeDef *dma, uint32_t stream_rx, uint32_t stream_tx); @@ -32,55 +33,56 @@ public: } __attribute__((aligned)); struct Stats { - uint32_t overrun; - uint32_t hdrError; - 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; + uint32_t overrun = 0; + uint32_t hdrError = 0; + uint32_t payloadErrror = 0; + uint32_t pep1 = 0; + uint32_t pep2 = 0; + uint32_t rxDmaError = 0; + uint32_t txDmaError = 0; + uint32_t rcvd = 0; + uint32_t premature_hdr = 0; + uint32_t premature_payload = 0; + uint32_t sent = 0; + uint32_t skiped = 0; }; struct IHsUsartCallback { virtual bool PacketReceived(LL_HsUsart *caller, uintptr_t userParam, Packet const &packet) = 0; }; - //LL_CRCHandler::ICallback interface functions + // LL_CRCHandler::ICallback interface functions virtual void CrcSucceeded(uintptr_t callbackParam, uint32_t crc, int prio); virtual void CrcFailed(uintptr_t callbackParam, uint32_t crc, int prio); + // LL_UsartCore pure virtual function implementations + virtual void ReceiverIdle(void); + virtual void TransmissionComplete(void); + virtual void RxDmaTransferComplete(void); + virtual void RxDmaHalfTransfer(void); + virtual void RxDmaError(LL_DmaHelper::DmaErrorType reason); + virtual void TxDmaTransferComplete(void); + virtual void TxDmaHalfTransfer(void); + virtual void TxDmaError(LL_DmaHelper::DmaErrorType reason); + void PostPacket(uint8_t const *payload, uint8_t length, bool waitForCrcQueue = true); void SetupReceive(void); void RxProcessed(bool second); uint8_t* GetTxPacketBuffer(void); USART_TypeDef* GetUsart(void); - Stats const & GetStats(); - bool IsTxBusy(); - bool IsTxFailed(); + Stats const & GetStats(void); + bool IsTxBusy(void); + bool IsTxFailed(void); bool IsRxBusy(bool second); bool IsRxFailed(bool second); void SetCallback(IHsUsartCallback* callback, uintptr_t callbackParam); - static inline void HandleUsartIrq(LL_HsUsart *obj) { - obj->UsartIrq(); - } - static inline void HandleRxDmaIrq(LL_HsUsart *obj) { - obj->RxDmaIrq(); - } - static inline void HandleTxDmaIrq(LL_HsUsart *obj) { - obj->TxDmaIrq(); - } private: void BuildHeader(Packet &packet, uint8_t serialNo, uint8_t length); bool CheckHeader(PacketHeader &header); - void UsartIrq(void); - void RxDmaIrq(void); - void TxDmaIrq(void); + void SwitchRxBuffers(void); struct Buffer { Packet packet; @@ -93,9 +95,6 @@ private: static const uint8_t STARTMARKER = 0x95; - USART_TypeDef *m_usart; - LL_DmaHelper m_rxDma; - LL_DmaHelper m_txDma; uint8_t m_rxSerialNo = -1; uint8_t m_txSerialNo = -1; Stats m_stats; diff --git a/lib/ll_usartcore.cpp b/lib/ll_usartcore.cpp new file mode 100644 index 0000000..c8bce70 --- /dev/null +++ b/lib/ll_usartcore.cpp @@ -0,0 +1,116 @@ +/* + * ll_dmadrivenusartcore.cpp + * + * Created on: Nov 4, 2019 + * Author: abody + */ + +#include + +namespace f4ll { + +LL_UsartCore::LL_UsartCore(USART_TypeDef *usart, DMA_TypeDef *dma, uint32_t streamRx, uint32_t streamTx) +: m_usart(usart) +, m_rxDma(dma, streamRx) +, m_txDma(dma, streamTx) +{ + LL_DMA_EnableIT_TC(dma, streamRx); + LL_DMA_EnableIT_TE(dma, streamRx); + LL_DMA_EnableIT_TC(dma, streamTx); + LL_DMA_EnableIT_TE(dma, streamTx); + LL_USART_EnableIT_IDLE(usart); +} + +void LL_UsartCore::UsartIsr() +{ + if(LL_USART_IsActiveFlag_IDLE(m_usart) && LL_USART_IsEnabledIT_IDLE(m_usart)) { // receiver idle + LL_USART_ClearFlag_IDLE(m_usart); + ReceiverIdle(); + } else if(LL_USART_IsActiveFlag_TC(m_usart) && LL_USART_IsEnabledIT_TC(m_usart)) { // transmission complete + LL_USART_DisableIT_TC(m_usart); + TransmissionComplete(); + } +} + + +void LL_UsartCore::RxDmaIsr() +{ + if(*m_rxDma.GetIsReg() & m_rxDma.GetTcMask()) { + *m_rxDma.GetIfcReg() = m_rxDma.GetTcMask(); + if(m_rxDma.IsEnabledIt_TC()) + RxDmaTransferComplete(); + } + if(*m_rxDma.GetIsReg() & m_rxDma.GetHtMask()) { + *m_rxDma.GetIfcReg() = m_rxDma.GetHtMask(); + if(m_rxDma.IsEnabledIt_HT()) + RxDmaHalfTransfer(); + } + if(*m_rxDma.GetIsReg() & m_rxDma.GetTeMask()) { + *m_rxDma.GetIfcReg() = m_rxDma.GetTeMask(); + if(m_rxDma.IsEnabledIt_TE()) + RxDmaError(LL_DmaHelper::DmaErrorType::Transfer); + } + if(*m_rxDma.GetIsReg() & m_rxDma.GetFeMask()) { + *m_rxDma.GetIfcReg() = m_rxDma.GetFeMask(); + if(m_rxDma.IsEnabledIt_FE()) + RxDmaError(LL_DmaHelper::DmaErrorType::Fifo); + } + if(*m_rxDma.GetIsReg() & m_rxDma.GetDmeMask()) { + *m_rxDma.GetIfcReg() = m_rxDma.GetDmeMask(); + if(m_rxDma.IsEnabledIt_DME()) + RxDmaError(LL_DmaHelper::DmaErrorType::DirectMode); + } +} + + +void LL_UsartCore::TxDmaIsr() +{ + if(*m_txDma.GetIsReg() & m_txDma.GetTcMask()) { // DMA transfer complete + *m_txDma.GetIfcReg() = m_txDma.GetTcMask(); + if(m_txDma.IsEnabledIt_TC()) + TxDmaTransferComplete(); + } + if(*m_txDma.GetIsReg() & m_txDma.GetHtMask()) { + *m_txDma.GetIfcReg() = m_txDma.GetHtMask(); + if(m_txDma.IsEnabledIt_HT()) + TxDmaHalfTransfer(); + } + if(*m_txDma.GetIsReg() & m_txDma.GetTeMask()) { + *m_txDma.GetIfcReg() = m_txDma.GetTeMask(); + if(m_txDma.IsEnabledIt_TE()) + TxDmaError(LL_DmaHelper::DmaErrorType::Transfer); + } + if(*m_txDma.GetIsReg() & m_txDma.GetFeMask()) { + *m_txDma.GetIfcReg() = m_txDma.GetFeMask(); + if(m_txDma.IsEnabledIt_FE()) + TxDmaError(LL_DmaHelper::DmaErrorType::Fifo); + } + if(*m_txDma.GetIsReg() & m_txDma.GetDmeMask()) { + *m_txDma.GetIfcReg() = m_txDma.GetDmeMask(); + if(m_txDma.IsEnabledIt_DME()) + TxDmaError(LL_DmaHelper::DmaErrorType::DirectMode); + } +} + + +void LL_UsartCore::SetupTransmit(void const *buffer, uint16_t length) +{ + LL_DMA_ConfigAddresses(m_txDma.GetDma(), m_txDma.GetStream(), reinterpret_cast(buffer), + LL_USART_DMA_GetRegAddr(m_usart), LL_DMA_DIRECTION_MEMORY_TO_PERIPH); + LL_DMA_SetDataLength(m_txDma.GetDma(), m_txDma.GetStream(), length); + LL_USART_EnableDMAReq_TX(m_usart); + LL_DMA_EnableStream(m_txDma.GetDma(), m_txDma.GetStream()); +} + + +void LL_UsartCore::SetupReceive(void *buffer, uint16_t length) +{ + LL_DMA_ConfigAddresses(m_rxDma.GetDma(), m_rxDma.GetStream(), LL_USART_DMA_GetRegAddr(m_usart), + reinterpret_cast(buffer), LL_DMA_DIRECTION_PERIPH_TO_MEMORY); + LL_DMA_SetDataLength(m_rxDma.GetDma(), m_rxDma.GetStream(), length); + LL_USART_EnableDMAReq_RX(m_usart); + LL_USART_ClearFlag_ORE(m_usart); + LL_DMA_EnableStream(m_rxDma.GetDma(), m_rxDma.GetStream()); +} + +} /* namespace f4ll */ diff --git a/lib/ll_usartcore.h b/lib/ll_usartcore.h new file mode 100644 index 0000000..7b3672c --- /dev/null +++ b/lib/ll_usartcore.h @@ -0,0 +1,51 @@ +/* + * ll_dmadrivenusartcore.h + * + * Created on: Nov 4, 2019 + * Author: abody + */ + +#ifndef LL_USARTCORE_H_ +#define LL_USARTCORE_H_ +#include + +#include "ll_dmahelper.h" + +namespace f4ll { + +class LL_UsartCore +{ +public: + static inline void HandleUsartIrq(LL_UsartCore *_this) { _this->UsartIsr(); } + static inline void HandleRxDmaIrq(LL_UsartCore *_this) { _this->RxDmaIsr(); } + static inline void HandleTxDmaIrq(LL_UsartCore *_this) { _this->TxDmaIsr(); } + +protected: + LL_UsartCore(USART_TypeDef *usart, DMA_TypeDef *dma, uint32_t streamRx, uint32_t streamTx); + + virtual void ReceiverIdle() = 0; + virtual void TransmissionComplete() = 0; + + virtual void RxDmaTransferComplete() = 0; + virtual void RxDmaHalfTransfer() = 0; + virtual void RxDmaError(LL_DmaHelper::DmaErrorType reason) = 0; + + virtual void TxDmaTransferComplete() = 0; + virtual void TxDmaHalfTransfer() = 0; + virtual void TxDmaError(LL_DmaHelper::DmaErrorType reason) = 0; + + void SetupTransmit(void const *buffer, uint16_t length); + void SetupReceive(void *buffer, uint16_t length); + + void UsartIsr(); + void RxDmaIsr(); + void TxDmaIsr(); + + USART_TypeDef *m_usart; + LL_DmaHelper m_rxDma; + LL_DmaHelper m_txDma; +}; + +} /* namespace f4ll */ + +#endif /* LL_USARTCORE_H_ */