diff -r 180e4a7d945c -r 1c23952dbde1 confnodes/canfestival/canfestival.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/confnodes/canfestival/canfestival.py Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,484 @@ +import os, sys +base_folder = os.path.split(sys.path[0])[0] +CanFestivalPath = os.path.join(base_folder, "CanFestival-3") +sys.path.append(os.path.join(CanFestivalPath, "objdictgen")) + +from nodelist import NodeList +from nodemanager import NodeManager +import config_utils, gen_cfile, eds_utils +from networkedit import networkedit +from objdictedit import objdictedit +import canfestival_config as local_canfestival_config +from ConfigTree import ConfigTreeNode +from commondialogs import CreateNodeDialog +import wx + +from SlaveEditor import SlaveEditor +from NetworkEditor import NetworkEditor + +from gnosis.xml.pickle import * +from gnosis.xml.pickle.util import setParanoia +setParanoia(0) + +if wx.Platform == '__WXMSW__': + DEFAULT_SETTINGS = { + "CAN_Driver": "can_tcp_win32", + "CAN_Device": "127.0.0.1", + "CAN_Baudrate": "125K", + "Slave_NodeId": 2, + "Master_NodeId": 1, + } +else: + DEFAULT_SETTINGS = { + "CAN_Driver": "../CanFestival-3/drivers/can_socket/libcanfestival_can_socket.so", + "CAN_Device": "vcan0", + "CAN_Baudrate": "125K", + "Slave_NodeId": 2, + "Master_NodeId": 1, + } + +#-------------------------------------------------- +# SLAVE +#-------------------------------------------------- + +class _SlavePlug(NodeManager): + XSD = """ + + + + + + + + + + + + + + + + + + + """ % DEFAULT_SETTINGS + + EditorType = SlaveEditor + + def __init__(self): + # TODO change netname when name change + NodeManager.__init__(self) + odfilepath = self.GetSlaveODPath() + if(os.path.isfile(odfilepath)): + self.OpenFileInCurrent(odfilepath) + else: + self.FilePath = "" + dialog = CreateNodeDialog(None, wx.OK) + dialog.Type.Enable(False) + dialog.GenSYNC.Enable(False) + if dialog.ShowModal() == wx.ID_OK: + name, id, nodetype, description = dialog.GetValues() + profile, filepath = dialog.GetProfile() + NMT = dialog.GetNMTManagement() + options = dialog.GetOptions() + self.CreateNewNode(name, # Name - will be changed at build time + id, # NodeID - will be changed at build time + "slave", # Type + description,# description + profile, # profile + filepath, # prfile filepath + NMT, # NMT + options) # options + else: + self.CreateNewNode("SlaveNode", # Name - will be changed at build time + 0x00, # NodeID - will be changed at build time + "slave", # Type + "", # description + "None", # profile + "", # prfile filepath + "heartbeat", # NMT + []) # options + dialog.Destroy() + self.OnPlugSave() + + def GetSlaveODPath(self): + return os.path.join(self.PlugPath(), 'slave.od') + + def GetCanDevice(self): + return self.CanFestivalSlaveNode.getCan_Device() + + def _OpenView(self): + ConfigTreeNode._OpenView(self) + if self._View is not None: + self._View.SetBusId(self.GetCurrentLocation()) + + ConfNodeMethods = [ + {"bitmap" : os.path.join("images", "NetworkEdit"), + "name" : "Edit slave", + "tooltip" : "Edit CanOpen slave with ObjdictEdit", + "method" : "_OpenView"}, + ] + + def OnPlugClose(self): + if self._View: + self._View.Close() + + def PlugTestModified(self): + return self.ChangesToSave or self.OneFileHasChanged() + + def OnPlugSave(self): + return self.SaveCurrentInFile(self.GetSlaveODPath()) + + def SetParamsAttribute(self, path, value): + result = ConfigTreeNode.SetParamsAttribute(self, path, value) + + # Filter IEC_Channel and Name, that have specific behavior + if path == "BaseParams.IEC_Channel" and self._View is not None: + self._View.SetBusId(self.GetCurrentLocation()) + + return result + + def PlugGenerate_C(self, buildpath, locations): + """ + Generate C code + @param current_location: Tupple containing confnode IEC location : %I0.0.4.5 => (0,0,4,5) + @param locations: List of complete variables locations \ + [{"IEC_TYPE" : the IEC type (i.e. "INT", "STRING", ...) + "NAME" : name of the variable (generally "__IW0_1_2" style) + "DIR" : direction "Q","I" or "M" + "SIZE" : size "X", "B", "W", "D", "L" + "LOC" : tuple of interger for IEC location (0,1,2,...) + }, ...] + @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND + """ + current_location = self.GetCurrentLocation() + # define a unique name for the generated C file + prefix = "_".join(map(str, current_location)) + Gen_OD_path = os.path.join(buildpath, "OD_%s.c"%prefix ) + # Create a new copy of the model + slave = self.GetCurrentNodeCopy() + slave.SetNodeName("OD_%s"%prefix) + # allow access to local OD from Slave PLC + pointers = config_utils.LocalODPointers(locations, current_location, slave) + res = gen_cfile.GenerateFile(Gen_OD_path, slave, pointers) + if res : + raise Exception, res + res = eds_utils.GenerateEDSFile(os.path.join(buildpath, "Slave_%s.eds"%prefix), slave) + if res : + raise Exception, res + return [(Gen_OD_path,local_canfestival_config.getCFLAGS(CanFestivalPath))],"",False + + def LoadPrevious(self): + self.LoadCurrentPrevious() + + def LoadNext(self): + self.LoadCurrentNext() + + def GetBufferState(self): + return self.GetCurrentBufferState() + +#-------------------------------------------------- +# MASTER +#-------------------------------------------------- + +class MiniNodeManager(NodeManager): + + def __init__(self, parent, filepath, fullname): + NodeManager.__init__(self) + + self.OpenFileInCurrent(filepath) + + self.Parent = parent + self.Fullname = fullname + + def OnCloseEditor(self, view): + self.Parent.OnCloseEditor(view) + + def PlugFullName(self): + return self.Fullname + + def GetBufferState(self): + return self.GetCurrentBufferState() + +class _NodeListPlug(NodeList): + XSD = """ + + + + + + + + + + + """ % DEFAULT_SETTINGS + + EditorType = NetworkEditor + + def __init__(self): + manager = NodeManager() + NodeList.__init__(self, manager) + self.LoadProject(self.PlugPath()) + self.SetNetworkName(self.BaseParams.getName()) + + def GetCanDevice(self): + return self.CanFestivalNode.getCan_Device() + + def SetParamsAttribute(self, path, value): + result = ConfigTreeNode.SetParamsAttribute(self, path, value) + + # Filter IEC_Channel and Name, that have specific behavior + if path == "BaseParams.IEC_Channel" and self._View is not None: + self._View.SetBusId(self.GetCurrentLocation()) + elif path == "BaseParams.Name": + self.SetNetworkName(value) + + return result + + def _OpenView(self): + ConfigTreeNode._OpenView(self) + if self._View is not None: + self._View.SetBusId(self.GetCurrentLocation()) + + _GeneratedView = None + def _ShowMasterGenerated(self): + if self._GeneratedView is None: + buildpath = self._getBuildPath() + # Eventually create build dir + if not os.path.exists(buildpath): + self.GetPlugRoot().logger.write_error(_("Error: No PLC built\n")) + return + + masterpath = os.path.join(buildpath, "MasterGenerated.od") + if not os.path.exists(masterpath): + self.GetPlugRoot().logger.write_error(_("Error: No Master generated\n")) + return + + app_frame = self.GetPlugRoot().AppFrame + + manager = MiniNodeManager(self, masterpath, self.PlugFullName() + ".generated_master") + self._GeneratedView = SlaveEditor(app_frame.TabsOpened, manager, app_frame, False) + + app_frame.EditProjectElement(self._GeneratedView, "MasterGenerated") + + def _CloseGenerateView(self): + if self._GeneratedView is not None: + app_frame = self.GetPlugRoot().AppFrame + if app_frame is not None: + app_frame.DeletePage(self._GeneratedView) + + ConfNodeMethods = [ + {"bitmap" : os.path.join("images", "NetworkEdit"), + "name" : _("Edit network"), + "tooltip" : _("Edit CanOpen Network with NetworkEdit"), + "method" : "_OpenView"}, + {"bitmap" : os.path.join("images", "ShowMaster"), + "name" : _("Show Master"), + "tooltip" : _("Show Master generated by config_utils"), + "method" : "_ShowMasterGenerated"} + ] + + def OnCloseEditor(self, view): + ConfigTreeNode.OnCloseEditor(self, view) + if self._GeneratedView == view: + self._GeneratedView = None + + def OnPlugClose(self): + ConfigTreeNode.OnPlugClose(self) + self._CloseGenerateView() + return True + + def PlugTestModified(self): + return self.ChangesToSave or self.HasChanged() + + def OnPlugSave(self): + self.SetRoot(self.PlugPath()) + return self.SaveProject() is None + + def PlugGenerate_C(self, buildpath, locations): + """ + Generate C code + @param current_location: Tupple containing confnode IEC location : %I0.0.4.5 => (0,0,4,5) + @param locations: List of complete variables locations \ + [{"IEC_TYPE" : the IEC type (i.e. "INT", "STRING", ...) + "NAME" : name of the variable (generally "__IW0_1_2" style) + "DIR" : direction "Q","I" or "M" + "SIZE" : size "X", "B", "W", "D", "L" + "LOC" : tuple of interger for IEC location (0,1,2,...) + }, ...] + @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND + """ + self._CloseGenerateView() + current_location = self.GetCurrentLocation() + # define a unique name for the generated C file + prefix = "_".join(map(str, current_location)) + Gen_OD_path = os.path.join(buildpath, "OD_%s.c"%prefix ) + # Create a new copy of the model with DCF loaded with PDO mappings for desired location + try: + master, pointers = config_utils.GenerateConciseDCF(locations, current_location, self, self.CanFestivalNode.getSync_TPDOs(),"OD_%s"%prefix) + except config_utils.PDOmappingException, e: + raise Exception, e.message + # Do generate C file. + res = gen_cfile.GenerateFile(Gen_OD_path, master, pointers) + if res : + raise Exception, res + + file = open(os.path.join(buildpath, "MasterGenerated.od"), "w") + dump(master, file) + file.close() + + return [(Gen_OD_path,local_canfestival_config.getCFLAGS(CanFestivalPath))],"",False + + def LoadPrevious(self): + self.Manager.LoadCurrentPrevious() + + def LoadNext(self): + self.Manager.LoadCurrentNext() + + def GetBufferState(self): + return self.Manager.GetCurrentBufferState() + +class RootClass: + XSD = """ + + + + + + + + + """ % DEFAULT_SETTINGS + + PlugChildsTypes = [("CanOpenNode",_NodeListPlug, "CanOpen Master"), + ("CanOpenSlave",_SlavePlug, "CanOpen Slave")] + def GetParamsAttributes(self, path = None): + infos = ConfigTreeNode.GetParamsAttributes(self, path = None) + for element in infos: + if element["name"] == "CanFestivalInstance": + for child in element["children"]: + if child["name"] == "CAN_Driver": + DLL_LIST= getattr(local_canfestival_config,"DLL_LIST",None) + if DLL_LIST is not None: + child["type"] = DLL_LIST + return infos + + def GetCanDriver(self): + can_driver = self.CanFestivalInstance.getCAN_Driver() + if sys.platform == 'win32': + if self.CanFestivalInstance.getDebug_mode() and os.path.isfile(os.path.join("%s"%(can_driver + '_DEBUG.dll'))): + can_driver += '_DEBUG.dll' + else: + can_driver += '.dll' + return can_driver + + def PlugGenerate_C(self, buildpath, locations): + + format_dict = {"locstr" : "_".join(map(str,self.GetCurrentLocation())), + "candriver" : self.GetCanDriver(), + "nodes_includes" : "", + "board_decls" : "", + "nodes_init" : "", + "nodes_open" : "", + "nodes_stop" : "", + "nodes_close" : "", + "nodes_send_sync" : "", + "nodes_proceed_sync" : "", + "slavebootups" : "", + "slavebootup_register" : "", + "post_sync" : "", + "post_sync_register" : "", + } + for child in self.IECSortedChilds(): + childlocstr = "_".join(map(str,child.GetCurrentLocation())) + nodename = "OD_%s" % childlocstr + + # Try to get Slave Node + child_data = getattr(child, "CanFestivalSlaveNode", None) + if child_data is None: + # Not a slave -> master + child_data = getattr(child, "CanFestivalNode") + # Apply sync setting + format_dict["nodes_init"] += 'NODE_MASTER_INIT(%s, %s)\n '%( + nodename, + child_data.getNodeId()) + if child_data.getSync_TPDOs(): + format_dict["nodes_send_sync"] += 'NODE_SEND_SYNC(%s)\n '%(nodename) + format_dict["nodes_proceed_sync"] += 'NODE_PROCEED_SYNC(%s)\n '%(nodename) + + # initialize and declare node boot status variables for post_SlaveBootup lookup + SlaveIDs = child.GetSlaveIDs() + if len(SlaveIDs) == 0: + # define post_SlaveBootup lookup functions + format_dict["slavebootups"] += ( + "static void %s_post_SlaveBootup(CO_Data* d, UNS8 nodeId){}\n"%(nodename)) + else: + for id in SlaveIDs: + format_dict["slavebootups"] += ( + "int %s_slave_%d_booted = 0;\n"%(nodename, id)) + # define post_SlaveBootup lookup functions + format_dict["slavebootups"] += ( + "static void %s_post_SlaveBootup(CO_Data* d, UNS8 nodeId){\n"%(nodename)+ + " switch(nodeId){\n") + # one case per declared node, mark node as booted + for id in SlaveIDs: + format_dict["slavebootups"] += ( + " case %d:\n"%(id)+ + " %s_slave_%d_booted = 1;\n"%(nodename, id)+ + " break;\n") + format_dict["slavebootups"] += ( + " default:\n"+ + " break;\n"+ + " }\n"+ + " if( ") + # expression to test if all declared nodes booted + format_dict["slavebootups"] += " && ".join(["%s_slave_%d_booted"%(nodename, id) for id in SlaveIDs]) + format_dict["slavebootups"] += " )\n" + ( + " Master_post_SlaveBootup(d,nodeId);\n"+ + "}\n") + # register previously declared func as post_SlaveBootup callback for that node + format_dict["slavebootup_register"] += ( + "%s_Data.post_SlaveBootup = %s_post_SlaveBootup;\n"%(nodename,nodename)) + else: + # Slave node + align = child_data.getSync_Align() + align_ratio=child_data.getSync_Align_Ratio() + if align > 0: + format_dict["post_sync"] += ( + "static int %s_CalCount = 0;\n"%(nodename)+ + "static void %s_post_sync(CO_Data* d){\n"%(nodename)+ + " if(%s_CalCount < %d){\n"%(nodename, align)+ + " %s_CalCount++;\n"%(nodename)+ + " align_tick(-1);\n"+ + " }else{\n"+ + " align_tick(%d);\n"%(align_ratio)+ + " }\n"+ + "}\n") + format_dict["post_sync_register"] += ( + "%s_Data.post_sync = %s_post_sync;\n"%(nodename,nodename)) + format_dict["nodes_init"] += 'NODE_SLAVE_INIT(%s, %s)\n '%( + nodename, + child_data.getNodeId()) + + # Include generated OD headers + format_dict["nodes_includes"] += '#include "%s.h"\n'%(nodename) + # Declare CAN channels according user filled config + format_dict["board_decls"] += 'BOARD_DECL(%s, "%s", "%s")\n'%( + nodename, + child.GetCanDevice(), + child_data.getCAN_Baudrate()) + format_dict["nodes_open"] += 'NODE_OPEN(%s)\n '%(nodename) + format_dict["nodes_close"] += 'NODE_CLOSE(%s)\n '%(nodename) + format_dict["nodes_stop"] += 'NODE_STOP(%s)\n '%(nodename) + + filename = os.path.join(os.path.split(__file__)[0],"cf_runtime.c") + cf_main = open(filename).read() % format_dict + cf_main_path = os.path.join(buildpath, "CF_%(locstr)s.c"%format_dict) + f = open(cf_main_path,'w') + f.write(cf_main) + f.close() + + return [(cf_main_path, local_canfestival_config.getCFLAGS(CanFestivalPath))],local_canfestival_config.getLDFLAGS(CanFestivalPath), True + +