Skip to content
This repository has been archived by the owner on Jan 7, 2019. It is now read-only.

Commit

Permalink
Add a block device interface and several drivers
Browse files Browse the repository at this point in the history
Drivers to store data in a SPI SST flash `xpcc::BdSpiFlash`, to store data in a
file (on hosted) `xpcc::BdFile` and to store data in RAM (for testing purposes)
`xpcc::BdHeap` are included.
Additionally, `xpcc::BdMirror` is a virtual block device that behaves like
RAID1 devices.

For every driver a test is included.

The flash chip driver has been tested on a Nucleo-F429ZI board.
  • Loading branch information
salkinium committed Jan 14, 2018
2 parents 9b44afb + e1e8af3 commit a945513
Show file tree
Hide file tree
Showing 21 changed files with 1,635 additions and 0 deletions.
8 changes: 8 additions & 0 deletions examples/linux/block_device/file/SConstruct
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# path to the xpcc root directory
xpccpath = '../../../..'

# create empty `test.bin~` file (if it does not exist)
open('test.bin~', 'a').close()

# execute the common SConstruct file
exec(compile(open(xpccpath + '/scons/SConstruct', "rb").read(), xpccpath + '/scons/SConstruct', 'exec'))
85 changes: 85 additions & 0 deletions examples/linux/block_device/file/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#include <xpcc/architecture.hpp>
#include <xpcc/debug/logger.hpp>

#include <xpcc/driver/storage/block_device_file.hpp>

// Set the log level
#undef XPCC_LOG_LEVEL
#define XPCC_LOG_LEVEL xpcc::log::INFO

void printMemoryContent(const uint8_t* address, std::size_t size) {
for (std::size_t i = 0; i < size; i++) {
XPCC_LOG_INFO.printf("%x", address[i]);
}
}

// `test.bin~` file is created from `SConstruct`
struct Filename {
static constexpr const char* name = "test.bin~";
};

int
main()
{
/**
* This example/test writes alternating patterns into
* a `xpcc::BdFile` block device with a size of 1M.
* The memory content is afterwards read and compared
* to the pattern.
* Write and read operations are done on 64 byte blocks.
*/

constexpr uint32_t BlockSize = 64;
constexpr uint32_t MemorySize = 1024*1024;

uint8_t bufferA[BlockSize];
uint8_t bufferB[BlockSize];
uint8_t bufferC[BlockSize];
std::memset(bufferA, 0xAA, BlockSize);
std::memset(bufferB, 0x55, BlockSize);

xpcc::BdFile<Filename, MemorySize> storageDevice;

if(!RF_CALL_BLOCKING(storageDevice.initialize())) {
XPCC_LOG_INFO << "Error: Unable to initialize device.";
exit(1);
}

if(!RF_CALL_BLOCKING(storageDevice.erase(0, MemorySize))) {
XPCC_LOG_INFO << "Error: Unable to erase device.";
exit(1);
}

XPCC_LOG_INFO << "Starting memory test!" << xpcc::endl;

for(uint16_t iteration = 0; iteration < 10; iteration++) {
uint8_t* pattern = (iteration % 2 == 0) ? bufferA : bufferB;

for(uint32_t i = 0; i < MemorySize; i += BlockSize) {
if(!RF_CALL_BLOCKING(storageDevice.write(pattern, i, BlockSize))) {
XPCC_LOG_INFO << "Error: Unable to write data.";
exit(1);
}
}

for(uint32_t i = 0; i < MemorySize; i += BlockSize) {
if(!RF_CALL_BLOCKING(storageDevice.read(bufferC, i, BlockSize))) {
XPCC_LOG_INFO << "Error: Unable to read data.";
exit(1);
}
else if(std::memcmp(pattern, bufferC, BlockSize)) {
XPCC_LOG_INFO << "Error: Read '";
printMemoryContent(bufferC, BlockSize);
XPCC_LOG_INFO << "', expected: '";
printMemoryContent(pattern, BlockSize);
XPCC_LOG_INFO << "'." << xpcc::endl;
exit(1);
}
}
XPCC_LOG_INFO << ".";
}

XPCC_LOG_INFO << xpcc::endl << "Finished!" << xpcc::endl;

return 0;
}
3 changes: 3 additions & 0 deletions examples/linux/block_device/file/project.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[build]
device = hosted
buildpath = ${xpccpath}/build/linux/${name}
9 changes: 9 additions & 0 deletions examples/linux/block_device/mirror/SConstruct
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# path to the xpcc root directory
xpccpath = '../../../..'

# create empty `testA.bin~` and `testA.bin~` files (if they do not exist)
open('testA.bin~', 'a').close()
open('testB.bin~', 'a').close()

# execute the common SConstruct file
exec(compile(open(xpccpath + '/scons/SConstruct', "rb").read(), xpccpath + '/scons/SConstruct', 'exec'))
90 changes: 90 additions & 0 deletions examples/linux/block_device/mirror/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
#include <xpcc/architecture.hpp>
#include <xpcc/debug/logger.hpp>

#include <xpcc/driver/storage/block_device_file.hpp>
#include <xpcc/driver/storage/block_device_mirror.hpp>

// Set the log level
#undef XPCC_LOG_LEVEL
#define XPCC_LOG_LEVEL xpcc::log::INFO

void printMemoryContent(const uint8_t* address, std::size_t size) {
for (std::size_t i = 0; i < size; i++) {
XPCC_LOG_INFO.printf("%x", address[i]);
}
}
// `testA.bin~` and `testB.bin~` files are created from `SConstruct`
struct FilenameA {
static constexpr const char* name = "testA.bin~";
};

struct FilenameB {
static constexpr const char* name = "testB.bin~";
};

int
main()
{
/**
* This example/test writes alternating patterns into
* two `xpcc::BdFile` block device with a size of 1M
* to test the virtual `xpcc::BdMirror` block device.
* The memory content is afterwards read and compared
* to the pattern.
* Write and read operations are done on 64 byte blocks.
*/

constexpr uint32_t BlockSize = 256;
constexpr uint32_t MemorySize = 16*1024*1024;

uint8_t bufferA[BlockSize];
uint8_t bufferB[BlockSize];
uint8_t bufferC[BlockSize];
std::memset(bufferA, 0xAA, BlockSize);
std::memset(bufferB, 0x55, BlockSize);

xpcc::BdMirror<xpcc::BdFile<FilenameA, MemorySize>, xpcc::BdFile<FilenameB, MemorySize>> storageDevice;

if(!RF_CALL_BLOCKING(storageDevice.initialize())) {
XPCC_LOG_INFO << "Error: Unable to initialize device.";
exit(1);
}

XPCC_LOG_INFO << "Starting memory test!" << xpcc::endl;

for(uint16_t iteration = 0; iteration < 10; iteration++) {
uint8_t* pattern = (iteration % 2 == 0) ? bufferA : bufferB;

if(!RF_CALL_BLOCKING(storageDevice.erase(0, MemorySize))) {
XPCC_LOG_INFO << "Error: Unable to erase device.";
exit(1);
}

for(uint32_t i = 0; i < MemorySize; i += BlockSize) {
if(!RF_CALL_BLOCKING(storageDevice.program(pattern, i, BlockSize))) {
XPCC_LOG_INFO << "Error: Unable to write data.";
exit(1);
}
}

for(uint32_t i = 0; i < MemorySize; i += BlockSize) {
if(!RF_CALL_BLOCKING(storageDevice.read(bufferC, i, BlockSize))) {
XPCC_LOG_INFO << "Error: Unable to read data.";
exit(1);
}
else if(std::memcmp(pattern, bufferC, BlockSize)) {
XPCC_LOG_INFO << "Error: Read '";
printMemoryContent(bufferC, BlockSize);
XPCC_LOG_INFO << "', expected: '";
printMemoryContent(pattern, BlockSize);
XPCC_LOG_INFO << "'." << xpcc::endl;
break;
}
}
XPCC_LOG_INFO << ".";
}

XPCC_LOG_INFO << xpcc::endl << "Finished!" << xpcc::endl;

return 0;
}
3 changes: 3 additions & 0 deletions examples/linux/block_device/mirror/project.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[build]
device = hosted
buildpath = ${xpccpath}/build/linux/${name}
4 changes: 4 additions & 0 deletions examples/linux/block_device/ram/SConstruct
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# path to the xpcc root directory
xpccpath = '../../../..'
# execute the common SConstruct file
exec(compile(open(xpccpath + '/scons/SConstruct', "rb").read(), xpccpath + '/scons/SConstruct', 'exec'))
75 changes: 75 additions & 0 deletions examples/linux/block_device/ram/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#include <xpcc/architecture.hpp>
#include <xpcc/debug/logger.hpp>

#include <xpcc/driver/storage/block_device_heap.hpp>

// Set the log level
#undef XPCC_LOG_LEVEL
#define XPCC_LOG_LEVEL xpcc::log::INFO

void printMemoryContent(const uint8_t* address, std::size_t size) {
for (std::size_t i = 0; i < size; i++) {
XPCC_LOG_INFO.printf("%x", address[i]);
}
}

int
main()
{
/**
* This example/test writes alternating patterns into
* a `xpcc::BdHeap` block device with a size of 1M.
* The memory content is afterwards read and compared
* to the pattern.
* Write and read operations are done on 64 byte blocks.
*/

constexpr uint32_t BlockSize = 64;
constexpr uint32_t MemorySize = 1024*1024;

uint8_t bufferA[BlockSize];
uint8_t bufferB[BlockSize];
uint8_t bufferC[BlockSize];
std::memset(bufferA, 0xAA, BlockSize);
std::memset(bufferB, 0x55, BlockSize);

xpcc::BdHeap<MemorySize> storageDevice;
if(!RF_CALL_BLOCKING(storageDevice.initialize())) {
XPCC_LOG_INFO << "Error: Unable to initialize device.";
exit(1);
}
RF_CALL_BLOCKING(storageDevice.erase(0, MemorySize));

XPCC_LOG_INFO << "Starting memory test!" << xpcc::endl;

for(uint16_t iteration = 0; iteration < 1000; iteration++) {
uint8_t* pattern = (iteration % 2 == 0) ? bufferA : bufferB;

for(uint32_t i = 0; i < MemorySize; i += BlockSize) {
if(!RF_CALL_BLOCKING(storageDevice.write(pattern, i, BlockSize))) {
XPCC_LOG_INFO << "Error: Unable to write data.";
exit(1);
}
}

for(uint32_t i = 0; i < MemorySize; i += BlockSize) {
if(!RF_CALL_BLOCKING(storageDevice.read(bufferC, i, BlockSize))) {
XPCC_LOG_INFO << "Error: Unable to read data.";
exit(1);
}
else if(std::memcmp(pattern, bufferC, BlockSize)) {
XPCC_LOG_INFO << "Error: Read '";
printMemoryContent(bufferC, BlockSize);
XPCC_LOG_INFO << "', expected: '";
printMemoryContent(pattern, BlockSize);
XPCC_LOG_INFO << "'." << xpcc::endl;
exit(1);
}
}
XPCC_LOG_INFO << ".";
}

XPCC_LOG_INFO << xpcc::endl << "Finished!" << xpcc::endl;

return 0;
}
3 changes: 3 additions & 0 deletions examples/linux/block_device/ram/project.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[build]
device = hosted
buildpath = ${xpccpath}/build/linux/block_device/${name}
4 changes: 4 additions & 0 deletions examples/nucleo_f429zi/spi_flash/SConstruct
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# path to the xpcc root directory
xpccpath = '../../..'
# execute the common SConstruct file
exec(compile(open(xpccpath + '/scons/SConstruct', "rb").read(), xpccpath + '/scons/SConstruct', 'exec'))
Loading

0 comments on commit a945513

Please sign in to comment.