| // 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 <array> |
| #include <cstddef> |
| #include <cstring> |
| |
| #include "pw_kvs/flash_memory.h" |
| #include "pw_span/span.h" |
| #include "pw_status/status.h" |
| |
| namespace pw::kvs { |
| |
| // This uses a buffer to mimic the behaviour of flash (requires erase before |
| // write, checks alignments, and is addressed in sectors). The underlying buffer |
| // is not initialized. |
| class InMemoryFakeFlash : public FlashMemory { |
| public: |
| // Default to 8-bit alignment. |
| static constexpr size_t kDefaultAlignmentBytes = 1; |
| |
| static constexpr std::byte kErasedValue = std::byte{0xff}; |
| |
| InMemoryFakeFlash(span<std::byte> buffer, |
| size_t sector_size, |
| size_t sector_count, |
| size_t alignment_bytes = kDefaultAlignmentBytes) |
| : FlashMemory(sector_size, sector_count, alignment_bytes), |
| buffer_(buffer) {} |
| |
| // The fake flash is always enabled. |
| Status Enable() override { return Status::OK; } |
| |
| Status Disable() override { return Status::OK; } |
| |
| bool IsEnabled() const override { return true; } |
| |
| // Erase num_sectors starting at a given address. |
| Status Erase(Address address, size_t num_sectors) override; |
| |
| // Reads bytes from flash into buffer. |
| StatusWithSize Read(Address address, span<std::byte> output) override; |
| |
| // Writes bytes to flash. |
| StatusWithSize Write(Address address, span<const std::byte> data) override; |
| |
| // Access the underlying buffer for testing purposes. Not part of the |
| // FlashMemory API. |
| span<std::byte> buffer() const { return buffer_; } |
| |
| private: |
| const span<std::byte> buffer_; |
| }; |
| |
| // Creates an InMemoryFakeFlash backed by a std::array. The array is initialized |
| // to the erased value. A byte array to which to initialize the memory may be |
| // provided. |
| template <size_t kSectorSize, size_t kSectorCount> |
| class FakeFlashBuffer : public InMemoryFakeFlash { |
| public: |
| // Creates a flash memory with no data written. |
| FakeFlashBuffer(size_t alignment_bytes = kDefaultAlignmentBytes) |
| : FakeFlashBuffer(std::array<std::byte, 0>{}, alignment_bytes) {} |
| |
| // Creates a flash memory initialized to the provided contents. |
| FakeFlashBuffer(span<const std::byte> contents, |
| size_t alignment_bytes = kDefaultAlignmentBytes) |
| : InMemoryFakeFlash(buffer_, kSectorSize, kSectorCount, alignment_bytes) { |
| std::memset(buffer_.data(), int(kErasedValue), buffer_.size()); |
| std::memcpy(buffer_.data(), |
| contents.data(), |
| std::min(contents.size(), buffer_.size())); |
| } |
| |
| private: |
| std::array<std::byte, kSectorCount * kSectorSize> buffer_; |
| }; |
| |
| } // namespace pw::kvs |