view 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 source
/*
 * 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);
}