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_ENABLE_SEND_WHILE_IN_RECORDING_MODE) != 0) {
err = eyevec_set_eye_data_enabled(eyevec,
EYEVEC_ENABLE_SEND_WHILE_IN_RECORDING_MODE, 0); (2)
printError("eyevec_set_eye_data_enabled(0x1, 0)", err);
}
else {
err = eyevec_set_eye_data_enabled(eyevec,
0, EYEVEC_ENABLE_SEND_WHILE_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 data mode and drift-check mode (the green circles in the eye-tracker mode state diagram), then call eyevec_set_eye_data_enabled().
To try this add the following to processInput()
:
else if (ch == 'E') {
uint32_t enabled = eyevec_get_eye_data_enabled(eyevec);
if ((enabled & EYEVEC_ENABLE_SEND_WHILE_IN_DATA_MODE) != 0) {
err = eyevec_set_eye_data_enabled(eyevec,
EYEVEC_ENABLE_SEND_WHILE_IN_DATA_MODE, 0);
printError("eyevec_set_eye_data_enabled(0x2, 0)", err);
}
else {
err = eyevec_set_eye_data_enabled(eyevec,
0, EYEVEC_ENABLE_SEND_WHILE_IN_DATA_MODE);
printError("eyevec_set_eye_data_enabled(0, 0x2)", err);
}
}
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
o
to calleyevec_open()
. Eye-tracker should go from off mode to idle mode. -
Press
z
to 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
e
to calleyevec_set_eye_data_events_enabled(0, EYEVEC_ENABLE_SEND_WHILE_IN_RECORDING_MODE)
. This enables the sending of eye sample events. -
Press
r
to calleyevec_start_recording()
. Eye-tracker should go from data mode to recording mode. Eye sample events should be printed. -
Press
r
to calleyevec_stop_recording()
. Eye-tracker should go from recording mode to data mode. No more eye sample events will be printed. -
Press
q
to 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