140a360c2SBrad Bishop#!/usr/bin/python -u
240a360c2SBrad Bishop
340a360c2SBrad Bishopimport sys
440a360c2SBrad Bishopimport subprocess
540a360c2SBrad Bishopimport gobject
640a360c2SBrad Bishopimport dbus
740a360c2SBrad Bishopimport dbus.service
840a360c2SBrad Bishopimport dbus.mainloop.glib
940a360c2SBrad Bishopimport os
1040a360c2SBrad Bishopimport time
1140a360c2SBrad Bishopimport obmc.dbuslib.propertycacher as PropertyCacher
1240a360c2SBrad Bishopfrom obmc.dbuslib.bindings import DbusProperties, DbusObjectManager, get_dbus
1340a360c2SBrad Bishopimport obmc.enums
140b380f7bSBrad Bishopimport obmc_system_config as System
1540a360c2SBrad Bishop
1640a360c2SBrad BishopDBUS_NAME = 'org.openbmc.managers.System'
1740a360c2SBrad BishopOBJ_NAME = '/org/openbmc/managers/System'
1840a360c2SBrad BishopHEARTBEAT_CHECK_INTERVAL = 20000
1940a360c2SBrad BishopSTATE_START_TIMEOUT = 10
2040a360c2SBrad BishopINTF_SENSOR = 'org.openbmc.SensorValue'
2140a360c2SBrad BishopINTF_ITEM = 'org.openbmc.InventoryItem'
2240a360c2SBrad BishopINTF_CONTROL = 'org.openbmc.Control'
2340a360c2SBrad Bishop
2440a360c2SBrad Bishop
2540a360c2SBrad Bishopclass SystemManager(DbusProperties,DbusObjectManager):
2640a360c2SBrad Bishop	def __init__(self,bus,obj_name):
2740a360c2SBrad Bishop		DbusProperties.__init__(self)
2840a360c2SBrad Bishop		DbusObjectManager.__init__(self)
2940a360c2SBrad Bishop		dbus.service.Object.__init__(self,bus,obj_name)
3040a360c2SBrad Bishop
3140a360c2SBrad Bishop		bus.add_signal_receiver(self.NewObjectHandler,
3240a360c2SBrad Bishop			signal_name = "InterfacesAdded", sender_keyword = 'bus_name')
3340a360c2SBrad Bishop		bus.add_signal_receiver(self.SystemStateHandler,signal_name = "GotoSystemState")
3440a360c2SBrad Bishop
3540a360c2SBrad Bishop		self.Set(DBUS_NAME,"current_state","")
3640a360c2SBrad Bishop		self.system_states = {}
3740a360c2SBrad Bishop		self.bus_name_lookup = {}
3840a360c2SBrad Bishop		self.bin_path = os.path.dirname(os.path.realpath(sys.argv[0]))
3940a360c2SBrad Bishop
4040a360c2SBrad Bishop		for name in System.APPS.keys():
4140a360c2SBrad Bishop			sys_state = System.APPS[name]['system_state']
4240a360c2SBrad Bishop			if (self.system_states.has_key(sys_state) == False):
4340a360c2SBrad Bishop				self.system_states[sys_state] = []
4440a360c2SBrad Bishop			self.system_states[sys_state].append(name)
4540a360c2SBrad Bishop
4640a360c2SBrad Bishop		## replace symbolic path in ID_LOOKUP
4740a360c2SBrad Bishop		for category in System.ID_LOOKUP:
4840a360c2SBrad Bishop			for key in System.ID_LOOKUP[category]:
4940a360c2SBrad Bishop				val = System.ID_LOOKUP[category][key]
5040a360c2SBrad Bishop				new_val = val.replace("<inventory_root>",System.INVENTORY_ROOT)
5140a360c2SBrad Bishop				System.ID_LOOKUP[category][key] = new_val
5240a360c2SBrad Bishop
5340a360c2SBrad Bishop		self.SystemStateHandler(System.SYSTEM_STATES[0])
5440a360c2SBrad Bishop
5540a360c2SBrad Bishop		if not os.path.exists(PropertyCacher.CACHE_PATH):
5640a360c2SBrad Bishop			print "Creating cache directory: "+PropertyCacher.CACHE_PATH
5740a360c2SBrad Bishop   			os.makedirs(PropertyCacher.CACHE_PATH)
5840a360c2SBrad Bishop
5940a360c2SBrad Bishop		self.InterfacesAdded(obj_name,self.properties)
6040a360c2SBrad Bishop		print "SystemManager Init Done"
6140a360c2SBrad Bishop
6240a360c2SBrad Bishop
63*4de42643SBrad Bishop	def try_next_state(self):
64*4de42643SBrad Bishop		current_state = self.Get(DBUS_NAME,"current_state")
65*4de42643SBrad Bishop		if current_state not in System.EXIT_STATE_DEPEND:
66*4de42643SBrad Bishop			return
67*4de42643SBrad Bishop
68*4de42643SBrad Bishop		if all(System.EXIT_STATE_DEPEND[current_state].values()):
69*4de42643SBrad Bishop			print "All required objects started for "+current_state
70*4de42643SBrad Bishop			self.gotoNextState()
71*4de42643SBrad Bishop
72*4de42643SBrad Bishop
7340a360c2SBrad Bishop	def SystemStateHandler(self,state_name):
7440a360c2SBrad Bishop		## clearing object started flags
7540a360c2SBrad Bishop		current_state = self.Get(DBUS_NAME,"current_state")
7640a360c2SBrad Bishop		try:
7740a360c2SBrad Bishop			for obj_path in System.EXIT_STATE_DEPEND[current_state]:
7840a360c2SBrad Bishop				System.EXIT_STATE_DEPEND[current_state][obj_path] = 0
7940a360c2SBrad Bishop		except:
8040a360c2SBrad Bishop			pass
8140a360c2SBrad Bishop
8240a360c2SBrad Bishop		print "Running System State: "+state_name
8340a360c2SBrad Bishop		if (self.system_states.has_key(state_name)):
8440a360c2SBrad Bishop			for name in self.system_states[state_name]:
8540a360c2SBrad Bishop				self.start_process(name)
8640a360c2SBrad Bishop
8740a360c2SBrad Bishop		if (state_name == "BMC_INIT"):
8840a360c2SBrad Bishop			## Add poll for heartbeat
8940a360c2SBrad Bishop	    		gobject.timeout_add(HEARTBEAT_CHECK_INTERVAL, self.heartbeat_check)
9040a360c2SBrad Bishop
9140a360c2SBrad Bishop		try:
9240a360c2SBrad Bishop			cb = System.ENTER_STATE_CALLBACK[state_name]
9340a360c2SBrad Bishop			for methd in cb.keys():
9440a360c2SBrad Bishop				obj = bus.get_object(cb[methd]['bus_name'],cb[methd]['obj_name'],introspect=False)
9540a360c2SBrad Bishop				method = obj.get_dbus_method(methd,cb[methd]['interface_name'])
9640a360c2SBrad Bishop				method()
9740a360c2SBrad Bishop		except:
9840a360c2SBrad Bishop			pass
9940a360c2SBrad Bishop
10040a360c2SBrad Bishop		self.Set(DBUS_NAME,"current_state",state_name)
10140a360c2SBrad Bishop
10240a360c2SBrad Bishop	def gotoNextState(self):
10340a360c2SBrad Bishop		s = 0
10440a360c2SBrad Bishop		current_state = self.Get(DBUS_NAME,"current_state")
10540a360c2SBrad Bishop		for i in range(len(System.SYSTEM_STATES)):
10640a360c2SBrad Bishop			if (System.SYSTEM_STATES[i] == current_state):
10740a360c2SBrad Bishop				s = i+1
10840a360c2SBrad Bishop
10940a360c2SBrad Bishop		if (s == len(System.SYSTEM_STATES)):
11040a360c2SBrad Bishop			print "ERROR SystemManager: No more system states"
11140a360c2SBrad Bishop		else:
11240a360c2SBrad Bishop			new_state_name = System.SYSTEM_STATES[s]
11340a360c2SBrad Bishop			print "SystemManager Goto System State: "+new_state_name
11440a360c2SBrad Bishop			self.SystemStateHandler(new_state_name)
11540a360c2SBrad Bishop
11640a360c2SBrad Bishop
11740a360c2SBrad Bishop	@dbus.service.method(DBUS_NAME,
11840a360c2SBrad Bishop		in_signature='', out_signature='s')
11940a360c2SBrad Bishop	def getSystemState(self):
12040a360c2SBrad Bishop		return self.Get(DBUS_NAME,"current_state")
12140a360c2SBrad Bishop
12240a360c2SBrad Bishop	def doObjectLookup(self,category,key):
12340a360c2SBrad Bishop		bus_name = ""
12440a360c2SBrad Bishop		obj_path = ""
12540a360c2SBrad Bishop		intf_name = INTF_ITEM
12640a360c2SBrad Bishop		try:
12740a360c2SBrad Bishop			obj_path = System.ID_LOOKUP[category][key]
12840a360c2SBrad Bishop			bus_name = self.bus_name_lookup[obj_path]
12940a360c2SBrad Bishop			parts = obj_path.split('/')
13040a360c2SBrad Bishop			if (parts[3] == 'sensors'):
13140a360c2SBrad Bishop				intf_name = INTF_SENSOR
13240a360c2SBrad Bishop		except Exception as e:
13340a360c2SBrad Bishop			print "ERROR SystemManager: "+str(e)+" not found in lookup"
13440a360c2SBrad Bishop
13540a360c2SBrad Bishop		return [bus_name,obj_path,intf_name]
13640a360c2SBrad Bishop
13740a360c2SBrad Bishop	@dbus.service.method(DBUS_NAME,
13840a360c2SBrad Bishop		in_signature='ss', out_signature='(sss)')
13940a360c2SBrad Bishop	def getObjectFromId(self,category,key):
14040a360c2SBrad Bishop		return self.doObjectLookup(category,key)
14140a360c2SBrad Bishop
14240a360c2SBrad Bishop	@dbus.service.method(DBUS_NAME,
14340a360c2SBrad Bishop		in_signature='sy', out_signature='(sss)')
14440a360c2SBrad Bishop	def getObjectFromByteId(self,category,key):
14540a360c2SBrad Bishop		byte = int(key)
14640a360c2SBrad Bishop		return self.doObjectLookup(category,byte)
14740a360c2SBrad Bishop
14840a360c2SBrad Bishop	# Get the FRU area names defined in ID_LOOKUP table given a fru_id.
14940a360c2SBrad Bishop	# If serval areas are defined for a fru_id, the areas are returned
15040a360c2SBrad Bishop	# together as a string with each area name seperated with ','.
15140a360c2SBrad Bishop	# If no fru area defined in ID_LOOKUP, an empty string will be returned.
15240a360c2SBrad Bishop	@dbus.service.method(DBUS_NAME,
15340a360c2SBrad Bishop		in_signature='y', out_signature='s')
15440a360c2SBrad Bishop	def getFRUArea(self,fru_id):
15540a360c2SBrad Bishop		ret_str = ''
15640a360c2SBrad Bishop		fru_id = '_' + str(fru_id)
15740a360c2SBrad Bishop		area_list = [area for area in System.ID_LOOKUP['FRU_STR'].keys() \
15840a360c2SBrad Bishop				if area.endswith(fru_id)]
15940a360c2SBrad Bishop		for area in area_list:
16040a360c2SBrad Bishop			ret_str = area + ',' + ret_str
16140a360c2SBrad Bishop		# remove the last ','
16240a360c2SBrad Bishop		return ret_str[:-1]
16340a360c2SBrad Bishop
16440a360c2SBrad Bishop	def start_process(self,name):
16540a360c2SBrad Bishop		if (System.APPS[name]['start_process'] == True):
16640a360c2SBrad Bishop			app = System.APPS[name]
16740a360c2SBrad Bishop			process_name = self.bin_path+"/"+app['process_name']
16840a360c2SBrad Bishop			cmdline = [ ]
16940a360c2SBrad Bishop			cmdline.append(process_name)
17040a360c2SBrad Bishop			if (app.has_key('args')):
17140a360c2SBrad Bishop				for a in app['args']:
17240a360c2SBrad Bishop					cmdline.append(a)
17340a360c2SBrad Bishop			try:
17440a360c2SBrad Bishop				print "Starting process: "+" ".join(cmdline)+": "+name
17540a360c2SBrad Bishop				if (app['monitor_process'] == True):
17640a360c2SBrad Bishop					app['popen'] = subprocess.Popen(cmdline)
17740a360c2SBrad Bishop				else:
17840a360c2SBrad Bishop					subprocess.Popen(cmdline)
17940a360c2SBrad Bishop
18040a360c2SBrad Bishop			except Exception as e:
18140a360c2SBrad Bishop				## TODO: error
18240a360c2SBrad Bishop				print "ERROR: starting process: "+" ".join(cmdline)
18340a360c2SBrad Bishop
18440a360c2SBrad Bishop	def heartbeat_check(self):
18540a360c2SBrad Bishop		for name in System.APPS.keys():
18640a360c2SBrad Bishop			app = System.APPS[name]
18740a360c2SBrad Bishop			if (app['start_process'] == True and app.has_key('popen')):
18840a360c2SBrad Bishop				##   make sure process is still alive
18940a360c2SBrad Bishop				p = app['popen']
19040a360c2SBrad Bishop				p.poll()
19140a360c2SBrad Bishop				if (p.returncode != None):
19240a360c2SBrad Bishop					print "Process for "+name+" appears to be dead"
19340a360c2SBrad Bishop					self.start_process(name)
19440a360c2SBrad Bishop
19540a360c2SBrad Bishop		return True
19640a360c2SBrad Bishop
19740a360c2SBrad Bishop	def NewObjectHandler(self, obj_path, iprops, bus_name = None):
19840a360c2SBrad Bishop		current_state = self.Get(DBUS_NAME,"current_state")
19940a360c2SBrad Bishop		if (self.bus_name_lookup.has_key(obj_path)):
20040a360c2SBrad Bishop			if (self.bus_name_lookup[obj_path] == bus_name):
20140a360c2SBrad Bishop				return
20240a360c2SBrad Bishop		self.bus_name_lookup[obj_path] = bus_name
203*4de42643SBrad Bishop		if current_state not in System.EXIT_STATE_DEPEND:
204*4de42643SBrad Bishop			return
20540a360c2SBrad Bishop
206*4de42643SBrad Bishop		if obj_path in System.EXIT_STATE_DEPEND[current_state]:
207*4de42643SBrad Bishop			print "New object: "+obj_path+" ("+bus_name+")"
208*4de42643SBrad Bishop			System.EXIT_STATE_DEPEND[current_state][obj_path] = 1
209*4de42643SBrad Bishop			## check if all required objects are
210*4de42643SBrad Bishop			# started to move to next state
211*4de42643SBrad Bishop			self.try_next_state()
21240a360c2SBrad Bishop
21340a360c2SBrad Bishop	@dbus.service.method(DBUS_NAME,
21440a360c2SBrad Bishop		in_signature='s', out_signature='sis')
21540a360c2SBrad Bishop	def gpioInit(self,name):
21640a360c2SBrad Bishop		gpio_path = ''
21740a360c2SBrad Bishop		gpio_num = -1
21840a360c2SBrad Bishop		r = ['',gpio_num,'']
21940a360c2SBrad Bishop		if (System.GPIO_CONFIG.has_key(name) == False):
22040a360c2SBrad Bishop			# TODO: Error handling
22140a360c2SBrad Bishop			print "ERROR: "+name+" not found in GPIO config table"
22240a360c2SBrad Bishop		else:
22340a360c2SBrad Bishop
22440a360c2SBrad Bishop			gpio_num = -1
22540a360c2SBrad Bishop			gpio = System.GPIO_CONFIG[name]
22640a360c2SBrad Bishop			if (System.GPIO_CONFIG[name].has_key('gpio_num')):
22740a360c2SBrad Bishop				gpio_num = gpio['gpio_num']
22840a360c2SBrad Bishop			else:
22940a360c2SBrad Bishop				if (System.GPIO_CONFIG[name].has_key('gpio_pin')):
23040a360c2SBrad Bishop					gpio_num = System.convertGpio(gpio['gpio_pin'])
23140a360c2SBrad Bishop				else:
23240a360c2SBrad Bishop					print "ERROR: SystemManager - GPIO lookup failed for "+name
23340a360c2SBrad Bishop
23440a360c2SBrad Bishop			if (gpio_num != -1):
23540a360c2SBrad Bishop				r = [obmc.enums.GPIO_DEV, gpio_num, gpio['direction']]
23640a360c2SBrad Bishop		return r
23740a360c2SBrad Bishop
23840a360c2SBrad Bishop
23940a360c2SBrad Bishop
24040a360c2SBrad Bishopif __name__ == '__main__':
24140a360c2SBrad Bishop    dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
24240a360c2SBrad Bishop    bus = get_dbus()
24340a360c2SBrad Bishop    name = dbus.service.BusName(DBUS_NAME,bus)
24440a360c2SBrad Bishop    obj = SystemManager(bus,OBJ_NAME)
24540a360c2SBrad Bishop    mainloop = gobject.MainLoop()
24640a360c2SBrad Bishop
24740a360c2SBrad Bishop    print "Running SystemManager"
24840a360c2SBrad Bishop    mainloop.run()
24940a360c2SBrad Bishop
250