ChibiOS/demos/STM32/RT-VFS-FATFS/main.c

380 lines
10 KiB
C

/*
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include <string.h>
#include "ch.h"
#include "hal.h"
#include "vfs.h"
#include "chprintf.h"
#include "nullstreams.h"
#include "xshell.h"
#include "portab.h"
/*===========================================================================*/
/* Card insertion monitor. */
/*===========================================================================*/
/**
* @brief Card event sources.
*/
static event_source_t inserted_event, removed_event;
#define POLLING_INTERVAL 10
#define POLLING_DELAY 10
/**
* @brief Card monitor timer.
*/
static virtual_timer_t tmr;
/**
* @brief Debounce counter.
*/
static unsigned cnt;
/**
* @brief Insertion monitor timer callback function.
*
* @param[in] p pointer to the @p BaseBlockDevice object
*
* @notapi
*/
static void tmrfunc(virtual_timer_t *vtp, void *p) {
BaseBlockDevice *bbdp = p;
chSysLockFromISR();
if (cnt > 0) {
if (blkIsInserted(bbdp)) {
if (--cnt == 0) {
chEvtBroadcastI(&inserted_event);
}
}
else
cnt = POLLING_INTERVAL;
}
else {
if (!blkIsInserted(bbdp)) {
cnt = POLLING_INTERVAL;
chEvtBroadcastI(&removed_event);
}
}
chVTSetI(vtp, TIME_MS2I(POLLING_DELAY), tmrfunc, bbdp);
chSysUnlockFromISR();
}
/**
* @brief Polling monitor start.
*
* @param[in] p pointer to an object implementing @p BaseBlockDevice
*
* @notapi
*/
static void tmr_init(void *p) {
chEvtObjectInit(&inserted_event);
chEvtObjectInit(&removed_event);
chSysLock();
cnt = POLLING_INTERVAL;
chVTSetI(&tmr, TIME_MS2I(POLLING_DELAY), tmrfunc, p);
chSysUnlock();
}
/*===========================================================================*/
/* FatFS related. */
/*===========================================================================*/
/* FS mounted and ready.*/
static bool fs_ready = false;
/*===========================================================================*/
/* VFS related. */
/*===========================================================================*/
/* VFS FatFS driver object to be mounted as /.*/
static vfs_fatfs_driver_c ffs_driver;
/* VFS streams driver object to be mounted as /dev.*/
static vfs_streams_driver_c dev_driver;
/* VFS overlay driver object representing the root directory.*/
static vfs_overlay_driver_c root_overlay_driver;
/* Global pointer to the root VFS driver.*/
vfs_driver_c *vfs_root = (vfs_driver_c *)&root_overlay_driver;
/* A null stream object.*/
static NullStream nullstream;
/* Stream to be exposed under /dev as files.*/
static const drv_streams_element_t streams[] = {
{"VSD1", (sequential_stream_i *)&PORTAB_SD1, VFS_MODE_S_IFCHR},
{"null", (sequential_stream_i *)&nullstream, VFS_MODE_S_IFCHR},
{NULL, NULL, 0}
};
/*===========================================================================*/
/* Command line related. */
/*===========================================================================*/
#define SHELL_WA_SIZE THD_STACK_SIZE(2048)
static void cmd_halt(xshell_manager_t *smp, BaseSequentialStream *stream,
int argc, char *argv[]) {
(void)smp;
(void)argv;
if (argc != 1) {
xshellUsage(stream, "halt");
return;
}
chprintf(stream, XSHELL_NEWLINE_STR "halted");
chThdSleepMilliseconds(10);
chSysHalt("shell halt");
}
/* Can be measured using dd if=/dev/xxxx of=/dev/null bs=512 count=10000.*/
static void cmd_write(xshell_manager_t *smp, BaseSequentialStream *stream,
int argc, char *argv[]) {
static uint8_t buf[] =
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
(void)smp;
(void)argv;
if (argc != 1) {
xshellUsage(stream, "write");
return;
}
while (chnGetTimeout((BaseChannel *)stream, TIME_IMMEDIATE) == Q_TIMEOUT) {
chnWrite(stream, buf, sizeof buf - 1);
}
chprintf(stream, XSHELL_NEWLINE_STR "stopped" XSHELL_NEWLINE_STR);
}
static const xshell_command_t commands[] = {
{"halt", cmd_halt},
{"write", cmd_write},
{NULL, NULL}
};
static const xshell_manager_config_t cfg1 = {
.thread_name = "shell",
.banner = XSHELL_DEFAULT_BANNER_STR,
.prompt = XSHELL_DEFAULT_PROMPT_STR,
.commands = commands,
.use_heap = true,
.stack.size = SHELL_WA_SIZE
};
static xshell_manager_t sm1;
/*===========================================================================*/
/* Main and generic code. */
/*===========================================================================*/
static thread_t *shelltp = NULL;
#if !HAL_USE_SDC
static uint8_t __nocache_mmcbuf[MMC_BUFFER_SIZE];
mmc_spi_driver_t MMCD1;
/* MMC/SD over SPI driver configuration.*/
static MMCConfig mmccfg = {&PORTAB_SPI1, &ls_spicfg, &hs_spicfg};
#endif
/*
* Card insertion event.
*/
static void InsertHandler(eventid_t id) {
msg_t err;
(void)id;
#if HAL_USE_SDC
if (sdcConnect(&PORTAB_SDCD1)) {
return;
}
#else
if (mmcConnect(&MMCD1)) {
return;
}
#endif
err = ffdrvMount("0:", 1);
if (CH_RET_IS_ERROR(err)) {
#if HAL_USE_SDC
sdcDisconnect(&PORTAB_SDCD1);
#else
mmcDisconnect(&MMCD1);
#endif
return;
}
fs_ready = true;
}
/*
* Card removal event.
*/
static void RemoveHandler(eventid_t id) {
(void)id;
#if HAL_USE_SDC
sdcDisconnect(&PORTAB_SDCD1);
#else
mmcDisconnect(&MMCD1);
#endif
fs_ready = false;
}
/*
* Shell exit event.
*/
static void ShellHandler(eventid_t id) {
(void)id;
(void) chThdWait(shelltp);
shelltp = NULL;
}
/*
* LED blinker thread, times are in milliseconds.
*/
static THD_STACK(thd1_stack, 256);
static THD_FUNCTION(thd1_func, arg) {
(void)arg;
while (true) {
palToggleLine(PORTAB_LINE_LED1);
chThdSleepMilliseconds(fs_ready ? 100 : 500);
}
}
/*
* Application entry point.
*/
int main(void) {
vfs_file_node_c *file1;
msg_t msg;
event_listener_t el0, el1, el2;
static const evhandler_t evhndl[] = {
InsertHandler,
RemoveHandler,
ShellHandler
};
/*
* System initializations.
* - HAL initialization, this also initializes the configured device drivers
* and performs the board-specific initializations.
* - Kernel initialization, the main() function becomes a thread and the
* RTOS is active.
* - Virtual File System initialization.
*/
halInit();
chSysInit();
vfsInit();
/* Board-dependent setup code.*/
portab_setup();
/* Spawning a blinker thread.*/
static thread_t thd1;
static const THD_DECL_STATIC(thd1_desc, "blinker", thd1_stack,
NORMALPRIO + 10, thd1_func, NULL, NULL);
chThdSpawnRunning(&thd1, &thd1_desc);
#if HAL_USE_SDC
/* Activates the SDC driver using default configuration.*/
sdcStart(&PORTAB_SDCD1, NULL);
/* Activates the card insertion monitor.*/
tmr_init(&PORTAB_SDCD1);
#else
/* Activates the MMC_SPI driver.*/
mmcObjectInit(&MMCD1, __nocache_mmcbuf);
mmcStart(&MMCD1, &mmccfg);
/* Activates the card insertion monitor.*/
tmr_init(&MMCD1);
#endif
/* Activates the SIO driver and a null stream.*/
sdStart(&PORTAB_SD1, NULL);
nullObjectInit(&nullstream);
/* Initialization of the VFS FatFS driver object.*/
ffdrvObjectInit(&ffs_driver);
/* Initialization of the VFS stream driver object.*/
stmdrvObjectInit(&dev_driver, &streams[0]);
/* Initializing an overlay VFS object overlaying the LittleFS driver.*/
ovldrvObjectInit(&root_overlay_driver, (vfs_driver_c *)&ffs_driver, NULL);
/* Registering the streams VFS driver on the VFS overlay root as "/dev".*/
msg = ovldrvRegisterDriver(&root_overlay_driver, (vfs_driver_c *)&dev_driver, "dev");
if (CH_RET_IS_ERROR(msg)) {
chSysHalt("VFS");
}
/* Opening a file for shell I/O.*/
msg = vfsOpenFile("/dev/VSD1", VO_RDWR, &file1);
if (CH_RET_IS_ERROR(msg)) {
chSysHalt("VFS");
}
/* Shell manager initialization.*/
xshellObjectInit(&sm1, &cfg1);
/* Normal main() thread activity, spawning shells.*/
chEvtRegister(&inserted_event, &el0, 0);
chEvtRegister(&removed_event, &el1, 1);
chEvtRegister(&sm1.events, &el2, 2);
while (true) {
if (shelltp == NULL) {
/* Spawning a shell.*/
shelltp = xshellSpawn(&sm1,
(BaseSequentialStream *)vfsGetFileStream(file1),
NORMALPRIO + 1);
}
chEvtDispatch(evhndl, chEvtWaitOneTimeout(ALL_EVENTS, TIME_MS2I(500)));
}
}