pw_kvs: Add to build; get tests passing

Change-Id: Idfd357beaf60b94ebaf9b4b1f8cd1b3d712e9b10
diff --git a/BUILD.gn b/BUILD.gn
index 0a0b5f2..6379134 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -53,6 +53,7 @@
     "$dir_pigweed/docs",
     "$dir_pw_base64",
     "$dir_pw_checksum",
+    "$dir_pw_kvs",
     "$dir_pw_polyfill",
     "$dir_pw_preprocessor",
     "$dir_pw_protobuf",
@@ -70,6 +71,7 @@
   group_deps = [
     "$dir_pw_base64:tests",
     "$dir_pw_checksum:tests",
+    "$dir_pw_kvs:tests",
     "$dir_pw_log:tests",
     "$dir_pw_polyfill:tests",
     "$dir_pw_preprocessor:tests",
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b7b5d46..d8ed777 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -24,6 +24,7 @@
 add_subdirectory(pw_cpu_exception_armv7m)
 add_subdirectory(pw_dumb_io)
 add_subdirectory(pw_dumb_io_stdio)
+add_subdirectory(pw_kvs)
 add_subdirectory(pw_log)
 add_subdirectory(pw_log_basic)
 add_subdirectory(pw_polyfill)
diff --git a/modules.gni b/modules.gni
index d122bae..41fe5cf 100644
--- a/modules.gni
+++ b/modules.gni
@@ -29,6 +29,7 @@
 dir_pw_dumb_io_baremetal_stm32f429 =
     "$dir_pigweed/pw_dumb_io_baremetal_stm32f429"
 dir_pw_dumb_io_stdio = "$dir_pigweed/pw_dumb_io_stdio"
+dir_pw_kvs = "$dir_pigweed/pw_kvs"
 dir_pw_log = "$dir_pigweed/pw_log"
 dir_pw_log_basic = "$dir_pigweed/pw_log_basic"
 dir_pw_module = "$dir_pigweed/pw_module"
diff --git a/pw_kvs/BUILD b/pw_kvs/BUILD
new file mode 100644
index 0000000..b646357
--- /dev/null
+++ b/pw_kvs/BUILD
@@ -0,0 +1,66 @@
+# 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",
+    "pw_cc_test",
+)
+
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"])  # Apache License 2.0
+
+pw_cc_library(
+    name = "pw_kvs",
+    srcs = [
+        "flash.cc",
+        "key_value_store.cc",
+    ],
+    hdrs = [
+        "public/pw_kvs/assert.h",
+        "public/pw_kvs/flash.h",
+        "public/pw_kvs/flash_memory.h",
+        "public/pw_kvs/in_memory_fake_flash.h",
+        "public/pw_kvs/key_value_store.h",
+        "public/pw_kvs/partition_table_entry.h",
+    ],
+    includes = ["public"],
+    deps = [
+        "//pw_checksum",
+        "//pw_log",
+        "//pw_status",
+        "//pw_string",
+    ],
+)
+
+pw_cc_test(
+    name = "key_value_store_test",
+    srcs = ["key_value_store_test.cc"],
+    deps = [
+        ":pw_kvs",
+        "//pw_checksum",
+        "//pw_log",
+    ],
+)
+
+pw_cc_test(
+    name = "key_value_store_sub_sector_test",
+    srcs = ["key_value_store_sub_sector_test.cc"],
+    deps = [
+        ":pw_kvs",
+        "//pw_checksum",
+        "//pw_log",
+    ],
+)
diff --git a/pw_kvs/BUILD.gn b/pw_kvs/BUILD.gn
new file mode 100644
index 0000000..0c59dd1
--- /dev/null
+++ b/pw_kvs/BUILD.gn
@@ -0,0 +1,80 @@
+# 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.
+
+import("$dir_pw_docgen/docs.gni")
+import("$dir_pw_unit_test/test.gni")
+
+config("default_config") {
+  include_dirs = [ "public" ]
+}
+
+source_set("pw_kvs") {
+  public_configs = [ ":default_config" ]
+  public = [
+    "public/pw_kvs/assert.h",
+    "public/pw_kvs/flash.h",
+    "public/pw_kvs/flash_memory.h",
+    "public/pw_kvs/in_memory_fake_flash.h",
+    "public/pw_kvs/key_value_store.h",
+    "public/pw_kvs/partition_table_entry.h",
+  ]
+  sources = [
+    "flash.cc",
+    "key_value_store.cc",
+  ]
+  sources += public
+  public_deps = [
+    "$dir_pw_status",
+  ]
+  deps = [
+    dir_pw_checksum,
+    dir_pw_log,
+    dir_pw_string,
+  ]
+}
+
+pw_test_group("tests") {
+  tests = [
+    ":key_value_store_test",
+    ":key_value_store_sub_sector_test",
+  ]
+}
+
+pw_test("key_value_store_test") {
+  deps = [
+    ":pw_kvs",
+    dir_pw_checksum,
+    dir_pw_log,
+  ]
+  sources = [
+    "key_value_store_test.cc",
+  ]
+}
+
+pw_test("key_value_store_sub_sector_test") {
+  deps = [
+    ":pw_kvs",
+    dir_pw_checksum,
+    dir_pw_log,
+  ]
+  sources = [
+    "key_value_store_sub_sector_test.cc",
+  ]
+}
+
+pw_doc_group("docs") {
+  sources = [
+    "docs.rst",
+  ]
+}
diff --git a/pw_kvs/CMakeLists.txt b/pw_kvs/CMakeLists.txt
new file mode 100644
index 0000000..2d998bb
--- /dev/null
+++ b/pw_kvs/CMakeLists.txt
@@ -0,0 +1,22 @@
+# 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.
+
+pw_auto_add_simple_module(pw_kvs
+  PUBLIC_DEPS
+    pw_status
+  PRIVATE_DEPS
+    pw_checksum
+    pw_log
+    pw_string
+)
diff --git a/pw_kvs/flash.cc b/pw_kvs/flash.cc
index bcc695f..dad5fab 100644
--- a/pw_kvs/flash.cc
+++ b/pw_kvs/flash.cc
@@ -12,29 +12,41 @@
 // License for the specific language governing permissions and limitations under
 // the License.
 
-#include "pw_kvs/util/flash.h"
+#include "pw_kvs/flash.h"
 
-#include "pw_kvs/config.h"
+#include <cstring>
 
-namespace pw {
+namespace pw::kvs {
+namespace cfg {
+
+// Configure the maximum supported alignment for the flash utility functions.
+constexpr size_t kFlashUtilMaxAlignmentBytes = 16;
+
+}  // namespace cfg
 
 Status PaddedWrite(FlashPartition* partition,
                    FlashPartition::Address address,
                    const uint8_t* buffer,
                    uint16_t size) {
-  RETURN_STATUS_IF(
-      address % partition->GetAlignmentBytes() ||
-          partition->GetAlignmentBytes() > cfg::kFlashUtilMaxAlignmentBytes,
-      Status::INVALID_ARGUMENT);
+  if (address % partition->GetAlignmentBytes() ||
+      partition->GetAlignmentBytes() > cfg::kFlashUtilMaxAlignmentBytes) {
+    return Status::INVALID_ARGUMENT;
+  }
   uint8_t alignment_buffer[cfg::kFlashUtilMaxAlignmentBytes] = {0};
   uint16_t aligned_bytes = size - size % partition->GetAlignmentBytes();
-  RETURN_IF_ERROR(partition->Write(address, buffer, aligned_bytes));
+  if (Status status = partition->Write(address, buffer, aligned_bytes);
+      !status.ok()) {
+    return status;
+  }
   uint16_t remaining_bytes = size - aligned_bytes;
   if (remaining_bytes > 0) {
-    memcpy(alignment_buffer, &buffer[aligned_bytes], remaining_bytes);
-    RETURN_IF_ERROR(partition->Write(address + aligned_bytes,
-                                     alignment_buffer,
-                                     partition->GetAlignmentBytes()));
+    std::memcpy(alignment_buffer, &buffer[aligned_bytes], remaining_bytes);
+    if (Status status = partition->Write(address + aligned_bytes,
+                                         alignment_buffer,
+                                         partition->GetAlignmentBytes());
+        !status.ok()) {
+      return status;
+    }
   }
   return Status::OK;
 }
@@ -43,21 +55,27 @@
                      uint8_t* buffer,
                      FlashPartition::Address address,
                      uint16_t size) {
-  RETURN_STATUS_IF(
-      address % partition->GetAlignmentBytes() ||
-          partition->GetAlignmentBytes() > cfg::kFlashUtilMaxAlignmentBytes,
-      Status::INVALID_ARGUMENT);
+  if (address % partition->GetAlignmentBytes() ||
+      partition->GetAlignmentBytes() > cfg::kFlashUtilMaxAlignmentBytes) {
+    return Status::INVALID_ARGUMENT;
+  }
   uint16_t aligned_bytes = size - size % partition->GetAlignmentBytes();
-  RETURN_IF_ERROR(partition->Read(buffer, address, aligned_bytes));
+  if (Status status = partition->Read(buffer, address, aligned_bytes);
+      !status.ok()) {
+    return status;
+  }
   uint16_t remaining_bytes = size - aligned_bytes;
   if (remaining_bytes > 0) {
     uint8_t alignment_buffer[cfg::kFlashUtilMaxAlignmentBytes];
-    RETURN_IF_ERROR(partition->Read(alignment_buffer,
-                                    address + aligned_bytes,
-                                    partition->GetAlignmentBytes()));
+    if (Status status = partition->Read(alignment_buffer,
+                                        address + aligned_bytes,
+                                        partition->GetAlignmentBytes());
+        !status.ok()) {
+      return status;
+    }
     memcpy(&buffer[aligned_bytes], alignment_buffer, remaining_bytes);
   }
   return Status::OK;
 }
 
-}  // namespace pw
+}  // namespace pw::kvs
diff --git a/pw_kvs/key_value_store.cc b/pw_kvs/key_value_store.cc
index ce21740..b1a6505 100644
--- a/pw_kvs/key_value_store.cc
+++ b/pw_kvs/key_value_store.cc
@@ -46,19 +46,16 @@
 
 #include <cstring>
 
-#include "pw_kvs/os/mutex.h"
-#include "pw_kvs/util/ccitt_crc16.h"
-#include "pw_kvs/util/constexpr.h"
-#include "pw_kvs/util/flash.h"
+#include "pw_checksum/ccitt_crc16.h"
+#include "pw_kvs/flash.h"
+#include "pw_log/log.h"
+#include "pw_string/string_builder.h"
+#include "pw_string/util.h"
 
-namespace pw {
-
-// Declare static constexpr variables so it can be used for pass-by-reference
-// functions.
-constexpr uint16_t KeyValueStore::kSectorReadyValue;
+namespace pw::kvs {
 
 Status KeyValueStore::Enable() {
-  os::MutexLock lock(&lock_);
+  // TODO: LOCK MUTEX
   if (enabled_) {
     return Status::OK;
   }
@@ -71,9 +68,11 @@
   alignment_bytes_ = partition_.GetAlignmentBytes();
   DCHECK(alignment_bytes_ <= kMaxAlignmentBytes);
 
-  LOG_WARN_IF(partition_.GetSectorCount() > kSectorCountMax,
-              "Partition is larger then KVS max sector count, not all space "
-              "will be used.");
+  if (partition_.GetSectorCount() > kSectorCountMax) {
+    PW_LOG_WARN(
+        "Partition is larger then KVS max sector count, "
+        "not all space will be used.");
+  }
   // Load map and setup sectors if needed (first word isn't kSectorReadyValue).
   next_sector_clean_order_ = 0;
   for (SectorIndex i = 0; i < SectorCount(); i++) {
@@ -82,45 +81,60 @@
     // may give random values. It's important to make sure that data is not
     // erased before trying to see if there is a token match.
     bool is_sector_meta_erased;
-    RETURN_IF_ERROR(partition_.IsChunkErased(
-        SectorIndexToAddress(i),
-        RoundUpForAlignment(sizeof(sector_header_meta)),
-        &is_sector_meta_erased));
-    RETURN_IF_ERROR(
-        UnalignedRead(&partition_,
-                      reinterpret_cast<uint8_t*>(&sector_header_meta),
-                      SectorIndexToAddress(i),
-                      sizeof(sector_header_meta)));
+    if (Status status = partition_.IsChunkErased(
+            SectorIndexToAddress(i),
+            RoundUpForAlignment(sizeof(sector_header_meta)),
+            &is_sector_meta_erased);
+        !status.ok()) {
+      return status;
+    };
+    if (Status status =
+            UnalignedRead(&partition_,
+                          reinterpret_cast<uint8_t*>(&sector_header_meta),
+                          SectorIndexToAddress(i),
+                          sizeof(sector_header_meta));
+        !status.ok()) {
+      return status;
+    }
 
     constexpr int kVersion3 = 3;  // Version 3 only cleans 1 sector at a time.
     constexpr int kVersion2 = 2;  // Version 2 is always 1 byte aligned.
     if (is_sector_meta_erased ||
         sector_header_meta.synchronize_token != kSectorReadyValue) {
       // Sector needs to be setup
-      RETURN_IF_ERROR(ResetSector(i));
+      if (Status status = ResetSector(i); !status.ok()) {
+        return status;
+      }
       continue;
     } else if (sector_header_meta.version != kVersion &&
                sector_header_meta.version != kVersion3 &&  // Allow version 3
                sector_header_meta.version != kVersion2) {  // Allow version 2
-      LOG(ERROR) << "Unsupported KVS version in sector: " << i;
+      PW_LOG_ERROR("Unsupported KVS version in sector: %u",
+                   static_cast<unsigned>(i));
       return Status::FAILED_PRECONDITION;
     }
     uint32_t sector_header_cleaning_offset =
         RoundUpForAlignment(sizeof(KvsSectorHeaderMeta));
 
     bool clean_not_pending;
-    RETURN_IF_ERROR(partition_.IsChunkErased(
-        SectorIndexToAddress(i) + sector_header_cleaning_offset,
-        RoundUpForAlignment(sizeof(KvsSectorHeaderCleaning)),
-        &clean_not_pending));
+    if (Status status = partition_.IsChunkErased(
+            SectorIndexToAddress(i) + sector_header_cleaning_offset,
+            RoundUpForAlignment(sizeof(KvsSectorHeaderCleaning)),
+            &clean_not_pending);
+        !status.ok()) {
+      return status;
+    }
 
     if (!clean_not_pending) {
       // Sector is marked for cleaning, read the sector_clean_order
-      RETURN_IF_ERROR(
-          UnalignedRead(&partition_,
-                        reinterpret_cast<uint8_t*>(&sector_clean_order_[i]),
-                        SectorIndexToAddress(i) + sector_header_cleaning_offset,
-                        sizeof(KvsSectorHeaderCleaning::sector_clean_order)));
+      if (Status status = UnalignedRead(
+              &partition_,
+              reinterpret_cast<uint8_t*>(&sector_clean_order_[i]),
+              SectorIndexToAddress(i) + sector_header_cleaning_offset,
+              sizeof(KvsSectorHeaderCleaning::sector_clean_order));
+          !status.ok()) {
+        return status;
+      }
       next_sector_clean_order_ =
           std::max(sector_clean_order_[i] + 1, next_sector_clean_order_);
     } else {
@@ -133,9 +147,10 @@
     }
     if (sector_header_meta.alignment_bytes != alignment_bytes_) {
       // NOTE: For now all sectors must have same alignment.
-      LOG(ERROR) << "Sector " << i << " has unexpected alignment "
-                 << alignment_bytes_
-                 << " != " << sector_header_meta.alignment_bytes;
+      PW_LOG_ERROR("Sector %u has unexpected alignment %u != %u",
+                   unsigned(i),
+                   unsigned(alignment_bytes_),
+                   unsigned(sector_header_meta.alignment_bytes));
       return Status::FAILED_PRECONDITION;
     }
 
@@ -154,15 +169,23 @@
       // Because underlying flash can be encrypted + erased, trying to readback
       // may give random values. It's important to make sure that data is not
       // erased before trying to see if there is a token match.
-      RETURN_IF_ERROR(partition_.IsChunkErased(
-          address, RoundUpForAlignment(sizeof(header)), &is_kvs_header_erased));
-      RETURN_IF_ERROR(UnalignedRead(&partition_,
-                                    reinterpret_cast<uint8_t*>(&header),
-                                    address,
-                                    sizeof(header)));
+      if (Status status =
+              partition_.IsChunkErased(address,
+                                       RoundUpForAlignment(sizeof(header)),
+                                       &is_kvs_header_erased);
+          !status.ok()) {
+        return status;
+      }
+      if (Status status = UnalignedRead(&partition_,
+                                        reinterpret_cast<uint8_t*>(&header),
+                                        address,
+                                        sizeof(header));
+          !status.ok()) {
+        return status;
+      }
       if (is_kvs_header_erased || header.synchronize_token != kChunkSyncValue) {
         if (!is_kvs_header_erased) {
-          LOG_ERROR("Next sync_token is not clear!");
+          PW_LOG_ERROR("Next sync_token is not clear!");
           // TODO: handle this?
         }
         break;  // End of elements in sector
@@ -174,18 +197,24 @@
                     "nul-terminator.");
 
       // Read key and add to map
-      RETURN_IF_ERROR(
-          UnalignedRead(&partition_,
-                        reinterpret_cast<uint8_t*>(&temp_key_buffer_),
-                        address + RoundUpForAlignment(sizeof(header)),
-                        header.key_len));
+      if (Status status =
+              UnalignedRead(&partition_,
+                            reinterpret_cast<uint8_t*>(&temp_key_buffer_),
+                            address + RoundUpForAlignment(sizeof(header)),
+                            header.key_len);
+          !status.ok()) {
+        return status;
+      }
       temp_key_buffer_[header.key_len] = '\0';
       bool is_erased = header.flags & kFlagsIsErasedMask;
 
       KeyIndex index = FindKeyInMap(temp_key_buffer_);
       if (index == kListCapacityMax) {
-        RETURN_IF_ERROR(AppendToMap(
-            temp_key_buffer_, address, header.chunk_len, is_erased));
+        if (Status status = AppendToMap(
+                temp_key_buffer_, address, header.chunk_len, is_erased);
+            !status.ok()) {
+          return status;
+        }
       } else if (sector_clean_order_[i] >=
                  sector_clean_order_[AddressToSectorIndex(
                      key_map_[index].address)]) {
@@ -202,8 +231,11 @@
         clean_not_pending ? partition_.GetSectorSizeBytes() - offset : 0;
   }
 
-  LOG_IF_ERROR(EnforceFreeSector())
-      << "Failed to force clean at boot, no free sectors available!";
+  if (Status status = EnforceFreeSector(); !status.ok()) {
+    PW_LOG_ERROR(
+        "%s: Failed to force clean at boot, no free sectors available!",
+        status.str());
+  }
   enabled_ = true;
   return Status::OK;
 }
@@ -218,17 +250,17 @@
     return Status::INVALID_ARGUMENT;
   }
 
-  size_t key_len = util::StringLength(key, kChunkKeyLengthMax + 1u);
+  size_t key_len = string::Length(key, kChunkKeyLengthMax + 1u);
   if (key_len == 0 || key_len > kChunkKeyLengthMax) {
     return Status::INVALID_ARGUMENT;
   }
 
   // TODO: Support unaligned offset reads.
   if (offset % alignment_bytes_ != 0) {
-    LOG_ERROR("Currently unaligned offsets are not supported");
+    PW_LOG_ERROR("Currently unaligned offsets are not supported");
     return Status::INVALID_ARGUMENT;
   }
-  os::MutexLock lock(&lock_);
+  // TODO: LOCK MUTEX
   if (!enabled_) {
     return Status::FAILED_PRECONDITION;
   }
@@ -239,35 +271,41 @@
   }
   KvsHeader header;
   // TODO: Could cache the CRC and avoid reading the header.
-  RETURN_IF_ERROR(UnalignedRead(&partition_,
-                                reinterpret_cast<uint8_t*>(&header),
-                                key_map_[key_index].address,
-                                sizeof(header)));
+  if (Status status = UnalignedRead(&partition_,
+                                    reinterpret_cast<uint8_t*>(&header),
+                                    key_map_[key_index].address,
+                                    sizeof(header));
+      !status.ok()) {
+    return status;
+  }
   if (kChunkSyncValue != header.synchronize_token) {
     return Status::DATA_LOSS;
   }
   if (size + offset > header.chunk_len) {
-    LOG_ERROR("Out of bounds read: offset(%u) + size(%u) > data_size(%u)",
-              offset,
-              size,
-              header.chunk_len);
+    PW_LOG_ERROR("Out of bounds read: offset(%u) + size(%u) > data_size(%u)",
+                 offset,
+                 size,
+                 header.chunk_len);
     return Status::INVALID_ARGUMENT;
   }
-  RETURN_IF_ERROR(UnalignedRead(
-      &partition_,
-      value,
-      key_map_[key_index].address + RoundUpForAlignment(sizeof(KvsHeader)) +
-          RoundUpForAlignment(header.key_len) + offset,
-      size));
+  if (Status status = UnalignedRead(
+          &partition_,
+          value,
+          key_map_[key_index].address + RoundUpForAlignment(sizeof(KvsHeader)) +
+              RoundUpForAlignment(header.key_len) + offset,
+          size);
+      !status.ok()) {
+    return status;
+  }
 
   // Verify CRC only when full packet was read.
   if (offset == 0 && size == header.chunk_len) {
     uint16_t crc = CalculateCrc(key, key_len, value, size);
     if (crc != header.crc) {
-      LOG_ERROR("KVS CRC does not match for key=%s [expected %u, found %u]",
-                key,
-                header.crc,
-                crc);
+      PW_LOG_ERROR("KVS CRC does not match for key=%s [expected %u, found %u]",
+                   key,
+                   header.crc,
+                   crc);
       return Status::DATA_LOSS;
     }
   }
@@ -278,9 +316,8 @@
                                      uint16_t key_size,
                                      const uint8_t* value,
                                      uint16_t value_size) const {
-  CcittCrc16 crc;
-  crc.AppendBytes(ConstBuffer(reinterpret_cast<const uint8_t*>(key), key_size));
-  return crc.AppendBytes(ConstBuffer(value, value_size));
+  uint16_t crc = checksum::CcittCrc16(as_bytes(span(key, key_size)));
+  return checksum::CcittCrc16(as_bytes(span(value, value_size)), crc);
 }
 
 Status KeyValueStore::CalculateCrcFromValueAddress(
@@ -289,15 +326,17 @@
     FlashPartition::Address value_address,
     uint16_t value_size,
     uint16_t* crc_ret) {
-  CcittCrc16 crc;
-  crc.AppendBytes(ConstBuffer(reinterpret_cast<const uint8_t*>(key), key_size));
+  uint16_t crc = checksum::CcittCrc16(as_bytes(span(key, key_size)));
   for (size_t i = 0; i < value_size; i += TempBufferAlignedSize()) {
     auto read_size = std::min(value_size - i, TempBufferAlignedSize());
-    RETURN_IF_ERROR(
-        UnalignedRead(&partition_, temp_buffer_, value_address + i, read_size));
-    crc.AppendBytes(ConstBuffer(temp_buffer_, read_size));
+    if (Status status = UnalignedRead(
+            &partition_, temp_buffer_, value_address + i, read_size);
+        !status.ok()) {
+      return status;
+    }
+    crc = checksum::CcittCrc16(as_bytes(span(temp_buffer_, read_size)));
   }
-  *crc_ret = crc.CurrentValue();
+  *crc_ret = crc;
   return Status::OK;
 }
 
@@ -309,13 +348,13 @@
     return Status::INVALID_ARGUMENT;
   }
 
-  size_t key_len = util::StringLength(key, (kChunkKeyLengthMax + 1u));
+  size_t key_len = string::Length(key, kChunkKeyLengthMax + 1u);
   if (key_len == 0 || key_len > kChunkKeyLengthMax ||
       size > kChunkValueLengthMax) {
     return Status::INVALID_ARGUMENT;
   }
 
-  os::MutexLock lock(&lock_);
+  // TODO: LOCK MUTEX
   if (!enabled_) {
     return Status::FAILED_PRECONDITION;
   }
@@ -333,7 +372,9 @@
   // Check if this would use the last empty sector on KVS with multiple sectors
   if (SectorCount() > 1 && IsInLastFreeSector(address)) {
     // Forcing a full garbage collect to free more sectors.
-    RETURN_IF_ERROR(FullGarbageCollect());
+    if (Status status = FullGarbageCollect(); !status.ok()) {
+      return status;
+    }
     address = FindSpace(ChunkSize(key_len, size));
     if (address == kSectorInvalid || IsInLastFreeSector(address)) {
       // Couldn't find space, KVS is full.
@@ -341,8 +382,12 @@
     }
   }
 
-  RETURN_IF_ERROR(WriteKeyValue(address, key, value, size));
-  RETURN_IF_ERROR(AppendToMap(key, address, size));
+  if (Status status = WriteKeyValue(address, key, value, size); !status.ok()) {
+    return status;
+  }
+  if (Status status = AppendToMap(key, address, size); !status.ok()) {
+    return status;
+  }
 
   return Status::OK;
 }
@@ -362,7 +407,9 @@
     if (clean_pending_sectors ==
         (sector_clean_order_[sector] != kSectorCleanNotPending)) {
       if (!clean_pending_sectors) {
-        RETURN_IF_ERROR(MarkSectorForClean(sector));
+        if (Status status = MarkSectorForClean(sector); !status.ok()) {
+          return status;
+        }
       }
       Status status = CleanSector(sector);
       if (!status.ok() && status != Status::RESOURCE_EXHAUSTED) {
@@ -380,22 +427,31 @@
   if (SectorCount() == 1 || HasEmptySector()) {
     return Status::OK;
   }
-  LOG_INFO("KVS garbage collecting to get a free sector");
-  RETURN_IF_ERROR(GarbageCollectImpl(true /*clean_pending_sectors*/,
-                                     true /*exit_when_have_free_sector*/));
+  PW_LOG_INFO("KVS garbage collecting to get a free sector");
+  if (Status status = GarbageCollectImpl(true /*clean_pending_sectors*/,
+                                         true /*exit_when_have_free_sector*/);
+      !status.ok()) {
+    return status;
+  }
   if (HasEmptySector()) {
     return Status::OK;
   }
-  LOG_INFO("KVS: trying to clean non-pending sectors for more space");
-  RETURN_IF_ERROR(GarbageCollectImpl(false /*clean_pending_sectors*/,
-                                     true /*exit_when_have_free_sector*/));
+  PW_LOG_INFO("KVS: trying to clean non-pending sectors for more space");
+  if (Status status = GarbageCollectImpl(false /*clean_pending_sectors*/,
+                                         true /*exit_when_have_free_sector*/);
+      !status.ok()) {
+    return status;
+  }
   return HaveEmptySectorImpl() ? Status::OK : Status::RESOURCE_EXHAUSTED;
 }
 
 Status KeyValueStore::FullGarbageCollect() {
-  LOG_INFO("KVS: Full garbage collecting to try to free space");
-  RETURN_IF_ERROR(GarbageCollectImpl(true /*clean_pending_sectors*/,
-                                     false /*exit_when_have_free_sector*/));
+  PW_LOG_INFO("KVS: Full garbage collecting to try to free space");
+  if (Status status = GarbageCollectImpl(true /*clean_pending_sectors*/,
+                                         false /*exit_when_have_free_sector*/);
+      !status.ok()) {
+    return status;
+  }
   return GarbageCollectImpl(false /*clean_pending_sectors*/,
                             false /*exit_when_have_free_sector*/);
 }
@@ -410,8 +466,10 @@
   }
 
   size_t key_length =
-      util::StringLength(key_map_[key_index].key, (kChunkKeyLengthMax + 1u));
-  RETURN_STATUS_IF(key_length > kChunkKeyLengthMax, Status::INTERNAL);
+      string::Length(key_map_[key_index].key, kChunkKeyLengthMax + 1u);
+  if (key_length > kChunkKeyLengthMax) {
+    return Status::INTERNAL;
+  }
 
   uint32_t space_required = ChunkSize(key_length, size);
   SectorIndex sector = AddressToSectorIndex(key_map_[key_index].address);
@@ -424,14 +482,19 @@
               sector_space_remaining;
   } else {
     // No space in current sector, mark sector for clean and use another sector.
-    RETURN_IF_ERROR(MarkSectorForClean(sector));
+    if (Status status = MarkSectorForClean(sector); !status.ok()) {
+      return status;
+    }
     address = FindSpace(ChunkSize(key_length, size));
   }
   if (address == kSectorInvalid) {
     return Status::RESOURCE_EXHAUSTED;
   }
-  RETURN_IF_ERROR(
-      WriteKeyValue(address, key_map_[key_index].key, value, size, is_erased));
+  if (Status status = WriteKeyValue(
+          address, key_map_[key_index].key, value, size, is_erased);
+      !status.ok()) {
+    return status;
+  }
   UpdateMap(key_index, address, size, is_erased);
 
   return EnforceFreeSector();
@@ -451,7 +514,7 @@
                 key_map_[index].address,
                 sizeof(header));
   uint8_t key_len =
-      util::StringLength(key_map_[index].key, (kChunkKeyLengthMax + 1u));
+      string::Length(key_map_[index].key, kChunkKeyLengthMax + 1u);
   if (key_len > kChunkKeyLengthMax) {
     return false;
   }
@@ -477,7 +540,7 @@
     auto status =
         UnalignedRead(&partition_, temp_buffer_, address + i, read_size);
     if (!status.ok()) {
-      LOG(ERROR) << "Failed to read chunk: " << status;
+      PW_LOG_ERROR("Failed to read chunk: %s", status.str());
       return false;
     }
     if (memcmp(value + i, temp_buffer_, read_size) != 0) {
@@ -492,11 +555,11 @@
     return Status::INVALID_ARGUMENT;
   }
 
-  size_t key_len = util::StringLength(key, (kChunkKeyLengthMax + 1u));
+  size_t key_len = string::Length(key, kChunkKeyLengthMax + 1u);
   if (key_len == 0 || key_len > kChunkKeyLengthMax) {
     return Status::INVALID_ARGUMENT;
   }
-  os::MutexLock lock(&lock_);
+  // TODO: LOCK MUTEX
   if (!enabled_) {
     return Status::FAILED_PRECONDITION;
   }
@@ -525,10 +588,14 @@
     return status;
   }
 
-  RETURN_IF_ERROR(PaddedWrite(&partition_,
-                              SectorIndexToAddress(sector_index),
-                              reinterpret_cast<const uint8_t*>(&sector_header),
-                              sizeof(sector_header)));
+  if (Status status =
+          PaddedWrite(&partition_,
+                      SectorIndexToAddress(sector_index),
+                      reinterpret_cast<const uint8_t*>(&sector_header),
+                      sizeof(sector_header));
+      !status.ok()) {
+    return status;
+  }
 
   // Update space remaining
   sector_clean_order_[sector_index] = kSectorCleanNotPending;
@@ -541,8 +608,10 @@
                                     const uint8_t* value,
                                     uint16_t size,
                                     bool is_erased) {
-  uint16_t key_length = util::StringLength(key, (kChunkKeyLengthMax + 1u));
-  RETURN_STATUS_IF(key_length > kChunkKeyLengthMax, Status::INTERNAL);
+  uint16_t key_length = string::Length(key, kChunkKeyLengthMax + 1u);
+  if (key_length > kChunkKeyLengthMax) {
+    return Status::INTERNAL;
+  }
 
   constexpr uint16_t kFlagDefaultValue = 0;
   KvsHeader header = {
@@ -553,16 +622,26 @@
       .chunk_len = size};
 
   SectorIndex sector = AddressToSectorIndex(address);
-  RETURN_IF_ERROR(PaddedWrite(&partition_,
-                              address,
-                              reinterpret_cast<uint8_t*>(&header),
-                              sizeof(header)));
+  if (Status status = PaddedWrite(&partition_,
+                                  address,
+                                  reinterpret_cast<uint8_t*>(&header),
+                                  sizeof(header));
+      !status.ok()) {
+    return status;
+  }
   address += RoundUpForAlignment(sizeof(header));
-  RETURN_IF_ERROR(PaddedWrite(
-      &partition_, address, reinterpret_cast<const uint8_t*>(key), key_length));
+  if (Status status = PaddedWrite(&partition_,
+                                  address,
+                                  reinterpret_cast<const uint8_t*>(key),
+                                  key_length);
+      !status.ok()) {
+  }
   address += RoundUpForAlignment(key_length);
   if (size > 0) {
-    RETURN_IF_ERROR(PaddedWrite(&partition_, address, value, size));
+    if (Status status = PaddedWrite(&partition_, address, value, size);
+        !status.ok()) {
+      return status;
+    }
   }
   sector_space_remaining_[sector] -= ChunkSize(key_length, size);
   return Status::OK;
@@ -579,9 +658,16 @@
   for (size_t i = 0; i < size; i += TempBufferAlignedSize()) {
     size_t move_size = std::min(size - i, TempBufferAlignedSize());
     DCHECK_EQ(move_size % alignment_bytes_, 0);
-    RETURN_IF_ERROR(partition_.Read(temp_buffer_, src_address + i, move_size));
-    RETURN_IF_ERROR(
-        partition_.Write(dest_address + i, temp_buffer_, move_size));
+    if (Status status =
+            partition_.Read(temp_buffer_, src_address + i, move_size);
+        !status.ok()) {
+      return status;
+    }
+    if (Status status =
+            partition_.Write(dest_address + i, temp_buffer_, move_size);
+        !status.ok()) {
+      return status;
+    }
   }
   return Status::OK;
 }
@@ -594,12 +680,15 @@
   // Flag the sector as clean being active. This ensures we can handle losing
   // power while a clean is active.
   const KvsSectorHeaderCleaning kValue = {next_sector_clean_order_};
-  RETURN_IF_ERROR(
-      PaddedWrite(&partition_,
-                  SectorIndexToAddress(sector) +
-                      RoundUpForAlignment(sizeof(KvsSectorHeaderMeta)),
-                  reinterpret_cast<const uint8_t*>(&kValue),
-                  sizeof(kValue)));
+  if (Status status =
+          PaddedWrite(&partition_,
+                      SectorIndexToAddress(sector) +
+                          RoundUpForAlignment(sizeof(KvsSectorHeaderMeta)),
+                      reinterpret_cast<const uint8_t*>(&kValue),
+                      sizeof(kValue));
+      !status.ok()) {
+    return status;
+  }
   sector_space_remaining_[sector] = 0;
   sector_clean_order_[sector] = next_sector_clean_order_;
   next_sector_clean_order_++;
@@ -621,14 +710,17 @@
 
     if (i < map_size_ && sector == AddressToSectorIndex(key_map_[i].address)) {
       uint8_t key_len =
-          util::StringLength(key_map_[i].key, (kChunkKeyLengthMax + 1u));
+          string::Length(key_map_[i].key, kChunkKeyLengthMax + 1u);
       FlashPartition::Address address = key_map_[i].address;
       auto size = ChunkSize(key_len, key_map_[i].chunk_len);
       FlashPartition::Address move_address = FindSpace(size);
       if (move_address == kSectorInvalid) {
         return Status::RESOURCE_EXHAUSTED;
       }
-      RETURN_IF_ERROR(MoveChunk(move_address, address, size));
+      if (Status status = MoveChunk(move_address, address, size);
+          !status.ok()) {
+        return status;
+      }
       sector_space_remaining_[AddressToSectorIndex(move_address)] -= size;
       key_map_[i].address = move_address;  // Update map
     }
@@ -641,7 +733,7 @@
   if (all_sectors_have_been_cleaned == nullptr) {
     return Status::INVALID_ARGUMENT;
   }
-  os::MutexLock lock(&lock_);
+  // TODO: LOCK MUTEX
   bool have_cleaned_sector = false;
   for (SectorIndex sector = 0; sector < SectorCount(); sector++) {
     if (sector_clean_order_[sector] != kSectorCleanNotPending) {
@@ -649,7 +741,9 @@
         *all_sectors_have_been_cleaned = false;
         return Status::OK;
       }
-      RETURN_IF_ERROR(CleanSector(sector));
+      if (Status status = CleanSector(sector); !status.ok()) {
+        return status;
+      }
       have_cleaned_sector = true;
     }
   }
@@ -660,7 +754,9 @@
 Status KeyValueStore::CleanAllInternal() {
   for (SectorIndex sector = 0; sector < SectorCount(); sector++) {
     if (sector_clean_order_[sector] != kSectorCleanNotPending) {
-      RETURN_IF_ERROR(CleanSector(sector));
+      if (Status status = CleanSector(sector); !status.ok()) {
+        return status;
+      }
     }
   }
   return Status::OK;
@@ -703,11 +799,11 @@
     return Status::INVALID_ARGUMENT;
   }
 
-  size_t key_len = util::StringLength(key, (kChunkKeyLengthMax + 1u));
+  size_t key_len = string::Length(key, kChunkKeyLengthMax + 2u);
   if (key_len == 0 || key_len > kChunkKeyLengthMax) {
     return Status::INVALID_ARGUMENT;
   }
-  os::MutexLock lock(&lock_);
+  // TODO: LOCK MUTEX
   if (!enabled_) {
     return Status::FAILED_PRECONDITION;
   }
@@ -725,17 +821,17 @@
                                   uint16_t chunk_len,
                                   bool is_erased) {
   if (map_size_ >= kListCapacityMax) {
-    LOG_ERROR("Can't add: reached max supported keys %d", kListCapacityMax);
+    PW_LOG_ERROR("Can't add: reached max supported keys %d", kListCapacityMax);
     return Status::INTERNAL;
   }
 
   // Copy incoming key into map entry, ensuring size checks and nul-termination.
-  StringBuilder key_builder(key_map_[map_size_].key,
-                            sizeof(key_map_[map_size_].key));
+  StringBuilder key_builder(
+      span(key_map_[map_size_].key, sizeof(key_map_[map_size_].key)));
   key_builder.append(key);
 
   if (!key_builder.status().ok()) {
-    LOG_ERROR("Can't add: got invalid key: %s!", key_builder.status().str());
+    PW_LOG_ERROR("Can't add: got invalid key: %s!", key_builder.status().str());
     return Status::INTERNAL;
   }
 
@@ -802,4 +898,4 @@
   return 0;
 }
 
-}  // namespace pw
+}  // namespace pw::kvs
diff --git a/pw_kvs/key_value_store_sub_sector_test.cc b/pw_kvs/key_value_store_sub_sector_test.cc
index ff908f5..0e13167 100644
--- a/pw_kvs/key_value_store_sub_sector_test.cc
+++ b/pw_kvs/key_value_store_sub_sector_test.cc
@@ -12,34 +12,29 @@
 // License for the specific language governing permissions and limitations under
 // the License.
 
-#include "pw_kvs/key_value_store.h"
-
+#include "gtest/gtest.h"
 #include "pw_kvs/assert.h"
-#include "pw_kvs/devices/flash_memory.h"
-#include "pw_kvs/platform/board.h"
-#include "pw_kvs/status.h"
-#include "pw_kvs/test/fixture.h"
-#include "pw_kvs/test/framework.h"
-#include "pw_kvs/test/status_macros.h"
+#include "pw_kvs/flash_memory.h"
+#include "pw_kvs/key_value_store.h"
+#include "pw_status/status.h"
+
+#define USE_MEMORY_BUFFER 1
 
 #if USE_MEMORY_BUFFER
-#include "pw_kvs/test/fakes/in_memory_fake_flash.h"
+#include "pw_kvs/in_memory_fake_flash.h"
 #endif  // USE_MEMORY_BUFFER
 
-namespace pw {
+namespace pw::kvs {
 namespace {
 
 #if USE_MEMORY_BUFFER
 InMemoryFakeFlash<1024, 4> test_flash(8);  // 4 x 1k sectors, 8 byte alignment
 FlashPartition test_partition(&test_flash, 0, test_flash.GetSectorCount());
-// Test KVS against FlashSubSector
-FlashMemorySubSector test_subsector_flash(&test_flash,
-                                          0,
-                                          128);  // Expose less than a sector.
-#else   // Device test
-FlashPartition& test_partition = Board::Instance().FlashExternalTestPartition();
-FlashMemorySubSector& test_subsector_flash =
-    Board::Instance().FlashMemorySubSectorTestChunk();
+// Test KVS against FlashSubSector.  Expose less than a sector.
+FlashMemorySubSector test_subsector_flash(&test_flash, 0, 128);
+#else   // TODO: Test with real flash
+FlashPartition& test_partition = FlashExternalTestPartition();
+FlashMemorySubSector& test_subsector_flash = FlashMemorySubSectorTestChunk();
 #endif  // USE_MEMORY_BUFFER
 
 FlashPartition test_subsector_partition(&test_subsector_flash, 0, 1);
@@ -53,41 +48,45 @@
   // The subsector region is assumed to be a part of the test partition.
   // In order to clear state before the test, we must erase the entire test
   // partition because erase operations are disallowed on FlashMemorySubSectors.
-  ASSERT_OK(test_partition.Erase(0, test_partition.GetSectorCount()));
+  ASSERT_EQ(Status::OK,
+            test_partition.Erase(0, test_partition.GetSectorCount()));
 
   // Reset KVS
   subsector_kvs.Disable();
-  ASSERT_OK(subsector_kvs.Enable());
+  ASSERT_EQ(Status::OK, subsector_kvs.Enable());
 
   // Add some data
   uint8_t value1 = 0xDA;
-  ASSERT_OK(subsector_kvs.Put(keys[0], &value1, sizeof(value1)));
+  ASSERT_EQ(Status::OK, subsector_kvs.Put(keys[0], &value1, sizeof(value1)));
 
   uint32_t value2 = 0xBAD0301f;
-  ASSERT_OK(subsector_kvs.Put(
-      keys[1], reinterpret_cast<uint8_t*>(&value2), sizeof(value2)));
+  ASSERT_EQ(Status::OK,
+            subsector_kvs.Put(
+                keys[1], reinterpret_cast<uint8_t*>(&value2), sizeof(value2)));
 
   // Verify data
   uint32_t test2;
-  EXPECT_OK(subsector_kvs.Get(
-      keys[1], reinterpret_cast<uint8_t*>(&test2), sizeof(test2)));
+  EXPECT_EQ(Status::OK,
+            subsector_kvs.Get(
+                keys[1], reinterpret_cast<uint8_t*>(&test2), sizeof(test2)));
   uint8_t test1;
-  ASSERT_OK(subsector_kvs.Get(
-      keys[0], reinterpret_cast<uint8_t*>(&test1), sizeof(test1)));
+  ASSERT_EQ(Status::OK,
+            subsector_kvs.Get(
+                keys[0], reinterpret_cast<uint8_t*>(&test1), sizeof(test1)));
 
   EXPECT_EQ(test1, value1);
 
   // Erase a key
-  ASSERT_OK(subsector_kvs.Erase(keys[0]));
+  ASSERT_EQ(Status::OK, subsector_kvs.Erase(keys[0]));
 
   // Verify it was erased
-  EXPECT_EQ(subsector_kvs
-                .Get(keys[0], reinterpret_cast<uint8_t*>(&test1), sizeof(test1))
-                .code(),
+  EXPECT_EQ(subsector_kvs.Get(
+                keys[0], reinterpret_cast<uint8_t*>(&test1), sizeof(test1)),
             Status::NOT_FOUND);
   test2 = 0;
-  ASSERT_OK(subsector_kvs.Get(
-      keys[1], reinterpret_cast<uint8_t*>(&test2), sizeof(test2)));
+  ASSERT_EQ(Status::OK,
+            subsector_kvs.Get(
+                keys[1], reinterpret_cast<uint8_t*>(&test2), sizeof(test2)));
   EXPECT_EQ(test2, value2);
 
   // Erase other key
@@ -101,11 +100,12 @@
   // The subsector region is assumed to be a part of the test partition.
   // In order to clear state before the test, we must erase the entire test
   // partition because erase operations are disallowed on FlashMemorySubSectors.
-  ASSERT_OK(test_partition.Erase(0, test_partition.GetSectorCount()));
+  ASSERT_EQ(Status::OK,
+            test_partition.Erase(0, test_partition.GetSectorCount()));
 
   // Reset KVS
   subsector_kvs.Disable();
-  ASSERT_OK(subsector_kvs.Enable());
+  ASSERT_EQ(Status::OK, subsector_kvs.Enable());
 
   // Store as much data as possible in the KVS until it fills up.
   uint64_t test = 0;
@@ -123,8 +123,8 @@
   // Even though we failed to fill the KVS, it still works, and we
   // should have the previous test value as the most recent value in the KVS.
   uint64_t value = 0;
-  ASSERT_OK(subsector_kvs.Get(keys[0], &value));
+  ASSERT_EQ(Status::OK, subsector_kvs.Get(keys[0], &value));
   EXPECT_EQ(test - 1, value);
 }
 
-}  // namespace pw
+}  // namespace pw::kvs
diff --git a/pw_kvs/key_value_store_test.cc b/pw_kvs/key_value_store_test.cc
index fa5eaf9..92bc6a5 100644
--- a/pw_kvs/key_value_store_test.cc
+++ b/pw_kvs/key_value_store_test.cc
@@ -14,21 +14,22 @@
 
 #include "pw_kvs/key_value_store.h"
 
+#include "pw_span/span.h"
+
+#define USE_MEMORY_BUFFER 1
+
+#include "gtest/gtest.h"
+#include "pw_checksum/ccitt_crc16.h"
 #include "pw_kvs/assert.h"
-#include "pw_kvs/devices/flash_memory.h"
-#include "pw_kvs/os/stack_checks.h"
-#include "pw_kvs/platform/board.h"
-#include "pw_kvs/status.h"
-#include "pw_kvs/test/fixture.h"
-#include "pw_kvs/test/framework.h"
-#include "pw_kvs/test/status_macros.h"
-#include "pw_kvs/util/ccitt_crc16.h"
+#include "pw_kvs/flash_memory.h"
+#include "pw_status/status.h"
+#include "pw_string/util.h"
 
 #if USE_MEMORY_BUFFER
-#include "pw_kvs/test/fakes/in_memory_fake_flash.h"
+#include "pw_kvs/in_memory_fake_flash.h"
 #endif  // USE_MEMORY_BUFFER
 
-namespace pw {
+namespace pw::kvs {
 namespace {
 
 #if USE_MEMORY_BUFFER
@@ -41,8 +42,8 @@
 FlashPartition large_test_partition(&large_test_flash,
                                     0,
                                     large_test_flash.GetSectorCount());
-#else   // Device test
-FlashPartition& test_partition = Board::Instance().FlashExternalTestPartition();
+#else   // TODO: Test with real flash
+FlashPartition& test_partition = FlashExternalTestPartition();
 #endif  // USE_MEMORY_BUFFER
 
 KeyValueStore kvs(&test_partition);
@@ -65,13 +66,19 @@
   static constexpr uint16_t kMaxAlignmentBytes = 128;
   uint8_t alignment_buffer[kMaxAlignmentBytes] = {0};
   uint16_t aligned_bytes = size - (size % partition->GetAlignmentBytes());
-  RETURN_IF_ERROR(partition->Write(address, buf, aligned_bytes));
+  if (Status status = partition->Write(address, buf, aligned_bytes);
+      !status.ok()) {
+    return status;
+  }
   uint16_t remaining_bytes = size - aligned_bytes;
   if (remaining_bytes > 0) {
     memcpy(alignment_buffer, &buf[aligned_bytes], remaining_bytes);
-    RETURN_IF_ERROR(partition->Write(address + aligned_bytes,
-                                     alignment_buffer,
-                                     partition->GetAlignmentBytes()));
+    if (Status status = partition->Write(address + aligned_bytes,
+                                         alignment_buffer,
+                                         partition->GetAlignmentBytes());
+        !status.ok()) {
+      return status;
+    }
   }
   return Status::OK;
 }
@@ -138,51 +145,51 @@
   memset(buffer.data(), 0, buffer.size());
   while (size_to_fill > 0) {
     buffer[0]++;  // Changing buffer value so put actually does something
-    ASSERT_OK(
+    ASSERT_EQ(
+        Status::OK,
         kvs.Put(key,
                 buffer.data(),
                 chunk_len - kvs_attr.ChunkHeaderSize() - kvs_attr.KeySize()));
     size_to_fill -= chunk_len;
     chunk_len = std::min(size_to_fill, kMaxPutSize);
   }
-  ASSERT_OK(kvs.Erase(key));
+  ASSERT_EQ(Status::OK, kvs.Erase(key));
 }
 
 uint16_t CalcKvsCrc(const char* key, const void* data, size_t data_len) {
-  CcittCrc16 crc;
   static constexpr size_t kChunkKeyLengthMax = 15;
-  crc.AppendBytes(
-      ConstBuffer(reinterpret_cast<const uint8_t*>(key),
-                  pw::util::StringLength(key, kChunkKeyLengthMax)));
-  return crc.AppendBytes(
-      ConstBuffer(reinterpret_cast<const uint8_t*>(data), data_len));
+  uint16_t crc = checksum::CcittCrc16(
+      as_bytes(span(key, string::Length(key, kChunkKeyLengthMax))));
+  return checksum::CcittCrc16(
+      span(static_cast<const std::byte*>(data), data_len), crc);
 }
 
 uint16_t CalcTestPartitionCrc() {
   uint8_t buf[16];  // Read as 16 byte chunks
   CHECK_EQ(sizeof(buf) % test_partition.GetAlignmentBytes(), 0);
   CHECK_EQ(test_partition.GetSizeBytes() % sizeof(buf), 0);
-  CcittCrc16 crc;
+  uint16_t crc = checksum::kCcittCrc16DefaultInitialValue;
   for (size_t i = 0; i < test_partition.GetSizeBytes(); i += sizeof(buf)) {
     test_partition.Read(buf, i, sizeof(buf));
-    crc.AppendBytes(ConstBuffer(buf, sizeof(buf)));
+    crc = checksum::CcittCrc16(as_bytes(span(buf)), crc);
   }
-  return crc.CurrentValue();
+  return crc;
 }
 }  // namespace
 
 TEST_F(KeyValueStoreTest, FuzzTest) {
   if (test_partition.GetSectorSizeBytes() < 4 * 1024 ||
       test_partition.GetSectorCount() < 4) {
-    LOG_INFO("Sectors too small, skipping test.");
+    PW_LOG_INFO("Sectors too small, skipping test.");
     return;  // TODO: Test could be generalized
   }
   // Erase
-  ASSERT_OK(test_partition.Erase(0, test_partition.GetSectorCount()));
+  ASSERT_EQ(Status::OK,
+            test_partition.Erase(0, test_partition.GetSectorCount()));
 
   // Reset KVS
   kvs.Disable();
-  ASSERT_OK(kvs.Enable());
+  ASSERT_EQ(Status::OK, kvs.Enable());
   const char* key1 = "Buf1";
   const char* key2 = "Buf2";
   const size_t kLargestBufSize = 3 * 1024;
@@ -192,10 +199,10 @@
   memset(buf2, 2, sizeof(buf2));
 
   // Start with things in KVS
-  ASSERT_OK(kvs.Put(key1, buf1, sizeof(buf1)));
-  ASSERT_OK(kvs.Put(key2, buf2, sizeof(buf2)));
+  ASSERT_EQ(Status::OK, kvs.Put(key1, buf1, sizeof(buf1)));
+  ASSERT_EQ(Status::OK, kvs.Put(key2, buf2, sizeof(buf2)));
   for (size_t j = 0; j < keys.size(); j++) {
-    ASSERT_OK(kvs.Put(keys[j], j));
+    ASSERT_EQ(Status::OK, kvs.Put(keys[j], j));
   }
 
   for (size_t i = 0; i < 100; i++) {
@@ -204,29 +211,29 @@
     size_t size2 = (kLargestBufSize) / (100 - i);
     for (size_t j = 0; j < 50; j++) {
       // Rewrite a single key many times, can fill up a sector
-      ASSERT_OK(kvs.Put("some_data", j));
+      ASSERT_EQ(Status::OK, kvs.Put("some_data", j));
     }
     // Delete and re-add everything
-    ASSERT_OK(kvs.Erase(key1));
-    ASSERT_OK(kvs.Put(key1, buf1, size1));
-    ASSERT_OK(kvs.Erase(key2));
-    ASSERT_OK(kvs.Put(key2, buf2, size2));
+    ASSERT_EQ(Status::OK, kvs.Erase(key1));
+    ASSERT_EQ(Status::OK, kvs.Put(key1, buf1, size1));
+    ASSERT_EQ(Status::OK, kvs.Erase(key2));
+    ASSERT_EQ(Status::OK, kvs.Put(key2, buf2, size2));
     for (size_t j = 0; j < keys.size(); j++) {
-      ASSERT_OK(kvs.Erase(keys[j]));
-      ASSERT_OK(kvs.Put(keys[j], j));
+      ASSERT_EQ(Status::OK, kvs.Erase(keys[j]));
+      ASSERT_EQ(Status::OK, kvs.Put(keys[j], j));
     }
 
     // Re-enable and verify
     kvs.Disable();
-    ASSERT_OK(kvs.Enable());
+    ASSERT_EQ(Status::OK, kvs.Enable());
     static uint8_t buf[4 * 1024];
-    ASSERT_OK(kvs.Get(key1, buf, size1));
+    ASSERT_EQ(Status::OK, kvs.Get(key1, buf, size1));
     ASSERT_EQ(memcmp(buf, buf1, size1), 0);
-    ASSERT_OK(kvs.Get(key2, buf, size2));
+    ASSERT_EQ(Status::OK, kvs.Get(key2, buf, size2));
     ASSERT_EQ(memcmp(buf2, buf2, size2), 0);
     for (size_t j = 0; j < keys.size(); j++) {
       size_t ret = 1000;
-      ASSERT_OK(kvs.Get(keys[j], &ret));
+      ASSERT_EQ(Status::OK, kvs.Get(keys[j], &ret));
       ASSERT_EQ(ret, j);
     }
   }
@@ -234,40 +241,44 @@
 
 TEST_F(KeyValueStoreTest, Basic) {
   // Erase
-  ASSERT_OK(test_partition.Erase(0, test_partition.GetSectorCount()));
+  ASSERT_EQ(Status::OK,
+            test_partition.Erase(0, test_partition.GetSectorCount()));
 
   // Reset KVS
   kvs.Disable();
-  ASSERT_OK(kvs.Enable());
+  ASSERT_EQ(Status::OK, kvs.Enable());
 
   // Add some data
   uint8_t value1 = 0xDA;
-  ASSERT_OK(kvs.Put(keys[0], &value1, sizeof(value1)));
+  ASSERT_EQ(Status::OK, kvs.Put(keys[0], &value1, sizeof(value1)));
 
   uint32_t value2 = 0xBAD0301f;
-  ASSERT_OK(
+  ASSERT_EQ(
+      Status::OK,
       kvs.Put(keys[1], reinterpret_cast<uint8_t*>(&value2), sizeof(value2)));
 
   // Verify data
   uint32_t test2;
-  EXPECT_OK(
+  EXPECT_EQ(
+      Status::OK,
       kvs.Get(keys[1], reinterpret_cast<uint8_t*>(&test2), sizeof(test2)));
   uint8_t test1;
-  ASSERT_OK(
+  ASSERT_EQ(
+      Status::OK,
       kvs.Get(keys[0], reinterpret_cast<uint8_t*>(&test1), sizeof(test1)));
 
   EXPECT_EQ(test1, value1);
   EXPECT_EQ(test2, value2);
 
   // Erase a key
-  EXPECT_OK(kvs.Erase(keys[0]));
+  EXPECT_EQ(Status::OK, kvs.Erase(keys[0]));
 
   // Verify it was erased
-  EXPECT_EQ(kvs.Get(keys[0], reinterpret_cast<uint8_t*>(&test1), sizeof(test1))
-                .code(),
+  EXPECT_EQ(kvs.Get(keys[0], reinterpret_cast<uint8_t*>(&test1), sizeof(test1)),
             Status::NOT_FOUND);
   test2 = 0;
-  ASSERT_OK(
+  ASSERT_EQ(
+      Status::OK,
       kvs.Get(keys[1], reinterpret_cast<uint8_t*>(&test2), sizeof(test2)));
   EXPECT_EQ(test2, value2);
 
@@ -280,27 +291,28 @@
 
 TEST_F(KeyValueStoreTest, MaxKeyLength) {
   // Erase
-  ASSERT_OK(test_partition.Erase(0, test_partition.GetSectorCount()));
+  ASSERT_EQ(Status::OK,
+            test_partition.Erase(0, test_partition.GetSectorCount()));
 
   // Reset KVS
   kvs.Disable();
-  ASSERT_OK(kvs.Enable());
+  ASSERT_EQ(Status::OK, kvs.Enable());
 
   // Add some data
   char key[16] = "123456789abcdef";  // key length 15 (without \0)
   int value = 1;
-  ASSERT_OK(kvs.Put(key, value));
+  ASSERT_EQ(Status::OK, kvs.Put(key, value));
 
   // Verify data
   int test = 0;
-  ASSERT_OK(kvs.Get(key, &test));
+  ASSERT_EQ(Status::OK, kvs.Get(key, &test));
   EXPECT_EQ(test, value);
 
   // Erase a key
   kvs.Erase(key);
 
   // Verify it was erased
-  EXPECT_EQ(kvs.Get(key, &test).code(), Status::NOT_FOUND);
+  EXPECT_EQ(kvs.Get(key, &test), Status::NOT_FOUND);
 }
 
 TEST_F(KeyValueStoreTest, LargeBuffers) {
@@ -321,21 +333,22 @@
   const size_t kAvailSectorSpace = test_partition.GetSectorSizeBytes() *
                                    (test_partition.GetSectorCount() - 1);
   if (kAvailSectorSpace < kMinSize) {
-    LOG_INFO("KVS too small, skipping test.");
+    PW_LOG_INFO("KVS too small, skipping test.");
     return;
   }
   // Reset KVS
   kvs.Disable();
-  ASSERT_OK(kvs.Enable());
+  ASSERT_EQ(Status::OK, kvs.Enable());
 
   // Add and verify
   for (unsigned add_idx = 0; add_idx < keys.size(); add_idx++) {
     memset(buffer.data(), add_idx, buffer.size());
-    ASSERT_OK(kvs.Put(keys[add_idx], buffer.data(), buffer.size()));
+    ASSERT_EQ(Status::OK, kvs.Put(keys[add_idx], buffer.data(), buffer.size()));
     EXPECT_EQ(kvs.KeyCount(), add_idx + 1);
     for (unsigned verify_idx = 0; verify_idx <= add_idx; verify_idx++) {
       memset(buffer.data(), 0, buffer.size());
-      ASSERT_OK(kvs.Get(keys[verify_idx], buffer.data(), buffer.size()));
+      ASSERT_EQ(Status::OK,
+                kvs.Get(keys[verify_idx], buffer.data(), buffer.size()));
       for (unsigned i = 0; i < buffer.size(); i++) {
         EXPECT_EQ(buffer[i], verify_idx);
       }
@@ -344,16 +357,16 @@
 
   // Erase and verify
   for (unsigned erase_idx = 0; erase_idx < keys.size(); erase_idx++) {
-    ASSERT_OK(kvs.Erase(keys[erase_idx]));
+    ASSERT_EQ(Status::OK, kvs.Erase(keys[erase_idx]));
     EXPECT_EQ(kvs.KeyCount(), keys.size() - erase_idx - 1);
     for (unsigned verify_idx = 0; verify_idx < keys.size(); verify_idx++) {
       memset(buffer.data(), 0, buffer.size());
       if (verify_idx <= erase_idx) {
-        ASSERT_EQ(
-            kvs.Get(keys[verify_idx], buffer.data(), buffer.size()).code(),
-            Status::NOT_FOUND);
+        ASSERT_EQ(kvs.Get(keys[verify_idx], buffer.data(), buffer.size()),
+                  Status::NOT_FOUND);
       } else {
-        ASSERT_OK(kvs.Get(keys[verify_idx], buffer.data(), buffer.size()));
+        ASSERT_EQ(Status::OK,
+                  kvs.Get(keys[verify_idx], buffer.data(), buffer.size()));
         for (uint32_t i = 0; i < buffer.size(); i++) {
           EXPECT_EQ(buffer[i], verify_idx);
         }
@@ -377,39 +390,40 @@
   const size_t kAvailSectorSpace = test_partition.GetSectorSizeBytes() *
                                    (test_partition.GetSectorCount() - 1);
   if (kAvailSectorSpace < kMinSize) {
-    LOG_INFO("KVS too small, skipping test.");
+    PW_LOG_INFO("KVS too small, skipping test.");
     return;
   }
 
   // Reset KVS
   kvs.Disable();
-  ASSERT_OK(kvs.Enable());
+  ASSERT_EQ(Status::OK, kvs.Enable());
 
   // Add some items
   for (unsigned add_idx = 0; add_idx < keys.size(); add_idx++) {
     memset(buffer.data(), add_idx, buffer.size());
-    ASSERT_OK(kvs.Put(keys[add_idx], buffer.data(), buffer.size()));
+    ASSERT_EQ(Status::OK, kvs.Put(keys[add_idx], buffer.data(), buffer.size()));
     EXPECT_EQ(kvs.KeyCount(), add_idx + 1);
   }
 
   // Enable different KVS which should be able to properly setup the same map
   // from what is stored in flash.
-  ASSERT_OK(kvs_local_.Enable());
+  ASSERT_EQ(Status::OK, kvs_local_.Enable());
   EXPECT_EQ(kvs_local_.KeyCount(), keys.size());
 
   // Ensure adding to new KVS works
   uint8_t value = 0xDA;
   const char* key = "new_key";
-  ASSERT_OK(kvs_local_.Put(key, &value, sizeof(value)));
+  ASSERT_EQ(Status::OK, kvs_local_.Put(key, &value, sizeof(value)));
   uint8_t test;
-  ASSERT_OK(kvs_local_.Get(key, &test, sizeof(test)));
+  ASSERT_EQ(Status::OK, kvs_local_.Get(key, &test, sizeof(test)));
   EXPECT_EQ(value, test);
   EXPECT_EQ(kvs_local_.KeyCount(), keys.size() + 1);
 
   // Verify previous data
   for (unsigned verify_idx = 0; verify_idx < keys.size(); verify_idx++) {
     memset(buffer.data(), 0, buffer.size());
-    ASSERT_OK(kvs_local_.Get(keys[verify_idx], buffer.data(), buffer.size()));
+    ASSERT_EQ(Status::OK,
+              kvs_local_.Get(keys[verify_idx], buffer.data(), buffer.size()));
     for (uint32_t i = 0; i < buffer.size(); i++) {
       EXPECT_EQ(buffer[i], verify_idx);
     }
@@ -421,18 +435,18 @@
 
   // Reset KVS
   kvs.Disable();
-  ASSERT_OK(kvs.Enable());
+  ASSERT_EQ(Status::OK, kvs.Enable());
 
   // Calculate number of elements to ensure multiple sectors are required.
   uint16_t add_count =
       (test_partition.GetSectorSizeBytes() / buffer.size()) + 1;
 
   if (kvs.GetMaxKeys() < add_count) {
-    LOG_INFO("Sector size too large, skipping test.");
+    PW_LOG_INFO("Sector size too large, skipping test.");
     return;  // this chip has very large sectors, test won't work
   }
   if (test_partition.GetSectorCount() < 3) {
-    LOG_INFO("Not enough sectors, skipping test.");
+    PW_LOG_INFO("Not enough sectors, skipping test.");
     return;  // need at least 3 sectors for multi-sector test
   }
 
@@ -440,14 +454,14 @@
   for (unsigned add_idx = 0; add_idx < add_count; add_idx++) {
     memset(buffer.data(), add_idx, buffer.size());
     snprintf(key, sizeof(key), "key_%u", add_idx);
-    ASSERT_OK(kvs.Put(key, buffer.data(), buffer.size()));
+    ASSERT_EQ(Status::OK, kvs.Put(key, buffer.data(), buffer.size()));
     EXPECT_EQ(kvs.KeyCount(), add_idx + 1);
   }
 
   for (unsigned verify_idx = 0; verify_idx < add_count; verify_idx++) {
     memset(buffer.data(), 0, buffer.size());
     snprintf(key, sizeof(key), "key_%u", verify_idx);
-    ASSERT_OK(kvs.Get(key, buffer.data(), buffer.size()));
+    ASSERT_EQ(Status::OK, kvs.Get(key, buffer.data(), buffer.size()));
     for (uint32_t i = 0; i < buffer.size(); i++) {
       EXPECT_EQ(buffer[i], verify_idx);
     }
@@ -456,7 +470,7 @@
   // Check erase
   for (unsigned erase_idx = 0; erase_idx < add_count; erase_idx++) {
     snprintf(key, sizeof(key), "key_%u", erase_idx);
-    ASSERT_OK(kvs.Erase(key));
+    ASSERT_EQ(Status::OK, kvs.Erase(key));
     EXPECT_EQ(kvs.KeyCount(), add_count - erase_idx - 1);
   }
 }
@@ -466,24 +480,26 @@
 
   // Reset KVS
   kvs.Disable();
-  ASSERT_OK(kvs.Enable());
+  ASSERT_EQ(Status::OK, kvs.Enable());
 
   // Write first value
   const uint8_t kValue1 = 0xDA;
   const uint8_t kValue2 = 0x12;
   const char* key = "the_key";
-  ASSERT_OK(kvs.Put(key, &kValue1, sizeof(kValue1)));
+  ASSERT_EQ(Status::OK, kvs.Put(key, &kValue1, sizeof(kValue1)));
 
   // Verify
   uint8_t value;
-  ASSERT_OK(kvs.Get(key, reinterpret_cast<uint8_t*>(&value), sizeof(value)));
+  ASSERT_EQ(Status::OK,
+            kvs.Get(key, reinterpret_cast<uint8_t*>(&value), sizeof(value)));
   EXPECT_EQ(kValue1, value);
 
   // Write new value for key
-  ASSERT_OK(kvs.Put(key, &kValue2, sizeof(kValue2)));
+  ASSERT_EQ(Status::OK, kvs.Put(key, &kValue2, sizeof(kValue2)));
 
   // Verify
-  ASSERT_OK(kvs.Get(key, reinterpret_cast<uint8_t*>(&value), sizeof(value)));
+  ASSERT_EQ(Status::OK,
+            kvs.Get(key, reinterpret_cast<uint8_t*>(&value), sizeof(value)));
   EXPECT_EQ(kValue2, value);
 
   // Verify only 1 element exists
@@ -495,7 +511,7 @@
 
   // Reset KVS
   kvs.Disable();
-  ASSERT_OK(kvs.Enable());
+  ASSERT_EQ(Status::OK, kvs.Enable());
 
   const char* key = "the_key";
   constexpr uint8_t kReadSize = 16;  // needs to be a multiple of alignment
@@ -507,13 +523,14 @@
   for (uint8_t i = 0; i < kTestBufferSize; i++) {
     buffer[i] = i;
   }
-  ASSERT_OK(kvs.Put(key, buffer.data(), kTestBufferSize));
+  ASSERT_EQ(Status::OK, kvs.Put(key, buffer.data(), kTestBufferSize));
   EXPECT_EQ(kvs.KeyCount(), 1);
 
   // Read in small chunks and verify
   for (int i = 0; i < kTestBufferSize / kReadSize; i++) {
     memset(buffer.data(), 0, buffer.size());
-    ASSERT_OK(kvs.Get(key, buffer.data(), kReadSize, i * kReadSize));
+    ASSERT_EQ(Status::OK,
+              kvs.Get(key, buffer.data(), kReadSize, i * kReadSize));
     for (unsigned j = 0; j < kReadSize; j++) {
       ASSERT_EQ(buffer[j], j + i * kReadSize);
     }
@@ -526,7 +543,7 @@
 
   // Reset KVS
   kvs.Disable();
-  ASSERT_OK(kvs.Enable());
+  ASSERT_EQ(Status::OK, kvs.Enable());
 
   // Calculate number of elements to ensure multiple sectors are required.
   unsigned add_count =
@@ -540,13 +557,13 @@
     if (add_idx == add_count - 1) {  // last value
       memset(buffer.data(), kGoodVal, buffer.size());
     }
-    ASSERT_OK(kvs.Put(key, buffer.data(), buffer.size()));
+    ASSERT_EQ(Status::OK, kvs.Put(key, buffer.data(), buffer.size()));
     EXPECT_EQ(kvs.KeyCount(), 1);
   }
 
   // Verify
   memset(buffer.data(), 0, buffer.size());
-  ASSERT_OK(kvs.Get(key, buffer.data(), buffer.size()));
+  ASSERT_EQ(Status::OK, kvs.Get(key, buffer.data(), buffer.size()));
   for (uint32_t i = 0; i < buffer.size(); i++) {
     ASSERT_EQ(buffer[i], kGoodVal);
   }
@@ -559,7 +576,7 @@
 
   // Reset KVS
   kvs.Disable();
-  ASSERT_OK(kvs.Enable());
+  ASSERT_EQ(Status::OK, kvs.Enable());
 
   ASSERT_EQ(std::strlen(keys[0]), 8U);  // Easier for alignment
   ASSERT_EQ(std::strlen(keys[2]), 8U);  // Easier for alignment
@@ -570,13 +587,13 @@
   constexpr uint8_t kKey0Pattern = 0xBA;
 
   memset(buffer.data(), kKey0Pattern, kvs_attr.DataSize());
-  ASSERT_OK(kvs.Put(keys[0], buffer.data(), kvs_attr.DataSize()));
+  ASSERT_EQ(Status::OK, kvs.Put(keys[0], buffer.data(), kvs_attr.DataSize()));
   bytes_remaining -= kvs_attr.MinPutSize();
   memset(buffer.data(), 1, kvs_attr.DataSize());
-  ASSERT_OK(kvs.Put(keys[2], buffer.data(), kvs_attr.DataSize()));
+  ASSERT_EQ(Status::OK, kvs.Put(keys[2], buffer.data(), kvs_attr.DataSize()));
   bytes_remaining -= kvs_attr.MinPutSize();
   EXPECT_EQ(kvs.KeyCount(), 2);
-  ASSERT_OK(kvs.Erase(keys[2]));
+  ASSERT_EQ(Status::OK, kvs.Erase(keys[2]));
   bytes_remaining -= kvs_attr.EraseSize();
   EXPECT_EQ(kvs.KeyCount(), 1);
 
@@ -586,7 +603,7 @@
 
   // Verify key[0]
   memset(buffer.data(), 0, kvs_attr.DataSize());
-  ASSERT_OK(kvs.Get(keys[0], buffer.data(), kvs_attr.DataSize()));
+  ASSERT_EQ(Status::OK, kvs.Get(keys[0], buffer.data(), kvs_attr.DataSize()));
   for (uint32_t i = 0; i < kvs_attr.DataSize(); i++) {
     EXPECT_EQ(buffer[i], kKey0Pattern);
   }
@@ -597,19 +614,19 @@
 
   // Reset KVS
   kvs.Disable();
-  ASSERT_OK(kvs.Enable());
+  ASSERT_EQ(Status::OK, kvs.Enable());
 
   const uint8_t kValue1 = 0xDA;
   const uint8_t kValue2 = 0x12;
   uint8_t value[1];
-  ASSERT_OK(kvs.Put(keys[0], &kValue1, sizeof(kValue1)));
+  ASSERT_EQ(Status::OK, kvs.Put(keys[0], &kValue1, sizeof(kValue1)));
   EXPECT_EQ(kvs.KeyCount(), 1);
-  ASSERT_OK(kvs.Erase(keys[0]));
+  ASSERT_EQ(Status::OK, kvs.Erase(keys[0]));
   EXPECT_EQ(kvs.Get(keys[0], value, sizeof(value)), Status::NOT_FOUND);
-  ASSERT_OK(kvs.Put(keys[1], &kValue1, sizeof(kValue1)));
-  ASSERT_OK(kvs.Put(keys[2], &kValue2, sizeof(kValue2)));
-  ASSERT_OK(kvs.Erase(keys[1]));
-  EXPECT_OK(kvs.Get(keys[2], value, sizeof(value)));
+  ASSERT_EQ(Status::OK, kvs.Put(keys[1], &kValue1, sizeof(kValue1)));
+  ASSERT_EQ(Status::OK, kvs.Put(keys[2], &kValue2, sizeof(kValue2)));
+  ASSERT_EQ(Status::OK, kvs.Erase(keys[1]));
+  EXPECT_EQ(Status::OK, kvs.Get(keys[2], value, sizeof(value)));
   EXPECT_EQ(kValue2, value[0]);
 
   EXPECT_EQ(kvs.KeyCount(), 1);
@@ -670,38 +687,48 @@
       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Alignment to 16
   };
   // clang-format on
-  ASSERT_OK(test_partition.Erase(0, test_partition.GetSectorCount()));
+  ASSERT_EQ(Status::OK,
+            test_partition.Erase(0, test_partition.GetSectorCount()));
 
   // We don't actually care about the size values provided, since we are only
   // using kvs_attr to get Sector Size
   KvsAttributes kvs_attr(8, 8);
   if (test_partition.GetAlignmentBytes() == 1) {
-    ASSERT_OK(test_partition.Write(
-        0, kKvsTestDataAligned1Top, sizeof(kKvsTestDataAligned1Top)));
-    ASSERT_OK(test_partition.Write(kvs_attr.SectorHeaderSize(),
+    ASSERT_EQ(Status::OK,
+              test_partition.Write(
+                  0, kKvsTestDataAligned1Top, sizeof(kKvsTestDataAligned1Top)));
+    ASSERT_EQ(Status::OK,
+              test_partition.Write(kvs_attr.SectorHeaderSize(),
                                    kKvsTestDataAligned1Bottom,
                                    sizeof(kKvsTestDataAligned1Bottom)));
   } else if (test_partition.GetAlignmentBytes() == 2) {
-    ASSERT_OK(test_partition.Write(
-        0, kKvsTestDataAligned2Top, sizeof(kKvsTestDataAligned2Top)));
-    ASSERT_OK(test_partition.Write(kvs_attr.SectorHeaderSize(),
+    ASSERT_EQ(Status::OK,
+              test_partition.Write(
+                  0, kKvsTestDataAligned2Top, sizeof(kKvsTestDataAligned2Top)));
+    ASSERT_EQ(Status::OK,
+              test_partition.Write(kvs_attr.SectorHeaderSize(),
                                    kKvsTestDataAligned2Bottom,
                                    sizeof(kKvsTestDataAligned2Bottom)));
   } else if (test_partition.GetAlignmentBytes() == 8) {
-    ASSERT_OK(test_partition.Write(
-        0, kKvsTestDataAligned8Top, sizeof(kKvsTestDataAligned8Top)));
-    ASSERT_OK(test_partition.Write(kvs_attr.SectorHeaderSize(),
+    ASSERT_EQ(Status::OK,
+              test_partition.Write(
+                  0, kKvsTestDataAligned8Top, sizeof(kKvsTestDataAligned8Top)));
+    ASSERT_EQ(Status::OK,
+              test_partition.Write(kvs_attr.SectorHeaderSize(),
                                    kKvsTestDataAligned8Bottom,
                                    sizeof(kKvsTestDataAligned8Bottom)));
   } else if (test_partition.GetAlignmentBytes() == 16) {
-    ASSERT_OK(test_partition.Write(
-        0, kKvsTestDataAligned16Top, sizeof(kKvsTestDataAligned16Top)));
-    ASSERT_OK(test_partition.Write(kvs_attr.SectorHeaderSize(),
+    ASSERT_EQ(
+        Status::OK,
+        test_partition.Write(
+            0, kKvsTestDataAligned16Top, sizeof(kKvsTestDataAligned16Top)));
+    ASSERT_EQ(Status::OK,
+              test_partition.Write(kvs_attr.SectorHeaderSize(),
                                    kKvsTestDataAligned16Bottom,
                                    sizeof(kKvsTestDataAligned16Bottom)));
   } else {
-    LOG_ERROR("Test only supports 1, 2, 8 and 16 byte alignments.");
-    ASSERT_OK(false);
+    PW_LOG_ERROR("Test only supports 1, 2, 8 and 16 byte alignments.");
+    ASSERT_EQ(Status::OK, false);
   }
 
   EXPECT_EQ(kvs_local_.Enable(), Status::OK);
@@ -711,21 +738,22 @@
 
   // Value with correct CRC should still be available.
   uint32_t test2 = 0;
-  ASSERT_OK(kvs_local_.Get(
-      keys[1], reinterpret_cast<uint8_t*>(&test2), sizeof(test2)));
+  ASSERT_EQ(Status::OK,
+            kvs_local_.Get(
+                keys[1], reinterpret_cast<uint8_t*>(&test2), sizeof(test2)));
   EXPECT_EQ(kTestPattern, test2);
 
   // Test rewriting over corrupted data.
-  ASSERT_OK(kvs_local_.Put(keys[0], kTestPattern));
+  ASSERT_EQ(Status::OK, kvs_local_.Put(keys[0], kTestPattern));
   test2 = 0;
-  EXPECT_OK(kvs_local_.Get(keys[0], &test2));
+  EXPECT_EQ(Status::OK, kvs_local_.Get(keys[0], &test2));
   EXPECT_EQ(kTestPattern, test2);
 
   // Check correct when re-enabled
   kvs_local_.Disable();
   EXPECT_EQ(kvs_local_.Enable(), Status::OK);
   test2 = 0;
-  EXPECT_OK(kvs_local_.Get(keys[0], &test2));
+  EXPECT_EQ(Status::OK, kvs_local_.Get(keys[0], &test2));
   EXPECT_EQ(kTestPattern, test2);
 }
 
@@ -744,10 +772,11 @@
     // Test only runs on 1 byte alignment partitions
     test_partition.Erase(0, test_partition.GetSectorCount());
     test_partition.Write(0, kKvsTestDataAligned1, sizeof(kKvsTestDataAligned1));
-    EXPECT_OK(kvs_local_.Enable());
+    EXPECT_EQ(Status::OK, kvs_local_.Enable());
     uint32_t test2 = 0;
-    ASSERT_OK(kvs_local_.Get(
-        keys[1], reinterpret_cast<uint8_t*>(&test2), sizeof(test2)));
+    ASSERT_EQ(Status::OK,
+              kvs_local_.Get(
+                  keys[1], reinterpret_cast<uint8_t*>(&test2), sizeof(test2)));
     EXPECT_EQ(kTestPattern, test2);
   }
 }
@@ -757,16 +786,17 @@
 
   // Reset KVS
   kvs.Disable();
-  ASSERT_OK(kvs.Enable());
+  ASSERT_EQ(Status::OK, kvs.Enable());
   kvs.Disable();
 
-  EXPECT_OK(kvs_local_.Enable());
+  EXPECT_EQ(Status::OK, kvs_local_.Enable());
   // Write value
   const uint8_t kValue = 0xDA;
-  ASSERT_OK(kvs_local_.Put(keys[0], &kValue, sizeof(kValue)));
+  ASSERT_EQ(Status::OK, kvs_local_.Put(keys[0], &kValue, sizeof(kValue)));
   uint8_t value;
-  ASSERT_OK(kvs_local_.Get(
-      keys[0], reinterpret_cast<uint8_t*>(&value), sizeof(value)));
+  ASSERT_EQ(Status::OK,
+            kvs_local_.Get(
+                keys[0], reinterpret_cast<uint8_t*>(&value), sizeof(value)));
 
   // Verify
   EXPECT_EQ(kValue, value);
@@ -777,19 +807,19 @@
 
   // Reset KVS
   kvs.Disable();
-  ASSERT_OK(kvs.Enable());
+  ASSERT_EQ(Status::OK, kvs.Enable());
 
   // Write value
   const uint8_t kValue = 0xDA;
-  ASSERT_OK(kvs.Put(keys[0], &kValue, sizeof(kValue)));
+  ASSERT_EQ(Status::OK, kvs.Put(keys[0], &kValue, sizeof(kValue)));
 
-  ASSERT_OK(kvs.Erase(keys[0]));
+  ASSERT_EQ(Status::OK, kvs.Erase(keys[0]));
   uint8_t value[1];
   ASSERT_EQ(kvs.Get(keys[0], value, sizeof(value)), Status::NOT_FOUND);
 
   // Reset KVS, ensure captured at enable
   kvs.Disable();
-  ASSERT_OK(kvs.Enable());
+  ASSERT_EQ(Status::OK, kvs.Enable());
 
   ASSERT_EQ(kvs.Get(keys[0], value, sizeof(value)), Status::NOT_FOUND);
 }
@@ -798,14 +828,14 @@
   test_partition.Erase(0, test_partition.GetSectorCount());
   // Reset KVS
   kvs.Disable();
-  ASSERT_OK(kvs.Enable());
+  ASSERT_EQ(Status::OK, kvs.Enable());
   // Store a value with the convenience method.
   const uint32_t kValue = 0x12345678;
-  ASSERT_OK(kvs.Put(keys[0], kValue));
+  ASSERT_EQ(Status::OK, kvs.Put(keys[0], kValue));
 
   // Read it back with the other convenience method.
   uint32_t value;
-  ASSERT_OK(kvs.Get(keys[0], &value));
+  ASSERT_EQ(Status::OK, kvs.Get(keys[0], &value));
   ASSERT_EQ(kValue, value);
 
   // Make sure we cannot get something where size isn't what we expect
@@ -854,53 +884,64 @@
   };
   // clang-format on
 
-  ASSERT_OK(test_partition.Erase(0, test_partition.GetSectorCount()));
+  ASSERT_EQ(Status::OK,
+            test_partition.Erase(0, test_partition.GetSectorCount()));
   // We don't actually care about the size values provided, since we are only
   // using kvs_attr to get Sector Size
   KvsAttributes kvs_attr(8, 8);
-  pw::FlashPartition::Address address = kvs_attr.SectorHeaderSize();
+  FlashPartition::Address address = kvs_attr.SectorHeaderSize();
   if (test_partition.GetAlignmentBytes() == 1) {
-    ASSERT_OK(test_partition.Write(
-        0, kKvsTestDataAligned1Top, sizeof(kKvsTestDataAligned1Top)));
-    ASSERT_OK(test_partition.Write(address,
+    ASSERT_EQ(Status::OK,
+              test_partition.Write(
+                  0, kKvsTestDataAligned1Top, sizeof(kKvsTestDataAligned1Top)));
+    ASSERT_EQ(Status::OK,
+              test_partition.Write(address,
                                    kKvsTestDataAligned1Bottom,
                                    sizeof(kKvsTestDataAligned1Bottom)));
     address += sizeof(kKvsTestDataAligned1Bottom);
   } else if (test_partition.GetAlignmentBytes() == 2) {
-    ASSERT_OK(test_partition.Write(
-        0, kKvsTestDataAligned2Top, sizeof(kKvsTestDataAligned2Top)));
-    ASSERT_OK(test_partition.Write(address,
+    ASSERT_EQ(Status::OK,
+              test_partition.Write(
+                  0, kKvsTestDataAligned2Top, sizeof(kKvsTestDataAligned2Top)));
+    ASSERT_EQ(Status::OK,
+              test_partition.Write(address,
                                    kKvsTestDataAligned2Bottom,
                                    sizeof(kKvsTestDataAligned2Bottom)));
     address += sizeof(kKvsTestDataAligned2Bottom);
   } else if (test_partition.GetAlignmentBytes() == 8) {
-    ASSERT_OK(test_partition.Write(
-        0, kKvsTestDataAligned8Top, sizeof(kKvsTestDataAligned8Top)));
-    ASSERT_OK(test_partition.Write(address,
+    ASSERT_EQ(Status::OK,
+              test_partition.Write(
+                  0, kKvsTestDataAligned8Top, sizeof(kKvsTestDataAligned8Top)));
+    ASSERT_EQ(Status::OK,
+              test_partition.Write(address,
                                    kKvsTestDataAligned8Bottom,
                                    sizeof(kKvsTestDataAligned8Bottom)));
     address += sizeof(kKvsTestDataAligned8Bottom);
   } else if (test_partition.GetAlignmentBytes() == 16) {
-    ASSERT_OK(test_partition.Write(
-        0, kKvsTestDataAligned16Top, sizeof(kKvsTestDataAligned16Top)));
-    ASSERT_OK(test_partition.Write(address,
+    ASSERT_EQ(
+        Status::OK,
+        test_partition.Write(
+            0, kKvsTestDataAligned16Top, sizeof(kKvsTestDataAligned16Top)));
+    ASSERT_EQ(Status::OK,
+              test_partition.Write(address,
                                    kKvsTestDataAligned16Bottom,
                                    sizeof(kKvsTestDataAligned16Bottom)));
     address += sizeof(kKvsTestDataAligned16Bottom);
   } else {
-    LOG_ERROR("Test only supports 1, 2, 8 and 16 byte alignments.");
+    PW_LOG_ERROR("Test only supports 1, 2, 8 and 16 byte alignments.");
     ASSERT_EQ(true, false);
   }
 
-  ASSERT_OK(kvs_local_.Enable());
+  ASSERT_EQ(Status::OK, kvs_local_.Enable());
   EXPECT_TRUE(kvs_local_.IsEnabled());
 
   // Put in same key/value pair
-  ASSERT_OK(kvs_local_.Put(keys[1], kTestPattern));
+  ASSERT_EQ(Status::OK, kvs_local_.Put(keys[1], kTestPattern));
 
   bool is_erased = false;
-  ASSERT_OK(test_partition.IsChunkErased(
-      address, test_partition.GetAlignmentBytes(), &is_erased));
+  ASSERT_EQ(Status::OK,
+            test_partition.IsChunkErased(
+                address, test_partition.GetAlignmentBytes(), &is_erased));
   EXPECT_EQ(is_erased, true);
 }
 
@@ -909,14 +950,14 @@
 // the sector.
 TEST_F(KeyValueStoreTest, FillSector2) {
   if (test_partition.GetSectorCount() < 3) {
-    LOG_INFO("Not enough sectors, skipping test.");
+    PW_LOG_INFO("Not enough sectors, skipping test.");
     return;  // need at least 3 sectors
   }
 
   // Reset KVS
   kvs.Disable();
   test_partition.Erase(0, test_partition.GetSectorCount());
-  ASSERT_OK(kvs.Enable());
+  ASSERT_EQ(Status::OK, kvs.Enable());
 
   // Start of by filling flash sector to near full
   constexpr int kHalfBufferSize = buffer.size() / 2;
@@ -931,11 +972,12 @@
   size_t new_keyvalue_size = 0;
   size_t alignment = test_partition.GetAlignmentBytes();
   // Starts on second sector since it will try to keep first sector free
-  pw::FlashPartition::Address read_address =
+  FlashPartition::Address read_address =
       2 * test_partition.GetSectorSizeBytes() - alignment;
   for (; read_address > 0; read_address -= alignment) {
     bool is_erased = false;
-    ASSERT_OK(
+    ASSERT_EQ(
+        Status::OK,
         test_partition.IsChunkErased(read_address, alignment, &is_erased));
     if (is_erased) {
       new_keyvalue_size += alignment;
@@ -953,15 +995,15 @@
   constexpr uint8_t kTestPattern = 0xBA;
   new_keyvalue_size -= kValueLessThanChunkHeaderSize;
   memset(buffer.data(), kTestPattern, new_keyvalue_size);
-  ASSERT_OK(kvs.Put(kNewKey, buffer.data(), new_keyvalue_size));
+  ASSERT_EQ(Status::OK, kvs.Put(kNewKey, buffer.data(), new_keyvalue_size));
 
   // In failed corner case, adding new key is deceptively successful. It isn't
   // until KVS is disabled and reenabled that issue can be detected.
   kvs.Disable();
-  ASSERT_OK(kvs.Enable());
+  ASSERT_EQ(Status::OK, kvs.Enable());
 
   // Might as well check that new key-value is what we expect it to be
-  ASSERT_OK(kvs.Get(kNewKey, buffer.data(), new_keyvalue_size));
+  ASSERT_EQ(Status::OK, kvs.Get(kNewKey, buffer.data(), new_keyvalue_size));
   for (size_t i = 0; i < new_keyvalue_size; i++) {
     EXPECT_EQ(buffer[i], kTestPattern);
   }
@@ -980,7 +1022,7 @@
 
   // Reset KVS
   test_partition.Erase(0, test_partition.GetSectorCount());
-  ASSERT_OK(kvs.Enable());
+  ASSERT_EQ(Status::OK, kvs.Enable());
 
   // Try some case that are expected to fail
   ASSERT_EQ(kvs.GetValueSize(keys[0], &value_size), Status::NOT_FOUND);
@@ -989,12 +1031,12 @@
 
   // Add key[0] and test we get the right value size for it.
   memset(buffer.data(), kKey0Pattern, kSizeOfValueToFill);
-  ASSERT_OK(kvs.Put(keys[0], buffer.data(), kSizeOfValueToFill));
-  ASSERT_OK(kvs.GetValueSize(keys[0], &value_size));
+  ASSERT_EQ(Status::OK, kvs.Put(keys[0], buffer.data(), kSizeOfValueToFill));
+  ASSERT_EQ(Status::OK, kvs.GetValueSize(keys[0], &value_size));
   ASSERT_EQ(value_size, kSizeOfValueToFill);
 
   // Verify after erase key is not found
-  ASSERT_OK(kvs.Erase(keys[0]));
+  ASSERT_EQ(Status::OK, kvs.Erase(keys[0]));
   ASSERT_EQ(kvs.GetValueSize(keys[0], &value_size), Status::NOT_FOUND);
 }
 
@@ -1002,7 +1044,7 @@
   // Reset KVS
   kvs.Disable();
   test_partition.Erase(0, test_partition.GetSectorCount());
-  ASSERT_OK(kvs.Enable());
+  ASSERT_EQ(Status::OK, kvs.Enable());
 
   // Get exactly the number of bytes that can fit in the space remaining for
   // a large value, accounting for alignment.
@@ -1035,15 +1077,15 @@
 
   // Reset KVS
   kvs.Disable();
-  ASSERT_OK(kvs.Enable());
-  ASSERT_OK(kvs.Put(kKey, kValue1));
+  ASSERT_EQ(Status::OK, kvs.Enable());
+  ASSERT_EQ(Status::OK, kvs.Put(kKey, kValue1));
 
   // Now try to rewrite with the similar value.
-  ASSERT_OK(kvs.Put(kKey, kValue2));
+  ASSERT_EQ(Status::OK, kvs.Put(kKey, kValue2));
 
   // Read it back and check it is correct
   char value[3];
-  ASSERT_OK(kvs.Get(kKey, value, sizeof(value)));
+  ASSERT_EQ(Status::OK, kvs.Get(kKey, value, sizeof(value)));
   ASSERT_EQ(memcmp(value, kValue2, sizeof(value)), 0);
 }
 
@@ -1052,11 +1094,11 @@
 
   // Reset KVS
   kvs.Disable();
-  ASSERT_OK(kvs.Enable());
+  ASSERT_EQ(Status::OK, kvs.Enable());
 
   const uint8_t kValue = 0xDA;
-  ASSERT_OK(kvs.Put(keys[0], &kValue, sizeof(kValue)));
-  ASSERT_OK(kvs.Erase(keys[0]));
+  ASSERT_EQ(Status::OK, kvs.Put(keys[0], &kValue, sizeof(kValue)));
+  ASSERT_EQ(Status::OK, kvs.Erase(keys[0]));
   uint16_t crc = CalcTestPartitionCrc();
   EXPECT_EQ(kvs.Erase(keys[0]), Status::NOT_FOUND);
   // Verify the flash has not changed
@@ -1073,18 +1115,18 @@
 
   test_partition.Erase(0, test_partition.GetSectorCount());
 
-  ASSERT_OK(kvs1.Enable());
-  ASSERT_OK(kvs2.Enable());
+  ASSERT_EQ(Status::OK, kvs1.Enable());
+  ASSERT_EQ(Status::OK, kvs2.Enable());
 
   int values1[3] = {100, 101, 102};
-  ASSERT_OK(kvs1.Put(keys[0], values1[0]));
-  ASSERT_OK(kvs1.Put(keys[1], values1[1]));
-  ASSERT_OK(kvs1.Put(keys[2], values1[2]));
+  ASSERT_EQ(Status::OK, kvs1.Put(keys[0], values1[0]));
+  ASSERT_EQ(Status::OK, kvs1.Put(keys[1], values1[1]));
+  ASSERT_EQ(Status::OK, kvs1.Put(keys[2], values1[2]));
 
   int values2[3] = {200, 201, 202};
-  ASSERT_OK(kvs2.Put(keys[0], values2[0]));
-  ASSERT_OK(kvs2.Put(keys[1], values2[1]));
-  ASSERT_OK(kvs2.Erase(keys[1]));
+  ASSERT_EQ(Status::OK, kvs2.Put(keys[0], values2[0]));
+  ASSERT_EQ(Status::OK, kvs2.Put(keys[1], values2[1]));
+  ASSERT_EQ(Status::OK, kvs2.Erase(keys[1]));
 
   kvs1.Disable();
   kvs2.Disable();
@@ -1094,19 +1136,20 @@
   // key 2 is only in first sector
 
   uint64_t mark_clean_count = 5;
-  ASSERT_OK(PaddedWrite(&test_partition_sector1,
+  ASSERT_EQ(Status::OK,
+            PaddedWrite(&test_partition_sector1,
                         RoundUpForAlignment(KeyValueStore::kHeaderSize),
                         reinterpret_cast<uint8_t*>(&mark_clean_count),
                         sizeof(uint64_t)));
 
   // Reset KVS
   kvs.Disable();
-  ASSERT_OK(kvs.Enable());
+  ASSERT_EQ(Status::OK, kvs.Enable());
   int value;
-  ASSERT_OK(kvs.Get(keys[0], &value));
+  ASSERT_EQ(Status::OK, kvs.Get(keys[0], &value));
   ASSERT_EQ(values2[0], value);
   ASSERT_EQ(kvs.Get(keys[1], &value), Status::NOT_FOUND);
-  ASSERT_OK(kvs.Get(keys[2], &value));
+  ASSERT_EQ(Status::OK, kvs.Get(keys[2], &value));
   ASSERT_EQ(values1[2], value);
 
   if (test_partition.GetSectorCount() == 2) {
@@ -1118,25 +1161,29 @@
   }
 
   mark_clean_count--;
-  ASSERT_OK(PaddedWrite(&test_partition_sector2,
+  ASSERT_EQ(Status::OK,
+            PaddedWrite(&test_partition_sector2,
                         RoundUpForAlignment(KeyValueStore::kHeaderSize),
                         reinterpret_cast<uint8_t*>(&mark_clean_count),
                         sizeof(uint64_t)));
   // Reset KVS
   kvs.Disable();
-  ASSERT_OK(kvs.Enable());
+  ASSERT_EQ(Status::OK, kvs.Enable());
   EXPECT_EQ(kvs.PendingCleanCount(), 2u);
-  ASSERT_OK(kvs.Get(keys[0], &value));
+  ASSERT_EQ(Status::OK, kvs.Get(keys[0], &value));
   ASSERT_EQ(values1[0], value);
-  ASSERT_OK(kvs.Get(keys[1], &value));
+  ASSERT_EQ(Status::OK, kvs.Get(keys[1], &value));
   ASSERT_EQ(values1[1], value);
-  ASSERT_OK(kvs.Get(keys[2], &value));
+  ASSERT_EQ(Status::OK, kvs.Get(keys[2], &value));
   ASSERT_EQ(values1[2], value);
 }
 
+// TODO: temporary
+size_t CurrentTaskStackFree() { return -1; }
+
 TEST_F(KeyValueStoreTest, PartialClean) {
   if (CurrentTaskStackFree() < sizeof(KeyValueStore) * 2) {
-    LOG_ERROR("Not enough stack for test, skipping");
+    PW_LOG_ERROR("Not enough stack for test, skipping");
     return;
   }
   StackHeavyPartialClean();
@@ -1149,40 +1196,42 @@
   KeyValueStore kvs1(&test_partition_sector1);
   test_partition.Erase(0, test_partition.GetSectorCount());
 
-  ASSERT_OK(kvs1.Enable());
+  ASSERT_EQ(Status::OK, kvs1.Enable());
 
   int values1[3] = {100, 101, 102};
-  ASSERT_OK(kvs1.Put(keys[0], values1[0]));
-  ASSERT_OK(kvs1.Put(keys[1], values1[1]));
-  ASSERT_OK(kvs1.Put(keys[2], values1[2] - 100));  //  force a rewrite
-  ASSERT_OK(kvs1.Put(keys[2], values1[2]));
+  ASSERT_EQ(Status::OK, kvs1.Put(keys[0], values1[0]));
+  ASSERT_EQ(Status::OK, kvs1.Put(keys[1], values1[1]));
+  ASSERT_EQ(Status::OK,
+            kvs1.Put(keys[2], values1[2] - 100));  //  force a rewrite
+  ASSERT_EQ(Status::OK, kvs1.Put(keys[2], values1[2]));
 
   kvs1.Disable();
 
   uint64_t mark_clean_count = 5;
-  ASSERT_OK(PaddedWrite(&test_partition_sector1,
+  ASSERT_EQ(Status::OK,
+            PaddedWrite(&test_partition_sector1,
                         RoundUpForAlignment(KeyValueStore::kHeaderSize),
                         reinterpret_cast<uint8_t*>(&mark_clean_count),
                         sizeof(uint64_t)));
 
   // Reset KVS
   kvs.Disable();
-  ASSERT_OK(kvs.Enable());
+  ASSERT_EQ(Status::OK, kvs.Enable());
   int value;
   EXPECT_EQ(kvs.PendingCleanCount(), 1u);
-  ASSERT_OK(kvs.CleanAll());
+  ASSERT_EQ(Status::OK, kvs.CleanAll());
   EXPECT_EQ(kvs.PendingCleanCount(), 0u);
-  ASSERT_OK(kvs.Get(keys[0], &value));
+  ASSERT_EQ(Status::OK, kvs.Get(keys[0], &value));
   ASSERT_EQ(values1[0], value);
-  ASSERT_OK(kvs.Get(keys[1], &value));
+  ASSERT_EQ(Status::OK, kvs.Get(keys[1], &value));
   ASSERT_EQ(values1[1], value);
-  ASSERT_OK(kvs.Get(keys[2], &value));
+  ASSERT_EQ(Status::OK, kvs.Get(keys[2], &value));
   ASSERT_EQ(values1[2], value);
 }
 
 TEST_F(KeyValueStoreTest, CleanAll) {
   if (CurrentTaskStackFree() < sizeof(KeyValueStore) * 1) {
-    LOG_ERROR("Not enough stack for test, skipping");
+    PW_LOG_ERROR("Not enough stack for test, skipping");
     return;
   }
   StackHeavyCleanAll();
@@ -1198,18 +1247,18 @@
 
   test_partition.Erase(0, test_partition.GetSectorCount());
 
-  ASSERT_OK(kvs1.Enable());
-  ASSERT_OK(kvs2.Enable());
+  ASSERT_EQ(Status::OK, kvs1.Enable());
+  ASSERT_EQ(Status::OK, kvs2.Enable());
 
   int values1[3] = {100, 101, 102};
-  ASSERT_OK(kvs1.Put(keys[0], values1[0]));
-  ASSERT_OK(kvs1.Put(keys[1], values1[1]));
-  ASSERT_OK(kvs1.Put(keys[2], values1[2]));
+  ASSERT_EQ(Status::OK, kvs1.Put(keys[0], values1[0]));
+  ASSERT_EQ(Status::OK, kvs1.Put(keys[1], values1[1]));
+  ASSERT_EQ(Status::OK, kvs1.Put(keys[2], values1[2]));
 
   int values2[3] = {200, 201, 202};
-  ASSERT_OK(kvs2.Put(keys[0], values2[0]));
-  ASSERT_OK(kvs2.Put(keys[1], values2[1]));
-  ASSERT_OK(kvs2.Erase(keys[1]));
+  ASSERT_EQ(Status::OK, kvs2.Put(keys[0], values2[0]));
+  ASSERT_EQ(Status::OK, kvs2.Put(keys[1], values2[1]));
+  ASSERT_EQ(Status::OK, kvs2.Erase(keys[1]));
 
   kvs1.Disable();
   kvs2.Disable();
@@ -1220,18 +1269,19 @@
   // key 2 is only in first sector
 
   uint64_t mark_clean_count = 4569877515;
-  ASSERT_OK(PaddedWrite(&test_partition_sector1,
+  ASSERT_EQ(Status::OK,
+            PaddedWrite(&test_partition_sector1,
                         RoundUpForAlignment(KeyValueStore::kHeaderSize),
                         reinterpret_cast<uint8_t*>(&mark_clean_count),
                         sizeof(uint64_t)));
 
   // Reset KVS
-  ASSERT_OK(kvs.Enable());
+  ASSERT_EQ(Status::OK, kvs.Enable());
   int value;
-  ASSERT_OK(kvs.Get(keys[0], &value));
+  ASSERT_EQ(Status::OK, kvs.Get(keys[0], &value));
   ASSERT_EQ(values2[0], value);
   ASSERT_EQ(kvs.Get(keys[1], &value), Status::NOT_FOUND);
-  ASSERT_OK(kvs.Get(keys[2], &value));
+  ASSERT_EQ(Status::OK, kvs.Get(keys[2], &value));
   ASSERT_EQ(values1[2], value);
 
   if (test_partition.GetSectorCount() == 2) {
@@ -1245,24 +1295,25 @@
   kvs.Disable();
 
   mark_clean_count--;
-  ASSERT_OK(PaddedWrite(&test_partition_sector2,
+  ASSERT_EQ(Status::OK,
+            PaddedWrite(&test_partition_sector2,
                         RoundUpForAlignment(KeyValueStore::kHeaderSize),
                         reinterpret_cast<uint8_t*>(&mark_clean_count),
                         sizeof(uint64_t)));
   // Reset KVS
-  ASSERT_OK(kvs.Enable());
+  ASSERT_EQ(Status::OK, kvs.Enable());
   EXPECT_EQ(kvs.PendingCleanCount(), 2u);
-  ASSERT_OK(kvs.Get(keys[0], &value));
+  ASSERT_EQ(Status::OK, kvs.Get(keys[0], &value));
   ASSERT_EQ(values1[0], value);
-  ASSERT_OK(kvs.Get(keys[1], &value));
+  ASSERT_EQ(Status::OK, kvs.Get(keys[1], &value));
   ASSERT_EQ(values1[1], value);
-  ASSERT_OK(kvs.Get(keys[2], &value));
+  ASSERT_EQ(Status::OK, kvs.Get(keys[2], &value));
   ASSERT_EQ(values1[2], value);
 }
 
 TEST_F(KeyValueStoreTest, PartialCleanLargeCounts) {
   if (CurrentTaskStackFree() < sizeof(KeyValueStore) * 2) {
-    LOG_ERROR("Not enough stack for test, skipping");
+    PW_LOG_ERROR("Not enough stack for test, skipping");
     return;
   }
   StackHeavyPartialCleanLargeCounts();
@@ -1280,31 +1331,31 @@
 
   test_partition.Erase(0, test_partition.GetSectorCount());
 
-  ASSERT_OK(kvs1.Enable());
-  ASSERT_OK(kvs2.Enable());
+  ASSERT_EQ(Status::OK, kvs1.Enable());
+  ASSERT_EQ(Status::OK, kvs2.Enable());
 
   int values[3] = {100, 101};
-  ASSERT_OK(kvs1.Put(keys[0], values[0]));
+  ASSERT_EQ(Status::OK, kvs1.Put(keys[0], values[0]));
   ASSERT_FALSE(kvs1.HasEmptySector());
-  ASSERT_OK(kvs2.Put(keys[1], values[1]));
+  ASSERT_EQ(Status::OK, kvs2.Put(keys[1], values[1]));
   ASSERT_FALSE(kvs2.HasEmptySector());
 
   kvs1.Disable();
   kvs2.Disable();
 
   // Reset KVS
-  ASSERT_OK(kvs_both.Enable());
+  ASSERT_EQ(Status::OK, kvs_both.Enable());
   ASSERT_TRUE(kvs_both.HasEmptySector());
   int value;
-  ASSERT_OK(kvs_both.Get(keys[0], &value));
+  ASSERT_EQ(Status::OK, kvs_both.Get(keys[0], &value));
   ASSERT_EQ(values[0], value);
-  ASSERT_OK(kvs_both.Get(keys[1], &value));
+  ASSERT_EQ(Status::OK, kvs_both.Get(keys[1], &value));
   ASSERT_EQ(values[1], value);
 }
 
 TEST_F(KeyValueStoreTest, RecoverNoFreeSectors) {
   if (CurrentTaskStackFree() < sizeof(KeyValueStore) * 3) {
-    LOG_ERROR("Not enough stack for test, skipping");
+    PW_LOG_ERROR("Not enough stack for test, skipping");
     return;
   }
   StackHeavyRecoverNoFreeSectors();
@@ -1319,45 +1370,46 @@
 
   test_partition.Erase(0, test_partition.GetSectorCount());
 
-  ASSERT_OK(kvs1.Enable());
+  ASSERT_EQ(Status::OK, kvs1.Enable());
 
   int values[3] = {100, 101, 102};
-  ASSERT_OK(kvs1.Put(keys[0], values[0]));
-  ASSERT_OK(kvs1.Put(keys[1], values[1]));
-  ASSERT_OK(kvs1.Put(keys[2], values[2]));
+  ASSERT_EQ(Status::OK, kvs1.Put(keys[0], values[0]));
+  ASSERT_EQ(Status::OK, kvs1.Put(keys[1], values[1]));
+  ASSERT_EQ(Status::OK, kvs1.Put(keys[2], values[2]));
 
   kvs1.Disable();
   kvs.Disable();
 
   uint64_t mark_clean_count = 1;
-  ASSERT_OK(PaddedWrite(&test_partition_sector1,
+  ASSERT_EQ(Status::OK,
+            PaddedWrite(&test_partition_sector1,
                         RoundUpForAlignment(KeyValueStore::kHeaderSize),
                         reinterpret_cast<uint8_t*>(&mark_clean_count),
                         sizeof(uint64_t)));
 
   // Reset KVS
-  ASSERT_OK(kvs.Enable());
+  ASSERT_EQ(Status::OK, kvs.Enable());
 
   EXPECT_EQ(kvs.PendingCleanCount(), 1u);
 
   bool all_sectors_have_been_cleaned = false;
-  ASSERT_OK(kvs.CleanOneSector(&all_sectors_have_been_cleaned));
+  ASSERT_EQ(Status::OK, kvs.CleanOneSector(&all_sectors_have_been_cleaned));
   EXPECT_EQ(all_sectors_have_been_cleaned, true);
   EXPECT_EQ(kvs.PendingCleanCount(), 0u);
-  ASSERT_OK(kvs.CleanOneSector(&all_sectors_have_been_cleaned));
+  ASSERT_EQ(Status::OK, kvs.CleanOneSector(&all_sectors_have_been_cleaned));
   EXPECT_EQ(all_sectors_have_been_cleaned, true);
   int value;
-  ASSERT_OK(kvs.Get(keys[0], &value));
+  ASSERT_EQ(Status::OK, kvs.Get(keys[0], &value));
   ASSERT_EQ(values[0], value);
-  ASSERT_OK(kvs.Get(keys[1], &value));
+  ASSERT_EQ(Status::OK, kvs.Get(keys[1], &value));
   ASSERT_EQ(values[1], value);
-  ASSERT_OK(kvs.Get(keys[2], &value));
+  ASSERT_EQ(Status::OK, kvs.Get(keys[2], &value));
   ASSERT_EQ(values[2], value);
 }
 
 TEST_F(KeyValueStoreTest, CleanOneSector) {
   if (CurrentTaskStackFree() < sizeof(KeyValueStore)) {
-    LOG_ERROR("Not enough stack for test, skipping");
+    PW_LOG_ERROR("Not enough stack for test, skipping");
     return;
   }
   StackHeavyCleanOneSector();
@@ -1367,30 +1419,30 @@
 
 TEST_F(KeyValueStoreTest, LargePartition) {
   if (CurrentTaskStackFree() < sizeof(KeyValueStore)) {
-    LOG_ERROR("Not enough stack for test, skipping");
+    PW_LOG_ERROR("Not enough stack for test, skipping");
     return;
   }
   large_test_partition.Erase(0, large_test_partition.GetSectorCount());
   KeyValueStore large_kvs(&large_test_partition);
   // Reset KVS
   large_kvs.Disable();
-  ASSERT_OK(large_kvs.Enable());
+  ASSERT_EQ(Status::OK, large_kvs.Enable());
 
   const uint8_t kValue1 = 0xDA;
   const uint8_t kValue2 = 0x12;
   uint8_t value[1];
-  ASSERT_OK(large_kvs.Put(keys[0], &kValue1, sizeof(kValue1)));
+  ASSERT_EQ(Status::OK, large_kvs.Put(keys[0], &kValue1, sizeof(kValue1)));
   EXPECT_EQ(large_kvs.KeyCount(), 1);
-  ASSERT_OK(large_kvs.Erase(keys[0]));
+  ASSERT_EQ(Status::OK, large_kvs.Erase(keys[0]));
   EXPECT_EQ(large_kvs.Get(keys[0], value, sizeof(value)), Status::NOT_FOUND);
-  ASSERT_OK(large_kvs.Put(keys[1], &kValue1, sizeof(kValue1)));
-  ASSERT_OK(large_kvs.Put(keys[2], &kValue2, sizeof(kValue2)));
-  ASSERT_OK(large_kvs.Erase(keys[1]));
-  EXPECT_OK(large_kvs.Get(keys[2], value, sizeof(value)));
+  ASSERT_EQ(Status::OK, large_kvs.Put(keys[1], &kValue1, sizeof(kValue1)));
+  ASSERT_EQ(Status::OK, large_kvs.Put(keys[2], &kValue2, sizeof(kValue2)));
+  ASSERT_EQ(Status::OK, large_kvs.Erase(keys[1]));
+  EXPECT_EQ(Status::OK, large_kvs.Get(keys[2], value, sizeof(value)));
   EXPECT_EQ(kValue2, value[0]);
   ASSERT_EQ(large_kvs.Get(keys[1], &value), Status::NOT_FOUND);
   EXPECT_EQ(large_kvs.KeyCount(), 1);
 }
 #endif  // USE_MEMORY_BUFFER
 
-}  // namespace pw
+}  // namespace pw::kvs
diff --git a/pw_kvs/public/pw_kvs/assert.h b/pw_kvs/public/pw_kvs/assert.h
new file mode 100644
index 0000000..36f232b
--- /dev/null
+++ b/pw_kvs/public/pw_kvs/assert.h
@@ -0,0 +1,69 @@
+// 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
+
+#include <algorithm>
+#include <type_traits>
+
+// Compares the provided value to nullptr and returns it. This is intended to be
+// used as part of another statement.
+#define CHECK_NOTNULL(value) \
+  ::pw::log::CheckNotNull("", __LINE__, #value " != nullptr", value)
+
+// In release builds, DCHECK_NOTNULL simply passes along the value.
+// DCHECK_NOTNULL must not be used as a standalone expression, since the result
+// would be unused on release builds. Use DCHECK_NE instead.
+//#define DCHECK_NOTNULL(value) value
+
+#define DCHECK_NOTNULL(value) \
+  ::pw::log::DCheckNotNull("", __LINE__, #value " != nullptr", value)
+
+namespace pw::log {
+
+template <typename T>
+constexpr T CheckNotNull(const char* /* file */,
+                         unsigned /* line */,
+                         const char* /* message */,
+                         T&& value) {
+  static_assert(!std::is_null_pointer<T>(),
+                "CHECK_NOTNULL statements cannot be passed nullptr");
+  if (value == nullptr) {
+    std::exit(1);
+  }
+  return std::forward<T>(value);
+}
+
+// DCHECK_NOTNULL cannot be used in standalone expressions, so add a
+// [[nodiscard]] attribute to prevent this in debug builds. Standalone
+// DCHECK_NOTNULL statements in release builds trigger an unused-value warning.
+template <typename T>
+[[nodiscard]] constexpr T DCheckNotNull(const char* file,
+                                        unsigned line,
+                                        const char* message,
+                                        T&& value) {
+  return CheckNotNull<T>(file, line, message, std::forward<T>(value));
+}
+
+}  // namespace pw::log
+
+// Assert stubs
+#define DCHECK CHECK
+#define DCHECK_EQ CHECK_EQ
+
+#define CHECK(...)
+#define CHECK_EQ(...)
+#define CHECK_GE(...)
+#define CHECK_GT(...)
+#define CHECK_LE(...)
+#define CHECK_LT(...)
diff --git a/pw_kvs/public/pw_kvs/flash.h b/pw_kvs/public/pw_kvs/flash.h
index 5cb80cd..6eecea7 100644
--- a/pw_kvs/public/pw_kvs/flash.h
+++ b/pw_kvs/public/pw_kvs/flash.h
@@ -13,9 +13,9 @@
 // the License.
 #pragma once
 
-#include "pw_kvs/devices/flash_memory.h"
+#include "pw_kvs/flash_memory.h"
 
-namespace pw {
+namespace pw::kvs {
 
 // Writes a buffer which is not guaranteed to be aligned, pads remaining
 // bytes with 0.
@@ -30,4 +30,4 @@
                      FlashPartition::Address address,
                      uint16_t size);
 
-}  // namespace pw
+}  // namespace pw::kvs
diff --git a/pw_kvs/public/pw_kvs/flash_memory.h b/pw_kvs/public/pw_kvs/flash_memory.h
index 707f128..d62f794 100644
--- a/pw_kvs/public/pw_kvs/flash_memory.h
+++ b/pw_kvs/public/pw_kvs/flash_memory.h
@@ -14,14 +14,16 @@
 #pragma once
 
 #include <algorithm>
+#include <cinttypes>
+#include <cstring>
 
 #include "pw_kvs/assert.h"
-#include "pw_kvs/logging.h"
-#include "pw_kvs/peripherals/partition_table_entry.h"
-#include "pw_kvs/status.h"
-#include "pw_kvs/status_macros.h"
+#include "pw_kvs/partition_table_entry.h"
+#include "pw_log/log.h"
+#include "pw_status/status.h"
 
-namespace pw {
+namespace pw::kvs {
+
 class FlashMemory {
  public:
   // The flash address is in the range of: 0 to FlashSize.
@@ -39,6 +41,8 @@
         sector_start_(sector_start),
         erased_memory_content_(erased_memory_content) {}
 
+  virtual ~FlashMemory() = default;
+
   virtual Status Enable() = 0;
   virtual Status Disable() = 0;
   virtual bool IsEnabled() const = 0;
@@ -72,9 +76,7 @@
 
   // Convert an Address to an MCU pointer, this can be used for memory
   // mapped reads. Return NULL if the memory is not memory mapped.
-  virtual uint8_t* FlashAddressToMcuAddress(Address address) const {
-    return nullptr;
-  }
+  virtual uint8_t* FlashAddressToMcuAddress(Address) const { return nullptr; }
 
   // GetStartSector() is useful for FlashMemory instances where the
   // sector start is not 0. (ex.: cases where there are portions of flash
@@ -137,9 +139,7 @@
   bool IsEnabled() const override { return flash_.IsEnabled(); }
   Status SelfTest() override { return flash_.SelfTest(); }
 
-  Status Erase(Address flash_address, uint32_t num_sectors) override {
-    return Status::UNIMPLEMENTED;
-  }
+  Status Erase(Address, uint32_t) override { return Status::UNIMPLEMENTED; }
 
   Status Read(uint8_t* destination_ram_address,
               Address source_flash_address,
@@ -185,6 +185,8 @@
                       entry.partition_start_sector_index + 1),
         permission_(entry.partition_permission) {}
 
+  virtual ~FlashPartition() = default;
+
   // Erase num_sectors starting at a given address. Blocking call.
   // Address should be on a sector boundary.
   // Returns: OK, on success.
@@ -193,9 +195,14 @@
   //          PERMISSION_DENIED, if partition is read only.
   //          UNKNOWN, on HAL error
   virtual Status Erase(Address address, uint32_t num_sectors) {
-    RETURN_STATUS_IF(permission_ == PartitionPermission::kReadOnly,
-                     Status::PERMISSION_DENIED);
-    RETURN_IF_ERROR(CheckBounds(address, num_sectors * GetSectorSizeBytes()));
+    if (permission_ == PartitionPermission::kReadOnly) {
+      return Status::PERMISSION_DENIED;
+    }
+    if (Status status =
+            CheckBounds(address, num_sectors * GetSectorSizeBytes());
+        !status.ok()) {
+      return status;
+    }
     return flash_.Erase(PartitionToFlashAddress(address), num_sectors);
   }
 
@@ -207,7 +214,9 @@
   virtual Status Read(uint8_t* destination_ram_address,
                       Address source_flash_address,
                       uint32_t len) {
-    RETURN_IF_ERROR(CheckBounds(source_flash_address, len));
+    if (Status status = CheckBounds(source_flash_address, len); !status.ok()) {
+      return status;
+    }
     return flash_.Read(destination_ram_address,
                        PartitionToFlashAddress(source_flash_address),
                        len);
@@ -222,9 +231,13 @@
   virtual Status Write(Address destination_flash_address,
                        const uint8_t* source_ram_address,
                        uint32_t len) {
-    RETURN_STATUS_IF(permission_ == PartitionPermission::kReadOnly,
-                     Status::PERMISSION_DENIED);
-    RETURN_IF_ERROR(CheckBounds(destination_flash_address, len));
+    if (permission_ == PartitionPermission::kReadOnly) {
+      return Status::PERMISSION_DENIED;
+    }
+    if (Status status = CheckBounds(destination_flash_address, len);
+        !status.ok()) {
+      return status;
+    }
     return flash_.Write(PartitionToFlashAddress(destination_flash_address),
                         source_ram_address,
                         len);
@@ -243,24 +256,31 @@
     // function. Using 16 because it's the alignment of encrypted flash.
     const uint8_t kMaxAlignment = 16;
     // Relying on Read() to check address and len arguments.
-    RETURN_STATUS_IF(!is_erased, Status::INVALID_ARGUMENT);
+    if (!is_erased) {
+      return Status::INVALID_ARGUMENT;
+    }
     uint8_t alignment = GetAlignmentBytes();
-    RETURN_STATUS_IF(alignment > kMaxAlignment, Status::INVALID_ARGUMENT);
-    RETURN_STATUS_IF(kMaxAlignment % alignment, Status::INVALID_ARGUMENT);
-    RETURN_STATUS_IF(len % alignment, Status::INVALID_ARGUMENT);
+    if (alignment > kMaxAlignment || kMaxAlignment % alignment ||
+        len % alignment) {
+      return Status::INVALID_ARGUMENT;
+    }
 
     uint8_t buffer[kMaxAlignment];
     uint8_t erased_pattern_buffer[kMaxAlignment];
     size_t offset = 0;
-    memset(erased_pattern_buffer,
-           flash_.GetErasedMemoryContent(),
-           sizeof(erased_pattern_buffer));
+    std::memset(erased_pattern_buffer,
+                flash_.GetErasedMemoryContent(),
+                sizeof(erased_pattern_buffer));
     *is_erased = false;
     while (len > 0) {
       // Check earlier that len is aligned, no need to round up
       uint16_t read_size = std::min(static_cast<uint32_t>(sizeof(buffer)), len);
-      RETURN_IF_ERROR(Read(buffer, source_flash_address + offset, read_size));
-      if (memcmp(buffer, erased_pattern_buffer, read_size)) {
+      if (Status status =
+              Read(buffer, source_flash_address + offset, read_size);
+          !status.ok()) {
+        return status;
+      }
+      if (std::memcmp(buffer, erased_pattern_buffer, read_size)) {
         // Detected memory chunk is not entirely erased
         return Status::OK;
       }
@@ -301,8 +321,11 @@
  protected:
   Status CheckBounds(Address address, uint32_t len) const {
     if (address + len > GetSizeBytes()) {
-      LOG(ERROR) << "Attempted out-of-bound flash memory access (address:"
-                 << address << " length:" << len << ")";
+      PW_LOG_ERROR(
+          "Attempted out-of-bound flash memory access (address: %" PRIu32
+          " length: %zu)",
+          address,
+          len);
       return Status::INVALID_ARGUMENT;
     }
     return Status::OK;
@@ -331,14 +354,20 @@
         sector_count_(sector_count) {}
 
   Status Erase(Address address, uint32_t num_sectors) override {
-    RETURN_IF_ERROR(CheckBounds(address, num_sectors * GetSectorSizeBytes()));
+    if (Status status =
+            CheckBounds(address, num_sectors * GetSectorSizeBytes());
+        !status.ok()) {
+      return status;
+    }
     return partition_->Erase(ParentAddress(address), num_sectors);
   }
 
   Status Read(uint8_t* destination_ram_address,
               Address source_flash_address,
               uint32_t len) override {
-    RETURN_IF_ERROR(CheckBounds(source_flash_address, len));
+    if (Status status = CheckBounds(source_flash_address, len); !status.ok()) {
+      return status;
+    }
     return partition_->Read(
         destination_ram_address, ParentAddress(source_flash_address), len);
   }
@@ -346,7 +375,10 @@
   Status Write(Address destination_flash_address,
                const uint8_t* source_ram_address,
                uint32_t len) override {
-    RETURN_IF_ERROR(CheckBounds(destination_flash_address, len));
+    if (Status status = CheckBounds(destination_flash_address, len);
+        !status.ok()) {
+      return status;
+    }
     return partition_->Write(
         ParentAddress(destination_flash_address), source_ram_address, len);
   }
@@ -354,7 +386,9 @@
   Status IsChunkErased(Address source_flash_address,
                        uint32_t len,
                        bool* is_erased) override {
-    RETURN_IF_ERROR(CheckBounds(source_flash_address, len));
+    if (Status status = CheckBounds(source_flash_address, len); !status.ok()) {
+      return status;
+    }
     return partition_->IsChunkErased(
         ParentAddress(source_flash_address), len, is_erased);
   }
@@ -374,4 +408,4 @@
   const uint32_t sector_count_;
 };
 
-}  // namespace pw
+}  // namespace pw::kvs
diff --git a/pw_kvs/public/pw_kvs/in_memory_fake_flash.h b/pw_kvs/public/pw_kvs/in_memory_fake_flash.h
index a67c770..d2ea67c 100644
--- a/pw_kvs/public/pw_kvs/in_memory_fake_flash.h
+++ b/pw_kvs/public/pw_kvs/in_memory_fake_flash.h
@@ -15,11 +15,10 @@
 
 #include <array>
 
-#include "pw_kvs/devices/flash_memory.h"
-#include "pw_kvs/status.h"
-#include "pw_kvs/status_macros.h"
+#include "pw_kvs/flash_memory.h"
+#include "pw_status/status.h"
 
-namespace pw {
+namespace pw::kvs {
 
 // This creates a buffer which mimics the behaviour of flash (requires erase,
 // before write, checks alignments, and is addressed in sectors).
@@ -40,12 +39,15 @@
   //          INVALID_ARGUMENT, if address or sector count is invalid.
   //          UNKNOWN, on HAL error
   Status Erase(Address addr, uint32_t num_sectors) override {
-    RETURN_STATUS_IF(addr % GetSectorSizeBytes() != 0,
-                     Status::INVALID_ARGUMENT);
-    RETURN_STATUS_IF(
-        addr / GetSectorSizeBytes() + num_sectors > GetSectorCount(),
-        Status::UNKNOWN);
-    RETURN_STATUS_IF(addr % GetAlignmentBytes() != 0, Status::INVALID_ARGUMENT);
+    if (addr % GetSectorSizeBytes() != 0) {
+      return Status::INVALID_ARGUMENT;
+    }
+    if (addr / GetSectorSizeBytes() + num_sectors > GetSectorCount()) {
+      return Status::UNKNOWN;
+    }
+    if (addr % GetAlignmentBytes() != 0) {
+      return Status::INVALID_ARGUMENT;
+    }
     memset(&buffer_[addr], 0xFF, GetSectorSizeBytes() * num_sectors);
     return Status::OK;
   }
@@ -57,9 +59,9 @@
   Status Read(uint8_t* dest_ram_addr,
               Address source_flash_addr,
               uint32_t len) override {
-    RETURN_STATUS_IF(
-        (source_flash_addr + len) >= GetSectorCount() * GetSizeBytes(),
-        Status::INVALID_ARGUMENT);
+    if ((source_flash_addr + len) >= GetSectorCount() * GetSizeBytes()) {
+      return Status::INVALID_ARGUMENT;
+    }
     memcpy(dest_ram_addr, &buffer_[source_flash_addr], len);
     return Status::OK;
   }
@@ -71,15 +73,16 @@
   Status Write(Address dest_flash_addr,
                const uint8_t* source_ram_addr,
                uint32_t len) override {
-    RETURN_STATUS_IF(
-        (dest_flash_addr + len) >= GetSectorCount() * GetSizeBytes(),
-        Status::INVALID_ARGUMENT);
-    RETURN_STATUS_IF(dest_flash_addr % GetAlignmentBytes() != 0,
-                     Status::INVALID_ARGUMENT);
-    RETURN_STATUS_IF(len % GetAlignmentBytes() != 0, Status::INVALID_ARGUMENT);
+    if ((dest_flash_addr + len) >= GetSectorCount() * GetSizeBytes() ||
+        dest_flash_addr % GetAlignmentBytes() != 0 ||
+        len % GetAlignmentBytes() != 0) {
+      return Status::INVALID_ARGUMENT;
+    }
     // Check in erased state
     for (unsigned i = 0; i < len; i++) {
-      RETURN_STATUS_IF(buffer_[dest_flash_addr + i] != 0xFF, Status::UNKNOWN);
+      if (buffer_[dest_flash_addr + i] != 0xFF) {
+        return Status::UNKNOWN;
+      }
     }
     memcpy(&buffer_[dest_flash_addr], source_ram_addr, len);
     return Status::OK;
@@ -89,4 +92,4 @@
   std::array<uint8_t, kSectorCount * kSectorSize> buffer_;
 };
 
-}  // namespace pw
+}  // namespace pw::kvs
diff --git a/pw_kvs/public/pw_kvs/key_value_store.h b/pw_kvs/public/pw_kvs/key_value_store.h
index dca6507..d9bb34f 100644
--- a/pw_kvs/public/pw_kvs/key_value_store.h
+++ b/pw_kvs/public/pw_kvs/key_value_store.h
@@ -16,17 +16,37 @@
 #include <algorithm>
 #include <type_traits>
 
-#include "pw_kvs/devices/flash_memory.h"
-#include "pw_kvs/logging.h"
-#include "pw_kvs/os/mutex.h"
-#include "pw_kvs/status.h"
+#include "pw_kvs/flash_memory.h"
+#include "pw_status/status.h"
 
-namespace pw {
+namespace cfg {
+
+// KVS requires a temporary buffer for some operations, this config allows
+// tuning the buffer size. This is a trade-off between a value which is large
+// and therefore requires more RAM, or having a value which is small which will
+// result in some operations taking longer, as the operations are broken into
+// smaller chunks.
+// NOTE: This value can not be smaller then the flash alignment, and it will
+//       round the size down to be a multiple of the flash alignment for all
+//       operations.
+inline constexpr size_t kKvsBufferSize = 64;
+
+// This represents the maximum amount of keys which can be in the KVS at any
+// given time.
+inline constexpr uint8_t kKvsMaxKeyCount = 50;
+
+// This is the maximum amount of sectors the KVS can operate on, an invalid
+// value will cause an error during enable.
+inline constexpr uint32_t kKvsMaxSectorCount = 20;
+
+}  // namespace cfg
+
+namespace pw::kvs {
 
 // This object is very large and should not be placed on the stack.
 class KeyValueStore {
  public:
-  KeyValueStore(FlashPartition* partition) : partition_(*partition) {}
+  constexpr KeyValueStore(FlashPartition* partition) : partition_(*partition) {}
 
   // Enable the KVS, scans the sectors of the partition for any current KVS
   // data. Erases and initializes any sectors which are not initialized.
@@ -39,7 +59,7 @@
     if (enabled_ == false) {
       return;
     }
-    os::MutexLock lock(&lock_);
+    // TODO: LOCK MUTEX
     enabled_ = false;
   }
 
@@ -67,9 +87,14 @@
   Status Get(const char* key, T* value) {
     static_assert(std::is_trivially_copyable<T>(), "KVS values must copyable");
     static_assert(!std::is_pointer<T>(), "KVS values cannot be pointers");
+
     uint16_t value_size = 0;
-    RETURN_IF_ERROR(GetValueSize(key, &value_size));
-    RETURN_STATUS_IF(value_size != sizeof(T), Status::INVALID_ARGUMENT);
+    if (Status status = GetValueSize(key, &value_size)) {
+      return status;
+    }
+    if (value_size != sizeof(T)) {
+      return Status::INVALID_ARGUMENT;
+    }
     return Get(key, value, sizeof(T));
   }
 
@@ -107,11 +132,11 @@
   // CleanAll cleans each sector which is currently marked for cleaning.
   // Note: if any data is invalid/corrupt it could be lost.
   Status CleanAll() {
-    os::MutexLock lock(&lock_);
+    // TODO: LOCK MUTEX
     return CleanAllInternal();
   }
   size_t PendingCleanCount() {
-    os::MutexLock lock(&lock_);
+    // TODO: LOCK MUTEX
     size_t ret = 0;
     for (size_t i = 0; i < SectorCount(); i++) {
       ret += sector_space_remaining_[i] == 0 ? 1 : 0;
@@ -345,7 +370,7 @@
   }
 
   FlashPartition& partition_;
-  os::Mutex lock_;
+  // TODO: MUTEX
   bool enabled_ = false;
   uint8_t alignment_bytes_ = 0;
   uint64_t next_sector_clean_order_ = 0;
@@ -353,7 +378,7 @@
   // Free space available in each sector, set to 0 when clean is pending/active
   uint32_t sector_space_remaining_[kSectorCountMax] = {0};
   uint64_t sector_clean_order_[kSectorCountMax] = {kSectorCleanNotPending};
-  KeyMap key_map_[kListCapacityMax] = {{{0}}};
+  KeyMap key_map_[kListCapacityMax] = {};
   KeyIndex map_size_ = 0;
 
   // +1 for nul-terminator since keys are stored as Length + Value and no nul
@@ -363,4 +388,4 @@
   uint8_t temp_buffer_[cfg::kKvsBufferSize] = {0};
 };
 
-}  // namespace pw
+}  // namespace pw::kvs