二:Sensor Hal层代码分析
Hal code放在/vendor/qcom/proprietary/sensors-see/中
图5
sensors-hal文件夹中包含framework和sensors文件夹,为本文重点分析对象。
首先分析sensors文件夹:
根据C++继承的特性,相同的操作各个class共同拥有,不同的操作每个class可以重写,该文件夹内文件为每个sensor不同的地方,porting sensor主要是在这部分做的。sensors文件夹中包含很多sensor cpp文件比如:accelerometer.cpp为accel sensor的hal层code,step_count.cpp为计步器的hal层的code等等,主要是针对不同sensor type的操作。下面以accelerometer.cpp为例:
//accelerometer.cppSENSOR_MODULE_INIT(accelerometer_module_init);//sensor.h#define SENSOR_MODULE_INIT(module_init_func) \staticconstbool__mod_init = (module_init_func)();
每个cpp都有SENSOR_MODULE_INIT入口,__mod_init具体实现在code没有找到,不过应该类似kernel中module_init,在系统加载.so时调用。故可知,所有特定sensor的cpp在加载.so时会被调SENSOR_MODULE_INIT进行加载。
//accelerometer.cppstaticboolaccelerometer_module_init(){/* register supported sensor types with factory */sensor_factory::register_sensor(SENSOR_TYPE_ACCELEROMETER, get_available_accel_calibrated); sensor_factory::register_sensor(SENSOR_TYPE_ACCELEROMETER_UNCALIBRATED, get_available_accel_uncalibrated); sensor_factory::request_datatype(SSC_DATATYPE_ACCEL);returntrue;}//sensor_factory.hstaticvoidregister_sensor(inttype, get_available_sensors_func func){try{ callbacks().emplace(type, func); }catch(conststd::exception& e) { sns_loge("failed to register type %d", type); } }staticstd::unordered_map& callbacks() {staticstd::unordered_map _callbacks;return_callbacks; }//sensor_factory.hstaticvoidrequest_datatype(constchar*datatype){try{ datatypes().insert(std::string(datatype)); }catch(conststd::exception& e) { sns_loge("failed to insert %s", datatype); } }
所以在,在.so被调用后,accelerometer_module_init会被执行!通过register_sensor将type和func放入callbacks的unordered_map中。并将datatype插入到datatypes的unordered_set中,以便后面使用。
下面以get_available_accel_calibrated为例继续研究:
//accelerometer.cppstaticvector> get_available_accel_calibrated(){constvector& accel_suids = sensor_factory::instance().get_suids(SSC_DATATYPE_ACCEL);// No.1vector> sensors;for(constauto& suid : accel_suids) {if(!(sensor_factory::instance().get_settings()// No.2& DISABLE_WAKEUP_SENSORS_FLAG)) {try{ sensors.push_back(make_unique(suid, SENSOR_WAKEUP,//No.3SENSOR_CALIBRATED)); }catch(constexception& e) { sns_loge("failed for wakeup, %s", e.what()); } }try{ sensors.push_back(make_unique(suid, SENSOR_NO_WAKEUP, SENSOR_CALIBRATED)); }catch(constexception& e) { sns_loge("failed for nowakeup, %s", e.what()); } }returnsensors;}
No.1中:accel_suids可以通过sensor_factory实例中get_suids函数来获取:
conststd::vector& sensor_factory::get_suids(conststd::string& datatype)const{autoit = _suid_map.find(datatype);if(it != _suid_map.end()) {returnit->second; }else{staticvector empty;returnempty; }}
从_suids_map中查找datatype来获取accel的suid。那什么时候将accel的suid插入到_suids_map中内,在framework文件夹中,后续会介绍。
No.2中:通过getsetting来查看是否有DISABLE_WAKEUP_SENSORS_FLAG flag,若有则为no wakeup,若无则为wake up sensor。
No.3中:为调用accelerometer的构造函数。
accelerometer::accelerometer(sensor_uid suid, sensor_wakeup_type wakeup, sensor_cal_type cal_type): ssc_sensor(suid, wakeup)// No.a{if(cal_type == SENSOR_UNCALIBRATED) {// No.bset_type(SENSOR_TYPE_ACCELEROMETER_UNCALIBRATED); set_string_type(SENSOR_STRING_TYPE_ACCELEROMETER_UNCALIBRATED); set_sensor_typename("Accelerometer-Uncalibrated"); }else{ set_type(SENSOR_TYPE_ACCELEROMETER); set_string_type(SENSOR_STRING_TYPE_ACCELEROMETER); set_sensor_typename("Accelerometer"); } ... _cal_type = cal_type; set_fifo_reserved_count(ACCEL_RESERVED_FIFO_COUNT); set_resampling(true);/* convert range from Gs to m/s^2 */set_max_range(get_sensor_info().maxRange * ONE_G);/* convert resolution from mG to m/s^2 */set_resolution(get_sensor_info().resolution * ONE_G /1000.0);}
No.a中:继承ssc_sensor,ssc_sensor的构造函数中,主要设置一些common的参数。
No.b中:设置accel中不common的参数。比如string_type、sensor_typename、是否使用resampling、最大range、分辨率等等。
Ok,accelerometer.cpp基本介绍完毕。
对了,还有个handle_sns_std_sensor_event函数是干什么的呢?
//accelerometer.cppvirtualvoidhandle_sns_std_sensor_event(constsns_client_event_msg_sns_client_event& pb_event)override;voidaccelerometer::handle_sns_std_sensor_event(constsns_client_event_msg_sns_client_event& pb_event){ sns_std_sensor_event pb_sensor_event; pb_sensor_event.ParseFromString(pb_event.payload());sensors_event_thal_event = create_sensor_hal_event(pb_event.timestamp());if(_cal_type == SENSOR_CALIBRATED) { hal_event.acceleration.x = pb_sensor_event.data(0); hal_event.acceleration.y = pb_sensor_event.data(1); hal_event.acceleration.z = pb_sensor_event.data(2); hal_event.acceleration.status = sensors_hal_sample_status(pb_sensor_event.status()); ... }if(_cal_type == SENSOR_UNCALIBRATED) { hal_event.uncalibrated_accelerometer.x_uncalib = pb_sensor_event.data(0); hal_event.uncalibrated_accelerometer.y_uncalib = pb_sensor_event.data(1); hal_event.uncalibrated_accelerometer.z_uncalib = pb_sensor_event.data(2); hal_event.uncalibrated_accelerometer.x_bias =0; hal_event.uncalibrated_accelerometer.y_bias =0; hal_event.uncalibrated_accelerometer.z_bias =0; .... } submit_sensors_hal_event(hal_event);}//framework/ssc_sensor.cppvoidssc_sensor::handle_sns_std_sensor_event(constsns_client_event_msg_sns_client_event& pb_event){ sns_std_sensor_event pb_stream_event; pb_stream_event.ParseFromString(pb_event.payload());sensors_event_thal_event = create_sensor_hal_event(pb_event.timestamp());intnum_items = pb_stream_event.data_size(); ...for(inti =0; i < num_items; i++) { hal_event.data[i] = pb_stream_event.data(i); } ... submit_sensors_hal_event(hal_event);}
可以看到handle_sns_std_sensor_event为虚函数,在framework中有实现,在accelerometer.cpp中也有实现。Ok,若sensors文件中xxxx.cpp中没有重写handle_sns_std_sensor_event则可以使用framework common的进行实现,若有的话,则使用xxxx.cpp中的handle_sns_std_sensor_event。
接着介绍framework文件夹:
//sensors_hw_module.cppstructsensors_module_tHAL_MODULE_INFO_SYM= {.common = { .tag = HARDWARE_MODULE_TAG, .module_api_version = (uint16_t)SENSORS_DEVICE_API_VERSION_1_4, .hal_api_version = HARDWARE_HAL_API_VERSION, .id = SENSORS_HARDWARE_MODULE_ID, .name ="QTI Sensors HAL Module", .author ="Qualcomm Technologies, Inc.", .methods = &sensors_module_methods, .dso =NULL, .reserved = {0}, }, .get_sensors_list = get_sensors_list, .set_operation_mode = sensors_set_operation_mode,};
对Android Hal层比较熟的都知道sensors_module_t这个数据结构,hardware通过dlopen打开.so lib,并通过dlsym加载symbols,然后即可使用相应的方法,具体细节不再重复介绍。
从hardware/libhardware/modules/sensors/multihal.cpp中可以看到,首先会调用get_sensor_list函数。
staticvoidlazy_init_sensors_list(){ ...conststructsensor_t*subhal_sensors_list;for(std::vector::iterator it = sub_hw_modules->begin(); it != sub_hw_modules->end(); it++) {structsensors_module_t*module= (structsensors_module_t*) *it;global_sensors_count +=module->get_sensors_list(module, &subhal_sensors_list); ALOGV("increased global_sensors_count to %d", global_sensors_count); } ...}
对应sensor_hw_module.cpp中函数如下:
//sensors_hw_module.cppstaticintget_sensors_list(structsensors_module_t*module, structsensor_tconst**list){ sensors_hal& hal = sensors_hal::get_instance();returnhal.get_sensors_list(list);}
获取sensors_hal的实例,然后调用get_sensors_list
//sensors_hal.hstaticsensors_hal&get_instance(){staticsensors_hal hal;returnhal; }
sensor_hal为static的,故执行构造函数。
//sensors_hal.cppsensors_hal::sensors_hal(){ ...try{ init_sensors(); ... } ...}voidsensors_hal::init_sensors(){autosensors = sensor_factory::instance().get_all_available_sensors();//No.1autocb = [this](constauto& event,autowakeup) { _event_queue.push(event, wakeup); };//No.2for(unique_ptr& s : sensors) {//No.3assert(s !=nullptr); s->register_callback(cb);constsensor_t& sensor_info = s->get_sensor_info(); ... _hal_sensors.push_back(sensor_info); _sensors[sensor_info.handle] =std::move(s); } ...}
No.1中:通过sensor_factory实例中get_available_sensors()来获取sensor class。
sensor_factory实例:
staticsensor_factory&instance(){staticsensor_factory factory;returnfactory; }
调构造函数
sensor_factory::sensor_factory(){ ... _settings = get_sns_settings();// No.1_pending_attributes =0;// No.2if(!(_settings & DISABLE_SENSORS_FLAG)) {/* find available sensors on ssc */discover_sensors();// No.3if(_suid_map.size() >0) { retrieve_attributes();// No.4} ... }}
No.1中:通过"/persist/sensors/registry/registry/sensors_settings"文件来设置setting。
No.2中:_pending_attributes为pending sensor的数目。
No.3中:discover_sensors用来发现所有的sensor。
//sensor_factory.cppvoidsensor_factory::discover_sensors(){usingnamespacestd::chrono;suid_lookuplookup(//No.a[this](conststring& datatype,constauto& suids){ suid_lookup_callback(datatype, suids); });for(conststring& dt : datatypes()) { sns_logd("requesting %s", dt.c_str()); lookup.request_suid(dt);//No.b}autotp_wait_start = steady_clock::now();/* wait for some time for discovery of available sensors */autodelay = get_discovery_timeout_ms(); this_thread::sleep_for(std::chrono::milliseconds(delay));/* additional wait for discovery of critical sensors */wait_for_mandatory_sensors(lookup); sns_logd("available sensors on ssc");for(constauto& item : _suid_map) { sns_logd("%-20s%4u", item.first.c_str(), (unsignedint)item.second.size()); }}
No.a中:suid_lookup继承_ssc_conn(get_ssc_event_cb()),其中get_ssc_event_cb为回调函数。event在该函数中处理。
suid_lookup_callback(datatype, suids);函数比较重要,把suid加入到_suid_map中,回头看sensors文件夹中的 sensor_factory::get_suids函数,即从_suid_map中查找datatype为accel的suid。前后联系在一起了。那么suids和datatype哪儿来的呢?透露一下,发送request后等待callback函数接收到event并获取到datatype和suids。然后会执行该函数。
No.b中:通过loopup类中的request_suid发送request给SLPI中的sensor。dt为accel、gryo、mag等等。
下面分析下request_suid函数:
//ssc_utils.cppvoidsuid_lookup::request_suid(std::stringdatatype){ sns_client_request_msg pb_req_msg;//No.asns_suid_req pb_suid_req;stringpb_suid_req_encoded;constsensor_uid LOOKUP_SUID = {//No.b12370169555311111083ull,12370169555311111083ull }; .../* populate SUID request *///No.cpb_suid_req.set_data_type(datatype); pb_suid_req.set_register_updates(true); pb_suid_req.SerializeToString(&pb_suid_req_encoded);/* populate the client request message */pb_req_msg.set_msg_id(SNS_SUID_MSGID_SNS_SUID_REQ);//No.dpb_req_msg.mutable_request()->set_payload(pb_suid_req_encoded); pb_req_msg.mutable_suid()->set_suid_high(LOOKUP_SUID.high); pb_req_msg.mutable_suid()->set_suid_low(LOOKUP_SUID.low); pb_req_msg.mutable_susp_config()->set_delivery_type(SNS_CLIENT_DELIVERY_WAKEUP); pb_req_msg.mutable_susp_config()->set_client_proc_type(SNS_STD_CLIENT_PROCESSOR_APSS);stringpb_req_msg_encoded; pb_req_msg.SerializeToString(&pb_req_msg_encoded); _ssc_conn.send_request(pb_req_msg_encoded);//No.e}//sns_client.pb.htypedefstruct_sns_client_request_msg{sns_std_suid suid;uint32_tmsg_id; sns_client_request_msg_suspend_config susp_config; sns_std_request request;/* @@protoc_insertion_point(struct:sns_client_request_msg) */} sns_client_request_msg;
No.a中:sns_client_request_msg 为最外层的requset封装。sns_suid_req 包在sns_client_request_msg->requset->payload中,pb_suid_req_encoded 为encode后的字符串。
No.b中:suid sensor的suid。这里需要说明一下,在sdm845 see中,包含物理sensor、虚拟sensor和platform sensor。前面两个sensor我们都了解,platform sensor是什么呢?原来 高通在see上定义专门为platform服务的sensor,这些sensor是内嵌的,可以被任何sensor或者sensor instance使用,来提供相应的功能。这里suid sensor为platform sensor,它的作用是为所有其他sensor提供suid。suid sensor会根据不同的datatype提供相应的suid。当然suid sensor也有个suid。这个suid也是固定不变的,就是No.b中的数字。
拓展:除了suid sensor外还有很多platform sensor,比如:register sensor , 可以解析并获取其他sensor的register;Interrupt sensor,为其他sensor提供中断;等等。
No.c中:填充pb_suid_req,设置datatype,register_updates;并将pb_suid_req序列化成字符串格式,成为pb_suid_req_encoded,以便ps_req_msg使用。
No.d中:填充pb_req_msg,设置msg_id,这里msg_id比较重要,到SLPI侧sensor driver中,会根据该msg_id做相应的操作,这是后话。
设置成员request中的payload为pb_suid_req_encoded。设置成员suid中的suid_high、suid_low为LOOKUP_SUID的高、低位。
设置成员susp_config中内容。。。
最后将pb_req_msg序列化字符串pb_req_msg_encoded。
No.e中:通过_ssc_conn.request将该字符串发送出去。
发送的流程我们在此不再研究,都是高通封装好的API,我们直接使用即可,有兴趣的童鞋可以继续追code。
发送完request后,我们需要静等callback。根据前面描述可知,callback为suid_lookup::handle_ssc_event()函数,在该函数中,
No.a中sns_client_event_msg为对应event的封装,通过PaseFromArray解码data & size生成。
//ssc_utils.cppvoidsuid_lookup::handle_ssc_event(constuint8_t*data,size_tsize){/* parse the pb encoded event */sns_client_event_msg pb_event_msg;//No.a pb_event_msg.ParseFromArray(data, size);/* iterate over all events in the message */for(inti =0; i < pb_event_msg.events_size(); i++) {//No.bauto& pb_event = pb_event_msg.events(i);if(pb_event.msg_id() != SNS_SUID_MSGID_SNS_SUID_EVENT) { sns_loge("invalid event msg_id=%d", pb_event.msg_id());continue; } sns_suid_event pb_suid_event;//No.cpb_suid_event.ParseFromString(pb_event.payload());conststring& datatype = pb_suid_event.data_type(); .../* create a list of all suids found for this datatype */vector suids(pb_suid_event.suid_size());//No.dfor(intj=0; j < pb_suid_event.suid_size(); j++) { suids[j] = sensor_uid(pb_suid_event.suid(j).suid_low(), pb_suid_event.suid(j).suid_high()); }/* send callback for this datatype */_cb(datatype, suids); }}//sns_suid.pb.htypedefenum_sns_suid_msgid { SNS_SUID_MSGID_SNS_SUID_REQ =512, SNS_SUID_MSGID_SNS_SUID_EVENT =768} sns_suid_msgid;
No.b中:要判断msg_id是否是SNS_SUID_MSGID_SNS_SUID_EVENT,可以看到与SNS_SUID_MSGID_SNS_SUID_REQ对应。
No.c中:同No.a一样,将pb_event.payload() 解码成sns_suid_event。
No.d中:创建一个suid的vector,将获得suid string放进去。然后调用_cb将suids保存起来,即调用suid_lookup_callback函数将datatype和suids放入到_suid_map的unordered_map中。
Ok,discover_sensors基本介绍完毕,sensor_factory构造函数中还会在retrieve_attributes()发送request来获取attribute。并放在_attributes的unordered_map中。操作基本相同,只是request发送的msg_id不同而已,在此不再详细介绍。
接着,继续回到init_sensors()的No.1中。
vector> sensor_factory::get_all_available_sensors()const{vector> all_sensors;for(constauto& item : callbacks()) {// No.aconstauto& get_sensors = item.second;// No.bvector> sensors = get_sensors(); sns_logd("type=%d, num_sensors=%u", item.first, (unsignedint)sensors.size());for(auto&& s : sensors) { all_sensors.push_back(std::move(s));// No.c} }returnall_sensors;}
No.a中,又看到了callbacks,上面sensors文件夹中可知,通过register_sensor将type和func放入到叫callbacks的unordered_map中。
No.b中,get_sensors获取callbacks中第二个元素get_available_sensors_func。然后通过get_sensors()函数即get_available_sensors_func()来获取sensor class。对应sensors文件中accelerometer.cpp中get_available_accel_calibrated()和get_available_accel_uncalibrated()。
No.c中,将获取到的vector
回到init_sensors函数:
No.2中:将event和wakeup push到_event_queue中,即变成sensors_event_t _event_queue。
No.3中:register_callback 后,通过get_sensor_info()获取sensor_info。然后,把sensor_info push到_hal_sensors的vector中,将sensor class放到unordered_map _sensors的sensor_info.handle成员中。
init_sensors解析完毕。注:数据结构放在sensors.h中(/hardware/libhardware/include/hardware/sensors.h)
然后继续分析get_sensors_list:
//sensors_hal.cppintsensors_hal::get_sensors_list(constsensor_t**s_list){intnum_sensors = (int)_hal_sensors.size(); sns_logi("num_sensors=%d", num_sensors); *s_list = &_hal_sensors[0];returnnum_sensors;}
通过判断_hal_sensors的大小获取到所有sensor的数目。并将_hal_sensors的首地址赋给s_list。
至此,系统获取了全部sensor的suid和attributes,并将其放在指定的容器中保存起来,完成sensor的初始化工作。下面就等user来使用了。
Enable/Disable Sensor
framewark层getDefaultSensor并registerListener后,经过一系列函数后,最终会调到sensors_hal中activate函数来enable/disable。
//sensors_hal.cppintsensors_hal::activate(inthandle,intenable){ ....if(enable) { sensor->activate(); }else{ sensor->deactivate(); } ....return0;}
再以accelerometer.cpp为例:
因为accelerometer class继承ssc_sensor class,故会调用ssc_sensor中的activate。
//ssc_sensor.cppvoidssc_sensor::activate(){std::lock_guard lk(_mutex);//No.1if(!is_active()) {/* establish a new connection to ssc */_ssc_conn = make_unique( [this](constuint8_t*data,size_tsize) { ssc_conn_event_cb(data, size);//No.2});if( _wakeup_type == SENSOR_WAKEUP) _ssc_conn->set_unsuspendable_channel();//No.3_ssc_conn->register_error_cb([this](autoe){ ssc_conn_error_cb(e); }); send_sensor_config_request();//No.4}}voidssc_sensor::deactivate(){std::lock_guard lk(_mutex);if(is_active()) { _ssc_conn.reset();//No.5}}
No.1中:申请互斥锁lk。
No.2中:接收event的callback函数。
No.3中:针对wakeup sensor处理的函数。
No.4中发送config request,enabe accle sensor。
等发送到enable request后,等待接收event。然后通过submit_sensors_hal_event(hal_event)将数据上报。
No.5中:deactivate为disable sensor,首先判断sensor状态是否是active,若是则reset,若不是,不做任何处理。
Factory Calibration
加速度传感器在进工厂时需要进行calibration。下面提供accelerometer calibration的code。顺便加深下上面学习的知识。
voidaccel_cal::init_ssc_connectiions(){ ssc_suid_cb = [this](constuint8_t* msg ,intmsgLength) {this->handle_ssc_suid_event(msg, msgLength);};if(NULL== (ssc_suid_obj =newssc_connection(ssc_suid_cb))) { ALOGE("ssc connection for suid failed");return; } ssc_accel_cal_cb = [this](constuint8_t* msg ,intmsgLength) {this->handle_ssc_accel_cal_event(msg, msgLength);};if(NULL== (ssc_accel_cal_obj =newssc_connection(ssc_accel_cal_cb))) { ALOGE("ssc connection failed");return; } ssc_accel_enable_cb = [this](constuint8_t* msg ,intmsgLength) {this->handle_ssc_enable_accel_event(msg, msgLength);};if(NULL== (ssc_accel_enable_obj =newssc_connection(ssc_accel_enable_cb))) { ALOGE("ssc connection failed");return; } ALOGI("ssc connections successful");}
上面函数是在new的时候调用,建立 3个callback函数,分别用来接收suid的event、accel calibration的event、accel enable的event。
intaccel_cal::cal_init(){intresult =true;std::stringdatatype_accel = ACCEL; pthread_mutex_lock(&cb_mutex); request_suid(datatype_accel); pthread_cond_wait(&condition, &cb_mutex); enable_accel(); usleep(10000); request_accel_cal(); timeout =0;while((accel_sensor_indication !=1) && timeout <2000){ usleep(1000); timeout++; } result = accel_sensor_indication;returnresult;}
上面request_suid发送request来获取accel的suid。
上面enable_accel发送request来enabe accel
上面request_accel_cal发送request来让SLPI侧的sensor进行calibration。
超时处理,当2s内没有接收到callback,退出。
void accel_cal::request_suid(std::string datatype){ sns_client_request_msg pb_req_msg; sns_suid_req pb_suid_req; string pb_suid_req_encoded;constsensor_uid LOOKUP_SUID = {12370169555311111083ull,12370169555311111083ull };/* populate SUID request */pb_suid_req.set_data_type(datatype); pb_suid_req.set_register_updates(false); pb_suid_req.SerializeToString(&pb_suid_req_encoded);/* populate the client request message */pb_req_msg.set_msg_id(SNS_SUID_MSGID_SNS_SUID_REQ); pb_req_msg.mutable_request()->set_payload(pb_suid_req_encoded); pb_req_msg.mutable_suid()->set_suid_high(LOOKUP_SUID.high); pb_req_msg.mutable_suid()->set_suid_low(LOOKUP_SUID.low); pb_req_msg.mutable_susp_config()->set_delivery_type( SNS_CLIENT_DELIVERY_NO_WAKEUP); pb_req_msg.mutable_susp_config()->set_client_proc_type( SNS_STD_CLIENT_PROCESSOR_APSS); string pb_req_msg_encoded; pb_req_msg.SerializeToString(&pb_req_msg_encoded);//DEBUG_LOG(log_instance," sending request to QMI connection for accel suid ");ssc_suid_obj->send_request(pb_req_msg_encoded);}void accel_cal::enable_accel(){ float sample_rate =80; sns_client_request_msg pb_req_msg; sns_std_sensor_config pb_stream_cfg; string pb_stream_cfg_encoded; pb_stream_cfg.set_sample_rate(sample_rate); pb_stream_cfg.SerializeToString(&pb_stream_cfg_encoded); pb_req_msg.set_msg_id(SNS_STD_SENSOR_MSGID_SNS_STD_SENSOR_CONFIG); pb_req_msg.mutable_request()->set_payload(pb_stream_cfg_encoded); pb_req_msg.mutable_suid()->set_suid_high(accel_suid.high); pb_req_msg.mutable_suid()->set_suid_low(accel_suid.low); pb_req_msg.mutable_susp_config()->set_delivery_type( SNS_CLIENT_DELIVERY_WAKEUP); pb_req_msg.mutable_susp_config()->set_client_proc_type( SNS_STD_CLIENT_PROCESSOR_APSS); string pb_req_msg_encoded; pb_req_msg.SerializeToString(&pb_req_msg_encoded); pb_req_msg.SerializeToString(&pb_req_msg_encoded); ssc_accel_cal_obj->send_request(pb_req_msg_encoded); }void accel_cal::request_accel_cal(){ string pb_req_msg_encoded; string config_encoded; sns_client_request_msg pb_req_msg; sns_physical_sensor_test_config config; config.set_test_type((sns_physical_sensor_test_type)accel_test_type); config.SerializeToString(&config_encoded); pb_req_msg.set_msg_id(SNS_PHYSICAL_SENSOR_TEST_MSGID_SNS_PHYSICAL_SENSOR_TEST_CONFIG); pb_req_msg.mutable_request()->set_payload(config_encoded); pb_req_msg.mutable_suid()->set_suid_high(accel_suid.high); pb_req_msg.mutable_suid()->set_suid_low(accel_suid.low); pb_req_msg.mutable_susp_config()->set_delivery_type(SNS_CLIENT_DELIVERY_WAKEUP); pb_req_msg.mutable_susp_config()-> set_client_proc_type(SNS_STD_CLIENT_PROCESSOR_APSS); pb_req_msg.SerializeToString(&pb_req_msg_encoded); ssc_accel_cal_obj->send_request(pb_req_msg_encoded); }
上面为三个request请求函数处理。
request_suid的msg_id为SNS_SUID_MSGID_SNS_SUID_REQ;
enable_accel的msg_id为SNS_STD_SENSOR_MSGID_SNS_STD_SENSOR_CONFIG;
request_accel_cal的msg_id为SNS_PHYSICAL_SENSOR_TEST_MSGID_SNS_PHYSICAL_SENSOR_TEST_CONFIG,test_type为SELF_TEST_TYPE_FACTORY。
voidaccel_cal::handle_ssc_enable_accel_event(constuint8_t*data,size_tsize){ ALOGI("event callback start:\n"); }voidaccel_cal::handle_ssc_accel_cal_event(constuint8_t*data,size_tsize){ ALOGI("event callback start:\n"); sns_client_event_msg pb_event_msg; FILE *file =NULL; sns_physical_sensor_test_event test_event; pb_event_msg.ParseFromArray(data, size);for(inti=0; i < pb_event_msg.events_size(); i++) {auto&& pb_event = pb_event_msg.events(i); ALOGI("event[%d] msg_id=%d", i, pb_event.msg_id());if(pb_event.msg_id() == SNS_PHYSICAL_SENSOR_TEST_MSGID_SNS_PHYSICAL_SENSOR_TEST_EVENT) test_event.ParseFromString(pb_event.payload());intresult = test_event.test_passed();if(result==1&& test_event.test_data().size() >3){ file = fopen(GsensorCalibration_factory_file,"w+");if(NULL== file) { ALOGI("accel fopen error \n"); accel_sensor_indication =3; }else{fprintf(file,"%s\n",test_event.test_data().c_str()); accel_sensor_indication =1; } fclose(file); }else{ accel_sensor_indication =2; } }}voidaccel_cal::handle_ssc_suid_event(constuint8_t*data,size_tsize){ ALOGI(" event received for accel suid");/* parse the pb encoded event */sns_client_event_msg pb_event_msg; pb_event_msg.ParseFromArray(data, size);for(inti =0; i < pb_event_msg.events_size(); i++) { ALOGI("suid event iteration %d", i);auto& pb_event = pb_event_msg.events(i);if(pb_event.msg_id() != SNS_SUID_MSGID_SNS_SUID_EVENT) {return; } sns_suid_event pb_suid_event; pb_suid_event.ParseFromString(pb_event.payload());conststring& datatype = pb_suid_event.data_type();for(intj =0; j < pb_suid_event.suid_size(); j++) { ALOGI("suid number %d", j);if(datatype == ACCEL) { accel_suid.low = pb_suid_event.suid(j).suid_low(); accel_suid.high = pb_suid_event.suid(j).suid_high();stringstreamsuidLow; suidLow <
上面为callback函数:
handle_ssc_suid_event 中msg_id为SNS_SUID_MSGID_SNS_SUID_EVENT,并将suid保存到sensor_uid accel_suid数据结构中。
handle_ssc_enable_accel_event中没有做任务处理,因为我们不需要gsensor数据,只需要enable它。
handle_ssc_accel_cal_event中为gsensor calibration,msg_id为:SNS_PHYSICAL_SENSOR_TEST_MSGID_SNS_PHYSICAL_SENSOR_TEST_EVENT,该command下下去后,会在SLPI侧accel driver中进行factory calibration,然后把calibration的数据通过event传回client。
然后将calibration的数据保存在/factory/GsensorCalibration.ini中,以便调用。
除了上面的方式外,还可以在enable accel后,获取accel 数据自行进行calibration。
比如下面一段code:
voidaccel_cal::request_accel_cal(){floatsample_rate =20; sns_client_request_msg pb_req_msg; sns_std_sensor_config pb_stream_cfg;stringpb_stream_cfg_encoded; pb_stream_cfg.set_sample_rate(sample_rate); pb_stream_cfg.SerializeToString(&pb_stream_cfg_encoded); pb_req_msg.set_msg_id(SNS_STD_SENSOR_MSGID_SNS_STD_SENSOR_CONFIG); pb_req_msg.mutable_request()->set_payload(pb_stream_cfg_encoded); pb_req_msg.mutable_suid()->set_suid_high(accel_suid.high); pb_req_msg.mutable_suid()->set_suid_low(accel_suid.low); pb_req_msg.mutable_susp_config()->set_delivery_type( SNS_CLIENT_DELIVERY_WAKEUP); pb_req_msg.mutable_susp_config()->set_client_proc_type( SNS_STD_CLIENT_PROCESSOR_APSS);stringpb_req_msg_encoded; pb_req_msg.SerializeToString(&pb_req_msg_encoded);//setting number of samples recieved to 0, and allocate the input arrayaccel_sample_number =0; samples_for_bias_calculation =newfloat*[SAMPLE_COUNT_REQUIRED_FORALGO];//SAMPLE_COUNT_REQUIRED_FORALGO = 64if(samples_for_bias_calculation ==NULL){ sns_loge("Memory allocation failed for samples_for_bias_calculation");return; }for(inti =0; i < SAMPLE_COUNT_REQUIRED_FORALGO; i++) { samples_for_bias_calculation[i] =newfloat[3]; } ssc_accel_cal_obj->send_request(pb_req_msg_encoded);}
采样64组accel data。
voidaccel_cal::calculate_bias(bias_output* output){ sns_logd("calculating bias for 64 samples"); output->motionState =0;floatsampleSum[NUM_AXIS] = {0};floatsampleSqSum[NUM_AXIS] = {0};floatvariance[NUM_AXIS] = {0};for(intj =0; j < SAMPLE_COUNT_REQUIRED_FORALGO; j++) {for(inti =0; i < NUM_AXIS; i++) { sampleSum[i] += samples_for_bias_calculation[j][i]; sampleSqSum[i] += ((float) (samples_for_bias_calculation[j][i]) * (float) (samples_for_bias_calculation[j][i])); } }floatvarT;for(inti =0; i < NUM_AXIS; i++) { varT = (float) (sampleSum[i]) * (float) (sampleSum[i]); variance[i] = (sampleSqSum[i] - (varT / (float) SAMPLE_COUNT_REQUIRED_FORALGO)) / (float) SAMPLE_COUNT_REQUIRED_FORALGO;if(variance[i] > variance_threshold) { output->motionState =0;return; }elseif(0== variance[i]) { output->motionState =0;return; }elseif( FX_ABS(sampleSum[i] / SAMPLE_COUNT_REQUIRED_FORALGO) > bias_thresholds[i]) { output->motionState =0;return; } } output->motionState =1; output->x = sampleSum[0] / SAMPLE_COUNT_REQUIRED_FORALGO; output->y = sampleSum[1] / SAMPLE_COUNT_REQUIRED_FORALGO; output->z = sampleSum[2] / SAMPLE_COUNT_REQUIRED_FORALGO; sns_logd("bias successfully calculated for 64 samples");}voidaccel_cal::handle_ssc_accel_cal_event(constuint8_t*data,size_tsize){ sns_logd("event received for accel config"); sns_client_event_msg pb_event_msg; pb_event_msg.ParseFromArray(data, size);inteventSize = pb_event_msg.events_size();for(inti =0; i < eventSize; i++) {auto&& pb_event = pb_event_msg.events(i);if(pb_event.msg_id() == SNS_STD_SENSOR_MSGID_SNS_STD_SENSOR_EVENT) { sns_std_sensor_event pb_sensor_event; pb_sensor_event.ParseFromString(pb_event.payload());floatx = pb_sensor_event.data(0);floaty = pb_sensor_event.data(1);floatz = pb_sensor_event.data(2); sns_logd("accel data received from event ::: x=%f, y=%f, z=%f", x,y, z); sample_cal.x = x; sample_cal.y = y; sample_cal.z = z; sample_calculated_offset.x =0; sample_calculated_offset.y =0; sample_calculated_offset.z =0; ... samples_for_bias_calculation[accel_sample_number][0] = x; samples_for_bias_calculation[accel_sample_number][1] = y; samples_for_bias_calculation[accel_sample_number][2] = z;if(accel_sample_number == SAMPLE_COUNT_REQUIRED_FORALGO -1) { bias_output output; calculate_bias(&output);//对64组accel data进行calibration。if(output.motionState ==0) { sns_logd("Motion detected."); }else{ sns_logd("Device at rest"); sns_logd("calculated cal values: %f, %f, %f", output.x,output.y, output.z); curr_cal.x = output.x; curr_cal.y = output.y; curr_cal.z = output.z; } } accel_sample_number = (accel_sample_number +1) %64; } }}
上面通过event获取accel sample ,当收集64笔时进行calibration。并将calibration的数据输出。
通过上面的操作也可以完成gsensor的calibration。不过算法要自己设计。
Ok,accel的calibration的操作已经完成。
作者:汉克233
链接:https://www.jianshu.com/p/9a77a3655f1f
来源:
著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。