# HG changeset patch # User etisserant # Date 1214326931 -7200 # Node ID 121b18748de0c24d54b098c1c4776a3172b733dd # Parent f9c6c9e3672515ea012112991494f168171e2910 Preliminary CANopen slave generation support diff -r f9c6c9e36725 -r 121b18748de0 plugins/canfestival/canfestival.py --- a/plugins/canfestival/canfestival.py Mon Jun 23 18:22:40 2008 +0200 +++ b/plugins/canfestival/canfestival.py Tue Jun 24 19:02:11 2008 +0200 @@ -19,17 +19,10 @@ # SLAVE #-------------------------------------------------- -class _NodeEdit(objdictedit): - " Overload some of CanFestival Node Editor methods " - def OnCloseFrame(self, event): - " Do reset _NodeListPlug.View when closed" - self._onclose() - event.Skip() - class _SlavePlug(NodeManager): XSD = """ - + @@ -40,7 +33,7 @@ """ def GetSlaveODPath(self): - os.path.join(self.PlugPath(), 'slave.od') + return os.path.join(self.PlugPath(), 'slave.od') def __init__(self): # TODO change netname when name change @@ -65,36 +58,18 @@ self._View = None def _onsave(): self.GetPlugRoot().SaveProject() - self._View = _NodeEdit(self.GetPlugRoot().AppFrame, self) + self._View = objdictedit(self.GetPlugRoot().AppFrame, self) # TODO redefine BusId when IEC channel change self._View.SetBusId(self.GetCurrentLocation()) self._View._onclose = _onclose self._View._onsave = _onsave self._View.Show() - def _ShowMasterGenerated(self, logger): - buildpath = self._getBuildPath() - # Eventually create build dir - if not os.path.exists(buildpath): - logger.write_error("Error: No PLC built\n") - return - - masterpath = os.path.join(buildpath, "MasterGenerated.od") - if not os.path.exists(masterpath): - logger.write_error("Error: No Master generated\n") - return - - new_dialog = objdictedit(None, [masterpath]) - new_dialog.Show() - PluginMethods = [ {"bitmap" : os.path.join("images", "NetworkEdit"), - "name" : "Edit network", - "tooltip" : "Edit CanOpen Network with NetworkEdit", + "name" : "Edit slave", + "tooltip" : "Edit CanOpen slave with ObjdictEdit", "method" : "_OpenView"}, - {"name" : "Show Master", - "tooltip" : "Show Master generated by config_utils", - "method" : "_ShowMasterGenerated"} ] def OnPlugClose(self): @@ -102,12 +77,10 @@ self._View.Close() def PlugTestModified(self): - return self.ChangesToSave or self.HasChanged() + return self.ChangesToSave or self.OneFileHasChanged() def OnPlugSave(self): - self.SetRoot(self.PlugPath()) - self.SaveProject() - return True + return self.SaveCurrentInFile(self.GetSlaveODPath()) def PlugGenerate_C(self, buildpath, locations, logger): """ @@ -124,31 +97,23 @@ """ current_location = self.GetCurrentLocation() # define a unique name for the generated C file - prefix = "_".join(map(lambda x:str(x), current_location)) + 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 - master = config_utils.GenerateConciseDCF(locations, current_location, self, self.CanFestivalNode.getSync_TPDOs(),"OD_%s"%prefix) - res = gen_cfile.GenerateFile(Gen_OD_path, master) + # 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 - - file = open(os.path.join(buildpath, "MasterGenerated.od"), "w") - dump(master, file) - file.close() - + self.ExportCurrentToEDSFile(os.path.join(buildpath, "Slave_%s.eds"%prefix)) return [(Gen_OD_path,canfestival_config.getCFLAGS(CanFestivalPath))],"",False #-------------------------------------------------- # MASTER #-------------------------------------------------- -class _NetworkEdit(networkedit): - " Overload some of CanFestival Network Editor methods " - def OnCloseFrame(self, event): - " Do reset _NodeListPlug.View when closed" - self._onclose() - event.Skip() - class _NodeListPlug(NodeList): XSD = """ @@ -176,7 +141,7 @@ self._View = None def _onsave(): self.GetPlugRoot().SaveProject() - self._View = _NetworkEdit(self.GetPlugRoot().AppFrame, self) + self._View = networkedit(self.GetPlugRoot().AppFrame, self) # TODO redefine BusId when IEC channel change self._View.SetBusId(self.GetCurrentLocation()) self._View._onclose = _onclose @@ -217,8 +182,7 @@ def OnPlugSave(self): self.SetRoot(self.PlugPath()) - self.SaveProject() - return True + return self.SaveProject() is not None def PlugGenerate_C(self, buildpath, locations, logger): """ @@ -235,10 +199,13 @@ """ current_location = self.GetCurrentLocation() # define a unique name for the generated C file - prefix = "_".join(map(lambda x:str(x), current_location)) + 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 master, pointers = config_utils.GenerateConciseDCF(locations, current_location, self, self.CanFestivalNode.getSync_TPDOs(),"OD_%s"%prefix) + # allow access to local OD from Master PLC + pointers.update(config_utils.LocalODPointers(locations, current_location, master)) + # Do generate C file. res = gen_cfile.GenerateFile(Gen_OD_path, master, pointers) if res : raise Exception, res @@ -288,22 +255,29 @@ 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") + 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) format_dict["nodes_includes"] += '#include "%s.h"\n'%(nodename) format_dict["board_decls"] += 'BOARD_DECL(%s, "%s", "%s")\n'%( nodename, - child.CanFestivalNode.getCAN_Device(), - child.CanFestivalNode.getCAN_Baudrate()) + child_data.getCAN_Device(), + child_data.getCAN_Baudrate()) format_dict["nodes_declare"] += 'NODE_DECLARE(%s, %s)\n '%( nodename, - child.CanFestivalNode.getNodeId()) + child_data.getNodeId()) format_dict["nodes_init"] += 'NODE_INIT(%s, %s)\n '%( nodename, - child.CanFestivalNode.getNodeId()) + child_data.getNodeId()) format_dict["nodes_open"] += 'NODE_OPEN(%s)\n '%(nodename) format_dict["nodes_close"] += 'NODE_CLOSE(%s)\n '%(nodename) - format_dict["nodes_send_sync"] += 'NODE_SEND_SYNC(%s)\n '%(nodename) - format_dict["nodes_proceed_sync"] += 'NODE_PROCEED_SYNC(%s)\n '%(nodename) if sys.platform == 'win32': if self.CanFestivalInstance.getDebug_mode() and os.path.isfile(os.path.join("%s"%(format_dict["candriver"] + '_DEBUG.dll'))): diff -r f9c6c9e36725 -r 121b18748de0 plugins/canfestival/config_utils.py --- a/plugins/canfestival/config_utils.py Mon Jun 23 18:22:40 2008 +0200 +++ b/plugins/canfestival/config_utils.py Tue Jun 24 19:02:11 2008 +0200 @@ -341,8 +341,10 @@ # Get only the part of the location that concern this node loc = location["LOC"][len(current_location):] # loc correspond to (ID, INDEX, SUBINDEX [,BIT]) - if len(loc) not in (3, 4): + if len(loc) not in (2, 3, 4): raise ValueError, "Bad location size : %s"%str(loc) + elif len(loc) == 2: + continue direction = location["DIR"] @@ -374,9 +376,8 @@ else: numbit = None - entryinfos = node.GetSubentryInfos(index, subindex) - if location["IEC_TYPE"] != "BOOL" and entryinfos["type"] != COlocationtype: - raise ValueError, "Invalid type \"%s\"-> %d != %d for location\"%s\"" % (location["IEC_TYPE"], COlocationtype, entryinfos["type"] , name) + if location["IEC_TYPE"] != "BOOL" and subentry_infos["type"] != COlocationtype: + raise ValueError, "Invalid type \"%s\"-> %d != %d for location\"%s\"" % (location["IEC_TYPE"], COlocationtype, subentry_infos["type"] , name) typeinfos = node.GetEntryInfos(COlocationtype) self.IECLocations[name] = {"type":COlocationtype, "pdotype":SlavePDOType[direction], @@ -584,6 +585,40 @@ dcfgenerator.GenerateDCF(locations, current_location, sync_TPDOs) return dcfgenerator.GetMasterNode(), dcfgenerator.GetPointedVariables() +def LocalODPointers(locations, current_location, slave): + IECLocations = {} + pointers = {} + for location in locations: + COlocationtype = IECToCOType[location["IEC_TYPE"]] + name = location["NAME"] + if name in IECLocations: + if IECLocations[name] != COlocationtype: + raise ValueError, "Conflict type for location \"%s\"" % name + else: + # Get only the part of the location that concern this node + loc = location["LOC"][len(current_location):] + # loc correspond to (ID, INDEX, SUBINDEX [,BIT]) + if len(loc) not in (2, 3, 4): + raise ValueError, "Bad location size : %s"%str(loc) + elif len(loc) != 2: + continue + + # Extract and check nodeid + index, subindex = loc[:2] + + # Extract and check index and subindex + if not slave.IsEntry(index, subindex): + raise ValueError, "No such index/subindex (%x,%x) (variable %s)" % (index, subindex, name) + + # Get the entry info + subentry_infos = slave.GetSubentryInfos(index, subindex) + if subentry_infos["type"] != COlocationtype: + raise ValueError, "Invalid type \"%s\"-> %d != %d for location\"%s\"" % (location["IEC_TYPE"], COlocationtype, subentry_infos["type"] , name) + + IECLocations[name] = COlocationtype + pointers[(index, subindex)] = name + return pointers + if __name__ == "__main__": import os, sys, getopt