etisserant@163: import os, sys laurent@815: etisserant@20: base_folder = os.path.split(sys.path[0])[0] etisserant@49: CanFestivalPath = os.path.join(base_folder, "CanFestival-3") etisserant@49: sys.path.append(os.path.join(CanFestivalPath, "objdictgen")) etisserant@20: laurent@815: import wx laurent@815: lbessard@11: from nodelist import NodeList lbessard@11: from nodemanager import NodeManager etisserant@178: import config_utils, gen_cfile, eds_utils etisserant@12: from networkedit import networkedit lbessard@77: from objdictedit import objdictedit edouard@512: import canfestival_config as local_canfestival_config Edouard@725: from ConfigTreeNode import ConfigTreeNode etisserant@169: from commondialogs import CreateNodeDialog lbessard@11: laurent@777: from SlaveEditor import SlaveEditor, MasterViewer smarteh-dev@682: from NetworkEditor import NetworkEditor smarteh-dev@682: lbessard@77: from gnosis.xml.pickle import * lbessard@77: from gnosis.xml.pickle.util import setParanoia lbessard@77: setParanoia(0) lbessard@77: laurent@815: from util.TranslationCatalogs import AddCatalog laurent@815: AddCatalog(os.path.join(CanFestivalPath, "objdictgen", "locale")) laurent@815: laurent@411: if wx.Platform == '__WXMSW__': laurent@411: DEFAULT_SETTINGS = { laurent@411: "CAN_Driver": "can_tcp_win32", laurent@411: "CAN_Device": "127.0.0.1", laurent@411: "CAN_Baudrate": "125K", laurent@411: "Slave_NodeId": 2, laurent@411: "Master_NodeId": 1, laurent@411: } laurent@411: else: laurent@411: DEFAULT_SETTINGS = { laurent@411: "CAN_Driver": "../CanFestival-3/drivers/can_socket/libcanfestival_can_socket.so", laurent@411: "CAN_Device": "vcan0", laurent@411: "CAN_Baudrate": "125K", laurent@411: "Slave_NodeId": 2, laurent@411: "Master_NodeId": 1, laurent@411: } laurent@411: etisserant@163: #-------------------------------------------------- etisserant@163: # SLAVE etisserant@163: #-------------------------------------------------- etisserant@163: Edouard@718: class _SlaveCTN(NodeManager): etisserant@12: XSD = """ etisserant@12: etisserant@166: etisserant@12: laurent@411: laurent@411: laurent@411: etisserant@178: etisserant@203: etisserant@203: etisserant@203: etisserant@203: etisserant@203: etisserant@203: etisserant@203: etisserant@203: etisserant@12: etisserant@12: etisserant@12: laurent@411: """ % DEFAULT_SETTINGS smarteh-dev@682: smarteh-dev@682: EditorType = SlaveEditor laurent@738: IconPath = os.path.join(CanFestivalPath, "objdictgen", "networkedit.png") etisserant@163: lbessard@17: def __init__(self): etisserant@23: # TODO change netname when name change etisserant@163: NodeManager.__init__(self) etisserant@163: odfilepath = self.GetSlaveODPath() etisserant@163: if(os.path.isfile(odfilepath)): etisserant@163: self.OpenFileInCurrent(odfilepath) etisserant@163: else: etisserant@169: self.FilePath = "" etisserant@169: dialog = CreateNodeDialog(None, wx.OK) etisserant@169: dialog.Type.Enable(False) etisserant@169: dialog.GenSYNC.Enable(False) etisserant@169: if dialog.ShowModal() == wx.ID_OK: etisserant@169: name, id, nodetype, description = dialog.GetValues() etisserant@169: profile, filepath = dialog.GetProfile() etisserant@169: NMT = dialog.GetNMTManagement() etisserant@169: options = dialog.GetOptions() etisserant@169: self.CreateNewNode(name, # Name - will be changed at build time etisserant@169: id, # NodeID - will be changed at build time etisserant@169: "slave", # Type etisserant@169: description,# description etisserant@169: profile, # profile etisserant@169: filepath, # prfile filepath etisserant@169: NMT, # NMT etisserant@169: options) # options etisserant@169: else: etisserant@169: self.CreateNewNode("SlaveNode", # Name - will be changed at build time etisserant@169: 0x00, # NodeID - will be changed at build time etisserant@169: "slave", # Type etisserant@169: "", # description etisserant@169: "None", # profile etisserant@169: "", # prfile filepath etisserant@169: "heartbeat", # NMT etisserant@169: []) # options etisserant@169: dialog.Destroy() Edouard@718: self.OnCTNSave() smarteh-dev@682: smarteh-dev@682: def GetSlaveODPath(self): Edouard@718: return os.path.join(self.CTNPath(), 'slave.od') smarteh-dev@682: smarteh-dev@682: def GetCanDevice(self): smarteh-dev@682: return self.CanFestivalSlaveNode.getCan_Device() smarteh-dev@682: laurent@784: def _OpenView(self, name=None, onlyopened=False): laurent@784: ConfigTreeNode._OpenView(self, name, onlyopened) smarteh-dev@682: if self._View is not None: smarteh-dev@682: self._View.SetBusId(self.GetCurrentLocation()) laurent@774: return self._View laurent@777: laurent@777: def _ExportSlave(self): laurent@777: dialog = wx.FileDialog(self.GetCTRoot().AppFrame, _("Choose a file"), os.getcwd(), "", _("EDS files (*.eds)|*.eds|All files|*.*"), wx.SAVE|wx.OVERWRITE_PROMPT) laurent@777: if dialog.ShowModal() == wx.ID_OK: laurent@777: result = eds_utils.GenerateEDSFile(dialog.GetPath(), self.GetCurrentNodeCopy()) laurent@777: if result: laurent@777: self.GetCTRoot().logger.write_error(_("Error: Export slave failed\n")) laurent@777: dialog.Destroy() laurent@777: Edouard@717: ConfNodeMethods = [ laurent@777: {"bitmap" : "ExportSlave", laurent@777: "name" : _("Export slave"), laurent@777: "tooltip" : _("Export CanOpen slave to EDS file"), laurent@777: "method" : "_ExportSlave"}, lbessard@65: ] laurent@777: Edouard@718: def CTNTestModified(self): etisserant@166: return self.ChangesToSave or self.OneFileHasChanged() etisserant@12: Edouard@718: def OnCTNSave(self): etisserant@166: return self.SaveCurrentInFile(self.GetSlaveODPath()) etisserant@12: smarteh-dev@682: def SetParamsAttribute(self, path, value): Edouard@717: result = ConfigTreeNode.SetParamsAttribute(self, path, value) smarteh-dev@682: smarteh-dev@682: # Filter IEC_Channel and Name, that have specific behavior smarteh-dev@682: if path == "BaseParams.IEC_Channel" and self._View is not None: smarteh-dev@682: self._View.SetBusId(self.GetCurrentLocation()) smarteh-dev@682: smarteh-dev@682: return result smarteh-dev@682: Edouard@718: def CTNGenerate_C(self, buildpath, locations): etisserant@12: """ etisserant@15: Generate C code Edouard@717: @param current_location: Tupple containing confnode IEC location : %I0.0.4.5 => (0,0,4,5) etisserant@15: @param locations: List of complete variables locations \ etisserant@22: [{"IEC_TYPE" : the IEC type (i.e. "INT", "STRING", ...) etisserant@22: "NAME" : name of the variable (generally "__IW0_1_2" style) etisserant@22: "DIR" : direction "Q","I" or "M" etisserant@22: "SIZE" : size "X", "B", "W", "D", "L" etisserant@22: "LOC" : tuple of interger for IEC location (0,1,2,...) etisserant@22: }, ...] etisserant@22: @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND etisserant@12: """ etisserant@24: current_location = self.GetCurrentLocation() etisserant@22: # define a unique name for the generated C file etisserant@166: prefix = "_".join(map(str, current_location)) etisserant@49: Gen_OD_path = os.path.join(buildpath, "OD_%s.c"%prefix ) etisserant@166: # Create a new copy of the model etisserant@166: slave = self.GetCurrentNodeCopy() etisserant@166: slave.SetNodeName("OD_%s"%prefix) etisserant@166: # allow access to local OD from Slave PLC etisserant@166: pointers = config_utils.LocalODPointers(locations, current_location, slave) etisserant@166: res = gen_cfile.GenerateFile(Gen_OD_path, slave, pointers) etisserant@15: if res : etisserant@15: raise Exception, res lbessard@172: res = eds_utils.GenerateEDSFile(os.path.join(buildpath, "Slave_%s.eds"%prefix), slave) lbessard@172: if res : lbessard@172: raise Exception, res edouard@512: return [(Gen_OD_path,local_canfestival_config.getCFLAGS(CanFestivalPath))],"",False etisserant@163: smarteh-dev@682: def LoadPrevious(self): smarteh-dev@682: self.LoadCurrentPrevious() smarteh-dev@682: smarteh-dev@682: def LoadNext(self): smarteh-dev@682: self.LoadCurrentNext() smarteh-dev@682: smarteh-dev@682: def GetBufferState(self): smarteh-dev@682: return self.GetCurrentBufferState() smarteh-dev@682: etisserant@163: #-------------------------------------------------- etisserant@163: # MASTER etisserant@163: #-------------------------------------------------- etisserant@163: smarteh-dev@682: class MiniNodeManager(NodeManager): smarteh-dev@682: smarteh-dev@682: def __init__(self, parent, filepath, fullname): smarteh-dev@682: NodeManager.__init__(self) smarteh-dev@682: smarteh-dev@682: self.OpenFileInCurrent(filepath) smarteh-dev@682: smarteh-dev@682: self.Parent = parent smarteh-dev@682: self.Fullname = fullname laurent@777: laurent@781: def GetIconName(self): laurent@777: return None laurent@777: smarteh-dev@682: def OnCloseEditor(self, view): smarteh-dev@682: self.Parent.OnCloseEditor(view) smarteh-dev@682: Edouard@718: def CTNFullName(self): smarteh-dev@682: return self.Fullname smarteh-dev@682: laurent@777: def CTNTestModified(self): laurent@777: return False laurent@777: smarteh-dev@682: def GetBufferState(self): smarteh-dev@682: return self.GetCurrentBufferState() laurent@777: laurent@774: ConfNodeMethods = [] laurent@774: Edouard@718: class _NodeListCTN(NodeList): etisserant@163: XSD = """ etisserant@163: etisserant@163: etisserant@163: laurent@411: laurent@411: laurent@411: etisserant@163: etisserant@163: etisserant@163: etisserant@163: laurent@411: """ % DEFAULT_SETTINGS smarteh-dev@682: smarteh-dev@682: EditorType = NetworkEditor laurent@738: IconPath = os.path.join(CanFestivalPath, "objdictgen", "networkedit.png") smarteh-dev@682: etisserant@163: def __init__(self): etisserant@163: manager = NodeManager() smarteh-dev@682: NodeList.__init__(self, manager) Edouard@718: self.LoadProject(self.CTNPath()) smarteh-dev@682: self.SetNetworkName(self.BaseParams.getName()) smarteh-dev@682: smarteh-dev@682: def GetCanDevice(self): smarteh-dev@682: return self.CanFestivalNode.getCan_Device() smarteh-dev@682: smarteh-dev@682: def SetParamsAttribute(self, path, value): Edouard@717: result = ConfigTreeNode.SetParamsAttribute(self, path, value) smarteh-dev@682: smarteh-dev@682: # Filter IEC_Channel and Name, that have specific behavior smarteh-dev@682: if path == "BaseParams.IEC_Channel" and self._View is not None: smarteh-dev@682: self._View.SetBusId(self.GetCurrentLocation()) smarteh-dev@682: elif path == "BaseParams.Name": smarteh-dev@682: self.SetNetworkName(value) smarteh-dev@682: smarteh-dev@682: return result smarteh-dev@682: laurent@774: _GeneratedMasterView = None laurent@774: def _ShowGeneratedMaster(self): laurent@774: self._OpenView("Generated master") laurent@774: laurent@782: def _OpenView(self, name=None, onlyopened=False): laurent@774: if name == "Generated master": laurent@782: app_frame = self.GetCTRoot().AppFrame laurent@774: if self._GeneratedMasterView is None: laurent@774: buildpath = self._getBuildPath() laurent@774: # Eventually create build dir laurent@774: if not os.path.exists(buildpath): laurent@774: self.GetCTRoot().logger.write_error(_("Error: No PLC built\n")) laurent@774: return laurent@774: laurent@774: masterpath = os.path.join(buildpath, "MasterGenerated.od") laurent@774: if not os.path.exists(masterpath): laurent@774: self.GetCTRoot().logger.write_error(_("Error: No Master generated\n")) laurent@774: return laurent@774: laurent@774: manager = MiniNodeManager(self, masterpath, self.CTNFullName() + ".generated_master") laurent@777: self._GeneratedMasterView = MasterViewer(app_frame.TabsOpened, manager, app_frame) laurent@774: laurent@784: if self._GeneratedMasterView is not None: laurent@802: app_frame.EditProjectElement(self._GeneratedMasterView, name) laurent@782: laurent@774: return self._GeneratedMasterView laurent@774: else: laurent@782: ConfigTreeNode._OpenView(self, name, onlyopened) laurent@774: if self._View is not None: laurent@774: self._View.SetBusId(self.GetCurrentLocation()) laurent@774: return self._View smarteh-dev@682: Edouard@717: ConfNodeMethods = [ laurent@762: {"bitmap" : "ShowMaster", edouard@372: "name" : _("Show Master"), laurent@361: "tooltip" : _("Show Master generated by config_utils"), laurent@774: "method" : "_ShowGeneratedMaster"} etisserant@163: ] smarteh-dev@682: smarteh-dev@682: def OnCloseEditor(self, view): Edouard@717: ConfigTreeNode.OnCloseEditor(self, view) laurent@774: if self._GeneratedMasterView == view: laurent@774: self._GeneratedMasterView = None laurent@774: Edouard@718: def OnCTNClose(self): Edouard@718: ConfigTreeNode.OnCTNClose(self) laurent@774: self._CloseView(self._GeneratedMasterView) smarteh-dev@682: return True etisserant@163: Edouard@718: def CTNTestModified(self): etisserant@163: return self.ChangesToSave or self.HasChanged() etisserant@163: Edouard@718: def OnCTNSave(self): Edouard@718: self.SetRoot(self.CTNPath()) lbessard@250: return self.SaveProject() is None etisserant@163: Edouard@718: def CTNGenerate_C(self, buildpath, locations): etisserant@163: """ etisserant@163: Generate C code Edouard@717: @param current_location: Tupple containing confnode IEC location : %I0.0.4.5 => (0,0,4,5) etisserant@163: @param locations: List of complete variables locations \ etisserant@163: [{"IEC_TYPE" : the IEC type (i.e. "INT", "STRING", ...) etisserant@163: "NAME" : name of the variable (generally "__IW0_1_2" style) etisserant@163: "DIR" : direction "Q","I" or "M" etisserant@163: "SIZE" : size "X", "B", "W", "D", "L" etisserant@163: "LOC" : tuple of interger for IEC location (0,1,2,...) etisserant@163: }, ...] etisserant@163: @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND etisserant@163: """ laurent@774: self._CloseView(self._GeneratedMasterView) etisserant@163: current_location = self.GetCurrentLocation() etisserant@163: # define a unique name for the generated C file etisserant@166: prefix = "_".join(map(str, current_location)) etisserant@163: Gen_OD_path = os.path.join(buildpath, "OD_%s.c"%prefix ) etisserant@163: # Create a new copy of the model with DCF loaded with PDO mappings for desired location greg@341: try: greg@341: master, pointers = config_utils.GenerateConciseDCF(locations, current_location, self, self.CanFestivalNode.getSync_TPDOs(),"OD_%s"%prefix) greg@341: except config_utils.PDOmappingException, e: greg@341: raise Exception, e.message etisserant@166: # Do generate C file. etisserant@163: res = gen_cfile.GenerateFile(Gen_OD_path, master, pointers) etisserant@163: if res : etisserant@163: raise Exception, res etisserant@163: etisserant@163: file = open(os.path.join(buildpath, "MasterGenerated.od"), "w") etisserant@163: dump(master, file) etisserant@163: file.close() etisserant@163: edouard@512: return [(Gen_OD_path,local_canfestival_config.getCFLAGS(CanFestivalPath))],"",False etisserant@12: smarteh-dev@682: def LoadPrevious(self): smarteh-dev@682: self.Manager.LoadCurrentPrevious() smarteh-dev@682: smarteh-dev@682: def LoadNext(self): smarteh-dev@682: self.Manager.LoadCurrentNext() smarteh-dev@682: smarteh-dev@682: def GetBufferState(self): smarteh-dev@682: return self.Manager.GetCurrentBufferState() smarteh-dev@682: etisserant@13: class RootClass: etisserant@12: XSD = """ etisserant@12: etisserant@12: etisserant@12: laurent@411: greg@157: etisserant@12: etisserant@12: etisserant@12: laurent@411: """ % DEFAULT_SETTINGS laurent@411: Edouard@718: CTNChildrenTypes = [("CanOpenNode",_NodeListCTN, "CanOpen Master"), Edouard@718: ("CanOpenSlave",_SlaveCTN, "CanOpen Slave")] greg@95: def GetParamsAttributes(self, path = None): Edouard@717: infos = ConfigTreeNode.GetParamsAttributes(self, path = None) greg@95: for element in infos: etisserant@163: if element["name"] == "CanFestivalInstance": greg@95: for child in element["children"]: greg@95: if child["name"] == "CAN_Driver": edouard@512: DLL_LIST= getattr(local_canfestival_config,"DLL_LIST",None) greg@95: if DLL_LIST is not None: smarteh-dev@682: child["type"] = DLL_LIST greg@95: return infos smarteh-dev@682: smarteh-dev@682: def GetCanDriver(self): smarteh-dev@682: can_driver = self.CanFestivalInstance.getCAN_Driver() smarteh-dev@682: if sys.platform == 'win32': smarteh-dev@682: if self.CanFestivalInstance.getDebug_mode() and os.path.isfile(os.path.join("%s"%(can_driver + '_DEBUG.dll'))): smarteh-dev@682: can_driver += '_DEBUG.dll' smarteh-dev@682: else: smarteh-dev@682: can_driver += '.dll' smarteh-dev@682: return can_driver smarteh-dev@682: Edouard@718: def CTNGenerate_C(self, buildpath, locations): etisserant@52: etisserant@52: format_dict = {"locstr" : "_".join(map(str,self.GetCurrentLocation())), smarteh-dev@682: "candriver" : self.GetCanDriver(), etisserant@52: "nodes_includes" : "", etisserant@52: "board_decls" : "", etisserant@52: "nodes_init" : "", etisserant@52: "nodes_open" : "", greg@336: "nodes_stop" : "", etisserant@57: "nodes_close" : "", etisserant@57: "nodes_send_sync" : "", etisserant@169: "nodes_proceed_sync" : "", etisserant@174: "slavebootups" : "", etisserant@178: "slavebootup_register" : "", etisserant@178: "post_sync" : "", etisserant@178: "post_sync_register" : "", Edouard@778: "pre_op" : "", Edouard@778: "pre_op_register" : "", etisserant@178: } Edouard@718: for child in self.IECSortedChildren(): etisserant@52: childlocstr = "_".join(map(str,child.GetCurrentLocation())) etisserant@52: nodename = "OD_%s" % childlocstr etisserant@166: etisserant@166: # Try to get Slave Node etisserant@166: child_data = getattr(child, "CanFestivalSlaveNode", None) etisserant@166: if child_data is None: etisserant@166: # Not a slave -> master etisserant@166: child_data = getattr(child, "CanFestivalNode") etisserant@169: # Apply sync setting etisserant@178: format_dict["nodes_init"] += 'NODE_MASTER_INIT(%s, %s)\n '%( etisserant@178: nodename, etisserant@178: child_data.getNodeId()) etisserant@166: if child_data.getSync_TPDOs(): etisserant@166: format_dict["nodes_send_sync"] += 'NODE_SEND_SYNC(%s)\n '%(nodename) etisserant@166: format_dict["nodes_proceed_sync"] += 'NODE_PROCEED_SYNC(%s)\n '%(nodename) etisserant@178: etisserant@178: # initialize and declare node boot status variables for post_SlaveBootup lookup etisserant@169: SlaveIDs = child.GetSlaveIDs() smarteh-dev@682: if len(SlaveIDs) == 0: smarteh-dev@682: # define post_SlaveBootup lookup functions etisserant@178: format_dict["slavebootups"] += ( smarteh-dev@682: "static void %s_post_SlaveBootup(CO_Data* d, UNS8 nodeId){}\n"%(nodename)) smarteh-dev@682: else: etisserant@178: format_dict["slavebootups"] += ( smarteh-dev@682: "static void %s_post_SlaveBootup(CO_Data* d, UNS8 nodeId){\n"%(nodename)+ Edouard@776: " check_and_start_node(d, nodeId);\n"+ smarteh-dev@682: "}\n") etisserant@178: # register previously declared func as post_SlaveBootup callback for that node etisserant@178: format_dict["slavebootup_register"] += ( etisserant@178: "%s_Data.post_SlaveBootup = %s_post_SlaveBootup;\n"%(nodename,nodename)) Edouard@779: format_dict["pre_op"] += ( Edouard@779: "static void %s_preOperational(CO_Data* d){\n "%(nodename)+ Edouard@779: "".join([" masterSendNMTstateChange(d, %d, NMT_Reset_Comunication);\n"%NdId for NdId in SlaveIDs])+ Edouard@779: "}\n") Edouard@779: format_dict["pre_op_register"] += ( Edouard@779: "%s_Data.preOperational = %s_preOperational;\n"%(nodename,nodename)) etisserant@178: else: etisserant@178: # Slave node etisserant@178: align = child_data.getSync_Align() etisserant@203: align_ratio=child_data.getSync_Align_Ratio() etisserant@178: if align > 0: etisserant@178: format_dict["post_sync"] += ( etisserant@178: "static int %s_CalCount = 0;\n"%(nodename)+ etisserant@178: "static void %s_post_sync(CO_Data* d){\n"%(nodename)+ etisserant@178: " if(%s_CalCount < %d){\n"%(nodename, align)+ etisserant@178: " %s_CalCount++;\n"%(nodename)+ etisserant@203: " align_tick(-1);\n"+ etisserant@178: " }else{\n"+ etisserant@203: " align_tick(%d);\n"%(align_ratio)+ etisserant@178: " }\n"+ etisserant@178: "}\n") etisserant@178: format_dict["post_sync_register"] += ( etisserant@178: "%s_Data.post_sync = %s_post_sync;\n"%(nodename,nodename)) etisserant@178: format_dict["nodes_init"] += 'NODE_SLAVE_INIT(%s, %s)\n '%( etisserant@178: nodename, etisserant@178: child_data.getNodeId()) etisserant@178: etisserant@178: # Include generated OD headers etisserant@52: format_dict["nodes_includes"] += '#include "%s.h"\n'%(nodename) etisserant@178: # Declare CAN channels according user filled config etisserant@52: format_dict["board_decls"] += 'BOARD_DECL(%s, "%s", "%s")\n'%( etisserant@52: nodename, smarteh-dev@682: child.GetCanDevice(), etisserant@166: child_data.getCAN_Baudrate()) etisserant@57: format_dict["nodes_open"] += 'NODE_OPEN(%s)\n '%(nodename) etisserant@57: format_dict["nodes_close"] += 'NODE_CLOSE(%s)\n '%(nodename) smarteh-dev@682: format_dict["nodes_stop"] += 'NODE_STOP(%s)\n '%(nodename) greg@157: etisserant@52: filename = os.path.join(os.path.split(__file__)[0],"cf_runtime.c") etisserant@52: cf_main = open(filename).read() % format_dict etisserant@52: cf_main_path = os.path.join(buildpath, "CF_%(locstr)s.c"%format_dict) etisserant@52: f = open(cf_main_path,'w') etisserant@52: f.write(cf_main) etisserant@52: f.close() etisserant@52: edouard@512: return [(cf_main_path, local_canfestival_config.getCFLAGS(CanFestivalPath))],local_canfestival_config.getLDFLAGS(CanFestivalPath), True edouard@512: edouard@512: