rt300@0
|
1 //
|
rt300@0
|
2 // eventLogger.mm
|
rt300@0
|
3 // oscSenderExample
|
rt300@0
|
4 //
|
rt300@0
|
5 // Created by Robert Tubb on 05/11/2012.
|
rt300@0
|
6 //
|
rt300@0
|
7 //
|
rt300@0
|
8
|
rt300@0
|
9 //---------------------------------------------------------------------------
|
rt300@0
|
10 #include "eventLogger.h"
|
rt300@0
|
11
|
rt300@0
|
12 EventLogger eventLogger;
|
rt300@0
|
13
|
rt300@0
|
14 //---------------------------------------------------------------------------
|
rt300@0
|
15 EventLogger::EventLogger(){
|
rt300@0
|
16
|
rt300@0
|
17 consentGiven = true; // unless told otherwise firstAppOpen
|
rt300@0
|
18 loggingEnabled = true;
|
rt300@0
|
19 serverConnectionOK = false;
|
rt300@0
|
20 questionnaireCompleted = false;
|
rt300@0
|
21 questionnaireUploaded = false;
|
rt300@0
|
22 logUploadInProgress = false;
|
rt300@0
|
23
|
rt300@0
|
24 nextUploadQty = UPLOAD_CHUNK_SIZE; // amount of data uploaded is always more than UPLOAD_CHUNK_SIZE events
|
rt300@0
|
25 serverComms = [[ServerComms alloc] init];
|
rt300@0
|
26
|
rt300@0
|
27 }
|
rt300@18
|
28 // for RIFTATHON this replaces startLoadAll
|
rt300@18
|
29 // because we can't look at logs or presets until we know user
|
rt300@18
|
30
|
rt300@18
|
31 void EventLogger::onUsernameEntered(){
|
rt300@18
|
32 sessionStartTime = ofGetSystemTime();
|
rt300@18
|
33 // userName = name; done already by dialog
|
rt300@18
|
34 // check for eventlog with this name
|
rt300@18
|
35
|
rt300@18
|
36
|
rt300@18
|
37 string path = ofxiPhoneGetDocumentsDirectory();
|
rt300@18
|
38 ofDirectory dir(path);
|
rt300@18
|
39 //only show png files
|
rt300@18
|
40 dir.allowExt("json");
|
rt300@18
|
41 //populate the directory object
|
rt300@18
|
42 dir.listDir();
|
rt300@18
|
43
|
rt300@18
|
44 //chek for username's logs
|
rt300@18
|
45 bool userHasLogs = false;
|
rt300@18
|
46 int numExistingLogs = 0;
|
rt300@18
|
47 for(int i = 0; i < dir.numFiles(); i++){
|
rt300@18
|
48 string fname = dir.getName(i);
|
rt300@18
|
49 if( 0 == fname.compare(0, userName.length() + 10, userName + "_eventlog_" )){
|
rt300@18
|
50 numExistingLogs++;
|
rt300@18
|
51 userHasLogs = true;
|
rt300@18
|
52 }
|
rt300@18
|
53
|
rt300@18
|
54 }
|
rt300@18
|
55 // if found, load other details such as device id
|
rt300@18
|
56 loadUserDetailsFromLastLogFile(numExistingLogs);
|
rt300@18
|
57 nextLogFileIndex = numExistingLogs+1;
|
rt300@18
|
58
|
rt300@18
|
59 }
|
rt300@18
|
60
|
rt300@0
|
61 //---------------------------------------------------------------------------
|
rt300@0
|
62 void EventLogger::startLoadAll(){
|
rt300@0
|
63
|
rt300@0
|
64 // TODO pilot doesn't check existing
|
rt300@0
|
65 //loadExistingLogFile(ofxiPhoneGetDocumentsDirectory() + EVENT_LOG_FILENAME);
|
rt300@0
|
66
|
rt300@0
|
67
|
rt300@0
|
68 sessionStartTime = ofGetSystemTime();
|
rt300@0
|
69
|
rt300@0
|
70 // TODO pilot
|
rt300@0
|
71 // testConnection();
|
rt300@0
|
72
|
rt300@0
|
73 // if we have a back log of events upload them
|
rt300@0
|
74 if(theEvents.size() > nextUploadQty && ! logUploadInProgress){
|
rt300@0
|
75 //try to upload
|
rt300@0
|
76
|
rt300@0
|
77 // TODO pilot doesn't upload
|
rt300@0
|
78 //uploadEventLog(true);
|
rt300@0
|
79 }
|
rt300@0
|
80
|
rt300@0
|
81 if(questionnaireCompleted && !questionnaireUploaded){
|
rt300@0
|
82 uploadQuestionnaire();
|
rt300@0
|
83 }
|
rt300@0
|
84
|
rt300@0
|
85 //TODO if questionnaire wasn't reached but still opened then set the timer to something sensible
|
rt300@0
|
86
|
rt300@0
|
87 //timer.setInteractionTime(savedInteractionTime);
|
rt300@0
|
88 //timer.setOrderFromPrevious(interfaceOrder);
|
rt300@0
|
89
|
rt300@0
|
90 // for now sod it, start from scratch
|
rt300@0
|
91 if(!questionnaireCompleted){
|
rt300@0
|
92 cout<<"Questionnaire NOT completed - first APP open called\n";
|
rt300@0
|
93 firstEverAppOpen();
|
rt300@0
|
94 }
|
rt300@0
|
95
|
rt300@0
|
96 }
|
rt300@0
|
97 //---------------------------------------------------------------------------
|
rt300@0
|
98 void EventLogger::testConnection(){
|
rt300@0
|
99 Json::Value root;
|
rt300@0
|
100 root["x"] = "y";
|
rt300@0
|
101 cout << "testConnection\n";
|
rt300@0
|
102 sendToServer("testConnection", root, true);
|
rt300@0
|
103
|
rt300@0
|
104 }
|
rt300@0
|
105 //---------------------------------------------------------------------------
|
rt300@18
|
106
|
rt300@18
|
107 void EventLogger::loadUserDetailsFromLastLogFile(int numExistingLogs){
|
rt300@18
|
108
|
rt300@18
|
109
|
rt300@18
|
110 }
|
rt300@18
|
111 //---------------------------------------------------------------------------
|
rt300@18
|
112
|
rt300@18
|
113
|
rt300@0
|
114 // this reads the persistent log file , checks if we've used the app before and
|
rt300@0
|
115 // if we've answered questionnaire or not
|
rt300@0
|
116
|
rt300@0
|
117 // should just store stuff. the start up state should be handled by testAPp
|
rt300@0
|
118
|
rt300@0
|
119 void EventLogger::loadExistingLogFile(const string &jsonFile){
|
rt300@0
|
120 Json::Value root;
|
rt300@0
|
121 Json::Reader reader;
|
rt300@0
|
122
|
rt300@0
|
123 /////////////
|
rt300@0
|
124 // read file
|
rt300@0
|
125
|
rt300@0
|
126 ifstream theFile(jsonFile.c_str());
|
rt300@0
|
127 stringstream fileText;
|
rt300@0
|
128 string line;
|
rt300@0
|
129 if(!theFile){
|
rt300@0
|
130 cout<<"No event log file found - first APP open called\n";
|
rt300@0
|
131 firstEverAppOpen();
|
rt300@0
|
132 return;
|
rt300@0
|
133 }else{
|
rt300@0
|
134 while(theFile){
|
rt300@0
|
135 theFile >> line;
|
rt300@0
|
136 // cout << line; // lots!!!!
|
rt300@0
|
137 fileText << line;
|
rt300@0
|
138 }
|
rt300@0
|
139 theFile.close();
|
rt300@0
|
140 }
|
rt300@0
|
141
|
rt300@0
|
142 cout << "size of log JSON string:" << fileText.str().length() << "BYTES \n";
|
rt300@0
|
143
|
rt300@0
|
144 bool parsingSuccessful = reader.parse( fileText.str(), root );
|
rt300@0
|
145
|
rt300@0
|
146 if ( !parsingSuccessful )
|
rt300@0
|
147 {
|
rt300@0
|
148 // report to the user the failure and their locations in the document.
|
rt300@0
|
149 std::cout << "Failed to parse event log JSON: \n"
|
rt300@0
|
150 << reader.getFormattedErrorMessages();
|
rt300@0
|
151 return;
|
rt300@0
|
152 }
|
rt300@0
|
153
|
rt300@0
|
154 /////////////////
|
rt300@0
|
155 // now put user deets into variables
|
rt300@0
|
156
|
rt300@0
|
157 userName = root["userName"].asString();
|
rt300@0
|
158 deviceID = root["deviceID"].asLargestInt();
|
rt300@0
|
159 nextUploadNumber = root["uploadNumber"].asInt();
|
rt300@0
|
160 savedInteractionTime = root["savedInteractionTime"].asLargestInt();
|
rt300@0
|
161 questionnaireCompleted = root["questionnaireCompleted"].asBool();
|
rt300@0
|
162 questionnaireUploaded = root["questionnaireUploaded"].asBool();
|
rt300@0
|
163
|
rt300@0
|
164 // check for unuploaded evts
|
rt300@0
|
165 const Json::Value jlogs = root["events"];
|
rt300@0
|
166
|
rt300@0
|
167 for ( int index = 0; index < jlogs.size(); ++index ) theEvents.push_back(lEvent(jlogs[index]));
|
rt300@0
|
168
|
rt300@0
|
169
|
rt300@0
|
170 //////////////
|
rt300@0
|
171
|
rt300@0
|
172 if(questionnaireCompleted && !questionnaireUploaded){
|
rt300@0
|
173 // then read it in and upload it
|
rt300@0
|
174 Json::Value JQ = root["questionnaire"];
|
rt300@0
|
175 Json::Value JArray = JQ["qAnswers"];
|
rt300@0
|
176 if(JArray.size() < 2){
|
rt300@0
|
177 cout << "Error - status of questionnaire is wierd\n";
|
rt300@0
|
178 }
|
rt300@0
|
179 for ( unsigned int i = 0; i < JArray.size(); i++ )
|
rt300@0
|
180 {
|
rt300@0
|
181 questionnaireAnswers.push_back(JArray[i].asInt());
|
rt300@0
|
182 }
|
rt300@0
|
183 questionnaireComments = JQ["comments"].toStyledString();
|
rt300@0
|
184 //uploadQuestionnaire();
|
rt300@0
|
185 }
|
rt300@0
|
186
|
rt300@0
|
187 // TODO interaction time seems to be balls
|
rt300@0
|
188 cout << "Total interaction time: " << savedInteractionTime << '\n';
|
rt300@0
|
189
|
rt300@0
|
190 }
|
rt300@0
|
191
|
rt300@0
|
192 //---------------------------------------------------------------------------
|
rt300@0
|
193
|
rt300@0
|
194 void EventLogger::firstEverAppOpen(){
|
rt300@0
|
195
|
rt300@0
|
196 nextUploadNumber = 0;
|
rt300@0
|
197 deviceID = ofGetSystemTimeMicros();
|
rt300@0
|
198 savedInteractionTime = 0;
|
rt300@0
|
199 questionnaireCompleted = false;
|
rt300@0
|
200 questionnaireUploaded = false;
|
rt300@0
|
201
|
rt300@0
|
202 }
|
rt300@0
|
203
|
rt300@0
|
204
|
rt300@0
|
205 //---------------------------------------------------------------------------
|
rt300@0
|
206 void EventLogger::questionnaireAnswersObtained(vector<int> answers, const char* userComments){
|
rt300@0
|
207
|
rt300@0
|
208 questionnaireCompleted = true;
|
rt300@0
|
209 questionnaireAnswers = answers;
|
rt300@0
|
210 questionnaireComments = userComments;
|
rt300@0
|
211 uploadQuestionnaire();
|
rt300@0
|
212 logEvent(QUESTIONNAIRE_COMPLETED);
|
rt300@0
|
213
|
rt300@0
|
214 }
|
rt300@0
|
215 //---------------------------------------------------------------------------
|
rt300@0
|
216 void EventLogger::uploadQuestionnaire(){
|
rt300@0
|
217 // show indicator
|
rt300@0
|
218 cout << "^^^^^^^^ UPLOADING QUESTIONNAIRE ^^^^^^^^ \n";
|
rt300@0
|
219 cout << questionnaireToJson() << "\n";
|
rt300@0
|
220 sendToServer("questionnaire", questionnaireToJson(), true);
|
rt300@0
|
221
|
rt300@0
|
222 }
|
rt300@0
|
223 //---------------------------------------------------------------------------
|
rt300@0
|
224 bool EventLogger::sendToServer(string functionName, Json::Value jsonData, bool async = false){
|
rt300@0
|
225
|
rt300@0
|
226 Json::FastWriter writer;
|
rt300@0
|
227 string jsontext = writer.write( jsonData );
|
rt300@0
|
228
|
rt300@0
|
229 // remove newline
|
rt300@0
|
230 if (!jsontext.empty() && jsontext[jsontext.length()-1] == '\n') {
|
rt300@0
|
231 jsontext.erase(jsontext.length()-1);
|
rt300@0
|
232 }
|
rt300@0
|
233 ostringstream jd;
|
rt300@0
|
234 jd << jsontext;
|
rt300@0
|
235 NSString *theData = [NSString stringWithUTF8String:jd.str().c_str()];
|
rt300@0
|
236 NSString *theType = [NSString stringWithUTF8String:functionName.c_str()];
|
rt300@0
|
237
|
rt300@0
|
238 if(async){
|
rt300@0
|
239 [serverComms doPostRequest:theType withData:theData];
|
rt300@0
|
240 }else{
|
rt300@0
|
241 bool success = [serverComms doSyncPostRequest:theType withData:theData];
|
rt300@0
|
242 return success;
|
rt300@0
|
243 }
|
rt300@0
|
244
|
rt300@0
|
245 }
|
rt300@0
|
246 //-----------------------------
|
rt300@0
|
247 void EventLogger::questionnaireOK(){
|
rt300@0
|
248 questionnaireUploaded = true;
|
rt300@0
|
249 questionnaireComments = "";
|
rt300@0
|
250 }
|
rt300@0
|
251 //-----------------------------
|
rt300@0
|
252 void EventLogger::eventlogOK(){
|
rt300@0
|
253 // COMMENT THIS IF UPLAODING FROM IPAD TO XCODE
|
rt300@0
|
254
|
rt300@0
|
255 // it's a bad idea to do this in another thread...
|
rt300@0
|
256 theEvents.clear();
|
rt300@0
|
257 cout << "EVENT LOG UPLOAD SUCCESS\n";
|
rt300@0
|
258 nextUploadNumber++;
|
rt300@0
|
259 logUploadInProgress = false;
|
rt300@0
|
260 }
|
rt300@0
|
261 //-----------------------------
|
rt300@0
|
262 void EventLogger::testConnectionOK(){
|
rt300@0
|
263 cout << "^^^^^^^^ server connection OK ^^^^^^^^ \n";
|
rt300@0
|
264 serverConnectionOK = true;
|
rt300@0
|
265 }
|
rt300@0
|
266 //-----------------------------
|
rt300@0
|
267 void EventLogger::questionnaireNotOK(){
|
rt300@0
|
268 cout << "XXXXX questionnaire NOT OK XXXXXXX \n";
|
rt300@0
|
269 questionnaireUploaded = false;
|
rt300@0
|
270 }
|
rt300@0
|
271 //-----------------------------
|
rt300@0
|
272 void EventLogger::eventlogNotOK(){
|
rt300@0
|
273 // try later
|
rt300@0
|
274 cout << "XXXXX event log NOT OK XXXXXXX \n";
|
rt300@0
|
275 nextUploadQty += UPLOAD_CHUNK_SIZE;
|
rt300@0
|
276 logUploadInProgress = false;
|
rt300@0
|
277 }
|
rt300@0
|
278 //-----------------------------
|
rt300@0
|
279 void EventLogger::testConnectionNotOK(){
|
rt300@0
|
280 cout << "XXXXX server connection NOT OK XXXXXXX \n";
|
rt300@0
|
281 serverConnectionOK = false;
|
rt300@0
|
282 // alert?
|
rt300@0
|
283
|
rt300@0
|
284 }
|
rt300@0
|
285
|
rt300@0
|
286
|
rt300@0
|
287 //---------------------------------------------------------------------------
|
rt300@0
|
288
|
rt300@0
|
289 bool EventLogger::uploadEventLog(bool async){
|
rt300@0
|
290
|
rt300@0
|
291 // show indicator
|
rt300@0
|
292 logUploadInProgress = true;
|
rt300@0
|
293 cout << "^^^^^^^^ ATTEMPTING TO UPLOAD " << theEvents.size() << " EVENTS ^^^^^^^^ .\n";
|
rt300@0
|
294 if(!async){
|
rt300@0
|
295 bool success = sendToServer("eventlog", logsToJson(), async);
|
rt300@0
|
296 if(!success){
|
rt300@0
|
297 // try later
|
rt300@0
|
298 nextUploadQty += UPLOAD_CHUNK_SIZE;
|
rt300@0
|
299 // increment upload number?
|
rt300@0
|
300 }else{
|
rt300@0
|
301
|
rt300@0
|
302 // if success - clear memory
|
rt300@0
|
303 // IF UPLAODING FROM IPAD TO XCODE COMMENT OUT
|
rt300@0
|
304 theEvents.clear();
|
rt300@0
|
305 cout << "UPLOAD SUCCESS\n";
|
rt300@0
|
306 nextUploadNumber++;
|
rt300@0
|
307 }
|
rt300@0
|
308 logUploadInProgress = false;
|
rt300@0
|
309 return success;
|
rt300@0
|
310 }else{
|
rt300@0
|
311 sendToServer("eventlog", logsToJson(), async);
|
rt300@0
|
312 }
|
rt300@0
|
313 }
|
rt300@0
|
314 //---------------------------------------------------------------------------
|
rt300@0
|
315 // only called when doing supervised tests
|
rt300@0
|
316 void EventLogger::newUser(){
|
rt300@0
|
317 // store old stuff
|
rt300@0
|
318
|
rt300@0
|
319 saveSessionToFile();
|
rt300@0
|
320 cout<<"setup new user\n";
|
rt300@0
|
321 deleteLogs();
|
rt300@0
|
322 nextUploadNumber = 0;
|
rt300@0
|
323 deviceID = ofGetSystemTimeMicros();
|
rt300@0
|
324 savedInteractionTime = 0;
|
rt300@0
|
325 totalInteractionTime = 0;
|
rt300@0
|
326 sessionStartTime = ofGetSystemTime();
|
rt300@0
|
327 questionnaireCompleted = false;
|
rt300@0
|
328 questionnaireUploaded = false;
|
rt300@0
|
329
|
rt300@0
|
330 //((testApp *)ofGetAppPtr())->showIntro();
|
rt300@0
|
331
|
rt300@0
|
332 }
|
rt300@0
|
333 //---------------------------------------------------------------------------
|
rt300@0
|
334 // called from alertView OK in iViewController
|
rt300@0
|
335 void EventLogger::setUsername(const char *u){
|
rt300@0
|
336 userName = u;
|
rt300@0
|
337
|
rt300@0
|
338 }
|
rt300@0
|
339 //---------------------------------------------------------------------------
|
rt300@0
|
340 //new tweakathlon event logger with vector
|
rt300@0
|
341 void EventLogger::logEvent(const leventType& evtType, const vector<int> eventData){
|
rt300@0
|
342 Poco::Mutex::ScopedLock lock(_mutex);
|
rt300@0
|
343 if(!loggingEnabled) return;
|
rt300@0
|
344
|
rt300@0
|
345 switch ( evtType ) {
|
rt300@0
|
346
|
rt300@0
|
347 // case CANDIDATE_PARAM_ADJUSTED:
|
rt300@0
|
348 // // TODO thinning here. maybe. was a pain in the butt.
|
rt300@0
|
349 // thinnedSliderEvent(lEvent(evtType,eventData));
|
rt300@0
|
350 // break;
|
rt300@0
|
351 default:
|
rt300@0
|
352 // default is just an event type with vector of ints. matlab will know what they are.
|
rt300@0
|
353
|
rt300@0
|
354
|
rt300@0
|
355 theEvents.push_back(lEvent(evtType, eventData));
|
rt300@0
|
356
|
rt300@0
|
357 break;
|
rt300@0
|
358 }
|
rt300@0
|
359
|
rt300@18
|
360 // new riftathon save as we go
|
rt300@18
|
361 if (theEvents.size() > SAVE_CHUNK_SIZE){
|
rt300@18
|
362 saveSessionToFile();
|
rt300@18
|
363 theEvents.clear();
|
rt300@0
|
364 }
|
rt300@18
|
365
|
rt300@0
|
366 //TODO thiswrong?
|
rt300@0
|
367 totalInteractionTime = savedInteractionTime + (ofGetSystemTime() - sessionStartTime); // milliseconds
|
rt300@0
|
368
|
rt300@0
|
369 }
|
rt300@0
|
370 //---------------------------------------------------------------------------
|
rt300@0
|
371 // OLD SONIC ZOOM EVT - still used for simple events with no data
|
rt300@0
|
372 void EventLogger::logEvent(const leventType& evtType){
|
rt300@0
|
373 Poco::Mutex::ScopedLock lock(_mutex);
|
rt300@0
|
374 if(!loggingEnabled) return;
|
rt300@0
|
375
|
rt300@0
|
376 switch ( evtType ) {
|
rt300@0
|
377 // data thinning here
|
rt300@0
|
378 case APP_LOADED:
|
rt300@0
|
379 theEvents.push_back(lEvent(evtType));
|
rt300@0
|
380 default:
|
rt300@0
|
381 // default is just an event type with vector of ints. matlab will know what they are.
|
rt300@0
|
382
|
rt300@0
|
383
|
rt300@0
|
384 theEvents.push_back(lEvent(evtType));
|
rt300@0
|
385
|
rt300@0
|
386 }
|
rt300@0
|
387
|
rt300@0
|
388 if(theEvents.size() > nextUploadQty && !logUploadInProgress){
|
rt300@0
|
389 //try to upload asynchronously
|
rt300@0
|
390 // TODO pilot doesn't upload
|
rt300@0
|
391 //uploadEventLog(true);
|
rt300@0
|
392 }
|
rt300@18
|
393
|
rt300@34
|
394 // new riftathon save as we go NEVER REACHES HERE?
|
rt300@18
|
395 if (theEvents.size() > SAVE_CHUNK_SIZE){
|
rt300@18
|
396 saveSessionToFile();
|
rt300@18
|
397 }
|
rt300@18
|
398
|
rt300@0
|
399 //TODO thiswrong?
|
rt300@0
|
400 totalInteractionTime = savedInteractionTime + (ofGetSystemTime() - sessionStartTime); // milliseconds
|
rt300@0
|
401
|
rt300@0
|
402 }
|
rt300@0
|
403 // UnaryPredicate
|
rt300@0
|
404 template <class T>
|
rt300@0
|
405 bool EventLogger::matchID(T thing){
|
rt300@0
|
406 return true;
|
rt300@0
|
407 }
|
rt300@0
|
408 bool EventLogger::matchID2(){
|
rt300@0
|
409 return true;
|
rt300@0
|
410 }
|
rt300@0
|
411 //---------------------------------------------------------------------------
|
rt300@0
|
412 void EventLogger::thinnedSliderEvent(lEvent newEvent){
|
rt300@0
|
413 static vector<lEvent> unloggedEventsCache; // list of all different slider events
|
rt300@0
|
414 static int eventCounter = 0;
|
rt300@0
|
415
|
rt300@0
|
416 // if first event then log it.
|
rt300@0
|
417 if(theEvents.size() == 0){
|
rt300@0
|
418 theEvents.push_back(newEvent);
|
rt300@0
|
419 }
|
rt300@0
|
420
|
rt300@0
|
421 // look for last event in the cache that had this mappingID
|
rt300@0
|
422 cout << unloggedEventsCache.size() << endl;
|
rt300@0
|
423
|
rt300@0
|
424 vector<lEvent>::iterator lastMatching;
|
rt300@0
|
425 for(lastMatching = unloggedEventsCache.begin();
|
rt300@0
|
426 lastMatching != unloggedEventsCache.end() && ( (*lastMatching).eventData[0] != newEvent.eventData[0]);
|
rt300@0
|
427 lastMatching++);
|
rt300@0
|
428
|
rt300@0
|
429
|
rt300@0
|
430 if (lastMatching != unloggedEventsCache.end()){
|
rt300@0
|
431 //cout << "matching id logevent: " << (*lastMatching).eventData[0] << " " << newEvent.eventData[0] << endl;
|
rt300@0
|
432 // we have another, check gap
|
rt300@0
|
433 int gap = newEvent.eventTime - (*lastMatching).eventTime;
|
rt300@0
|
434 if(gap > 300){
|
rt300@0
|
435 theEvents.push_back((*lastMatching));
|
rt300@0
|
436
|
rt300@0
|
437 // also log new slider evt
|
rt300@0
|
438 theEvents.push_back(newEvent);
|
rt300@0
|
439 eventCounter = 0;
|
rt300@0
|
440
|
rt300@0
|
441 }else if(eventCounter >= EVENT_THIN_FACTOR){ // otherwise only record every Nth event
|
rt300@0
|
442 theEvents.push_back(newEvent);
|
rt300@0
|
443 eventCounter = 0;
|
rt300@0
|
444 // DELETE THAT PREVIOUS EVENT
|
rt300@0
|
445 unloggedEventsCache.erase(lastMatching);
|
rt300@0
|
446
|
rt300@0
|
447 }else{
|
rt300@0
|
448 // ignore for now but put in unlogged
|
rt300@0
|
449 unloggedEventsCache.push_back(newEvent);
|
rt300@0
|
450 }
|
rt300@0
|
451
|
rt300@0
|
452 }else{
|
rt300@0
|
453 // this event type wasnt in the cache
|
rt300@0
|
454 if(eventCounter >= EVENT_THIN_FACTOR){ // otherwise only record every Nth event
|
rt300@0
|
455 theEvents.push_back(newEvent);
|
rt300@0
|
456 eventCounter = 0;
|
rt300@0
|
457 }else{
|
rt300@0
|
458 unloggedEventsCache.push_back(newEvent);
|
rt300@0
|
459 }
|
rt300@0
|
460
|
rt300@0
|
461 }
|
rt300@0
|
462 // always count the new one
|
rt300@0
|
463 eventCounter++;
|
rt300@0
|
464
|
rt300@0
|
465
|
rt300@0
|
466
|
rt300@0
|
467 }
|
rt300@0
|
468
|
rt300@0
|
469 //--------------------------------------------------------------------
|
rt300@0
|
470 // called from newUser
|
rt300@0
|
471 void EventLogger::deleteLogs(){
|
rt300@18
|
472 return;
|
rt300@0
|
473 // the
|
rt300@0
|
474 theEvents.clear();
|
rt300@0
|
475 string fname = ofxiPhoneGetDocumentsDirectory() + EVENT_LOG_FILENAME;
|
rt300@0
|
476 ofFile logFile(fname,ofFile::WriteOnly);
|
rt300@0
|
477 logFile << "";
|
rt300@0
|
478 logFile.close();
|
rt300@0
|
479 }
|
rt300@0
|
480
|
rt300@0
|
481 //---------------------------------------------------------------------------
|
rt300@0
|
482
|
rt300@0
|
483 Json::Value EventLogger::logsToJson(){
|
rt300@0
|
484 // put all logged events into Json formatted string
|
rt300@0
|
485 Json::Value root;
|
rt300@0
|
486
|
rt300@0
|
487 vector<lEvent>::iterator eventIter;
|
rt300@0
|
488
|
rt300@0
|
489 root["programVersion"] = PROGRAM_VERSION;
|
rt300@0
|
490 root["userName"] = userName;
|
rt300@0
|
491 root["deviceID"] = deviceID;
|
rt300@0
|
492 root["uploadNumber"] = nextUploadNumber;
|
rt300@0
|
493 root["savedInteractionTime"] = savedInteractionTime;
|
rt300@0
|
494 root["questionnaireCompleted"] = questionnaireCompleted;
|
rt300@0
|
495 root["questionnaireUploaded"] = questionnaireUploaded;
|
rt300@0
|
496
|
rt300@0
|
497 // this can mess up matlab script if it doesn't find this field
|
rt300@0
|
498 root["questionnaire"] = questionnaireToJson();
|
rt300@0
|
499
|
rt300@0
|
500
|
rt300@0
|
501 int i = 0;
|
rt300@0
|
502 for(eventIter = theEvents.begin(); eventIter < theEvents.end(); eventIter++){
|
rt300@0
|
503 root["events"][i] = (*eventIter).eventToJson();
|
rt300@0
|
504 i++;
|
rt300@0
|
505 }
|
rt300@0
|
506 root["numEventsHere"] = i;
|
rt300@0
|
507 return root;
|
rt300@0
|
508 }
|
rt300@0
|
509
|
rt300@0
|
510 //---------------------------------------------------------------------------
|
rt300@0
|
511
|
rt300@0
|
512 Json::Value EventLogger::questionnaireToJson(){
|
rt300@0
|
513 // put all answers into Json formatted string
|
rt300@0
|
514 Json::Value root;
|
rt300@0
|
515
|
rt300@0
|
516 vector<int>::iterator aIter;
|
rt300@0
|
517
|
rt300@0
|
518 Json::Value questionnaire;
|
rt300@0
|
519
|
rt300@0
|
520 int i = 0;
|
rt300@0
|
521 for(aIter = questionnaireAnswers.begin(); aIter < questionnaireAnswers.end(); aIter++){
|
rt300@0
|
522 questionnaire[i] = (*aIter);
|
rt300@0
|
523 i++;
|
rt300@0
|
524 }
|
rt300@0
|
525
|
rt300@0
|
526 root["qAnswers"] = questionnaire;
|
rt300@0
|
527 root["comments"] = questionnaireComments;
|
rt300@0
|
528 root["userName"] = userName;
|
rt300@0
|
529 root["deviceID"] = deviceID;
|
rt300@0
|
530 root["programVersion"] = PROGRAM_VERSION;
|
rt300@0
|
531
|
rt300@0
|
532 return root;
|
rt300@0
|
533 }
|
rt300@0
|
534
|
rt300@0
|
535 //---------------------------------------------------------------------------
|
rt300@0
|
536 void EventLogger::printAll(){
|
rt300@0
|
537 cout << "-----------------ALL LOGGED EVENTS----------------- \n";
|
rt300@0
|
538 vector<lEvent>::iterator evIter;
|
rt300@0
|
539 cout << logsToJson() << "\n";
|
rt300@0
|
540 cout << "---------------------QUESTIONNAIRE---------------- \n";
|
rt300@0
|
541 cout << questionnaireToJson() << "\n";
|
rt300@0
|
542 };
|
rt300@0
|
543 //---------------------------------------------------------------------------
|
rt300@0
|
544
|
rt300@0
|
545 void EventLogger::saveSessionToFile(){
|
rt300@0
|
546 stringstream fn;
|
rt300@18
|
547 fn << ofxiPhoneGetDocumentsDirectory() << userName << "_eventlog_" << nextLogFileIndexString() << ".json";
|
rt300@0
|
548
|
rt300@0
|
549 string fname = fn.str(); //ofxiPhoneGetDocumentsDirectory() + userName + '_' + "TESTSAVE.json";
|
rt300@0
|
550
|
rt300@0
|
551 // write to file
|
rt300@18
|
552
|
rt300@0
|
553 Json::Value jlogs = logsToJson();
|
rt300@0
|
554 ofFile logFile(fname,ofFile::WriteOnly);
|
rt300@0
|
555 logFile << jlogs;
|
rt300@0
|
556 logFile.close();
|
rt300@18
|
557 nextLogFileIndex++;
|
rt300@34
|
558 theEvents.clear();
|
rt300@18
|
559 }
|
rt300@18
|
560
|
rt300@18
|
561 string EventLogger::nextLogFileIndexString(){
|
rt300@18
|
562 string num = ofToString(nextLogFileIndex);
|
rt300@18
|
563 string zero = ofToString(0);
|
rt300@18
|
564 int numzeros = 4 - num.length();
|
rt300@18
|
565 for (int i=0; i< numzeros;i++){
|
rt300@18
|
566 num = zero + num;
|
rt300@18
|
567 }
|
rt300@18
|
568 return num;
|
rt300@0
|
569
|
rt300@0
|
570 }
|
rt300@0
|
571 //----------------------------------------------------------------------------
|
rt300@0
|
572
|
rt300@0
|
573 // this builds up a file incrementally, which can be recovered on crash
|
rt300@0
|
574 //void EventLogger::appendToFile(){
|
rt300@0
|
575 //
|
rt300@0
|
576 //
|
rt300@0
|
577 //}
|
rt300@32
|
578
|
rt300@32
|
579 //---------------------------------------------------------------------------
|
rt300@32
|
580
|
rt300@32
|
581 void EventLogger::exitAndSave(){
|
rt300@32
|
582
|
rt300@32
|
583 saveSessionToFile();
|
rt300@32
|
584 return;
|
rt300@32
|
585
|
rt300@32
|
586 if(!consentGiven){
|
rt300@32
|
587 Json::Value jlogs = logsToJson();
|
rt300@32
|
588 // try to upload TODO (no - might hang and prevent exit???)
|
rt300@32
|
589
|
rt300@32
|
590 // TODO pilot doesn't upload
|
rt300@32
|
591 // uploadEventLog(true);
|
rt300@32
|
592 return;
|
rt300@32
|
593 }
|
rt300@32
|
594
|
rt300@32
|
595 savedInteractionTime = savedInteractionTime + (ofGetSystemTime() - sessionStartTime);
|
rt300@32
|
596 // save user details
|
rt300@32
|
597 string fname = ofxiPhoneGetDocumentsDirectory() + userName + '_' + EVENT_LOG_FILENAME;
|
rt300@32
|
598
|
rt300@32
|
599 // try to upload
|
rt300@32
|
600 // do it sync because event list needs to be cleared to prevent saving on device
|
rt300@32
|
601
|
rt300@32
|
602 // TODO for pilot store to ipad
|
rt300@32
|
603 // uploadEventLog(false);
|
rt300@32
|
604
|
rt300@32
|
605 // write to file
|
rt300@32
|
606 // json without the logs that were uploaded!
|
rt300@32
|
607 Json::Value jlogs = logsToJson();
|
rt300@32
|
608 ofFile logFile(fname,ofFile::WriteOnly);
|
rt300@32
|
609 logFile << jlogs;
|
rt300@32
|
610 cout << jlogs;
|
rt300@32
|
611 logFile.close();
|
rt300@32
|
612
|
rt300@32
|
613 } |