blob: 63dd70d85a06592fa972e5f5c7af0fd7b3744953 [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>
5
6#include "third_party/GSL/include/gsl/gsl"
7
8namespace frc971 {
9namespace teensy {
10
11// Manages a circular buffer of data to send out.
12template<int kSize>
13class UartBuffer {
14 public:
15 // Returns the number of characters added.
Brian Silverman4787a6e2018-10-06 16:00:54 -070016 __attribute__((warn_unused_result)) int PushSpan(gsl::span<const char> data);
Brian Silverman55c62022018-09-03 19:13:44 -070017
18 bool empty() const { return size_ == 0; }
19
20 // This may only be called when !empty().
21 char PopSingle();
22
23 static constexpr int size() { return kSize; }
24
25 private:
26 // The index at which we will push the next character.
27 int start_ = 0;
28 // How many characters we currently have.
29 int size_ = 0;
30
31 ::std::array<char, kSize> data_;
32};
33
34template<int kSize>
Brian Silverman4787a6e2018-10-06 16:00:54 -070035int UartBuffer<kSize>::PushSpan(gsl::span<const char> data) {
Brian Silverman55c62022018-09-03 19:13:44 -070036 const int end_location = (start_ + size_) % kSize;
37 const int remaining_end = ::std::min(kSize - size_, kSize - end_location);
38 const int on_end = ::std::min<int>(data.size(), remaining_end);
39 if (on_end > 0) {
40 memcpy(&data_[end_location], data.data(), on_end);
41 }
42 size_ += on_end;
43 const int not_on_end = data.size() - on_end;
44 if (not_on_end == 0) {
45 return data.size();
46 }
47
48 const int remaining_start = ::std::min(kSize - size_, start_);
49 const int on_start = ::std::min(not_on_end, remaining_start);
50 memcpy(data_.data(), &data[on_end], on_start);
51 size_ += on_start;
52 return on_end + on_start;
53}
54
55template<int kSize>
56char UartBuffer<kSize>::PopSingle() {
57 const char r = data_[start_];
58 --size_;
59 start_ = (start_ + 1) % kSize;
60 return r;
61}
62
63} // namespace teensy
64} // namespace frc971
65
66#endif // MOTORS_PERIPHERAL_UART_BUFFER_H_