rcbench
Servo and ESC test bench: panel, IOmcu and shared C
Loading...
Searching...
No Matches
storage.c File Reference

The SD card on SDMMC slot 0: mount, unmount, holds, and the look at a card that does not mount. More...

#include "storage.h"
#include "storage_priv.h"
#include <stdatomic.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "board_pins.h"
#include "ff.h"
#include "diskio_impl.h"
#include "diskio_sdmmc.h"
#include "driver/sdmmc_host.h"
#include "esp_check.h"
#include "esp_log.h"
#include "esp_vfs_fat.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "sd_pwr_ctrl_by_on_chip_ldo.h"
#include "sdmmc_cmd.h"

Data Structures

struct  [struct].s
 Driver state of the UART: the claimed machines and the pins. More...

Macros

#define STORAGE_IDF_MOUNT_TAG   "vfs_fat_sdmmc"
#define STORAGE_IDF_DISKIO_TAG   "diskio_sdmmc"
#define STORAGE_IDF_CMD_TAG   "sdmmc_cmd"

Functions

static bool lock_ready (void)
static void lock (void)
static void unlock (void)
static void set_state (card_state_t state)
static void publish (void)
static void name_set (const char *name)
static void read_name (void)
static const char * volume_format (void)
static int probe_fatfs (const sdmmc_host_t *host, const sdmmc_slot_config_t *slot, esp_err_t *why)
 What FatFs says of the card esp_vfs_fat_sdmmc_mount() just gave up on.
static void mount_failed (esp_err_t err, const sdmmc_host_t *host, const sdmmc_slot_config_t *slot)
 A mount that failed after the card started: which kind of card it is, said once in the log and kept for the screens.
static bool fat_usage (uint64_t *total, uint64_t *freebytes)
static esp_err_t mount_locked (void)
 Mount whatever the slot holds, under s.lock, with nothing mounted.
static void unmount_locked (void)
 Let the volume go, under s.lock, with nothing holding it.
static void drop_locked (card_state_t state)
static void lose_locked (int fr, const char *how)
static int probe_locked (void)
static bool removal_shaped (int fr)
esp_err_t storage_init (void)
 Switch the card's supply on and mount the card at /sdcard.
card_state_t storage_check (void)
bool storage_hold (void)
bool storage_hold_mount (unsigned mount)
void storage_release (void)
FILE * storage_fopen (const char *path, const char *mode)
int storage_fclose (FILE *f)
void storage_deinit (void)
 Unmount and switch the card's supply off. Safe to call when nothing was mounted. Clears storage_status() and storage_card_state(). The end of the card's use: nothing may still be open, and no hold is waited for.
unsigned storage_mount_count (void)
bool storage_mounted (void)
void storage_card_name (char *out, size_t n)
const char * storage_status (void)
 What went wrong, in a few words for the console and the start-up line: "no card", "no FAT volume", "FatFs <n>", "LDO <error>" or ESP-IDF's error name. "" when all is well. At most 47 characters.
card_state_t storage_card_state (void)
uint64_t storage_total_bytes (void)
uint64_t storage_free_bytes (void)
static bool read_failed_locked (int fr, const char *how)
const char * storage_drive (void)
bool storage_read_end (int fr, const char *how, bool may_mount)

Variables

static const char * TAG = "storage"
static struct  s
static portMUX_TYPE s_name_mux = portMUX_INITIALIZER_UNLOCKED

Detailed Description

The SD card on SDMMC slot 0: mount, unmount, holds, and the look at a card that does not mount.

The SDMMC host is shared with the ESP32-C6's SDIO link on slot 1 (wifi_radio.c). Each slot's start and card start set the host's clock divider, which both slots share, and send the clock update commands outside ESP-IDF's request mutex (sdmmc_host_set_card_clk(), sdmmc_host.c 301-351). So a mount here can make a C6 transfer under way fail, and esp_hosted's start of slot 1 (at the first Wi-Fi start, and at each C6 reset it makes) can make a card read or write under way fail. Neither is measured. test_storage holds the slot count against test/host/storage_stub/storage_fake.c, which counts slots as ESP-IDF does; the shared clock divider is not modelled there.

SPDX-License-Identifier: MIT

Function Documentation

◆ mount_failed()

void mount_failed ( esp_err_t err,
const sdmmc_host_t * host,
const sdmmc_slot_config_t * slot )
static

A mount that failed after the card started: which kind of card it is, said once in the log and kept for the screens.

Parameters
errThe mount's error.
hostThe host as the mount had it.
slotThe slot as the mount had it.

◆ mount_locked()

esp_err_t mount_locked ( void )
static

Mount whatever the slot holds, under s.lock, with nothing mounted.

Returns
As storage_init().

◆ probe_fatfs()

int probe_fatfs ( const sdmmc_host_t * host,
const sdmmc_slot_config_t * slot,
esp_err_t * why )
static

What FatFs says of the card esp_vfs_fat_sdmmc_mount() just gave up on.

That mount answers ESP_FAIL for every FatFs refusal alike, and only after the card has started (its own start-up errors come back as they are): no FAT volume on the card, a read error and an internal error are one code to its caller. So the card is started again here, the way the mount starts it, and handed to FatFs alone, without the VFS (virtual file system) path: f_mount()'s own answer, e.g. FR_NO_FILESYSTEM (13) for a card that holds NTFS, a GPT or nothing. The volume is let go before returning; a mount is still storage_init()'s alone.

Only on that failure, so a card that mounts costs nothing more. The work area is on the heap for the call: FATFS holds a sector, 4096 bytes with the panel's CONFIG_FATFS_SECTOR_4096.

Parameters
hostThe host as the mount had it, SDMMC slot 0.
slotThe slot's pins and width as the mount had them.
whySet to the error that kept FatFs from being asked, or ESP_OK.
Returns
f_mount()'s FRESULT, or -1 with why set when FatFs could not be asked: no device, a card that no longer starts, no memory.

◆ storage_card_name()

void storage_card_name ( char * out,
size_t n )

The card's name, into out of n bytes (40 hold every name): its volume label, or the product name in its CID (card identification register) when it has no label. Read once per mount. "" when nothing is mounted. A copy, so that a mount on another task cannot change it under the caller.

◆ storage_card_state()

card_state_t storage_card_state ( void )

What the slot holds as the last mount or look found it, or CARD_STATE_MOUNTED while a volume is mounted. CARD_STATE_NONE before the first try, after storage_deinit() and for a card found gone. CARD_STATE_UNREADABLE for a card that mounted, answers and fails a read. Lock-free: the control task and every frame may ask.

◆ storage_check()

card_state_t storage_check ( void )

What the slot holds now, at an event that reads the card: LOGS opening, RESCAN, a page of LOGS, a file opened in LOGS, a run's or a servo test's start, the servo programmer looking for its card. Not once a frame.

A mounted volume is asked whether its card still answers: one SEND_STATUS (CMD13) command through FatFs. A card that does not is taken out or swapped; the volume is let go and the slot mounted again, so the volume label, the list and the run alerts are the card's in the slot now. Held (storage_hold()), the volume is let go at the last release instead, and reads as no card until the next call. An empty slot or one whose card did not mount is tried again. ESP-IDF's E lines for a card that is not there are quiet for the call; the outcome is one I or W line of its own.

Returns
storage_card_state() after the look.

◆ storage_drive()

const char * storage_drive ( void )

The FatFs drive of the mounted volume, "0:", or "" with none. Read under a hold (storage_hold()), which keeps it from changing.

◆ storage_fclose()

int storage_fclose ( FILE * f)

fclose() of a storage_fopen() file, and its hold given back. The close is made also on a card found gone: FatFs refuses it without card traffic, and the handle and its descriptor are freed.

◆ storage_fopen()

FILE * storage_fopen ( const char * path,
const char * mode )

fopen() under a hold that the file keeps until storage_fclose(); NULL, with no hold kept, when nothing is mounted or the open fails.

◆ storage_hold()

bool storage_hold ( void )

Keep the mounted volume from being let go: around every path call (fopen(), stat(), mkdir(), unlink(), rename(), opendir()) and for as long as a file or folder stays open. Counted; every true is matched by one storage_release().

Returns
false with nothing mounted, or with a card found gone: the caller makes no card call.

◆ storage_hold_mount()

bool storage_hold_mount ( unsigned mount)

storage_hold() of the volume of mount mount (storage_mount_count()) only: false once another volume is mounted, so a name read from one card is not opened or deleted on the next.

◆ storage_init()

esp_err_t storage_init ( void )

Switch the card's supply on and mount the card at /sdcard.

Never formats. A card that starts and does not mount is looked at once more, so storage_card_state() can tell a card with no FAT (File Allocation Table) volume from one that fails another way. The first call makes the lock every other call takes: the start-up's, on app_main, before any task that reaches the card exists.

Returns
ESP_OK when a volume is mounted, also when one already was. ESP_ERR_NOT_FOUND when no card answers, which is a normal state: the bench runs without a card. ESP_FAIL for a card FatFs does not mount, ESP-IDF's code for a card that does not start or a supply that does not come up. ESP_ERR_INVALID_STATE while a card found gone is still held (storage_hold()).

◆ storage_mount_count()

unsigned storage_mount_count ( void )

The mounts that worked since the start: another number after a storage_check() is another volume, the same card's or a new one's. Lock-free.

◆ storage_mounted()

bool storage_mounted ( void )

A volume is mounted and its card was not found gone. Lock-free.

◆ storage_read_end()

bool storage_read_end ( int fr,
const char * how,
bool may_mount )

The end of a read made under storage_hold(): the hold given back, and the read's FatFs answer fr (0 for one that worked) weighed. A failure that says the card is gone lets the volume go (storage_walk() says how); how names the read in the log line. With may_mount, a volume let go with nothing else holding it is mounted again once.

Returns
whether a card in the slot was mounted again by this call.

◆ storage_release()

void storage_release ( void )

The end of a storage_hold() that answered true. The last release of a volume whose card was found gone lets the volume go.

◆ storage_status()

const char * storage_status ( void )

What went wrong, in a few words for the console and the start-up line: "no card", "no FAT volume", "FatFs <n>", "LDO <error>" or ESP-IDF's error name. "" when all is well. At most 47 characters.

Returns
the text, static; "" when all is well

◆ storage_total_bytes()

uint64_t storage_total_bytes ( void )

Card size and free space in bytes; 0 when nothing is mounted.

◆ unmount_locked()

void unmount_locked ( void )
static

Let the volume go, under s.lock, with nothing holding it.

No card traffic: f_mount(NULL) forgets the volume without writing, and the slot is let go. The SDMMC host stays up: the radio's slot 1 shares it.