1. 程式人生 > >三:Sensor SLPI層程式碼分析---

三:Sensor SLPI層程式碼分析---

三:Sensor SLPI層程式碼分析

在學習SLPI側程式碼前我們先了解下SEE的registry&config。
registry 放在/persist/sensors/registry/registry中,它是通過config生成的,是給SLPI解析的檔案。
config 放在/persist/sensors/registry/config中,它需要RD修改更新,用來生成register以便SLPI使用。每次config update後,即會更新registry。每次reboot後,會重新載入registry。

config都是以.json為字尾的檔案,每個物理sensor會有兩個json檔案,一個是包含所有平臺的特殊配置檔案,另一個是sensor driver的特殊配置檔案。

如果config檔案不存在並且sensor driver支援預設引數,則sensor library會將預設引數填充到registry中。

sensor driver可以通過傳送request給registry sensor來隨時更新registry。

下面來詳細介紹下json檔案:以高通給的demo檔案為例。
/persist/sensors/registry/config/sdm845_lsm6dsm_0.json

{
  "config":{
    "hw_platform": ["HDK"],
    "soc_id": ["341"]
  },
  "lsm6dso_0_platform"
:{ "owner": "lsm6dso", ".config":{ "owner": "lsm6dso", "bus_type":{ "type": "int", "ver": "0", "data": "1" }, "bus_instance":{ "type": "int", "ver": "0", "data": "2" }, "slave_config":{ "type": "int", "ver": "0", "data": "0" }, "min_bus_speed_khz"
:{ "type": "int", "ver": "0", "data": "0" }, "max_bus_speed_khz":{ "type": "int", "ver": "0", "data": "3300" }, ... }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

上面config為platform-specific configuration, 格式為:target _ sensor_name _ hadware_id

圖1
上圖說明了platform-specific config中每個元素的含義。

圖2
上圖為可以用作SPI or I2C的GPIO,這些GPIO是可以複用的,
舉個栗子:
bus_type:1,bus_instance:2,slave_config:1
意思為:使用SPI bus,QUP為2,即使用SSC_6、SSC_7、SSC_8、SSC_9、SSC_10、SSC_11這6組GPIO。slave_config為0,即裝置連在SSC_6(QUP2 lane4)上。

若bus_type :0 ,其他不變的話。
意思為:使用I2C bus,QUP為2,即使用SSC_2、SSC_3,I2C2這組I2C。slave address為0x01。

圖3
上圖為sensor中斷GPIO。高通強烈建議使用者使用中斷GPIO時與上圖一一對應,所以accel的中斷pin為117,mag的中斷pin為119。

//sdm845_icm206xx_0.json
"dri_irq_num":{ "type": "int", "ver": "0",
        "data": "117"
      },

//sdm845_ak0991x_0.json
"dri_irq_num":{ "type": "int", "ver": "0",
        "data": "119"
      },

  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

下面說下driver-specific configuration
/persist/sensors/registry/config/lsm6dsm_0.json

{
  "config":
  {
    "hw_platform": ["QRD", "MTP", "Dragon", "Surf", "HDK"],
    "soc_id": ["336", "341"]
  },
  "lsm6dso_0":{
    "owner": "lsm6dso",
    ".accel":{
      "owner": "lsm6dso",
      ".config":{
        "owner": "lsm6dso",
        "is_dri":{ "type": "int", "ver": "0",
          "data": "1"
        },
        "hw_id":{ "type": "int", "ver": "0",
          "data": "0"
        },
        "res_idx":{ "type": "int", "ver": "0",
          "data": "2"
        },
        "sync_stream":{ "type": "int", "ver": "0",
          "data": "0"
        }
      }
    },
    ".gyro":{
      "owner": "lsm6dso",
      ".config":{
        "owner": "lsm6dso",
        "is_dri":{ "type": "int", "ver": "0",
          "data": "1"
        },
        "hw_id":{ "type": "int", "ver": "0",
          "data": "0"
        },
        "res_idx":{ "type": "int", "ver": "0",
          "data": "4"
        },
        "sync_stream":{ "type": "int", "ver": "0",
          "data": "0"
        }
      }
    },
   ...
}
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

格式為: sensor_name_hadware_id

圖4
上圖說明了driver-specific config中每個元素的含義。

瞭解完registry & config,下面開始學習SLPI層Sensor。

/slpi/ssc/utils/osa/中為整個slpi的入口函式,分析build下osa.scons。可以看到user部分初始化函式為sns_user_pd_init。

 env.AddRCInitFunc(
    ['SSC_SLPI_USER','MODEM_MODEM','SSC_ADSP_USER'],
    {
      'sequence_group'             : 'RCINIT_GROUP_7',           # required
      'init_name'                  : 'sns',                      # required
      'init_function'              : 'sns_user_pd_init',         # required
      'dependencies'               : ['uTimetick','i2cbsp_init','adsppm_client','pram_mgr_clnt']
    })

  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

該init函式為高通開放給custormer的入口函式,可以理解為main函式。

sns_rc sns_user_pd_init()
{
  if(false == sns_init_done)
  {
/* If enabled, this will delay the framework initialization by 7 seconds.
   This is to easily capture init messages when SSC boots up */
#if defined(SNS_DELAY_INIT)
    const sns_time one_second_in_ticks = 19200000ULL;
    for(int i = 7; i > 0; i--)
    {
      MSG_1(MSG_SSID_SNS, DBG_MED_PRIO, "init countdown %d ", i);
      /* sns_busy_wait is implemented as a sleep() */
      sns_busy_wait(one_second_in_ticks);
    }
#endif
    ...
    sns_fw_init();
    ...
}
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

這裡我們不關心其他init,只研究sns_fw_init。我們開始進入SEE的framework層。
1.framework層
code放在/slpi/ssc/framework/中。

另外還要注意一下,SNS_DELAY_INIT這個巨集,當定義後,會delay 7s後再進行framework 初始化。一般在debug時會加上該巨集,用來抓取SSC boots up時的log。

//sns_fw_init.c
int sns_fw_init(void)
{
  ...
  rc = sns_sensor_init_fw();                      //No.1
  ...
  rc = sns_sensor_instance_init_fw();             //No.2
  ...
  rc = register_static_sensors();                 //No.3
  ...
  return 0;
}

//sns_sensor.c
sns_rc
sns_sensor_init_fw(void)
{
  ...
  sensor_cb = (sns_sensor_cb)
  {
    .struct_len = sizeof(sensor_cb),
    .get_service_manager = &get_service_manager,
    .get_sensor_instance = &get_sensor_instance,
    .create_instance = &sns_sensor_instance_init,
    .remove_instance = &sns_sensor_instance_deinit,
    .get_library_sensor = &get_library_sensor,
    .get_registration_index = &get_registration_index,
  };

  return SNS_RC_SUCCESS;
}

//sns_sensor_instance.c
sns_rc
sns_sensor_instance_init_fw(void)
{
  instance_cb = (sns_sensor_instance_cb)
  {
    .struct_len = sizeof(instance_cb),
    .get_service_manager = &get_service_manager,
    .get_client_request = &get_client_request,
    .remove_client_request = &remove_client_request,
    .add_client_request = &add_client_request
  };

  return SNS_RC_SUCCESS;
}

  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48

在sns_fw_init函式中我們著重分析上面三個函式,
No.1中是sns_sensor_cb的回撥函式,這裡需要注意下,後面分析sensor driver時會非常頻繁的用到這些回撥函式。
No.2中是sns_sensor_instance_cb的回到函式,同樣需要注意下,後面使用也很頻繁。
No.3中是所有sensor的靜態註冊函式。需要說明下,這個靜態註冊非常有意思。為了方便新增和移除sensor,高通SDM845中將註冊函式寫到build檔案中,每次build image時,會動態的將build中註冊函式寫到特定的sensor註冊檔案中,以便register_static_sensors()使用。

舉個例子,以accel的driver icm206xx為例,進入/slpi/ssc/sensors/icm206xx/中,看下build指令碼sns_icm206xx.scons。

if 'USES_SSC_STATIC_LIB_BUILDER' in env:
  if 'SSC_TARGET_HEXAGON' in env['CPPDEFINES']:
    env.AddSSCSU(inspect.getfile(inspect.currentframe()),
               flavor = ["hexagon"],
               register_func_name = "sns_register_icm206xx",
               binary_lib = False,
               add_island_files = icm206xx_island_enable)
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

上面的含義是,若USES_SSC_STATIC_LIB_BUILDER在環境中,則往環境中新增如下資料。。。。可以看到register_func_name = “sns_register_icm206xx”,後面解析可以知道sns_register_icm206xx為accel sensor的入口函式,這裡僅說明一下。

那麼build環境中是否有USES_SSC_STATIC_LIB_BUILDER呢?
在SLPI build指令碼ssc_static_lib_builder.py中中可以看到有加入該flag。

  env.AddUsesFlags('USES_SSC_STATIC_LIB_BUILDER')
  env.AddMethod(add_ssc_su, 'AddSSCSU')
  
  • 1
  • 2

那如何使用sensor入口函式sns_register_icm206xx呢?
還是在ssc_static_lib_builder.py中,有個函式generate_static_sensor_list()

if "sns_register_suid_sensor" == register_func_name:
          static_sensors.insert(0, (register_func_name, registration_cnt))
        else:
          static_sensors.append((register_func_name, registration_cnt))

#==============================================================================
# Generates sns_static_sensors.c
#==============================================================================
def generate_static_sensor_list(env, tags):
  global static_sensors
  if env.IsKeyEnable(tags) is True:
    logger.info("generate_static_sensor_list() called with %d sensors" % len(static_sensors))

    #dest = os.path.join(env.subst('${SSC_ROOT}'), 'framework', 'src')
    #if not os.path.isdir(dest) or not os.listdir(dest):
    #  return None

    if len(static_sensors) == 0:
      logger.error("There are no static sensors?!!!")
      return None

    static_sensors_file = os.path.join(env.subst('${SSC_ROOT}'),
                                       'framework', 'src', 'sns_static_sensors.c')
    fo = open(static_sensors_file, "w")
    fo.write("/* Autogenerated file.  Manual modification is pointless. */\n\n")
    fo.write("#include \"sns_rc.h\"\n")
    fo.write("#include \"sns_register.h\"\n")
    fo.write("#include \"sns_types.h\"\n")
    fo.write("\n")
    for reg_func,reg_cnt in static_sensors:
      fo.write("sns_rc %s(sns_register_cb const *register_api);\n" % reg_func)
    fo.write("\nconst sns_register_entry sns_register_sensor_list[] =\n{\n")
    for reg_func,reg_cnt in static_sensors:
      fo.write(" { %s, %i},\n" % (reg_func, reg_cnt))
    fo.write("};\n\n")
    fo.write("const uint32_t sns_register_sensor_list_len = ARR_SIZE(sns_register_sensor_list);\n\n")
    fo.close()

  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

這個函式的作用是根據所有sensor的build指令碼xxx.scons中入口函式,生成一個新的檔案sns_static_sensors.c。
ok,編譯完後git diff下,看到了生成的sns_static_sensors.c中新加了sns_register_icm206xx。

 sns_rc sns_gyro_cal_register(sns_register_cb const *register_api);
 sns_rc sns_gyro_rot_matrix_register(sns_register_cb const *register_api);
+sns_rc sns_register_icm206xx(sns_register_cb const *register_api);
 sns_rc sns_register_interrupt(sns_register_cb const *register_api);

const sns_register_entry sns_register_sensor_list[] =
 {
  { sns_gyro_rot_matrix_register, 1},
+ { sns_register_icm206xx, 1},
  { sns_register_interrupt, 1},
 }
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

我想大家應該都瞭解了吧,這樣做的目的就是很快捷的新增或刪除driver。

回到No.3,register_static_sensors函式中,

static sns_rc register_static_sensors(void)
{
  sns_register_cb reg_cb = (sns_register_cb)             //No.1
  {
    .struct_len = sizeof(reg_cb),
    .init_sensor = &sns_sensor_init                   
  };

  for(int i = 0; i < sns_register_sensor_list_len; i++)
  {
    for(int j = 0; j < sns_register_sensor_list[i].cnt; j++)      //No.2
    {
      ...
      sns_register_sensor_list[i].func(&reg_cb);
      sns_sensor_library_start(library);                        //No.3
      ...
    }
  }

  return SNS_RC_SUCCESS;
}
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

No.1中,sns_register_cb的回撥函式,每個sensor driver入口函式都會呼叫該資料結構中.init_sensor函式。該函式的主要作用是,(1)判斷是否是island mode,後面會將什麼是island mode。(2)將相關資料結構加入到連結串列。比如library、sensors等等。
No.2中,上面生成sns_static_sensors.c檔案中的sns_register_sensor_list.func,即sensor註冊的入口函式;然後執行。執行後就進入的sensor driver的世界。
No.3中,sns_sensor_library_start,主要呼叫sensor_api->init函式和sensor_api->get_sensor_uid函式,至於sensor_api是什麼,後面會講,這裡不懂先略過。

Ok,framework層初始化流程部分講了一部分,下面開始講sensor driver層,在sensor driver層講解中順帶會說下相關的framework層,這樣可以更深入的瞭解SEE框架。

2.sensor driver層
code放在/slpi/ssc/sensors/中
我們研究高通提供的demo sensor driver code:lsm6dso。

進入qcom_firware->slpi_proc->ssc->sensors->lsm6dso目錄後,首先下看下build指令碼。

####lsm6dso.scons######
Import('env')
import os,inspect

if ('SSC_TARGET_HEXAGON_MDSP' in env['CPPDEFINES']):
  Return()

lsm6dso_island_enable = False

if 'SNS_ISLAND_INCLUDE_LSM6DSO' in env:                                      #No.1
  lsm6dso_island_enable = True
if ('SSC_TARGET_HEXAGON' in env['CPPDEFINES']) and ('SENSORS_DD_DEV_FLAG' not in env):
  env.AddSSCSU(inspect.getfile(inspect.currentframe()),                      #No.2
               register_func_name = "sns_register_lsm6dso",
               binary_lib = False,
               add_island_files = lsm6dso_island_enable)

if 'SENSORS_DD_DEV_FLAG' in env:                                                   #No.3
  ME = inspect.getfile(inspect.currentframe())
  MY_ROOT = os.path.dirname(os.path.dirname(ME))
  REMOVE_FILES = env.FindFiles(['*.*'], MY_ROOT)
  env.CleanPack(env['SSC_BUILD_TAGS'], REMOVE_FILES)

  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

No.1中若存在flag=SNS_ISLAND_INCLUDE_LSM6DSO,則lsm6dso_island_enable=true,即lsm6dso被設定成island mode。何為Island mode,高通解釋island有著很低的功耗。

如何設定成為island mode呢?

在build指令碼上,我們需要設定flag,在build/ssc.scons中加入。

env.AddUsesFlags(['SNS_ISLAND_INCLUDE_LSM6DSO'])
  
  • 1

在sensor driver code上,我們我要
(1) 把sensor中這些API放到sns_< drv_name >_sensor_island.c中實現

//本例為sns_lsm6dso_sensor_island.c
sns_sensor_api 內容
get_sensor_uid()
set_client_request()  only for accel driver libraries
  
  • 1
  • 2
  • 3
  • 4

(2)把sensor instance中這些API放到sns_< drv_name >_sensor_instance_island.c中實現

//本例為sns_lsm6dso_sensor_instance_island.c
sns_sensor_instance_api內容
notify_event()
set_client_config()   only for accel driver libraries
  
  • 1
  • 2
  • 3
  • 4

(3)把所有sensor & sensor instance island中呼叫的函式放到sns_< drv_name >_hal_island.c中實現:

//本例為sns_lsm6dso_hal_island.c
lsm6dso_com_write_wrapper()
lsm6dso_start_fifo_streaming()
and so on...
  
  • 1
  • 2
  • 3
  • 4

Normal情況哪些API放在哪些檔案中呢?
(1) 把sensor中這些API放到sns_< drv_name >_sensor.c中實現

init()
deinit()
set_client_request() for non-accel driver libraries
notify_event()
  
  • 1
  • 2
  • 3
  • 4

(2) 把sensor instance中這些API放到sns_< drv_name >_sensor_instance.c中實現

init()
deinit()
set_client_config() only for non-accel driver libraries
  
  • 1
  • 2
  • 3

(3)所有sensor & sensor instance 非island中呼叫的函式放到sns_< drv_name >_hal.c中實現。

No.2中設定flag=SSC_TARGET_HEXAGON是動態註冊,registry_func_name=”sns_register_lsm6dso”為sensor driver的入口函式。binary_lib為是否是二進位制lib,高通的一些虛擬sensor比如計步器、amd、smd等等都是以lib形式提供給customer的。customer只要呼叫API使用即可,不需要知道如何實現。

No.3中設定flag=SENSORS_DD_DEV_FLAG是靜態註冊,在SDM845上使用的均為動態註冊。

接著來到入口函式中:

//sns_lsm6dso.c
sns_rc sns_register_lsm6dso(sns_register_cb const *register_api)
{
  int i = 0;
  /** Register Sensors */
  for(i = 0; i< ARR_SIZE(lsm6dso_supported_sensors) ; i++) {
    register_api->init_sensor(sizeof(lsm6dso_state), lsm6dso_supported_sensors[i].sensor_api,
        lsm6dso_supported_sensors[i].instance_api);
  }
  return SNS_RC_SUCCESS;
}

//sns_lsm6dso_sensor_island.c
const lsm6dso_sensors lsm6dso_supported_sensors[ MAX_SUPPORTED_SENSORS ] = {
  {LSM6DSO_ACCEL, &lsm6dso_accel_sensor_api, &lsm6dso_sensor_instance_api},
  {LSM6DSO_GYRO, &lsm6dso_gyro_sensor_api, &lsm6dso_sensor_instance_api},
  {LSM6DSO_MOTION_DETECT , &lsm6dso_motion_detect_sensor_api, &lsm6dso_sensor_instance_api},
  {LSM6DSO_SENSOR_TEMP, &lsm6dso_sensor_temp_sensor_api, &lsm6dso_sensor_instance_api}
};
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

上面入口函式中註冊四組api,每組api包含sns_sensor_api 和 sns_sensor_instance_api。
sns_sensor_api資料結構放在sns_lsm6dso_sensor_island.c中;該部分主要是為了sensor的初始化
sns_sensor_instance_api資料結構放在sns_lsm6dso_sensor_instance_island.c中;該部分主要是為了sensor對應的操作

以LSM6DSO_ACCEL為例:
1: sns_sensor_api定義在sns_sensor.h中,結構如下:

typedef struct sns_sensor_api
{
  uint32_t struct_len;

  /**
   * Initialize a Sensor to its hard-coded/default state.  Generate
   * requests for any other necessary data (e.g. Registry data).  A call to
   * sns_sensor_api::deinit will precede any subsequent calls to this function.
   *
   * @param[i] this Sensor reference
   *
   * @return
   * SNS_RC_INVALID_STATE - Requisite hardware not available
   * SNS_RC_POLICY - Required services not available
   * SNS_RC_SUCCESS
   */
  sns_rc (*init)(
    sns_sensor *const this);

  /**
   * Release all hardware and software resources associated with this Sensor
   *
   * @param[i] this Sensor reference
   *
   * @return
   * SNS_RC_INVALID_STATE - Error occurred: some resource could not be released
   * SNS_RC_SUCCESS
   */
  sns_rc (*deinit)(
    sns_sensor *const this);

  /**
   * Each Sensor must have a globally unique identifier; each algorithm
   * and driver will define their own. If a Sensor may be loaded twice on the
   * system, it is responsible for returning two unique values.  These must
   * not change across device reboots.
   *
   * @param[i] this Sensor reference
   *
   * @return The unique identifier for this Sensor
   */
  sns_sensor_uid const* (*get_sensor_uid)(
    sns_sensor const *const this);

  /**
   * Notification to the client that some data has been received.
   *
   * The client must use the sns_event_service to obtain this data
   * for processing.
   *
   * @return
   * SNS_RC_INVALID_STATE - A client error occurred; Framework shall destroy
   *                        client
   * SNS_RC_NOT_AVAILABLE - A transitory error occurred; Framework shall
   *                        remove all outstanding input
   * SNS_RC_INVALID_LIBRARY_STATE - A permanent error occurred; Framework shall
   *                        destroy all sensors present in the client library
   * SNS_RC_SUCCESS
   */
  sns_rc (*notify_event)(
    sns_sensor *const this);

  /**
   * Add, remove, or update a client's request to this Sensor.
   *
   * For each new request sent by a client, the Sensor (via this function)
   * will receive the new_request.  If the client has an active request
   * (which is to be replaced), it will be specified in exist_request.
   *
   * If 'remove' is false:
   * A client has sent a new request to this Sensor.  Determine if any
   * active Sensor Instance in sns_sensor_cb::get_sensor_instance()
   * will handle this request.  If yes, use add_client_request to associate
   * this new request with that existing Instance.
   *
   * If not, instantiate and initialize a new Sensor Instance with the
   * appropriate configuration, and similarly use add_client_request.
   *
   * In either case, if exist_request is provided and new_request provides
   * a superceding configuration, exist_request must be removed via
   * remove_client_request.
   *
   * If 'remove' is true:
   * Remove this client request by sns_sensor_instance_cb::remove_client_request;
   * re-arrange any remaining client requests/sensor instances.
   *
   * In all cases, if the result of the operation is a Sensor Instance with
   * zero clients, sns_sensor_cb::remove_instance must be called.
   *
   * @param[i] this Sensor reference
   * @param[i] exist_request If this request comes-in over an existing stream,
   *                       this is the existing request.
   * @param[i] new_request New request just received
   * @param[i] remove If the client no longer requires this data
   *
   * @return
   * The Sensor Instance chosen to handle this new client.  NULL if an error
   * occurred during processing; or if "remove" was true.
   * Or sns_instance_no_error (see above).
   */
  struct sns_sensor_instance* (*set_client_request)(
    sns_sensor *const this,
    struct sns_request const *exist_request,
    struct sns_request const *new_request,
    bool remove);
} sns_sensor_api;
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106

上面每個函式都有註釋,這裡不再解釋。

//sns_lsm6dso_sensor_island.c , sns_sensor_api放在island檔案中,上面island介紹中有解釋。
sns_sensor_api lsm6dso_accel_sensor_api =
{
  .struct_len         = sizeof(sns_sensor_api),
  .init               = &lsm6dso_accel_init,
  .deinit             = &lsm6dso_accel_deinit,
  .get_sensor_uid     = &lsm6dso_get_sensor_uid,
  .set_client_request = &lsm6dso_set_client_request,
  .notify_event       = &lsm6dso_sensor_notify_event,
};
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

Initialization
上面說到sns_sensor_library_start,主要呼叫sensor_api->init函式和sensor_api->get_sensor_uid函式,下面分別介紹.init和.get_sensor_uid函式。
(1)lsm6dso_accel_init

//sns_lsm6dso_accel_sensor.c
sns_rc lsm6dso_accel_init(sns_sensor *const this)
{
  lsm6dso_state *state = (lsm6dso_state*)this->state->state;                   //No.1
  lsm6dso_acc_publish_attributes(this);                                                    //No.2
  lsm6dso_init_sensor_info(this, &((sns_sensor_uid)ACCEL_SUID), LSM6DSO_ACCEL); //No.3
  DBG_PRINT(state->diag_service, this, LOW, __FILENAME__, __LINE__, "accel init");
  return SNS_RC_SUCCESS;
}
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

No.1中:此形式應用非常廣泛,同this指標中獲取lsm6dso_state。
lsm6dso_state定義在sns_lsm6dso_sensor.h中,是sensor driver兩個非常重要的資料結構之一,當然,另外一個是lsm6dso_instance_state。

(注:這裡寫成this,大家都明白什麼意思了吧,雖然c語言不是面嚮物件語言,但底層開發處處用到面向物件的思想,this這很明顯的說明sns_sensor類似於基類,不同的sensor都繼承該基類,該基類資料形式都是common的,強制型別轉換成每個sensor獨有的資料;在C語言中只不過不叫基類而已,在這裡叫做framework,在kernel中叫做core。)

No.2中:比較重要,將accel的atrributes publish到attribute service中並儲存起來。

void lsm6dso_acc_publish_attributes(sns_sensor *const this)
{
  const char type[] = "accel";
  const uint32_t active_current[3] = {25, 85, 150}; //uA
  const uint32_t sleep_current = 3; //uA

  lsm6dso_publish_def_attributes(this);
  {
    sns_std_attr_value_data values[] = {SNS_ATTR, SNS_ATTR, SNS_ATTR, SNS_ATTR,     //No.a
                                        SNS_ATTR, SNS_ATTR/*, SNS_ATTR, SNS_ATTR,SNS_ATTR*/};
    values[0].has_flt = true;
    values[0].flt = LSM6DSO_ODR_13;
    values[1].has_flt = true;
    values[1].flt = LSM6DSO_ODR_26;
    values[2].has_flt = true;
    values[2].flt = LSM6DSO_ODR_52;
    values[3].has_flt = true;
    values[3].flt = LSM6DSO_ODR_104;
    values[4].has_flt = true;
    values[4].flt = LSM6DSO_ODR_208;
    values[5].has_flt = true;
    values[5].flt = LSM6DSO_ODR_416;
    //QC currently we are limiting to 416
    /*
    values[6].has_flt = true;
    values[6].flt = LSM6DSO_ODR_833;
    values[7].has_flt = true;
    values[7].flt = LSM6DSO_ODR_1660;
    values[8].has_flt = true;
    values[8].flt = LSM6DSO_ODR_3330;
    values[9].has_flt = true;
    values[9].flt = LSM6DSO_ODR_6660;
    */
    sns_publish_attribute(this, SNS_STD_SENSOR_ATTRID_RATES,
        values, ARR_SIZE(values), false);
  }
  {                                                                                                      //No.b
    sns_std_attr_value_data value = sns_std_attr_value_data_init_default;
    value.str.funcs.encode = pb_encode_string_cb;
    value.str.arg = &((pb_buffer_arg)
        { .buf = type, .buf_len = sizeof(type) });
    sns_publish_attribute(
        this, SNS_STD_SENSOR_ATTRID_TYPE, &value, 1, false);
  }
  {                                                                                                 //No.c
    sns_std_attr_value_data values[] = {SNS_ATTR, SNS_ATTR, SNS_ATTR, SNS_ATTR};
    int i;
    for(i = 0; i < ARR_SIZE(values); i++)
    {
      values[i].has_flt = true;
      values[i].flt = lsm6dso_accel_resolutions[i];
    }
    sns_publish_attribute(this, SNS_STD_SENSOR_ATTRID_RESOLUTIONS,
        values, i, false);
  }
  {                                                                                                 //No.d
    sns_std_attr_value_data values[] = {SNS_ATTR, SNS_ATTR, SNS_ATTR};
    int i;
    for(i = 0; i < ARR_SIZE(active_current); i++)
    {
      values[i].has_sint = true;
      values[i].sint = active_current[i];
    }
    sns_publish_attribute(this, SNS_STD_SENSOR_ATTRID_ACTIVE_CURRENT,
        values, i, false);
  }
  {                                                                                            //No.e
    sns_std_attr_value_data value = sns_std_attr_value_data_init_default;
    value.has_sint = true;
    value.sint = sleep_current; //uA
    sns_publish_attribute(
        this, SNS_STD_SENSOR_ATTRID_SLEEP_CURRENT, &value, 1, false);
  }
  {                                                                                          //No.f
    sns_std_attr_value_data values[] = {SNS_ATTR, SNS_ATTR, SNS_ATTR, SNS_ATTR};

    sns_std_attr_value_data range1[] = {SNS_ATTR, SNS_ATTR};
    range1[0].has_flt = true;
    range1[0].flt = LSM6DSO_ACCEL_RANGE_2G_MIN;
    range1[1].has_flt = true;
    range1[1].flt = LSM6DSO_ACCEL_RANGE_2G_MAX;
    values[0].has_subtype = true;
    values[0].subtype.values.funcs.encode = sns_pb_encode_attr_cb;
    values[0].subtype.values.arg =
      &((pb_buffer_arg){ .buf = range1, .buf_len = ARR_SIZE(range1) });

    sns_std_attr_value_data range2[] = {SNS_ATTR, SNS_ATTR};
    range2[0].has_flt = true;
    range2[0].flt = LSM6DSO_ACCEL_RANGE_4G_MIN;
    range2[1].has_flt = true;
    range2[1].flt = LSM6DSO_ACCEL_RANGE_4G_MAX;
    values[1].has_subtype = true;
    values[1].subtype.values.funcs.encode = sns_pb_encode_attr_cb;
    values[1].subtype.values.arg =
      &((pb_buffer_arg){ .buf = range2, .buf_len = ARR_SIZE(range2) });

    sns_std_attr_value_data range3[] = {SNS_ATTR, SNS_ATTR};
    range3[0].has_flt = true;
    range3[0].flt = LSM6DSO_ACCEL_RANGE_8G_MIN;
    range3[1].has_flt = true;
    range3[1].flt = LSM6DSO_ACCEL_RANGE_8G_MIN;
    values[2].has_subtype = true;
    values[2].subtype.values.funcs.encode = sns_pb_encode_attr_cb;
    values[2].subtype.values.arg =
      &((pb_buffer_arg){ .buf = range3, .buf_len = ARR_SIZE(range3) });

    sns_std_attr_value_data range4[] = {SNS_ATTR, SNS_ATTR};
    range4[0].has_flt = true;
    range4[0].flt = LSM6DSO_ACCEL_RANGE_16G_MIN;
    range4[1].has_flt = true;
    range4[1].flt = LSM6DSO_ACCEL_RANGE_16G_MAX;
    values[3].has_subtype = true;
    values[3].subtype.values.funcs.encode = sns_pb_encode_attr_cb;
    values[3].subtype.values.arg =
      &((pb_buffer_arg){ .buf = range4, .buf_len = ARR_SIZE(range4) });
    sns_publish_attribute(this, SNS_STD_SENSOR_ATTRID_RANGES,
        values, ARR_SIZE(values), true);
  }
  {                                                                                                  //No.g
    sns_std_attr_value_data values[] = {SNS_ATTR};
    char const proto1[] = "sns_accel.proto";
    values[0].str.funcs.encode = pb_encode_string_cb;
    values[0].str.arg = &((pb_buffer_arg)
        { .buf = proto1, .buf_len = sizeof(proto1) });
    sns_publish_attribute(this, SNS_STD_SENSOR_ATTRID_API,
        values, ARR_SIZE(values), false);
  }
}
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128

看似好多東西啊,其實這些東西都是簡單的引數。就是lsm6dso driver中accel的一些屬性。
sns_publish_attribute引數分別代表:1,sns_sensor;2,attribute_id;3,value;4,value length;5,completed代表是否是最後一被設定的屬性,若為true,後續不能修改該屬性;若為false,後續可以修改該屬性。

No.a中,sns_std_attr_value_data是一個儲存attr value的data,初始化元素為SNS_ATTR

#define SNS_ATTR sns_std_attr_value_data_init_default

#define sns_std_attr_value_data_init_default     {false, sns_std_attr_value_init_default, {{NULL}, NULL}, false, 0, false, 0, false, 0}

typedef struct _sns_std_attr_value_data {
    bool has_subtype;