File ControlLink.cpp
File List > fw > rbcx-coprocessor > src > ControlLink.cpp
Go to the documentation of this file.
#include <array>
#include "stm32f1xx_hal.h"
#include "stm32f1xx_hal_dma.h"
#include "stm32f1xx_ll_usart.h"
#include "Bsp.hpp"
#include "Esp32Manager.hpp"
#include "coproc_codec.h"
#include "coproc_link_parser.h"
#include "rbcx.pb.h"
#include "utils/ByteFifo.hpp"
#include "utils/MessageBufferWrapper.hpp"
static DMA_HandleTypeDef dmaRxHandle;
static DMA_HandleTypeDef dmaTxHandle;
static rb::CoprocCodec codec;
static rb::CoprocLinkParser<CoprocReq, &CoprocReq_msg> parser(codec);
static ByteFifo<512> rxFifo;
// Encode TX frame in txEncodeBuf, push to txMessageBuf, move to txDmaBuf and send via DMA.
static std::array<uint8_t, codec.MaxFrameSize> txEncodeBuf;
static std::array<uint8_t, codec.MaxFrameSize> txDmaBuf;
static MessageBufferWrapper<512> txMessageBuf;
void controlUartInit() {
txMessageBuf.create();
LL_USART_InitTypeDef init;
LL_USART_StructInit(&init);
init.BaudRate = 921600;
init.DataWidth = LL_USART_DATAWIDTH_8B;
init.HardwareFlowControl = LL_USART_HWCONTROL_NONE;
init.Parity = LL_USART_PARITY_NONE;
init.StopBits = LL_USART_STOPBITS_1;
init.TransferDirection = LL_USART_DIRECTION_TX_RX;
LL_USART_Init(controlUart, &init);
LL_USART_Enable(controlUart);
// UART RX runs indefinitely in circular mode
dmaRxHandle.Instance = controlUartRxDmaChannel;
dmaRxHandle.Init.Direction = DMA_PERIPH_TO_MEMORY;
dmaRxHandle.Init.Mode = DMA_CIRCULAR;
dmaRxHandle.Init.MemInc = DMA_MINC_ENABLE;
dmaRxHandle.Init.PeriphInc = DMA_PINC_DISABLE;
dmaRxHandle.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
dmaRxHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
dmaRxHandle.Init.Priority = DMA_PRIORITY_MEDIUM;
HAL_DMA_Init(&dmaRxHandle);
HAL_DMA_Start(&dmaRxHandle, uintptr_t(&(controlUart->DR)),
uintptr_t(rxFifo.data()), rxFifo.size());
LL_USART_EnableDMAReq_RX(controlUart);
// UART TX burst is started ad hoc each time
dmaTxHandle.Instance = controlUartTxDmaChannel;
dmaTxHandle.Init.Direction = DMA_MEMORY_TO_PERIPH;
dmaTxHandle.Init.Mode = DMA_NORMAL;
dmaTxHandle.Init.MemInc = DMA_MINC_ENABLE;
dmaTxHandle.Init.PeriphInc = DMA_PINC_DISABLE;
dmaTxHandle.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
dmaTxHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
dmaTxHandle.Init.Priority = DMA_PRIORITY_MEDIUM;
HAL_DMA_Init(&dmaTxHandle);
HAL_NVIC_SetPriority(controlUartTxDmaIRQn, controlUartTxDmaIRQnPrio, 0);
HAL_NVIC_EnableIRQ(controlUartTxDmaIRQn);
LL_USART_EnableDMAReq_TX(controlUart);
}
static void controlLinkUpdateRxFifo() {
int rxHead = rxFifo.size() - __HAL_DMA_GET_COUNTER(&dmaRxHandle);
rxFifo.setHead(rxHead);
}
bool controlLinkRx(CoprocReq& incoming) {
controlLinkUpdateRxFifo();
while (rxFifo.hasData()) {
if (parser.add(rxFifo.pop())) {
incoming = parser.lastMessage();
return true;
}
}
return false;
}
void controlLinkTx(const CoprocStat& outgoing) {
auto encodedSize = codec.encodeWithHeader(
&CoprocStat_msg, &outgoing, txEncodeBuf.data(), txEncodeBuf.size());
if (encodedSize == 0)
abort();
if (!txMessageBuf.push_back(txEncodeBuf.data(), encodedSize, 0)) {
DEBUG("txMessageBuf overflow\n");
abort();
}
HAL_NVIC_SetPendingIRQ(controlUartTxDmaIRQn);
}
void controlLinkReset() {
controlLinkUpdateRxFifo();
rxFifo.clear();
while (!txMessageBuf.reset())
vTaskDelay(0);
}
extern "C" void CONTROLUART_TX_DMA_HANDLER() {
HAL_DMA_IRQHandler(&dmaTxHandle);
if (dmaTxHandle.State == HAL_DMA_STATE_READY) {
BaseType_t pxHigherPriorityTaskWoken = pdFALSE;
const auto len = txMessageBuf.pop_front(
txDmaBuf.data(), txDmaBuf.size(), 0, &pxHigherPriorityTaskWoken);
if (len > 0) {
HAL_DMA_Start_IT(&dmaTxHandle, uintptr_t(txDmaBuf.data()),
uintptr_t(&controlUart->DR), len);
}
portYIELD_FROM_ISR(pxHigherPriorityTaskWoken);
}
}