pw_log_tokenized: Base64 over HDLC backend

Change-Id: Ibd0ff83b555ae72d65aa0e3595cabf0ff6cd3832
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/23600
Commit-Queue: Wyatt Hepler <hepler@google.com>
Reviewed-by: Anthony DiGirolamo <tonymd@google.com>
diff --git a/pw_log_tokenized/BUILD b/pw_log_tokenized/BUILD
index 6f78805..c1f5d4a 100644
--- a/pw_log_tokenized/BUILD
+++ b/pw_log_tokenized/BUILD
@@ -45,6 +45,18 @@
     ],
 )
 
+pw_cc_library(
+    name = "base64_over_hdlc",
+    srcs = ["base64_over_hdlc.cc"],
+    hdrs = ["public/pw_log_tokenized/base64_over_hdlc.h"],
+    includes = ["public"],
+    deps = [
+        "//pw_hdlc_lite:encoder",
+        "//pw_tokenizer:base64",
+        "//pw_tokenizer:global_handler_with_payload.facade",
+    ],
+)
+
 pw_cc_test(
     name = "test",
     srcs = [
diff --git a/pw_log_tokenized/BUILD.gn b/pw_log_tokenized/BUILD.gn
index 94db9c1..d8df960 100644
--- a/pw_log_tokenized/BUILD.gn
+++ b/pw_log_tokenized/BUILD.gn
@@ -19,7 +19,7 @@
 import("$dir_pw_tokenizer/backend.gni")
 import("$dir_pw_unit_test/test.gni")
 
-config("default_config") {
+config("public_includes") {
   include_dirs = [ "public" ]
   visibility = [ ":*" ]
 }
@@ -42,7 +42,7 @@
 #   -> pw_log -> :log_backend --> pw_tokenizer:global_handler_with_payload
 #
 pw_source_set("pw_log_tokenized") {
-  public_configs = [ ":default_config" ]
+  public_configs = [ ":public_includes" ]
   public_deps = [
     "$dir_pw_log:facade",
     "$dir_pw_tokenizer:global_handler_with_payload.facade",
@@ -59,6 +59,19 @@
   deps = [ "$dir_pw_tokenizer:global_handler_with_payload" ]
 }
 
+# This target provides a backend for pw_tokenizer that encodes tokenized logs as
+# Base64, encodes them into HDLC frames, and writes them over sys_io.
+pw_source_set("base64_over_hdlc") {
+  public_configs = [ ":public_includes" ]
+  public = [ "public/pw_log_tokenized/base64_over_hdlc.h" ]
+  sources = [ "base64_over_hdlc.cc" ]
+  deps = [
+    "$dir_pw_hdlc_lite:encoder",
+    "$dir_pw_tokenizer:base64",
+    "$dir_pw_tokenizer:global_handler_with_payload.facade",
+  ]
+}
+
 pw_test_group("tests") {
   tests = [ ":test" ]
 }
diff --git a/pw_log_tokenized/base64_over_hdlc.cc b/pw_log_tokenized/base64_over_hdlc.cc
new file mode 100644
index 0000000..b8c7bdf
--- /dev/null
+++ b/pw_log_tokenized/base64_over_hdlc.cc
@@ -0,0 +1,52 @@
+// 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.
+
+// This function serves as a backend for pw_tokenizer / pw_log_tokenized that
+// encodes tokenized logs as Base64 and writes them using HDLC.
+
+#include "pw_log_tokenized/base64_over_hdlc.h"
+
+#include <span>
+
+#include "pw_hdlc_lite/encoder.h"
+#include "pw_hdlc_lite/sys_io_stream.h"
+#include "pw_tokenizer/base64.h"
+#include "pw_tokenizer/tokenize_to_global_handler_with_payload.h"
+
+namespace pw::log_tokenized {
+namespace {
+
+stream::SysIoWriter writer;
+
+}  // namespace
+
+// Base64-encodes tokenized logs and writes them to pw::sys_io as HDLC frames.
+extern "C" void pw_tokenizer_HandleEncodedMessageWithPayload(
+    pw_tokenizer_Payload,  // TODO(hepler): Use the metadata for filtering.
+    const uint8_t log_buffer[],
+    size_t size_bytes) {
+  // Encode the tokenized message as Base64.
+  char base64_buffer[tokenizer::kDefaultBase64EncodedBufferSize];
+  const size_t base64_bytes = tokenizer::PrefixedBase64Encode(
+      std::span(log_buffer, size_bytes), base64_buffer);
+  base64_buffer[base64_bytes] = '\0';
+
+  // HDLC-encode the Base64 string via a SysIoWriter.
+  hdlc_lite::WriteInformationFrame(
+      PW_LOG_TOKENIZED_BASE64_LOG_HDLC_ADDRESS,
+      std::as_bytes(std::span(base64_buffer, base64_bytes)),
+      writer);
+}
+
+}  // namespace pw::log_tokenized
diff --git a/pw_log_tokenized/public/pw_log_tokenized/base64_over_hdlc.h b/pw_log_tokenized/public/pw_log_tokenized/base64_over_hdlc.h
new file mode 100644
index 0000000..af31532
--- /dev/null
+++ b/pw_log_tokenized/public/pw_log_tokenized/base64_over_hdlc.h
@@ -0,0 +1,19 @@
+// 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.
+#pragma once
+
+// The HDLC address to which to write Base64-encoded tokenized logs.
+#ifndef PW_LOG_TOKENIZED_BASE64_LOG_HDLC_ADDRESS
+#define PW_LOG_TOKENIZED_BASE64_LOG_HDLC_ADDRESS 1
+#endif  // PW_LOG_TOKENIZED_BASE64_LOG_HDLC_ADDRESS