blob: 714cfe8b85d3b34008705ab8d1e499a167b2a536 [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
Stephan Pleinesd99b1ee2024-02-02 20:56:44 -08009namespace frc971::teensy {
Brian Silverman55c62022018-09-03 19:13:44 -070010
11// Manages a circular buffer of data to send out.
Philipp Schrader790cb542023-07-05 21:06:52 -070012template <int kSize>
Brian Silverman55c62022018-09-03 19:13:44 -070013class UartBuffer {
14 public:
15 // Returns the number of characters added.
Austin Schuh7fe04492022-01-02 13:37:21 -080016 __attribute__((warn_unused_result)) int PushSpan(absl::Span<const char> data);
Brian Silverman55c62022018-09-03 19:13:44 -070017
Brian Silverman333fc9e2019-02-24 15:09:17 -080018 // max is the maximum size the returned span should be.
Brian Silverman4f958792019-02-16 18:20:04 -080019 // The data in the result is only valid until another method is called.
20 // Note that this may not return all available data when doing so would
21 // require wrapping around, but it will always return a non-empty span if any
22 // data is available.
Austin Schuh7fe04492022-01-02 13:37:21 -080023 absl::Span<const char> PopSpan(int max);
Brian Silverman4f958792019-02-16 18:20:04 -080024
Brian Silverman55c62022018-09-03 19:13:44 -070025 bool empty() const { return size_ == 0; }
Brian Silverman4f958792019-02-16 18:20:04 -080026 bool full() const { return size_ == kSize; }
Brian Silverman55c62022018-09-03 19:13:44 -070027
Brian Silverman333fc9e2019-02-24 15:09:17 -080028 void clear() { size_ = 0; }
29
Brian Silverman55c62022018-09-03 19:13:44 -070030 // This may only be called when !empty().
31 char PopSingle();
Brian Silverman4f958792019-02-16 18:20:04 -080032 // This may only be called when !full().
33 void PushSingle(char c);
Brian Silverman55c62022018-09-03 19:13:44 -070034
35 static constexpr int size() { return kSize; }
36
37 private:
Brian Silverman4f958792019-02-16 18:20:04 -080038 // The index at which we will pop the next character.
Brian Silverman55c62022018-09-03 19:13:44 -070039 int start_ = 0;
40 // How many characters we currently have.
41 int size_ = 0;
42
43 ::std::array<char, kSize> data_;
44};
45
Brian Silverman4f958792019-02-16 18:20:04 -080046template <int kSize>
Austin Schuh7fe04492022-01-02 13:37:21 -080047int UartBuffer<kSize>::PushSpan(absl::Span<const char> data) {
Brian Silverman55c62022018-09-03 19:13:44 -070048 const int end_location = (start_ + size_) % kSize;
49 const int remaining_end = ::std::min(kSize - size_, kSize - end_location);
50 const int on_end = ::std::min<int>(data.size(), remaining_end);
51 if (on_end > 0) {
52 memcpy(&data_[end_location], data.data(), on_end);
53 }
54 size_ += on_end;
55 const int not_on_end = data.size() - on_end;
56 if (not_on_end == 0) {
57 return data.size();
58 }
59
60 const int remaining_start = ::std::min(kSize - size_, start_);
61 const int on_start = ::std::min(not_on_end, remaining_start);
62 memcpy(data_.data(), &data[on_end], on_start);
63 size_ += on_start;
64 return on_end + on_start;
65}
66
Brian Silverman4f958792019-02-16 18:20:04 -080067template <int kSize>
Austin Schuh7fe04492022-01-02 13:37:21 -080068absl::Span<const char> UartBuffer<kSize>::PopSpan(int max) {
Brian Silverman4f958792019-02-16 18:20:04 -080069 const size_t result_size = std::min(max, std::min(kSize - start_, size_));
Austin Schuh7fe04492022-01-02 13:37:21 -080070 const auto result =
71 absl::Span<const char>(data_).subspan(start_, result_size);
Brian Silverman4f958792019-02-16 18:20:04 -080072 start_ = (start_ + result_size) % kSize;
73 size_ -= result_size;
74 return result;
75}
76
77template <int kSize>
Brian Silverman55c62022018-09-03 19:13:44 -070078char UartBuffer<kSize>::PopSingle() {
79 const char r = data_[start_];
80 --size_;
81 start_ = (start_ + 1) % kSize;
82 return r;
83}
84
Brian Silverman4f958792019-02-16 18:20:04 -080085template <int kSize>
86void UartBuffer<kSize>::PushSingle(char c) {
87 const int end_location = (start_ + size_) % kSize;
88 data_[end_location] = c;
89 ++size_;
90}
91
Stephan Pleinesd99b1ee2024-02-02 20:56:44 -080092} // namespace frc971::teensy
Brian Silverman55c62022018-09-03 19:13:44 -070093
94#endif // MOTORS_PERIPHERAL_UART_BUFFER_H_