三: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
上圖說明了platform-specific config中每個元素的含義。
上圖為可以用作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。
上圖為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
上圖說明了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(®_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;