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 21 #include "pw_containers/vector.h" 22 #include "pw_kvs/flash_memory.h" 23 #include "pw_span/span.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(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(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, span<std::byte> output) override; 111 112 // Writes bytes to flash. 113 StatusWithSize Write(Address address, span<const std::byte> data) override; 114 FlashAddressToMcuAddress(Address)115 std::byte* FlashAddressToMcuAddress(Address) const override; 116 117 // Testing API 118 119 // Access the underlying buffer for testing purposes. Not part of the 120 // FlashMemory API. 121 span<std::byte> buffer() const { return buffer_; } 122 InjectReadError(const FlashError & error)123 bool InjectReadError(const FlashError& error) { 124 if (read_errors_.full()) { 125 return false; 126 } 127 read_errors_.push_back(error); 128 return true; 129 } 130 InjectWriteError(const FlashError & error)131 bool InjectWriteError(const FlashError& error) { 132 if (write_errors_.full()) { 133 return false; 134 } 135 write_errors_.push_back(error); 136 return true; 137 } 138 139 private: 140 static Vector<FlashError, 0> no_errors_; 141 142 const span<std::byte> buffer_; 143 Vector<FlashError>& read_errors_; 144 Vector<FlashError>& write_errors_; 145 }; 146 147 // Creates an FakeFlashMemory backed by a std::array. The array is initialized 148 // to the erased value. A byte array to which to initialize the memory may be 149 // provided. 150 template <size_t kSectorSize, size_t kSectorCount, size_t kInjectedErrors = 8> 151 class FakeFlashMemoryBuffer : public FakeFlashMemory { 152 public: 153 // Creates a flash memory with no data written. 154 explicit FakeFlashMemoryBuffer( 155 size_t alignment_bytes = kDefaultAlignmentBytes) FakeFlashMemory(buffer_,kSectorSize,kSectorCount,alignment_bytes,read_errors_,write_errors_)156 : FakeFlashMemory(buffer_, 157 kSectorSize, 158 kSectorCount, 159 alignment_bytes, 160 read_errors_, 161 write_errors_) { 162 std::memset(buffer_.data(), int(kErasedValue), buffer_.size()); 163 } 164 165 // Creates a flash memory initialized to the provided contents. 166 explicit FakeFlashMemoryBuffer( 167 span<const std::byte> contents, 168 size_t alignment_bytes = kDefaultAlignmentBytes) FakeFlashMemoryBuffer(alignment_bytes)169 : FakeFlashMemoryBuffer(alignment_bytes) { 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