speeduino/speeduino/SD_logger.cpp

799 lines
29 KiB
C++

#include "globals.h"
#include BOARD_H
#ifdef SD_LOGGING
#include <SPI.h>
#ifdef __SD_H__
#include <SD.h>
#else
#include "SdFat.h"
#endif
#include "SD_logger.h"
#include "logger.h"
#include "rtc_common.h"
#include "maths.h"
//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");
SdExFat sd;
ExFile logFile;
RingBuf<ExFile, RING_BUF_CAPACITY> rb;
uint8_t SD_status = SD_STATUS_OFF;
uint16_t currentLogFileNumber;
bool manualLogActive = false;
uint32_t logStartTime = 0; //In ms
void initSD()
{
//Set default state to ready. If any stage of the init fails, this will be changed
SD_status = SD_STATUS_READY;
//Set the RTC callback. This is used to set the correct timestamp on file creation and sync operations
FsDateTime::setCallback(dateTime);
// Initialise the SD.
if (!sd.begin(SD_CONFIG))
{
//sd.initErrorHalt(&Serial);
//if (sdErrorCode() == SD_CARD_ERROR_CMD0) { SD_status = SD_STATUS_ERROR_NO_CARD;
SD_status = SD_STATUS_ERROR_NO_CARD;
}
//Set the TunerStudio status variable
setTS_SD_status();
}
bool createLogFile()
{
//TunerStudio only supports 8.3 filename format.
char filenameBuffer[13]; //8 + 1 + 3 + 1
bool returnValue = false;
//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");
*/
//Lookup the next available file number
currentLogFileNumber = getNextSDLogFileNumber();
//Create the filename
//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);
logFile.close();
if (logFile.open(filenameBuffer, O_RDWR | O_CREAT | O_TRUNC))
{
returnValue = true;
}
return returnValue;
}
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
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);
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
}
//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(); }
//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
buffer[14] = lowByte(pTime);
buffer[15] = highByte(pTime);
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;
}
void readSDSectors(uint8_t* buffer, uint32_t sectorNumber, uint16_t sectorCount)
{
sd.card()->readSectors(sectorNumber, buffer, sectorCount);
}
// Forward declare
void writeSDLogHeader();
void beginSDLogging()
{
if(SD_status == SD_STATUS_READY)
{
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
// Open or create file - truncate existing file.
if (!createLogFile())
{
SD_status = SD_STATUS_ERROR_NO_WRITE;
setTS_SD_status();
return;
}
//Perform pre-allocation on card. This dramatically improves write speed
if (!logFile.preAllocate(SD_LOG_FILE_SIZE))
{
SD_status = SD_STATUS_ERROR_NO_SPACE;
setTS_SD_status();
return;
}
//initialise the RingBuf.
rb.begin(&logFile);
//Write a header row
writeSDLogHeader();
//Note the start time
logStartTime = millis();
}
}
void endSDLogging()
{
if(SD_status == SD_STATUS_ACTIVE)
{
// Write any RingBuf data to file.
rb.sync();
logFile.truncate();
logFile.rewind();
logFile.close();
logFile.sync(); //This is required to update the sd object. Without this any subsequent logfiles will overwrite this one
SD_status = SD_STATUS_READY;
setTS_SD_status();
}
}
// Forward declare
void checkForSDStart();
void checkForSDStop();
void writeSDLogEntry()
{
//Check if we're already running a log
if(SD_status == SD_STATUS_READY)
{
//Log not currently running, check if it should be
checkForSDStart();
}
if(SD_status == SD_STATUS_ACTIVE)
{
//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(',');
//Write the line to the ring buffer
for(byte x=0; x<SD_LOG_NUM_FIELDS; x++)
{
#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
if(x < (SD_LOG_NUM_FIELDS - 1)) { rb.print(","); }
}
rb.println("");
//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() )
{
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;
}
}
//Check whether we should stop logging
checkForSDStop();
//Check whether the file is full (IE When there is not enough room to write 1 more sector)
if( (logFile.dataLength() - logFile.curPosition()) < SD_SECTOR_SIZE)
{
//Provided the conditions for logging are still met, a new file will be created the next time writeSDLogEntry is called
endSDLogging();
beginSDLogging();
}
}
setTS_SD_status();
}
void writeSDLogHeader()
{
//Write header for Time field
rb.print("Time,");
//WRite remaining fields based on log definitions
for(byte x=0; x<SD_LOG_NUM_FIELDS; x++)
{
#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(","); }
}
rb.println("");
}
//Sets the status variable for TunerStudio
void setTS_SD_status()
{
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)
BIT_CLEAR(currentStatus.TS_SD_Status, SD_STATUS_CARD_UNUSED); //Unused bit is always 0
}
/**
* 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
//We must check the SD_status each time to prevent trying to init a new log file multiple times
if(configPage13.onboard_log_file_style > 0)
{
//Check for enable at boot
if( (configPage13.onboard_log_trigger_boot) && (SD_status == SD_STATUS_READY) )
{
//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
}
}
//Check for RPM based Enable
if( (configPage13.onboard_log_trigger_RPM) && (SD_status == SD_STATUS_READY) )
{
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
}
}
//Check for engine protection based enable
if((configPage13.onboard_log_trigger_prot) && (SD_status == SD_STATUS_READY) )
{
if(currentStatus.engineProtectStatus > 0)
{
beginSDLogging(); //Setup the log file, preallocation, header row
}
}
if( (configPage13.onboard_log_trigger_Vbat) && (SD_status == SD_STATUS_READY) )
{
}
if((configPage13.onboard_log_trigger_Epin) && (SD_status == SD_STATUS_READY) )
{
if(digitalRead(pinSDEnable) == LOW)
{
beginSDLogging(); //Setup the log file, preallocation, header row
}
}
}
}
/**
* Checks whether the SD logging should be stopped, based on the logging trigger conditions
*/
void checkForSDStop()
{
//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;
bool log_Epin = false;
//Logging only needs to be stopped if already active
if(SD_status == SD_STATUS_ACTIVE)
{
//Check for enable at boot
if(configPage13.onboard_log_trigger_boot)
{
//Check if we're past the logging duration
if((millis() / 1000) <= configPage13.onboard_log_tr1_duration)
{
log_boot = true;
}
}
if(configPage13.onboard_log_trigger_RPM)
{
if( (currentStatus.RPMdiv100 >= configPage13.onboard_log_tr2_thr_on) && (currentStatus.RPMdiv100 <= configPage13.onboard_log_tr2_thr_off) )
{
log_RPM = true;
}
}
if(configPage13.onboard_log_trigger_prot)
{
if(currentStatus.engineProtectStatus > 0)
{
log_prot = true;
}
}
if(configPage13.onboard_log_trigger_Vbat)
{
}
//External Pin
if(configPage13.onboard_log_trigger_Epin)
{
if(digitalRead(pinSDEnable) == LOW)
{
log_Epin = true;
}
}
//Check all conditions to see if we should stop logging
if( (log_boot == false) && (log_RPM == false) && (log_prot == false) && (log_Vbat == false) && (log_Epin == false) && (manualLogActive == false) )
{
endSDLogging();
}
//ALso check whether logging has been disabled entirely
if(configPage13.onboard_log_file_style == 0) { endSDLogging(); }
}
}
void syncSDLog()
{
if( (SD_status == SD_STATUS_ACTIVE) && (!logFile.isBusy()) && (!sd.isBusy()) )
{
logFile.sync();
}
}
/**
* 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
*/
void formatExFat()
{
bool result = false;
//Set the SD status to busy
BIT_CLEAR(currentStatus.TS_SD_Status, SD_STATUS_CARD_READY);
logFile.close();
if (sd.cardBegin(SD_CONFIG))
{
if(sd.format())
{
if (sd.volumeBegin())
{
result = true;
}
}
}
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
*
* 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
*
* @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))
{
sd.remove(logFileName);
}
}
// 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;
}
uint32_t sectorCount()
{
return sd.card()->sectorCount();
}
#endif