我是靠谱客的博主 纯真自行车,最近开发中收集的这篇文章主要介绍android Sensor 驱动编写--opt3001光感驱动为例,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

分析Android sensor

Android sensor Framework 层以及APP如何读取sensor 数据。网上有很多文章不再累述。

由于我使用的是Android 5.1(kernel 3.10) ,不自带 opt3001的驱动,我发现kernel 4.10 已经自带opt3001的驱动。我不会为了一个驱动而换掉 kernel。而且 kernel 4.10 opt3001的驱动高度依赖与iio。两个kernel 版本的iio修改较大。移植也不是简单的复制。索性不看 kernel 4.10 上的代码。我们分析 Android 5.1(kernel 3.10)的代码。

其实写一个驱动读取 opt3001 中的数据并不难。看一看opt3001 的数据手册,就几个寄存器。配置也很简单。

然后我们看一下Android 是如何从kernel 中读取 光感数据的。自然是去看 HAL层的代码。我可以在hardware目录下找到LightSensor.cpp 。一般我们拿到的源码 HAL层到Framework,数据通路都是好的。不需要修改。
我们分析一下 LightSensor.cpp 我们可以看到class LightSensor 继承自 SamsungSensorBase 。SamsungSensorBase 又继承自 SensorBase。分析这几个类。并没有什么难的。

我们先看 SensorBase。

SensorBase::SensorBase(
        const char* dev_name,
        const char* data_name)
    : dev_name(dev_name), data_name(data_name),
      dev_fd(-1), data_fd(-1)
{
    if (data_name) {
        data_fd = openInput(data_name);
    }
}
int SensorBase::open_device() {
    if (dev_fd<0 && dev_name) {
        dev_fd = open(dev_name, O_RDONLY);
        LOGE_IF(dev_fd<0, "Couldn't open %s (%s)", dev_name, strerror(errno));
    }
    return 0;
}
static int getInput(const char *inputName)
{
    int fd = -1;
    unsigned i; 
    static bool first = true;
    static struct input_dev dev[255];

    if (first) { 
        int fd = -1;
        const char *dirname = "/dev/input";
        char devname[PATH_MAX];
        char *filename;
        DIR *dir;
        struct dirent *de;

        first = false;
        for (i = 0; i < sizeof(dev)/sizeof(dev[0]); i++) {
            dev[i].fd = -1;
            dev[i].name[0] = '';
        } 
        i = 0;

        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] == '' || (de->d_name[1] == '.' && de->d_name[2] == '')))
                    continue;
            strcpy(filename, de->d_name);
            fd = open(devname, O_RDONLY);
            if (fd >= 0) {
                char name[80];
                if (ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) >= 1) {
                    dev[i].fd = fd;
                    strncpy(dev[i].name, name, sizeof(dev[i].name));
                }
            }
            i++;
        }
        closedir(dir);
    }

    for (i = 0; i < sizeof(dev)/sizeof(dev[0]); i++) {
        if (!strncmp(inputName, dev[i].name, sizeof(dev[i].name))) {
            fd = dev[i].fd;
            break;
        }
    }
    LOGE_IF(fd < 0, "couldn't find '%s' input device", inputName);

    return fd;
}
int SensorBase::openInput(const char* inputName) {
    int fd = -1;
    const char *dirname = "/dev/input";
    char devname[PATH_MAX];
    char *filename;
    DIR *dir;
    struct dirent *de;

    return getInput(inputName);

    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] == '' ||
                        (de->d_name[1] == '.' && de->d_name[2] == '')))
            continue;
        strcpy(filename, de->d_name);
        fd = open(devname, O_RDONLY);
        if (fd>=0) {
            char name[80];
            if (ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) {
                name[0] = '';
            }
            if (!strcmp(name, inputName)) {
                strcpy(input_name, filename);
                break;
            } else {
                close(fd);
                fd = -1;
            }
        }
    }
    closedir(dir);
    LOGE_IF(fd<0, "couldn't find '%s' input device", inputName);
    return fd;
}

这段代码很简单了。可以看出:
这里要用到 dev_name 和 data_name。
dev_name 用open()函数打开,这个最熟悉不过了。
data_name 从代码来看 是一个input 设备,从 getInput() 方法中很清楚的看到,程序要在 /dev/input目录下打开所有input 设备, 查找一个name 匹配 data_name的设备。

我们看一下 SamsungSensorBase

SamsungSensorBase::SamsungSensorBase(const char *dev_name,
                                     const char *data_name,
                                     int sensor_code)
    : SensorBase(dev_name, data_name),
      mEnabled(false), //cvt_zxl modify
      mHasPendingEvent(false),
      mInputReader(4),
      mSensorCode(sensor_code),
      mLock(PTHREAD_MUTEX_INITIALIZER)
{
    mPendingEvent.version = sizeof(sensors_event_t);
    memset(mPendingEvent.data, 0, sizeof(mPendingEvent.data));
    if (!data_fd)
        return;
    mInputSysfsEnable = makeSysfsName(input_name, "enable");
    if (!mInputSysfsEnable) {
        ALOGE("%s: unable to allocate mem for %s:enable", __func__,
             data_name);
        return;
    }
    mInputSysfsPollDelay = makeSysfsName(input_name, "poll_delay");
    if (!mInputSysfsPollDelay) {
        ALOGE("%s: unable to allocate mem for %s:poll_delay", __func__,
             data_name);
        return;
    }

    int flags = fcntl(data_fd, F_GETFL, 0);
    fcntl(data_fd, F_SETFL, flags | O_NONBLOCK);
}

int SamsungSensorBase::readEvents(sensors_event_t* data, int count)
{
    if (count < 1)
        return -EINVAL;

    pthread_mutex_lock(&mLock);
    int numEventReceived = 0;

    if (mHasPendingEvent) {
        mHasPendingEvent = false;
        if (mEnabled) {
            mPendingEvent.timestamp = getTimestamp();
            *data = mPendingEvent;
            numEventReceived++;
        }
        goto done;
    }

    input_event const* event;
    while (count && mInputReader.readEvent(data_fd, &event)) {
        if (event->type == EV_ABS) {
            if (event->code == mSensorCode) {
                if (mEnabled && handleEvent(event)) {
                    mPendingEvent.timestamp = timevalToNano(event->time);
                    *data++ = mPendingEvent;
                    count--;
                    numEventReceived++;
                }
            }
        }
        mInputReader.next();
    }

done:
    pthread_mutex_unlock(&mLock);
    return numEventReceived;

}

readEvents()这个方法 显然是在读input 设备上报的数据。充这个方法我们可以看到 input event 的 type 必须是 EV_ABS ,还有 code 必须是 mSensorCode ,mSensorCode 这个参数很显然 需要具体的实现类。
在 SamsungSensorBase 的构造函数中,可以看到 mSensorCode。
读取到 event 之后,把event 交给 handleEvent。handleEvent(),也由具体实现类来处理。
是时候去看一下 LightSensor 了

LightSensor::LightSensor()
    : SamsungSensorBase("/dev/lightsensor", "lightsensor-level", ABS_MISC)
{
    mPendingEvent.sensor = ID_L;
    mPendingEvent.type = SENSOR_TYPE_LIGHT;
    mPreviousLight = -1;
}

int LightSensor::handleEnable(int en) {
    mPreviousLight = -1;
    int flags = en ? 1 : 0;
    int err = 0;
    if (flags != mEnabled) {
        if (!mEnabled) {
            open_device();
        }
        err = ioctl(dev_fd, LIGHTSENSOR_IOCTL_ENABLE, &flags);
        err = err<0 ? -errno : 0;
        ALOGE_IF(err, "LIGHTSENSOR_IOCTL_ENABLE failed (%s)", strerror(-err));
        if (!err) {
            mEnabled = en ? 1 : 0;
        }
        if (!mEnabled) {
            close_device();
        }
    }
    return err;
}

bool LightSensor::handleEvent(input_event const *event) {
    if (event->value == -1) {
        return false;
    }
    mPendingEvent.light = indexToValue(event->value);
   // mPendingEvent.light = event->value;
    if (mPendingEvent.light != mPreviousLight) {
        mPreviousLight = mPendingEvent.light;
        return true;
    }
    return true;
}

float LightSensor::indexToValue(size_t index) const {
    /* Driver gives a rolling average adc value.  We convert it lux levels. */
    //subingxi modify
    float val;
    val = index/1000.0;
    return val;
}

从这里我们就看到了:
dev_name 为 /dev/lightsensor
data_name 为 lightsensor-level
mSensorCode 为 ABS_MISC
看 handleEvent(); 就知道,最终数据被填充到了 mPendingEvent.light。

整个过程就非常清晰了。

另外看一眼 handleEnable 就知道了 dev_name 用 ioctl(dev_fd, LIGHTSENSOR_IOCTL_ENABLE, &flags); 来控制使能。

驱动要求

知道这些,写驱动 就非常简单了。
我们需要写一个 miscdevice :

  • name 为 lightsensor
  • 支持ioctl ,LIGHTSENSOR_IOCTL_ENABLE 控制使能

我们要写一个input 设备:

  • name 为 lightsensor-level
  • 事件类型 EV_ABS
  • code 为 ABS_MISC

驱动编写

分析到这里,写驱动 就太简单了。列出几个代码片段

static struct miscdevice opt3001_lsensor_misc = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = "lightsensor",
    .fops = &opt3001_lsensor_fops
};



//读芯片id
static int opt3001_read_id(struct i2c_client *client)
{
    char manufacturer[2];
    u16 device_id;
    int ret;

    ret = i2c_smbus_read_word_swapped(client, OPT3001_MANUFACTURER_ID);
    if (ret < 0) {
        printk("failed to read register %02xn",
                OPT3001_MANUFACTURER_ID);
        return ret;

    }

    manufacturer[0] = ret >> 8;
    manufacturer[1] = ret & 0xff;

    ret = i2c_smbus_read_word_swapped(client, OPT3001_DEVICE_ID);
    if (ret < 0) {
        printk("failed to read register %02xn",
                OPT3001_DEVICE_ID);
        return ret;

    }

    device_id = ret;

    printk("Found %c%c OPT%04xn", manufacturer[0],
            manufacturer[1], device_id);

    return 0;

}
//配置 opt3001
static int opt3001_configure(struct i2c_client *client)
{
    int ret;
    ret = i2c_smbus_write_word_swapped(client, OPT3001_CONFIGURATION,
            OPT3001_CONFIGURATION_VAL);
    if (ret < 0) {
        printk("failed to write register %02xn",
                OPT3001_CONFIGURATION);
        return ret;
    }



    return 0;
}
//注册 input设备
static int init_input_dev(void) {

    int ret;
    input_dev = input_allocate_device();
    if(!input_dev){
        printk(KERN_ERR"%s: could not allocate input device for lsensorn", __FUNCTION__);
        return -ENOMEM;
    }
    input_dev->name = "lightsensor-level";
    set_bit(EV_ABS, input_dev->evbit);
    input_set_abs_params(input_dev, ABS_MISC, 0, 83865600, 0, 0);
    ret = input_register_device(input_dev);
    if(ret < 0) {
        printk(KERN_ERR"%s: could not register input device for lsensorn", __FUNCTION__);
        return ret;
    }
    return 0;

}
//读取 opt3001 光感强度
static int opt3001_get_lux(struct i2c_client *client)
{
    int ret;
    u16 mantissa;
    u8 exponent;
    u32 value;
    int lux;
    ret = i2c_smbus_read_word_swapped(client, OPT3001_RESULT);
        if (ret < 0) {
            printk("failed to read register %02xn",
                    OPT3001_RESULT);
            return -1;
        }

    value = ret;
    exponent = OPT3001_REG_EXPONENT(value);
    mantissa = OPT3001_REG_MANTISSA(value);
    lux = 10 * (mantissa << exponent);


    return lux;

}
//上传光强度
void opt3001_handler(struct work_struct *work) {
    struct i2c_client * client = g_client;
    int val;
    if(g_enable) {
      val = opt3001_get_lux(client);
      input_report_abs(input_dev,ABS_MISC,val);
      input_sync(input_dev);
    }
    schedule_delayed_work(&getwork,100);
}


最后

以上就是纯真自行车为你收集整理的android Sensor 驱动编写--opt3001光感驱动为例的全部内容,希望文章能够帮你解决android Sensor 驱动编写--opt3001光感驱动为例所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(47)

评论列表共有 0 条评论

立即
投稿
返回
顶部