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: 
Laurent@1061: import os, sys, shutil
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
etisserant@178: import config_utils, gen_cfile, 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: 
etisserant@163: #--------------------------------------------------
Laurent@1003: #              Location Tree Helper
Laurent@1003: #--------------------------------------------------
Laurent@1003: 
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),
Laurent@1003:                 "location": "%s%s"%(SizeConversion[size], ".".join(map(str, current_location + 
Laurent@1003:                                                                                 (index, subindex)))),
Laurent@1003:                 "description": "",
Laurent@1003:                 "children": []})
Laurent@1003:     return  {"name": name,
Laurent@1003:              "type": LOCATION_CONFNODE,
Laurent@1003:              "location": ".".join([str(i) for i in current_location]) + ".x",
Laurent@1003:              "children": entries
Laurent@1003:     }
Laurent@1003: 
Laurent@1003: #--------------------------------------------------
etisserant@163: #                    SLAVE
etisserant@163: #--------------------------------------------------
etisserant@163: 
Edouard@718: class _SlaveCTN(NodeManager):
etisserant@12:     XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
etisserant@12:     <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
etisserant@166:       <xsd:element name="CanFestivalSlaveNode">
etisserant@12:         <xsd:complexType>
Edouard@960:           <xsd:attribute name="CAN_Device" type="xsd:string" use="optional"/>
Edouard@960:           <xsd:attribute name="CAN_Baudrate" type="xsd:string" use="optional"/>
Edouard@960:           <xsd:attribute name="NodeId" type="xsd:integer" use="optional" default="2"/>
etisserant@178:           <xsd:attribute name="Sync_Align" type="xsd:integer" use="optional" default="0"/>
etisserant@203:           <xsd:attribute name="Sync_Align_Ratio" use="optional" default="50">
etisserant@203:             <xsd:simpleType>
etisserant@203:                 <xsd:restriction base="xsd:integer">
etisserant@203:                     <xsd:minInclusive value="1"/>
etisserant@203:                     <xsd:maxInclusive value="99"/>
etisserant@203:                 </xsd:restriction>
etisserant@203:             </xsd:simpleType>
etisserant@203:           </xsd:attribute>
etisserant@12:         </xsd:complexType>
etisserant@12:       </xsd:element>
etisserant@12:     </xsd:schema>
Edouard@960:     """
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: 
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
laurent@777:     
laurent@777:     def _ExportSlave(self):
laurent@847:         dialog = wx.FileDialog(self.GetCTRoot().AppFrame, 
laurent@847:                                _("Choose a file"), 
laurent@847:                                os.path.expanduser("~"), 
laurent@847:                                "%s.eds" % self.CTNName(),  
laurent@847:                                _("EDS files (*.eds)|*.eds|All files|*.*"),
laurent@847:                                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:         
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)
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
Laurent@1003:     
Laurent@1003:     def GetVariableLocationTree(self):
Laurent@1003:         current_location = self.GetCurrentLocation()
Laurent@1003:         return GetSlaveLocationTree(self.CurrentNode, 
Laurent@1003:                                     self.GetCurrentLocation(), 
Laurent@1003:                                     self.BaseParams.getName())
Laurent@1003:     
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: 
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
laurent@845:         
laurent@845:     def __del__(self):
laurent@845:         self.Parent = None
laurent@845:         
laurent@845:     def GetCurrentNodeName(self):
laurent@845:         return self.Parent.CTNName()
laurent@845:     
laurent@845:     def GetCurrentNodeID(self):
laurent@845:         return self.Parent.CanFestivalNode.getNodeId()
laurent@845:     
Edouard@718: class _NodeListCTN(NodeList):
etisserant@163:     XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
etisserant@163:     <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
etisserant@163:       <xsd:element name="CanFestivalNode">
etisserant@163:         <xsd:complexType>
Edouard@960:           <xsd:attribute name="CAN_Device" type="xsd:string" use="optional"/>
Edouard@960:           <xsd:attribute name="CAN_Baudrate" type="xsd:string" use="optional"/>
Edouard@960:           <xsd:attribute name="NodeId" type="xsd:integer" use="optional" default="1"/>
etisserant@163:           <xsd:attribute name="Sync_TPDOs" type="xsd:boolean" use="optional" default="true"/>
etisserant@163:         </xsd:complexType>
etisserant@163:       </xsd:element>
etisserant@163:     </xsd:schema>
Edouard@960:     """ 
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):
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())
smarteh-dev@682:     
smarteh-dev@682:     def GetCanDevice(self):
Laurent@948:         return self.CanFestivalNode.getCAN_Device()
smarteh-dev@682:     
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
laurent@845:         
laurent@845:         value, refresh = ConfigTreeNode.SetParamsAttribute(self, path, value)
laurent@845:         refresh_network = False
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)
laurent@845:             refresh_network = True
laurent@845:         elif path == "CanFestivalNode.NodeId":
laurent@845:             refresh_network = True
laurent@845:             
laurent@845:         if refresh_network and self._View is not None:
laurent@845:             wx.CallAfter(self._View.RefreshBufferState)
laurent@845:         return value, refresh
Laurent@1003:     
Laurent@1003:     def GetVariableLocationTree(self):
Laurent@1003:         current_location = self.GetCurrentLocation()
Laurent@1003:         nodeindexes = self.SlaveNodes.keys()
Laurent@1003:         nodeindexes.sort()
Laurent@1003:         return {"name": self.BaseParams.getName(),
Laurent@1003:                  "type": LOCATION_CONFNODE,
Laurent@1003:                  "location": self.GetFullIEC_Channel(),
Laurent@1003:                  "children": [GetSlaveLocationTree(self.Manager.GetCurrentNodeCopy(),
Laurent@1003:                                                    current_location,
Laurent@1003:                                                    _("Local entries"))] + 
Laurent@1003:                              [GetSlaveLocationTree(self.SlaveNodes[nodeid]["Node"], 
Laurent@1003:                                                    current_location + (nodeid,), 
Laurent@1003:                                                    self.SlaveNodes[nodeid]["Name"])
Laurent@1003:                               for nodeid in nodeindexes]
Laurent@1003:         }
Laurent@1003:     
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@847:                 manager = MiniNodeManager(self, masterpath, self.CTNFullName())
laurent@847:                 self._GeneratedMasterView = MasterViewer(app_frame.TabsOpened, manager, app_frame, name)
laurent@774:                 
laurent@784:             if self._GeneratedMasterView is not None:
laurent@847:                 app_frame.EditProjectElement(self._GeneratedMasterView, self._GeneratedMasterView.GetInstancePath())
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:         
Laurent@1061:     def OnCTNSave(self, from_project_path=None):
Edouard@718:         self.SetRoot(self.CTNPath())
Laurent@1063:         if from_project_path is not None:
Laurent@1063:             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))
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 = """<?xml version="1.0" encoding="ISO-8859-1" ?>
etisserant@12:     <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
etisserant@12:       <xsd:element name="CanFestivalInstance">
etisserant@12:         <xsd:complexType>
Edouard@960:           <xsd:attribute name="CAN_Driver" type="xsd:string" use="optional"/>
etisserant@12:         </xsd:complexType>
etisserant@12:       </xsd:element>
etisserant@12:     </xsd:schema>
Edouard@960:     """
laurent@411:     
Edouard@718:     CTNChildrenTypes = [("CanOpenNode",_NodeListCTN, "CanOpen Master"),
Edouard@718:                        ("CanOpenSlave",_SlaveCTN, "CanOpen Slave")]
greg@95:     def GetParamsAttributes(self, path = None):
Edouard@960:         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
smarteh-dev@682:     
Laurent@974:     def GetCanDriver(self):
Edouard@976:         res = self.CanFestivalInstance.getCAN_Driver()
Edouard@976:         if not res :
Edouard@976:             return ""
Edouard@976:         return res
Laurent@974:         
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
Edouard@976:             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: 
etisserant@52:         
etisserant@52:         format_dict = {"locstr" : "_".join(map(str,self.GetCurrentLocation())),
Edouard@960:                        "candriver" : can_driver_name,
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:         
andrej@1680:         filename = paths.AbsNeighbourFile(__file__,"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()
Edouard@957: 
Edouard@957:         res = [(cf_main_path, local_canfestival_config.getCFLAGS(CanFestivalPath))],local_canfestival_config.getLDFLAGS(CanFestivalPath), True
Laurent@974:         
Edouard@976:         if can_driver is not None:
Laurent@974:             can_driver_path = os.path.join(CanFestivalPath,"drivers",can_driver,can_driver_name)
Laurent@974:             if os.path.exists(can_driver_path):
Laurent@974:                 res += ((can_driver_name, file(can_driver_path,"rb")),)
Edouard@957: 
Edouard@957:         return res
Edouard@957: