andrej@1511: #!/usr/bin/env python andrej@1511: # -*- coding: utf-8 -*- andrej@1511: andrej@1511: # This file is part of Beremiz, a Integrated Development Environment for andrej@1511: # programming IEC 61131-3 automates supporting plcopen standard and CanFestival. andrej@1511: # andrej@1511: # Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD andrej@1680: # Copyright (C) 2017: Andrey Skvortsov andrej@1511: # andrej@1511: # See COPYING file for copyrights details. andrej@1511: # andrej@1511: # This program is free software; you can redistribute it and/or andrej@1511: # modify it under the terms of the GNU General Public License andrej@1511: # as published by the Free Software Foundation; either version 2 andrej@1511: # of the License, or (at your option) any later version. andrej@1511: # andrej@1511: # This program is distributed in the hope that it will be useful, andrej@1511: # but WITHOUT ANY WARRANTY; without even the implied warranty of andrej@1511: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the andrej@1511: # GNU General Public License for more details. andrej@1511: # andrej@1511: # You should have received a copy of the GNU General Public License andrej@1511: # along with this program; if not, write to the Free Software andrej@1511: # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. andrej@1511: andrej@1732: import os andrej@1732: import sys andrej@1732: import shutil andrej@1732: andrej@1680: import util.paths as paths andrej@1680: andrej@1680: base_folder = paths.AbsParentDir(__file__, 2) 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 andrej@1732: import config_utils andrej@1732: import gen_cfile andrej@1732: import eds_utils edouard@512: import canfestival_config as local_canfestival_config Edouard@725: from ConfigTreeNode import ConfigTreeNode etisserant@169: from commondialogs import CreateNodeDialog Laurent@1003: from subindextable import IECTypeConversion, SizeConversion Laurent@1003: Laurent@1003: from PLCControler import LOCATION_CONFNODE, LOCATION_MODULE, LOCATION_GROUP, LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY 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: andrej@1782: # -------------------------------------------------- Laurent@1003: # Location Tree Helper andrej@1782: # -------------------------------------------------- Laurent@1003: andrej@1736: Laurent@1003: def GetSlaveLocationTree(slave_node, current_location, name): Laurent@1003: entries = [] Laurent@1003: for index, subindex, size, entry_name in slave_node.GetMapVariableList(): Laurent@1003: subentry_infos = slave_node.GetSubentryInfos(index, subindex) Laurent@1003: typeinfos = slave_node.GetEntryInfos(subentry_infos["type"]) Laurent@1003: if typeinfos: Laurent@1003: entries.append({ Laurent@1003: "name": "0x%4.4x-0x%2.2x: %s" % (index, subindex, entry_name), Laurent@1003: "type": LOCATION_VAR_MEMORY, Laurent@1003: "size": size, Laurent@1003: "IEC_type": IECTypeConversion.get(typeinfos["name"]), Laurent@1003: "var_name": "%s_%4.4x_%2.2x" % ("_".join(name.split()), index, subindex), andrej@1734: "location": "%s%s" % (SizeConversion[size], ".".join(map(str, current_location + andrej@1767: (index, subindex)))), Laurent@1003: "description": "", Laurent@1003: "children": []}) andrej@1738: return {"name": name, andrej@1738: "type": LOCATION_CONFNODE, andrej@1738: "location": ".".join([str(i) for i in current_location]) + ".x", andrej@1773: "children": entries} Laurent@1003: andrej@1782: # -------------------------------------------------- etisserant@163: # SLAVE andrej@1782: # -------------------------------------------------- etisserant@163: andrej@1736: Edouard@718: class _SlaveCTN(NodeManager): etisserant@12: XSD = """ etisserant@12: etisserant@166: etisserant@12: Edouard@960: Edouard@960: Edouard@960: etisserant@178: etisserant@203: etisserant@203: etisserant@203: etisserant@203: etisserant@203: etisserant@203: etisserant@203: etisserant@203: etisserant@12: etisserant@12: etisserant@12: Edouard@960: """ andrej@1730: 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() andrej@1737: self.CreateNewNode(name, # Name - will be changed at build time andrej@1737: id, # NodeID - will be changed at build time andrej@1737: "slave", # Type andrej@1737: description, # description andrej@1737: profile, # profile andrej@1737: filepath, # prfile filepath andrej@1737: NMT, # NMT andrej@1737: 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 andrej@1730: "", # description etisserant@169: "None", # profile andrej@1737: "", # prfile filepath etisserant@169: "heartbeat", # NMT etisserant@169: []) # options etisserant@169: dialog.Destroy() Edouard@718: self.OnCTNSave() smarteh-dev@682: laurent@845: def GetCurrentNodeName(self): laurent@845: return self.CTNName() laurent@845: 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): Laurent@948: 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 andrej@1730: laurent@777: def _ExportSlave(self): andrej@1730: dialog = wx.FileDialog(self.GetCTRoot().AppFrame, andrej@1730: _("Choose a file"), andrej@1730: os.path.expanduser("~"), andrej@1730: "%s.eds" % self.CTNName(), laurent@847: _("EDS files (*.eds)|*.eds|All files|*.*"), andrej@1745: 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")) andrej@1730: dialog.Destroy() andrej@1730: Edouard@717: ConfNodeMethods = [ andrej@1739: { andrej@1739: "bitmap": "ExportSlave", andrej@1739: "name": _("Export slave"), andrej@1739: "tooltip": _("Export CanOpen slave to EDS file"), andrej@1739: "method": "_ExportSlave" andrej@1739: }, lbessard@65: ] andrej@1730: Edouard@718: def CTNTestModified(self): etisserant@166: return self.ChangesToSave or self.OneFileHasChanged() andrej@1730: Laurent@1061: def OnCTNSave(self, from_project_path=None): 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) andrej@1730: 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()) andrej@1730: smarteh-dev@682: return result andrej@1730: Laurent@1003: def GetVariableLocationTree(self): Laurent@1003: current_location = self.GetCurrentLocation() andrej@1730: return GetSlaveLocationTree(self.CurrentNode, andrej@1730: self.GetCurrentLocation(), Laurent@1003: self.BaseParams.getName()) andrej@1730: 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)) andrej@1746: 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() andrej@1734: 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) andrej@1739: if res: andrej@1765: raise Exception(res) andrej@1734: res = eds_utils.GenerateEDSFile(os.path.join(buildpath, "Slave_%s.eds" % prefix), slave) andrej@1739: if res: andrej@1765: raise Exception(res) andrej@1740: return [(Gen_OD_path, local_canfestival_config.getCFLAGS(CanFestivalPath))], "", False etisserant@163: smarteh-dev@682: def LoadPrevious(self): smarteh-dev@682: self.LoadCurrentPrevious() andrej@1730: smarteh-dev@682: def LoadNext(self): smarteh-dev@682: self.LoadCurrentNext() andrej@1730: smarteh-dev@682: def GetBufferState(self): smarteh-dev@682: return self.GetCurrentBufferState() smarteh-dev@682: andrej@1782: # -------------------------------------------------- etisserant@163: # MASTER andrej@1782: # -------------------------------------------------- etisserant@163: andrej@1736: smarteh-dev@682: class MiniNodeManager(NodeManager): andrej@1730: smarteh-dev@682: def __init__(self, parent, filepath, fullname): smarteh-dev@682: NodeManager.__init__(self) andrej@1730: smarteh-dev@682: self.OpenFileInCurrent(filepath) andrej@1730: smarteh-dev@682: self.Parent = parent smarteh-dev@682: self.Fullname = fullname andrej@1730: laurent@781: def GetIconName(self): laurent@777: return None andrej@1730: smarteh-dev@682: def OnCloseEditor(self, view): smarteh-dev@682: self.Parent.OnCloseEditor(view) andrej@1730: Edouard@718: def CTNFullName(self): smarteh-dev@682: return self.Fullname andrej@1730: laurent@777: def CTNTestModified(self): laurent@777: return False andrej@1730: smarteh-dev@682: def GetBufferState(self): smarteh-dev@682: return self.GetCurrentBufferState() andrej@1730: laurent@774: ConfNodeMethods = [] laurent@774: andrej@1736: laurent@845: class _NodeManager(NodeManager): laurent@845: laurent@845: def __init__(self, parent, *args, **kwargs): laurent@845: NodeManager.__init__(self, *args, **kwargs) laurent@845: self.Parent = parent andrej@1730: laurent@845: def __del__(self): laurent@845: self.Parent = None andrej@1730: laurent@845: def GetCurrentNodeName(self): laurent@845: return self.Parent.CTNName() andrej@1730: laurent@845: def GetCurrentNodeID(self): laurent@845: return self.Parent.CanFestivalNode.getNodeId() andrej@1730: andrej@1736: Edouard@718: class _NodeListCTN(NodeList): etisserant@163: XSD = """ etisserant@163: etisserant@163: etisserant@163: Edouard@960: Edouard@960: Edouard@960: etisserant@163: etisserant@163: etisserant@163: etisserant@163: andrej@1730: """ andrej@1730: smarteh-dev@682: EditorType = NetworkEditor laurent@738: IconPath = os.path.join(CanFestivalPath, "objdictgen", "networkedit.png") andrej@1730: etisserant@163: def __init__(self): laurent@845: manager = _NodeManager(self) smarteh-dev@682: NodeList.__init__(self, manager) Edouard@718: self.LoadProject(self.CTNPath()) smarteh-dev@682: self.SetNetworkName(self.BaseParams.getName()) andrej@1730: smarteh-dev@682: def GetCanDevice(self): Laurent@948: return self.CanFestivalNode.getCAN_Device() andrej@1730: smarteh-dev@682: def SetParamsAttribute(self, path, value): laurent@845: if path == "CanFestivalNode.NodeId": laurent@845: nodeid = self.CanFestivalNode.getNodeId() laurent@845: if value != nodeid: laurent@845: slaves = self.GetSlaveIDs() laurent@845: dir = (value - nodeid) / abs(value - nodeid) laurent@845: while value in slaves and value >= 0: laurent@845: value += dir laurent@845: if value < 0: laurent@845: value = nodeid andrej@1730: laurent@845: value, refresh = ConfigTreeNode.SetParamsAttribute(self, path, value) laurent@845: refresh_network = False andrej@1730: 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) laurent@845: refresh_network = True laurent@845: elif path == "CanFestivalNode.NodeId": laurent@845: refresh_network = True andrej@1730: laurent@845: if refresh_network and self._View is not None: laurent@845: wx.CallAfter(self._View.RefreshBufferState) laurent@845: return value, refresh andrej@1730: Laurent@1003: def GetVariableLocationTree(self): Laurent@1003: current_location = self.GetCurrentLocation() Laurent@1003: nodeindexes = self.SlaveNodes.keys() Laurent@1003: nodeindexes.sort() andrej@1767: children = [] andrej@1767: children += [GetSlaveLocationTree(self.Manager.GetCurrentNodeCopy(), andrej@1767: current_location, andrej@1767: _("Local entries"))] andrej@1767: children += [GetSlaveLocationTree(self.SlaveNodes[nodeid]["Node"], andrej@1767: current_location + (nodeid,), andrej@1767: self.SlaveNodes[nodeid]["Name"]) for nodeid in nodeindexes] andrej@1767: andrej@1767: return { andrej@1767: "name": self.BaseParams.getName(), andrej@1767: "type": LOCATION_CONFNODE, andrej@1767: "location": self.GetFullIEC_Channel(), andrej@1767: "children": children Laurent@1003: } andrej@1730: laurent@774: _GeneratedMasterView = None andrej@1751: laurent@774: def _ShowGeneratedMaster(self): laurent@774: self._OpenView("Generated master") andrej@1730: 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 andrej@1730: 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 andrej@1730: laurent@847: manager = MiniNodeManager(self, masterpath, self.CTNFullName()) laurent@847: self._GeneratedMasterView = MasterViewer(app_frame.TabsOpened, manager, app_frame, name) andrej@1730: laurent@784: if self._GeneratedMasterView is not None: laurent@847: app_frame.EditProjectElement(self._GeneratedMasterView, self._GeneratedMasterView.GetInstancePath()) andrej@1730: 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 andrej@1730: Edouard@717: ConfNodeMethods = [ andrej@1739: { andrej@1739: "bitmap": "ShowMaster", andrej@1739: "name": _("Show Master"), andrej@1739: "tooltip": _("Show Master generated by config_utils"), andrej@1739: "method": "_ShowGeneratedMaster" andrej@1739: } etisserant@163: ] andrej@1730: smarteh-dev@682: def OnCloseEditor(self, view): Edouard@717: ConfigTreeNode.OnCloseEditor(self, view) laurent@774: if self._GeneratedMasterView == view: laurent@774: self._GeneratedMasterView = None andrej@1730: 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() andrej@1730: Laurent@1061: def OnCTNSave(self, from_project_path=None): Edouard@718: self.SetRoot(self.CTNPath()) Laurent@1063: if from_project_path is not None: andrej@1730: shutil.copytree(self.GetEDSFolder(from_project_path), Laurent@1063: self.GetEDSFolder()) 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)) andrej@1746: 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: andrej@1740: master, pointers = config_utils.GenerateConciseDCF(locations, current_location, self, self.CanFestivalNode.getSync_TPDOs(), "OD_%s" % prefix) greg@341: except config_utils.PDOmappingException, e: andrej@1765: raise Exception(e.message) etisserant@166: # Do generate C file. etisserant@163: res = gen_cfile.GenerateFile(Gen_OD_path, master, pointers) andrej@1739: if res: andrej@1765: raise Exception(res) andrej@1730: etisserant@163: file = open(os.path.join(buildpath, "MasterGenerated.od"), "w") etisserant@163: dump(master, file) etisserant@163: file.close() andrej@1730: andrej@1740: return [(Gen_OD_path, local_canfestival_config.getCFLAGS(CanFestivalPath))], "", False andrej@1730: smarteh-dev@682: def LoadPrevious(self): smarteh-dev@682: self.Manager.LoadCurrentPrevious() andrej@1730: smarteh-dev@682: def LoadNext(self): smarteh-dev@682: self.Manager.LoadCurrentNext() andrej@1730: smarteh-dev@682: def GetBufferState(self): smarteh-dev@682: return self.Manager.GetCurrentBufferState() andrej@1730: andrej@1736: etisserant@13: class RootClass: etisserant@12: XSD = """ etisserant@12: etisserant@12: etisserant@12: Edouard@960: etisserant@12: etisserant@12: etisserant@12: Edouard@960: """ andrej@1730: andrej@1740: CTNChildrenTypes = [("CanOpenNode", _NodeListCTN, "CanOpen Master"), andrej@1746: ("CanOpenSlave", _SlaveCTN, "CanOpen Slave")] andrej@1751: andrej@1744: def GetParamsAttributes(self, path=None): andrej@1744: infos = ConfigTreeNode.GetParamsAttributes(self, path=path) 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@960: child["type"] = local_canfestival_config.DLL_LIST greg@95: return infos andrej@1730: Laurent@974: def GetCanDriver(self): Edouard@976: res = self.CanFestivalInstance.getCAN_Driver() andrej@1739: if not res: Edouard@976: return "" Edouard@976: return res andrej@1730: Laurent@974: def CTNGenerate_C(self, buildpath, locations): Edouard@976: can_driver = self.GetCanDriver() Edouard@976: if can_driver is not None: Edouard@976: can_drivers = local_canfestival_config.DLL_LIST andrej@1739: if can_driver not in can_drivers: Edouard@976: can_driver = can_drivers[0] Edouard@976: can_drv_ext = self.GetCTRoot().GetBuilder().extension Edouard@1279: can_drv_prefix = self.GetCTRoot().GetBuilder().dlopen_prefix Edouard@1279: can_driver_name = can_drv_prefix + "libcanfestival_" + can_driver + can_drv_ext Edouard@976: else: Edouard@976: can_driver_name = "" Edouard@976: andrej@1740: format_dict = {"locstr": "_".join(map(str, self.GetCurrentLocation())), andrej@1739: "candriver": can_driver_name, andrej@1739: "nodes_includes": "", andrej@1739: "board_decls": "", andrej@1739: "nodes_init": "", andrej@1739: "nodes_open": "", andrej@1739: "nodes_stop": "", andrej@1739: "nodes_close": "", andrej@1739: "nodes_send_sync": "", andrej@1739: "nodes_proceed_sync": "", andrej@1739: "slavebootups": "", andrej@1739: "slavebootup_register": "", andrej@1739: "post_sync": "", andrej@1739: "post_sync_register": "", andrej@1739: "pre_op": "", andrej@1739: "pre_op_register": "", etisserant@178: } Edouard@718: for child in self.IECSortedChildren(): andrej@1740: childlocstr = "_".join(map(str, child.GetCurrentLocation())) etisserant@52: nodename = "OD_%s" % childlocstr andrej@1730: 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 andrej@1734: 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(): andrej@1734: format_dict["nodes_send_sync"] += 'NODE_SEND_SYNC(%s)\n ' % (nodename) andrej@1734: 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"] += ( andrej@1734: "static void %s_post_SlaveBootup(CO_Data* d, UNS8 nodeId){}\n" % (nodename)) smarteh-dev@682: else: etisserant@178: format_dict["slavebootups"] += ( andrej@1742: "static void %s_post_SlaveBootup(CO_Data* d, UNS8 nodeId){\n" % (nodename) + andrej@1742: " 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"] += ( andrej@1740: "%s_Data.post_SlaveBootup = %s_post_SlaveBootup;\n" % (nodename, nodename)) Edouard@779: format_dict["pre_op"] += ( andrej@1742: "static void %s_preOperational(CO_Data* d){\n " % (nodename) + andrej@1742: "".join([" masterSendNMTstateChange(d, %d, NMT_Reset_Comunication);\n" % NdId for NdId in SlaveIDs]) + Edouard@779: "}\n") Edouard@779: format_dict["pre_op_register"] += ( andrej@1740: "%s_Data.preOperational = %s_preOperational;\n" % (nodename, nodename)) etisserant@178: else: etisserant@178: # Slave node etisserant@178: align = child_data.getSync_Align() andrej@1742: align_ratio = child_data.getSync_Align_Ratio() etisserant@178: if align > 0: etisserant@178: format_dict["post_sync"] += ( andrej@1742: "static int %s_CalCount = 0;\n" % (nodename) + andrej@1742: "static void %s_post_sync(CO_Data* d){\n" % (nodename) + andrej@1742: " if(%s_CalCount < %d){\n" % (nodename, align) + andrej@1742: " %s_CalCount++;\n" % (nodename) + andrej@1742: " align_tick(-1);\n" + andrej@1742: " }else{\n" + andrej@1742: " align_tick(%d);\n" % (align_ratio) + andrej@1742: " }\n" + etisserant@178: "}\n") etisserant@178: format_dict["post_sync_register"] += ( andrej@1740: "%s_Data.post_sync = %s_post_sync;\n" % (nodename, nodename)) andrej@1734: format_dict["nodes_init"] += 'NODE_SLAVE_INIT(%s, %s)\n ' % ( etisserant@178: nodename, etisserant@178: child_data.getNodeId()) andrej@1730: etisserant@178: # Include generated OD headers andrej@1734: format_dict["nodes_includes"] += '#include "%s.h"\n' % (nodename) etisserant@178: # Declare CAN channels according user filled config andrej@1734: format_dict["board_decls"] += 'BOARD_DECL(%s, "%s", "%s")\n' % ( etisserant@52: nodename, smarteh-dev@682: child.GetCanDevice(), etisserant@166: child_data.getCAN_Baudrate()) andrej@1734: format_dict["nodes_open"] += 'NODE_OPEN(%s)\n ' % (nodename) andrej@1734: format_dict["nodes_close"] += 'NODE_CLOSE(%s)\n ' % (nodename) andrej@1734: format_dict["nodes_stop"] += 'NODE_STOP(%s)\n ' % (nodename) andrej@1730: andrej@1740: filename = paths.AbsNeighbourFile(__file__, "cf_runtime.c") etisserant@52: cf_main = open(filename).read() % format_dict andrej@1734: cf_main_path = os.path.join(buildpath, "CF_%(locstr)s.c" % format_dict) andrej@1740: f = open(cf_main_path, 'w') etisserant@52: f.write(cf_main) etisserant@52: f.close() Edouard@957: andrej@1740: res = [(cf_main_path, local_canfestival_config.getCFLAGS(CanFestivalPath))], local_canfestival_config.getLDFLAGS(CanFestivalPath), True andrej@1730: Edouard@976: if can_driver is not None: andrej@1740: can_driver_path = os.path.join(CanFestivalPath, "drivers", can_driver, can_driver_name) Laurent@974: if os.path.exists(can_driver_path): andrej@1740: res += ((can_driver_name, file(can_driver_path, "rb")),) Edouard@957: Edouard@957: return res