roo_transport
API Documentation for roo_transport
Loading...
Searching...
No Matches
reliable_serial.h
Go to the documentation of this file.
1#pragma once
2
3#if (defined ARDUINO)
4#if (defined ESP32 || defined ROO_TESTING)
5
6#include "Arduino.h"
7#include "hal/uart_types.h"
8#include "roo_io/uart/arduino/serial_input_stream.h"
9#include "roo_io/uart/arduino/serial_output_stream.h"
10#include "roo_io/uart/esp32/uart_input_stream.h"
11#include "roo_io/uart/esp32/uart_output_stream.h"
12#include "roo_threads.h"
13#include "roo_threads/thread.h"
19
20namespace roo_transport {
21namespace esp32 {
22
23template <typename SerialType>
24class Esp32SerialLinkTransportBase {
25 public:
26 Esp32SerialLinkTransportBase(SerialType& serial, uart_port_t ignored)
27 : serial_(serial), output_(serial_), input_(serial_) {}
28
29 protected:
30 SerialType& serial_;
31 roo_io::ArduinoSerialOutputStream output_;
32 roo_io::ArduinoSerialInputStream input_;
33};
34
35// Specialization for HardwareSerial that uses more efficient UART streams
36// (directly using esp-idf UART driver).
37template <>
38class Esp32SerialLinkTransportBase<HardwareSerial> {
39 public:
40 Esp32SerialLinkTransportBase(HardwareSerial& serial, uart_port_t port)
41 : serial_(serial), output_(port), input_(port) {}
42
43 protected:
44 HardwareSerial& serial_;
45 roo_io::Esp32UartOutputStream output_;
46 roo_io::Esp32UartInputStream input_;
47};
48
49// Similar to LinkStreamTransport, but specialized for Serial types on ESP32.
50// The user still needs to initialize the underlying serial (by calling
51// begin()), but there is no need to call receive() or tryReceive() to process
52// incoming packets; this class takes care of that by registering the receive
53// handlers.
54template <typename SerialType>
55class Esp32SerialLinkTransport
56 : public Esp32SerialLinkTransportBase<SerialType> {
57 public:
58 Esp32SerialLinkTransport(SerialType& serial, uart_port_t port,
59 roo::string_view name,
60 LinkBufferSize sendbuf = kBufferSize4KB,
61 LinkBufferSize recvbuf = kBufferSize4KB)
62 : Esp32SerialLinkTransportBase<SerialType>(serial, port),
63 sender_(this->output_),
64 receiver_(this->input_),
65 transport_(sender_, name, sendbuf, recvbuf),
66 process_fn_([this](const roo::byte* buf, size_t len) {
67 transport_.processIncomingPacket(buf, len);
68 }) {}
69
70 void begin() {
71 transport_.begin();
72 this->serial_.onReceive([this]() { receiver_.tryReceive(process_fn_); });
73 this->serial_.onReceiveError(
74 [this](hardwareSerial_error_t) { receiver_.tryReceive(process_fn_); });
75 }
76
77 void end() {
78 this->serial_.onReceive(nullptr);
79 this->serial_.onReceiveError(nullptr);
80 transport_.end();
81 }
82
83 // Establishes a new connection and returns the Link object representing it.
84 LinkStream connect(std::function<void()> disconnect_fn = nullptr) {
85 LinkStream link = connectAsync(std::move(disconnect_fn));
86 link.awaitConnected();
87 return LinkStream(std::move(link));
88 }
89
90 // Establishes a new connection asynchronously and returns the Link object
91 // representing it. Until the connection is established, the link will be in
92 // the "connecting" state.
93 LinkStream connectAsync(std::function<void()> disconnect_fn = nullptr) {
94 return LinkStream(transport_.connect(std::move(disconnect_fn)));
95 }
96
97 // Establishes a new connection and returns the Link object representing it.
98 // If the peer attempts reconnection (e.g. after a reset), the program
99 // will terminate (usually to reconnect after reboot).
100 LinkStream connectOrDie() {
101 return connect(
102 []() { LOG(FATAL) << "LinkTransport: peer reset; rebooting"; });
103 }
104
105 LinkTransport& transport() { return transport_; }
106
107 // Allow implicit conversion to LinkTransport&, so that this Arduino wrapper
108 // can be used seamlessly in place of LinkTransport when a reference to the
109 // latter is needed (e.g., when constructing LinkMessaging).
110 operator LinkTransport&() { return transport_; }
111
112 LinkTransport::StatsMonitor statsMonitor() {
113 return LinkTransport::StatsMonitor(transport_);
114 }
115
116 private:
117 PacketSenderOverStream sender_;
118 PacketReceiverOverStream receiver_;
119
120 LinkTransport transport_;
121
122 std::function<void(const roo::byte* buf, size_t len)> process_fn_;
123};
124
125// NOTE: these clases rely on the event task created by the Arduino core. By
126// default, that task gets created with a very low stack size of just 2048
127// bytes. In practice, it might be insufficient, especially if you enable any
128// connection logging. Therefore, it is recommended to increase the stack size
129// by adding the following line to your platformio.ini or Arduino build flags:
130//
131// -D ARDUINO_SERIAL_EVENT_TASK_STACK_SIZE=3072
132
133#if defined(ROO_TESTING)
134#define UART_NUM_0 0
135#define UART_NUM_1 1
136#define UART_NUM_2 2
137#endif
138
139class ReliableSerial : public Esp32SerialLinkTransport<decltype(Serial)> {
140 public:
141 ReliableSerial(LinkBufferSize sendbuf = kBufferSize4KB,
142 LinkBufferSize recvbuf = kBufferSize4KB)
143 : ReliableSerial("serial", sendbuf, recvbuf) {}
144
145 ReliableSerial(roo::string_view name, LinkBufferSize sendbuf = kBufferSize4KB,
146 LinkBufferSize recvbuf = kBufferSize4KB)
147 : Esp32SerialLinkTransport<decltype(Serial)>(Serial, UART_NUM_0, name,
148 sendbuf, recvbuf) {}
149};
150
151#if SOC_UART_NUM > 1
152class ReliableSerial1 : public Esp32SerialLinkTransport<decltype(Serial1)> {
153 public:
154 ReliableSerial1(LinkBufferSize sendbuf = kBufferSize4KB,
155 LinkBufferSize recvbuf = kBufferSize4KB)
156 : ReliableSerial1("serial1", sendbuf, recvbuf) {}
157
158 ReliableSerial1(roo::string_view name,
159 LinkBufferSize sendbuf = kBufferSize4KB,
160 LinkBufferSize recvbuf = kBufferSize4KB)
161 : Esp32SerialLinkTransport<decltype(Serial1)>(Serial1, UART_NUM_1, name,
162 sendbuf, recvbuf) {}
163};
164#endif // SOC_UART_NUM > 1
165#if SOC_UART_NUM > 2
166class ReliableSerial2 : public Esp32SerialLinkTransport<decltype(Serial2)> {
167 public:
168 ReliableSerial2(LinkBufferSize sendbuf = kBufferSize4KB,
169 LinkBufferSize recvbuf = kBufferSize4KB)
170 : ReliableSerial2("serial2", sendbuf, recvbuf) {}
171
172 ReliableSerial2(roo::string_view name,
173 LinkBufferSize sendbuf = kBufferSize4KB,
174 LinkBufferSize recvbuf = kBufferSize4KB)
175 : Esp32SerialLinkTransport<decltype(Serial2)>(Serial2, UART_NUM_2, name,
176 sendbuf, recvbuf) {}
177};
178#endif // SOC_UART_NUM > 2
179
180} // namespace esp32
181} // namespace roo_transport
182
183#endif // defined(ESP32 || defined ROO_TESTING)
184
185#endif // defined(ARDUINO)