Fix uart logging issues

This commit is contained in:
Bartosz Wieczorek 2025-04-22 11:25:15 +02:00
parent f5be4c4e18
commit 31ecbc1bda
7 changed files with 443 additions and 300 deletions

View File

@ -50,7 +50,7 @@ CONFIG_LOG_BACKEND_UART=n # Use UART for log output
CONFIG_MAIN_STACK_SIZE=1500
#
CONFIG_CRC=y
CONFIG_ASSERT=n
CONFIG_ASSERT=y
#CONFIG_NUM_PREEMPT_PRIORITIES=0

View File

@ -1,8 +1,8 @@
#pragma once
#include "zephyr.hpp"
#include "zephyr/sys/__assert.h"
#include <array>
#include <cassert>
#include <cstddef>
#include <cstring>
@ -11,17 +11,6 @@
namespace rims {
// template <typename T> class circular_buffer_base {
// public:
// virtual ~circular_buffer_base() = default;
// virtual const T &back() const = 0;
// virtual T &back() = 0;
// virtual T &emplace_back(T &&item) = 0;
// virtual void pop_back() = 0;
// };
template <typename T, std::size_t Capacity> class static_vector {
private:
std::array<T, Capacity> buffer;
@ -32,7 +21,7 @@ template <typename T, std::size_t Capacity> class static_vector {
return count;
}
constexpr void clean() noexcept {
constexpr void clean() noexcept { /// TODO call dtors
count = 0;
}
@ -60,308 +49,432 @@ template <typename T, std::size_t Capacity> class static_vector {
}
};
template <class T, std::size_t N> class circular_buffer {
struct RingIndex {
using index_t = uint16_t;
constexpr RingIndex(index_t n) : N{n} {
}
constexpr void reset() {
_head = 0;
_tail = 0;
_full = false;
}
constexpr bool empty() const {
return (!_full && _head == _tail);
}
constexpr bool full() const {
return _full;
}
constexpr std::size_t size() const {
if (full()) {
return N;
}
if (_head >= _tail) {
return _head - _tail;
} else {
return N + _head - _tail;
}
}
constexpr std::size_t capacity() const {
return N;
}
constexpr std::size_t free() const {
return capacity() - size();
}
constexpr index_t increment_head() {
__ASSERT(not full(), "Cannot increment head on full buffer");
return increment_head(1);
}
constexpr index_t increment_head(index_t n) {
__ASSERT(free() >= n, "Cannot increment head more than free space");
_head = (_head + n) % N;
_full = _head == _tail;
return prev_head();
}
constexpr index_t decrement_head() {
__ASSERT(not empty(), "Cannot decrement head on empty buffer");
_head = (_head + N - 1) % N;
_full = false;
return _head;
}
constexpr index_t increment_tail() {
__ASSERT(!empty(), "Cannot increment tail on empty buffer");
return increment_tail(1);
}
constexpr index_t increment_tail(index_t n) {
__ASSERT(size() >= n, "Tail cannot pass head");
_tail = (_tail + n) % N;
_full = false;
return prev_tail();
}
constexpr index_t head() const {
return _head;
}
constexpr index_t tail() const {
return _tail;
}
constexpr index_t firstFree() const {
__ASSERT(!full(), "Buffer is full");
return head();
}
constexpr bool headAfterTail() const {
return head() >= tail();
}
constexpr std::size_t spaceBack() const {
if (headAfterTail()) {
return capacity() - head();
} else {
if (spaceMid() == 0) {
return capacity() - tail() - 1;
}
}
return 0;
}
constexpr std::size_t spaceFront() const {
if (headAfterTail()) {
return tail();
} else {
if (spaceMid() == 0) {
return head();
}
}
return 0;
}
constexpr std::size_t spaceMid() const {
const auto head2Tail = tail() - head();
return head2Tail > 0 ? head2Tail : 0;
}
using area = std::pair<index_t, std::size_t>;
constexpr std::pair<area, area> getFreeAreas() const {
__ASSERT((spaceFront() + spaceBack() + spaceMid()) == free(), "check that capacity always matches");
const std::size_t capacityMid = spaceMid();
if (capacityMid) {
return {{head(), capacityMid}, {0, 0}};
} else {
return {{head(), spaceBack()}, {0, spaceFront()}};
}
}
private:
constexpr index_t prev_tail() const {
return _tail == 0 ? N - 1 : _tail - 1;
}
constexpr index_t prev_head() const {
return _head == 0 ? N - 1 : _head - 1;
}
index_t N{0};
index_t _head{0};
index_t _tail{0};
bool _full{false};
};
template <class T, std::size_t N> class ring_buffer {
public:
explicit circular_buffer() = default;
using value_type = T;
explicit ring_buffer() : _index{N} {
}
T &emplace_front(const T &item) {
if (size() == capacity()) {
std::destroy_at(std::addressof(buf_[head_]));
std::memset(std::addressof(buf_[head_]), 0, sizeof(T));
}
auto at = head_;
std::construct_at(reinterpret_cast<T *>(std::addressof(buf_[head_])), item);
if (full_) {
tail_ = (tail_ + 1) % N;
T &push_back(const T &item) {
if (full()) {
pop_front();
}
head_ = (head_ + 1) % N;
full_ = head_ == tail_;
auto at = _index.head();
std::construct_at(reinterpret_cast<T *>(std::addressof(buf_[_index.increment_head()])), item);
return directy_at(at);
}
void put_n(const T *items, std::size_t n) {
static_assert(std::is_trivially_constructible_v<T>);
__ASSERT(_index.free() >= n, "need to have space for all items");
auto areas = _index.getFreeAreas();
__ASSERT((areas.first.second + areas.second.second) >= n, "areas should contains enaough free space to fit all items");
std::memcpy(buf_[areas.first.first], items, areas.first.second * sizeof(T));
if (areas.first.second <= n) std::memcpy(buf_[areas.second.first], items + areas.first.second, areas.second.second * sizeof(T));
_index.increment_head(n);
}
T get() {
__ASSERT_NO_MSG(not empty());
// Read data and advance the tail (we now have a free space)
T val = std::move(*reinterpret_cast<T *>(std::addressof(buf_[tail_])));
std::destroy_at(std::addressof(buf_[tail_]));
std::memset(std::addressof(buf_[tail_]), 0, sizeof(T));
tail_ = (tail_ + 1) % N;
full_ = false;
// Read data and advance the tail (we now have a free space)
T val = std::move(*reinterpret_cast<T *>(std::addressof(buf_[_index.tail()])));
destroy_at(_index.increment_tail());
return val;
}
// removes the last (youngest) element
void pop_back() {
std::destroy_at(std::addressof(buf_[tail_]));
std::memset(std::addressof(buf_[tail_]), 0, sizeof(T));
tail_ = (tail_ + 1) % N;
full_ = false;
__ASSERT_NO_MSG(not empty());
destroy_at(_index.decrement_head());
}
// removes the first (oldest) element
void pop_front() {
std::destroy_at(std::addressof(buf_[head_]));
std::memset(std::addressof(buf_[head_]), 0, sizeof(T));
head_ = (head_ - 1) % N;
full_ = false;
__ASSERT_NO_MSG(not empty());
destroy_at(_index.increment_tail());
}
// oldest element
const T &front() const {
assert(!empty());
return *begin();
__ASSERT_NO_MSG(not empty());
return *cbegin();
}
T &front() {
int i = head_ - 1;
if (i == -1) i = N - 1;
__ASSERT_NO_MSG(not empty());
return *begin();
}
const T &back() const {
int i = head_ - 1;
if (i == -1) i = N - 1;
return directy_at(i);
__ASSERT_NO_MSG(not empty());
return *std::prev(cend());
}
T &back() {
int i = head_ - 1;
if (i == -1) i = N - 1;
return directy_at(i);
__ASSERT_NO_MSG(not empty());
return *(std::prev(end()));
}
constexpr void reset() {
head_ = tail_;
full_ = false;
// destroy elements? :|
_index.reset();
}
bool empty() const {
return (!full() && (head_ == tail_));
constexpr bool empty() const {
return _index.empty();
}
bool full() const {
return full_;
constexpr bool full() const {
return _index.full();
}
std::size_t capacity() const {
return N;
constexpr std::size_t capacity() const {
return _index.capacity();
}
std::size_t size() const {
std::size_t size = N;
if (!full()) {
if (head_ >= tail_) {
size = head_ - tail_;
} else {
size = N + head_ - tail_;
}
}
return size;
constexpr std::size_t size() const {
return _index.size();
}
// Iterator class for circular_buffer
class iterator {
constexpr std::size_t free() const {
return _index.free();
}
// Iterator class for ring_buffer
template <bool CONST> class iterator_base {
public:
using iterator_category = std::forward_iterator_tag;
using iterator_category = std::random_access_iterator_tag;
using value_type = T;
using difference_type = std::ptrdiff_t;
using pointer = T *;
using reference = T &;
using pointer = std::conditional_t<CONST, const value_type *, value_type *>;
using reference = std::conditional_t<CONST, const value_type &, value_type &>;
iterator(std::array<std::byte[sizeof(T)], N> &buf, std::size_t index, std::size_t tail, std::size_t head)
: buf_(buf), index_(index), tail_(tail), head_(head), looped_(false) {
using iterator_t = iterator_base<CONST>;
using buf_t = std::conditional_t<CONST, const std::array<std::byte[sizeof(T)], N>, std::array<std::byte[sizeof(T)], N>>;
constexpr iterator_base() = default;
constexpr iterator_base(buf_t &buf, std::size_t index, std::size_t tail, std::size_t head)
: buf_(&buf), current_(index), tail_(tail), head_(head), looped_(false) {
}
reference operator*() {
return *reinterpret_cast<T *>(std::addressof(buf_[index_]));
}
pointer operator->() {
return reinterpret_cast<T *>(std::addressof(buf_[index_]));
}
iterator &operator++() {
index_ = (index_ + 1) % N;
// Detect if we have looped over the circular buffer
if (index_ == tail_ && looped_) {
index_ = head_; // Move iterator to end
}
if (index_ == head_) {
looped_ = true;
}
return *this;
}
iterator operator++(int) {
iterator tmp = *this;
++(*this);
return tmp;
}
iterator operator+(difference_type n) const {
std::size_t new_index = (index_ + n) % N;
return iterator(buf_, new_index, tail_, head_);
}
iterator operator-(difference_type n) const {
std::size_t new_index = (index_ + N - (n % N)) % N;
return iterator(buf_, new_index, tail_, head_);
}
iterator& operator+=(difference_type n) {
index_ = (index_ + n) % N;
return *this;
}
iterator& operator-=(difference_type n) {
index_ = (index_ + N - (n % N)) % N;
return *this;
}
reference operator[](difference_type n) {
std::size_t idx = (index_ + n) % N;
return *reinterpret_cast<T*>(std::addressof(buf_[idx]));
}
bool operator<(const iterator& other) const {
return (*this - other) < 0;
}
bool operator>(const iterator& other) const {
return other < *this;
}
bool operator<=(const iterator& other) const {
return !(*this > other);
}
bool operator>=(const iterator& other) const {
return !(*this < other);
}
bool operator==(const iterator &other) const {
return index_ == other.index_ && looped_;
}
bool operator!=(const iterator &other) const {
return !(*this == other);
}
private:
std::array<std::byte[sizeof(T)], N> &buf_;
std::size_t index_;
const std::size_t tail_;
const std::size_t head_;
bool looped_;
};
class const_iterator {
public:
using iterator_category = std::forward_iterator_tag;
using value_type = T;
using difference_type = std::ptrdiff_t;
using pointer = const T *;
using reference = const T &;
const_iterator(const std::array<std::byte[sizeof(T)], N> &buf, std::size_t index, std::size_t tail, std::size_t head)
: buf_(buf), index_(index), tail_(tail), head_(head), looped_(false) {
}
constexpr iterator_base(const iterator_base &rhs) = default;
constexpr iterator_base(iterator_base &&rhs) = default;
constexpr iterator_base &operator=(const iterator_base &rhs) = default;
constexpr iterator_base &operator=(iterator_base &&rhs) = default;
reference operator*() const {
return *reinterpret_cast<const T *>(std::addressof(buf_[index_]));
return *reinterpret_cast<pointer>(std::addressof((*buf_)[current_]));
}
pointer operator->() const {
return reinterpret_cast<const T *>(std::addressof(buf_[index_]));
return std::addressof(operator*());
}
const_iterator &operator++() {
index_ = (index_ + 1) % N;
constexpr iterator_t &operator++() {
current_ = (current_ + 1) % N;
// Detect if we have looped over the circular buffer
if (index_ == tail_ && looped_) {
index_ = head_; // Move iterator to end
if (current_ == tail_ && looped_) {
current_ = head_; // Move iterator to end
}
if (index_ == head_) {
if (current_ == head_) {
looped_ = true;
}
return *this;
}
const_iterator operator++(int) {
iterator tmp = *this;
constexpr iterator_t operator++(int) {
iterator_t tmp = *this;
++(*this);
return tmp;
}
const_iterator operator+(difference_type n) const {
std::size_t new_index = (index_ + n) % N;
return {buf_, new_index, tail_, head_};
}
const_iterator operator-(difference_type n) const {
std::size_t new_index = (index_ + N - (n % N)) % N;
return {buf_, new_index, tail_, head_};
}
const_iterator& operator+=(difference_type n) {
index_ = (index_ + n) % N;
constexpr iterator_t &operator--() {
if (current_ == 0) current_ = N - 1;
else current_--;
// Detect if we have looped over the circular buffer
if (current_ == head_ && looped_) {
current_ = tail_; // Move iterator to end
}
if (current_ == tail_) {
looped_ = true;
}
return *this;
}
const_iterator& operator-=(difference_type n) {
index_ = (index_ + N - (n % N)) % N;
constexpr iterator_t operator--(int) {
iterator_t tmp = *this;
--(*this);
return tmp;
}
constexpr bool operator==(const iterator_t &other) const {
return current_ == other.current_ && looped_;
}
constexpr iterator_t &operator+=(difference_type n) {
current_ = (current_ + n) % N;
return *this;
}
reference operator[](difference_type n) {
std::size_t idx = (index_ + n) % N;
return *reinterpret_cast<T*>(std::addressof(buf_[idx]));
}
bool operator<(const iterator& other) const {
return (*this - other) < 0;
}
bool operator>(const iterator& other) const {
return other < *this;
}
bool operator<=(const iterator& other) const {
return !(*this > other);
}
bool operator>=(const iterator& other) const {
return !(*this < other);
constexpr iterator_t &operator+=(const iterator_t &n) {
current_ = (current_ + n.current_) % N;
return *this;
}
bool operator==(const const_iterator &other) const {
return index_ == other.index_ && looped_;
constexpr iterator_t operator+(difference_type n) const {
std::size_t new_index = (current_ + n) % N;
return iterator_t(*buf_, new_index, tail_, head_);
}
bool operator!=(const const_iterator &other) const {
return !(*this == other);
constexpr friend iterator_t operator+(iterator_t it, const iterator_t &n) {
it += n;
return it;
}
constexpr friend iterator_t operator+(difference_type it, const iterator_t &n) {
iterator_t tmp = n;
tmp += it;
return tmp;
}
constexpr iterator_t &operator-=(difference_type n) {
current_ = (current_ + N - (n % N)) % N;
return *this;
}
constexpr friend iterator_t operator-(const iterator_t &lhs, difference_type n) {
iterator_t tmp = lhs;
tmp -= n;
return tmp;
}
constexpr friend difference_type operator-(const iterator_t &lhs, const iterator_t &rhs) {
if (lhs.current_ >= rhs.current_) {
return static_cast<difference_type>(lhs.current_ - rhs.current_);
} else {
return static_cast<difference_type>(N + lhs.current_ - rhs.current_);
}
}
constexpr reference operator[](difference_type n) const {
return *(*this + n);
}
// constexpr bool operator<(const iterator_t & other) const {
// return (*this - other) < 0;
// }
// constexpr bool operator>(const iterator_t & other) const {
// return other < *this;
// }
// constexpr bool operator<=(const iterator_t & other) const {
// return !(*this > other);
// }
// constexpr bool operator>=(const iterator_t & other) const {
// return !(*this < other);
// }
// constexpr bool operator!=(const iterator_t & other) const {
// return !(*this == other);
// }
private:
const std::array<std::byte[sizeof(T)], N> &buf_;
std::size_t index_;
const std::size_t tail_;
const std::size_t head_;
bool looped_;
buf_t *buf_{nullptr};
std::size_t current_{0};
std::size_t tail_{0};
std::size_t head_{0};
bool looped_{false};
};
using iterator = iterator_base<false>;
using const_iterator = iterator_base<true>;
static_assert(std::bidirectional_iterator<iterator>);
// static_assert(std::random_access_iterator< iterator >);
static_assert(std::bidirectional_iterator<const_iterator>);
// static_assert(std::random_access_iterator< const_iterator >);
// Begin and end functions to return iterator
iterator begin() {
return iterator(buf_, tail_, tail_, head_);
return {buf_, _index.tail(), _index.tail(), _index.head()};
}
iterator end() {
return iterator(buf_, head_, tail_, head_);
const_iterator begin() const {
return {buf_, _index.tail(), _index.tail(), _index.head()};
}
const_iterator cbegin() const {
return const_iterator(buf_, tail_, tail_, head_);
return {buf_, _index.tail(), _index.tail(), _index.head()};
}
iterator end() {
return {buf_, _index.head(), _index.tail(), _index.head()};
}
const_iterator end() const {
return {buf_, _index.head(), _index.tail(), _index.head()};
}
const_iterator cend() const {
return const_iterator(buf_, head_, tail_, head_);
return {buf_, _index.head(), _index.tail(), _index.head()};
}
private:
void destroy_at(int index) {
std::destroy_at(std::addressof(buf_[index]));
std::memset(std::addressof(buf_[index]), 0, sizeof(T));
}
const T &directy_at(int index) const {
return *reinterpret_cast<const T *>(std::addressof(buf_[index]));
}
@ -369,13 +482,9 @@ template <class T, std::size_t N> class circular_buffer {
return *reinterpret_cast<T *>(std::addressof(buf_[index]));
}
// std::mutex mutex_;
std::array<std::byte[sizeof(T)], N> buf_;
std::size_t head_ = 0;
std::size_t tail_ = 0;
bool full_{false};
RingIndex _index;
};
class ZephyrMutex {
public:
ZephyrMutex() {
@ -402,8 +511,8 @@ class ZephyrMutex {
ZephyrMutex &operator=(const ZephyrMutex &) = delete;
};
template <typename T, size_t N> class thread_safe_circular_buffer : public circular_buffer<T, N> {
using base = circular_buffer<T, N>;
template <typename T, size_t N> class thread_safe_circular_buffer : public ring_buffer<T, N> {
using base = ring_buffer<T, N>;
public:
const T &back() const {
@ -455,9 +564,9 @@ template <typename T, size_t N> class zephyr_fifo_buffer {
try {
if (not el) return false; // should be a assert
fn(el->item); // consume item, fn can throw
_elements.pop_back(); // clear item from queue
_elements.pop_front(); // clear first item from queue
} catch (...) {
_elements.pop_back();
_elements.pop_front();
throw;
}
@ -472,7 +581,7 @@ template <typename T, size_t N> class zephyr_fifo_buffer {
auto tmp = ZephyrFifoElement<T>{};
if (fn(tmp.item)) // fill new data
{
auto &el = _elements.emplace_front(std::move(tmp));
auto &el = _elements.push_back(std::move(tmp));
k_fifo_put(&_fifo, &el); // put data into a queue
}
@ -481,8 +590,8 @@ template <typename T, size_t N> class zephyr_fifo_buffer {
private:
// ZephyrMutex _mutex{};
circular_buffer<ZephyrFifoElement<T>, N> _elements{};
k_fifo &_fifo;
ring_buffer<ZephyrFifoElement<T>, N> _elements{};
k_fifo &_fifo;
};
} // namespace rims

View File

@ -29,7 +29,7 @@ TStack messengerStack{k_messengerStack, K_THREAD_STACK_SIZEOF(k_messengerStack)}
static K_THREAD_STACK_DEFINE(k_uartStack, 2048);
TStack uartStack{k_uartStack, K_THREAD_STACK_SIZEOF(k_uartStack)};
static K_THREAD_STACK_DEFINE(k_temperatureSamplerStack, 4096);
static K_THREAD_STACK_DEFINE(k_temperatureSamplerStack, 2048);
TStack temperatureSamplerStack{k_temperatureSamplerStack, K_THREAD_STACK_SIZEOF(k_temperatureSamplerStack)};
static K_THREAD_STACK_DEFINE(k_zeroCrossDetectionStack, 2048);
@ -105,7 +105,7 @@ int main() {
zephyr::gpio::pin_configure(gprelay_2_en, GPIO_OUTPUT_INACTIVE);
while (1) {
std::this_thread::sleep_for(std::chrono::seconds{5});
std::this_thread::sleep_for(std::chrono::seconds{1});
// zephyr::gpio::pin_toggle_dt(gprelay_2_en);
// const unsigned char data[] = {'b', 0x55};

View File

@ -20,6 +20,8 @@
#include <zephyr/drivers/gpio.h>
#include "zephyr.hpp"
#include "zephyr/device.h"
#include "zephyr/sys/__assert.h"
#define ADC_NODE DT_NODELABEL(adc1)
#define DT_ADC_TEMP_NODELABEL DT_NODELABEL(adc_temp)
@ -94,7 +96,7 @@ template <typename T> void PB_encode_egress(const T &tempresp) {
void TemperatureSampler::take_sample() {
ULOG_DEBUG("Samples on ch %d, size %d", this->_channel, this->_samples.size());
_samples.emplace_front(adc_take_sample());
_samples.push_back(adc_take_sample());
}
TemperatureSampler::TemperatureSampler(uint8_t channel)
@ -424,7 +426,9 @@ void TemperatureSamplerOrchestrator::action_sendTemperature(uint8_t ch) {
int TemperatureSamplerThread::do_hardwarenInit() {
const device *adc = DEVICE_DT_GET(ADC_NODE);
const gpio_dt_spec chsel_pin_dev = GPIO_DT_SPEC_GET(DT_NODELABEL(temp_channel_sel), gpios);
__ASSERT(device_is_ready(adc), "adc needs to work");
zephyr::gpio::pin_configure(chsel_pin_dev, GPIO_OUTPUT_INACTIVE);
if (!device_is_ready(adc)) {
@ -451,12 +455,12 @@ int TemperatureSamplerThread::do_hardwarenInit() {
};
const adc_channel_cfg adc_temp = ADC_CHANNEL_CFG_DT(DT_NODELABEL(adc_temp));
// adc_channel_cfg adc_current_ch1 = ADC_CHANNEL_CFG_DT(DT_NODELABEL(adc_current_ch1));
// adc_channel_cfg adc_current_ch2 = ADC_CHANNEL_CFG_DT(DT_NODELABEL(adc_current_ch2));
adc_channel_cfg adc_current_ch1 = ADC_CHANNEL_CFG_DT(DT_NODELABEL(adc_current_ch1));
adc_channel_cfg adc_current_ch2 = ADC_CHANNEL_CFG_DT(DT_NODELABEL(adc_current_ch2));
auto ret = configurechannel(adc_temp);
// configurechannel(adc_current_ch1);
// configurechannel(adc_current_ch2);
configurechannel(adc_current_ch1);
configurechannel(adc_current_ch2);
zephyr::gpio::pin_configure(rmax_en_gpio_dt, GPIO_OUTPUT_INACTIVE);
zephyr::gpio::pin_configure(rmin_en_gpio_dt, GPIO_OUTPUT_INACTIVE);

View File

@ -70,7 +70,7 @@ class TemperatureSampler {
// zephyr::semaphore::sem _samplerSem{0, 1};
// RecurringSemaphoreTimer _samplerTimer;
circular_buffer<Sample, MaxSampleSize> _samples;
ring_buffer<Sample, MaxSampleSize> _samples;
std::size_t _samplesNumber{MaxSampleSize};
const std::uint8_t _channel{};
@ -109,7 +109,7 @@ class TemperatureSamplerOrchestrator {
class TemperatureSamplerThread : public ZephyrThread {
public:
TemperatureSamplerThread(TStackBase &stack) : ZephyrThread(stack, 15, 0, "TemperatureSampler"){};
TemperatureSamplerThread(TStackBase &stack) : ZephyrThread(stack, 14, 0, "TemperatureSampler"){};
int do_hardwarenInit() override;
void threadMain() override;
};

View File

@ -3,6 +3,10 @@
#include "log.hpp"
#include "messenger.hpp"
#include "syscalls/uart.h"
#include "zephyr/device.h"
#include "zephyr/irq.h"
#include "zephyr/spinlock.h"
#include "zephyr/sys/__assert.h"
#include <chrono>
#include <cstddef>
@ -79,26 +83,27 @@ void AsyncUART::loop() {
}
}
static std::size_t buffer_copy_wait {};
// free function, only need to copy data to uart's TX_BUFFER and that's it
void AsyncUART::transmit(AsyncUART *dev, std::span<std::uint8_t> bytes) {
if (bytes.empty()) return;
__ASSERT(bytes.size_bytes() <= dev->tx_buffer.capacity(), "for now, all bytes needs to fir in tx buffer");
bool first = true;
for (auto byte : bytes) {
if (first) {
if (dev->tx_buffer.empty()) {
dev->tx_buffer.emplace_front(byte);
uart_irq_tx_enable(dev->_dev); // enable interrupt
continue;
}
first = false;
}
while (dev->tx_buffer.full()) {
std::this_thread::sleep_for(std::chrono::microseconds{12});
};
dev->tx_buffer.emplace_front(byte);
while (dev->tx_buffer.free() < bytes.size_bytes()) {
buffer_copy_wait++;
std::this_thread::sleep_for(std::chrono::microseconds{20});
}
k_spinlock_key_t key = k_spin_lock(&dev->tx_lock);
__ASSERT(dev->no_copyInProgress(), "multiple copies at the same time are not allowed");
// copy all data to TX
dev->tx_buffer.put_n(bytes.data(), bytes.size());
// if disabled, enable tx interrupts
if (not dev->tx_irq_enabled()) dev->tx_irq_enable();
k_spin_unlock(&dev->tx_lock, key);
}
void AsyncUART::uartCallback(const device *dev, void *user_data) {
@ -107,13 +112,14 @@ void AsyncUART::uartCallback(const device *dev, void *user_data) {
}
void AsyncUART::uartISR() {
__ASSERT(device_is_ready(_dev), "device needs to work");
try {
while (uart_irq_update(_dev) && uart_irq_is_pending(_dev)) {
if (rxHasByte()) {
if (uart_irq_rx_ready(_dev)) {
readByteUart();
}
if (uart_irq_tx_ready(_dev)) {
putByteUart();
writeByteUart();
}
}
@ -128,21 +134,21 @@ void AsyncUART::uartISR() {
}
}
bool AsyncUART::rxHasByte() const {
return uart_irq_rx_ready(_dev);
}
void AsyncUART::readByteUart() {
if (faultFlag) {
if (rxByte() == 0) faultFlag = false;
if (_faultFlag) {
if (rxByte() == 0) _faultFlag = false;
}
// throw on buffer overflow
else if (tx_buffer.full()) {
else if (rxBuffer().full()) {
throw uart_rx_buffer_overflow{};
}
// push_back returns last placed byte, if the byte is 0x00 we got end of frame
else if (rxBuffer().push_back(rxByte()) == 0) {
processMessage();
if(rxBuffer().size()>1){
processMessage();
}else{
rxBuffer().clean();
}
}
}
@ -175,24 +181,20 @@ void AsyncUART::switchRxBuffer() {
}
bool AsyncUART::txHasByte() const {
return tx_buffer.size();
return not tx_buffer.empty();
}
bool AsyncUART::txByte(uint8_t byte) {
auto send_len = uart_fifo_fill(_dev, &byte, 1);
if (send_len != 1) {
// LOG_ERR("Drop %d bytes", rb_len - send_len);
while (1) {
/// just loop here
}
void AsyncUART::txByte(uint8_t byte) {
[[maybe_unused]] auto send_len = uart_fifo_fill(_dev, &byte, 1);
__ASSERT(send_len == 1, "fifo fill has to work as expected");
}
void AsyncUART::writeByteUart() {
if (txHasByte()) {
txByte(tx_buffer.get());
} else {
tx_irq_disable();
}
return false;
}
void AsyncUART::putByteUart() {
bool hasData = txHasByte();
if (hasData) txByte(tx_buffer.get());
else uart_irq_tx_disable(_dev);
}
void AsyncUART::handleRxBufferOverflowError(const uart_rx_buffer_overflow &e) {
@ -205,7 +207,7 @@ void AsyncUART::handleRxBufferOverflowError(const uart_rx_buffer_overflow &e) {
rxBuffer().clean();
// indicate the driver to skip bytes until end of frame
faultFlag = true;
_faultFlag = true;
}
void AsyncUART::handleRxNotReadyError(const uart_rx_not_ready_error &e) {

View File

@ -19,27 +19,55 @@ class uart_rx_not_ready_error;
class AsyncUART {
using rx_buffer_t = static_vector<uint8_t, 256>;
using tx_buffer_t = circular_buffer<uint8_t, 256>;
using tx_buffer_t = ring_buffer<uint8_t, 256>;
public:
AsyncUART();
void loop();
static void transmit(AsyncUART *dev, std::span<uint8_t> bytes);
static void workHandler(k_work *work);
static void uartCallback(const struct device *dev, void *user_data);
void uartISR();
const device *_dev;
void uartISR();
bool tx_irq_enabled() const {
return _txIrqEnabled;
}
void tx_irq_enable() {
_txIrqEnabled = true;
uart_irq_tx_enable(_dev);
}
void tx_irq_disable() {
_txIrqEnabled = false;
uart_irq_tx_disable(_dev);
}
void beginCopy() {
_copyInProgress = true;
}
void endCopy() {
_copyInProgress = false;
}
constexpr bool copyInProgress() const {
return _copyInProgress;
}
constexpr bool no_copyInProgress() const {
return not _copyInProgress;
}
const device *_dev;
private:
std::array<rx_buffer_t, 2> rx_buffers;
uint8_t _currentBufferIndex{};
bool faultFlag = false;
tx_buffer_t tx_buffer;
bool _faultFlag = false;
bool _copyInProgress = false;
bool _txIrqEnabled = false;
k_spinlock tx_lock;
tx_buffer_t tx_buffer;
// ISR RX part
inline bool rxHasByte() const;
inline void readByteUart(); // process byte
inline uint8_t rxByte(); // low level read byte from device
inline void processMessage();
@ -47,9 +75,9 @@ class AsyncUART {
inline void switchRxBuffer();
// ISR TX part
inline void putByteUart();
inline void writeByteUart();
inline bool txHasByte() const;
inline bool txByte(uint8_t byte); // low level write byte to device
inline void txByte(uint8_t byte); // low level write byte to device
// exception handlers
inline void handleRxNotReadyError(const uart_rx_not_ready_error &e);