From 7ceb22b8c4f395ac7a83610718710d8ea5d62430 Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Mon, 4 Aug 2014 09:46:39 -0400 Subject: [PATCH] Handle non-linear and unrecognized linearizations Since we cannot hope to linearize a linearizable value without understanding the formula (OEM or future spec), treat all unrecognized linearizations and non-linearizable and rely upon get sensor reading factors to determine the value. Add the capability to actually get the sensor reading factors and then pass the resultant data through the same decode_formula that would have been use had the factors been retrieved through the SDR record. Change-Id: I4c3a6bbbd6c68f7a0d19c2a7a221eb5fb57c99de --- pyghmi/ipmi/sdr.py | 69 +++++++++++++++++++++++++++------------------- 1 file changed, 41 insertions(+), 28 deletions(-) diff --git a/pyghmi/ipmi/sdr.py b/pyghmi/ipmi/sdr.py index 67b20376..f3556df1 100644 --- a/pyghmi/ipmi/sdr.py +++ b/pyghmi/ipmi/sdr.py @@ -243,10 +243,11 @@ class SDREntry(object): external code to pay attention to this class. """ - def __init__(self, entrybytes, reportunsupported=False): + def __init__(self, entrybytes, ipmicmd, reportunsupported=False): # ignore record id for now, we only care about the sensor number for # moment self.reportunsupported = reportunsupported + self.ipmicmd = ipmicmd if entrybytes[2] != 0x51: # only recognize '1.5', the only version defined at time of writing raise NotImplementedError @@ -364,7 +365,7 @@ class SDREntry(object): # factors on the fly. # the formula could apply if we bother with nominal # reading interpretation - self.decode_formula(entry) + self.decode_formula(entry[19:25]) def _decode_state(self, state): mapping = ipmiconst.discrete_type_offsets @@ -451,55 +452,67 @@ class SDREntry(object): output['states'].append(upper + " non-recoverable threshold") return SensorReading(output, self.unit_suffix) + def _set_tmp_formula(self, value): + rsp = self.ipmicmd.raw_command(netfn=4, command=0x23, + data=(self.sensor_number, value)) + # skip next reading field, not used in on-demand situation + self.decode_formula(rsp['data'][1:]) + def decode_value(self, value): # Take the input value and return meaningful value - if self.linearization == 0x70: # direct calling code to get factors - #TODO(jbjohnso): implement get sensor reading factors support for - #non linear sensor - raise NotImplementedError("Need to do get sensor reading factors") + linearization = self.linearization + if linearization > 11: # direct calling code to get factors + # for now, we will get the factors on demand + # the facility is engineered such that at construction + # time the entire BMC table should be fetchable in a reasonable + # fashion. However for now opt for retrieving rows as needed + # rather than tracking all that information for a relatively + # rare behavior + self._set_tmp_formula(value) + linearization = 0 # time to compute the pre-linearization value. decoded = float((value * self.m + self.b) * (10 ** self.resultexponent)) - if self.linearization == 0: + if linearization == 0: return decoded - elif self.linearization == 1: + elif linearization == 1: return math.log(decoded) - elif self.linearization == 2: + elif linearization == 2: return math.log(decoded, 10) - elif self.linearization == 3: + elif linearization == 3: return math.log(decoded, 2) - elif self.linearization == 4: + elif linearization == 4: return math.exp(decoded) - elif self.linearization == 5: + elif linearization == 5: return 10 ** decoded - elif self.linearization == 6: + elif linearization == 6: return 2 ** decoded - elif self.linearization == 7: + elif linearization == 7: return 1 / decoded - elif self.linearization == 8: + elif linearization == 8: return decoded ** 2 - elif self.linearization == 9: + elif linearization == 9: return decoded ** 3 - elif self.linearization == 10: + elif linearization == 10: return math.sqrt(decoded) - elif self.linearization == 11: + elif linearization == 11: return decoded ** (1.0/3) else: raise NotImplementedError def decode_formula(self, entry): self.m = \ - twos_complement(entry[19] + ((entry[20] & 0b11000000) << 2), 10) - self.tolerance = entry[20] & 0b111111 + twos_complement(entry[0] + ((entry[1] & 0b11000000) << 2), 10) + self.tolerance = entry[1] & 0b111111 self.b = \ - twos_complement(entry[21] + ((entry[22] & 0b11000000) << 2), 10) - self.accuracy = (entry[22] & 0b111111) + \ - (entry[23] & 0b11110000) << 2 - self.accuracyexp = (entry[23] & 0b1100) >> 2 - self.direction = entry[23] & 0b11 + twos_complement(entry[2] + ((entry[3] & 0b11000000) << 2), 10) + self.accuracy = (entry[3] & 0b111111) + \ + (entry[4] & 0b11110000) << 2 + self.accuracyexp = (entry[4] & 0b1100) >> 2 + self.direction = entry[4] & 0b11 #0 = n/a, 1 = input, 2 = output - self.resultexponent = twos_complement((entry[24] & 0b11110000) >> 4, 4) - bexponent = twos_complement(entry[24] & 0b1111, 4) + self.resultexponent = twos_complement((entry[5] & 0b11110000) >> 4, 4) + bexponent = twos_complement(entry[5] & 0b1111, 4) # might as well do the math to 'b' now rather than wait for later self.b = self.b * (10**bexponent) @@ -651,7 +664,7 @@ class SDR(object): return self.sensors.iterkeys() def add_sdr(self, sdrbytes): - newent = SDREntry(sdrbytes) + newent = SDREntry(sdrbytes, self.ipmicmd) if newent.sdrtype == TYPE_SENSOR: id = newent.sensor_number if id in self.sensors: