Skip to content

Commit ca27f6c

Browse files
committed
bd: Added utility block device classes
- ChainingBlockDevice - SlicingBlockDevice
1 parent 5a6294d commit ca27f6c

File tree

5 files changed

+821
-0
lines changed

5 files changed

+821
-0
lines changed
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
/* mbed Microcontroller Library
2+
* Copyright (c) 2017 ARM Limited
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
#include "mbed.h"
17+
#include "greentea-client/test_env.h"
18+
#include "unity.h"
19+
#include "utest.h"
20+
21+
#include "HeapBlockDevice.h"
22+
#include "SlicingBlockDevice.h"
23+
#include "ChainingBlockDevice.h"
24+
#include <stdlib.h>
25+
26+
using namespace utest::v1;
27+
28+
#define BLOCK_COUNT 16
29+
#define BLOCK_SIZE 512
30+
uint8_t write_block[BLOCK_SIZE];
31+
uint8_t read_block[BLOCK_SIZE];
32+
33+
// Simple test which read/writes blocks on a sliced block device
34+
void test_slicing() {
35+
HeapBlockDevice bd(BLOCK_COUNT*BLOCK_SIZE, BLOCK_SIZE);
36+
37+
// Test with first slice of block device
38+
SlicingBlockDevice slice1(&bd, 0, (BLOCK_COUNT/2)*BLOCK_SIZE);
39+
40+
int err = slice1.init();
41+
TEST_ASSERT_EQUAL(0, err);
42+
43+
TEST_ASSERT_EQUAL(BLOCK_SIZE, slice1.get_write_size());
44+
TEST_ASSERT_EQUAL((BLOCK_COUNT/2)*BLOCK_SIZE, slice1.size());
45+
46+
// Fill with random sequence
47+
srand(1);
48+
for (int i = 0; i < BLOCK_SIZE; i++) {
49+
write_block[i] = 0xff & rand();
50+
}
51+
52+
// Write, sync, and read the block
53+
err = slice1.write(write_block, 0, BLOCK_SIZE);
54+
TEST_ASSERT_EQUAL(0, err);
55+
56+
err = slice1.read(read_block, 0, BLOCK_SIZE);
57+
TEST_ASSERT_EQUAL(0, err);
58+
59+
// Check that the data was unmodified
60+
srand(1);
61+
for (int i = 0; i < BLOCK_SIZE; i++) {
62+
TEST_ASSERT_EQUAL(0xff & rand(), read_block[i]);
63+
}
64+
65+
// Check with original block device
66+
err = bd.read(read_block, 0, BLOCK_SIZE);
67+
TEST_ASSERT_EQUAL(0, err);
68+
69+
// Check that the data was unmodified
70+
srand(1);
71+
for (int i = 0; i < BLOCK_SIZE; i++) {
72+
TEST_ASSERT_EQUAL(0xff & rand(), read_block[i]);
73+
}
74+
75+
err = slice1.deinit();
76+
TEST_ASSERT_EQUAL(0, err);
77+
78+
79+
// Test with second slice of block device
80+
SlicingBlockDevice slice2(&bd, -(BLOCK_COUNT/2)*BLOCK_SIZE);
81+
82+
err = slice2.init();
83+
TEST_ASSERT_EQUAL(0, err);
84+
85+
TEST_ASSERT_EQUAL(BLOCK_SIZE, slice2.get_write_size());
86+
TEST_ASSERT_EQUAL((BLOCK_COUNT/2)*BLOCK_SIZE, slice2.size());
87+
88+
// Fill with random sequence
89+
srand(1);
90+
for (int i = 0; i < BLOCK_SIZE; i++) {
91+
write_block[i] = 0xff & rand();
92+
}
93+
94+
// Write, sync, and read the block
95+
err = slice2.write(write_block, 0, BLOCK_SIZE);
96+
TEST_ASSERT_EQUAL(0, err);
97+
98+
err = slice2.read(read_block, 0, BLOCK_SIZE);
99+
TEST_ASSERT_EQUAL(0, err);
100+
101+
// Check that the data was unmodified
102+
srand(1);
103+
for (int i = 0; i < BLOCK_SIZE; i++) {
104+
TEST_ASSERT_EQUAL(0xff & rand(), read_block[i]);
105+
}
106+
107+
// Check with original block device
108+
err = bd.read(read_block, (BLOCK_COUNT/2)*BLOCK_SIZE, BLOCK_SIZE);
109+
TEST_ASSERT_EQUAL(0, err);
110+
111+
// Check that the data was unmodified
112+
srand(1);
113+
for (int i = 0; i < BLOCK_SIZE; i++) {
114+
TEST_ASSERT_EQUAL(0xff & rand(), read_block[i]);
115+
}
116+
117+
err = slice2.deinit();
118+
TEST_ASSERT_EQUAL(0, err);
119+
}
120+
121+
// Simple test which read/writes blocks on a chain of block devices
122+
void test_chaining() {
123+
HeapBlockDevice bd1((BLOCK_COUNT/2)*BLOCK_SIZE, BLOCK_SIZE);
124+
HeapBlockDevice bd2((BLOCK_COUNT/2)*BLOCK_SIZE, BLOCK_SIZE);
125+
126+
// Test with chain of block device
127+
BlockDevice *bds[] = {&bd1, &bd2};
128+
ChainingBlockDevice chain(bds);
129+
130+
int err = chain.init();
131+
TEST_ASSERT_EQUAL(0, err);
132+
133+
TEST_ASSERT_EQUAL(BLOCK_SIZE, chain.get_write_size());
134+
TEST_ASSERT_EQUAL(BLOCK_COUNT*BLOCK_SIZE, chain.size());
135+
136+
// Fill with random sequence
137+
srand(1);
138+
for (int i = 0; i < BLOCK_SIZE; i++) {
139+
write_block[i] = 0xff & rand();
140+
}
141+
142+
// Write, sync, and read the block
143+
err = chain.write(write_block, 0, BLOCK_SIZE);
144+
TEST_ASSERT_EQUAL(0, err);
145+
146+
err = chain.read(read_block, 0, BLOCK_SIZE);
147+
TEST_ASSERT_EQUAL(0, err);
148+
149+
// Check that the data was unmodified
150+
srand(1);
151+
for (int i = 0; i < BLOCK_SIZE; i++) {
152+
TEST_ASSERT_EQUAL(0xff & rand(), read_block[i]);
153+
}
154+
155+
// Write, sync, and read the block
156+
err = chain.write(write_block, (BLOCK_COUNT/2)*BLOCK_SIZE, BLOCK_SIZE);
157+
TEST_ASSERT_EQUAL(0, err);
158+
159+
err = chain.read(read_block, (BLOCK_COUNT/2)*BLOCK_SIZE, BLOCK_SIZE);
160+
TEST_ASSERT_EQUAL(0, err);
161+
162+
// Check that the data was unmodified
163+
srand(1);
164+
for (int i = 0; i < BLOCK_SIZE; i++) {
165+
TEST_ASSERT_EQUAL(0xff & rand(), read_block[i]);
166+
}
167+
168+
err = chain.deinit();
169+
TEST_ASSERT_EQUAL(0, err);
170+
}
171+
172+
173+
// Test setup
174+
utest::v1::status_t test_setup(const size_t number_of_cases) {
175+
GREENTEA_SETUP(10, "default_auto");
176+
return verbose_test_setup_handler(number_of_cases);
177+
}
178+
179+
Case cases[] = {
180+
Case("Testing slicing of a block device", test_slicing),
181+
Case("Testing chaining of block devices", test_chaining),
182+
};
183+
184+
Specification specification(test_setup, cases);
185+
186+
int main() {
187+
return !Harness::run(specification);
188+
}
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
/* mbed Microcontroller Library
2+
* Copyright (c) 2017 ARM Limited
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include "ChainingBlockDevice.h"
18+
19+
20+
ChainingBlockDevice::ChainingBlockDevice(BlockDevice **bds, size_t bd_count)
21+
: _bds(bds), _bd_count(bd_count)
22+
, _read_size(0), _program_size(0), _erase_size(0), _size(0)
23+
{
24+
}
25+
26+
static bool is_aligned(uint64_t x, uint64_t alignment)
27+
{
28+
return (x / alignment) * alignment == x;
29+
}
30+
31+
bd_error_t ChainingBlockDevice::init()
32+
{
33+
_read_size = 0;
34+
_program_size = 0;
35+
_erase_size = 0;
36+
_size = 0;
37+
38+
// Initialize children block devices, find all sizes and
39+
// assert that block sizes are similar. We can't do this in
40+
// the constructor since some block devices may need to be
41+
// initialized before they know their block size/count
42+
for (size_t i = 0; i < _bd_count; i++) {
43+
bd_error_t err = _bds[i]->init();
44+
if (err) {
45+
return err;
46+
}
47+
48+
bd_size_t read = _bds[i]->get_read_size();
49+
if (i == 0 || (read >= _read_size && is_aligned(read, _read_size))) {
50+
_read_size = read;
51+
} else if (!(_read_size > read && is_aligned(_read_size, read))) {
52+
return BD_ERROR_PARAMETER;
53+
}
54+
55+
bd_size_t program = _bds[i]->get_program_size();
56+
if (i == 0 || (program >= _program_size && is_aligned(program, _program_size))) {
57+
_program_size = program;
58+
} else if (!(_program_size > program && is_aligned(_program_size, program))) {
59+
return BD_ERROR_PARAMETER;
60+
}
61+
62+
bd_size_t erase = _bds[i]->get_erase_size();
63+
if (i == 0 || (erase >= _erase_size && is_aligned(erase, _erase_size))) {
64+
_erase_size = erase;
65+
} else if (!(_erase_size > erase && is_aligned(_erase_size, erase))) {
66+
return BD_ERROR_PARAMETER;
67+
}
68+
69+
_size += _bds[i]->size();
70+
}
71+
72+
return 0;
73+
}
74+
75+
bd_error_t ChainingBlockDevice::deinit()
76+
{
77+
for (size_t i = 0; i < _bd_count; i++) {
78+
bd_error_t err = _bds[i]->deinit();
79+
if (err) {
80+
return err;
81+
}
82+
}
83+
84+
return 0;
85+
}
86+
87+
bd_error_t ChainingBlockDevice::read(void *b, bd_addr_t addr, bd_size_t size)
88+
{
89+
if (!is_valid_read(addr, size)) {
90+
return BD_ERROR_PARAMETER;
91+
}
92+
93+
uint8_t *buffer = static_cast<uint8_t*>(b);
94+
95+
// Find block devices containing blocks, may span multiple block devices
96+
for (size_t i = 0; i < _bd_count && size > 0; i++) {
97+
bd_size_t bdsize = _bds[i]->size();
98+
99+
if (addr < bdsize) {
100+
bd_size_t read = size;
101+
if (addr + read > bdsize) {
102+
read = bdsize - addr;
103+
}
104+
105+
bd_error_t err = _bds[i]->read(buffer, addr, read);
106+
if (err) {
107+
return err;
108+
}
109+
110+
buffer += read;
111+
addr += read;
112+
size -= read;
113+
}
114+
115+
addr -= size;
116+
}
117+
118+
return 0;
119+
}
120+
121+
bd_error_t ChainingBlockDevice::program(const void *b, bd_addr_t addr, bd_size_t size)
122+
{
123+
if (!is_valid_program(addr, size)) {
124+
return BD_ERROR_PARAMETER;
125+
}
126+
127+
const uint8_t *buffer = static_cast<const uint8_t*>(b);
128+
129+
// Find block devices containing blocks, may span multiple block devices
130+
for (size_t i = 0; i < _bd_count && size > 0; i++) {
131+
bd_size_t bdsize = _bds[i]->size();
132+
133+
if (addr < bdsize) {
134+
bd_size_t program = size;
135+
if (addr + program > bdsize) {
136+
program = bdsize - addr;
137+
}
138+
139+
bd_error_t err = _bds[i]->program(buffer, addr, program);
140+
if (err) {
141+
return err;
142+
}
143+
144+
buffer += program;
145+
addr += program;
146+
size -= program;
147+
}
148+
149+
addr -= size;
150+
}
151+
152+
return 0;
153+
}
154+
155+
bd_error_t ChainingBlockDevice::erase(bd_addr_t addr, bd_size_t size)
156+
{
157+
if (!is_valid_erase(addr, size)) {
158+
return BD_ERROR_PARAMETER;
159+
}
160+
161+
// Find block devices containing blocks, may span multiple block devices
162+
for (size_t i = 0; i < _bd_count && size > 0; i++) {
163+
bd_size_t bdsize = _bds[i]->size();
164+
165+
if (addr < bdsize) {
166+
bd_size_t erase = size;
167+
if (addr + erase > bdsize) {
168+
erase = bdsize - addr;
169+
}
170+
171+
bd_error_t err = _bds[i]->erase(addr, erase);
172+
if (err) {
173+
return err;
174+
}
175+
176+
addr += erase;
177+
size -= erase;
178+
}
179+
180+
addr -= size;
181+
}
182+
183+
return 0;
184+
}
185+
186+
bd_size_t ChainingBlockDevice::get_read_size()
187+
{
188+
return _read_size;
189+
}
190+
191+
bd_size_t ChainingBlockDevice::get_program_size()
192+
{
193+
return _program_size;
194+
}
195+
196+
bd_size_t ChainingBlockDevice::get_erase_size()
197+
{
198+
return _erase_size;
199+
}
200+
201+
bd_size_t ChainingBlockDevice::size()
202+
{
203+
return _size;
204+
}

0 commit comments

Comments
 (0)