SD Driver: reinit sd card on error (#2493)
* SD Driver: reinit sd card on error * SD Driver: cleanup fatfs bindings * Storage: optimized glue * Storage: move fatfs initialization to appropriate subsystems, minor code cleanup * SD Driver: minor code cleanup Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
parent
6ec62f48f9
commit
f7024cff78
@ -73,29 +73,34 @@ uint32_t storage_data_get_timestamp(StorageData* storage) {
|
|||||||
|
|
||||||
/****************** storage glue ******************/
|
/****************** storage glue ******************/
|
||||||
|
|
||||||
bool storage_has_file(const File* file, StorageData* storage_data) {
|
static StorageFile* storage_get_file(const File* file, StorageData* storage) {
|
||||||
bool result = false;
|
StorageFile* storage_file_ref = NULL;
|
||||||
|
|
||||||
StorageFileList_it_t it;
|
StorageFileList_it_t it;
|
||||||
for(StorageFileList_it(it, storage_data->files); !StorageFileList_end_p(it);
|
for(StorageFileList_it(it, storage->files); !StorageFileList_end_p(it);
|
||||||
StorageFileList_next(it)) {
|
StorageFileList_next(it)) {
|
||||||
const StorageFile* storage_file = StorageFileList_cref(it);
|
StorageFile* storage_file = StorageFileList_ref(it);
|
||||||
|
|
||||||
if(storage_file->file->file_id == file->file_id) {
|
if(storage_file->file->file_id == file->file_id) {
|
||||||
result = true;
|
storage_file_ref = storage_file;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return storage_file_ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool storage_path_already_open(FuriString* path, StorageFileList_t array) {
|
bool storage_has_file(const File* file, StorageData* storage) {
|
||||||
|
return storage_get_file(file, storage) != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool storage_path_already_open(FuriString* path, StorageData* storage) {
|
||||||
bool open = false;
|
bool open = false;
|
||||||
|
|
||||||
StorageFileList_it_t it;
|
StorageFileList_it_t it;
|
||||||
|
|
||||||
for(StorageFileList_it(it, array); !StorageFileList_end_p(it); StorageFileList_next(it)) {
|
for(StorageFileList_it(it, storage->files); !StorageFileList_end_p(it);
|
||||||
|
StorageFileList_next(it)) {
|
||||||
const StorageFile* storage_file = StorageFileList_cref(it);
|
const StorageFile* storage_file = StorageFileList_cref(it);
|
||||||
|
|
||||||
if(furi_string_cmp(storage_file->path, path) == 0) {
|
if(furi_string_cmp(storage_file->path, path) == 0) {
|
||||||
@ -108,43 +113,15 @@ bool storage_path_already_open(FuriString* path, StorageFileList_t array) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void storage_set_storage_file_data(const File* file, void* file_data, StorageData* storage) {
|
void storage_set_storage_file_data(const File* file, void* file_data, StorageData* storage) {
|
||||||
StorageFile* founded_file = NULL;
|
StorageFile* storage_file_ref = storage_get_file(file, storage);
|
||||||
|
furi_check(storage_file_ref != NULL);
|
||||||
StorageFileList_it_t it;
|
storage_file_ref->file_data = file_data;
|
||||||
|
|
||||||
for(StorageFileList_it(it, storage->files); !StorageFileList_end_p(it);
|
|
||||||
StorageFileList_next(it)) {
|
|
||||||
StorageFile* storage_file = StorageFileList_ref(it);
|
|
||||||
|
|
||||||
if(storage_file->file->file_id == file->file_id) {
|
|
||||||
founded_file = storage_file;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
furi_check(founded_file != NULL);
|
|
||||||
|
|
||||||
founded_file->file_data = file_data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void* storage_get_storage_file_data(const File* file, StorageData* storage) {
|
void* storage_get_storage_file_data(const File* file, StorageData* storage) {
|
||||||
const StorageFile* founded_file = NULL;
|
StorageFile* storage_file_ref = storage_get_file(file, storage);
|
||||||
|
furi_check(storage_file_ref != NULL);
|
||||||
StorageFileList_it_t it;
|
return storage_file_ref->file_data;
|
||||||
|
|
||||||
for(StorageFileList_it(it, storage->files); !StorageFileList_end_p(it);
|
|
||||||
StorageFileList_next(it)) {
|
|
||||||
const StorageFile* storage_file = StorageFileList_cref(it);
|
|
||||||
|
|
||||||
if(storage_file->file->file_id == file->file_id) {
|
|
||||||
founded_file = storage_file;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
furi_check(founded_file != NULL);
|
|
||||||
|
|
||||||
return founded_file->file_data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void storage_push_storage_file(File* file, FuriString* path, StorageData* storage) {
|
void storage_push_storage_file(File* file, FuriString* path, StorageData* storage) {
|
||||||
|
@ -60,7 +60,7 @@ struct StorageData {
|
|||||||
};
|
};
|
||||||
|
|
||||||
bool storage_has_file(const File* file, StorageData* storage_data);
|
bool storage_has_file(const File* file, StorageData* storage_data);
|
||||||
bool storage_path_already_open(FuriString* path, StorageFileList_t files);
|
bool storage_path_already_open(FuriString* path, StorageData* storage_data);
|
||||||
|
|
||||||
void storage_set_storage_file_data(const File* file, void* file_data, StorageData* storage);
|
void storage_set_storage_file_data(const File* file, void* file_data, StorageData* storage);
|
||||||
void* storage_get_storage_file_data(const File* file, StorageData* storage);
|
void* storage_get_storage_file_data(const File* file, StorageData* storage);
|
||||||
|
@ -77,7 +77,7 @@ static void storage_path_change_to_real_storage(FuriString* path, StorageType re
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FS_Error storage_get_data(Storage* app, FuriString* path, StorageData** storage) {
|
static FS_Error storage_get_data(Storage* app, FuriString* path, StorageData** storage) {
|
||||||
StorageType type = storage_get_type_by_path(path);
|
StorageType type = storage_get_type_by_path(path);
|
||||||
|
|
||||||
if(storage_type_is_valid(type)) {
|
if(storage_type_is_valid(type)) {
|
||||||
@ -111,7 +111,7 @@ bool storage_process_file_open(
|
|||||||
file->error_id = storage_get_data(app, path, &storage);
|
file->error_id = storage_get_data(app, path, &storage);
|
||||||
|
|
||||||
if(file->error_id == FSE_OK) {
|
if(file->error_id == FSE_OK) {
|
||||||
if(storage_path_already_open(path, storage->files)) {
|
if(storage_path_already_open(path, storage)) {
|
||||||
file->error_id = FSE_ALREADY_OPEN;
|
file->error_id = FSE_ALREADY_OPEN;
|
||||||
} else {
|
} else {
|
||||||
if(access_mode & FSAM_WRITE) {
|
if(access_mode & FSAM_WRITE) {
|
||||||
@ -268,7 +268,7 @@ bool storage_process_dir_open(Storage* app, File* file, FuriString* path) {
|
|||||||
file->error_id = storage_get_data(app, path, &storage);
|
file->error_id = storage_get_data(app, path, &storage);
|
||||||
|
|
||||||
if(file->error_id == FSE_OK) {
|
if(file->error_id == FSE_OK) {
|
||||||
if(storage_path_already_open(path, storage->files)) {
|
if(storage_path_already_open(path, storage)) {
|
||||||
file->error_id = FSE_ALREADY_OPEN;
|
file->error_id = FSE_ALREADY_OPEN;
|
||||||
} else {
|
} else {
|
||||||
storage_push_storage_file(file, path, storage);
|
storage_push_storage_file(file, path, storage);
|
||||||
@ -357,7 +357,7 @@ static FS_Error storage_process_common_remove(Storage* app, FuriString* path) {
|
|||||||
FS_Error ret = storage_get_data(app, path, &storage);
|
FS_Error ret = storage_get_data(app, path, &storage);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if(storage_path_already_open(path, storage->files)) {
|
if(storage_path_already_open(path, storage)) {
|
||||||
ret = FSE_ALREADY_OPEN;
|
ret = FSE_ALREADY_OPEN;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -618,8 +618,10 @@ static const FS_Api fs_api = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
void storage_ext_init(StorageData* storage) {
|
void storage_ext_init(StorageData* storage) {
|
||||||
|
fatfs_init();
|
||||||
|
|
||||||
SDData* sd_data = malloc(sizeof(SDData));
|
SDData* sd_data = malloc(sizeof(SDData));
|
||||||
sd_data->fs = &USERFatFS;
|
sd_data->fs = &fatfs_object;
|
||||||
sd_data->path = "0:/";
|
sd_data->path = "0:/";
|
||||||
sd_data->sd_was_present = true;
|
sd_data->sd_was_present = true;
|
||||||
|
|
||||||
|
@ -3,8 +3,6 @@
|
|||||||
|
|
||||||
#include <stm32wbxx_ll_cortex.h>
|
#include <stm32wbxx_ll_cortex.h>
|
||||||
|
|
||||||
#include <fatfs.h>
|
|
||||||
|
|
||||||
#define TAG "FuriHal"
|
#define TAG "FuriHal"
|
||||||
|
|
||||||
void furi_hal_init_early() {
|
void furi_hal_init_early() {
|
||||||
@ -74,10 +72,6 @@ void furi_hal_init() {
|
|||||||
#endif
|
#endif
|
||||||
furi_hal_bt_init();
|
furi_hal_bt_init();
|
||||||
furi_hal_compress_icon_init();
|
furi_hal_compress_icon_init();
|
||||||
|
|
||||||
// FatFS driver initialization
|
|
||||||
MX_FATFS_Init();
|
|
||||||
FURI_LOG_I(TAG, "FATFS OK");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void furi_hal_switch(void* address) {
|
void furi_hal_switch(void* address) {
|
||||||
|
@ -1,39 +1,12 @@
|
|||||||
/**
|
|
||||||
******************************************************************************
|
|
||||||
* @file fatfs.c
|
|
||||||
* @brief Code for fatfs applications
|
|
||||||
******************************************************************************
|
|
||||||
* @attention
|
|
||||||
*
|
|
||||||
* <h2><center>© Copyright (c) 2020 STMicroelectronics.
|
|
||||||
* All rights reserved.</center></h2>
|
|
||||||
*
|
|
||||||
* This software component is licensed by ST under Ultimate Liberty license
|
|
||||||
* SLA0044, the "License"; You may not use this file except in compliance with
|
|
||||||
* the License. You may obtain a copy of the License at:
|
|
||||||
* www.st.com/SLA0044
|
|
||||||
*
|
|
||||||
******************************************************************************
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "fatfs.h"
|
#include "fatfs.h"
|
||||||
|
|
||||||
uint8_t retUSER; /* Return value for USER */
|
/** logical drive path */
|
||||||
char USERPath[4]; /* USER logical drive path */
|
char fatfs_path[4];
|
||||||
FATFS USERFatFS; /* File system object for USER logical drive */
|
/** File system object */
|
||||||
FIL USERFile; /* File object for USER */
|
FATFS fatfs_object;
|
||||||
|
|
||||||
/* USER CODE BEGIN Variables */
|
void fatfs_init(void) {
|
||||||
|
FATFS_LinkDriver(&sd_fatfs_driver, fatfs_path);
|
||||||
/* USER CODE END Variables */
|
|
||||||
|
|
||||||
void MX_FATFS_Init(void) {
|
|
||||||
/*## FatFS: Link the USER driver ###########################*/
|
|
||||||
retUSER = FATFS_LinkDriver(&USER_Driver, USERPath);
|
|
||||||
|
|
||||||
/* USER CODE BEGIN Init */
|
|
||||||
/* additional user code for init */
|
|
||||||
/* USER CODE END Init */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -42,13 +15,5 @@ void MX_FATFS_Init(void) {
|
|||||||
* @retval Time in DWORD
|
* @retval Time in DWORD
|
||||||
*/
|
*/
|
||||||
DWORD get_fattime(void) {
|
DWORD get_fattime(void) {
|
||||||
/* USER CODE BEGIN get_fattime */
|
|
||||||
return 0;
|
return 0;
|
||||||
/* USER CODE END get_fattime */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* USER CODE BEGIN Application */
|
|
||||||
|
|
||||||
/* USER CODE END Application */
|
|
||||||
|
|
||||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
|
||||||
|
@ -1,49 +1,19 @@
|
|||||||
/**
|
#pragma once
|
||||||
******************************************************************************
|
|
||||||
* @file fatfs.h
|
#include "fatfs/ff.h"
|
||||||
* @brief Header for fatfs applications
|
#include "fatfs/ff_gen_drv.h"
|
||||||
******************************************************************************
|
#include "user_diskio.h"
|
||||||
* @attention
|
|
||||||
*
|
|
||||||
* <h2><center>© Copyright (c) 2020 STMicroelectronics.
|
|
||||||
* All rights reserved.</center></h2>
|
|
||||||
*
|
|
||||||
* This software component is licensed by ST under Ultimate Liberty license
|
|
||||||
* SLA0044, the "License"; You may not use this file except in compliance with
|
|
||||||
* the License. You may obtain a copy of the License at:
|
|
||||||
* www.st.com/SLA0044
|
|
||||||
*
|
|
||||||
******************************************************************************
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
|
||||||
#ifndef __fatfs_H
|
|
||||||
#define __fatfs_H
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "fatfs/ff.h"
|
/** File system object */
|
||||||
#include "fatfs/ff_gen_drv.h"
|
extern FATFS fatfs_object;
|
||||||
#include "user_diskio.h" /* defines USER_Driver as external */
|
|
||||||
|
|
||||||
/* USER CODE BEGIN Includes */
|
/** Init file system driver */
|
||||||
|
void fatfs_init(void);
|
||||||
|
|
||||||
/* USER CODE END Includes */
|
|
||||||
|
|
||||||
extern uint8_t retUSER; /* Return value for USER */
|
|
||||||
extern char USERPath[4]; /* USER logical drive path */
|
|
||||||
extern FATFS USERFatFS; /* File system object for USER logical drive */
|
|
||||||
extern FIL USERFile; /* File object for USER */
|
|
||||||
|
|
||||||
void MX_FATFS_Init(void);
|
|
||||||
|
|
||||||
/* USER CODE BEGIN Prototypes */
|
|
||||||
|
|
||||||
/* USER CODE END Prototypes */
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif /*__fatfs_H */
|
|
||||||
|
|
||||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
|
@ -164,7 +164,7 @@
|
|||||||
|
|
||||||
/* USER CODE BEGIN Volumes */
|
/* USER CODE BEGIN Volumes */
|
||||||
#define _STR_VOLUME_ID 0 /* 0:Use only 0-9 for drive ID, 1:Use strings for drive ID */
|
#define _STR_VOLUME_ID 0 /* 0:Use only 0-9 for drive ID, 1:Use strings for drive ID */
|
||||||
#define _VOLUME_STRS "RAM", "NAND", "CF", "SD1", "SD2", "USB1", "USB2", "USB3"
|
#define _VOLUME_STRS "SD"
|
||||||
/* _STR_VOLUME_ID switches string support of volume ID.
|
/* _STR_VOLUME_ID switches string support of volume ID.
|
||||||
/ When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive
|
/ When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive
|
||||||
/ number in the path name. _VOLUME_STRS defines the drive ID strings for each
|
/ number in the path name. _VOLUME_STRS defines the drive ID strings for each
|
||||||
|
@ -1,116 +0,0 @@
|
|||||||
/*------------------------------------------------------------------------*/
|
|
||||||
/* Sample code of OS dependent controls for FatFs */
|
|
||||||
/* (C)ChaN, 2014 */
|
|
||||||
/* Portions COPYRIGHT 2017 STMicroelectronics */
|
|
||||||
/* Portions Copyright (C) 2014, ChaN, all right reserved */
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
******************************************************************************
|
|
||||||
* @attention
|
|
||||||
*
|
|
||||||
* Copyright (c) 2017 STMicroelectronics. All rights reserved.
|
|
||||||
*
|
|
||||||
* This software component is licensed by ST under BSD 3-Clause license,
|
|
||||||
* the "License"; You may not use this file except in compliance with the
|
|
||||||
* License. You may obtain a copy of the License at:
|
|
||||||
* opensource.org/licenses/BSD-3-Clause
|
|
||||||
*
|
|
||||||
******************************************************************************
|
|
||||||
**/
|
|
||||||
|
|
||||||
#include "fatfs/ff.h"
|
|
||||||
|
|
||||||
#if _FS_REENTRANT
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
/* Create a Synchronization Object */
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
/* This function is called in f_mount() function to create a new
|
|
||||||
/ synchronization object, such as semaphore and mutex. When a 0 is returned,
|
|
||||||
/ the f_mount() function fails with FR_INT_ERR.
|
|
||||||
*/
|
|
||||||
|
|
||||||
int ff_cre_syncobj(/* 1:Function succeeded, 0:Could not create the sync object */
|
|
||||||
BYTE vol, /* Corresponding volume (logical drive number) */
|
|
||||||
_SYNC_t* sobj /* Pointer to return the created sync object */
|
|
||||||
) {
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
//osSemaphoreDef(SEM);
|
|
||||||
//*sobj = osSemaphoreCreate(osSemaphore(SEM), 1);
|
|
||||||
*sobj = furi_mutex_alloc(FuriMutexTypeNormal);
|
|
||||||
ret = (*sobj != NULL);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
/* Delete a Synchronization Object */
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
/* This function is called in f_mount() function to delete a synchronization
|
|
||||||
/ object that created with ff_cre_syncobj() function. When a 0 is returned,
|
|
||||||
/ the f_mount() function fails with FR_INT_ERR.
|
|
||||||
*/
|
|
||||||
|
|
||||||
int ff_del_syncobj(/* 1:Function succeeded, 0:Could not delete due to any error */
|
|
||||||
_SYNC_t sobj /* Sync object tied to the logical drive to be deleted */
|
|
||||||
) {
|
|
||||||
furi_mutex_free(sobj);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
/* Request Grant to Access the Volume */
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
/* This function is called on entering file functions to lock the volume.
|
|
||||||
/ When a 0 is returned, the file function fails with FR_TIMEOUT.
|
|
||||||
*/
|
|
||||||
|
|
||||||
int ff_req_grant(/* 1:Got a grant to access the volume, 0:Could not get a grant */
|
|
||||||
_SYNC_t sobj /* Sync object to wait */
|
|
||||||
) {
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
if(furi_mutex_acquire(sobj, _FS_TIMEOUT) == FuriStatusOk) {
|
|
||||||
ret = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
/* Release Grant to Access the Volume */
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
/* This function is called on leaving file functions to unlock the volume.
|
|
||||||
*/
|
|
||||||
|
|
||||||
void ff_rel_grant(_SYNC_t sobj /* Sync object to be signaled */
|
|
||||||
) {
|
|
||||||
furi_mutex_release(sobj);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if _USE_LFN == 3 /* LFN with a working buffer on the heap */
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
/* Allocate a memory block */
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
/* If a NULL is returned, the file function fails with FR_NOT_ENOUGH_CORE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
void* ff_memalloc(/* Returns pointer to the allocated memory block */
|
|
||||||
UINT msize /* Number of bytes to allocate */
|
|
||||||
) {
|
|
||||||
return ff_malloc(msize); /* Allocate a new memory block with POSIX API */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
/* Free a memory block */
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
void ff_memfree(void* mblock /* Pointer to the memory block to free */
|
|
||||||
) {
|
|
||||||
ff_free(mblock); /* Discard the memory block with POSIX API */
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,50 +1,10 @@
|
|||||||
/* USER CODE BEGIN Header */
|
|
||||||
/**
|
|
||||||
******************************************************************************
|
|
||||||
* @file user_diskio.c
|
|
||||||
* @brief This file includes a diskio driver skeleton to be completed by the user.
|
|
||||||
******************************************************************************
|
|
||||||
* @attention
|
|
||||||
*
|
|
||||||
* <h2><center>© Copyright (c) 2020 STMicroelectronics.
|
|
||||||
* All rights reserved.</center></h2>
|
|
||||||
*
|
|
||||||
* This software component is licensed by ST under Ultimate Liberty license
|
|
||||||
* SLA0044, the "License"; You may not use this file except in compliance with
|
|
||||||
* the License. You may obtain a copy of the License at:
|
|
||||||
* www.st.com/SLA0044
|
|
||||||
*
|
|
||||||
******************************************************************************
|
|
||||||
*/
|
|
||||||
/* USER CODE END Header */
|
|
||||||
|
|
||||||
#ifdef USE_OBSOLETE_USER_CODE_SECTION_0
|
|
||||||
/*
|
|
||||||
* Warning: the user section 0 is no more in use (starting from CubeMx version 4.16.0)
|
|
||||||
* To be suppressed in the future.
|
|
||||||
* Kept to ensure backward compatibility with previous CubeMx versions when
|
|
||||||
* migrating projects.
|
|
||||||
* User code previously added there should be copied in the new user sections before
|
|
||||||
* the section contents can be deleted.
|
|
||||||
*/
|
|
||||||
/* USER CODE BEGIN 0 */
|
|
||||||
/* USER CODE END 0 */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* USER CODE BEGIN DECL */
|
|
||||||
|
|
||||||
/* Includes ------------------------------------------------------------------*/
|
|
||||||
#include "user_diskio.h"
|
#include "user_diskio.h"
|
||||||
#include <furi_hal.h>
|
#include <furi_hal.h>
|
||||||
#include "sector_cache.h"
|
#include "sector_cache.h"
|
||||||
/* Private typedef -----------------------------------------------------------*/
|
|
||||||
/* Private define ------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/* Private variables ---------------------------------------------------------*/
|
|
||||||
/* Disk status */
|
|
||||||
static volatile DSTATUS Stat = STA_NOINIT;
|
static volatile DSTATUS Stat = STA_NOINIT;
|
||||||
|
|
||||||
static DSTATUS User_CheckStatus(BYTE lun) {
|
static DSTATUS driver_check_status(BYTE lun) {
|
||||||
UNUSED(lun);
|
UNUSED(lun);
|
||||||
Stat = STA_NOINIT;
|
Stat = STA_NOINIT;
|
||||||
if(sd_get_card_state() == SdSpiStatusOK) {
|
if(sd_get_card_state() == SdSpiStatusOK) {
|
||||||
@ -54,32 +14,20 @@ static DSTATUS User_CheckStatus(BYTE lun) {
|
|||||||
return Stat;
|
return Stat;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* USER CODE END DECL */
|
static DSTATUS driver_initialize(BYTE pdrv);
|
||||||
|
static DSTATUS driver_status(BYTE pdrv);
|
||||||
|
static DRESULT driver_read(BYTE pdrv, BYTE* buff, DWORD sector, UINT count);
|
||||||
|
static DRESULT driver_write(BYTE pdrv, const BYTE* buff, DWORD sector, UINT count);
|
||||||
|
static DRESULT driver_ioctl(BYTE pdrv, BYTE cmd, void* buff);
|
||||||
|
|
||||||
/* Private function prototypes -----------------------------------------------*/
|
Diskio_drvTypeDef sd_fatfs_driver = {
|
||||||
DSTATUS USER_initialize(BYTE pdrv);
|
driver_initialize,
|
||||||
DSTATUS USER_status(BYTE pdrv);
|
driver_status,
|
||||||
DRESULT USER_read(BYTE pdrv, BYTE* buff, DWORD sector, UINT count);
|
driver_read,
|
||||||
#if _USE_WRITE == 1
|
driver_write,
|
||||||
DRESULT USER_write(BYTE pdrv, const BYTE* buff, DWORD sector, UINT count);
|
driver_ioctl,
|
||||||
#endif /* _USE_WRITE == 1 */
|
|
||||||
#if _USE_IOCTL == 1
|
|
||||||
DRESULT USER_ioctl(BYTE pdrv, BYTE cmd, void* buff);
|
|
||||||
#endif /* _USE_IOCTL == 1 */
|
|
||||||
|
|
||||||
Diskio_drvTypeDef USER_Driver = {
|
|
||||||
USER_initialize,
|
|
||||||
USER_status,
|
|
||||||
USER_read,
|
|
||||||
#if _USE_WRITE
|
|
||||||
USER_write,
|
|
||||||
#endif /* _USE_WRITE == 1 */
|
|
||||||
#if _USE_IOCTL == 1
|
|
||||||
USER_ioctl,
|
|
||||||
#endif /* _USE_IOCTL == 1 */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Private functions ---------------------------------------------------------*/
|
|
||||||
static inline bool sd_cache_get(uint32_t address, uint32_t* data) {
|
static inline bool sd_cache_get(uint32_t address, uint32_t* data) {
|
||||||
uint8_t* cached_data = sector_cache_get(address);
|
uint8_t* cached_data = sector_cache_get(address);
|
||||||
if(cached_data) {
|
if(cached_data) {
|
||||||
@ -101,24 +49,73 @@ static inline void sd_cache_invalidate_all() {
|
|||||||
sector_cache_init();
|
sector_cache_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool sd_device_read(uint32_t* buff, uint32_t sector, uint32_t count) {
|
||||||
|
bool result = false;
|
||||||
|
|
||||||
|
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_sd_fast);
|
||||||
|
furi_hal_sd_spi_handle = &furi_hal_spi_bus_handle_sd_fast;
|
||||||
|
|
||||||
|
if(sd_read_blocks(buff, sector, count, SD_TIMEOUT_MS) == SdSpiStatusOK) {
|
||||||
|
FuriHalCortexTimer timer = furi_hal_cortex_timer_get(SD_TIMEOUT_MS * 1000);
|
||||||
|
|
||||||
|
/* wait until the read operation is finished */
|
||||||
|
result = true;
|
||||||
|
while(sd_get_card_state() != SdSpiStatusOK) {
|
||||||
|
if(furi_hal_cortex_timer_is_expired(timer)) {
|
||||||
|
result = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
furi_hal_sd_spi_handle = NULL;
|
||||||
|
furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_fast);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool sd_device_write(uint32_t* buff, uint32_t sector, uint32_t count) {
|
||||||
|
bool result = false;
|
||||||
|
|
||||||
|
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_sd_fast);
|
||||||
|
furi_hal_sd_spi_handle = &furi_hal_spi_bus_handle_sd_fast;
|
||||||
|
|
||||||
|
if(sd_write_blocks(buff, sector, count, SD_TIMEOUT_MS) == SdSpiStatusOK) {
|
||||||
|
FuriHalCortexTimer timer = furi_hal_cortex_timer_get(SD_TIMEOUT_MS * 1000);
|
||||||
|
|
||||||
|
/* wait until the Write operation is finished */
|
||||||
|
result = true;
|
||||||
|
while(sd_get_card_state() != SdSpiStatusOK) {
|
||||||
|
if(furi_hal_cortex_timer_is_expired(timer)) {
|
||||||
|
sd_cache_invalidate_all();
|
||||||
|
|
||||||
|
result = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
furi_hal_sd_spi_handle = NULL;
|
||||||
|
furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_fast);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Initializes a Drive
|
* @brief Initializes a Drive
|
||||||
* @param pdrv: Physical drive number (0..)
|
* @param pdrv: Physical drive number (0..)
|
||||||
* @retval DSTATUS: Operation status
|
* @retval DSTATUS: Operation status
|
||||||
*/
|
*/
|
||||||
DSTATUS USER_initialize(BYTE pdrv) {
|
static DSTATUS driver_initialize(BYTE pdrv) {
|
||||||
/* USER CODE BEGIN INIT */
|
|
||||||
|
|
||||||
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_sd_fast);
|
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_sd_fast);
|
||||||
furi_hal_sd_spi_handle = &furi_hal_spi_bus_handle_sd_fast;
|
furi_hal_sd_spi_handle = &furi_hal_spi_bus_handle_sd_fast;
|
||||||
|
|
||||||
DSTATUS status = User_CheckStatus(pdrv);
|
DSTATUS status = driver_check_status(pdrv);
|
||||||
|
|
||||||
furi_hal_sd_spi_handle = NULL;
|
furi_hal_sd_spi_handle = NULL;
|
||||||
furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_fast);
|
furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_fast);
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
/* USER CODE END INIT */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -126,11 +123,9 @@ DSTATUS USER_initialize(BYTE pdrv) {
|
|||||||
* @param pdrv: Physical drive number (0..)
|
* @param pdrv: Physical drive number (0..)
|
||||||
* @retval DSTATUS: Operation status
|
* @retval DSTATUS: Operation status
|
||||||
*/
|
*/
|
||||||
DSTATUS USER_status(BYTE pdrv) {
|
static DSTATUS driver_status(BYTE pdrv) {
|
||||||
/* USER CODE BEGIN STATUS */
|
|
||||||
UNUSED(pdrv);
|
UNUSED(pdrv);
|
||||||
return Stat;
|
return Stat;
|
||||||
/* USER CODE END STATUS */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -141,11 +136,10 @@ DSTATUS USER_status(BYTE pdrv) {
|
|||||||
* @param count: Number of sectors to read (1..128)
|
* @param count: Number of sectors to read (1..128)
|
||||||
* @retval DRESULT: Operation result
|
* @retval DRESULT: Operation result
|
||||||
*/
|
*/
|
||||||
DRESULT USER_read(BYTE pdrv, BYTE* buff, DWORD sector, UINT count) {
|
static DRESULT driver_read(BYTE pdrv, BYTE* buff, DWORD sector, UINT count) {
|
||||||
/* USER CODE BEGIN READ */
|
|
||||||
UNUSED(pdrv);
|
UNUSED(pdrv);
|
||||||
DRESULT res = RES_ERROR;
|
|
||||||
|
|
||||||
|
bool result;
|
||||||
bool single_sector = count == 1;
|
bool single_sector = count == 1;
|
||||||
|
|
||||||
if(single_sector) {
|
if(single_sector) {
|
||||||
@ -154,32 +148,33 @@ DRESULT USER_read(BYTE pdrv, BYTE* buff, DWORD sector, UINT count) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_sd_fast);
|
result = sd_device_read((uint32_t*)buff, (uint32_t)(sector), count);
|
||||||
furi_hal_sd_spi_handle = &furi_hal_spi_bus_handle_sd_fast;
|
|
||||||
|
|
||||||
if(sd_read_blocks((uint32_t*)buff, (uint32_t)(sector), count, SD_TIMEOUT_MS) ==
|
if(!result) {
|
||||||
SdSpiStatusOK) {
|
uint8_t counter = sd_max_mount_retry_count();
|
||||||
FuriHalCortexTimer timer = furi_hal_cortex_timer_get(SD_TIMEOUT_MS * 1000);
|
|
||||||
|
|
||||||
/* wait until the read operation is finished */
|
while(result == false && counter > 0 && hal_sd_detect()) {
|
||||||
res = RES_OK;
|
SdSpiStatus status;
|
||||||
while(sd_get_card_state() != SdSpiStatusOK) {
|
|
||||||
if(furi_hal_cortex_timer_is_expired(timer)) {
|
if((counter % 2) == 0) {
|
||||||
res = RES_ERROR;
|
// power reset sd card
|
||||||
break;
|
status = sd_init(true);
|
||||||
|
} else {
|
||||||
|
status = sd_init(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(status == SdSpiStatusOK) {
|
||||||
|
result = sd_device_read((uint32_t*)buff, (uint32_t)(sector), count);
|
||||||
|
}
|
||||||
|
counter--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
furi_hal_sd_spi_handle = NULL;
|
if(single_sector && result == true) {
|
||||||
furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_fast);
|
|
||||||
|
|
||||||
if(single_sector && res == RES_OK) {
|
|
||||||
sd_cache_put(sector, (uint32_t*)buff);
|
sd_cache_put(sector, (uint32_t*)buff);
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return result ? RES_OK : RES_ERROR;
|
||||||
/* USER CODE END READ */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -190,41 +185,36 @@ DRESULT USER_read(BYTE pdrv, BYTE* buff, DWORD sector, UINT count) {
|
|||||||
* @param count: Number of sectors to write (1..128)
|
* @param count: Number of sectors to write (1..128)
|
||||||
* @retval DRESULT: Operation result
|
* @retval DRESULT: Operation result
|
||||||
*/
|
*/
|
||||||
#if _USE_WRITE == 1
|
static DRESULT driver_write(BYTE pdrv, const BYTE* buff, DWORD sector, UINT count) {
|
||||||
DRESULT USER_write(BYTE pdrv, const BYTE* buff, DWORD sector, UINT count) {
|
|
||||||
/* USER CODE BEGIN WRITE */
|
|
||||||
/* USER CODE HERE */
|
|
||||||
UNUSED(pdrv);
|
UNUSED(pdrv);
|
||||||
DRESULT res = RES_ERROR;
|
bool result;
|
||||||
|
|
||||||
sd_cache_invalidate_range(sector, sector + count);
|
sd_cache_invalidate_range(sector, sector + count);
|
||||||
|
|
||||||
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_sd_fast);
|
result = sd_device_write((uint32_t*)buff, (uint32_t)(sector), count);
|
||||||
furi_hal_sd_spi_handle = &furi_hal_spi_bus_handle_sd_fast;
|
|
||||||
|
|
||||||
if(sd_write_blocks((uint32_t*)buff, (uint32_t)(sector), count, SD_TIMEOUT_MS) ==
|
if(!result) {
|
||||||
SdSpiStatusOK) {
|
uint8_t counter = sd_max_mount_retry_count();
|
||||||
FuriHalCortexTimer timer = furi_hal_cortex_timer_get(SD_TIMEOUT_MS * 1000);
|
|
||||||
|
|
||||||
/* wait until the Write operation is finished */
|
while(result == false && counter > 0 && hal_sd_detect()) {
|
||||||
res = RES_OK;
|
SdSpiStatus status;
|
||||||
while(sd_get_card_state() != SdSpiStatusOK) {
|
|
||||||
if(furi_hal_cortex_timer_is_expired(timer)) {
|
|
||||||
sd_cache_invalidate_all();
|
|
||||||
|
|
||||||
res = RES_ERROR;
|
if((counter % 2) == 0) {
|
||||||
break;
|
// power reset sd card
|
||||||
|
status = sd_init(true);
|
||||||
|
} else {
|
||||||
|
status = sd_init(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(status == SdSpiStatusOK) {
|
||||||
|
result = sd_device_write((uint32_t*)buff, (uint32_t)(sector), count);
|
||||||
|
}
|
||||||
|
counter--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
furi_hal_sd_spi_handle = NULL;
|
return result ? RES_OK : RES_ERROR;
|
||||||
furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_fast);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
/* USER CODE END WRITE */
|
|
||||||
}
|
}
|
||||||
#endif /* _USE_WRITE == 1 */
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief I/O control operation
|
* @brief I/O control operation
|
||||||
@ -233,9 +223,7 @@ DRESULT USER_write(BYTE pdrv, const BYTE* buff, DWORD sector, UINT count) {
|
|||||||
* @param *buff: Buffer to send/receive control data
|
* @param *buff: Buffer to send/receive control data
|
||||||
* @retval DRESULT: Operation result
|
* @retval DRESULT: Operation result
|
||||||
*/
|
*/
|
||||||
#if _USE_IOCTL == 1
|
static DRESULT driver_ioctl(BYTE pdrv, BYTE cmd, void* buff) {
|
||||||
DRESULT USER_ioctl(BYTE pdrv, BYTE cmd, void* buff) {
|
|
||||||
/* USER CODE BEGIN IOCTL */
|
|
||||||
UNUSED(pdrv);
|
UNUSED(pdrv);
|
||||||
DRESULT res = RES_ERROR;
|
DRESULT res = RES_ERROR;
|
||||||
SD_CardInfo CardInfo;
|
SD_CardInfo CardInfo;
|
||||||
@ -280,8 +268,4 @@ DRESULT USER_ioctl(BYTE pdrv, BYTE cmd, void* buff) {
|
|||||||
furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_fast);
|
furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_fast);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
/* USER CODE END IOCTL */
|
|
||||||
}
|
}
|
||||||
#endif /* _USE_IOCTL == 1 */
|
|
||||||
|
|
||||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
|
||||||
|
@ -1,48 +1,14 @@
|
|||||||
/* USER CODE BEGIN Header */
|
#pragma once
|
||||||
/**
|
|
||||||
******************************************************************************
|
|
||||||
* @file user_diskio.h
|
|
||||||
* @brief This file contains the common defines and functions prototypes for
|
|
||||||
* the user_diskio driver.
|
|
||||||
******************************************************************************
|
|
||||||
* @attention
|
|
||||||
*
|
|
||||||
* <h2><center>© Copyright (c) 2020 STMicroelectronics.
|
|
||||||
* All rights reserved.</center></h2>
|
|
||||||
*
|
|
||||||
* This software component is licensed by ST under Ultimate Liberty license
|
|
||||||
* SLA0044, the "License"; You may not use this file except in compliance with
|
|
||||||
* the License. You may obtain a copy of the License at:
|
|
||||||
* www.st.com/SLA0044
|
|
||||||
*
|
|
||||||
******************************************************************************
|
|
||||||
*/
|
|
||||||
/* USER CODE END Header */
|
|
||||||
|
|
||||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
|
||||||
#ifndef __USER_DISKIO_H
|
|
||||||
#define __USER_DISKIO_H
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* USER CODE BEGIN 0 */
|
|
||||||
|
|
||||||
/* Includes ------------------------------------------------------------------*/
|
|
||||||
#include "sd_spi_io.h"
|
#include "sd_spi_io.h"
|
||||||
#include "fatfs/ff_gen_drv.h"
|
#include "fatfs/ff_gen_drv.h"
|
||||||
/* Exported types ------------------------------------------------------------*/
|
|
||||||
/* Exported constants --------------------------------------------------------*/
|
|
||||||
/* Exported functions ------------------------------------------------------- */
|
|
||||||
extern Diskio_drvTypeDef USER_Driver;
|
|
||||||
|
|
||||||
/* USER CODE END 0 */
|
extern Diskio_drvTypeDef sd_fatfs_driver;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* __USER_DISKIO_H */
|
|
||||||
|
|
||||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
|
@ -4,8 +4,6 @@
|
|||||||
|
|
||||||
#include <stm32wbxx_ll_cortex.h>
|
#include <stm32wbxx_ll_cortex.h>
|
||||||
|
|
||||||
#include <fatfs.h>
|
|
||||||
|
|
||||||
#define TAG "FuriHal"
|
#define TAG "FuriHal"
|
||||||
|
|
||||||
void furi_hal_init_early() {
|
void furi_hal_init_early() {
|
||||||
@ -81,10 +79,6 @@ void furi_hal_init() {
|
|||||||
furi_hal_nfc_init();
|
furi_hal_nfc_init();
|
||||||
furi_hal_rfid_init();
|
furi_hal_rfid_init();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// FatFS driver initialization
|
|
||||||
MX_FATFS_Init();
|
|
||||||
FURI_LOG_I(TAG, "FATFS OK");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void furi_hal_switch(void* address) {
|
void furi_hal_switch(void* address) {
|
||||||
|
@ -44,7 +44,7 @@ static bool flipper_update_init() {
|
|||||||
|
|
||||||
furi_hal_spi_config_init();
|
furi_hal_spi_config_init();
|
||||||
|
|
||||||
MX_FATFS_Init();
|
fatfs_init();
|
||||||
if(!hal_sd_detect()) {
|
if(!hal_sd_detect()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user