This is example 19. This example demonstrates the following:

  1. 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:

  1. Press o to call eyevec_open(). Eye-tracker should go from off mode to idle mode.

  2. Press z to call eyevec_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.

  3. Press e to call eyevec_set_eye_data_events_enabled(0, EYEVEC_ENABLE_SEND_WHILE_IN_RECORDING_MODE). This enables the sending of eye sample events.

  4. Press r to call eyevec_start_recording(). Eye-tracker should go from data mode to recording mode. Eye sample events should be printed.

  5. Press r to call eyevec_stop_recording(). Eye-tracker should go from recording mode to data mode. No more eye sample events will be printed.

  6. 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