Mercurial > hg > beaglert
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) +{ + +}