/** * @file mmc_card.cpp * * @date Dec 28, 2013 * @author Kot_dnz * @author Andrey Belomutskiy, (c) 2012-2020 * * 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 */ #include "pch.h" #if EFI_FILE_LOGGING #include "buffered_writer.h" #include "status_loop.h" #include "binary_logging.h" // Divide logs into 32Mb chunks. // With this opstion defined SW will pre-allocate file with given size and // should not touch FAT structures until file is fully filled // This should protect FS from corruption at sudden power loss #define LOGGER_MAX_FILE_SIZE (32 * 1024 * 1024) // at about 20Hz we write about 2Kb per second, looks like we flush once every ~2 seconds #define F_SYNC_FREQUENCY 10 static bool sdLoggerReady = false; #if EFI_PROD_CODE #include #include #include "mmc_card.h" #include "ff.h" #include "mmc_card_util.h" #include "mass_storage_init.h" #include "hellen_meta.h" #include "rtc_helper.h" // TODO: do we need this additioal layer of buffering? // FIL structure already have buffer of FF_MAX_SS size // check if it is better to increase FF_MAX_SS and drop BufferedWriter? struct SdLogBufferWriter final : public BufferedWriter<512> { bool failed = false; int start(FIL *fd) { if (m_fd) { efiPrintf("SD logger already started!"); return -1; } totalLoggedBytes = 0; writeCounter = 0; m_fd = fd; return 0; } void stop() { m_fd = nullptr; flush(); totalLoggedBytes = 0; writeCounter = 0; } size_t writen() { return totalLoggedBytes; } size_t writeInternal(const char* buffer, size_t count) override { if ((!m_fd) || (failed)) { return 0; } size_t bytesWritten; efiAssert(ObdCode::CUSTOM_STACK_6627, hasLotsOfRemainingStack(), "sdlow#3", 0); FRESULT err = f_write(m_fd, buffer, count, &bytesWritten); if (err) { printError("log file write", err); failed = true; return 0; } else if (bytesWritten != count) { printError("log file write partitial", err); failed = true; return 0; } else { writeCounter++; totalLoggedBytes += count; 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 actually measure the relative cost of f_sync */ f_sync(m_fd); writeCounter = 0; } } return bytesWritten; } private: FIL *m_fd = nullptr; size_t totalLoggedBytes = 0; size_t writeCounter = 0; }; #else // not EFI_PROD_CODE (simulator) #include class SdLogBufferWriter final : public BufferedWriter<512> { public: bool failed = false; SdLogBufferWriter() : m_stream("rusefi_simulator_log.mlg", std::ios::binary | std::ios::trunc) { sdLoggerReady = true; } size_t writeInternal(const char* buffer, size_t count) override { m_stream.write(buffer, count); m_stream.flush(); return count; } private: std::ofstream m_stream; }; #endif static NO_CACHE SdLogBufferWriter logBuffer; #if EFI_PROD_CODE // This is dirty workaround to fix compilation without adding this function prototype // to error_handling.h file that will also need to add "ff.h" include to same file and // cause simulator fail to build. extern void errorHandlerWriteReportFile(FIL *fd); extern int errorHandlerCheckReportFiles(); extern void errorHandlerDeleteReports(); typedef enum { SD_STATUS_INIT = 0, SD_STATUS_MOUNTED, SD_STATUS_MOUNT_FAILED, SD_STATUS_OPEN_FAILED, SD_STATUS_SEEK_FAILED, SD_STATUS_NOT_INSERTED, SD_STATUS_CONNECTING, SD_STATUS_MSD, SD_STATUS_MMC_FAILED } SD_STATUS; // todo: shall we migrate to enum with enum2string for consistency? maybe not until we start reading sdStatus? static const char *sdStatusNames[] = { "INIT", "MOUNTED", "MOUNT_FAILED", "OPEN_FAILED", "SEEK_FAILED", "NOT_INSERTED", "CONNECTING", "MSD", "MMC_CONNECT_FAILED" }; static const char *sdStatusName(SD_STATUS status) { return sdStatusNames[status]; } static SD_STATUS sdStatus = SD_STATUS_INIT; static SD_MODE sdMode = SD_MODE_IDLE; // by default we want SD card for logs static SD_MODE sdTargerMode = SD_MODE_ECU; static bool sdNeedRemoveReports = false; /** * on't re-read SD card spi device after boot - it could change mid transaction (TS thread could preempt), * which will cause disaster (usually multiple-unlock of the same mutex in UNLOCK_SD_SPI) */ static spi_device_e mmcSpiDevice = SPI_NONE; #define RUSEFI_LOG_PREFIX "re_" #define PREFIX_LEN 3 #define SHORT_TIME_LEN 13 #define FILE_LIST_MAX_COUNT 20 #if HAL_USE_MMC_SPI /** * MMC driver instance. */ MMCDriver MMCD1; /* MMC/SD over SPI driver configuration.*/ static MMCConfig mmccfg = { .spip = NULL, .lscfg = &mmc_ls_spicfg, .hscfg = &mmc_hs_spicfg }; #if MMC_USE_MUTUAL_EXCLUSION == TRUE #define LOCK_SD_SPI() #define UNLOCK_SD_SPI() #else #define LOCK_SD_SPI() lockSpi(mmcSpiDevice) #define UNLOCK_SD_SPI() unlockSpi(mmcSpiDevice) #endif #endif /* HAL_USE_MMC_SPI */ /** * fatfs MMC/SPI */ static NO_CACHE FATFS MMC_FS; static void sdLoggerSetReady(bool value) { sdLoggerReady = value; } static bool sdLoggerIsReady(void) { return sdLoggerReady; } /* See ff.h FRESULT enum */ static const char *fatErrors[] = { "FR_OK: Succeeded", "FR_DISK_ERR: A hard error occurred in the low level disk I/O layer", "FR_INT_ERR: Assertion failed", "FR_NOT_READY: The physical drive cannot work", "FR_NO_FILE: Could not find the file", "FR_NO_PATH: Could not find the path", "FR_INVALID_NAME: The path name format is invalid", "FR_DENIED: Access denied due to prohibited access or directory full", "FR_EXIST: Access denied due to prohibited access", "FR_INVALID_OBJECT: The file/directory object is invalid", "FR_WRITE_PROTECTED: The physical drive is write protected", "FR_INVALID_DRIVE: The logical drive number is invalid", "FR_NOT_ENABLED: The volume has no work area", "FR_NO_FILESYSTEM: There is no valid FAT volume", "FR_MKFS_ABORTED: The f_mkfs() aborted due to any problem", "FR_TIMEOUT: Could not get a grant to access the volume within defined period", "FR_LOCKED: The operation is rejected according to the file sharing policy", "FR_NOT_ENOUGH_CORE: LFN working buffer could not be allocated", "FR_TOO_MANY_OPEN_FILES: Number of open files > FF_FS_LOCK", "FR_INVALID_PARAMETER: Given parameter is invalid" }; // print FAT error function void printError(const char *str, FRESULT f_error) { static int fatFsErrors = 0; if (fatFsErrors++ > 16) { // no reason to spam the console return; } efiPrintf("FATfs Error \"%s\" %d %s", str, f_error, f_error <= FR_INVALID_PARAMETER ? fatErrors[f_error] : "unknown"); } // Warning: shared between all FS users, please release it after use static FIL FDLogFile NO_CACHE; extern int logFileIndex; static char logName[_MAX_FILLER + 20]; static void printMmcPinout() { efiPrintf("MMC CS %s", hwPortname(engineConfiguration->sdCardCsPin)); // todo: we need to figure out the right SPI pinout, not just SPI2 // efiPrintf("MMC SCK %s:%d", portname(EFI_SPI2_SCK_PORT), EFI_SPI2_SCK_PIN); // efiPrintf("MMC MISO %s:%d", portname(EFI_SPI2_MISO_PORT), EFI_SPI2_MISO_PIN); // efiPrintf("MMC MOSI %s:%d", portname(EFI_SPI2_MOSI_PORT), EFI_SPI2_MOSI_PIN); } static void sdStatistics() { printMmcPinout(); efiPrintf("SD enabled=%s status=%s", boolToString(engineConfiguration->isSdCardEnabled), sdStatusName(sdStatus)); printSpiConfig("SD", mmcSpiDevice); #if HAL_USE_MMC_SPI && (defined(STM32F4XX) || defined(STM32F7XX)) efiPrintf("HS clock %d Hz", spiGetBaseClock(mmccfg.spip) / (2 << ((mmc_hs_spicfg.cr1 & SPI_CR1_BR_Msk) >> SPI_CR1_BR_Pos))); efiPrintf("LS clock %d Hz", spiGetBaseClock(mmccfg.spip) / (2 << ((mmc_ls_spicfg.cr1 & SPI_CR1_BR_Msk) >> SPI_CR1_BR_Pos))); #endif if (sdLoggerIsReady()) { efiPrintf("filename=%s size=%d", logName, logBuffer.writen()); } #if EFI_FILE_LOGGING efiPrintf("%d SD card fields", getSdCardFieldsCount()); #endif } static void sdSetMode(const char *mode) { if (strcmp(mode, "pc") == 0) { sdCardRequestMode(SD_MODE_PC); } else if (strcmp(mode, "ecu") == 0) { sdCardRequestMode(SD_MODE_ECU); } else { efiPrintf("Invalid mode %s allowed modes pc and ecu", mode); } } static void prepareLogFileName() { strcpy(logName, RUSEFI_LOG_PREFIX); char *ptr; // TS SD protocol supports only short 8 symbol file names, good thing that we do not use TS SD protocol! bool result = dateToStringShort(&logName[PREFIX_LEN]); if (result) { ptr = &logName[PREFIX_LEN + SHORT_TIME_LEN]; } else { ptr = itoa10(&logName[PREFIX_LEN], logFileIndex); } if (engineConfiguration->sdTriggerLog) { strcat(ptr, ".teeth"); } else { strcat(ptr, DOT_MLG); } } /** * @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 sdLoggerCreateFile(FIL *fd) { // clear the memory memset(fd, 0, sizeof(FIL)); prepareLogFileName(); efiPrintf("starting log file %s", logName); // Create new file. If file is exist - truncate and overwrite, we need header to be at zero offset. FRESULT err = f_open(fd, logName, FA_CREATE_ALWAYS | FA_WRITE); if (err != FR_OK && err != FR_EXIST) { sdStatus = SD_STATUS_OPEN_FAILED; warning(ObdCode::CUSTOM_ERR_SD_MOUNT_FAILED, "SD: mount failed"); printError("log file create", err); // else - show error return; } #ifdef LOGGER_MAX_FILE_SIZE //pre-allocate data ahead err = f_expand(fd, LOGGER_MAX_FILE_SIZE, /* Find and allocate */ 1); if (err != FR_OK) { printError("pre-allocate", err); // this is not critical } #endif // SD logger is ok sdLoggerSetReady(true); } static void sdLoggerCloseFile(FIL *fd) { #ifdef LOGGER_MAX_FILE_SIZE // truncate file to actual size f_truncate(fd); #endif // close file f_close(fd); // f_sync is called internally //f_sync(&FDLogFile); // SD logger is inactive sdLoggerSetReady(false); } static void removeFile(const char *pathx) { if (sdMode != SD_MODE_ECU) { efiPrintf("SD card should be mounted to ECU"); return; } f_unlink(pathx); } #if HAL_USE_USB_MSD static chibios_rt::BinarySemaphore usbConnectedSemaphore(/* taken =*/ true); void onUsbConnectedNotifyMmcI() { usbConnectedSemaphore.signalI(); } #endif /* HAL_USE_USB_MSD */ #if HAL_USE_MMC_SPI /* * Attempts to initialize the MMC card connected over SPI. * Returns a BaseBlockDevice* corresponding to the SD card if successful, otherwise nullptr. */ static BaseBlockDevice* initializeMmcBlockDevice() { // Configures and activates the MMC peripheral. mmcSpiDevice = engineConfiguration->sdCardSpiDevice; // todo: reuse initSpiCs method? mmc_hs_spicfg.ssport = mmc_ls_spicfg.ssport = getHwPort("mmc", engineConfiguration->sdCardCsPin); mmc_hs_spicfg.sspad = mmc_ls_spicfg.sspad = getHwPin("mmc", engineConfiguration->sdCardCsPin); mmccfg.spip = getSpiDevice(mmcSpiDevice); // Invalid SPI device, abort. if (!mmccfg.spip) { return nullptr; } // max SPI rate is 25 MHz after init spiCalcClockDiv(mmccfg.spip, &mmc_hs_spicfg, 25 * 1000 * 1000); // and 250 KHz during initialization spiCalcClockDiv(mmccfg.spip, &mmc_ls_spicfg, 250 * 1000); // We think we have everything for the card, let's try to mount it! mmcObjectInit(&MMCD1); mmcStart(&MMCD1, &mmccfg); // Performs the initialization procedure on the inserted card. LOCK_SD_SPI(); if (blkConnect(&MMCD1) != HAL_SUCCESS) { sdStatus = SD_STATUS_MMC_FAILED; UNLOCK_SD_SPI(); return nullptr; } // We intentionally never unlock in case of success, we take exclusive access of that spi device for SD use return reinterpret_cast(&MMCD1); } static void deinitializeMmcBlockDevide() { blkDisconnect(&MMCD1); // Brings the driver in a state safe for card removal. mmcStop(&MMCD1); // Disables the MMC peripheral. UNLOCK_SD_SPI(); } #endif /* HAL_USE_MMC_SPI */ #ifndef RE_SDC_MODE #define RE_SDC_MODE SDC_MODE_4BIT #endif // RE_SDC_MODE // Some ECUs are wired for SDIO/SDMMC instead of SPI #ifdef EFI_SDC_DEVICE static const SDCConfig sdcConfig = { .bus_width = RE_SDC_MODE }; /* * Attempts to initialize the MMC card connected over SDIO. * Returns a BaseBlockDevice* corresponding to the SD card if successful, otherwise nullptr. */ static BaseBlockDevice* initializeMmcBlockDevice() { sdcStart(&EFI_SDC_DEVICE, &sdcConfig); if (blkConnect(&EFI_SDC_DEVICE) != HAL_SUCCESS) { return nullptr; } return reinterpret_cast(&EFI_SDC_DEVICE); } static void deinitializeMmcBlockDevide() { blkDisconnect(&EFI_SDC_DEVICE); sdcStop(&EFI_SDC_DEVICE); } #endif /* EFI_SDC_DEVICE */ #if HAL_USE_USB_MSD static bool useMsdMode() { if (engineConfiguration->alwaysWriteSdCard) { return false; } // Wait for the USB stack to wake up, or a 15 second timeout, whichever occurs first msg_t usbResult = usbConnectedSemaphore.wait(TIME_MS2I(15000)); return usbResult == MSG_OK; } #endif // HAL_USE_USB_MSD static BaseBlockDevice* cardBlockDevice = nullptr; // Initialize SD card. static bool initMmc() { // Don't try to mount SD card in case of fatal error - hardware may be in an unexpected state if (hasFirmwareError()) { return false; } cardBlockDevice = initializeMmcBlockDevice(); #if EFI_TUNER_STUDIO // If not null, card is present engine->outputChannels.sd_present = cardBlockDevice != nullptr; #endif return (cardBlockDevice != nullptr); } static void deinitMmc() { if (cardBlockDevice) { deinitializeMmcBlockDevide(); } cardBlockDevice = nullptr; engine->outputChannels.sd_present = false; } // Mount the SD card. // Returns true if the filesystem was successfully mounted for writing. static bool mountMmc() { bool ret = false; // if no card, don't try to mount FS if (cardBlockDevice != nullptr) { // We were able to connect the SD card, mount the filesystem memset(&MMC_FS, 0, sizeof(FATFS)); ret = (f_mount(&MMC_FS, "/", /* Mount immediately */ 1) == FR_OK); if (ret == false) { sdStatus = SD_STATUS_MOUNT_FAILED; efiPrintf("MMC/SD card mount failed!"); } } if (ret) { sdStatus = SD_STATUS_MOUNTED; efiPrintf("MMC/SD mounted!"); } #if EFI_TUNER_STUDIO engine->outputChannels.sd_logging_internal = ret; #endif return ret; } /* * MMC card un-mount. * @return true if we had SD card alive */ static void unmountMmc() { // FATFS: Unregister work area prior to discard it f_mount(NULL, 0, 0); #if EFI_TUNER_STUDIO engine->outputChannels.sd_logging_internal = false; #endif efiPrintf("SD card unmounted"); } #else // not EFI_PROD_CODE (simulator) bool initMmc() { // Stub so the loop thinks the MMC is present return true; } bool mountMmc() { // Stub so the loop thinks the MMC mounted OK return true; } #endif // EFI_PROD_CODE #if EFI_PROD_CODE // Log 'regular' ECU log to MLG file static int mlgLogger(); // Log binary trigger log static int sdTriggerLogger(); static bool sdLoggerInitDone = false; static bool sdLoggerFailed = false; static int sdLogger() { int ret = 0; if (!sdLoggerInitDone) { incLogFileName(&FDLogFile); sdLoggerCreateFile(&FDLogFile); logBuffer.start(&FDLogFile); resetFileLogging(); sdLoggerInitDone = true; } if (!sdLoggerFailed) { if (engineConfiguration->sdTriggerLog) { ret = sdTriggerLogger(); } else { ret = mlgLogger(); } } if (ret < 0) { sdLoggerFailed = true; } #ifdef LOGGER_MAX_FILE_SIZE // check if we need to start next log file // in next write (assume same size as current) will cross LOGGER_MAX_FILE_SIZE boundary // TODO: use f_tell() instead ? if (logBuffer.writen() + ret > LOGGER_MAX_FILE_SIZE) { logBuffer.stop(); sdLoggerCloseFile(&FDLogFile); //start new file incLogFileName(&FDLogFile); sdLoggerCreateFile(&FDLogFile); logBuffer.start(&FDLogFile); resetFileLogging(); } #endif return ret; } static void sdLoggerStart(void) { sdLoggerInitDone = false; sdLoggerFailed = false; #if EFI_TOOTH_LOGGER // TODO: cache this config option untill sdLoggerStop() if (engineConfiguration->sdTriggerLog) { EnableToothLogger(); } #endif } static void sdLoggerStop(void) { sdLoggerCloseFile(&FDLogFile); #if EFI_TOOTH_LOGGER // TODO: cache this config option untill sdLoggerStop() if (engineConfiguration->sdTriggerLog) { DisableToothLogger(); } #endif } // TODO: optimal cluster size? // buffer is needed only for f_mkfs, use some shared buffer? #define FATFS_CLUSTER_SIZE 1024 static NO_CACHE BYTE formatBuff[FATFS_CLUSTER_SIZE]; static bool sdFormat() { //FRESULT ret = f_mkfs("", nullptr, formatBuff, sizeof(formatBuff)); FRESULT ret = f_mkfs("", nullptr, formatBuff, sizeof(formatBuff)); if (ret) { printError("format failed", ret); warning(ObdCode::CUSTOM_ERR_SD_MOUNT_FAILED, "SD: format failed"); return false; } ret = f_setlabel(SD_CARD_LABEL); if (ret) { printError("setlabel failed", ret); // this is not critical } return true; } static int sdModeSwitchToIdle(SD_MODE from) { switch (from) { case SD_MODE_IDLE: return 0; case SD_MODE_ECU: sdLoggerStop(); unmountMmc(); return 0; case SD_MODE_PC: deattachMsdSdCard(); return 0; case SD_MODE_UNMOUNT: return 0; case SD_MODE_FORMAT: //not allowed to interrupt formating process return -1; } efiPrintf("Invalid SD card thread state: %d", static_cast(from)); return -1; } static int sdModeSwitcher() { if (sdTargerMode == SD_MODE_IDLE) { return 0; } if (sdMode == sdTargerMode) { // already here sdTargerMode = SD_MODE_IDLE; return 0; } if (sdMode != SD_MODE_IDLE) { int ret = sdModeSwitchToIdle(sdMode); if (ret) { return ret; } sdMode = SD_MODE_IDLE; } if (sdMode != SD_MODE_IDLE) { return -1; } // Now SD card is in idle state, we can switch into target state switch (sdTargerMode) { case SD_MODE_IDLE: return 0; case SD_MODE_UNMOUNT: // everithing is done in sdModeSwitchToIdle(); sdMode = SD_MODE_UNMOUNT; sdTargerMode = SD_MODE_IDLE; return 0; case SD_MODE_ECU: if (mountMmc()) { sdLoggerStart(); sdMode = SD_MODE_ECU; } else { // failed to mount SD card to ECU, go to idle sdMode = SD_MODE_IDLE; } sdTargerMode = SD_MODE_IDLE; return 0; case SD_MODE_PC: attachMsdSdCard(cardBlockDevice); sdStatus = SD_STATUS_MSD; sdMode = SD_MODE_PC; sdTargerMode = SD_MODE_IDLE; return 0; case SD_MODE_FORMAT: if (sdFormat()) { // formated ok } sdMode = SD_MODE_IDLE; // TODO: return to mode that was used before format was requested! sdTargerMode = SD_MODE_IDLE; return 0; } // should not happen return -1; } static int sdModeExecuter() { switch (sdMode) { case SD_MODE_IDLE: case SD_MODE_PC: case SD_MODE_UNMOUNT: case SD_MODE_FORMAT: // nothing to do in these state, just sleep chThdSleepMilliseconds(TIME_MS2I(100)); return 0; case SD_MODE_ECU: if (sdNeedRemoveReports) { errorHandlerDeleteReports(); sdNeedRemoveReports = false; } // execute logger return sdLogger(); } return 0; } static int sdReportStorageInit() { if (mountMmc()) { // write error report file if needed errorHandlerWriteReportFile(&FDLogFile); // check for any exist reports errorHandlerCheckReportFiles(); // done with SD card unmountMmc(); return 0; } // card is failed to mount return -1; } static THD_WORKING_AREA(mmcThreadStack, 3 * UTILITY_THREAD_STACK_SIZE); // MMC monitor thread static THD_FUNCTION(MMCmonThread, arg) { (void)arg; chRegSetThreadName("MMC Card Logger"); #if HW_HELLEN && EFI_PROD_CODE // on mega-module we manage SD card power supply while (!getHellenBoardEnabled()) { // wait until board enables peripheral chThdSleepMilliseconds(100); if (getTimeNowS() > 4 && !isIgnVoltage()) { // looks like vehicle is OFF and we are hooked to USB - turn on peripheral to get Mass Storage Device USB profile efiPrintf(" *** turning board ON to power SD card ***"); hellenEnableEn(); break; } } chThdSleepMilliseconds(300); #endif sdStatus = SD_STATUS_CONNECTING; if (!initMmc()) { efiPrintf("Card is not preset/failed to init"); sdStatus = SD_STATUS_NOT_INSERTED; // give up until next boot goto die; } // Try to mount SD card, drop critical report if needed and check for previously stored reports sdReportStorageInit(); #if HAL_USE_USB_MSD // Wait for the USB stack to wake up, or a 15 second timeout, whichever occurs first // If we have a device AND USB is connected, mount the card to USB, otherwise // mount the null device and try to mount the filesystem ourselves if (useMsdMode()) { sdTargerMode = SD_MODE_PC; } #endif while (1) { sdModeSwitcher(); sdModeExecuter(); } die: // bring SD interface to safe state deinitMmc(); efiPrintf("SD logger has died!"); // exiting thread will create zombie! while(1) { chThdSleepMilliseconds(100); } } static int mlgLogger() { // TODO: move this check somewhere out of here! // if the SPI device got un-picked somehow, cancel SD card // Don't do this check at all if using SDMMC interface instead of SPI #if EFI_PROD_CODE && !defined(EFI_SDC_DEVICE) if (engineConfiguration->sdCardSpiDevice == SPI_NONE) { return 0; } #endif systime_t before = chVTGetSystemTime(); size_t writen = writeSdLogLine(logBuffer); // Something went wrong (already handled), so cancel further writes if (logBuffer.failed) { return -1; } auto freq = engineConfiguration->sdCardLogFrequency; if (freq > 250) { freq = 250; } else if (freq < 1) { freq = 1; } systime_t period = CH_CFG_ST_FREQUENCY / freq; chThdSleepUntilWindowed(before, before + period); return writen; } static int sdTriggerLogger() { size_t toWrite = 0; #if EFI_TOOTH_LOGGER auto buffer = GetToothLoggerBufferBlocking(); // can return nullptr if (buffer) { toWrite = buffer->nextIdx * sizeof(composite_logger_s); logBuffer.write(reinterpret_cast(buffer->buffer), toWrite); if (logBuffer.failed) { return -1; } ReturnToothLoggerBuffer(buffer); } #endif /* EFI_TOOTH_LOGGER */ return toWrite; } #endif // EFI_PROD_CODE void updateSdCardLiveFlags() { #if EFI_PROD_CODE if (cardBlockDevice) { engine->outputChannels.sd_active_wr = (blkGetDriverState(cardBlockDevice) == BLK_WRITING); engine->outputChannels.sd_active_rd = (blkGetDriverState(cardBlockDevice) == BLK_READING); } else #endif // EFI_PROD_CODE { engine->outputChannels.sd_active_wr = false; engine->outputChannels.sd_active_rd = false; } } // Pre-config load init void initEarlyMmcCard() { #if EFI_PROD_CODE logName[0] = 0; addConsoleAction("sdinfo", sdStatistics); addConsoleActionS("del", removeFile); addConsoleActionS("sdmode", sdSetMode); addConsoleAction("delreports", sdCardRemoveReportFiles); //incLogFileName() use same shared FDLogFile, calling it while FDLogFile is used by log writer will cause damage //addConsoleAction("incfilename", incLogFileName); #endif // EFI_PROD_CODE } static bool isSdCardEnabled() { return engineConfiguration->isSdCardEnabled && engineConfiguration->sdCardSpiDevice != SPI_NONE && isBrainPinValid(engineConfiguration->sdCardCsPin); } void initMmcCard() { if (!isSdCardEnabled()) { // do not even bother starting the thread if SD card is not enabled & configured on start-up return; } #if EFI_PROD_CODE chThdCreateStatic(mmcThreadStack, sizeof(mmcThreadStack), PRIO_MMC, (tfunc_t)(void*) MMCmonThread, NULL); #endif // EFI_PROD_CODE } #if EFI_PROD_CODE void sdCardRequestMode(SD_MODE mode) { if (sdTargerMode == SD_MODE_IDLE) { sdTargerMode = mode; } } void sdCardRemoveReportFiles() { if (sdMode != SD_MODE_ECU) { efiPrintf("SD card should be mounted to ECU"); return; } sdNeedRemoveReports = true; } #endif // EFI_PROD_CODE #endif /* EFI_FILE_LOGGING */