pkg/fatfs: integrate diskio layer to mtd interface

This commit is contained in:
MichelRottleuthner 2017-07-05 14:54:42 +02:00
parent ee17dae5af
commit 198ced4933
21 changed files with 513 additions and 705 deletions

View File

@ -669,17 +669,8 @@ ifneq (,$(filter ccn-lite,$(USEPKG)))
endif
ifneq (,$(filter fatfs_vfs,$(USEMODULE)))
USEPKG += fatfs
USEMODULE += vfs
ifeq ($(BOARD),native)
USEMODULE += fatfs_diskio_native
FATFS_DISKIO_NATIVE_DEFAULT_FILE ?= \"riot_fatfs_disk.img\"
else
USEMODULE += fatfs_diskio_sdcard_spi
USEMODULE += auto_init_storage
endif
USEPKG += fatfs
USEMODULE += vfs
endif
# always select gpio (until explicit dependencies are sorted out)

View File

@ -1,10 +1,6 @@
ifneq (,$(filter fatfs_diskio_sdcard_spi,$(USEMODULE)))
USEMODULE += sdcard_spi
endif
ifneq (,$(filter fatfs,$(USEPKG)))
USEMODULE += fatfs_diskio_common
endif
USEMODULE += fatfs_diskio_mtd
USEMODULE += auto_init_storage
USEMODULE += mtd
include $(RIOTBASE)/boards/$(BOARD)/Makefile.features

View File

@ -1,19 +1,12 @@
INCLUDES += -I$(PKGDIRBASE)
INCLUDES += -I$(RIOTPKG)/fatfs/fatfs_diskio/common/include
INCLUDES += -I$(RIOTPKG)/fatfs/fatfs_diskio/mtd/include
DIRS += $(PKGDIRBASE)/fatfs
DIRS += $(RIOTBASE)/pkg/fatfs/fatfs_diskio/common
DIRS += $(RIOTBASE)/pkg/fatfs/fatfs_diskio/mtd
ifneq (,$(filter fatfs_diskio_native,$(USEMODULE)))
DIRS += $(RIOTBASE)/pkg/fatfs/fatfs_diskio/native
endif
ifneq (,$(filter fatfs_diskio_sdcard_spi,$(USEMODULE)))
DIRS += $(RIOTBASE)/pkg/fatfs/fatfs_diskio/sdcard_spi
endif
ifneq (,$(filter fatfs_vfs,$(USEMODULE)))
DIRS += $(RIOTBASE)/pkg/fatfs/fatfs_vfs
DIRS += $(RIOTBASE)/pkg/fatfs/fatfs_vfs
endif
ifeq ($(shell uname -s),Darwin)

View File

@ -1,51 +0,0 @@
/*
* Copyright (C) 2016 Michel Rottleuthner <michel.rottleuthner@haw-hamburg.de>
*
* 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_fatfs_diskio
* @{
*
* @file
* @brief Implementation of common FatFs interface for native and sdcard_spi
* Based on low level disk I/O module example for FatFs by ChaN, 2016
*
* @author Michel Rottleuthner <michel.rottleuthner@haw-hamburg.de>
*
* @}
*/
#include "fatfs/diskio.h" /* FatFs lower layer API */
#include "fatfs_diskio_common.h"
#include "time.h"
#include "stdint.h"
#if FATFS_FFCONF_OPT_FS_NORTC == 0
#include "periph/rtc.h"
DWORD get_fattime(void)
{
struct tm time;
rtc_get_time(&time);
/* bit 31:25 Year origin from 1980 (0..127) */
uint8_t year = time.tm_year + RTC_YEAR_OFFSET - FATFS_YEAR_OFFSET;
uint8_t month = time.tm_mon + 1; /* bit 24:21 month (1..12) */
uint8_t day_of_month = time.tm_mon + 1; /* bit 20:16 day (1..31) */
uint8_t hour = time.tm_hour; /* bit 15:11 hour (0..23) */
uint8_t minute = time.tm_min; /* bit 10:5 minute (0..59) */
uint8_t second = (time.tm_sec / 2); /* bit 4:0 second/2 (0..29) */
return year << FATFS_DISKIO_FATTIME_YEAR_OFFS |
month << FATFS_DISKIO_FATTIME_MON_OFFS |
day_of_month << FATFS_DISKIO_FATTIME_DAY_OFFS |
hour << FATFS_DISKIO_FATTIME_HH_OFFS |
minute << FATFS_DISKIO_FATTIME_MM_OFFS |
second;
}
#endif

View File

@ -1,3 +1,3 @@
MODULE = fatfs_diskio_common
MODULE = fatfs_diskio_mtd
include $(RIOTBASE)/Makefile.base

View File

@ -15,8 +15,8 @@
* @author Michel Rottleuthner <michel.rottleuthner@haw-hamburg.de>
*/
#ifndef FATFS_DISKIO_COMMON_H
#define FATFS_DISKIO_COMMON_H
#ifndef FATFS_DISKIO_MTD_H
#define FATFS_DISKIO_MTD_H
#ifdef __cplusplus
extern "C" {
@ -41,5 +41,5 @@ extern "C" {
}
#endif
#endif /* FATFS_DISKIO_COMMON_H */
#endif /* FATFS_DISKIO_MTD_H */
/** @} */

View File

@ -0,0 +1,228 @@
/*
* Copyright (C) 2017 Michel Rottleuthner <michel.rottleuthner@haw-hamburg.de>
*
* 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_fatfs_diskio
* @{
*
* @file
* @brief Implementation of fatfs diskio interface that supports mtd driver
* based on low level disk I/O module example for FatFs by ChaN, 2016
*
* @author Michel Rottleuthner <michel.rottleuthner@haw-hamburg.de>
*
* @}
*/
#include "fatfs/diskio.h" /**< FatFs lower layer API */
#include "fatfs_diskio_mtd.h"
#include "fatfs/ffconf.h"
#include "mtd.h"
#include "fatfs/integer.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
#if FATFS_FFCONF_OPT_FS_NORTC == 0
#include "periph/rtc.h"
#endif
/* mtd devices for use by FatFs should be provided by the application */
extern mtd_dev_t *fatfs_mtd_devs[_VOLUMES];
/**
* @brief returns the status of the disk
*
* @param[in] pdrv drive number to identify the drive
*
* @return STA_NODISK if no disk exists with the given id
* @return 0 if disk is initialized
* @return STA_NOINIT if disk id exists, but disk isn't initialized
*/
DSTATUS disk_status(BYTE pdrv)
{
DEBUG("disk_status %d\n", pdrv);
if (pdrv >= _VOLUMES) {
return STA_NODISK;
} else if (fatfs_mtd_devs[pdrv]->driver == NULL){
return STA_NOINIT;
}
return FATFS_DISKIO_DSTASTUS_OK;
}
/**
* @brief initializes the disk
*
* @param[in] pdrv drive number to identify the drive
*
* @return STA_NODISK if no disk exists with the given id
* @return 0 if disk was initialized sucessfully
* @return STA_NOINIT if disk id exists, but couldn't be initialized
*/
DSTATUS disk_initialize(BYTE pdrv)
{
DEBUG("disk_initialize %d\n", pdrv);
if (pdrv >= _VOLUMES) {
return STA_NODISK;
} else if (fatfs_mtd_devs[pdrv]->driver == NULL){
return STA_NOINIT;
}
return (mtd_init(fatfs_mtd_devs[pdrv]) == 0) ? FATFS_DISKIO_DSTASTUS_OK
: STA_NOINIT;
}
/**
* @brief reads sectors from disk
*
* @param[in] pdrv drive number to identify the drive
* @param[out] buff Data buffer to store read data
* @param[in] sector Start sector in LBA
* @param[in] count Number of sectors to read
*
* @return RES_OK if no error occurred
* @return RES_ERROR if data wasn't read completely
* @return RES_PARERR if prdv is invalid or has no mtd-driver set
*/
DRESULT disk_read(BYTE pdrv, BYTE *buff, DWORD sector, UINT count)
{
DEBUG("disk_read: %d, %lu, %d\n", pdrv, sector, count);
if ((pdrv >= _VOLUMES) || (fatfs_mtd_devs[pdrv]->driver == NULL)) {
return RES_PARERR;
}
int res = mtd_read(fatfs_mtd_devs[pdrv], buff,
sector * fatfs_mtd_devs[pdrv]->page_size,
count * fatfs_mtd_devs[pdrv]->page_size);
if (res >= 0) {
uint32_t r_sect = ((unsigned)res) / fatfs_mtd_devs[pdrv]->page_size;
return ((r_sect == count) ? RES_OK : RES_ERROR);
}
return RES_ERROR;
}
/**
* @brief writes sectors to disk
*
* @param[in] pdrv Physical drive nmuber to identify the drive
* @param[in] buff Data to be written
* @param[in] sector Start sector in LBA
* @param[in] count Number of sectors to write
*
* @return RES_OK if no error occurred
* @return RES_ERROR if data wasn't written completely
* @return RES_PARERR if prdv is invalid or has no mtd-driver set
*/
DRESULT disk_write(BYTE pdrv, const BYTE *buff, DWORD sector, UINT count)
{
DEBUG("disk_write: %d, %lu, %d\n", pdrv, sector, count);
if ((pdrv >= _VOLUMES) || (fatfs_mtd_devs[pdrv]->driver == NULL)) {
return RES_PARERR;
}
/* erase memory before writing to it */
int res = mtd_erase(fatfs_mtd_devs[pdrv],
sector * fatfs_mtd_devs[pdrv]->page_size,
count * fatfs_mtd_devs[pdrv]->page_size);
if (res != 0) {
return RES_ERROR; /* erase failed! */
}
res = mtd_write(fatfs_mtd_devs[pdrv], buff,
sector * fatfs_mtd_devs[pdrv]->page_size,
count * fatfs_mtd_devs[pdrv]->page_size);
if (res >= 0) {
uint32_t w_sect = ((unsigned)res) / fatfs_mtd_devs[pdrv]->page_size;
return ((w_sect == count) ? RES_OK : RES_ERROR);
}
return RES_ERROR;
}
/**
* @brief perform miscellaneous low-level control functions
*
* @param[in] pdrv Physical drive nmuber (0.._VOLUMES-1)
* @param[in out] cmd Control code
* @param[in] sector Buffer to send/receive control data
*
* @return RES_OK if no error occurred
* @return RES_PARERR if cmd is unknown or
* prdv is either invalid or has no mtd-driver set
*/
DRESULT disk_ioctl(BYTE pdrv, BYTE cmd, void *buff)
{
if ((pdrv >= _VOLUMES) || (fatfs_mtd_devs[pdrv]->driver == NULL)) {
return RES_PARERR;
}
switch (cmd) {
#if (_FS_READONLY == 0)
case CTRL_SYNC:
/* r/w is always finished within r/w-functions of mtd */
return RES_OK;
#endif
#if (_USE_MKFS == 1)
case GET_SECTOR_COUNT:
*(DWORD *)buff = fatfs_mtd_devs[pdrv]->sector_count;
return RES_OK;
/*Erase block size in number of sectors (1 to 32768 in power of 2).
Return 1 if the erase block size is unknown. */
case GET_BLOCK_SIZE:
*(DWORD *)buff = fatfs_mtd_devs[pdrv]->pages_per_sector;
return RES_OK;
#endif
#if (_MAX_SS != _MIN_SS)
case GET_SECTOR_SIZE:
*(DWORD *)buff = fatfs_mtd_devs[pdrv]->page_size;
return RES_OK;
#endif
#if (_USE_TRIM == 1)
case CTRL_TRIM:
return RES_OK;
#endif
}
return RES_PARERR;
}
#if FATFS_FFCONF_OPT_FS_NORTC == 0
/**
* @brief store local time in a 32-bit bitfiled
*
* @return timestamp as bitfield
*/
DWORD get_fattime(void)
{
struct tm time;
rtc_get_time(&time);
/* bit 31:25 Year origin from 1980 (0..127) */
uint8_t year = time.tm_year + RTC_YEAR_OFFSET - FATFS_YEAR_OFFSET;
uint8_t month = time.tm_mon + 1; /* bit 24:21 month (1..12) */
uint8_t day_of_month = time.tm_mon + 1; /* bit 20:16 day (1..31) */
uint8_t hour = time.tm_hour; /* bit 15:11 hour (0..23) */
uint8_t minute = time.tm_min; /* bit 10:5 minute (0..59) */
uint8_t second = (time.tm_sec / 2); /* bit 4:0 second/2 (0..29) */
return year << FATFS_DISKIO_FATTIME_YEAR_OFFS |
month << FATFS_DISKIO_FATTIME_MON_OFFS |
day_of_month << FATFS_DISKIO_FATTIME_DAY_OFFS |
hour << FATFS_DISKIO_FATTIME_HH_OFFS |
minute << FATFS_DISKIO_FATTIME_MM_OFFS |
second;
}
#endif

View File

@ -1,7 +0,0 @@
MODULE = fatfs_diskio_native
FATFS_DISKIO_NATIVE_DEFAULT_FILE ?= \"riot_fatfs_disk.img\"
CFLAGS += -DFATFS_DISKIO_NATIVE_DEFAULT_FILE=$(FATFS_DISKIO_NATIVE_DEFAULT_FILE)
include $(RIOTBASE)/Makefile.base

View File

@ -1,263 +0,0 @@
/*
* Copyright (C) 2016 Michel Rottleuthner <michel.rottleuthner@haw-hamburg.de>
*
* 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_fatfs_diskio
* @{
*
* @file
* @brief Implementation of FatFs interface that makes use of a fatfs image
* file instead of hardware to allow FatFs usage/testing on native.
* Based on low level disk I/O module example for FatFs by ChaN, 2016
*
* @author Michel Rottleuthner <michel.rottleuthner@haw-hamburg.de>
*
* @}
*/
#define ENABLE_DEBUG (0)
#include "debug.h"
#include "fatfs/ffconf.h"
#include "fatfs/diskio.h"
#include "fatfs_diskio_common.h"
#include "fatfs/integer.h"
#include "periph/rtc.h"
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/stat.h>
bool rtc_init_done = false;
typedef struct {
const char *image_path;
FILE *fd;
bool opened;
} dummy_volume_t;
static dummy_volume_t volume_files[] = {
{
.image_path = FATFS_DISKIO_NATIVE_DEFAULT_FILE,
.fd = NULL,
.opened = false
},
};
static inline dummy_volume_t *get_volume_file(uint32_t idx)
{
if (idx < sizeof(volume_files) / sizeof(dummy_volume_t)) {
return &volume_files[idx];
}
else {
return NULL;
}
}
/**
* @brief returns the status of the disk
*
* @param[in] pdrv drive number to identify the drive
*
* @return STA_NODISK if no disk exists with the given id
* @return 0 if disk is initialized
* @return STA_NOINIT if disk id exists, but disk isn't initialized
*/
DSTATUS disk_status(BYTE pdrv)
{
dummy_volume_t *volume = get_volume_file(pdrv);
if (volume == NULL) {
return STA_NODISK;
}
if (volume->opened) {
return FATFS_DISKIO_DSTASTUS_OK;
}
else {
return STA_NOINIT;
}
}
/**
* @brief initializes the disk
*
* @param[in] pdrv drive number to identify the drive
*
* @return STA_NODISK if no disk exists with the given id
* @return 0 if disk was initialized successfully
* @return STA_NOINIT if disk id exists, but couldn't be initialized
*/
DSTATUS disk_initialize(BYTE pdrv)
{
dummy_volume_t *volume = get_volume_file(pdrv);
DEBUG("disk_initialize: %d\n", pdrv);
if (volume == NULL) {
return STA_NODISK;
}
if (volume->opened) { /* if volume is already opened close it first */
fclose(volume->fd);
volume->opened = false;
}
/* open file for r/w but don't create if it doesn't exist */
FILE *fd = fopen(volume->image_path, "r+");
DEBUG("fd: %p\n", (void *)fd);
if (fd == NULL) {
DEBUG("diskio_native.c: disk_initialize: fopen: "
"errno: 0x%08x\n", errno);
return STA_NOINIT;
}
else {
volume->fd = fd;
volume->opened = true;
return FATFS_DISKIO_DSTASTUS_OK;
}
}
/**
* @brief reads sectors from disk
*
* @param[in] pdrv drive number to identify the drive
* @param[out] buff Data buffer to store read data
* @param[in] sector Start sector in LBA
* @param[in] count Number of sectors to read
*
* @return RES_OK if no error occurred
* @return RES_NOTRDY if data wasn't read completely
*/
DRESULT disk_read(BYTE pdrv, BYTE *buff, DWORD sector, UINT count)
{
dummy_volume_t *volume = get_volume_file(pdrv);
if ((volume != NULL) && volume->opened) {
/* set read pointer to secor equivalent position */
if (fseek(volume->fd, sector * FIXED_BLOCK_SIZE, SEEK_SET) == 0) {
if (fread(buff, FIXED_BLOCK_SIZE, count, volume->fd) == count) {
return RES_OK;
}
else {
DEBUG("diskio_native.c: disk_read: fread: "
"errno: 0x%08x\n", errno);
}
}
else {
DEBUG("diskio_native.c: disk_read: fseek: errno: 0x%08x\n", errno);
}
}
return RES_NOTRDY;
}
/**
* @brief writes sectors to disk
*
* @param[in] pdrv Physical drive nmuber to identify the drive
* @param[in] buff Data to be written
* @param[in] sector Start sector in LBA
* @param[in] count Number of sectors to write
*
* @return RES_OK if no error occurred
* @return RES_NOTRDY if data wasn't written completely
*/
DRESULT disk_write(BYTE pdrv, const BYTE *buff, DWORD sector, UINT count)
{
dummy_volume_t *volume = get_volume_file(pdrv);
if ((volume != NULL) && volume->opened) {
/* set write pointer to secor equivalent position */
if (fseek(volume->fd, sector * FIXED_BLOCK_SIZE, SEEK_SET) == 0) {
if (fwrite(buff, FIXED_BLOCK_SIZE, count, volume->fd) == count) {
if (fflush(volume->fd) == 0) {
return RES_OK;
}
else {
DEBUG("diskio_native.c: disk_write: fflush: "
"errno: 0x%08x\n", errno);
}
}
else {
DEBUG("diskio_native.c: disk_write: fwrite: "
"errno: 0x%08x\n", errno);
}
}
else {
DEBUG("diskio_native.c: disk_write: fseek: errno: 0x%08x\n", errno);
}
}
return RES_NOTRDY;
}
/**
* @brief perform miscellaneous low-level control functions
*
* @param[in] pdrv Physical drive nmuber (0..)
* @param[in out] cmd Control code
* @param[in] sector Buffer to send/receive control data
*
* @return RES_OK if no error occurred
* @return RES_ERROR if an error occurred
* @return RES_PARERR if an error occurred
*/
DRESULT disk_ioctl(
BYTE pdrv, /* */
BYTE cmd, /* */
void *buff /* Buffer to send/receive control data */
)
{
(void) pdrv; /* prevent warning about unused param */
(void) buff; /* prevent warning about unused param */
#if (_USE_MKFS == 1)
dummy_volume_t *volume;
struct stat s;
#endif
DEBUG("disk_ioctl: %d\n", cmd);
switch (cmd) {
#if (_FS_READONLY == 0)
case CTRL_SYNC:
/* r/w is always finished within r/w-functions */
return RES_OK;
#endif
#if (_MAX_SS != _MIN_SS)
case GET_SECTOR_SIZE;
*buff = FIXED_BLOCK_SIZE;
return RES_OK;
#endif
#if (_USE_MKFS == 1)
case GET_SECTOR_COUNT:
volume = get_volume_file(pdrv);
DEBUG("GET_SECTOR_COUNT: volume: %p\n", (void*)volume);
if ((volume != NULL) && volume->opened) {
if (stat(volume->image_path, &s) == 0) {
*(DWORD *)buff = s.st_size / FIXED_BLOCK_SIZE;
DEBUG("GET_SECTOR_COUNT\n");
return RES_OK;
}
DEBUG("GET_SECTOR_COUNT: RES_ERROR\n");
}
return RES_ERROR;
case GET_BLOCK_SIZE:
*(DWORD *)buff = FIXED_BLOCK_SIZE;
DEBUG("GET_BLOCK_SIZE: %d\n", FIXED_BLOCK_SIZE);
return RES_OK;
#endif
#if (_USE_TRIM == 1)
case CTRL_TRIM:
return RES_OK;
#endif
}
return RES_PARERR;
}

View File

@ -1,5 +0,0 @@
MODULE = fatfs_diskio_sdcard_spi
USEMODULE += sdcard_spi
include $(RIOTBASE)/Makefile.base

View File

@ -1,211 +0,0 @@
/*
* Copyright (C) 2016 Michel Rottleuthner <michel.rottleuthner@haw-hamburg.de>
*
* 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_fatfs_diskio
* @{
*
* @file
* @brief Implementation of fatfs interface that supports sdcard_spi driver
* based on low level disk I/O module example for FatFs by ChaN, 2016
*
* @author Michel Rottleuthner <michel.rottleuthner@haw-hamburg.de>
*
* @}
*/
#include "fatfs/diskio.h" /* FatFs lower layer API */
#include "fatfs_diskio_common.h"
#include "fatfs/ffconf.h"
#include "fatfs/integer.h"
#include "sdcard_spi.h"
#include "sdcard_spi_internal.h"
#include "sdcard_spi_params.h"
#include <stdio.h>
#include <time.h>
#include "periph_conf.h"
#include "periph/rtc.h"
#include "xtimer.h"
#include "debug.h"
#define NUM_OF_SD_CARDS (sizeof(sdcard_spi_params) / sizeof(sdcard_spi_params[0]))
extern sdcard_spi_t sdcard_spi_devs[NUM_OF_SD_CARDS];
static inline sdcard_spi_t *get_sd_card(int idx)
{
if (idx < (int)NUM_OF_SD_CARDS) {
return &(sdcard_spi_devs[idx]);
}
return NULL;
}
/**
* @brief returns the status of the disk
*
* @param[in] pdrv drive number to identify the drive
*
* @return STA_NODISK if no disk exists with the given id
* @return 0 if disk is initialized
* @return STA_NOINIT if disk id exists, but disk isn't initialized
*/
DSTATUS disk_status(BYTE pdrv)
{
sdcard_spi_t *card = get_sd_card(pdrv);
if (card == NULL) {
return STA_NODISK;
}
else if (card->init_done) {
return FATFS_DISKIO_DSTASTUS_OK;
}
return STA_NOINIT;
}
/**
* @brief initializes the disk
*
* @param[in] pdrv drive number to identify the drive
*
* @return STA_NODISK if no disk exists with the given id
* @return 0 if disk was initialized successfully
* @return STA_NOINIT if disk id exists, but couldn't be initialized
*/
DSTATUS disk_initialize(BYTE pdrv)
{
sdcard_spi_t *card = get_sd_card(pdrv);
if (card == NULL) {
return STA_NODISK;
}
else if (sdcard_spi_init(card, &sdcard_spi_params[pdrv]) == 0) {
return FATFS_DISKIO_DSTASTUS_OK;
}
return STA_NOINIT;
}
/**
* @brief reads sectors from disk
*
* @param[in] pdrv drive number to identify the drive
* @param[out] buff Data buffer to store read data
* @param[in] sector Start sector in LBA
* @param[in] count Number of sectors to read
*
* @return RES_OK if no error occurred
* @return RES_NOTRDY if data wasn't read completely
*/
DRESULT disk_read(BYTE pdrv, BYTE *buff, DWORD sector, UINT count)
{
sdcard_spi_t *card = get_sd_card(pdrv);
if ((card != NULL) && card->init_done) {
sd_rw_response_t state;
if ((int)count != sdcard_spi_read_blocks(card, sector,
(char *)buff,
SD_HC_BLOCK_SIZE,
count, &state)) {
printf("[ERROR] disk_read: sdcard_spi_read_blocks: %d\n", state);
return RES_NOTRDY;
}
return RES_OK;
}
return RES_NOTRDY;
}
/**
* @brief writes sectors to disk
*
* @param[in] pdrv Physical drive nmuber to identify the drive
* @param[in] buff Data to be written
* @param[in] sector Start sector in LBA
* @param[in] count Number of sectors to write
*
* @return RES_OK if no error occurred
* @return RES_NOTRDY if data wasn't written completely
*/
DRESULT disk_write(BYTE pdrv, const BYTE *buff, DWORD sector, UINT count)
{
sdcard_spi_t *card = get_sd_card(pdrv);
if ((card != NULL) && card->init_done) {
sd_rw_response_t state;
if ((int)count != sdcard_spi_write_blocks(card, sector,
(char *)buff,
SD_HC_BLOCK_SIZE,
count, &state)) {
printf("[ERROR] disk_write: sdcard_spi_write_blocks: %d\n", state);
return RES_NOTRDY;
}
return RES_OK;
}
return RES_NOTRDY;
}
/**
* @brief perform miscellaneous low-level control functions
*
* @param[in] pdrv Physical drive nmuber (0..)
* @param[in out] cmd Control code
* @param[in] sector Buffer to send/receive control data
*
* @return RES_OK if no error occurred
* @return RES_ERROR if an error occurred
* @return RES_PARERR if an error occurred
*/
DRESULT disk_ioctl(BYTE pdrv, BYTE cmd, void *buff)
{
#if (_USE_MKFS == 1)
sdcard_spi_t *card = get_sd_card(pdrv);
#endif
switch (cmd) {
#if (_FS_READONLY == 0)
case CTRL_SYNC:
/* r/w is always finished within r/w-functions of sdcard_spi */
return RES_OK;
#endif
#if (_USE_MKFS == 1)
case GET_SECTOR_COUNT:
if ((card != NULL) && card->init_done) {
*(DWORD *)buff = sdcard_spi_get_sector_count(card);
return RES_OK;
}
else {
return RES_ERROR;
}
case GET_BLOCK_SIZE:
if ((card != NULL) && card->init_done) {
/* erase block size in unit of sector */
*(DWORD *)buff = sdcard_spi_get_au_size(card) / SD_HC_BLOCK_SIZE;
return RES_OK;
}
*(DWORD *)buff = 0;
return RES_ERROR;
#endif
#if (_MAX_SS != _MIN_SS)
case GET_SECTOR_SIZE:
*buff = SD_HC_BLOCK_SIZE;
return RES_OK;
#endif
#if (_USE_TRIM == 1)
case CTRL_TRIM:
return RES_OK;
#endif
}
return RES_PARERR;
}

View File

@ -88,46 +88,44 @@ static int _umount(vfs_mount_t *mountp)
static int _unlink(vfs_mount_t *mountp, const char *name)
{
char fatfs_abs_path[FATFS_MAX_VOL_STR_LEN + VFS_NAME_MAX + 1];
fatfs_desc_t *fs_desc = (fatfs_desc_t *)mountp->private_data;
snprintf(fatfs_abs_path, sizeof(fatfs_abs_path), "%d:/%s",
snprintf(fs_desc->abs_path_str_buff, FATFS_MAX_ABS_PATH_SIZE, "%d:/%s",
fs_desc->vol_idx, name);
return fatfs_err_to_errno(f_unlink(fatfs_abs_path));
return fatfs_err_to_errno(f_unlink(fs_desc->abs_path_str_buff));
}
static int _rename(vfs_mount_t *mountp, const char *from_path,
const char *to_path)
{
char fatfs_abs_path_f[FATFS_MAX_VOL_STR_LEN + VFS_NAME_MAX + 1];
char fatfs_abs_path_t[FATFS_MAX_VOL_STR_LEN + VFS_NAME_MAX + 1];
char fatfs_abs_path_to[FATFS_MAX_ABS_PATH_SIZE];
fatfs_desc_t *fs_desc = (fatfs_desc_t *)mountp->private_data;
snprintf(fatfs_abs_path_f, sizeof(fatfs_abs_path_f), "%d:/%s",
snprintf(fs_desc->abs_path_str_buff, FATFS_MAX_ABS_PATH_SIZE, "%d:/%s",
fs_desc->vol_idx, from_path);
snprintf(fatfs_abs_path_t, sizeof(fatfs_abs_path_t), "%d:/%s",
snprintf(fatfs_abs_path_to, sizeof(fatfs_abs_path_to), "%d:/%s",
fs_desc->vol_idx, to_path);
return fatfs_err_to_errno(f_rename(fatfs_abs_path_f, fatfs_abs_path_t));
return fatfs_err_to_errno(f_rename(fs_desc->abs_path_str_buff,
fatfs_abs_path_to));
}
static int _open(vfs_file_t *filp, const char *name, int flags, mode_t mode,
const char *abs_path)
{
fatfs_file_desc_t *fd = (fatfs_file_desc_t *)&filp->private_data.buffer[0];
char fatfs_abs_path[FATFS_MAX_VOL_STR_LEN + VFS_NAME_MAX + 1];
fatfs_desc_t *fs_desc = (fatfs_desc_t *)filp->mp->private_data;
snprintf(fatfs_abs_path, sizeof(fatfs_abs_path), "%d:/%s", fs_desc->vol_idx,
name);
snprintf(fs_desc->abs_path_str_buff, FATFS_MAX_ABS_PATH_SIZE, "%d:/%s",
fs_desc->vol_idx, name);
(void) abs_path;
(void) mode; /* fatfs can't use mode param with f_open*/
DEBUG("fatfs_vfs.c: _open: private_data = %p, name = %s; flags = 0x%x\n",
filp->mp->private_data, name, flags);
strncpy(fd->fname, fatfs_abs_path, VFS_NAME_MAX);
strncpy(fd->fname, fs_desc->abs_path_str_buff, VFS_NAME_MAX);
uint8_t fatfs_flags = 0;
@ -153,7 +151,9 @@ static int _open(vfs_file_t *filp, const char *name, int flags, mode_t mode,
fatfs_flags |= FA_OPEN_EXISTING;
}
FRESULT open_resu = f_open(&fd->file, fatfs_abs_path, fatfs_flags);
FRESULT open_resu = f_open(&fd->file, fs_desc->abs_path_str_buff,
fatfs_flags);
if (open_resu == FR_OK) {
DEBUG("[OK]");
}
@ -247,17 +247,16 @@ static off_t _lseek(vfs_file_t *filp, off_t off, int whence)
static int _fstat(vfs_file_t *filp, struct stat *buf)
{
fatfs_file_desc_t *fd = (fatfs_file_desc_t *)filp->private_data.buffer;
char fatfs_abs_path[FATFS_MAX_VOL_STR_LEN + VFS_NAME_MAX + 1];
fatfs_desc_t *fs_desc = (fatfs_desc_t *)filp->mp->private_data;
FILINFO fi;
FRESULT res;
snprintf(fatfs_abs_path, sizeof(fatfs_abs_path), "%d:/%s", fs_desc->vol_idx,
fd->fname);
snprintf(fs_desc->abs_path_str_buff, FATFS_MAX_ABS_PATH_SIZE, "%d:/%s",
fs_desc->vol_idx, fd->fname);
memset(buf, 0, sizeof(*buf));
res = f_stat(fatfs_abs_path, &fi);
res = f_stat(fs_desc->abs_path_str_buff, &fi);
if (res != FR_OK) {
return fatfs_err_to_errno(res);
@ -266,11 +265,11 @@ static int _fstat(vfs_file_t *filp, struct stat *buf)
buf->st_size = fi.fsize;
/* set last modification timestamp */
#ifdef SYS_STAT_H_
#ifdef SYS_STAT_H
_fatfs_time_to_timespec(fi.fdate, fi.ftime, &(buf->st_mtim.tv_sec));
#else
#else
_fatfs_time_to_timespec(fi.fdate, fi.ftime, &(buf->st_mtime));
#endif
#endif
if (fi.fattrib & AM_DIR) {
buf->st_mode = S_IFDIR; /**< it's a directory */
@ -293,14 +292,13 @@ static int _fstat(vfs_file_t *filp, struct stat *buf)
static int _opendir(vfs_DIR *dirp, const char *dirname, const char *abs_path)
{
DIR *dir = (DIR *)&dirp->private_data.buffer;
char fatfs_abs_path[FATFS_MAX_VOL_STR_LEN + VFS_NAME_MAX + 1];
fatfs_desc_t *fs_desc = (fatfs_desc_t *)dirp->mp->private_data;
(void) abs_path;
snprintf(fatfs_abs_path, sizeof(fatfs_abs_path), "%d:/%s", fs_desc->vol_idx,
dirname);
snprintf(fs_desc->abs_path_str_buff, FATFS_MAX_ABS_PATH_SIZE, "%d:/%s",
fs_desc->vol_idx, dirname);
return fatfs_err_to_errno(f_opendir(dir, fatfs_abs_path));
return fatfs_err_to_errno(f_opendir(dir, fs_desc->abs_path_str_buff));
}
static int _readdir(vfs_DIR *dirp, vfs_dirent_t *entry)
@ -333,23 +331,23 @@ static int _closedir(vfs_DIR *dirp)
static int _mkdir (vfs_mount_t *mountp, const char *name, mode_t mode)
{
char fatfs_abs_path[FATFS_MAX_VOL_STR_LEN + VFS_NAME_MAX + 1];
fatfs_desc_t *fs_desc = (fatfs_desc_t *)mountp->private_data;
(void) mode;
snprintf(fatfs_abs_path, sizeof(fatfs_abs_path), "%d:/%s", fs_desc->vol_idx,
name);
return fatfs_err_to_errno(f_mkdir(fatfs_abs_path));
snprintf(fs_desc->abs_path_str_buff, FATFS_MAX_ABS_PATH_SIZE, "%d:/%s",
fs_desc->vol_idx, name);
return fatfs_err_to_errno(f_mkdir(fs_desc->abs_path_str_buff));
}
static int _rmdir (vfs_mount_t *mountp, const char *name)
{
char fatfs_abs_path[FATFS_MAX_VOL_STR_LEN + VFS_NAME_MAX + 1];
fatfs_desc_t *fs_desc = (fatfs_desc_t *)mountp->private_data;
snprintf(fatfs_abs_path, sizeof(fatfs_abs_path), "%d:/%s", fs_desc->vol_idx,
name);
return fatfs_err_to_errno(f_unlink(fatfs_abs_path));
snprintf(fs_desc->abs_path_str_buff, FATFS_MAX_ABS_PATH_SIZE, "%d:/%s",
fs_desc->vol_idx, name);
return fatfs_err_to_errno(f_unlink(fs_desc->abs_path_str_buff));
}
static void _fatfs_time_to_timespec(WORD fdate, WORD ftime, time_t *time)
@ -406,11 +404,11 @@ static int fatfs_err_to_errno(int32_t err)
case FR_EXIST:
return -EEXIST;
case FR_INVALID_OBJECT:
#ifdef EBADFD
#ifdef EBADFD
return -EBADFD;
#else
#else
return -EINVAL;
#endif
#endif
case FR_WRITE_PROTECTED:
return -EACCES;
case FR_INVALID_DRIVE:

View File

@ -17,39 +17,42 @@
* @author Michel Rottleuthner <michel.rottleuthner@haw-hamburg.de>
*/
#ifndef FATFS_H
#define FATFS_H
#ifndef FS_FATFS_H
#define FS_FATFS_H
#ifdef __cplusplus
extern "C" {
#endif
#ifndef VFS_DIR_BUFFER_SIZE
#define VFS_DIR_BUFFER_SIZE (44)
#endif
#ifndef VFS_FILE_BUFFER_SIZE
#define VFS_FILE_BUFFER_SIZE (72)
#endif
#include "fatfs/ff.h"
#include "vfs.h"
#ifndef FATFS_YEAR_OFFSET
/** The year in FatFs timestamps is relative to this offset */
#define FATFS_YEAR_OFFSET (1980)
#endif
/** The epoch offset is used to convert between FatFs and time_t timestamps */
#define EPOCH_YEAR_OFFSET (1970)
/** Size of the buffer needed for directory -> should be: sizeof(DIR)*/
/** Size of the buffer needed for a directory entry -> @attention this should be: sizeof(DIR).
sizeof(DIR) currently isn't used directly because it's not possible to use that within
preprocessor-if (see below) */
#define FATFS_DIR_SIZE (44)
/** the problem with the above is: it's not possible to use sizeof(DIR) as this is later usen in #if (see below) */
/** Size of the buffer needed for directory -> should be: sizeof(fatfs_file_desc_t)*/
/** Size of the buffer needed for directory
-> should be: sizeof(fatfs_file_desc_t) */
#define FATFS_FILE_SIZE (72)
#define FATFS_MAX_VOL_STR_LEN (4) /**< size needed for volume strings like "n:/" where n is the volume id */
#define FATFS_MOUNT_OPT (1) /**< 0:mount on first file access, 1 mount in f_mount() call */
/** size needed for volume strings like "n:/" where n is the volume id */
#define FATFS_MAX_VOL_STR_LEN (4)
/** 0:mount on first file access, 1 mount in f_mount() call */
#define FATFS_MOUNT_OPT (1)
/** most FatFs file operations need an absolute path. This defines the size of the
needed buffer to circumvent stack allocation within vfs-wrappers */
#define FATFS_MAX_ABS_PATH_SIZE (FATFS_MAX_VOL_STR_LEN + VFS_NAME_MAX + 1)
#if (VFS_DIR_BUFFER_SIZE < FATFS_DIR_SIZE)
#error "VFS_DIR_BUFFER_SIZE too small"
@ -65,23 +68,29 @@ extern "C" {
typedef struct fatfs_desc {
FATFS fat_fs; /**< FatFs work area needed for each volume */
uint8_t vol_idx; /**< low level device that is used by FatFs */
/** most FatFs file operations need an absolute path. This buffer provides
static memory to circumvent stack allocation within vfs-wrappers */
char abs_path_str_buff[FATFS_MAX_ABS_PATH_SIZE];
} fatfs_desc_t;
/**
* info of a single opened file
*/
typedef struct fatfs_file_desc {
FIL file; /**< FatFs work area for a single file */
char fname[VFS_NAME_MAX + 1]; /**< name of the file (some FatFs functions e.g. f_stat use filename instead of FIL) */
FIL file; /**< FatFs work area for a single file */
char fname[VFS_NAME_MAX + 1]; /**< name of the file (e.g. f_stat uses
filename instead of FIL) */
} fatfs_file_desc_t;
/** The FatFs vfs driver, a pointer to a fatfs_desc_t must be provided as vfs_mountp::private_data */
/** The FatFs vfs driver, a pointer to a fatfs_desc_t must be
provided as vfs_mountp::private_data */
extern const vfs_file_system_t fatfs_file_system;
#ifdef __cplusplus
}
#endif
#endif /* FATFS_H */
#endif /* FS_FATFS_H */
/** @} */

View File

@ -1,34 +1,51 @@
include ../Makefile.tests_common
USEMODULE += shell
BOARD ?= native
FEATURES_OPTIONAL += periph_rtc
# whitelist can be removed when the problem described in #6063 was resolved
# this list is composed of boards that support spi + native
BOARD_WHITELIST := native airfy-beacon arduino-due arduino-duemilanove arduino-mega2560 \
arduino-uno arduino-zero avsextrem cc2538dk fox frdm-k64f iotlab-a8-m3 \
iotlab-m3 limifrog-v1 maple-mini msb-430 msb-430h msba2 msbiot mulle \
nrf52840dk nrf52dk nrf6310 nucleo-f072 nucleo-f091 nucleo-f103 \
nucleo-f302 nucleo-f303 nucleo-f334 nucleo-f401 nucleo-f410 nucleo-f411 \
nucleo-f446 nucleo-l053 nucleo-l073 nucleo-l152 nucleo-l476 nucleo144-f207 \
nucleo144-f303 nucleo144-f413 nucleo144-f429 nucleo144-f446 nucleo32-f031 \
nucleo32-f042 nucleo32-f303 nucleo32-l031 nucleo32-l432 openmote-cc2538 \
pba-d-01-kw2x remote-pa remote-reva remote-revb samd21-xpro \
saml21-xpro samr21-xpro sodaq-autonomo spark-core stm32f0discovery \
# this list is composed of boards that support spi/gpio + native
BOARD_WHITELIST := airfy-beacon arduino-due arduino-duemilanove arduino-mega2560 \
arduino-mkr1000 arduino-mkrzero arduino-uno arduino-zero avsextrem \
b-l072z-lrwan1 b-l475e-iot01a bluepill cc2538dk ek-lm4f120xl \
feather-m0 fox frdm-k22f frdm-k64f ikea-tradfri iotlab-a8-m3 \
iotlab-m3 limifrog-v1 maple-mini msb-430 msb-430h msba2 msbiot \
mulle nrf52840dk nrf52dk nrf6310 nucleo144-f207 nucleo144-f303 \
nucleo144-f412 nucleo144-f413 nucleo144-f429 nucleo144-f446 \
nucleo32-f031 nucleo32-f042 nucleo32-f303 nucleo32-l031 \
nucleo32-l432 nucleo-f072 nucleo-f091 nucleo-f103 nucleo-f302 \
nucleo-f303 nucleo-f334 nucleo-f401 nucleo-f410 nucleo-f411 \
nucleo-f446 nucleo-l053 nucleo-l073 nucleo-l152 nucleo-l476 \
nz32-sc151 openmote-cc2538 pba-d-01-kw2x remote-pa remote-reva \
remote-revb samd21-xpro saml21-xpro samr21-xpro sltb001a \
sodaq-autonomo sodaq-explorer spark-core stm32f0discovery \
stm32f3discovery stm32f4discovery telosb udoo waspmote-pro \
wsn430-v1_3b wsn430-v1_4 yunjia-nrf51822 z1
wsn430-v1_3b wsn430-v1_4 yunjia-nrf51822 z1 native
USEMODULE += shell
USEMODULE += fatfs_diskio_mtd
USEMODULE += mtd
USEPKG += fatfs
FATFS_IMAGE_FILE_SIZE_MIB ?= 128
ifeq ($(BOARD),native)
USEMODULE += fatfs_diskio_native
FATFS_DISKIO_NATIVE_DEFAULT_FILE ?= \"riot_fatfs_disk.img\"
#overwrite default mtd_native-config to use fat image as flash device
CFLAGS += -DMTD_NATIVE_FILENAME=\"./bin/riot_fatfs_disk.img\"
CFLAGS += -DMTD_NATIVE_PAGE_SIZE=512
CFLAGS += -DMTD_NATIVE_SECTOR_SIZE=512
CFLAGS += -DFATFS_IMAGE_FILE_SIZE_MIB=$(FATFS_IMAGE_FILE_SIZE_MIB)
CFLAGS += -DMTD_NATIVE_SECTOR_NUM=\(\(\(FATFS_IMAGE_FILE_SIZE_MIB\)*1024*1024\)/MTD_NATIVE_SECTOR_SIZE\)
else
USEMODULE += fatfs_diskio_sdcard_spi
USEMODULE += auto_init_storage
# for actual hardware use mtd_sdcard as storage device
USEMODULE += mtd_sdcard
endif
USEPKG += fatfs
image:
@tar -xjf riot_fatfs_disk.tar.gz -C ./bin/
#this generates a compressed fat image file that can be used by the fat driver on native
compressed-image:
@./create_fat_image_file.sh $(FATFS_IMAGE_FILE_SIZE_MIB)
include $(RIOTBASE)/Makefile.include

View File

@ -1,27 +1,17 @@
Using FatFs on native
Using FatFs on RIOT
=======================================
To use this test on native you need a FAT image file. The following commands can be used to create such an image and mount it afterwards so you can add files to your virtual disk that can later be accessed from RIOT.
1. create an enpty file with a size of 128MB
`dd if=/dev/zero of=riot_fatfs_disk.img bs=1M count=128`
# native
2. create a FAT file system within the file
`mkfs.fat riot_fatfs_disk.img`
To use this test on native you can either use a FAT-formatted image file or directly use the mkfs command from the RIOT shell.
Use `make image` to extract a prepared image file that already contains a simple test.txt file.
This is only a convinience function to allow testing against a "default linux" formatted fat volume without the need to call mount or other stuff that may require super user privileges.
Optionally `make compressed-image` can be used to generate the compressed image that is in turn used by `make image`.
3. create a mount point which you can use later to add files with your file browser
`sudo mkdir -p /media/riot_fatfs_disk`
To tell RIOT where your image file is located you can use the define `MTD_NATIVE_FILENAME`.
4. give all needed rights for that mountpoint to your user
`sudo chown <your_username> /media/riot_fatfs_disk/`
NOTE: You shouldn't leave the image mounted while you use it in RIOT, the abstraction layer between FatFs and the image file mimics a dumb block device (i.e. behaves much like the devices that are actually meant to be used with FAT) That implies it doesn't show any modifications in RIOT that you perform on your OS and the other way round. So always remember to mount/unmount correctly or your FS will probably get damaged.
5. mount the image -> the disk should now be accessible from any program
`sudo mount -o loop,umask=000 riot_fatfs_disk.img /media/riot_fatfs_disk`
# Real Hardware
6. When you are done -> unmount the disk before you use it under RIOT
`sudo umount /media/riot_fatfs_disk`
#####NOTE:
You shouldn't leave the image mounted while you use it in RIOT, the abstraction layer between FatFs and the image file mimics a dumb block device
(i.e. behaves much like the devices that are actually meant to be used with FAT) That implies it doesn't show any modifications in RIOT that you perform on your OS and the other way round. So always remember to mount/unmount correctly or your FS will probably get damaged.
To tell RIOT where your image file is located you can use the image_path entry in the volume_files array in fatfs_diskio_native/diskio.c.
Currently the test defaults to sdcard_spi on real hardware. But generally any device that supports the mtd-interface can be used with FatFs.

View File

@ -21,7 +21,8 @@
#if FATFS_FFCONF_OPT_FS_NORTC == 0
#include "periph/rtc.h"
#endif
#include "fatfs_diskio_common.h"
#include "mtd.h"
#include "fatfs_diskio_mtd.h"
#include "fatfs/ff.h"
#include "shell.h"
#include <string.h>
@ -47,7 +48,23 @@
#define IEC_KIBI 1024
#define SI_KILO 1000
FATFS fat_fs; /* FatFs work area needed for each volume */
FATFS fat_fs; /* FatFs work area needed for each volume */
#ifdef MODULE_MTD_NATIVE
/* mtd device for native is provided in boards/native/board_init.c */
extern mtd_dev_t *mtd0;
mtd_dev_t *fatfs_mtd_devs[1];
#elif MODULE_MTD_SDCARD
#include "mtd_sdcard.h"
#include "sdcard_spi_params.h"
#define SDCARD_SPI_NUM (sizeof(sdcard_spi_params) / sizeof(sdcard_spi_params[0]))
/* sdcard devs are provided by sys/auto_init/storage/auto_init_sdcard_spi.c */
extern sdcard_spi_t sdcard_spi_devs[SDCARD_SPI_NUM];
mtd_sdcard_t mtd_sdcard_devs[SDCARD_SPI_NUM];
mtd_dev_t *fatfs_mtd_devs[SDCARD_SPI_NUM];
#endif
#define MTD_NUM (sizeof(fatfs_mtd_devs) / sizeof(fatfs_mtd_devs[0]))
static int _mount(int argc, char **argv)
{
@ -58,7 +75,12 @@ static int _mount(int argc, char **argv)
return -1;
}
vol_idx = (int)atoi(argv[1]);
vol_idx = atoi(argv[1]);
if (vol_idx > (int)(MTD_NUM-1)) {
printf("max allowed <volume_idx> is %d\n", (int)(MTD_NUM - 1));
return -1;
}
char volume_str[TEST_FATFS_MAX_VOL_STR_LEN];
sprintf(volume_str, "%d:/", vol_idx);
@ -300,7 +322,7 @@ static int _mkfs(int argc, char **argv)
BYTE opt;
if (argc == 3) {
vol_idx = (int)atoi(argv[1]);
vol_idx = atoi(argv[1]);
if (strcmp(argv[2], "fat") == 0) {
opt = FM_FAT;
@ -320,6 +342,11 @@ static int _mkfs(int argc, char **argv)
return -1;
}
if (vol_idx > (int)(MTD_NUM - 1)) {
printf("max allowed <volume_idx> is %d\n", (int)(MTD_NUM - 1));
return -1;
}
char volume_str[TEST_FATFS_MAX_VOL_STR_LEN];
sprintf(volume_str, "%d:/", vol_idx);
BYTE work[_MAX_SS];
@ -373,6 +400,24 @@ int main(void)
rtc_set_time(&time);
#endif
#if MODULE_MTD_NATIVE
fatfs_mtd_devs[0] = mtd0;
#elif MODULE_MTD_SDCARD
for (unsigned int i = 0; i < SDCARD_SPI_NUM; i++){
mtd_sdcard_devs[i].base.driver = &mtd_sdcard_driver;
mtd_sdcard_devs[i].sd_card = &sdcard_spi_devs[i];
mtd_sdcard_devs[i].params = &sdcard_spi_params[i];
fatfs_mtd_devs[i] = &mtd_sdcard_devs[i].base;
if(mtd_init(&mtd_sdcard_devs[i].base) == 0) {
printf("init sdcard_mtd %u [OK]\n", i);
}else{
printf("init sdcard_mtd %u [FAILED]\n", i);
}
}
#endif
char line_buf[SHELL_DEFAULT_BUFSIZE];
shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE);

View File

@ -2,33 +2,57 @@ APPLICATION = pkg_fatfs_vfs
include ../Makefile.tests_common
USEMODULE += fatfs_vfs
FEATURES_OPTIONAL += periph_rtc
FATFS_DISKIO_NATIVE_DEFAULT_FILE ?= \"./bin/riot_fatfs_disk.img\"
CFLAGS += -DVFS_FILE_BUFFER_SIZE=72 -DVFS_DIR_BUFFER_SIZE=44
# whitelist can be removed when the problem described in #6063 was resolved
# this list is composed of boards that support spi + native
BOARD_WHITELIST := native airfy-beacon arduino-due arduino-duemilanove arduino-mega2560 \
arduino-uno arduino-zero avsextrem cc2538dk fox frdm-k64f iotlab-a8-m3 \
iotlab-m3 limifrog-v1 maple-mini msb-430 msb-430h msba2 msbiot mulle \
nrf52840dk nrf52dk nrf6310 nucleo-f072 nucleo-f091 nucleo-f103 \
nucleo-f302 nucleo-f303 nucleo-f334 nucleo-f401 nucleo-f410 nucleo-f411 \
nucleo-f446 nucleo-l053 nucleo-l073 nucleo-l1 nucleo-l476 nucleo144-f207 \
nucleo144-f303 nucleo144-f413 nucleo144-f429 nucleo144-f446 nucleo32-f031 \
nucleo32-f042 nucleo32-f303 nucleo32-l031 nucleo32-l432 openmote-cc2538 \
pba-d-01-kw2x pca10005 remote-pa remote-reva remote-revb samd21-xpro \
saml21-xpro samr21-xpro sodaq-autonomo spark-core stm32f0discovery \
stm32f3discovery stm32f4discovery telosb udoo waspmote-pro weio \
wsn430-v1_3b wsn430-v1_4 yunjia-nrf51822 z1
FATFS_IMAGE_FILE_SIZE_MIB ?= 128
# export is needed to pass this value to the Makefile of the native_diskio module
export FATFS_DISKIO_NATIVE_DEFAULT_FILE
ifeq ($(BOARD),native)
USEMODULE += mtd_native
#overwrite default mtd_native-config to use fat image as flash device
MTD_NATIVE_FILENAME ?= \"./bin/riot_fatfs_disk.img\"
MTD_NATIVE_PAGE_SIZE ?= 512
MTD_NATIVE_SECTOR_SIZE ?= 512
MTD_NATIVE_SECTOR_NUM ?= \(\(\(FATFS_IMAGE_FILE_SIZE_MIB\)*1024*1024\)/MTD_NATIVE_SECTOR_SIZE\)
CFLAGS += -DMTD_NATIVE_FILENAME=$(MTD_NATIVE_FILENAME)
CFLAGS += -DMTD_NATIVE_PAGE_SIZE=$(MTD_NATIVE_PAGE_SIZE)
CFLAGS += -DMTD_NATIVE_SECTOR_SIZE=$(MTD_NATIVE_SECTOR_SIZE)
CFLAGS += -DFATFS_IMAGE_FILE_SIZE_MIB=$(FATFS_IMAGE_FILE_SIZE_MIB)
CFLAGS += -DMTD_NATIVE_SECTOR_NUM=$(MTD_NATIVE_SECTOR_NUM)
else
USEMODULE += mtd_sdcard
endif
BOARD_INSUFFICIENT_MEMORY := nucleo32-f031
# this list is composed of boards with sufficient memory and support spi/gpio + native
BOARD_WHITELIST := airfy-beacon arduino-due arduino-duemilanove arduino-mega2560 \
arduino-mkr1000 arduino-mkrzero arduino-uno arduino-zero avsextrem \
b-l072z-lrwan1 b-l475e-iot01a bluepill cc2538dk ek-lm4f120xl \
feather-m0 fox frdm-k22f frdm-k64f ikea-tradfri iotlab-a8-m3 \
iotlab-m3 limifrog-v1 maple-mini msb-430 msb-430h msba2 msbiot \
mulle nrf52840dk nrf52dk nrf6310 nucleo144-f207 nucleo144-f303 \
nucleo144-f412 nucleo144-f413 nucleo144-f429 nucleo144-f446 \
nucleo32-f042 nucleo32-f303 nucleo32-l031 \
nucleo32-l432 nucleo-f072 nucleo-f091 nucleo-f103 nucleo-f302 \
nucleo-f303 nucleo-f334 nucleo-f401 nucleo-f410 nucleo-f411 \
nucleo-f446 nucleo-l053 nucleo-l073 nucleo-l152 nucleo-l476 \
nz32-sc151 openmote-cc2538 pba-d-01-kw2x remote-pa remote-reva \
remote-revb samd21-xpro saml21-xpro samr21-xpro sltb001a \
sodaq-autonomo sodaq-explorer spark-core stm32f0discovery \
stm32f3discovery stm32f4discovery telosb udoo waspmote-pro \
wsn430-v1_3b wsn430-v1_4 yunjia-nrf51822 z1 native
include $(RIOTBASE)/Makefile.include
#this generates a compressed fat image file that can be used by the fat driver on native
fatimage:
@./create_fat_image_file.sh
test:
image:
@tar -xjf riot_fatfs_disk.tar.gz -C ./bin/
#this generates a compressed fat image file that can be used by the fat driver on native
compressed-image:
@./create_fat_image_file.sh $(FATFS_IMAGE_FILE_SIZE_MIB)
test: image
./tests/01-run.py

View File

@ -0,0 +1,20 @@
Using FatFs (with VFS) on RIOT
=======================================
# native
To use this test on native you can either use a FAT-formatted image file or directly use the mkfs command from the RIOT shell.
Use `make image` to extract a prepared image file that already contains a simple test.txt file.
This is only a convinience function to allow testing against a "default linux" formatted fat volume without the need to call mount or other stuff that may require super user privileges.
Optionally `make compressed-image` can be used to generate the compressed image that is in turn used by `make image`.
To tell RIOT where your image file is located you can use the define `MTD_NATIVE_FILENAME`.
NOTE: You shouldn't leave the image mounted while you use it in RIOT, the abstraction layer between FatFs and the image file mimics a dumb block device (i.e. behaves much like the devices that are actually meant to be used with FAT) That implies it doesn't show any modifications in RIOT that you perform on your OS and the other way round. So always remember to mount/unmount correctly or your FS will probably get damaged.
# Real Hardware
Currently the test defaults to sdcard_spi on real hardware. But generally any device that supports the mtd-interface can be used with FatFs.
To use the automated test in pkg_fatfs_vfs you need to copy the generated image to your storage device (e.g. your SD-card).
To copy the image onto the card you can use something like `make image && dd if=bin/riot_fatfs_disk.img of=/dev/<your_sdcard>`.
After that you can connect the card to your RIOT device and check the test output via terminal.

View File

@ -6,7 +6,7 @@
# General Public License v2.1. See the file LICENSE in the top level
# directory for more details.
#
dd if=/dev/zero of=riot_fatfs_disk.img bs=1M count=128
dd if=/dev/zero of=riot_fatfs_disk.img bs=1M count=$1
mkfs.fat riot_fatfs_disk.img
sudo mkdir -p /media/riot_fatfs_disk
sudo mount -o loop,umask=000 riot_fatfs_disk.img /media/riot_fatfs_disk

View File

@ -24,6 +24,13 @@
#include "fs/fatfs.h"
#include "vfs.h"
#include "mtd.h"
#ifdef MODULE_MTD_SDCARD
#include "mtd_sdcard.h"
#include "sdcard_spi.h"
#include "sdcard_spi_params.h"
#endif
#if FATFS_FFCONF_OPT_FS_NORTC == 0
#include "periph/rtc.h"
@ -54,6 +61,20 @@ static vfs_mount_t _test_vfs_mount = {
.private_data = (void *)&fatfs,
};
/* provide mtd devices for use within diskio layer of fatfs */
mtd_dev_t *fatfs_mtd_devs[_VOLUMES];
#ifdef MODULE_MTD_NATIVE
/* mtd device for native is provided in boards/native/board_init.c */
extern mtd_dev_t *mtd0;
#elif MODULE_MTD_SDCARD
#define SDCARD_SPI_NUM (sizeof(sdcard_spi_params) / sizeof(sdcard_spi_params[0]))
extern sdcard_spi_t sdcard_spi_devs[SDCARD_SPI_NUM];
mtd_sdcard_t mtd_sdcard_devs[SDCARD_SPI_NUM];
/* always default to first sdcard*/
static mtd_dev_t *mtd1 = (mtd_dev_t*)&mtd_sdcard_devs[0];
#endif
static void print_test_result(const char *test_name, int ok)
{
printf("%s:[%s]\n", test_name, ok ? "OK" : "FAILED");
@ -116,7 +137,7 @@ static void test_rw(void)
/* try to read from WO file (success if no bytes are actually read) */
nr = vfs_read(fd, buf, sizeof(test_txt));
print_test_result("test_rw__read_wo", nw <= 0);
print_test_result("test_rw__read_wo", nr <= 0);
print_test_result("test_rw__close_wo", vfs_close(fd) == 0);
@ -146,7 +167,6 @@ static void test_rw(void)
test_txt2,
sizeof(test_txt2)) == 0));
print_test_result("test_rw__close_rw", vfs_close(fd) == 0);
/* create new file */
@ -273,12 +293,27 @@ static void test_create(void)
print_test_result("test_create__umount", vfs_umount(&_test_vfs_mount) == 0);
}
int main(void)
{
#if FATFS_FFCONF_OPT_FS_NORTC == 0
#if defined(BOARD_NATIVE) && (FATFS_FFCONF_OPT_FS_NORTC == 0)
rtc_init();
#endif
#endif
#if MODULE_MTD_SDCARD
for(unsigned int i = 0; i < SDCARD_SPI_NUM; i++){
mtd_sdcard_devs[i].base.driver = &mtd_sdcard_driver;
mtd_sdcard_devs[i].sd_card = &sdcard_spi_devs[i];
mtd_sdcard_devs[i].params = &sdcard_spi_params[i];
fatfs_mtd_devs[i] = &mtd_sdcard_devs[i].base;
mtd_init(&mtd_sdcard_devs[i].base);
}
#endif
#ifdef MODULE_MTD_NATIVE
fatfs_mtd_devs[fatfs.vol_idx] = mtd0;
#else
fatfs_mtd_devs[fatfs.vol_idx] = mtd1;
#endif
printf("Tests for FatFs over VFS - test results will be printed "
"in the format test_name:result\n");
@ -293,6 +328,5 @@ int main(void)
test_create();
printf("Test end.\n");
return 0;
}

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# Copyright (C) 2017 HAW-Hamburg.de
#
@ -9,28 +9,28 @@
import os
import sys
sys.path.append(os.path.join(os.environ['RIOTBASE'], 'dist/tools/testrunner'))
import testrunner
from datetime import datetime
class TestFailed(Exception):
pass
def testfunc(child):
child.expect(u"Tests for FatFs over VFS - test results will be printed in "
"the format test_name:result\r\n")
"the format test_name:result\r\n")
while True:
res = child.expect([u"[^\n]*:\[OK\]\r\n",
u"Test end.\r\n",
u".[^\n]*:\[FAILED\]\r\n" ,
u".[^\n]*:\[FAILED\]\r\n",
u".*\r\n"])
if res > 1:
raise TestFailed(child.after.split(':',1)[0] + " test failed!")
raise TestFailed(child.after.split(':', 1)[0] + " test failed!")
elif res == 1:
break;
break
if __name__ == "__main__":
sys.path.append(os.path.join(os.environ['RIOTBASE'], 'dist/tools/testrunner'))
import testrunner
sys.exit(testrunner.run(testfunc))