lib/rpc: rp2040 reboot and temp RPCs

Change-Id: I4cddbc71ed22fc0d84f6d98822346c7857cb40b1
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/kudzu/+/193730
Reviewed-by: Armando Montanez <amontanez@google.com>
Commit-Queue: Anthony DiGirolamo <tonymd@google.com>
diff --git a/BUILD.gn b/BUILD.gn
index d4b13b5..a8168db 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -69,7 +69,7 @@
 # single super Python package for installation into the bootstrapped virtual
 # environment.
 pw_python_distribution("kudzu_python_distribution") {
-  packages = _pigweed_python_packages
+  packages = _all_python_packages
   generate_setup_cfg = {
     name = "kudzu-dist"
     version = "0.0.1"
diff --git a/README.md b/README.md
index 3eac59e..945efbd 100644
--- a/README.md
+++ b/README.md
@@ -126,12 +126,11 @@
 
 ### Host
 
-Run the host app and connect to it via `pw-system-console`:
+Run the host app and connect to it via `pw console`:
 
 ```sh
 ./out/gn/host_device_simulator.speed_optimized/obj/applications/badge/bin/badge & \
-  pw-system-console --socket-addr default \
-    --proto-globs third_party/pigweed/pw_rpc/echo.proto ; \
+  pw console --socket-addr default ; \
   killall badge
 ```
 
@@ -145,12 +144,18 @@
   picotool load -x $ELF
 ```
 
-Connect with `pw-system-console`:
+Connect with `pw console`:
 
 ```sh
-pw-system-console --verbose \
+pw console --verbose \
   --baudrate 115200 \
-  --proto-globs third_party/pigweed/pw_rpc/echo.proto \
   --token-databases ./out/gn/rp2040.size_optimized/obj/applications/badge/bin/badge.elf \
   --device /dev/rp2040
 ```
+
+From Python Repl window you can issue RPCs interactively:
+
+```
+>>> device.rpcs.kudzu.rpc.Kudzu.PackageTemp()
+(Status.OK, kudzu.rpc.PackageTempResponse(temp=27.60657501220703))
+```
diff --git a/applications/app_common_impl/BUILD.gn b/applications/app_common_impl/BUILD.gn
index ab29dba..242b24d 100644
--- a/applications/app_common_impl/BUILD.gn
+++ b/applications/app_common_impl/BUILD.gn
@@ -61,6 +61,7 @@
 _pico_common_deps = [
   "$PICO_ROOT/src/common/pico_base",
   "$PICO_ROOT/src/common/pico_stdlib",
+  "$PICO_ROOT/src/rp2_common/hardware_adc",
   "$PICO_ROOT/src/rp2_common/hardware_pwm",
   "$PICO_ROOT/src/rp2_common/hardware_spi",
   "$PICO_ROOT/src/rp2_common/hardware_vreg",
diff --git a/applications/app_common_impl/common_pico.cc b/applications/app_common_impl/common_pico.cc
index c3d6cf1..d94b060 100644
--- a/applications/app_common_impl/common_pico.cc
+++ b/applications/app_common_impl/common_pico.cc
@@ -20,6 +20,7 @@
 
 #include "FreeRTOS.h"
 #include "ft6236/device.h"
+#include "hardware/adc.h"
 #include "hardware/gpio.h"
 #include "hardware/pwm.h"
 #include "hardware/vreg.h"
@@ -305,6 +306,8 @@
   set_sys_clock_khz(250000, false);
 #endif
 
+  adc_init();
+
   ConfigStatusRgb();
   // Set to a dim pink.
   SetStatusRgb(32, 12, 32);
diff --git a/lib/rpc/BUILD.gn b/lib/rpc/BUILD.gn
new file mode 100644
index 0000000..4d3ad21
--- /dev/null
+++ b/lib/rpc/BUILD.gn
@@ -0,0 +1,40 @@
+# Copyright 2024 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.
+
+import("//build_overrides/pi_pico.gni")
+import("//build_overrides/pigweed.gni")
+
+import("$dir_pw_protobuf_compiler/proto.gni")
+
+config("public") {
+  include_dirs = [ "public" ]
+  visibility = [ ":*" ]
+}
+
+pw_proto_library("protos") {
+  sources = [ "kudzu.proto" ]
+  inputs = [ "kudzu.options" ]
+  deps = [ "$dir_pw_protobuf:common_protos" ]
+  prefix = "kudzu"
+}
+
+pw_source_set("kudzu_service") {
+  public_configs = [ ":public" ]
+  public_deps = [
+    ":protos.pwpb_rpc",
+    "$PICO_ROOT/src/rp2_common/hardware_adc",
+    "$PICO_ROOT/src/rp2_common/pico_bootrom",
+  ]
+  sources = [ "public/kudzu/kudzu_service_pwpb.h" ]
+}
diff --git a/lib/rpc/kudzu.options b/lib/rpc/kudzu.options
new file mode 100644
index 0000000..02cd8c4
--- /dev/null
+++ b/lib/rpc/kudzu.options
@@ -0,0 +1,13 @@
+// Copyright 2024 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.
diff --git a/lib/rpc/kudzu.proto b/lib/rpc/kudzu.proto
new file mode 100644
index 0000000..0e06513
--- /dev/null
+++ b/lib/rpc/kudzu.proto
@@ -0,0 +1,43 @@
+// Copyright 2024 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.
+syntax = "proto3";
+
+package kudzu.rpc;
+
+import "pw_protobuf_protos/common.proto";
+
+service Kudzu {
+  rpc Reboot(RebootRequest) returns (RebootResponse);
+  rpc PackageTemp(PackageTempRequest) returns (PackageTempResponse);
+}
+
+message RebootType {
+  enum Enum {
+    UKNOWN = 0;
+    BOTH_MASS_STORAGE_AND_PICOBOOT = 1;
+    PICOBOOT_ONLY = 2;
+    MASS_STORAGE_ONLY = 3;
+  };
+}
+
+message RebootRequest {
+  RebootType.Enum reboot_type = 1;  // Required
+}
+
+message RebootResponse {}
+
+message PackageTempRequest {}
+message PackageTempResponse {
+  float temp = 1;
+}
diff --git a/lib/rpc/public/kudzu/kudzu_service_pwpb.h b/lib/rpc/public/kudzu/kudzu_service_pwpb.h
new file mode 100644
index 0000000..9bf7e54
--- /dev/null
+++ b/lib/rpc/public/kudzu/kudzu_service_pwpb.h
@@ -0,0 +1,61 @@
+// Copyright 2024 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.
+#pragma once
+
+#include "hardware/adc.h"
+#include "kudzu/kudzu.pwpb.h"
+#include "kudzu/kudzu.rpc.pwpb.h"
+#include "pico/bootrom.h"
+#include "pw_status/status.h"
+
+namespace kudzu::rpc {
+
+class KudzuService final : public pw_rpc::pwpb::Kudzu::Service<KudzuService> {
+ public:
+  pw::Status Reboot(const pwpb::RebootRequest::Message& request,
+                    pwpb::RebootResponse::Message& /*response*/) {
+    uint32_t disable_interface_mask = 0;
+
+    if (request.reboot_type ==
+        pwpb::RebootType::Enum::BOTH_MASS_STORAGE_AND_PICOBOOT) {
+      disable_interface_mask = 0;
+    } else if (request.reboot_type == pwpb::RebootType::Enum::PICOBOOT_ONLY) {
+      disable_interface_mask = 1;
+    } else if (request.reboot_type ==
+               pwpb::RebootType::Enum::MASS_STORAGE_ONLY) {
+      disable_interface_mask = 2;
+    } else {
+      return pw::Status::Unknown();
+    }
+
+    reset_usb_boot(0, disable_interface_mask);
+    return pw::OkStatus();
+  }
+
+  pw::Status PackageTemp(const pwpb::PackageTempRequest::Message& /*request*/,
+                         pwpb::PackageTempResponse::Message& response) {
+    adc_set_temp_sensor_enabled(true);
+    adc_select_input(4);  // 4 is the on board temp sensor.
+
+    // See raspberry-pi-pico-c-sdk.pdf, Section '4.1.1. hardware_adc'
+    const float conversion_factor = 3.3f / (1 << 12);
+    float adc = static_cast<float>(adc_read()) * conversion_factor;
+    float temp_c = 27.0f - (adc - 0.706f) / 0.001721f;
+    response.temp = temp_c;
+
+    return pw::OkStatus();
+  }
+};
+
+}  // namespace kudzu::rpc
diff --git a/pigweed.json b/pigweed.json
index 400d886..c5291a2 100644
--- a/pigweed.json
+++ b/pigweed.json
@@ -23,7 +23,7 @@
           "function": "main"
         },
         "console": {
-          "module": "pw_system.console",
+          "module": "kudzu_tools.console",
           "function": "main"
         },
         "package": {
diff --git a/targets/rp2040/BUILD.gn b/targets/rp2040/BUILD.gn
index 6c7d9e7..ae3ba35 100644
--- a/targets/rp2040/BUILD.gn
+++ b/targets/rp2040/BUILD.gn
@@ -36,6 +36,7 @@
       "$dir_pw_string",
       "$dir_pw_system",
       "$dir_pw_third_party/freertos",
+      "//lib/rpc:kudzu_service",
     ]
     sources = [ "boot.cc" ]
   }
diff --git a/targets/rp2040/boot.cc b/targets/rp2040/boot.cc
index 5ca25c8..788ec32 100644
--- a/targets/rp2040/boot.cc
+++ b/targets/rp2040/boot.cc
@@ -14,9 +14,12 @@
 
 #include <array>
 
+#include "pw_system/rpc_server.h"
+
 #define PW_LOG_MODULE_NAME "pw_system"
 
 #include "FreeRTOS.h"
+#include "kudzu/kudzu_service_pwpb.h"
 #include "pico/stdlib.h"
 #include "pw_log/log.h"
 #include "pw_string/util.h"
@@ -66,6 +69,8 @@
   *pulIdleTaskStackSize = freertos_idle_stack.size();
 }
 
+kudzu::rpc::KudzuService kudzu_service;
+
 int main() {
   // PICO_SDK Inits
   stdio_init_all();
@@ -74,6 +79,7 @@
   PW_LOG_INFO("pw_system main");
 
   pw::system::Init();
+  pw::system::GetRpcServer().RegisterService(kudzu_service);
   vTaskStartScheduler();
   PW_UNREACHABLE;
 }
diff --git a/tools/BUILD.gn b/tools/BUILD.gn
index ab199a1..af1fe2a 100644
--- a/tools/BUILD.gn
+++ b/tools/BUILD.gn
@@ -24,12 +24,19 @@
   sources = [
     "kudzu_tools/__init__.py",
     "kudzu_tools/build_project.py",
+    "kudzu_tools/console.py",
     "kudzu_tools/presubmit_checks.py",
   ]
   python_deps = [
     "$dir_pw_build/py",
     "$dir_pw_cli/py",
     "$dir_pw_presubmit/py",
+    "$dir_pw_protobuf:common_protos.python",
+    "$dir_pw_rpc:protos.python",
+    "$dir_pw_system/py",
+
+    # RPC protos to include for console interaction.
+    "//lib/rpc:protos.python",
   ]
   pylintrc = "$dir_pigweed/.pylintrc"
 }
diff --git a/tools/kudzu_tools/console.py b/tools/kudzu_tools/console.py
new file mode 100644
index 0000000..f184b6e
--- /dev/null
+++ b/tools/kudzu_tools/console.py
@@ -0,0 +1,36 @@
+# Copyright 2024 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.
+"""Wraps pw_system's console to inject additional RPC protos."""
+
+import argparse
+import sys
+from typing import Optional
+
+from pw_protobuf_protos import common_pb2
+import pw_system.console
+from kudzu import kudzu_pb2
+from pw_rpc import echo_pb2
+
+
+def main(args: Optional[argparse.Namespace] = None) -> int:
+    compiled_protos = [
+        common_pb2,
+        echo_pb2,
+        kudzu_pb2,
+    ]
+    return pw_system.console.main_with_compiled_protos(compiled_protos, args)
+
+
+if __name__ == '__main__':
+    sys.exit(main())