changeset 157:f36313cbb55d

Added capability to WriteFile to save binary files, added example project
author Giulio Moro <giuliomoro@yahoo.it>
date Tue, 13 Oct 2015 02:01:05 +0100
parents 89f28a867a09
children 45fc760622c9
files .cproject core/WriteFile.cpp include/WriteFile.h projects/loggingSensors/main.cpp projects/loggingSensors/render.cpp
diffstat 5 files changed, 247 insertions(+), 29 deletions(-) [+]
line wrap: on
line diff
--- a/.cproject	Wed Oct 07 23:38:52 2015 +0100
+++ b/.cproject	Tue Oct 13 02:01:05 2015 +0100
@@ -93,7 +93,7 @@
 					<sourceEntries>
 						<entry excluding="default_main.cpp|audio_routines_old.S" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="core"/>
 						<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="include"/>
-						<entry flags="VALUE_WORKSPACE_PATH" kind="sourcePath" name="projects/basic_writeFile"/>
+						<entry flags="VALUE_WORKSPACE_PATH" kind="sourcePath" name="projects/loggingSensors"/>
 						<entry flags="VALUE_WORKSPACE_PATH" kind="sourcePath" name="source"/>
 					</sourceEntries>
 				</configuration>
@@ -184,7 +184,7 @@
 					<sourceEntries>
 						<entry excluding="default_main.cpp|audio_routines_old.S" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="core"/>
 						<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="include"/>
-						<entry flags="VALUE_WORKSPACE_PATH" kind="sourcePath" name="projects/scope"/>
+						<entry flags="VALUE_WORKSPACE_PATH" kind="sourcePath" name="projects/loggingSensors"/>
 						<entry flags="VALUE_WORKSPACE_PATH" kind="sourcePath" name="source"/>
 					</sourceEntries>
 				</configuration>
--- a/core/WriteFile.cpp	Wed Oct 07 23:38:52 2015 +0100
+++ b/core/WriteFile.cpp	Tue Oct 13 02:01:05 2015 +0100
@@ -37,42 +37,60 @@
 	lineLength = 0;
 	echo = false;
 	bufferLength = 0;
-	readPointer = 0;
+	textReadPointer = 0;
+	binaryReadPointer = 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
+	staticConstructor(); //TODO: this line should be in the constructor, but cannot be because of a bug in BeagleRT
 	objAddrs.push_back(this);
+	echoedLines = 0;
+	echoPeriod = 1;
 }
 
+void WriteFile::setFileType(WriteFileType newFileType){
+	fileType = newFileType;
+}
 void WriteFile::setEcho(bool newEcho){
 	echo=newEcho;
 }
-
+void WriteFile::setEchoInterval(int newEchoPeriod){
+	echoPeriod = newEchoPeriod;
+	if(echoPeriod != 0)
+		echo = true;
+	else
+		echo = false;
+}
 void WriteFile::print(const char* string){
 	if(echo == true){
-		printf("%s", string);
+		echoedLines++;
+		if (echoedLines >= echoPeriod){
+			echoedLines = 0;
+			printf("%s", string);
+		}
 	}
-	if(file != NULL){
+	if(file != NULL && fileType != kBinary){
 		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;
+	if(echo == true || fileType != kBinary){
+		int stringBufferPointer = 0;
+		for(unsigned int n = 0; n < formatTokens.size(); n++){
+			int numOfCharsWritten = snprintf( &stringBuffer[stringBufferPointer], stringBufferLength - stringBufferPointer,
+								formatTokens[n], buffer[textReadPointer]);
+			stringBufferPointer += numOfCharsWritten;
+			textReadPointer++;
+			if (textReadPointer >= bufferLength){
+				textReadPointer -= bufferLength;
+			}
 		}
+		print(stringBuffer);
 	}
-	print(stringBuffer);
 }
 
 void WriteFile::setLineLength(int newLineLength){
@@ -83,15 +101,16 @@
 }
 
 void WriteFile::log(float value){
-	if(format == NULL || buffer == NULL)
+	if(fileType != kBinary && (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((fileType == kText && writePointer == textReadPointer - 1) ||
+			(fileType == kBinary && writePointer == binaryReadPointer - 1)){
+		fprintf(stderr, "%d %d WriteFile: pointers crossed, you should probably slow down your writing to disk\n", writePointer, binaryReadPointer);
 	}
 	if(threadRunning == false){
 		startThread();
@@ -168,23 +187,52 @@
 	return 1-getOffset()/(float)bufferLength;
 }
 
+int WriteFile::getOffsetFromPointer(int aReadPointer){
+	int offset = writePointer - aReadPointer;
+		if( offset < 0)
+			offset += bufferLength;
+		return offset;
+}
 int WriteFile::getOffset(){
-	int offset = writePointer - readPointer;
-	if( offset < 0)
-		offset += bufferLength;
-	return offset;
+	if(fileType == kBinary){
+		return getOffsetFromPointer(binaryReadPointer);
+	}
+	else{
+		return getOffsetFromPointer(textReadPointer);
+	}
 }
 
-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
+void WriteFile::writeOutput(bool writeAll){
+	while( getOffsetFromPointer(textReadPointer) >= lineLength){ //if there is less than one line worth of data to write, skip over.
+							 	 // So we make sure we only write full lines
 		writeLine();
 	}
+	if(fileType == kBinary){
+		int numBinaryElementsToWriteAtOnce = 100;
+		while(getOffsetFromPointer(binaryReadPointer) > numBinaryElementsToWriteAtOnce){
+			int elementsToEndOfBuffer = bufferLength - binaryReadPointer;
+			int numberElementsToWrite = numBinaryElementsToWriteAtOnce < elementsToEndOfBuffer ?
+					numBinaryElementsToWriteAtOnce : elementsToEndOfBuffer;
+			numberElementsToWrite = fwrite(&(buffer[binaryReadPointer]), sizeof(float), numberElementsToWrite, file);
+			binaryReadPointer += numberElementsToWrite;
+			if(binaryReadPointer >= bufferLength){
+				binaryReadPointer = 0;
+			}
+		}
+		if(writeAll == true){ // flush all the buffer to the file
+			while(getOffsetFromPointer(binaryReadPointer) != 0){
+				binaryReadPointer += fwrite(&(buffer[binaryReadPointer]), sizeof(float), 1, file);
+				if(binaryReadPointer >= bufferLength){
+					binaryReadPointer = 0;
+				}
+			}
+		}
+	}
 }
 
 void WriteFile::writeAllOutputs(){
 	for(unsigned int n = 0; n < objAddrs.size(); n++){
-		objAddrs[n] -> writeOutput();
+		objAddrs[n] -> writeOutput(false);
 	}
 }
 
--- a/include/WriteFile.h	Wed Oct 07 23:38:52 2015 +0100
+++ b/include/WriteFile.h	Tue Oct 13 02:01:05 2015 +0100
@@ -14,21 +14,30 @@
 #include <string.h>
 #include <unistd.h>
 
+typedef enum {
+	kBinary,
+	kText
+} WriteFileType;
+
 class WriteFile {
 private:
 	static AuxiliaryTask writeAllFilesTask;
 	bool echo;
+	int echoedLines;
+	int echoPeriod;
 	char *header;
 	char *footer;
 	char *stringBuffer;
 	int stringBufferLength;
 	int bufferLength;
 	float* buffer;
-	int readPointer;
+	int textReadPointer;
+	int binaryReadPointer;
 	int writePointer;
 	bool variableOpen;
 	char* format;
 	int lineLength;
+	WriteFileType fileType;
 	static int sleepTimeMs;
 	FILE *file;
 	void writeLine();
@@ -36,7 +45,9 @@
 	void writeFooter();
 	void allocateAndCopyString(const char* source, char** destination);
 	void print(const char* string);
+	void printBinary(const char* string);
 	void setLineLength(int newLineLength);
+	int getOffsetFromPointer(int aPointer);
 	std::vector<char *> formatTokens;
 	static void sanitizeString(char* string);
 	static void sanitizeString(char* string, int numberOfArguments);
@@ -48,11 +59,36 @@
     static bool staticConstructed;
 	static void staticConstructor();
 	static std::vector<WriteFile *> objAddrs;
+	void writeOutput(bool writeAll);
 public:
 	WriteFile();
+	/**
+	 * Set the type of file to write, can be either kText or kBinary.
+	 * Binary files can be imported e.g. in Matlab:
+	 *   fid=fopen('out','r');
+	 *   A = fread(fid, 'float');
+	 * */
+	void setFileType(WriteFileType newFileType);
 	void setEcho(bool newEcho);
+	void setEchoInterval(int newPeriod);
+	/**
+	 *  Set the format that you want to use for your output.
+	 *
+	 * Only %f is allowed (with modifiers). When in binary mode,
+	 * the specified format is used only for echoing to console.
+	 */
 	void setFormat(const char* newFormat);
+	/**
+	 * Set one or more lines to be printed at the beginning of the file.
+	 *
+	 * This is ignored in binary mode.
+	 */
 	void setHeader(const char* newHeader);
+	/**
+	 * Set one or more lines to be printed at the end of the file.
+	 *
+	 * This is ignored in binary mode.
+	 */
 	void setFooter(const char* newFooter);
 	void log(float* array, int length);
 	void log(float value);
@@ -71,7 +107,6 @@
 	 * and 1 being buffer empty (writing to disk is fast enough).
 	 */
 	float getBufferStatus();
-	void writeOutput();
 	~WriteFile();
     static int getNumInstances();
     static void writeAllHeaders();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/projects/loggingSensors/main.cpp	Tue Oct 13 02:01:05 2015 +0100
@@ -0,0 +1,97 @@
+/*
+ * main.cpp
+ *
+ *  Created on: Oct 24, 2014
+ *      Author: parallels
+ */
+#include <unistd.h>
+#include <iostream>
+#include <cstdlib>
+#include <libgen.h>
+#include <signal.h>
+#include <getopt.h>
+#include <BeagleRT.h>
+
+using namespace std;
+
+// Handle Ctrl-C by requesting that the audio rendering stop
+void interrupt_handler(int var)
+{
+	gShouldStop = true;
+}
+
+// Print usage information
+void usage(const char * processName)
+{
+	cerr << "Usage: " << processName << " [options]" << endl;
+
+	BeagleRT_usage();
+
+	cerr << "   --frequency [-f] frequency: Set the frequency of the oscillator\n";
+	cerr << "   --help [-h]:                Print this menu\n";
+}
+
+int main(int argc, char *argv[])
+{
+	BeagleRTInitSettings settings;	// Standard audio settings
+	float frequency = 440.0;	// Frequency of oscillator
+
+	struct option customOptions[] =
+	{
+		{"help", 0, NULL, 'h'},
+		{"frequency", 1, NULL, 'f'},
+		{NULL, 0, NULL, 0}
+	};
+
+	// Set default settings
+	BeagleRT_defaultSettings(&settings);
+
+	// Parse command-line arguments
+	while (1) {
+		int c;
+		if ((c = BeagleRT_getopt_long(argc, argv, "hf:", customOptions, &settings)) < 0)
+				break;
+		switch (c) {
+		case 'h':
+				usage(basename(argv[0]));
+				exit(0);
+		case 'f':
+				frequency = atof(optarg);
+				break;
+		case '?':
+		default:
+				usage(basename(argv[0]));
+				exit(1);
+		}
+	}
+
+	// Initialise the PRU audio device
+	if(BeagleRT_initAudio(&settings, &frequency) != 0) {
+		cout << "Error: unable to initialise audio" << endl;
+		return -1;
+	}
+
+	// Start the audio device running
+	if(BeagleRT_startAudio()) {
+		cout << "Error: unable to start real-time audio" << endl;
+		return -1;
+	}
+
+	// Set up interrupt handler to catch Control-C and SIGTERM
+	signal(SIGINT, interrupt_handler);
+	signal(SIGTERM, interrupt_handler);
+
+	// Run until told to stop
+	while(!gShouldStop) {
+		usleep(100000);
+	}
+
+	// Stop the audio device
+	BeagleRT_stopAudio();
+
+	// Clean up any resources allocated for audio
+	BeagleRT_cleanupAudio();
+
+	// All done!
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/projects/loggingSensors/render.cpp	Tue Oct 13 02:01:05 2015 +0100
@@ -0,0 +1,38 @@
+#include <BeagleRT.h> 
+#include <Scope.h>
+#include <cmath>
+#include <WriteFile.h>
+
+WriteFile file1;
+WriteFile file2;
+
+bool setup(BeagleRTContext *context, void *userData)
+{
+	file1.init("out.bin"); //set the file name to write to
+	file1.setEchoInterval(1000);
+	file1.setFileType(kBinary);
+	file1.setFormat("%.4f %.4f\n"); // set the format that you want to use for your output. Please use %f only (with modifiers). When in binary mode, this is used only for echoing to console
+	file2.init("out.m"); //set the file name to write to
+	file2.setHeader("myvar=[\n"); //set one or more lines to be printed at the beginning of the file
+	file2.setFooter("];\n"); //set one or more lines to be printed at the end of the file
+	file2.setFormat("%.4f\n"); // set the format that you want to use for your output. Please use %f only (with modifiers)
+	file2.setFileType(kText);
+	file2.setEchoInterval(10000); // only print to the console 1 line every other 10000
+	return true; 
+}
+
+void render(BeagleRTContext *context, void *userData)
+{
+	for(unsigned int n = 0; n < context->analogFrames; n++) {
+			file1.log(&(context->analogIn[n*context->analogFrames]), 2); // log an array of values
+			file2.log(context->analogIn[n*context->analogFrames]); // log a single value
+	}
+}
+
+// cleanup_render() is called once at the end, after the audio has stopped.
+// Release any resources that were allocated in initialise_render().
+
+void cleanup(BeagleRTContext *context, void *userData)
+{
+    
+}