pw_rpc: Fix RPC MTU allocations
Fixes RPC server channel definitions to properly allocate necessary MTU
overhead for RPC/HDLC encoding.
Change-Id: I121216ca429879f2ce65c965a48760a7d107ae65
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/101780
Pigweed-Auto-Submit: Armando Montanez <amontanez@google.com>
Reviewed-by: Wyatt Hepler <hepler@google.com>
Commit-Queue: Auto-Submit <auto-submit@pigweed.google.com.iam.gserviceaccount.com>
diff --git a/pw_rpc/integration_testing.cc b/pw_rpc/integration_testing.cc
index 576e445..d0b18fa 100644
--- a/pw_rpc/integration_testing.cc
+++ b/pw_rpc/integration_testing.cc
@@ -24,7 +24,9 @@
namespace pw::rpc::integration_test {
namespace {
-SocketClientContext<512> context;
+// Hard-coded to 1055 bytes, which is enough to fit 512-byte payloads when using
+// HDLC framing.
+SocketClientContext<1055> context;
unit_test::LoggingEventHandler log_test_events;
} // namespace
diff --git a/pw_rpc/public/pw_rpc/integration_test_socket_client.h b/pw_rpc/public/pw_rpc/integration_test_socket_client.h
index c571f0e..2d4ba0d 100644
--- a/pw_rpc/public/pw_rpc/integration_test_socket_client.h
+++ b/pw_rpc/public/pw_rpc/integration_test_socket_client.h
@@ -18,6 +18,7 @@
#include <optional>
#include <thread>
+#include "pw_hdlc/encoded_size.h"
#include "pw_hdlc/rpc_channel.h"
#include "pw_hdlc/rpc_packets.h"
#include "pw_rpc/integration_testing.h"
@@ -125,7 +126,7 @@
std::atomic_flag should_terminate_ = ATOMIC_FLAG_INIT;
std::optional<std::thread> rpc_dispatch_thread_handle_;
stream::SocketStream stream_;
- hdlc::RpcChannelOutput channel_output_;
+ hdlc::FixedMtuChannelOutput<kMaxTransmissionUnit> channel_output_;
ChannelOutputWithManipulator channel_output_with_manipulator_;
ChannelManipulator* ingress_channel_manipulator_;
Channel channel_;
@@ -134,7 +135,9 @@
template <size_t kMaxTransmissionUnit>
void SocketClientContext<kMaxTransmissionUnit>::ProcessPackets() {
- std::byte decode_buffer[kMaxTransmissionUnit];
+ constexpr size_t kDecoderBufferSize =
+ hdlc::Decoder::RequiredBufferSizeForFrameSize(kMaxTransmissionUnit);
+ std::array<std::byte, kDecoderBufferSize> decode_buffer;
hdlc::Decoder decoder(decode_buffer);
while (true) {
diff --git a/pw_system/hdlc_rpc_server.cc b/pw_system/hdlc_rpc_server.cc
index fe45826..dc8ab2f 100644
--- a/pw_system/hdlc_rpc_server.cc
+++ b/pw_system/hdlc_rpc_server.cc
@@ -18,6 +18,7 @@
#include <cstdio>
#include "pw_assert/check.h"
+#include "pw_hdlc/encoded_size.h"
#include "pw_hdlc/rpc_channel.h"
#include "pw_hdlc/rpc_packets.h"
#include "pw_log/log.h"
@@ -31,15 +32,19 @@
constexpr size_t kMaxTransmissionUnit = PW_SYSTEM_MAX_TRANSMISSION_UNIT;
-hdlc::RpcChannelOutput hdlc_channel_output(GetWriter(),
- PW_SYSTEM_DEFAULT_RPC_HDLC_ADDRESS,
- "HDLC channel");
+static_assert(kMaxTransmissionUnit ==
+ hdlc::MaxEncodedFrameSize(rpc::cfg::kEncodingBufferSizeBytes));
+
+hdlc::FixedMtuChannelOutput<kMaxTransmissionUnit> hdlc_channel_output(
+ GetWriter(), PW_SYSTEM_DEFAULT_RPC_HDLC_ADDRESS, "HDLC channel");
rpc::Channel channels[] = {
rpc::Channel::Create<kDefaultRpcChannelId>(&hdlc_channel_output)};
rpc::Server server(channels);
+constexpr size_t kDecoderBufferSize =
+ hdlc::Decoder::RequiredBufferSizeForFrameSize(kMaxTransmissionUnit);
// Declare a buffer for decoding incoming HDLC frames.
-std::array<std::byte, kMaxTransmissionUnit> input_buffer;
+std::array<std::byte, kDecoderBufferSize> input_buffer;
hdlc::Decoder decoder(input_buffer);
std::array<std::byte, 1> data;
diff --git a/pw_system/log.cc b/pw_system/log.cc
index 7cfbd82..652f3e2 100644
--- a/pw_system/log.cc
+++ b/pw_system/log.cc
@@ -36,7 +36,12 @@
// To save RAM, share the mutex and buffer between drains, since drains are
// flushed sequentially.
sync::Mutex drains_mutex;
+
// Buffer to decode and remove entries from log buffer, to send to a drain.
+//
+// TODO(amontanez): pw_log_rpc should provide a helper for this since there's
+// proto encoding overhead unaccounted for here.
+static_assert(rpc::MaxSafePayloadSize() >= PW_SYSTEM_MAX_LOG_ENTRY_SIZE);
std::array<std::byte, PW_SYSTEM_MAX_LOG_ENTRY_SIZE> log_decode_buffer
PW_GUARDED_BY(drains_mutex);
@@ -49,10 +54,7 @@
log_rpc::RpcLogDrainMap drain_map(drains);
-// TODO(amontanez): Is there a helper to subtract RPC overhead?
-constexpr size_t kMaxPackedLogMessagesSize =
- PW_SYSTEM_MAX_TRANSMISSION_UNIT - 32;
-
+constexpr size_t kMaxPackedLogMessagesSize = rpc::MaxSafePayloadSize();
std::array<std::byte, kMaxPackedLogMessagesSize> log_packing_buffer;
} // namespace
diff --git a/pw_system/public/pw_system/config.h b/pw_system/public/pw_system/config.h
index e7021eb..e8400d7 100644
--- a/pw_system/public/pw_system/config.h
+++ b/pw_system/public/pw_system/config.h
@@ -24,16 +24,17 @@
// PW_SYSTEM_MAX_LOG_ENTRY_SIZE limits the proto-encoded log entry size. This
// value might depend on a target interface's MTU.
//
-// Defaults to 512B.
+// Defaults to 256B.
#ifndef PW_SYSTEM_MAX_LOG_ENTRY_SIZE
-#define PW_SYSTEM_MAX_LOG_ENTRY_SIZE 512
+#define PW_SYSTEM_MAX_LOG_ENTRY_SIZE 256
#endif // PW_SYSTEM_MAX_LOG_ENTRY_SIZE
// PW_SYSTEM_MAX_TRANSMISSION_UNIT target's MTU.
//
-// Defaults to 512B.
+// Defaults to 1055 bytes, which is enough to fit 512-byte payloads when using
+// HDLC framing.
#ifndef PW_SYSTEM_MAX_TRANSMISSION_UNIT
-#define PW_SYSTEM_MAX_TRANSMISSION_UNIT 512
+#define PW_SYSTEM_MAX_TRANSMISSION_UNIT 1055
#endif // PW_SYSTEM_MAX_TRANSMISSION_UNIT
// PW_SYSTEM_DEFAULT_CHANNEL_ID RPC channel ID to host.
diff --git a/pw_transfer/integration_test/client.cc b/pw_transfer/integration_test/client.cc
index e567cbc..a0d152e 100644
--- a/pw_transfer/integration_test/client.cc
+++ b/pw_transfer/integration_test/client.cc
@@ -29,6 +29,7 @@
#include "google/protobuf/text_format.h"
#include "pw_assert/check.h"
#include "pw_log/log.h"
+#include "pw_rpc/channel.h"
#include "pw_rpc/integration_testing.h"
#include "pw_status/status.h"
#include "pw_status/try.h"
@@ -77,15 +78,15 @@
// Create a pw_transfer client and perform the transfer actions.
pw::Status PerformTransferActions(const pw::transfer::ClientConfig& config) {
- std::byte chunk_buffer[512];
- std::byte encode_buffer[512];
+ constexpr size_t kMaxPayloadSize = rpc::MaxSafePayloadSize();
+ std::byte chunk_buffer[kMaxPayloadSize];
+ std::byte encode_buffer[kMaxPayloadSize];
transfer::Thread<2, 2> transfer_thread(chunk_buffer, encode_buffer);
thread::Thread system_thread(TransferThreadOptions(), transfer_thread);
pw::transfer::Client client(rpc::integration_test::client(),
rpc::integration_test::kChannelId,
- transfer_thread,
- /*max_bytes_to_receive=*/256);
+ transfer_thread);
Status status = pw::OkStatus();
for (const pw::transfer::TransferAction& action : config.transfer_actions()) {
diff --git a/targets/arduino/system_rpc_server.cc b/targets/arduino/system_rpc_server.cc
index b87e654..65ef5d2 100644
--- a/targets/arduino/system_rpc_server.cc
+++ b/targets/arduino/system_rpc_server.cc
@@ -14,6 +14,7 @@
#include <cstddef>
+#include "pw_hdlc/encoded_size.h"
#include "pw_hdlc/rpc_channel.h"
#include "pw_hdlc/rpc_packets.h"
#include "pw_log/log.h"
@@ -23,16 +24,20 @@
namespace pw::rpc::system_server {
namespace {
-constexpr size_t kMaxTransmissionUnit = 256;
+// Hard-coded to 1055 bytes, which is enough to fit 512-byte payloads when using
+// HDLC framing.
+constexpr size_t kMaxTransmissionUnit = 1055;
+
+static_assert(kMaxTransmissionUnit ==
+ hdlc::MaxEncodedFrameSize(rpc::cfg::kEncodingBufferSizeBytes));
// Used to write HDLC data to pw::sys_io.
stream::SysIoWriter writer;
stream::SysIoReader reader;
// Set up the output channel for the pw_rpc server to use.
-hdlc::RpcChannelOutput hdlc_channel_output(writer,
- pw::hdlc::kDefaultRpcAddress,
- "HDLC channel");
+hdlc::FixedMtuChannelOutput<kMaxTransmissionUnit> hdlc_channel_output(
+ writer, pw::hdlc::kDefaultRpcAddress, "HDLC channel");
Channel channels[] = {pw::rpc::Channel::Create<1>(&hdlc_channel_output)};
rpc::Server server(channels);
@@ -49,8 +54,10 @@
rpc::Server& Server() { return server; }
Status Start() {
+ constexpr size_t kDecoderBufferSize =
+ hdlc::Decoder::RequiredBufferSizeForFrameSize(kMaxTransmissionUnit);
// Declare a buffer for decoding incoming HDLC frames.
- std::array<std::byte, kMaxTransmissionUnit> input_buffer;
+ std::array<std::byte, kDecoderBufferSize> input_buffer;
hdlc::Decoder decoder(input_buffer);
while (true) {
diff --git a/targets/host/system_rpc_server.cc b/targets/host/system_rpc_server.cc
index 7a27e7a..4647647 100644
--- a/targets/host/system_rpc_server.cc
+++ b/targets/host/system_rpc_server.cc
@@ -17,6 +17,7 @@
#include <cstdio>
#include "pw_assert/check.h"
+#include "pw_hdlc/encoded_size.h"
#include "pw_hdlc/rpc_channel.h"
#include "pw_hdlc/rpc_packets.h"
#include "pw_log/log.h"
@@ -26,14 +27,18 @@
namespace pw::rpc::system_server {
namespace {
-constexpr size_t kMaxTransmissionUnit = 512;
+// Hard-coded to 1055 bytes, which is enough to fit 512-byte payloads when using
+// HDLC framing.
+constexpr size_t kMaxTransmissionUnit = 1055;
uint16_t socket_port = 33000;
+static_assert(kMaxTransmissionUnit ==
+ hdlc::MaxEncodedFrameSize(rpc::cfg::kEncodingBufferSizeBytes));
+
stream::SocketStream socket_stream;
-hdlc::RpcChannelOutput hdlc_channel_output(socket_stream,
- hdlc::kDefaultRpcAddress,
- "HDLC channel");
+hdlc::FixedMtuChannelOutput<kMaxTransmissionUnit> hdlc_channel_output(
+ socket_stream, hdlc::kDefaultRpcAddress, "HDLC channel");
Channel channels[] = {rpc::Channel::Create<1>(&hdlc_channel_output)};
rpc::Server server(channels);
@@ -59,8 +64,10 @@
rpc::Server& Server() { return server; }
Status Start() {
+ constexpr size_t kDecoderBufferSize =
+ hdlc::Decoder::RequiredBufferSizeForFrameSize(kMaxTransmissionUnit);
// Declare a buffer for decoding incoming HDLC frames.
- std::array<std::byte, kMaxTransmissionUnit> input_buffer;
+ std::array<std::byte, kDecoderBufferSize> input_buffer;
hdlc::Decoder decoder(input_buffer);
while (true) {
diff --git a/targets/mimxrt595_evk/system_rpc_server.cc b/targets/mimxrt595_evk/system_rpc_server.cc
index b87e654..65ef5d2 100644
--- a/targets/mimxrt595_evk/system_rpc_server.cc
+++ b/targets/mimxrt595_evk/system_rpc_server.cc
@@ -14,6 +14,7 @@
#include <cstddef>
+#include "pw_hdlc/encoded_size.h"
#include "pw_hdlc/rpc_channel.h"
#include "pw_hdlc/rpc_packets.h"
#include "pw_log/log.h"
@@ -23,16 +24,20 @@
namespace pw::rpc::system_server {
namespace {
-constexpr size_t kMaxTransmissionUnit = 256;
+// Hard-coded to 1055 bytes, which is enough to fit 512-byte payloads when using
+// HDLC framing.
+constexpr size_t kMaxTransmissionUnit = 1055;
+
+static_assert(kMaxTransmissionUnit ==
+ hdlc::MaxEncodedFrameSize(rpc::cfg::kEncodingBufferSizeBytes));
// Used to write HDLC data to pw::sys_io.
stream::SysIoWriter writer;
stream::SysIoReader reader;
// Set up the output channel for the pw_rpc server to use.
-hdlc::RpcChannelOutput hdlc_channel_output(writer,
- pw::hdlc::kDefaultRpcAddress,
- "HDLC channel");
+hdlc::FixedMtuChannelOutput<kMaxTransmissionUnit> hdlc_channel_output(
+ writer, pw::hdlc::kDefaultRpcAddress, "HDLC channel");
Channel channels[] = {pw::rpc::Channel::Create<1>(&hdlc_channel_output)};
rpc::Server server(channels);
@@ -49,8 +54,10 @@
rpc::Server& Server() { return server; }
Status Start() {
+ constexpr size_t kDecoderBufferSize =
+ hdlc::Decoder::RequiredBufferSizeForFrameSize(kMaxTransmissionUnit);
// Declare a buffer for decoding incoming HDLC frames.
- std::array<std::byte, kMaxTransmissionUnit> input_buffer;
+ std::array<std::byte, kDecoderBufferSize> input_buffer;
hdlc::Decoder decoder(input_buffer);
while (true) {
diff --git a/targets/stm32f429i_disc1/system_rpc_server.cc b/targets/stm32f429i_disc1/system_rpc_server.cc
index b87e654..65ef5d2 100644
--- a/targets/stm32f429i_disc1/system_rpc_server.cc
+++ b/targets/stm32f429i_disc1/system_rpc_server.cc
@@ -14,6 +14,7 @@
#include <cstddef>
+#include "pw_hdlc/encoded_size.h"
#include "pw_hdlc/rpc_channel.h"
#include "pw_hdlc/rpc_packets.h"
#include "pw_log/log.h"
@@ -23,16 +24,20 @@
namespace pw::rpc::system_server {
namespace {
-constexpr size_t kMaxTransmissionUnit = 256;
+// Hard-coded to 1055 bytes, which is enough to fit 512-byte payloads when using
+// HDLC framing.
+constexpr size_t kMaxTransmissionUnit = 1055;
+
+static_assert(kMaxTransmissionUnit ==
+ hdlc::MaxEncodedFrameSize(rpc::cfg::kEncodingBufferSizeBytes));
// Used to write HDLC data to pw::sys_io.
stream::SysIoWriter writer;
stream::SysIoReader reader;
// Set up the output channel for the pw_rpc server to use.
-hdlc::RpcChannelOutput hdlc_channel_output(writer,
- pw::hdlc::kDefaultRpcAddress,
- "HDLC channel");
+hdlc::FixedMtuChannelOutput<kMaxTransmissionUnit> hdlc_channel_output(
+ writer, pw::hdlc::kDefaultRpcAddress, "HDLC channel");
Channel channels[] = {pw::rpc::Channel::Create<1>(&hdlc_channel_output)};
rpc::Server server(channels);
@@ -49,8 +54,10 @@
rpc::Server& Server() { return server; }
Status Start() {
+ constexpr size_t kDecoderBufferSize =
+ hdlc::Decoder::RequiredBufferSizeForFrameSize(kMaxTransmissionUnit);
// Declare a buffer for decoding incoming HDLC frames.
- std::array<std::byte, kMaxTransmissionUnit> input_buffer;
+ std::array<std::byte, kDecoderBufferSize> input_buffer;
hdlc::Decoder decoder(input_buffer);
while (true) {