etherlab/etherlab.py
changeset 2032 766078d83e22
parent 2031 c6f32810723e
child 2034 ae8fecf082a1
equal deleted inserted replaced
2031:c6f32810723e 2032:766078d83e22
     3 from xml.dom import minidom
     3 from xml.dom import minidom
     4 
     4 
     5 import wx
     5 import wx
     6 
     6 
     7 from xmlclass import *
     7 from xmlclass import *
       
     8 from plugger import PlugTemplate
     8 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
     9 from ConfigEditor import ConfigEditor, ETHERCAT_VENDOR, ETHERCAT_GROUP, ETHERCAT_DEVICE
    10 from ConfigEditor import ConfigEditor, ETHERCAT_VENDOR, ETHERCAT_GROUP, ETHERCAT_DEVICE
       
    11 
       
    12 #--------------------------------------------------
       
    13 #                 Ethercat DS402 Node
       
    14 #--------------------------------------------------
       
    15 
       
    16 NODE_VARIABLES = [
       
    17     ("ControlWord", 0x6040, 0x00, "UINT", "Q"),
       
    18     ("StatusWord", 0x6041, 0x00, "UINT", "I"),
       
    19     ("ModesOfOperationDisplay", 0x06061, 0x00, "SINT", "I"),
       
    20     ("ErrorCode", 0x603f, 0x00, "UINT", "I"),
       
    21 ]
       
    22 
       
    23 class _EthercatDS402SlavePlug:
       
    24     XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
       
    25     <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
       
    26       <xsd:element name="EtherlabDS402Slave">
       
    27         <xsd:complexType>
       
    28           <xsd:attribute name="Node_Type" type="xsd:string" use="optional"/>
       
    29         </xsd:complexType>
       
    30       </xsd:element>
       
    31     </xsd:schema>
       
    32     """
       
    33     
       
    34     def _GetChildBySomething(self, something, toks):
       
    35         return self
       
    36     
       
    37     def GetParamsAttributes(self, path = None):
       
    38         infos = PlugTemplate.GetParamsAttributes(self, path = None)
       
    39         for element in infos:
       
    40             if element["name"] == "EtherlabDS402Slave":
       
    41                 for child in element["children"]:
       
    42                     if child["name"] == "Node_Type":
       
    43                         child["type"] = [module[0] for module in self.PlugParent.GetModulesByProfile(402)]
       
    44         return infos
       
    45     
       
    46     def GetAllChannels(self):
       
    47         AllChannels = PlugTemplate.GetAllChannels(self)
       
    48         for slave_pos in self.PlugParent.GetSlaves():
       
    49             if slave_pos[0] not in AllChannels:
       
    50                 AllChannels.append(slave_pos[0])
       
    51         AllChannels.sort()
       
    52         return AllChannels
       
    53 
       
    54     def GetCurrentLocation(self):
       
    55         """
       
    56         @return:  Tupple containing plugin IEC location of current plugin : %I0.0.4.5 => (0,0,4,5)
       
    57         """
       
    58         return self.PlugParent.GetCurrentLocation() + (self.BaseParams.getIEC_Channel(), 0)
       
    59 
       
    60     def GetSlaveInfos(self):
       
    61         slave_type = self.EtherlabDS402Slave.getNode_Type()
       
    62         
       
    63         for module_type, vendor_id, product_code, revision_number in self.PlugParent.GetModulesByProfile(402):
       
    64             if module_type == slave_type:
       
    65                 return {"device_type": module_type,
       
    66                         "vendor": GenerateHexDecValue(vendor_id),
       
    67                         "product_code": GenerateHexDecValue(product_code, 16),
       
    68                         "revision_number": GenerateHexDecValue(revision_number, 16)}
       
    69         
       
    70         return None
       
    71 
       
    72     def GetVariableLocationTree(self):
       
    73         slave_infos = self.GetSlaveInfos()
       
    74         vars = []
       
    75         if slave_infos is not None:
       
    76             vars = self.PlugParent.GetDeviceLocationTree(self.GetCurrentLocation(), slave_infos) 
       
    77 
       
    78         return  {"name": self.BaseParams.getName(),
       
    79                  "type": LOCATION_PLUGIN,
       
    80                  "location": self.GetFullIEC_Channel(),
       
    81                  "children": vars}
       
    82 
       
    83     def PlugGenerate_C(self, buildpath, locations):
       
    84         """
       
    85         Generate C code
       
    86         @param current_location: Tupple containing plugin IEC location : %I0.0.4.5 => (0,0,4,5)
       
    87         @param locations: List of complete variables locations \
       
    88             [{"IEC_TYPE" : the IEC type (i.e. "INT", "STRING", ...)
       
    89             "NAME" : name of the variable (generally "__IW0_1_2" style)
       
    90             "DIR" : direction "Q","I" or "M"
       
    91             "SIZE" : size "X", "B", "W", "D", "L"
       
    92             "LOC" : tuple of interger for IEC location (0,1,2,...)
       
    93             }, ...]
       
    94         @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND
       
    95         """
       
    96         current_location = self.GetCurrentLocation()
       
    97         
       
    98         location_str = "_".join(map(lambda x:str(x), current_location))
       
    99         
       
   100         slave_pos = current_location[-2:]
       
   101         
       
   102         slave_infos = self.GetSlaveInfos()
       
   103         device = None
       
   104         if slave_infos is not None:
       
   105             device = self.PlugParent.GetModuleInfos(slave_infos)
       
   106         
       
   107         if device is None:
       
   108             raise (ValueError, 
       
   109                    _("No information found for DS402 node \"%s\" at location %s!") % (
       
   110                       slave_infos["device_type"], ".".join(current_location)))
       
   111             
       
   112         slave_idx = self.PlugParent.FileGenerator.DeclareSlave(slave_pos, slave_infos)
       
   113         
       
   114         plc_ds402node_filepath = os.path.join(os.path.split(__file__)[0], "plc_ds402node.c")
       
   115         plc_ds402node_file = open(plc_ds402node_filepath, 'r')
       
   116         plc_ds402node_code = plc_ds402node_file.read()
       
   117         plc_ds402node_file.close()
       
   118         
       
   119         str_completion = {
       
   120             "location": location_str,
       
   121             "MCL_includes": "",
       
   122             "located_variables_declaration": [],
       
   123             "entry_variables": [],
       
   124             "extern_pdo_entry_configuration": [],
       
   125             "retrieve_variables": [],
       
   126             "publish_variables": [],
       
   127         }
       
   128         
       
   129         variables = {}
       
   130         for variable in NODE_VARIABLES:
       
   131             var_infos = dict(zip(["name", "index", "subindex", "var_type", "dir"], variable))
       
   132             var_infos["location"] = location_str
       
   133             var_infos["slave"] = slave_idx
       
   134             var_infos["var_size"] = self.PlugParent.GetSizeOfType(var_infos["var_type"])
       
   135             var_infos["var_name"] = "__%(dir)s%(var_size)s%(location)s_%(index)d_%(subindex)d" % var_infos
       
   136             var_infos["real_var"] = "__DS402Node_%(location)s.%(name)s" % var_infos
       
   137             var_infos.update(slave_infos)
       
   138             
       
   139             variables[(var_infos["index"], var_infos["subindex"])] = var_infos["name"]
       
   140             
       
   141             str_completion["entry_variables"].append("    IEC_%(var_type)s %(name)s;" % var_infos)
       
   142             
       
   143             ConfigureVariable(var_infos, str_completion)
       
   144             
       
   145             str_completion["extern_pdo_entry_configuration"].append(
       
   146                 "extern unsigned int slave%(slave)d_%(index).4x_%(subindex).2x;" % var_infos)
       
   147                 
       
   148             if var_infos["var_type"] == "BOOL":
       
   149                 str_completion["extern_pdo_entry_configuration"].append(
       
   150                     "extern unsigned int slave%(slave)d_%(index).4x_%(subindex).2x_bit;" % var_infos)
       
   151             
       
   152             self.PlugParent.FileGenerator.DeclareVariable(
       
   153                     slave_pos, var_infos["index"], var_infos["subindex"], 
       
   154                     var_infos["var_type"], var_infos["dir"], var_infos["var_name"], False)
       
   155         
       
   156         for element in ["located_variables_declaration", 
       
   157                         "entry_variables", 
       
   158                         "extern_pdo_entry_configuration", 
       
   159                         "retrieve_variables", 
       
   160                         "publish_variables"]:
       
   161             str_completion[element] = "\n".join(str_completion[element])
       
   162         
       
   163         Gen_DS402Nodefile_path = os.path.join(buildpath, "ds402node_%s.c"%location_str)
       
   164         ds402nodefile = open(Gen_DS402Nodefile_path, 'w')
       
   165         ds402nodefile.write(plc_ds402node_code % str_completion)
       
   166         ds402nodefile.close()
       
   167         
       
   168         for location in locations:
       
   169             loc = location["LOC"][len(current_location):]
       
   170             if variables.get(loc, None) is None:
       
   171                 self.PlugParent.FileGenerator.DeclareVariable(
       
   172                     slave_pos, loc[0], loc[1], location["IEC_TYPE"], location["DIR"], location["NAME"])
       
   173         
       
   174         return [(Gen_DS402Nodefile_path, '"-I%s"'%os.path.abspath(self.GetPlugRoot().GetIECLibPath()))],"",True
       
   175         
       
   176 
    10 
   177 
    11 TYPECONVERSION = {"BOOL" : "X", "SINT" : "B", "INT" : "W", "DINT" : "D", "LINT" : "L",
   178 TYPECONVERSION = {"BOOL" : "X", "SINT" : "B", "INT" : "W", "DINT" : "D", "LINT" : "L",
    12     "USINT" : "B", "UINT" : "W", "UDINT" : "D", "ULINT" : "L", 
   179     "USINT" : "B", "UINT" : "W", "UDINT" : "D", "ULINT" : "L", 
    13     "BYTE" : "B", "WORD" : "W", "DWORD" : "D", "LWORD" : "L"}
   180     "BYTE" : "B", "WORD" : "W", "DWORD" : "D", "LWORD" : "L"}
    14 
   181 
    15 DATATYPECONVERSION = {"BOOL" : "BIT", "SINT" : "S8", "INT" : "S16", "DINT" : "S32", "LINT" : "S64",
   182 DATATYPECONVERSION = {"BOOL" : "BIT", "SINT" : "S8", "INT" : "S16", "DINT" : "S32", "LINT" : "S64",
    16     "USINT" : "U8", "UINT" : "U16", "UDINT" : "U32", "ULINT" : "U64", 
   183     "USINT" : "U8", "UINT" : "U16", "UDINT" : "U32", "ULINT" : "U64", 
    17     "BYTE" : "U8", "WORD" : "U16", "DWORD" : "U32", "LWORD" : "U64"}
   184     "BYTE" : "U8", "WORD" : "U16", "DWORD" : "U32", "LWORD" : "U64"}
    18 
   185 
    19 VARCLASSCONVERSION = {"ro": LOCATION_VAR_INPUT, "wo": LOCATION_VAR_OUTPUT, "rw": LOCATION_VAR_MEMORY}
   186 VARCLASSCONVERSION = {"T": LOCATION_VAR_INPUT, "R": LOCATION_VAR_OUTPUT, "RT": LOCATION_VAR_MEMORY}
    20 
   187 
    21 #--------------------------------------------------
   188 #--------------------------------------------------
    22 #                 Ethercat MASTER
   189 #                 Ethercat MASTER
    23 #--------------------------------------------------
   190 #--------------------------------------------------
    24 
   191 
    84       </xsd:element>
   251       </xsd:element>
    85     </xsd:schema>
   252     </xsd:schema>
    86     """
   253     """
    87     EditorType = ConfigEditor
   254     EditorType = ConfigEditor
    88     
   255     
       
   256     PlugChildsTypes = [("EthercatDS402Slave", _EthercatDS402SlavePlug, "Ethercat DS402 Slave")]
       
   257     
    89     def __init__(self):
   258     def __init__(self):
    90         filepath = self.ConfigFileName()
   259         filepath = self.ConfigFileName()
    91         
   260         
    92         self.Config = EtherCATConfigClasses["EtherCATConfig"]()
   261         self.Config = EtherCATConfigClasses["EtherCATConfig"]()
    93         if os.path.isfile(filepath):
   262         if os.path.isfile(filepath):
   126                 return slave
   295                 return slave
   127         return None
   296         return None
   128 
   297 
   129     def AddSlave(self):
   298     def AddSlave(self):
   130         slaves = self.GetSlaves()
   299         slaves = self.GetSlaves()
       
   300         for PlugInstance in self.IterChilds():
       
   301             slaves.append((PlugInstance.BaseParams.getIEC_Channel(), 0))
       
   302         slaves.sort()
   131         if len(slaves) > 0:
   303         if len(slaves) > 0:
   132             new_pos = (slaves[-1][0] + 1, 0)
   304             new_pos = (slaves[-1][0] + 1, 0)
   133         else:
   305         else:
   134             new_pos = (0, 0)
   306             new_pos = (0, 0)
   135         slave = EtherCATConfigClasses["Config_Slave"]()
   307         slave = EtherCATConfigClasses["Config_Slave"]()
   149                 self.BufferConfig()
   321                 self.BufferConfig()
   150                 return True
   322                 return True
   151         return False
   323         return False
   152     
   324     
   153     def SetSlavePos(self, slave_pos, alias=None, position=None):
   325     def SetSlavePos(self, slave_pos, alias=None, position=None):
       
   326         for PlugInstance in self.IterChilds():
       
   327             if PlugInstance.BaseParams.getIEC_Channel() == alias:
       
   328                 return _("Slave with alias \"%d\" already exists!" % alias)
   154         slave = self.GetSlave(slave_pos)
   329         slave = self.GetSlave(slave_pos)
   155         if slave is not None:
   330         if slave is not None:
   156             slave_info = slave.getInfo()
   331             slave_info = slave.getInfo()
   157             new_pos = slave_pos
   332             new_pos = slave_pos
   158             if alias is not None:
   333             if alias is not None:
   195         return None
   370         return None
   196     
   371     
   197     def GetModuleInfos(self, type_infos):
   372     def GetModuleInfos(self, type_infos):
   198         return self.PlugParent.GetModuleInfos(type_infos)
   373         return self.PlugParent.GetModuleInfos(type_infos)
   199     
   374     
       
   375     def GetModulesByProfile(self, profile_type):
       
   376         return self.PlugParent.GetModulesByProfile(profile_type)
       
   377     
   200     def GetSlaveTypesLibrary(self):
   378     def GetSlaveTypesLibrary(self):
   201         return self.PlugParent.GetModulesLibrary()
   379         return self.PlugParent.GetModulesLibrary()
       
   380     
       
   381     def GetDeviceLocationTree(self, current_location, type_infos):
       
   382         vars = []
       
   383         
       
   384         device = self.GetModuleInfos(type_infos)
       
   385         if device is not None:
       
   386             sync_managers = []
       
   387             for sync_manager in device.getSm():
       
   388                 sync_manager_control_byte = ExtractHexDecValue(sync_manager.getControlByte())
       
   389                 sync_manager_direction = sync_manager_control_byte & 0x0c
       
   390                 if sync_manager_direction:
       
   391                     sync_managers.append(LOCATION_VAR_OUTPUT)
       
   392                 else:
       
   393                     sync_managers.append(LOCATION_VAR_INPUT)
       
   394             
       
   395             entries = device.GetEntriesList().items()
       
   396             entries.sort()
       
   397             for (index, subindex), entry in entries:
       
   398                 var_size = self.GetSizeOfType(entry["Type"])
       
   399                 if var_size is not None:
       
   400                     var_class = VARCLASSCONVERSION.get(entry["PDOMapping"], None)
       
   401                     if var_class is not None:
       
   402                         if var_class == LOCATION_VAR_INPUT:
       
   403                             var_dir = "%I"
       
   404                         else:
       
   405                             var_dir = "%Q"    
       
   406                     
       
   407                         vars.append({"name": "0x%4.4x-0x%2.2x: %s" % (index, subindex, entry["Name"]),
       
   408                                      "type": var_class,
       
   409                                      "size": var_size,
       
   410                                      "IEC_type": entry["Type"],
       
   411                                      "var_name": "%s_%4.4x_%2.2x" % (type_infos["device_type"], index, subindex),
       
   412                                      "location": "%s%s%s"%(var_dir, var_size, ".".join(map(str, current_location + 
       
   413                                                                                                 (index, subindex)))),
       
   414                                      "description": "",
       
   415                                      "children": []})
       
   416         
       
   417         return vars
   202     
   418     
   203     def GetVariableLocationTree(self):
   419     def GetVariableLocationTree(self):
   204         '''See PlugTemplate.GetVariableLocationTree() for a description.'''
   420         '''See PlugTemplate.GetVariableLocationTree() for a description.'''
   205 
   421 
   206         current_location = self.GetCurrentLocation()
   422         current_location = self.GetCurrentLocation()
   210             
   426             
   211             slave = self.GetSlave(slave_pos)
   427             slave = self.GetSlave(slave_pos)
   212             if slave is not None:
   428             if slave is not None:
   213                 type_infos = slave.getType()
   429                 type_infos = slave.getType()
   214                 
   430                 
   215                 device = self.GetModuleInfos(type_infos)
   431                 vars = self.GetDeviceLocationTree(current_location + slave_pos, type_infos)
   216                 if device is not None:
   432                 if len(vars) > 0:
   217                     vars = []
       
   218                     
       
   219                     sync_managers = []
       
   220                     for sync_manager in device.getSm():
       
   221                         sync_manager_control_byte = ExtractHexDecValue(sync_manager.getControlByte())
       
   222                         sync_manager_direction = sync_manager_control_byte & 0x0c
       
   223                         if sync_manager_direction:
       
   224                             sync_managers.append(LOCATION_VAR_OUTPUT)
       
   225                         else:
       
   226                             sync_managers.append(LOCATION_VAR_INPUT)
       
   227                     
       
   228                     entries = device.GetEntriesList().items()
       
   229                     entries.sort()
       
   230                     for (index, subindex), entry in entries:
       
   231                         var_size = self.GetSizeOfType(entry["Type"])
       
   232                         if var_size is not None:
       
   233                             var_class = VARCLASSCONVERSION.get(entry["Access"], LOCATION_VAR_MEMORY)
       
   234                             if var_class == LOCATION_VAR_INPUT:
       
   235                                 var_dir = "%I"
       
   236                             else:
       
   237                                 var_dir = "%Q"    
       
   238                             
       
   239                             vars.append({"name": "0x%4.4x-0x%2.2x: %s" % (index, subindex, entry["Name"]),
       
   240                                          "type": var_class,
       
   241                                          "size": var_size,
       
   242                                          "IEC_type": entry["Type"],
       
   243                                          "var_name": "%s_%4.4x_%2.2x" % (type_infos["device_type"], index, subindex),
       
   244                                          "location": "%s%s%s"%(var_dir, var_size, ".".join(map(str, current_location + 
       
   245                                                                                                     slave_pos + 
       
   246                                                                                                     (index, subindex)))),
       
   247                                          "description": "",
       
   248                                          "children": []})
       
   249                     
       
   250                     groups.append({"name": "%s (%d,%d)" % ((type_infos["device_type"],) + slave_pos),
   433                     groups.append({"name": "%s (%d,%d)" % ((type_infos["device_type"],) + slave_pos),
   251                                    "type": LOCATION_GROUP,
   434                                    "type": LOCATION_GROUP,
   252                                    "location": ".".join(map(str, current_location + slave_pos)) + ".x",
   435                                    "location": ".".join(map(str, current_location + slave_pos)) + ".x",
   253                                    "children": vars})
   436                                    "children": vars})
   254                 
   437                 
   279         xmlfile.write(text.encode("utf-8"))
   462         xmlfile.write(text.encode("utf-8"))
   280         xmlfile.close()
   463         xmlfile.close()
   281         
   464         
   282         self.ConfigBuffer.CurrentSaved()
   465         self.ConfigBuffer.CurrentSaved()
   283         return True
   466         return True
       
   467 
       
   468     def _Generate_C(self, buildpath, locations):
       
   469         current_location = self.GetCurrentLocation()
       
   470         # define a unique name for the generated C file
       
   471         location_str = "_".join(map(lambda x:str(x), current_location))
       
   472         
       
   473         Gen_Ethercatfile_path = os.path.join(buildpath, "ethercat_%s.c"%location_str)
       
   474         
       
   475         self.FileGenerator = _EthercatCFileGenerator(self)
       
   476         
       
   477         LocationCFilesAndCFLAGS, LDFLAGS, extra_files = PlugTemplate._Generate_C(self, buildpath, locations)
       
   478         
       
   479         self.FileGenerator.GenerateCFile(Gen_Ethercatfile_path, location_str, self.EtherlabNode)
       
   480         
       
   481         LocationCFilesAndCFLAGS.append(
       
   482             (current_location, 
       
   483              [(Gen_Ethercatfile_path, '"-I%s"'%os.path.abspath(self.GetPlugRoot().GetIECLibPath()))], 
       
   484              True))
       
   485         LDFLAGS.append("-lethercat -lrtdm")
       
   486         
       
   487         return LocationCFilesAndCFLAGS, LDFLAGS, extra_files
   284 
   488 
   285     def PlugGenerate_C(self, buildpath, locations):
   489     def PlugGenerate_C(self, buildpath, locations):
   286         """
   490         """
   287         Generate C code
   491         Generate C code
   288         @param current_location: Tupple containing plugin IEC location : %I0.0.4.5 => (0,0,4,5)
   492         @param current_location: Tupple containing plugin IEC location : %I0.0.4.5 => (0,0,4,5)
   294             "LOC" : tuple of interger for IEC location (0,1,2,...)
   498             "LOC" : tuple of interger for IEC location (0,1,2,...)
   295             }, ...]
   499             }, ...]
   296         @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND
   500         @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND
   297         """
   501         """
   298         current_location = self.GetCurrentLocation()
   502         current_location = self.GetCurrentLocation()
   299         # define a unique name for the generated C file
   503         
   300         location_str = "_".join(map(lambda x:str(x), current_location))
   504         slaves = self.GetSlaves()
   301         
   505         for slave_pos in slaves:
   302         Gen_Ethercatfile_path = os.path.join(buildpath, "ethercat_%s.c"%location_str)
   506             slave = self.GetSlave(slave_pos)
   303         
   507             if slave is not None:
   304         file_generator = _EthercatCFileGenerator(self, Gen_Ethercatfile_path)
   508                 self.FileGenerator.DeclareSlave(slave_pos, slave.getType())
   305         
   509         
   306         for location in locations:
   510         for location in locations:
   307             loc = location["LOC"][len(current_location):]
   511             loc = location["LOC"][len(current_location):]
   308             file_generator.DeclareVariable(loc[:2], loc[2], loc[3], location["IEC_TYPE"], location["DIR"], location["NAME"])
   512             slave_pos = loc[:2]
   309         
   513             if slave_pos in slaves:
   310         file_generator.GenerateCFile()
   514                 self.FileGenerator.DeclareVariable(
   311         
   515                     slave_pos, loc[2], loc[3], location["IEC_TYPE"], location["DIR"], location["NAME"])
   312         return [(Gen_Ethercatfile_path, '"-I%s"'%os.path.abspath(self.GetPlugRoot().GetIECLibPath()))], "-lethercat -lrtdm", True
   516         
   313 
   517         return [],"",False
       
   518         
   314 #-------------------------------------------------------------------------------
   519 #-------------------------------------------------------------------------------
   315 #                      Current Buffering Management Functions
   520 #                      Current Buffering Management Functions
   316 #-------------------------------------------------------------------------------
   521 #-------------------------------------------------------------------------------
   317 
   522 
   318     """
   523     """
   376         fprintf(stderr, "Failed to configure PDOs for slave %(device_type)s at alias %(alias)d and position %(position)d.\\n");
   581         fprintf(stderr, "Failed to configure PDOs for slave %(device_type)s at alias %(alias)d and position %(position)d.\\n");
   377         return -1;
   582         return -1;
   378     }
   583     }
   379 """
   584 """
   380 
   585 
       
   586 SLAVE_INITIALIZATION_TEMPLATE = """
       
   587     {
       
   588         uint8_t value[] = {%(data)s};
       
   589         if (ecrt_master_sdo_download(master, %(slave)d, 0x%(index).4x, 0x%(subindex).2x, (uint8_t *)value, %(data_size)d, &abort_code)) {
       
   590             fprintf(stderr, "Failed to initialize slave %(device_type)s at alias %(alias)d and position %(position)d.\\nError: %%d\\n", abort_code);
       
   591             return -1;
       
   592         }
       
   593     }
       
   594 """
       
   595 
   381 def ConfigureVariable(entry_infos, str_completion):
   596 def ConfigureVariable(entry_infos, str_completion):
   382     data_type = DATATYPECONVERSION.get(entry_infos["var_type"], None)
   597     entry_infos["data_type"] = DATATYPECONVERSION.get(entry_infos["var_type"], None)
   383     if data_type is None:
   598     if entry_infos["data_type"] is None:
   384         raise ValueError, _("Type of location \"%s\" not yet supported!") % entry_infos["var_name"]
   599         raise ValueError, _("Type of location \"%s\" not yet supported!") % entry_infos["var_name"]
   385     
   600 
   386     str_completion["located_variables_declaration"].extend(
   601     if not entry_infos.has_key("real_var"):
   387         ["IEC_%(var_type)s beremiz%(var_name)s;" % entry_infos,
   602         entry_infos["real_var"] = "beremiz" + entry_infos["var_name"]
   388          "IEC_%(var_type)s *%(var_name)s = &beremiz%(var_name)s;" % entry_infos])
   603         str_completion["located_variables_declaration"].append(
   389     
   604             "IEC_%(var_type)s %(real_var)s;" % entry_infos)
   390     if data_type == "BIT":
   605     str_completion["located_variables_declaration"].append(
   391         str_completion["used_pdo_entry_offset_variables_declaration"].extend(
   606          "IEC_%(var_type)s *%(var_name)s = &%(real_var)s;" % entry_infos)
   392             ["static unsigned int slave%(slave)d_%(index).4x_%(subindex).2x;" % entry_infos,
   607     
   393              "static unsigned int slave%(slave)d_%(index).4x_%(subindex).2x_bit;" % entry_infos])
   608     if entry_infos["data_type"] == "BIT":
       
   609         if entry_infos["dir"] == "I":
       
   610             str_completion["retrieve_variables"].append(
       
   611               ("    %(real_var)s = EC_READ_BIT(domain1_pd + slave%(slave)d_%(index).4x_%(subindex).2x, " + 
       
   612                "slave%(slave)d_%(index).4x_%(subindex).2x_bit);") % entry_infos)
       
   613         elif entry_infos["dir"] == "Q":
       
   614             str_completion["publish_variables"].append(
       
   615               ("    EC_WRITE_BIT(domain1_pd + slave%(slave)d_%(index).4x_%(subindex).2x, " + 
       
   616                "slave%(slave)d_%(index).4x_%(subindex).2x_bit, %(real_var)s);") % entry_infos)
       
   617     
       
   618     else:
       
   619         if entry_infos["dir"] == "I":
       
   620             str_completion["retrieve_variables"].append(
       
   621                 ("    %(real_var)s = EC_READ_%(data_type)s(domain1_pd + " + 
       
   622                  "slave%(slave)d_%(index).4x_%(subindex).2x);") % entry_infos)
       
   623         elif entry_infos["dir"] == "Q":
       
   624             str_completion["publish_variables"].append(
       
   625                 ("    EC_WRITE_%(data_type)s(domain1_pd + slave%(slave)d_%(index).4x_%(subindex).2x, " + 
       
   626                  "%(real_var)s);") % entry_infos)
       
   627 
       
   628 def ConfigurePDO(entry_infos, str_completion):
       
   629     str_completion["used_pdo_entry_offset_variables_declaration"].append(
       
   630         "unsigned int slave%(slave)d_%(index).4x_%(subindex).2x;" % entry_infos)
       
   631         
       
   632     if entry_infos["var_type"] == "BOOL":
       
   633         str_completion["used_pdo_entry_offset_variables_declaration"].append(
       
   634             "unsigned int slave%(slave)d_%(index).4x_%(subindex).2x_bit;" % entry_infos)
   394         
   635         
   395         str_completion["used_pdo_entry_configuration"].append(
   636         str_completion["used_pdo_entry_configuration"].append(
   396              ("    {%(alias)d, %(position)d, 0x%(vendor).8x, 0x%(product_code).8x, " + 
   637              ("    {%(alias)d, %(position)d, 0x%(vendor).8x, 0x%(product_code).8x, " + 
   397               "0x%(index).4x, %(subindex)d, &slave%(slave)d_%(index).4x_%(subindex).2x, " + 
   638               "0x%(index).4x, %(subindex)d, &slave%(slave)d_%(index).4x_%(subindex).2x, " + 
   398               "&slave%(slave)d_%(index).4x_%(subindex).2x_bit},") % entry_infos)
   639               "&slave%(slave)d_%(index).4x_%(subindex).2x_bit},") % entry_infos)
   399         
   640         
   400         if entry_infos["dir"] == "I":
       
   401             str_completion["retrieve_variables"].append(
       
   402               ("    beremiz%(name)s = EC_READ_BIT(domain1_pd + slave%(slave)d_%(index).4x_%(subindex).2x, " + 
       
   403                "slave%(slave)d_%(index).4x_%(subindex).2x_bit);") % entry_infos)
       
   404         elif entry_infos["dir"] == "Q":
       
   405             str_completion["publish_variables"].append(
       
   406               ("    EC_WRITE_BIT(domain1_pd + slave%(slave)d_%(index).4x_%(subindex).2x, " + 
       
   407                "slave%(slave)d_%(index).4x_%(subindex).2x_bit, beremiz%(var_name)s);") % entry_infos)
       
   408     
       
   409     else:
   641     else:
   410         entry_infos["data_type"] = data_type
       
   411         
       
   412         str_completion["used_pdo_entry_offset_variables_declaration"].append(
       
   413             "static unsigned int slave%(slave)d_%(index).4x_%(subindex).2x;" % entry_infos)
       
   414         
   642         
   415         str_completion["used_pdo_entry_configuration"].append(
   643         str_completion["used_pdo_entry_configuration"].append(
   416             ("    {%(alias)d, %(position)d, 0x%(vendor).8x, 0x%(product_code).8x, 0x%(index).4x, " + 
   644             ("    {%(alias)d, %(position)d, 0x%(vendor).8x, 0x%(product_code).8x, 0x%(index).4x, " + 
   417              "%(subindex)d, &slave%(slave)d_%(index).4x_%(subindex).2x},") % entry_infos)
   645              "%(subindex)d, &slave%(slave)d_%(index).4x_%(subindex).2x},") % entry_infos)
   418         
       
   419         if entry_infos["dir"] == "I":
       
   420             str_completion["retrieve_variables"].append(
       
   421                 ("    beremiz%(var_name)s = EC_READ_%(data_type)s(domain1_pd + " + 
       
   422                  "slave%(slave)d_%(index).4x_%(subindex).2x);") % entry_infos)
       
   423         elif entry_infos["dir"] == "Q":
       
   424             str_completion["publish_variables"].append(
       
   425                 ("    EC_WRITE_%(data_type)s(domain1_pd + slave%(slave)d_%(index).4x_%(subindex).2x, " + 
       
   426                  "beremiz%(var_name)s);") % entry_infos)
       
   427         
       
   428 
   646 
   429 class _EthercatCFileGenerator:
   647 class _EthercatCFileGenerator:
   430     
   648     
   431     def __init__(self, controler, filepath):
   649     def __init__(self, controler):
   432         self.Controler = controler
   650         self.Controler = controler
   433         self.FilePath = filepath
   651         
   434         
   652         self.Slaves = []
   435         self.UsedVariables = {}
   653         self.UsedVariables = {}
   436         
   654 
   437     def __del__(self):
   655     def __del__(self):
   438         self.Controler = None
   656         self.Controler = None            
   439 
   657 
   440     def DeclareVariable(self, slave_identifier, index, subindex, iec_type, dir, name):
   658     def DeclareSlave(self, slave_identifier, slave):
       
   659         self.Slaves.append((slave_identifier, slave))
       
   660         self.Slaves.sort()
       
   661         return self.Slaves.index((slave_identifier, slave))
       
   662 
       
   663     def DeclareVariable(self, slave_identifier, index, subindex, iec_type, dir, name, configure=True):
   441         slave_variables = self.UsedVariables.setdefault(slave_identifier, {})
   664         slave_variables = self.UsedVariables.setdefault(slave_identifier, {})
   442         
   665         
   443         entry_infos = slave_variables.get((index, subindex), None)
   666         entry_infos = slave_variables.get((index, subindex), None)
   444         if entry_infos is None:
   667         if entry_infos is None:
   445             slave_variables[(index, subindex)] = {
   668             slave_variables[(index, subindex)] = {
   446                 "infos": (iec_type, dir, name),
   669                 "infos": (iec_type, dir, name),
       
   670                 "configure": configure,
   447                 "mapped": False}
   671                 "mapped": False}
   448         elif entry_infos["infos"] != (iec_type, dir, name):
   672         elif entry_infos["infos"] != (iec_type, dir, name):
   449             raise ValueError, _("Definition conflict for location \"%s\"") % name 
   673             raise ValueError, _("Definition conflict for location \"%s\"") % name 
   450         
   674         
   451     def GenerateCFile(self):
   675     def GenerateCFile(self, filepath, location_str, etherlab_node_infos):
   452         
       
   453         current_location = self.Controler.GetCurrentLocation()
       
   454         # define a unique name for the generated C file
       
   455         location_str = "_".join(map(lambda x:str(x), current_location))
       
   456         
   676         
   457         plc_etherlab_filepath = os.path.join(os.path.split(__file__)[0], "plc_etherlab.c")
   677         plc_etherlab_filepath = os.path.join(os.path.split(__file__)[0], "plc_etherlab.c")
   458         plc_etherlab_file = open(plc_etherlab_filepath, 'r')
   678         plc_etherlab_file = open(plc_etherlab_filepath, 'r')
   459         plc_etherlab_code = plc_etherlab_file.read()
   679         plc_etherlab_code = plc_etherlab_file.read()
   460         plc_etherlab_file.close()
   680         plc_etherlab_file.close()
   461         
   681         
   462         str_completion = {
   682         str_completion = {
   463             "location": location_str,
   683             "location": location_str,
   464             "configure_pdos": int(self.Controler.EtherlabNode.getConfigurePDOs()),
   684             "configure_pdos": int(etherlab_node_infos.getConfigurePDOs()),
   465             "master_number": self.Controler.EtherlabNode.getMasterNumber(),
   685             "master_number": etherlab_node_infos.getMasterNumber(),
   466             "located_variables_declaration": [],
   686             "located_variables_declaration": [],
   467             "used_pdo_entry_offset_variables_declaration": [],
   687             "used_pdo_entry_offset_variables_declaration": [],
   468             "used_pdo_entry_configuration": [],
   688             "used_pdo_entry_configuration": [],
   469             "pdos_configuration_declaration": "",
   689             "pdos_configuration_declaration": "",
   470             "slaves_declaration": "",
   690             "slaves_declaration": "",
   471             "slaves_configuration": "",
   691             "slaves_configuration": "",
       
   692             "slaves_initialization": "",
   472             "retrieve_variables": [],
   693             "retrieve_variables": [],
   473             "publish_variables": [],
   694             "publish_variables": [],
   474         }
   695         }
   475         
   696         
   476         for slave_entries in self.UsedVariables.itervalues():
   697         for slave_entries in self.UsedVariables.itervalues():
   477             for entry_infos in slave_entries.itervalues():
   698             for entry_infos in slave_entries.itervalues():
   478                 entry_infos["mapped"] = False
   699                 entry_infos["mapped"] = False
   479         
   700         
   480         for slave_idx, slave_pos in enumerate(self.Controler.GetSlaves()):
   701         for slave_idx, (slave_pos, type_infos) in enumerate(self.Slaves):
   481             
   702             
   482             slave = self.Controler.GetSlave(slave_pos)
   703             device = self.Controler.GetModuleInfos(type_infos)
   483             if slave is not None:
   704             if device is not None:
   484                 type_infos = slave.getType()
   705             
       
   706                 slave_variables = self.UsedVariables.get(slave_pos, {})
       
   707                 device_entries = device.GetEntriesList()
   485                 
   708                 
   486                 device = self.Controler.GetModuleInfos(type_infos)
   709                 if len(device.getTxPdo() + device.getRxPdo()) > 0 or len(slave_variables) > 0:
   487                 if device is not None:
       
   488                     slave_variables = self.UsedVariables.get(slave_pos, {})
       
   489                     device_entries = device.GetEntriesList()
       
   490                     
   710                     
   491                     if len(device.getTxPdo() + device.getRxPdo()) > 0 or len(slave_variables) > 0:
   711                     for element in ["vendor", "product_code", "revision_number"]:
       
   712                         type_infos[element] = ExtractHexDecValue(type_infos[element])
       
   713                     type_infos.update(dict(zip(["slave", "alias", "position"], (slave_idx,) + slave_pos)))
       
   714                 
       
   715                     str_completion["slaves_declaration"] += "static ec_slave_config_t *slave%(slave)d = NULL;\n" % type_infos
       
   716                     str_completion["slaves_configuration"] += SLAVE_CONFIGURATION_TEMPLATE % type_infos
       
   717     
       
   718                     for initCmd in device.getInitCmd():
       
   719                         index = ExtractHexDecValue(initCmd.getIndex())
       
   720                         subindex = ExtractHexDecValue(initCmd.getSubIndex())
       
   721                         entry = device_entries.get((index, subindex), None)
       
   722                         if entry is not None:
       
   723                             data_size = entry["BitSize"] / 8
       
   724                             data = ("%%.%dx" % (data_size * 2)) % initCmd.getData().getcontent()
       
   725                             data_str = ",".join(["0x%s" % data[i:i+2] for i in xrange(0, data_size * 2, 2)])
       
   726                             init_cmd_infos = {
       
   727                                 "index": index,
       
   728                                 "subindex": subindex,
       
   729                                 "data": data_str,
       
   730                                 "data_size": data_size
       
   731                             }
       
   732                             init_cmd_infos.update(type_infos)
       
   733                             str_completion["slaves_initialization"] += SLAVE_INITIALIZATION_TEMPLATE % init_cmd_infos
       
   734 
       
   735                     pdos_infos = {
       
   736                         "pdos_entries_infos": [],
       
   737                         "pdos_infos": [],
       
   738                         "pdos_sync_infos": [], 
       
   739                     }
       
   740                     pdos_infos.update(type_infos)
       
   741                     
       
   742                     sync_managers = []
       
   743                     for sync_manager_idx, sync_manager in enumerate(device.getSm()):
       
   744                         sync_manager_infos = {
       
   745                             "index": sync_manager_idx, 
       
   746                             "name": sync_manager.getcontent(),
       
   747                             "slave": slave_idx,
       
   748                             "pdos": [], 
       
   749                             "pdos_number": 0,
       
   750                         }
   492                         
   751                         
   493                         for element in ["vendor", "product_code", "revision_number"]:
   752                         sync_manager_control_byte = ExtractHexDecValue(sync_manager.getControlByte())
   494                             type_infos[element] = ExtractHexDecValue(type_infos[element])
   753                         sync_manager_direction = sync_manager_control_byte & 0x0c
   495                         type_infos.update(dict(zip(["slave", "alias", "position"], (slave_idx,) + slave_pos)))
   754                         sync_manager_watchdog = sync_manager_control_byte & 0x40
       
   755                         if sync_manager_direction:
       
   756                             sync_manager_infos["sync_manager_type"] = "EC_DIR_OUTPUT"
       
   757                         else:
       
   758                             sync_manager_infos["sync_manager_type"] = "EC_DIR_INPUT"
       
   759                         if sync_manager_watchdog:
       
   760                             sync_manager_infos["watchdog"] = "EC_WD_ENABLE"
       
   761                         else:
       
   762                             sync_manager_infos["watchdog"] = "EC_WD_DISABLE"
       
   763                         
       
   764                         sync_managers.append(sync_manager_infos)
   496                     
   765                     
   497                         str_completion["slaves_declaration"] += "static ec_slave_config_t *slave%(slave)d = NULL;\n" % type_infos
   766                     pdos_index = []
   498                         str_completion["slaves_configuration"] += SLAVE_CONFIGURATION_TEMPLATE % type_infos
   767                     for only_mandatory in [True, False]:
   499     
   768                         for pdo, pdo_type in ([(pdo, "Inputs") for pdo in device.getTxPdo()] +
   500                         pdos_infos = {
   769                                               [(pdo, "Outputs") for pdo in device.getRxPdo()]):
   501                             "pdos_entries_infos": [],
   770                             entries = pdo.getEntry()
   502                             "pdos_infos": [],
   771                             
   503                             "pdos_sync_infos": [], 
   772                             pdo_needed = pdo.getMandatory()
   504                         }
   773                             if pdo_needed is None:
   505                         pdos_infos.update(type_infos)
   774                                 pdo_needed = False
   506                         
   775                             if only_mandatory != pdo_needed:
   507                         sync_managers = []
   776                                 continue
   508                         for sync_manager_idx, sync_manager in enumerate(device.getSm()):
   777                             
   509                             sync_manager_infos = {
   778                             pdo_index = ExtractHexDecValue(pdo.getIndex().getcontent())
   510                                 "index": sync_manager_idx, 
   779                             pdos_index.append(pdo_index)
   511                                 "name": sync_manager.getcontent(),
   780                             entries_infos = []
   512                                 "slave": slave_idx,
   781                             
   513                                 "pdos": [], 
   782                             for entry in entries:
   514                                 "pdos_number": 0,
   783                                 index = ExtractHexDecValue(entry.getIndex().getcontent())
   515                             }
   784                                 subindex = ExtractHexDecValue(entry.getSubIndex())
   516                             
       
   517                             sync_manager_control_byte = ExtractHexDecValue(sync_manager.getControlByte())
       
   518                             sync_manager_direction = sync_manager_control_byte & 0x0c
       
   519                             sync_manager_watchdog = sync_manager_control_byte & 0x40
       
   520                             if sync_manager_direction:
       
   521                                 sync_manager_infos["sync_manager_type"] = "EC_DIR_OUTPUT"
       
   522                             else:
       
   523                                 sync_manager_infos["sync_manager_type"] = "EC_DIR_INPUT"
       
   524                             if sync_manager_watchdog:
       
   525                                 sync_manager_infos["watchdog"] = "EC_WD_ENABLE"
       
   526                             else:
       
   527                                 sync_manager_infos["watchdog"] = "EC_WD_DISABLE"
       
   528                             
       
   529                             sync_managers.append(sync_manager_infos)
       
   530                         
       
   531                         pdos_index = []
       
   532                         for only_mandatory in [True, False]:
       
   533                             for pdo, pdo_type in ([(pdo, "Inputs") for pdo in device.getTxPdo()] +
       
   534                                                   [(pdo, "Outputs") for pdo in device.getRxPdo()]):
       
   535                                 entries = pdo.getEntry()
       
   536                                 
       
   537                                 pdo_needed = pdo.getMandatory()
       
   538                                 if only_mandatory != pdo_needed:
       
   539                                     continue
       
   540                                 
       
   541                                 pdo_index = ExtractHexDecValue(pdo.getIndex().getcontent())
       
   542                                 pdos_index.append(pdo_index)
       
   543                                 entries_infos = []
       
   544                                 
       
   545                                 for entry in entries:
       
   546                                     index = ExtractHexDecValue(entry.getIndex().getcontent())
       
   547                                     subindex = ExtractHexDecValue(entry.getSubIndex())
       
   548                                     entry_infos = {
       
   549                                         "index": index,
       
   550                                         "subindex": subindex,
       
   551                                         "name": ExtractName(entry.getName()),
       
   552                                         "bitlen": entry.getBitLen(),
       
   553                                     }
       
   554                                     entry_infos.update(type_infos)
       
   555                                     entries_infos.append("    {0x%(index).4x, 0x%(subindex).2x, %(bitlen)d}, /* %(name)s */" % entry_infos)
       
   556                                     
       
   557                                     entry_declaration = slave_variables.get((index, subindex), None)
       
   558                                     if entry_declaration is not None and not entry_declaration["mapped"]:
       
   559                                         pdo_needed = True
       
   560                                         
       
   561                                         entry_infos.update(dict(zip(["var_type", "dir", "var_name"], entry_declaration["infos"])))
       
   562                                         entry_declaration["mapped"] = True
       
   563                                         
       
   564                                         if entry_infos["var_type"] != entry.getDataType().getcontent():
       
   565                                             raise ValueError, _("Wrong type for location \"%s\"!") % entry_infos["var_name"]
       
   566                                         
       
   567                                         if (entry_infos["dir"] == "I" and pdo_type != "Inputs" or 
       
   568                                             entry_infos["dir"] == "Q" and pdo_type != "Outputs"):
       
   569                                             raise ValueError, _("Wrong direction for location \"%s\"!") % entry_infos["var_name"]
       
   570                                         
       
   571                                         ConfigureVariable(entry_infos, str_completion)
       
   572                                 
       
   573                                 if pdo_needed:
       
   574                                     sm = pdo.getSm()
       
   575                                     if sm is None:
       
   576                                         for sm_idx, sync_manager in enumerate(sync_managers):
       
   577                                             if sync_manager["name"] == pdo_type:
       
   578                                                 sm = sm_idx
       
   579                                     if sm is None:
       
   580                                         raise ValueError, _("No sync manager available for %s pdo!") % pdo_type
       
   581                                         
       
   582                                     sync_managers[sm]["pdos_number"] += 1
       
   583                                     sync_managers[sm]["pdos"].append(
       
   584                                         {"slave": slave_idx,
       
   585                                          "index": pdo_index,
       
   586                                          "name": ExtractName(pdo.getName()),
       
   587                                          "type": pdo_type, 
       
   588                                          "entries": entries_infos,
       
   589                                          "entries_number": len(entries_infos),
       
   590                                          "fixed": pdo.getFixed() == True})
       
   591                         
       
   592                         dynamic_pdos = {}
       
   593                         dynamic_pdos_number = 0
       
   594                         for category, min_index, max_index in [("Inputs", 0x1600, 0x1800), 
       
   595                                                                ("Outputs", 0x1a00, 0x1C00)]:
       
   596                             for sync_manager in sync_managers:
       
   597                                 if sync_manager["name"] == category:
       
   598                                     category_infos = dynamic_pdos.setdefault(category, {})
       
   599                                     category_infos["sync_manager"] = sync_manager
       
   600                                     category_infos["pdos"] = [pdo for pdo in category_infos["sync_manager"]["pdos"] 
       
   601                                                               if not pdo["fixed"] and pdo["type"] == category]
       
   602                                     category_infos["current_index"] = min_index
       
   603                                     category_infos["max_index"] = max_index
       
   604                                     break
       
   605                         
       
   606                         for (index, subindex), entry_declaration in slave_variables.iteritems():
       
   607                             
       
   608                             if not entry_declaration["mapped"]:
       
   609                                 entry = device_entries.get((index, subindex), None)
       
   610                                 if entry is None:
       
   611                                     raise ValueError, _("Unknown entry index 0x%4.4x, subindex 0x%2.2x for device %s") % \
       
   612                                                      (index, subindex, type_infos["device_type"])
       
   613                                 
       
   614                                 entry_infos = {
   785                                 entry_infos = {
   615                                     "index": index,
   786                                     "index": index,
   616                                     "subindex": subindex,
   787                                     "subindex": subindex,
   617                                     "name": entry["Name"],
   788                                     "name": ExtractName(entry.getName()),
   618                                     "bitlen": entry["BitSize"],
   789                                     "bitlen": entry.getBitLen(),
   619                                 }
   790                                 }
   620                                 entry_infos.update(type_infos)
   791                                 entry_infos.update(type_infos)
       
   792                                 entries_infos.append("    {0x%(index).4x, 0x%(subindex).2x, %(bitlen)d}, /* %(name)s */" % entry_infos)
   621                                 
   793                                 
   622                                 entry_infos.update(dict(zip(["var_type", "dir", "var_name"], entry_declaration["infos"])))
   794                                 entry_declaration = slave_variables.get((index, subindex), None)
   623                                 entry_declaration["mapped"] = True
   795                                 if entry_declaration is not None and not entry_declaration["mapped"]:
       
   796                                     pdo_needed = True
       
   797                                     
       
   798                                     entry_infos.update(dict(zip(["var_type", "dir", "var_name"], entry_declaration["infos"])))
       
   799                                     entry_declaration["mapped"] = True
       
   800                                     
       
   801                                     if entry_infos["var_type"] != entry.getDataType().getcontent():
       
   802                                         raise ValueError, _("Wrong type for location \"%s\"!") % entry_infos["var_name"]
       
   803                                     
       
   804                                     if (entry_infos["dir"] == "I" and pdo_type != "Inputs" or 
       
   805                                         entry_infos["dir"] == "Q" and pdo_type != "Outputs"):
       
   806                                         raise ValueError, _("Wrong direction for location \"%s\"!") % entry_infos["var_name"]
       
   807                                     
       
   808                                     if entry_declaration["configure"]:
       
   809                                         ConfigureVariable(entry_infos, str_completion)
       
   810                                     ConfigurePDO(entry_infos, str_completion)
       
   811                             
       
   812                             if pdo_needed:
       
   813                                 sm = pdo.getSm()
       
   814                                 if sm is None:
       
   815                                     for sm_idx, sync_manager in enumerate(sync_managers):
       
   816                                         if sync_manager["name"] == pdo_type:
       
   817                                             sm = sm_idx
       
   818                                 if sm is None:
       
   819                                     raise ValueError, _("No sync manager available for %s pdo!") % pdo_type
       
   820                                     
       
   821                                 sync_managers[sm]["pdos_number"] += 1
       
   822                                 sync_managers[sm]["pdos"].append(
       
   823                                     {"slave": slave_idx,
       
   824                                      "index": pdo_index,
       
   825                                      "name": ExtractName(pdo.getName()),
       
   826                                      "type": pdo_type, 
       
   827                                      "entries": entries_infos,
       
   828                                      "entries_number": len(entries_infos),
       
   829                                      "fixed": pdo.getFixed() == True})
       
   830                     
       
   831                     dynamic_pdos = {}
       
   832                     dynamic_pdos_number = 0
       
   833                     for category, min_index, max_index in [("Inputs", 0x1600, 0x1800), 
       
   834                                                            ("Outputs", 0x1a00, 0x1C00)]:
       
   835                         for sync_manager in sync_managers:
       
   836                             if sync_manager["name"] == category:
       
   837                                 category_infos = dynamic_pdos.setdefault(category, {})
       
   838                                 category_infos["sync_manager"] = sync_manager
       
   839                                 category_infos["pdos"] = [pdo for pdo in category_infos["sync_manager"]["pdos"] 
       
   840                                                           if not pdo["fixed"] and pdo["type"] == category]
       
   841                                 category_infos["current_index"] = min_index
       
   842                                 category_infos["max_index"] = max_index
       
   843                                 break
       
   844                     
       
   845                     for (index, subindex), entry_declaration in slave_variables.iteritems():
       
   846                         
       
   847                         if not entry_declaration["mapped"]:
       
   848                             entry = device_entries.get((index, subindex), None)
       
   849                             if entry is None:
       
   850                                 raise ValueError, _("Unknown entry index 0x%4.4x, subindex 0x%2.2x for device %s") % \
       
   851                                                  (index, subindex, type_infos["device_type"])
       
   852                             
       
   853                             entry_infos = {
       
   854                                 "index": index,
       
   855                                 "subindex": subindex,
       
   856                                 "name": entry["Name"],
       
   857                                 "bitlen": entry["BitSize"],
       
   858                             }
       
   859                             entry_infos.update(type_infos)
       
   860                             
       
   861                             entry_infos.update(dict(zip(["var_type", "dir", "var_name", "real_var"], entry_declaration["infos"])))
       
   862                             entry_declaration["mapped"] = True
       
   863                             
       
   864                             if entry_infos["var_type"] != entry["Type"]:
       
   865                                 raise ValueError, _("Wrong type for location \"%s\"!") % entry_infos["var_name"]
       
   866                             
       
   867                             if entry_infos["dir"] == "I" and entry["PDOMapping"] in ["T", "RT"]:
       
   868                                 pdo_type = "Inputs"
       
   869                             elif entry_infos["dir"] == "Q" and entry["PDOMapping"] in ["R", "RT"]:
       
   870                                 pdo_type = "Outputs"
       
   871                             else:
       
   872                                 raise ValueError, _("Wrong direction for location \"%s\"!") % entry_infos["var_name"]
       
   873                             
       
   874                             if not dynamic_pdos.has_key(pdo_type):
       
   875                                 raise ValueError, _("No Sync manager defined for %s!") % pdo_type
       
   876                             
       
   877                             if entry_declaration["configure"]:
       
   878                                 ConfigureVariable(entry_infos, str_completion)
       
   879                             ConfigurePDO(entry_infos, str_completion)
       
   880                             
       
   881                             if len(dynamic_pdos[pdo_type]["pdos"]) > 0:
       
   882                                 pdo = dynamic_pdos[pdo_type]["pdos"][0]
       
   883                             else:
       
   884                                 while dynamic_pdos[pdo_type]["current_index"] in pdos_index:
       
   885                                     dynamic_pdos[pdo_type]["current_index"] += 1
       
   886                                 if dynamic_pdos[pdo_type]["current_index"] >= dynamic_pdos[pdo_type]["max_index"]:
       
   887                                     raise ValueError, _("No more free PDO index available for %s!") % pdo_type
       
   888                                 pdos_index.append(dynamic_pdos[pdo_type]["current_index"])
   624                                 
   889                                 
   625                                 if entry_infos["var_type"] != entry["Type"]:
   890                                 dynamic_pdos_number += 1
   626                                     raise ValueError, _("Wrong type for location \"%s\"!") % entry_infos["var_name"]
   891                                 pdo = {"slave": slave_idx,
   627                                 
   892                                        "index": dynamic_pdos[pdo_type]["current_index"],
   628                                 if entry_infos["dir"] == "I" and entry["Access"] in ["ro", "rw"]:
   893                                        "name": "Dynamic PDO %d" % dynamic_pdos_number,
   629                                     pdo_type = "Inputs"
   894                                        "type": pdo_type, 
   630                                 elif entry_infos["dir"] == "Q" and entry["Access"] in ["wo", "rw"]:
   895                                        "entries": [],
   631                                     pdo_type = "Outputs"
   896                                        "entries_number": 0,
   632                                 else:
   897                                        "fixed": False}
   633                                     raise ValueError, _("Wrong direction for location \"%s\"!") % entry_infos["var_name"]
   898                                 dynamic_pdos[pdo_type]["sync_manager"]["pdos_number"] += 1
   634                                 
   899                                 dynamic_pdos[pdo_type]["sync_manager"]["pdos"].append(pdo)
   635                                 if not dynamic_pdos.has_key(pdo_type):
   900                                 dynamic_pdos[pdo_type]["pdos"].append(pdo)
   636                                     raise ValueError, _("No Sync manager defined for %s!") % pdo_type
   901                             
   637                                 
   902                             pdo["entries"].append("    {0x%(index).4x, 0x%(subindex).2x, %(bitlen)d}, /* %(name)s */" % entry_infos)
   638                                 ConfigureVariable(entry_infos, str_completion)
   903                             pdo["entries_number"] += 1
   639                                 
   904                             
   640                                 if len(dynamic_pdos[pdo_type]["pdos"]) > 0:
   905                             if pdo["entries_number"] == 255:
   641                                     pdo = dynamic_pdos[pdo_type]["pdos"][0]
   906                                 dynamic_pdos[pdo_type]["pdos"].pop(0)
   642                                 else:
   907                             
   643                                     while dynamic_pdos[pdo_type]["current_index"] in pdos_index:
   908                     pdo_offset = 0
   644                                         dynamic_pdos[pdo_type]["current_index"] += 1
   909                     entry_offset = 0
   645                                     if dynamic_pdos[pdo_type]["current_index"] >= dynamic_pdos[pdo_type]["max_index"]:
   910                     for sync_manager_infos in sync_managers:
   646                                         raise ValueError, _("No more free PDO index available for %s!") % pdo_type
       
   647                                     pdos_index.append(dynamic_pdos[pdo_type]["current_index"])
       
   648                                     
       
   649                                     dynamic_pdos_number += 1
       
   650                                     pdo = {"slave": slave_idx,
       
   651                                            "index": dynamic_pdos[pdo_type]["current_index"],
       
   652                                            "name": "Dynamic PDO %d" % dynamic_pdos_number,
       
   653                                            "type": pdo_type, 
       
   654                                            "entries": [],
       
   655                                            "entries_number": 0,
       
   656                                            "fixed": False}
       
   657                                     dynamic_pdos[pdo_type]["sync_manager"]["pdos_number"] += 1
       
   658                                     dynamic_pdos[pdo_type]["sync_manager"]["pdos"].append(pdo)
       
   659                                     dynamic_pdos[pdo_type]["pdos"].append(pdo)
       
   660                                 
       
   661                                 pdo["entries"].append("    {0x%(index).4x, 0x%(subindex).2x, %(bitlen)d}, /* %(name)s */" % entry_infos)
       
   662                                 pdo["entries_number"] += 1
       
   663                                 
       
   664                                 if pdo["entries_number"] == 255:
       
   665                                     dynamic_pdos[pdo_type]["pdos"].pop(0)
       
   666                                 
       
   667                         pdo_offset = 0
       
   668                         entry_offset = 0
       
   669                         for sync_manager_infos in sync_managers:
       
   670                             
       
   671                             for pdo_infos in sync_manager_infos["pdos"]:
       
   672                                 pdo_infos["offset"] = entry_offset
       
   673                                 pdo_entries = pdo_infos["entries"]
       
   674                                 pdos_infos["pdos_infos"].append(
       
   675                                     ("    {0x%(index).4x, %(entries_number)d, " + 
       
   676                                      "slave_%(slave)d_pdo_entries + %(offset)d}, /* %(name)s */") % pdo_infos)
       
   677                                 entry_offset += len(pdo_entries)
       
   678                                 pdos_infos["pdos_entries_infos"].extend(pdo_entries)
       
   679                             
       
   680                             sync_manager_infos["offset"] = pdo_offset
       
   681                             pdos_infos["pdos_sync_infos"].append(
       
   682                                 ("    {%(index)d, %(sync_manager_type)s, %(pdos_number)d, " + 
       
   683                                  "slave_%(slave)d_pdos + %(offset)d, %(watchdog)s},") % sync_manager_infos)
       
   684                             pdo_offset += sync_manager_infos["pdos_number"]
       
   685                         
   911                         
   686                         for element in ["pdos_entries_infos", "pdos_infos", "pdos_sync_infos"]:
   912                         for pdo_infos in sync_manager_infos["pdos"]:
   687                             pdos_infos[element] = "\n".join(pdos_infos[element])
   913                             pdo_infos["offset"] = entry_offset
       
   914                             pdo_entries = pdo_infos["entries"]
       
   915                             pdos_infos["pdos_infos"].append(
       
   916                                 ("    {0x%(index).4x, %(entries_number)d, " + 
       
   917                                  "slave_%(slave)d_pdo_entries + %(offset)d}, /* %(name)s */") % pdo_infos)
       
   918                             entry_offset += len(pdo_entries)
       
   919                             pdos_infos["pdos_entries_infos"].extend(pdo_entries)
   688                         
   920                         
   689                         str_completion["pdos_configuration_declaration"] += SLAVE_PDOS_CONFIGURATION_DECLARATION % pdos_infos
   921                         sync_manager_infos["offset"] = pdo_offset
       
   922                         pdos_infos["pdos_sync_infos"].append(
       
   923                             ("    {%(index)d, %(sync_manager_type)s, %(pdos_number)d, " + 
       
   924                              "slave_%(slave)d_pdos + %(offset)d, %(watchdog)s},") % sync_manager_infos)
       
   925                         pdo_offset += sync_manager_infos["pdos_number"]
       
   926                     
       
   927                     for element in ["pdos_entries_infos", "pdos_infos", "pdos_sync_infos"]:
       
   928                         pdos_infos[element] = "\n".join(pdos_infos[element])
       
   929                     
       
   930                     str_completion["pdos_configuration_declaration"] += SLAVE_PDOS_CONFIGURATION_DECLARATION % pdos_infos
   690         
   931         
   691         for element in ["used_pdo_entry_offset_variables_declaration", 
   932         for element in ["used_pdo_entry_offset_variables_declaration", 
   692                         "used_pdo_entry_configuration", 
   933                         "used_pdo_entry_configuration", 
   693                         "located_variables_declaration", 
   934                         "located_variables_declaration", 
   694                         "retrieve_variables", 
   935                         "retrieve_variables", 
   695                         "publish_variables"]:
   936                         "publish_variables"]:
   696             str_completion[element] = "\n".join(str_completion[element])
   937             str_completion[element] = "\n".join(str_completion[element])
   697         
   938         
   698         etherlabfile = open(self.FilePath,'w')
   939         etherlabfile = open(filepath, 'w')
   699         etherlabfile.write(plc_etherlab_code % str_completion)
   940         etherlabfile.write(plc_etherlab_code % str_completion)
   700         etherlabfile.close()
   941         etherlabfile.close()
   701 
   942 
   702 #--------------------------------------------------
   943 #--------------------------------------------------
   703 #                 Ethercat Plugin
   944 #                 Ethercat Plugin
   706 EtherCATInfoClasses = GenerateClassesFromXSD(os.path.join(os.path.dirname(__file__), "EtherCATInfo.xsd")) 
   947 EtherCATInfoClasses = GenerateClassesFromXSD(os.path.join(os.path.dirname(__file__), "EtherCATInfo.xsd")) 
   707 
   948 
   708 cls = EtherCATInfoClasses["EtherCATInfo.xsd"].get("DeviceType", None)
   949 cls = EtherCATInfoClasses["EtherCATInfo.xsd"].get("DeviceType", None)
   709 if cls:
   950 if cls:
   710     cls.DataTypes = None
   951     cls.DataTypes = None
       
   952     
       
   953     def GetProfileNumbers(self):
       
   954         profiles = []
       
   955         
       
   956         for profile in self.getProfile():
       
   957             profile_content = profile.getcontent()
       
   958             if profile_content is None:
       
   959                 continue
       
   960             
       
   961             for content_element in profile_content["value"]:
       
   962                 if content_element["name"] == "ProfileNo":
       
   963                     profiles.append(content_element["value"])
       
   964         
       
   965         return profiles
       
   966     setattr(cls, "GetProfileNumbers", GetProfileNumbers)
   711     
   967     
   712     def GetProfileDictionaries(self):
   968     def GetProfileDictionaries(self):
   713         dictionaries = []
   969         dictionaries = []
   714         
   970         
   715         for profile in self.getProfile():
   971         for profile in self.getProfile():
   740                     if content is not None and content["name"] == "SubItem":
   996                     if content is not None and content["name"] == "SubItem":
   741                         self.DataTypes[datatype.getName()] = datatype
   997                         self.DataTypes[datatype.getName()] = datatype
   742     
   998     
   743     setattr(cls, "ExtractDataTypes", ExtractDataTypes)
   999     setattr(cls, "ExtractDataTypes", ExtractDataTypes)
   744     
  1000     
       
  1001     def getInitCmd(self):
       
  1002         mailbox = self.getMailbox()
       
  1003         if mailbox is None:
       
  1004             return []
       
  1005         
       
  1006         coe = mailbox.getCoE()
       
  1007         if coe is None:
       
  1008             return []
       
  1009 
       
  1010         return coe.getInitCmd()
       
  1011     setattr(cls, "getInitCmd", getInitCmd)
       
  1012 
   745     def GetEntriesList(self):
  1013     def GetEntriesList(self):
   746         if self.DataTypes is None:
  1014         if self.DataTypes is None:
   747             self.ExtractDataTypes()
  1015             self.ExtractDataTypes()
   748         
  1016         
   749         entries = {}
  1017         entries = {}
   763                         entry_subidx = subitem.getSubIdx()
  1031                         entry_subidx = subitem.getSubIdx()
   764                         if entry_subidx is None:
  1032                         if entry_subidx is None:
   765                             entry_subidx = "0"
  1033                             entry_subidx = "0"
   766                         subidx = ExtractHexDecValue(entry_subidx)
  1034                         subidx = ExtractHexDecValue(entry_subidx)
   767                         subitem_access = ""
  1035                         subitem_access = ""
       
  1036                         subitem_pdomapping = ""
   768                         subitem_flags = subitem.getFlags()
  1037                         subitem_flags = subitem.getFlags()
   769                         if subitem_flags is not None:
  1038                         if subitem_flags is not None:
   770                             access = subitem_flags.getAccess()
  1039                             access = subitem_flags.getAccess()
   771                             if access is not None:
  1040                             if access is not None:
   772                                 subitem_access = access.getcontent()
  1041                                 subitem_access = access.getcontent()
       
  1042                             pdomapping = subitem_flags.getPdoMapping()
       
  1043                             if pdomapping is not None:
       
  1044                                 subitem_pdomapping = pdomapping.upper()
   773                         entries[(index, subidx)] = {
  1045                         entries[(index, subidx)] = {
   774                             "Index": entry_index,
  1046                             "Index": entry_index,
   775                             "SubIndex": entry_subidx,
  1047                             "SubIndex": entry_subidx,
   776                             "Name": "%s - %s" % 
  1048                             "Name": "%s - %s" % 
   777                                     (entry_name.decode("utf-8"),
  1049                                     (entry_name.decode("utf-8"),
   778                                      ExtractName(subitem.getDisplayName(), 
  1050                                      ExtractName(subitem.getDisplayName(), 
   779                                                  subitem.getName()).decode("utf-8")),
  1051                                                  subitem.getName()).decode("utf-8")),
   780                             "Type": subitem.getType(),
  1052                             "Type": subitem.getType(),
   781                             "BitSize": subitem.getBitSize(),
  1053                             "BitSize": subitem.getBitSize(),
   782                             "Access": subitem_access, 
  1054                             "Access": subitem_access, 
       
  1055                             "PDOMapping": subitem_pdomapping, 
   783                             "PDO index": "", 
  1056                             "PDO index": "", 
   784                             "PDO name": "", 
  1057                             "PDO name": "", 
   785                             "PDO type": ""}
  1058                             "PDO type": ""}
   786                 else:
  1059                 else:
   787                     entry_access = ""
  1060                     entry_access = ""
       
  1061                     entry_pdomapping = ""
   788                     entry_flags = object.getFlags()
  1062                     entry_flags = object.getFlags()
   789                     if entry_flags is not None:
  1063                     if entry_flags is not None:
   790                         access = entry_flags.getAccess()
  1064                         access = entry_flags.getAccess()
   791                         if access is not None:
  1065                         if access is not None:
   792                             entry_access = access.getcontent()
  1066                             entry_access = access.getcontent()
       
  1067                         pdomapping = entry_flags.getPdoMapping()
       
  1068                         if pdomapping is not None:
       
  1069                             entry_pdomapping = pdomapping.upper()
   793                     entries[(index, 0)] = {
  1070                     entries[(index, 0)] = {
   794                          "Index": entry_index,
  1071                          "Index": entry_index,
   795                          "SubIndex": "0",
  1072                          "SubIndex": "0",
   796                          "Name": entry_name,
  1073                          "Name": entry_name,
   797                          "Type": entry_type,
  1074                          "Type": entry_type,
   798                          "BitSize": object.getBitSize(),
  1075                          "BitSize": object.getBitSize(),
   799                          "Access": entry_access,
  1076                          "Access": entry_access,
       
  1077                          "PDOMapping": entry_pdomapping, 
   800                          "PDO index": "", 
  1078                          "PDO index": "", 
   801                          "PDO name": "", 
  1079                          "PDO name": "", 
   802                          "PDO type": ""}
  1080                          "PDO type": ""}
   803         
  1081         
   804         for TxPdo in self.getTxPdo():
  1082         for TxPdo in self.getTxPdo():
   867         else:
  1145         else:
   868             entry_type = pdo_entry.getDataType()
  1146             entry_type = pdo_entry.getDataType()
   869             if entry_type is not None:
  1147             if entry_type is not None:
   870                 if pdo_type == "Transmit":
  1148                 if pdo_type == "Transmit":
   871                     access = "ro"
  1149                     access = "ro"
       
  1150                     pdomapping = "T"
   872                 else:
  1151                 else:
   873                     access = "wo"
  1152                     access = "wo"
       
  1153                     pdomapping = "R"
   874                 entries[(index, subindex)] = {
  1154                 entries[(index, subindex)] = {
   875                     "Index": entry_index,
  1155                     "Index": entry_index,
   876                     "SubIndex": entry_subindex,
  1156                     "SubIndex": entry_subindex,
   877                     "Name": ExtractName(pdo_entry.getName()),
  1157                     "Name": ExtractName(pdo_entry.getName()),
   878                     "Type": entry_type.getcontent(),
  1158                     "Type": entry_type.getcontent(),
   879                     "Access": access,
  1159                     "Access": access,
       
  1160                     "PDOMapping": pdomapping,
   880                     "PDO index": pdo_index, 
  1161                     "PDO index": pdo_index, 
   881                     "PDO name": pdo_name, 
  1162                     "PDO name": pdo_name, 
   882                     "PDO type": pdo_type}
  1163                     "PDO type": pdo_type}
   883 
  1164 
   884 class RootClass:
  1165 class RootClass:
  1002                         product_code == ExtractHexDecValue(type_infos["product_code"]) and
  1283                         product_code == ExtractHexDecValue(type_infos["product_code"]) and
  1003                         revision_number == ExtractHexDecValue(type_infos["revision_number"])):
  1284                         revision_number == ExtractHexDecValue(type_infos["revision_number"])):
  1004                         return device
  1285                         return device
  1005         return None
  1286         return None
  1006     
  1287     
       
  1288     def GetModulesByProfile(self, profile_type):
       
  1289         modules = []
       
  1290         for vendor_id, vendor in self.ModulesLibrary.iteritems():
       
  1291             for group_type, group in vendor["groups"].iteritems():
       
  1292                 for device_type, device in group["devices"]:
       
  1293                     if profile_type in device.GetProfileNumbers():
       
  1294                         product_code = ExtractHexDecValue(device.getType().getProductCode())
       
  1295                         revision_number = ExtractHexDecValue(device.getType().getRevisionNo())
       
  1296                         modules.append((device_type, vendor_id, product_code, revision_number))
       
  1297         return modules
       
  1298 
       
  1299