rusefi/firmware/hw_layer/mmc_card.cpp

502 lines
13 KiB
C++
Raw Normal View History

2015-07-10 06:01:56 -07:00
/**
* @file mmc_card.cpp
*
* @date Dec 28, 2013
* @author Kot_dnz
2018-01-20 17:55:31 -08:00
* @author Andrey Belomutskiy, (c) 2012-2018
2015-07-10 06:01:56 -07:00
*
* default pinouts in case of SPI2 connected to MMC: PB13 - SCK, PB14 - MISO, PB15 - MOSI, PD4 - CS, 3.3v
* default pinouts in case of SPI3 connected to MMC: PB3 - SCK, PB4 - MISO, PB5 - MOSI, PD4 - CS, 3.3v
*
*
* todo: extract some logic into a controller file
*/
2018-09-16 19:26:57 -07:00
#include "global.h"
2015-07-10 06:01:56 -07:00
2019-04-12 17:52:51 -07:00
#if EFI_FILE_LOGGING
2015-07-10 06:01:56 -07:00
#include <stdio.h>
#include <string.h>
#include "mmc_card.h"
#include "pin_repository.h"
#include "ff.h"
#include "hardware.h"
#include "engine_configuration.h"
#include "status_loop.h"
2016-07-05 06:01:23 -07:00
#include "usb_msd_cfg.h"
2016-08-08 21:03:08 -07:00
#include "rtc_helper.h"
2016-07-05 06:01:23 -07:00
2019-09-21 08:09:03 -07:00
#if EFI_TUNER_STUDIO
extern TunerStudioOutputChannels tsOutputChannels;
#endif
2017-02-08 20:03:36 -08:00
#define SD_STATE_INIT "init"
#define SD_STATE_MOUNTED "MOUNTED"
#define SD_STATE_MOUNT_FAILED "MOUNT_FAILED"
#define SD_STATE_OPEN_FAILED "OPEN_FAILED"
#define SD_STATE_SEEK_FAILED "SEEK_FAILED"
#define SD_STATE_NOT_INSERTED "NOT_INSERTED"
#define SD_STATE_CONNECTING "CONNECTING"
#define SD_STATE_NOT_CONNECTED "NOT_CONNECTED"
static const char *sdStatus = SD_STATE_INIT;
static bool fs_ready = false;
2016-07-05 06:01:23 -07:00
EXTERN_ENGINE;
2015-07-10 06:01:56 -07:00
#define F_SYNC_FREQUENCY 100
2019-09-21 08:09:03 -07:00
static int totalLoggedBytes = 0;
static int writeCounter = 0;
2019-09-21 08:09:03 -07:00
static int totalWritesCounter = 0;
static int totalSyncCounter = 0;
2015-07-10 06:01:56 -07:00
#define LOG_INDEX_FILENAME "index.txt"
2016-08-08 21:03:08 -07:00
2015-07-10 06:01:56 -07:00
#define RUSEFI_LOG_PREFIX "rus"
2016-08-08 21:03:08 -07:00
#define PREFIX_LEN 3
#define SHORT_TIME_LEN 11
2015-07-10 06:01:56 -07:00
#define LS_RESPONSE "ls_result"
#define FILE_LIST_MAX_COUNT 20
2017-05-24 08:12:09 -07:00
#if HAL_USE_USB_MSD
2019-02-03 19:17:46 -08:00
#include "hal_usb_msd.h"
2017-06-18 00:09:12 -07:00
#if STM32_USB_USE_OTG2
USBDriver *usb_driver = &USBD2;
#else
USBDriver *usb_driver = &USBD1;
#endif
extern const USBConfig msdusbcfg;
2017-05-24 08:12:09 -07:00
#endif /* HAL_USE_USB_MSD */
2016-07-05 06:01:23 -07:00
2015-07-10 06:01:56 -07:00
#define PUSHPULLDELAY 500
2016-09-11 19:03:02 -07:00
static THD_WORKING_AREA(mmcThreadStack,3 * UTILITY_THREAD_STACK_SIZE); // MMC monitor thread
2015-07-10 06:01:56 -07:00
/**
* MMC driver instance.
*/
MMCDriver MMCD1;
static SPIConfig hs_spicfg = {
.circular = false,
.end_cb = NULL,
.ssport = NULL,
.sspad = 0,
.cr1 = SPI_BaudRatePrescaler_8,
.cr2 = 0};
static SPIConfig ls_spicfg = {
.circular = false,
.end_cb = NULL,
.ssport = NULL,
.sspad = 0,
.cr1 = SPI_BaudRatePrescaler_256,
.cr2 = 0};
2015-07-10 06:01:56 -07:00
/* MMC/SD over SPI driver configuration.*/
2016-07-04 12:01:27 -07:00
// don't forget check if STM32_SPI_USE_SPI2 defined and spi has init with correct GPIO in hardware.cpp
2017-11-19 12:24:36 -08:00
static MMCConfig mmccfg = { NULL, &ls_spicfg, &hs_spicfg };
2015-07-10 06:01:56 -07:00
/**
* fatfs MMC/SPI
*/
static FATFS MMC_FS;
static LoggingWithStorage logger("mmcCard");
2018-01-24 18:50:56 -08:00
static int fatFsErrors = 0;
2019-09-21 08:20:04 -07:00
static void setSdCardReady(bool value) {
fs_ready = value;
}
2015-07-10 06:01:56 -07:00
// print FAT error function
static void printError(const char *str, FRESULT f_error) {
2018-01-24 18:50:56 -08:00
if (fatFsErrors++ > 16) {
// no reason to spam the console
return;
}
2015-07-10 06:01:56 -07:00
scheduleMsg(&logger, "FATfs Error \"%s\" %d", str, f_error);
}
static FIL FDLogFile;
static FIL FDCurrFile;
static int logFileIndex = 1;
2016-08-09 21:04:24 -07:00
static char logName[_MAX_FILLER + 20];
2015-07-10 06:01:56 -07:00
static void printMmcPinout(void) {
scheduleMsg(&logger, "MMC CS %s", hwPortname(CONFIGB(sdCardCsPin)));
2015-07-10 06:01:56 -07:00
// todo: we need to figure out the right SPI pinout, not just SPI2
// scheduleMsg(&logger, "MMC SCK %s:%d", portname(EFI_SPI2_SCK_PORT), EFI_SPI2_SCK_PIN);
// scheduleMsg(&logger, "MMC MISO %s:%d", portname(EFI_SPI2_MISO_PORT), EFI_SPI2_MISO_PIN);
// scheduleMsg(&logger, "MMC MOSI %s:%d", portname(EFI_SPI2_MOSI_PORT), EFI_SPI2_MOSI_PIN);
}
static void sdStatistics(void) {
printMmcPinout();
scheduleMsg(&logger, "SD enabled=%s status=%s", boolToString(CONFIGB(isSdCardEnabled)),
2017-02-08 20:03:36 -08:00
sdStatus);
2019-09-21 08:20:04 -07:00
if (isSdCardAlive()) {
2019-09-21 08:09:03 -07:00
scheduleMsg(&logger, "filename=%s size=%d", logName, totalLoggedBytes);
2017-02-08 20:03:36 -08:00
}
2015-07-10 06:01:56 -07:00
}
static void incLogFileName(void) {
lockSpi(SPI_NONE);
memset(&FDCurrFile, 0, sizeof(FIL)); // clear the memory
FRESULT err = f_open(&FDCurrFile, LOG_INDEX_FILENAME, FA_READ); // This file has the index for next log file name
2016-08-09 21:04:24 -07:00
char data[_MAX_FILLER];
2015-07-10 06:01:56 -07:00
UINT result = 0;
if (err != FR_OK && err != FR_EXIST) {
logFileIndex = 1;
scheduleMsg(&logger, "%s: not found or error: %d", LOG_INDEX_FILENAME, err);
} else {
f_read(&FDCurrFile, (void*)data, sizeof(data), &result);
scheduleMsg(&logger, "Got content [%s] size %d", data, result);
f_close(&FDCurrFile);
if (result < 5) {
data[result] = 0;
logFileIndex = atoi(data);
if (absI(logFileIndex) == ERROR_CODE) {
logFileIndex = 1;
} else {
logFileIndex++; // next file would use next file name
}
} else {
logFileIndex = 1;
}
}
err = f_open(&FDCurrFile, LOG_INDEX_FILENAME, FA_OPEN_ALWAYS | FA_WRITE);
itoa10(data, logFileIndex);
f_write(&FDCurrFile, (void*)data, strlen(data), &result);
f_close(&FDCurrFile);
scheduleMsg(&logger, "Done %d", logFileIndex);
unlockSpi();
}
2016-08-08 21:03:08 -07:00
static void prepareLogFileName(void) {
strcpy(logName, RUSEFI_LOG_PREFIX);
2016-08-09 22:01:43 -07:00
bool result = dateToStringShort(&logName[PREFIX_LEN]);
2016-08-08 21:03:08 -07:00
char *ptr;
2016-08-09 22:01:43 -07:00
if (result) {
ptr = &logName[PREFIX_LEN + SHORT_TIME_LEN];
} else {
2016-08-08 21:03:08 -07:00
ptr = itoa10(&logName[PREFIX_LEN], logFileIndex);
2016-08-09 22:01:43 -07:00
}
2016-08-08 21:03:08 -07:00
strcat(ptr, ".msl");
}
2015-07-10 06:01:56 -07:00
/**
* @brief Create a new file with the specified name
*
* This function saves the name of the file in a global variable
* so that we can later append to that file
*/
static void createLogFile(void) {
lockSpi(SPI_NONE);
memset(&FDLogFile, 0, sizeof(FIL)); // clear the memory
2016-08-08 21:03:08 -07:00
prepareLogFileName();
2015-07-10 06:01:56 -07:00
FRESULT err = f_open(&FDLogFile, logName, FA_OPEN_ALWAYS | FA_WRITE); // Create new file
if (err != FR_OK && err != FR_EXIST) {
unlockSpi();
2017-02-08 20:03:36 -08:00
sdStatus = SD_STATE_OPEN_FAILED;
warning(CUSTOM_ERR_SD_MOUNT_FAILED, "SD: mount failed");
2015-07-10 06:01:56 -07:00
printError("FS mount failed", err); // else - show error
return;
}
err = f_lseek(&FDLogFile, f_size(&FDLogFile)); // Move to end of the file to append data
if (err) {
unlockSpi();
2017-02-08 20:03:36 -08:00
sdStatus = SD_STATE_SEEK_FAILED;
warning(CUSTOM_ERR_SD_SEEK_FAILED, "SD: seek failed");
2015-07-10 06:01:56 -07:00
printError("Seek error", err);
return;
}
2019-09-21 08:09:03 -07:00
f_sync(&FDLogFile);
2019-09-21 08:20:04 -07:00
setSdCardReady(true); // everything Ok
2015-07-10 06:01:56 -07:00
unlockSpi();
}
static void removeFile(const char *pathx) {
2019-09-21 08:20:04 -07:00
if (!isSdCardAlive()) {
2015-07-10 06:01:56 -07:00
scheduleMsg(&logger, "Error: No File system is mounted");
return;
}
lockSpi(SPI_NONE);
f_unlink(pathx);
unlockSpi();
}
2016-08-10 05:03:48 -07:00
int
mystrncasecmp(const char *s1, const char *s2, size_t n)
{
if (n != 0) {
2016-08-20 19:02:12 -07:00
const char *us1 = (const char *)s1;
const char *us2 = (const char *)s2;
2016-08-10 05:03:48 -07:00
do {
if (mytolower(*us1) != mytolower(*us2))
return (mytolower(*us1) - mytolower(*us2));
if (*us1++ == '\0')
break;
us2++;
} while (--n != 0);
}
return (0);
}
2015-07-10 06:01:56 -07:00
static void listDirectory(const char *path) {
2019-09-21 08:20:04 -07:00
if (!isSdCardAlive()) {
2015-07-10 06:01:56 -07:00
scheduleMsg(&logger, "Error: No File system is mounted");
return;
}
lockSpi(SPI_NONE);
DIR dir;
FRESULT res = f_opendir(&dir, path);
if (res != FR_OK) {
scheduleMsg(&logger, "Error opening directory %s", path);
unlockSpi();
return;
}
scheduleMsg(&logger, LS_RESPONSE);
int i = strlen(path);
for (int count = 0;count < FILE_LIST_MAX_COUNT;) {
FILINFO fno;
2018-01-23 19:24:11 -08:00
2015-07-10 06:01:56 -07:00
res = f_readdir(&dir, &fno);
if (res != FR_OK || fno.fname[0] == 0)
break;
2016-08-09 22:01:43 -07:00
if (fno.fname[0] == '.')
2015-07-10 06:01:56 -07:00
continue;
2016-08-10 05:03:48 -07:00
if ((fno.fattrib & AM_DIR) || mystrncasecmp(RUSEFI_LOG_PREFIX, fno.fname, sizeof(RUSEFI_LOG_PREFIX) - 1)) {
2015-07-10 06:01:56 -07:00
continue;
}
2018-01-23 19:23:24 -08:00
scheduleMsg(&logger, "logfile%lu:%s", fno.fsize, fno.fname);
2015-07-10 06:01:56 -07:00
count++;
// scheduleMsg(&logger, "%c%c%c%c%c %u/%02u/%02u %02u:%02u %9lu %-12s", (fno.fattrib & AM_DIR) ? 'D' : '-',
// (fno.fattrib & AM_RDO) ? 'R' : '-', (fno.fattrib & AM_HID) ? 'H' : '-',
// (fno.fattrib & AM_SYS) ? 'S' : '-', (fno.fattrib & AM_ARC) ? 'A' : '-', (fno.fdate >> 9) + 1980,
// (fno.fdate >> 5) & 15, fno.fdate & 31, (fno.ftime >> 11), (fno.ftime >> 5) & 63, fno.fsize,
// fno.fname);
}
unlockSpi();
}
static int errorReported = FALSE; // this is used to report the error only once
2016-05-06 21:01:23 -07:00
void readLogFileContent(char *buffer, short fileId, short offset, short length) {
}
2015-07-10 06:01:56 -07:00
/**
* @brief Appends specified line to the current log file
*/
void appendToLog(const char *line) {
2019-09-20 22:49:46 -07:00
UINT bytesWritten;
2015-07-10 06:01:56 -07:00
2019-09-21 08:20:04 -07:00
if (!isSdCardAlive()) {
2015-07-10 06:01:56 -07:00
if (!errorReported)
scheduleMsg(&logger, "appendToLog Error: No File system is mounted");
errorReported = TRUE;
return;
}
UINT lineLength = strlen(line);
2019-09-21 08:09:03 -07:00
totalLoggedBytes += lineLength;
2015-07-10 06:01:56 -07:00
lockSpi(SPI_NONE);
2019-09-20 22:49:46 -07:00
FRESULT err = f_write(&FDLogFile, line, lineLength, &bytesWritten);
if (bytesWritten < lineLength) {
2015-07-10 06:01:56 -07:00
printError("write error or disk full", err); // error or disk full
}
2019-09-21 08:09:03 -07:00
writeCounter++;
totalWritesCounter++;
if (writeCounter >= F_SYNC_FREQUENCY) {
/**
* Performance optimization: not f_sync after each line, f_sync is probably a heavy operation
* todo: one day someone should actualy measure the relative cost of f_sync
*/
f_sync(&FDLogFile);
totalSyncCounter++;
writeCounter = 0;
}
2015-07-10 06:01:56 -07:00
unlockSpi();
2019-09-21 08:09:03 -07:00
if (engineConfiguration->debugMode == DBG_SD_CARD) {
tsOutputChannels.debugIntField1 = totalLoggedBytes;
tsOutputChannels.debugIntField2 = totalWritesCounter;
tsOutputChannels.debugIntField3 = totalSyncCounter;
}
2015-07-10 06:01:56 -07:00
}
/*
* MMC card umount.
*/
static void MMCumount(void) {
2019-09-21 08:20:04 -07:00
if (!isSdCardAlive()) {
2015-07-10 06:01:56 -07:00
scheduleMsg(&logger, "Error: No File system is mounted. \"mountsd\" first");
return;
}
f_close(&FDLogFile); // close file
f_sync(&FDLogFile); // sync ALL
mmcDisconnect(&MMCD1); // Brings the driver in a state safe for card removal.
mmcStop(&MMCD1); // Disables the MMC peripheral.
2017-04-02 20:28:05 -07:00
f_mount(NULL, 0, 0); // FATFS: Unregister work area prior to discard it
2015-07-10 06:01:56 -07:00
memset(&FDLogFile, 0, sizeof(FIL)); // clear FDLogFile
2019-09-21 08:20:04 -07:00
setSdCardReady(false); // status = false
2015-07-10 06:01:56 -07:00
scheduleMsg(&logger, "MMC/SD card removed");
}
2017-06-19 20:04:06 -07:00
#define RAMDISK_BLOCK_SIZE 512U
static uint8_t blkbuf[RAMDISK_BLOCK_SIZE];
2015-07-10 06:01:56 -07:00
/*
* MMC card mount.
*/
static void MMCmount(void) {
// printMmcPinout();
2019-09-21 08:20:04 -07:00
if (isSdCardAlive()) {
2015-07-10 06:01:56 -07:00
scheduleMsg(&logger, "Error: Already mounted. \"umountsd\" first");
return;
}
2017-04-02 20:28:05 -07:00
if ((MMCD1.state == BLK_STOP) || (MMCD1.state == BLK_ACTIVE)) {
// looks like we would only get here after manual unmount with mmcStop? Do we really need to ever mmcStop?
// not sure if this code is needed
// start to initialize MMC/SD
mmcStart(&MMCD1, &mmccfg); // Configures and activates the MMC peripheral.
}
2015-07-10 06:01:56 -07:00
// Performs the initialization procedure on the inserted card.
lockSpi(SPI_NONE);
2017-02-08 20:03:36 -08:00
sdStatus = SD_STATE_CONNECTING;
2017-03-21 11:58:14 -07:00
if (mmcConnect(&MMCD1) != HAL_SUCCESS) {
2017-02-08 20:03:36 -08:00
sdStatus = SD_STATE_NOT_CONNECTED;
2016-07-22 14:03:21 -07:00
warning(CUSTOM_OBD_MMC_ERROR, "Can't connect or mount MMC/SD");
2015-07-10 06:01:56 -07:00
unlockSpi();
return;
}
2016-07-05 06:01:23 -07:00
2017-06-18 00:09:12 -07:00
// if (engineConfiguration->storageMode == MS_ALWAYS) {
#if HAL_USE_USB_MSD
msdObjectInit(&USBMSD1);
2017-06-19 20:04:06 -07:00
BaseBlockDevice *bbdp = (BaseBlockDevice*)&MMCD1;
msdStart(&USBMSD1, usb_driver, bbdp, blkbuf, NULL);
2016-07-05 06:01:23 -07:00
// const usb_msd_driver_state_t msd_driver_state = msdInit(ms_usb_driver, bbdp, &UMSD1, USB_MS_DATA_EP, USB_MSD_INTERFACE_NUMBER);
2017-06-18 00:09:12 -07:00
// UMSD1.chp = NULL;
/*Disconnect the USB Bus*/
2017-06-19 20:04:06 -07:00
usbDisconnectBus(usb_driver);
chThdSleepMilliseconds(200);
2016-07-05 06:01:23 -07:00
//
// /*Start the useful functions*/
// msdStart(&UMSD1);
2017-06-19 20:04:06 -07:00
usbStart(usb_driver, &msdusbcfg);
2016-07-05 06:01:23 -07:00
//
2017-06-19 20:04:06 -07:00
/*Connect the USB Bus*/
usbConnectBus(usb_driver);
2017-06-18 00:09:12 -07:00
#endif
//}
2016-07-05 06:01:23 -07:00
2015-07-10 06:01:56 -07:00
unlockSpi();
2017-06-19 20:04:06 -07:00
#if HAL_USE_USB_MSD
sdStatus = SD_STATE_MOUNTED;
return;
#endif
2015-07-10 06:01:56 -07:00
// if Ok - mount FS now
memset(&MMC_FS, 0, sizeof(FATFS));
2017-04-02 20:28:05 -07:00
if (f_mount(&MMC_FS, "/", 1) == FR_OK) {
2017-02-08 20:03:36 -08:00
sdStatus = SD_STATE_MOUNTED;
2015-07-10 06:01:56 -07:00
incLogFileName();
createLogFile();
scheduleMsg(&logger, "MMC/SD mounted!");
2017-02-08 20:03:36 -08:00
} else {
sdStatus = SD_STATE_MOUNT_FAILED;
2015-07-10 06:01:56 -07:00
}
}
2016-01-15 20:01:43 -08:00
static THD_FUNCTION(MMCmonThread, arg) {
2015-07-10 06:01:56 -07:00
chRegSetThreadName("MMC_Monitor");
while (true) {
// this returns TRUE if SD module is there, even without an SD card?
if (blkIsInserted(&MMCD1)) {
2019-09-21 08:20:04 -07:00
if (!isSdCardAlive()) {
2015-07-10 06:01:56 -07:00
MMCmount();
}
2017-02-08 20:03:36 -08:00
} else {
sdStatus = SD_STATE_NOT_INSERTED;
2015-07-10 06:01:56 -07:00
}
2019-09-21 08:09:03 -07:00
if (isSdCardAlive()) {
2015-07-10 06:01:56 -07:00
writeLogLine();
2019-09-21 08:09:03 -07:00
} else {
chThdSleepMilliseconds(100);
}
2015-07-10 06:01:56 -07:00
2019-09-21 08:09:03 -07:00
if (boardConfiguration->sdCardPeriodMs > 0) {
chThdSleepMilliseconds(boardConfiguration->sdCardPeriodMs);
}
2015-07-10 06:01:56 -07:00
}
}
bool isSdCardAlive(void) {
return fs_ready;
}
void initMmcCard(void) {
logName[0] = 0;
addConsoleAction("sdinfo", sdStatistics);
if (!CONFIGB(isSdCardEnabled)) {
2015-07-10 06:01:56 -07:00
return;
}
2019-03-25 19:41:31 -07:00
// todo: reuse initSpiCs method?
hs_spicfg.ssport = ls_spicfg.ssport = getHwPort("mmc", CONFIGB(sdCardCsPin));
hs_spicfg.sspad = ls_spicfg.sspad = getHwPin("mmc", CONFIGB(sdCardCsPin));
2017-04-11 16:25:31 -07:00
mmccfg.spip = getSpiDevice(engineConfiguration->sdCardSpiDevice);
2015-07-10 06:01:56 -07:00
/**
* FYI: SPI does not work with CCM memory, be sure to have main() stack in RAM, not in CCMRAM
*/
2016-07-07 07:01:47 -07:00
// start to initialize MMC/SD
mmcObjectInit(&MMCD1); // Initializes an instance.
2016-07-06 21:05:28 -07:00
mmcStart(&MMCD1, &mmccfg);
2015-07-10 06:01:56 -07:00
2018-12-27 06:40:40 -08:00
chThdCreateStatic(mmcThreadStack, sizeof(mmcThreadStack), LOWPRIO, (tfunc_t)(void*) MMCmonThread, NULL);
2015-07-10 06:01:56 -07:00
addConsoleAction("mountsd", MMCmount);
addConsoleActionS("appendtolog", appendToLog);
2015-07-10 06:01:56 -07:00
addConsoleAction("umountsd", MMCumount);
addConsoleActionS("ls", listDirectory);
addConsoleActionS("del", removeFile);
addConsoleAction("incfilename", incLogFileName);
}
#endif /* EFI_FILE_LOGGING */