//Chris Xiong 2018 //3-Clause BSD License #include #include #include #include #include #include #include #include #include "utils.hpp" #include "sensors.hpp" void SensorBase::parse_type_string(std::string type,scan_t* ti) { char endian[4],sign; if(type.find('X')!=type.npos) sscanf(type.c_str(),"%2s:%c%hhu/%hhuX%hhu>>%hhu", endian,&sign,&ti->bits,&ti->storagebits,&ti->repeat,&ti->shift ); else { ti->repeat=0; sscanf(type.c_str(),"%2s:%c%hhu/%hhu>>%hhu", endian,&sign,&ti->bits,&ti->storagebits,&ti->shift ); } ti->is_le=std::string(endian)=="le"; ti->is_signed=sign=='s'; } void SensorBase::readbuffer() { pollfd p[2]; p[0]=pollfd{devfd,POLLIN,0}; p[1]=pollfd{qpipe[0],POLLIN,0}; if(poll(p,2,-1)<=0)return; char* buf=new char[readsize]; if(p[1].revents&POLLIN) { ignore_result(read(qpipe[0],buf,readsize)); delete[] buf; return; } ssize_t sz=read(devfd,buf,readsize); if(sz==readsize&&!paused) { char *p=buf; for(int i=0;p-buf(enabled_scan_elem[i]); std::string es=std::get(enabled_scan_elem[i])+"_value"; std::vector pp(p,p+ti.storagebits/8); if(ti.is_le^PLATFORM_IS_LITTLEENDIAN) std::reverse(pp.begin(),pp.end()); auto readint=[&](auto t){ memcpy(&t,pp.data(),ti.storagebits/8); t>>=ti.shift;dict[es]=t; }; switch(ti.storagebits) { case 8: if(ti.is_signed)readint(int8_t(0)); else readint(uint8_t(0)); break; case 16: if(ti.is_signed)readint(int16_t(0)); else readint(uint16_t(0)); break; case 32: if(ti.is_signed)readint(int32_t(0)); else readint(uint32_t(0)); break; case 64: if(ti.is_signed)readint(int64_t(0)); else readint(uint64_t(0)); break; } p+=ti.storagebits/8; } } delete[] buf; } void SensorBase::enable_buffer() { using filesystem::path; path buffer_enable_path=sysfspath/"buffer"/"enable"; writeint(buffer_enable_path.c_str(),1); } void SensorBase::enable_scan_element(std::string elem) { using filesystem::path; std::string elem_base=sensor_basename+(elem.length()?"_"+elem:""); path elem_type_path=sysfspath/"scan_elements"/(elem_base+"_type"); std::string ts;dict[elem_base+"_type"]=ts=readstr(elem_type_path.c_str()); scan_t st;parse_type_string(ts,&st); readsize+=st.storagebits/8;//assume this is aligned to byte path elem_en_path=sysfspath/"scan_elements"/(elem_base+"_en"); writeint(elem_en_path.c_str(),1); path elem_idx_path=sysfspath/"scan_elements"/(elem_base+"_index"); int idx;dict[elem_base+"_index"]=idx=readint(elem_idx_path.c_str()); path raw_val_path=sysfspath/(elem_base+"_raw");//initial value dict[elem_base+"_value"]=readint(raw_val_path.c_str()); enabled_scan_elem.insert( std::upper_bound(enabled_scan_elem.begin(),enabled_scan_elem.end(), std::make_tuple(idx,elem_base,st), [](const auto&a,const auto&b){return std::get<0>(a)(b);} ),std::make_tuple(idx,elem_base,st) ); } bool SensorBase::init(int id,std::string _sensor_basename) { sysfspath=IIODEV_SYSFS_PATH_BASE+std::to_string(id); devbufpath=DEV_PATH+std::to_string(id); sensor_basename=_sensor_basename; using filesystem::path; path name_path=sysfspath/"name"; type=readstr(name_path.c_str()); path scale_path=sysfspath/(sensor_basename+"_scale"); dict[sensor_basename+"_scale"]=readfloat(scale_path.c_str()); path offset_path=sysfspath/(sensor_basename+"_offset"); dict[sensor_basename+"_offset"]=readfloat(offset_path.c_str()); reset(); ignore_result(pipe(qpipe)); enabled_scan_elem.clear(); enable_scan_elements(); update_values(); enable_buffer(); devfd=open(devbufpath.c_str(),O_RDONLY); if(!~devfd) return LOG('E',"failed to open the iio buffer device: %s",devbufpath.c_str()),1; return 0; } void SensorBase::deinit() { if(~devfd)close(devfd); devfd=-1; } void SensorBase::reset() { deinit(); using filesystem::path; path buffer_enable_path=sysfspath/"buffer"/"enable"; writeint(buffer_enable_path.c_str(),0); for(auto& ent:filesystem::directory_iterator(sysfspath/"scan_elements")) if(ent.path().string().substr(ent.path().string().length()-3)=="_en") writeint(ent.path().c_str(),0); readsize=0; } void SensorBase::worker() { for(workerquit=0;!workerquit;) { read_m.lock(); readbuffer(); read_m.unlock(); update_values(); if(readercb!=nullptr)readercb(this); } deinit(); } void SensorBase::quit_worker() { workerquit=1; ignore_result(write(qpipe[1],"q",1)); close(qpipe[1]); } void SensorBase::pause_worker() { if(~devfd) { paused=1; while(!read_m.try_lock())//just spin lock, I don't care { ignore_result(write(qpipe[1],"p",1)); std::this_thread::yield(); } reset(); } } void SensorBase::resume_worker() { enabled_scan_elem.clear(); enable_scan_elements(); update_values(); enable_buffer(); devfd=open(devbufpath.c_str(),O_RDONLY); if(!~devfd) return (void)LOG('E',"failed to open the iio buffer device: %s",devbufpath.c_str()); paused=0; read_m.unlock(); } void SensorBase::set_reader_callback(std::function cb) {readercb=cb;} std::string SensorBase::get_type(int id) { using filesystem::path; path sysfspath=path(IIODEV_SYSFS_PATH_BASE+std::to_string(id)); path name_path=sysfspath/"name"; return readstr(name_path.c_str()); } int SensorBase::detect_sensor(std::string type) { using filesystem::path; path sysfsbasepath=path(IIODEV_SYSFS_PATH_BASE).remove_filename(); for(auto& ent:filesystem::directory_iterator(sysfsbasepath)) { path name_path=ent.path()/"name"; if(trim(readstr(name_path.c_str()))==type) { std::string es=ent.path().filename().string(); size_t i; for(i=0;i'9');++i); if(i