giuliomoro@153
|
1 /*
|
giuliomoro@153
|
2 * WriteFile.cpp
|
giuliomoro@153
|
3 *
|
giuliomoro@153
|
4 * Created on: 5 Oct 2015
|
giuliomoro@153
|
5 * Author: giulio
|
giuliomoro@153
|
6 */
|
giuliomoro@153
|
7
|
giuliomoro@153
|
8 #include "WriteFile.h"
|
giuliomoro@153
|
9 //initialise static members
|
giuliomoro@153
|
10 bool WriteFile::staticConstructed=false;
|
giuliomoro@153
|
11 AuxiliaryTask WriteFile::writeAllFilesTask=NULL;
|
giuliomoro@153
|
12 std::vector<WriteFile *> WriteFile::objAddrs(0);
|
giuliomoro@153
|
13 bool WriteFile::threadRunning;
|
giuliomoro@153
|
14 bool WriteFile::threadIsExiting;
|
giuliomoro@153
|
15 int WriteFile::sleepTimeMs;
|
giuliomoro@153
|
16
|
giuliomoro@153
|
17 void WriteFile::staticConstructor(){
|
giuliomoro@153
|
18 if(staticConstructed==true)
|
giuliomoro@153
|
19 return;
|
giuliomoro@153
|
20 staticConstructed=true;
|
giuliomoro@153
|
21 threadIsExiting=false;
|
giuliomoro@153
|
22 threadRunning=false;
|
giuliomoro@301
|
23 writeAllFilesTask = Bela_createAuxiliaryTask(WriteFile::run, 60, "writeAllFilesTask");
|
giuliomoro@153
|
24 }
|
giuliomoro@153
|
25
|
giuliomoro@153
|
26 WriteFile::WriteFile(){
|
giuliomoro@153
|
27 buffer = NULL;
|
giuliomoro@153
|
28 format = NULL;
|
giuliomoro@153
|
29 header = NULL;
|
giuliomoro@153
|
30 footer = NULL;
|
giuliomoro@153
|
31 stringBuffer = NULL;
|
giuliomoro@153
|
32 };
|
giuliomoro@153
|
33
|
giuliomoro@153
|
34 void WriteFile::init(const char* filename){ //if you do not call this before using the object, results are undefined
|
giuliomoro@153
|
35 file = fopen(filename, "w");
|
giuliomoro@153
|
36 variableOpen = false;
|
giuliomoro@153
|
37 lineLength = 0;
|
giuliomoro@159
|
38 setEcho(false);
|
giuliomoro@153
|
39 bufferLength = 0;
|
giuliomoro@157
|
40 textReadPointer = 0;
|
giuliomoro@157
|
41 binaryReadPointer = 0;
|
giuliomoro@153
|
42 writePointer = 0;
|
giuliomoro@153
|
43 sleepTimeMs = 1;
|
giuliomoro@153
|
44 stringBufferLength = 1000;
|
giuliomoro@153
|
45 stringBuffer = (char*)malloc(sizeof(char) * (stringBufferLength));
|
giuliomoro@153
|
46 setHeader("variable=[\n");
|
giuliomoro@153
|
47 setFooter("];\n");
|
giuliomoro@301
|
48 staticConstructor(); //TODO: this line should be in the constructor, but cannot be because of a bug in Bela
|
giuliomoro@153
|
49 objAddrs.push_back(this);
|
giuliomoro@157
|
50 echoedLines = 0;
|
giuliomoro@157
|
51 echoPeriod = 1;
|
giuliomoro@153
|
52 }
|
giuliomoro@153
|
53
|
giuliomoro@157
|
54 void WriteFile::setFileType(WriteFileType newFileType){
|
giuliomoro@157
|
55 fileType = newFileType;
|
giuliomoro@159
|
56 if(fileType == kBinary)
|
giuliomoro@159
|
57 setLineLength(1);
|
giuliomoro@157
|
58 }
|
giuliomoro@153
|
59 void WriteFile::setEcho(bool newEcho){
|
giuliomoro@153
|
60 echo=newEcho;
|
giuliomoro@153
|
61 }
|
giuliomoro@157
|
62 void WriteFile::setEchoInterval(int newEchoPeriod){
|
giuliomoro@157
|
63 echoPeriod = newEchoPeriod;
|
giuliomoro@157
|
64 if(echoPeriod != 0)
|
giuliomoro@157
|
65 echo = true;
|
giuliomoro@157
|
66 else
|
giuliomoro@157
|
67 echo = false;
|
giuliomoro@157
|
68 }
|
giuliomoro@153
|
69 void WriteFile::print(const char* string){
|
giuliomoro@153
|
70 if(echo == true){
|
giuliomoro@157
|
71 echoedLines++;
|
giuliomoro@157
|
72 if (echoedLines >= echoPeriod){
|
giuliomoro@157
|
73 echoedLines = 0;
|
giuliomoro@157
|
74 printf("%s", string);
|
giuliomoro@157
|
75 }
|
giuliomoro@153
|
76 }
|
giuliomoro@157
|
77 if(file != NULL && fileType != kBinary){
|
giuliomoro@153
|
78 fprintf(file, "%s", string);
|
giuliomoro@153
|
79 }
|
giuliomoro@153
|
80 }
|
giuliomoro@153
|
81
|
giuliomoro@153
|
82 void WriteFile::writeLine(){
|
giuliomoro@157
|
83 if(echo == true || fileType != kBinary){
|
giuliomoro@157
|
84 int stringBufferPointer = 0;
|
giuliomoro@157
|
85 for(unsigned int n = 0; n < formatTokens.size(); n++){
|
giuliomoro@157
|
86 int numOfCharsWritten = snprintf( &stringBuffer[stringBufferPointer], stringBufferLength - stringBufferPointer,
|
giuliomoro@157
|
87 formatTokens[n], buffer[textReadPointer]);
|
giuliomoro@157
|
88 stringBufferPointer += numOfCharsWritten;
|
giuliomoro@157
|
89 textReadPointer++;
|
giuliomoro@159
|
90 if(textReadPointer >= bufferLength){
|
giuliomoro@157
|
91 textReadPointer -= bufferLength;
|
giuliomoro@157
|
92 }
|
giuliomoro@153
|
93 }
|
giuliomoro@157
|
94 print(stringBuffer);
|
giuliomoro@153
|
95 }
|
giuliomoro@153
|
96 }
|
giuliomoro@153
|
97
|
giuliomoro@153
|
98 void WriteFile::setLineLength(int newLineLength){
|
giuliomoro@153
|
99 lineLength=newLineLength;
|
giuliomoro@153
|
100 free(buffer);
|
giuliomoro@159
|
101 bufferLength = lineLength * (int)1e7; // circular buffer of length 1e7 lineLenghts
|
giuliomoro@153
|
102 buffer = (float*)malloc(sizeof(float) * bufferLength);
|
giuliomoro@153
|
103 }
|
giuliomoro@153
|
104
|
giuliomoro@153
|
105 void WriteFile::log(float value){
|
giuliomoro@157
|
106 if(fileType != kBinary && (format == NULL || buffer == NULL))
|
giuliomoro@153
|
107 return;
|
giuliomoro@153
|
108 buffer[writePointer] = value;
|
giuliomoro@153
|
109 writePointer++;
|
giuliomoro@153
|
110 if(writePointer == bufferLength){
|
giuliomoro@153
|
111 writePointer = 0;
|
giuliomoro@153
|
112 }
|
giuliomoro@157
|
113 if((fileType == kText && writePointer == textReadPointer - 1) ||
|
giuliomoro@157
|
114 (fileType == kBinary && writePointer == binaryReadPointer - 1)){
|
giuliomoro@157
|
115 fprintf(stderr, "%d %d WriteFile: pointers crossed, you should probably slow down your writing to disk\n", writePointer, binaryReadPointer);
|
giuliomoro@153
|
116 }
|
giuliomoro@153
|
117 if(threadRunning == false){
|
giuliomoro@153
|
118 startThread();
|
giuliomoro@153
|
119 }
|
giuliomoro@153
|
120 }
|
giuliomoro@153
|
121
|
giuliomoro@395
|
122 void WriteFile::log(const float* array, int length){
|
giuliomoro@153
|
123 for(int n = 0; n < length; n++){
|
giuliomoro@153
|
124 log(array[n]);
|
giuliomoro@153
|
125 }
|
giuliomoro@153
|
126 }
|
giuliomoro@153
|
127
|
giuliomoro@153
|
128 WriteFile::~WriteFile() {
|
giuliomoro@153
|
129 free(format);
|
giuliomoro@153
|
130 free(buffer);
|
giuliomoro@153
|
131 free(header);
|
giuliomoro@153
|
132 free(footer);
|
giuliomoro@153
|
133 free(stringBuffer);
|
giuliomoro@153
|
134 }
|
giuliomoro@153
|
135
|
giuliomoro@153
|
136 void WriteFile::setFormat(const char* newFormat){
|
giuliomoro@153
|
137 allocateAndCopyString(newFormat, &format);
|
giuliomoro@153
|
138 for(unsigned int n = 0; n < formatTokens.size(); n++){
|
giuliomoro@153
|
139 free(formatTokens[n]);
|
giuliomoro@153
|
140 }
|
giuliomoro@153
|
141 formatTokens.clear();
|
giuliomoro@153
|
142 int tokenStart = 0;
|
giuliomoro@153
|
143 bool firstToken = true;
|
giuliomoro@153
|
144 for(unsigned int n = 0; n < strlen(format)+1; n++){
|
giuliomoro@153
|
145 if(format[n] == '%' && format[n + 1] == '%'){
|
giuliomoro@153
|
146 n++;
|
giuliomoro@153
|
147 } else if (format[n] == '%' || format[n] == 0){
|
giuliomoro@153
|
148 if(firstToken == true){
|
giuliomoro@153
|
149 firstToken = false;
|
giuliomoro@153
|
150 continue;
|
giuliomoro@153
|
151 }
|
giuliomoro@153
|
152 char* string;
|
giuliomoro@153
|
153 unsigned int tokenLength = n - tokenStart;
|
giuliomoro@153
|
154 if(tokenLength == 0)
|
giuliomoro@153
|
155 continue;
|
giuliomoro@153
|
156 string = (char*)malloc((1+tokenLength)*sizeof(char));
|
giuliomoro@153
|
157 for(unsigned int i = 0; i < tokenLength; i++){
|
giuliomoro@153
|
158 string[i] = format[tokenStart + i];
|
giuliomoro@153
|
159 }
|
giuliomoro@153
|
160 string[tokenLength] = 0;
|
giuliomoro@153
|
161 formatTokens.push_back(string);
|
giuliomoro@153
|
162 tokenStart = n;
|
giuliomoro@153
|
163 }
|
giuliomoro@153
|
164 }
|
giuliomoro@153
|
165 setLineLength(formatTokens.size());
|
giuliomoro@153
|
166 }
|
giuliomoro@153
|
167
|
giuliomoro@153
|
168 int WriteFile::getNumInstances(){
|
giuliomoro@153
|
169 return objAddrs.size();
|
giuliomoro@153
|
170 }
|
giuliomoro@153
|
171
|
giuliomoro@153
|
172 void WriteFile::startThread(){
|
giuliomoro@301
|
173 Bela_scheduleAuxiliaryTask(writeAllFilesTask);
|
giuliomoro@153
|
174 }
|
giuliomoro@153
|
175
|
giuliomoro@153
|
176 void WriteFile::stopThread(){
|
giuliomoro@153
|
177 threadIsExiting=true;
|
giuliomoro@153
|
178 }
|
giuliomoro@153
|
179
|
giuliomoro@153
|
180 bool WriteFile::threadShouldExit(){
|
giuliomoro@153
|
181 return(gShouldStop || threadIsExiting);
|
giuliomoro@153
|
182 }
|
giuliomoro@153
|
183
|
giuliomoro@153
|
184 bool WriteFile::isThreadRunning(){
|
giuliomoro@153
|
185 return threadRunning;
|
giuliomoro@153
|
186 }
|
giuliomoro@153
|
187
|
giuliomoro@153
|
188 float WriteFile::getBufferStatus(){
|
giuliomoro@153
|
189 return 1-getOffset()/(float)bufferLength;
|
giuliomoro@153
|
190 }
|
giuliomoro@153
|
191
|
giuliomoro@157
|
192 int WriteFile::getOffsetFromPointer(int aReadPointer){
|
giuliomoro@157
|
193 int offset = writePointer - aReadPointer;
|
giuliomoro@157
|
194 if( offset < 0)
|
giuliomoro@157
|
195 offset += bufferLength;
|
giuliomoro@157
|
196 return offset;
|
giuliomoro@157
|
197 }
|
giuliomoro@153
|
198 int WriteFile::getOffset(){
|
giuliomoro@157
|
199 if(fileType == kBinary){
|
giuliomoro@157
|
200 return getOffsetFromPointer(binaryReadPointer);
|
giuliomoro@157
|
201 }
|
giuliomoro@157
|
202 else{
|
giuliomoro@157
|
203 return getOffsetFromPointer(textReadPointer);
|
giuliomoro@157
|
204 }
|
giuliomoro@153
|
205 }
|
giuliomoro@153
|
206
|
giuliomoro@159
|
207 void WriteFile::writeOutput(bool flush){
|
giuliomoro@158
|
208 while((echo == true || fileType == kText) && getOffsetFromPointer(textReadPointer) >= lineLength){ //if there is less than one line worth of data to write, skip over.
|
giuliomoro@157
|
209 // So we make sure we only write full lines
|
giuliomoro@153
|
210 writeLine();
|
giuliomoro@153
|
211 }
|
giuliomoro@157
|
212 if(fileType == kBinary){
|
giuliomoro@159
|
213 int numBinaryElementsToWriteAtOnce = 3*(int)1e5;
|
giuliomoro@157
|
214 while(getOffsetFromPointer(binaryReadPointer) > numBinaryElementsToWriteAtOnce){
|
giuliomoro@157
|
215 int elementsToEndOfBuffer = bufferLength - binaryReadPointer;
|
giuliomoro@157
|
216 int numberElementsToWrite = numBinaryElementsToWriteAtOnce < elementsToEndOfBuffer ?
|
giuliomoro@157
|
217 numBinaryElementsToWriteAtOnce : elementsToEndOfBuffer;
|
giuliomoro@157
|
218 numberElementsToWrite = fwrite(&(buffer[binaryReadPointer]), sizeof(float), numberElementsToWrite, file);
|
giuliomoro@157
|
219 binaryReadPointer += numberElementsToWrite;
|
giuliomoro@157
|
220 if(binaryReadPointer >= bufferLength){
|
giuliomoro@157
|
221 binaryReadPointer = 0;
|
giuliomoro@157
|
222 }
|
giuliomoro@157
|
223 }
|
giuliomoro@159
|
224 if(flush == true){ // flush all the buffer to the file
|
giuliomoro@157
|
225 while(getOffsetFromPointer(binaryReadPointer) != 0){
|
giuliomoro@157
|
226 binaryReadPointer += fwrite(&(buffer[binaryReadPointer]), sizeof(float), 1, file);
|
giuliomoro@157
|
227 if(binaryReadPointer >= bufferLength){
|
giuliomoro@157
|
228 binaryReadPointer = 0;
|
giuliomoro@157
|
229 }
|
giuliomoro@157
|
230 }
|
giuliomoro@157
|
231 }
|
giuliomoro@157
|
232 }
|
giuliomoro@153
|
233 }
|
giuliomoro@153
|
234
|
giuliomoro@159
|
235 void WriteFile::writeAllOutputs(bool flush){
|
giuliomoro@153
|
236 for(unsigned int n = 0; n < objAddrs.size(); n++){
|
giuliomoro@159
|
237 objAddrs[n] -> writeOutput(flush);
|
giuliomoro@153
|
238 }
|
giuliomoro@153
|
239 }
|
giuliomoro@153
|
240
|
giuliomoro@153
|
241 void WriteFile::writeAllHeaders(){
|
giuliomoro@153
|
242 for(unsigned int n = 0; n < objAddrs.size(); n++){
|
giuliomoro@153
|
243 objAddrs[n] -> writeHeader();
|
giuliomoro@153
|
244 }
|
giuliomoro@153
|
245 }
|
giuliomoro@153
|
246
|
giuliomoro@153
|
247 void WriteFile::writeAllFooters(){
|
giuliomoro@153
|
248 for(unsigned int n = 0; n < objAddrs.size(); n++){
|
giuliomoro@153
|
249 objAddrs[n] -> writeFooter();
|
giuliomoro@153
|
250 }
|
giuliomoro@153
|
251 }
|
giuliomoro@153
|
252
|
giuliomoro@153
|
253 void WriteFile::writeHeader(){
|
giuliomoro@153
|
254 print(header);
|
giuliomoro@153
|
255 }
|
giuliomoro@153
|
256
|
giuliomoro@153
|
257 void WriteFile::writeFooter(){
|
giuliomoro@153
|
258 print(footer);
|
giuliomoro@153
|
259 fflush(file);
|
giuliomoro@153
|
260 fclose(file);
|
giuliomoro@153
|
261 }
|
giuliomoro@153
|
262
|
giuliomoro@153
|
263 void WriteFile::setHeader(const char* newHeader){
|
giuliomoro@153
|
264 allocateAndCopyString(newHeader, &header);
|
giuliomoro@153
|
265 sanitizeString(header);
|
giuliomoro@153
|
266 }
|
giuliomoro@153
|
267
|
giuliomoro@153
|
268 void WriteFile::setFooter(const char* newFooter){
|
giuliomoro@153
|
269 allocateAndCopyString(newFooter, &footer);
|
giuliomoro@153
|
270 }
|
giuliomoro@153
|
271
|
giuliomoro@153
|
272 void WriteFile::sanitizeString(char* string){
|
giuliomoro@153
|
273 for(int unsigned n = 0; n < strlen(string); n++){ //purge %'s from the string
|
giuliomoro@153
|
274 if(string[n] == '%'){
|
giuliomoro@153
|
275 string[n] = ' ';
|
giuliomoro@153
|
276 }
|
giuliomoro@153
|
277 }
|
giuliomoro@153
|
278 }
|
giuliomoro@153
|
279
|
giuliomoro@153
|
280 void WriteFile::run(){
|
giuliomoro@153
|
281 threadRunning = true;
|
giuliomoro@153
|
282 writeAllHeaders();
|
giuliomoro@153
|
283 while(threadShouldExit()==false){
|
giuliomoro@159
|
284 writeAllOutputs(false);
|
giuliomoro@153
|
285 usleep(sleepTimeMs*1000);
|
giuliomoro@153
|
286 }
|
giuliomoro@159
|
287 writeAllOutputs(true);
|
giuliomoro@153
|
288 writeAllFooters(); // when ctrl-c is pressed, the last line is closed and the file is closed
|
giuliomoro@153
|
289 threadRunning = false;
|
giuliomoro@153
|
290 }
|
giuliomoro@153
|
291
|
giuliomoro@153
|
292 void WriteFile::allocateAndCopyString(const char* source, char** destination){
|
giuliomoro@153
|
293 free(*destination);
|
giuliomoro@153
|
294 *destination = (char*)malloc(sizeof(char) * (strlen(source) + 1));
|
giuliomoro@153
|
295 strcpy(*destination, source);
|
giuliomoro@153
|
296 }
|