我是靠谱客的博主 明亮雨,最近开发中收集的这篇文章主要介绍1.高通SEE 虚拟sensor分析,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

在SEE中,处理硬件sensor,高通实现的platform sensor,还有一类是通过硬件sensor等各种数据计算,抽象出来的虚拟sensor。

我们以高通提供的参考为例,看如何添加一个虚拟sensor和虚拟sensor执行流程。

1.pb协议文件定位sensor类型数据

在Non-HLOSadsp_procssc_apipbsns_oem1.proto中定义了oem1这个虚拟sensor的sns_oem1_msgid和sns_oem1_data。

syntax = "proto2";
import "nanopb.proto";
import "sns_std_sensor.proto";

enum sns_oem1_msgid
{
  option (nanopb_enumopt).long_names = false;

  SNS_OEM1_MSGID_SNS_OEM1_DATA = 1024;
}

// Data Message
// Output data event generated by the oem1 sensor.
message sns_oem1_data
{
  // oem1 Vector along axis x,y,z in m/s2
  repeated float oem1 = 1 [(nanopb).max_count = 3];

  // Accuracy of the data
  required sns_std_sensor_sample_status accuracy = 2;
}

这个文件在pb工具编译后,将生成对应的.c和.h文件。pb是一种数据打包协议,SEE中传递数据和事件信息,全都通过pb进行打包,打包将会包含这笔数据的msgid,表示是什么数据。对应oem1这个sensor, 如果是数据类型是sns_oem1_msgid,则还会包含sns_oem1_data类型数据。

2.sensor

虚拟sensor的在sns_oem1.c中的sns_oem1_register方法。这个方法将被调用,用来将sensor和sensor_instance对应的api注册到framework。

sns_rc sns_oem1_register(sns_register_cb const *register_api)
{
  register_api->init_sensor(sizeof(sns_oem1_sensor_state),
                            &sns_oem1_api,
                            &sns_oem1_sensor_instance_api);
  return SNS_RC_SUCCESS;
}

sns_oem1_register被放到framework的一个数组中,用来逐个注册sensor。register_api方法有framework提供,代码如下:

extern sns_sensor_cb sensor_cb;
  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,
  };

这个结构的具体意义已经在结构注释中说明。

另外这里有sensor_api和sensor_inst_api。虚拟sensor中sensor用户虚招要使用的其他sensor, 发布sensor attr表示这个sensor存在,以及创建和管理sensor instance。sensor instance是实际存在和发布数据的实体。

我们在看sns_sensor_instance_api和sns_sensor_api这两个结构。我们首先看sensor_api.

typedef struct sns_sensor_api
{
  uint32_t struct_len;
  sns_rc (*init)(
    sns_sensor *const this);//初始化
   sns_rc (*deinit)(
    sns_sensor *const this);//反初始化释放资源
    sns_sensor_uid const* (*get_sensor_uid)(
    sns_sensor const *const this); //获取sensor uid
    sns_rc (*notify_event)(
    sns_sensor *const this); //通知sensor有数据
    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); //接收client的request
}

sensor_api的init在开机时被framework调用。

sns_rc
sns_oem1_init(sns_sensor *const this)
{
  sns_oem1_sensor_state *state = (sns_oem1_sensor_state*)this->state->state;
  // cb获取sensor manager
  struct sns_service_manager *smgr = this->cb->get_service_manager(this);
  float data[3];

  state->diag_service = (sns_diag_service*)
        smgr->get_service(smgr, SNS_DIAG_SERVICE);

  // set default output value corresponding to OEM1_FACING_DOWN to 50. will 
  // rewrite if registry sensor is available
  state->config.down_value = 50.0;
  state->first_pass = true;

  // determine encoded output event size
  state->config.encoded_data_event_len =
      pb_get_encoded_size_sensor_stream_event(data, 3);

 // 通过sensor的datatype查找sensor对应的suid.在frmework中会将每个sensor的datatype和suid绑定,这些sensor是本虚拟sensor数据来源
  SNS_SUID_LOOKUP_INIT(state->suid_lookup_data, NULL);
  sns_suid_lookup_add(this, &state->suid_lookup_data, "gyro");//accel
  sns_suid_lookup_add(this, &state->suid_lookup_data, "registry");
#ifndef OEM1_SUPPORT_DIRECT_SENSOR_REQUEST
  sns_suid_lookup_add(this, &state->suid_lookup_data, "resampler");
#endif

  //发布snesor信息,包括sensor的datatype, sample rate等
  publish_attributes(this);
  SNS_PRINTF(MED, this, "OEM1 init success and attributes published");
  return SNS_RC_SUCCESS;
}

在sns_suid_lookup_add查找suid完成,会通过sensor framework调用sensor_api->notify_event。sns_suid_lookup_add()方法将创建和suid_sensor的流并做请求,请求后的回复通过framework调用notify_event。如果找到则宣布sensor就绪。

sns_rc
sns_oem1_notify_event(sns_sensor *const this)//接收sns_suid_lookup_add返回
{
	sns_oem1_sensor_state *state = (sns_oem1_sensor_state*)this->state->state;
  SNS_PRINTF(LOW, this, "sns_oem1_notify_event");
  sns_suid_lookup_handle(this, &state->suid_lookup_data);
  
  if(sns_suid_lookup_complete(&state->suid_lookup_data)) {
  	publish_available(this);
    sns_suid_lookup_deinit(this, &state->suid_lookup_data);
  }
  return SNS_RC_SUCCESS;
}

publish_available发布改sensor可用。到这里sensor就准备好了。

sensor发布出去后,AP测就可以查询到并且使用。当AP测应用程序激活sensor,sensor_api->set_client_request将被调用,而且AP测发送过来的数据,也是通过pb打包的。

sns_sensor_instance*
sns_oem1_set_client_request(sns_sensor *const this,
    sns_request const *curr_req,
    sns_request const *new_req,
    bool remove)
{
  sns_sensor_instance *curr_inst =
      sns_sensor_util_find_instance(
          this,
          curr_req,
          this->sensor_api->get_sensor_uid(this));
  sns_sensor_instance *rv_inst = NULL;
  sns_sensor_instance *match_inst = NULL;
 // 接收到到config message
	else if((new_req->message_id == SNS_STD_SENSOR_MSGID_SNS_STD_SENSOR_CONFIG) ||  (new_req->message_id == SNS_STD_SENSOR_MSGID_SNS_STD_ON_CHANGE_CONFIG))
	{
	pb_simple_cb_arg arg =
    { .decoded_struct = &config, .fields = sns_std_sensor_config_fields };
    request.payload = (struct pb_callback_s)
          { .funcs.decode = &pb_decode_simple_cb, .arg = &arg };
    //获取到请求的流
    stream = pb_istream_from_buffer(new_req->request, new_req->request_len);
   //从流中解析出请求数据,标准sensor请求数据只有sample_rate
    if(pb_decode(&stream, sns_std_request_fields, &request))
    {
      decoded_req.message_id = new_req->message_id;
      decoded_req.request_len = sizeof(config);
      decoded_req.request = &config;
      match_inst = sns_sensor_util_find_instance_match(
          this, &decoded_req, &find_instance_match);
    }
    
    //然后创建sensor instance,将请求的设置在instance中设置
    rv_inst = this->cb->create_instance(this,
              (sizeof(sns_oem1_inst_state)));
              
          if(NULL != rv_inst)
      {
        rv_inst->cb->add_client_request(rv_inst, new_req);
#ifndef OEM1_SUPPORT_EVENT_TYPE
        this->instance_api->set_client_config(rv_inst, &decoded_req);
#else
        this->instance_api->set_client_config(rv_inst, new_req);
#endif
      }
	}
	
}

上面代码接收来自client的config请求,并根据请求创建或者复用一个sensor instance,设置需要的配置。到这里就进入到sensor instance。

3.sensor instance

sensor管理者sensor instance,sensor instance实际管理者sensor数据。create_instance由framework完成,具体实现为:

  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,
  };
  
  sns_rc
sns_sensor_init(uint32_t state_len, struct sns_sensor_api const *sensor_api,
    struct sns_sensor_instance_api const *instance_api) {
  	sensor->sensor.cb = &sensor_cb;
  }

现在看sensor instance的注册入口:

sns_sensor_instance_api sns_oem1_sensor_instance_api =
{
    .struct_len = sizeof(sns_sensor_instance_api),
    .init = &sns_oem1_inst_init,
    .deinit = &sns_oem1_inst_deinit,
    .set_client_config = &sns_oem1_inst_set_client_config,
    .notify_event = &sns_oem1_inst_notify_event
};

sns_sensor_instance_init()创建instance将会调用到sns_sensor_instance_api->init,完成instance的init过程。

在init中我们查找在sensor中寻找的sensor uid,并且对需要的非resampler sensor创建流。resampler sensor的流放到请求resampler之前。

sns_rc
sns_oem1_inst_init(sns_sensor_instance *this,
    sns_sensor_state const *state)
    {
    	sns_service_manager *service_mgr = this->cb->get_service_manager(this);
    	sns_stream_service *stream_service = (sns_stream_service*)
        service_mgr->get_service(service_mgr, SNS_STREAM_SERVICE);
        
        sns_suid_lookup_get(&sensor_state->suid_lookup_data, "gyro", &inst_state->accel_suid);
        
    	stream_service->api->create_sensor_instance_stream(
      stream_service,
      this,
      inst_state->accel_suid,
      &inst_state->accel_stream);
    }

最后

以上就是明亮雨为你收集整理的1.高通SEE 虚拟sensor分析的全部内容,希望文章能够帮你解决1.高通SEE 虚拟sensor分析所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(47)

评论列表共有 0 条评论

立即
投稿
返回
顶部