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

[driver] Block device #328

Merged
merged 9 commits into from
Jan 14, 2018
Merged

Conversation

rleh
Copy link
Member

@rleh rleh commented Jan 12, 2018

This PR adds a block device interface to xpcc, inspired by mbeds block device interface.

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.

Copy link
Member

@salkinium salkinium left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice interface and implementation. The drivers need to inherit the interface though for doxygen to understand this relationship.

}

struct FilenameA {
static constexpr const char* name = "testA.bin";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean to commit the examples/linux/block_device/mirror/testA.bin and testB.bin files below?

Copy link
Member Author

@rleh rleh Jan 12, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, because otherwise the test*.bin files have to be created manually by the user (or CI) before running the example.
The is no nice way to create the files from C++.

Idea: Create the file in the SConstruct:

# 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'))

(Filename changed to test.bin~ so that it is ignored by gitignore.)

(Edit: filename test.bin~)

* @author Raphael Lehmann
* @ingroup storage
*/
#ifdef __DOXYGEN__
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be inside the class? And the drivers then inherit from this class.

* @return True on success
*/
xpcc::ResumableResult<bool>
read(uint8_t *buffer, uint32_t address, size_t size);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add a using address_t = uint32_t; to use here and then specialize this for implementations.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

/**
* \brief Block device using heap (RAM)
*
* Usually not persistant, but at least useful for testing
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is useful for battery backed SRAM, some stm32 have up to 4kB of this stuff. Very nice!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For this use-case BdHeap is now extended to optionally use externally supplied memory instead of allocation memory. See here.

#ifndef XPCC_BLOCK_DEVICE_FILE_HPP
#define XPCC_BLOCK_DEVICE_FILE_HPP

#include <xpcc/processing/resumable.hpp>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This and all other drivers should include <xpcc/architecture/interface/block_device.hpp> and inherit from it.

#ifndef XPCC_BLOCK_DEVICE_SPIFLASH_HPP
#error "Don't include this file directly, use 'block_device_spiflash.hpp' instead!"
#endif
#include "block_device_spiflash.hpp"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nope.

#ifndef XPCC_BLOCK_DEVICE_MIRROR_HPP
#error "Don't include this file directly, use 'block_device_mirror.hpp' instead!"
#endif
#include "block_device_mirror.hpp"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nope.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why? This includes don't hurt and make QtCreators syntax highlighting and auto-completion work.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, ok, that's a good enough reason.

#ifndef XPCC_BLOCK_DEVICE_FILE_HPP
#error "Don't include this file directly, use 'block_device_file.hpp' instead!"
#endif
#include "block_device_file.hpp"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nope.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See below.


/** Writes data to one or more blocks after erasing them
*
* The blocks are erased proir to being programmed
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pior


/** Writes data to one or more blocks after erasing them
*
* The blocks are erased proir to being programmed
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

prior

@salkinium
Copy link
Member

Oh, and Travis is broken, just ignore it.

@rleh rleh force-pushed the feature/block_device branch 2 times, most recently from fa13256 to 106f443 Compare January 12, 2018 19:48
salkinium
salkinium previously approved these changes Jan 12, 2018
Copy link
Member

@salkinium salkinium left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

* \ingroup driver_storage
* \author Raphael Lehmann
*/
template <typename Spi, typename Cs, size_t flashSize>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On AVR size_t is a 16 bit unsigned int. This wouldn't allow you to use a flash larger than 65535 bytes. You could take a plain uint32_t or something like using flash_size_t = ... and define it to uint32_t on microcontrollers and size_t on hosted to also support 4GB+ files. The same applies for the size_t function parameters.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This wouldn't allow you to use a flash larger than 65535 bytes.

No. You are just unable to write, read or delete >64k memory at once. address is a uint32_t, so you can write/read to/from a <=4GBit flash chip in <=64kBit blocks.

For write and read operations you would need a >64k buffer in your AVRs RAM, but erasing a complete 64MBit flash chip at once on AVR is more realistic. Hmmm...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I missed that this size_t is the template parameter and not an read/write/erase function argument.

I'll change the flashSize type to uint32_t here.

#undef XPCC_LOG_LEVEL
#define XPCC_LOG_LEVEL xpcc::log::INFO

void printMemoryContent(uint8_t* address, std::size_t size) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const uint8_t*

#undef XPCC_LOG_LEVEL
#define XPCC_LOG_LEVEL xpcc::log::INFO

void printMemoryContent(uint8_t* address, std::size_t size) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const uint8_t*

* Most persistent storage devices require `program()`, `erase()`
* and sometimes `read()` operations to be executed on fixed sized blocks.
*/
static constexpr std::size_t BlockSizeRead = 1;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason for mixing std::size_t and plain size_t? It is guaranteed to be the same type anyway (since C++11).

Copy link
Member Author

@rleh rleh Jan 12, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. I'll change all size_t to std::size_t.

(std::size_t has 385 vs size_t has only 184 occurrences in xpcc.)

*
* @return BlockDeviceA
*/
inline BlockDeviceA getBlockDeviceA() {return blockDeviceA;};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Returning a copy is probably not what you intended. I suppose you meant BlockDeviceA&. Probably being able to copy an spi flash driver object is a bad idea. Maybe deleting the copy constructor and copy assignment operator would prevent bugs like that.

*
* @return BlockDeviceB
*/
inline BlockDeviceB getBlockDeviceB() {return blockDeviceB;};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BlockDeviceB&

@salkinium salkinium merged commit e1e8af3 into roboterclubaachen:develop Jan 14, 2018
@rleh rleh deleted the feature/block_device branch January 14, 2018 17:36
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants