ssc sensor 转载

三: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"},      ...}

上面config为platform-specific configuration,格式为:<sensor_name>

图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"},

下面说下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"}      }    },  ...}

格式为:<sensor_name>_<hadware_id>

图4

上图说明了driver-specific config中每个元素的含义。

了解完registry & config,下面开始学习SLPI层Sensor。

我们研究高通提供的demo sensor driver code:lsm6dso,顺带会说下SLPI侧sensor framework的code。

进入qcom_firware->slpi_proc->ssc->sensors->lsm6dso目录后,首先下看下build脚本。

####lsm6dso.scons######Import('env')importos,inspectif('SSC_TARGET_HEXAGON_MDSP'inenv['CPPDEFINES']):  Return()lsm6dso_island_enable =Falseif'SNS_ISLAND_INCLUDE_LSM6DSO'inenv:#No.1lsm6dso_island_enable =Trueif('SSC_TARGET_HEXAGON'inenv['CPPDEFINES'])and('SENSORS_DD_DEV_FLAG'notinenv):  env.AddSSCSU(inspect.getfile(inspect.currentframe()),#No.2register_func_name ="sns_register_lsm6dso",              binary_lib =False,              add_island_files = lsm6dso_island_enable)if'SENSORS_DD_DEV_FLAG'inenv:#No.3ME = 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)

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'])

在sensor driver code上,我们我要

(1) 把sensor中这些API放到sns__sensor_island.c中实现

//本例为sns_lsm6dso_sensor_island.csns_sensor_api 内容get_sensor_uid()set_client_request()  onlyforaccel driver libraries

(2)把sensor instance中这些API放到sns_<drv_name>_sensor_instance_island.c中实现

//本例为sns_lsm6dso_sensor_instance_island.csns_sensor_instance_api内容notify_event()set_client_config()  onlyforaccel driver libraries

(3)把所有sensor & sensor instance island中调用的函数放到sns_<drv_name>_hal_island.c中实现:

//本例为sns_lsm6dso_hal_island.clsm6dso_com_write_wrapper()lsm6dso_start_fifo_streaming()andso on...

Normal情况哪些API放在哪些文件中呢?

(1) 把sensor中这些API放到sns__sensor.c中实现

init()deinit()set_client_request()fornon-accel driver librariesnotify_event()

(2) 把sensor instance中这些API放到sns_<drv_name>_sensor_instance.c中实现

init()deinit()set_client_config() onlyfornon-accel driver libraries

(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.csns_rcsns_register_lsm6dso(sns_register_cbconst*register_api){inti =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);  }returnSNS_RC_SUCCESS;}//sns_lsm6dso_sensor_island.cconstlsm6dso_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}};

上面入口函数中注册四组api,每组api包含sns_sensor_api 和 sns_sensor_instance_api。

sns_sensor_api数据结构放在sns_lsm6dso_sensor_island.c中;

sns_sensor_instance_api数据结构放在sns_lsm6dso_sensor_instance_island.c中。

以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 *constthis);/**  * 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 *constthis);/**  * 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  *  *@returnThe unique identifier for this Sensor  */sns_sensor_uidconst* (*get_sensor_uid)(    sns_sensorconst*constthis);/**  * 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 *constthis);/**  * 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 *constthis,    struct sns_requestconst*exist_request,    struct sns_requestconst*new_request,    bool remove);} sns_sensor_api;

上面每个函数都有注释,这里不再解释。

//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)lsm6dso_accel_init

//sns_lsm6dso_accel_sensor.csns_rclsm6dso_accel_init(sns_sensor *constthis){  lsm6dso_state *state = (lsm6dso_state*)this->state->state;//No.1lsm6dso_acc_publish_attributes(this);//No.2lsm6dso_init_sensor_info(this, &((sns_sensor_uid)ACCEL_SUID), LSM6DSO_ACCEL);//No.3DBG_PRINT(state->diag_service,this, LOW, __FILENAME__, __LINE__,"accel init");returnSNS_RC_SUCCESS;}

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中并保存起来。

voidlsm6dso_acc_publish_attributes(sns_sensor *constthis){constchartype[] ="accel";constuint32_tactive_current[3] = {25,85,150};//uAconstuint32_tsleep_current =3;//uAlsm6dso_publish_def_attributes(this);  {    sns_std_attr_value_data values[] = {SNS_ATTR, SNS_ATTR, SNS_ATTR, SNS_ATTR,//No.aSNS_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.bsns_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.csns_std_attr_value_data values[] = {SNS_ATTR, SNS_ATTR, SNS_ATTR, SNS_ATTR};inti;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.dsns_std_attr_value_data values[] = {SNS_ATTR, SNS_ATTR, SNS_ATTR};inti;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.esns_std_attr_value_data value = sns_std_attr_value_data_init_default;    value.has_sint =true;    value.sint = sleep_current;//uAsns_publish_attribute(this, SNS_STD_SENSOR_ATTRID_SLEEP_CURRENT, &value,1,false);  }  {//No.fsns_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.gsns_std_attr_value_data values[] = {SNS_ATTR};charconstproto1[] ="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);  }}

看似好多东西啊,其实这些东西都是简单的参数。就是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

#defineSNS_ATTR sns_std_attr_value_data_init_default#definesns_std_attr_value_data_init_default    {false, sns_std_attr_value_init_default, {{NULL}, NULL}, false, 0, false, 0, false, 0}typedefstruct_sns_std_attr_value_data{boolhas_subtype;    sns_std_attr_value subtype;pb_callback_tstr;boolhas_flt;floatflt;boolhas_sint;int64_tsint;boolhas_boolean;boolboolean;/* @@protoc_insertion_point(struct:sns_std_attr_value_data) */} sns_std_attr_value_data;

可以看到有6个SNS_ATTR,即后面有6个value[ 0 ~ 5 ],value的has_flt位均设为true,value的flt为LSM6DSO_ODR_13、LSM6DSO_ODR_26、LSM6DSO_ODR_52等等,

设置完后,通过sns_publish_attribute将attribute_id为SNS_STD_SENSOR_ATTRID_RATES publish到attribute service中。

后面简略的介绍下sns_publish_attribute函数后续流程。

//sns_attribute_util.cSNS_SECTION(".text.sns")void//No.asns_publish_attribute(sns_sensor *constsensor,uint32_tattribute_id, sns_std_attr_value_dataconst*values,uint32_tvalues_len,boolcompleted){size_tattribute_len =0;  sns_std_attr std_attr = (sns_std_attr)//No.b{ .attr_id = attribute_id, .value.values.funcs.encode = &sns_pb_encode_attr_cb,      .value.values.arg = &((pb_buffer_arg){ .buf = values, .buf_len = values_len }) };if(pb_get_encoded_size(&attribute_len, sns_std_attr_fields, &std_attr))//No.c{    sns_service_manager *manager = sensor->cb->get_service_manager(sensor);    sns_attribute_service *attribute_service =      (sns_attribute_service*)manager->get_service(manager, SNS_ATTRIBUTE_SERVICE);uint8_tattribute[attribute_len];pb_ostream_tstream = pb_ostream_from_buffer(attribute, attribute_len);if(pb_encode(&stream, sns_std_attr_fields, &std_attr))//No.dattribute_service->api->publish_attribute(attribute_service, sensor,        attribute, attribute_len, attribute_id, completed);// PEND: Print a message upon errors}}

No.a 中 SNS_SECTION(".text.sns"),将函数放到.text.sns段。

No.b 中根据前面的values填充pb_buffer_arg、填充sns_std_attr数据结构。

typedefstruct_sns_std_attr{int32_tattr_id;    sns_std_attr_value value;/* @@protoc_insertion_point(struct:sns_std_attr) */} sns_std_attr;

No.c 中获取sns_service_manager,然后通过get_service来获取attribute service。

No.d 中通过attribute service中api进行push_attribute。

SNS_SECTION(".text.sns")staticsns_rcpublish_attribute(sns_attribute_service *this,structsns_sensor *sensor,voidconst*attribute, uint32_t attribute_len, sns_attribute_id attribute_id,boolcompleted){  UNUSED_VAR(this);  UNUSED_VAR(completed);  sns_list_iter iter;  sns_fw_sensor *fw_sensor = (sns_fw_sensor*)sensor;//No.asns_attribute *new_attr;  sns_mem_heap_id heap =    (SNS_STD_SENSOR_ATTRID_TYPE == attribute_id ||    SNS_STD_SENSOR_ATTRID_VENDOR == attribute_id)    ? SNS_HEAP_ISLAND : SNS_HEAP_MAIN;  SNS_ISLAND_EXIT();  new_attr = sns_malloc(heap,sizeof(*new_attr) + attribute_len);if(SNS_HEAP_ISLAND == heap &&NULL== new_attr)  {    new_attr = sns_malloc(SNS_HEAP_MAIN,sizeof(*new_attr) + attribute_len);    fw_sensor->island_operation = SNS_ISLAND_STATE_ISLAND_DISABLED;  }  SNS_ASSERT(NULL!= new_attr);  sns_list_item_init(&new_attr->list_entry, new_attr);  new_attr->id= attribute_id;  new_attr->value_len = attribute_len;  sns_memscpy(&new_attr->value, attribute_len, attribute, attribute_len);for(sns_list_iter_init(&iter, &fw_sensor->attr_info->attributes,true);NULL!= sns_list_iter_curr(&iter);      sns_list_iter_advance(&iter))  {    sns_attribute *attr =      (sns_attribute*)sns_list_item_get_data(sns_list_iter_curr(&iter));if(attr->id== attribute_id)    {      sns_list_iter_remove(&iter);      sns_free(attr);break;    }  }  sns_list_iter_insert(&iter, &new_attr->list_entry,false);  process_special_attributes(new_attr, fw_sensor);//No.breturnSNS_RC_SUCCESS;}

No.a中有个重要的数据结构sns_fw_sensor,该数据结构定义在sns_fw_sensor.h,每个sensor都有自己的sns_fw_sensor。将sns_sensor地址赋给sns_fw_sensor,所以sns_fw_sensor第一个成员为sns_sensor,而且sns_fw_sensor只用在framework层,不开放给sensor开发者使用。

No.b中process_special_attributes继续:

SNS_SECTION(".text.sns")staticvoidprocess_special_attributes(sns_attribute *new_attr, sns_fw_sensor *fw_sensor){if(SNS_STD_SENSOR_ATTRID_AVAILABLE == new_attr->id)    {boolavailable = (bool)decode_attribute(new_attr, &pb_decode_attr_value_cb);if(available != sns_attr_info_get_available(fw_sensor->attr_info))    {chardata_type[32];      sns_attr_info_get_data_type(fw_sensor->attr_info, data_type,sizeof(data_type));      sns_attr_info_set_available(fw_sensor->attr_info, available);      sns_suid_sensor_apprise(data_type);    }    sns_diag_register_sensor(fw_sensor);  }elseif(SNS_STD_SENSOR_ATTRID_TYPE == new_attr->id)  {    sns_attr_priority priority = {false,false};charconst*data_type =      (char*)decode_attribute(new_attr, &pb_decode_attr_value_cb);    SNS_ASSERT(NULL!= data_type);    sns_attr_info_set_data_type(fw_sensor->attr_info, data_type);for(uint8_ti =0; i < ARR_SIZE(event_priority_datatypes); i++)    {if(0==strcmp(data_type, event_priority_datatypes[i]))      {        priority.event_priority =true;break;      }    }for(uint8_ti =0; i < ARR_SIZE(req_priority_datatypes); i++)    {if(0==strcmp(data_type, req_priority_datatypes[i]))      {        priority.req_priority =true;break;      }    }    sns_attr_info_set_priority(fw_sensor->attr_info, priority);  }elseif(SNS_STD_SENSOR_ATTRID_VENDOR == new_attr->id)  {charconst*vendor = (char*)decode_attribute(new_attr, &pb_decode_attr_value_cb);    sns_attr_info_set_vendor(fw_sensor->attr_info, vendor);  }elseif(SNS_STD_SENSOR_ATTRID_PHYSICAL_SENSOR == new_attr->id &&          !sns_attr_info_get_is_physical_sensor(fw_sensor->attr_info))  {boolphysical_sensor = (bool)decode_attribute(new_attr, &pb_decode_attr_value_cb);    sns_attr_info_set_is_physical_sensor(fw_sensor->attr_info, physical_sensor);  }}

上面函数主要根据attribute_id进行不同的处理,并将数据保存在fw_sensor->attr_info中。

Ok,上面关于sns_publish_attribute大概介绍完毕,有兴趣的童鞋可以仔细研究,没有兴趣的话不影响大局,可以略过不看,只需记得attribte参数放进sns_fw_sensor->attr_info中,以便后续使用!

回到lsm6dso_acc_publish_attributes中。

No.b中:同样publish attribute_id为SNS_STD_SENSOR_ATTRID_TYPE的value。

No.c中:同样publish attribute_id为SNS_STD_SENSOR_ATTRID_RESOLUTIONS的value。

No.d中:同样publish attribute_id为SNS_STD_SENSOR_ATTRID_ACTIVE_CURRENT的value。

No.e中:同样publish attribute_id为SNS_STD_SENSOR_ATTRID_SLEEP_CURRENT的value。

No.f中:同样publish attribute_id为SNS_STD_SENSOR_ATTRID_RANGES的value。范围

No.g中:同样publish attribute_id为SNS_STD_SENSOR_ATTRID_API的value。API使用的是sns_accel.proto。

回到lsm6dso_init_sensor_info中,

首先介绍几个数据结构。之前我们知道有个struct sns_sensor,sns_sensor有个成员为struct sns_sensor_cb const*cb我们没有介绍过。

//sns_sensor.htypedefstructsns_sensor{/* Functions which call back into the framework; provided by the Framework */structsns_sensor_cbconst*cb;/* API implementation provided for and by this Sensor */structsns_sensor_apiconst*sensor_api;/* The associated API for an Sensor Instances created for and by this

  * Sensor. */structsns_sensor_instance_apiconst*instance_api;/* State space allocated by the Framework for the sole use of the Sensor

  * developer. */structsns_sensor_state*state;} sns_sensor;

//sns_sensor.htypedef struct sns_sensor_cb{  uint32_t struct_len;/**  * Get a reference to the Service Manager.  With this object, a reference  * to any other utility service can be obtained.  *  *@param[i] this Sensor reference  *  *@returnService Manager reference  */struct sns_service_manager* (*get_service_manager)(    sns_sensorconst*this);/**  * Return the next Sensor Instance associated with this Sensor.  *  * Each Sensor has a list of associated Sensor Instances; entries are added  * to that list within calls to 'create_instance', and removed from the  * list when it services no client requests.  *  * Each call to this function iterates over the list, and returns the next  * entry.  NULL is returned at the end of the list, or if the list is empty.  *  *@param[i] this Sensor reference  *@param[i] first Return the first instance; reset the internal iterator  *                Must be called first to initialize iteration  *  *@returnNext Sensor Instance associated with this Sensor  */struct sns_sensor_instance* (*get_sensor_instance)(    sns_sensorconst*this,    bool first);/**  * Allocate and initialize a new Sensor Instance to be associated with this  * Sensor.  Will call sns_sensor_instance::init.  *  *@noteDirect pointers to the returned value should not be saved.  *  *@param[i] this Sensor reference  *@param[i] stateLen Allocation size for sns_sensor_instance::state  *  *@returnNewly created Sensor Instance  */struct sns_sensor_instance* (*create_instance)(    sns_sensor *this,    uint32_t state_len);/**  * Remove and deallocate a Sensor Instance.  Will call  * sns_sensor_instance::deinit.  *  *@param[i] instance Instance received within set_client_request  */void(*remove_instance)(    struct sns_sensor_instance *instance);/**  * Return the next Sensor associated with this library.  *  * Each Sensor is a member of a library; each library may contain several  * Sensors.  Sensors may be removed from a library upon errors, but no  * entries are added after Framework initialization has completed.  *  * Each call to this function iterates over the list, and returns the next  * entry.  NULL is returned at the end of the list, or if the list is empty.  *  * This function is intended to be used by Sensors which share physical  * hardware with another sensor, and hence must share state/instances.  *  *@param[i] this Sensor reference  *@param[i] first Return the first sensor; reset the internal iterator;  *                Must be called first to initialize iteration  *  *@returnNext Sensor associated with this library.  */struct sns_sensor* (*get_library_sensor)(    sns_sensorconst*this,    bool first);/**  * If multiple copies of this Sensor Library have been registered with SEE,  * this returns the index (starting at '0') of this particular copy.  See  * parameter registration_cnt of env.AddSSCSU.  *  *@param[i] this Sensor reference  *  *@returnLibrary registration index  */uint32_t (*get_registration_index)(    sns_sensorconst*this);} sns_sensor_cb;

sns_sensor_cb是通过SEE framework 提供来给sensor使用的callback。其中包含5个函数,分别是

*.get_service_manager():用来获取service manager handle。

*.get_sensor_instance():用来获取sensor的下一个instance。

*.create_instance():创建新的instance。

*.remove_instance():移除存在的instance。

*.get_library_sensor():通过sensor library 获取另一个sensor的support。

No.3中:填充lsm6dso_state,

通过sns_sensor ->cb->get_service_manager来获取一个sns_service_manager的handle。sns_service_manager是可以管理所有service的数据结构。

然后在介绍下init_dependencies比较重要:

//sns_lsm6dso_sensor.cstaticchardef_dependency[][MAX_DEP_LENGTH] =  {"interrupt","async_com_port","timer","data_acquisition_engine","registry"};staticvoidinit_dependencies(sns_sensor *constthis){inti =0;  lsm6dso_state *state = (lsm6dso_state*)this->state->state;  DBG_PRINT(state->diag_service,this, LOW, __FILENAME__, __LINE__,"init_dependencies sensor");for(i=0;i

accel 所依赖的platform sensor。有interrupt、async_com_port、timer、registry等等。

send_suid_req函数内容比较中要!因为后面很多地方会用到,这里我们重点介绍下:

staticvoid send_suid_req(sns_sensor *this, char *constdata_type, uint32_t data_type_len){  lsm6dso_state *state = (lsm6dso_state*)this->state->state;if(state->fw_stream ==NULL)//No.a{    sns_service_manager *manager = this->cb->get_service_manager(this);    sns_stream_service *stream_service =      (sns_stream_service*)manager->get_service(manager, SNS_STREAM_SERVICE);    stream_service->api->create_sensor_stream(stream_service, this, sns_get_suid_lookup(),                                              &state->fw_stream);  }if(state->fw_stream !=NULL)//No.b{    size_t encoded_len;    pb_buffer_arg data = (pb_buffer_arg){ .buf = data_type, .buf_len = data_type_len };    uint8_t buffer[50];    sns_suid_req suid_req = sns_suid_req_init_default;                suid_req.has_register_updates =true;    suid_req.register_updates =true;    suid_req.data_type.funcs.encode = &pb_encode_string_cb;    suid_req.data_type.arg = &data;    sns_rc rc = SNS_RC_SUCCESS;    encoded_len = pb_encode_request(buffer, sizeof(buffer), &suid_req, sns_suid_req_fields,NULL);if(0< encoded_len)    {      sns_request request = (sns_request){        .request_len = encoded_len, .request = buffer, .message_id = SNS_SUID_MSGID_SNS_SUID_REQ };      rc = state->fw_stream->api->send_request(state->fw_stream, &request);    }if(0>= encoded_len || SNS_RC_SUCCESS != rc)    {      DBG_PRINT(state->diag_service, this, ERROR, __FILENAME__,__LINE__,"encoded_len=%d rc=%u", encoded_len, rc);    }  }}

No.a中:首先介绍个数据结构sns_data_stream

//sns_data_stream.htypedef struct sns_data_stream{  struct sns_data_stream_api *api;} sns_data_stream;typedef struct sns_data_stream_api{  uint32_t struct_len;/**  * Send a request to some other service/Sensor.  This request may  * update or replace the existing stream, depending on the Sensor  * specification.  *  *@param[io] data_stream Data stream on which to send the request  *@param[i] Request to be sent; Framework will copy request  *  *@return* SNS_RC_INVALID_TYPE - Request ID not valid  * SNS_RC_INVALID_STATE - Stream is no longer available; create again  * SNS_RC_SUCCESS  */sns_rc (*send_request)(    sns_data_stream *data_stream,    sns_request *request);/**  * Initiate a flush on the connection associated with sensorUID.  *  *@noteThis is a helper function; clients may also initiate a flush  * by generating a flush request message, and sending it via send_request.  *  *@param[io] data_stream Data stream on which to initiate the flush  *  *@return* SNS_RC_INVALID_STATE - Stream is no longer available; create again  * SNS_RC_SUCCESS  */sns_rc (*initiate_flush)(    sns_data_stream *data_stream);/**  * Retrieve a pointer to the oldest unprocessed input sample associated with  * this data stream from the event queue.  This event is a single, logical  * sample, as produced and published by the source Sensor.  *  *@noteMultiple sequential calls to this function will return the same  * pointer.  *  *@param[io] data_stream Data stream from which to get an event  *  *@returnNext unprocessed event on the queue; NULL if no events remain  */sns_sensor_event* (*peek_input)(    sns_data_stream *data_stream);/**  * Remove the current event from the input queue (the event that would  * be returned via peek_input).  Return the next unprocessed event from the  * event queue.  *  * Once this function returns, there is no means to retrieve the removed  * Event again; the data has been freed, and its memory should not be  * accessed.  *  *@param[io] data_stream Data stream from which to get an event  *  *@returnThe next unprocessed event on the queue (after the removal occurs)  *        NULL if no further events remain  */sns_sensor_event* (*get_next_input)(    sns_data_stream *data_stream);/**  * Lookup the current number of input pending on this data stream.  This  * value may change at any time, and should not be treated as precise.  *  *@noteDo no rely on this value to assume valid input from peek_input.  *  *@param[io] data_stream Data stream from which to get the input count  *  *@returnNumber of input events (aka samples) available for processing  */uint32_t (*get_input_cnt)(    sns_data_stream *data_stream);} sns_data_stream_api;

上面注释很清楚了,不再解释。

第一次很定进入state->fw_stream==NULL,通过获取sns_service_manager获取sns_service_type为SNS_STREAM_SERVICE的stream_service。并通过stream_service来创建一个新的sensor stream。

No.b中:接着会进入state->fw_stream != NULL,这里比较重要的是:会填充一个sns_suid_req,并通过pb_encode_request函数编码成buffer,然后继续填充sns_request,最后,通过state->fw_stream->api->send_request发送改message_id为SNS_SUID_MSGID_SNS_SUID_REQ的sns_request。后面不用说也可以知道,通过SNS_SUID_MSGID_SNS_SUID_EVENT接收的event,获取suid。不信,你可以看lsm6dso_sensor_notify_event中lsm6dso_process_suid_events函数。就是对SNS_SUID_MSGID_SNS_SUID_EVENT进行处理的。后面再详细介绍。

Ok,lsm6dso_accel_init解析完毕。

(2)init对应的是deinit

sns_rclsm6dso_accel_deinit(sns_sensor *constthis){  UNUSED_VAR(this);// Turn Sensor OFF.// Close COM port.// Turn Power Rails OFF.// No need to clear lsm6dso_state because it will get freed anyway.returnSNS_RC_SUCCESS;}

(3)lsm6dso_get_sensor_uid函数,用来获取suid。

sns_sensor_uidconst*lsm6dso_get_sensor_uid(sns_sensorconst*constthis){  lsm6dso_state *state = (lsm6dso_state*)this->state->state;return&state->my_suid;}

(4)lsm6dso_set_client_request函数,用来设置来自client的request。并创建sensor instance。

set_client_request函数的解释如下:

该函数是用来Add、remove、update来自client的request。

如果remove设为false:任何从sns_sensor_cb::get_sensor_instance()获取active的sensor instance来决定是否处理该request,若是,使用add_client_request将new request和existing instance关联起来。若不是,同样使用add_client_request来实例化并初始化一个新的sensor instance。在这两种情况下,exist_request存在,并且new_request提供一个超配置,exsit_request必须通过removed_client_request来移除。

如果remove为true:通过sns_sensor_instance_cb::remove_client_request来删除这个client,并重排来自client的request和sensor_instances。

可以看到在sns_stream_service.c的handle_req中,set_client_request的remove参数为false的。在handle_stream_destroy中,set_client_request的remove参数为true。

sns_sensor_instance* lsm6dso_set_client_request(sns_sensor *constthis,                                                struct sns_requestconst*exist_request,                                                struct sns_requestconst*new_request,                                                bool remove){  lsm6dso_state *state = (lsm6dso_state*)this->state->state;//No.1sns_sensor_instance *instance = sns_sensor_util_get_shared_instance(this);//No.2sns_diag_service* diag = state->diag_service;  sns_time on_timestamp;//No.3sns_time delta;  bool reval_config =false;  ...if(remove)//No.4{if(NULL== instance) {      DBG_PRINT(diag, this, ERROR, __FILENAME__,__LINE__,"lsm6dso_set_client_request:: Instance not available! Returning!");returninstance;    }    DBG_PRINT(diag, this, MED, __FILENAME__,__LINE__,"lsm6dso_set_client_request:: remove request");    lsm6dso_instance_state *inst_state =      (lsm6dso_instance_state*)instance->state->state;    inst_state->config_sensors |= state->sensor;    instance->cb->remove_client_request(instance, exist_request);/* Assumption: The FW will call deinit() on the instance before destroying it.

      Putting all HW resources (sensor HW, COM port, power rail)in

      low power state happens in Instance deinit().*/if(exist_request->message_id != SNS_PHYSICAL_SENSOR_TEST_MSGID_SNS_PHYSICAL_SENSOR_TEST_CONFIG)    {      lsm6dso_reval_instance_config(this, instance, state->sensor);    }else{      lsm6dso_instance_state *inst_state =        (lsm6dso_instance_state*)instance->state->state;//if reconfigure hw has been postponed due to a remove request during self test. Do it nowif(inst_state->self_test_info.reconfig_postpone)      {        DBG_PRINT(diag, this, MED, __FILENAME__,__LINE__,"Reconfiguring HW for request recieved during self-test");        lsm6dso_reval_instance_config(this, instance, state->sensor);        inst_state->fifo_info.interrupt_cnt =0;        inst_state->self_test_info.reconfig_postpone =false;      }//If a factory self test was run, update the registry & sensor->stateif(inst_state->self_test_info.update_registry)      {        DBG_PRINT(diag, this, MED, __FILENAME__,__LINE__,"Updating registry and sensor state with new calibration values");//copy to sensor stateif(LSM6DSO_ACCEL == inst_state->self_test_info.sensor)        {          sns_memscpy(state->fac_cal_bias, sizeof(state->fac_cal_bias),                      inst_state->accel_registry_cfg.fac_cal_bias, sizeof(inst_state->accel_registry_cfg.fac_cal_bias));        }elseif(LSM6DSO_GYRO == inst_state->self_test_info.sensor)        {          sns_memscpy(state->fac_cal_bias, sizeof(state->fac_cal_bias),                      inst_state->gyro_registry_cfg.fac_cal_bias, sizeof(inst_state->gyro_registry_cfg.fac_cal_bias));        }//Update flag in sensor_state to indicate which registry is to be updated//write registryinst_state->registry_reset.request =false;        lsm6dso_sensor_write_output_to_registry(this, instance);// Set the flag to false indicating that the registry is updatedinst_state->self_test_info.update_registry =false;      }    }  }else//No.5{// 1. If new request then://    a. Power ON rails.//    b. Power ON COM port - Instance must handle COM port power.//    c. Create new instance.//    d. Re-evaluate existing requests and choose appropriate instance config.//    e. set_client_config for this instance.//    f. Add new_request to list of requests handled by the Instance.//    g. Power OFF COM port if not needed- Instance must handle COM port power.//    h. Return the Instance.// 2. If there is an Instance already present://    a. Add new_request to list of requests handled by the Instance.//    b. Remove exist_request from list of requests handled by the Instance.//    c. Re-evaluate existing requests and choose appropriate Instance config.//    d. set_client_config for the Instance if not the same as current config.//    e. publish the updated config.//    f. Return the Instance.// 3.  If "flush" request://    a. Perform flush on the instance.//    b. Return NULL.DBG_PRINT(diag, this, MED, __FILENAME__,__LINE__,"lsm6dso_set_client_request:: add request ");if(NULL!= instance)    {      lsm6dso_instance_state *inst_state =        (lsm6dso_instance_state*)instance->state->state;if(inst_state->self_test_info.test_alive)      {        DBG_PRINT(diag, this, HIGH, __FILENAME__,__LINE__,"Self test is running. Ignoring new request! ");returnNULL;// Return without honouring any request for any sensor streaming}    }if(NULL== instance)    {if(state->sensor == LSM6DSO_GYRO)      {        state->rail_config.rail_vote = SNS_RAIL_ON_NPM;      }else{        state->rail_config.rail_vote = SNS_RAIL_ON_LPM;      }      state->pwr_rail_service->api->sns_vote_power_rail_update(          state->pwr_rail_service,          this,          &state->rail_config,          &on_timestamp);      delta = sns_get_system_time() - on_timestamp;// Use on_timestamp to determine correct Timer value.if(delta < sns_convert_ns_to_ticks(LSM6DSO_OFF_TO_IDLE_MS*1000*1000))      {        DBG_PRINT(diag, this, MED, __FILENAME__,__LINE__,"lsm6dso_set_client_request:: start power rail timer");        lsm6dso_start_power_rail_timer(this,            sns_convert_ns_to_ticks(LSM6DSO_OFF_TO_IDLE_MS*1000*1000) - delta,            LSM6DSO_POWER_RAIL_PENDING_SET_CLIENT_REQ);      }else{// rail is already ONDBG_PRINT(diag, this, MED, __FILENAME__,__LINE__,"lsm6dso_set_client_request::  power rail already ON");        state->power_rail_pend_state = LSM6DSO_POWER_RAIL_PENDING_NONE;        reval_config =true;      }      DBG_PRINT(diag, this, MED, __FILENAME__,__LINE__,"lsm6dso_set_client_request::  creating instance");/** create_instance() calls init() for the Sensor Instance */instance = this->cb->create_instance(this,          sizeof(lsm6dso_instance_state));/* If rail is already ON then flag instance OK to configure */if(reval_config)      {        lsm6dso_instance_state *inst_state =          (lsm6dso_instance_state*)instance->state->state;        inst_state->instance_is_ready_to_configure =true;      }    }else{      DBG_PRINT(diag, this, HIGH, __FILENAME__,__LINE__,"lsm6dso_set_client_request::  instance already available");if(NULL!= new_request)        DBG_PRINT(diag, this, MED, __FILENAME__,__LINE__,"sensor %d new_req msg_id %d",state->sensor, new_request->message_id);if(NULL!= exist_request          &&NULL!= new_request          &&          new_request->message_id == SNS_STD_MSGID_SNS_STD_FLUSH_REQ)      {        lsm6dso_instance_state *inst_state =          (lsm6dso_instance_state*)instance->state->state;if(inst_state->fifo_info.fifo_enabled &&          ((state->sensor == LSM6DSO_ACCEL) || (state->sensor == LSM6DSO_GYRO)))        {          lsm6dso_send_flush_config(this, instance);/** Do not update instance client request list at this point

            because FIFO flush is a transitory request for an on-going

            stream request. */returninstance;        }else{/** There aren't any FIFO sensors enabled to support flush.

          *  Send flush complete event anyway. */lsm6dso_send_fifo_flush_done(instance, &state->my_suid);returninstance;        }      }else{        reval_config =true;/** An existing client is changing request*/if((NULL!= exist_request) && (NULL!= new_request))        {          instance->cb->remove_client_request(instance, exist_request);        }/** A new client sent new_request*/elseif(NULL!= new_request)        {// No-op. new_request will be added to requests list below.}      }    }/** Add the new request to list of client_requests.*/if(NULL!= instance)    {      lsm6dso_instance_state *inst_state =        (lsm6dso_instance_state*)instance->state->state;if(NULL!= new_request)      {        instance->cb->add_client_request(instance, new_request);        DBG_PRINT(diag, this, HIGH, __FILENAME__,__LINE__,"lsm6dso_set_client_request::  adding new client request reval_config = %d inst_ready_to_config = %d", reval_config, inst_state->instance_is_ready_to_configure);        DBG_PRINT(diag, this, HIGH, __FILENAME__,__LINE__,"lsm6dso_set_client_request::  adding new client request sensor %d msg_id %d", state->sensor, new_request->message_id);if(LSM6DSO_MOTION_DETECT == state->sensor) {          sns_memscpy(&inst_state->md_info.md_config, sizeof(inst_state->md_info.md_config),              &state->md_config, sizeof(state->md_config));          DBG_PRINT(diag, this, HIGH, __FILENAME__,__LINE__,"lsm6dso_set_client_request:: copying md config");        }if(new_request->message_id == SNS_STD_SENSOR_MSGID_SNS_STD_SENSOR_CONFIG            ||            new_request->message_id == SNS_STD_EVENT_GATED_SENSOR_MSGID_SNS_STD_SENSOR_CONFIG) {          inst_state->config_sensors |= state->sensor;//copy range/resolution to inst stateif(LSM6DSO_ACCEL == state->sensor)          {            inst_state->accel_info.sstvt = lsm6dso_accel_resolutions[state->resolution_idx]*1000;//convert to micro-g/LSBinst_state->accel_info.range = lsm6dso_accel_ranges[state->resolution_idx];            inst_state->accel_info.range_idx = state->resolution_idx;          }elseif(LSM6DSO_GYRO == state->sensor)          {            inst_state->gyro_info.sstvt = lsm6dso_gyro_resolutions[state->resolution_idx];            inst_state->gyro_info.range = lsm6dso_gyro_ranges[state->resolution_idx];            inst_state->gyro_info.range_idx = state->resolution_idx;          }        }if(new_request->message_id == SNS_CAL_MSGID_SNS_CAL_RESET) {          DBG_PRINT(diag, this, HIGH, __FILENAME__,__LINE__,"Received event: SNS_CAL_MSGID_SNS_CAL_RESET");          inst_state->registry_reset.request =true;          inst_state->registry_reset.sensor_type = state->sensor;          lsm6dso_sensor_write_output_to_registry(this, instance);//copy to sensor stateif(LSM6DSO_ACCEL == state->sensor)          {            sns_memscpy(state->fac_cal_bias, sizeof(state->fac_cal_bias),                        inst_state->accel_registry_cfg.fac_cal_bias, sizeof(inst_state->accel_registry_cfg.fac_cal_bias));            sns_memscpy(&state->fac_cal_corr_mat, sizeof(state->fac_cal_corr_mat),                        &inst_state->accel_registry_cfg.fac_cal_corr_mat, sizeof(inst_state->accel_registry_cfg.fac_cal_corr_mat));          }elseif(LSM6DSO_GYRO == state->sensor)          {            sns_memscpy(state->fac_cal_bias, sizeof(state->fac_cal_bias),                        inst_state->gyro_registry_cfg.fac_cal_bias, sizeof(inst_state->gyro_registry_cfg.fac_cal_bias));            sns_memscpy(&state->fac_cal_corr_mat, sizeof(state->fac_cal_corr_mat),                        &inst_state->gyro_registry_cfg.fac_cal_corr_mat, sizeof(inst_state->gyro_registry_cfg.fac_cal_corr_mat));          }          lsm6dso_send_cal_event(instance, state->sensor);        }if(new_request->message_id == SNS_STD_SENSOR_MSGID_SNS_STD_ON_CHANGE_CONFIG          &&          state->sensor == LSM6DSO_MOTION_DETECT)        {if(inst_state->fifo_info.publish_sensors & LSM6DSO_ACCEL) {//send event as MD disabled since non-gated client is active//no need of this as we alreay set md_info statesns_motion_detect_event md_state;            md_state.motion_detect_event_type = SNS_MOTION_DETECT_EVENT_TYPE_DISABLED;            DBG_PRINT(diag, this, MED, __FILENAME__,__LINE__,"send MD_event =%d",                md_state.motion_detect_event_type);            pb_send_event(instance,                sns_motion_detect_event_fields,                &md_state,                sns_get_system_time(),                SNS_MOTION_DETECT_MSGID_SNS_MOTION_DETECT_EVENT,                &inst_state->md_info.suid);            reval_config =false;          }elseif(inst_state->md_info.enable_md_int) {//there is exsisting md client already present, just send eventDBG_PRINT(diag, this, MED, __FILENAME__,__LINE__,"send MD_event =%d",                inst_state->md_info.cur_md_state.motion_detect_event_type);            pb_send_event(instance,                sns_motion_detect_event_fields,                &inst_state->md_info.cur_md_state,                sns_get_system_time(),                SNS_MOTION_DETECT_MSGID_SNS_MOTION_DETECT_EVENT,                &inst_state->md_info.suid);            reval_config =false;          }elseinst_state->md_info.md_new_req =true;        }      }if(reval_config && inst_state->instance_is_ready_to_configure)      {        lsm6dso_reval_instance_config(this, instance, state->sensor);      }    }  }if(NULL!= instance) {    lsm6dso_instance_state *inst_state =      (lsm6dso_instance_state*)instance->state->state;//reset config sensor bit if sensor is not present if fifo enabledif(!(inst_state->fifo_info.fifo_enabled & state->sensor))      inst_state->config_sensors &= ~state->sensor;  }// Sensors are required to call remove_instance when clientlessif(NULL!= instance &&NULL== instance->cb->get_client_request(instance,      &(sns_sensor_uid)ACCEL_SUID,true) &&NULL== instance->cb->get_client_request(instance,      &(sns_sensor_uid)MOTION_DETECT_SUID,true) &&NULL== instance->cb->get_client_request(instance,      &(sns_sensor_uid)GYRO_SUID,true) &&NULL== instance->cb->get_client_request(instance,      &(sns_sensor_uid)SENSOR_TEMPERATURE_SUID,true))  {    this->cb->remove_instance(instance);  }returninstance;}

炒鸡多,一步步分析吧。开始之前,在了解下sns_sensor_instance中的sns_sensor_instance_cb的callback函数吧,上面我们介绍了sns_sensor中的sns_sensor_cb callback函数。

//sns_sensor_instance.htypedefstructsns_sensor_instance{/* Functions which call back into the framework; provided by the Framework */structsns_sensor_instance_cbconst*cb;/* State space allocated by the Framework for the sole use of the Sensor

  * Instance developer. */structsns_sensor_instance_state*state;} sns_sensor_instance;

//sns_sensor_instance.htypedef struct sns_sensor_instance_cb{  uint32_t struct_len;/**  * Get a reference to the Service Manager.  With this object, a reference  * to any other utility service can be obtained.  *  *@param[i] this Sensor Instance reference  *  *@returnService Manager reference  */struct sns_service_manager* (*get_service_manager)(    sns_sensor_instance *this);/**  * Return the next client request associated with this Sensor Instance and  * SUID.  *  * Each Sensor Instance has a list of client requests per SUID which it is  * servicing.  Entries are added via calls to add_client_request; removed  * via remove_client_request.  *  * Each call to this function iterates over the list, and returns the next  * entry.  NULL is returned at the end of the list, or if the list is empty.  *  *@noteAn Instance may be handling client requests for multiple  * (related) Sensors; must use SUID parameter to filter.  *  *@param[i] this Sensor Instance reference  *@param[i] suid Sensor associated with this Instance  *@param[i] first Return the first request; reset the internal iterator  *                Must be called first to initialize iteration  *  * SNS_RC_NOT_AVAILABLE - The Framework is not aware of SUID  * SNS_RC_SUCCESS  */struct sns_requestconst* (*get_client_request)(    sns_sensor_instance *this,    sns_sensor_uidconst*suid,    bool first);/**    * Remove a client request from this Sensor Instance.    *    *@param[i] this Sensor Instance reference    *@param[i] request Client request to be removed    */void(*remove_client_request)(    sns_sensor_instance *this,    struct sns_requestconst*request);/**  * Assign this Sensor Instance to service the client request.  *  *@noteThis function may only be given sns_request objects received  * from sns_sensor_api::set_client_request.  *  *@noteThe SUID of the recepient Sensor will be noted upon addition;  * this SUID must be used within get_client_request.  *  *@param[i] this Sensor Instance reference  *@param[i] request Client request to be added  */void(*add_client_request)(    sns_sensor_instance *this,    struct sns_requestconst*request);} sns_sensor_instance_cb;

四个函数分别如下:

*.get_service_manager():获取service manger的handle

*.get_client_request():获取与instance相关联的下一次client request。

*.remove_client_request():通过instance移除一个client的request handle。

*.add_client_request():通过instance添加一个client request handle。

然后就可以继续分析set_client_request代码了。

No.1:获取lsm6dso_state指针。

No.2:获取一个共享的instance,许多物理sensor会共享一个单独的instance,这个函数就是查找这个共享的instance,若有返回instance,若无返回NULL。

No.3:获取diag_service

No.4:remove为true,即为移除instance。首先判断instance是否为NULL,

若为NULL,OK,已经不能用了,直接返回即可。

若不为NULL,现获取从instance中获取lsm6dso_instance_state,并通过instance_state的callback函数cb来remove_client_request来从instance中移除exist_request。

紧接着,

若msg_id不是SNS_PHYSICAL_SENSOR_TEST_MSGID_SNS_PHYSICAL_SENSOR_TEST_CONFIG,需要设置instance的config并关电。在lsm6dso_reval_instance_config函数中进行处理。

若msg_id是,会将config数据写到registry sensor中,通过lsm6dso_sensor_write_output_to_registry()函数保存在“/persist/sensor/registry/registry/lsm6dso_0_platform.accel.fac_cal”和“/persist/sensor/registry/registry/lsm6dso_0_platform.gyro.fac_cal”中。

具体细节不再分析。

No.5:else为remove为false的情况。也为创建新的instance的情况。

高通代码给出了相应的注释。

若instance不为NULL,从instance获取lsm6dso_instance_state

若instance为NULL,

填充state的rail_config,设置rail电压。并通过sns_vote_power_rail_update配置rail config。

通过sns_get_system_time获取时间

lsm6dso_start_power_rail_timer来上电

通过create_instance来创建新的instance。

若instance不为NULL

若exist_request & new_request不为NULL,且new_request的msg_id为SNS_STD_MSGID_SNS_STD_FLUSH_REQ,若fifo enable,则发送flush fifo config,ACCEL & GYRO使用fifo,若fifo disable 或者不是accel or gyro,发送flash 完成的event。不再enable fifo 。(这里注意下:不要在enable后更新client的request给instance,因为FIFO是一个持续的stream request。)

若exist_request or  new_request为NULL 或者msg_id不为上面的msg_id,相应处理。

若instance 不为NULL,再跟进new_request->msg_id不同设置相应的config。这里我们看到了常见的new_request->message_id == SNS_STD_SENSOR_MSGID_SNS_STD_SENSOR_CONFIG。

然后都完成后,通过lsm6dso_reval_instance_config函数来通过sensor instance进行处理。

接着分析下lsm6dso_reval_instance_config(),主要有一个函数lsm6dso_set_inst_config,在该函数中,可以看到,client request发送到sensor API中.set_client_request的数据,最终通过lsm6dso_set_inst_config函数发送给sensor_instance API中.set_client_config。

voidlsm6dso_reval_instance_config(sns_sensor *this,                              sns_sensor_instance *instance,                              lsm6dso_sensor_type sensor_type){  ...uint8_tsensor_count = ARR_SIZE(lsm6dso_supported_sensors);struct{lsm6dso_sensor_type sensor;floatsample_rate;floatreport_rate;uint64_tflush_period_ticks;boolngated_client_present;//= client_presentboolgated_client_present;//incase of accel and md} sensor_info[sensor_count];  ...for(; i< sensor_count ; i++) {    ...if((sensor_info[i].sensor == LSM6DSO_ACCEL) ||        (sensor_info[i].sensor == LSM6DSO_GYRO)) {      lsm6dso_get_imu_config(this, instance, sensor_info[i].sensor,          &sensor_info[i].sample_rate,          &sensor_info[i].report_rate,          &sensor_info[i].flush_period_ticks,          &sensor_info[i].ngated_client_present,          &sensor_info[i].gated_client_present);      message_id = SNS_STD_SENSOR_MSGID_SNS_STD_SENSOR_CONFIG;      ...    }elseif(sensor_info[i].sensor == LSM6DSO_MOTION_DETECT) {      lsm6dso_get_motion_detect_config(this,          instance,          &sensor_info[i].ngated_client_present);          ...        message_id = SNS_STD_SENSOR_MSGID_SNS_STD_ON_CHANGE_CONFIG;        ...    }elseif(sensor_info[i].sensor == LSM6DSO_SENSOR_TEMP) {      lsm6dso_get_sensor_temp_config(this, instance,          &sensor_info[i].sample_rate,          &sensor_info[i].report_rate,          &sensor_info[i].flush_period_ticks,          &sensor_info[i].ngated_client_present);      message_id = SNS_STD_SENSOR_MSGID_SNS_STD_SENSOR_CONFIG;    } .    chosen_sample_rate = SNS_MAX(chosen_sample_rate, sensor_info[i].sample_rate);    chosen_report_rate = SNS_MAX(chosen_report_rate, sensor_info[i].report_rate);    chosen_flush_ticks = SNS_MAX(chosen_flush_ticks, sensor_info[i].flush_period_ticks);  ...  lsm6dso_set_inst_config(this,      instance,      sensor_type,      chosen_report_rate,      chosen_sample_rate,      chosen_flush_ticks,      registry_cfg,      message_id); ...}

lsm6dso_reval_instance_config函数中会针对不同sensor type进行不同的处理,比如accel & gyro,使用lsm6dso_get_imu_config来从request中获取payload数据填充sensor_info;motion_detect,使用lsm6dso_get_motion_detect_config来填充sensor_info等等,chosen_sample_rate & chosen_sample_rate & chosen_flush_ticks会通过request中参数和他们自己进行比较取最大者。并通过lsm6dso_set_inst_config传递给sensor instance。

staticvoidlsm6dso_set_inst_config(sns_sensor *this,    sns_sensor_instance *instance,    lsm6dso_sensor_type sensor,floatchosen_report_rate,floatchosen_sample_rate,uint64_tchosen_flush_ticks,    sns_lsm6dso_registry_cfg registry_cfg,uint32_tmessage_id){  ...if(((sensor == LSM6DSO_ACCEL) ||      (sensor == LSM6DSO_GYRO) ||      (sensor == LSM6DSO_MOTION_DETECT) ||      (sensor == LSM6DSO_SENSOR_TEMP)) &&      (inst_state->common_info.mode & LSM6DSO_MODE_SELF_TEST) &&      (!inst_state->self_test_info.test_alive)) {    sns_lsm6dso_self_test_req client_config;    client_config.test_type = inst_state->self_test_info.test_type;    req_config.message_id = SNS_PHYSICAL_SENSOR_TEST_MSGID_SNS_PHYSICAL_SENSOR_TEST_CONFIG;    req_config.request_len =sizeof(sns_lsm6dso_self_test_req);    req_config.request = &client_config;this->instance_api->set_client_config(instance, &req_config);  }elseif((sensor == LSM6DSO_ACCEL) ||      (sensor == LSM6DSO_GYRO) ||      (sensor == LSM6DSO_MOTION_DETECT) ||      (sensor == LSM6DSO_SENSOR_TEMP)) {    sns_lsm6dso_req client_config;    client_config.desired_report_rate = chosen_report_rate;    client_config.desired_sample_rate = chosen_sample_rate;    client_config.desired_flush_ticks = chosen_flush_ticks;    client_config.registry_cfg = registry_cfg;    req_config.message_id = message_id;    req_config.request_len =sizeof(sns_lsm6dso_req);    req_config.request = &client_config;this->instance_api->set_client_config(instance, &req_config);  }elsereturn;}

在该函数,

if中当inst_state->common_info.mode & LSM6DSO_MODE_SELF_TEST && (!inst_state->self_test_info.test_alive)为true,会用msg_id=SNS_PHYSICAL_SENSOR_TEST_MSGID_SNS_PHYSICAL_SENSOR_TEST_CONFIG进行factory calibration,往上追code发现,当client request中msg_id为SNS_PHYSICAL_SENSOR_TEST_MSGID_SNS_PHYSICAL_SENSOR_TEST_CONFIG时,会把inst_state->common_info.mode设成LSM6DSO_MODE_SELF_TEST的,这里是一一对应的。另外一个inst_state->self_test_info.test_alive,即此时正在进行操作,当然正在factory calibration操作时不能再操作,所以要满足该条件。

else中为正常走的流程,msg_id=SNS_STD_SENSOR_MSGID_SNS_STD_SENSOR_CONFIG也会走该路。两者最后都会调用this->instance_api->set_client_config(instance, &req_config);进入sensor instance中。

此时,sns_sensor_api除了.notify_event其他均分析完了,为了高清流程性,.notify_event会最后分析。

2: sns_sensor_instance_api定义在sns_sensor_instance.h中,结构如下:

//sns_sensor_instance.htypedef struct sns_sensor_instance_api{  uint32_t struct_len;/**  * Initialize a Sensor Instance to its default state.  A call to  * sns_sensor_instance_api::deinit will precede any subsequent calls  * to this function.  *  *@notePersistent configuration can be made available using the  * sensor_state.  *  *@param[i] this Sensor Instance reference  *@param[i] sensor_state State of the Sensor which created this Instance  *  *@return* SNS_RC_NOT_AVAILABLE - Sensor state does not allow for this operation  * SNS_RC_SUCCESS  */sns_rc (*init)(    sns_sensor_instance *constthis,    sns_sensor_stateconst*sensor_state);/**  * Release all hardware and software resources associated with this Sensor  * Instance.  *  *@param[i] this Sensor Instance reference  *  *@return* SNS_RC_INVALID_STATE - Error occurred: some resource could not be released  * SNS_RC_SUCCESS  */sns_rc (*deinit)(    sns_sensor_instance *constthis);/**  * Update a Sensor Instance configuration to this sensorRequest.  *  * The Sensor Instance is expected to start all dependent streams, timers, etc..  *  *@note* A Sensor may define any number of unique request types they support.  * However, a client may only have a single active stream; an enable  * request can inherently serve as a "reconfiguration" request.  *  *@param[i] this Sensor Instance reference  *  *@return* SNS_RC_INVALID_VALUE - Invalid client request  * SNS_RC_SUCCESS  */sns_rc (*set_client_config)(    sns_sensor_instance *constthis,    struct sns_requestconst*client_request);/**  * Notification to the client that some data has been received.  *  * The client must use the sns_manager_event 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_SUCCESS  */sns_rc (*notify_event)(    sns_sensor_instance *constthis);} sns_sensor_instance_api;

上面每个函数都有注释,这里不再解释。

什么时候会进入sns_sensor_instance API .init呢?在上面介绍中在lsm6dso_set_client_request有如下一段代码,

/** create_instance() calls init() for the Sensor Instance */instance =this->cb->create_instance(this,sizeof(lsm6dso_instance_state));

当instance为NULL时,通过cb创建一个instance,SEE framework会创建一个sensor instance并调用其.init函数。简略的追下code。

//sns_sensor.csns_rcsns_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,  };returnSNS_RC_SUCCESS;}

其中create_instance回调的是sns_sensor_instance_init。

//sns_sensor_instance.cSNS_SECTION(".text.sns") sns_sensor_instance*sns_sensor_instance_init(sns_sensor *sensor, uint32_t state_len){    sns_fw_sensor_instance *instance =NULL;    instance = sns_sensor_instance_alloc(fw_sensor, state_len);    ...    rv = sensor->instance_api->init(          (sns_sensor_instance*)instance, sensor->state);  ...return(sns_sensor_instance*)instance;}

其他不用管,可以看到sensor->instance_api->init()。

sns_rc lsm6dso_inst_init(sns_sensor_instance *constthis,    sns_sensor_stateconst*sstate){  state->scp_service = (sns_sync_com_port_service*)              service_mgr->get_service(service_mgr, SNS_SYNC_COM_PORT_SERVICE);/**---------Setup stream connections with dependent Sensors---------*/stream_mgr->api->create_sensor_instance_stream(stream_mgr,                                                this,                                                sensor_state->irq_suid,                                                &state->interrupt_data_stream);  stream_mgr->api->create_sensor_instance_stream(stream_mgr,                                                this,                                                sensor_state->acp_suid,                                                &state->async_com_port_data_stream);

在lsm6dso_inst_init中多数为初始化设置,包含获取sync_com_port service和创建async_com_port&interrupt data stream。

state->scp_service->api->sns_scp_register_com_port(&state->com_port_info.com_config,

                                              &state->com_port_info.port_handle);

通过instance注册com port。

在instance state复制所有sensor uids,初始化FIFO状态,初始Accel状态,初始Gyro状态等等,初始化中断数据,初始化com config,enable async com port:

/** Configure the Async Com Port */{    sns_data_stream* data_stream = state->async_com_port_data_stream;    uint8_t pb_encode_buffer[100];    sns_request async_com_port_request =    {      .message_id  = SNS_ASYNC_COM_PORT_MSGID_SNS_ASYNC_COM_PORT_CONFIG,      .request    = &pb_encode_buffer    };    async_com_port_request.request_len =      pb_encode_request(pb_encode_buffer,                        sizeof(pb_encode_buffer),                        &state->ascp_config,                        sns_async_com_port_config_fields,NULL);    data_stream->api->send_request(data_stream, &async_com_port_request);  }

等等。。。

对应的是lsm6dso_inst_deinit

sns_rclsm6dso_inst_deinit(sns_sensor_instance *constthis){  lsm6dso_instance_state *state =                  (lsm6dso_instance_state*)this->state->state;  inst_cleanup(this, state);returnSNS_RC_SUCCESS;}

staticvoid inst_cleanup(sns_sensor_instance *constthis,                        lsm6dso_instance_state *state){  ...if(NULL!= state->com_port_info.port_handle)  {    state->scp_service->api->sns_scp_update_bus_power(state->com_port_info.port_handle,true);  }  lsm6dso_set_fifo_config(this,0,0,0,0);  lsm6dso_reconfig_hw(this);if(NULL!= state->com_port_info.port_handle)  {    state->scp_service->api->sns_scp_update_bus_power(state->com_port_info.port_handle,false);  }  sns_sensor_util_remove_sensor_instance_stream(this, &state->interrupt_data_stream);  sns_sensor_util_remove_sensor_instance_stream(this, &state->async_com_port_data_stream);  sns_sensor_util_remove_sensor_instance_stream(this, &state->timer_sensor_temp_data_stream);  sns_sensor_util_remove_sensor_instance_stream(this, &state->timer_md_data_stream);  sns_sensor_util_remove_sensor_instance_stream(this, &state->timer_self_test_data_stream);  sns_sensor_util_remove_sensor_instance_stream(this, &state->timer_heart_beat_data_stream);if(NULL!= state->scp_service)  {    state->scp_service->api->sns_scp_close(state->com_port_info.port_handle);    state->scp_service->api->sns_scp_deregister_com_port(&state->com_port_info.port_handle);    state->scp_service =NULL;  }  lsm6dso_dae_if_deinit(this);}

inst_cleanup中:

判断port_handle是否存在,存在则关电。

通过sns_sensor_util_remove_sensor_instance_stream,remove掉所有在instance中创建的data_stream。

scp_service设成NULL

lsm6dso_dae_if_deinit

上面代码中client request最终进入的sensor instance  .set_client_config中。

作者:汉克233

链接:https://www.jianshu.com/p/6eaad04bdc00

来源:简书

简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容

  • 二:Sensor Hal层代码分析 Hal code放在/vendor/qcom/proprietary/sens...
    汉克233阅读 7,530评论 0 4
  • 英文文档,一开始我也是抗拒的,边翻译边看,也就花费了1个小时基本就阅读过了,我的英文基础其实很差。附上链接:链接:...
    lonecolonel阅读 9,845评论 3 1
  • NAME dnsmasq - A lightweight DHCP and caching DNS server....
    ximitc阅读 2,805评论 0 0
  • Awesome Ruby Toolbox Awesome A collection of awesome Ruby...
    debbbbie阅读 2,769评论 0 3
  • 一:简介 高通从SDM845平台开始,Sensor使用新的架构SEE(Sensors Execution Envi...
    seuwt阅读 1,864评论 0 51