Skip to content

Fix the general block device for better support of low memory boards #9362

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

Merged
merged 1 commit into from
Jan 14, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 58 additions & 45 deletions features/storage/TESTS/blockdevice/general_block_device/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ void basic_erase_program_read_test(BlockDevice *block_device, bd_size_t block_si
write_block[i_ind] = 0xff & rand();
}
// Write, sync, and read the block
utest_printf("\ntest %0*llx:%llu...", addrwidth, block, block_size);
utest_printf("test %0*llx:%llu...\n", addrwidth, block, block_size);
_mutex->unlock();

err = block_device->erase(block, block_size);
Expand Down Expand Up @@ -100,7 +100,7 @@ void test_random_program_read_erase()

BlockDevice *block_device = BlockDevice::get_default_instance();

TEST_SKIP_UNLESS_MESSAGE(block_device != NULL, "\nno block device found.\n");
TEST_SKIP_UNLESS_MESSAGE(block_device != NULL, "no block device found.");

int err = block_device->init();
TEST_ASSERT_EQUAL(0, err);
Expand All @@ -123,7 +123,7 @@ void test_random_program_read_erase()
uint8_t *write_block = new (std::nothrow) uint8_t[block_size];
uint8_t *read_block = new (std::nothrow) uint8_t[block_size];
if (!write_block || !read_block) {
utest_printf("\n Not enough memory for test");
utest_printf("Not enough memory for test\n");
goto end;
}

Expand Down Expand Up @@ -152,7 +152,7 @@ static void test_thread_job(void *block_device_ptr)
uint8_t *read_block = new (std::nothrow) uint8_t[block_size];

if (!write_block || !read_block) {
utest_printf("\n Not enough memory for test");
utest_printf("Not enough memory for test\n");
goto end;
}

Expand All @@ -173,6 +173,10 @@ void test_multi_threads()

TEST_SKIP_UNLESS_MESSAGE(block_device != NULL, "\nno block device found.\n");

char *dummy = new (std::nothrow) char[TEST_NUM_OF_THREADS * OS_STACK_SIZE];
TEST_SKIP_UNLESS_MESSAGE(dummy, "Not enough memory for test.\n");
delete[] dummy;

int err = block_device->init();
TEST_ASSERT_EQUAL(0, err);

Expand All @@ -196,7 +200,7 @@ void test_multi_threads()
for (i_ind = 0; i_ind < TEST_NUM_OF_THREADS; i_ind++) {
threadStatus = bd_thread[i_ind].start(callback(test_thread_job, (void *)block_device));
if (threadStatus != 0) {
utest_printf("\n Thread %d Start Failed!", i_ind + 1);
utest_printf("Thread %d Start Failed!\n", i_ind + 1);
}
}

Expand All @@ -219,15 +223,15 @@ void test_get_erase_value()
// 3. Read erased region and compare with get_erase_value()

BlockDevice *block_device = BlockDevice::get_default_instance();
TEST_SKIP_UNLESS_MESSAGE(block_device != NULL, "\nno block device found.\n");
TEST_SKIP_UNLESS_MESSAGE(block_device != NULL, "no block device found.");

int err = block_device->init();
TEST_ASSERT_EQUAL(0, err);

// Check erase value
int erase_value_int = block_device->get_erase_value();
utest_printf("\nblock_device->get_erase_value()=%d", erase_value_int);
TEST_SKIP_UNLESS_MESSAGE(erase_value_int >= 0, "\nerase value is negative which means the erase value is unknown\n");
utest_printf("block_device->get_erase_value()=%d\n", erase_value_int);
TEST_SKIP_UNLESS_MESSAGE(erase_value_int >= 0, "Erase not supported in this block device. Test skipped.");

// Assuming that get_erase_value() returns byte value as documentation mentions
// "If get_erase_value() returns a non-negative byte value" for unknown case.
Expand All @@ -245,33 +249,33 @@ void test_get_erase_value()
start_address %= block_device->size() - data_buf_size - erase_size; // fit all data + alignment reserve
start_address += erase_size; // add alignment reserve
start_address -= start_address % erase_size; // align with erase_block
utest_printf("\nstart_address=0x%016" PRIx64, start_address);
utest_printf("start_address=0x%016" PRIx64 "\n", start_address);

// Allocate buffer for read test data
uint8_t *data_buf = (uint8_t *)malloc(data_buf_size);
TEST_ASSERT_NOT_NULL(data_buf);
TEST_SKIP_UNLESS_MESSAGE(data_buf, "Not enough memory for test.\n");

// Write random data to selected region to make sure data is not accidentally set to "erased" value.
// With this pre-write, the test case will fail even if block_device->erase() is broken.
for (bd_size_t i = 0; i < data_buf_size; i++) {
data_buf[i] = (uint8_t) rand();
}
utest_printf("\nwriting given memory region");
utest_printf("writing given memory region\n");
err = block_device->program((const void *)data_buf, start_address, data_buf_size);
TEST_ASSERT_EQUAL(0, err);

// Erase given memory region
utest_printf("\nerasing given memory region");
utest_printf("erasing given memory region\n");
err = block_device->erase(start_address, data_buf_size);
TEST_ASSERT_EQUAL(0, err);

// Read erased memory region
utest_printf("\nreading erased memory region");
utest_printf("reading erased memory region\n");
err = block_device->read((void *)data_buf, start_address, data_buf_size);
TEST_ASSERT_EQUAL(0, err);

// Verify erased memory region
utest_printf("\nverifying erased memory region");
utest_printf("verifying erased memory region\n");
for (bd_size_t i = 0; i < data_buf_size; i++) {
TEST_ASSERT_EQUAL(erase_value, data_buf[i]);
}
Expand All @@ -295,7 +299,7 @@ void test_contiguous_erase_write_read()
// 3. Return step 2 for whole erase region

BlockDevice *block_device = BlockDevice::get_default_instance();
TEST_SKIP_UNLESS_MESSAGE(block_device != NULL, "\nno block device found.\n");
TEST_SKIP_UNLESS_MESSAGE(block_device != NULL, "no block device found.");

// Initialize BlockDevice
int err = block_device->init();
Expand All @@ -306,9 +310,9 @@ void test_contiguous_erase_write_read()
TEST_ASSERT(erase_size > 0);
bd_size_t program_size = block_device->get_program_size();
TEST_ASSERT(program_size > 0);
utest_printf("\nerase_size=%d", erase_size);
utest_printf("\nprogram_size=%d", program_size);
utest_printf("\nblock_device->size()=%" PRId64, block_device->size());
utest_printf("erase_size=%" PRId64 "\n", erase_size);
utest_printf("program_size=%" PRId64 "\n", program_size);
utest_printf("block_device->size()=%" PRId64 "\n", block_device->size());

// Determine write/read buffer size
// start write_read_buf_size from 1% block_device->size()
Expand All @@ -324,18 +328,18 @@ void test_contiguous_erase_write_read()
bd_size_t contiguous_write_read_blocks_per_region = write_read_buf_size /
program_size; // 2 is minimum to test contiguous write
write_read_buf_size = contiguous_write_read_blocks_per_region * program_size;
utest_printf("\ncontiguous_write_read_blocks_per_region=%" PRIu64, contiguous_write_read_blocks_per_region);
utest_printf("\nwrite_read_buf_size=%" PRIu64, write_read_buf_size);
utest_printf("contiguous_write_read_blocks_per_region=%" PRIu64 "\n", contiguous_write_read_blocks_per_region);
utest_printf("write_read_buf_size=%" PRIu64 "\n", write_read_buf_size);

// Determine test region count
int contiguous_write_read_regions = TEST_BLOCK_COUNT;
utest_printf("\ncontiguous_write_read_regions=%d", contiguous_write_read_regions);
utest_printf("contiguous_write_read_regions=%d\n", contiguous_write_read_regions);

// Determine whole erase size
bd_size_t contiguous_erase_size = write_read_buf_size * contiguous_write_read_regions;
contiguous_erase_size -= contiguous_erase_size % erase_size; // aligned to erase_size
contiguous_erase_size += erase_size; // but larger than write/read size * regions
utest_printf("\ncontiguous_erase_size=%" PRIu64, contiguous_erase_size);
utest_printf("contiguous_erase_size=%" PRIu64 "\n", contiguous_erase_size);

// Determine starting address
bd_addr_t start_address = rand(); // low 32 bytes
Expand All @@ -344,70 +348,70 @@ void test_contiguous_erase_write_read()
start_address += erase_size; // add alignment reserve
start_address -= start_address % erase_size; // align with erase_block
bd_addr_t stop_address = start_address + write_read_buf_size * contiguous_write_read_regions;
utest_printf("\nstart_address=0x%016" PRIx64, start_address);
utest_printf("\nstop_address=0x%016" PRIx64, stop_address);
utest_printf("start_address=0x%016" PRIx64 "\n", start_address);
utest_printf("stop_address=0x%016" PRIx64 "\n", stop_address);

// Allocate write/read buffer
uint8_t *write_read_buf = (uint8_t *)malloc(write_read_buf_size);
if (write_read_buf == NULL) {
block_device->deinit();
TEST_SKIP_MESSAGE("\nnot enough memory for test");
TEST_SKIP_MESSAGE("not enough memory for test");
}
utest_printf("\nwrite_read_buf_size=%" PRIu64 "", (uint64_t)write_read_buf_size);
utest_printf("write_read_buf_size=%" PRIu64 "\n", (uint64_t)write_read_buf_size);

// Pre-fill the to-be-erased region. By pre-filling the region,
// we can be sure the test will not pass if the erase doesn't work.
for (bd_size_t offset = 0; start_address + offset < stop_address; offset += write_read_buf_size) {
for (size_t i = 0; i < write_read_buf_size; i++) {
write_read_buf[i] = (uint8_t)rand();
}
utest_printf("\npre-filling memory, from 0x%" PRIx64 " of size 0x%" PRIx64, start_address + offset,
utest_printf("pre-filling memory, from 0x%" PRIx64 " of size 0x%" PRIx64 "\n", start_address + offset,
write_read_buf_size);
err = block_device->program((const void *)write_read_buf, start_address + offset, write_read_buf_size);
TEST_ASSERT_EQUAL(0, err);
}

// Erase the whole region first
utest_printf("\nerasing memory, from 0x%" PRIx64 " of size 0x%" PRIx64, start_address, contiguous_erase_size);
utest_printf("erasing memory, from 0x%" PRIx64 " of size 0x%" PRIx64 "\n", start_address, contiguous_erase_size);
err = block_device->erase(start_address, contiguous_erase_size);
TEST_ASSERT_EQUAL(0, err);

// Loop through all write/read regions
int region = 0;
for (; start_address < stop_address; start_address += write_read_buf_size) {
utest_printf("\n\nregion #%d start_address=0x%016" PRIx64, region++, start_address);
utest_printf("\nregion #%d start_address=0x%016" PRIx64 "\n", region++, start_address);

// Generate test data
unsigned int seed = rand();
utest_printf("\ngenerating test data, seed=%u", seed);
utest_printf("generating test data, seed=%u\n", seed);
srand(seed);
for (size_t i = 0; i < write_read_buf_size; i++) {
write_read_buf[i] = (uint8_t)rand();
}

// Write test data
utest_printf("\nwriting test data");
utest_printf("writing test data\n");
err = block_device->program((const void *)write_read_buf, start_address, write_read_buf_size);
TEST_ASSERT_EQUAL(0, err);

// Read test data
memset(write_read_buf, 0, (size_t)write_read_buf_size);
utest_printf("\nreading test data");
utest_printf("reading test data\n");
err = block_device->read(write_read_buf, start_address, write_read_buf_size);
TEST_ASSERT_EQUAL(0, err);

// Verify read data
utest_printf("\nverifying test data");
utest_printf("verifying test data\n");
srand(seed);
for (size_t i = 0; i < write_read_buf_size; i++) {
uint8_t expected_value = (uint8_t)rand();
if (write_read_buf[i] != expected_value) {
utest_printf("\ndata verify failed, write_read_buf[%d]=%" PRIu8 " and not %" PRIu8 "\n",
utest_printf("data verify failed, write_read_buf[%d]=%" PRIu8 " and not %" PRIu8 "\n",
i, write_read_buf[i], expected_value);
}
TEST_ASSERT_EQUAL(write_read_buf[i], expected_value);
}
utest_printf("\nverify OK");
utest_printf("verify OK\n");
}

free(write_read_buf);
Expand All @@ -423,22 +427,34 @@ void test_program_read_small_data_sizes()

BlockDevice *bd = BlockDevice::get_default_instance();

TEST_SKIP_UNLESS_MESSAGE(bd != NULL, "\nno block device found.\n");
TEST_SKIP_UNLESS_MESSAGE(bd != NULL, "no block device found.");

int err = bd->init();
TEST_ASSERT_EQUAL(0, err);

bd_size_t erase_size = bd->get_erase_size();
bd_size_t program_size = bd->get_program_size();
bd_size_t read_size = bd->get_read_size();
TEST_ASSERT(program_size > 0);

err = bd->deinit();
TEST_ASSERT_EQUAL(0, err);

// See that we have enough memory for buffered block device
char *dummy = new (std::nothrow) char[program_size + read_size];
TEST_SKIP_UNLESS_MESSAGE(dummy, "Not enough memory for test.\n");
delete[] dummy;

// use BufferedBlockDevice for better handling of block devices program and read
BufferedBlockDevice *block_device = new BufferedBlockDevice(bd);

// BlockDevice initialization
int err = block_device->init();
err = block_device->init();
TEST_ASSERT_EQUAL(0, err);

const char write_buffer[] = "1234567";
char read_buffer[7] = {};

bd_size_t erase_size = block_device->get_erase_size();
bd_size_t program_size = block_device->get_program_size();
TEST_ASSERT(program_size > 0);

// Determine starting address
bd_addr_t start_address = 0;

Expand Down Expand Up @@ -469,10 +485,7 @@ void test_program_read_small_data_sizes()
void test_get_type_functionality()
{
BlockDevice *block_device = BlockDevice::get_default_instance();
if (block_device == NULL) {
TEST_SKIP_MESSAGE("No block device component is defined for this target");
return;
}
TEST_SKIP_UNLESS_MESSAGE(block_device, "No block device component is defined for this target");
const char *bd_type = block_device->get_type();
TEST_ASSERT_NOT_EQUAL(0, bd_type);

Expand Down