giuliomoro@153: /* giuliomoro@153: * WriteFile.cpp giuliomoro@153: * giuliomoro@153: * Created on: 5 Oct 2015 giuliomoro@153: * Author: giulio giuliomoro@153: */ giuliomoro@153: giuliomoro@153: #include "WriteFile.h" giuliomoro@153: //initialise static members giuliomoro@153: bool WriteFile::staticConstructed=false; giuliomoro@153: AuxiliaryTask WriteFile::writeAllFilesTask=NULL; giuliomoro@153: std::vector WriteFile::objAddrs(0); giuliomoro@153: bool WriteFile::threadRunning; giuliomoro@153: bool WriteFile::threadIsExiting; giuliomoro@153: int WriteFile::sleepTimeMs; giuliomoro@153: giuliomoro@153: void WriteFile::staticConstructor(){ giuliomoro@153: if(staticConstructed==true) giuliomoro@153: return; giuliomoro@153: staticConstructed=true; giuliomoro@153: threadIsExiting=false; giuliomoro@153: threadRunning=false; giuliomoro@301: writeAllFilesTask = Bela_createAuxiliaryTask(WriteFile::run, 60, "writeAllFilesTask"); giuliomoro@153: } giuliomoro@153: giuliomoro@153: WriteFile::WriteFile(){ giuliomoro@153: buffer = NULL; giuliomoro@153: format = NULL; giuliomoro@153: header = NULL; giuliomoro@153: footer = NULL; giuliomoro@153: stringBuffer = NULL; giuliomoro@153: }; giuliomoro@153: giuliomoro@153: void WriteFile::init(const char* filename){ //if you do not call this before using the object, results are undefined giuliomoro@153: file = fopen(filename, "w"); giuliomoro@153: variableOpen = false; giuliomoro@153: lineLength = 0; giuliomoro@159: setEcho(false); giuliomoro@153: bufferLength = 0; giuliomoro@157: textReadPointer = 0; giuliomoro@157: binaryReadPointer = 0; giuliomoro@153: writePointer = 0; giuliomoro@153: sleepTimeMs = 1; giuliomoro@153: stringBufferLength = 1000; giuliomoro@153: stringBuffer = (char*)malloc(sizeof(char) * (stringBufferLength)); giuliomoro@153: setHeader("variable=[\n"); giuliomoro@153: setFooter("];\n"); giuliomoro@301: staticConstructor(); //TODO: this line should be in the constructor, but cannot be because of a bug in Bela giuliomoro@153: objAddrs.push_back(this); giuliomoro@157: echoedLines = 0; giuliomoro@157: echoPeriod = 1; giuliomoro@153: } giuliomoro@153: giuliomoro@157: void WriteFile::setFileType(WriteFileType newFileType){ giuliomoro@157: fileType = newFileType; giuliomoro@159: if(fileType == kBinary) giuliomoro@159: setLineLength(1); giuliomoro@157: } giuliomoro@153: void WriteFile::setEcho(bool newEcho){ giuliomoro@153: echo=newEcho; giuliomoro@153: } giuliomoro@157: void WriteFile::setEchoInterval(int newEchoPeriod){ giuliomoro@157: echoPeriod = newEchoPeriod; giuliomoro@157: if(echoPeriod != 0) giuliomoro@157: echo = true; giuliomoro@157: else giuliomoro@157: echo = false; giuliomoro@157: } giuliomoro@153: void WriteFile::print(const char* string){ giuliomoro@153: if(echo == true){ giuliomoro@157: echoedLines++; giuliomoro@157: if (echoedLines >= echoPeriod){ giuliomoro@157: echoedLines = 0; giuliomoro@157: printf("%s", string); giuliomoro@157: } giuliomoro@153: } giuliomoro@157: if(file != NULL && fileType != kBinary){ giuliomoro@153: fprintf(file, "%s", string); giuliomoro@153: } giuliomoro@153: } giuliomoro@153: giuliomoro@153: void WriteFile::writeLine(){ giuliomoro@157: if(echo == true || fileType != kBinary){ giuliomoro@157: int stringBufferPointer = 0; giuliomoro@157: for(unsigned int n = 0; n < formatTokens.size(); n++){ giuliomoro@157: int numOfCharsWritten = snprintf( &stringBuffer[stringBufferPointer], stringBufferLength - stringBufferPointer, giuliomoro@157: formatTokens[n], buffer[textReadPointer]); giuliomoro@157: stringBufferPointer += numOfCharsWritten; giuliomoro@157: textReadPointer++; giuliomoro@159: if(textReadPointer >= bufferLength){ giuliomoro@157: textReadPointer -= bufferLength; giuliomoro@157: } giuliomoro@153: } giuliomoro@157: print(stringBuffer); giuliomoro@153: } giuliomoro@153: } giuliomoro@153: giuliomoro@153: void WriteFile::setLineLength(int newLineLength){ giuliomoro@153: lineLength=newLineLength; giuliomoro@153: free(buffer); giuliomoro@159: bufferLength = lineLength * (int)1e7; // circular buffer of length 1e7 lineLenghts giuliomoro@153: buffer = (float*)malloc(sizeof(float) * bufferLength); giuliomoro@153: } giuliomoro@153: giuliomoro@153: void WriteFile::log(float value){ giuliomoro@157: if(fileType != kBinary && (format == NULL || buffer == NULL)) giuliomoro@153: return; giuliomoro@153: buffer[writePointer] = value; giuliomoro@153: writePointer++; giuliomoro@153: if(writePointer == bufferLength){ giuliomoro@153: writePointer = 0; giuliomoro@153: } giuliomoro@157: if((fileType == kText && writePointer == textReadPointer - 1) || giuliomoro@157: (fileType == kBinary && writePointer == binaryReadPointer - 1)){ giuliomoro@157: fprintf(stderr, "%d %d WriteFile: pointers crossed, you should probably slow down your writing to disk\n", writePointer, binaryReadPointer); giuliomoro@153: } giuliomoro@153: if(threadRunning == false){ giuliomoro@153: startThread(); giuliomoro@153: } giuliomoro@153: } giuliomoro@153: giuliomoro@153: void WriteFile::log(float* array, int length){ giuliomoro@153: for(int n = 0; n < length; n++){ giuliomoro@153: log(array[n]); giuliomoro@153: } giuliomoro@153: } giuliomoro@153: giuliomoro@153: WriteFile::~WriteFile() { giuliomoro@153: free(format); giuliomoro@153: free(buffer); giuliomoro@153: free(header); giuliomoro@153: free(footer); giuliomoro@153: free(stringBuffer); giuliomoro@153: } giuliomoro@153: giuliomoro@153: void WriteFile::setFormat(const char* newFormat){ giuliomoro@153: allocateAndCopyString(newFormat, &format); giuliomoro@153: for(unsigned int n = 0; n < formatTokens.size(); n++){ giuliomoro@153: free(formatTokens[n]); giuliomoro@153: } giuliomoro@153: formatTokens.clear(); giuliomoro@153: int tokenStart = 0; giuliomoro@153: bool firstToken = true; giuliomoro@153: for(unsigned int n = 0; n < strlen(format)+1; n++){ giuliomoro@153: if(format[n] == '%' && format[n + 1] == '%'){ giuliomoro@153: n++; giuliomoro@153: } else if (format[n] == '%' || format[n] == 0){ giuliomoro@153: if(firstToken == true){ giuliomoro@153: firstToken = false; giuliomoro@153: continue; giuliomoro@153: } giuliomoro@153: char* string; giuliomoro@153: unsigned int tokenLength = n - tokenStart; giuliomoro@153: if(tokenLength == 0) giuliomoro@153: continue; giuliomoro@153: string = (char*)malloc((1+tokenLength)*sizeof(char)); giuliomoro@153: for(unsigned int i = 0; i < tokenLength; i++){ giuliomoro@153: string[i] = format[tokenStart + i]; giuliomoro@153: } giuliomoro@153: string[tokenLength] = 0; giuliomoro@153: formatTokens.push_back(string); giuliomoro@153: tokenStart = n; giuliomoro@153: } giuliomoro@153: } giuliomoro@153: setLineLength(formatTokens.size()); giuliomoro@153: } giuliomoro@153: giuliomoro@153: int WriteFile::getNumInstances(){ giuliomoro@153: return objAddrs.size(); giuliomoro@153: } giuliomoro@153: giuliomoro@153: void WriteFile::startThread(){ giuliomoro@301: Bela_scheduleAuxiliaryTask(writeAllFilesTask); giuliomoro@153: } giuliomoro@153: giuliomoro@153: void WriteFile::stopThread(){ giuliomoro@153: threadIsExiting=true; giuliomoro@153: } giuliomoro@153: giuliomoro@153: bool WriteFile::threadShouldExit(){ giuliomoro@153: return(gShouldStop || threadIsExiting); giuliomoro@153: } giuliomoro@153: giuliomoro@153: bool WriteFile::isThreadRunning(){ giuliomoro@153: return threadRunning; giuliomoro@153: } giuliomoro@153: giuliomoro@153: float WriteFile::getBufferStatus(){ giuliomoro@153: return 1-getOffset()/(float)bufferLength; giuliomoro@153: } giuliomoro@153: giuliomoro@157: int WriteFile::getOffsetFromPointer(int aReadPointer){ giuliomoro@157: int offset = writePointer - aReadPointer; giuliomoro@157: if( offset < 0) giuliomoro@157: offset += bufferLength; giuliomoro@157: return offset; giuliomoro@157: } giuliomoro@153: int WriteFile::getOffset(){ giuliomoro@157: if(fileType == kBinary){ giuliomoro@157: return getOffsetFromPointer(binaryReadPointer); giuliomoro@157: } giuliomoro@157: else{ giuliomoro@157: return getOffsetFromPointer(textReadPointer); giuliomoro@157: } giuliomoro@153: } giuliomoro@153: giuliomoro@159: void WriteFile::writeOutput(bool flush){ giuliomoro@158: while((echo == true || fileType == kText) && getOffsetFromPointer(textReadPointer) >= lineLength){ //if there is less than one line worth of data to write, skip over. giuliomoro@157: // So we make sure we only write full lines giuliomoro@153: writeLine(); giuliomoro@153: } giuliomoro@157: if(fileType == kBinary){ giuliomoro@159: int numBinaryElementsToWriteAtOnce = 3*(int)1e5; giuliomoro@157: while(getOffsetFromPointer(binaryReadPointer) > numBinaryElementsToWriteAtOnce){ giuliomoro@157: int elementsToEndOfBuffer = bufferLength - binaryReadPointer; giuliomoro@157: int numberElementsToWrite = numBinaryElementsToWriteAtOnce < elementsToEndOfBuffer ? giuliomoro@157: numBinaryElementsToWriteAtOnce : elementsToEndOfBuffer; giuliomoro@157: numberElementsToWrite = fwrite(&(buffer[binaryReadPointer]), sizeof(float), numberElementsToWrite, file); giuliomoro@157: binaryReadPointer += numberElementsToWrite; giuliomoro@157: if(binaryReadPointer >= bufferLength){ giuliomoro@157: binaryReadPointer = 0; giuliomoro@157: } giuliomoro@157: } giuliomoro@159: if(flush == true){ // flush all the buffer to the file giuliomoro@157: while(getOffsetFromPointer(binaryReadPointer) != 0){ giuliomoro@157: binaryReadPointer += fwrite(&(buffer[binaryReadPointer]), sizeof(float), 1, file); giuliomoro@157: if(binaryReadPointer >= bufferLength){ giuliomoro@157: binaryReadPointer = 0; giuliomoro@157: } giuliomoro@157: } giuliomoro@157: } giuliomoro@157: } giuliomoro@153: } giuliomoro@153: giuliomoro@159: void WriteFile::writeAllOutputs(bool flush){ giuliomoro@153: for(unsigned int n = 0; n < objAddrs.size(); n++){ giuliomoro@159: objAddrs[n] -> writeOutput(flush); giuliomoro@153: } giuliomoro@153: } giuliomoro@153: giuliomoro@153: void WriteFile::writeAllHeaders(){ giuliomoro@153: for(unsigned int n = 0; n < objAddrs.size(); n++){ giuliomoro@153: objAddrs[n] -> writeHeader(); giuliomoro@153: } giuliomoro@153: } giuliomoro@153: giuliomoro@153: void WriteFile::writeAllFooters(){ giuliomoro@153: for(unsigned int n = 0; n < objAddrs.size(); n++){ giuliomoro@153: objAddrs[n] -> writeFooter(); giuliomoro@153: } giuliomoro@153: } giuliomoro@153: giuliomoro@153: void WriteFile::writeHeader(){ giuliomoro@153: print(header); giuliomoro@153: } giuliomoro@153: giuliomoro@153: void WriteFile::writeFooter(){ giuliomoro@153: print(footer); giuliomoro@153: fflush(file); giuliomoro@153: fclose(file); giuliomoro@153: } giuliomoro@153: giuliomoro@153: void WriteFile::setHeader(const char* newHeader){ giuliomoro@153: allocateAndCopyString(newHeader, &header); giuliomoro@153: sanitizeString(header); giuliomoro@153: } giuliomoro@153: giuliomoro@153: void WriteFile::setFooter(const char* newFooter){ giuliomoro@153: allocateAndCopyString(newFooter, &footer); giuliomoro@153: } giuliomoro@153: giuliomoro@153: void WriteFile::sanitizeString(char* string){ giuliomoro@153: for(int unsigned n = 0; n < strlen(string); n++){ //purge %'s from the string giuliomoro@153: if(string[n] == '%'){ giuliomoro@153: string[n] = ' '; giuliomoro@153: } giuliomoro@153: } giuliomoro@153: } giuliomoro@153: giuliomoro@153: void WriteFile::run(){ giuliomoro@153: threadRunning = true; giuliomoro@153: writeAllHeaders(); giuliomoro@153: while(threadShouldExit()==false){ giuliomoro@159: writeAllOutputs(false); giuliomoro@153: usleep(sleepTimeMs*1000); giuliomoro@153: } giuliomoro@159: writeAllOutputs(true); giuliomoro@153: writeAllFooters(); // when ctrl-c is pressed, the last line is closed and the file is closed giuliomoro@153: threadRunning = false; giuliomoro@153: } giuliomoro@153: giuliomoro@153: void WriteFile::allocateAndCopyString(const char* source, char** destination){ giuliomoro@153: free(*destination); giuliomoro@153: *destination = (char*)malloc(sizeof(char) * (strlen(source) + 1)); giuliomoro@153: strcpy(*destination, source); giuliomoro@153: }