Add async UART logger (running on DMA).
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Erki 2021-03-21 17:03:06 +02:00
parent b7789064fa
commit faa1685e18
4 changed files with 185 additions and 0 deletions

View File

@ -0,0 +1,49 @@
/*
* utility_asyncaurtlogger.hpp
*
* Created on: Mar 20, 2021
* Author: erki
*/
#ifndef SKULLC_UTILITY_ASYNCAURTLOGGER_HPP_
#define SKULLC_UTILITY_ASYNCAURTLOGGER_HPP_
#include "utility_ilogger.hpp"
#include "utility_ringbuffer.hpp"
#include "usart.h"
namespace Utility
{
class AsyncUARTLogger : public ILogger
{
public:
explicit AsyncUARTLogger(UART_HandleTypeDef* huart);
AsyncUARTLogger() = delete;
AsyncUARTLogger(const AsyncUARTLogger&) = delete;
AsyncUARTLogger(AsyncUARTLogger&&) = delete;
void log(const char* format, ...);
private:
struct _Data
{
std::array<char, 255> buffer;
std::int32_t length;
};
Ringbuffer<_Data, 10> _buffer_queue;
UART_HandleTypeDef* _huart;
bool _in_flight = false;
static AsyncUARTLogger* _this;
static void _txCompleteCallback(UART_HandleTypeDef* huart);
void _sendNextLog();
};
}
#endif /* SKULLC_UTILITY_ASYNCAURTLOGGER_HPP_ */

View File

@ -0,0 +1,31 @@
/*
* utility_atomicscopeguard.hpp
*
* Created on: Mar 21, 2021
* Author: erki
*/
#ifndef UTILITY_INC_UTILITY_ATOMICSCOPEGUARD_HPP_
#define UTILITY_INC_UTILITY_ATOMICSCOPEGUARD_HPP_
#include <cstdint>
namespace Utility
{
class AtomicScopeGuard
{
public:
AtomicScopeGuard();
AtomicScopeGuard(const AtomicScopeGuard&) = delete;
AtomicScopeGuard(AtomicScopeGuard&&) = delete;
~AtomicScopeGuard();
private:
static std::int32_t _reentrancy_counter;
};
}
#endif /* UTILITY_INC_UTILITY_ATOMICSCOPEGUARD_HPP_ */

View File

@ -0,0 +1,73 @@
/*
* utility_asynchuartlogger.cpp
*
* Created on: Mar 20, 2021
* Author: erki
*/
#include "utility_asyncaurtlogger.hpp"
#include <cstdlib>
#include <cstdarg>
#include <cassert>
#include "utility_atomicscopeguard.hpp"
namespace Utility
{
AsyncUARTLogger* AsyncUARTLogger::_this = nullptr;
AsyncUARTLogger::AsyncUARTLogger(UART_HandleTypeDef* huart)
: _huart(huart)
{
assert(!_this);
_this = this;
_huart->TxCpltCallback = &AsyncUARTLogger::_txCompleteCallback;
}
void AsyncUARTLogger::log(const char* format, ...)
{
{
AtomicScopeGuard s;
if (_buffer_queue.size() == _buffer_queue.max_size())
return;
}
std::va_list args;
va_start(args, format);
auto tail = _buffer_queue.end();
std::array<char, 255>& buffer = tail->buffer;
tail->length = vsnprintf(buffer.data(), buffer.size(), format, args);
{
AtomicScopeGuard s;
_buffer_queue.increment_tail();
if (!_in_flight)
_sendNextLog();
}
}
void AsyncUARTLogger::_txCompleteCallback(UART_HandleTypeDef*)
{
if (!AsyncUARTLogger::_this->_buffer_queue.empty())
AsyncUARTLogger::_this->_sendNextLog();
else
AsyncUARTLogger::_this->_in_flight = false;
}
void AsyncUARTLogger::_sendNextLog()
{
_in_flight = true;
_Data& head = _buffer_queue.front();
HAL_UART_Transmit_DMA(_huart, reinterpret_cast<uint8_t*>(head.buffer.data()), head.length);
_buffer_queue.pop_front();
}
}

View File

@ -0,0 +1,32 @@
/*
* utility_atomicscopeguard.cpp
*
* Created on: Mar 21, 2021
* Author: erki
*/
#include "utility_atomicscopeguard.hpp"
#include "cmsis_gcc.h"
namespace Utility
{
std::int32_t AtomicScopeGuard::_reentrancy_counter;
AtomicScopeGuard::AtomicScopeGuard()
{
__disable_irq();
_reentrancy_counter++;
}
AtomicScopeGuard::~AtomicScopeGuard()
{
_reentrancy_counter--;
if (!_reentrancy_counter)
__enable_irq();
}
}