Skip to content

Commit f538013

Browse files
committed
bd: Added utility block device classes
- ChainingBlockDevice - SlicingBlockDevice
1 parent 40130cc commit f538013

File tree

5 files changed

+810
-0
lines changed

5 files changed

+810
-0
lines changed
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
#include "mbed.h"
2+
#include "greentea-client/test_env.h"
3+
#include "unity.h"
4+
#include "utest.h"
5+
6+
#include "HeapBlockDevice.h"
7+
#include "SlicingBlockDevice.h"
8+
#include "ChainingBlockDevice.h"
9+
#include <stdlib.h>
10+
11+
using namespace utest::v1;
12+
13+
#define BLOCK_SIZE 512
14+
uint8_t write_block[BLOCK_SIZE];
15+
uint8_t read_block[BLOCK_SIZE];
16+
17+
18+
void test_slicing() {
19+
HeapBlockDevice bd(16*BLOCK_SIZE, BLOCK_SIZE);
20+
21+
// Test with first slice of block device
22+
SlicingBlockDevice slice1(&bd, 0, 8*BLOCK_SIZE);
23+
24+
int err = slice1.init();
25+
TEST_ASSERT_EQUAL(0, err);
26+
27+
TEST_ASSERT_EQUAL(BLOCK_SIZE, slice1.write_size());
28+
TEST_ASSERT_EQUAL(8*BLOCK_SIZE, slice1.size());
29+
30+
// Fill with random sequence
31+
srand(1);
32+
for (int i = 0; i < BLOCK_SIZE; i++) {
33+
write_block[i] = 0xff & rand();
34+
}
35+
36+
// Write, sync, and read the block
37+
err = slice1.write(write_block, 0, BLOCK_SIZE);
38+
TEST_ASSERT_EQUAL(0, err);
39+
40+
err = slice1.read(read_block, 0, BLOCK_SIZE);
41+
TEST_ASSERT_EQUAL(0, err);
42+
43+
// Check that the data was unmodified
44+
srand(1);
45+
for (int i = 0; i < BLOCK_SIZE; i++) {
46+
TEST_ASSERT_EQUAL(0xff & rand(), read_block[i]);
47+
}
48+
49+
// Check with original block device
50+
err = bd.read(read_block, 0, BLOCK_SIZE);
51+
TEST_ASSERT_EQUAL(0, err);
52+
53+
// Check that the data was unmodified
54+
srand(1);
55+
for (int i = 0; i < BLOCK_SIZE; i++) {
56+
TEST_ASSERT_EQUAL(0xff & rand(), read_block[i]);
57+
}
58+
59+
err = slice1.deinit();
60+
TEST_ASSERT_EQUAL(0, err);
61+
62+
63+
// Test with second slice of block device
64+
SlicingBlockDevice slice2(&bd, -8*BLOCK_SIZE);
65+
66+
err = slice2.init();
67+
TEST_ASSERT_EQUAL(0, err);
68+
69+
TEST_ASSERT_EQUAL(BLOCK_SIZE, slice2.write_size());
70+
TEST_ASSERT_EQUAL(8*BLOCK_SIZE, slice2.size());
71+
72+
// Fill with random sequence
73+
srand(1);
74+
for (int i = 0; i < BLOCK_SIZE; i++) {
75+
write_block[i] = 0xff & rand();
76+
}
77+
78+
// Write, sync, and read the block
79+
err = slice2.write(write_block, 0, BLOCK_SIZE);
80+
TEST_ASSERT_EQUAL(0, err);
81+
82+
err = slice2.read(read_block, 0, BLOCK_SIZE);
83+
TEST_ASSERT_EQUAL(0, err);
84+
85+
// Check that the data was unmodified
86+
srand(1);
87+
for (int i = 0; i < BLOCK_SIZE; i++) {
88+
TEST_ASSERT_EQUAL(0xff & rand(), read_block[i]);
89+
}
90+
91+
// Check with original block device
92+
err = bd.read(read_block, 8*BLOCK_SIZE, BLOCK_SIZE);
93+
TEST_ASSERT_EQUAL(0, err);
94+
95+
// Check that the data was unmodified
96+
srand(1);
97+
for (int i = 0; i < BLOCK_SIZE; i++) {
98+
TEST_ASSERT_EQUAL(0xff & rand(), read_block[i]);
99+
}
100+
101+
err = slice2.deinit();
102+
TEST_ASSERT_EQUAL(0, err);
103+
}
104+
105+
void test_chaining() {
106+
HeapBlockDevice bd1(8*BLOCK_SIZE, BLOCK_SIZE);
107+
HeapBlockDevice bd2(8*BLOCK_SIZE, BLOCK_SIZE);
108+
109+
// Test with chain of block device
110+
BlockDevice *bds[] = {&bd1, &bd2};
111+
ChainingBlockDevice chain(bds);
112+
113+
int err = chain.init();
114+
TEST_ASSERT_EQUAL(0, err);
115+
116+
TEST_ASSERT_EQUAL(BLOCK_SIZE, chain.write_size());
117+
TEST_ASSERT_EQUAL(16*BLOCK_SIZE, chain.size());
118+
119+
// Fill with random sequence
120+
srand(1);
121+
for (int i = 0; i < BLOCK_SIZE; i++) {
122+
write_block[i] = 0xff & rand();
123+
}
124+
125+
// Write, sync, and read the block
126+
err = chain.write(write_block, 0, BLOCK_SIZE);
127+
TEST_ASSERT_EQUAL(0, err);
128+
129+
err = chain.read(read_block, 0, BLOCK_SIZE);
130+
TEST_ASSERT_EQUAL(0, err);
131+
132+
// Check that the data was unmodified
133+
srand(1);
134+
for (int i = 0; i < BLOCK_SIZE; i++) {
135+
TEST_ASSERT_EQUAL(0xff & rand(), read_block[i]);
136+
}
137+
138+
// Write, sync, and read the block
139+
err = chain.write(write_block, 8*BLOCK_SIZE, BLOCK_SIZE);
140+
TEST_ASSERT_EQUAL(0, err);
141+
142+
err = chain.read(read_block, 8*BLOCK_SIZE, BLOCK_SIZE);
143+
TEST_ASSERT_EQUAL(0, err);
144+
145+
// Check that the data was unmodified
146+
srand(1);
147+
for (int i = 0; i < BLOCK_SIZE; i++) {
148+
TEST_ASSERT_EQUAL(0xff & rand(), read_block[i]);
149+
}
150+
151+
err = chain.deinit();
152+
TEST_ASSERT_EQUAL(0, err);
153+
}
154+
155+
156+
// Test setup
157+
utest::v1::status_t test_setup(const size_t number_of_cases) {
158+
GREENTEA_SETUP(10, "default_auto");
159+
return verbose_test_setup_handler(number_of_cases);
160+
}
161+
162+
Case cases[] = {
163+
Case("Testing slicing of a block device", test_slicing),
164+
Case("Testing chaining of block devices", test_chaining),
165+
};
166+
167+
Specification specification(test_setup, cases);
168+
169+
int main() {
170+
return !Harness::run(specification);
171+
}
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
/* mbed Microcontroller Library
2+
* Copyright (c) 2016 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]->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+
_read_size = _read_size;
53+
} else {
54+
return BD_ERROR_PARAMETER;
55+
}
56+
57+
bd_size_t program = _bds[i]->program_size();
58+
if (i == 0 || (program >= _program_size && is_aligned(program, _program_size))) {
59+
_program_size = program;
60+
} else if (_program_size > program && is_aligned(_program_size, program)) {
61+
_program_size = _program_size;
62+
} else {
63+
return BD_ERROR_PARAMETER;
64+
}
65+
66+
bd_size_t erase = _bds[i]->erase_size();
67+
if (i == 0 || (erase >= _erase_size && is_aligned(erase, _erase_size))) {
68+
_erase_size = erase;
69+
} else if (_erase_size > erase && is_aligned(_erase_size, erase)) {
70+
_erase_size = _erase_size;
71+
} else {
72+
return BD_ERROR_PARAMETER;
73+
}
74+
75+
_size += _bds[i]->size();
76+
}
77+
78+
return 0;
79+
}
80+
81+
bd_error_t ChainingBlockDevice::deinit()
82+
{
83+
for (size_t i = 0; i < _bd_count; i++) {
84+
bd_error_t err = _bds[i]->deinit();
85+
if (err) {
86+
return err;
87+
}
88+
}
89+
90+
return 0;
91+
}
92+
93+
bd_error_t ChainingBlockDevice::read(void *b, bd_addr_t addr, bd_size_t size)
94+
{
95+
if (!is_valid_read(addr, size)) {
96+
return BD_ERROR_PARAMETER;
97+
}
98+
99+
uint8_t *buffer = static_cast<uint8_t*>(b);
100+
101+
// Find block devices containing blocks, may span multiple block devices
102+
for (size_t i = 0; i < _bd_count && size > 0; i++) {
103+
bd_size_t bdsize = _bds[i]->size();
104+
105+
if (addr < bdsize) {
106+
bd_size_t read = size;
107+
if (addr + read > bdsize) {
108+
read = bdsize - addr;
109+
}
110+
111+
bd_error_t err = _bds[i]->read(buffer, addr, read);
112+
if (err) {
113+
return err;
114+
}
115+
116+
buffer += read;
117+
addr += read;
118+
size -= read;
119+
}
120+
121+
addr -= size;
122+
}
123+
124+
return 0;
125+
}
126+
127+
bd_error_t ChainingBlockDevice::program(const void *b, bd_addr_t addr, bd_size_t size)
128+
{
129+
if (!is_valid_program(addr, size)) {
130+
return BD_ERROR_PARAMETER;
131+
}
132+
133+
const uint8_t *buffer = static_cast<const uint8_t*>(b);
134+
135+
// Find block devices containing blocks, may span multiple block devices
136+
for (size_t i = 0; i < _bd_count && size > 0; i++) {
137+
bd_size_t bdsize = _bds[i]->size();
138+
139+
if (addr < bdsize) {
140+
bd_size_t program = size;
141+
if (addr + program > bdsize) {
142+
program = bdsize - addr;
143+
}
144+
145+
bd_error_t err = _bds[i]->program(buffer, addr, program);
146+
if (err) {
147+
return err;
148+
}
149+
150+
buffer += program;
151+
addr += program;
152+
size -= program;
153+
}
154+
155+
addr -= size;
156+
}
157+
158+
return 0;
159+
}
160+
161+
bd_error_t ChainingBlockDevice::erase(bd_addr_t addr, bd_size_t size)
162+
{
163+
if (!is_valid_erase(addr, size)) {
164+
return BD_ERROR_PARAMETER;
165+
}
166+
167+
// Find block devices containing blocks, may span multiple block devices
168+
for (size_t i = 0; i < _bd_count && size > 0; i++) {
169+
bd_size_t bdsize = _bds[i]->size();
170+
171+
if (addr < bdsize) {
172+
bd_size_t erase = size;
173+
if (addr + erase > bdsize) {
174+
erase = bdsize - addr;
175+
}
176+
177+
bd_error_t err = _bds[i]->erase(addr, erase);
178+
if (err) {
179+
return err;
180+
}
181+
182+
addr += erase;
183+
size -= erase;
184+
}
185+
186+
addr -= size;
187+
}
188+
189+
return 0;
190+
}
191+
192+
bd_size_t ChainingBlockDevice::read_size()
193+
{
194+
return _read_size;
195+
}
196+
197+
bd_size_t ChainingBlockDevice::program_size()
198+
{
199+
return _program_size;
200+
}
201+
202+
bd_size_t ChainingBlockDevice::erase_size()
203+
{
204+
return _erase_size;
205+
}
206+
207+
bd_size_t ChainingBlockDevice::size()
208+
{
209+
return _size;
210+
}

0 commit comments

Comments
 (0)