Emotiv EPOC plugin 1.0

D:/SVN/Scol/trunk/plugins/Epoc/src/Epoc.cpp

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 }