blob: c324a2dd723c7aff2ff1bc0a27588d91b2bd1f17 [file] [log] [blame]
Brian Silverman55c62022018-09-03 19:13:44 -07001#ifndef MOTORS_PERIPHERAL_UART_BUFFER_H_
2#define MOTORS_PERIPHERAL_UART_BUFFER_H_
3
4#include <array>
Austin Schuh7fe04492022-01-02 13:37:21 -08005#include <cstring>
Brian Silverman55c62022018-09-03 19:13:44 -07006
Austin Schuh7fe04492022-01-02 13:37:21 -08007#include "absl/types/span.h"
Brian Silverman55c62022018-09-03 19:13:44 -07008
9namespace frc971 {
10namespace teensy {
11
12// Manages a circular buffer of data to send out.
13template<int kSize>
14class UartBuffer {
15 public:
16 // Returns the number of characters added.
Austin Schuh7fe04492022-01-02 13:37:21 -080017 __attribute__((warn_unused_result)) int PushSpan(absl::Span<const char> data);
Brian Silverman55c62022018-09-03 19:13:44 -070018
Brian Silverman333fc9e2019-02-24 15:09:17 -080019 // max is the maximum size the returned span should be.
Brian Silverman4f958792019-02-16 18:20:04 -080020 // The data in the result is only valid until another method is called.
21 // Note that this may not return all available data when doing so would
22 // require wrapping around, but it will always return a non-empty span if any
23 // data is available.
Austin Schuh7fe04492022-01-02 13:37:21 -080024 absl::Span<const char> PopSpan(int max);
Brian Silverman4f958792019-02-16 18:20:04 -080025
Brian Silverman55c62022018-09-03 19:13:44 -070026 bool empty() const { return size_ == 0; }
Brian Silverman4f958792019-02-16 18:20:04 -080027 bool full() const { return size_ == kSize; }
Brian Silverman55c62022018-09-03 19:13:44 -070028
Brian Silverman333fc9e2019-02-24 15:09:17 -080029 void clear() { size_ = 0; }
30
Brian Silverman55c62022018-09-03 19:13:44 -070031 // This may only be called when !empty().
32 char PopSingle();
Brian Silverman4f958792019-02-16 18:20:04 -080033 // This may only be called when !full().
34 void PushSingle(char c);
Brian Silverman55c62022018-09-03 19:13:44 -070035
36 static constexpr int size() { return kSize; }
37
38 private:
Brian Silverman4f958792019-02-16 18:20:04 -080039 // The index at which we will pop the next character.
Brian Silverman55c62022018-09-03 19:13:44 -070040 int start_ = 0;
41 // How many characters we currently have.
42 int size_ = 0;
43
44 ::std::array<char, kSize> data_;
45};
46
Brian Silverman4f958792019-02-16 18:20:04 -080047template <int kSize>
Austin Schuh7fe04492022-01-02 13:37:21 -080048int UartBuffer<kSize>::PushSpan(absl::Span<const char> data) {
Brian Silverman55c62022018-09-03 19:13:44 -070049 const int end_location = (start_ + size_) % kSize;
50 const int remaining_end = ::std::min(kSize - size_, kSize - end_location);
51 const int on_end = ::std::min<int>(data.size(), remaining_end);
52 if (on_end > 0) {
53 memcpy(&data_[end_location], data.data(), on_end);
54 }
55 size_ += on_end;
56 const int not_on_end = data.size() - on_end;
57 if (not_on_end == 0) {
58 return data.size();
59 }
60
61 const int remaining_start = ::std::min(kSize - size_, start_);
62 const int on_start = ::std::min(not_on_end, remaining_start);
63 memcpy(data_.data(), &data[on_end], on_start);
64 size_ += on_start;
65 return on_end + on_start;
66}
67
Brian Silverman4f958792019-02-16 18:20:04 -080068template <int kSize>
Austin Schuh7fe04492022-01-02 13:37:21 -080069absl::Span<const char> UartBuffer<kSize>::PopSpan(int max) {
Brian Silverman4f958792019-02-16 18:20:04 -080070 const size_t result_size = std::min(max, std::min(kSize - start_, size_));
Austin Schuh7fe04492022-01-02 13:37:21 -080071 const auto result =
72 absl::Span<const char>(data_).subspan(start_, result_size);
Brian Silverman4f958792019-02-16 18:20:04 -080073 start_ = (start_ + result_size) % kSize;
74 size_ -= result_size;
75 return result;
76}
77
78template <int kSize>
Brian Silverman55c62022018-09-03 19:13:44 -070079char UartBuffer<kSize>::PopSingle() {
80 const char r = data_[start_];
81 --size_;
82 start_ = (start_ + 1) % kSize;
83 return r;
84}
85
Brian Silverman4f958792019-02-16 18:20:04 -080086template <int kSize>
87void UartBuffer<kSize>::PushSingle(char c) {
88 const int end_location = (start_ + size_) % kSize;
89 data_[end_location] = c;
90 ++size_;
91}
92
Brian Silverman55c62022018-09-03 19:13:44 -070093} // namespace teensy
94} // namespace frc971
95
96#endif // MOTORS_PERIPHERAL_UART_BUFFER_H_