From 07bfc6025cfe8f6590982265549171cff237fc71 Mon Sep 17 00:00:00 2001 From: Josh Stewart Date: Wed, 24 Nov 2021 10:23:15 +1100 Subject: [PATCH] Add file listing of SD card through to TS --- speeduino/SD_logger.h | 8 +++- speeduino/SD_logger.ino | 95 ++++++++++++++++++++++++++++++++++++++++- speeduino/comms.h | 24 ----------- speeduino/newComms.cpp | 42 +++++++++++++++--- speeduino/newComms.h | 10 +++-- 5 files changed, 145 insertions(+), 34 deletions(-) diff --git a/speeduino/SD_logger.h b/speeduino/SD_logger.h index 62f34e24..2bc366ef 100644 --- a/speeduino/SD_logger.h +++ b/speeduino/SD_logger.h @@ -23,6 +23,7 @@ #define SD_STATUS_CARD_ERROR 4 //0=no error, 1=error #define SD_STATUS_CARD_VERSION 5 //0=1.x, 1=2.x #define SD_STATUS_CARD_FS 6 //0=no FAT16, 1=FAT32 +#define SD_STATUS_CARD_UNUSED 7 //0=normal, 1=unused #define SD_SECTOR_SIZE 512 // Standard SD sector size @@ -35,7 +36,9 @@ //Test values only #define SD_LOG_FILE_SIZE 10000000 //Defuault 10mb file size -#define LOG_FILENAME "SdioLogger.csv" +#define MAX_LOG_FILES 10000 +#define LOG_FILE_PREFIX "SPD_" +#define LOG_FILE_EXTENSION "csv" #define RING_BUF_CAPACITY SD_LOG_ENTRY_SIZE * 10 //Allow for 10 entries in the ringbuffer. Will need tuning /* @@ -50,6 +53,7 @@ extern ExFile logFile; extern RingBuf rb; extern uint8_t SD_status; +extern uint16_t currentLogFileNumber; void initSD(); void writeSDLogEntry(); @@ -60,6 +64,8 @@ void setTS_SD_status(); void formatExFat(); bool createLogFile(); void dateTime(uint16_t*, uint16_t*, uint8_t*); //Used for timestamping with RTC +uint16_t getNextSDLogFileNumber(); +bool getSDLogFileDetails(uint8_t* , uint16_t); diff --git a/speeduino/SD_logger.ino b/speeduino/SD_logger.ino index 152655a3..23126d0c 100644 --- a/speeduino/SD_logger.ino +++ b/speeduino/SD_logger.ino @@ -9,6 +9,7 @@ SdExFat sd; ExFile logFile; RingBuf rb; uint8_t SD_status = SD_STATUS_OFF; +uint16_t currentLogFileNumber; void initSD() { @@ -32,9 +33,11 @@ void initSD() bool createLogFile() { - char filenameBuffer[24]; + //TunerStudio only supports 8.3 filename format. + char filenameBuffer[13]; //8 + 1 + 3 + 1 bool returnValue = false; + /* //Filename format is: YYYY-MM-DD_HH.MM.SS.csv char intBuffer[5]; itoa(rtc_getYear(), intBuffer, 10); @@ -55,6 +58,14 @@ bool createLogFile() itoa(rtc_getSecond(), intBuffer, 10); strcat(filenameBuffer, intBuffer); strcat(filenameBuffer, ".csv"); + */ + if(currentLogFileNumber == 0) + { + //Lookup the next available file number + currentLogFileNumber = getNextSDLogFileNumber(); + } + //Create the filename + sprintf(filenameBuffer, "%s%04d.%s", LOG_FILE_PREFIX, currentLogFileNumber, LOG_FILE_EXTENSION); //if (!logFile.open(LOG_FILENAME, O_RDWR | O_CREAT | O_TRUNC)) if (logFile.open(filenameBuffer, O_RDWR | O_CREAT | O_TRUNC)) @@ -65,6 +76,87 @@ bool createLogFile() 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 + sprintf(filenameBuffer, "%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 + } + + //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(pDate); + buffer[15] = highByte(pDate); + 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 beginSDLogging() { if(SD_status == SD_STATUS_READY) @@ -183,6 +275,7 @@ void setTS_SD_status() 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 } diff --git a/speeduino/comms.h b/speeduino/comms.h index f6b73309..a7212228 100644 --- a/speeduino/comms.h +++ b/speeduino/comms.h @@ -10,30 +10,6 @@ #ifndef COMMS_H #define COMMS_H -//Hardcoded TunerStudio addresses/commands for various SD/RTC commands -#define SD_READWRITE_PAGE 0x11 -#define SD_RTC_PAGE 0x07 -#define SD_READ_STAT_OFFSET 0x0000 -#define SD_READ_STAT_LENGTH 0x1000 -#define SD_READ_DIR_OFFSET 0x0100 -#define SD_READ_DIR_LENGTH 0x0200 -#define SD_READ_SEC_OFFSET 0x0200 -#define SD_READ_SEC_LENGTH 0x0400 -#define SD_READ_STRM_OFFSET 0x0400 -#define SD_READ_STRM_LENGTH 0x0100 -#define SD_WRITE_DO_OFFSET 0x0000 -#define SD_WRITE_DO_LENGTH 0x0001 -#define SD_WRITE_SEC_OFFSET 0x0300 -#define SD_WRITE_SEC_LENGTH 0x0402 -#define SD_ERASEFILE_OFFSET 0x0600 -#define SD_ERASEFILE_LENGTH 0x0600 -#define SD_SPD_TEST_OFFSET 0x0700 -#define SD_SPD_TEST_LENGTH 0x0400 -#define SD_RTC_WRITE_OFFSET 0x7E02 -#define SD_RTC_WRITE_LENGTH 0x0900 -#define SD_RTC_READ_OFFSET 0x4D02 -#define SD_RTC_READ_LENGTH 0x0800 - extern byte currentPage;//Not the same as the speeduino config page numbers extern bool isMap; /**< Whether or not the currentPage contains only a 3D map that would require translation */ diff --git a/speeduino/newComms.cpp b/speeduino/newComms.cpp index 3fe7db49..7300dcd7 100644 --- a/speeduino/newComms.cpp +++ b/speeduino/newComms.cpp @@ -31,6 +31,7 @@ uint16_t serialPayloadLength = 0; bool serialReceivePending = false; /**< Whether or not a serial request has only been partially received. This occurs when a the length has been received in the serial buffer, but not all of the payload or CRC has yet been received. */ uint16_t serialBytesReceived = 0; uint32_t serialCRC = 0; +uint16_t SDcurrentDirChunk; uint8_t serialPayload[SERIAL_BUFFER_SIZE]; /**< Pointer to the serial payload buffer. */ /** Processes the incoming data on the serial buffer based on the command sent. @@ -397,9 +398,8 @@ void processSerialCommand() serialPayload[0] = SERIAL_RC_OK; - - //Serial.write(currentStatus.TS_SD_Status); - serialPayload[1] = 5; + serialPayload[1] = currentStatus.TS_SD_Status; + //serialPayload[1] = 5; serialPayload[2] = 0; //All other values are 2 bytes @@ -430,10 +430,33 @@ void processSerialCommand() sendSerialPayload(&serialPayload, 17); } - //else if(length == 0x202) + else if((offset == SD_READ_DIR_OFFSET) && (length == SD_READ_DIR_LENGTH)) + { + //Send file details + serialPayload[0] = SERIAL_RC_OK; + + uint16_t logFileNumber = (SDcurrentDirChunk * 16) + 1; + uint8_t filesInCurrentChunk = 0; + uint16_t payloadIndex = 1; + while((filesInCurrentChunk < 16) && (getSDLogFileDetails(&serialPayload[payloadIndex], logFileNumber) == true)) + { + logFileNumber++; + filesInCurrentChunk++; + payloadIndex += 32; + } + serialPayload[33] = lowByte(SDcurrentDirChunk); + serialPayload[34] = highByte(SDcurrentDirChunk); + + + + sendSerialPayload(&serialPayload, (payloadIndex + 2)); + + } + else if((offset == SD_READ_STAT_OFFSET) && (length == SD_READ_STAT_LENGTH)) { //File info } + } else if(cmd == 0x14) { @@ -572,7 +595,16 @@ void processSerialCommand() 4 Load status variable 5 Init SD card */ - setTS_SD_status(); //Set SD status values + uint8_t command = serialPayload[7]; + if(command == 4) { setTS_SD_status(); } //Set SD status values + + sendSerialReturnCode(SERIAL_RC_OK); + } + else if((valueOffset == SD_WRITE_DIR_OFFSET) && (chunkSize == SD_WRITE_DIR_LENGTH)) + { + //Begin SD directory read. Value in payload represents the directory chunk to read + //Directory chunks are each 32 files long + SDcurrentDirChunk = word(serialPayload[7], serialPayload[8]); sendSerialReturnCode(SERIAL_RC_OK); } else if((valueOffset == SD_WRITE_SEC_OFFSET) && (chunkSize == SD_WRITE_SEC_LENGTH)) diff --git a/speeduino/newComms.h b/speeduino/newComms.h index e83ca88f..76ee8dff 100644 --- a/speeduino/newComms.h +++ b/speeduino/newComms.h @@ -15,14 +15,17 @@ #define SD_RTC_PAGE 0x07 #define SD_READ_STAT_OFFSET 0x0000 #define SD_READ_STAT_LENGTH 0x1000 -#define SD_READ_DIR_OFFSET 0x0100 -#define SD_READ_DIR_LENGTH 0x0200 +#define SD_READ_DIR_OFFSET 0x0000 +#define SD_READ_DIR_LENGTH 0x0202 #define SD_READ_SEC_OFFSET 0x0200 #define SD_READ_SEC_LENGTH 0x0400 #define SD_READ_STRM_OFFSET 0x0400 #define SD_READ_STRM_LENGTH 0x0100 #define SD_WRITE_DO_OFFSET 0x0000 -#define SD_WRITE_DO_LENGTH 0x0001 +//#define SD_WRITE_DO_LENGTH 0x0001 +#define SD_WRITE_DO_LENGTH 0x0100 +#define SD_WRITE_DIR_OFFSET 0x0100 +#define SD_WRITE_DIR_LENGTH 0x0200 #define SD_WRITE_SEC_OFFSET 0x0300 #define SD_WRITE_SEC_LENGTH 0x0402 #define SD_ERASEFILE_OFFSET 0x0600 @@ -54,6 +57,7 @@ extern bool serialReceivePending; /**< Whether or not a serial request has only extern uint8_t serialPayload[SERIAL_BUFFER_SIZE]; /**< Pointer to the serial payload buffer. */ extern uint16_t serialBytesReceived; /**< The number of bytes received in the serial buffer during the current command. */ extern bool serialWriteInProgress; +extern uint16_t SDcurrentDirChunk; void parseSerial();//This is the heart of the Command Line Interpeter. All that needed to be done was to make it human readable. void processSerialCommand();