pw_rpc: Move system_server backends into targets

Backends for the pw_rpc/system_server facade were defined in the pw_rpc
module, preventing targets from customizing their server configurations
and channels. This change moves the backends into the respective target
directories. Additionally, pw_unit_test's RPC main is updated to use the
system server.

Change-Id: I670e13dd178ab8a7fc8dfa8fade3f82a46d5208c
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/28500
Reviewed-by: Wyatt Hepler <hepler@google.com>
Reviewed-by: Keir Mierle <keir@google.com>
Commit-Queue: Alexei Frolov <frolv@google.com>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 020cf7b..9a84842 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -50,6 +50,8 @@
 add_subdirectory(pw_unit_test EXCLUDE_FROM_ALL)
 add_subdirectory(pw_varint EXCLUDE_FROM_ALL)
 
+add_subdirectory(targets/host EXCLUDE_FROM_ALL)
+
 add_subdirectory(third_party/nanopb EXCLUDE_FROM_ALL)
 
 add_custom_target(pw_apps)
diff --git a/pw_hdlc_lite/BUILD.gn b/pw_hdlc_lite/BUILD.gn
index 877526c..11aa3ec 100644
--- a/pw_hdlc_lite/BUILD.gn
+++ b/pw_hdlc_lite/BUILD.gn
@@ -66,12 +66,18 @@
   friend = [ ":*" ]
 }
 
+pw_source_set("rpc_channel_output") {
+  public_configs = [ ":default_config" ]
+  public = [ "public/pw_hdlc_lite/rpc_channel.h" ]
+  public_deps = [
+    ":pw_hdlc_lite",
+    "$dir_pw_rpc:server",
+  ]
+}
+
 pw_source_set("pw_rpc") {
   public_configs = [ ":default_config" ]
-  public = [
-    "public/pw_hdlc_lite/rpc_channel.h",
-    "public/pw_hdlc_lite/rpc_packets.h",
-  ]
+  public = [ "public/pw_hdlc_lite/rpc_packets.h" ]
   sources = [ "rpc_packets.cc" ]
   public_deps = [
     ":pw_hdlc_lite",
@@ -116,7 +122,7 @@
 pw_test("rpc_channel_test") {
   deps = [
     ":pw_hdlc_lite",
-    ":pw_rpc",
+    ":rpc_channel_output",
   ]
   sources = [ "rpc_channel_test.cc" ]
 }
diff --git a/pw_rpc/system_server/BUILD b/pw_rpc/system_server/BUILD
index 383ed97..253c803 100644
--- a/pw_rpc/system_server/BUILD
+++ b/pw_rpc/system_server/BUILD
@@ -38,26 +38,5 @@
         ":facade",
         "//pw_span",
         "//pw_status",
-        # For now, hard-code to depend on stdio until bazel build is updated
-        # to support multiple target configurations.
-        "//pw_rpc/system_server:sys_io",
-    ],
-)
-
-pw_cc_library(
-    name = "socket",
-    srcs = ["socket_rpc_server.cc"],
-    deps = [
-        ":facade",
-        "//pw_hdlc_lite:pw_rpc",
-    ],
-)
-
-pw_cc_library(
-    name = "sys_io",
-    srcs = ["sys_io_rpc_server.cc"],
-    deps = [
-        ":facade",
-        "//pw_hdlc_lite:pw_rpc",
     ],
 )
diff --git a/pw_rpc/system_server/BUILD.gn b/pw_rpc/system_server/BUILD.gn
index ef36c58..c420352 100644
--- a/pw_rpc/system_server/BUILD.gn
+++ b/pw_rpc/system_server/BUILD.gn
@@ -32,23 +32,3 @@
   ]
   public = [ "public/pw_rpc_system_server/rpc_server.h" ]
 }
-
-pw_source_set("socket") {
-  deps = [
-    ":facade",
-    "$dir_pw_hdlc_lite:pw_rpc",
-    "$dir_pw_stream:socket_stream",
-    dir_pw_log,
-  ]
-  sources = [ "socket_rpc_server.cc" ]
-}
-
-pw_source_set("sys_io") {
-  deps = [
-    ":facade",
-    "$dir_pw_hdlc_lite:pw_rpc",
-    "$dir_pw_stream:sys_io_stream",
-    dir_pw_log,
-  ]
-  sources = [ "sys_io_rpc_server.cc" ]
-}
diff --git a/pw_rpc/system_server/CMakeLists.txt b/pw_rpc/system_server/CMakeLists.txt
index 60cabb1..12f9cb6 100644
--- a/pw_rpc/system_server/CMakeLists.txt
+++ b/pw_rpc/system_server/CMakeLists.txt
@@ -19,24 +19,3 @@
     pw_rpc.server
     pw_stream
 )
-
-pw_add_module_library(pw_rpc.system_server.socket
-  IMPLEMENTS_FACADES
-    pw_rpc.system_server
-  SOURCES
-    socket_rpc_server.cc
-  PRIVATE_DEPS
-    pw_hdlc_lite
-    pw_rpc.server
-    pw_stream.socket_stream
-)
-
-pw_add_module_library(pw_rpc.system_server.sys_io
-  IMPLEMENTS_FACADES
-    pw_rpc.system_server
-  SOURCES
-    sys_io_rpc_server.cc
-  PUBLIC_DEPS
-    pw_hdlc_lite
-    pw_stream.sys_io_stream
-)
diff --git a/pw_toolchain/host_clang/toolchain.cmake b/pw_toolchain/host_clang/toolchain.cmake
index 5457f94..8c0f866 100644
--- a/pw_toolchain/host_clang/toolchain.cmake
+++ b/pw_toolchain/host_clang/toolchain.cmake
@@ -16,7 +16,7 @@
 
 pw_set_backend(pw_log pw_log_basic)
 pw_set_backend(pw_assert pw_assert_log)
-pw_set_backend(pw_rpc.system_server pw_rpc.system_server.socket)
+pw_set_backend(pw_rpc.system_server targets.host.system_rpc_server)
 pw_set_backend(pw_sys_io pw_sys_io_stdio)
 
 set(CMAKE_C_COMPILER clang)
diff --git a/pw_toolchain/host_gcc/toolchain.cmake b/pw_toolchain/host_gcc/toolchain.cmake
index 97e5360..e2ce85f 100644
--- a/pw_toolchain/host_gcc/toolchain.cmake
+++ b/pw_toolchain/host_gcc/toolchain.cmake
@@ -16,7 +16,7 @@
 
 pw_set_backend(pw_log pw_log_basic)
 pw_set_backend(pw_assert pw_assert_log)
-pw_set_backend(pw_rpc.system_server pw_rpc.system_server.socket)
+pw_set_backend(pw_rpc.system_server targets.host.system_rpc_server)
 pw_set_backend(pw_sys_io pw_sys_io_stdio)
 
 set(CMAKE_C_COMPILER gcc)
diff --git a/pw_unit_test/BUILD.gn b/pw_unit_test/BUILD.gn
index 33695f8..a693e09 100644
--- a/pw_unit_test/BUILD.gn
+++ b/pw_unit_test/BUILD.gn
@@ -106,8 +106,7 @@
   public_deps = [ ":pw_unit_test" ]
   deps = [
     ":rpc_service",
-    "$dir_pw_hdlc_lite:pw_rpc",
-    "$dir_pw_rpc:server",
+    "$dir_pw_rpc/system_server",
     dir_pw_log,
   ]
   sources = [ "rpc_main.cc" ]
diff --git a/pw_unit_test/rpc_main.cc b/pw_unit_test/rpc_main.cc
index dd634f1..912deb7 100644
--- a/pw_unit_test/rpc_main.cc
+++ b/pw_unit_test/rpc_main.cc
@@ -12,54 +12,23 @@
 // License for the specific language governing permissions and limitations under
 // the License.
 
-#include "pw_hdlc_lite/encoder.h"
-#include "pw_hdlc_lite/rpc_channel.h"
-#include "pw_hdlc_lite/rpc_packets.h"
 #include "pw_hdlc_lite/sys_io_stream.h"
 #include "pw_log/log.h"
 #include "pw_unit_test/framework.h"
 #include "pw_unit_test/unit_test_service.h"
 
-// TODO(frolv): This file is largely copied from the HDLC RPC example. It should
-// be updated to use the system RPC server facade when that is ready.
-
-namespace pw {
 namespace {
 
-constexpr size_t kMaxTransmissionUnit = 256;
-
-// Used to write HDLC data to pw::sys_io.
-stream::SysIoWriter writer;
-
-// Set up the output channel for the pw_rpc server to use to use.
-hdlc_lite::RpcChannelOutputBuffer<kMaxTransmissionUnit> hdlc_channel_output(
-    writer, hdlc_lite::kDefaultRpcAddress, "HDLC channel");
-
-rpc::Channel channels[] = {rpc::Channel::Create<1>(&hdlc_channel_output)};
-
-// Declare the pw_rpc server with the HDLC channel.
-rpc::Server server(channels);
-
 unit_test::UnitTestService unit_test_service;
 
-void RegisterServices() { server.RegisterService(unit_test_service); }
-
 }  // namespace
 
-extern "C" int main() {
-  // Send log messages to HDLC address 1. This prevents logs from interfering
-  // with pw_rpc communications.
-  log_basic::SetOutput([](std::string_view log) {
-    hdlc_lite::WriteUIFrame(1, std::as_bytes(std::span(log)), writer);
-  });
-
-  RegisterServices();
-
-  // Declare a buffer for decoding incoming HDLC frames.
-  std::array<std::byte, kMaxTransmissionUnit> input_buffer;
+int main() {
+  pw::rpc::system_server::Init();
+  pw::rpc::system_server::Server().RegisterService(unit_test_service);
 
   PW_LOG_INFO("Starting pw_rpc server");
-  hdlc_lite::ReadAndProcessPackets(server, hdlc_channel_output, input_buffer);
+  pw::rpc::system_server::Start();
 
   return 0;
 }
diff --git a/targets/host/BUILD b/targets/host/BUILD
new file mode 100644
index 0000000..5967231
--- /dev/null
+++ b/targets/host/BUILD
@@ -0,0 +1,32 @@
+# Copyright 2020 The Pigweed Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+load(
+    "//pw_build:pigweed.bzl",
+    "pw_cc_library",
+)
+
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"])  # Apache License 2.0
+
+pw_cc_library(
+    name = "system_rpc_server",
+    srcs = ["system_rpc_server.cc"],
+    deps = [
+        "//pw_rpc/system_server:facade",
+        "//pw_hdlc_lite:pw_rpc",
+    ],
+)
+
diff --git a/targets/host/BUILD.gn b/targets/host/BUILD.gn
index 801ef9f..cbb53ca 100644
--- a/targets/host/BUILD.gn
+++ b/targets/host/BUILD.gn
@@ -25,3 +25,16 @@
 pw_doc_group("target_docs") {
   sources = [ "target_docs.rst" ]
 }
+
+if (current_toolchain != default_toolchain) {
+  pw_source_set("system_rpc_server") {
+    deps = [
+      "$dir_pw_hdlc_lite:pw_rpc",
+      "$dir_pw_hdlc_lite:rpc_channel_output",
+      "$dir_pw_rpc/system_server:facade",
+      "$dir_pw_stream:socket_stream",
+      dir_pw_log,
+    ]
+    sources = [ "system_rpc_server.cc" ]
+  }
+}
diff --git a/targets/host/CMakeLists.txt b/targets/host/CMakeLists.txt
new file mode 100644
index 0000000..345ae92
--- /dev/null
+++ b/targets/host/CMakeLists.txt
@@ -0,0 +1,27 @@
+# Copyright 2020 The Pigweed Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+include("$ENV{PW_ROOT}/pw_build/pigweed.cmake")
+
+pw_add_module_library(targets.host.system_rpc_server
+  IMPLEMENTS_FACADE
+    pw_rpc.system_server
+  SOURCES
+    system_rpc_server.cc
+  PRIVATE_DEPS
+    pw_rpc.system_server.facade
+    pw_hdlc_lite
+    pw_rpc.server
+    pw_stream.socket_stream
+)
diff --git a/pw_rpc/system_server/socket_rpc_server.cc b/targets/host/system_rpc_server.cc
similarity index 100%
rename from pw_rpc/system_server/socket_rpc_server.cc
rename to targets/host/system_rpc_server.cc
diff --git a/targets/host/target_docs.rst b/targets/host/target_docs.rst
index de087a1..7d20d17 100644
--- a/targets/host/target_docs.rst
+++ b/targets/host/target_docs.rst
@@ -30,6 +30,12 @@
 
   $ ./out/host_[compiler]_debug/obj/pw_status/status_test
 
+RPC server
+==========
+The host target implements a system RPC server that runs over a local socket,
+defaulting to port 33000. To communicate with a process running the host RPC
+server, use ``pw rpc -s localhost:33000 <protos>``.
+
 Configuration
 =============
 The host target exposes a few options that may be used to change the host build
diff --git a/targets/host/target_toolchains.gni b/targets/host/target_toolchains.gni
index 2a77cc9..1c08013 100644
--- a/targets/host/target_toolchains.gni
+++ b/targets/host/target_toolchains.gni
@@ -40,7 +40,7 @@
   pw_sys_io_BACKEND = "$dir_pw_sys_io_stdio"
 
   # Configure backend for pw_rpc_system_server.
-  pw_rpc_system_server_BACKEND = "$dir_pw_rpc/system_server:socket"
+  pw_rpc_system_server_BACKEND = "$dir_pigweed/targets/host:system_rpc_server"
 
   # Configure backend for trace facade.
   pw_trace_BACKEND = "$dir_pw_trace_tokenized"
diff --git a/targets/stm32f429i-disc1/BUILD b/targets/stm32f429i-disc1/BUILD
index 1414169..3dd27d2 100644
--- a/targets/stm32f429i-disc1/BUILD
+++ b/targets/stm32f429i-disc1/BUILD
@@ -34,3 +34,12 @@
         "//pw_sys_io_baremetal_stm32f429",
     ],
 )
+
+pw_cc_library(
+    name = "system_rpc_server",
+    srcs = ["system_rpc_server.cc"],
+    deps = [
+        "//pw_rpc/system_server:facade",
+        "//pw_hdlc_lite:pw_rpc",
+    ],
+)
diff --git a/targets/stm32f429i-disc1/BUILD.gn b/targets/stm32f429i-disc1/BUILD.gn
index 6b18a9e..2549920 100644
--- a/targets/stm32f429i-disc1/BUILD.gn
+++ b/targets/stm32f429i-disc1/BUILD.gn
@@ -46,6 +46,17 @@
       "vector_table.cc",
     ]
   }
+
+  pw_source_set("system_rpc_server") {
+    deps = [
+      "$dir_pw_hdlc_lite:pw_rpc",
+      "$dir_pw_hdlc_lite:rpc_channel_output",
+      "$dir_pw_rpc/system_server:facade",
+      "$dir_pw_stream:sys_io_stream",
+      dir_pw_log,
+    ]
+    sources = [ "system_rpc_server.cc" ]
+  }
 }
 
 pw_doc_group("target_docs") {
diff --git a/pw_rpc/system_server/sys_io_rpc_server.cc b/targets/stm32f429i-disc1/system_rpc_server.cc
similarity index 100%
rename from pw_rpc/system_server/sys_io_rpc_server.cc
rename to targets/stm32f429i-disc1/system_rpc_server.cc
diff --git a/targets/stm32f429i-disc1/target_docs.rst b/targets/stm32f429i-disc1/target_docs.rst
index 68e34d8..2e4fcbd 100644
--- a/targets/stm32f429i-disc1/target_docs.rst
+++ b/targets/stm32f429i-disc1/target_docs.rst
@@ -98,6 +98,11 @@
 run on the attached device(s). Alternatively, you may use ``pw watch`` to set up
 Pigweed to build/test whenever it sees changes to source files.
 
+RPC server
+==========
+The stm32f429i target implements a system RPC server that over a simple UART
+driver. To communicate with a device running the RPC server, run
+``pw rpc -d <device> -b 115200 <protos>``.
 
 Debugging
 =========
diff --git a/targets/stm32f429i-disc1/target_toolchains.gni b/targets/stm32f429i-disc1/target_toolchains.gni
index 9a4a41f..e6eae02 100644
--- a/targets/stm32f429i-disc1/target_toolchains.gni
+++ b/targets/stm32f429i-disc1/target_toolchains.gni
@@ -50,7 +50,8 @@
   pw_cpu_exception_SUPPORT_BACKEND = "$dir_pw_cpu_exception_armv7m:support"
   pw_log_BACKEND = dir_pw_log_basic
   pw_sys_io_BACKEND = dir_pw_sys_io_baremetal_stm32f429
-  pw_rpc_system_server_BACKEND = "$dir_pw_rpc/system_server:sys_io"
+  pw_rpc_system_server_BACKEND =
+      "$dir_pigweed/targets/stm32f429i-disc1:system_rpc_server"
   pw_malloc_BACKEND = dir_pw_malloc_freelist
 
   pw_boot_armv7m_LINK_CONFIG_DEFINES = [