Commit d5e7f10c authored by Michael Ott's avatar Michael Ott

Fix drift for Lenovo XCC sensors

parent 38f55963
......@@ -88,6 +88,7 @@ uint64_t IPMISensorGroup::readRaw(const std::vector<uint8_t> &rawCmd, uint8_t ls
void IPMISensorGroup::read() {
reading_t reading;
reading.value = 0;
reading.timestamp = getTimestamp();
//TODO with SensorGroup refactor we lost the ability to sleep until
......@@ -108,7 +109,7 @@ void IPMISensorGroup::read() {
for (int i=0; i<readings.size(); i++) {
s->storeReading(readings[i], s->getFactor());
}
reading = readings[2999];
reading = readings.back();
}
break;
}
......@@ -124,7 +125,7 @@ void IPMISensorGroup::read() {
for (unsigned int i=0; i<readings.size(); i++) {
s->storeReading(readings[i], s->getFactor());
}
reading = readings[99];
reading = readings.back();
}
break;
}
......@@ -134,7 +135,7 @@ void IPMISensorGroup::read() {
for (unsigned int i=0; i<readings.size(); i++) {
s->storeReading(readings[i], s->getFactor());
}
reading = readings[99];
reading = readings.back();
}
break;
}
......@@ -158,7 +159,7 @@ void IPMISensorGroup::read() {
break;
}
#ifdef DEBUG
LOG(debug) << _groupName << "::" << s->getName() << " reading: ts=" << reading.timestamp << " val=" << reading.value;
LOG(debug) << s->getName() << " reading: ts=" << prettyPrintTimestamp(reading.timestamp) << " val=" << reading.value;
#endif
} catch (const std::exception &e) {
LOG(error) << _groupName << "::" << s->getName() << " could not read value: " << e.what();
......
......@@ -11,42 +11,35 @@
#include <cstring>
#include <iostream>
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;
_drift = 0;
_generalDrift = 0;
_datastoreDrift = 0;
}
LenovoXCC::~LenovoXCC() {}
int LenovoXCC::getDatastorePower(std::vector<reading_t> &readings) {
if (openDatastore() == 0) {
uint64_t ts1, ts2;
uint8_t buf[256];
ts2 = 0;
if (_drift || getDrift() == 0) {
if (_datastoreDrift || getDatastoreDrift() == 0) {
if (openDatastore() == 0) {
uint64_t ts1, ts2;
uint8_t buf[256];
int i = 0;
if ((ts1 = readDatastoreTimestamp()) > 0) {
ts2 = 0;
readings.resize(3000);
while (ts1 != ts2) {
int i = 0;
i = 0;
for (int 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];
for (int j=0; j<n; j++) {
reading_t r;
r.timestamp = ts1 + _drift + MS_TO_NS(i * 10);
r.value = buf16[j];
readings.push_back(r);
readings[i].timestamp = ts1 + _datastoreDrift + MS_TO_NS(i * 10);
readings[i].value = buf16[j];
i++;
}
}
......@@ -55,21 +48,18 @@ int LenovoXCC::getDatastorePower(std::vector<reading_t> &readings) {
ts2 = readDatastoreTimestamp();
}
}
closeDatastore();
return i != 3000;
}
closeDatastore();
}
if (readings.size() == 3000) {
return 0;
} else {
return 1;
}
return 1;
}
int LenovoXCC::getSingleEnergy(reading_t &reading) {
if (_drift || getDrift() == 0) {
if (_generalDrift || getGeneralDrift() == 0) {
uint64_t ts, energy;
if (readSingleEnergyRaw(ts, energy) == 0) {
reading.timestamp = ts + _drift;
reading.timestamp = ts + _generalDrift;
reading.value = energy;
return 0;
}
......@@ -78,10 +68,11 @@ int LenovoXCC::getSingleEnergy(reading_t &reading) {
}
int LenovoXCC::getBulkPower(std::vector<reading_t> &readings) {
if (_drift || getDrift() == 0) {
if (_generalDrift || getGeneralDrift() == 0) {
uint8_t buf[256];
uint8_t getBulkCmd[] = {0x00, 0x3a, 0x32, 0x04, 0x00, 0x00, 0x00, 0x00};
int len = -1;
try {
len = _host->sendRawCmd(getBulkCmd, sizeof(getBulkCmd), buf, sizeof(buf));
} catch (const std::exception &e) {
......@@ -90,14 +81,14 @@ int LenovoXCC::getBulkPower(std::vector<reading_t> &readings) {
}
if ((len == 208) && (buf[0] == 0x32) && (buf[1] == 0x00)) {
uint64_t timeStamp = extractTimestamp(&buf[2]) + _drift;
reading_t r = {0,0};
readings.resize(100, r);
// The timestamp is the timestamp of the first reading, the last reading is 100*10ms later
uint64_t timeStamp = extractTimestamp(&buf[2]) + _generalDrift - MS_TO_NS(1000);
readings.resize(100);
uint16_t *buf16 = (uint16_t *)&buf[8];
for (int i=0; i<100; i++) {
readings[i].timestamp = timeStamp + MS_TO_NS(i * 10);
readings[i].value = buf16[i];
readings[i].value = buf16[(99-i)]; // The order of readings is descending
}
return 0;
}
......@@ -107,7 +98,7 @@ int LenovoXCC::getBulkPower(std::vector<reading_t> &readings) {
}
int LenovoXCC::getBulkEnergy(std::vector<reading_t> &readings) {
if (_drift || getDrift() == 0) {
if (_generalDrift || getGeneralDrift() == 0) {
uint8_t buf[256];
uint8_t getBulkCmd[] = {0x00, 0x3a, 0x32, 0x04, 0x01, 0x00, 0x00, 0x00};
int len = -1;
......@@ -119,20 +110,20 @@ int LenovoXCC::getBulkEnergy(std::vector<reading_t> &readings) {
}
if ((len == 212) && (buf[0] == 0x32) && (buf[1] == 0x00)) {
uint64_t timeStamp = extractTimestamp(&buf[2]) + _drift;
// The timestamp is the timestamp of the first reading, the last reading is 101*10ms later
uint64_t timeStamp = extractTimestamp(&buf[2]) + _generalDrift - MS_TO_NS(1010);
uint32_t baseEnergy;
memcpy(&baseEnergy, &buf[8], sizeof(baseEnergy));
reading_t r = {0,0};
readings.resize(101, r); // This is really 101!
readings.resize(101); // This is really 101!
readings[0].timestamp = timeStamp;
readings[0].value = baseEnergy;
uint16_t *buf16 = (uint16_t *)&buf[12];
for (int i=1; i<101; i++) {
readings[i].timestamp = timeStamp + MS_TO_NS(i * 10);
readings[i].value = baseEnergy + buf16[i-1];
readings[i].value = baseEnergy + buf16[i-1] ;
}
return 0;
}
......@@ -182,19 +173,6 @@ int LenovoXCC::readSingleEnergyRaw(uint64_t &timeStamp, uint64_t &energy) {
return -1;
}
int LenovoXCC::getDrift() {
uint64_t xccTs, dummy;
uint64_t sysTs1 = getTimestamp();
if (readSingleEnergyRaw(xccTs, dummy) == 0) {
uint64_t sysTs2 = getTimestamp();
_drift = sysTs1 + (sysTs2 - sysTs1) / 2 - xccTs;
return 0;
}
return 1;
}
int LenovoXCC::openDatastore() {
if (_handle) {
closeDatastore();
......@@ -210,7 +188,6 @@ int LenovoXCC::openDatastore() {
return 255;
}
//printbuf("open", buf, len);
if ((len == 9) && (buf[0] == 0x90) && (buf[1] == 0x00)) {
memcpy(&_handle, &buf[5], sizeof(_handle));
return 0;
......@@ -236,7 +213,6 @@ int LenovoXCC::closeDatastore() {
return 255;
}
//printbuf("close", buf, len);
if ((len == 5) && (buf[0] == 0x90) && (buf[1] == 0x00)) {
_handle = 0;
return 0;
......@@ -259,7 +235,6 @@ int LenovoXCC::readDatastoreRange(uint32_t offset, uint16_t count, uint8_t *buf,
}
if ((len >= 2) && (buf[0] == 0x90) && (buf[1] == 0x00)) {
//printbuf("readDataStoreRange", buf, len);
return len;
} else {
return -1;
......@@ -284,3 +259,46 @@ uint64_t LenovoXCC::readDatastoreTimestamp() {
return 0;
}
}
int LenovoXCC::getDatastoreDrift() {
if ((_handle != 0) || (openDatastore() == 0)) {
uint64_t dsTs1, dsTs2, sysTs1, sysTs2;
dsTs1 = dsTs2 = readDatastoreTimestamp();
// Loop until the timestamp changes so we can be sure it's not outdated
do {
usleep(5000);
sysTs1 = getTimestamp();
dsTs2 = readDatastoreTimestamp();
sysTs2 = getTimestamp();
} while (dsTs1 == dsTs2);
// The timestamp is the timestamp of the first reading, the last reading is 30s later
_datastoreDrift = sysTs1 - (sysTs2 - sysTs1) / 2 - dsTs2 - S_TO_NS(30);
closeDatastore();
#ifdef DEBUG
LOGGER lg;
LOG(debug) << " Datastore drift: " << prettyPrintTimestamp(_datastoreDrift) << " (" << (sysTs2 - sysTs1) << ")" << std::endl;
#endif
return 0;
}
return 1;
}
int LenovoXCC::getGeneralDrift() {
uint64_t xccTs, dummy;
// Do a dummy read to make sure we have the IPMI connection open in order to minimize latency
readSingleEnergyRaw(xccTs, dummy);
uint64_t sysTs1 = getTimestamp();
if (readSingleEnergyRaw(xccTs, dummy) == 0) {
uint64_t sysTs2 = getTimestamp();
_generalDrift = sysTs1 - (sysTs2 - sysTs1) / 2 - xccTs;
#ifdef DEBUG
LOGGER lg;
LOG(debug) << "General drift: " << prettyPrintTimestamp(_generalDrift) << " (" << (sysTs2 - sysTs1) << ")" << std::endl;
#endif
return 0;
}
return 1;
}
......@@ -24,17 +24,23 @@ class LenovoXCC {
int getBulkPower(std::vector<reading_t> &readings);
int getBulkEnergy(std::vector<reading_t> &readings);
int getGeneralDrift();
int getDatastoreDrift();
private:
uint64_t extractTimestamp(const uint8_t *buf);
int readSingleEnergyRaw(uint64_t &timeStamp, uint64_t &energy);
int getDrift();
// int getGeneralDrift();
int openDatastore();
int closeDatastore();
uint64_t readDatastoreTimestamp();
int readDatastoreRange(uint32_t offset, uint16_t count, uint8_t *buf, uint16_t bufLen);
// int getDatastoreDrift();
IPMIHost *_host;
uint32_t _handle;
int64_t _drift;
int64_t _generalDrift;
int64_t _datastoreDrift;
};
#endif /* LenovoXCC_hpp */
Markdown is supported
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