上一篇我們將 framework 層和 HAL 層的溝通,
是怎麼透過 HIDL service 的方式串接起來介紹完了,
這篇就來實際找一個 AOSP 內部代碼的 sensor 架構來看看,
在 hardware
資料夾內找到一個內建的 invensense/65xx/
可以來看看:
hardware/invensense/65xx/libsensors_iio/sensors_mpl.cpp
66 static struct hw_module_methods_t sensors_module_methods = {
67 open: open_sensors
68 };
啟始點一定是叫什麼 sensors.cpp
的,
而後面的 mpl 即是 Motion Processing Library,
是 Invensense 專利的演算法庫 (想當然是不開源),
其作用是傳感器融合和動態標定。
進來看之後就更確定,
可以看到 hw_module_methods_t
裡面只有一個開始函數 open_sensors()
:
hardware/invensense/65xx/libsensors_iio/sensors_mpl.cpp
381 /** Open a new instance of a sensor device using name */
382 static int open_sensors(const struct hw_module_t* module, const char* id,
383 struct hw_device_t** device)
384 {
385 FUNC_LOG;
386 int status = -EINVAL;
387 **sensors_poll_context_t *dev = new sensors_poll_context_t();**
388
389 memset(&dev->device, 0, sizeof(sensors_poll_device_1));
390
391 dev->device.common.tag = HARDWARE_DEVICE_TAG;
392 dev->device.common.version = SENSORS_DEVICE_API_VERSION_1_0;
393 dev->device.common.module = const_cast<hw_module_t*>(module);
394 dev->device.common.close = poll__close;
395 dev->device.activate = poll__activate;
396 dev->device.setDelay = poll__setDelay;
397 dev->device.poll = poll__poll;
398
399 /* Batch processing */
400 dev->device.batch = poll__batch;
401 dev->device.flush = poll__flush;
402
403 *device = &dev->device.common;
404 status = 0;
405
406 return status;
407 }
特別講一下各個用途:
get_sensors_list
activate
batch
setDelay
flush
poll
該接口還定義了這些函數使用的幾個類型。
可參閱 sensors.h
了解有關這些類型的更多信息,
主要類型如下:
我們特別看一下 sensors_poll_device_t
裡面有一個 mPollFds
的宣告:
hardware/invensense/65xx/libsensors_iio/sensors_mpl.cpp
86 struct sensors_poll_context_t {
87 sensors_poll_device_1_t device; // must be first
88
89 sensors_poll_context_t();
90 ~sensors_poll_context_t();
91 int activate(int handle, int enabled);
92 int setDelay(int handle, int64_t ns);
93 int pollEvents(sensors_event_t* data, int count);
94 int query(int what, int *value);
95 int batch(int handle, int flags, int64_t period_ns, int64_t timeout);
96 int flush(int handle);
97
98 private:
99 enum {
100 mpl = 0,
101 compass,
102 dmpOrient,
103 dmpSign,
104 dmpPed,
105 numSensorDrivers, // wake pipe goes here
106 numFds,
107 };
108
109 **struct pollfd mPollFds[numFds]**;
110 **SensorBase *mSensor**;
111 CompassSensor *mCompassSensor;
112
113 static const size_t wake = numSensorDrivers;
114 static const char WAKE_MESSAGE = 'W';
115 int mWritePipeFd;
116 };
它會在 sensors_poll_context_t()
底下指定參數和呼叫 getFd()
:
hardware/invensense/65xx/libsensors_iio/sensors_mpl.cpp
120 sensors_poll_context_t::sensors_poll_context_t() {
121 VFUNC_LOG;
... ...
124 mCompassSensor = new CompassSensor();
125 MPLSensor *mplSensor = new MPLSensor(mCompassSensor);
... ...
140 **mSensor = mplSensor**;
141 **mPollFds[mpl].fd = mSensor->getFd()**;
142 **mPollFds[mpl].events = POLLIN**;
143 **mPollFds[mpl].revents = 0**;
... ...
它這裡就會帶到 MPLSensor.cpp
中的 getFd()
,
返回 iio_fd
的位置來讀取和寫入:
hardware/invensense/65xx/libsensors_iio/MPLSensor.cpp
4196 int MPLSensor::getFd(void) const
4197 {
4198 VFUNC_LOG;
4199 LOGV_IF(EXTRA_VERBOSE, "getFd returning %d", iio_fd);
4200 **return iio_fd**;
4201 }
這裡直接寫在 enable 相關函式時候獲取 iio_fd
的值:
hardware/invensense/65xx/libsensors_iio/MPLSensor.cpp
680 void MPLSensor::enable_iio_sysfs(void)
681 {
682 VFUNC_LOG;
683
684 char iio_device_node[MAX_CHIP_ID_LEN];
... ...
723 **inv_get_iio_device_node(iio_device_node);**
724 **iio_fd = open(iio_device_node, O_RDONLY);**
725 if (iio_fd < 0) {
726 LOGE("HAL:could not open iio device node");
727 } else {
728 LOGV_IF(ENG_VERBOSE, "HAL:iio iio_fd opened : %d", iio_fd);
729 }
730 }
hardware/invensense/65xx/libsensors_iio/software/core/mllite/linux/ml_sysfs_helper.c
513 /**
514 * @brief return iio device node. If iio is not initialized, return false.
515 * So the return must be checked to make sure the numeber is valid.
516 * @unsigned char *name: This should be array big enough to hold the device
517 * node. It should be zeroed before calling this function.
518 * Or it could have unpredicable result.
519 */
520 inv_error_t inv_get_iio_device_node(const char *name)
521 {
522 if (**process_sysfs_request(CMD_GET_DEVICE_NODE, (char *)name)** < 0)
523 return INV_ERROR_NOT_OPENED;
524 else
525 return INV_SUCCESS;
526 }
可以看出這裡一樣是透過字串拼接出來的節點名稱:
hardware/invensense/65xx/libsensors_iio/software/core/mllite/linux/ml_sysfs_helper.c
242 static int process_sysfs_request(enum PROC_SYSFS_CMD cmd, char *data)
243 {
... ...
277 case **CMD_GET_DEVICE_NODE**:
278 **sprintf(data, "/dev/iio:device%d", iio_dev_num);**
279 break;
iio_dev_num
是由 dev_num
來的,
但是看來又是從 iio_chip
來的:
hardware/invensense/65xx/libsensors_iio/software/core/mllite/linux/ml_sysfs_helper.c
46 #define CHIP_NUM ARRAY_SIZE(chip_name)
... ...
224 static void init_iio() {
225 int i, j;
226 char iio_chip[10];
227 int dev_num;
228 for(j=0; j< CHIP_NUM; j++) {
229 for (i=0; i<strlen(chip_name[j]); i++) {
230 iio_chip[i] = tolower(chip_name[j][i]);
231 }
232 **iio_chip[strlen(chip_name[j])] = '\0';**
233 **dev_num = find_type_by_name(iio_chip, "iio:device");**
234 if(dev_num >= 0) {
235 iio_initialized = 1;
236 **iio_dev_num = dev_num**;
237 chip_ind = j;
238 }
239 }
240 }
iio_chip
是從 chip_name
這個建構子中的順序得來的:
hardware/invensense/65xx/libsensors_iio/software/core/mllite/linux/ml_sysfs_helper.c
24 static char *chip_name[] = {
25 "ITG3500",
26 "MPU6050",
27 "MPU9150",
28 "MPU3050",
29 "MPU6500",
30 "MPU9250",
31 "MPU6XXX",
32 "MPU9350",
33 "MPU6515",
34 };
到這裡就結束了,
再往回頭看就可以知道 enable_iio_sysfs
會打開模組,
然後由 HAL 這邊發起對模組的初始化。
中途在鐵人賽第 20 日忘記 po 文而宣告終結,
其實還都有預留很多文章待發,
很氣自己粗心也覺得很遺憾。
但有時就是這樣,總是會有意外發生,
重要的是記取教訓就好。
明年會每天設定鬧鐘發文的!哈哈!
這系列就這樣結束囉,
很感謝看完的各位優秀先進們,
往後也會不定時以自己所學更新文章。