blob: d51bcfec88aaada62976868d21e8edc2e53530eb [file] [log] [blame]
Brian Silverman55c62022018-09-03 19:13:44 -07001#ifndef MOTORS_PERIPHERAL_UART_H_
2#define MOTORS_PERIPHERAL_UART_H_
3
Austin Schuh7fe04492022-01-02 13:37:21 -08004#include "absl/types/span.h"
Brian Silverman4f958792019-02-16 18:20:04 -08005#include "aos/containers/sized_array.h"
Brian Silverman55c62022018-09-03 19:13:44 -07006#include "motors/core/kinetis.h"
7#include "motors/peripheral/uart_buffer.h"
8#include "motors/util.h"
Brian Silverman55c62022018-09-03 19:13:44 -07009
10namespace frc971 {
11namespace teensy {
12
13// Simple synchronous interface to a UART.
14class Uart {
15 public:
16 Uart(KINETISK_UART_t *module, int module_clock_frequency)
17 : module_(module), module_clock_frequency_(module_clock_frequency) {}
18 Uart(const Uart &) = delete;
19 ~Uart();
20 Uart &operator=(const Uart &) = delete;
21
22 void Initialize(int baud_rate);
23
24 // Blocks until all of the data is at least queued.
Austin Schuh7fe04492022-01-02 13:37:21 -080025 void Write(absl::Span<const char> data, const DisableInterrupts &) {
Brian Silverman4787a6e2018-10-06 16:00:54 -070026 DoWrite(data);
27 }
Brian Silverman55c62022018-09-03 19:13:44 -070028
Brian Silverman4f958792019-02-16 18:20:04 -080029 // Returns all the data which is currently available.
30 aos::SizedArray<char, 4> Read(const DisableInterrupts &) {
31 return DoRead();
32 }
33
Brian Silverman55c62022018-09-03 19:13:44 -070034 bool SpaceAvailable() const { return module_->S1 & M_UART_TDRE; }
35 // Only call this if SpaceAvailable() has just returned true.
36 void WriteCharacter(char c) { module_->D = c; }
37
Brian Silverman4f958792019-02-16 18:20:04 -080038 bool DataAvailable() const { return module_->S1 & M_UART_RDRF; }
39 // Only call this if DataAvailable() has just returned true.
40 char ReadCharacter() { return module_->D; }
41
42 // TODO(Brian): These APIs for enabling/disabling interrupts aren't quite
43 // right. Redo them some time. Some issues:
44 // * They get called during initialization/destruction time, which means
45 // interrupts don't really need to be disabled because everything is
46 // singlethreaded.
47 // * Often, several C2 modifications are made in a single
48 // interrupts-disabled section. These could be batched to reduce
49 // peripheral writes. Sometimes, no modifications are made at all, in
50 // which case there doesn't even need to be a single write.
51
52 void EnableTransmitInterrupt(const DisableInterrupts &) {
Brian Silverman55c62022018-09-03 19:13:44 -070053 c2_value_ |= M_UART_TIE;
54 module_->C2 = c2_value_;
55 }
56
Brian Silverman4f958792019-02-16 18:20:04 -080057 void DisableTransmitInterrupt(const DisableInterrupts &) {
58 DoDisableTransmitInterrupt();
59 }
60
61 void EnableReceiveInterrupt(const DisableInterrupts &) {
62 c2_value_ |= M_UART_RIE;
Brian Silverman55c62022018-09-03 19:13:44 -070063 module_->C2 = c2_value_;
64 }
65
Brian Silverman4f958792019-02-16 18:20:04 -080066 void DisableReceiveInterrupt(const DisableInterrupts &) {
67 DoDisableReceiveInterrupt();
68 }
69
Brian Silverman55c62022018-09-03 19:13:44 -070070 private:
Brian Silverman4f958792019-02-16 18:20:04 -080071 void DoDisableTransmitInterrupt() {
72 c2_value_ &= ~M_UART_TIE;
73 module_->C2 = c2_value_;
74 }
75 void DoDisableReceiveInterrupt() {
76 c2_value_ &= ~M_UART_RIE;
77 module_->C2 = c2_value_;
78 }
79
Austin Schuh7fe04492022-01-02 13:37:21 -080080 void DoWrite(absl::Span<const char> data);
Brian Silverman4f958792019-02-16 18:20:04 -080081 aos::SizedArray<char, 4> DoRead();
Brian Silverman55c62022018-09-03 19:13:44 -070082
83 KINETISK_UART_t *const module_;
84 const int module_clock_frequency_;
85 // What we put in C2 except TE.
86 uint8_t c2_value_;
87
88 int tx_fifo_size_, rx_fifo_size_;
89};
90
91// Interrupt-based buffered interface to a UART.
Brian Silverman4f958792019-02-16 18:20:04 -080092// TODO(Brian): Move DisableInterrupts calls up to the caller of this.
Brian Silverman55c62022018-09-03 19:13:44 -070093class InterruptBufferedUart {
94 public:
95 InterruptBufferedUart(KINETISK_UART_t *module, int module_clock_frequency)
96 : uart_(module, module_clock_frequency) {}
Brian Silverman4f958792019-02-16 18:20:04 -080097 ~InterruptBufferedUart();
Brian Silverman55c62022018-09-03 19:13:44 -070098
99 void Initialize(int baud_rate);
100
Brian Silverman4f958792019-02-16 18:20:04 -0800101 // Queues up the given data for immediate writing. Blocks only if the queue
102 // fills up before all of data is enqueued.
Austin Schuh7fe04492022-01-02 13:37:21 -0800103 void Write(absl::Span<const char> data);
Brian Silverman55c62022018-09-03 19:13:44 -0700104
Brian Silverman4f958792019-02-16 18:20:04 -0800105 // Reads currently available data.
106 // Returns all the data which is currently available (possibly none);
107 // buffer is where to store the result. The return value will be a subspan of
108 // this.
Austin Schuh7fe04492022-01-02 13:37:21 -0800109 absl::Span<char> Read(absl::Span<char> buffer);
Brian Silverman4f958792019-02-16 18:20:04 -0800110
Brian Silverman55c62022018-09-03 19:13:44 -0700111 // Should be called as the body of the interrupt handler.
112 void HandleInterrupt(const DisableInterrupts &disable_interrupts) {
113 WriteCharacters(true, disable_interrupts);
Brian Silverman4f958792019-02-16 18:20:04 -0800114 ReadCharacters(disable_interrupts);
Brian Silverman55c62022018-09-03 19:13:44 -0700115 }
116
117 private:
118 void WriteCharacters(bool disable_empty, const DisableInterrupts &);
Brian Silverman4f958792019-02-16 18:20:04 -0800119 void ReadCharacters(const DisableInterrupts &);
Brian Silverman55c62022018-09-03 19:13:44 -0700120
121 Uart uart_;
Brian Silverman4f958792019-02-16 18:20:04 -0800122 UartBuffer<1024> transmit_buffer_, receive_buffer_;
Brian Silverman55c62022018-09-03 19:13:44 -0700123};
124
125} // namespace teensy
126} // namespace frc971
127
128#endif // MOTORS_PERIPHERAL_UART_H_