blob: fcb3ee6a07dd0396290ad40eda26923f36d1a28a [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']
168 if self.value_dirty:
169 ## new value externally set, so just return to hwmon
170 ## process to write value
171 self.value_dirty = False
172 val = (
173 self.properties[SensorValue.IFACE_NAME]['value']
174 - offset) * scale
175 return [True, val]
176 else:
177 # Keep the val as integer. scale may be floating point
178 val = int(value/scale + offset)
179 if (val != self.value):
180 SensorValue.setValue(self, val)
181 self.check_thresholds(val)
182 self.value = val
183
184 return [False, 0]
185
186
187CONTROL_IFACE = 'org.openbmc.Control'
188
189
190class PowerCap(VirtualSensor):
191 def __init__(self, bus, name):
192 VirtualSensor.__init__(self, bus, name)
193 SensorValue.setValue(self, 0)
194 self.sysfs_attr = "/sys/class/hwmon/hwmon3/user_powercap"
195
196 ##override setValue method
197 @dbus.service.method(
198 SensorValue.IFACE_NAME, in_signature='v', out_signature='')
199 def setValue(self, value):
200 try:
201 cmd_str = "echo "+str(value)+" > "+self.sysfs_attr
202 ret = subprocess.check_output(cmd_str, shell=True)
203 except subprocess.CalledProcessError as powerexc:
204 print "Set PowerCap Error", powerexc.returncode,
205 powerexc.output
206 return
207 print "Set PowerCap: ", value
208 SensorValue.setValue(self, value)
209
210
211class BootProgressSensor(VirtualSensor):
212 def __init__(self, bus, name):
213 VirtualSensor.__init__(self, bus, name)
214 self.setValue("Off")
215 bus.add_signal_receiver(
216 self.SystemStateHandler, signal_name="GotoSystemState")
217
218 def SystemStateHandler(self, state):
219 if (state == "HOST_POWERED_OFF"):
220 self.setValue("Off")
221
222 ##override setValue method
223 @dbus.service.method(
224 SensorValue.IFACE_NAME,
225 in_signature='v', out_signature='')
226 def setValue(self, value):
227 SensorValue.setValue(self, value)
228 if (value == "FW Progress, Starting OS"):
229 self.GotoSystemState("HOST_BOOTED")
230
231 @dbus.service.signal(CONTROL_IFACE, signature='s')
232 def GotoSystemState(self, state):
233 pass
234
235
236class OccStatusSensor(VirtualSensor):
237 def __init__(self, bus, name, sysfs=None):
238 ## default path. can be override
239 if sysfs is None:
240 self.sysfs_attr = "/sys/class/i2c-adapter/i2c-3/3-0050/online"
241 else:
242 self.sysfs_attr = sysfs
243 VirtualSensor.__init__(self, bus, name)
244 self.setValue("Disabled")
245 bus.add_signal_receiver(
246 self.SystemStateHandler, signal_name="GotoSystemState")
247
248 def SystemStateHandler(self, state):
249 if (state == "HOST_POWERED_OFF"):
250 self.setValue("Disabled")
251
252 ##override setValue method
253 @dbus.service.method(
254 SensorValue.IFACE_NAME, in_signature='v', out_signature='')
255 def setValue(self, value):
256 if (value == "Enabled"):
257 print "Installing OCC device"
258 os.system("echo 1 > " + self.sysfs_attr)
259 else:
260 print "Deleting OCC device"
261 os.system("echo 0 > " + self.sysfs_attr)
262 SensorValue.setValue(self, value)
263
264 @dbus.service.signal(CONTROL_IFACE, signature='s')
265 def GotoSystemState(self, state):
266 pass
267
268
269class BootCountSensor(VirtualSensor):
270 def __init__(self, bus, name):
271 VirtualSensor.__init__(self, bus, name)
272 self.setValue(2)
273
274
275class OperatingSystemStatusSensor(VirtualSensor):
276 def __init__(self, bus, name):
277 VirtualSensor.__init__(self, bus, name)
278 self.setValue("Off")
279 bus.add_signal_receiver(
280 self.SystemStateHandler, signal_name="GotoSystemState")
281
282 def SystemStateHandler(self, state):
283 if (state == "HOST_POWERED_OFF"):
284 self.setValue("Off")