etherlab/etherlab.py
changeset 2041 ce3727171207
parent 2039 3a218f6bd805
child 2042 563ccc918ded
equal deleted inserted replaced
2040:d676082c1d2f 2041:ce3727171207
     5 import wx
     5 import wx
     6 
     6 
     7 from xmlclass import *
     7 from xmlclass import *
     8 from plugger import PlugTemplate
     8 from plugger import PlugTemplate
     9 from PLCControler import UndoBuffer, LOCATION_PLUGIN, LOCATION_MODULE, LOCATION_GROUP, LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY
     9 from PLCControler import UndoBuffer, LOCATION_PLUGIN, LOCATION_MODULE, LOCATION_GROUP, LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY
    10 from ConfigEditor import ConfigEditor, DS402NodeEditor, ETHERCAT_VENDOR, ETHERCAT_GROUP, ETHERCAT_DEVICE
    10 from ConfigEditor import NodeEditor, DS402NodeEditor, ETHERCAT_VENDOR, ETHERCAT_GROUP, ETHERCAT_DEVICE
       
    11 
       
    12 try:
       
    13     from plugins.motion import Headers, AxisXSD
       
    14     HAS_MCL = True
       
    15 except:
       
    16     HAS_MCL = False
       
    17 
       
    18 
       
    19 TYPECONVERSION = {"BOOL" : "X", "SINT" : "B", "INT" : "W", "DINT" : "D", "LINT" : "L",
       
    20     "USINT" : "B", "UINT" : "W", "UDINT" : "D", "ULINT" : "L", 
       
    21     "BYTE" : "B", "WORD" : "W", "DWORD" : "D", "LWORD" : "L"}
       
    22 
       
    23 DATATYPECONVERSION = {"BOOL" : "BIT", "SINT" : "S8", "INT" : "S16", "DINT" : "S32", "LINT" : "S64",
       
    24     "USINT" : "U8", "UINT" : "U16", "UDINT" : "U32", "ULINT" : "U64", 
       
    25     "BYTE" : "U8", "WORD" : "U16", "DWORD" : "U32", "LWORD" : "U64"}
       
    26 
       
    27 VARCLASSCONVERSION = {"T": LOCATION_VAR_INPUT, "R": LOCATION_VAR_OUTPUT, "RT": LOCATION_VAR_MEMORY}
    11 
    28 
    12 #--------------------------------------------------
    29 #--------------------------------------------------
    13 #                 Ethercat DS402 Node
    30 #         Remote Exec Etherlab Commands
    14 #--------------------------------------------------
    31 #--------------------------------------------------
    15 
    32 
    16 NODE_VARIABLES = [
    33 SCAN_COMMAND = """
    17     ("ControlWord", 0x6040, 0x00, "UINT", "Q"),
    34 import commands
    18     ("TargetPosition", 0x607a, 0x00, "DINT", "Q"),
    35 result = commands.getoutput("ethercat slaves")
    19     ("StatusWord", 0x6041, 0x00, "UINT", "I"),
    36 slaves = []
    20     ("ModesOfOperationDisplay", 0x06061, 0x00, "SINT", "I"),
    37 for slave_line in result.splitlines():
    21     ("ActualPosition", 0x6064, 0x00, "DINT", "I"),
    38     chunks = slave_line.split()
    22     ("ErrorCode", 0x603f, 0x00, "UINT", "I"),
    39     idx, pos, state, flag = chunks[:4]
    23 ]
    40     name = " ".join(chunks[4:])
    24 
    41     alias, position = pos.split(":")
    25 class _EthercatDS402SlavePlug:
    42     slave = {"idx": int(idx),
    26     XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
    43              "alias": int(alias),
    27     <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    44              "position": int(position),
    28       <xsd:element name="EtherlabDS402Slave">
    45              "name": name}
    29         <xsd:complexType>
    46     details = commands.getoutput("ethercat slaves -p %d -v" % slave["idx"])
    30           <xsd:attribute name="Node_Type" type="xsd:string" use="optional"/>
    47     for details_line in details.splitlines():
    31         </xsd:complexType>
    48         details_line = details_line.strip()
    32       </xsd:element>
    49         for header, param in [("Vendor Id:", "vendor_id"),
    33     </xsd:schema>
    50                               ("Product code:", "product_code"),
    34     """
    51                               ("Revision number:", "revision_number")]:
    35     EditorType = DS402NodeEditor
    52             if details_line.startswith(header):
       
    53                 slave[param] = int(details_line.split()[-1], 16)
       
    54                 break
       
    55     slaves.append(slave)
       
    56 returnVal = slaves
       
    57 """
       
    58 
       
    59 #--------------------------------------------------
       
    60 #                    Ethercat Node
       
    61 #--------------------------------------------------
       
    62 
       
    63 class _EthercatSlavePlug:
       
    64 
       
    65     NODE_PROFILE = None
       
    66     EditorType = NodeEditor
    36     
    67     
    37     def ExtractHexDecValue(self, value):
    68     def ExtractHexDecValue(self, value):
    38         return ExtractHexDecValue(value)
    69         return ExtractHexDecValue(value)
    39 
    70     
    40     def GetSizeOfType(self, type):
    71     def GetSizeOfType(self, type):
    41         return TYPECONVERSION.get(self.GetPlugRoot().GetBaseType(type), None)
    72         return TYPECONVERSION.get(self.GetPlugRoot().GetBaseType(type), None)
    42     
    73     
    43     def _GetChildBySomething(self, something, toks):
    74     def GetSlavePos(self):
    44         return self
    75         return self.BaseParams.getIEC_Channel()
    45     
    76     
    46     def GetParamsAttributes(self, path = None):
    77     def GetParamsAttributes(self, path = None):
    47         infos = PlugTemplate.GetParamsAttributes(self, path = None)
    78         if path:
    48         for element in infos:
    79             parts = path.split(".", 1)
    49             if element["name"] == "EtherlabDS402Slave":
    80             if self.MandatoryParams and parts[0] == self.MandatoryParams[0]:
    50                 for child in element["children"]:
    81                 return self.MandatoryParams[1].getElementInfos(parts[0], parts[1])
    51                     if child["name"] == "Node_Type":
    82             elif self.PlugParams and parts[0] == self.PlugParams[0]:
    52                         child["type"] = [module[0] for module in self.PlugParent.GetModulesByProfile(402)]
    83                 return self.PlugParams[1].getElementInfos(parts[0], parts[1])
    53         return infos
    84         else:
    54     
    85             params = []
    55     def GetAllChannels(self):
    86             if wx.VERSION < (2, 8, 0) and self.MandatoryParams:
    56         AllChannels = PlugTemplate.GetAllChannels(self)
    87                 params.append(self.MandatoryParams[1].getElementInfos(self.MandatoryParams[0]))
    57         for slave_pos in self.PlugParent.GetSlaves():
    88             slave_type = self.PlugParent.GetSlaveType(self.GetSlavePos())
    58             if slave_pos[0] not in AllChannels:
    89             params.append({
    59                 AllChannels.append(slave_pos[0])
    90                 'use': 'required', 
    60         AllChannels.sort()
    91                 'type': 'element', 
    61         return AllChannels
    92                 'name': 'SlaveParams', 
    62 
    93                 'value': None, 
    63     def GetCurrentLocation(self):
    94                 'children': [{
    64         """
    95                     'use': 'optional', 
    65         @return:  Tupple containing plugin IEC location of current plugin : %I0.0.4.5 => (0,0,4,5)
    96                     'type': self.PlugParent.GetSlaveTypesLibrary(self.NODE_PROFILE), 
    66         """
    97                     'name': 'Type', 
    67         return self.PlugParent.GetCurrentLocation() + self.GetSlavePos()
    98                     'value': (slave_type["device_type"], slave_type)}, 
    68 
    99                    {'use': 'optional', 
    69     def GetSlavePos(self):
   100                     'type': 'unsignedLong', 
    70         return self.BaseParams.getIEC_Channel(), 0
   101                     'name': 'Alias', 
    71 
   102                     'value': self.PlugParent.GetSlaveAlias(self.GetSlavePos())}]
    72     def GetSlaveTypeInfos(self):
   103             })
    73         slave_type = self.EtherlabDS402Slave.getNode_Type()
   104             if self.PlugParams:
    74         
   105                 params.append(self.PlugParams[1].getElementInfos(self.PlugParams[0]))
    75         for module_type, vendor_id, product_code, revision_number in self.PlugParent.GetModulesByProfile(402):
   106             return params
    76             if module_type == slave_type:
   107         
    77                 return {"device_type": module_type,
   108     def SetParamsAttribute(self, path, value):
    78                         "vendor": GenerateHexDecValue(vendor_id),
   109         position = self.BaseParams.getIEC_Channel()
    79                         "product_code": GenerateHexDecValue(product_code, 16),
   110         value, changed = PlugTemplate.SetParamsAttribute(self, path, value)
    80                         "revision_number": GenerateHexDecValue(revision_number, 16)}
   111         # Filter IEC_Channel, Slave_Type and Alias that have specific behavior
    81         
   112         if path == "BaseParams.IEC_Channel":
    82         return None
   113             self.PlugParent.SetSlavePosition(position, value)
       
   114         elif path == "SlaveParams.Type":
       
   115             self.PlugParent.SetSlaveType(position, value)
       
   116             slave_type = self.PlugParent.GetSlaveType(self.GetSlavePos())
       
   117             value = (slave_type["device_type"], slave_type)
       
   118             changed = True
       
   119         elif path == "SlaveParams.Alias":
       
   120             self.PlugParent.SetSlaveAlias(position, value)
       
   121             changed = True
       
   122         return value, changed
    83 
   123 
    84     def GetSlaveInfos(self):
   124     def GetSlaveInfos(self):
    85         slave_typeinfos = self.GetSlaveTypeInfos()
   125         return self.PlugParent.GetSlaveInfos(self.GetSlavePos())
    86         if slave_typeinfos is not None:
   126     
    87             device = self.PlugParent.GetModuleInfos(slave_typeinfos)
       
    88             if device is not None:
       
    89                 infos = slave_typeinfos.copy()
       
    90                 entries = device.GetEntriesList()
       
    91                 entries_list = entries.items()
       
    92                 entries_list.sort()
       
    93                 entries = []
       
    94                 current_index = None
       
    95                 current_entry = None
       
    96                 for (index, subindex), entry in entries_list:
       
    97                     entry["children"] = []
       
    98                     if index != current_index:
       
    99                         current_index = index
       
   100                         current_entry = entry
       
   101                         entries.append(entry)
       
   102                     elif current_entry is not None:
       
   103                         current_entry["children"].append(entry)
       
   104                     else:
       
   105                         entries.append(entry)
       
   106                 infos.update({"physics": device.getPhysics(),
       
   107                               "sync_managers": device.GetSyncManagers(),
       
   108                               "entries": entries})
       
   109                 return infos
       
   110         return None
       
   111 
       
   112     def GetVariableLocationTree(self):
   127     def GetVariableLocationTree(self):
   113         slave_typeinfos = self.GetSlaveTypeInfos()
       
   114         vars = []
       
   115         if slave_typeinfos is not None:
       
   116             vars = self.PlugParent.GetDeviceLocationTree(self.GetCurrentLocation(), slave_typeinfos) 
       
   117 
       
   118         return  {"name": self.BaseParams.getName(),
   128         return  {"name": self.BaseParams.getName(),
   119                  "type": LOCATION_PLUGIN,
   129                  "type": LOCATION_PLUGIN,
   120                  "location": self.GetFullIEC_Channel(),
   130                  "location": self.GetFullIEC_Channel(),
   121                  "children": vars}
   131                  "children": self.PlugParent.GetDeviceLocationTree(self.GetSlavePos(), self.GetCurrentLocation(), self.BaseParams.getName())
       
   132         }
   122 
   133 
   123     PluginMethods = [
   134     PluginMethods = [
   124         {"bitmap" : os.path.join("images", "EditCfile"),
   135         {"bitmap" : os.path.join("images", "EditCfile"),
   125          "name" : _("Edit Node"), 
   136          "name" : _("Edit Node"), 
   126          "tooltip" : _("Edit Node"),
   137          "tooltip" : _("Edit Node"),
   127          "method" : "_OpenView"},
   138          "method" : "_OpenView"},
   128     ]
   139     ]
   129 
       
   130 
   140 
   131     def PlugGenerate_C(self, buildpath, locations):
   141     def PlugGenerate_C(self, buildpath, locations):
   132         """
   142         """
   133         Generate C code
   143         Generate C code
   134         @param current_location: Tupple containing plugin IEC location : %I0.0.4.5 => (0,0,4,5)
   144         @param current_location: Tupple containing plugin IEC location : %I0.0.4.5 => (0,0,4,5)
   139             "SIZE" : size "X", "B", "W", "D", "L"
   149             "SIZE" : size "X", "B", "W", "D", "L"
   140             "LOC" : tuple of interger for IEC location (0,1,2,...)
   150             "LOC" : tuple of interger for IEC location (0,1,2,...)
   141             }, ...]
   151             }, ...]
   142         @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND
   152         @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND
   143         """
   153         """
   144         current_location = self.GetCurrentLocation()
   154         return [],"",False
   145         
   155 
   146         location_str = "_".join(map(lambda x:str(x), current_location))
   156 #--------------------------------------------------
   147         
   157 #                 Ethercat DS402 Node
   148         slave_pos = current_location[-2:]
   158 #--------------------------------------------------
   149         
   159 
   150         slave_typeinfos = self.GetSlaveTypeInfos()
   160 if HAS_MCL:
   151         device = None
   161     
   152         if slave_typeinfos is not None:
   162     NODE_VARIABLES = [
   153             device = self.PlugParent.GetModuleInfos(slave_typeinfos)
   163         ("ControlWord", 0x6040, 0x00, "UINT", "Q"),
   154         
   164         ("TargetPosition", 0x607a, 0x00, "DINT", "Q"),
   155         if device is None:
   165         ("StatusWord", 0x6041, 0x00, "UINT", "I"),
   156             raise (ValueError, 
   166         ("ModesOfOperationDisplay", 0x06061, 0x00, "SINT", "I"),
   157                    _("No information found for DS402 node \"%s\" at location %s!") % (
   167         ("ActualPosition", 0x6064, 0x00, "DINT", "I"),
   158                       slave_typeinfos["device_type"], ".".join(current_location)))
   168         ("ErrorCode", 0x603f, 0x00, "UINT", "I"),
   159             
   169     ]
   160         self.PlugParent.FileGenerator.DeclareSlave(slave_pos, slave_typeinfos)
   170     
   161         
   171     class _EthercatDS402SlavePlug(_EthercatSlavePlug):
   162         plc_ds402node_filepath = os.path.join(os.path.split(__file__)[0], "plc_ds402node.c")
   172         XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
   163         plc_ds402node_file = open(plc_ds402node_filepath, 'r')
   173         <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   164         plc_ds402node_code = plc_ds402node_file.read()
   174           <xsd:element name="DS402SlaveParams">
   165         plc_ds402node_file.close()
   175             <xsd:complexType>
   166         
   176               %s
   167         from plugins.motion import Headers
   177             </xsd:complexType>
   168         
   178           </xsd:element>
   169         str_completion = {
   179         </xsd:schema>
   170             "location": location_str,
   180         """ % AxisXSD
   171             "MCL_headers": Headers,
   181         
   172             "extern_located_variables_declaration": [],
   182         NODE_PROFILE = 402
   173             "entry_variables": [],
   183         EditorType = DS402NodeEditor
   174             "init_entry_variables": [],
   184         
   175         }
   185         def PlugGenerate_C(self, buildpath, locations):
   176         
   186             """
   177         for variable in NODE_VARIABLES:
   187             Generate C code
   178             var_infos = dict(zip(["name", "index", "subindex", "var_type", "dir"], variable))
   188             @param current_location: Tupple containing plugin IEC location : %I0.0.4.5 => (0,0,4,5)
   179             var_infos["location"] = location_str
   189             @param locations: List of complete variables locations \
   180             var_infos["var_size"] = self.PlugParent.GetSizeOfType(var_infos["var_type"])
   190                 [{"IEC_TYPE" : the IEC type (i.e. "INT", "STRING", ...)
   181             var_infos["var_name"] = "__%(dir)s%(var_size)s%(location)s_%(index)d_%(subindex)d" % var_infos
   191                 "NAME" : name of the variable (generally "__IW0_1_2" style)
   182             
   192                 "DIR" : direction "Q","I" or "M"
   183             str_completion["extern_located_variables_declaration"].append(
   193                 "SIZE" : size "X", "B", "W", "D", "L"
   184                     "IEC_%(var_type)s *%(var_name)s;" % var_infos)
   194                 "LOC" : tuple of interger for IEC location (0,1,2,...)
   185             str_completion["entry_variables"].append(
   195                 }, ...]
   186                     "    IEC_%(var_type)s *%(name)s;" % var_infos)
   196             @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND
   187             str_completion["init_entry_variables"].append(
   197             """
   188                     "    __DS402Node_%(location)s.%(name)s = %(var_name)s;" % var_infos)
   198             current_location = self.GetCurrentLocation()
   189             
   199             
   190             self.PlugParent.FileGenerator.DeclareVariable(
   200             location_str = "_".join(map(lambda x:str(x), current_location))
   191                     slave_pos, var_infos["index"], var_infos["subindex"], 
   201             
   192                     var_infos["var_type"], var_infos["dir"], var_infos["var_name"])
   202             plc_ds402node_filepath = os.path.join(os.path.split(__file__)[0], "plc_ds402node.c")
   193         
   203             plc_ds402node_file = open(plc_ds402node_filepath, 'r')
   194         for element in ["extern_located_variables_declaration", 
   204             plc_ds402node_code = plc_ds402node_file.read()
   195                         "entry_variables", 
   205             plc_ds402node_file.close()
   196                         "init_entry_variables"]:
   206             
   197             str_completion[element] = "\n".join(str_completion[element])
   207             str_completion = {
   198         
   208                 "location": location_str,
   199         Gen_DS402Nodefile_path = os.path.join(buildpath, "ds402node_%s.c"%location_str)
   209                 "MCL_headers": Headers,
   200         ds402nodefile = open(Gen_DS402Nodefile_path, 'w')
   210                 "extern_located_variables_declaration": [],
   201         ds402nodefile.write(plc_ds402node_code % str_completion)
   211                 "entry_variables": [],
   202         ds402nodefile.close()
   212                 "init_axis_params": [],
   203         
   213                 "init_entry_variables": [],
   204         return [(Gen_DS402Nodefile_path, '"-I%s"'%os.path.abspath(self.GetPlugRoot().GetIECLibPath()))],"",True
   214             }
   205         
   215             
   206 
   216             for variable in NODE_VARIABLES:
   207 
   217                 var_infos = dict(zip(["name", "index", "subindex", "var_type", "dir"], variable))
   208 TYPECONVERSION = {"BOOL" : "X", "SINT" : "B", "INT" : "W", "DINT" : "D", "LINT" : "L",
   218                 var_infos["location"] = location_str
   209     "USINT" : "B", "UINT" : "W", "UDINT" : "D", "ULINT" : "L", 
   219                 var_infos["var_size"] = self.GetSizeOfType(var_infos["var_type"])
   210     "BYTE" : "B", "WORD" : "W", "DWORD" : "D", "LWORD" : "L"}
   220                 var_infos["var_name"] = "__%(dir)s%(var_size)s%(location)s_%(index)d_%(subindex)d" % var_infos
   211 
   221                 
   212 DATATYPECONVERSION = {"BOOL" : "BIT", "SINT" : "S8", "INT" : "S16", "DINT" : "S32", "LINT" : "S64",
   222                 str_completion["extern_located_variables_declaration"].append(
   213     "USINT" : "U8", "UINT" : "U16", "UDINT" : "U32", "ULINT" : "U64", 
   223                         "IEC_%(var_type)s *%(var_name)s;" % var_infos)
   214     "BYTE" : "U8", "WORD" : "U16", "DWORD" : "U32", "LWORD" : "U64"}
   224                 str_completion["entry_variables"].append(
   215 
   225                         "    IEC_%(var_type)s *%(name)s;" % var_infos)
   216 VARCLASSCONVERSION = {"T": LOCATION_VAR_INPUT, "R": LOCATION_VAR_OUTPUT, "RT": LOCATION_VAR_MEMORY}
   226                 str_completion["init_entry_variables"].append(
       
   227                         "    __DS402Node_%(location)s.%(name)s = %(var_name)s;" % var_infos)
       
   228                 
       
   229                 self.PlugParent.FileGenerator.DeclareVariable(
       
   230                         self.GetSlavePos(), var_infos["index"], var_infos["subindex"], 
       
   231                         var_infos["var_type"], var_infos["dir"], var_infos["var_name"])
       
   232             
       
   233             params = self.PlugParams[1].getElementInfos(self.PlugParams[0])
       
   234             for param in params["children"]:
       
   235                 if param["value"] is not None:
       
   236                     param_infos = {
       
   237                         "location": location_str,
       
   238                         "param_name": param["name"],
       
   239                     }
       
   240                     if param["type"] == "boolean":
       
   241                         param_infos["param_value"] = {True: "true", False: "false"}[param["value"]]
       
   242                     else:
       
   243                         param_infos["param_value"] = str(param["value"])
       
   244                     str_completion["init_axis_params"].append(
       
   245                         "        __DS402Node_%(location)s.axis->%(param_name)s = %(param_value)s;" % param_infos)
       
   246             
       
   247             for element in ["extern_located_variables_declaration", 
       
   248                             "entry_variables", 
       
   249                             "init_axis_params", 
       
   250                             "init_entry_variables"]:
       
   251                 str_completion[element] = "\n".join(str_completion[element])
       
   252             
       
   253             Gen_DS402Nodefile_path = os.path.join(buildpath, "ds402node_%s.c"%location_str)
       
   254             ds402nodefile = open(Gen_DS402Nodefile_path, 'w')
       
   255             ds402nodefile.write(plc_ds402node_code % str_completion)
       
   256             ds402nodefile.close()
       
   257             
       
   258             return [(Gen_DS402Nodefile_path, '"-I%s"'%os.path.abspath(self.GetPlugRoot().GetIECLibPath()))],"",True
   217 
   259 
   218 #--------------------------------------------------
   260 #--------------------------------------------------
   219 #                 Ethercat MASTER
   261 #                 Ethercat MASTER
   220 #--------------------------------------------------
   262 #--------------------------------------------------
   221 
   263 
   255         slave_info.setName(type_infos["device_type"])
   297         slave_info.setName(type_infos["device_type"])
   256         slave_info.setVendorId(ExtractHexDecValue(type_infos["vendor"]))
   298         slave_info.setVendorId(ExtractHexDecValue(type_infos["vendor"]))
   257         slave_info.setProductCode(ExtractHexDecValue(type_infos["product_code"]))
   299         slave_info.setProductCode(ExtractHexDecValue(type_infos["product_code"]))
   258         slave_info.setRevisionNo(ExtractHexDecValue(type_infos["revision_number"]))
   300         slave_info.setRevisionNo(ExtractHexDecValue(type_infos["revision_number"]))
   259     setattr(cls, "setType", setType)
   301     setattr(cls, "setType", setType)
   260     
       
   261 cls = EtherCATConfigClasses.get("Slave_Info", None)
       
   262 if cls:
       
   263 
       
   264     def getSlavePosition(self):
       
   265         return self.getPhysAddr(), self.getAutoIncAddr()
       
   266     setattr(cls, "getSlavePosition", getSlavePosition)
       
   267 
       
   268     def setSlavePosition(self, alias, pos):
       
   269         self.setPhysAddr(alias)
       
   270         self.setAutoIncAddr(pos)
       
   271     setattr(cls, "setSlavePosition", setSlavePosition)
       
   272 
   302 
   273 class _EthercatPlug:
   303 class _EthercatPlug:
   274     XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
   304     XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
   275     <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   305     <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   276       <xsd:element name="EtherlabNode">
   306       <xsd:element name="EtherlabNode">
   279           <xsd:attribute name="ConfigurePDOs" type="xsd:boolean" use="optional" default="true"/>
   309           <xsd:attribute name="ConfigurePDOs" type="xsd:boolean" use="optional" default="true"/>
   280         </xsd:complexType>
   310         </xsd:complexType>
   281       </xsd:element>
   311       </xsd:element>
   282     </xsd:schema>
   312     </xsd:schema>
   283     """
   313     """
   284     EditorType = ConfigEditor
   314     
   285     
   315     PlugChildsTypes = [("EthercatSlave", _EthercatSlavePlug, "Ethercat Slave")]
   286     PlugChildsTypes = [("EthercatDS402Slave", _EthercatDS402SlavePlug, "Ethercat DS402 Slave")]
   316     if HAS_MCL:
       
   317         PlugChildsTypes.append(("EthercatDS402Slave", _EthercatDS402SlavePlug, "Ethercat DS402 Slave"))
   287     
   318     
   288     def __init__(self):
   319     def __init__(self):
   289         filepath = self.ConfigFileName()
   320         filepath = self.ConfigFileName()
   290         
   321         
   291         self.Config = EtherCATConfigClasses["EtherCATConfig"]()
   322         self.Config = EtherCATConfigClasses["EtherCATConfig"]()
   312         return os.path.join(self.PlugPath(), "config.xml")
   343         return os.path.join(self.PlugPath(), "config.xml")
   313 
   344 
   314     def GetSlaves(self):
   345     def GetSlaves(self):
   315         slaves = []
   346         slaves = []
   316         for slave in self.Config.getConfig().getSlave():
   347         for slave in self.Config.getConfig().getSlave():
   317             slaves.append(slave.getInfo().getSlavePosition())
   348             slaves.append(slave.getInfo().getPhysAddr())
   318         slaves.sort()
   349         slaves.sort()
   319         return slaves
   350         return slaves
   320 
   351 
   321     def GetSlave(self, slave_pos):
   352     def GetSlave(self, slave_pos):
   322         for slave in self.Config.getConfig().getSlave():
   353         for slave in self.Config.getConfig().getSlave():
   323             slave_info = slave.getInfo()
   354             slave_info = slave.getInfo()
   324             if slave_info.getSlavePosition() == slave_pos:
   355             if slave_info.getPhysAddr() == slave_pos:
   325                 return slave
   356                 return slave
   326         return None
   357         return None
   327 
   358 
   328     def AddSlave(self):
   359     def PlugAddChild(self, PlugName, PlugType, IEC_Channel=0):
   329         slaves = self.GetSlaves()
   360         """
   330         for PlugInstance in self.IterChilds():
   361         Create the plugins that may be added as child to this node self
   331             slaves.append(PlugInstance.GetSlavePos())
   362         @param PlugType: string desining the plugin class name (get name from PlugChildsTypes)
   332         slaves.sort()
   363         @param PlugName: string for the name of the plugin instance
   333         if len(slaves) > 0:
   364         """
   334             new_pos = (slaves[-1][0] + 1, 0)
   365         newPluginOpj = PlugTemplate.PlugAddChild(self, PlugName, PlugType, IEC_Channel)
   335         else:
   366         
   336             new_pos = (0, 0)
   367         slave = self.GetSlave(newPluginOpj.BaseParams.getIEC_Channel())
   337         slave = EtherCATConfigClasses["Config_Slave"]()
   368         if slave is None:
   338         slave_infos = slave.getInfo()
   369             slave = EtherCATConfigClasses["Config_Slave"]()
   339         slave_infos.setName("undefined")
   370             slave_infos = slave.getInfo()
   340         slave_infos.setSlavePosition(new_pos[0], new_pos[1])
   371             slave_infos.setName("undefined")
   341         self.Config.getConfig().appendSlave(slave)
   372             slave_infos.setPhysAddr(newPluginOpj.BaseParams.getIEC_Channel())
   342         self.BufferConfig()
   373             slave_infos.setAutoIncAddr(0)
   343         return new_pos
   374             self.Config.getConfig().appendSlave(slave)
   344     
   375             self.BufferConfig()
   345     def RemoveSlave(self, slave_pos):
   376             self.OnPlugSave()
       
   377         
       
   378         return newPluginOpj
       
   379 
       
   380     def _doRemoveChild(self, PlugInstance):
       
   381         slave_pos = PlugInstance.GetSlavePos()
   346         config = self.Config.getConfig()
   382         config = self.Config.getConfig()
   347         for idx, slave in enumerate(config.getSlave()):
   383         for idx, slave in enumerate(config.getSlave()):
   348             slave_infos = slave.getInfo()
   384             slave_infos = slave.getInfo()
   349             if slave_infos.getSlavePosition() == slave_pos:
   385             if slave_infos.getPhysAddr() == slave_pos:
   350                 config.removeSlave(idx)
   386                 config.removeSlave(idx)
   351                 self.BufferConfig()
   387                 self.BufferConfig()
   352                 return True
   388                 self.OnPlugSave()
   353         return False
   389         PlugTemplate._doRemoveChild(self, PlugInstance)
   354     
   390 
   355     def SetSlavePos(self, slave_pos, alias=None, position=None):
   391     def SetSlavePosition(self, slave_pos, new_pos):
   356         for PlugInstance in self.IterChilds():
       
   357             if PlugInstance.BaseParams.getIEC_Channel() == alias:
       
   358                 return _("Slave with alias \"%d\" already exists!" % alias)
       
   359         slave = self.GetSlave(slave_pos)
   392         slave = self.GetSlave(slave_pos)
   360         if slave is not None:
   393         if slave is not None:
   361             slave_info = slave.getInfo()
   394             slave_info = slave.getInfo()
   362             new_pos = slave_pos
   395             slave_info.setPhysAddr(new_pos)
   363             if alias is not None:
       
   364                 new_pos = (alias, new_pos[1])
       
   365             if position is not None:
       
   366                 new_pos = (new_pos[0], position)
       
   367             if self.GetSlave(new_pos) is not None:
       
   368                 return _("Slave with position \"%d:%d\" already exists!" % new_pos)
       
   369             slave_info.setSlavePosition(*new_pos)
       
   370             self.BufferConfig()
   396             self.BufferConfig()
       
   397     
       
   398     def GetSlaveAlias(self, slave_pos):
       
   399         slave = self.GetSlave(slave_pos)
       
   400         if slave is not None:
       
   401             slave_info = slave.getInfo()
       
   402             return slave_info.getAutoIncAddr()
   371         return None
   403         return None
       
   404     
       
   405     def SetSlaveAlias(self, slave_pos, alias):
       
   406         slave = self.GetSlave(slave_pos)
       
   407         if slave is not None:
       
   408             slave_info = slave.getInfo()
       
   409             slave_info.setAutoIncAddr(alias)
       
   410             self.BufferConfig()
   372     
   411     
   373     def GetSlaveType(self, slave_pos):
   412     def GetSlaveType(self, slave_pos):
   374         slave = self.GetSlave(slave_pos)
   413         slave = self.GetSlave(slave_pos)
   375         if slave is not None:
   414         if slave is not None:
   376             return slave.getType()
   415             return slave.getType()
   379     def SetSlaveType(self, slave_pos, type_infos):
   418     def SetSlaveType(self, slave_pos, type_infos):
   380         slave = self.GetSlave(slave_pos)
   419         slave = self.GetSlave(slave_pos)
   381         if slave is not None:
   420         if slave is not None:
   382             slave.setType(type_infos)
   421             slave.setType(type_infos)
   383             self.BufferConfig()
   422             self.BufferConfig()
   384         return None
       
   385     
   423     
   386     def GetSlaveInfos(self, slave_pos):
   424     def GetSlaveInfos(self, slave_pos):
   387         slave = self.GetSlave(slave_pos)
   425         slave = self.GetSlave(slave_pos)
   388         if slave is not None:
   426         if slave is not None:
   389             type_infos = slave.getType()
   427             type_infos = slave.getType()
   413         return None
   451         return None
   414     
   452     
   415     def GetModuleInfos(self, type_infos):
   453     def GetModuleInfos(self, type_infos):
   416         return self.PlugParent.GetModuleInfos(type_infos)
   454         return self.PlugParent.GetModuleInfos(type_infos)
   417     
   455     
   418     def GetModulesByProfile(self, profile_type):
   456     def GetSlaveTypesLibrary(self, profile_filter=None):
   419         return self.PlugParent.GetModulesByProfile(profile_type)
   457         return self.PlugParent.GetModulesLibrary(profile_filter)
   420     
   458     
   421     def GetSlaveTypesLibrary(self):
   459     def GetDeviceLocationTree(self, slave_pos, current_location, device_name):
   422         return self.PlugParent.GetModulesLibrary()
   460         slave = self.GetSlave(slave_pos)
   423     
   461         if slave is not None:
   424     def GetDeviceLocationTree(self, current_location, type_infos):
   462             type_infos = slave.getType()
   425         vars = []
   463         
   426         
   464             vars = []
   427         device = self.GetModuleInfos(type_infos)
   465             
   428         if device is not None:
   466             device = self.GetModuleInfos(type_infos)
   429             sync_managers = []
   467             if device is not None:
   430             for sync_manager in device.getSm():
   468                 sync_managers = []
   431                 sync_manager_control_byte = ExtractHexDecValue(sync_manager.getControlByte())
   469                 for sync_manager in device.getSm():
   432                 sync_manager_direction = sync_manager_control_byte & 0x0c
   470                     sync_manager_control_byte = ExtractHexDecValue(sync_manager.getControlByte())
   433                 if sync_manager_direction:
   471                     sync_manager_direction = sync_manager_control_byte & 0x0c
   434                     sync_managers.append(LOCATION_VAR_OUTPUT)
   472                     if sync_manager_direction:
   435                 else:
   473                         sync_managers.append(LOCATION_VAR_OUTPUT)
   436                     sync_managers.append(LOCATION_VAR_INPUT)
   474                     else:
   437             
   475                         sync_managers.append(LOCATION_VAR_INPUT)
   438             entries = device.GetEntriesList().items()
   476                 
   439             entries.sort()
   477                 entries = device.GetEntriesList().items()
   440             for (index, subindex), entry in entries:
   478                 entries.sort()
   441                 var_size = self.GetSizeOfType(entry["Type"])
   479                 for (index, subindex), entry in entries:
   442                 if var_size is not None:
   480                     var_size = self.GetSizeOfType(entry["Type"])
   443                     var_class = VARCLASSCONVERSION.get(entry["PDOMapping"], None)
   481                     if var_size is not None:
   444                     if var_class is not None:
   482                         var_class = VARCLASSCONVERSION.get(entry["PDOMapping"], None)
   445                         if var_class == LOCATION_VAR_INPUT:
   483                         if var_class is not None:
   446                             var_dir = "%I"
   484                             if var_class == LOCATION_VAR_INPUT:
   447                         else:
   485                                 var_dir = "%I"
   448                             var_dir = "%Q"    
   486                             else:
   449                     
   487                                 var_dir = "%Q"    
   450                         vars.append({"name": "0x%4.4x-0x%2.2x: %s" % (index, subindex, entry["Name"]),
   488                         
   451                                      "type": var_class,
   489                             vars.append({"name": "0x%4.4x-0x%2.2x: %s" % (index, subindex, entry["Name"]),
   452                                      "size": var_size,
   490                                          "type": var_class,
   453                                      "IEC_type": entry["Type"],
   491                                          "size": var_size,
   454                                      "var_name": "%s_%4.4x_%2.2x" % ("_".join(type_infos["device_type"].split()), index, subindex),
   492                                          "IEC_type": entry["Type"],
   455                                      "location": "%s%s%s"%(var_dir, var_size, ".".join(map(str, current_location + 
   493                                          "var_name": "%s_%4.4x_%2.2x" % ("_".join(device_name.split()), index, subindex),
   456                                                                                                 (index, subindex)))),
   494                                          "location": "%s%s%s"%(var_dir, var_size, ".".join(map(str, current_location + 
   457                                      "description": "",
   495                                                                                                     (index, subindex)))),
   458                                      "children": []})
   496                                          "description": "",
       
   497                                          "children": []})
   459         
   498         
   460         return vars
   499         return vars
   461     
   500     
   462     def GetVariableLocationTree(self):
       
   463         '''See PlugTemplate.GetVariableLocationTree() for a description.'''
       
   464 
       
   465         current_location = self.GetCurrentLocation()
       
   466         
       
   467         groups = []
       
   468         for slave_pos in self.GetSlaves():
       
   469             
       
   470             slave = self.GetSlave(slave_pos)
       
   471             if slave is not None:
       
   472                 type_infos = slave.getType()
       
   473                 
       
   474                 vars = self.GetDeviceLocationTree(current_location + slave_pos, type_infos)
       
   475                 if len(vars) > 0:
       
   476                     groups.append({"name": "%s (%d,%d)" % ((type_infos["device_type"],) + slave_pos),
       
   477                                    "type": LOCATION_GROUP,
       
   478                                    "location": ".".join(map(str, current_location + slave_pos)) + ".x",
       
   479                                    "children": vars})
       
   480                 
       
   481         return  {"name": self.BaseParams.getName(),
       
   482                  "type": LOCATION_PLUGIN,
       
   483                  "location": self.GetFullIEC_Channel(),
       
   484                  "children": groups}
       
   485     
       
   486     PluginMethods = [
       
   487         {"bitmap" : os.path.join("images", "EditCfile"),
       
   488          "name" : _("Edit Config"), 
       
   489          "tooltip" : _("Edit Config"),
       
   490          "method" : "_OpenView"},
       
   491     ]
       
   492 
       
   493     def PlugTestModified(self):
   501     def PlugTestModified(self):
   494         return self.ChangesToSave or not self.ConfigIsSaved()    
   502         return self.ChangesToSave or not self.ConfigIsSaved()    
   495 
   503 
   496     def OnPlugSave(self):
   504     def OnPlugSave(self):
   497         filepath = self.ConfigFileName()
   505         filepath = self.ConfigFileName()
   546         
   554         
   547         slaves = self.GetSlaves()
   555         slaves = self.GetSlaves()
   548         for slave_pos in slaves:
   556         for slave_pos in slaves:
   549             slave = self.GetSlave(slave_pos)
   557             slave = self.GetSlave(slave_pos)
   550             if slave is not None:
   558             if slave is not None:
   551                 self.FileGenerator.DeclareSlave(slave_pos, slave.getType())
   559                 self.FileGenerator.DeclareSlave(slave_pos, slave.getInfo().getAutoIncAddr(), slave.getType())
   552         
   560         
   553         for location in locations:
   561         for location in locations:
   554             loc = location["LOC"][len(current_location):]
   562             loc = location["LOC"][len(current_location):]
   555             slave_pos = loc[:2]
   563             slave_pos = loc[0]
   556             if slave_pos in slaves:
   564             if slave_pos in slaves and len(loc) == 3:
   557                 self.FileGenerator.DeclareVariable(
   565                 self.FileGenerator.DeclareVariable(
   558                     slave_pos, loc[2], loc[3], location["IEC_TYPE"], location["DIR"], location["NAME"])
   566                     slave_pos, loc[1], loc[2], location["IEC_TYPE"], location["DIR"], location["NAME"])
   559         
   567         
   560         return [],"",False
   568         return [],"",False
   561         
   569         
   562 #-------------------------------------------------------------------------------
   570 #-------------------------------------------------------------------------------
   563 #                      Current Buffering Management Functions
   571 #                      Current Buffering Management Functions
   707         self.UsedVariables = {}
   715         self.UsedVariables = {}
   708 
   716 
   709     def __del__(self):
   717     def __del__(self):
   710         self.Controler = None            
   718         self.Controler = None            
   711 
   719 
   712     def DeclareSlave(self, slave_identifier, slave):
   720     def DeclareSlave(self, slave_index, slave_alias, slave):
   713         self.Slaves.append((slave_identifier, slave))
   721         self.Slaves.append((slave_index, slave_alias, slave))
   714         self.Slaves.sort()
   722 
   715         return self.Slaves.index((slave_identifier, slave))
   723     def DeclareVariable(self, slave_index, index, subindex, iec_type, dir, name):
   716 
   724         slave_variables = self.UsedVariables.setdefault(slave_index, {})
   717     def DeclareVariable(self, slave_identifier, index, subindex, iec_type, dir, name):
       
   718         slave_variables = self.UsedVariables.setdefault(slave_identifier, {})
       
   719         
   725         
   720         entry_infos = slave_variables.get((index, subindex), None)
   726         entry_infos = slave_variables.get((index, subindex), None)
   721         if entry_infos is None:
   727         if entry_infos is None:
   722             slave_variables[(index, subindex)] = {
   728             slave_variables[(index, subindex)] = {
   723                 "infos": (iec_type, dir, name),
   729                 "infos": (iec_type, dir, name),
   750         
   756         
   751         for slave_entries in self.UsedVariables.itervalues():
   757         for slave_entries in self.UsedVariables.itervalues():
   752             for entry_infos in slave_entries.itervalues():
   758             for entry_infos in slave_entries.itervalues():
   753                 entry_infos["mapped"] = False
   759                 entry_infos["mapped"] = False
   754         
   760         
   755         for slave_idx, (slave_pos, type_infos) in enumerate(self.Slaves):
   761         self.Slaves.sort()
       
   762         alias = {}
       
   763         for (slave_idx, slave_alias, type_infos) in self.Slaves:
       
   764             if alias.get(slave_alias) is not None:
       
   765                 alias[slave_alias] += 1
       
   766             else:
       
   767                 alias[slave_alias] = 0
       
   768             slave_pos = (slave_alias, alias[slave_alias])
   756             
   769             
   757             device = self.Controler.GetModuleInfos(type_infos)
   770             device = self.Controler.GetModuleInfos(type_infos)
   758             if device is not None:
   771             if device is not None:
   759             
   772             
   760                 slave_variables = self.UsedVariables.get(slave_pos, {})
   773                 slave_variables = self.UsedVariables.get(slave_idx, {})
   761                 device_entries = device.GetEntriesList()
   774                 device_entries = device.GetEntriesList()
   762                 
   775                 
   763                 if len(device.getTxPdo() + device.getRxPdo()) > 0 or len(slave_variables) > 0:
   776                 if len(device.getTxPdo() + device.getRxPdo()) > 0 or len(slave_variables) > 0:
   764                     
   777                     
   765                     for element in ["vendor", "product_code", "revision_number"]:
   778                     for element in ["vendor", "product_code", "revision_number"]:
  1304                         device_group = device.getGroupType()
  1317                         device_group = device.getGroupType()
  1305                         if not vendor_category["groups"].has_key(device_group):
  1318                         if not vendor_category["groups"].has_key(device_group):
  1306                             raise ValueError, "Not such group \"%\"" % device_group
  1319                             raise ValueError, "Not such group \"%\"" % device_group
  1307                         vendor_category["groups"][device_group]["devices"].append((device.getType().getcontent(), device))
  1320                         vendor_category["groups"][device_group]["devices"].append((device.getType().getcontent(), device))
  1308     
  1321     
  1309     def GetModulesLibrary(self):
  1322     def GetModulesLibrary(self, profile_filter=None):
  1310         library = []
  1323         library = []
  1311         children_dict = {}
  1324         children_dict = {}
  1312         for vendor_id, vendor in self.ModulesLibrary.iteritems():
  1325         for vendor_id, vendor in self.ModulesLibrary.iteritems():
  1313             groups = []
  1326             groups = []
  1314             library.append({"name": vendor["name"],
       
  1315                             "type": ETHERCAT_VENDOR,
       
  1316                             "children": groups})
       
  1317             for group_type, group in vendor["groups"].iteritems():
  1327             for group_type, group in vendor["groups"].iteritems():
  1318                 group_infos = {"name": group["name"],
  1328                 group_infos = {"name": group["name"],
  1319                                "order": group["order"],
  1329                                "order": group["order"],
  1320                                "type": ETHERCAT_GROUP,
  1330                                "type": ETHERCAT_GROUP,
       
  1331                                "infos": None,
  1321                                "children": children_dict.setdefault(group_type, [])}
  1332                                "children": children_dict.setdefault(group_type, [])}
  1322                 if group["parent"] is not None:
       
  1323                     parent_children = children_dict.setdefault(group["parent"], [])
       
  1324                     parent_children.append(group_infos)
       
  1325                 else:
       
  1326                     groups.append(group_infos)
       
  1327                 device_dict = {}
  1333                 device_dict = {}
  1328                 for device_type, device in group["devices"]:
  1334                 for device_type, device in group["devices"]:
  1329                     device_infos = {"name": ExtractName(device.getName()),
  1335                     if profile_filter is None or profile_filter in device.GetProfileNumbers():
  1330                                     "type": ETHERCAT_DEVICE,
  1336                         device_infos = {"name": ExtractName(device.getName()),
  1331                                     "infos": {"device_type": device_type,
  1337                                         "type": ETHERCAT_DEVICE,
  1332                                               "vendor": vendor_id,
  1338                                         "infos": {"device_type": device_type,
  1333                                               "product_code": device.getType().getProductCode(),
  1339                                                   "vendor": vendor_id,
  1334                                               "revision_number": device.getType().getRevisionNo()}}
  1340                                                   "product_code": device.getType().getProductCode(),
  1335                     group_infos["children"].append(device_infos)
  1341                                                   "revision_number": device.getType().getRevisionNo()},
  1336                     device_type_occurrences = device_dict.setdefault(device_type, [])
  1342                                         "children": []}
  1337                     device_type_occurrences.append(device_infos)
  1343                         group_infos["children"].append(device_infos)
       
  1344                         device_type_occurrences = device_dict.setdefault(device_type, [])
       
  1345                         device_type_occurrences.append(device_infos)
  1338                 for device_type_occurrences in device_dict.itervalues():
  1346                 for device_type_occurrences in device_dict.itervalues():
  1339                     if len(device_type_occurrences) > 1:
  1347                     if len(device_type_occurrences) > 1:
  1340                         for occurrence in device_type_occurrences:
  1348                         for occurrence in device_type_occurrences:
  1341                             occurrence["name"] += _(" (rev. %s)") % occurrence["infos"]["revision_number"]
  1349                             occurrence["name"] += _(" (rev. %s)") % occurrence["infos"]["revision_number"]
       
  1350                 if len(group_infos["children"]) > 0:
       
  1351                     if group["parent"] is not None:
       
  1352                         parent_children = children_dict.setdefault(group["parent"], [])
       
  1353                         parent_children.append(group_infos)
       
  1354                     else:
       
  1355                         groups.append(group_infos)
       
  1356             if len(groups) > 0:
       
  1357                 library.append({"name": vendor["name"],
       
  1358                                 "type": ETHERCAT_VENDOR,
       
  1359                                 "infos": None,
       
  1360                                 "children": groups})
  1342         library.sort(lambda x, y: cmp(x["name"], y["name"]))
  1361         library.sort(lambda x, y: cmp(x["name"], y["name"]))
  1343         return library
  1362         return library
  1344     
  1363     
  1345     def GetModuleInfos(self, type_infos):
  1364     def GetModuleInfos(self, type_infos):
  1346         vendor = self.ModulesLibrary.get(ExtractHexDecValue(type_infos["vendor"]), None)
  1365         vendor = self.ModulesLibrary.get(ExtractHexDecValue(type_infos["vendor"]), None)
  1352                     if (device_type == type_infos["device_type"] and
  1371                     if (device_type == type_infos["device_type"] and
  1353                         product_code == ExtractHexDecValue(type_infos["product_code"]) and
  1372                         product_code == ExtractHexDecValue(type_infos["product_code"]) and
  1354                         revision_number == ExtractHexDecValue(type_infos["revision_number"])):
  1373                         revision_number == ExtractHexDecValue(type_infos["revision_number"])):
  1355                         return device
  1374                         return device
  1356         return None
  1375         return None
  1357     
  1376 
  1358     def GetModulesByProfile(self, profile_type):
  1377             
  1359         modules = []
       
  1360         for vendor_id, vendor in self.ModulesLibrary.iteritems():
       
  1361             for group_type, group in vendor["groups"].iteritems():
       
  1362                 for device_type, device in group["devices"]:
       
  1363                     if profile_type in device.GetProfileNumbers():
       
  1364                         product_code = ExtractHexDecValue(device.getType().getProductCode())
       
  1365                         revision_number = ExtractHexDecValue(device.getType().getRevisionNo())
       
  1366                         modules.append((device_type, vendor_id, product_code, revision_number))
       
  1367         return modules
       
  1368 
       
  1369