Android 的传感器系统
传感器的种类
传感器名称 |
Java中的名称 |
本地接口名称 |
数值 |
加速度 |
TYPE_ACCELEROMETER |
SENSOR_TYPE_ACCELEROMETER |
1 |
磁场 |
TYPE_MAGNETIC_FIELD |
SENSOR_TYPE_MAGNETIC_FIELD |
2 |
方向 |
TYPE_ORIENTATION |
SENSOR_TYPE_ORIENTATION |
3 |
陀螺仪 |
TYPE_GYROSCOPE |
SENSOR_TTYPE_GYROSCOPE |
4 |
光线(亮度) |
TYPE_LIGHT |
SENSOR_TTYPE_LIGHT |
5 |
压力 |
TYPE_PRESSURE |
SENSOR_TTYPE_PRESSURE |
6 |
温度 |
TYPE_TEMPERATURE |
SENSOR_TTYPE_TEMPERATURE |
7 |
接近 |
TYPE_PROXIMITY |
SENSOR_TTYPE_PROXIMITY |
8 |
重力传感
直线加速度
旋转矢量传感器
NFC(near field communication)近场通信
传感器的系统结构
传感器系统的java部分
代码路径为:\frameworks\base\core\java\android\hardware
传感器系统的JNI部分
代码路径为:\frameworks\base\core\jni\android_hardware_SensorManager.cpp
传感器系统的底层部分
代码路径为: \frameworks\base\include\gui
传感器的系统层次结构
传感器系统的各个层次,自下而上为:
驱动程序
硬件抽象层
JNI层
JAVA 层
框架层对传感器器的应用
应用对传感器的应用
注本地部分已包含在JNI层中没有单独的实现库
传感器的JNI层
直接调用硬件抽象层,包含头文件 sensor.h头文件该 文件的路径为:ardware\libhardware\include\hardware
static JNINativeMethod gMethods[] = {
{"nativeClassInit", "()V", (void*)nativeClassInit },
{"sensors_module_init","()I", (void*)sensors_module_init },
{"sensors_module_get_next_sensor","(Landroid/hardware/Sensor;I)I",
(void*)sensors_module_get_next_sensor },
{"sensors_create_queue", "()I", (void*)sensors_create_queue },
{"sensors_destroy_queue", "(I)V", (void*)sensors_destroy_queue },
{"sensors_enable_sensor", "(ILjava/lang/String;II)Z",
(void*)sensors_enable_sensor },
{"sensors_data_poll", "(I[F[I[J)I", (void*)sensors_data_poll },
};
这些方法主要是供java层的sensorManager.java
static jint
sensors_module_init(JNIEnv *env, jclass clazz)
{
SensorManager::getInstance();
return 0;
}
调用hw_get_module()函数是硬件模块的通用接口,根据传感器硬件模块的标识SENSORS_HARDWARE_MODULE_ID打开这个硬件模块
传感器系统的java代码
代码的路径为:\frameworks\base\core\java\android\hardware
sensorManager.java 传感器的核心管理类
Sensor.java 传感器的实体类
sensorEvent.java 传感器的事件类
(接口)
sensorEventListener.java 传感器事件的监听者
sensorListener.java 传感器的监听者 (不推荐使用)
sensorManager.java的几个主要方法:
public class SensorManager{
public Sensor getDefaultSensor(int type) { } // 取得默认传感器
public List<Sensor> getSensorList(int type) {} //取默认传感器列表
以下两个方法使用sensorEventListener接口作为传感器的监听者
public boolean registerListener(SensorListener listener, int sensors) { }//注册传感器的监听者
public void unregisterListener(SensorListener listener, int sensors) {}//注销注册监听
在这个类中还定义了一些常量
public static final float GRAVITY_*** //重力常量
public static final float MAGNETIC_***磁场常量
public static final float LIGHT_***//亮度传感器
public class Sensor {
//以下是android 支持的十一种传感器类型
public static final int TYPE_ACCELEROMETER = 1;
public static final int TYPE_MAGNETIC_FIELD = 2;
public static final int TYPE_ORIENTATION = 3;
public static final int TYPE_GYROSCOPE = 4;
public static final int TYPE_LIGHT = 5;
public static final int TYPE_PRESSURE = 6;
public static final int TYPE_TEMPERATURE = 7;
public static final int TYPE_PROXIMITY = 8;
public static final int TYPE_GRAVITY = 9;
public static final int TYPE_LINEAR_ACCELERATION = 10;
public static final int TYPE_ROTATION_VECTOR = 11;
//所有传感器类型
public static final int TYPE_ALL = -1;
private String mName; //名称
private String mVendor; //
private int mVersion; //版本
private int mType; //类型
private float mMaxRange; //取得传感器的最大范围
private float mResolution;// 传感器的解析度
private int mHandle; //
//以下是2.3版本中新添加
private float mPower;
private int mMinDelay;
private int mLegacyType;
}
//传感器监听
public interface SensorEventListener {
//数值发生变化时调用
public void onSensorChanged(SensorEvent event);
// 传感器精度发生变化时调用
public void onAccuracyChanged(Sensor sensor, int accuracy);
}
传感器系统的硬件抽象层
代码路径如下:\hardware\libhardware\include\hardware
Sensors.h头文件的部分路径如下:
//定义传感器类型
#define SENSOR_TYPE_ACCELEROMETER 1
#define SENSOR_TYPE_MAGNETIC_FIELD 2
#define SENSOR_TYPE_ORIENTATION 3
#define SENSOR_TYPE_GYROSCOPE 4
#define SENSOR_TYPE_LIGHT 5
#define SENSOR_TYPE_PRESSURE 6
#define SENSOR_TYPE_TEMPERATURE 7
#define SENSOR_TYPE_PROXIMITY 8
#define SENSOR_TYPE_GRAVITY 9
#define SENSOR_TYPE_LINEAR_ACCELERATION 10
#define SENSOR_TYPE_ROTATION_VECTOR 11
//在hw_module_t common标准的硬件模块
struct sensors_module_t {
struct hw_module_t common;
//获取传感器列表
int (*get_sensors_list)(struct sensors_module_t* module,
struct sensor_t const** list);
};
//传感器的描述性定义
struct sensor_t {
const char* name;
const char* vendor;
int version;
int handle; //传感器的句柄
int type;
float maxRange;
float resolution;
float power; //能耗 ma
int32_t minDelay;
void* reserved[8];
};
//表示传感器的数据
union {
float data[16];
sensors_vec_t acceleration; //方向
sensors_vec_t magnetic; //磁矢量
sensors_vec_t orientation; //加速度
sensors_vec_t gyro; //陀螺仪
float temperature; //温度
float distance; //距离
float light; //亮度
float pressure; //压强
};
uint32_t reserved1[4];
} sensors_event_t;
//用户控制设备
struct sensors_poll_device_t {
struct hw_device_t common;
int (*activate)(struct sensors_poll_device_t *dev,
int handle, int enabled);
int (*setDelay)(struct sensors_poll_device_t *dev,
int handle, int64_t ns);
int (*poll)(struct sensors_poll_device_t *dev,
sensors_event_t* data, int count);
};
//用于打开和关闭传感器设备, 打开的过程从native_handle_t开始, pull函数是核心,
调用时被子阻塞,直到传感器获得数据返回
static inline int sensors_open(const struct hw_module_t* module,
struct sensors_poll_device_t** device) {
return module->methods->open(module,
SENSORS_HARDWARE_POLL, (struct hw_device_t**)device);
}
static inline int sensors_close(struct sensors_poll_device_t* device) {
return device->common.close(&device->common);
}
硬件抽象层的示例实现
模似器提供了一个示例实现,代码路径为:sdk\emulator\sensors
//
static struct hw_module_methods_t sensors_module_methods = {
.open = open_sensors
};
open_sensors函数用于构建控制设备和数据设备
static int
open_sensors(const struct hw_module_t* module,
const char* name,
struct hw_device_t* *device)
{
int status = -EINVAL;
D("%s: name=%s", __FUNCTION__, name);
if (!strcmp(name, SENSORS_HARDWARE_CONTROL))
{
SensorControl *dev = malloc(sizeof(*dev));
memset(dev, 0, sizeof(*dev));
dev->device.common.tag = HARDWARE_DEVICE_TAG;
dev->device.common.version = 0;
dev->device.common.module = (struct hw_module_t*) module;
dev->device.common.close = control__close;
dev->device.open_data_source = control__open_data_source;
dev->device.activate = control__activate;
dev->device.set_delay = control__set_delay;
dev->device.wake = control__wake;
dev->fd = -1;
*device = &dev->device.common;
status = 0;
}
else if (!strcmp(name, SENSORS_HARDWARE_DATA)) {
SensorData *dev = malloc(sizeof(*dev));
memset(dev, 0, sizeof(*dev));
dev->device.common.tag = HARDWARE_DEVICE_TAG;
dev->device.common.version = 0;
dev->device.common.module = (struct hw_module_t*) module;
dev->device.common.close = data__close;
dev->device.data_open = data__data_open;
dev->device.data_close = data__data_close;
dev->device.poll = data__poll;
dev->events_fd = -1;
*device = &dev->device.common;
status = 0;
}
return status;
}
//定义取得传感器列表的函数指针
const struct sensors_module_t HAL_MODULE_INFO_SYM = {
.common = {
.tag = HARDWARE_MODULE_TAG,
.version_major = 1,
.version_minor = 0,
.id = SENSORS_HARDWARE_MODULE_ID,
.name = "Goldfish SENSORS Module",
.author = "The Android Open Source Project",
.methods = &sensors_module_methods,
},
.get_sensors_list = sensors__get_sensors_list
};
static uint32_t sensors__get_sensors_list(struct sensors_module_t* module,
struct sensor_t const** list)
{
int fd = qemud_channel_open(SENSORS_SERVICE_NAME);
char buffer[12];
int mask, nn, count;
int ret;
if (fd < 0) {
E("%s: no qemud connection", __FUNCTION__);
return 0;
}
ret = qemud_channel_send(fd, "list-sensors", -1);
if (ret < 0) {
E("%s: could not query sensor list: %s", __FUNCTION__,
strerror(errno));
close(fd);
return 0;
}
ret = qemud_channel_recv(fd, buffer, sizeof buffer-1);
if (ret < 0) {
E("%s: could not receive sensor list: %s", __FUNCTION__,
strerror(errno));
close(fd);
return 0;
}
buffer[ret] = 0;
close(fd);
/* the result is a integer used as a mask for available sensors */
mask = atoi(buffer);
count = 0;
for (nn = 0; nn < MAX_NUM_SENSORS; nn++) {
if (((1 << nn) & mask) == 0)
continue;
sSensorList[count++] = sSensorListInit[nn];
}
D("%s: returned %d sensors (mask=%d)", __FUNCTION__, count, mask);
*list = sSensorList;
return count;
}
最后返回的是一个sensor_t类型的数组,部分代码如下(定义了四个传感器):
static const struct sensor_t sSensorListInit[] = {
//加速度
{ .name = "Goldfish 3-axis Accelerometer",
.vendor = "The Android Open Source Project",
.version = 1,
.handle = ID_ACCELERATION,
.type = SENSOR_TYPE_ACCELEROMETER,
.maxRange = 2.8f,
.resolution = 1.0f/4032.0f,
.power = 3.0f,
.reserved = {}
},
//磁场
{ .name = "Goldfish 3-axis Magnetic field sensor",
.vendor = "The Android Open Source Project",
.version = 1,
.handle = ID_MAGNETIC_FIELD,
.type = SENSOR_TYPE_MAGNETIC_FIELD,
.maxRange = 2000.0f,
.resolution = 1.0f,
.power = 6.7f,
.reserved = {}
},
//方向
{ .name = "Goldfish Orientation sensor",
.vendor = "The Android Open Source Project",
.version = 1,
.handle = ID_ORIENTATION,
.type = SENSOR_TYPE_ORIENTATION,
.maxRange = 360.0f,
.resolution = 1.0f,
.power = 9.7f,
.reserved = {}
},
//温度
{ .name = "Goldfish Temperature sensor",
.vendor = "The Android Open Source Project",
.version = 1,
.handle = ID_TEMPERATURE,
.type = SENSOR_TYPE_TEMPERATURE,
.maxRange = 80.0f,
.resolution = 1.0f,
.power = 0.0f,
.reserved = {}
},
};
static int
data__poll(struct sensors_data_device_t *dev, sensors_data_t* values)
{
SensorData* data = (void*)dev;
int fd = data->events_fd;
D("%s: data=%p", __FUNCTION__, dev);
// there are pending sensors, returns them now...
if (data->pendingSensors) {
return pick_sensor(data, values);
}
// wait until we get a complete event for an enabled sensor
uint32_t new_sensors = 0;
//读取传感器信息 ,设置sensor_data_t结构体数据
while (1) {
/* read the next event */
char buff[256];
int len = qemud_channel_recv(data->events_fd, buff, sizeof buff-1);
float params[3];
int64_t event_time;
if (len < 0) {
E("%s: len=%d, errno=%d: %s", __FUNCTION__, len, errno, strerror(errno));
return -errno;
}
buff[len] = 0;
/* "wake" is sent from the emulator to exit this loop. This shall
* really be because another thread called "control__wake" in this
* process.
*/
if (!strcmp((const char*)data, "wake")) {
return 0x7FFFFFFF;
}
/* "acceleration:<x>:<y>:<z>" corresponds to an acceleration event */
if (sscanf(buff, "acceleration:%g:%g:%g", params+0, params+1, params+2) == 3) {
new_sensors |= SENSORS_ACCELERATION;
data->sensors[ID_ACCELERATION].acceleration.x = params[0];
data->sensors[ID_ACCELERATION].acceleration.y = params[1];
data->sensors[ID_ACCELERATION].acceleration.z = params[2];
continue;
}
/* "orientation:<azimuth>:<pitch>:<roll>" is sent when orientation changes */
if (sscanf(buff, "orientation:%g:%g:%g", params+0, params+1, params+2) == 3) {
new_sensors |= SENSORS_ORIENTATION;
data->sensors[ID_ORIENTATION].orientation.azimuth = params[0];
data->sensors[ID_ORIENTATION].orientation.pitch = params[1];
data->sensors[ID_ORIENTATION].orientation.roll = params[2];
continue;
}
/* "magnetic:<x>:<y>:<z>" is sent for the params of the magnetic field */
if (sscanf(buff, "magnetic:%g:%g:%g", params+0, params+1, params+2) == 3) {
new_sensors |= SENSORS_MAGNETIC_FIELD;
data->sensors[ID_MAGNETIC_FIELD].magnetic.x = params[0];
data->sensors[ID_MAGNETIC_FIELD].magnetic.y = params[1];
data->sensors[ID_MAGNETIC_FIELD].magnetic.z = params[2];
continue;
}
/* "temperature:<celsius>" */
if (sscanf(buff, "temperature:%g", params+0) == 2) {
new_sensors |= SENSORS_TEMPERATURE;
data->sensors[ID_TEMPERATURE].temperature = params[0];
continue;
}
/* "sync:<time>" is sent after a series of sensor events.
* where 'time' is expressed in micro-seconds and corresponds
* to the VM time when the real poll occured.
*/
if (sscanf(buff, "sync:%lld", &event_time) == 1) {
if (new_sensors) {
data->pendingSensors = new_sensors;
int64_t t = event_time * 1000LL; /* convert to nano-seconds */
/* use the time at the first sync: as the base for later
* time values */
if (data->timeStart == 0) {
data->timeStart = data__now_ns();
data->timeOffset = data->timeStart - t;
}
t += data->timeOffset;
while (new_sensors) {
uint32_t i = 31 - __builtin_clz(new_sensors);
new_sensors &= ~(1<<i);
data->sensors[i].time = t;
}
return pick_sensor(data, values);
} else {
D("huh ? sync without any sensor data ?");
}
continue;
}
D("huh ? unsupported command");
}
}
传感器硬件层实现的要点
1 可以支持多个传感器,也可支多个同类型的传感器,需要构建一个sensor_t类型的数组
2 传感器的控制设备和数据设备可能被扩展,用来保存传感器抽象层的上下文
前提是sensor_control_device_t和sensors_data_device_t两个数据结构需要作为扩展结构体的第一个成员
3 传感器在linux内核的驱动程序很可能使用misc驱动程序 这时需要在开发控制设备时,同样使用open 打开传感器的设备结点
4 传感器数据设备poll指针是实现的重点, 传感器在没有数据变化时实现阻塞,在数据变化时返回,
根据驱动程序的情况可以使用poll,read 或者ioctl等接口来实现,这些驱动程序可以实现相应的阻塞
当传感器控制设备的wake()被调用时,需要让数据设备的pool立即返回0x7fffffff
传感器的使用
取得SensorManager(系统服务)
sensorManager = (SensorManager) this.getSystemService(Context.SENSOR_SERVICE);
OrientationEventListener扩展了sensorEventListener
public OrientationEventListener(Context context, int rate) {
//取得传感器服务
mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
mRate = rate;
//取得加速度传感器
mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
if (mSensor != null) {
// Create listener only if sensors do exist
mSensorEventListener = new SensorEventListenerImpl();
}
}
//注册传感器的监听事件
public void enable() {
if (mSensor == null) {
Log.w(TAG, "Cannot detect sensors. Not enabled");
return;
}
if (mEnabled == false) {
if (localLOGV) Log.d(TAG, "OrientationEventListener enabled");
mSensorManager.registerListener(mSensorEventListener, mSensor, mRate);
mEnabled = true;
}
}
class SensorEventListenerImpl implements SensorEventListener {
//通过加速度信信息取得方向信息
public void onSensorChanged(SensorEvent event) {}
}
在清单文件中设置activity属性
android:screenOrientation="sensor" //根据传感器设置屏幕方向
如果属性设置为nosensor 则不会改变方向