蚂蚁森林有个行走赚绿色能量的方法,但奈何我的手机不支持运动传感器,Android
本身已支持计步器传感器,如果写个计步器的驱动,那应该就可以显示步数了。刚开始想
参考计步传感器的驱动来写,但发现都没有真实的计步传感器,更别提参考了。网上搜
代码在hardware/qcom/sensors/sensors.h加上SENSOR_TYPE_STEP_COUNTER,并将压力传
感器bmp180的相关hal代码进行改造,计步器正常工作了。用其他APP读数,汇报的值跟APP
读到的值一致,但蚂蚁森林上的读数比较久才跟新下,应该跟其内部的实现有关。
本身已支持计步器传感器,如果写个计步器的驱动,那应该就可以显示步数了。刚开始想
参考计步传感器的驱动来写,但发现都没有真实的计步传感器,更别提参考了。网上搜
索发现了一篇文档(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
读到的值一致,但蚂蚁森林上的读数比较久才跟新下,应该跟其内部的实现有关。
相关修改如下
见证成果的时候到了。