Commit 53a60288 authored by Michael Ott's avatar Michael Ott
Browse files

Add support for Lenovo XCC power readings

parent 5d792aaa
......@@ -84,7 +84,7 @@ libdcdbplugin_sysfs.$(LIBEXT): sensors/sysfs/SysfsSensorGroup.o sensors/sysfs/Sy
libdcdbplugin_perfevent.$(LIBEXT): sensors/perfevent/PerfSensorGroup.o sensors/perfevent/PerfeventConfigurator.o
$(CXX) $(LIBFLAGS)$@ -o $@ $^ -L$(DCDBDEPLOYPATH)/lib/ -lboost_log -lboost_system
libdcdbplugin_ipmi.$(LIBEXT): sensors/ipmi/IPMISensorGroup.o sensors/ipmi/IPMIHost.o sensors/ipmi/IPMIConfigurator.o
libdcdbplugin_ipmi.$(LIBEXT): sensors/ipmi/IPMISensorGroup.o sensors/ipmi/IPMIHost.o sensors/ipmi/IPMIConfigurator.o sensors/ipmi/LenovoXCC.o
$(CXX) $(LIBFLAGS)$@ -o $@ $^ -L$(DCDBDEPLOYPATH)/lib/ -lboost_log -lboost_system -lboost_regex -lfreeipmi
libdcdbplugin_pdu.$(LIBEXT): sensors/pdu/PDUSensorGroup.o sensors/pdu/PDUUnit.o sensors/pdu/PDUConfigurator.o
......
......@@ -87,7 +87,8 @@ public:
enum sensorType {
undefined = 0,
raw,
sdr
sdr,
xcc
};
uint16_t getRecordId() const { return _recordId; }
......@@ -104,10 +105,12 @@ public:
}
uint8_t getLsb() const { return _lsb; }
uint8_t getMsb() const { return _msb; }
std::string getType() const {
sensorType getType() const { return _type; }
std::string getTypeString() const {
switch(_type) {
case raw: return std::string("raw");
case sdr: return std::string("sdr");
case xcc: return std::string("xcc");
default: return std::string("undefined");
}
}
......@@ -136,6 +139,8 @@ public:
_type = raw;
} else if (boost::iequals(type, "sdr")) {
_type = sdr;
} else if (boost::iequals(type, "xcc")) {
_type = xcc;
} else {
_type = undefined;
}
......@@ -143,7 +148,7 @@ public:
void printConfig(LOG_LEVEL ll, LOGGER& lg, unsigned leadingSpaces=16) {
std::string leading(leadingSpaces, ' ');
LOG_VAR(ll) << leading << " Type: " << getType();
LOG_VAR(ll) << leading << " Type: " << getTypeString();
switch(_type) {
case raw:
LOG_VAR(ll) << leading << " Raw Cmd: " << getRawCmdString();
......@@ -153,11 +158,14 @@ public:
case sdr:
LOG_VAR(ll) << leading << " Record Id: " << _recordId;
break;
default:
break;
}
LOG_VAR(ll) << leading << " Factor: " << _factor;
}
protected:
sensorType _type;
uint16_t _recordId;
std::vector<uint8_t> _sdrRecord;
double _factor;
......@@ -165,7 +173,6 @@ protected:
std::vector<uint8_t> _rawCmd;
uint8_t _lsb;
uint8_t _msb;
sensorType _type;
};
#endif /* SRC_SENSORS_IPMI_IPMISENSORBASE_H_ */
......@@ -27,6 +27,7 @@
#include "IPMISensorGroup.h"
#include "IPMIHost.h"
#include "LenovoXCC.h"
#include <iostream>
#include <exception>
......@@ -100,20 +101,46 @@ void IPMISensorGroup::read() {
for(const auto& s : _sensors) {
try {
if (s->getRecordId() != 0) { /* recordId was set */
std::vector<uint8_t> sdrRecord = s->getSdrRecord();
if (sdrRecord.size() == 0) {
_entity->getSdrRecord(s->getRecordId(), sdrRecord);
s->setSdrRecord(sdrRecord);
}
reading.value = _entity->readSensorRecord(sdrRecord);
} else { /* use raw command */
reading.value = readRaw(s->getRawCmd(), s->getLsb(), s->getMsb());
}
if (s->getType() == IPMISensorBase::sensorType::xcc) {
LenovoXCC xcc(_entity);
if (xcc.openDatastore() == 0) {
uint64_t ts1, ts2;
std::vector<uint16_t> readings;
if ((ts1 = xcc.readDatastoreTimestamp()) > 0) {
if (xcc.readDatastorePower(readings) == 0) {
// Check whether the timestamp changed during readDatastorePower() and re-read if it did
ts2 = xcc.readDatastoreTimestamp();
if (ts2 > ts1) {
xcc.readDatastorePower(readings);
ts1 = ts2;
}
}
xcc.closeDatastore();
}
ts1+= xcc.getDrift();
for (unsigned int i=0; i<readings.size(); i++) {
reading.timestamp = ts1 + MS_TO_NS(i*10);
reading.value = readings[i];
s->storeReading(reading, s->getFactor());
// LOG(debug) << _groupName << "::" << s->getName() << " xcc: " << i << " " << reading.timestamp << " " << reading.value;
}
}
} else {
if (s->getType() == IPMISensorBase::sensorType::sdr) {
std::vector<uint8_t> sdrRecord = s->getSdrRecord();
if (sdrRecord.size() == 0) {
_entity->getSdrRecord(s->getRecordId(), sdrRecord);
s->setSdrRecord(sdrRecord);
}
reading.value = _entity->readSensorRecord(sdrRecord);
} else {
reading.value = readRaw(s->getRawCmd(), s->getLsb(), s->getMsb());
}
#ifdef DEBUG
LOG(debug) << _groupName << "::" << s->getName() << " raw reading: \"" << reading.value << "\"";
LOG(debug) << _groupName << "::" << s->getName() << " raw reading: \"" << reading.value << "\"";
#endif
s->storeReading(reading, s->getFactor());
s->storeReading(reading, s->getFactor());
}
} catch (const std::exception& e) {
LOG(error) << _groupName << "::" << s->getName() << " could not read value: " << e.what();
continue;
......
//
// LenovoXCC.cpp
// dcdb
//
// Created by Ott, Michael on 21.08.19.
// Copyright © 2019 LRZ. All rights reserved.
//
#include "LenovoXCC.h"
#include "timestamp.h"
#include <iostream>
#include <cstring>
void printbuf(std::string header, uint8_t* buf, int len) {
std::cout << header << " [" << len << "]" << std::hex;
for (int i=0; i<len; i++) {
std::cout << " " << (int) buf[i];
}
std::cout << std::endl;
}
LenovoXCC::LenovoXCC(IPMIHost* host) {
_host = host;
_handle = 0;
}
LenovoXCC::~LenovoXCC() {}
int LenovoXCC::getSingleEnergy(uint64_t& timeStamp, uint64_t& energy) {
uint8_t buf[256];
uint8_t getSingleEnergyCmd[] = { 0x00, 0x3a, 0x32, 0x04, 0x02, 0x00, 0x00, 0x00};
int len = -1;
try {
len = _host->sendRawCmd(getSingleEnergyCmd, sizeof(getSingleEnergyCmd), buf, sizeof(buf));
} catch (const std::exception& e) {
throw e;
return 1;
}
if ((len == 16) && (buf[0] == 0x32) && (buf[1] == 0x00)) {
uint32_t ts1;
uint16_t ts2;
memcpy(&ts1, &buf[10], sizeof(ts1));
memcpy(&ts2, &buf[14], sizeof(ts2));
timeStamp = S_TO_NS(ts1);
if (ts2 < 1000) {
timeStamp+= MS_TO_NS(ts2);
}
uint32_t joules;
uint16_t mJoules;
memcpy(&joules, &buf[4], sizeof(joules));
memcpy(&mJoules, &buf[8], sizeof(mJoules));
energy = ((uint32_t) joules) * 1000;
if (mJoules < 1000) {
energy+= mJoules;
}
return 0;
}
return -1;
}
int64_t LenovoXCC::getDrift() {
int64_t drift = 0;
uint64_t xccTs, dummy;
uint64_t sysTs1 = getTimestamp();
if (getSingleEnergy(xccTs, dummy) == 0) {
uint64_t sysTs2 = getTimestamp();
drift = sysTs1 + (sysTs2-sysTs1)/2 - xccTs;
}
return drift;
}
int LenovoXCC::openDatastore() {
if (_handle) {
closeDatastore();
}
uint8_t buf[256];
uint8_t getHandleCmd[] = { 0x00, 0x2e, 0x90, 0x66, 0x4a, 0x00, 0x01, 0x01, 0x01, 0xF0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x70, 0x77, 0x72, 0x5f, 0x6d, 0x65, 0x74, 0x65, 0x72 };
int len = -1;
try {
len = _host->sendRawCmd(getHandleCmd, sizeof(getHandleCmd), buf, sizeof(buf));
} catch (const std::exception& e) {
throw e;
return 255;
}
//printbuf("open", buf, len);
if ((len == 9) && (buf[0] == 0x90) && (buf[1] == 0x00)) {
memcpy(&_handle, &buf[5], sizeof(_handle));
return 0;
} else {
return -1;
}
}
int LenovoXCC::closeDatastore() {
if (!_handle) {
return 2;
}
uint8_t buf[256];
uint8_t closeHandleCmd[] = { 0x00, 0x2e, 0x90, 0x66, 0x4a, 0x00, 0x05, 0xff, 0xff, 0xff, 0xff };
memcpy(&closeHandleCmd[7], &_handle, sizeof(_handle));
int len = -1;
try {
len = _host->sendRawCmd(closeHandleCmd, sizeof(closeHandleCmd), buf, sizeof(buf));
} catch (const std::exception& e) {
throw e;
return 255;
}
//printbuf("close", buf, len);
if ((len == 5) && (buf[0] == 0x90) && (buf[1] == 0x00)) {
_handle = 0;
return 0;
} else {
return -1;
}
}
int LenovoXCC::readDatastoreRange(uint32_t offset, uint16_t count, uint8_t* buf, uint16_t bufLen) {
uint8_t getDataCmd[] = { 0x00, 0x2e, 0x90, 0x66, 0x4a, 0x00, 0x02, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00 };
memcpy(&getDataCmd[7], &_handle, sizeof(_handle));
memcpy(&getDataCmd[11], &offset, sizeof(offset));
memcpy(&getDataCmd[15], &count, sizeof(count));
int len = -1;
try {
len = _host->sendRawCmd(getDataCmd, sizeof(getDataCmd), buf, bufLen);
} catch (const std::exception& e) {
throw e;
return -1;
}
if ((len >= 2) && (buf[0] == 0x90) && (buf[1] == 0x00)) {
//printbuf("readDataStoreRange", buf, len);
return len;
} else {
return -1;
}
}
uint64_t LenovoXCC::readDatastoreTimestamp() {
uint8_t buf[256];
int len=-1;
try {
len = readDatastoreRange(0, 16, buf, sizeof(buf));
} catch (const std::exception& e) {
throw e;
return 0;
}
if (len >= 20) {
uint32_t ts1;
uint16_t ts2;
uint64_t ts;
uint64_t index;
memcpy(&ts1, &buf[7], sizeof(ts1));
memcpy(&ts2, &buf[11], sizeof(ts2));
memcpy(&index, &buf[15], sizeof(index));
ts = (uint64_t) ts1 * 1000 + index * 10;
if (ts2 < 1000) {
ts+= ts2;
}
ts = MS_TO_NS(ts);
return ts;
} else {
return 0;
}
}
int LenovoXCC::readDatastorePower(std::vector<uint16_t>& readings) {
uint8_t buf[256];
try {
for (uint16_t offset=16; offset<6016; offset+=200) {
int len = readDatastoreRange(offset, 200, buf, sizeof(buf));
if (len >= 0) {
uint16_t n = (buf[5] | buf[6] << 8) / 2;
uint16_t* buf16 = (uint16_t *) &buf[7];
readings.insert(readings.end(), buf16, buf16+n);
}
}
} catch (const std::exception& e) {
throw e;
return 1;
}
if (readings.size()) {
return 0;
} else {
return -1;
}
}
//
// LenovoXCC.hpp
// dcdb
//
// Created by Ott, Michael on 21.08.19.
// Copyright © 2019 LRZ. All rights reserved.
//
#ifndef LenovoXCC_hpp
#define LenovoXCC_hpp
#include <cstdint>
#include "IPMIHost.h"
class LenovoXCC {
public:
LenovoXCC(IPMIHost* host);
virtual ~LenovoXCC();
int getSingleEnergy(uint64_t& timeStamp, uint64_t& energy);
int64_t getDrift();
int openDatastore();
int closeDatastore();
uint64_t readDatastoreTimestamp();
int readDatastorePower(std::vector<uint16_t>& readings);
private:
int readDatastoreRange(uint32_t offset, uint16_t count, uint8_t* buf, uint16_t bufLen);
IPMIHost* _host;
uint32_t _handle;
};
#endif /* LenovoXCC_hpp */
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment