Android增加自定义Sensor -- Human Sensor

该文档将告诉你如何在Android系统上增加人体接近感应Sensor,包含如何增加驱动、修改Hardware、Framework,以及APP如何使用该Sensor。

[toc]

源码

完整源码请参考:Android-HumanSensor

Driver

1. 新建 kernel/drivers/input/sensors/mwsensor/mwsensor.c

#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/ctype.h>
#include <linux/delay.h>
#include <linux/idr.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/signal.h>
#include <linux/pm.h>
#include <linux/notifier.h>
#include <linux/fb.h>
#include <linux/input.h>
#include <linux/ioport.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/kthread.h>
#include <linux/time.h>
#include <linux/timer.h>
#include <linux/regulator/consumer.h>
#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_gpio.h>
#include <linux/of_platform.h>
#include <linux/miscdevice.h>
#include <linux/uaccess.h>

#define MW_SENSOR_NAME "mwsensor"

#define MW_SENSOR_NEAR 1
#define MW_SENSOR_FAR  2

// ioctl cmd
#define MW_SENSOR_IOC_MAGIC  'm'

#define MW_SENSOR_IOC_ENABLE _IOW(MW_SENSOR_IOC_MAGIC, 1, int)
#define MW_SENSOR_IOC_SET_RATE _IOW(MW_SENSOR_IOC_MAGIC, 2, int)

#define MW_SENSOR_IOC_MAXNR 2


struct mw_sensor_data {
    struct platform_device  *platform_dev;
    struct miscdevice       mw_sensor_device;
    struct input_dev        *input_dev;
    struct notifier_block   notifier;
    
    int                     irq;
    int                     irq_gpio;
    unsigned long           suspend_time;
    bool                    is_suspended;
    u32                     is_delay;
    u32                     is_poll;
    u32                     delay_time;
    bool                    enabled;
};

static inline uint32_t gettime_now(void)
{
    struct timeval tv;
    do_gettimeofday(&tv);
    return tv.tv_sec;
}

static void mw_sensor_report_event(struct mw_sensor_data *mw_sensor, s32 data)
{
    struct input_dev *input = mw_sensor->input_dev;

    if (!mw_sensor->enabled) {
        return;
    }

    input_report_rel(input, REL_MISC, data);
    input_sync(input);
}

static int mw_sensor_enable(struct mw_sensor_data *mw_sensor) {
    mw_sensor->enabled = true;
    if (gpio_get_value(mw_sensor->irq_gpio)) {
         mw_sensor_report_event(mw_sensor, MW_SENSOR_NEAR); 
    } else {
        mw_sensor_report_event(mw_sensor, MW_SENSOR_FAR); 
    }
    return 0;
}

static int mw_sensor_disable(struct mw_sensor_data *mw_sensor) {
    mw_sensor->enabled = false;
    return 0;
}

static int mw_sensor_suspend(struct mw_sensor_data *mw_sensor)
{
    dev_info(&mw_sensor->platform_dev->dev, "mw_sensor_suspend\n");
    mw_sensor->suspend_time = gettime_now();
    mw_sensor->is_suspended = true;
    //enable_irq_wake(mw_sensor->irq);
    
    return 0;
}

static int mw_sensor_resume(struct mw_sensor_data *mw_sensor)
{
    dev_info(&mw_sensor->platform_dev->dev, "mw_sensor_resume\n");
    //mw_sensor->is_suspended = false;
    //disable_irq_wake(mw_sensor->irq);

    return 0;
}

static int mw_sensor_fb_event_notify(struct notifier_block *noti,
                                     unsigned long event, void *data)
{
    int *blank;
    struct fb_event *ev_data = data;
    struct mw_sensor_data *mw_sensor = container_of(noti,
                                struct mw_sensor_data, notifier);

    if (ev_data && ev_data->data && event == FB_EVENT_BLANK && mw_sensor) {
        blank = ev_data->data;
        if (*blank == FB_BLANK_UNBLANK) {
            mw_sensor_resume(mw_sensor);
        } else if (*blank == FB_BLANK_POWERDOWN) {
            mw_sensor_suspend(mw_sensor);
        }
    }

    return NOTIFY_OK;
}

static void mw_sensor_wakeup(struct mw_sensor_data *mw_sensor) {
    dev_info(&mw_sensor->platform_dev->dev, "%s, wake up\n", __func__);
    
    input_report_key(mw_sensor->input_dev, KEY_POWER, 1);
    input_sync(mw_sensor->input_dev);
    input_report_key(mw_sensor->input_dev, KEY_POWER, 0);
    input_sync(mw_sensor->input_dev);
}

static irqreturn_t mw_sensor_irq_handle(int irq, void *dev_id)
{
    struct mw_sensor_data *mw_sensor = dev_id;
    unsigned long cur_time = gettime_now();

    // dts中配置是否延时,因为待机过程会产生干扰,导致微波Sensor误触发
    if (!mw_sensor->is_delay || abs(cur_time - mw_sensor->suspend_time) > mw_sensor->delay_time) {
        if (gpio_get_value(mw_sensor->irq_gpio)) {
            if (mw_sensor->is_suspended) {
                mw_sensor->is_suspended = false;
                mw_sensor_wakeup(mw_sensor);
                msleep(100);
                mw_sensor_report_event(mw_sensor, MW_SENSOR_NEAR);
            } else {
                mw_sensor_report_event(mw_sensor, MW_SENSOR_NEAR); 
            }
        } else {
            mw_sensor_report_event(mw_sensor, MW_SENSOR_FAR); 
        }
    }

    return IRQ_HANDLED;
}

static void mw_sensor_free_irq(struct mw_sensor_data *mw_sensor)
{
    if(mw_sensor) {
        free_irq(mw_sensor->irq, mw_sensor);
    }
}

static void mw_sensor_free_io_port(struct mw_sensor_data *mw_sensor)
{
    if(gpio_is_valid(mw_sensor->irq_gpio)) {
        gpio_free(mw_sensor->irq_gpio);
    }
    return;
}

static int mw_sensor_parse_dt(struct device *dev,
                              struct mw_sensor_data *mw_sensor)
{
    int ret = 0;
    struct device_node *np = dev->of_node;

    mw_sensor->irq_gpio = of_get_named_gpio(np, "irq-gpios", 0);
    if(!gpio_is_valid(mw_sensor->irq_gpio)) {
        dev_err(dev, "No valid irq gpio");
        return -1;
    }

    ret = of_property_read_u32(np, "mwsensor,is_delay", &mw_sensor->is_delay);
    if (ret) {
        mw_sensor->is_delay = 0;
    }

    ret = of_property_read_u32(np, "mwsensor,delay_time", &mw_sensor->delay_time);
    if (ret) {
        mw_sensor->delay_time = 3;
    }

    ret = of_property_read_u32(np, "mwsensor,is_poll", &mw_sensor->is_poll);
    if (ret) {
        mw_sensor->is_poll = 0;
    }

    dev_info(dev, "mw_sensor_parse_dt, is_delay=%d is_poll=%d delay_time=%d\n", 
        mw_sensor->is_delay, mw_sensor->is_poll, mw_sensor->delay_time);

    return 0;
}

static int mw_sensor_request_io_port(struct mw_sensor_data *mw_sensor)
{
    int ret = 0;

    if(gpio_is_valid(mw_sensor->irq_gpio)) {
        ret = gpio_request(mw_sensor->irq_gpio, "mw_sensor_int");

        if(ret < 0) {
            dev_err(&mw_sensor->platform_dev->dev,
                    "Failed to request GPIO:%d, ERRNO:%d\n",
                    (s32)mw_sensor->irq_gpio, ret);
            return -ENODEV;
        }

        gpio_direction_input(mw_sensor->irq_gpio);
        dev_info(&mw_sensor->platform_dev->dev, "Success request irq-gpio\n");
    }

    return ret;
}

static s8 mw_sensor_request_input_dev(struct mw_sensor_data *mw_sensor)
{
    s8 ret = -1;

    mw_sensor->input_dev = input_allocate_device();
    if(mw_sensor->input_dev == NULL) {
        dev_err(&mw_sensor->platform_dev->dev, "Failed to allocate input device\n");
        return -ENOMEM;
    }

    mw_sensor->input_dev->name = MW_SENSOR_NAME;
    input_set_drvdata(mw_sensor->input_dev, mw_sensor);

    input_set_capability(mw_sensor->input_dev, EV_KEY, KEY_POWER);
    input_set_capability(mw_sensor->input_dev, EV_REL, REL_MISC);

    ret = input_register_device(mw_sensor->input_dev);
    if(ret) {
        dev_err(&mw_sensor->platform_dev->dev, "Register %s input device failed\n",
                mw_sensor->input_dev->name);
        input_free_device(mw_sensor->input_dev);
        return -ENODEV;
    }

    return 0;
}

static int mw_sensor_dev_open(struct inode *inode, struct file *filp)
{
    int ret = 0;

    struct mw_sensor_data *mw_sensor = container_of(filp->private_data,
                                  struct mw_sensor_data,
                                  mw_sensor_device);
    filp->private_data = mw_sensor;
    dev_info(&mw_sensor->platform_dev->dev,
             "device node major=%d, minor=%d\n", imajor(inode), iminor(inode));

    return ret;
}

static long mw_sensor_dev_ioctl(struct file *pfile,
                                 unsigned int cmd, unsigned long arg)
{
    int ret = 0;
    int data = 0;
    struct mw_sensor_data *mw_sensor = pfile->private_data;

    if (_IOC_TYPE(cmd) != MW_SENSOR_IOC_MAGIC) {
        return -EINVAL;
    }
    if (_IOC_NR(cmd) > MW_SENSOR_IOC_MAXNR) {
        return -EINVAL;
    }

    if (_IOC_DIR(cmd) & _IOC_READ) {
        ret = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd));
    } else if (_IOC_DIR(cmd) & _IOC_WRITE) {
        ret = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd));
    }
    if (ret) {
        return -EFAULT;
    }

    if (copy_from_user(&data, (int *)arg, sizeof(int))) {
        dev_err(&mw_sensor->platform_dev->dev,
                "%s, copy from user failed\n", __func__);
        return -EFAULT;
    }

    dev_info(&mw_sensor->platform_dev->dev,
             "%s, (%x, %lx): data=%d\n", __func__, cmd,
             arg, data);

    switch (cmd) {
        case MW_SENSOR_IOC_ENABLE:
            if (data > 0) {
                mw_sensor_enable(mw_sensor);
            } else {
                mw_sensor_disable(mw_sensor);
            }
            break;

        case MW_SENSOR_IOC_SET_RATE:
            break;

        default:
            return -EINVAL;
    }

    return ret;
}

static const struct file_operations mw_sensor_dev_fops = {
    .owner = THIS_MODULE,
    .open = mw_sensor_dev_open,
    .unlocked_ioctl = mw_sensor_dev_ioctl
};

static int mw_sensor_request_irq(struct mw_sensor_data *mw_sensor)
{
    int ret = 0;

    /* use irq */
    if(gpio_is_valid(mw_sensor->irq_gpio) || mw_sensor->irq > 0) {
        if(gpio_is_valid(mw_sensor->irq_gpio))
            mw_sensor->irq = gpio_to_irq(mw_sensor->irq_gpio);

        dev_info(&mw_sensor->platform_dev->dev, "INT num %d, trigger type:%d\n",
                 mw_sensor->irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING);
        ret = request_threaded_irq(mw_sensor->irq, NULL,
                                   mw_sensor_irq_handle,
                                   IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
                                   mw_sensor->platform_dev->name,
                                   mw_sensor);

        if(ret < 0) {
            dev_err(&mw_sensor->platform_dev->dev,
                    "Failed to request irq %d\n", mw_sensor->irq);
        }
    }

    return ret;
}

static int mw_sensor_probe(struct platform_device *pdev)
{
    int ret = 0;
    struct mw_sensor_data *mw_sensor;

    mw_sensor = devm_kzalloc(&pdev->dev, sizeof(*mw_sensor), GFP_KERNEL);
    if(mw_sensor == NULL) {
        dev_err(&pdev->dev, "Failed alloc ts memory\n");
        return -ENOMEM;
    }

    if(pdev->dev.of_node) {
        ret = mw_sensor_parse_dt(&pdev->dev, mw_sensor);
        if(ret) {
            dev_err(&pdev->dev, "Failed parse dts\n");
            goto exit_free_data;
        }
    }

    mw_sensor->platform_dev = pdev;

    ret = mw_sensor_request_io_port(mw_sensor);
    if(ret < 0) {
        dev_err(&pdev->dev, "Failed request IO port\n");
        goto exit_free_data;
    }

    ret = mw_sensor_request_input_dev(mw_sensor);
    if(ret < 0) {
        dev_err(&pdev->dev, "Failed request IO port\n");
        goto exit_free_io_port;
    }

    ret = mw_sensor_request_irq(mw_sensor);
    if(ret < 0) {
        dev_err(&pdev->dev, "Failed create work thread\n");
        goto exit_unreg_input_dev;
    }

    ret = enable_irq_wake(mw_sensor->irq);
    if (ret < 0) {
        dev_err(&pdev->dev, "Failed set irq wake\n");
        goto exit_free_irq;
    }

    mw_sensor->mw_sensor_device.minor = MISC_DYNAMIC_MINOR;
    mw_sensor->mw_sensor_device.name = MW_SENSOR_NAME;
    mw_sensor->mw_sensor_device.fops = &mw_sensor_dev_fops;
    ret = misc_register(&mw_sensor->mw_sensor_device);
    if (ret) {
        dev_err(&pdev->dev, "Failed to misc_register\n");
        goto exit_free_irq;
    }

    mw_sensor->notifier.notifier_call = mw_sensor_fb_event_notify;
    fb_register_client(&mw_sensor->notifier);

    platform_set_drvdata(pdev, mw_sensor);

    dev_info(&pdev->dev, "%s, over\n", __func__);
    return 0;

exit_free_irq:
    free_irq(mw_sensor->irq, mw_sensor);
    
exit_unreg_input_dev:
    input_unregister_device(mw_sensor->input_dev);
    
exit_free_io_port:
    if(gpio_is_valid(mw_sensor->irq_gpio))
        gpio_free(mw_sensor->irq_gpio);
    
exit_free_data:
    devm_kfree(&pdev->dev, mw_sensor);

    return ret;
}

static int mw_sensor_remove(struct platform_device *pdev)
{
    struct mw_sensor_data *mw_sensor = platform_get_drvdata(pdev);
    input_unregister_device(mw_sensor->input_dev);
    input_free_device(mw_sensor->input_dev);
    fb_unregister_client(&mw_sensor->notifier);
    mw_sensor_free_irq(mw_sensor);
    mw_sensor_free_io_port(mw_sensor);
    kfree(mw_sensor);

    return 0;
}

static const struct of_device_id mw_sensor_of_match[] = {
    { .compatible =  "topband,mwsensor"},
    {},
};

MODULE_DEVICE_TABLE(of, mw_sensor_of_match);

static struct platform_driver mw_sensor_driver = {
    .probe = mw_sensor_probe,
    .remove = mw_sensor_remove,
    .driver = {
        .name = MW_SENSOR_NAME,
        .owner  = THIS_MODULE,
        .of_match_table = mw_sensor_of_match,
    },
};

module_platform_driver(mw_sensor_driver);

MODULE_AUTHOR("shenhb@topband.com.cn");
MODULE_DESCRIPTION("Microware Sensor");
MODULE_VERSION("1.0");
MODULE_LICENSE("GPL");

注意:

  • ==注意input设备的设备名,因为Android Sensor HAL层是通过此设备名找到对应的input设备文件的。==
  • ==注意input事件上报类型,因为Android Sensor HAL层轮训input事件时要与之一致。==
  • ==ioctl至少实现enable与set rate两个功能,enable用于开关Sensor,set rate用于设置数据采样频率。==
  • ==数据读取采用中断方式==

2. 在驱动源文件同目录下增加Kconfig与Makefile

kernel/drivers/input/sensors/mwsensor/Kconfig

config SENSORS_MICROWAVE
     tristate "Microwave sensor"
     help
       This driver support the microwave sensor.
    
       To compile this driver as a module, choose M here. The module will be called microwave.

kernel/drivers/input/sensors/mwsensor/Makefile

obj-$(CONFIG_SENSORS_MICROWAVE)  += mwsensor.o

3. 修改上层Kconfig与Makefile

kernel/drivers/input/sensors/Kconfig

 source "drivers/input/sensors/pressure/Kconfig"
 source "drivers/input/sensors/hall/Kconfig"
 source "drivers/input/sensors/lsm6ds3/Kconfig"
+source "drivers/input/sensors/mwsensor/Kconfig"

kernel/drivers/input/sensors/Makefile

 obj-$(CONFIG_PRESSURE_DEVICE)      += pressure/
 obj-$(CONFIG_HALL_DEVICE)          += hall/
 obj-$(CONFIG_INPUT_LSM6DS3)        += lsm6ds3/
+obj-$(CONFIG_SENSORS_MICROWAVE)    += mwsensor/

4. 在内核config中打开

 # CONFIG_MPU_SENSORS_BMA085 is not set
 # CONFIG_MPU_USERSPACE_DEBUG is not set
 CONFIG_INPUT_LSM6DS3=y
+CONFIG_SENSORS_MICROWAVE=y

5. 编译kernel

编译kernel,烧录,启动,通过getevent能看到对应的input设备:

shell@rk312x_bt:/ # getevent
getevent
add device 1: /dev/input/event4
  name:     "SIGMACHIP Usb Mouse"
add device 2: /dev/input/event2
  name:     "mwsensor"
add device 3: /dev/input/event0
  name:     ""
add device 4: /dev/input/event1
  name:     "rk816_pwrkey"
add device 5: /dev/input/event3
  name:     "rk29-keypad"

Hardware

1. 新建 hardware\rockchip\sensor\st\HumanSensor.cpp

/*********************************************************************************
* Copyright 2019 Bob Shen
* FileName: HumanSensor.cpp
* Author: Bob Shen
* Version: 1.0.0
* Date: 2019-7-26
* Description:
*     Custom human sensor for detecting human proximity.
*
* Revision:
*     Date:
*     Reviser:
*     Description:
*********************************************************************************/

#include <fcntl.h>
#include <errno.h>
#include <math.h>
#include <poll.h>
#include <unistd.h>
#include <dirent.h>
#include <math.h>
#include <sys/select.h>
#include <cutils/log.h>
#include <utils/BitSet.h>
#include <cutils/properties.h>
#include <linux/ioctl.h>

#include "HumanSensor.h"

// ioctl cmd
#define MW_SENSOR_IOC_MAGIC  'm'

#define MW_SENSOR_IOC_ENABLE _IOW(MW_SENSOR_IOC_MAGIC, 1, int)
#define MW_SENSOR_IOC_SET_RATE _IOW(MW_SENSOR_IOC_MAGIC, 2, int)

HumanSensor::HumanSensor()
    : SensorBase(HUMAN_DEVICE_NAME, "mwsensor"),
      mEnabled(0),
      mInputReader(32)
{
    mPendingEvent.version = sizeof(sensors_event_t);
    mPendingEvent.sensor = ID_HUMAN;
    mPendingEvent.type = SENSOR_TYPE_HUMAN;
    memset(mPendingEvent.data, 0x00, sizeof(mPendingEvent.data));

    int err = 0;
    err = open_device();
    err = err < 0 ? -errno : 0;
    if (err) {
        LOGE("%s:%s\n", __func__, strerror(-err));
        return;
    }
}

HumanSensor::~HumanSensor()
{
    if (mEnabled) {
        enable(0, 0);
    }

    if (dev_fd > 0) {
        close(dev_fd);
        dev_fd = -1;
    }
}

int HumanSensor::enable(int32_t, int en)
{
    int newState = en ? 1 : 0;
    int err = 0;

    if (newState != mEnabled) {
        if (dev_fd < 0) {
            open_device();
        }

        if (0 > (err = ioctl(dev_fd, MW_SENSOR_IOC_ENABLE, &newState))) {
            LOGE("fail to perform MW_SENSOR_IOC_ENABLE, err = %d, error is '%s'", err, strerror(errno));
            goto EXIT;
        }

        mEnabled = newState;
    }

EXIT:
    return err;
}

int HumanSensor::setDelay(int32_t handle, int64_t ns)
{
    int err = 0;

    if (ns < 0) {
        return -EINVAL;
    }

    if (dev_fd < 0) {
        open_device();
    }

    short delay = ns / 1000000;

    if ((err = ioctl(dev_fd, MW_SENSOR_IOC_SET_RATE, &delay)) < 0) {
        LOGE("fail to perform MW_SENSOR_IOC_SET_RATE, result = %d, error is '%s'", err, strerror(errno));
    }

    return err;
}

int HumanSensor::isActivated(int /* handle */)
{
    return mEnabled;
}

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

    ssize_t n = mInputReader.fill(data_fd);
    if (n < 0) {
        return n;
    }

    int numEventReceived = 0;
    input_event const* event;

    while (count && mInputReader.readEvent(&event)) {
        int type = event->type;

        LOGI("HumanSensor: read event (type=%d, code=%d)", type, event->code);

        if (type == EV_REL) {
            processEvent(event->code, event->value);
        } else if (type == EV_SYN) {
            mPendingEvent.timestamp = getTimestamp();
            *data++ = mPendingEvent;
            count--;
            numEventReceived++;
        } else {
            LOGE("HumanSensor: unknown event (type=%d, code=%d)", type, event->code);
        }

        mInputReader.next();
    }

    return numEventReceived;
}

void HumanSensor::processEvent(int code, int value)
{
    switch (code) {
        case EVENT_TYPE_HUMAN:
            mPendingEvent.human = value;
            break;
    }
}

注意:

  • ==HUMAN_DEVICE_NAME 驱动中注册的设备文件,用于ioctl开关Sensor和设置轮训频率。==
  • ==“mwsensor” 为input设备名,用于事件读取。==
  • ==readEvents() 中用到的事件类型要与驱动中一致,否则无法读取事件。==
  • ==processEvent() 中主要对数据进一步加工。==

2. 增加头文件

hardware\rockchip\sensor\st\HumanSensor.h

/*********************************************************************************
* Copyright 2019 Bob Shen
* FileName: HumanSensor.h
* Author: Bob Shen
* Version: 1.0.0
* Date: 2019-7-26
* Description:
*     Custom human sensor for detecting human proximity.
*
* Revision:
*     Date:
*     Reviser:
*     Description:
*********************************************************************************/

#ifndef ANDROID_HUMAN_SENSOR_H
#define ANDROID_HUMAN_SENSOR_H

#include <stdint.h>
#include <errno.h>
#include <sys/cdefs.h>
#include <sys/types.h>

#include "nusensors.h"
#include "SensorBase.h"
#include "InputEventReader.h"

struct input_event;

class HumanSensor : public SensorBase
{
    private:
        int mEnabled;
        InputEventCircularReader mInputReader;
        sensors_event_t mPendingEvent;

    public:
        HumanSensor();
        virtual ~HumanSensor();
        virtual int readEvents(sensors_event_t* data, int count);
        void processEvent(int code, int value);
        virtual int setDelay(int32_t handle, int64_t ns);
        virtual int enable(int32_t handle, int enabled);
        virtual int isActivated(int handle);
};

#endif  // ANDROID_HUMAN_SENSOR_H

3. 将源文件加入到Android.mk

diff --git a/hardware/rockchip/sensor/st/Android.mk b/hardware/rockchip/sensor/st/Android.mk
index 50b2364..f602c90 100755
--- a/hardware/rockchip/sensor/st/Android.mk
+++ b/hardware/rockchip/sensor/st/Android.mk
@@ -41,6 +41,7 @@ LOCAL_SRC_FILES :=                        \
                ProximitySensor.cpp     \
                PressureSensor.cpp      \
                TemperatureSensor.cpp       \
+               HumanSensor.cpp

4. 修改其它HAL文件,将新增的AdcSensor加入其中

diff --git a/hardware/libhardware/include/hardware/sensors.h b/hardware/libhardware/include/hardware/sensors.h
index 6f38243..3a649bf 100755
--- a/hardware/libhardware/include/hardware/sensors.h
+++ b/hardware/libhardware/include/hardware/sensors.h
@@ -612,6 +612,15 @@ enum {
 #define SENSOR_STRING_TYPE_ADC                                 "android.sensor.adc"
 
 /**
+ * SENSOR_TYPE_HUMAN
+ * reporting-mode: one-shot
+ *
+ * Custom human sensor, for detecting human proximity.
+ */
+#define SENSOR_TYPE_HUMAN                                      (27)
+#define SENSOR_STRING_TYPE_HUMAN                               "android.sensor.human"
+
+/**
  * Values returned by the accelerometer in various locations in the universe.
  * all values are in SI units (m/s^2)
  */
@@ -740,6 +749,9 @@ typedef struct sensors_event_t {
             /* voltage values are in voltage(mV)*/
             float           voltage;
 
+            /* human values indicates whether someone is near*/
+            float           human;
+
             /* distance in centimeters */
             float           distance;
 
diff --git a/hardware/rockchip/sensor/st/Android.mk b/hardware/rockchip/sensor/st/Android.mk
index f602c90..030f8bd 100755
--- a/hardware/rockchip/sensor/st/Android.mk
+++ b/hardware/rockchip/sensor/st/Android.mk
@@ -41,7 +41,8 @@ LOCAL_SRC_FILES :=                        \
                ProximitySensor.cpp     \
                PressureSensor.cpp      \
                TemperatureSensor.cpp       \
-               AdcSensor.cpp
+               AdcSensor.cpp \
+               HumanSensor.cpp
                
 LOCAL_SHARED_LIBRARIES := liblog \
    libcutils \
diff --git a/hardware/rockchip/sensor/st/nusensors.cpp b/hardware/rockchip/sensor/st/nusensors.cpp
index c71f07c..50049e3 100755
--- a/hardware/rockchip/sensor/st/nusensors.cpp
+++ b/hardware/rockchip/sensor/st/nusensors.cpp
@@ -37,6 +37,7 @@
 #include "PressureSensor.h"
 #include "TemperatureSensor.h"
 #include "AdcSensor.h"
+#include "HumanSensor.h"
 
 #if defined(CALIBRATION_SUPPORT)
 typedef        unsigned short      uint16;
@@ -160,6 +161,7 @@ private:
         pressure        = 5,
         temperature        = 6,
         adc             = 7,
+        human           = 8,
         numSensorDrivers,
         numFds,
     };
@@ -189,6 +191,8 @@ private:
                return temperature;
             case ID_ADC:
                return adc;
+            case ID_HUMAN:
+               return human;
         }
         return -EINVAL;
     }
@@ -241,6 +245,11 @@ sensors_poll_context_t::sensors_poll_context_t()
     mPollFds[adc].events = POLLIN;
     mPollFds[adc].revents = 0;
 
+    mSensors[human] = new HumanSensor();
+    mPollFds[human].fd = mSensors[human]->getFd();
+    mPollFds[human].events = POLLIN;
+    mPollFds[human].revents = 0;
+
     int wakeFds[2];
     int result = pipe(wakeFds);
     LOGE_IF(result<0, "error creating wake pipe (%s)", strerror(errno));
diff --git a/hardware/rockchip/sensor/st/nusensors.h b/hardware/rockchip/sensor/st/nusensors.h
index e6d8edd..1ad1780 100755
--- a/hardware/rockchip/sensor/st/nusensors.h
+++ b/hardware/rockchip/sensor/st/nusensors.h
@@ -62,6 +62,7 @@ int init_nusensors(hw_module_t const* module, hw_device_t** device);
 #define ID_PR   (6)
 #define ID_TMP  (7)
 #define ID_ADC  (8)
+#define ID_HUMAN (9)
 
@@ -83,6 +84,7 @@ int init_nusensors(hw_module_t const* module, hw_device_t** device);
 #define PR_DEVICE_NAME      "/dev/pressure"
 #define TMP_DEVICE_NAME     "/dev/temperature"
 #define ADC_DEVICE_NAME     "/dev/adcsensor"
+#define HUMAN_DEVICE_NAME   "/dev/mwsensor"
 
 // for LSM6DS3
 #define GSENSOR_IOC_ENABLE          LSM6DS3_IOC_ENABLE
@@ -118,6 +120,7 @@ int init_nusensors(hw_module_t const* module, hw_device_t** device);
 #define EVENT_TYPE_PRESSURE         ABS_PRESSURE
 
 #define EVENT_TYPE_ADC              REL_MISC
+#define EVENT_TYPE_HUMAN            REL_MISC
 
 #define ACCELERATION_RATIO_ANDROID_TO_HW        (9.80665f / 1000000)
diff --git a/hardware/rockchip/sensor/st/sensors.c b/hardware/rockchip/sensor/st/sensors.c
index 9ca012e..3a26359 100755
--- a/hardware/rockchip/sensor/st/sensors.c
+++ b/hardware/rockchip/sensor/st/sensors.c
@@ -141,6 +141,18 @@ static const struct sensor_t sSensorList[] = {
           .minDelay   = 5000,
           .reserved   = {}
         },
+
+    { .name       = "Human sensor",
+          .vendor     = "The Android Open Source Project",
+          .version    = 1,
+          .handle     = SENSORS_HANDLE_BASE+ID_HUMAN,
+          .type       = SENSOR_TYPE_HUMAN,
+          .maxRange   = 110000.0f,
+          .resolution = 1.0f,
+          .power      = 1.0f,
+          .minDelay   = 5000,
+          .reserved   = {}
+        },
 };
 
 static int open_sensors(const struct hw_module_t* module, const char* name,

Framework

1. framework参考下面修改

diff --git a/frameworks/base/core/java/android/hardware/LegacySensorManager.java b/frameworks/base/core/java/android/hardware/LegacySensorManager.java
index 806925e..015f184 100755
--- a/frameworks/base/core/java/android/hardware/LegacySensorManager.java
+++ b/frameworks/base/core/java/android/hardware/LegacySensorManager.java
@@ -84,6 +84,9 @@ final class LegacySensorManager {
                 case Sensor.TYPE_ADC:
                     result |= SensorManager.SENSOR_ADC;
                     break;
+                case Sensor.TYPE_HUMAN:
+                    result |= SensorManager.SENSOR_HUMAN;
+                    break;
             }
         }
         return result;
@@ -106,6 +109,8 @@ final class LegacySensorManager {
                 Sensor.TYPE_TEMPERATURE, listener, sensors, rate) || result;
         result = registerLegacyListener(SensorManager.SENSOR_ADC,
                 Sensor.TYPE_ADC, listener, sensors, rate) || result;
+        result = registerLegacyListener(SensorManager.SENSOR_HUMAN,
+                Sensor.TYPE_HUMAN, listener, sensors, rate) || result;
         return result;
     }
 
@@ -162,6 +167,8 @@ final class LegacySensorManager {
                 listener, sensors);
         unregisterLegacyListener(SensorManager.SENSOR_ADC, Sensor.TYPE_ADC,
                 listener, sensors);
+        unregisterLegacyListener(SensorManager.SENSOR_HUMAN, Sensor.TYPE_HUMAN,
+                listener, sensors);
     }
 
     private void unregisterLegacyListener(int legacyType, int type,
diff --git a/frameworks/base/core/java/android/hardware/Sensor.java b/frameworks/base/core/java/android/hardware/Sensor.java
index 18927e7..70cbddd 100755
--- a/frameworks/base/core/java/android/hardware/Sensor.java
+++ b/frameworks/base/core/java/android/hardware/Sensor.java
@@ -527,6 +527,23 @@ public final class Sensor {
      * @see #TYPE_ADC
      */
     public static final String STRING_TYPE_ADC = "android.sensor.adc";
+    
+    /**
+     * A constant describing a pick up sensor.
+     *
+     * Custom human sensor, for detecting human proximity.
+     *
+     * @hide Expected to be used internally for always on display.
+     */
+    public static final int TYPE_HUMAN = 27;
+
+    /**
+     * A constant string describing a pick up sensor.
+     *
+     * @hide This sensor is expected to be used internally for always on display.
+     * @see #TYPE_HUMAN
+     */
+    public static final String STRING_TYPE_HUMAN = "android.sensor.human";
 
     /**
      * A constant describing all sensor types.
diff --git a/frameworks/base/core/java/android/hardware/SensorManager.java b/frameworks/base/core/java/android/hardware/SensorManager.java
index 63d46dc..3c037ad 100755
--- a/frameworks/base/core/java/android/hardware/SensorManager.java
+++ b/frameworks/base/core/java/android/hardware/SensorManager.java
@@ -171,6 +171,15 @@ public abstract class SensorManager {
      */
     @Deprecated
     public static final int SENSOR_ADC = 1 << 8;
+    
+    /**
+     * A constant describing an adc sensor. See
+     * {@link android.hardware.SensorListener SensorListener} for more details.
+     *
+     * @deprecated use {@link android.hardware.Sensor Sensor} instead.
+     */
+    @Deprecated
+    public static final int SENSOR_HUMAN = 1 << 9;
 
     /**
      * A constant that includes all sensors
diff --git a/frameworks/native/include/android/sensor.h b/frameworks/native/include/android/sensor.h
index 3ca6287..b6dbb62 100755
--- a/frameworks/native/include/android/sensor.h
+++ b/frameworks/native/include/android/sensor.h
@@ -60,7 +60,8 @@ enum {
     ASENSOR_TYPE_GYROSCOPE          = 4,
     ASENSOR_TYPE_LIGHT              = 5,
     ASENSOR_TYPE_PROXIMITY          = 8,
-    ASENSOR_TYPE_ADC                = 26
+    ASENSOR_TYPE_ADC                = 26,
+    ASENSOR_TYPE_HUMAN              = 27
 };
 
 /*
@@ -162,6 +163,7 @@ typedef struct ASensorEvent {
             ASensorVector   magnetic;
             float           temperature;
             float           voltage;
+            float           human;
             float           distance;
             float           light;
             float           pressure;
diff --git a/frameworks/native/include/gui/Sensor.h b/frameworks/native/include/gui/Sensor.h
index 37b5958..68c2d59 100755
--- a/frameworks/native/include/gui/Sensor.h
+++ b/frameworks/native/include/gui/Sensor.h
@@ -50,7 +50,8 @@ public:
         TYPE_GYROSCOPE      = ASENSOR_TYPE_GYROSCOPE,
         TYPE_LIGHT          = ASENSOR_TYPE_LIGHT,
         TYPE_PROXIMITY      = ASENSOR_TYPE_PROXIMITY,
-        TYPE_ADC            = ASENSOR_TYPE_ADC
+        TYPE_ADC            = ASENSOR_TYPE_ADC,
+        TYPE_HUMAN          = ASENSOR_TYPE_HUMAN
     };
 
             Sensor();
diff --git a/device/rockchip/common/ueventd.rockchip.rc b/device/rockchip/common/ueventd.rockchip.rc
index ae35a49..4d1c8cb 100755
--- a/device/rockchip/common/ueventd.rockchip.rc
+++ b/device/rockchip/common/ueventd.rockchip.rc
@@ -18,6 +18,7 @@
 /dev/step_d               0660   system     system
 /dev/tilt                 0660   system     system
 /dev/adcsensor            0660   system     system
+/dev/mwsensor             0660   system     system
 
 /dev/ion                  0666   system     system
 /dev/galcore              0666   system     graphics

2. 编译更新API

make update-api

APP使用

demo下载

Android增加自定义Sensor后,APP的使用方式同Android其它默认Sensor,只需要将Sensor type改为 Sensor.TYPE_HUMAN 即可。

下面为监听Human Sensor状态变化为实现方法,仅供参考:

mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
if (null != mSensorManager) {
    // Human Sensor
    Sensor humanSensor = mSensorManager.getDefaultSensor(27); // 27: Sensor.TYPE_HUMAN
    if (humanSensor != null) {
        mHumanSensorEventListener = new SensorEventListener() {
            @Override
            public void onSensorChanged(SensorEvent event) {
                float human = event.values[0];
                mSensorView.updateHumanSensorData(human);
            }

            @Override
            public void onAccuracyChanged(Sensor sensor, int accuracy) {

            }
        };
        mSensorManager.registerListener(mHumanSensorEventListener, humanSensor, SensorManager.SENSOR_DELAY_NORMAL);
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容