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@1853: from __future__ import absolute_import
andrej@2437: from __future__ import division
andrej@1732: import os
andrej@1732: import sys
andrej@1732: import shutil
andrej@1783: import wx
Edouard@1919: from gnosis.xml.pickle import * # pylint: disable=import-error
Edouard@1919: from gnosis.xml.pickle.util import setParanoia # pylint: disable=import-error
andrej@1732:
andrej@1680: import util.paths as paths
Edouard@2736:
andrej@1783: from util.TranslationCatalogs import AddCatalog
andrej@1783: from ConfigTreeNode import ConfigTreeNode
andrej@1783: from PLCControler import \
andrej@1783: LOCATION_CONFNODE, \
andrej@1783: LOCATION_VAR_MEMORY
andrej@1783:
Edouard@2736: CanFestivalPath = paths.ThirdPartyPath("CanFestival-3") # noqa
Edouard@1997: sys.path.append(os.path.join(CanFestivalPath, "objdictgen")) # noqa
Edouard@1997:
Edouard@1997: # pylint: disable=wrong-import-position
Edouard@1979: from nodelist import NodeList
lbessard@11: from nodemanager import NodeManager
andrej@1732: import gen_cfile
andrej@1732: import eds_utils
Edouard@1919: import canfestival_config as local_canfestival_config # pylint: disable=import-error
etisserant@169: from commondialogs import CreateNodeDialog
Laurent@1003: from subindextable import IECTypeConversion, SizeConversion
andrej@1853: from canfestival import config_utils
andrej@1853: from canfestival.SlaveEditor import SlaveEditor, MasterViewer
andrej@1853: from canfestival.NetworkEditor import NetworkEditor
smarteh-dev@682:
andrej@1783:
andrej@1783: AddCatalog(os.path.join(CanFestivalPath, "objdictgen", "locale"))
lbessard@77: setParanoia(0)
lbessard@77:
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()
andrej@1828: 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:
andrej@1847: 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):
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()
andrej@2437: 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)
andrej@2418: except config_utils.PDOmappingException as 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")
Edouard@1919: # linter disabled here, undefined variable happens
Edouard@1919: # here because gnosis isn't impored while linting
Edouard@1919: dump(master, file) # pylint: disable=undefined-variable
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:
andrej@1831: class RootClass(object):
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@1878: format_dict = {
andrej@1878: "locstr": "_".join(map(str, self.GetCurrentLocation())),
andrej@1878: "candriver": can_driver_name,
andrej@1878: "nodes_includes": "",
andrej@1878: "board_decls": "",
andrej@1878: "nodes_init": "",
andrej@1878: "nodes_open": "",
andrej@1878: "nodes_stop": "",
andrej@1878: "nodes_close": "",
andrej@1878: "nodes_send_sync": "",
andrej@1878: "nodes_proceed_sync": "",
andrej@1878: "slavebootups": "",
andrej@1878: "slavebootup_register": "",
andrej@1878: "post_sync": "",
andrej@1878: "post_sync_register": "",
andrej@1878: "pre_op": "",
andrej@1878: "pre_op_register": "",
andrej@1878: }
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 ' % (
andrej@1878: nodename,
andrej@1878: 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 ' % (
andrej@1878: nodename,
andrej@1878: 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' % (
andrej@1878: nodename,
andrej@1878: child.GetCanDevice(),
andrej@1878: 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@2442: res += ((can_driver_name, open(can_driver_path, "rb")),)
Edouard@957:
Edouard@957: return res