This is example 19. This example demonstrates the following:
-
Processing online eye samples
This example is based on
example 10. This example adds an
onEyeData() event handler function to print eye sample events.
Source code
Source file: example19.c
Initialization
In the eyevec_create_thread() function in the initialization part we provide
an eye sample event callback function.
int main(void)
{
.
.
EyeVecResult err = eyevec_create_thread(eyevec,
onModeChange,
NULL, // onDisplayData,
onEyeData, (1)
NULL, // onBlinkEvent,
NULL, // onSaccadeEvent,
NULL, // onFixationEvent,
NULL, // onTestItemEvent,
&clientdata);
printError("eyevec_create_thread()", err);
if (err) return EXIT_FAILURE;
.
.
| 1 | Callback function for eye sample events. |
processInput()
The following single character commands are implemented here:
q: quit
o: open/close device
u: show/hide control window
x: toggle show gui on setup mode
X: toggle show gui on data mode
i: enter idle mode
s: enter setup mode
z: enter data mode
r: start/stop recording
m: toggle show mode-change events
e: toggle eye sample events
When you press e then eyevec_set_eye_data_enabled() will be called
to toggle (enable or disable) sending eye sample events. The default is
not sending them.
static int processInput(EyeVec* eyevec, ClientData* clientdata, int ch)
{
.
.
.
else if (ch == 'e') {
uint32_t enabled = eyevec_get_eye_data_enabled(eyevec); (1)
if ((enabled & EYEVEC_SEND_IN_RECORDING_MODE) != 0) {
err = eyevec_set_eye_data_enabled(eyevec,
EYEVEC_SEND_IN_RECORDING_MODE, 0); (2)
printError("eyevec_set_eye_data_enabled(0x1, 0)", err);
}
else {
err = eyevec_set_eye_data_enabled(eyevec,
0, EYEVEC_SEND_IN_RECORDING_MODE); (3)
printError("eyevec_set_eye_data_enabled(0, 0x1)", err);
}
}
.
.
.
}
| 1 | Check if eye sample events are currently enabled. |
| 2 | Disable sending eye sample events. |
| 3 | Enable sending eye sample events. |
If for some reason you need to receive eye sample events not only when in
recording mode, but also when in drift-check mode, then call
eyevec_set_eye_data_enabled()
with the EYEVEC_SEND_IN_DRIFT_CHECK_MODE flag set.
To try this add the following to processInput():
else if (ch == 'E') {
uint32_t enabled = eyevec_get_eye_data_enabled(eyevec);
if ((enabled & EYEVEC_SEND_IN_DRIFT_CHECK_MODE) != 0) {
err = eyevec_set_eye_data_enabled(eyevec,
EYEVEC_SEND_IN_DRIFT_CHECK_MODE, 0);
printError("eyevec_set_eye_data_enabled(0x2, 0)", err);
}
else {
err = eyevec_set_eye_data_enabled(eyevec,
0, EYEVEC_SEND_IN_DRIFT_CHECK_MODE);
printError("eyevec_set_eye_data_enabled(0, 0x2)", err);
}
}
If instead you simply want to receive eye data events when in data mode or
above, so all green circles in the the
state diagram,
then in the above code use the EYEVEC_SEND_IN_DATA_MODE flag
instead.
onEyeData()
This function prints all EyeVecEyeSampleEventData attributes defined for the eye sample event.
static int onEyeData(const EyeVec* eyevec, int64_t eventtime,
const EyeVecEyeSampleEventData* eyedata, void* cldata)
{
(void)eyevec;
const ClientData* clientdata = (const ClientData*)cldata;
if (clientdata == NULL) return 0;
printf("onEyeData:\n");
printf(" eventtime: %" PRId64 "\n",
eventtime);
if ((eyedata->side & 1) != 0 && (1)
eyedata->eye[0].pupil.status != EYEVEC_EYE_STATUS_SKIPPED) { (1)
// Right eye data present.
printf(" right:\n");
printEye(&eyedata->eye[0]); (2)
}
if ((eyedata->side & 2) != 0 && (3)
eyedata->eye[1].pupil.status != EYEVEC_EYE_STATUS_SKIPPED) { (3)
// Left eye data present.
printf(" left:\n");
printEye(&eyedata->eye[1]); (4)
}
// return -1; // -1 means disable sending eye sample events
return 0; // 0 means keep going
}
| 1 | Check if right eye data present in eyedata. |
| 2 | Print right eye data. Print functions omitted for brevity. See source file. |
| 3 | Check if left eye data present in eyedata. |
| 4 | Print left eye data. |
Running
After a succesful build run the program:
-
Press
oto calleyevec_open(). Eye-tracker should go from off mode to idle mode. -
Press
zto calleyevec_enter_data_mode(). Eye-tracker should go from idle mode to data mode. Note, we’re skipping setup and calibration here; still make sure the eye-tracker can see your eyes. -
Press
eto calleyevec_set_eye_data_events_enabled(0, EYEVEC_SEND_IN_RECORDING_MODE). This enables the sending of eye sample events. -
Press
rto calleyevec_start_recording(). Eye-tracker should go from data mode to recording mode. Eye sample events should be printed. -
Press
rto calleyevec_stop_recording(). Eye-tracker should go from recording mode to data mode. No more eye sample events will be printed. -
Press
qto quit.
Output might look like this (empty lines added for clarity):
eyevec_create_thread(): OK
eyevec_initialize(): OK
Type q to quit, ? for help.
[o]
onModeChange:
eventtime: 1750701837312353
oldmode: TRACKER_MODE_OFF
newmode: TRACKER_MODE_IDLE
eyevec_open(): OK
[z]
onModeChange:
eventtime: 1750701839782163
oldmode: TRACKER_MODE_IDLE
newmode: TRACKER_MODE_DATA
eyevec_enter_data_mode(): OK
[e]
eyevec_set_eye_data_enabled(0, 0x1): OK
[r]
onModeChange:
eventtime: 1750701877149733
oldmode: TRACKER_MODE_DATA
newmode: TRACKER_MODE_RECORDING
eyevec_start_recording(): OK
onEyeData:
eventtime: 1750701877149496
right:
pupil.status: 1
pupil.position: 1212.227, 1187.328
pupil.position_raw: 1212.287, 1187.392
pupil.area: 864.613
pupil.visibility: 1.045
pupil.ellipse: 17.864, 17.017, 0.347
cr.status: 1
cr.position: 1212.684, 1194.926
cr.position_raw: 1212.729, 1194.999
cr.area: 42.847
gaze.status: 1
gaze.position: 0.289, 0.738
gaze.position_raw: 0.289, 0.737
gaze.position_avg: 0.000, 0.000
gaze.velocity: 1000.000, 0.000
state: 4
pxpermm: 7.936
left:
pupil.status: 1
pupil.position: 1683.379, 1204.849
pupil.position_raw: 1683.411, 1204.925
pupil.area: 983.516
pupil.visibility: 1.038
pupil.ellipse: 18.594, 18.161, 0.013
cr.status: 1
cr.position: 1678.714, 1210.330
cr.position_raw: 1678.723, 1210.412
cr.area: 35.693
gaze.status: 1
gaze.position: 0.306, 0.713
gaze.position_raw: 0.305, 0.713
gaze.position_avg: 0.000, 0.000
gaze.velocity: 1000.000, 0.000
state: 4
pxpermm: 7.936
onEyeData:
eventtime: 1750701877151497
right:
pupil.status: 1
pupil.position: 1212.187, 1187.354
pupil.position_raw: 1212.214, 1187.442
pupil.area: 867.258
pupil.visibility: 1.048
pupil.ellipse: 17.825, 17.013, 0.354
cr.status: 1
cr.position: 1212.653, 1194.948
cr.position_raw: 1212.709, 1195.016
cr.area: 42.630
gaze.status: 1
gaze.position: 0.289, 0.738
gaze.position_raw: 0.291, 0.739
gaze.position_avg: 0.000, 0.000
gaze.velocity: 1000.000, 0.000
state: 4
pxpermm: 7.936
left:
pupil.status: 1
pupil.position: 1683.342, 1204.824
pupil.position_raw: 1683.378, 1204.889
pupil.area: 976.250
pupil.visibility: 1.031
pupil.ellipse: 18.567, 18.189, -0.014
cr.status: 1
cr.position: 1678.671, 1210.304
cr.position_raw: 1678.704, 1210.396
cr.area: 35.696
gaze.status: 1
gaze.position: 0.306, 0.713
gaze.position_raw: 0.306, 0.712
gaze.position_avg: 0.000, 0.000
gaze.velocity: 1000.000, 0.000
state: 4
pxpermm: 7.936
.
.
.
[q]
eyevec_cleanup(): OK
eyevec_destroy_thread(): OK