libctru  v2.4.1
qtm.h
Go to the documentation of this file.
1 /**
2  * @file qtm.h
3  * @brief QTM services.
4  *
5  * QTM is responsible for the following:
6  * - tracking and predicting the position of the user's eyes. This is done by using the inner
7  * camera sampling at 320x240px at 30 FPS, and by using the gyroscope to predict the position
8  * of the eyes between two camera samples (effectively doubling the tracking rate).
9  * The API reporting eye tracking data is actually *console-agnostic*. This concept is most
10  * likely covered by patent US9098112B2
11  * - automatically managing the IR LED emitter used for eye tracking in low-light conditions
12  * - managing the state of the parallax barrier by controlling the positions of the barrier's
13  * mask (opaque/transparent state by repeating pattern of 12 units, plus polarity). This is
14  * done via a TI TCA6416A I2C->Parallel expander (highlighted in yellow in this teardown photo:
15  * https://guide-images.cdn.ifixit.com/igi/IKlW6WTZKKmapYkt.full, with the expected 12 traces
16  * being clearly visible near the ribbon cable slot)
17  * - updating the barrier position according to eye tracking data relative to an optimal setting
18  * stored in calibration data: this is what Nintendo calls "Super Stable 3D" (SS3D); not done
19  * when in 2D mode
20  *
21  * Head-tracking can be used even if SS3D is disabled.
22  *
23  * SS3D works as follows:
24  * - compute the raw X and Y pixel coordinates for the eye midpoint:
25  * `rawX = (leftEyeRawPxCoords.x + rightEyeRawPxCoords.x) / 2`
26  * `rawY = (leftEyeRawPxCoords.y + rightEyeRawPxCoords.y) / 2`
27  * - rotate the value around the optical Z-axis using the optimal eye-to-camera angle from
28  * calibration data, with a rotation matrix
29  * - normalize the X value:
30  * `xC = (rawX / 320) - 0.5`
31  * - transform into world space coordinate, using fovX from calibration (convert to radians first).
32  * Note that this fovX doesn't take lens distortion into account and is slightly different from
33  * the hardcoded angle used in \ref QTMU_GetTrackingData
34  * `x = xC * tan(fovX/2)`
35  * - multiply by length of adjacent side (eye-to-camera distance) to get the length of the opposite
36  * side. This is the eye horizontal deviation to camera lens in mm, which is then converted to
37  * number of iod/12 units:
38  * `delta = x * optimalDistance / (iod/12)`
39  * - we then obtain the new target position of the parallax barrier (expressed in iod/12 units,
40  * mod iod/12):
41  * `pos = centerPos + delta`
42  * - the value is then rounded to nearest integer. To avoid artifacts, if the rounded value is
43  * going to increase, then 0.01 is subtracted, and if it is going to decrease, then 0.01 is added.
44  * The value is rounded again to compute the final discrete value written to the expander (barrier
45  * position).
46  * - note: all calculation in QTM and otherwise assume interocular distance to be 62mm (the average).
47  * Assumedly, if the user's IOD is different, then "optimal distance to screen" effectively changes
48  * for that user.
49  *
50  * QTM services are not present on O3DS, thus caller must call \ref qtmCheckServicesRegistered to check
51  * if the services are registered. Moreover, since QTM functionality might not always be available (due
52  * to blacklist or console being N2DSXL), `qtm:u` users should check Result return values, and `qtm:s`
53  * users can call \ref QTMS_SetQtmStatus to check the actual availability status.
54  *
55  * Considering that the eye tracking data reporting API is hardware-agnostic, it is advisable to
56  * hardcode neither camera aspect ratio (even if it is 4/3 on real hardware) and resolution nor
57  * field-of-view angle.
58  *
59  * There is a separate QTM service, `qtm:c` ("hardware check"), that lets you manipulate parallax barrier
60  * pattern directly. It is covered in \ref qtmc.h instead.
61  */
62 #pragma once
63 
64 #include <3ds/types.h>
65 
66 /// ID of QTM status data (fully enabled/SS3D disabled) in `cfg`
67 #define QTM_STATUS_CFG_BLK_ID 0x180000u
68 
69 /// ID of QTM calibration data in `cfg`
70 #define QTM_CAL_CFG_BLK_ID 0x180001u
71 
72 /**
73  * @brief QTM enablement status (when cameras not in use by user), set by `qtm:s`.
74  * @note Manual IR LED control, camera lux, and `qtm:c` commands remain available
75  * for use on N3DS and N3DSXL regardless.
76  */
77 typedef enum QtmStatus {
78  QTM_STATUS_ENABLED = 0, ///< QTM is fully enabled.
79  QTM_STATUS_SS3D_DISABLED = 1, ///< QTM "super stable 3D" feature is disabled. Parallax barrier hardware state is configured to match O3DS.
80 
81  /**
82  * @brief QTM is unavailable: either "blacklisted" (usually by NS) for the current title, **or console is a N2DSXL**.
83  *
84  * In this state, all QTM functionality is disabled. This includes "super-stable 3D"
85  * (ie. auto barrier adjustment) including `qtm:s` manual barrier position setting functions,
86  * head tracking, IR LED control and camera luminance reporting (400.0 is returned instead).
87  *
88  * @note `qtm:c` barrier hardware state setting function (\ref blah) bypasses this state.
89  * @note Due to an oversight, \ref QTMS_SetQtmStatus allows changing QTM state on N2DSXL. This is not intended
90  * to be done, and is in fact never done by official software.
91  */
93 } QtmStatus;
94 
95 /// QTM status data (fully enabled/SS3D disabled) in `cfg`. Usually all-zero on N2DSXL.
96 typedef struct QtmStatusCfgData {
97  QtmStatus defaultStats; ///< QTM status at boot (fully enabled or SS3D disabled).
98  /**
99  * @brief "Global variable" (.data) section load mode? Unused.
100  * From CTRAging:
101  * - 0: "normal"
102  * - 1: "single reacq"
103  * - 2: "double reacq"
104  - 3/4/5: "w2w copy 1/10/100"
105  */
107  u8 _padding[2]; ///< Padding.
109 
110 /// QTM calibration data (fully enabled/SS3D disabled) in `cfg`. Usually all-zero on N2DSXL.
111 typedef struct QtmCalibrationData {
112  /**
113  * @brief Neutral (center) barrier position/offset (with slit width of 6 units), when the user is
114  * facing directly facing the camera, that is to say, their eye midpoint normalized X coord
115  * in the camera's plane is 0, assuming the user's head is located at the expected viewing distance
116  * and at the expected eye-to-camera angle (as per the rest of this structure).
117  * This is expressed in terms of iod/12 units modulo iod/12 (thus, range is 0 to 11 included),
118  * with IOD (interocular distance) assumed to be 62mm.
119  * @note This field is floating-point for QTM auto-adjustment purposes, however the actual barrier
120  * position in hardware is an integer.
121  * @note This is the field that System Settings lets you add -1.0 to +1.0 to.
122  * @note Moreover, this field can be directly changed through \ref QTMS_SetCenterBarrierPosition.
123  */
125 
126  float translationX; ///< Lens X coord in inner camera space? Very low value and seems to be unused.
127  float translationY; ///< Lens Y coord in inner camera space? Very low value and seems to be unused.
128  float rotationZ; ///< Optimal eye-to-camera angle, in radians, without accounting for lens distortion.
129  float fovX; ///< Camera's horizontal FoV in degrees, without accounting for lens distortion.
130  float viewingDistance; ///< Optimal viewing distance between user and top screen, assuming iod to be 62mm.
132 
133 /// Left eye or right eye, for \ref QtmTrackingData and \ref QtmRawTrackingData
134 typedef enum QtmEyeSide {
135  QTM_EYE_LEFT = 0, ///< Left eye.
136  QTM_EYE_RIGHT = 1, ///< Right eye.
137 
138  QTM_EYE_NUM, ///< Number of eyes.
139 } QtmEyeSide;
140 
141 /// QTM raw eye tracking data
142 typedef struct QtmRawTrackingData {
143  /**
144  * @brief Eye position detected or predicted, equals (confidenceLevel > 0).
145  * If false, QTM will attempt to make a guess based on gyro data.
146  * If the console isn't moving either, then QTM will assume the user's eyes are progressively
147  * moving back to face the screen.
148  */
149  bool eyesTracked; ///< Eye position detected or predicted, equals (confidenceLevel > 0).
150  u8 _padding[3]; ///< Padding.
151  u32 singletonQtmPtr; ///< Pointer to eye-tracking singleton pointer, in QTM's .bss, located in N3DS extra memory.
152  float confidenceLevel; ///< Eye tracking confidence level (0 to 1).
153 
154  /**
155  * @brief Raw predicted or detected eye coordinates. Each eye is represented as one point.
156  * Fractional part is *not* necessarily zero.
157  * @note X coord is within 0 to 320.
158  * @note Y coord is within 0 to 240.
159  */
161 
162  float dPitch; ///< Difference in gyro pitch from position at console boot.
163  float dYaw; ///< Difference in gyro yaw from position at console boot.
164  float dRoll; ///< Difference in gyro roll from position at console boot.
165 
166  s64 samplingTick; ///< Time point the current measurements were made.
168 
169 /// QTM processed eye tracking data, suitable for 3D programming
170 typedef struct QtmTrackingData {
171  bool eyesTracked; ///< Eye position detected or tracked with some confidence, equals (confidenceLevel > 0). Even if false, QTM may make a guess
172  bool faceDetected; ///< Whether or not the entirety of the user's face has been detected with good confidence.
173  bool eyesDetected; ///< Whether or not the user's eyes have actually been detected with full confidence.
174  u8 _unused; ///< Unused.
175  bool clamped; ///< Whether or not the normalized eye coordinates have been clamped after accounting for lens distortion.
176  u8 _padding[3]; ///< Padding.
177 
178  float confidenceLevel; ///< Eye tracking confidence level (0 to 1).
179 
180  /**
181  * @brief Normalized eye coordinates, for each eye, after accounting for lens distortion, centered around camera.
182  * X coord is in the -1 to 1 range, and Y coord range depends on inverse aspect ratio (-0.75 to 0.75 on real hardware).
183  * @note On real hardware, X coord equals `((rawX / 160.0) - 1.00) * 1.0639` before clamping.
184  * @note On real hardware, Y coord equals `((rawY / 160.0) - 0.75) * 1.0637` before clamping.
185  */
187 
188  /**
189  * @brief Normalized eye coordinates, for each eye, in world space.
190  * Corresponds to \ref eyeCameraCoordinates multiplied by tangent of field of view.
191  * @note On real hardware, X coord equals `eyeCameraCoordinates.x * tan(64.9 deg / 2)`.
192  * @note On real hardware, Y coord equals `eyeCameraCoordinates.x * tan(51.0 deg / 2)`.
193  */
195 
196  float dPitch; ///< Difference in gyro pitch from position at console boot.
197  float dYaw; ///< Difference in gyro yaw from position at console boot.
198  float dRoll; ///< Difference in gyro roll from position at console boot.
199 
200 
201  s64 samplingTick; ///< Time point the current measurements were made.
203 
204 /// QTM service name enum, excluding `qtm:c`
205 typedef enum QtmServiceName {
206  /**
207  * @brief `qtm:u`: has eye-tracking commands and IR LED control commands, but for some
208  * reason cannot fetch ambiant lux data from the camera's luminosity sensor.
209  */
211 
212  /**
213  * @brief `qtm:s`: has access to all `qtm:u` commands, plus luminosity sensor, plus
214  * manual barrier position setting and calibration adjustment commands.
215  * Automatic barrier control is reenabled on session exit.
216  */
218 
219  /**
220  * @brief `qtm:sp`: has access to all `qtm:s` (and `qtm:u`) commands, and merely has a
221  * few more commands that GSP uses to notify QTM of 2D<>3D mode switches and
222  * power events. Automatic barrier control is reenabled on session exit.
223  * GSP always keeps a `qtm:sp` sessions open (at least on latest system version),
224  * whereas NS opens then immediately closes a `qtm:sp` sessions only when dealing
225  * with a "blacklisted" application (that is, almost never).
226  */
229 
230 /**
231  * @brief Check whether or not QTM services are registered.
232  * @return True on O3DS systems, false on N3DS systems.
233  */
235 
236 /**
237  * @brief Initializes QTM (except `qtm:c`).
238  * Excluding `qtm:c`, QTM has three main services.
239  * Only 3 sessions (2 until 9.3.0 sysupdate) for ALL services COMBINED, including `qtm:c`,
240  * can be open at a time.
241  * Refer to \ref QtmServiceName enum value descriptions to see which service to choose.
242  *
243  * @param serviceName QTM service name enum value (corresponding to `qtm:u`, `qtm:s` and `qtm:sp`
244  * respectively).
245  * @note Result of \ref qtmCheckServicesRegistered should be checked before calling this function.
246  */
248 
249 /// Exits QTM.
250 void qtmExit(void);
251 
252 /// Checks whether or not a `qtm:u`, `qtm:s` or `qtm:sp` session is active.
253 bool qtmIsInitialized(void);
254 
255 /// Returns a pointer to the current `qtm:u` / `qtm:s` / `qtm:sp` session handle.
257 
258 /**
259  * @brief Gets the current raw eye tracking data, with an optional prediction made for predictionTimePointOrZero = t+dt,
260  * or for the current time point (QTM makes predictions based on gyro data since inner camera runs at 30 FPS).
261  *
262  * @param[out] outData Where to write the raw tracking data to. Cleared to all-zero on failure (instead of being left uninitialized).
263  * @param predictionTimePointOrZero Either zero, or the time point (in system ticks) for which to make a prediction for.
264  * Maximum 1 frame (at 30 FPS) in the past, and up to 5 frames in the future.
265  * @return `0xC8A18008` if camera is in use by user, or `0xC8A183EF` if QTM is unavailable (in particular, QTM is always
266  * unavailable on N2DSXL), Otherwise, 0 (success). Return value should be checked by caller.
267  * @note Consider using \ref QTMU_GetTrackingDataEx instead.
268  */
269 Result QTMU_GetRawTrackingDataEx(QtmRawTrackingData *outData, s64 predictionTimePointOrZero);
270 
271 /**
272  * @brief Gets the current raw eye tracking data.
273  *
274  * @param[out] outData Where to write the raw tracking data to. Cleared to all-zero on failure (instead of being left uninitialized).
275  * @return `0xC8A18008` if camera is in use by user, or `0xC8A183EF` if QTM is unavailable (in particular, QTM is always
276  * unavailable on N2DSXL), Otherwise, 0 (success). Return value should be checked by caller.
277  * @note Consider using \ref QTMU_GetTrackingData instead.
278  */
280 {
281  return QTMU_GetRawTrackingDataEx(outData, 0LL);
282 }
283 
284 /**
285  * @brief Gets the current normalized eye tracking data, made suitable for 3D programming with an optional prediction made
286  * for predictionTimePointOrZero = t+dt, or for the current time point (QTM makes predictions based on gyro data since
287  * inner camera runs at 30 FPS).
288  *
289  * @param[out] outData Where to write the raw tracking data to. Cleared to all-zero on failure (instead of being left uninitialized).
290  * @param predictionTimePointOrZero Either zero, or the time point (in system ticks) for which to make a prediction for.
291  * Maximum 1 frame (at 30 FPS) in the past, and up to 5 frames in the future.
292  * @return `0xC8A18008` if camera is in use by user, or `0xC8A183EF` if QTM is unavailable (in particular, QTM is always
293  * unavailable on N2DSXL). Otherwise, 0 (success). Return value should be checked by caller.
294  * @note This can, for example, be used in games to allow the user to control the scene's camera with their own face.
295  */
296 Result QTMU_GetTrackingDataEx(QtmTrackingData *outData, s64 predictionTimePointOrZero);
297 
298 /**
299  * @brief Gets the current normalized eye tracking data, made suitable for 3D programming.
300  *
301  * @param[out] outData Where to write the raw tracking data to. Cleared to all-zero on failure (instead of being left uninitialized).
302  * @return `0xC8A18008` if camera is in use by user, or `0xC8A183EF` if QTM is unavailable (in particular, QTM is always
303  * unavailable on N2DSXL). Otherwise, 0 (success). Return value should be checked by caller.
304  * @note This can, for example, be used in games to allow the user to control the scene's camera with their own face.
305  */
307 {
308  return QTMU_GetTrackingDataEx(outData, 0LL);
309 }
310 
311 /**
312  * @brief Computes an approximation of the horizontal angular field of view of the camera based on eye tracking data.
313  *
314  * @param data Eye tracking data, obtained from \ref QTMU_GetTrackingData or \ref QTMU_GetTrackingDataEx.
315  * @return Horizontal angular field of view in radians. Corresponds to 64.9 degrees on real hardware.
316  */
317 float qtmComputeFovX(const QtmTrackingData *data);
318 
319 /**
320  * @brief Computes an approximation of the vertical angular field of view of the camera based on eye tracking data.
321  *
322  * @param data Eye tracking data, obtained from \ref QTMU_GetTrackingData or \ref QTMU_GetTrackingDataEx.
323  * @return Vertical angular field of view in radians. Corresponds to 51.0 degrees on real hardware.
324  */
325 float qtmComputeFovY(const QtmTrackingData *data);
326 
327 /**
328  * @brief Computes a rough approximation of the inverse of the aspect ration of the camera based on eye tracking data.
329  *
330  * @param data Eye tracking data, obtained from \ref QTMU_GetTrackingData or \ref QTMU_GetTrackingDataEx.
331  * @return Rough approximation of the inverse of the aspect ratio of the camera. Aspect ratio is exactly 0.75 on real hardware.
332  */
334 
335 /**
336  * @brief Computes the user's head tilt angle, that is, the angle between the line through both eyes and the camera's
337  * horizontal axis in camera space.
338  *
339  * @param data Eye tracking data, obtained from \ref QTMU_GetTrackingData or \ref QTMU_GetTrackingDataEx.
340  * @return Horizontal head angle relative to camera, in radians.
341  */
343 
344 /**
345  * @brief Estimates the distance between the user's eyes and the camera, based on
346  * eye tracking data. This may be a little bit inaccurate, as this assumes
347  * interocular distance of 62mm (like all 3DS software does), and that both
348  * eyes are at the same distance from the screen.
349  *
350  * @param data Eye tracking data, obtained from \ref QTMU_GetTrackingData or \ref QTMU_GetTrackingDataEx.
351  * @return Eye-to-camera distance in millimeters.
352  */
354 
355 /**
356  * @brief Temporarily enables manual control of the IR LED by user, disabling its automatic control.
357  * If not already done, this also turns off the IR LED. This setting is cleared when user closes the console's shell.
358  * @return Always 0 (success).
359  */
361 
362 /**
363  * @brief Temporarily disables manual control of the IR LED by user, re-enabling its automatic control.
364  * If not already done, this also turns off the IR LED.
365  * @return Always 0 (success).
366  */
368 
369 /**
370  * @brief Turns the IR LED on or off during manual control. \ref QTMU_EnableManualIrLedControl must have been called.
371  *
372  * @param on Whether to turn the IR LED on or off.
373  * @return `0xC8A18005` if manual control was not enabled or if the operation failed, `0xC8A18008` if camera is in use
374  * by user, or `0xC8A18009` if QTM is unavailable (in particular, QTM is always unavailable on N2DSXL).
375  * Otherwise, 0 (success).
376  */
378 
379 /**
380  * @brief Attempts to clear IR LED overrides from any of the relevant commands in `qtm:u`, `qtm:s` (and `qtm:c`) commands
381  * by calling \ref QTMU_EnableManualIrLedControl followed by \ref QTMU_DisableManualIrLedControl, so that auto IR LED
382  * management takes place again.
383  * @return The value returned by \ref QTMU_DisableManualIrLedControl.
384  */
386 
387 /**
388  * @brief Checks whether or not QTM has been blacklisted, ie. that it has been made unavailable.
389  * In detail, this means that the last call to \ref QTMS_SetQtmStatus was made with argument \ref QTM_STATUS_UNAVAILABLE,
390  * usually by NS. This feature seems to only be used for some internal test titles.
391  *
392  * @param[out] outBlacklisted Whether or not QTM is unavailable. Always true on N2DSXL.
393  * @return Always 0 (success).
394  * @note On N2DSXL, even though status is always supposed to be \ref QTM_STATUS_UNAVAILABLE, this function often returns true
395  * (because NS doesn't change QTM's status if title isn't blacklisted). Do not rely on this for N2DSXL detection.
396  * @note Refer to https://www.3dbrew.org/wiki/NS_CFA for a list of title UIDs this is used for.
397  */
398 Result QTMU_IsCurrentAppBlacklisted(bool *outBlacklisted);
399 
400 /**
401  * @brief Sets the neutral (center) barrier position/offset in calibration, _without_ saving it to `cfg`.
402  * Takes effect immediately. SS3D works by calculating the position of the eye midpoint, rotated
403  * by the ideal eye-to-camera angle, expressed in (iod/12 units, iod assumed to be 62mm).
404  *
405  * @param position Center barrier position, in terms of iod/12 units modulo iod/12.
406  * @note This field is floating-point for QTM auto-adjustment purposes, however the actual barrier position
407  * in hardware is an integer.
408  * @note This is the field that System Settings lets you add -1.0 to +1.0 to.
409  * @note There is no "get" counterpart for this.
410  * @return `0xC8A18009` if QTM is unavailable (in particular, QTM is always unavailable on N2DSXL), otherwise
411  0 (success).
412  */
414 
415 /**
416  * @brief Gets the average ambient luminance as perceived by the inner camera (in lux).
417  * If QTM is unavailable (in particular, QTM is always unavailable on N2DSXL), returns 400.0 instead
418  * of the actual luminance.
419  *
420  * @param[out] outLuminanceLux Where to write the luminance to. Always 400.0 on N2DSXL.
421  * @note Camera exposure, and in particular auto-exposure affects the returned luminance value. This must be
422  * taken into consideration, because this value can thus surge when user covers the inner camera.
423  * @return Always 0 (success).
424  */
425 Result QTMS_GetCameraLuminance(float *outLuminanceLux);
426 
427 /**
428  * @brief Enables automatic barrier control when in 3D mode with "super stable 3D" enabled.
429  *
430  * @note This is automatically called upon `qtm:s` and `qtm:sp` session exit.
431  * @return `0xC8A18009` if QTM is unavailable (in particular, QTM is always unavailable on N2DSXL), otherwise
432  0 (success).
433  * @note Due to an oversight, \ref QTMS_SetQtmStatus allows changing QTM state on N2DSXL. This is not intended
434  * to be done, and is in fact never done by official software. If that is regardless the case,
435  * this function here does nothing.
436  */
438 
439 /**
440  * @brief Temporarily disables automatic barrier control (when in 3D mode with "super stable 3D" enabled).
441  *
442  * @note This is automatically called upon `qtm:s` and `qtm:sp` session exit.
443  * @return `0xC8A18009` if QTM is unavailable (in particular, QTM is always unavailable on N2DSXL), otherwise
444  0 (success).
445  * @note Due to an oversight, \ref QTMS_SetQtmStatus allows changing QTM state on N2DSXL. This is not intended
446  * to be done, and is in fact never done by official software. If that is regardless the case,
447  * this function here does nothing.
448  */
450 
451 /**
452  * @brief Temporarily sets the parallax barrier's position (offset in iod/12 units, assuming slit width of 6 units).
453  * Does nothing in 2D mode and/or if "super stable 3D" is disabled.
454  *
455  * @param position Parallax barrier position (offset in units), must be between 0 and 11 (both included)
456  * @return `0xC8A18009` if QTM is unavailable (in particular, QTM is always unavailable on N2DSXL), 0xE0E18002
457  * if \p position is not in range, otherwise 0 (success).
458  * @note Due to an oversight, \ref QTMS_SetQtmStatus allows changing QTM state on N2DSXL. This is not intended
459  * to be done, and is in fact never done by official software. If that is regardless the case,
460  * this function here does nothing.
461  * @note No effect when the screen is in 2D mode.
462  * @see QTMC_SetBarrierPattern
463  */
465 
466 /**
467  * @brief Gets the current position of the parallax barrier (offset in iod/12 units, slit width of 6 units).
468  * When "super stable 3D" is disabled, returns 13 instead.
469  *
470  * @param[out] outPosition Where to write the barrier's position to.
471  * @return `0xC8A18009` if QTM is unavailable (in particular, QTM is always unavailable on N2DSXL), otherwise
472  0 (success).
473  * @note When SS3D is disabled, this returns 13 to \p outPosition . When in 2D mode, the returned position is not
474  updated.
475  * @note Due to an oversight, \ref QTMS_SetQtmStatus allows changing QTM state on N2DSXL. This is not intended
476  * to be done, and is in fact never done by official software. If that is regardless the case,
477  * this function here returns 13 to \p outPosition .
478  * @see QTMC_SetBarrierPattern
479  */
481 
482 /**
483  * @brief Temporarily overrides IR LED state. Requires "manual control" from `qtm:u` to be disabled, and has
484  * lower priority than it.
485  *
486  * @param on Whether to turn the IR LED on or off.
487  * @return `0xC8A18005` if manual control was enabled or if the operation failed, `0xC8A18008` if camera is in use
488  * by user (unless "hardware check" API enabled), or `0xC8A18009` if QTM is unavailable (in particular,
489  * QTM is always unavailable on N2DSXL). Otherwise, 0 (success).
490  */
492 
493 /**
494  * @brief Sets calibration data, taking effect immediately, and optionally saves it to `cfg`.
495  *
496  * @param cal Pointer to calibration data.
497  * @param saveCalToCfg Whether or not to persist the calibration data in `cfg`.
498  * @return `0xC8A18009` if QTM is unavailable (in particular, QTM is always unavailable on N2DSXL), otherwise
499  whatever `cfg:s` commands return (if used), or 0 (success).
500  * @note There is no "get" counterpart for this function, and there is no way to see the current calibration data
501  in use unless it has been saved to `cfg`.
502  * @note Due to an oversight, \ref QTMS_SetQtmStatus allows changing QTM state on N2DSXL. This is not intended
503  * to be done, and is in fact never done by official software. If that is regardless the case,
504  * this function here doesn't apply calibrations parameters (they may still be saved, however,
505  * even though QTM calibration blocks are always normally 0 on N2DSXL).
506  */
507 Result QTMS_SetCalibrationData(const QtmCalibrationData *cal, bool saveCalToCfg);
508 
509 /**
510  * @brief Gets the current QTM status (enabled/ss3d disabled/unavailable).
511  *
512  * @param[out] outQtmStatus Where to write the QTM status to.
513  * @return Always 0.
514  */
516 
517 /**
518  * @brief Gets the current QTM status (enabled/ss3d disabled/unavailable). Also sets or clear the
519  * "blacklisted" flag returned by \ref QTMU_IsCurrentAppBlacklisted.
520  *
521  * @param qtmStatus QTM status to set. If equal to \ref QTM_STATUS_UNAVAILABLE, sets the "blacklisted" flag,
522  * otherwise clears it.
523  * @return `0xE0E18002` if enum value is invalid, otherwise 0 (success).
524  * @note System settings uses this to disable super-stable 3D, and NS to "blacklist" (make QTM unavailable)
525  * specific applications.
526  */
528 
529 /**
530  * @brief Called by GSP's LCD driver to signal 2D<>3D mode change
531  * @param newMode 0 for 2D, 1 for 800px 2D (unused for this function, same as 0), 2 for 3D
532  * @return Always 0 (success).
533  */
535 
536 /**
537  * @brief Called by GSP's LCD driver during top LCD power-on to signal to QTM that it may power on
538  * and/or reconfigure then use the TI TCA6416A expander. In the process, QTM re-creates its
539  * expander thread.
540  * @return Always 0 (success).
541  */
543 
544 /**
545  * @brief Called by GSP's LCD driver to know whether or not QTM's expander thread is using
546  * the TI TCA6416A expander; it is waiting for this to become true/false during LCD
547  * power on/power off to proceed. Always false on N2DSXL.
548  * @param[out] outActive Where to write the "in use" status to.
549  * @return Always 0 (success).
550  */
551 Result QTMSP_IsExpanderInUse(bool *outActive);
552 
553 /**
554  * @brief Called by GSP's LCD driver during top LCD power-on to signal to QTM that it needs to
555  * switch the parallax barrier state to a 2D state (all-transparent mask). Causes QTM's
556  * expander thread to exit, relinquishing its `i2c::QTM` session with it.
557  * @return Always 0 (success).
558  */
static Result QTMU_GetTrackingData(QtmTrackingData *outData)
Gets the current normalized eye tracking data, made suitable for 3D programming.
Definition: qtm.h:306
Result QTMSP_NotifyTopLcdPowerOn(void)
Called by GSP's LCD driver during top LCD power-on to signal to QTM that it may power on and/or recon...
QtmServiceName
QTM service name enum, excluding qtm:c
Definition: qtm.h:205
@ QTM_SERVICE_SYSTEM_PROCESS
qtm:sp: has access to all qtm:s (and qtm:u) commands, and merely has a few more commands that GSP use...
Definition: qtm.h:227
@ QTM_SERVICE_USER
qtm:u: has eye-tracking commands and IR LED control commands, but for some reason cannot fetch ambian...
Definition: qtm.h:210
@ QTM_SERVICE_SYSTEM
qtm:s: has access to all qtm:u commands, plus luminosity sensor, plus manual barrier position setting...
Definition: qtm.h:217
void qtmExit(void)
Exits QTM.
Result QTMU_SetIrLedStatus(bool on)
Turns the IR LED on or off during manual control.
float qtmComputeInverseAspectRatio(const QtmTrackingData *data)
Computes a rough approximation of the inverse of the aspect ration of the camera based on eye trackin...
Result QTMU_DisableManualIrLedControl(void)
Temporarily disables manual control of the IR LED by user, re-enabling its automatic control.
float qtmComputeFovX(const QtmTrackingData *data)
Computes an approximation of the horizontal angular field of view of the camera based on eye tracking...
float qtmComputeFovY(const QtmTrackingData *data)
Computes an approximation of the vertical angular field of view of the camera based on eye tracking d...
Result QTMS_GetCurrentBarrierPosition(u8 *outPosition)
Gets the current position of the parallax barrier (offset in iod/12 units, slit width of 6 units).
bool qtmIsInitialized(void)
Checks whether or not a qtm:u, qtm:s or qtm:sp session is active.
Result qtmInit(QtmServiceName serviceName)
Initializes QTM (except qtm:c).
Result QTMSP_IsExpanderInUse(bool *outActive)
Called by GSP's LCD driver to know whether or not QTM's expander thread is using the TI TCA6416A expa...
bool qtmCheckServicesRegistered(void)
Check whether or not QTM services are registered.
Result QTMS_SetIrLedStatusOverride(bool on)
Temporarily overrides IR LED state.
static Result QTMU_GetRawTrackingData(QtmRawTrackingData *outData)
Gets the current raw eye tracking data.
Definition: qtm.h:279
QtmStatus
QTM enablement status (when cameras not in use by user), set by qtm:s.
Definition: qtm.h:77
@ QTM_STATUS_SS3D_DISABLED
QTM "super stable 3D" feature is disabled. Parallax barrier hardware state is configured to match O3D...
Definition: qtm.h:79
@ QTM_STATUS_ENABLED
QTM is fully enabled.
Definition: qtm.h:78
@ QTM_STATUS_UNAVAILABLE
QTM is unavailable: either "blacklisted" (usually by NS) for the current title, or console is a N2DSX...
Definition: qtm.h:92
Result QTMS_GetCameraLuminance(float *outLuminanceLux)
Gets the average ambient luminance as perceived by the inner camera (in lux).
Result QTMS_DisableAutoBarrierControl(void)
Temporarily disables automatic barrier control (when in 3D mode with "super stable 3D" enabled).
Result QTMU_GetRawTrackingDataEx(QtmRawTrackingData *outData, s64 predictionTimePointOrZero)
Gets the current raw eye tracking data, with an optional prediction made for predictionTimePointOrZer...
Result QTMS_SetCalibrationData(const QtmCalibrationData *cal, bool saveCalToCfg)
Sets calibration data, taking effect immediately, and optionally saves it to cfg.
Result qtmClearIrLedOverrides(void)
Attempts to clear IR LED overrides from any of the relevant commands in qtm:u, qtm:s (and qtm:c) comm...
Result QTMS_SetQtmStatus(QtmStatus qtmStatus)
Gets the current QTM status (enabled/ss3d disabled/unavailable).
Result QTMSP_NotifyTopLcdModeChange(u8 newMode)
Called by GSP's LCD driver to signal 2D<>3D mode change.
Result QTMS_SetCenterBarrierPosition(float position)
Sets the neutral (center) barrier position/offset in calibration, without saving it to cfg.
float qtmComputeHeadTiltAngle(const QtmTrackingData *data)
Computes the user's head tilt angle, that is, the angle between the line through both eyes and the ca...
Result QTMU_IsCurrentAppBlacklisted(bool *outBlacklisted)
Checks whether or not QTM has been blacklisted, ie.
Result QTMU_GetTrackingDataEx(QtmTrackingData *outData, s64 predictionTimePointOrZero)
Gets the current normalized eye tracking data, made suitable for 3D programming with an optional pred...
float qtmEstimateEyeToCameraDistance(const QtmTrackingData *data)
Estimates the distance between the user's eyes and the camera, based on eye tracking data.
Result QTMSP_NotifyTopLcdPowerOff(void)
Called by GSP's LCD driver during top LCD power-on to signal to QTM that it needs to switch the paral...
Result QTMS_EnableAutoBarrierControl(void)
Enables automatic barrier control when in 3D mode with "super stable 3D" enabled.
Result QTMU_EnableManualIrLedControl(void)
Temporarily enables manual control of the IR LED by user, disabling its automatic control.
Result QTMS_GetQtmStatus(QtmStatus *outQtmStatus)
Gets the current QTM status (enabled/ss3d disabled/unavailable).
QtmEyeSide
Left eye or right eye, for QtmTrackingData and QtmRawTrackingData.
Definition: qtm.h:134
@ QTM_EYE_LEFT
Left eye.
Definition: qtm.h:135
@ QTM_EYE_NUM
Number of eyes.
Definition: qtm.h:138
@ QTM_EYE_RIGHT
Right eye.
Definition: qtm.h:136
Handle * qtmGetSessionHandle(void)
Returns a pointer to the current qtm:u / qtm:s / qtm:sp session handle.
Result QTMS_SetBarrierPosition(u8 position)
Temporarily sets the parallax barrier's position (offset in iod/12 units, assuming slit width of 6 un...
QTM calibration data (fully enabled/SS3D disabled) in cfg. Usually all-zero on N2DSXL.
Definition: qtm.h:111
float translationY
Lens Y coord in inner camera space? Very low value and seems to be unused.
Definition: qtm.h:127
float rotationZ
Optimal eye-to-camera angle, in radians, without accounting for lens distortion.
Definition: qtm.h:128
float viewingDistance
Optimal viewing distance between user and top screen, assuming iod to be 62mm.
Definition: qtm.h:130
float translationX
Lens X coord in inner camera space? Very low value and seems to be unused.
Definition: qtm.h:126
float fovX
Camera's horizontal FoV in degrees, without accounting for lens distortion.
Definition: qtm.h:129
float centerBarrierPosition
Neutral (center) barrier position/offset (with slit width of 6 units), when the user is facing direct...
Definition: qtm.h:124
QTM raw eye tracking data.
Definition: qtm.h:142
s64 samplingTick
Time point the current measurements were made.
Definition: qtm.h:166
u8 _padding[3]
Padding.
Definition: qtm.h:150
float confidenceLevel
Eye tracking confidence level (0 to 1).
Definition: qtm.h:152
float dRoll
Difference in gyro roll from position at console boot.
Definition: qtm.h:164
float dYaw
Difference in gyro yaw from position at console boot.
Definition: qtm.h:163
bool eyesTracked
Eye position detected or predicted, equals (confidenceLevel > 0).
Definition: qtm.h:149
u32 singletonQtmPtr
Pointer to eye-tracking singleton pointer, in QTM's .bss, located in N3DS extra memory.
Definition: qtm.h:151
float rawEyeCameraCoordinates[QTM_EYE_NUM][2]
Raw predicted or detected eye coordinates.
Definition: qtm.h:160
float dPitch
Difference in gyro pitch from position at console boot.
Definition: qtm.h:162
QTM status data (fully enabled/SS3D disabled) in cfg. Usually all-zero on N2DSXL.
Definition: qtm.h:96
u8 gvLoadMode
"Global variable" (.data) section load mode? Unused.
Definition: qtm.h:106
QtmStatus defaultStats
QTM status at boot (fully enabled or SS3D disabled).
Definition: qtm.h:97
u8 _padding[2]
Padding.
Definition: qtm.h:107
QTM processed eye tracking data, suitable for 3D programming.
Definition: qtm.h:170
bool eyesDetected
Whether or not the user's eyes have actually been detected with full confidence.
Definition: qtm.h:173
bool faceDetected
Whether or not the entirety of the user's face has been detected with good confidence.
Definition: qtm.h:172
u8 _padding[3]
Padding.
Definition: qtm.h:176
float dPitch
Difference in gyro pitch from position at console boot.
Definition: qtm.h:196
float confidenceLevel
Eye tracking confidence level (0 to 1).
Definition: qtm.h:178
float eyeWorldCoordinates[QTM_EYE_NUM][2]
Normalized eye coordinates, for each eye, in world space.
Definition: qtm.h:194
bool clamped
Whether or not the normalized eye coordinates have been clamped after accounting for lens distortion.
Definition: qtm.h:175
bool eyesTracked
Eye position detected or tracked with some confidence, equals (confidenceLevel > 0)....
Definition: qtm.h:171
float dYaw
Difference in gyro yaw from position at console boot.
Definition: qtm.h:197
u8 _unused
Unused.
Definition: qtm.h:174
s64 samplingTick
Time point the current measurements were made.
Definition: qtm.h:201
float eyeCameraCoordinates[QTM_EYE_NUM][2]
Normalized eye coordinates, for each eye, after accounting for lens distortion, centered around camer...
Definition: qtm.h:186
float dRoll
Difference in gyro roll from position at console boot.
Definition: qtm.h:198
Various system types.
int64_t s64
64-bit signed integer
Definition: types.h:29
uint8_t u8
would be nice if newlib had this already
Definition: types.h:21
u32 Handle
Resource handle.
Definition: types.h:41
s32 Result
Function result.
Definition: types.h:42
uint32_t u32
32-bit unsigned integer
Definition: types.h:23