塞班传感器编程
塞班传感器编程
塞班系统于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签名不能使用这两个能力,万恶啊)