Calibrating the Magnetic North sensor channel

The hardware sensor used in a mobile device to find magnetic north usually needs to be calibrated before it will provide accurate data. Use the Magnetic North sensor channel (KSensrvChannelTypeIdMagneticNorthData) to retrieve the relation of the device to magnetic north. However, only the Magnetometer sensor channel (KSensrvChannelTypeIdMagnetometerXYZAxisData) maintains the calibration level of the data in the property KSensrvPropCalibrationLevel. This means you need to open both channels, one for reading the data and the other for checking the calibration.

Retrieve the calibration level from the magnetometer channel with CSensrvChannel::GetPropertyL().
TInt iMagnetometerCalibrationLevel;
CSensrvChannel* iMagnetometerSensor;
CSensrvChannel* iMagneticNorthSensor;
...
TSensrvProperty property;
iMagnetometerSensor->GetPropertyL(KSensrvPropCalibrationLevel, KSensrvItemIndexNone, property);
property.GetValue(iMagnetometerCalibrationLevel);
The calibration level will be one of the following values:
Table: Calibration levels

Value

Meaning

0

Not calibrated

1

Low calibration.

2

Medium calibration

3

High accuracy

The Magnetic North sensor is auto-calibrating, but first you need to enable the auto calibration. Do this by setting the KSensrvPropAutoCalibrationActive property of the sensor.

iMagnetometerSensor->GetPropertyL(KSensrvPropAutoCalibrationActive, KSensrvItemIndexNone, property);
property.SetValue(1); // set auto-calibration on. Note, do SetValue(0) to disable auto-calibration
iMagnetometerSensor->SetProperty(property);

It takes some time to calibrate the Magnetic North sensor and, even after being calibrated, it can become uncalibrated. So, for an application to be sure the data coming from the Magnetic North sensor channel is accurate, you must monitor changes in the calibration property and inform the user if something needs to be done to recalibrate the sensor. Monitor the calibration property by setting the property listener and implementing the MSensrvPropertyListener::PropertyChanged() method.

...
iMagnetometerSensor->SetPropertyListenerL(this); // where "this" is CMagneticNorthSensorChannelApp
...
void CMagneticNorthSensorChannelApp::PropertyChanged( CSensrvChannel& aChannel, 
		const TSensrvProperty& aChangedProperty )
	{
	TSensrvChannelInfo info = aChannel.GetChannelInfo();
	if (info.iChannelType == KSensrvChannelTypeIdMagnetometerXYZAxisData)
		{
		if(aChangedProperty.GetPropertyId()==KSensrvPropCalibrationLevel)
			{
			aChangedProperty.GetValue(iMagnetometerCalibrationLevel);
			// Test iMagnetometerCalibrationLevel here to make sure it is still acceptable. If not,
			// then notify the UI.
			}
		}
	}

Your MSensrvDataListener::DataReceived() implementation should take note of the calibration level before using the data that has been received. In the code example above, the calibration level is stored in the instance variable iMagnetometerCalibrationLevel so that it is easily accessible from other parts of the application.

TInt iAngleFromMagneticNorth;
TTime iAngleFromMagneticNorthTimeStamp;
...
void CMagneticNorthSensorChannelApp::DataReceived(CSensrvChannel& aChannel,
		TInt /* aCount */, TInt /* aDataLost */)
	{
	TSensrvChannelInfo info = aChannel.GetChannelInfo();
	if (info.iChannelType == KSensrvChannelTypeIdMagneticNorthData)
		{
		TSensrvMagneticNorthData magNorthData;
		TPckg<TSensrvMagneticNorthData>  magNorthPackage(magNorthData);
 		aChannel.GetData(magNorthPackage);
  		if(iMagnetometerCalibrationLevel >= 2)
 			{
 			// Store the data
			iAngleFromMagneticNorth = magNorthData.iAngleFromMagneticNorth;
			iAngleFromMagneticNorthTimeStamp = magNorthData.iTimeStamp;
			// Inform owner about the new data
			// ...
 			}
 		else
 			{
 			// Don't use the data.
			// Maybe inform the owner that the sensor is uncalibrated and therefore inaccurate
			// ...
			}
		}
 	}