1*40a360c2SBrad Bishop#!/usr/bin/python -u
2*40a360c2SBrad Bishop
3*40a360c2SBrad Bishopimport sys
4*40a360c2SBrad Bishopimport subprocess
5*40a360c2SBrad Bishopimport gobject
6*40a360c2SBrad Bishopimport dbus
7*40a360c2SBrad Bishopimport dbus.service
8*40a360c2SBrad Bishopimport dbus.mainloop.glib
9*40a360c2SBrad Bishopimport os
10*40a360c2SBrad Bishopimport time
11*40a360c2SBrad Bishopimport obmc.dbuslib.propertycacher as PropertyCacher
12*40a360c2SBrad Bishopfrom obmc.dbuslib.bindings import DbusProperties, DbusObjectManager, get_dbus
13*40a360c2SBrad Bishopimport obmc.enums
14*40a360c2SBrad Bishop
15*40a360c2SBrad Bishopif (len(sys.argv) < 2):
16*40a360c2SBrad Bishop	print "Usage:  system_manager.py [system name]"
17*40a360c2SBrad Bishop	exit(1)
18*40a360c2SBrad Bishop
19*40a360c2SBrad BishopSystem = __import__(sys.argv[1])
20*40a360c2SBrad Bishop
21*40a360c2SBrad BishopDBUS_NAME = 'org.openbmc.managers.System'
22*40a360c2SBrad BishopOBJ_NAME = '/org/openbmc/managers/System'
23*40a360c2SBrad BishopHEARTBEAT_CHECK_INTERVAL = 20000
24*40a360c2SBrad BishopSTATE_START_TIMEOUT = 10
25*40a360c2SBrad BishopINTF_SENSOR = 'org.openbmc.SensorValue'
26*40a360c2SBrad BishopINTF_ITEM = 'org.openbmc.InventoryItem'
27*40a360c2SBrad BishopINTF_CONTROL = 'org.openbmc.Control'
28*40a360c2SBrad Bishop
29*40a360c2SBrad Bishop
30*40a360c2SBrad Bishopclass SystemManager(DbusProperties,DbusObjectManager):
31*40a360c2SBrad Bishop	def __init__(self,bus,obj_name):
32*40a360c2SBrad Bishop		DbusProperties.__init__(self)
33*40a360c2SBrad Bishop		DbusObjectManager.__init__(self)
34*40a360c2SBrad Bishop		dbus.service.Object.__init__(self,bus,obj_name)
35*40a360c2SBrad Bishop
36*40a360c2SBrad Bishop		bus.add_signal_receiver(self.NewObjectHandler,
37*40a360c2SBrad Bishop			signal_name = "InterfacesAdded", sender_keyword = 'bus_name')
38*40a360c2SBrad Bishop		bus.add_signal_receiver(self.SystemStateHandler,signal_name = "GotoSystemState")
39*40a360c2SBrad Bishop
40*40a360c2SBrad Bishop		self.Set(DBUS_NAME,"current_state","")
41*40a360c2SBrad Bishop		self.system_states = {}
42*40a360c2SBrad Bishop		self.bus_name_lookup = {}
43*40a360c2SBrad Bishop		self.bin_path = os.path.dirname(os.path.realpath(sys.argv[0]))
44*40a360c2SBrad Bishop
45*40a360c2SBrad Bishop		for name in System.APPS.keys():
46*40a360c2SBrad Bishop			sys_state = System.APPS[name]['system_state']
47*40a360c2SBrad Bishop			if (self.system_states.has_key(sys_state) == False):
48*40a360c2SBrad Bishop				self.system_states[sys_state] = []
49*40a360c2SBrad Bishop			self.system_states[sys_state].append(name)
50*40a360c2SBrad Bishop
51*40a360c2SBrad Bishop		## replace symbolic path in ID_LOOKUP
52*40a360c2SBrad Bishop		for category in System.ID_LOOKUP:
53*40a360c2SBrad Bishop			for key in System.ID_LOOKUP[category]:
54*40a360c2SBrad Bishop				val = System.ID_LOOKUP[category][key]
55*40a360c2SBrad Bishop				new_val = val.replace("<inventory_root>",System.INVENTORY_ROOT)
56*40a360c2SBrad Bishop				System.ID_LOOKUP[category][key] = new_val
57*40a360c2SBrad Bishop
58*40a360c2SBrad Bishop		self.SystemStateHandler(System.SYSTEM_STATES[0])
59*40a360c2SBrad Bishop
60*40a360c2SBrad Bishop		if not os.path.exists(PropertyCacher.CACHE_PATH):
61*40a360c2SBrad Bishop			print "Creating cache directory: "+PropertyCacher.CACHE_PATH
62*40a360c2SBrad Bishop   			os.makedirs(PropertyCacher.CACHE_PATH)
63*40a360c2SBrad Bishop
64*40a360c2SBrad Bishop		self.InterfacesAdded(obj_name,self.properties)
65*40a360c2SBrad Bishop		print "SystemManager Init Done"
66*40a360c2SBrad Bishop
67*40a360c2SBrad Bishop
68*40a360c2SBrad Bishop	def SystemStateHandler(self,state_name):
69*40a360c2SBrad Bishop		## clearing object started flags
70*40a360c2SBrad Bishop		current_state = self.Get(DBUS_NAME,"current_state")
71*40a360c2SBrad Bishop		try:
72*40a360c2SBrad Bishop			for obj_path in System.EXIT_STATE_DEPEND[current_state]:
73*40a360c2SBrad Bishop				System.EXIT_STATE_DEPEND[current_state][obj_path] = 0
74*40a360c2SBrad Bishop		except:
75*40a360c2SBrad Bishop			pass
76*40a360c2SBrad Bishop
77*40a360c2SBrad Bishop		print "Running System State: "+state_name
78*40a360c2SBrad Bishop		if (self.system_states.has_key(state_name)):
79*40a360c2SBrad Bishop			for name in self.system_states[state_name]:
80*40a360c2SBrad Bishop				self.start_process(name)
81*40a360c2SBrad Bishop
82*40a360c2SBrad Bishop		if (state_name == "BMC_INIT"):
83*40a360c2SBrad Bishop			## Add poll for heartbeat
84*40a360c2SBrad Bishop	    		gobject.timeout_add(HEARTBEAT_CHECK_INTERVAL, self.heartbeat_check)
85*40a360c2SBrad Bishop
86*40a360c2SBrad Bishop		try:
87*40a360c2SBrad Bishop			cb = System.ENTER_STATE_CALLBACK[state_name]
88*40a360c2SBrad Bishop			for methd in cb.keys():
89*40a360c2SBrad Bishop				obj = bus.get_object(cb[methd]['bus_name'],cb[methd]['obj_name'],introspect=False)
90*40a360c2SBrad Bishop				method = obj.get_dbus_method(methd,cb[methd]['interface_name'])
91*40a360c2SBrad Bishop				method()
92*40a360c2SBrad Bishop		except:
93*40a360c2SBrad Bishop			pass
94*40a360c2SBrad Bishop
95*40a360c2SBrad Bishop		self.Set(DBUS_NAME,"current_state",state_name)
96*40a360c2SBrad Bishop
97*40a360c2SBrad Bishop	def gotoNextState(self):
98*40a360c2SBrad Bishop		s = 0
99*40a360c2SBrad Bishop		current_state = self.Get(DBUS_NAME,"current_state")
100*40a360c2SBrad Bishop		for i in range(len(System.SYSTEM_STATES)):
101*40a360c2SBrad Bishop			if (System.SYSTEM_STATES[i] == current_state):
102*40a360c2SBrad Bishop				s = i+1
103*40a360c2SBrad Bishop
104*40a360c2SBrad Bishop		if (s == len(System.SYSTEM_STATES)):
105*40a360c2SBrad Bishop			print "ERROR SystemManager: No more system states"
106*40a360c2SBrad Bishop		else:
107*40a360c2SBrad Bishop			new_state_name = System.SYSTEM_STATES[s]
108*40a360c2SBrad Bishop			print "SystemManager Goto System State: "+new_state_name
109*40a360c2SBrad Bishop			self.SystemStateHandler(new_state_name)
110*40a360c2SBrad Bishop
111*40a360c2SBrad Bishop
112*40a360c2SBrad Bishop	@dbus.service.method(DBUS_NAME,
113*40a360c2SBrad Bishop		in_signature='', out_signature='s')
114*40a360c2SBrad Bishop	def getSystemState(self):
115*40a360c2SBrad Bishop		return self.Get(DBUS_NAME,"current_state")
116*40a360c2SBrad Bishop
117*40a360c2SBrad Bishop	def doObjectLookup(self,category,key):
118*40a360c2SBrad Bishop		bus_name = ""
119*40a360c2SBrad Bishop		obj_path = ""
120*40a360c2SBrad Bishop		intf_name = INTF_ITEM
121*40a360c2SBrad Bishop		try:
122*40a360c2SBrad Bishop			obj_path = System.ID_LOOKUP[category][key]
123*40a360c2SBrad Bishop			bus_name = self.bus_name_lookup[obj_path]
124*40a360c2SBrad Bishop			parts = obj_path.split('/')
125*40a360c2SBrad Bishop			if (parts[3] == 'sensors'):
126*40a360c2SBrad Bishop				intf_name = INTF_SENSOR
127*40a360c2SBrad Bishop		except Exception as e:
128*40a360c2SBrad Bishop			print "ERROR SystemManager: "+str(e)+" not found in lookup"
129*40a360c2SBrad Bishop
130*40a360c2SBrad Bishop		return [bus_name,obj_path,intf_name]
131*40a360c2SBrad Bishop
132*40a360c2SBrad Bishop	@dbus.service.method(DBUS_NAME,
133*40a360c2SBrad Bishop		in_signature='ss', out_signature='(sss)')
134*40a360c2SBrad Bishop	def getObjectFromId(self,category,key):
135*40a360c2SBrad Bishop		return self.doObjectLookup(category,key)
136*40a360c2SBrad Bishop
137*40a360c2SBrad Bishop	@dbus.service.method(DBUS_NAME,
138*40a360c2SBrad Bishop		in_signature='sy', out_signature='(sss)')
139*40a360c2SBrad Bishop	def getObjectFromByteId(self,category,key):
140*40a360c2SBrad Bishop		byte = int(key)
141*40a360c2SBrad Bishop		return self.doObjectLookup(category,byte)
142*40a360c2SBrad Bishop
143*40a360c2SBrad Bishop	# Get the FRU area names defined in ID_LOOKUP table given a fru_id.
144*40a360c2SBrad Bishop	# If serval areas are defined for a fru_id, the areas are returned
145*40a360c2SBrad Bishop	# together as a string with each area name seperated with ','.
146*40a360c2SBrad Bishop	# If no fru area defined in ID_LOOKUP, an empty string will be returned.
147*40a360c2SBrad Bishop	@dbus.service.method(DBUS_NAME,
148*40a360c2SBrad Bishop		in_signature='y', out_signature='s')
149*40a360c2SBrad Bishop	def getFRUArea(self,fru_id):
150*40a360c2SBrad Bishop		ret_str = ''
151*40a360c2SBrad Bishop		fru_id = '_' + str(fru_id)
152*40a360c2SBrad Bishop		area_list = [area for area in System.ID_LOOKUP['FRU_STR'].keys() \
153*40a360c2SBrad Bishop				if area.endswith(fru_id)]
154*40a360c2SBrad Bishop		for area in area_list:
155*40a360c2SBrad Bishop			ret_str = area + ',' + ret_str
156*40a360c2SBrad Bishop		# remove the last ','
157*40a360c2SBrad Bishop		return ret_str[:-1]
158*40a360c2SBrad Bishop
159*40a360c2SBrad Bishop	def start_process(self,name):
160*40a360c2SBrad Bishop		if (System.APPS[name]['start_process'] == True):
161*40a360c2SBrad Bishop			app = System.APPS[name]
162*40a360c2SBrad Bishop			process_name = self.bin_path+"/"+app['process_name']
163*40a360c2SBrad Bishop			cmdline = [ ]
164*40a360c2SBrad Bishop			cmdline.append(process_name)
165*40a360c2SBrad Bishop			if (app.has_key('args')):
166*40a360c2SBrad Bishop				for a in app['args']:
167*40a360c2SBrad Bishop					cmdline.append(a)
168*40a360c2SBrad Bishop			try:
169*40a360c2SBrad Bishop				print "Starting process: "+" ".join(cmdline)+": "+name
170*40a360c2SBrad Bishop				if (app['monitor_process'] == True):
171*40a360c2SBrad Bishop					app['popen'] = subprocess.Popen(cmdline)
172*40a360c2SBrad Bishop				else:
173*40a360c2SBrad Bishop					subprocess.Popen(cmdline)
174*40a360c2SBrad Bishop
175*40a360c2SBrad Bishop			except Exception as e:
176*40a360c2SBrad Bishop				## TODO: error
177*40a360c2SBrad Bishop				print "ERROR: starting process: "+" ".join(cmdline)
178*40a360c2SBrad Bishop
179*40a360c2SBrad Bishop	def heartbeat_check(self):
180*40a360c2SBrad Bishop		for name in System.APPS.keys():
181*40a360c2SBrad Bishop			app = System.APPS[name]
182*40a360c2SBrad Bishop			if (app['start_process'] == True and app.has_key('popen')):
183*40a360c2SBrad Bishop				##   make sure process is still alive
184*40a360c2SBrad Bishop				p = app['popen']
185*40a360c2SBrad Bishop				p.poll()
186*40a360c2SBrad Bishop				if (p.returncode != None):
187*40a360c2SBrad Bishop					print "Process for "+name+" appears to be dead"
188*40a360c2SBrad Bishop					self.start_process(name)
189*40a360c2SBrad Bishop
190*40a360c2SBrad Bishop		return True
191*40a360c2SBrad Bishop
192*40a360c2SBrad Bishop	def NewObjectHandler(self, obj_path, iprops, bus_name = None):
193*40a360c2SBrad Bishop		current_state = self.Get(DBUS_NAME,"current_state")
194*40a360c2SBrad Bishop		if (self.bus_name_lookup.has_key(obj_path)):
195*40a360c2SBrad Bishop			if (self.bus_name_lookup[obj_path] == bus_name):
196*40a360c2SBrad Bishop				return
197*40a360c2SBrad Bishop		self.bus_name_lookup[obj_path] = bus_name
198*40a360c2SBrad Bishop		print "New object: "+obj_path+" ("+bus_name+")"
199*40a360c2SBrad Bishop		try:
200*40a360c2SBrad Bishop			if (System.EXIT_STATE_DEPEND[current_state].has_key(obj_path) == True):
201*40a360c2SBrad Bishop				System.EXIT_STATE_DEPEND[current_state][obj_path] = 1
202*40a360c2SBrad Bishop			## check if all required objects are started to move to next state
203*40a360c2SBrad Bishop			state = 1
204*40a360c2SBrad Bishop			for obj_path in System.EXIT_STATE_DEPEND[current_state]:
205*40a360c2SBrad Bishop				if (System.EXIT_STATE_DEPEND[current_state][obj_path] == 0):
206*40a360c2SBrad Bishop					state = 0
207*40a360c2SBrad Bishop			## all required objects have started so go to next state
208*40a360c2SBrad Bishop			if (state == 1):
209*40a360c2SBrad Bishop				print "All required objects started for "+current_state
210*40a360c2SBrad Bishop				self.gotoNextState()
211*40a360c2SBrad Bishop		except:
212*40a360c2SBrad Bishop			pass
213*40a360c2SBrad Bishop
214*40a360c2SBrad Bishop
215*40a360c2SBrad Bishop	@dbus.service.method(DBUS_NAME,
216*40a360c2SBrad Bishop		in_signature='s', out_signature='sis')
217*40a360c2SBrad Bishop	def gpioInit(self,name):
218*40a360c2SBrad Bishop		gpio_path = ''
219*40a360c2SBrad Bishop		gpio_num = -1
220*40a360c2SBrad Bishop		r = ['',gpio_num,'']
221*40a360c2SBrad Bishop		if (System.GPIO_CONFIG.has_key(name) == False):
222*40a360c2SBrad Bishop			# TODO: Error handling
223*40a360c2SBrad Bishop			print "ERROR: "+name+" not found in GPIO config table"
224*40a360c2SBrad Bishop		else:
225*40a360c2SBrad Bishop
226*40a360c2SBrad Bishop			gpio_num = -1
227*40a360c2SBrad Bishop			gpio = System.GPIO_CONFIG[name]
228*40a360c2SBrad Bishop			if (System.GPIO_CONFIG[name].has_key('gpio_num')):
229*40a360c2SBrad Bishop				gpio_num = gpio['gpio_num']
230*40a360c2SBrad Bishop			else:
231*40a360c2SBrad Bishop				if (System.GPIO_CONFIG[name].has_key('gpio_pin')):
232*40a360c2SBrad Bishop					gpio_num = System.convertGpio(gpio['gpio_pin'])
233*40a360c2SBrad Bishop				else:
234*40a360c2SBrad Bishop					print "ERROR: SystemManager - GPIO lookup failed for "+name
235*40a360c2SBrad Bishop
236*40a360c2SBrad Bishop			if (gpio_num != -1):
237*40a360c2SBrad Bishop				r = [obmc.enums.GPIO_DEV, gpio_num, gpio['direction']]
238*40a360c2SBrad Bishop		return r
239*40a360c2SBrad Bishop
240*40a360c2SBrad Bishop
241*40a360c2SBrad Bishop
242*40a360c2SBrad Bishopif __name__ == '__main__':
243*40a360c2SBrad Bishop    dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
244*40a360c2SBrad Bishop    bus = get_dbus()
245*40a360c2SBrad Bishop    name = dbus.service.BusName(DBUS_NAME,bus)
246*40a360c2SBrad Bishop    obj = SystemManager(bus,OBJ_NAME)
247*40a360c2SBrad Bishop    mainloop = gobject.MainLoop()
248*40a360c2SBrad Bishop
249*40a360c2SBrad Bishop    print "Running SystemManager"
250*40a360c2SBrad Bishop    mainloop.run()
251*40a360c2SBrad Bishop
252