iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 20
1
Mobile Development

Android Pie 底層開發學習心得系列 第 30

[Day-30] Android Pie Sensor (7) 硬件抽象層 (2)

  • 分享至 

  • xImage
  •  
  • Guide:
    • 介紹 (Overview)
    • 架構 (Architecture)
    • 應用 (Application)
    • 服務 (Service)
    • 硬件抽象層 (HAL)

動作傳感器

上一篇我們將 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

    • 僅用於 1.0 版本的 HAL。設置指定傳感器的採樣率。
  • flush

    • 刷寫指定傳感器的 FIFO 並在完成後報告刷寫完成事件。
  • poll

    • 返回可用的傳感器事件。

該接口還定義了這些函數使用的幾個類型。
可參閱 sensors.h 了解有關這些類型的更多信息,
主要類型如下:

  • sensors_module_t
  • sensors_poll_device_t
  • sensor_t
  • sensors_event_t

我們特別看一下 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 文而宣告終結,
其實還都有預留很多文章待發,
很氣自己粗心也覺得很遺憾。
但有時就是這樣,總是會有意外發生,
重要的是記取教訓就好。
明年會每天設定鬧鐘發文的!哈哈!
這系列就這樣結束囉,
很感謝看完的各位優秀先進們,
往後也會不定時以自己所學更新文章。


上一篇
[Day-29] Android Pie Sensor (6) 硬件抽象層 (1)
系列文
Android Pie 底層開發學習心得30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
阿展展展
iT邦好手 1 級 ‧ 2020-02-24 04:56:20

可惜計算中斷惹
辛苦了 /images/emoticon/emoticon47.gif

海波浪 iT邦新手 5 級 ‧ 2020-02-24 12:14:26 檢舉

哈哈哈沒關係 我已釋懷 謝謝你 :)

我要留言

立即登入留言