Mercurial > hg > beaglert
diff core/WriteFile.cpp @ 153:3b7270949a97
Added WriteFile class to log data to disc in a low priority thread
author | Giulio Moro <giuliomoro@yahoo.it> |
---|---|
date | Wed, 07 Oct 2015 20:58:53 +0100 |
parents | |
children | f36313cbb55d |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/WriteFile.cpp Wed Oct 07 20:58:53 2015 +0100 @@ -0,0 +1,245 @@ +/* + * WriteFile.cpp + * + * Created on: 5 Oct 2015 + * Author: giulio + */ + +#include "WriteFile.h" +//initialise static members +bool WriteFile::staticConstructed=false; +AuxiliaryTask WriteFile::writeAllFilesTask=NULL; +std::vector<WriteFile *> WriteFile::objAddrs(0); +bool WriteFile::threadRunning; +bool WriteFile::threadIsExiting; +int WriteFile::sleepTimeMs; + +void WriteFile::staticConstructor(){ + if(staticConstructed==true) + return; + staticConstructed=true; + threadIsExiting=false; + threadRunning=false; + writeAllFilesTask = BeagleRT_createAuxiliaryTask(WriteFile::run, 60, "writeAllFilesTask"); +} + +WriteFile::WriteFile(){ + buffer = NULL; + format = NULL; + header = NULL; + footer = NULL; + stringBuffer = NULL; +}; + +void WriteFile::init(const char* filename){ //if you do not call this before using the object, results are undefined + file = fopen(filename, "w"); + variableOpen = false; + lineLength = 0; + echo = false; + bufferLength = 0; + readPointer = 0; + writePointer = 0; + sleepTimeMs = 1; + stringBufferLength = 1000; + stringBuffer = (char*)malloc(sizeof(char) * (stringBufferLength)); + setHeader("variable=[\n"); + setFooter("];\n"); + staticConstructor(); //TODO: this line should be in the constructor, but cannot because of a bug in BeagleRT + objAddrs.push_back(this); +} + +void WriteFile::setEcho(bool newEcho){ + echo=newEcho; +} + +void WriteFile::print(const char* string){ + if(echo == true){ + printf("%s", string); + } + if(file != NULL){ + fprintf(file, "%s", string); + } +} + +void WriteFile::writeLine(){ + int stringBufferPointer = 0; + for(unsigned int n = 0; n < formatTokens.size(); n++){ + int numOfCharsWritten = snprintf( &stringBuffer[stringBufferPointer], stringBufferLength - stringBufferPointer, + formatTokens[n], buffer[readPointer]); + stringBufferPointer += numOfCharsWritten; + readPointer++; + if (readPointer >= bufferLength){ + readPointer -= bufferLength; + } + } + print(stringBuffer); +} + +void WriteFile::setLineLength(int newLineLength){ + lineLength=newLineLength; + free(buffer); + bufferLength = lineLength * 10000; // circular buffer of length 10000 lineLenghts + buffer = (float*)malloc(sizeof(float) * bufferLength); +} + +void WriteFile::log(float value){ + if(format == NULL || buffer == NULL) + return; + buffer[writePointer] = value; + writePointer++; + if(writePointer == bufferLength){ + writePointer = 0; + } + if(writePointer == readPointer){ + fprintf(stderr, "WriteFile: pointers crossed, you should probably write less data to disk\n"); + } + if(threadRunning == false){ + startThread(); + } +} + +void WriteFile::log(float* array, int length){ + for(int n = 0; n < length; n++){ + log(array[n]); + } +} + +WriteFile::~WriteFile() { + free(format); + free(buffer); + free(header); + free(footer); + free(stringBuffer); +} + +void WriteFile::setFormat(const char* newFormat){ + allocateAndCopyString(newFormat, &format); + for(unsigned int n = 0; n < formatTokens.size(); n++){ + free(formatTokens[n]); + } + formatTokens.clear(); + int tokenStart = 0; + bool firstToken = true; + for(unsigned int n = 0; n < strlen(format)+1; n++){ + if(format[n] == '%' && format[n + 1] == '%'){ + n++; + } else if (format[n] == '%' || format[n] == 0){ + if(firstToken == true){ + firstToken = false; + continue; + } + char* string; + unsigned int tokenLength = n - tokenStart; + if(tokenLength == 0) + continue; + string = (char*)malloc((1+tokenLength)*sizeof(char)); + for(unsigned int i = 0; i < tokenLength; i++){ + string[i] = format[tokenStart + i]; + } + string[tokenLength] = 0; + formatTokens.push_back(string); + tokenStart = n; + } + } + setLineLength(formatTokens.size()); +} + +int WriteFile::getNumInstances(){ + return objAddrs.size(); +} + +void WriteFile::startThread(){ + BeagleRT_scheduleAuxiliaryTask(writeAllFilesTask); +} + +void WriteFile::stopThread(){ + threadIsExiting=true; +} + +bool WriteFile::threadShouldExit(){ + return(gShouldStop || threadIsExiting); +} + +bool WriteFile::isThreadRunning(){ + return threadRunning; +} + +float WriteFile::getBufferStatus(){ + return 1-getOffset()/(float)bufferLength; +} + +int WriteFile::getOffset(){ + int offset = writePointer - readPointer; + if( offset < 0) + offset += bufferLength; + return offset; +} + +void WriteFile::writeOutput(){ + while( getOffset() >= lineLength ){ //if there is less than one line worth of data to write, skip over. + // So we make sure we always write full lines + writeLine(); + } +} + +void WriteFile::writeAllOutputs(){ + for(unsigned int n = 0; n < objAddrs.size(); n++){ + objAddrs[n] -> writeOutput(); + } +} + +void WriteFile::writeAllHeaders(){ + for(unsigned int n = 0; n < objAddrs.size(); n++){ + objAddrs[n] -> writeHeader(); + } +} + +void WriteFile::writeAllFooters(){ + for(unsigned int n = 0; n < objAddrs.size(); n++){ + objAddrs[n] -> writeFooter(); + } +} + +void WriteFile::writeHeader(){ + print(header); +} + +void WriteFile::writeFooter(){ + print(footer); + fflush(file); + fclose(file); +} + +void WriteFile::setHeader(const char* newHeader){ + allocateAndCopyString(newHeader, &header); + sanitizeString(header); +} + +void WriteFile::setFooter(const char* newFooter){ + allocateAndCopyString(newFooter, &footer); +} + +void WriteFile::sanitizeString(char* string){ + for(int unsigned n = 0; n < strlen(string); n++){ //purge %'s from the string + if(string[n] == '%'){ + string[n] = ' '; + } + } +} + +void WriteFile::run(){ + threadRunning = true; + writeAllHeaders(); + while(threadShouldExit()==false){ + writeAllOutputs(); + usleep(sleepTimeMs*1000); + } + writeAllFooters(); // when ctrl-c is pressed, the last line is closed and the file is closed + threadRunning = false; +} + +void WriteFile::allocateAndCopyString(const char* source, char** destination){ + free(*destination); + *destination = (char*)malloc(sizeof(char) * (strlen(source) + 1)); + strcpy(*destination, source); +}