-
Notifications
You must be signed in to change notification settings - Fork 3k
Implement FlashSimBlockDevice - flash simulated block device over RAM #6559
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
/* mbed Microcontroller Library | ||
* Copyright (c) 2018 ARM Limited | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
#include "mbed.h" | ||
#include "greentea-client/test_env.h" | ||
#include "unity.h" | ||
#include "utest.h" | ||
|
||
#include "FlashSimBlockDevice.h" | ||
#include "HeapBlockDevice.h" | ||
#include <stdlib.h> | ||
|
||
using namespace utest::v1; | ||
|
||
static const bd_size_t read_size = 1; | ||
static const bd_size_t prog_size = 8; | ||
static const bd_size_t erase_size = 512; | ||
static const bd_size_t num_blocks = 4; | ||
static const bd_size_t test_buf_size = 64; | ||
static const uint8_t blank = 0xFF; | ||
|
||
// Simple test for all APIs | ||
void functionality_test() | ||
{ | ||
HeapBlockDevice heap_bd(num_blocks * erase_size, read_size, prog_size, erase_size); | ||
FlashSimBlockDevice bd(&heap_bd, blank); | ||
|
||
int err = bd.init(); | ||
TEST_ASSERT_EQUAL(0, err); | ||
|
||
uint8_t read_buf[test_buf_size], write_buf[test_buf_size]; | ||
|
||
TEST_ASSERT_EQUAL(num_blocks * erase_size, bd.size()); | ||
TEST_ASSERT_EQUAL(read_size, bd.get_read_size()); | ||
TEST_ASSERT_EQUAL(prog_size, bd.get_program_size()); | ||
TEST_ASSERT_EQUAL(erase_size, bd.get_erase_size()); | ||
TEST_ASSERT_EQUAL(blank, bd.get_erase_value()); | ||
|
||
srand(1); | ||
for (bd_size_t i = 0; i < test_buf_size; i++) { | ||
write_buf[i] = 0xff & rand(); | ||
} | ||
|
||
// Make sure we can't program if not erased (even after init) | ||
err = bd.program(write_buf, 0, test_buf_size); | ||
TEST_ASSERT_EQUAL(BD_ERROR_NOT_ERASED, err); | ||
|
||
err = bd.erase(0, erase_size * 2); | ||
TEST_ASSERT_EQUAL(0, err); | ||
|
||
err = bd.program(write_buf, 0, test_buf_size); | ||
TEST_ASSERT_EQUAL(0, err); | ||
|
||
// Allow programming same data | ||
err = bd.program(write_buf, 0, test_buf_size); | ||
TEST_ASSERT_EQUAL(0, err); | ||
|
||
srand(2); | ||
for (bd_size_t i = 0; i < test_buf_size; i++) { | ||
write_buf[i] = 0xff & rand(); | ||
} | ||
|
||
err = bd.program(write_buf, 0, test_buf_size); | ||
TEST_ASSERT_EQUAL(BD_ERROR_NOT_ERASED, err); | ||
|
||
err = bd.program(write_buf, 2 * erase_size - test_buf_size, test_buf_size); | ||
TEST_ASSERT_EQUAL(0, err); | ||
|
||
memset(write_buf, blank, test_buf_size / 2); | ||
err = bd.read(read_buf, test_buf_size * 2, test_buf_size / 2); | ||
TEST_ASSERT_EQUAL(0, err); | ||
TEST_ASSERT_EQUAL_UINT8_ARRAY(write_buf, read_buf, test_buf_size / 2); | ||
|
||
srand(1); | ||
for (bd_size_t i = 0; i < test_buf_size; i++) { | ||
write_buf[i] = 0xff & rand(); | ||
} | ||
|
||
err = bd.read(read_buf, 0, test_buf_size); | ||
TEST_ASSERT_EQUAL(0, err); | ||
TEST_ASSERT_EQUAL_UINT8_ARRAY(write_buf, read_buf, test_buf_size); | ||
|
||
srand(2); | ||
for (bd_size_t i = 0; i < test_buf_size; i++) { | ||
write_buf[i] = 0xff & rand(); | ||
} | ||
|
||
err = bd.read(read_buf, 2 * erase_size - test_buf_size, test_buf_size); | ||
TEST_ASSERT_EQUAL(0, err); | ||
TEST_ASSERT_EQUAL_UINT8_ARRAY(write_buf, read_buf, test_buf_size); | ||
|
||
err = bd.deinit(); | ||
TEST_ASSERT_EQUAL(0, err); | ||
|
||
err = bd.init(); | ||
TEST_ASSERT_EQUAL(0, err); | ||
|
||
// Make sure data lives across inits | ||
err = bd.read(read_buf, 2 * erase_size - test_buf_size, test_buf_size); | ||
TEST_ASSERT_EQUAL(0, err); | ||
TEST_ASSERT_EQUAL_UINT8_ARRAY(write_buf, read_buf, test_buf_size); | ||
|
||
err = bd.erase(0, erase_size); | ||
TEST_ASSERT_EQUAL(0, err); | ||
|
||
// Make sure erase returns the erase value | ||
memset(write_buf, blank, test_buf_size); | ||
err = bd.read(read_buf, 0, test_buf_size); | ||
TEST_ASSERT_EQUAL(0, err); | ||
TEST_ASSERT_EQUAL_UINT8_ARRAY(write_buf, read_buf, test_buf_size); | ||
} | ||
|
||
|
||
// Test setup | ||
utest::v1::status_t test_setup(const size_t number_of_cases) | ||
{ | ||
GREENTEA_SETUP(30, "default_auto"); | ||
return verbose_test_setup_handler(number_of_cases); | ||
} | ||
|
||
Case cases[] = { | ||
Case("FlashSimBlockDevice functionality test", functionality_test), | ||
}; | ||
|
||
Specification specification(test_setup, cases); | ||
|
||
int main() | ||
{ | ||
return !Harness::run(specification); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
/* mbed Microcontroller Library | ||
* Copyright (c) 2018 ARM Limited | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
#include "FlashSimBlockDevice.h" | ||
#include "mbed_assert.h" | ||
#include <algorithm> | ||
#include <stdlib.h> | ||
#include <string.h> | ||
|
||
static const bd_size_t min_blank_buf_size = 32; | ||
|
||
static inline uint32_t align_up(bd_size_t val, bd_size_t size) | ||
{ | ||
return (((val - 1) / size) + 1) * size; | ||
} | ||
|
||
FlashSimBlockDevice::FlashSimBlockDevice(BlockDevice *bd, uint8_t erase_value) : | ||
_erase_value(erase_value), _blank_buf_size(0), | ||
_blank_buf(0), _bd(bd) | ||
{ | ||
} | ||
|
||
FlashSimBlockDevice::~FlashSimBlockDevice() | ||
{ | ||
deinit(); | ||
delete[] _blank_buf; | ||
} | ||
|
||
int FlashSimBlockDevice::init() | ||
{ | ||
int ret = _bd->init(); | ||
if (ret) { | ||
return ret; | ||
} | ||
_blank_buf_size = align_up(min_blank_buf_size, _bd->get_program_size()); | ||
if (!_blank_buf) { | ||
_blank_buf = new uint8_t[_blank_buf_size]; | ||
MBED_ASSERT(_blank_buf); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Non blocking and can be fixed in future - New will assert if memory allocation fails, additional check is not needed. Do you intent to use malloc instead here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks, will remove the redundant check. And no - will keep using new[]. |
||
} | ||
return BD_ERROR_OK; | ||
} | ||
|
||
int FlashSimBlockDevice::deinit() | ||
{ | ||
return _bd->deinit(); | ||
} | ||
|
||
int FlashSimBlockDevice::sync() | ||
{ | ||
return _bd->sync(); | ||
} | ||
|
||
bd_size_t FlashSimBlockDevice::get_read_size() const | ||
{ | ||
return _bd->get_read_size(); | ||
} | ||
|
||
bd_size_t FlashSimBlockDevice::get_program_size() const | ||
{ | ||
return _bd->get_program_size(); | ||
} | ||
|
||
bd_size_t FlashSimBlockDevice::get_erase_size() const | ||
{ | ||
return _bd->get_erase_size(); | ||
} | ||
|
||
bd_size_t FlashSimBlockDevice::get_erase_size(bd_addr_t addr) const | ||
{ | ||
return _bd->get_erase_size(addr); | ||
} | ||
|
||
bd_size_t FlashSimBlockDevice::size() const | ||
{ | ||
return _bd->size(); | ||
} | ||
|
||
int FlashSimBlockDevice::read(void *b, bd_addr_t addr, bd_size_t size) | ||
{ | ||
return _bd->read(b, addr, size); | ||
} | ||
|
||
int FlashSimBlockDevice::program(const void *b, bd_addr_t addr, bd_size_t size) | ||
{ | ||
MBED_ASSERT(is_valid_program(addr, size)); | ||
bd_addr_t curr_addr = addr; | ||
bd_size_t curr_size = size; | ||
|
||
const uint8_t *buf = (const uint8_t *) b; | ||
while (curr_size) { | ||
bd_size_t read_size = std::min(_blank_buf_size, curr_size); | ||
int ret = _bd->read(_blank_buf, curr_addr, read_size); | ||
if (ret) { | ||
return ret; | ||
} | ||
for (bd_size_t i = 0; i < read_size; i++) { | ||
// Allow either programming on blanks or programming the same value | ||
// (as real flash devices do) | ||
if ((_blank_buf[i] != _erase_value) && (_blank_buf[i] != *buf)) { | ||
return BD_ERROR_NOT_ERASED; | ||
} | ||
buf++; | ||
} | ||
curr_addr += read_size; | ||
curr_size -= read_size; | ||
} | ||
|
||
return _bd->program(b, addr, size); | ||
} | ||
|
||
int FlashSimBlockDevice::erase(bd_addr_t addr, bd_size_t size) | ||
{ | ||
MBED_ASSERT(is_valid_erase(addr, size)); | ||
|
||
bd_addr_t curr_addr = addr; | ||
bd_size_t curr_size = size; | ||
|
||
memset(_blank_buf, _erase_value, (unsigned int) _blank_buf_size); | ||
|
||
while (curr_size) { | ||
bd_size_t prog_size = std::min(_blank_buf_size, curr_size); | ||
int ret = _bd->program(_blank_buf, curr_addr, prog_size); | ||
if (ret) { | ||
return ret; | ||
} | ||
curr_addr += prog_size; | ||
curr_size -= prog_size; | ||
} | ||
|
||
return BD_ERROR_OK; | ||
} | ||
|
||
int FlashSimBlockDevice::get_erase_value() const | ||
{ | ||
return _erase_value; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think there is value in making any of these values configurable? If the intention is to test the upper level code using the simulated layer wouldn't making this more configurable makes senses? Otherwise, everything looks ok to me.