This repository has been archived by the owner on Jan 7, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 39
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a block device interface and several drivers
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
Showing
21 changed files
with
1,635 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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')) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
[build] | ||
device = hosted | ||
buildpath = ${xpccpath}/build/linux/${name} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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')) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
[build] | ||
device = hosted | ||
buildpath = ${xpccpath}/build/linux/${name} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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')) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
[build] | ||
device = hosted | ||
buildpath = ${xpccpath}/build/linux/block_device/${name} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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')) |
Oops, something went wrong.