/* * interrupt.h * * Created on: Aug 29, 2019 * Author: abody */ #ifndef CONSOLEHANDLER_H_ #define CONSOLEHANDLER_H_ #include #include "usart.h" #include #include namespace f4ll_cpp { template class SerialConsole : protected UartBase { public: struct Buffer { volatile bool busy = false; volatile bool error = false; uint8_t len; char buffer[bufSize]; }; struct ISerialConsoleCallback { // these will be called from interrupt context 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: void SetupTransmit(void *buffer, uint16_t length); bool m_activeRxBuffer = false; Buffer m_rxBuffers[2]; Buffer m_txBuffer; ISerialConsoleCallback *m_callback; void *m_callbackUserParam; }; template SerialConsole::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 void SerialConsole::SetupTransmit(void *buffer, uint16_t length) { m_txBuffer.busy = true; UartBase::SetupTransmit(buffer, length); } template void SerialConsole::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 void SerialConsole::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 void SerialConsole::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 void SerialConsole::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 void SerialConsole::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); } } } // f4ll_cpp #endif /* CONSOLEHANDLER_H_ */