蚂蚁森林有个行走赚绿色能量的方法,但奈何我的手机不支持运动传感器(https://blog.csdn.net/mike8825/article/details/95898831),Android本身已支持计步传感器,如果写个计步器的驱动,那应该就可以显示步数了。网上搜索发现了一篇文档(lm80-p0436-9_sensors_porting_guide.pdf),感觉这个有希望。
驱动如下
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/sensors.h>
#include <linux/input.h>
#define POLL_DEFAULT_INTERVAL_MS 500
static unsigned long step_count;
struct sensors_classdev step_counter_cdev ={
.name = "simulated_step_counter",
.vendor = "www",
.version = 1,
.type = SENSOR_TYPE_STEP_COUNTER,
.sensors_enable = NULL,
.sensors_poll_delay = NULL,
};
struct step_counter {
atomic_t delay;
struct workqueue_struct *data_wq;
struct delayed_work dwork;
struct sensors_classdev cdev;
struct mutex enable_lock;
struct mutex step_count_lock;
struct input_dev *idev;
};
static int step_counter_set_enable(struct sensors_classdev *sensors_cdev,unsigned int enable)
{
struct step_counter *virtual_step_counter = container_of(sensors_cdev,struct step_counter, cdev);
mutex_lock(&virtual_step_counter->enable_lock);
if (enable)
{
queue_delayed_work(virtual_step_counter->data_wq,&virtual_step_counter->dwork,
msecs_to_jiffies(atomic_read(&virtual_step_counter->delay)));
} else
{
cancel_delayed_work_sync(&virtual_step_counter->dwork);
}
mutex_unlock(&virtual_step_counter->enable_lock);
return 0;
}
static ssize_t step_count_show(struct device *dev,struct device_attribute *attr, char *buf)
{
return sprintf(buf, "%lu\n", step_count);
}
static ssize_t step_count_store(struct device *dev,struct device_attribute *attr,const char *buf, size_t count)
{
unsigned long data;
int ret;
struct step_counter *virtual_step_counter=dev_get_drvdata(dev);
ret = kstrtoul(buf, 10, &data);
if (ret)
return ret;
mutex_lock(&virtual_step_counter->step_count_lock);
step_count=data;
mutex_unlock(&virtual_step_counter->step_count_lock);
return count;
}
static DEVICE_ATTR(step_count, S_IRUSR|S_IRGRP|S_IWUSR,step_count_show,step_count_store);
int step_counter_poll_delay(struct sensors_classdev *sensors_cdev,unsigned int delay_msec)
{
struct step_counter *virtual_step_counter = container_of(sensors_cdev,struct step_counter, cdev);
atomic_set(&virtual_step_counter->delay,delay_msec);
return 0;
}
static void step_counter_poll(struct work_struct *work)
{
struct step_counter *virtual_step_counter = container_of((struct delayed_work *)work,struct step_counter, dwork);
input_report_abs(virtual_step_counter->idev, ABS_MISC, step_count);
mutex_lock(&virtual_step_counter->step_count_lock);
step_count=step_count+1;
mutex_unlock(&virtual_step_counter->step_count_lock);
input_sync(virtual_step_counter->idev);
queue_delayed_work(virtual_step_counter->data_wq,&virtual_step_counter->dwork,
msecs_to_jiffies(atomic_read(&virtual_step_counter->delay)));
}
static struct input_dev *step_counter_init_input(struct device *dev)
{
int status;
struct input_dev *input = NULL;
input = devm_input_allocate_device(dev);
if (!input)
return NULL;
input->name = "step_counter";
input_set_capability(input, EV_ABS, ABS_MISC);
status = input_register_device(input);
if (status) {
dev_err(dev,"error registering input device\n");
return NULL;
}
return input;
}
static int step_counter_probe(struct platform_device *pdev)
{
int ret;
struct step_counter *virtual_step_counter;
printk("step_counter_probe start\n");
virtual_step_counter = devm_kzalloc(&pdev->dev, sizeof(struct step_counter),GFP_KERNEL);
if (!virtual_step_counter) {
dev_err(&pdev->dev, "memory allocation failed.\n");
goto out;
}
INIT_DELAYED_WORK(&virtual_step_counter->dwork, step_counter_poll);
virtual_step_counter->data_wq =create_freezable_workqueue("step_counter_data_work");
if (!virtual_step_counter->data_wq) {
dev_err(&pdev->dev, "Cannot create workqueue.\n");
goto out_create_workqueue;
}
atomic_set(&virtual_step_counter->delay, POLL_DEFAULT_INTERVAL_MS);
virtual_step_counter->idev=step_counter_init_input(&pdev->dev);
if(!virtual_step_counter->idev){
dev_err(&pdev->dev, "init input device failed\n");
ret = -ENODEV;
goto out_register_input;
}
virtual_step_counter->cdev=step_counter_cdev;
virtual_step_counter->cdev.sensors_enable=step_counter_set_enable;
virtual_step_counter->cdev.sensors_poll_delay=step_counter_poll_delay;
ret=sensors_classdev_register(&virtual_step_counter->idev->dev,&virtual_step_counter->cdev);
if (ret) {
dev_err(&pdev->dev, "sensors class register failed.\n");
goto out_register_classdev;
}
mutex_init(&virtual_step_counter->enable_lock);
mutex_init(&virtual_step_counter->step_count_lock);
dev_set_drvdata(&pdev->dev, virtual_step_counter);
ret = device_create_file(&pdev->dev, &dev_attr_step_count);
printk("step_counter_probe ok\n");
return 0;
out_register_classdev:
input_unregister_device(virtual_step_counter->idev);
out_create_workqueue:
out_register_input:
destroy_workqueue(virtual_step_counter->data_wq);
out:
printk("step_counter_probe fail\n");
return ret;
}
static int step_counter_remove(struct platform_device *pdev)
{
return 0;
}
static struct platform_device step_counter_devices =
{
.name = "simulated_step_counter",
.id = 0,
};
static struct platform_driver step_counter_driver =
{
.probe = step_counter_probe,
.remove = step_counter_remove,
.driver = {
.name = "simulated_step_counter",
.owner = THIS_MODULE,
},
};
static int sensor_init(void)
{
platform_device_register(&step_counter_devices);
platform_driver_register(&step_counter_driver);
return 0;
}
static void __exit sensor_exit(void)
{
platform_device_unregister(&step_counter_devices);
platform_driver_unregister(&step_counter_driver);
}
module_init(sensor_init);
module_exit(sensor_exit);
MODULE_LICENSE("GPL");
驱动工作了,并有相关的数据上传了,但上层APP说不支持计步传感器,查找相关
代码在hardware/qcom/sensors/sensors.h加上SENSOR_TYPE_STEP_COUNTER,并将压力传
感器bmp180的相关hal代码进行改造,计步器正常工作了。用其他APP读数,汇报的值跟APP
读到的值一致,但蚂蚁森林上的读数比较久才跟新下,应该跟其内部的实现有关。
相关修改如下
见证成果的时候到了。