rusEFI
The most advanced open source ECU
Loading...
Searching...
No Matches
mmc_card.cpp
Go to the documentation of this file.
1/**
2 * @file mmc_card.cpp
3 *
4 * @date Dec 28, 2013
5 * @author Kot_dnz
6 * @author Andrey Belomutskiy, (c) 2012-2020
7 *
8 * default pinouts in case of SPI2 connected to MMC: PB13 - SCK, PB14 - MISO, PB15 - MOSI, PD4 - CS, 3.3v
9 * default pinouts in case of SPI3 connected to MMC: PB3 - SCK, PB4 - MISO, PB5 - MOSI, PD4 - CS, 3.3v
10 *
11 *
12 * todo: extract some logic into a controller file
13 */
14
15#include "pch.h"
16
17#if EFI_FILE_LOGGING
18
19#include "buffered_writer.h"
20#include "status_loop.h"
21#include "binary_mlg_logging.h"
22
23// Divide logs into 32Mb chunks.
24// With this opstion defined SW will pre-allocate file with given size and
25// should not touch FAT structures until file is fully filled
26// This should protect FS from corruption at sudden power loss
27#define LOGGER_MAX_FILE_SIZE (32 * 1024 * 1024)
28
29// at about 20Hz we write about 2Kb per second, looks like we flush once every ~2 seconds
30#define F_SYNC_FREQUENCY 10
31
32static bool sdLoggerReady = false;
33
34#if EFI_PROD_CODE
35
36#include <cstdio>
37#include <cstring>
38#include "mmc_card.h"
39#include "ff.h"
40#include "mmc_card_util.h"
41#include "mass_storage_init.h"
42#include "hellen_meta.h"
43
44#include "rtc_helper.h"
45
46#if EFI_STORAGE_SD == TRUE
47#include "storage_sd.h"
48#endif // EFI_STORAGE_SD
49
50// TODO: do we need this additioal layer of buffering?
51// FIL structure already have buffer of FF_MAX_SS size
52// check if it is better to increase FF_MAX_SS and drop BufferedWriter?
53struct SdLogBufferWriter final : public BufferedWriter<512> {
54 bool failed = false;
55
56 int start(FIL *fd) {
57 if (m_fd) {
58 efiPrintf("SD logger already started!");
59 return -1;
60 }
61
62 totalLoggedBytes = 0;
63 writeCounter = 0;
64
65 m_fd = fd;
66
67 return 0;
68 }
69
70 void stop() {
71 m_fd = nullptr;
72
73 flush();
74
75 totalLoggedBytes = 0;
76 writeCounter = 0;
77 }
78
79 size_t writen() {
80 return totalLoggedBytes;
81 }
82
83 size_t writeInternal(const char* buffer, size_t count) override {
84 if ((!m_fd) || (failed)) {
85 return 0;
86 }
87
88 size_t bytesWritten;
89 efiAssert(ObdCode::CUSTOM_STACK_6627, hasLotsOfRemainingStack(), "sdlow#3", 0);
90 FRESULT err = f_write(m_fd, buffer, count, &bytesWritten);
91
92 if (err) {
93 printFatFsError("log file write", err);
94 failed = true;
95 return 0;
96 } else if (bytesWritten != count) {
97 printFatFsError("log file write partitial", err);
98 failed = true;
99 return 0;
100 } else {
101 writeCounter++;
102 totalLoggedBytes += count;
103 if (writeCounter >= F_SYNC_FREQUENCY) {
104 /**
105 * Performance optimization: not f_sync after each line, f_sync is probably a heavy operation
106 * todo: one day someone should actually measure the relative cost of f_sync
107 */
108 f_sync(m_fd);
109 writeCounter = 0;
110 }
111 }
112
113 return bytesWritten;
114 }
115
116private:
117 FIL *m_fd = nullptr;
118
119 size_t totalLoggedBytes = 0;
120 size_t writeCounter = 0;
121};
122
123#else // not EFI_PROD_CODE (simulator)
124
125#include <fstream>
126
127class SdLogBufferWriter final : public BufferedWriter<512> {
128public:
129 bool failed = false;
130
131 SdLogBufferWriter()
132 : m_stream("rusefi_simulator_log.mlg", std::ios::binary | std::ios::trunc)
133 {
134 sdLoggerReady = true;
135 }
136
137 size_t writeInternal(const char* buffer, size_t count) override {
138 m_stream.write(buffer, count);
139 m_stream.flush();
140 return count;
141 }
142
143private:
144 std::ofstream m_stream;
145};
146
147#endif
148
149static NO_CACHE SdLogBufferWriter logBuffer;
150
151#if EFI_PROD_CODE
152
153// This is dirty workaround to fix compilation without adding this function prototype
154// to error_handling.h file that will also need to add "ff.h" include to same file and
155// cause simulator fail to build.
156extern void errorHandlerWriteReportFile(FIL *fd);
158extern void errorHandlerDeleteReports();
159
160// see also SD_MODE
172
173// todo: shall we migrate to enum with enum2string for consistency? maybe not until we start reading sdStatus?
174static const char *sdStatusNames[] =
175{
176 "INIT",
177 "MOUNTED",
178 "MOUNT_FAILED",
179 "OPEN_FAILED",
180 "SEEK_FAILED",
181 "NOT_INSERTED",
182 "CONNECTING",
183 "MSD",
184 "MMC_CONNECT_FAILED"
185};
186
187static const char *sdStatusName(SD_STATUS status)
188{
189 return sdStatusNames[status];
190}
191
193
195// by default we want SD card for logs
197
198static bool sdNeedRemoveReports = false;
199
200#define RUSEFI_LOG_PREFIX "re_"
201#define PREFIX_LEN 3
202#define SHORT_TIME_LEN 13
203
204#define FILE_LIST_MAX_COUNT 20
205
206#if HAL_USE_MMC_SPI
207/**
208 * on't re-read SD card spi device after boot - it could change mid transaction (TS thread could preempt),
209 * which will cause disaster (usually multiple-unlock of the same mutex in UNLOCK_SD_SPI)
210 */
211static spi_device_e mmcSpiDevice = SPI_NONE;
212
213/**
214 * MMC driver instance.
215 */
216static NO_CACHE uint8_t mmcbuf[MMC_BUFFER_SIZE];
217MMCDriver MMCD1;
218
219/* MMC/SD over SPI driver configuration.*/
220static MMCConfig mmccfg = {
221 .spip = NULL,
222 .lscfg = &mmc_ls_spicfg,
223 .hscfg = &mmc_hs_spicfg
224};
225
226#if MMC_USE_MUTUAL_EXCLUSION == TRUE
227#define LOCK_SD_SPI()
228#define UNLOCK_SD_SPI()
229#else
230#define LOCK_SD_SPI() lockSpi(mmcSpiDevice)
231#define UNLOCK_SD_SPI() unlockSpi(mmcSpiDevice)
232#endif
233
234#endif /* HAL_USE_MMC_SPI */
235
236/**
237 * fatfs MMC/SPI
238 */
239static NO_CACHE FATFS MMC_FS;
240
241static void sdLoggerSetReady(bool value) {
242 sdLoggerReady = value;
243}
244
245static bool sdLoggerIsReady() {
246 return sdLoggerReady;
247}
248
249/* See ff.h FRESULT enum */
250static const char *fatErrors[] = {
251 "FR_OK: Succeeded",
252 "FR_DISK_ERR: A hard error occurred in the low level disk I/O layer",
253 "FR_INT_ERR: Assertion failed",
254 "FR_NOT_READY: The physical drive cannot work",
255 "FR_NO_FILE: Could not find the file",
256 "FR_NO_PATH: Could not find the path",
257 "FR_INVALID_NAME: The path name format is invalid",
258 "FR_DENIED: Access denied due to prohibited access or directory full",
259 "FR_EXIST: Access denied due to prohibited access",
260 "FR_INVALID_OBJECT: The file/directory object is invalid",
261 "FR_WRITE_PROTECTED: The physical drive is write protected",
262 "FR_INVALID_DRIVE: The logical drive number is invalid",
263 "FR_NOT_ENABLED: The volume has no work area",
264 "FR_NO_FILESYSTEM: There is no valid FAT volume",
265 "FR_MKFS_ABORTED: The f_mkfs() aborted due to any problem",
266 "FR_TIMEOUT: Could not get a grant to access the volume within defined period",
267 "FR_LOCKED: The operation is rejected according to the file sharing policy",
268 "FR_NOT_ENOUGH_CORE: LFN working buffer could not be allocated",
269 "FR_TOO_MANY_OPEN_FILES: Number of open files > FF_FS_LOCK",
270 "FR_INVALID_PARAMETER: Given parameter is invalid"
271};
272
273// print FAT error function
274void printFatFsError(const char *str, FRESULT f_error) {
275 static int fatFsErrors = 0;
276
277 if (fatFsErrors++ > 16) {
278 // no reason to spam the console
279 return;
280 }
281
282 efiPrintf("%s FATfs Error %d %s", str, f_error, f_error <= FR_INVALID_PARAMETER ? fatErrors[f_error] : "unknown");
283}
284
285// format, file access and MSD are used exclusively, we can union.
286static union {
287 // Warning: shared between all FS users, please release it after use
288 FIL fd;
289 // TODO: optimal cluster size?
290 #define FATFS_CLUSTER_SIZE 1024
291 BYTE formatBuff[FATFS_CLUSTER_SIZE];
292 // MSD read/write buffer
293 uint8_t blkbuf[4 * MMCSD_BLOCK_SIZE];
294} resources NO_CACHE;
295
296extern int logFileIndex;
297static char logName[_MAX_FILLER + 20];
298
299static void printMmcPinout() {
300#if HAL_USE_MMC_SPI
301 efiPrintf("MMC CS %s", hwPortname(engineConfiguration->sdCardCsPin));
302 // todo: we need to figure out the right SPI pinout, not just SPI2
303// efiPrintf("MMC SCK %s:%d", portname(EFI_SPI2_SCK_PORT), EFI_SPI2_SCK_PIN);
304// efiPrintf("MMC MISO %s:%d", portname(EFI_SPI2_MISO_PORT), EFI_SPI2_MISO_PIN);
305// efiPrintf("MMC MOSI %s:%d", portname(EFI_SPI2_MOSI_PORT), EFI_SPI2_MOSI_PIN);
306#else
307 // not sure if we need to print SDIO pinout
308#endif
309}
310
311static void sdStatistics() {
313 efiPrintf("SD enabled=%s status=%s", boolToString(engineConfiguration->isSdCardEnabled),
315#if HAL_USE_MMC_SPI
317 #if defined(STM32F4XX) || defined(STM32F7XX)
318 efiPrintf("HS clock %d Hz", spiGetBaseClock(mmccfg.spip) / (2 << ((mmc_hs_spicfg.cr1 & SPI_CR1_BR_Msk) >> SPI_CR1_BR_Pos)));
319 efiPrintf("LS clock %d Hz", spiGetBaseClock(mmccfg.spip) / (2 << ((mmc_ls_spicfg.cr1 & SPI_CR1_BR_Msk) >> SPI_CR1_BR_Pos)));
320 #else
321 efiPrintf("not implemented");
322 #endif
323#else
324 efiPrintf("SDIO mode");
325#endif
326 if (sdLoggerIsReady()) {
327 efiPrintf("filename=%s size=%d", logName, logBuffer.writen());
328 }
329#if EFI_FILE_LOGGING
330 efiPrintf("%d SD card fields", MLG::getSdCardFieldsCount());
331#endif
332}
333
334static void sdSetMode(const char *mode) {
335 if (strcmp(mode, "pc") == 0) {
337 } else if (strcmp(mode, "ecu") == 0) {
339 } else {
340 efiPrintf("Invalid mode %s allowed modes pc and ecu", mode);
341 }
342}
343
344static void prepareLogFileName() {
345 strcpy(logName, RUSEFI_LOG_PREFIX);
346 char *ptr;
347
348 // TS SD protocol supports only short 8 symbol file names, good thing that we do not use TS SD protocol!
349 bool result = dateToStringShort(&logName[PREFIX_LEN]);
350
351 if (result) {
352 ptr = &logName[PREFIX_LEN + SHORT_TIME_LEN];
353 } else {
354 ptr = itoa10(&logName[PREFIX_LEN], logFileIndex);
355 }
356
358 strcat(ptr, ".teeth");
359 } else {
360 strcat(ptr, DOT_MLG);
361 }
362}
363
364/**
365 * @brief Create a new file with the specified name
366 *
367 * This function saves the name of the file in a global variable
368 * so that we can later append to that file
369 */
370static int sdLoggerCreateFile(FIL *fd) {
371 // turn off indicator
372 sdLoggerSetReady(false);
373
374 // clear the memory
375 memset(fd, 0, sizeof(FIL));
377
378 efiPrintf("starting log file %s", logName);
379 // Create new file. If file is exist - truncate and overwrite, we need header to be at zero offset.
380 FRESULT err = f_open(fd, logName, FA_CREATE_ALWAYS | FA_WRITE);
381 if (err == FR_EXIST) {
382 err = FR_OK;
383 }
384#if EFI_TUNER_STUDIO
385 // Show error to TS
386 engine->outputChannels.sd_error = (uint8_t)err;
387#endif
388 if (err != FR_OK) {
390 warning(ObdCode::CUSTOM_ERR_SD_MOUNT_FAILED, "SD: file open failed");
391 printFatFsError("log file create", err);
392 return -1;
393 }
394
395#ifdef LOGGER_MAX_FILE_SIZE
396 //pre-allocate data ahead
397 err = f_expand(fd, LOGGER_MAX_FILE_SIZE, /* Find and allocate */ 1);
398 if (err != FR_OK) {
399 printFatFsError("pre-allocate", err);
400 // this is not critical
401 }
402#endif
403
404 // SD logger is ok
405 sdLoggerSetReady(true);
406
407 return 0;
408}
409
410static void sdLoggerCloseFile(FIL *fd)
411{
412#ifdef LOGGER_MAX_FILE_SIZE
413 // truncate file to actual size
414 f_truncate(fd);
415#endif
416
417 // close file
418 f_close(fd);
419
420 // SD logger is inactive
421 sdLoggerSetReady(false);
422}
423
424static void removeFile(const char *pathx) {
425 if (sdMode != SD_MODE_ECU) {
426 efiPrintf("SD card should be mounted to ECU");
427 return;
428 }
429
430 f_unlink(pathx);
431}
432
433#if HAL_USE_USB_MSD
434
435static chibios_rt::BinarySemaphore usbConnectedSemaphore(/* taken =*/ true);
436
440
441#endif /* HAL_USE_USB_MSD */
442
443#if HAL_USE_MMC_SPI
444
450
451/*
452 * Attempts to initialize the MMC card connected over SPI.
453 * Returns a BaseBlockDevice* corresponding to the SD card if successful, otherwise nullptr.
454 */
455static BaseBlockDevice* initializeMmcBlockDevice() {
456 // Configures and activates the MMC peripheral.
458
459 // todo: reuse initSpiCs method?
463
464 // Invalid SPI device, abort.
465 if (!mmccfg.spip) {
466 return nullptr;
467 }
468
469 // max SPI rate is 25 MHz after init
470 spiCalcClockDiv(mmccfg.spip, &mmc_hs_spicfg, 25 * 1000 * 1000);
471 // and 250 KHz during initialization
472 spiCalcClockDiv(mmccfg.spip, &mmc_ls_spicfg, 250 * 1000);
473
474 // We think we have everything for the card, let's try to mount it!
475 mmcObjectInit(&MMCD1, mmcbuf);
476 mmcStart(&MMCD1, &mmccfg);
477
478 // Performs the initialization procedure on the inserted card.
479 LOCK_SD_SPI();
480 if (blkConnect(&MMCD1) != HAL_SUCCESS) {
482 UNLOCK_SD_SPI();
483 return nullptr;
484 }
485 // We intentionally never unlock in case of success, we take exclusive access of that spi device for SD use
486
487 return reinterpret_cast<BaseBlockDevice*>(&MMCD1);
488}
489
491 blkDisconnect(&MMCD1); // Brings the driver in a state safe for card removal.
492 mmcStop(&MMCD1); // Disables the MMC peripheral.
493 UNLOCK_SD_SPI();
494}
495#endif /* HAL_USE_MMC_SPI */
496
497// Some ECUs are wired for SDIO/SDMMC instead of SPI
498#ifdef EFI_SDC_DEVICE
499
500#ifndef RE_SDC_MODE
501 #define RE_SDC_MODE SDC_MODE_4BIT
502#endif // RE_SDC_MODE
503
504static const SDCConfig sdcConfig = {
505 .bus_width = RE_SDC_MODE,
506 .slowdown = 0U
507};
508
509static bool isSdCardEnabled() {
511}
512
513/*
514 * Attempts to initialize the MMC card connected over SDIO.
515 * Returns a BaseBlockDevice* corresponding to the SD card if successful, otherwise nullptr.
516 */
517static BaseBlockDevice* initializeMmcBlockDevice() {
518 sdcStart(&EFI_SDC_DEVICE, &sdcConfig);
519 if (blkConnect(&EFI_SDC_DEVICE) != HAL_SUCCESS) {
520 return nullptr;
521 }
522
523 return reinterpret_cast<BaseBlockDevice*>(&EFI_SDC_DEVICE);
524}
525
526static void deinitializeMmcBlockDevide() {
527 blkDisconnect(&EFI_SDC_DEVICE);
528 sdcStop(&EFI_SDC_DEVICE);
529}
530
531#endif /* EFI_SDC_DEVICE */
532
533#if HAL_USE_USB_MSD
534static bool useMsdMode() {
536 return false;
537 }
538 if (isIgnVoltage()) {
539 // if we have battery voltage let's give priority to logging not reading
540 // this gives us a chance to SD card log cranking
541 return false;
542 }
543 // Wait for the USB stack to wake up, or a 15 second timeout, whichever occurs first
544 msg_t usbResult = usbConnectedSemaphore.wait(TIME_MS2I(15000));
545
546 return usbResult == MSG_OK;
547}
548#endif // HAL_USE_USB_MSD
549
550static BaseBlockDevice* cardBlockDevice = nullptr;
551
552// Initialize SD card.
553static bool initMmc() {
554 // Don't try to mount SD card in case of fatal error - hardware may be in an unexpected state
555 if (hasFirmwareError()) {
556 return false;
557 }
558
560
561#if EFI_TUNER_STUDIO
562 // If not null, card is present
564#endif
565
566 return (cardBlockDevice != nullptr);
567}
568
569static void deinitMmc() {
570 if (cardBlockDevice) {
572 }
573 cardBlockDevice = nullptr;
575}
576
577// Mount the SD card.
578// Returns true if the filesystem was successfully mounted for writing.
579static bool mountMmc() {
580 FRESULT ret = FR_NOT_READY;
581
582 // if no card, don't try to mount FS
583 if (cardBlockDevice != nullptr) {
584 // clean shared buffer
585 memset(&resources, 0x00, sizeof(resources));
586 // We were able to connect the SD card, mount the filesystem
587 memset(&MMC_FS, 0, sizeof(FATFS));
588 ret = f_mount(&MMC_FS, "", /* Mount immediately */ 1);
589
590 if (ret != FR_OK) {
592 printFatFsError("Mount failed", ret);
593 } else {
595 efiPrintf("SD card mounted!");
596 }
597 }
598
599#if EFI_STORAGE_SD == TRUE
600 if (ret == FR_OK) {
601 // notificate storage subsystem
603 }
604#endif // EFI_STORAGE_SD
605
606#if EFI_TUNER_STUDIO
607 engine->outputChannels.sd_error = (uint8_t) ret;
608 engine->outputChannels.sd_logging_internal = (ret == FR_OK);
609#endif
610
611 return (ret == FR_OK);
612}
613
614/*
615 * SD card un-mount.
616 * @return true if we had SD card alive
617 */
618static void unmountMmc() {
619 FRESULT ret;
620
621#if EFI_STORAGE_SD == TRUE
622 // notificate storage subsystem
624#endif // EFI_STORAGE_SD
625
626 // FATFS: Unregister work area prior to discard it
627 ret = f_unmount("");
628 if (ret != FR_OK) {
629 printFatFsError("Umount failed", ret);
630 }
631
632#if EFI_TUNER_STUDIO
633 engine->outputChannels.sd_error = (uint8_t) ret;
635#endif
636
637 efiPrintf("SD card unmounted");
638}
639
640#else // not EFI_PROD_CODE (simulator)
641
642bool initMmc() {
643 // Stub so the loop thinks the SD is present
644 return true;
645}
646
647bool mountMmc() {
648 // Stub so the loop thinks the SD mounted OK
649 return true;
650}
651
652#endif // EFI_PROD_CODE
653
654#if EFI_PROD_CODE
655
656// Log 'regular' ECU log to MLG file
657static int mlgLogger();
658
659// Log binary trigger log
660static int sdTriggerLogger();
661
662static bool sdLoggerInitDone = false;
663static bool sdLoggerFailed = false;
664
665static int sdLogger(FIL *fd)
666{
667 int ret = 0;
668
669 if (!sdLoggerInitDone) {
672
673 ret = sdLoggerCreateFile(fd);
674 if (ret == 0) {
675 ret = logBuffer.start(fd);
676 }
677
678 sdLoggerInitDone = true;
679
680 if (ret < 0) {
681 sdLoggerFailed = true;
682 return ret;
683 }
684 }
685
686 if (!sdLoggerFailed) {
688 ret = sdTriggerLogger();
689 } else {
690 ret = mlgLogger();
691 }
692 }
693
694 if (ret < 0) {
695 sdLoggerFailed = true;
696 return ret;
697 }
698
699 if (sdLoggerFailed) {
700 // logger is dead until restart, do not waste CPU
701 chThdSleepMilliseconds(100);
702 return -1;
703 }
704
705#ifdef LOGGER_MAX_FILE_SIZE
706 // check if we need to start next log file
707 // in next write (assume same size as current) will cross LOGGER_MAX_FILE_SIZE boundary
708 // TODO: use f_tell() instead ?
709 if (logBuffer.writen() + ret > LOGGER_MAX_FILE_SIZE) {
710 logBuffer.stop();
712
713 //need to start new file
714 sdLoggerInitDone = false;
715 }
716#endif
717
718 return ret;
719}
720
721static void sdLoggerStart()
722{
723 sdLoggerInitDone = false;
724 sdLoggerFailed = false;
725
726#if EFI_TOOTH_LOGGER
727 // TODO: cache this config option untill sdLoggerStop()
730 }
731#endif
732}
733
734static void sdLoggerStop()
735{
736 sdLoggerCloseFile(&resources.fd);
737#if EFI_TOOTH_LOGGER
738 // TODO: cache this config option untill sdLoggerStop()
741 }
742#endif
743}
744
745static bool sdFormat()
746{
747#if EFI_TUNER_STUDIO
750#endif
751 //FRESULT ret = f_mkfs("", nullptr, resources.formatBuff, sizeof(resources.formatBuff));
752 FRESULT ret = f_mkfs("", nullptr, resources.formatBuff, sizeof(resources.formatBuff));
753
754 if (ret) {
755 printFatFsError("format failed", ret);
756 warning(ObdCode::CUSTOM_ERR_SD_MOUNT_FAILED, "SD: format failed");
757 goto exit;
758 }
759 ret = f_setlabel(SD_CARD_LABEL);
760 if (ret) {
761 printFatFsError("setlabel failed", ret);
762 // this is not critical
763 ret = FR_OK;
764 }
765
766exit:
767#if EFI_TUNER_STUDIO
769 engine->outputChannels.sd_error = (uint8_t) ret;
770#endif
771
772 return (ret ? false : true);
773}
774
776{
777 switch (from) {
778 case SD_MODE_IDLE:
779 return 0;
780 case SD_MODE_ECU:
781 sdLoggerStop();
782 unmountMmc();
783 return 0;
784 case SD_MODE_PC:
786 return 0;
787 case SD_MODE_UNMOUNT:
788 return 0;
789 case SD_MODE_FORMAT:
790 //not allowed to interrupt formating process
791 return -1;
792 }
793
794 efiPrintf("Invalid SD card thread state: %d", static_cast<int>(from));
795 return -1;
796}
797
798static int sdModeSwitcher()
799{
800 if (sdTargetMode == SD_MODE_IDLE) {
801 return 0;
802 }
803
804 if (sdMode == sdTargetMode) {
805 // already here
807 return 0;
808 }
809
810 if (sdMode != SD_MODE_IDLE) {
811 int ret = sdModeSwitchToIdle(sdMode);
812 if (ret) {
813 return ret;
814 }
816 }
817
818 if (sdMode != SD_MODE_IDLE) {
819 return -1;
820 }
821
822 // Now SD card is in idle state, we can switch into target state
823 switch (sdTargetMode) {
824 case SD_MODE_IDLE:
825 return 0;
826 case SD_MODE_UNMOUNT:
827 // everything is done in sdModeSwitchToIdle();
830 return 0;
831 case SD_MODE_ECU:
832 if (mountMmc()) {
835 } else {
836 // failed to mount SD card to ECU, go to idle
838 }
840 return 0;
841 case SD_MODE_PC:
842 attachMsdSdCard(cardBlockDevice, resources.blkbuf, sizeof(resources.blkbuf));
846 return 0;
847 case SD_MODE_FORMAT:
848 if (sdFormat()) {
849 // formated ok
850 }
852 // TODO: return to mode that was used before format was requested!
854 return 0;
855 }
856
857 // should not happen
858 return -1;
859}
860
861static int sdModeExecuter()
862{
863 switch (sdMode) {
864 case SD_MODE_IDLE:
865 case SD_MODE_PC:
866 case SD_MODE_UNMOUNT:
867 case SD_MODE_FORMAT:
868 // nothing to do in these state, just sleep
869 chThdSleepMilliseconds(100);
870 return 0;
871 case SD_MODE_ECU:
874 sdNeedRemoveReports = false;
875 }
876 // execute logger
877 return sdLogger(&resources.fd);
878 }
879
880 return 0;
881}
882
884{
885 // write error report file if needed
886 errorHandlerWriteReportFile(&resources.fd);
887
888 // check for any exist reports
890
891 return 0;
892}
893
894PUBLIC_API_WEAK bool boardSdCardEnable() {
895 // assume powered and ready
896 return true;
897}
898
899PUBLIC_API_WEAK bool boardSdCardDisable() {
900 return true;
901}
902
903static THD_WORKING_AREA(mmcThreadStack, 3 * UTILITY_THREAD_STACK_SIZE); // MMC monitor thread
904static THD_FUNCTION(MMCmonThread, arg) {
905 (void)arg;
906
907 chRegSetThreadName("SD Card Logger");
908
909 while (!boardSdCardEnable()) {
910 // wait until board enables peripheral
911 chThdSleepMilliseconds(100);
912 }
913
915 if (!initMmc()) {
916 efiPrintf("Card is not preset/failed to init");
918 // give up until next boot
919 goto die;
920 }
921
922 // Try to mount SD card, drop critical report if needed and check for previously stored reports
923 if (mountMmc()) {
925
927
928#if EFI_STORAGE_SD == TRUE
929 // Give some time for storage manager to load settings from SD
930 chThdSleepMilliseconds(1000);
931#endif
932 }
933
934#if HAL_USE_USB_MSD
935 // Wait for the USB stack to wake up, or a 15 second timeout, whichever occurs first
936 // If we have a device AND USB is connected, mount the card to USB, otherwise
937 // mount the null device and try to mount the filesystem ourselves
938 if (useMsdMode()) {
940 }
941#endif
942
943 while (1) {
946 }
947
948die:
949 // bring SD interface to safe state
950 deinitMmc();
952
953 efiPrintf("SD logger has died!");
954
955 // exiting thread will create zombie!
956 while(1) {
957 chThdSleepMilliseconds(100);
958 }
959}
960
961static int mlgLogger() {
962 // TODO: move this check somewhere out of here!
963 // if the SPI device got un-picked somehow, cancel SD card
964 // Don't do this check at all if using SDMMC interface instead of SPI
965#if EFI_PROD_CODE && !defined(EFI_SDC_DEVICE)
966 if (engineConfiguration->sdCardSpiDevice == SPI_NONE) {
967 return 0;
968 }
969#endif
970
971 systime_t before = chVTGetSystemTime();
972
973 size_t writen = MLG::writeSdLogLine(logBuffer);
974
975 // Something went wrong (already handled), so cancel further writes
976 if (logBuffer.failed) {
977 return -1;
978 }
979
981 if (freq > 250) {
982 freq = 250;
983 } else if (freq < 1) {
984 freq = 1;
985 }
986
987 systime_t period = CH_CFG_ST_FREQUENCY / freq;
988 chThdSleepUntilWindowed(before, before + period);
989
990 return writen;
991}
992
993static int sdTriggerLogger() {
994 size_t toWrite = 0;
995#if EFI_TOOTH_LOGGER
997
998 // can return nullptr
999 if (buffer) {
1000 toWrite = buffer->nextIdx * sizeof(composite_logger_s);
1001 logBuffer.write(reinterpret_cast<const char*>(buffer->buffer), toWrite);
1002 if (logBuffer.failed) {
1003 return -1;
1004 }
1005
1007 }
1008#endif /* EFI_TOOTH_LOGGER */
1009 return toWrite;
1010}
1011
1012#endif // EFI_PROD_CODE
1013
1015#if EFI_PROD_CODE
1016 if (cardBlockDevice) {
1017 engine->outputChannels.sd_active_wr = (blkGetDriverState(cardBlockDevice) == BLK_WRITING);
1018 engine->outputChannels.sd_active_rd = (blkGetDriverState(cardBlockDevice) == BLK_READING);
1019 } else
1020#endif // EFI_PROD_CODE
1021 {
1024 }
1025}
1026
1027// Pre-config load init
1029#if EFI_PROD_CODE
1030 logName[0] = 0;
1031
1032 addConsoleAction("sdinfo", sdStatistics);
1034 // sdmode pc
1035 // sdmode ecu
1036 addConsoleActionS("sdmode", sdSetMode);
1038 //incLogFileName() use same shared FDLogFile, calling it while FDLogFile is used by log writer will cause damage
1039 //addConsoleAction("incfilename", incLogFileName);
1040#endif // EFI_PROD_CODE
1041}
1042
1044#if EFI_PROD_CODE
1045 if (!isSdCardEnabled()) {
1046 // do not even bother starting the thread if SD card is not enabled & configured on start-up
1047 return;
1048 }
1049 chThdCreateStatic(mmcThreadStack, sizeof(mmcThreadStack), PRIO_MMC, (tfunc_t)(void*) MMCmonThread, NULL);
1050#endif // EFI_PROD_CODE
1051}
1052
1053#if EFI_PROD_CODE
1054
1056{
1057 // Check if SD is not in transition state...
1058 if (sdTargetMode == SD_MODE_IDLE) {
1059 efiPrintf("sdCardRequestMode %d", (int)mode);
1060 sdTargetMode = mode;
1061 }
1062}
1063
1065{
1066 return sdMode;
1067}
1068
1070 if (sdMode != SD_MODE_ECU) {
1071 efiPrintf("SD card should be mounted to ECU");
1072 return;
1073 }
1074
1075 sdNeedRemoveReports = true;
1076}
1077
1078#endif // EFI_PROD_CODE
1079
1080#endif /* EFI_FILE_LOGGING */
int spiCalcClockDiv(SPIDriver *, SPIConfig *, unsigned int)
Definition at32_spi.cpp:260
SPIConfig mmc_hs_spicfg
Definition at32_spi.cpp:273
int spiGetBaseClock(SPIDriver *)
Definition at32_spi.cpp:254
SPIConfig mmc_ls_spicfg
Definition at32_spi.cpp:288
beuint32_t period
size_t flush() override
virtual size_t writeInternal(const char *buffer, size_t count)=0
TunerStudioOutputChannels outputChannels
Definition engine.h:109
void addConsoleActionS(const char *token, VoidCharPtr callback)
void addConsoleAction(const char *token, Void callback)
Register console action without parameters.
ioportid_t getHwPort(const char *msg, brain_pin_e brainPin)
ioportmask_t getHwPin(const char *msg, brain_pin_e brainPin)
const char * boolToString(bool value)
Definition efilib.cpp:19
char * itoa10(char *p, int num)
Definition efilib.cpp:107
static EngineAccessor engine
Definition engine.h:413
static constexpr engine_configuration_s * engineConfiguration
bool warning(ObdCode code, const char *fmt,...)
void printSpiConfig(const char *msg, spi_device_e device)
Definition hardware.cpp:259
SPIDriver * getSpiDevice(spi_device_e spiDevice)
Definition hardware.cpp:152
bool isIgnVoltage()
void deattachMsdSdCard(void)
void attachMsdSdCard(BaseBlockDevice *blkdev, uint8_t *blkbuf, size_t blkbufsize)
static bool useMsdMode()
Definition mmc_card.cpp:534
static THD_FUNCTION(MMCmonThread, arg)
Definition mmc_card.cpp:904
static bool sdLoggerIsReady()
Definition mmc_card.cpp:245
static void unmountMmc()
Definition mmc_card.cpp:618
static bool sdLoggerFailed
Definition mmc_card.cpp:663
static int sdTriggerLogger()
Definition mmc_card.cpp:993
static void sdStatistics()
Definition mmc_card.cpp:311
void initEarlyMmcCard()
PUBLIC_API_WEAK bool boardSdCardEnable()
Definition mmc_card.cpp:894
static void deinitializeMmcBlockDevide()
Definition mmc_card.cpp:490
int errorHandlerCheckReportFiles()
static spi_device_e mmcSpiDevice
Definition mmc_card.cpp:211
static chibios_rt::BinarySemaphore usbConnectedSemaphore(true)
static int sdReportStorageInit()
Definition mmc_card.cpp:883
BYTE formatBuff[FATFS_CLUSTER_SIZE]
Definition mmc_card.cpp:291
static bool sdFormat()
Definition mmc_card.cpp:745
static int sdModeExecuter()
Definition mmc_card.cpp:861
static NO_CACHE SdLogBufferWriter logBuffer
Definition mmc_card.cpp:149
MMCDriver MMCD1
Definition mmc_card.cpp:217
void sdCardRemoveReportFiles()
static bool sdLoggerReady
Definition mmc_card.cpp:32
static void sdLoggerStart()
Definition mmc_card.cpp:721
static bool mountMmc()
Definition mmc_card.cpp:579
static int sdModeSwitcher()
Definition mmc_card.cpp:798
static int sdLogger(FIL *fd)
Definition mmc_card.cpp:665
void updateSdCardLiveFlags()
SD_STATUS
Definition mmc_card.cpp:161
@ SD_STATUS_INIT
Definition mmc_card.cpp:162
@ SD_STATUS_MSD
Definition mmc_card.cpp:169
@ SD_STATUS_MOUNT_FAILED
Definition mmc_card.cpp:164
@ SD_STATUS_CONNECTING
Definition mmc_card.cpp:168
@ SD_STATUS_OPEN_FAILED
Definition mmc_card.cpp:165
@ SD_STATUS_MMC_FAILED
Definition mmc_card.cpp:170
@ SD_STATUS_NOT_INSERTED
Definition mmc_card.cpp:167
@ SD_STATUS_SEEK_FAILED
Definition mmc_card.cpp:166
@ SD_STATUS_MOUNTED
Definition mmc_card.cpp:163
static bool isSdCardEnabled()
Definition mmc_card.cpp:445
void sdCardRequestMode(SD_MODE mode)
static void sdLoggerCloseFile(FIL *fd)
Definition mmc_card.cpp:410
static const char * sdStatusName(SD_STATUS status)
Definition mmc_card.cpp:187
SD_MODE sdCardGetCurrentMode()
static union @47 NO_CACHE
static THD_WORKING_AREA(mmcThreadStack, 3 *UTILITY_THREAD_STACK_SIZE)
static NO_CACHE uint8_t mmcbuf[MMC_BUFFER_SIZE]
Definition mmc_card.cpp:216
static const char * fatErrors[]
Definition mmc_card.cpp:250
static bool sdNeedRemoveReports
Definition mmc_card.cpp:198
static void deinitMmc()
Definition mmc_card.cpp:569
static int sdModeSwitchToIdle(SD_MODE from)
Definition mmc_card.cpp:775
static const SDCConfig sdcConfig
Definition mmc_card.cpp:504
static SD_STATUS sdStatus
Definition mmc_card.cpp:192
void onUsbConnectedNotifyMmcI()
Definition mmc_card.cpp:437
void errorHandlerDeleteReports()
static MMCConfig mmccfg
Definition mmc_card.cpp:220
static void sdLoggerSetReady(bool value)
Definition mmc_card.cpp:241
static const char * sdStatusNames[]
Definition mmc_card.cpp:174
static void sdSetMode(const char *mode)
Definition mmc_card.cpp:334
static bool initMmc()
Definition mmc_card.cpp:553
static SD_MODE sdMode
Definition mmc_card.cpp:194
static bool sdLoggerInitDone
Definition mmc_card.cpp:662
static char logName[_MAX_FILLER+20]
Definition mmc_card.cpp:297
void printFatFsError(const char *str, FRESULT f_error)
Definition mmc_card.cpp:274
static void removeFile(const char *pathx)
Definition mmc_card.cpp:424
static void prepareLogFileName()
Definition mmc_card.cpp:344
FIL fd
Definition mmc_card.cpp:288
static void sdLoggerStop()
Definition mmc_card.cpp:734
int logFileIndex
static int sdLoggerCreateFile(FIL *fd)
Create a new file with the specified name.
Definition mmc_card.cpp:370
static int mlgLogger()
Definition mmc_card.cpp:961
PUBLIC_API_WEAK bool boardSdCardDisable()
Definition mmc_card.cpp:899
uint8_t blkbuf[4 *MMCSD_BLOCK_SIZE]
Definition mmc_card.cpp:293
static SD_MODE sdTargetMode
Definition mmc_card.cpp:196
void errorHandlerWriteReportFile(FIL *fd)
static BaseBlockDevice * initializeMmcBlockDevice()
Definition mmc_card.cpp:455
static NO_CACHE FATFS MMC_FS
Definition mmc_card.cpp:239
void initMmcCard()
static BaseBlockDevice * cardBlockDevice
Definition mmc_card.cpp:550
static void printMmcPinout()
Definition mmc_card.cpp:299
SD_MODE
Definition mmc_card.h:17
@ SD_MODE_UNMOUNT
Definition mmc_card.h:21
@ SD_MODE_PC
Definition mmc_card.h:20
@ SD_MODE_ECU
Definition mmc_card.h:19
@ SD_MODE_IDLE
Definition mmc_card.h:18
@ SD_MODE_FORMAT
Definition mmc_card.h:22
void incLogFileName(FIL *fd)
void resetFileLogging()
int getSdCardFieldsCount()
size_t writeSdLogLine(Writer &bufferedWriter)
@ CUSTOM_ERR_SD_MOUNT_FAILED
@ CUSTOM_STACK_6627
const char * hwPortname(brain_pin_e brainPin)
bool isBrainPinValid(brain_pin_e brainPin)
bool dateToStringShort(char *destination)
Real Time Clock helper.
spi_device_e
bool deinitStorageSD()
bool initStorageSD()
static NO_CACHE FIL fd
Storage interface to FatFS header.
void DisableToothLogger()
void EnableToothLogger()
void ReturnToothLoggerBuffer(CompositeBuffer *buffer)
CompositeBuffer * GetToothLoggerBufferBlocking()
composite_logger_s
static BigBufferHandle buffer
uint16_t count
Definition tunerstudio.h:1