Skip to content

Commit 1464471

Browse files
committed
bd: Adopted the block device api in the HeapBlockDevice
Port of MemBlockDevice from mbed 2
1 parent 95919ea commit 1464471

File tree

3 files changed

+367
-0
lines changed

3 files changed

+367
-0
lines changed
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
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 <stdlib.h>
23+
24+
using namespace utest::v1;
25+
26+
#define BLOCK_SIZE 512
27+
uint8_t write_block[BLOCK_SIZE];
28+
uint8_t read_block[BLOCK_SIZE];
29+
30+
// Simple test which reads and writes a block
31+
void test_read_write() {
32+
HeapBlockDevice bd(16*BLOCK_SIZE, BLOCK_SIZE);
33+
34+
int err = bd.init();
35+
TEST_ASSERT_EQUAL(0, err);
36+
37+
// Fill with random sequence
38+
srand(1);
39+
for (int i = 0; i < BLOCK_SIZE; i++) {
40+
write_block[i] = 0xff & rand();
41+
}
42+
43+
// Write, sync, and read the block
44+
err = bd.write(write_block, 0, BLOCK_SIZE);
45+
TEST_ASSERT_EQUAL(0, err);
46+
47+
err = bd.read(read_block, 0, BLOCK_SIZE);
48+
TEST_ASSERT_EQUAL(0, err);
49+
50+
// Check that the data was unmodified
51+
srand(1);
52+
for (int i = 0; i < BLOCK_SIZE; i++) {
53+
TEST_ASSERT_EQUAL(0xff & rand(), read_block[i]);
54+
}
55+
56+
err = bd.deinit();
57+
TEST_ASSERT_EQUAL(0, err);
58+
}
59+
60+
61+
// Test setup
62+
utest::v1::status_t test_setup(const size_t number_of_cases) {
63+
GREENTEA_SETUP(10, "default_auto");
64+
return verbose_test_setup_handler(number_of_cases);
65+
}
66+
67+
Case cases[] = {
68+
Case("Testing read write of a block", test_read_write),
69+
};
70+
71+
Specification specification(test_setup, cases);
72+
73+
int main() {
74+
return !Harness::run(specification);
75+
}
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
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 "HeapBlockDevice.h"
18+
19+
20+
HeapBlockDevice::HeapBlockDevice(bd_size_t size, bd_size_t block)
21+
: _read_size(block), _program_size(block), _erase_size(block)
22+
, _count(size / block), _blocks(0)
23+
{
24+
MBED_ASSERT(_count * _erase_size == size);
25+
}
26+
27+
HeapBlockDevice::HeapBlockDevice(bd_size_t size,
28+
bd_size_t read, bd_size_t program, bd_size_t erase)
29+
: _read_size(read), _program_size(program), _erase_size(erase)
30+
, _count(size / erase), _blocks(0)
31+
{
32+
MBED_ASSERT(_count * _erase_size == size);
33+
}
34+
35+
HeapBlockDevice::~HeapBlockDevice()
36+
{
37+
if (_blocks) {
38+
for (size_t i = 0; i < _count; i++) {
39+
free(_blocks[i]);
40+
}
41+
42+
delete[] _blocks;
43+
_blocks = 0;
44+
}
45+
}
46+
47+
bd_error_t HeapBlockDevice::init()
48+
{
49+
if (!_blocks) {
50+
_blocks = new uint8_t*[_count];
51+
for (size_t i = 0; i < _count; i++) {
52+
_blocks[i] = 0;
53+
}
54+
}
55+
56+
return BD_ERROR_OK;
57+
}
58+
59+
bd_error_t HeapBlockDevice::deinit()
60+
{
61+
// Heapory is lazily cleaned up in destructor to allow
62+
// data to live across de/reinitialization
63+
return BD_ERROR_OK;
64+
}
65+
66+
bd_size_t HeapBlockDevice::get_read_size()
67+
{
68+
return _read_size;
69+
}
70+
71+
bd_size_t HeapBlockDevice::get_program_size()
72+
{
73+
return _program_size;
74+
}
75+
76+
bd_size_t HeapBlockDevice::get_erase_size()
77+
{
78+
return _erase_size;
79+
}
80+
81+
bd_size_t HeapBlockDevice::size()
82+
{
83+
return _count * _erase_size;
84+
}
85+
86+
bd_error_t HeapBlockDevice::read(void *b, bd_addr_t addr, bd_size_t size)
87+
{
88+
if (!is_valid_read(addr, size)) {
89+
return BD_ERROR_PARAMETER;
90+
}
91+
92+
uint8_t *buffer = static_cast<uint8_t*>(b);
93+
while (size > 0) {
94+
bd_addr_t hi = addr / _erase_size;
95+
bd_addr_t lo = addr % _erase_size;
96+
97+
if (_blocks[hi]) {
98+
memcpy(buffer, &_blocks[hi][lo], _read_size);
99+
} else {
100+
memset(buffer, 0, _read_size);
101+
}
102+
103+
buffer += _read_size;
104+
addr += _read_size;
105+
size -= _read_size;
106+
}
107+
108+
return 0;
109+
}
110+
111+
bd_error_t HeapBlockDevice::program(const void *b, bd_addr_t addr, bd_size_t size)
112+
{
113+
if (!is_valid_program(addr, size)) {
114+
return BD_ERROR_PARAMETER;
115+
}
116+
117+
const uint8_t *buffer = static_cast<const uint8_t*>(b);
118+
while (size > 0) {
119+
bd_addr_t hi = addr / _erase_size;
120+
bd_addr_t lo = addr % _erase_size;
121+
122+
if (!_blocks[hi]) {
123+
_blocks[hi] = (uint8_t*)malloc(_erase_size);
124+
if (!_blocks[hi]) {
125+
return BD_ERROR_DEVICE_ERROR;
126+
}
127+
}
128+
129+
memcpy(&_blocks[hi][lo], buffer, _program_size);
130+
131+
buffer += _program_size;
132+
addr += _program_size;
133+
size -= _program_size;
134+
}
135+
136+
return 0;
137+
}
138+
139+
bd_error_t HeapBlockDevice::erase(bd_addr_t addr, bd_size_t size)
140+
{
141+
if (!is_valid_erase(addr, size)) {
142+
return BD_ERROR_PARAMETER;
143+
}
144+
145+
#ifndef NDEBUG
146+
while (size > 0) {
147+
bd_addr_t hi = addr / _erase_size;
148+
149+
if (_blocks[hi]) {
150+
memset(_blocks[hi], 0xcc, _erase_size);
151+
}
152+
153+
addr += _erase_size;
154+
size -= _erase_size;
155+
}
156+
#endif
157+
158+
return 0;
159+
}
160+
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
/* mbed Microcontroller Library
2+
* Copyright (c) 2017 ARM Limited
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a copy
5+
* of this software and associated documentation files (the "Software"), to deal
6+
* in the Software without restriction, including without limitation the rights
7+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
* copies of the Software, and to permit persons to whom the Software is
9+
* furnished to do so, subject to the following conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be included in
12+
* all copies or substantial portions of the Software.
13+
*
14+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20+
* SOFTWARE.
21+
*/
22+
#ifndef MBED_MEM_BLOCK_DEVICE_H
23+
#define MBED_MEM_BLOCK_DEVICE_H
24+
25+
#include "BlockDevice.h"
26+
#include "mbed.h"
27+
28+
29+
/** Lazily allocated heap-backed block device
30+
*
31+
* Useful for simulating a block device and tests
32+
*
33+
* @code
34+
* #include "mbed.h"
35+
* #include "HeapBlockDevice.h"
36+
*
37+
* HeapBlockDevice bd(2048, 512); // 2048 bytes with a block size of 512 bytes
38+
* uint8_t block[512] = "Hello World!\n";
39+
*
40+
* int main() {
41+
* bd.init();
42+
* bd.write(block, 0);
43+
* bd.read(block, 0);
44+
* printf("%s", block);
45+
* bd.deinit();
46+
* }
47+
*/
48+
class HeapBlockDevice : public BlockDevice {
49+
public:
50+
51+
/** Lifetime of the memory block device
52+
*/
53+
HeapBlockDevice(bd_size_t size, bd_size_t block=512);
54+
HeapBlockDevice(bd_size_t size, bd_size_t read, bd_size_t program, bd_size_t erase);
55+
virtual ~HeapBlockDevice();
56+
57+
/** Initialize a block device
58+
*
59+
* @return 0 on success or a negative error code on failure
60+
*/
61+
virtual bd_error_t init() = 0;
62+
63+
/** Deinitialize a block device
64+
*
65+
* @return 0 on success or a negative error code on failure
66+
*/
67+
virtual bd_error_t deinit() = 0;
68+
69+
/** Read blocks from a block device
70+
*
71+
* @param buffer Buffer to write blocks to
72+
* @param addr Address of block to begin reading from
73+
* @param size Size to read in bytes, must be a multiple of read block size
74+
* @return 0 on success, negative error code on failure
75+
*/
76+
virtual bd_error_t read(void *buffer, bd_addr_t addr, bd_size_t size) = 0;
77+
78+
/** Program blocks to a block device
79+
*
80+
* The blocks must have been erased prior to being programmed
81+
*
82+
* @param buffer Buffer of data to write to blocks
83+
* @param addr Address of block to begin writing to
84+
* @param size Size to write in bytes, must be a multiple of program block size
85+
* @return 0 on success, negative error code on failure
86+
*/
87+
virtual bd_error_t program(const void *buffer, bd_addr_t addr, bd_size_t size);
88+
89+
/** Erase blocks on a block device
90+
*
91+
* The state of an erased block is undefined until it has been programmed
92+
*
93+
* @param addr Address of block to begin erasing
94+
* @param size Size to erase in bytes, must be a multiple of erase block size
95+
* @return 0 on success, negative error code on failure
96+
*/
97+
virtual bd_error_t erase(bd_addr_t addr, bd_size_t size);
98+
99+
/** Get the size of a readable block
100+
*
101+
* @return Size of a readable block in bytes
102+
*/
103+
virtual bd_size_t get_read_size();
104+
105+
/** Get the size of a programable block
106+
*
107+
* @return Size of a programable block in bytes
108+
*/
109+
virtual bd_size_t get_program_size();
110+
111+
/** Get the size of a eraseable block
112+
*
113+
* @return Size of a eraseable block in bytes
114+
*/
115+
virtual bd_size_t get_erase_size();
116+
117+
/** Get the total size of the underlying device
118+
*
119+
* @return Size of the underlying device in bytes
120+
*/
121+
virtual bd_size_t size();
122+
123+
private:
124+
bd_size_t _read_size;
125+
bd_size_t _program_size;
126+
bd_size_t _erase_size;
127+
bd_size_t _count;
128+
uint8_t **_blocks;
129+
};
130+
131+
132+
#endif

0 commit comments

Comments
 (0)