//OpenSCADA module DAQ.System file: da_sensors.cpp /*************************************************************************** * Copyright (C) 2005-2024 by Roman Savochenko, * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; version 2 of the License. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include #include #include #include #include #include #if HAVE_SENSORS_SENSORS_H #include #endif #include "os_contr.h" #include "da_sensors.h" using namespace SystemCntr; const char *Sensors::mbmon_cmd = "mbmon -r -c 1"; //write one try to stdout //************************************************* //* Sensors * //************************************************* Sensors::Sensors( ) : libsensor_ok(false) { #if HAVE_SENSORS_SENSORS_H //Libsensor API init #if SENSORS_API_VERSION >= 0x400 if(sensors_init(NULL) == 0) libsensor_ok = true; #else FILE *f = fopen("/etc/sensors.conf", "r"); if(f) { if(sensors_init(f) == 0) libsensor_ok = true; if(fclose(f) != 0) mess_warning(nodePath().c_str(), _("Closing the file %p error '%s (%d)'!"), f, strerror(errno), errno); } #endif #endif } Sensors::~Sensors( ) { #if HAVE_SENSORS_SENSORS_H //Libsensor API cleanup if(libsensor_ok) sensors_cleanup(); #endif } void Sensors::getVal( TMdPrm *prm ) { bool devOK = false; string s_id, s_val; //Using directly the Linux sensors // reading /sys/devices/virtual/thermal/*/temp DIR *IdDir = NULL; dirent *scan_dirent = (dirent*)malloc(offsetof(dirent,d_name) + NAME_MAX + 1); if((IdDir=opendir(DIR_VDEV "thermal"))) { for(dirent *sRez = NULL; readdir_r(IdDir,scan_dirent,&sRez) == 0 && sRez; ) if((s_val=devRead(string("thermal")+"/"+sRez->d_name+"/temp")) != EVAL_STR) { if(!prm->vlPresent((s_id=string(sRez->d_name)+"_temp"))) fldAdd(new TFld(s_id.c_str(),string(sRez->d_name)+" temp",TFld::Real,TFld::NoWrite)); prm->vlAt(s_id).at().setR(1e-3*s2r(s_val), 0, true); devOK = true; } closedir(IdDir); } // reading /sys/devices/virtual/hwmon/*/temp* if((IdDir=opendir(DIR_VDEV "hwmon"))) { dirent *scan_dirent2 = (dirent*)malloc(offsetof(dirent,d_name) + NAME_MAX + 1); for(dirent *sRez = NULL; readdir_r(IdDir,scan_dirent,&sRez) == 0 && sRez; ) { if(!devChkAccess(string("hwmon")+"/"+sRez->d_name+"/temp1_input")) continue; DIR *IdDir2 = opendir((string(DIR_VDEV "hwmon")+"/"+sRez->d_name).c_str()); if(IdDir2) { for(dirent *sRez2 = NULL; readdir_r(IdDir2,scan_dirent2,&sRez2) == 0 && sRez2; ) { if(string(sRez2->d_name).find("temp") == 0 && (s_val=devRead(string("hwmon")+"/"+sRez->d_name+"/"+sRez2->d_name)) != EVAL_STR) { if(!prm->vlPresent((s_id=string(sRez->d_name)+"_"+sRez2->d_name))) fldAdd(new TFld(s_id.c_str(),string(sRez->d_name)+" "+sRez2->d_name,TFld::Real,TFld::NoWrite)); prm->vlAt(s_id).at().setR(1e-3*s2r(s_val), 0, true); devOK = true; } } closedir(IdDir2); } } closedir(IdDir); free(scan_dirent2); } free(scan_dirent); //Using libsensor if(libsensor_ok) { #if HAVE_SENSORS_SENSORS_H int nr = 0; double val; const sensors_chip_name *name; #if SENSORS_API_VERSION >= 0x400 while((name=sensors_get_detected_chips(NULL,&nr))) { const sensors_subfeature *feature = NULL; const sensors_feature *main_feature; int nr1 = 0; while((main_feature=sensors_get_features(name, &nr1))) { switch(main_feature->type) { case SENSORS_FEATURE_IN: feature = sensors_get_subfeature(name, main_feature, SENSORS_SUBFEATURE_IN_INPUT); break; case SENSORS_FEATURE_FAN: feature = sensors_get_subfeature(name, main_feature, SENSORS_SUBFEATURE_FAN_INPUT); break; case SENSORS_FEATURE_TEMP: feature = sensors_get_subfeature(name, main_feature, SENSORS_SUBFEATURE_TEMP_INPUT); break; default: break; } if(!feature) continue; s_id = string(name->prefix)+"_"+main_feature->name; if(!prm->vlPresent(s_id)) fldAdd(new TFld(s_id.c_str(),(string(name->prefix)+" "+main_feature->name).c_str(),TFld::Real,TFld::NoWrite)); if(sensors_get_value(name,feature->number,&val) == 0) prm->vlAt(s_id).at().setR(val, 0, true); devOK = true; } } #else while((name=sensors_get_detected_chips(&nr))) { int nr1 = 0, nr2 = 0; const sensors_feature_data *feature; while((feature=sensors_get_all_features(*name,&nr1,&nr2))) if(sensors_get_ignored(*name,feature->number) == 1 && feature->mapping == SENSORS_NO_MAPPING) { s_id = string(name->prefix) + "_" + feature->name; if(!prm->vlPresent(s_id)) fldAdd(new TFld(s_id.c_str(),(string(name->prefix)+" "+feature->name).c_str(), TFld::Real,TFld::NoWrite)); sensors_get_feature(*name, feature->number, &val); prm->vlAt(s_id).at().setR(val, 0, true); devOK = true; } } #endif #endif } //Using mbmon else { char buf[100], name[31]; float val; FILE *fp = popen(mbmon_cmd, "r"); if(fp == NULL) return; while(fgets(buf,sizeof(buf),fp)) { if(sscanf(buf,"%31s : %f",name,&val) != 2) continue; if(!prm->vlPresent(name)) fldAdd(new TFld(name,name,TFld::Real,TFld::NoWrite)); prm->vlAt(name).at().setR(val, 0, true); devOK = true; } if(pclose(fp) == -1) mess_warning(prm->nodePath().c_str(), _("Closing the pipe %p error '%s (%d)'!"), fp, strerror(errno), errno); } if(devOK) prm->daErr = ""; else if(!prm->daErr.getVal().size()) { prm->setEval(); prm->daErr = _("10:Device is not available."); } } void Sensors::makeActiveDA( TMdContr *aCntr, const string &dIdPref, const string &dNmPref ) { //Early checking for the corresponded parameter presence vector pLs; aCntr->list(pLs); unsigned iP; for(iP = 0; iP < pLs.size(); iP++) if(aCntr->at(pLs[iP]).at().cfg("TYPE").getS() == id()) break; if(iP < pLs.size()) return; //Checking for the sensors presence bool sens_allow = false; // ... directly the Linux sensors // Testing /sys/devices/virtual/thermal/*/temp DIR *IdDir = NULL; dirent *scan_dirent = (dirent*)malloc(offsetof(dirent,d_name) + NAME_MAX + 1); if((IdDir=opendir(DIR_VDEV "thermal"))) { for(dirent *sRez = NULL; !sens_allow && readdir_r(IdDir,scan_dirent,&sRez) == 0 && sRez; ) sens_allow = (devChkAccess(string("thermal")+"/"+sRez->d_name+"/temp")); closedir(IdDir); } // Testing /sys/devices/virtual/hwmon/*/temp* if(!sens_allow && (IdDir=opendir(DIR_VDEV "hwmon"))) { for(dirent *sRez = NULL; !sens_allow && readdir_r(IdDir,scan_dirent,&sRez) == 0 && sRez; ) sens_allow = (devChkAccess(string("hwmon")+"/"+sRez->d_name+"/temp1_input")); closedir(IdDir); } free(scan_dirent); // ... libsensor if(libsensor_ok) { #if HAVE_SENSORS_SENSORS_H int nr = 0; const sensors_chip_name *name; #if SENSORS_API_VERSION >= 0x400 while((name=sensors_get_detected_chips(NULL,&nr))) { const sensors_subfeature *feature = NULL; const sensors_feature *main_feature; int nr1 = 0; while((main_feature=sensors_get_features(name,&nr1))) { switch(main_feature->type) { case SENSORS_FEATURE_IN: feature = sensors_get_subfeature(name,main_feature,SENSORS_SUBFEATURE_IN_INPUT); break; case SENSORS_FEATURE_FAN: feature = sensors_get_subfeature(name, main_feature, SENSORS_SUBFEATURE_FAN_INPUT); break; case SENSORS_FEATURE_TEMP: feature = sensors_get_subfeature(name, main_feature, SENSORS_SUBFEATURE_TEMP_INPUT); break; default: break; } if(feature) { sens_allow |= true; break; } } } #else while(name = sensors_get_detected_chips(&nr)) { const sensors_feature_data *feature; int nr1 = 0, nr2 = 0; while(feature = sensors_get_all_features(*name,&nr1,&nr2)) if(sensors_get_ignored(*name,feature->number) == 1 && feature->mapping == SENSORS_NO_MAPPING) { sens_allow |= true; break; } } #endif #endif } // ... monitor else { char buf[100], name[31]; float val; FILE *fp = popen(mbmon_cmd, "r"); if(fp != NULL) { while(fgets(buf,sizeof(buf),fp)) if(sscanf(buf,"%31s : %f",name,&val) == 2) { sens_allow = true; break; } if(pclose(fp) == -1) mess_warning(aCntr->nodePath().c_str(), _("Closing the pipe %p error '%s (%d)'!"), fp, strerror(errno), errno); } } //Sensor parameter creating if(sens_allow) DA::makeActiveDA(aCntr, "Sensors", _("Sensors")); } bool Sensors::devChkAccess( const string &file, const string &acs ) { FILE *f = fopen(TSYS::strMess(DIR_VDEV "%s",file.c_str()).c_str(), acs.c_str()); bool rez = f; if(f && fclose(f) != 0) mess_warning(mod->nodePath().c_str(), _("Closing the file %p error '%s (%d)'!"), f, strerror(errno), errno); return rez; } string Sensors::devRead( const string &file ) { char buf[256]; string rez = EVAL_STR; FILE *f = fopen(TSYS::strMess(DIR_VDEV "%s",file.c_str()).c_str(), "r"); if(f) { rez = ""; while(fgets(buf,sizeof(buf),f) != NULL) rez.append(buf); if(rez.size() && rez[rez.size()-1] == '\n') rez.erase(rez.size()-1, 1); if(fclose(f) != 0) mess_warning(mod->nodePath().c_str(), _("Closing the file %p error '%s (%d)'!"), f, strerror(errno), errno); } return rez; }