rtthread的sensor框架存在两个版本,其中V2版的框架号称是为了解决V1对多传感器共用一颗IC的场景支持问题而设计的(之前PR群内沟通迭代计划时提到的)。
源码解析
源码路径
components\drivers\sensor\v2\sensor.c
注册入口
/** * Sensor mode * rt_uint16_t mode * 0000 | 0000 | 0000 | 0000 * unused accuracy power fetch data */ #define RT_SENSOR_MODE_ACCURACY_BIT_OFFSET (8) #define RT_SENSOR_MODE_POWER_BIT_OFFSET (4) #define RT_SENSOR_MODE_FETCH_BIT_OFFSET (0) #define RT_SENSOR_MODE_GET_ACCURACY(mode) (rt_uint8_t)((mode >> RT_SENSOR_MODE_ACCURACY_BIT_OFFSET) & 0x0F) #define RT_SENSOR_MODE_GET_POWER(mode) (rt_uint8_t)((mode >> RT_SENSOR_MODE_POWER_BIT_OFFSET) & 0x0F) #define RT_SENSOR_MODE_GET_FETCH(mode) (rt_uint8_t)((mode >> RT_SENSOR_MODE_FETCH_BIT_OFFSET) & 0x0F) #define RT_SENSOR_MODE_CLEAR_ACCURACY(mode) (mode &= ((rt_uint16_t)~((rt_uint16_t)0x0F << RT_SENSOR_MODE_ACCURACY_BIT_OFFSET))) #define RT_SENSOR_MODE_CLEAR_POWER(mode) (mode &= ((rt_uint16_t)~((rt_uint16_t)0x0F << RT_SENSOR_MODE_POWER_BIT_OFFSET))) #define RT_SENSOR_MODE_CLEAR_FETCH(mode) (mode &= ((rt_uint16_t)~((rt_uint16_t)0x0F << RT_SENSOR_MODE_FETCH_BIT_OFFSET))) #define RT_SENSOR_MODE_SET_ACCURACY(mode, accuracy_mode) RT_SENSOR_MODE_CLEAR_ACCURACY(mode); (mode |= (accuracy_mode << RT_SENSOR_MODE_ACCURACY_BIT_OFFSET)) #define RT_SENSOR_MODE_SET_POWER(mode, power_mode) RT_SENSOR_MODE_CLEAR_POWER(mode); (mode |= (power_mode << RT_SENSOR_MODE_POWER_BIT_OFFSET)) #define RT_SENSOR_MODE_SET_FETCH(mode, fetch_mode) RT_SENSOR_MODE_CLEAR_FETCH(mode); (mode |= (fetch_mode << RT_SENSOR_MODE_FETCH_BIT_OFFSET)) static char *const sensor_name_str[] = { "None", "ac-", /* Accelerometer */ "gy-", /* Gyroscope */ "ma-", /* Magnetometer */ "tm-", /* Temperature */ "hm-", /* Relative Humidity */ "br-", /* Barometer */ "li-", /* Ambient light */ "pr-", /* Proximity */ "hr-", /* Heart Rate */ "tv-", /* TVOC Level */ "ni-", /* Noise Loudness */ "st-", /* Step sensor */ "fr-", /* Force sensor */ "du-", /* Dust sensor */ "ec-", /* eCO2 sensor */ "gn-", /* GPS/GNSS sensor */ "tf-", /* TOF sensor */ "sp-", /* SpO2 sensor */ "ia-", /* IAQ sensor */ "et-", /* EtOH sensor */ "bp-", /* Blood Pressure */ RT_NULL }; /* sensor local ops */ static rt_ssize_t _local_fetch_data(rt_sensor_t sensor, rt_sensor_data_t buf, rt_size_t len) { LOG_D("Undefined fetch_data"); return -RT_EINVAL; } static rt_err_t _local_control(rt_sensor_t sensor, int cmd, void *arg) { LOG_D("Undefined control"); return -RT_EINVAL; } static struct rt_sensor_ops local_ops = { .fetch_data = _local_fetch_data, .control = _local_control }; int rt_hw_sensor_register(rt_sensor_t sensor, const char *name, rt_uint32_t flag, void *data) { rt_int8_t result; rt_device_t device; RT_ASSERT(sensor != RT_NULL); char *sensor_name = RT_NULL, *device_name = RT_NULL; if (sensor->ops == RT_NULL) { sensor->ops = &local_ops; } /* Add a type name for the sensor device */ sensor_name = sensor_name_str[sensor->info.type]; device_name = (char *)rt_calloc(1, rt_strlen(sensor_name) + 1 + rt_strlen(name)); if (device_name == RT_NULL) { LOG_E("device_name calloc failed!"); return -RT_ERROR; } rt_memcpy(device_name, sensor_name, rt_strlen(sensor_name) + 1); strcat(device_name, name); if (sensor->module != RT_NULL && sensor->module->lock == RT_NULL) { /* Create a mutex lock for the module */ sensor->module->lock = rt_mutex_create(name, RT_IPC_FLAG_PRIO); if (sensor->module->lock == RT_NULL) { rt_free(device_name); return -RT_ERROR; } } device = &sensor->parent; #ifdef RT_USING_DEVICE_OPS device->ops = &rt_sensor_ops; #else device->init = RT_NULL; device->open = _sensor_open; device->close = _sensor_close; device->read = _sensor_read; device->write = RT_NULL; device->control = _sensor_control; #endif device->type = RT_Device_Class_Sensor; device->rx_indicate = RT_NULL; device->tx_complete = RT_NULL; device->user_data = data; result = rt_device_register(device, device_name, flag | RT_DEVICE_FLAG_STANDALONE); if (result != RT_EOK) { LOG_E("sensor[%s] register err code: %d", device_name, result); rt_free(device_name); return result; } LOG_I("sensor[%s] init success", device_name); rt_free(device_name); return RT_EOK; }
注册函数和v1版相比,除了名称外,几乎没有任何修改,因此可以沿用v1的分析。
打开入口
static void _sensor_cb(rt_sensor_t sen) { if (sen->parent.rx_indicate == RT_NULL) { return; } if (sen->irq_handle != RT_NULL) { sen->irq_handle(sen); } /* The buffer is not empty. Read the data in the buffer first */ if (sen->data_len > 0) { sen->parent.rx_indicate(&sen->parent, sen->data_len / sizeof(struct rt_sensor_data)); } else if (RT_SENSOR_MODE_GET_FETCH(sen->info.mode) == RT_SENSOR_MODE_FETCH_INT) { /* The interrupt mode only produces one data at a time */ sen->parent.rx_indicate(&sen->parent, 1); } else if (RT_SENSOR_MODE_GET_FETCH(sen->info.mode) == RT_SENSOR_MODE_FETCH_FIFO) { sen->parent.rx_indicate(&sen->parent, sen->info.fifo_max); } } static void _irq_callback(void *args) { rt_sensor_t sensor = (rt_sensor_t)args; rt_uint8_t i; if (sensor->module) { /* Invoke a callback for all sensors in the module */ for (i = 0; i < sensor->module->sen_num; i++) { _sensor_cb(sensor->module->sen[i]); } } else { _sensor_cb(sensor); } } static rt_err_t _sensor_irq_init(rt_sensor_t sensor) { if (sensor->config.irq_pin.pin == PIN_IRQ_PIN_NONE) { return -RT_EINVAL; } rt_pin_mode(sensor->config.irq_pin.pin, sensor->config.irq_pin.mode); if (sensor->config.irq_pin.mode == PIN_MODE_INPUT_PULLDOWN) { rt_pin_attach_irq(sensor->config.irq_pin.pin, PIN_IRQ_MODE_RISING, _irq_callback, (void *)sensor); } else if (sensor->config.irq_pin.mode == PIN_MODE_INPUT_PULLUP) { rt_pin_attach_irq(sensor->config.irq_pin.pin, PIN_IRQ_MODE_FALLING, _irq_callback, (void *)sensor); } else if (sensor->config.irq_pin.mode == PIN_MODE_INPUT) { rt_pin_attach_irq(sensor->config.irq_pin.pin, PIN_IRQ_MODE_RISING_FALLING, _irq_callback, (void *)sensor); } rt_pin_irq_enable(sensor->config.irq_pin.pin, RT_TRUE); LOG_I("interrupt init success"); return 0; } static rt_err_t _sensor_open(rt_device_t dev, rt_uint16_t oflag) { rt_sensor_t sensor = (rt_sensor_t)dev; RT_ASSERT(dev != RT_NULL); rt_err_t res = RT_EOK; rt_err_t (*local_ctrl)(rt_sensor_t sensor, int cmd, void *arg) = _local_control; if (sensor->module) { /* take the module mutex */ rt_mutex_take(sensor->module->lock, RT_WAITING_FOREVER); } if (sensor->module != RT_NULL && sensor->info.fifo_max > 0 && sensor->data_buf == RT_NULL) { /* Allocate memory for the sensor buffer */ sensor->data_buf = rt_malloc(sizeof(struct rt_sensor_data) * sensor->info.fifo_max); if (sensor->data_buf == RT_NULL) { res = -RT_ENOMEM; goto __exit; } } if (sensor->ops->control != RT_NULL) { local_ctrl = sensor->ops->control; } if (oflag & RT_DEVICE_FLAG_RDONLY && dev->flag & RT_DEVICE_FLAG_RDONLY) { /* If polling mode is supported, configure it to polling mode */ if (local_ctrl(sensor, RT_SENSOR_CTRL_SET_FETCH_MODE, (void *)RT_SENSOR_MODE_FETCH_POLLING) == RT_EOK) { RT_SENSOR_MODE_SET_FETCH(sensor->info.mode, RT_SENSOR_MODE_FETCH_POLLING); } } else if (oflag & RT_DEVICE_FLAG_INT_RX && dev->flag & RT_DEVICE_FLAG_INT_RX) { /* If interrupt mode is supported, configure it to interrupt mode */ if (local_ctrl(sensor, RT_SENSOR_CTRL_SET_FETCH_MODE, (void *)RT_SENSOR_MODE_FETCH_INT) == RT_EOK) { /* Initialization sensor interrupt */ _sensor_irq_init(sensor); RT_SENSOR_MODE_SET_FETCH(sensor->info.mode, RT_SENSOR_MODE_FETCH_INT); } } else if (oflag & RT_DEVICE_FLAG_FIFO_RX && dev->flag & RT_DEVICE_FLAG_FIFO_RX) { /* If fifo mode is supported, configure it to fifo mode */ if (local_ctrl(sensor, RT_SENSOR_CTRL_SET_FETCH_MODE, (void *)RT_SENSOR_MODE_FETCH_FIFO) == RT_EOK) { /* Initialization sensor interrupt */ _sensor_irq_init(sensor); RT_SENSOR_MODE_SET_FETCH(sensor->info.mode, RT_SENSOR_MODE_FETCH_FIFO); } } else { res = -RT_EINVAL; goto __exit; } /* Configure power mode to highest mode */ if (local_ctrl(sensor, RT_SENSOR_CTRL_SET_POWER_MODE, (void *)RT_SENSOR_MODE_POWER_HIGHEST) == RT_EOK) { RT_SENSOR_MODE_SET_POWER(sensor->info.mode, RT_SENSOR_MODE_POWER_HIGHEST); } /* Configure accuracy mode to highest mode */ if (local_ctrl(sensor, RT_SENSOR_CTRL_SET_ACCURACY_MODE, (void *)RT_SENSOR_MODE_ACCURACY_HIGHEST) == RT_EOK) { RT_SENSOR_MODE_SET_ACCURACY(sensor->info.mode, RT_SENSOR_MODE_ACCURACY_HIGHEST); } __exit: if (sensor->module) { /* release the module mutex */ rt_mutex_release(sensor->module->lock); } return res; }
和V1版本相比,主要修改点有以下部分:
a.sen->info.mode的作用范围变宽,原先8bit表示一个意思,现在时3bit表示3种功能,剩余5bit为保留位,对应的操作也改为宏的方式隐藏
b.RT_PIN_NONE 变成了 PIN_IRQ_PIN_NONE,实际功能一致,个人怀疑是版本修改漏同步了v1
c.对应驱动的RT_SENSOR_CTRL_SET_MODE入口变成了 RT_SENSOR_CTRL_SET_FETCH_MODE,对应的传递到驱动的参数也由 RT_SENSOR_MODE_xxxx 变成了 RT_SENSOR_MODE_FETCH_xxxx,实际功能未变化
d.对应驱动的 RT_SENSOR_CTRL_SET_POWER入口变成了RT_SENSOR_CTRL_SET_POWER_MODE,参数 RT_SENSOR_POWER_NORMAL 变成了 RT_SENSOR_MODE_POWER_HIGHEST,具体功能未知,需从包管理器里面找到v2版驱动对应实现才清楚
e.新增接口 RT_SENSOR_CTRL_SET_ACCURACY_MODE,具体功能未知
关闭入口
static rt_err_t _sensor_close(rt_device_t dev) { rt_sensor_t sensor = (rt_sensor_t)dev; rt_err_t (*local_ctrl)(rt_sensor_t sensor, int cmd, void *arg) = _local_control; int i; RT_ASSERT(dev != RT_NULL); if (sensor->module) { rt_mutex_take(sensor->module->lock, RT_WAITING_FOREVER); } if (sensor->ops->control != RT_NULL) { local_ctrl = sensor->ops->control; } /* Configure power mode to power down mode */ if (local_ctrl(sensor, RT_SENSOR_CTRL_SET_POWER_MODE, (void *)RT_SENSOR_MODE_POWER_DOWN) == RT_EOK) { RT_SENSOR_MODE_SET_POWER(sensor->info.mode, RT_SENSOR_MODE_POWER_DOWN); } if (sensor->module != RT_NULL && sensor->info.fifo_max > 0 && sensor->data_buf != RT_NULL) { for (i = 0; i < sensor->module->sen_num; i ++) { if (sensor->module->sen[i]->parent.ref_count > 0) goto __exit; } /* Free memory for the sensor buffer */ for (i = 0; i < sensor->module->sen_num; i ++) { if (sensor->module->sen[i]->data_buf) { rt_free(sensor->module->sen[i]->data_buf); sensor->module->sen[i]->data_buf = RT_NULL; } } } if (RT_SENSOR_MODE_GET_FETCH(sensor->info.mode) != RT_SENSOR_MODE_FETCH_POLLING) { /* Sensor disable interrupt */ if (sensor->config.irq_pin.pin != PIN_IRQ_PIN_NONE) { rt_pin_irq_enable(sensor->config.irq_pin.pin, RT_FALSE); } } __exit: if (sensor->module) { rt_mutex_release(sensor->module->lock); } return RT_EOK; }
相比较于打开接口,关闭接口除了改变函数名称和参数名称,并未改任何功能,因此对照v1看就可以了。
读入口
static rt_ssize_t _sensor_read(rt_device_t dev, rt_off_t pos, void *buf, rt_size_t len) { rt_sensor_t sensor = (rt_sensor_t)dev; rt_size_t result = 0; RT_ASSERT(dev != RT_NULL); if (buf == NULL || len == 0) { return 0; } if (sensor->module) { rt_mutex_take(sensor->module->lock, RT_WAITING_FOREVER); } /* The buffer is not empty. Read the data in the buffer first */ if (sensor->data_len > 0) { if (len > sensor->data_len / sizeof(struct rt_sensor_data)) { len = sensor->data_len / sizeof(struct rt_sensor_data); } rt_memcpy(buf, sensor->data_buf, len * sizeof(struct rt_sensor_data)); /* Clear the buffer */ sensor->data_len = 0; result = len; } else { /* If the buffer is empty, read the data */ if (sensor->ops->fetch_data) { result = sensor->ops->fetch_data(sensor, buf, len); } } if (sensor->module) { rt_mutex_release(sensor->module->lock); } return result; }
与关闭接口一致,读入口也没有改变任何功能,仅仅是参数名和函数名的修改。
控制入口
static rt_err_t _sensor_control(rt_device_t dev, int cmd, void *args) { rt_sensor_t sensor = (rt_sensor_t)dev; rt_err_t result = RT_EOK; RT_ASSERT(dev != RT_NULL); rt_err_t (*local_ctrl)(rt_sensor_t sensor, int cmd, void *arg) = _local_control; rt_uint8_t mode; if (sensor->module) { rt_mutex_take(sensor->module->lock, RT_WAITING_FOREVER); } if (sensor->ops->control != RT_NULL) { local_ctrl = sensor->ops->control; } switch (cmd) { case RT_SENSOR_CTRL_GET_ID: if (args) { result = local_ctrl(sensor, RT_SENSOR_CTRL_GET_ID, args); } break; case RT_SENSOR_CTRL_SET_ACCURACY_MODE: /* Configuration sensor power mode */ mode = (rt_uint32_t)args & 0x000F; if (!(mode == RT_SENSOR_MODE_ACCURACY_HIGHEST || mode == RT_SENSOR_MODE_ACCURACY_HIGH ||\ mode == RT_SENSOR_MODE_ACCURACY_MEDIUM || mode == RT_SENSOR_MODE_ACCURACY_LOW ||\ mode == RT_SENSOR_MODE_ACCURACY_LOWEST || mode == RT_SENSOR_MODE_ACCURACY_NOTRUST)) { LOG_E("sensor accuracy mode illegal: %d", mode); return -RT_EINVAL; } result = local_ctrl(sensor, RT_SENSOR_CTRL_SET_ACCURACY_MODE, args); if (result == RT_EOK) { RT_SENSOR_MODE_SET_ACCURACY(sensor->info.mode, mode); LOG_D("set accuracy mode code: %d", RT_SENSOR_MODE_GET_ACCURACY(sensor->info.mode)); } break; case RT_SENSOR_CTRL_SET_POWER_MODE: /* Configuration sensor power mode */ mode = (rt_uint32_t)args & 0x000F; if (!(mode == RT_SENSOR_MODE_POWER_HIGHEST || mode == RT_SENSOR_MODE_POWER_HIGH ||\ mode == RT_SENSOR_MODE_POWER_MEDIUM || mode == RT_SENSOR_MODE_POWER_LOW ||\ mode == RT_SENSOR_MODE_POWER_LOWEST || mode == RT_SENSOR_MODE_POWER_DOWN)) { LOG_E("sensor power mode illegal: %d", mode); return -RT_EINVAL; } result = local_ctrl(sensor, RT_SENSOR_CTRL_SET_POWER_MODE, args); if (result == RT_EOK) { RT_SENSOR_MODE_SET_POWER(sensor->info.mode, mode); LOG_D("set power mode code: %d", RT_SENSOR_MODE_GET_POWER(sensor->info.mode)); } break; case RT_SENSOR_CTRL_SET_FETCH_MODE: /* Configuration sensor power mode */ mode = (rt_uint32_t)args & 0x000F; if (!(mode == RT_SENSOR_MODE_FETCH_POLLING || mode == RT_SENSOR_MODE_FETCH_INT ||\ mode == RT_SENSOR_MODE_FETCH_FIFO)) { LOG_E("sensor fetch data mode illegal: %d", mode); return -RT_EINVAL; } result = local_ctrl(sensor, RT_SENSOR_CTRL_SET_FETCH_MODE, args); if (result == RT_EOK) { RT_SENSOR_MODE_SET_FETCH(sensor->info.mode, mode); LOG_D("set fetch mode code: %d", RT_SENSOR_MODE_GET_FETCH(sensor->info.mode)); } break; case RT_SENSOR_CTRL_SELF_TEST: /* device self test */ result = local_ctrl(sensor, RT_SENSOR_CTRL_SELF_TEST, args); break; case RT_SENSOR_CTRL_SOFT_RESET: /* device soft reset */ result = local_ctrl(sensor, RT_SENSOR_CTRL_SOFT_RESET, args); break; default: if (cmd > RT_SENSOR_CTRL_USER_CMD_START) { /* Custom commands */ result = local_ctrl(sensor, cmd, args); } else { result = -RT_EINVAL; } break; } if (sensor->module) { rt_mutex_release(sensor->module->lock); } return result; }
控制入口算是V2版框架改动最大的地方,主要修改如下:
a.去掉了入口 RT_SENSOR_CTRL_GET_INFO,其实这个入口在V1上也没啥用,仅仅是系统自带的测试命令需要的入口,而v2版改为直接处理了,不再调用一层。
b.去掉了 RT_SENSOR_CTRL_SET_RANGE 和 RT_SENSOR_CTRL_SET_ODR两个入口,这个有点无厘头,因为按我理解,其实大部分传感器都支持设置采样率和量程范围的功能,去掉这个接口,意味着只能靠驱动自己内部默认几个参数了
c.RT_SENSOR_CTRL_SET_POWER 变成了 RT_SENSOR_CTRL_SET_POWER_MODE,功能个人猜测应该没变,但需要找已经适配的代码具体确认
d.新增了 RT_SENSOR_CTRL_SET_ACCURACY_MODE入口,具体功能未知,需找已适配的代码去确认
e.新增了入口 RT_SENSOR_CTRL_SET_FETCH_MODE,具体功能为切换传感器的工作模式(中断,轮询,FIFO)
f.新增了入口 RT_SENSOR_CTRL_SOFT_RESET,从名称上感觉是软复位,是否是需看已适配的v2驱动
新增入口 -- 查找传感器设备
rt_sensor_t rt_sensor_device_find(const char *name) { rt_uint8_t index; char device_name[RT_NAME_MAX]; rt_device_t device; for (index = 0; sensor_name_str[index] != RT_NULL; index++) { rt_memset(device_name, 0, sizeof(device_name)); rt_snprintf(device_name, sizeof(device_name), "%s%s", sensor_name_str[index], name); device = rt_device_find(device_name); if (device != RT_NULL) { return (rt_sensor_t)device; } } return RT_NULL; }
老实说,个人认为这个入口就是个坑,完全没考虑一颗芯片包含多种传感器的场景,如果不存在这种场景,可以考虑用一下这个接口,如果存在,那就不要用,很容易变成想要一个功能传感器,但拿到的是另一个功能的传感器。
总结
至此,v2版驱动已经分析完毕,相比较于v1版的驱动框架,个人认为宣传的改进不算大,相反,v2框架还去掉了一些必要的选项(量程和采样率的设置),反而限制了v2版传感器框架的使用。如果使用的话,在v2版框架成熟前,个人倾向于优先使用v1版传感器框架。事实上,如果没记错的话,去年下半年,rtt官方也默认禁用了V2版框架,个人猜测也是因为类似的原因吧。