|
Emotiv EPOC plugin 1.0
|
00001 //################################################################################### 00002 //# Emotiv EPOC Object # 00003 //# Used To Handle an Emotiv EPOC headset # 00004 //# Author : # 00005 //# Aymeric SUTEAU # 00006 //# LISA - ANGERS # 00007 //################################################################################### 00008 00009 00010 /* INCLUDES */ 00011 #include "Plugin.h" 00012 00013 /* DEFINES */ 00014 #define SCALE_FACTOR 0.5 00015 00016 /* GLOBAL VARIABLES */ 00017 int iChargeLevel = 0, iMaxChargeLevel = 0, iNbPads = 0; 00018 bool bHeadsetConnected = false; 00019 bool bExpressivTrainingSucceeded = false, bCognitivTrainingSucceeded = false; 00020 bool bNewData = false; 00021 unsigned long uActiveActions = 0; 00022 list<Epoc*> lEpocList; 00023 00024 // Gyro position 00025 float xMinPos = -(float)(GetSystemMetrics(SM_CXSCREEN)) / 2, xMaxPos = (float)(GetSystemMetrics(SM_CXSCREEN)) / 2; 00026 float yMinPos = -(float)(GetSystemMetrics(SM_CYSCREEN)) / 2, yMaxPos = (float)(GetSystemMetrics(SM_CYSCREEN)) / 2; 00027 float xCurrentPos = 0.f, yCurrentPos = 0.f; 00028 00029 // User profiles 00030 Profile *userProfile; 00031 unsigned char* baseProfile = 0; 00032 unsigned int baseProfileSize = 0; 00033 unsigned int profileSize = 0; 00034 unsigned char* profileBuffer = 0; 00035 static bool fileCreated = false; 00036 float secs = 1.0f; 00037 00038 // Definition of raw EEG data channels 00039 EE_DataChannel_t targetChannelList[] = 00040 { 00041 ED_COUNTER, 00042 ED_AF3, ED_F7, ED_F3, ED_FC5, ED_T7, 00043 ED_P7, ED_O1, ED_O2, ED_P8, ED_T8, 00044 ED_FC6, ED_F4, ED_F8, ED_AF4, ED_GYROX, ED_GYROY, ED_TIMESTAMP, 00045 ED_FUNC_ID, ED_FUNC_VALUE, ED_MARKER, ED_SYNC_SIGNAL 00046 }; 00047 00048 00049 /*-------------------------- CONSTRUCTOR AND DESTRUCTOR ---------------------------*/ 00050 Epoc::Epoc() : Thread() 00051 { 00052 // Initialize array size for sensor pads quality 00053 iContactQuality = new int[18]; 00054 00055 // Create new event handler and EmoState buffer 00056 eEvent = EE_EmoEngineEventCreate(); 00057 eProfile = EE_EmoEngineEventCreate(); 00058 eState = EE_EmoStateCreate(); 00059 SetUserID(0); 00060 00061 // Add current headset object to the global list 00062 lEpocList.push_back(this); 00063 00064 // Safely Disconnect the headset, to be sure that it's not running anymore 00065 EE_EngineDisconnect(); 00066 00067 // Initialize Affective Suite actions 00068 SetEngagementBoredom(0.f); 00069 SetFrustration(0.f); 00070 SetMeditation(0.f); 00071 SetInstantaneousExcitement(0.f); 00072 SetLongTermExcitement(0.f); 00073 00074 // Initialize Expressiv Suite actions 00075 SetEyeExpressionType(0); 00076 SetUpperFaceExpressionType(0); 00077 SetUpperFaceExpressionPower(0.f); 00078 SetLowerFaceExpressionType(0); 00079 SetLowerFaceExpressionPower(0.f); 00080 00081 // Initialize Cognitiv Suite actions 00082 SetActionType(0); 00083 SetActionPower(0.f); 00084 00085 // Initialize gyroscope 00086 SetGyroX(0.f); 00087 SetGyroY(0.f); 00088 00089 // Initialize user profiles path name and loading / saving status 00090 SetUserProfileFileName(""); 00091 SetProfileLoadingDone(true); 00092 SetProfileSavingDone(true); 00093 00094 // Start thread 00095 this->start(); 00096 this->bIsRunning = true; 00097 this->bStatus = false; 00098 00099 // Raw EEG data acquisition 00100 readyToCollect = false; 00101 } 00102 00103 Epoc::~Epoc() 00104 { 00105 // Stop thread 00106 this->bIsRunning = false; 00107 this->bStatus = false; 00108 this->stop(); 00109 00110 // DEBUG: Release connection to EmoEngine 00111 //Disconnect(); 00112 00113 // Remove current headset object from the global list 00114 lEpocList.remove(this); 00115 00116 // Delete dynamic arrays 00117 delete [] iContactQuality; 00118 if (baseProfile) 00119 { 00120 delete [] baseProfile, baseProfile = 0; 00121 } 00122 } 00123 00124 00125 /*------------------------------ GETTERS AND SETTERS ------------------------------*/ 00126 unsigned int Epoc::GetUserID() 00127 { 00128 return this->uUserID; 00129 } 00130 00131 void Epoc::SetUserID(unsigned int userID) 00132 { 00133 this->uUserID = userID; 00134 } 00135 00136 00137 // Headset Status 00138 float Epoc::GetSystemUpTime() 00139 { 00140 return this->fSystemUpTime; 00141 } 00142 00143 void Epoc::SetSystemUpTime(float systemTime) 00144 { 00145 this->fSystemUpTime = systemTime; 00146 } 00147 00148 int Epoc::GetDongleStatus() 00149 { 00150 return this->iDongleStatus; 00151 } 00152 00153 void Epoc::SetDongleStatus(int keyStatus) 00154 { 00155 this->iDongleStatus = keyStatus; 00156 } 00157 00158 int Epoc::GetHeadsetStatus() 00159 { 00160 return this->iHeadsetStatus; 00161 } 00162 00163 void Epoc::SetHeadsetStatus(int headsetStatus) 00164 { 00165 this->iHeadsetStatus = headsetStatus; 00166 } 00167 00168 float Epoc::GetWirelessSignal() 00169 { 00170 return this->fWirelessSignal; 00171 } 00172 00173 void Epoc::SetWirelessSignal(float wirelessSignal) 00174 { 00175 this->fWirelessSignal = wirelessSignal * 50; // indicator between 0 and 1 00176 } 00177 00178 float Epoc::GetBatteryPower() 00179 { 00180 return this->fBatteryPower; 00181 } 00182 00183 void Epoc::SetBatteryPower() 00184 { 00185 ES_GetBatteryChargeLevel(eState, &iChargeLevel, &iMaxChargeLevel); 00186 this->fBatteryPower = 100*((float)iChargeLevel / (float)iMaxChargeLevel); // indicator between 0 and 1 00187 } 00188 00189 00190 // Affectiv Suite 00191 float Epoc::GetEngagementBoredom() 00192 { 00193 return this->fEngagementBoredom; 00194 } 00195 00196 void Epoc::SetEngagementBoredom(float engagement) 00197 { 00198 this->fEngagementBoredom = engagement; 00199 } 00200 00201 float Epoc::GetFrustration() 00202 { 00203 return this->fFrustration; 00204 } 00205 00206 void Epoc::SetFrustration(float frustration) 00207 { 00208 this->fFrustration = frustration; 00209 } 00210 00211 float Epoc::GetMeditation() 00212 { 00213 return this->fMeditation; 00214 } 00215 00216 void Epoc::SetMeditation(float meditation) 00217 { 00218 this->fMeditation = meditation; 00219 } 00220 00221 float Epoc::GetInstantaneousExcitement() 00222 { 00223 return this->fInstantaneousExcitement; 00224 } 00225 00226 void Epoc::SetInstantaneousExcitement(float instantaneousExcitement) 00227 { 00228 this->fInstantaneousExcitement = instantaneousExcitement; 00229 } 00230 00231 float Epoc::GetLongTermExcitement() 00232 { 00233 return this->fLongTermExcitement; 00234 } 00235 00236 void Epoc::SetLongTermExcitement(float longTermExcitement) 00237 { 00238 this->fLongTermExcitement = longTermExcitement; 00239 } 00240 00241 00242 // Expressiv Suite 00243 unsigned int Epoc::GetEyeExpressionType() 00244 { 00245 return this->uEyeExpressionType; 00246 } 00247 00248 void Epoc::SetEyeExpressionType(unsigned int eyeExpressionType) 00249 { 00250 this->uEyeExpressionType = eyeExpressionType; 00251 } 00252 00253 unsigned int Epoc::GetUpperFaceExpressionType() 00254 { 00255 return this->uUpperFaceExpressionType; 00256 } 00257 00258 void Epoc::SetUpperFaceExpressionType(unsigned int upperFaceExpressionType) 00259 { 00260 this->uUpperFaceExpressionType = upperFaceExpressionType; 00261 } 00262 00263 float Epoc::GetUpperFaceExpressionPower() 00264 { 00265 return this->fUpperFaceExpressionPower; 00266 } 00267 00268 void Epoc::SetUpperFaceExpressionPower(float upperFaceExpressionPower) 00269 { 00270 this->fUpperFaceExpressionPower = upperFaceExpressionPower; 00271 } 00272 00273 unsigned int Epoc::GetLowerFaceExpressionType() 00274 { 00275 return this->uLowerFaceExpressionType; 00276 } 00277 00278 void Epoc::SetLowerFaceExpressionType(unsigned int lowerFaceExpressionType) 00279 { 00280 this->uLowerFaceExpressionType = lowerFaceExpressionType; 00281 } 00282 00283 float Epoc::GetLowerFaceExpressionPower() 00284 { 00285 return this->fLowerFaceExpressionPower; 00286 } 00287 00288 void Epoc::SetLowerFaceExpressionPower(float lowerFaceExpressionPower) 00289 { 00290 this->fLowerFaceExpressionPower = lowerFaceExpressionPower; 00291 } 00292 00293 00294 // Cognitiv Suite 00295 unsigned int Epoc::GetActionType() 00296 { 00297 return this->uActionType; 00298 } 00299 00300 void Epoc::SetActionType(unsigned int actionType) 00301 { 00302 this->uActionType = actionType; 00303 } 00304 00305 float Epoc::GetActionPower() 00306 { 00307 return this->fActionPower; 00308 } 00309 00310 void Epoc::SetActionPower(float actionPower) 00311 { 00312 this->fActionPower = actionPower; 00313 } 00314 00315 00316 // Gyro 00317 float Epoc::GetGyroX() 00318 { 00319 return this->fXGyro; 00320 } 00321 00322 void Epoc::SetGyroX(float xGyro) 00323 { 00324 this->fXGyro = xGyro; 00325 } 00326 00327 float Epoc::GetGyroY() 00328 { 00329 return this->fYGyro; 00330 } 00331 00332 void Epoc::SetGyroY(float yGyro) 00333 { 00334 this->fYGyro = yGyro; 00335 } 00336 00337 00338 // User profiles 00339 void Epoc::SetUserProfileFileName(char *path) 00340 { 00341 this->cUserProfileFileName = path; 00342 } 00343 00344 char * Epoc::GetUserProfileFileName() 00345 { 00346 return this->cUserProfileFileName; 00347 } 00348 00349 void Epoc::SetProfileLoadingDone(bool status) 00350 { 00351 this->bLoadProfileDone = status; 00352 } 00353 00354 bool Epoc::GetProfileLoadingDone() 00355 { 00356 return this->bLoadProfileDone; 00357 } 00358 00359 void Epoc::SetProfileSavingDone(bool status) 00360 { 00361 this->bSaveProfileDone = status; 00362 } 00363 00364 bool Epoc::GetProfileSavingDone() 00365 { 00366 return this->bSaveProfileDone; 00367 } 00368 00369 00370 /*--------------------------------- OTHER METHODS ---------------------------------*/ 00371 bool Epoc::Connect() 00372 { 00373 // Initialize the connection with Emotiv EmoEngine 00374 if (EE_EngineConnect() != EDK_OK) 00375 { 00376 MMechostr(MSKDEBUG, "Emotiv Engine start up failed...\n"); 00377 return false; 00378 } 00379 00380 // Retrieve the base profile and save it in buffer 00381 EE_GetBaseProfile(eProfile); 00382 ProfileToByteArray(eProfile, &baseProfile, &baseProfileSize); 00383 00384 // Update connection status for thread 00385 bStatus = true; 00386 return true; 00387 } 00388 00389 bool Epoc::Disconnect() 00390 { 00391 // Terminate the connection with EmoEngine 00392 if (EE_EngineDisconnect() != EDK_OK) 00393 return false; 00394 00395 // Free up memory allocated 00396 EE_EmoStateFree(eState); // EmoState buffer 00397 EE_EmoEngineEventFree(eEvent); // EmoEngine event handler 00398 EE_EmoEngineEventFree(eProfile); // User profile event handler 00399 00400 // Update connection status for thread 00401 bStatus = false; 00402 return true; 00403 } 00404 00405 void Epoc::ReadData() 00406 { 00407 unsigned int userID; 00408 unsigned int nSamplesTaken = 0; 00409 int iSample; 00410 00411 // New data received from Emotiv EPOC 00412 DataHandle hData = EE_DataCreate(); 00413 00414 // Initialize data buffer of sampled data 00415 EE_DataSetBufferSizeInSec(secs); 00416 00417 // Get next event from EmoEngine 00418 int state = EE_EngineGetNextEvent(eEvent); 00419 00420 // New event needs to be handled 00421 if (state == EDK_OK) 00422 { 00423 EE_Event_t eventType = EE_EmoEngineEventGetType(eEvent); 00424 EE_EmoEngineEventGetUserId(eEvent, &userID); 00425 SetUserID(userID); 00426 00427 // Eventually collect raw EEG data 00428 if (readyToCollect) 00429 { 00430 EE_DataUpdateHandle(0, hData); 00431 nSamplesTaken = 0; 00432 EE_DataGetNumberOfSample(hData, &nSamplesTaken); 00433 00434 if (nSamplesTaken != 0) 00435 { 00436 double* data = new double[nSamplesTaken]; 00437 for (int sampleIdx = 0; sampleIdx < (int)nSamplesTaken; ++sampleIdx) 00438 { 00439 iSample = 0; 00440 for (int i = 0; i < sizeof(targetChannelList)/sizeof(EE_DataChannel_t); i++) 00441 { 00442 EE_DataGet(hData, targetChannelList[i], data, nSamplesTaken); 00443 00444 // Get only electrode channel values 00445 if (i >= 1 && i <= 14) 00446 { 00447 this->fEEGData[iSample] = data[sampleIdx]; 00448 iSample++; 00449 } 00450 } 00451 } 00452 // Send new EEG raw data 00453 PostMessage(HScol, EPOC_RAW_EEG_CB, (int)this, (LPARAM)NULL); 00454 00455 // Delete dynamic array 00456 delete[] data; 00457 } 00458 } 00459 00460 switch (eventType) 00461 { 00462 // --- Events related to "Headset Setup" 00463 case EE_UserAdded: 00464 MMechostr(MSKDEBUG, "Event 1: User added...\n"); 00465 SetDongleStatus(1); // Headset key connected 00466 00467 // Enable EEG data acquisition 00468 EE_DataAcquisitionEnable(userID, true); 00469 readyToCollect = true; 00470 break; 00471 00472 case EE_UserRemoved: 00473 MMechostr(MSKDEBUG, "Event 2: User removed...\n"); 00474 SetDongleStatus(0); // Headset key disconnected 00475 break; 00476 00477 // New emotional state 00478 case EE_EmoStateUpdated: 00479 { 00480 //MMechostr(MSKDEBUG, "Event 3: New emotional state...\n"); 00481 EE_EmoEngineEventGetEmoState(eEvent, eState); 00482 00483 // Retrieve new data related to Headset setup 00484 HandleHeadsetSetupEvent(eState); 00485 00486 // If the headset is connected, retrieve new data related to Expressiv / Cognitiv / Affectiv suites 00487 if (bHeadsetConnected) 00488 { 00489 HandleAffectiveSuiteEvent(eState); 00490 HandleCognitivSuiteEvent(eState); 00491 HandleExpressivSuiteEvent(eState); 00492 bNewData = true; // New data is available (for thread) 00493 } 00494 break; 00495 } 00496 00497 // --- Events related to "Expressiv Suite" 00498 case EE_ExpressivEvent: 00499 MMechostr(MSKDEBUG, "Event 4: Expressiv event...\n"); 00500 HandleExpressivTrainingEvent(eEvent); 00501 break; 00502 00503 // --- Events related to "Cognitiv Setup" 00504 case EE_CognitivEvent: 00505 MMechostr(MSKDEBUG, "Event 5: Cognitiv event...\n"); 00506 HandleCognitivTrainingEvent(eEvent); 00507 break; 00508 } 00509 } 00510 else if (state != EDK_NO_EVENT) 00511 { 00512 MMechostr(MSKDEBUG, "No event !\n"); 00513 } 00514 00515 // Update headset status 00516 if (GetHeadsetStatus() == 1 && !bHeadsetConnected) 00517 { 00518 bHeadsetConnected = true; 00519 PostMessage(HScol, EPOC_CONNECTED_CB, (int)this, (LPARAM)NULL); 00520 } 00521 else if (GetHeadsetStatus() == 0 && bHeadsetConnected) 00522 { 00523 bHeadsetConnected = false; 00524 PostMessage(HScol, EPOC_DISCONNECTED_CB, (int)this, (LPARAM)NULL); 00525 } 00526 00527 // Release data handler 00528 EE_DataFree(hData); 00529 } 00530 00531 00532 /*-------------------------------- EVENTS HANDLING --------------------------------*/ 00533 // Event related to "Headset Setup" 00534 void Epoc::HandleHeadsetSetupEvent(EmoStateHandle eState) 00535 { 00536 // Retrieve general information (system up time, wireless signal, headset status and battery power) 00537 SetSystemUpTime(ES_GetTimeFromStart(eState)); 00538 SetWirelessSignal(static_cast<float>(ES_GetWirelessSignalStatus(eState))); 00539 if (GetWirelessSignal() == 0) 00540 SetHeadsetStatus(0); 00541 else 00542 SetHeadsetStatus(1); 00543 SetBatteryPower(); 00544 00545 // Handle bad wireless signal and low battery level 00546 // Only if neuroheadset and dongle are already connected 00547 if (GetHeadsetStatus() == 1 && bHeadsetConnected) 00548 { 00549 if (GetWirelessSignal() <= 0.25) 00550 PostMessage(HScol, EPOC_BAD_SIGNAL_CB, (int)this, (LPARAM)NULL); 00551 if (GetBatteryPower() <= 0.25) 00552 PostMessage(HScol, EPOC_LOW_BATTERY_CB, (int)this, (LPARAM)NULL); 00553 } 00554 00555 // Retrieve contact quality for all pads 00556 iNbPads = ES_GetNumContactQualityChannels(eState); 00557 for (int i=0; i<iNbPads; i++) 00558 { 00559 iContactQuality[i] = static_cast<int>(ES_GetContactQuality(eState, i)); 00560 } 00561 00562 // New Headset Setup data available 00563 PostMessage(HScol, EPOC_HEADSET_DATA_CB, (int)this, (LPARAM)NULL); 00564 } 00565 00566 00567 // Event related to "Expressiv Suite" 00568 void Epoc::HandleExpressivSuiteEvent(EmoStateHandle eState) 00569 { 00570 // Retrieve upper and lower face current actions 00571 EE_ExpressivAlgo_t upperFaceType = ES_ExpressivGetUpperFaceAction(eState); 00572 EE_ExpressivAlgo_t lowerFaceType = ES_ExpressivGetLowerFaceAction(eState); 00573 00574 float upperFaceAmp = ES_ExpressivGetUpperFaceActionPower(eState); 00575 float lowerFaceAmp = ES_ExpressivGetLowerFaceActionPower(eState); 00576 00577 // Update eye related actions 00578 if (ES_ExpressivIsBlink(eState)) 00579 SetEyeExpressionType(1); 00580 else if (ES_ExpressivIsLeftWink(eState)) 00581 SetEyeExpressionType(2); 00582 else if (ES_ExpressivIsRightWink(eState)) 00583 SetEyeExpressionType(4); 00584 else if (ES_ExpressivIsLookingLeft(eState)) 00585 SetEyeExpressionType(8); 00586 else if (ES_ExpressivIsLookingRight(eState)) 00587 SetEyeExpressionType(16); 00588 else if (ES_ExpressivIsLookingUp(eState)) 00589 SetEyeExpressionType(32); 00590 else if (ES_ExpressivIsLookingDown(eState)) 00591 SetEyeExpressionType(64); 00592 else 00593 SetEyeExpressionType(0); 00594 00595 // Update upper face actions 00596 if (upperFaceAmp > 0.0) 00597 { 00598 switch (upperFaceType) 00599 { 00600 case EXP_EYEBROW: 00601 SetUpperFaceExpressionType(1); 00602 break; 00603 00604 case EXP_FURROW: 00605 SetUpperFaceExpressionType(2); 00606 break; 00607 00608 default: 00609 break; 00610 } 00611 } 00612 SetUpperFaceExpressionPower(100*upperFaceAmp); 00613 00614 // Update lower face actions 00615 if (lowerFaceAmp > 0.0) 00616 { 00617 switch (lowerFaceType) 00618 { 00619 case EXP_CLENCH: 00620 SetLowerFaceExpressionType(1); 00621 break; 00622 00623 case EXP_SMILE: 00624 SetLowerFaceExpressionType(2); 00625 break; 00626 00627 case EXP_LAUGH: 00628 SetLowerFaceExpressionType(4); 00629 break; 00630 00631 case EXP_SMIRK_LEFT: 00632 SetLowerFaceExpressionType(8); 00633 break; 00634 00635 case EXP_SMIRK_RIGHT: 00636 SetLowerFaceExpressionType(16); 00637 break; 00638 00639 default: 00640 break; 00641 } 00642 } 00643 SetLowerFaceExpressionPower(100*lowerFaceAmp); 00644 00645 // New Expressiv data available 00646 PostMessage(HScol, EPOC_EXPRESSIV_DATA_CB, (int)this, (LPARAM)NULL); 00647 } 00648 00649 00650 // Event related to "Affectiv Suite" 00651 void Epoc::HandleAffectiveSuiteEvent(EmoStateHandle eState) 00652 { 00653 // Query whether the signal is too noisy for Affectiv detection to be active 00654 if (ES_AffectivIsActive(eState, AFF_ENGAGEMENT_BOREDOM)) 00655 SetEngagementBoredom(100*ES_AffectivGetEngagementBoredomScore(eState)); 00656 00657 if (ES_AffectivIsActive(eState, AFF_FRUSTRATION)) 00658 SetFrustration(100*ES_AffectivGetFrustrationScore(eState)); 00659 00660 if (ES_AffectivIsActive(eState, AFF_MEDITATION)) 00661 SetMeditation(100*ES_AffectivGetMeditationScore(eState)); 00662 00663 if (ES_AffectivIsActive(eState, AFF_EXCITEMENT)) 00664 { 00665 SetInstantaneousExcitement(100*ES_AffectivGetExcitementShortTermScore(eState)); 00666 SetLongTermExcitement(100*ES_AffectivGetExcitementLongTermScore(eState)); 00667 } 00668 00669 // New Affectiv data available 00670 PostMessage(HScol, EPOC_AFFECTIV_DATA_CB, (int)this, (LPARAM)NULL); 00671 } 00672 00673 00674 // Event related to "Cognitiv Suite" 00675 void Epoc::HandleCognitivSuiteEvent(EmoStateHandle eState) 00676 { 00677 // Get information about current action (type and power) 00678 EE_CognitivAction_t actionType = ES_CognitivGetCurrentAction(eState); 00679 float actionPower = ES_CognitivGetCurrentActionPower(eState); 00680 00681 // Query whether the signal is too noisy for Cognitiv detection to be active 00682 if (ES_CognitivIsActive(eState)) 00683 SetActionType(actionType); 00684 SetActionPower(100*actionPower); 00685 00686 // New Cognitiv data available 00687 PostMessage(HScol, EPOC_COGNITIV_DATA_CB, (int)this, (LPARAM)NULL); 00688 } 00689 00690 00691 /*------------------------------------ TRAINING -----------------------------------*/ 00692 // Events related to "Expressiv Suite" training 00693 void Epoc::HandleExpressivTrainingEvent(EmoEngineEventHandle eEvent) 00694 { 00695 int signatureAvailable = 0; 00696 unsigned int u_timeOut = 0; 00697 EE_ExpressivEvent_t eventType = EE_ExpressivEventGetType(eEvent); 00698 00699 switch (eventType) 00700 { 00701 // Training started 00702 case EE_ExpressivTrainingStarted: 00703 MMechostr(MSKDEBUG, "Expressiv training for user [%u] STARTED!\n", GetUserID()); 00704 PostMessage(HScol, EPOC_EXPRESSIV_TRAINING_STARTED_CB, (int)this, (LPARAM)NULL); 00705 break; 00706 00707 // Training succeeded 00708 case EE_ExpressivTrainingSucceeded: 00709 MMechostr(MSKDEBUG, "Expressiv training for user [%u] SUCCEEDED!\n", GetUserID()); 00710 PostMessage(HScol, EPOC_EXPRESSIV_TRAINING_SUCCEEDED_CB, (int)this, (LPARAM)NULL); 00711 00712 // Update status 00713 bExpressivTrainingSucceeded = true; 00714 break; 00715 00716 // Training failed 00717 case EE_ExpressivTrainingFailed: 00718 MMechostr(MSKDEBUG, "Expressiv training for user [%u] FAILED!\n", GetUserID()); 00719 PostMessage(HScol, EPOC_EXPRESSIV_TRAINING_FAILED_CB, (int)this, (LPARAM)NULL); 00720 break; 00721 00722 // Training completed 00723 case EE_ExpressivTrainingCompleted: 00724 MMechostr(MSKDEBUG, "Expressiv training for user [%u] COMPLETED!\n", GetUserID()); 00725 PostMessage(HScol, EPOC_EXPRESSIV_TRAINING_COMPLETED_CB, (int)this, (LPARAM)NULL); 00726 00727 // Switch from Universal to Trained Signature if possible 00728 // NOTE: At least 2 trainings (NEUTRAL + another expression) are required to be able to use trained signature 00729 EE_ExpressivGetTrainedSignatureAvailable(GetUserID(), &signatureAvailable); 00730 if (signatureAvailable) 00731 EE_ExpressivSetSignatureType(GetUserID(), EXP_SIG_TRAINED); 00732 break; 00733 00734 // Training rejected 00735 case EE_ExpressivTrainingRejected: 00736 MMechostr(MSKDEBUG, "Expressiv training for user [%u] REJECTED!\n", GetUserID()); 00737 PostMessage(HScol, EPOC_EXPRESSIV_TRAINING_REJECTED_CB, (int)this, (LPARAM)NULL); 00738 break; 00739 00740 // Training erased 00741 case EE_ExpressivTrainingDataErased: 00742 MMechostr(MSKDEBUG, "Expressiv training for user [%u] ERASED!\n", GetUserID()); 00743 PostMessage(HScol, EPOC_EXPRESSIV_TRAINING_ERASED_CB, (int)this, (LPARAM)NULL); 00744 break; 00745 00746 // Not handled cases 00747 case EE_ExpressivTrainingReset: 00748 case EE_ExpressivNoEvent: 00749 default: 00750 break; 00751 } 00752 } 00753 00754 00755 bool Epoc::StartExpressivSuiteTraining(EE_ExpressivAlgo_t eExpression) 00756 { 00757 // Set Expressiv training action 00758 if (EE_ExpressivSetTrainingAction(GetUserID(), eExpression) == EDK_OK) 00759 { 00760 if (EE_ExpressivSetTrainingControl(GetUserID(), EXP_START) == EDK_OK) 00761 return true; 00762 } 00763 return false; 00764 } 00765 00766 00767 bool Epoc::EraseExpressivSuiteTraining(EE_ExpressivAlgo_t eExpression) 00768 { 00769 // Set Expressiv training action 00770 if (EE_ExpressivSetTrainingAction(GetUserID(), eExpression) == EDK_OK) 00771 { 00772 // Erase training for a specific expression 00773 if (EE_ExpressivGetTrainingAction(GetUserID(), &eExpression) == EDK_OK) 00774 { 00775 if (EE_ExpressivSetTrainingControl(GetUserID(), EXP_ERASE) == EDK_OK) 00776 return true; 00777 } 00778 } 00779 return false; 00780 } 00781 00782 00783 // Events related to "Cognitiv Suite" training 00784 void Epoc::HandleCognitivTrainingEvent(EmoStateHandle cognitivEvent) 00785 { 00786 unsigned int u_timeOut = 0; 00787 EE_CognitivEvent_t eventType = EE_CognitivEventGetType(cognitivEvent); 00788 00789 switch (eventType) 00790 { 00791 // Training started 00792 case EE_CognitivTrainingStarted: 00793 MMechostr(MSKDEBUG, "Cognitiv training for user [%u] STARTED!\n", GetUserID()); 00794 PostMessage(HScol, EPOC_COGNITIV_TRAINING_STARTED_CB, (int)this, (LPARAM)NULL); 00795 break; 00796 00797 // Training succeeded 00798 case EE_CognitivTrainingSucceeded: 00799 MMechostr(MSKDEBUG, "Cognitiv training for user [%u] SUCCEEDED!\n", GetUserID()); 00800 PostMessage(HScol, EPOC_COGNITIV_TRAINING_SUCCEEDED_CB, (int)this, (LPARAM)NULL); 00801 00802 // Update status 00803 bCognitivTrainingSucceeded = true; 00804 break; 00805 00806 // Training failed 00807 case EE_CognitivTrainingFailed: 00808 MMechostr(MSKDEBUG, "Cognitiv training for user [%u] FAILED!\n", GetUserID()); 00809 PostMessage(HScol, EPOC_COGNITIV_TRAINING_FAILED_CB, (int)this, (LPARAM)NULL); 00810 break; 00811 00812 // Training completed 00813 case EE_CognitivTrainingCompleted: 00814 MMechostr(MSKDEBUG, "Cognitiv training for user [%u] COMPLETED!\n", GetUserID()); 00815 PostMessage(HScol, EPOC_COGNITIV_TRAINING_COMPLETED_CB, (int)this, (LPARAM)NULL); 00816 break; 00817 00818 // Training erased 00819 case EE_CognitivTrainingDataErased: 00820 MMechostr(MSKDEBUG, "Cognitiv training for user [%u] ERASED!\n", GetUserID()); 00821 PostMessage(HScol, EPOC_COGNITIV_TRAINING_ERASED_CB, (int)this, (LPARAM)NULL); 00822 break; 00823 00824 // Training rejected 00825 case EE_CognitivTrainingRejected: 00826 MMechostr(MSKDEBUG, "Cognitiv training for user [%u] REJECTED!\n", GetUserID()); 00827 PostMessage(HScol, EPOC_COGNITIV_TRAINING_REJECTED_CB, (int)this, (LPARAM)NULL); 00828 break; 00829 00830 // Not handled cases 00831 case EE_CognitivTrainingReset: 00832 case EE_CognitivAutoSamplingNeutralCompleted: 00833 case EE_CognitivSignatureUpdated: 00834 case EE_CognitivNoEvent: 00835 default: 00836 break; 00837 } 00838 } 00839 00840 00841 bool Epoc::StartCognitivSuiteTraining(EE_CognitivAction_t eAction) 00842 { 00843 // Add current action to the list of Cognitiv active actions 00844 unsigned long uActiveActions = 0; 00845 uActiveActions |= eAction; 00846 EE_CognitivSetActiveActions(GetUserID(), uActiveActions); 00847 00848 // Set Cognitiv training action 00849 if (EE_CognitivSetTrainingAction(GetUserID(), eAction) == EDK_OK) 00850 { 00851 // Start training 00852 if (EE_CognitivSetTrainingControl(GetUserID(), COG_START) == EDK_OK) 00853 return true; 00854 } 00855 return false; 00856 } 00857 00858 00859 bool Epoc::EraseCognitivSuiteTraining(EE_CognitivAction_t eAction) 00860 { 00861 // Retrieve list of active actions 00862 EE_CognitivGetActiveActions(GetUserID(), &uActiveActions); 00863 00864 // Delete current action from the list of Cognitiv active actions 00865 uActiveActions &= (~eAction); 00866 00867 // Update list of active actions 00868 EE_CognitivSetActiveActions(GetUserID(), uActiveActions); 00869 00870 // Set Cognitiv training action 00871 if (EE_CognitivSetTrainingAction(GetUserID(), eAction) == EDK_OK) 00872 { 00873 // Erase training for a specific action 00874 if (EE_CognitivGetTrainingAction(GetUserID(), &eAction) == EDK_OK) 00875 { 00876 if (EE_CognitivSetTrainingControl(GetUserID(), COG_ERASE) == EDK_OK) 00877 return true; 00878 } 00879 } 00880 return false; 00881 } 00882 00883 00884 /*--------------------------------- USER PROFILES ---------------------------------*/ 00885 // Get user profile byte stream 00886 bool Epoc::ProfileToByteArray(EmoEngineEventHandle eProfile, unsigned char** profileBuffer, unsigned int* profileSize) 00887 { 00888 if (*profileBuffer) 00889 delete [] *profileBuffer, *profileBuffer = 0; 00890 00891 // Query the size of the profile byte stream 00892 bool ok = (EE_GetUserProfileSize(eProfile, profileSize) == EDK_OK); 00893 if (ok && *profileSize > 0) 00894 { 00895 // Copy the content of profile byte stream into local buffer 00896 *profileBuffer = new unsigned char[*profileSize]; 00897 ok = (EE_GetUserProfileBytes(eProfile, *profileBuffer, *profileSize) == EDK_OK); 00898 if (!ok) 00899 delete [] *profileBuffer, *profileBuffer = 0; 00900 } 00901 return ok; 00902 } 00903 00904 00905 // Load and Save profile (new methods) 00906 bool Epoc::LoadProfile(char *fileName) 00907 { 00908 // Create binary file for user profile 00909 if (!fileCreated) 00910 { 00911 userProfile = new Profile(fileName); 00912 fileCreated = true; 00913 } 00914 00915 // Get binary data from file 00916 if (userProfile->ReadBinaryData()) { 00917 // Assign it to current user 00918 if (EE_SetUserProfile(GetUserID(), (unsigned char*)userProfile->GetFileData(), (unsigned int)userProfile->GetFileLength()) == EDK_OK) { 00919 MMechostr(MSKDEBUG, ">>> User profile [%s] loaded...\n", fileName); 00920 return true; 00921 } 00922 else { 00923 MMechostr(MSKDEBUG, ">>> Error when loading user profile [%s] !\n", fileName); 00924 return false; 00925 } 00926 } 00927 return false; 00928 } 00929 00930 void Epoc::SaveProfile(char* fileName) 00931 { 00932 EmoEngineEventHandle eProfileTemp = EE_ProfileEventCreate(); 00933 if (EE_GetUserProfile(GetUserID(), eProfile) == EDK_OK) 00934 { 00935 if (ProfileToByteArray(eProfile, &profileBuffer, &profileSize)) 00936 { 00937 // Write data twice : first for training data, second for missing data bytes (which are written at the end of the application when using API methods) 00938 MMechostr(MSKDEBUG, ">>> Profile size = %u\n", profileSize); 00939 userProfile->WriteBinaryData((char*)profileBuffer, profileSize); 00940 userProfile->WriteBinaryData((char*)profileBuffer, profileSize); 00941 00942 if (profileBuffer) 00943 delete [] profileBuffer, profileBuffer = 0; 00944 } 00945 else 00946 MMechostr(MSKDEBUG, ">>> Couldn't get profile byte array...\n"); 00947 } 00948 EE_EmoEngineEventFree(eProfileTemp); 00949 } 00950 00951 00952 /*-------------------------------------- GYRO -------------------------------------*/ 00953 bool Epoc::UpdateGyroPosition() 00954 { 00955 int gx = 0, gy = 0; 00956 if (EE_HeadsetGetGyroDelta(GetUserID(), &gx, &gy) == EDK_OK) 00957 { 00958 EE_HeadsetGyroRezero(GetUserID()); 00959 00960 // Update current position on the screen 00961 xCurrentPos += (float)SCALE_FACTOR * (float)gx; 00962 yCurrentPos += (float)SCALE_FACTOR * (float)gy; 00963 00964 // Check limit thresholds 00965 // X axis 00966 if (xCurrentPos >= xMaxPos) 00967 xCurrentPos = xMaxPos; 00968 else if (xCurrentPos <= xMinPos) 00969 xCurrentPos = xMinPos; 00970 00971 // Y axis 00972 if (yCurrentPos >= yMaxPos) 00973 yCurrentPos = yMaxPos; 00974 else if (yCurrentPos <= yMinPos) 00975 yCurrentPos = yMinPos; 00976 00977 // Scale values between 0 and 1 00978 SetGyroX(xCurrentPos / xMaxPos); 00979 SetGyroY(yCurrentPos / yMaxPos); 00980 return true; 00981 } 00982 return false; 00983 } 00984 00985 00986 /*-------------------------------- THREAD HANDLING --------------------------------*/ 00987 void Epoc::run() 00988 { 00989 try 00990 { 00991 while (bIsRunning) 00992 { 00993 // If connection has been established with EmoEngine 00994 if (bStatus) 00995 { 00996 // Parse data received from EmoEngine 00997 ReadData(); 00998 00999 // Accept / reject expressiv training 01000 if (bExpressivTrainingSucceeded) 01001 { 01002 EE_ExpressivSetTrainingControl(GetUserID(), EXP_ACCEPT); // EXP_ACCEPT to accept training, EXP_REJECT to reject 01003 //EE_ExpressivSetTrainingControl(GetUserID(), EXP_REJECT); 01004 bExpressivTrainingSucceeded = false; 01005 } 01006 01007 // Accept / reject cognitiv Training 01008 if (bCognitivTrainingSucceeded) 01009 { 01010 EE_CognitivSetTrainingControl(GetUserID(), COG_ACCEPT); // COG_ACCEPT to accept training, COG_REJECT to reject 01011 //EE_CognitivSetTrainingControl(GetUserID(), COG_REJECT); 01012 bCognitivTrainingSucceeded = false; 01013 } 01014 01015 // New position from gyro (if headset connected and delta position are greater than 0) 01016 if (bNewData && GetHeadsetStatus()) 01017 { 01018 UpdateGyroPosition(); 01019 bNewData = false; 01020 } 01021 01022 // Load profile 01023 if (!GetProfileLoadingDone()) 01024 { 01025 LoadProfile(GetUserProfileFileName()); 01026 SetProfileLoadingDone(true); 01027 } 01028 01029 // Save profile 01030 if (!GetProfileSavingDone()) 01031 { 01032 SaveProfile(GetUserProfileFileName()); 01033 SetProfileSavingDone(true); 01034 } 01035 } 01036 01037 // Sleep thread during 1ms to wait for the next data acquisition 01038 this->sleep(1); 01039 } 01040 01041 // Release connection to EmoEngine 01042 Disconnect(); 01043 } 01044 catch (ThreadException ex) 01045 { 01046 MMechostr(MSKDEBUG, "error thread : %s\n", ex.getMessage().c_str()); 01047 } 01048 }
1.7.3