blob: e5c79ef508e76c053c3167eab931d51b0d352a76 [file] [log] [blame]
Brad Bishop179b39b2016-05-12 16:45:57 -04001# Contributors Listed Below - COPYRIGHT 2016
2# [+] International Business Machines Corp.
3#
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
14# implied. See the License for the specific language governing
15# permissions and limitations under the License.
16
17import os
18import subprocess
19import dbus
20import dbus.service
21from obmc.dbuslib.bindings import DbusProperties
22
23
24## Abstract class, must subclass
25class SensorValue(DbusProperties):
26 IFACE_NAME = 'org.openbmc.SensorValue'
27
28 def __init__(self, bus, name):
29 self.Set(SensorValue.IFACE_NAME, 'units', "")
30 self.Set(SensorValue.IFACE_NAME, 'error', False)
31
32 @dbus.service.method(
33 IFACE_NAME, in_signature='v', out_signature='')
34 def setValue(self, value):
35 self.Set(SensorValue.IFACE_NAME, 'value', value)
36
37 @dbus.service.method(
38 IFACE_NAME, in_signature='', out_signature='v')
39 def getValue(self):
40 return self.Get(SensorValue.IFACE_NAME, 'value')
41
42
43class SensorThresholds(DbusProperties):
44 IFACE_NAME = 'org.openbmc.SensorThresholds'
45
46 def __init__(self, bus, name):
47 self.Set(
48 SensorThresholds.IFACE_NAME,
49 'thresholds_enabled',
50 False)
51 self.Set(
52 SensorThresholds.IFACE_NAME,
53 'emergency_enabled',
54 False)
55 self.Set(
56 SensorThresholds.IFACE_NAME,
57 'warning_upper',
58 0)
59 self.Set(
60 SensorThresholds.IFACE_NAME,
61 'warning_lower',
62 0)
63 self.Set(
64 SensorThresholds.IFACE_NAME,
65 'critical_upper',
66 0)
67 self.Set(
68 SensorThresholds.IFACE_NAME,
69 'critical_lower',
70 0)
71 self.Set(
72 SensorThresholds.IFACE_NAME,
73 'critical_lower',
74 0)
75 self.Set(
76 SensorThresholds.IFACE_NAME,
77 'threshold_state',
78 "NORMAL")
79 self.Set(
80 SensorThresholds.IFACE_NAME,
81 'worst_threshold_state',
82 "NORMAL")
83
84 @dbus.service.method(
85 IFACE_NAME, in_signature='', out_signature='')
86 def resetThresholdState(self):
87 self.Set(
88 SensorThresholds.IFACE_NAME,
89 'worst_threshold_state',
90 "NORMAL")
91
92 def check_thresholds(self, value):
93 iface = SensorThresholds.IFACE_NAME
94 if (self.Get(iface, 'thresholds_enabled') is False):
95 return False
96 rtn = False
97 current_state = "NORMAL"
98 if (value >= self.properties[iface]['critical_upper']):
99 current_state = "CRITICAL"
100 rtn = True
101 elif (value <= self.properties[iface]['critical_lower']):
102 current_state = "CRITICAL"
103 rtn = True
104 elif (value >= self.properties[iface]['warning_upper']):
105 current_state = "WARNING"
106 rtn = True
107 elif (value <= self.properties[iface]['warning_lower']):
108 current_state = "WARNING"
109 rtn = True
110
111 if self.Get(iface, 'threshold_state') != current_state and \
112 current_state == "CRITICAL" and \
113 self.Get(iface, 'emergency_enabled') is True:
Yi Li3cb85e92016-07-01 16:47:16 +0800114 message = type(self).__name__ + \
115 ' SensorThresholds.check_thresholds(): trigger emergency' + \
116 ' signal, sensor value: ' + str(value)
117 self.Emergency(message)
Brad Bishop179b39b2016-05-12 16:45:57 -0400118
119 self.Set(iface, 'threshold_state', current_state)
120 worst = self.properties[iface]['worst_threshold_state']
121 if (current_state == "CRITICAL" or
122 (current_state == "WARNING" and worst != "CRITICAL")):
123 self.Set(iface, 'worst_threshold_state', current_state)
124
125 return rtn
126
Yi Li3cb85e92016-07-01 16:47:16 +0800127 @dbus.service.signal(IFACE_NAME, signature='s')
128 def Emergency(self, message):
Brad Bishop179b39b2016-05-12 16:45:57 -0400129 pass
130
131
132class VirtualSensor(SensorValue):
133 def __init__(self, bus, name):
134 DbusProperties.__init__(self)
135 SensorValue.__init__(self, bus, name)
136 dbus.service.Object.__init__(self, bus, name)
137
138
139class HwmonSensor(SensorValue, SensorThresholds):
140 IFACE_NAME = 'org.openbmc.HwmonSensor'
141
142 def __init__(self, bus, name):
143 DbusProperties.__init__(self)
144 SensorValue.__init__(self, bus, name)
145 SensorThresholds.__init__(self, bus, name)
146 self.Set(HwmonSensor.IFACE_NAME, 'scale', 1)
147 self.Set(HwmonSensor.IFACE_NAME, 'offset', 0)
148 self.Set(HwmonSensor.IFACE_NAME, 'filename', '')
149 self.value_dirty = False
150
151 # need to cache value to know if changed
152 self.value = None
153 dbus.service.Object.__init__(self, bus, name)
154
155 @dbus.service.method(
156 SensorValue.IFACE_NAME, in_signature='v', out_signature='')
157 def setValue(self, value):
158 self.value_dirty = True
159 SensorValue.setValue(self, value)
160
161 ## Called by sensor process to update value from polling
162 ## if returns not None, then sensor process will update hwmon value
163 @dbus.service.method(
164 IFACE_NAME, in_signature='v', out_signature='(bv)')
165 def setByPoll(self, value):
166 scale = self.properties[HwmonSensor.IFACE_NAME]['scale']
167 offset = self.properties[HwmonSensor.IFACE_NAME]['offset']
Edward A. Jamesecf8bd82016-08-15 16:22:25 -0500168 try:
169 adjust = self.properties[HwmonSensor.IFACE_NAME]['adjust']
170 if adjust == 0:
171 adjust = 1
172 except:
173 adjust = 1
174
Brad Bishop179b39b2016-05-12 16:45:57 -0400175 if self.value_dirty:
176 ## new value externally set, so just return to hwmon
177 ## process to write value
178 self.value_dirty = False
Edward A. Jamesecf8bd82016-08-15 16:22:25 -0500179 val = int((
Brad Bishop179b39b2016-05-12 16:45:57 -0400180 self.properties[SensorValue.IFACE_NAME]['value']
Edward A. Jamesecf8bd82016-08-15 16:22:25 -0500181 - offset) * adjust)
Brad Bishop179b39b2016-05-12 16:45:57 -0400182 return [True, val]
183 else:
Edward A. Jamesecf8bd82016-08-15 16:22:25 -0500184 # Keep the val as integer. adjust may be floating point
185 val = int(value/adjust + offset)
Brad Bishop179b39b2016-05-12 16:45:57 -0400186 if (val != self.value):
187 SensorValue.setValue(self, val)
Edward A. Jamesecf8bd82016-08-15 16:22:25 -0500188 # scale the value to check threshold
189 self.check_thresholds(val * (10 ** scale))
Brad Bishop179b39b2016-05-12 16:45:57 -0400190 self.value = val
191
192 return [False, 0]
193
194
195CONTROL_IFACE = 'org.openbmc.Control'
196
197
198class PowerCap(VirtualSensor):
199 def __init__(self, bus, name):
200 VirtualSensor.__init__(self, bus, name)
201 SensorValue.setValue(self, 0)
202 self.sysfs_attr = "/sys/class/hwmon/hwmon3/user_powercap"
203
204 ##override setValue method
205 @dbus.service.method(
206 SensorValue.IFACE_NAME, in_signature='v', out_signature='')
207 def setValue(self, value):
208 try:
209 cmd_str = "echo "+str(value)+" > "+self.sysfs_attr
210 ret = subprocess.check_output(cmd_str, shell=True)
211 except subprocess.CalledProcessError as powerexc:
212 print "Set PowerCap Error", powerexc.returncode,
213 powerexc.output
214 return
215 print "Set PowerCap: ", value
216 SensorValue.setValue(self, value)
217
218
219class BootProgressSensor(VirtualSensor):
220 def __init__(self, bus, name):
221 VirtualSensor.__init__(self, bus, name)
222 self.setValue("Off")
223 bus.add_signal_receiver(
224 self.SystemStateHandler, signal_name="GotoSystemState")
225
226 def SystemStateHandler(self, state):
227 if (state == "HOST_POWERED_OFF"):
228 self.setValue("Off")
229
230 ##override setValue method
231 @dbus.service.method(
232 SensorValue.IFACE_NAME,
233 in_signature='v', out_signature='')
234 def setValue(self, value):
235 SensorValue.setValue(self, value)
236 if (value == "FW Progress, Starting OS"):
237 self.GotoSystemState("HOST_BOOTED")
238
239 @dbus.service.signal(CONTROL_IFACE, signature='s')
240 def GotoSystemState(self, state):
241 pass
242
243
244class OccStatusSensor(VirtualSensor):
245 def __init__(self, bus, name, sysfs=None):
246 ## default path. can be override
247 if sysfs is None:
248 self.sysfs_attr = "/sys/class/i2c-adapter/i2c-3/3-0050/online"
249 else:
250 self.sysfs_attr = sysfs
251 VirtualSensor.__init__(self, bus, name)
252 self.setValue("Disabled")
253 bus.add_signal_receiver(
254 self.SystemStateHandler, signal_name="GotoSystemState")
255
256 def SystemStateHandler(self, state):
257 if (state == "HOST_POWERED_OFF"):
258 self.setValue("Disabled")
259
260 ##override setValue method
261 @dbus.service.method(
262 SensorValue.IFACE_NAME, in_signature='v', out_signature='')
263 def setValue(self, value):
264 if (value == "Enabled"):
265 print "Installing OCC device"
266 os.system("echo 1 > " + self.sysfs_attr)
267 else:
268 print "Deleting OCC device"
269 os.system("echo 0 > " + self.sysfs_attr)
270 SensorValue.setValue(self, value)
271
272 @dbus.service.signal(CONTROL_IFACE, signature='s')
273 def GotoSystemState(self, state):
274 pass
275
276
277class BootCountSensor(VirtualSensor):
278 def __init__(self, bus, name):
279 VirtualSensor.__init__(self, bus, name)
280 self.setValue(2)
281
282
283class OperatingSystemStatusSensor(VirtualSensor):
284 def __init__(self, bus, name):
285 VirtualSensor.__init__(self, bus, name)
286 self.setValue("Off")
287 bus.add_signal_receiver(
288 self.SystemStateHandler, signal_name="GotoSystemState")
289
290 def SystemStateHandler(self, state):
291 if (state == "HOST_POWERED_OFF"):
292 self.setValue("Off")