1 // Copyright 2020 The Pigweed Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not 4 // use this file except in compliance with the License. You may obtain a copy of 5 // the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 // License for the specific language governing permissions and limitations under 13 // the License. 14 #pragma once 15 16 #include <algorithm> 17 #include <array> 18 #include <cstddef> 19 #include <cstring> 20 #include <span> 21 22 #include "pw_containers/vector.h" 23 #include "pw_kvs/flash_memory.h" 24 #include "pw_status/status.h" 25 26 namespace pw::kvs { 27 28 class FlashError { 29 public: 30 static constexpr FlashMemory::Address kAnyAddress = FlashMemory::Address(-1); 31 static constexpr size_t kAlways = size_t(-1); 32 33 // Creates a FlashError that always triggers on the next operation. 34 static constexpr FlashError Unconditional(Status status, 35 size_t times = kAlways, 36 size_t delay = 0) { 37 return FlashError(status, kAnyAddress, 0, times, delay); 38 } 39 40 // Creates a FlashError that triggers for particular addresses. 41 static constexpr FlashError InRange(Status status, 42 FlashMemory::Address address, 43 size_t size = 1, 44 size_t times = kAlways, 45 size_t delay = 0) { 46 return FlashError(status, address, size, times, delay); 47 } 48 49 // Determines if this FlashError applies to the operation. 50 Status Check(FlashMemory::Address start_address, size_t size); 51 52 // Determines if any of a series of FlashErrors applies to the operation. 53 static Status Check(std::span<FlashError> errors, 54 FlashMemory::Address address, 55 size_t size); 56 57 private: FlashError(Status status,FlashMemory::Address address,size_t size,size_t times,size_t delay)58 constexpr FlashError(Status status, 59 FlashMemory::Address address, 60 size_t size, // not used if address is kAnyAddress 61 size_t times, 62 size_t delay) 63 : status_(status), 64 begin_(address), 65 end_(address + size), // not used if address is kAnyAddress 66 delay_(delay), 67 remaining_(times) {} 68 69 const Status status_; 70 71 const FlashMemory::Address begin_; 72 const FlashMemory::Address end_; // exclusive 73 74 size_t delay_; 75 size_t remaining_; 76 }; 77 78 // This uses a buffer to mimic the behaviour of flash (requires erase before 79 // write, checks alignments, and is addressed in sectors). The underlying buffer 80 // is not initialized. 81 class FakeFlashMemory : public FlashMemory { 82 public: 83 // Default to 8-bit alignment. 84 static constexpr size_t kDefaultAlignmentBytes = 1; 85 86 static constexpr std::byte kErasedValue = std::byte{0xff}; 87 88 FakeFlashMemory(std::span<std::byte> buffer, 89 size_t sector_size, 90 size_t sector_count, 91 size_t alignment_bytes = kDefaultAlignmentBytes, 92 Vector<FlashError>& read_errors = no_errors_, 93 Vector<FlashError>& write_errors = no_errors_) FlashMemory(sector_size,sector_count,alignment_bytes)94 : FlashMemory(sector_size, sector_count, alignment_bytes), 95 buffer_(buffer), 96 read_errors_(read_errors), 97 write_errors_(write_errors) {} 98 99 // The fake flash is always enabled. Enable()100 Status Enable() override { return OkStatus(); } 101 Disable()102 Status Disable() override { return OkStatus(); } 103 IsEnabled()104 bool IsEnabled() const override { return true; } 105 106 // Erase num_sectors starting at a given address. 107 Status Erase(Address address, size_t num_sectors) override; 108 109 // Reads bytes from flash into buffer. 110 StatusWithSize Read(Address address, std::span<std::byte> output) override; 111 112 // Writes bytes to flash. 113 StatusWithSize Write(Address address, 114 std::span<const std::byte> data) override; 115 FlashAddressToMcuAddress(Address)116 std::byte* FlashAddressToMcuAddress(Address) const override; 117 118 // Testing API 119 120 // Access the underlying buffer for testing purposes. Not part of the 121 // FlashMemory API. 122 std::span<std::byte> buffer() const { return buffer_; } 123 InjectReadError(const FlashError & error)124 bool InjectReadError(const FlashError& error) { 125 if (read_errors_.full()) { 126 return false; 127 } 128 read_errors_.push_back(error); 129 return true; 130 } 131 InjectWriteError(const FlashError & error)132 bool InjectWriteError(const FlashError& error) { 133 if (write_errors_.full()) { 134 return false; 135 } 136 write_errors_.push_back(error); 137 return true; 138 } 139 140 private: 141 static inline Vector<FlashError, 0> no_errors_; 142 143 const std::span<std::byte> buffer_; 144 Vector<FlashError>& read_errors_; 145 Vector<FlashError>& write_errors_; 146 }; 147 148 // Creates an FakeFlashMemory backed by a std::array. The array is initialized 149 // to the erased value. A byte array to which to initialize the memory may be 150 // provided. 151 template <size_t kSectorSize, size_t kSectorCount, size_t kInjectedErrors = 8> 152 class FakeFlashMemoryBuffer : public FakeFlashMemory { 153 public: 154 // Creates a flash memory with no data written. 155 explicit FakeFlashMemoryBuffer( 156 size_t alignment_bytes = kDefaultAlignmentBytes) FakeFlashMemoryBuffer(std::array<std::byte,0>{},alignment_bytes)157 : FakeFlashMemoryBuffer(std::array<std::byte, 0>{}, alignment_bytes) {} 158 159 // Creates a flash memory initialized to the provided contents. 160 explicit FakeFlashMemoryBuffer( 161 std::span<const std::byte> contents, 162 size_t alignment_bytes = kDefaultAlignmentBytes) FakeFlashMemory(buffer_,kSectorSize,kSectorCount,alignment_bytes,read_errors_,write_errors_)163 : FakeFlashMemory(buffer_, 164 kSectorSize, 165 kSectorCount, 166 alignment_bytes, 167 read_errors_, 168 write_errors_) { 169 std::memset(buffer_.data(), int(kErasedValue), buffer_.size()); 170 std::memcpy(buffer_.data(), 171 contents.data(), 172 std::min(contents.size(), buffer_.size())); 173 } 174 175 private: 176 std::array<std::byte, kSectorCount * kSectorSize> buffer_; 177 Vector<FlashError, kInjectedErrors> read_errors_; 178 Vector<FlashError, kInjectedErrors> write_errors_; 179 }; 180 181 } // namespace pw::kvs 182