Skip to content

Commit

Permalink
Add flash emulation layer for native
Browse files Browse the repository at this point in the history
[flashsim] Fix broken unit tests

[flashsim] Add documentation

[flashsim] Properly namespace error enum

[flashsim] Fix header not renamed

[fs] replace custom error codes with errnos
  • Loading branch information
x3ro committed Dec 15, 2015
1 parent 4114382 commit 4ed4677
Show file tree
Hide file tree
Showing 14 changed files with 1,008 additions and 0 deletions.
4 changes: 4 additions & 0 deletions cpu/native/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ ifneq (,$(filter netdev2_tap,$(USEMODULE)))
DIRS += netdev2_tap
endif

ifneq (,$(filter mci,$(USEMODULE)))
DIRS += mci
endif

include $(RIOTBASE)/Makefile.base

INCLUDES = $(NATIVEINCLUDES)
1 change: 1 addition & 0 deletions cpu/native/mci/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include $(RIOTBASE)/Makefile.base
177 changes: 177 additions & 0 deletions cpu/native/mci/native-mci.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
/*
* Copyright (C) Lucas Jenß
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/

/**
* @ingroup native
* @{
*/

/**
* @file
* @brief Emulates the MCI storage driver by providing an in-memory
* backend. It is 8MiB by default and its size can be increased
* using `NATIVE_MCI_SIZE_MULTIPLIER` which gets multiplied by
* one MiB, resulting in the actual size of the virtual disk.
* Additional parameters are:
*
* Sector (page) size: 512B
* Eerase Block size: 512KiB (524288 Bytes)
*
* @author Lucas Jenß <lucas@x3ro.de>
*
*/

#include <string.h>
#include <stdbool.h>
#include "diskio.h"

#include "storage/flash_sim.h"

#define ENABLE_DEBUG (0)
#include "debug.h"

#ifndef NATIVE_MCI_SIZE_MULTIPLIER
#define NATIVE_MCI_SIZE_MULTIPLIER 8
#endif

#define NATIVE_MCI_SIZE (1024 * 1024 * NATIVE_MCI_SIZE_MULTIPLIER)
#define NATIVE_MCI_SECTOR_SIZE (512)
#define NATIVE_MCI_BLOCK_SIZE (512 * 1024)
#define NATIVE_MCI_SECTOR_COUNT (NATIVE_MCI_SIZE / NATIVE_MCI_SECTOR_SIZE)

flash_sim fs;

bool _validate_parameters(unsigned long sector, unsigned char count) {
if(count < 1) {
return false;
}

if(sector + count > NATIVE_MCI_SECTOR_COUNT) {
return false;
}

return true;
}

DSTATUS MCI_initialize(void) {
fs.page_size = NATIVE_MCI_SECTOR_SIZE;
fs.block_size = NATIVE_MCI_BLOCK_SIZE;
fs.storage_size = NATIVE_MCI_SIZE;
flash_sim_init(&fs);

return RES_OK;
}

DSTATUS MCI_status(void) {
return RES_OK;
}

/* Read |count| sectors starting at |sector| (LBA) */
DRESULT MCI_read(unsigned char *buff, unsigned long sector, unsigned char count) {
if(!_validate_parameters(sector, count)) {
return RES_PARERR;
}

for(unsigned int i=0; i<count; i++) {
unsigned char *page_buffer = buff + (i * NATIVE_MCI_SECTOR_SIZE);
flash_sim_read(&fs, page_buffer, sector + i);
}

return RES_OK;
}

/* Write |count| sectors starting at |sector| (LBA) */
DRESULT MCI_write(const unsigned char *buff, unsigned long sector, unsigned char count) {
if(!_validate_parameters(sector, count)) {
return RES_PARERR;
}

for(unsigned int i=0; i<count; i++) {
unsigned char *page_buffer = ((unsigned char*) buff) + (i * NATIVE_MCI_SECTOR_SIZE);
flash_sim_write(&fs, page_buffer, sector + i);
}

return RES_OK;
}

DRESULT MCI_ioctl(
unsigned char ctrl, /* Control code */
void *buff /* Buffer to send/receive data block */
) {
DRESULT res = RES_ERROR;
unsigned long block;

switch(ctrl) {

/* Get number of sectors on the disk (unsigned long) */
case GET_SECTOR_COUNT:
*(unsigned long *) buff = NATIVE_MCI_SECTOR_COUNT;
res = RES_OK;
break;

/* Get sector (page) size (unsigned short) */
case GET_SECTOR_SIZE:
*(unsigned short *) buff = NATIVE_MCI_SECTOR_SIZE;
res = RES_OK;
break;

/* Get erase block size (unsigned long) */
case GET_BLOCK_SIZE:
*(unsigned long *) buff = NATIVE_MCI_BLOCK_SIZE;
res = RES_OK;
break;

/* Erase a block of sectors */
case CTRL_ERASE_SECTOR:
block = *(unsigned long *)buff;

if(!_validate_parameters(block, 1)) {
return RES_PARERR;
}

flash_sim_erase(&fs, block);
res = RES_OK;
break;

/* Get card type flags (1 byte) */
case MMC_GET_TYPE:
// Not implemented
break;

/* Get CSD (16 bytes) */
case MMC_GET_CSD:
// Not implemented
break;

/* Get CID (16 bytes) */
case MMC_GET_CID:
// Not implemented
break;

/* Get OCR (4 bytes) */
case MMC_GET_OCR:
// Not implemented
break;

/* Receive SD status as a data block (64 bytes) */
case MMC_GET_SDSTAT:
// Not implemented
break;

/* No-Ops for virtual MCI */
case CTRL_SYNC: /* Make sure that all data has been written on the media */
case CTRL_POWER: /* Power on/off */
res = RES_OK;
break;

default:
res = RES_PARERR;
}

return res;
}
3 changes: 3 additions & 0 deletions sys/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ endif
ifneq (,$(filter udp,$(USEMODULE)))
DIRS += net/transport_layer/udp
endif
ifneq (,$(filter flash_sim,$(USEMODULE)))
DIRS += storage/flash_sim
endif

ifneq (,$(filter hamming256,$(USEMODULE)))
DIRS += ecc/hamming256
Expand Down
142 changes: 142 additions & 0 deletions sys/include/storage/flash_sim.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
/*
* Copyright (C) 2015 Lucas Jenß
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/

/**
* @ingroup sys_storage
* @brief
* @{
*
* @brief Simulates flash memory for easier testing of storage subsystems
* @author Lucas Jenß <lucas@x3ro.de>
*/

#ifndef _FS_FLASH_SIM_H
#define _FS_FLASH_SIM_H

#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>

#ifdef __cplusplus
extern "C" {
#endif

/**
* @brief Configuration for the flash simulation layer
*/
typedef struct flash_sim {
uint32_t page_size; //!< Page size to be emulated
uint32_t block_size; //!< Block size (must be a multiple of the page size)
uint64_t storage_size; //!< Total amount of storage to be made available

uint32_t pages; //!< Number of pages (computed from the above)
FILE *_fp; //!< File descriptor for the file simulating the flash device
} flash_sim;


/**
* @brief Initialize the flash simulation layer with the given configuration struct
* @param fs Configuration
* @return 0 on success
* @return -EINVAL if the given configuration struct was invalid
* @return -EBADFD if there was an error with the file used for simulated storage
* @return Any error #flash_sim_format may return
*/
int flash_sim_init(flash_sim *fs);

/**
* @brief Erases all blocks of the simulated flash device
* @param fs Configuration
*
* @return 0 on success
* @return -ENODEV if device has not been initialized
* @return -EBADFD if there was an error with the file used for simulated storage
*/
int flash_sim_format(flash_sim *fs);

/**
* @brief Reads the given page into the provided buffer
* @param fs Configuration
* @param buffer Target buffer (must be >= the size of a page)
* @param page Absolute page index to be read
*
* @return 0 on success
* @return -ENODEV if device has not been initialized
* @return -EFAULT if given page was out of range
*/
int flash_sim_read(const flash_sim *fs, void *buffer, uint32_t page);

/**
* @brief Partially reads data from the given page into the target buffer
* @param fs Configuration
* @param buffer Target buffer (must be >= the provided length)
* @param page Absolute page index to be read
* @param offset Offset inside the page from which to start reading
* @param length Amount of bytes to read
*
* @return 0 on success
* @return Any error #flash_sim_read may return
*/
int flash_sim_read_partial(const flash_sim *fs,
void *buffer,
uint32_t page,
uint32_t offset,
uint32_t length);

/**
* @brief Writes the provided buffer to the given page
* @param fs Configuration
* @param buffer Source buffer (must be >= the size of a page)
* @param page Absolute page index to be written to
*
* @return 0 on success
* @return -ENODEV if device has not been initialized
* @return -EIO if trying to perform an invalid write operation (e.g., setting bits
* back to 1 without erasing first)
* @return -EBADFD if there was an error with the file used for simulated storage
* @return -EFAULT if given page was out of range
* @return Any error #flash_sim_read may return
*/
int flash_sim_write(const flash_sim *fs, const void *buffer, uint32_t page);

/**
* @brief Partially writes data from the provided buffer to the given page
* @param fs Configuration
* @param buffer Target buffer (must be >= the provided length)
* @param page Absolute page index to be written to
* @param offset Offset inside the page indicating where to start writing
* @param length Amount of bytes to write
*
* @return 0 on success
* @return Any error #flash_sim_read may return
* @return Any error #flash_sim_write may return
*/
int flash_sim_write_partial(const flash_sim *fs,
const void *buffer,
uint32_t page,
uint32_t offset,
uint32_t length);

/**
* @brief Erase the given block
* @param fs Configuration
* @param block Absolute block index
*
* @return 0 on success
* @return -ENODEV if device has not been initialized
* @return -EBADFD if there was an error with the file used for simulated storage
* @return -EFAULT if given page was out of range
*/
int flash_sim_erase(const flash_sim *fs, uint32_t block);

#ifdef __cplusplus
}
#endif

#endif
/** @} */
14 changes: 14 additions & 0 deletions sys/storage/doc.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* Copyright (C) 2015 Lucas Jenß
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/

/**
* @defgroup sys_storage Data Storage
* @ingroup sys
*
* @brief RIOT's data storage subsystem
*/
1 change: 1 addition & 0 deletions sys/storage/flash_sim/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include $(RIOTBASE)/Makefile.base
7 changes: 7 additions & 0 deletions sys/storage/flash_sim/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# flash_sim

Implements an emulation of flash memory with its common properties:

* Per-page read
* Per-page write-once
* Per-sector erase
Loading

0 comments on commit 4ed4677

Please sign in to comment.