传感器是现在手机上不可或缺的的一部分,到了android4.0系统总共支持13类的传感器分别为
#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 #define SENSOR_TYPE_RELATIVE_HUMIDITY 12 #define SENSOR_TYPE_AMBIENT_TEMPERATURE 13
二、架构分析
1.应用程序层
从网上找到一个android应用程序访问传感器的方法,流程如下
//1、取得重力感应器Sensor对象 //在 Activity 中定义以下成员变量: private SensorManager mManager = null; private Sensor mSensor = null; //以下代码加入到 onCreate() 方法中: mManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); //创建SensorManager mSensor = manager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);//得到重力感应器 //2、创建监听器 //在 Activity 中定义以下成员变量: private SensorEventListener mListener = null; //以下代码加入到 onCreate() 方法中: mListener = new SensorEventListener() { public void onAccuracyChanged(Sensor sensor, int accuracy) { public void onSensorChanged(SensorEvent event) { float x = event.values[SensorManager.DATA_X]; float y = event.values[SensorManager.DATA_Y]; float z = event.values[SensorManager.DATA_Z]; doSomething(x, y, z); } }; //3、注册监听器 //以下代码加入到 onResume() 方法中: mManager.registerListener(mListener, mSensor, SensorManager.SENSOR_DELAY_GAME); //这里 SENSOR_DELAY_GAME 还可以是以下常量: //SENSOR_DELAY_FASTEST //SENSOR_DELAY_UI //SENSOR_DELAY_NORMAL //4、取消监听器 //以下代码加入到 onPause() 方法中: mManager.unregisterListener(mListener); 参考:http://www.oschina.net/code/snippet_12_687
2.framework层
SensorService代码在android\frameworks\base\services\sensorservice\SensorService.cpp中,
app中通过getSystemService()方法可以访问到getSystemService
SensorManager代码在android\frameworks\base\core\java\android\hardware\SensorManager.java中,
他是sensor事件的总管理器,包括打开设备读取事件 分发事件等功能
3jni层
jni层主要包含两个文件
android\frameworks\base\core\jni\android_hardware_SensorManager.cpp//主要是method的注册,为java提供下层访问接口
android\frameworks\base\services\sensorservice\SensorDevice.cpp//主要是动态链接库访问,jni层和hal层访问方式是通过
动态链接库来实现的,这个文件里实现了动态链接库的打开,和访问函数封装等一些操作
4.hal层
在这个层里,我们主要就分析动态链接库的实现的主要功能有哪些
这个库实现代码在android\hardware\imx\libsensors\sensors.cpp中它的入口代码为:
struct sensors_module_t HAL_MODULE_INFO_SYM = { common: { tag: HARDWARE_MODULE_TAG, version_major: 1, version_minor: 1, id: SENSORS_HARDWARE_MODULE_ID, name: "Freescale Sensor module", author: "Freescale Semiconductor Inc.", methods: &sensors_module_methods,//链接库的操作集 }, get_sensors_list: sensors__get_sensors_list, //sensorlist实现 };
static int sensors__get_sensors_list(struct sensors_module_t* module, struct sensor_t const** list) { *list = sSensorList; return ARRAY_SIZE(sSensorList); } static const struct sensor_t sSensorList[] = { { "MMA 3-axis Accelerometer", "Freescale Semiconductor Inc.", 1, SENSORS_ACCELERATION_HANDLE, SENSOR_TYPE_ACCELEROMETER, RANGE_A, CONVERT_A, 0.30f, 20000, { } }, { "MAG3110 3-axis Magnetic field sensor", "Freescale Semiconductor Inc.", 1, SENSORS_MAGNETIC_FIELD_HANDLE, SENSOR_TYPE_MAGNETIC_FIELD, 1500.0f, CONVERT_M, 0.50f, 100000, { } }, { "MAG3110 Orientation sensor", "Freescale Semiconductor Inc.", 1, SENSORS_ORIENTATION_HANDLE, SENSOR_TYPE_ORIENTATION, 360.0f, CONVERT_O, 0.50f, 100000, { } }, { "MPL3115 Pressure sensor", "Freescale Semiconductor Inc.", 1, SENSORS_PRESSURE_HANDLE, SENSOR_TYPE_PRESSURE, 1100.0f, CONVERT_PRESSURE, 0.35f, 0, { } }, { "MPL3115 Temperature sensor", "Freescale Semiconductor Inc.", 1, SENSORS_TEMPERATURE_HANDLE, SENSOR_TYPE_TEMPERATURE, 85.0f, CONVERT_TEMPERATURE, 0.35f, 0, { } }, { "ISL29023 Light sensor", "Intersil", 1, SENSORS_LIGHT_HANDLE, SENSOR_TYPE_LIGHT, 16000.0f, 1.0f, 0.35f, 0, { } }, };
然后来看sensors_module_methods传感器操作集
static struct hw_module_methods_t sensors_module_methods = { open: open_sensors }; static int open_sensors(const struct hw_module_t* module, const char* id, struct hw_device_t** device) { int status = -EINVAL; sensors_poll_context_t *dev = new sensors_poll_context_t(); memset(&dev->device, 0, sizeof(sensors_poll_device_t)); dev->device.common.tag = HARDWARE_DEVICE_TAG; dev->device.common.version = 0; dev->device.common.module = const_cast<hw_module_t*>(module); dev->device.common.close = poll__close; dev->device.activate = poll__activate; dev->device.setDelay = poll__setDelay; dev->device.poll = poll__poll; *device = &dev->device.common; status = 0; return status; }
static int poll__close(struct hw_device_t *dev) //直接删除设备上下文 { sensors_poll_context_t *ctx = (sensors_poll_context_t *)dev; if (ctx) { delete ctx; } return 0; } static int poll__activate(struct sensors_poll_device_t *dev, int handle, int enabled) { sensors_poll_context_t *ctx = (sensors_poll_context_t *)dev; return ctx->activate(handle, enabled); } | V int sensors_poll_context_t::activate(int handle, int enabled) { int index = handleToDriver(handle); int err = 0 ; if (index < 0) return index; if(handle == ID_O || handle == ID_M){ err = mSensors[accel]->enable(ID_A, enabled); if(err) return err; } err |= mSensors[index]->enable(handle, enabled); if (enabled && !err) { const char wakeMessage(WAKE_MESSAGE); int result = write(mWritePipeFd, &wakeMessage, 1); LOGE_IF(result<0, "error sending wake message (%s)", strerror(errno)); } return err; }
int SensorBase::enable(int32_t handle, int enabled) { sensorBaseEnable(handle,enabled); return 0; } int SensorBase::sensorBaseEnable(int32_t handle,int enabled){ 。。。。。。。。。。。。。 if((enable && mUser[what] == 1) || (enable ==0 && mUser[what] == 0 )) { snprintf(buf,sizeof(buf),"%d",enable); write_sysfs(sysfs_enable,buf,strlen(buf)); //向sysfs文件系统中写入数据,这里涉及到了文件系统的操作进入了内核空间。 mEnabled &= ~(1<<what); mEnabled |= (uint32_t(enable)<<what); } 。。。。。。。。。。。。。。 } static int poll__setDelay(struct sensors_poll_device_t *dev, int handle, int64_t ns) { sensors_poll_context_t *ctx = (sensors_poll_context_t *)dev; return ctx->setDelay(handle, ns); } | V int SensorBase::sensorBaseSetDelay(int32_t handle, int64_t ns){ char buf[6]; int ms; ms = ns/1000/1000; if(ms < mMinPollDelay) ms = mMinPollDelay ; else if(ms > mMaxPollDelay) ms = mMaxPollDelay; snprintf(buf,sizeof(buf),"%d",ms); return write_sysfs(sysfs_poll,buf,strlen(buf)); //想文件系统中写入数据 进入内核空间 } static int poll__poll(struct sensors_poll_device_t *dev, sensors_event_t* data, int count) { sensors_poll_context_t *ctx = (sensors_poll_context_t *)dev; return ctx->pollEvents(data, count); } | V static int poll__poll(struct sensors_poll_device_t *dev, sensors_event_t* data, int count) { sensors_poll_context_t *ctx = (sensors_poll_context_t *)dev; return ctx->pollEvents(data, count); } 我们来看pollEvents这个函数实现了设备事件的读取 int sensors_poll_context_t::pollEvents(sensors_event_t* data, int count) { int nbEvents = 0; int n = 0; do { // see if we have some leftover from the last poll() for (int i=0 ; count && i<numSensorDrivers ; i++) { //循环读取所有sensorlist中设备的event SensorBase* const sensor(mSensors[i]); if ((mPollFds[i].revents & POLLIN) || (sensor->hasPendingEvents())) { int nb = sensor->readEvents(data, count); //读取事件 if (nb < count) { // no more data for this sensor mPollFds[i].revents = 0; } count -= nb; nbEvents += nb; data += nb; } } 。。。。。。。。。。。。。。。。 return nbEvents; } 继续看 int SensorBase::readEvents(sensors_event_t* data, int count) { 。。。。。。 ssize_t n = mInputReader.fill(data_fd); //填充eventbuf //mInputReader代码在android\hardware\imx\libsensors\InputEventReader.cpp中这个类,在这里就不多做分析了, //内容比较简单,就是从设备文件中读取数据然后进行一定的处理传送给上层 。。。。。。。。 for (int j=0 ; count && mPendingMask && j<numSensors ; j++) { if (mPendingMask & (1<<j)) { mPendingMask &= ~(1<<j); mPendingEvents[j].timestamp = time; if (mEnabled & (1<<j)) { *data++ = mPendingEvents[j]; //数据复制到buf中 count--; numEventReceived++; } } } 。。。。。。。。。。 return numEventReceived; //返回读数个数 }
SensorBase::SensorBase( const char* dev_name, //打开的设备文件的名字 const char* data_name) : dev_name(dev_name), data_name(data_name), dev_fd(-1), data_fd(-1), mInputReader(64) { if (data_name) data_fd = openInput(data_name); } | | V int SensorBase::openInput(const char* inputName) { int fd = -1; int input_id = -1; const char *dirname = "/dev/input"; const char *inputsysfs = "/sys/class/input"; char devname[PATH_MAX]; char *filename; DIR *dir; struct dirent *de; dir = opendir(dirname); if(dir == NULL) return -1; strcpy(devname, dirname); filename = devname + strlen(devname); *filename++ = '/'; while((de = readdir(dir))) { if(de->d_name[0] == '.' && (de->d_name[1] == '\0' || (de->d_name[1] == '.' && de->d_name[2] == '\0'))) continue; strcpy(filename, de->d_name); fd = open(devname, O_RDONLY); //这里涉及到打开设备文件 。。。。。。。。。。。。。。。。。。。。。。。。 } closedir(dir); LOGE_IF(fd<0, "couldn't find '%s' input device", inputName); return fd; }到了这里hal层的分析已经完成了,总结一下:当android上层打开这个动态链接库的时候,sensors_poll_context_t这个类会
5.kernel层
对于kernel的input系统分析,我们前边有篇文章专门介绍过http://blog.csdn.net/dkleikesa/article/details/9384009大家可以参考
6.内核驱动
剩下的主要是设备驱动。在kernel中传感器设备都是hwmon类的,hwmon全名hardware monitor,是linux规定的硬件监测的设备类,这个类为我们提供了,设备文件和设备属性设定的通用方法,不过在freescale的android平台中貌似都没用到,这个平台android层和kernel层是通过input设备来通信的,下面 我们以mma8451三轴重力感应器为例子来讲述sensor驱动的具体写法
mma8451是一款i2c接口的传感器,驱动的整体架构也是跟其他i2c设备一样的,因此我们重点来开 probe 和 event发送的函数
static int __devinit mma8451_probe(struct i2c_client *client, const struct i2c_device_id *id) { int result, client_id; struct input_dev *idev; struct i2c_adapter *adapter; mma8451_i2c_client = client; adapter = to_i2c_adapter(client->dev.parent); result = i2c_check_functionality(adapter, //检测此i2c设备是否支持I2C_FUNC_SMBUS_BYTE和I2C_FUNC_SMBUS_BYTE_DATA这两个属性 I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA); if (!result) goto err_out; client_id = i2c_smbus_read_byte_data(client, MMA8451_WHO_AM_I);//读ID if (client_id != MMA8451_ID && client_id != MMA8452_ID && client_id != MMA8453_ID) { dev_err(&client->dev, "read chip ID 0x%x is not equal to 0x%x or 0x%x!\n", result, MMA8451_ID, MMA8452_ID); result = -EINVAL; goto err_out; } /* Initialize the MMA8451 chip */ result = mma8451_change_mode(client, senstive_mode); //初始化mma8451 就是配置一些寄存器 if (result) { dev_err(&client->dev, "error when init mma8451 chip:(%d)\n", result); goto err_out; } hwmon_dev = hwmon_device_register(&client->dev);//创建一个硬件监听设备 if (!hwmon_dev) { result = -ENOMEM; dev_err(&client->dev, "error when register hwmon device\n"); goto err_out; } mma8451_idev = input_allocate_polled_device(); //分配一个poll类型的input设备 if (!mma8451_idev) { result = -ENOMEM; dev_err(&client->dev, "alloc poll device failed!\n"); goto err_alloc_poll_device; } mma8451_idev->poll = mma8451_dev_poll;//poll回调函数 mma8451_idev->poll_interval = POLL_INTERVAL; mma8451_idev->poll_interval_min = POLL_INTERVAL_MIN; mma8451_idev->poll_interval_max = POLL_INTERVAL_MAX; idev = mma8451_idev->input; idev->name = "mma845x";//这个名字必须和hal层的名字对应上否则找不到设备文件 idev->id.bustype = BUS_I2C; idev->evbit[0] = BIT_MASK(EV_ABS); input_set_abs_params(idev, ABS_X, -8192, 8191, INPUT_FUZZ, INPUT_FLAT); //设备支持的3个数据 input_set_abs_params(idev, ABS_Y, -8192, 8191, INPUT_FUZZ, INPUT_FLAT); input_set_abs_params(idev, ABS_Z, -8192, 8191, INPUT_FUZZ, INPUT_FLAT); result = input_register_polled_device(mma8451_idev);//注册这个poll设备 if (result) { dev_err(&client->dev, "register poll device failed!\n"); goto err_register_polled_device; } result = sysfs_create_group(&idev->dev.kobj, &mma8451_attr_group);//为这个设备创建sysfs 设备文件 if (result) { dev_err(&client->dev, "create device file failed!\n"); result = -EINVAL; goto err_register_polled_device; } mma_status.position = *(int *)client->dev.platform_data; return 0; err_register_polled_device: input_free_polled_device(mma8451_idev); err_alloc_poll_device: hwmon_device_unregister(&client->dev); err_out: return result; }
下面我们看,poll设备注册的poll回调函数
static void mma8451_dev_poll(struct input_polled_dev *dev) { report_abs(); } static void report_abs(void) { short x, y, z; int result; int retry = 3; mutex_lock(&mma8451_lock); if (mma_status.active == MMA_STANDBY) goto out; /* wait for the data ready */ do { result = i2c_smbus_read_byte_data(mma8451_i2c_client, MMA8451_STATUS); retry--; msleep(1); } while (!(result & MMA8451_STATUS_ZYXDR) && retry > 0); if (retry == 0) goto out; if (mma8451_read_data(&x, &y, &z) != 0) goto out; mma8451_adjust_position(&x, &y, &z); //调整xyz 三轴 input_report_abs(mma8451_idev->input, ABS_X, x); //报告事件 input_report_abs(mma8451_idev->input, ABS_Y, y); input_report_abs(mma8451_idev->input, ABS_Z, z); input_sync(mma8451_idev->input); out: mutex_unlock(&mma8451_lock); } //从这个函数可以看出 sensor的事件报告方式是标准的input_report_abs()函数,并没什么特殊性不多做说明