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 ...@@ -88,6 +88,7 @@ uint64_t IPMISensorGroup::readRaw(const std::vector<uint8_t> &rawCmd, uint8_t ls
void IPMISensorGroup::read() { void IPMISensorGroup::read() {
reading_t reading; reading_t reading;
reading.value = 0;
reading.timestamp = getTimestamp(); reading.timestamp = getTimestamp();
//TODO with SensorGroup refactor we lost the ability to sleep until //TODO with SensorGroup refactor we lost the ability to sleep until
...@@ -108,7 +109,7 @@ void IPMISensorGroup::read() { ...@@ -108,7 +109,7 @@ void IPMISensorGroup::read() {
for (int i=0; i<readings.size(); i++) { for (int i=0; i<readings.size(); i++) {
s->storeReading(readings[i], s->getFactor()); s->storeReading(readings[i], s->getFactor());
} }
reading = readings[2999]; reading = readings.back();
} }
break; break;
} }
...@@ -124,7 +125,7 @@ void IPMISensorGroup::read() { ...@@ -124,7 +125,7 @@ void IPMISensorGroup::read() {
for (unsigned int i=0; i<readings.size(); i++) { for (unsigned int i=0; i<readings.size(); i++) {
s->storeReading(readings[i], s->getFactor()); s->storeReading(readings[i], s->getFactor());
} }
reading = readings[99]; reading = readings.back();
} }
break; break;
} }
...@@ -134,7 +135,7 @@ void IPMISensorGroup::read() { ...@@ -134,7 +135,7 @@ void IPMISensorGroup::read() {
for (unsigned int i=0; i<readings.size(); i++) { for (unsigned int i=0; i<readings.size(); i++) {
s->storeReading(readings[i], s->getFactor()); s->storeReading(readings[i], s->getFactor());
} }
reading = readings[99]; reading = readings.back();
} }
break; break;
} }
...@@ -158,7 +159,7 @@ void IPMISensorGroup::read() { ...@@ -158,7 +159,7 @@ void IPMISensorGroup::read() {
break; break;
} }
#ifdef DEBUG #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 #endif
} catch (const std::exception &e) { } catch (const std::exception &e) {
LOG(error) << _groupName << "::" << s->getName() << " could not read value: " << e.what(); LOG(error) << _groupName << "::" << s->getName() << " could not read value: " << e.what();
......
...@@ -11,42 +11,35 @@ ...@@ -11,42 +11,35 @@
#include <cstring> #include <cstring>
#include <iostream> #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) { LenovoXCC::LenovoXCC(IPMIHost *host) {
_host = host; _host = host;
_handle = 0; _handle = 0;
_drift = 0; _generalDrift = 0;
_datastoreDrift = 0;
} }
LenovoXCC::~LenovoXCC() {} LenovoXCC::~LenovoXCC() {}
int LenovoXCC::getDatastorePower(std::vector<reading_t> &readings) { int LenovoXCC::getDatastorePower(std::vector<reading_t> &readings) {
if (openDatastore() == 0) { if (_datastoreDrift || getDatastoreDrift() == 0) {
uint64_t ts1, ts2; if (openDatastore() == 0) {
uint8_t buf[256]; uint64_t ts1, ts2;
ts2 = 0; uint8_t buf[256];
int i = 0;
if (_drift || getDrift() == 0) {
if ((ts1 = readDatastoreTimestamp()) > 0) { if ((ts1 = readDatastoreTimestamp()) > 0) {
ts2 = 0;
readings.resize(3000);
while (ts1 != ts2) { while (ts1 != ts2) {
int i = 0; i = 0;
for (int offset=16; offset < 6016; offset += 200) { for (int offset=16; offset < 6016; offset += 200) {
int len = readDatastoreRange(offset, 200, buf, sizeof(buf)); int len = readDatastoreRange(offset, 200, buf, sizeof(buf));
if (len >= 0) { if (len >= 0) {
uint16_t n = (buf[5] | buf[6] << 8) / 2; uint16_t n = (buf[5] | buf[6] << 8) / 2;
uint16_t *buf16 = (uint16_t *)&buf[7]; uint16_t *buf16 = (uint16_t *)&buf[7];
for (int j=0; j<n; j++) { for (int j=0; j<n; j++) {
reading_t r; readings[i].timestamp = ts1 + _datastoreDrift + MS_TO_NS(i * 10);
r.timestamp = ts1 + _drift + MS_TO_NS(i * 10); readings[i].value = buf16[j];
r.value = buf16[j];
readings.push_back(r);
i++; i++;
} }
} }
...@@ -55,21 +48,18 @@ int LenovoXCC::getDatastorePower(std::vector<reading_t> &readings) { ...@@ -55,21 +48,18 @@ int LenovoXCC::getDatastorePower(std::vector<reading_t> &readings) {
ts2 = readDatastoreTimestamp(); ts2 = readDatastoreTimestamp();
} }
} }
closeDatastore();
return i != 3000;
} }
closeDatastore();
}
if (readings.size() == 3000) {
return 0;
} else {
return 1;
} }
return 1;
} }
int LenovoXCC::getSingleEnergy(reading_t &reading) { int LenovoXCC::getSingleEnergy(reading_t &reading) {
if (_drift || getDrift() == 0) { if (_generalDrift || getGeneralDrift() == 0) {
uint64_t ts, energy; uint64_t ts, energy;
if (readSingleEnergyRaw(ts, energy) == 0) { if (readSingleEnergyRaw(ts, energy) == 0) {
reading.timestamp = ts + _drift; reading.timestamp = ts + _generalDrift;
reading.value = energy; reading.value = energy;
return 0; return 0;
} }
...@@ -78,10 +68,11 @@ int LenovoXCC::getSingleEnergy(reading_t &reading) { ...@@ -78,10 +68,11 @@ int LenovoXCC::getSingleEnergy(reading_t &reading) {
} }
int LenovoXCC::getBulkPower(std::vector<reading_t> &readings) { int LenovoXCC::getBulkPower(std::vector<reading_t> &readings) {
if (_drift || getDrift() == 0) { if (_generalDrift || getGeneralDrift() == 0) {
uint8_t buf[256]; uint8_t buf[256];
uint8_t getBulkCmd[] = {0x00, 0x3a, 0x32, 0x04, 0x00, 0x00, 0x00, 0x00}; uint8_t getBulkCmd[] = {0x00, 0x3a, 0x32, 0x04, 0x00, 0x00, 0x00, 0x00};
int len = -1; int len = -1;
try { try {
len = _host->sendRawCmd(getBulkCmd, sizeof(getBulkCmd), buf, sizeof(buf)); len = _host->sendRawCmd(getBulkCmd, sizeof(getBulkCmd), buf, sizeof(buf));
} catch (const std::exception &e) { } catch (const std::exception &e) {
...@@ -90,14 +81,14 @@ int LenovoXCC::getBulkPower(std::vector<reading_t> &readings) { ...@@ -90,14 +81,14 @@ int LenovoXCC::getBulkPower(std::vector<reading_t> &readings) {
} }
if ((len == 208) && (buf[0] == 0x32) && (buf[1] == 0x00)) { if ((len == 208) && (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 100*10ms later
uint64_t timeStamp = extractTimestamp(&buf[2]) + _generalDrift - MS_TO_NS(1000);
reading_t r = {0,0};
readings.resize(100, r); readings.resize(100);
uint16_t *buf16 = (uint16_t *)&buf[8]; uint16_t *buf16 = (uint16_t *)&buf[8];
for (int i=0; i<100; i++) { for (int i=0; i<100; i++) {
readings[i].timestamp = timeStamp + MS_TO_NS(i * 10); 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; return 0;
} }
...@@ -107,7 +98,7 @@ int LenovoXCC::getBulkPower(std::vector<reading_t> &readings) { ...@@ -107,7 +98,7 @@ int LenovoXCC::getBulkPower(std::vector<reading_t> &readings) {
} }
int LenovoXCC::getBulkEnergy(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 buf[256];
uint8_t getBulkCmd[] = {0x00, 0x3a, 0x32, 0x04, 0x01, 0x00, 0x00, 0x00}; uint8_t getBulkCmd[] = {0x00, 0x3a, 0x32, 0x04, 0x01, 0x00, 0x00, 0x00};
int len = -1; int len = -1;
...@@ -119,20 +110,20 @@ int LenovoXCC::getBulkEnergy(std::vector<reading_t> &readings) { ...@@ -119,20 +110,20 @@ int LenovoXCC::getBulkEnergy(std::vector<reading_t> &readings) {
} }
if ((len == 212) && (buf[0] == 0x32) && (buf[1] == 0x00)) { 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; uint32_t baseEnergy;
memcpy(&baseEnergy, &buf[8], sizeof(baseEnergy)); memcpy(&baseEnergy, &buf[8], sizeof(baseEnergy));
reading_t r = {0,0}; readings.resize(101); // This is really 101!
readings.resize(101, r); // This is really 101!
readings[0].timestamp = timeStamp; readings[0].timestamp = timeStamp;
readings[0].value = baseEnergy; readings[0].value = baseEnergy;
uint16_t *buf16 = (uint16_t *)&buf[12]; uint16_t *buf16 = (uint16_t *)&buf[12];
for (int i=1; i<101; i++) { for (int i=1; i<101; i++) {
readings[i].timestamp = timeStamp + MS_TO_NS(i * 10); 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; return 0;
} }
...@@ -182,19 +173,6 @@ int LenovoXCC::readSingleEnergyRaw(uint64_t &timeStamp, uint64_t &energy) { ...@@ -182,19 +173,6 @@ int LenovoXCC::readSingleEnergyRaw(uint64_t &timeStamp, uint64_t &energy) {
return -1; 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() { int LenovoXCC::openDatastore() {
if (_handle) { if (_handle) {
closeDatastore(); closeDatastore();
...@@ -210,7 +188,6 @@ int LenovoXCC::openDatastore() { ...@@ -210,7 +188,6 @@ int LenovoXCC::openDatastore() {
return 255; return 255;
} }
//printbuf("open", buf, len);
if ((len == 9) && (buf[0] == 0x90) && (buf[1] == 0x00)) { if ((len == 9) && (buf[0] == 0x90) && (buf[1] == 0x00)) {
memcpy(&_handle, &buf[5], sizeof(_handle)); memcpy(&_handle, &buf[5], sizeof(_handle));
return 0; return 0;
...@@ -236,7 +213,6 @@ int LenovoXCC::closeDatastore() { ...@@ -236,7 +213,6 @@ int LenovoXCC::closeDatastore() {
return 255; return 255;
} }
//printbuf("close", buf, len);
if ((len == 5) && (buf[0] == 0x90) && (buf[1] == 0x00)) { if ((len == 5) && (buf[0] == 0x90) && (buf[1] == 0x00)) {
_handle = 0; _handle = 0;
return 0; return 0;
...@@ -259,7 +235,6 @@ int LenovoXCC::readDatastoreRange(uint32_t offset, uint16_t count, uint8_t *buf, ...@@ -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)) { if ((len >= 2) && (buf[0] == 0x90) && (buf[1] == 0x00)) {
//printbuf("readDataStoreRange", buf, len);
return len; return len;
} else { } else {
return -1; return -1;
...@@ -284,3 +259,46 @@ uint64_t LenovoXCC::readDatastoreTimestamp() { ...@@ -284,3 +259,46 @@ uint64_t LenovoXCC::readDatastoreTimestamp() {
return 0; 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 { ...@@ -24,17 +24,23 @@ class LenovoXCC {
int getBulkPower(std::vector<reading_t> &readings); int getBulkPower(std::vector<reading_t> &readings);
int getBulkEnergy(std::vector<reading_t> &readings); int getBulkEnergy(std::vector<reading_t> &readings);
int getGeneralDrift();
int getDatastoreDrift();
private: private:
uint64_t extractTimestamp(const uint8_t *buf); uint64_t extractTimestamp(const uint8_t *buf);
int readSingleEnergyRaw(uint64_t &timeStamp, uint64_t &energy); int readSingleEnergyRaw(uint64_t &timeStamp, uint64_t &energy);
int getDrift(); // int getGeneralDrift();
int openDatastore(); int openDatastore();
int closeDatastore(); int closeDatastore();
uint64_t readDatastoreTimestamp(); uint64_t readDatastoreTimestamp();
int readDatastoreRange(uint32_t offset, uint16_t count, uint8_t *buf, uint16_t bufLen); int readDatastoreRange(uint32_t offset, uint16_t count, uint8_t *buf, uint16_t bufLen);
// int getDatastoreDrift();
IPMIHost *_host; IPMIHost *_host;
uint32_t _handle; uint32_t _handle;
int64_t _drift; int64_t _generalDrift;
int64_t _datastoreDrift;
}; };
#endif /* LenovoXCC_hpp */ #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