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