塞班传感器编程

塞班传感器编程

塞班系统于v9.3开始支持传感器,从S60第五版SDK正式公布传感器接口(sensor API)。

传感器接口(sensor API)提供给用户侦听和接收来至传感器数据的功能,它包括两个部分:通道接口(Channel API)和定义接口(Definitions API)。Channel API定义了传感器的基本功能和作用,Definitions API描述了各种传感器数据定义上的特征。

通道也提供有条件的侦听数据,通道的属性也可以通过API配置,如数据频率。

通道种类(channels)

加速器(accelerometer)、旋转(rotation)、方向(orientation)、双击(double-tap)、距离(proximity)、环境光(ambient light)、罗盘或指北针(magnetic north)、磁力(magnetometer XYZ)。

1> 加速器(accelerometer)

加速器通道测量设备在三维笛卡尔坐标系下的加速度。设备沿X轴正向移动的时候,加速度为正值;沿X轴反向移动的时候,加速度为负值。

塞班传感器编程

图:Z轴正向与屏幕朝向一致。

2> 旋转(rotation)

探测围绕三维笛卡尔坐标轴的旋转量。(值范围0-359度)

图如上

3> 方向(orientation)

如下图相机有六个基本方向。

塞班传感器编程

4> 双击(double-tap)

双击通道当双击发生时发出事件,发送的事件数据用掩码(bitmask)表示双击发生的方向。

5> 距离(proximity)

距离传感器通道使用二进制位表示,设备是否接近人体。当该状态无法判断时,状态值为undefined。

6> 环境光(ambient light)

环境光传感器通道返回光线强度百分比。(0-100)

7> 罗盘或指北针(magnetic north)

罗盘传感器通道返回设备跟北极的顺时针夹角。(0-359)

8> 磁力(magnetometer XYZ)

返回磁场强度。

用例

通道侦听用例

查找、打开、关闭通道

侦听数据

侦听变化

通道属性用例

获取通道属性

设置通道属性

属性数组

缩放通道数据

侦听通道属性的变化

条件侦听

条件侦听

类结构

一个物理传感器可以提供几种类型的数据,通道(channel)则是提供来至物理传感器的某种特定类型的数据。例如,磁力传感器就提供了磁力通道和罗盘通道。

塞班传感器编程

图:传感器类的简图

上图显示一种物理传感器提供着几种通道(CSensrvChannel),通道通过MSensrvDataListener::DataReceived()回调接口提供了特定类型的数据(如 TSensrvXyzData),每个通道都对应着一个TSensrvChannelInfo结构来描述和查找,每个通道拥有多个属性(TSensrvProperty),每个属性可以通过ID和索引(index)来引用。

CSensrvChannelFinder提供查找通道的方法。继承MSensrvChannelListener接口,可以侦听到可用通道的变换,例如新通道被安装到设备时。

CSensrvChannel提供打开和控制通道的方法。

1> CSensrvChannel开始和停止侦听,MSensrvDataListener接口接收数据。

2> CSensrvChannel开始和停止有条件侦听,MSensrvChannelConditionListener接口接收数据。CSensrvChannelConditionSet 和 CSensrvChannelCondition 封装条件。

3> get和set获取和设置通道属性,MSensrvPropertyListener接口属性的变化。

塞班传感器编程

图:类图

客户端使用NewL创建C类的实例,继承并实现M类接口,并把M类的接口指针指派给相关函数用来接收数据。

使用传感器API

要使用通道,客户端必须先查找并打开它。CSensrvChannelFinder提供了查找的方法,CSensrvChannel提供了打开的方法。

不同的设置支持不同的通道。SDK定义了所有可能的通道,每个通道都有一个不变的唯一的ID和简述。例如下面的双击通道,它提供两种具体的通道,原数据通道(raw data channels)和事件通道(event channels)。原数据通道提供连续性数据,而事件通道提供事件提醒。

/**

* - Name: Double tapping event channel type

* - Type: Event

* - Datatype: TSensrvTappingData

* - Description: Double tapping events

*/

const TSensrvChannelTypeId KSensrvChannelTypeIdAccelerometerDoubleTappingData = 0x10205081;

每个通道的数据类型都在各自的头文件里有定义,它描述了通道可以提供的数据的类型。如下是双击通道的。

class TSensrvTappingData

{

public:

/**

* Channel data type Id number

*/

static const TSensrvChannelDataTypeId KDataTypeId = 0x1020507F;

/**

* Channel data type enumerations

*/

enum TSensrvAccelerometerAxisDataIndexes

{

iTimeStamp = 0,

iDirection

};

};

public:

/**

* - Item name: Sampling time.

* - Item Index: 0

* - Conditions: None

* - Description: Timestamp for a sample.

*/

TTime iTimeStamp;

/**

* - Item name: Tapping direction bitmask

* - Item Index: 1

* - Conditions: Binary

* - Description: Direction bitmask of the tapping event.

* See constant definitions above.

*/

TUint32 iDirection;

};

数据结构里的ID是不变的,每个通道唯一的。

Index用来指定结构中各个属性的位置。例如,双击通道的数据的结构里iTimeStamp和iDirection分别是0和1。这在属性数组和条件数组里会用到。

共用属性在sensrvgeneralproperties.h里声明,各通道独特属性在各自的头文件里声明。每种属性都有唯一的ID和描述,以及它们各自的数据成员,这些成员是TInt、TReal和TBuf类型。通道也可以定义属性的范围(scope)。

如下例,定义中的Mandatory部分表示该属性是否是通道必须的属性,Capalibity部分表示所需的能力。

/**

* - Name: Accuracy of the channel data

* - Type: TReal

* - Scope: Channel item property

* - Mandatory: No

* - Capability: None

* - Description: Returns the accuracy of this channel of the sensor as a

* percentage of reading (=data value).

*/

const TSensrvPropertyId KSensrvPropIdChannelAccuracy = 0x000000008;

通道数据中可以设置一些列属性。如果是传感器或通道属性,item Index应为KSensrvItemIndexNone。

iPropertyId = KSensrvPropIdChannelAccuracy

iItemIndex = KSensrvItemIndexNone

iArrayIndex = ESensrvSingleProperty

iRealValue = 10.0

iReadOnly = ETrue

iRealValueMax = n/a

iRealValueMin = n/a

iPropertyType = ESensrvRealProperty

iSecurityInfo = n/a

查找、打开、关闭通道

使用CSensrvChannelFinder的实例来查找通道,查找返回RSensrvChannelInfoList结构的结果。例如,要查找双击通道,在TSensrvChannelInfo对象中把通道类型设置为 KSensrvChannelTypeIdAccelerometerDoubleTappingData,然后使用FindChannelsL()方法获得包含通道信息的结构channelInfoList,CSensrvChannel类使用这个结构就可以创建一个通道的实例。

//Construct a channel finder.

CSensrvChannelFinder* channelFinder;

channelFinder = CSensrvChannelFinder::NewL();

CleanupStack::PushL( channelFinder );

//List of found channels.

RSensrvChannelInfoList channelInfoList;

CleanupClosePushL( channelInfoList );

//Create and fill channel search criteria.

//In this example double tapping channel is searched.

TSensrvChannelInfo channelInfo;

channelInfo.iChannelType = KSensrvChannelTypeIdAccelerometerDoubleTappingData;

//Find the double tapping channel

channelFinder->FindChannelsL( channelInfoList, channelInfo );

if( channelInfoList.Count() != 1 )

{

//The device doesn't support double tapping channel or

//there are several double tapping channels.

}

else

{

//double tapping channel found

}

//Open the double tapping channel.

//When the channel object is created the channel info object

//must be an object returned by CSensrvChannelFinder::FindChannelsL().

CSensrvChannel* sensorChannel;

sensorChannel = CSensrvChannel::NewL( channelInfoList[ 0 ] );

CleanupStack::PushL( sensorChannel );

sensorChannel->OpenChannelL();

//

//Double tapping channel is now open.

//

//Close the double tapping channel.

sensorChannel->CloseChannel();

CleanupStack::PopAndDestroy( sensorChannel );

CleanupStack::PopAndDestroy( &channelInfoList ); //Close() is being called on "channelInfoList"

CleanupStack::PopAndDestroy( channelFinder );

侦听数据

通道打开后,就可以侦听数据了。通道的数据保存在缓存中,可以通过GetData()方法获取。如果你要在新数据一到达时就接收,则要实现 MSensrvDataListener 接口的DataReceived()方法。

例如,把双击通道的desired count 和 maximum count设置为1,则在每次双击发生时都会收到一个提醒。buffering period设置为0,表示消息不延时,立即通知。通道数据的缓存是客户端线程在堆上分配的,大小为其结构的大小乘以数据项的maximum number,可以通过GetData()访问。所以,如果决定缓存大小的maximum number太小,则会引发进程间通讯,从而影响效率。

在这里,客户端实现了 MSensrvDataListener 接口,并把M类的指针赋给通道。

iSensorChannel->StartDataListeningL( this, //this object is data listener for this channel

1, //aDesiredCount is one, i.e. each double tapping is notified separately

1, //aMaximumCount is one, i.e. object count in receiving data buffer is one

0 );//buffering period is not used

侦听数据,需要实现 MSensrvDataListener 接口,需要重载它的 DataReceived() 方法。

void CTestClass::DataReceived( CSensrvChannel& aChannel,

TInt aCount,

TInt aDataLost )

{

if ( aChannel.GetChannelInfo().iChannelType == KSensrvChannelTypeIdAccelerometerDoubleTappingData )

{

TSensrvTappingData tappingData;

TPckg<TSensrvTappingData> tappingPackage( tappingData );

aChannel.GetData( tappingPackage );

}

}

通道的 StopDataListening() 方法停止侦听。

侦听变化

获取通道属性

设置通道属性

属性数组

缩放通道数据

侦听通道属性的变化

条件侦听

(暂略)

错误处理

塞班系统的 leave 等错误机制依然有效。

内存开销

传感器的内存开销基本集中在侦听数据的缓存。侦听频率和缓存大小如果不相匹配,则会引发进程间通讯,从而影响效率。

能力(capabilities)

WriteDeviceData 修改channel属性时需要。

ReadDeviceData 接收或读取channel数据时需要。

(注:自签名和Express签名不能使用这两个能力,万恶啊)