2023-05-23 22:21:29 -07:00
# include "globals.h"
# include BOARD_H
2019-12-18 22:31:02 -08:00
# ifdef SD_LOGGING
# include <SPI.h>
2022-02-04 14:15:58 -08:00
# ifdef __SD_H__
# include <SD.h>
# else
# include "SdFat.h"
# endif
2019-12-18 22:31:02 -08:00
# include "SD_logger.h"
# include "logger.h"
2021-10-12 17:53:46 -07:00
# include "rtc_common.h"
2023-05-23 22:21:29 -07:00
# include "maths.h"
2019-12-18 22:31:02 -08:00
2023-10-05 21:07:12 -07:00
//List of logger field names. This must be in the same order and length as logger_updateLogdataCSV()
constexpr char header_0 [ ] PROGMEM = " secl " ;
constexpr char header_1 [ ] PROGMEM = " status1 " ;
constexpr char header_2 [ ] PROGMEM = " engine " ;
constexpr char header_3 [ ] PROGMEM = " Sync Loss # " ;
constexpr char header_4 [ ] PROGMEM = " MAP " ;
constexpr char header_5 [ ] PROGMEM = " IAT(C) " ;
constexpr char header_6 [ ] PROGMEM = " CLT(C) " ;
constexpr char header_7 [ ] PROGMEM = " Battery Correction " ;
constexpr char header_8 [ ] PROGMEM = " Battery V " ;
constexpr char header_9 [ ] PROGMEM = " AFR " ;
constexpr char header_10 [ ] PROGMEM = " EGO Correction " ;
constexpr char header_11 [ ] PROGMEM = " IAT Correction " ;
constexpr char header_12 [ ] PROGMEM = " WUE Correction " ;
constexpr char header_13 [ ] PROGMEM = " RPM " ;
constexpr char header_14 [ ] PROGMEM = " Accel. Correction " ;
constexpr char header_15 [ ] PROGMEM = " Gamma Correction " ;
constexpr char header_16 [ ] PROGMEM = " VE1 " ;
constexpr char header_17 [ ] PROGMEM = " VE2 " ;
constexpr char header_18 [ ] PROGMEM = " AFR Target " ;
constexpr char header_19 [ ] PROGMEM = " TPSdot " ;
constexpr char header_20 [ ] PROGMEM = " Advance Current " ;
constexpr char header_21 [ ] PROGMEM = " TPS " ;
constexpr char header_22 [ ] PROGMEM = " Loops/S " ;
constexpr char header_23 [ ] PROGMEM = " Free RAM " ;
constexpr char header_24 [ ] PROGMEM = " Boost Target " ;
constexpr char header_25 [ ] PROGMEM = " Boost Duty " ;
constexpr char header_26 [ ] PROGMEM = " status2 " ;
constexpr char header_27 [ ] PROGMEM = " rpmDOT " ;
constexpr char header_28 [ ] PROGMEM = " Eth% " ;
constexpr char header_29 [ ] PROGMEM = " Flex Fuel Correction " ;
constexpr char header_30 [ ] PROGMEM = " Flex Adv Correction " ;
constexpr char header_31 [ ] PROGMEM = " IAC Steps/Duty " ;
constexpr char header_32 [ ] PROGMEM = " testoutputs " ;
constexpr char header_33 [ ] PROGMEM = " AFR2 " ;
constexpr char header_34 [ ] PROGMEM = " Baro " ;
constexpr char header_35 [ ] PROGMEM = " AUX_IN 0 " ;
constexpr char header_36 [ ] PROGMEM = " AUX_IN 1 " ;
constexpr char header_37 [ ] PROGMEM = " AUX_IN 2 " ;
constexpr char header_38 [ ] PROGMEM = " AUX_IN 3 " ;
constexpr char header_39 [ ] PROGMEM = " AUX_IN 4 " ;
constexpr char header_40 [ ] PROGMEM = " AUX_IN 5 " ;
constexpr char header_41 [ ] PROGMEM = " AUX_IN 6 " ;
constexpr char header_42 [ ] PROGMEM = " AUX_IN 7 " ;
constexpr char header_43 [ ] PROGMEM = " AUX_IN 8 " ;
constexpr char header_44 [ ] PROGMEM = " AUX_IN 9 " ;
constexpr char header_45 [ ] PROGMEM = " AUX_IN 10 " ;
constexpr char header_46 [ ] PROGMEM = " AUX_IN 11 " ;
constexpr char header_47 [ ] PROGMEM = " AUX_IN 12 " ;
constexpr char header_48 [ ] PROGMEM = " AUX_IN 13 " ;
constexpr char header_49 [ ] PROGMEM = " AUX_IN 14 " ;
constexpr char header_50 [ ] PROGMEM = " AUX_IN 15 " ;
constexpr char header_51 [ ] PROGMEM = " TPS ADC " ;
constexpr char header_52 [ ] PROGMEM = " Errors " ;
constexpr char header_53 [ ] PROGMEM = " PW " ;
constexpr char header_54 [ ] PROGMEM = " PW2 " ;
constexpr char header_55 [ ] PROGMEM = " PW3 " ;
constexpr char header_56 [ ] PROGMEM = " PW4 " ;
constexpr char header_57 [ ] PROGMEM = " status3 " ;
constexpr char header_58 [ ] PROGMEM = " Engine Protect " ;
constexpr char header_59 [ ] PROGMEM = " " ;
constexpr char header_60 [ ] PROGMEM = " Fuel Load " ;
constexpr char header_61 [ ] PROGMEM = " Ign Load " ;
constexpr char header_62 [ ] PROGMEM = " Dwell Requested " ;
constexpr char header_63 [ ] PROGMEM = " Idle Target (RPM) " ;
constexpr char header_64 [ ] PROGMEM = " MAP DOT " ;
constexpr char header_65 [ ] PROGMEM = " VVT1 Angle " ;
constexpr char header_66 [ ] PROGMEM = " VVT1 Target " ;
constexpr char header_67 [ ] PROGMEM = " VVT1 Duty " ;
constexpr char header_68 [ ] PROGMEM = " Flex Boost Adj " ;
constexpr char header_69 [ ] PROGMEM = " Baro Correction " ;
constexpr char header_70 [ ] PROGMEM = " VE Current " ;
constexpr char header_71 [ ] PROGMEM = " ASE Correction " ;
constexpr char header_72 [ ] PROGMEM = " Vehicle Speed " ;
constexpr char header_73 [ ] PROGMEM = " Gear " ;
constexpr char header_74 [ ] PROGMEM = " Fuel Pressure " ;
constexpr char header_75 [ ] PROGMEM = " Oil Pressure " ;
constexpr char header_76 [ ] PROGMEM = " WMI PW " ;
constexpr char header_77 [ ] PROGMEM = " status4 " ;
constexpr char header_78 [ ] PROGMEM = " VVT2 Angle " ;
constexpr char header_79 [ ] PROGMEM = " VVT2 Target " ;
constexpr char header_80 [ ] PROGMEM = " VVT2 Duty " ;
constexpr char header_81 [ ] PROGMEM = " outputs " ;
constexpr char header_82 [ ] PROGMEM = " Fuel Temp " ;
constexpr char header_83 [ ] PROGMEM = " Fuel Temp Correction " ;
constexpr char header_84 [ ] PROGMEM = " Advance 1 " ;
constexpr char header_85 [ ] PROGMEM = " Advance 2 " ;
constexpr char header_86 [ ] PROGMEM = " SD Status " ;
constexpr char header_87 [ ] PROGMEM = " EMAP " ;
constexpr char header_88 [ ] PROGMEM = " Fan Duty " ;
constexpr char header_89 [ ] PROGMEM = " AirConStatus " ;
constexpr char header_90 [ ] PROGMEM = " Dwell Actual " ;
/*
constexpr char header_91 [ ] PROGMEM = " " ;
constexpr char header_92 [ ] PROGMEM = " " ;
constexpr char header_93 [ ] PROGMEM = " " ;
constexpr char header_94 [ ] PROGMEM = " " ;
constexpr char header_95 [ ] PROGMEM = " " ;
constexpr char header_96 [ ] PROGMEM = " " ;
constexpr char header_97 [ ] PROGMEM = " " ;
constexpr char header_98 [ ] PROGMEM = " " ;
constexpr char header_99 [ ] PROGMEM = " " ;
constexpr char header_100 [ ] PROGMEM = " " ;
constexpr char header_101 [ ] PROGMEM = " " ;
constexpr char header_102 [ ] PROGMEM = " " ;
constexpr char header_103 [ ] PROGMEM = " " ;
constexpr char header_104 [ ] PROGMEM = " " ;
constexpr char header_105 [ ] PROGMEM = " " ;
constexpr char header_106 [ ] PROGMEM = " " ;
constexpr char header_107 [ ] PROGMEM = " " ;
constexpr char header_108 [ ] PROGMEM = " " ;
constexpr char header_109 [ ] PROGMEM = " " ;
constexpr char header_110 [ ] PROGMEM = " " ;
constexpr char header_111 [ ] PROGMEM = " " ;
constexpr char header_112 [ ] PROGMEM = " " ;
constexpr char header_113 [ ] PROGMEM = " " ;
constexpr char header_114 [ ] PROGMEM = " " ;
constexpr char header_115 [ ] PROGMEM = " " ;
constexpr char header_116 [ ] PROGMEM = " " ;
constexpr char header_117 [ ] PROGMEM = " " ;
constexpr char header_118 [ ] PROGMEM = " " ;
constexpr char header_119 [ ] PROGMEM = " " ;
constexpr char header_120 [ ] PROGMEM = " " ;
constexpr char header_121 [ ] PROGMEM = " " ;
*/
constexpr const char * header_table [ ] PROGMEM = { header_0 , \
header_1 , \
header_2 , \
header_3 , \
header_4 , \
header_5 , \
header_6 , \
header_7 , \
header_8 , \
header_9 , \
header_10 , \
header_11 , \
header_12 , \
header_13 , \
header_14 , \
header_15 , \
header_16 , \
header_17 , \
header_18 , \
header_19 , \
header_20 , \
header_21 , \
header_22 , \
header_23 , \
header_24 , \
header_25 , \
header_26 , \
header_27 , \
header_28 , \
header_29 , \
header_30 , \
header_31 , \
header_32 , \
header_33 , \
header_34 , \
header_35 , \
header_36 , \
header_37 , \
header_38 , \
header_39 , \
header_40 , \
header_41 , \
header_42 , \
header_43 , \
header_44 , \
header_45 , \
header_46 , \
header_47 , \
header_48 , \
header_49 , \
header_50 , \
header_51 , \
header_52 , \
header_53 , \
header_54 , \
header_55 , \
header_56 , \
header_57 , \
header_58 , \
header_59 , \
header_60 , \
header_61 , \
header_62 , \
header_63 , \
header_64 , \
header_65 , \
header_66 , \
header_67 , \
header_68 , \
header_69 , \
header_70 , \
header_71 , \
header_72 , \
header_73 , \
header_74 , \
header_75 , \
header_76 , \
header_77 , \
header_78 , \
header_79 , \
header_80 , \
header_81 , \
header_82 , \
header_83 , \
header_84 , \
header_85 , \
header_86 , \
header_87 , \
header_88 , \
header_89 , \
header_90 , \
/*
header_91 , \
header_92 , \
header_93 , \
header_94 , \
header_95 , \
header_96 , \
header_97 , \
header_98 , \
header_99 , \
header_100 , \
header_101 , \
header_102 , \
header_103 , \
header_104 , \
header_105 , \
header_106 , \
header_107 , \
header_108 , \
header_109 , \
header_110 , \
header_111 , \
header_112 , \
header_113 , \
header_114 , \
header_115 , \
header_116 , \
header_117 , \
header_118 , \
header_119 , \
header_120 , \
header_121 , \
*/
} ;
# define SD_LOG_NUM_FIELDS 91 /**< The number of fields that are in the log. This is always smaller than the entry size due to some fields being 2 bytes */
static_assert ( sizeof ( header_table ) = = ( sizeof ( char * ) * SD_LOG_NUM_FIELDS ) , " Number of header table titles must match number of log fields " ) ;
2021-11-19 13:29:11 -08:00
SdExFat sd ;
ExFile logFile ;
RingBuf < ExFile , RING_BUF_CAPACITY > rb ;
uint8_t SD_status = SD_STATUS_OFF ;
2021-11-23 15:23:15 -08:00
uint16_t currentLogFileNumber ;
2021-11-23 21:14:31 -08:00
bool manualLogActive = false ;
2022-03-17 17:38:24 -07:00
uint32_t logStartTime = 0 ; //In ms
2021-11-19 13:29:11 -08:00
2019-12-18 22:31:02 -08:00
void initSD ( )
{
2021-10-03 06:09:53 -07:00
//Set default state to ready. If any stage of the init fails, this will be changed
SD_status = SD_STATUS_READY ;
2021-10-12 17:53:46 -07:00
//Set the RTC callback. This is used to set the correct timestamp on file creation and sync operations
2021-10-12 23:10:05 -07:00
FsDateTime : : setCallback ( dateTime ) ;
2021-10-12 17:53:46 -07:00
2022-04-10 17:49:58 -07:00
// Initialise the SD.
2021-10-03 06:09:53 -07:00
if ( ! sd . begin ( SD_CONFIG ) )
2021-01-21 21:16:30 -08:00
{
2021-10-03 06:09:53 -07:00
//sd.initErrorHalt(&Serial);
//if (sdErrorCode() == SD_CARD_ERROR_CMD0) { SD_status = SD_STATUS_ERROR_NO_CARD;
SD_status = SD_STATUS_ERROR_NO_CARD ;
}
2021-10-12 17:53:46 -07:00
2022-04-10 17:49:58 -07:00
//Set the TunerStudio status variable
2021-10-12 17:53:46 -07:00
setTS_SD_status ( ) ;
}
2021-10-03 06:09:53 -07:00
2021-10-12 17:53:46 -07:00
bool createLogFile ( )
{
2021-11-23 15:23:15 -08:00
//TunerStudio only supports 8.3 filename format.
char filenameBuffer [ 13 ] ; //8 + 1 + 3 + 1
2021-10-12 17:53:46 -07:00
bool returnValue = false ;
2021-10-03 06:09:53 -07:00
2022-03-17 17:38:24 -07:00
//Saving this in case we ever go back to the datestamped filename
/*
//Filename format is: YYYY-MM-DD_HH.MM.SS.csv
char intBuffer [ 5 ] ;
itoa ( rtc_getYear ( ) , intBuffer , 10 ) ;
strcpy ( filenameBuffer , intBuffer ) ;
strcat ( filenameBuffer , " - " ) ;
itoa ( rtc_getMonth ( ) , intBuffer , 10 ) ;
strcat ( filenameBuffer , intBuffer ) ;
strcat ( filenameBuffer , " - " ) ;
itoa ( rtc_getDay ( ) , intBuffer , 10 ) ;
strcat ( filenameBuffer , intBuffer ) ;
strcat ( filenameBuffer , " _ " ) ;
itoa ( rtc_getHour ( ) , intBuffer , 10 ) ;
strcat ( filenameBuffer , intBuffer ) ;
strcat ( filenameBuffer , " . " ) ;
itoa ( rtc_getMinute ( ) , intBuffer , 10 ) ;
strcat ( filenameBuffer , intBuffer ) ;
strcat ( filenameBuffer , " . " ) ;
itoa ( rtc_getSecond ( ) , intBuffer , 10 ) ;
strcat ( filenameBuffer , intBuffer ) ;
strcat ( filenameBuffer , " .csv " ) ;
*/
2021-12-23 19:58:53 -08:00
//Lookup the next available file number
currentLogFileNumber = getNextSDLogFileNumber ( ) ;
2021-11-23 15:23:15 -08:00
//Create the filename
2023-11-14 13:24:58 -08:00
//sprintf(filenameBuffer, "%s%04d.%s", LOG_FILE_PREFIX, currentLogFileNumber, LOG_FILE_EXTENSION);
if ( currentLogFileNumber > MAX_LOG_FILES ) { currentLogFileNumber = 1 ; } //If we've run out of file numbers, start again from 1
snprintf ( filenameBuffer , 13 , " %s%04d.%s " , LOG_FILE_PREFIX , currentLogFileNumber , LOG_FILE_EXTENSION ) ;
2021-01-21 21:16:30 -08:00
2023-05-23 22:21:29 -07:00
logFile . close ( ) ;
2021-10-12 17:53:46 -07:00
if ( logFile . open ( filenameBuffer , O_RDWR | O_CREAT | O_TRUNC ) )
2021-01-21 21:16:30 -08:00
{
2021-10-12 17:53:46 -07:00
returnValue = true ;
2021-01-21 21:16:30 -08:00
}
2021-10-12 17:53:46 -07:00
return returnValue ;
2019-12-18 22:31:02 -08:00
}
2021-11-23 15:23:15 -08:00
uint16_t getNextSDLogFileNumber ( )
{
uint16_t nextFileNumber = 1 ;
char filenameBuffer [ 13 ] ; //8 + 1 + 3 + 1
sprintf ( filenameBuffer , " %s%04d.%s " , LOG_FILE_PREFIX , nextFileNumber , LOG_FILE_EXTENSION ) ;
//Lookup the next available file number
while ( ( nextFileNumber < MAX_LOG_FILES ) & & ( sd . exists ( filenameBuffer ) ) )
{
nextFileNumber + + ;
sprintf ( filenameBuffer , " %s%04d.%s " , LOG_FILE_PREFIX , nextFileNumber , LOG_FILE_EXTENSION ) ;
}
return nextFileNumber ;
}
bool getSDLogFileDetails ( uint8_t * buffer , uint16_t logNumber )
{
bool fileFound = false ;
if ( logFile . isOpen ( ) ) { endSDLogging ( ) ; }
char filenameBuffer [ 13 ] ; //8 + 1 + 3 + 1
2023-11-14 13:24:58 -08:00
if ( logNumber > MAX_LOG_FILES ) { logNumber = MAX_LOG_FILES ; } //If we've run out of file numbers, start again from 1
snprintf ( filenameBuffer , 13 , " %s%04d.%s " , LOG_FILE_PREFIX , logNumber , LOG_FILE_EXTENSION ) ;
2021-11-23 21:14:31 -08:00
2021-11-23 15:23:15 -08:00
if ( sd . exists ( filenameBuffer ) )
{
fileFound = true ;
logFile = sd . open ( filenameBuffer , O_RDONLY ) ;
//Copy the filename into the buffer. Note we do not copy the termination character or the fullstop
for ( byte i = 0 ; i < 12 ; i + + )
{
//We don't copy the fullstop to the buffer
//As TS requires 8.3 filenames, it's always in the same spot
if ( i < 8 ) { buffer [ i ] = filenameBuffer [ i ] ; } //Everything before the fullstop
else if ( i > 8 ) { buffer [ i - 1 ] = filenameBuffer [ i ] ; } //Everything after the fullstop
}
2021-12-23 19:58:53 -08:00
//Maintenance check, truncate the file. This will usually do nothing, but in the case where a prior log was interrupted, this will truncate the file
//Due to overhead, only bother doing this if the engine isn't running
if ( currentStatus . RPM = = 0 ) { logFile . truncate ( ) ; }
2021-11-23 15:23:15 -08:00
//Is File or ignore
buffer [ 11 ] = 1 ;
//No idea
buffer [ 12 ] = 0 ;
//5 bytes for FAT creation date/time
uint16_t pDate = 0 ;
uint16_t pTime = 0 ;
logFile . getCreateDateTime ( & pDate , & pTime ) ;
buffer [ 13 ] = 0 ; //Not sure what this byte is for yet
2021-11-23 21:14:31 -08:00
buffer [ 14 ] = lowByte ( pTime ) ;
buffer [ 15 ] = highByte ( pTime ) ;
2021-11-23 15:23:15 -08:00
buffer [ 16 ] = lowByte ( pDate ) ;
buffer [ 17 ] = highByte ( pDate ) ;
//Sector number (4 bytes) - This byte order might be backwards
uint32_t sector = logFile . firstSector ( ) ;
buffer [ 18 ] = ( ( sector ) & 255 ) ;
buffer [ 19 ] = ( ( sector > > 8 ) & 255 ) ;
buffer [ 20 ] = ( ( sector > > 16 ) & 255 ) ;
buffer [ 21 ] = ( ( sector > > 24 ) & 255 ) ;
//Unsure on the below 6 bytes, possibly last accessed or modified date/time?
buffer [ 22 ] = 0 ;
buffer [ 23 ] = 0 ;
buffer [ 24 ] = 0 ;
buffer [ 25 ] = 0 ;
buffer [ 26 ] = 0 ;
buffer [ 27 ] = 0 ;
//File size (4 bytes). Little endian
uint32_t size = logFile . fileSize ( ) ;
buffer [ 28 ] = ( ( size ) & 255 ) ;
buffer [ 29 ] = ( ( size > > 8 ) & 255 ) ;
buffer [ 30 ] = ( ( size > > 16 ) & 255 ) ;
buffer [ 31 ] = ( ( size > > 24 ) & 255 ) ;
}
return fileFound ;
}
2021-11-24 18:19:54 -08:00
void readSDSectors ( uint8_t * buffer , uint32_t sectorNumber , uint16_t sectorCount )
{
sd . card ( ) - > readSectors ( sectorNumber , buffer , sectorCount ) ;
}
2023-04-25 22:54:15 -07:00
// Forward declare
void writeSDLogHeader ( ) ;
2021-10-12 23:10:05 -07:00
void beginSDLogging ( )
{
if ( SD_status = = SD_STATUS_READY )
{
2022-04-10 17:49:58 -07:00
SD_status = SD_STATUS_ACTIVE ; //Set the status as being active so that entries will begin to be written. This will be updated below if there is an error
2021-10-12 23:10:05 -07:00
// Open or create file - truncate existing file.
if ( ! createLogFile ( ) )
{
SD_status = SD_STATUS_ERROR_NO_WRITE ;
2023-05-23 22:21:29 -07:00
setTS_SD_status ( ) ;
return ;
2021-10-12 23:10:05 -07:00
}
2022-04-10 17:49:58 -07:00
//Perform pre-allocation on card. This dramatically improves write speed
2021-10-12 23:10:05 -07:00
if ( ! logFile . preAllocate ( SD_LOG_FILE_SIZE ) )
{
SD_status = SD_STATUS_ERROR_NO_SPACE ;
2023-05-23 22:21:29 -07:00
setTS_SD_status ( ) ;
return ;
2021-10-12 23:10:05 -07:00
}
2022-04-10 17:49:58 -07:00
//initialise the RingBuf.
2021-10-12 23:10:05 -07:00
rb . begin ( & logFile ) ;
//Write a header row
writeSDLogHeader ( ) ;
2022-03-17 17:38:24 -07:00
//Note the start time
logStartTime = millis ( ) ;
2021-10-12 23:10:05 -07:00
}
}
void endSDLogging ( )
2019-12-18 22:31:02 -08:00
{
2023-05-23 22:21:29 -07:00
if ( SD_status = = SD_STATUS_ACTIVE )
2021-10-12 17:53:46 -07:00
{
// Write any RingBuf data to file.
rb . sync ( ) ;
logFile . truncate ( ) ;
logFile . rewind ( ) ;
logFile . close ( ) ;
2021-12-23 19:58:53 -08:00
logFile . sync ( ) ; //This is required to update the sd object. Without this any subsequent logfiles will overwrite this one
2021-10-12 17:53:46 -07:00
2021-10-12 23:10:05 -07:00
SD_status = SD_STATUS_READY ;
2023-05-23 22:21:29 -07:00
setTS_SD_status ( ) ;
2021-10-12 17:53:46 -07:00
}
2019-12-18 22:31:02 -08:00
}
2023-04-25 22:54:15 -07:00
// Forward declare
void checkForSDStart ( ) ;
void checkForSDStop ( ) ;
2020-09-17 17:48:08 -07:00
void writeSDLogEntry ( )
2019-12-18 22:31:02 -08:00
{
2021-10-12 17:53:46 -07:00
//Check if we're already running a log
2021-10-03 06:09:53 -07:00
if ( SD_status = = SD_STATUS_READY )
{
2021-10-12 17:53:46 -07:00
//Log not currently running, check if it should be
2021-10-12 23:10:05 -07:00
checkForSDStart ( ) ;
2021-10-12 17:53:46 -07:00
}
if ( SD_status = = SD_STATUS_ACTIVE )
{
2022-03-17 17:38:24 -07:00
//Write the timestamp (x.yyy seconds format)
uint32_t duration = millis ( ) - logStartTime ;
uint32_t seconds = duration / 1000 ;
uint32_t milliseconds = duration % 1000 ;
rb . print ( seconds ) ;
rb . print ( ' . ' ) ;
if ( milliseconds < 100 ) { rb . print ( " 0 " ) ; }
if ( milliseconds < 10 ) { rb . print ( " 0 " ) ; }
rb . print ( milliseconds ) ;
rb . print ( ' , ' ) ;
2021-12-23 18:30:14 -08:00
//Write the line to the ring buffer
2021-10-12 17:53:46 -07:00
for ( byte x = 0 ; x < SD_LOG_NUM_FIELDS ; x + + )
2020-09-17 17:48:08 -07:00
{
2022-08-09 19:12:42 -07:00
# if FPU_MAX_SIZE >= 32
float entryValue = getReadableFloatLogEntry ( x ) ;
if ( IS_INTEGER ( entryValue ) ) { rb . print ( ( uint16_t ) entryValue ) ; }
else { rb . print ( entryValue ) ; }
# else
rb . print ( getReadableLogEntry ( x ) ) ;
# endif
2021-10-12 17:53:46 -07:00
if ( x < ( SD_LOG_NUM_FIELDS - 1 ) ) { rb . print ( " , " ) ; }
2021-10-03 06:09:53 -07:00
}
rb . println ( " " ) ;
2021-10-12 17:53:46 -07:00
2021-10-12 23:10:05 -07:00
//Check if write to SD from ringbuffer is needed
//We write to SD when there is more than 1 sector worth of data in the ringbuffer and there is not already a write being performed
if ( ( rb . bytesUsed ( ) > = SD_SECTOR_SIZE ) & & ! logFile . isBusy ( ) )
2021-10-03 06:09:53 -07:00
{
2021-10-12 23:10:05 -07:00
uint16_t bytesWritten = rb . writeOut ( SD_SECTOR_SIZE ) ;
//Make sure that the entire sector was written successfully
if ( SD_SECTOR_SIZE ! = bytesWritten )
{
SD_status = SD_STATUS_ERROR_WRITE_FAIL ;
}
2021-10-12 17:53:46 -07:00
}
2021-10-12 23:10:05 -07:00
//Check whether we should stop logging
checkForSDStop ( ) ;
2021-12-23 18:30:14 -08:00
//Check whether the file is full (IE When there is not enough room to write 1 more sector)
2021-12-23 19:58:53 -08:00
if ( ( logFile . dataLength ( ) - logFile . curPosition ( ) ) < SD_SECTOR_SIZE )
2021-12-23 18:30:14 -08:00
{
//Provided the conditions for logging are still met, a new file will be created the next time writeSDLogEntry is called
endSDLogging ( ) ;
2021-12-23 19:58:53 -08:00
beginSDLogging ( ) ;
2021-12-23 18:30:14 -08:00
}
2021-10-12 17:53:46 -07:00
}
2021-10-12 23:10:05 -07:00
setTS_SD_status ( ) ;
2021-10-12 17:53:46 -07:00
}
void writeSDLogHeader ( )
{
2022-03-17 17:38:24 -07:00
//Write header for Time field
rb . print ( " Time, " ) ;
//WRite remaining fields based on log definitions
2021-10-12 23:10:05 -07:00
for ( byte x = 0 ; x < SD_LOG_NUM_FIELDS ; x + + )
2021-10-12 17:53:46 -07:00
{
2021-10-12 23:10:05 -07:00
# ifdef CORE_AVR
//This will probably never be used
char buffer [ 30 ] ;
strcpy_P ( buffer , ( char * ) pgm_read_word ( & ( header_table [ x ] ) ) ) ;
rb . print ( buffer ) ;
# else
rb . print ( header_table [ x ] ) ;
# endif
if ( x < ( SD_LOG_NUM_FIELDS - 1 ) ) { rb . print ( " , " ) ; }
2021-10-03 06:09:53 -07:00
}
2021-10-12 23:10:05 -07:00
rb . println ( " " ) ;
2019-12-18 22:31:02 -08:00
}
2021-01-21 21:16:30 -08:00
//Sets the status variable for TunerStudio
void setTS_SD_status ( )
{
2021-11-19 13:29:11 -08:00
if ( SD_status = = SD_STATUS_ERROR_NO_CARD ) { BIT_CLEAR ( currentStatus . TS_SD_Status , SD_STATUS_CARD_PRESENT ) ; } // CARD is not present
else { BIT_SET ( currentStatus . TS_SD_Status , SD_STATUS_CARD_PRESENT ) ; } // CARD present
BIT_SET ( currentStatus . TS_SD_Status , SD_STATUS_CARD_TYPE ) ; // CARD is SDHC
BIT_SET ( currentStatus . TS_SD_Status , SD_STATUS_CARD_READY ) ; // CARD is ready
if ( SD_status = = SD_STATUS_ACTIVE ) { BIT_SET ( currentStatus . TS_SD_Status , SD_STATUS_CARD_LOGGING ) ; } // CARD is logging
else { BIT_CLEAR ( currentStatus . TS_SD_Status , SD_STATUS_CARD_LOGGING ) ; } // CARD is not logging
if ( ( SD_status > = SD_STATUS_ERROR_NO_FS ) ) { BIT_SET ( currentStatus . TS_SD_Status , SD_STATUS_CARD_ERROR ) ; } // CARD has an error
else { BIT_CLEAR ( currentStatus . TS_SD_Status , SD_STATUS_CARD_ERROR ) ; } // CARD has no error
BIT_SET ( currentStatus . TS_SD_Status , SD_STATUS_CARD_FS ) ; // CARD has a FAT32 filesystem (Though this will be exFAT)
2021-11-23 15:23:15 -08:00
BIT_CLEAR ( currentStatus . TS_SD_Status , SD_STATUS_CARD_UNUSED ) ; //Unused bit is always 0
2021-10-12 17:53:46 -07:00
}
/**
* Checks whether the SD logging should be started based on the logging trigger conditions
*/
void checkForSDStart ( )
{
//Logging can only start if we're in the ready state
2021-10-12 23:10:05 -07:00
//We must check the SD_status each time to prevent trying to init a new log file multiple times
2022-08-30 21:48:46 -07:00
if ( configPage13 . onboard_log_file_style > 0 )
2021-10-12 17:53:46 -07:00
{
2022-08-30 21:48:46 -07:00
//Check for enable at boot
if ( ( configPage13 . onboard_log_trigger_boot ) & & ( SD_status = = SD_STATUS_READY ) )
2021-10-12 17:53:46 -07:00
{
2022-08-30 21:48:46 -07:00
//Check that we're not already finished the logging
if ( ( millis ( ) / 1000 ) < = configPage13 . onboard_log_tr1_duration )
{
beginSDLogging ( ) ; //Setup the log file, preallocation, header row
}
}
2021-10-12 17:53:46 -07:00
2022-08-30 21:48:46 -07:00
//Check for RPM based Enable
if ( ( configPage13 . onboard_log_trigger_RPM ) & & ( SD_status = = SD_STATUS_READY ) )
2021-10-12 17:53:46 -07:00
{
2022-08-30 21:48:46 -07:00
if ( ( currentStatus . RPMdiv100 > = configPage13 . onboard_log_tr2_thr_on ) & & ( currentStatus . RPMdiv100 < = configPage13 . onboard_log_tr2_thr_off ) ) //Need to check both on and off conditions to prevent logging starting and stopping continually
{
beginSDLogging ( ) ; //Setup the log file, preallocation, header row
}
2021-10-12 17:53:46 -07:00
}
2022-08-30 21:48:46 -07:00
//Check for engine protection based enable
if ( ( configPage13 . onboard_log_trigger_prot ) & & ( SD_status = = SD_STATUS_READY ) )
2021-12-21 20:20:39 -08:00
{
2022-08-30 21:48:46 -07:00
if ( currentStatus . engineProtectStatus > 0 )
{
beginSDLogging ( ) ; //Setup the log file, preallocation, header row
}
2021-12-21 20:20:39 -08:00
}
2021-10-12 23:10:05 -07:00
2022-08-30 21:48:46 -07:00
if ( ( configPage13 . onboard_log_trigger_Vbat ) & & ( SD_status = = SD_STATUS_READY ) )
{
2021-10-12 23:10:05 -07:00
2022-08-30 21:48:46 -07:00
}
2021-10-12 23:10:05 -07:00
2022-08-30 21:48:46 -07:00
if ( ( configPage13 . onboard_log_trigger_Epin ) & & ( SD_status = = SD_STATUS_READY ) )
2022-07-07 21:31:48 -07:00
{
2022-08-30 21:48:46 -07:00
if ( digitalRead ( pinSDEnable ) = = LOW )
{
beginSDLogging ( ) ; //Setup the log file, preallocation, header row
}
2022-07-07 21:31:48 -07:00
}
2021-10-12 17:53:46 -07:00
}
}
/**
* Checks whether the SD logging should be stopped , based on the logging trigger conditions
*/
void checkForSDStop ( )
{
2021-11-23 21:14:31 -08:00
//Check the various conditions to see if we should stop logging
bool log_boot = false ;
bool log_RPM = false ;
bool log_prot = false ;
bool log_Vbat = false ;
2022-07-07 21:31:48 -07:00
bool log_Epin = false ;
2021-11-23 21:14:31 -08:00
2021-10-12 23:10:05 -07:00
//Logging only needs to be stopped if already active
2021-10-12 17:53:46 -07:00
if ( SD_status = = SD_STATUS_ACTIVE )
{
2021-10-12 23:10:05 -07:00
//Check for enable at boot
if ( configPage13 . onboard_log_trigger_boot )
{
//Check if we're past the logging duration
2021-11-23 21:14:31 -08:00
if ( ( millis ( ) / 1000 ) < = configPage13 . onboard_log_tr1_duration )
2021-10-12 23:10:05 -07:00
{
2021-11-23 21:14:31 -08:00
log_boot = true ;
2021-10-12 23:10:05 -07:00
}
}
2021-11-23 21:14:31 -08:00
if ( configPage13 . onboard_log_trigger_RPM )
{
2022-04-05 00:56:18 -07:00
if ( ( currentStatus . RPMdiv100 > = configPage13 . onboard_log_tr2_thr_on ) & & ( currentStatus . RPMdiv100 < = configPage13 . onboard_log_tr2_thr_off ) )
2021-11-23 21:14:31 -08:00
{
log_RPM = true ;
}
}
if ( configPage13 . onboard_log_trigger_prot )
{
2021-12-21 21:10:06 -08:00
if ( currentStatus . engineProtectStatus > 0 )
2021-12-21 20:20:39 -08:00
{
log_prot = true ;
}
2021-11-23 21:14:31 -08:00
}
if ( configPage13 . onboard_log_trigger_Vbat )
{
}
2022-07-07 21:31:48 -07:00
//External Pin
if ( configPage13 . onboard_log_trigger_Epin )
{
if ( digitalRead ( pinSDEnable ) = = LOW )
{
log_Epin = true ;
}
}
2021-11-23 21:14:31 -08:00
//Check all conditions to see if we should stop logging
2022-07-07 21:31:48 -07:00
if ( ( log_boot = = false ) & & ( log_RPM = = false ) & & ( log_prot = = false ) & & ( log_Vbat = = false ) & & ( log_Epin = = false ) & & ( manualLogActive = = false ) )
2021-11-23 21:14:31 -08:00
{
2022-08-30 21:48:46 -07:00
endSDLogging ( ) ;
2021-11-23 21:14:31 -08:00
}
2022-08-30 21:48:46 -07:00
//ALso check whether logging has been disabled entirely
if ( configPage13 . onboard_log_file_style = = 0 ) { endSDLogging ( ) ; }
2021-10-12 17:53:46 -07:00
}
2021-11-23 21:14:31 -08:00
2021-10-12 17:53:46 -07:00
}
2023-05-01 20:13:19 -07:00
void syncSDLog ( )
{
2023-05-23 22:21:29 -07:00
if ( ( SD_status = = SD_STATUS_ACTIVE ) & & ( ! logFile . isBusy ( ) ) & & ( ! sd . isBusy ( ) ) )
2023-05-01 20:13:19 -07:00
{
logFile . sync ( ) ;
}
}
2021-10-12 17:53:46 -07:00
/**
2021-12-09 19:29:01 -08:00
* Will perform a complete format of the SD card to ExFAT .
* This will delete all files and create a new empty file system .
* The SD status will be set to busy when this happens to prevent any other operations
2021-10-12 17:53:46 -07:00
*/
void formatExFat ( )
{
bool result = false ;
2021-12-09 19:29:01 -08:00
//Set the SD status to busy
BIT_CLEAR ( currentStatus . TS_SD_Status , SD_STATUS_CARD_READY ) ;
2021-12-23 18:30:14 -08:00
logFile . close ( ) ;
2021-10-12 17:53:46 -07:00
if ( sd . cardBegin ( SD_CONFIG ) )
{
if ( sd . format ( ) )
{
if ( sd . volumeBegin ( ) )
{
result = true ;
}
}
}
2021-01-21 21:16:30 -08:00
2021-12-09 19:29:01 -08:00
if ( result = = false ) { SD_status = SD_STATUS_ERROR_FORMAT_FAIL ; }
else { BIT_SET ( currentStatus . TS_SD_Status , SD_STATUS_CARD_READY ) ; }
}
/**
* @ brief Deletes a log file from the SD card
*
2022-04-10 17:49:58 -07:00
* Log files all have the same name with a 4 digit number at the end ( Eg SPD_0001 . csv ) . TS sends the 4 digits as ASCII characters and they are combined here with the logfile prefix
2021-12-09 19:29:01 -08:00
*
* @ param log1
* @ param log2
* @ param log3
* @ param log4
*/
void deleteLogFile ( char log1 , char log2 , char log3 , char log4 )
{
char logFileName [ 13 ] ;
strcpy ( logFileName , LOG_FILE_PREFIX ) ;
logFileName [ 4 ] = log1 ;
logFileName [ 5 ] = log2 ;
logFileName [ 6 ] = log3 ;
logFileName [ 7 ] = log4 ;
logFileName [ 8 ] = ' . ' ;
strcpy ( logFileName + 9 , LOG_FILE_EXTENSION ) ;
//logFileName[8] = '\0';
if ( sd . exists ( logFileName ) )
2021-10-12 17:53:46 -07:00
{
2021-12-09 19:29:01 -08:00
sd . remove ( logFileName ) ;
2021-10-12 17:53:46 -07:00
}
}
// Call back for file timestamps. Only called for file create and sync().
void dateTime ( uint16_t * date , uint16_t * time , uint8_t * ms10 ) {
// Return date using FS_DATE macro to format fields.
//*date = FS_DATE(year(), month(), day());
* date = FS_DATE ( rtc_getYear ( ) , rtc_getMonth ( ) , rtc_getDay ( ) ) ;
// Return time using FS_TIME macro to format fields.
* time = FS_TIME ( rtc_getHour ( ) , rtc_getMinute ( ) , rtc_getSecond ( ) ) ;
// Return low time bits in units of 10 ms.
* ms10 = rtc_getSecond ( ) & 1 ? 100 : 0 ;
2021-01-21 21:16:30 -08:00
}
2021-11-29 19:40:01 -08:00
uint32_t sectorCount ( )
{
return sd . card ( ) - > sectorCount ( ) ;
}
2022-04-10 17:49:58 -07:00
# endif