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