Device Operations
Taking measurements
Once the device is connected and in an idle state, it is possible to take measurements by calling measure()
(see Kotlin or Java APIs).
- The varargs
modes
argument may be omitted to run measurements in all modes supported by the device. This is the recommended option. - If the varargs
modes
arguments are supplied, measurements will be provided only for the specified scan modes. In most cases, this will not speed up the measurement cycle time, so this is not recommended. - The measurement operation is asynchronous and will return immediately. While the measurement is in progress, no other commands can be sent to the Nix device.
- Every call to
measure()
will result in a callback with either a success or error code. - Results of the measurement operation are provided via the
onDeviceResult()
callback in anOnDeviceResultListener
interface (Kotlin or Java). This callback provides two arguments:- A
CommandStatus
status code (see Kotlin or Java APIs), which will beSUCCESS
for a successful operation. - A map containing the measurement values as
IMeasurementData
instances. The keys in this map correspond to theScanMode
enum (see Kotlin or Java APIs) for each measurement value. - See Handling Measurement Data for notes on interpreting the measurement data.
- The supported scan modes for a particular device are provided in the list from
getSupportedModes()
on theIDeviceCompat
instance. Support for a scan mode can also be checked explicitly by callingisModeSupported()
on theIDeviceCompat
instance. The expected results by device are shown below:
- A
Device Type | M0 | M1 | M2 |
---|---|---|---|
Mini | ☐ | ☐ | ☑ |
Mini 2 | ☐ | ☐ | ☑ |
Mini 3 | ☐ | ☐ | ☑ |
Pro | ☐ | ☐ | ☑ |
Pro 2 | ☐ | ☐ | ☑ |
QC | ☐ | ☐ | ☑ |
Spectro 2 (F1.0.0) | ☑ | ☑ | ☐ |
Spectro 2 (F2.0.0) | ☑ | ☑ | ☑ |
Spectro L | ☑ | ☑ | ☑ |
// Device instance
var device: IDeviceCompat
// Define callback for measurement
val measureListener = object : OnDeviceResultListener {
override fun onDeviceResult(
status: CommandStatus,
measurements: Map<ScanMode, IMeasurementData>?
) {
when (status) {
CommandStatus.SUCCESS -> {
// Successful operation
// Handle measurement data here
// ...
}
CommandStatus.ERROR_NOT_READY -> {
// Did not complete because the device was busy
// ...
}
CommandStatus.ERROR_NOT_SUPPORTED -> {
// Did not complete because an unsupported scan mode was
// specified
// ...
}
CommandStatus.ERROR_LOW_POWER -> {
// Did not complete because the battery level is too low
// ...
}
CommandStatus.ERROR_TIMEOUT -> {
// Timeout when waiting for result
// ...
}
CommandStatus.ERROR_AMBIENT_LIGHT -> {
// Did not complete because of ambient light leakage
// ...
}
CommandStatus.ERROR_LICENSE -> {
// Scan did not complete because of a license issue
// Check LicenseManager.state
// ...
}
else -> {
// Did not complete because of other internal error
// ...
}
}
}
}
// Run the measurement
device.measure(measureListener)
// Device instance
IDeviceCompat device;
// Define callback for measurement
OnDeviceResultListener measureListener = (commandStatus, measurements) -> {
switch (commandStatus) {
case SUCCESS:
// Successful operation
// Handle measurement data here
// ...
break;
case ERROR_NOT_READY:
// Did not complete because the device was busy
// ...
break;
case ERROR_NOT_SUPPORTED:
// Did not complete because an unsupported scan mode was
// specified
// ...
break;
case ERROR_LOW_POWER:
// Did not complete because the battery level is too low
// ...
break;
case ERROR_TIMEOUT:
// Timeout when waiting for result
// ...
break;
case ERROR_AMBIENT_LIGHT:
// Did not complete because of ambient light leakage
// ...
break;
case ERROR_LICENSE:
// Scan did not complete because of a license issue
// Check LicenseManager.Shared.state
// ...
break;
default:
// Did not complete because of other internal error
// ...
break;
}
};
// Run the measurement
device.measure(measureListener);
Performing in-field profiling / calibration with reference tile
Certain device types support in-field profiling or calibration using a provided reference tile. This process requires first decoding a string from the QR code attached to the reference tile and then directing the user to measure the same tile. Any necessary adjustments/corrections are performed internally by the SDK and/or the Nix device firmware itself.
- The in-field calibration procedure may be performed as often or seldom as desired by the user. However, the flag
getFieldCalibrationDue()
indicates whether or not in-field calibration is recommended for the connected device.- This flag is updated after each regular measurement
- This flag is determined automatically by both elapsed time and ambient temperature change
- Calling
invalidateFieldCalibration()
will force the calibration record to expire on QC and Spectro 2 devices, so thatgetFieldCalibrationDue()
returnstrue
- The in-field calibration procedure can exit with status
ERROR_SCAN_DELTA
if a large difference is detected between the tile reference and measurement.- This status indicates an unexpected tile measurement, possibly due to:
- User error (e.g. - a surface other than the reference tile was measured). In this case, the user should repeat the operation
- The reference tile is damaged
- The device has drifted too far from factory calibration for the field calibration to be reliable
- The failure threshold can vary by device type and can be checked by calling
getFieldCalibrationMaxDelta()
- The failure threshold can be overridden by calling
setFieldCalibrationMaxDelta()
but this is NOT RECOMMENDED
- This status indicates an unexpected tile measurement, possibly due to:
- The flag
getSupportsFieldCalibration()
indicates whether or not a connected device supports this feature. The expected result by device type is shown below:
Device Type | Supported |
---|---|
Mini | ☐ |
Mini 2 | ☐ |
Mini 3 | ☑ |
Pro | ☐ |
Pro 2 | ☐ |
QC | ☑ |
Spectro 2 | ☑ |
Spectro L | ☑ |
The steps to perform in-field profiling include:
- Decode the QR code printed on the device reference tile and interpret as a string. Do not parse this data further.
- Check if the parsed data is valid using
isTileStringValid()
on theIDeviceCompat
instance. If valid, continue to the next step. - Instruct the user to place the device on the reference tile.
- Using the decoded tile string, run the in-field calibration routine by calling
runFieldCalibration()
on theIDeviceCompat
instance and wait for callback (see Kotlin or Java APIs).- This operation is asynchronous and returns immediately. While the operation is in progress, no other commands can be sent to the Nix device (wait for the callback)
- Every call to
runFieldCalibration()
will result in a callback with either a success or error code.
// Device instance
var device: IDeviceCompat
// String decoded from the reference tile
val tileString: String
// Define callback for field calibration
val calibrateListener = object : OnDeviceResultListener {
override fun onDeviceResult(
status: CommandStatus,
measurements: Map<ScanMode, IMeasurementData>?
) {
when (status) {
CommandStatus.SUCCESS -> {
// Successful operation
// ...
}
CommandStatus.WARNING_TEMPERATURE -> {
// Completed successfully, but ambient temperature is outside
// of the recommended range
// ...
}
CommandStatus.ERROR_SCAN_DELTA -> {
// Operation failed because the measured value of the
// reference tile is too far from the expected value
// (high delta E)
// ...
}
CommandStatus.ERROR_NOT_READY -> {
// Did not complete because the device was busy
// ...
}
CommandStatus.ERROR_NOT_SUPPORTED -> {
// Did not complete because this device does not support
// this command
// ...
}
CommandStatus.ERROR_INVALID_ARGUMENT -> {
// Did not complete because the tileString is invalid
// ...
}
CommandStatus.ERROR_LOW_POWER -> {
// Did not complete because the battery level is too low
// ...
}
CommandStatus.ERROR_TIMEOUT -> {
// Timeout when waiting for result
// ...
}
CommandStatus.ERROR_AMBIENT_LIGHT -> {
// Did not complete because of ambient light leakage
// ...
}
CommandStatus.ERROR_LICENSE -> {
// Scan did not complete because of a license issue
// Check LicenseManager.state
// ...
}
else -> {
// Did not complete because of other internal error
// ...
}
}
}
}
// Run field calibration scan
device.runFieldCalibration(calibrateListener, tileString)
// Device instance
IDeviceCompat device;
// String decoded from the reference tile
String tileString;
// Define callback for field calibration
OnDeviceResultListener calibrateListener =
(commandStatus, measurements) ->
{
switch (commandStatus) {
case SUCCESS:
// Successful operation
// ...
break;
case WARNING_TEMPERATURE:
// Completed successfully, but ambient temperature is outside
// of the recommended range
// ...
break;
case ERROR_SCAN_DELTA:
// Operation failed because the measured value of the reference
// tile is too far from the expected value (high delta E)
// ...
break;
case ERROR_NOT_READY:
// Did not complete because the device was busy
// ...
break;
case ERROR_NOT_SUPPORTED:
// Did not complete because this device does not support this
// command
// ...
break;
case ERROR_INVALID_ARGUMENT:
// Did not complete because the tileString is invalid
// ...
break;
case ERROR_LOW_POWER:
// Did not complete because the battery level is too low
// ...
break;
case ERROR_TIMEOUT:
// Timeout when waiting for result
// ...
break;
case ERROR_AMBIENT_LIGHT:
// Did not complete because of ambient light leakage
// ...
break;
case ERROR_LICENSE:
// Scan did not complete because of a license issue
// Check LicenseManager.Shared.state
// ...
break;
default:
// Did not complete because of other internal error
// ...
break;
}
};
// Run field calibration scan
device.runFieldCalibration(calibrateListener, tileString);
Other device options
Some Nix devices support certain boolean
options. These options are set to be enabled by default (if supported) and do not usually need to be changed. Current state and device support can be checked at runtime on the IDeviceCompat
instance:
- Applying temperature compensation
- Current state:
getTemperatureCompensationEnabled()
- Is supported?:
getSupportsTemperatureCompensation()
- Current state:
- Applying in-field calibration
- Current state:
getFieldCalibrationEnabled()
- Is supported?:
getSupportsFieldCalibration()
- Current state:
- Using on-device haptic feedback
- Current state:
getHapticFeedbackEnabled()
- Is supported?:
getSupportsHapticFeedback()
- Current state:
- Using on-device RGB feedback
- Current state:
getRgbFeedbackEnabled()
- Is supported?:
getSupportsRgbFeedback()
- Current state:
A summary of device support is shown below, but can be checked at runtime.
Device type | Temp comp. | Field cal. | Haptic | RGB |
---|---|---|---|---|
Mini | ☐ | ☐ | ☐ | ☐ |
Mini 2 | ☑ | ☐ | ☐ | ☐ |
Mini 3 | ☑ | ☑ | ☐ | ☑ |
Pro | ☐ | ☐ | ☐ | ☐ |
Pro 2 | ☑ | ☐ | ☐ | ☐ |
QC | ☑ | ☑ | ☐ | ☐ |
Spectro 2 | ☑ | ☑ | ☑ | ☑ |
Spectro L | ☑ | ☑ | ☑ | ☑ |
Changing any of these options may require communication with the device itself and is an asynchronous operation, with the status of the operation provided via a onDeviceResult()
callback in the specified OnDeviceResultListener
interface.
- To enable or bypass temperature compensation, use
setTemperatureCompensationEnabled()
- To enable or bypass applying in-field calibration, use
setFieldCalibrationEnabled()
- To enable or disable haptic feedback, use
setHapticFeedbackEnabled()
- To enable or disable RGB feedback, use
setRgbFeedbackEnabled()
Other device properties
The IDeviceCompat
interface defines other properties that can be read once the device has connected and reached an idle state. These include, but are not limited to:
extPowerState
: status of external power connection / chargingbatteryLevel
: current battery level,null
otherwisefirmwareVersion
: device firmware revisionhardwareVersion
: device hardware revisionsoftwareVersion
: device software revisionserialNumber
: device serial numbernote
: device allocation / production codeprovidesSpectral
: indicates whether or not this device provides spectral dataprovidesDensity
: indicates whether or not this device provides density datasupportedModes
: list of supported measurement modes for this devicesupportedReferences
: list of supported reference white values provided by the measurement data from this device
getExtPowerState()
: status of external power connection / charginggetBatteryLevel()
: current battery level,null
otherwisegetFirmwareVersion()
: device firmware revisiongetHardwareVersion()
: device hardware revisiongetSoftwareVersion()
: device software revisiongetSerialNumber()
: device serial numbergetNote()
: device allocation / production codegetProvidesSpectral()
: indicates whether or not this device provides spectral datagetProvidesDensity()
: indicates whether or not this device provides density datagetSupportedModes()
: list of supported measurement modes for this devicegetSupportedReferences()
: list of supported reference white values provided by the measurement data from this device
Warning
The providesDensity
and providesSpectral
properties indicate whether or not the hardware device is capable of providing these data types. However, these measurements will only be available if these features are enabled by the current license. See Other license properties for more details.