blob: 6b5a9ceaae4e7d6455a9def1551f9945ce884aee [file] [log] [blame]
David Rogersca592962020-07-01 09:21:54 -07001// 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
15#include "pw_kvs/flash_partition_test.h"
16
17#include <span>
18
19#include "gtest/gtest.h"
20#include "pw_kvs/flash_memory.h"
21#include "pw_kvs_private/config.h"
22#include "pw_log/log.h"
23
24namespace pw::kvs::PartitionTest {
25
26constexpr size_t kTestDataSize = kMaxFlashAlignment;
27
28namespace {
29
30void WriteData(FlashPartition& partition, uint8_t fill_byte) {
31 uint8_t test_data[kTestDataSize];
32 memset(test_data, fill_byte, sizeof(test_data));
33
34 ASSERT_GE(kTestDataSize, partition.alignment_bytes());
35
36 partition.Erase(0, partition.sector_count());
37
38 const size_t chunks_per_sector =
39 partition.sector_size_bytes() / partition.alignment_bytes();
40
41 // Fill partition sector by sector. Fill the sector with an integer number
42 // of alignment-size chunks. If the sector is not evenly divisible by
43 // alignment-size, the remainder is not written.
44 for (size_t sector_index = 0; sector_index < partition.sector_count();
45 sector_index++) {
46 FlashPartition::Address address =
47 sector_index * partition.sector_size_bytes();
48
49 for (size_t chunk_index = 0; chunk_index < chunks_per_sector;
50 chunk_index++) {
51 StatusWithSize status = partition.Write(
52 address, as_bytes(std::span(test_data, partition.alignment_bytes())));
53 ASSERT_EQ(Status::OK, status.status());
54 ASSERT_EQ(partition.alignment_bytes(), status.size());
55 address += partition.alignment_bytes();
56 }
57 }
58
59 // Check the fill result. Use expect so the test doesn't bail on error.
60 // Count the errors and print if any errors are found.
61 size_t error_count = 0;
62 for (size_t sector_index = 0; sector_index < partition.sector_count();
63 sector_index++) {
64 FlashPartition::Address address =
65 sector_index * partition.sector_size_bytes();
66
67 for (size_t chunk_index = 0; chunk_index < chunks_per_sector;
68 chunk_index++) {
69 memset(test_data, 0, sizeof(test_data));
70 StatusWithSize status =
71 partition.Read(address, partition.alignment_bytes(), test_data);
72
73 EXPECT_EQ(Status::OK, status.status());
74 EXPECT_EQ(partition.alignment_bytes(), status.size());
75 if (!status.ok() || (partition.alignment_bytes() != status.size())) {
76 error_count++;
77 continue;
78 }
79
80 for (size_t i = 0; i < partition.alignment_bytes(); i++) {
81 if (test_data[i] != fill_byte) {
82 error_count++;
83 }
84 }
85
86 address += partition.alignment_bytes();
87 }
88 }
89
90 EXPECT_EQ(error_count, 0U);
91 if (error_count != 0) {
92 PW_LOG_ERROR("Partition test, fill '%c', %u errors found",
93 fill_byte,
94 unsigned(error_count));
95 }
96}
97
98} // namespace
99
100void WriteTest(FlashPartition& partition, size_t test_iterations) {
101 ASSERT_GE(kTestDataSize, partition.alignment_bytes());
102
103 for (size_t i = 0; i < test_iterations; i++) {
104 WriteData(partition, 0);
105 WriteData(partition, 0xff);
106 WriteData(partition, 0x55);
107 WriteData(partition, 0xa3);
108 }
109}
110
111void EraseTest(FlashPartition& partition) {
112 static const uint8_t fill_byte = 0x55;
113 uint8_t test_data[kTestDataSize];
114 memset(test_data, fill_byte, sizeof(test_data));
115
116 ASSERT_GE(kTestDataSize, partition.alignment_bytes());
117
118 const size_t block_size =
119 std::min(sizeof(test_data), partition.sector_size_bytes());
120 auto data_span = std::span(test_data, block_size);
121
122 ASSERT_EQ(Status::OK, partition.Erase(0, partition.sector_count()));
123
124 // Write to the first page of each sector.
125 for (size_t sector_index = 0; sector_index < partition.sector_count();
126 sector_index++) {
127 FlashPartition::Address address =
128 sector_index * partition.sector_size_bytes();
129
130 StatusWithSize status = partition.Write(address, as_bytes(data_span));
131 ASSERT_EQ(Status::OK, status.status());
132 ASSERT_EQ(block_size, status.size());
133 }
134
135 ASSERT_EQ(Status::OK, partition.Erase());
136
137 bool is_erased;
138 ASSERT_EQ(Status::OK,
139 partition.IsRegionErased(0, partition.size_bytes(), &is_erased));
140 ASSERT_EQ(true, is_erased);
141
142 // Read the first page of each sector and make sure it has been erased.
143 for (size_t sector_index = 0; sector_index < partition.sector_count();
144 sector_index++) {
145 FlashPartition::Address address =
146 sector_index * partition.sector_size_bytes();
147
148 StatusWithSize status =
149 partition.Read(address, data_span.size_bytes(), data_span.data());
150 ASSERT_EQ(Status::OK, status.status());
151 ASSERT_EQ(data_span.size_bytes(), status.size());
152
153 ASSERT_EQ(true, partition.AppearsErased(as_bytes(data_span)));
154 }
155}
156
157void ReadOnlyTest(FlashPartition& partition) {
158 uint8_t test_data[kTestDataSize];
159 auto data_span = std::span(test_data);
160
161 ASSERT_EQ(Status::PERMISSION_DENIED,
162 partition.Erase(0, partition.sector_count()));
163
164 ASSERT_EQ(Status::PERMISSION_DENIED,
165 partition.Write(0, as_bytes(data_span)).status());
166}
167
168} // namespace pw::kvs::PartitionTest