etherlab/etherlab.py
changeset 2079 49242019a9ca
parent 2077 14dfb786c53e
child 2080 6d0d94cd0fe0
equal deleted inserted replaced
2078:7d0ebbff1d08 2079:49242019a9ca
    59 #                    Ethercat Node
    59 #                    Ethercat Node
    60 #--------------------------------------------------
    60 #--------------------------------------------------
    61 
    61 
    62 class _EthercatSlaveCTN:
    62 class _EthercatSlaveCTN:
    63     
    63     
    64     XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
       
    65     <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
       
    66       <xsd:element name="SlaveParams">
       
    67         <xsd:complexType>
       
    68           <xsd:attribute name="DynamicPDOs" type="xsd:boolean" use="optional" default="true"/>
       
    69         </xsd:complexType>
       
    70       </xsd:element>
       
    71     </xsd:schema>
       
    72     """
       
    73     
       
    74     NODE_PROFILE = None
    64     NODE_PROFILE = None
    75     EditorType = NodeEditor
    65     EditorType = NodeEditor
    76     
    66     
    77     def GetIconName(self):
    67     def GetIconName(self):
    78         return "Slave"
    68         return "Slave"
   182     class _EthercatCIA402SlaveCTN(_EthercatSlaveCTN):
   172     class _EthercatCIA402SlaveCTN(_EthercatSlaveCTN):
   183         XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
   173         XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
   184         <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   174         <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   185           <xsd:element name="CIA402SlaveParams">
   175           <xsd:element name="CIA402SlaveParams">
   186             <xsd:complexType>
   176             <xsd:complexType>
   187               <xsd:attribute name="DynamicPDOs" type="xsd:boolean" use="optional" default="true"/>
       
   188               %s
   177               %s
   189             </xsd:complexType>
   178             </xsd:complexType>
   190           </xsd:element>
   179           </xsd:element>
   191         </xsd:schema>
   180         </xsd:schema>
   192         """ % AxisXSD
   181         """ % AxisXSD
   359     XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
   348     XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
   360     <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   349     <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   361       <xsd:element name="EtherlabNode">
   350       <xsd:element name="EtherlabNode">
   362         <xsd:complexType>
   351         <xsd:complexType>
   363           <xsd:attribute name="MasterNumber" type="xsd:integer" use="optional" default="0"/>
   352           <xsd:attribute name="MasterNumber" type="xsd:integer" use="optional" default="0"/>
   364           <xsd:attribute name="ConfigurePDOs" type="xsd:boolean" use="optional" default="true"/>
       
   365         </xsd:complexType>
   353         </xsd:complexType>
   366       </xsd:element>
   354       </xsd:element>
   367     </xsd:schema>
   355     </xsd:schema>
   368     """
   356     """
   369     
   357     
   653         current_location = self.GetCurrentLocation()
   641         current_location = self.GetCurrentLocation()
   654         
   642         
   655         slaves = self.GetSlaves()
   643         slaves = self.GetSlaves()
   656         for slave_pos in slaves:
   644         for slave_pos in slaves:
   657             slave = self.GetSlave(slave_pos)
   645             slave = self.GetSlave(slave_pos)
   658             slave_node = self.GetChildByIECLocation([slave_pos])
       
   659             if slave_node.CTNParams is not None:
       
   660                 slave_infos = slave_node.CTNParams[1]
       
   661             else:
       
   662                 slave_infos = None
       
   663             if slave is not None:
   646             if slave is not None:
   664                 self.FileGenerator.DeclareSlave(slave_pos, slave.getInfo().getAutoIncAddr(), slave.getType(), slave_infos)
   647                 self.FileGenerator.DeclareSlave(slave_pos, slave.getInfo().getAutoIncAddr(), slave.getType())
   665         
   648         
   666         for location in locations:
   649         for location in locations:
   667             loc = location["LOC"][len(current_location):]
   650             loc = location["LOC"][len(current_location):]
   668             slave_pos = loc[0]
   651             slave_pos = loc[0]
   669             if slave_pos in slaves and len(loc) == 3:
   652             if slave_pos in slaves and len(loc) == 3:
   819         self.Slaves = []
   802         self.Slaves = []
   820         self.UsedVariables = {}
   803         self.UsedVariables = {}
   821 
   804 
   822     def __del__(self):
   805     def __del__(self):
   823         self.Controler = None            
   806         self.Controler = None            
   824 
   807     
   825     def DeclareSlave(self, slave_index, slave_alias, slave, slave_infos):
   808     def DeclareSlave(self, slave_index, slave_alias, slave):
   826         self.Slaves.append((slave_index, slave_alias, slave, slave_infos))
   809         self.Slaves.append((slave_index, slave_alias, slave))
   827 
   810 
   828     def DeclareVariable(self, slave_index, index, subindex, iec_type, dir, name):
   811     def DeclareVariable(self, slave_index, index, subindex, iec_type, dir, name):
   829         slave_variables = self.UsedVariables.setdefault(slave_index, {})
   812         slave_variables = self.UsedVariables.setdefault(slave_index, {})
   830         
   813         
   831         entry_infos = slave_variables.get((index, subindex), None)
   814         entry_infos = slave_variables.get((index, subindex), None)
   836         elif entry_infos["infos"] != (iec_type, dir, name):
   819         elif entry_infos["infos"] != (iec_type, dir, name):
   837             raise ValueError, _("Definition conflict for location \"%s\"") % name 
   820             raise ValueError, _("Definition conflict for location \"%s\"") % name 
   838         
   821         
   839     def GenerateCFile(self, filepath, location_str, etherlab_node_infos):
   822     def GenerateCFile(self, filepath, location_str, etherlab_node_infos):
   840         
   823         
       
   824         # Extract etherlab master code template
   841         plc_etherlab_filepath = os.path.join(os.path.split(__file__)[0], "plc_etherlab.c")
   825         plc_etherlab_filepath = os.path.join(os.path.split(__file__)[0], "plc_etherlab.c")
   842         plc_etherlab_file = open(plc_etherlab_filepath, 'r')
   826         plc_etherlab_file = open(plc_etherlab_filepath, 'r')
   843         plc_etherlab_code = plc_etherlab_file.read()
   827         plc_etherlab_code = plc_etherlab_file.read()
   844         plc_etherlab_file.close()
   828         plc_etherlab_file.close()
   845         
   829         
       
   830         # Initialize strings for formatting master code template
   846         str_completion = {
   831         str_completion = {
   847             "location": location_str,
   832             "location": location_str,
   848             "configure_pdos": int(etherlab_node_infos.getConfigurePDOs()),
       
   849             "master_number": etherlab_node_infos.getMasterNumber(),
   833             "master_number": etherlab_node_infos.getMasterNumber(),
   850             "located_variables_declaration": [],
   834             "located_variables_declaration": [],
   851             "used_pdo_entry_offset_variables_declaration": [],
   835             "used_pdo_entry_offset_variables_declaration": [],
   852             "used_pdo_entry_configuration": [],
   836             "used_pdo_entry_configuration": [],
   853             "pdos_configuration_declaration": "",
   837             "pdos_configuration_declaration": "",
   857             "slaves_initialization": "",
   841             "slaves_initialization": "",
   858             "retrieve_variables": [],
   842             "retrieve_variables": [],
   859             "publish_variables": [],
   843             "publish_variables": [],
   860         }
   844         }
   861         
   845         
       
   846         # Initialize variable storing variable mapping state
   862         for slave_entries in self.UsedVariables.itervalues():
   847         for slave_entries in self.UsedVariables.itervalues():
   863             for entry_infos in slave_entries.itervalues():
   848             for entry_infos in slave_entries.itervalues():
   864                 entry_infos["mapped"] = False
   849                 entry_infos["mapped"] = False
   865         
   850         
       
   851         # Sort slaves by position (IEC_Channel)
   866         self.Slaves.sort()
   852         self.Slaves.sort()
       
   853         # Initialize dictionary storing alias auto-increment position values
   867         alias = {}
   854         alias = {}
   868         for (slave_idx, slave_alias, type_infos, slave_infos) in self.Slaves:
   855         
       
   856         # Generating code for each slave
       
   857         for (slave_idx, slave_alias, type_infos) in self.Slaves:
       
   858             
       
   859             # Defining slave alias and auto-increment position
   869             if alias.get(slave_alias) is not None:
   860             if alias.get(slave_alias) is not None:
   870                 alias[slave_alias] += 1
   861                 alias[slave_alias] += 1
   871             else:
   862             else:
   872                 alias[slave_alias] = 0
   863                 alias[slave_alias] = 0
   873             slave_pos = (slave_alias, alias[slave_alias])
   864             slave_pos = (slave_alias, alias[slave_alias])
   874             
   865             
       
   866             # Extract slave device informations
   875             device = self.Controler.GetModuleInfos(type_infos)
   867             device = self.Controler.GetModuleInfos(type_infos)
   876             if device is not None:
   868             if device is not None:
   877             
   869                 
       
   870                 # Extract slaves variables to be mapped
   878                 slave_variables = self.UsedVariables.get(slave_idx, {})
   871                 slave_variables = self.UsedVariables.get(slave_idx, {})
       
   872                 
       
   873                 # Extract slave device object dictionary entries
   879                 device_entries = device.GetEntriesList()
   874                 device_entries = device.GetEntriesList()
   880                 
   875                 
   881                 if len(device.getTxPdo() + device.getRxPdo()) > 0 or len(slave_variables) > 0:
   876                 # Adding code for declaring slave in master code template strings
       
   877                 for element in ["vendor", "product_code", "revision_number"]:
       
   878                     type_infos[element] = ExtractHexDecValue(type_infos[element])
       
   879                 type_infos.update(dict(zip(["slave", "alias", "position"], (slave_idx,) + slave_pos)))
       
   880                 
       
   881                 # Extract slave device CoE informations
       
   882                 device_coe = device.getCoE()
       
   883                 if device_coe is not None:
   882                     
   884                     
   883                     for element in ["vendor", "product_code", "revision_number"]:
   885                     # If device support CanOpen over Ethernet, adding code for calling 
   884                         type_infos[element] = ExtractHexDecValue(type_infos[element])
   886                     # init commands when initializing slave in master code template strings
   885                     type_infos.update(dict(zip(["slave", "alias", "position"], (slave_idx,) + slave_pos)))
   887                     for initCmd in device_coe.getInitCmd():
   886                 
       
   887                     str_completion["slaves_declaration"] += "static ec_slave_config_t *slave%(slave)d = NULL;\n" % type_infos
       
   888                     str_completion["slaves_configuration"] += SLAVE_CONFIGURATION_TEMPLATE % type_infos
       
   889     
       
   890                     for initCmd in device.getInitCmd():
       
   891                         index = ExtractHexDecValue(initCmd.getIndex())
   888                         index = ExtractHexDecValue(initCmd.getIndex())
   892                         subindex = ExtractHexDecValue(initCmd.getSubIndex())
   889                         subindex = ExtractHexDecValue(initCmd.getSubIndex())
   893                         entry = device_entries.get((index, subindex), None)
   890                         entry = device_entries.get((index, subindex), None)
   894                         if entry is not None:
   891                         if entry is not None:
   895                             data_size = entry["BitSize"] / 8
   892                             data_size = entry["BitSize"] / 8
   901                                 "data": data_str,
   898                                 "data": data_str,
   902                                 "data_size": data_size
   899                                 "data_size": data_size
   903                             }
   900                             }
   904                             init_cmd_infos.update(type_infos)
   901                             init_cmd_infos.update(type_infos)
   905                             str_completion["slaves_initialization"] += SLAVE_INITIALIZATION_TEMPLATE % init_cmd_infos
   902                             str_completion["slaves_initialization"] += SLAVE_INITIALIZATION_TEMPLATE % init_cmd_infos
   906 
   903                 
       
   904                     # Extract slave device PDO configuration capabilities
       
   905                     PdoAssign = device_coe.getPdoAssign()
       
   906                     PdoConfig = device_coe.getPdoConfig()
       
   907                 else:
       
   908                     PdoAssign = PdoConfig = False
       
   909                 
       
   910                 # Test if slave has a configuration or need one
       
   911                 if len(device.getTxPdo() + device.getRxPdo()) > 0 or len(slave_variables) > 0 and PdoConfig and PdoAssign:
       
   912                     
       
   913                     str_completion["slaves_declaration"] += "static ec_slave_config_t *slave%(slave)d = NULL;\n" % type_infos
       
   914                     str_completion["slaves_configuration"] += SLAVE_CONFIGURATION_TEMPLATE % type_infos
       
   915                     
       
   916                     # Initializing 
   907                     pdos_infos = {
   917                     pdos_infos = {
   908                         "pdos_entries_infos": [],
   918                         "pdos_entries_infos": [],
   909                         "pdos_infos": [],
   919                         "pdos_infos": [],
   910                         "pdos_sync_infos": [], 
   920                         "pdos_sync_infos": [], 
   911                     }
   921                     }
   987                                         entry_infos["dir"] == "Q" and pdo_type != "Outputs"):
   997                                         entry_infos["dir"] == "Q" and pdo_type != "Outputs"):
   988                                         raise ValueError, _("Wrong direction for location \"%s\"!") % entry_infos["var_name"]
   998                                         raise ValueError, _("Wrong direction for location \"%s\"!") % entry_infos["var_name"]
   989                                     
   999                                     
   990                                     ConfigureVariable(entry_infos, str_completion)
  1000                                     ConfigureVariable(entry_infos, str_completion)
   991                                 
  1001                                 
   992                                 elif pdo_type == "Outputs" and entry.getDataType() is not None:
  1002                                 elif pdo_type == "Outputs" and entry.getDataType() is not None and device_coe is not None:
   993                                     entry_infos["dir"] = "Q"
  1003                                     entry_infos["dir"] = "Q"
   994                                     entry_infos["data_size"] = max(1, entry_infos["bitlen"] / 8)
  1004                                     entry_infos["data_size"] = max(1, entry_infos["bitlen"] / 8)
   995                                     entry_infos["var_type"] = entry.getDataType().getcontent()
  1005                                     entry_infos["var_type"] = entry.getDataType().getcontent()
   996                                     entry_infos["real_var"] = "slave%(slave)d_%(index).4x_%(subindex).2x_default" % entry_infos
  1006                                     entry_infos["real_var"] = "slave%(slave)d_%(index).4x_%(subindex).2x_default" % entry_infos
   997                                     
  1007                                     
  1022                                      "type": pdo_type, 
  1032                                      "type": pdo_type, 
  1023                                      "entries": entries_infos,
  1033                                      "entries": entries_infos,
  1024                                      "entries_number": len(entries_infos),
  1034                                      "entries_number": len(entries_infos),
  1025                                      "fixed": pdo.getFixed() == True})
  1035                                      "fixed": pdo.getFixed() == True})
  1026                     
  1036                     
  1027                     if slave_infos is None or slave_infos.getDynamicPDOs():
  1037                     if PdoConfig and PdoAssign:
  1028                         dynamic_pdos = {}
  1038                         dynamic_pdos = {}
  1029                         dynamic_pdos_number = 0
  1039                         dynamic_pdos_number = 0
  1030                         for category, min_index, max_index in [("Inputs", 0x1600, 0x1800), 
  1040                         for category, min_index, max_index in [("Inputs", 0x1600, 0x1800), 
  1031                                                                ("Outputs", 0x1a00, 0x1C00)]:
  1041                                                                ("Outputs", 0x1a00, 0x1C00)]:
  1032                             for sync_manager in sync_managers:
  1042                             for sync_manager in sync_managers:
  1102                                 pdo["entries"].append("    {0x%(index).4x, 0x%(subindex).2x, %(bitlen)d}, /* %(name)s */" % entry_infos)
  1112                                 pdo["entries"].append("    {0x%(index).4x, 0x%(subindex).2x, %(bitlen)d}, /* %(name)s */" % entry_infos)
  1103                                 pdo["entries_number"] += 1
  1113                                 pdo["entries_number"] += 1
  1104                                 
  1114                                 
  1105                                 if pdo["entries_number"] == 255:
  1115                                 if pdo["entries_number"] == 255:
  1106                                     dynamic_pdos[pdo_type]["pdos"].pop(0)
  1116                                     dynamic_pdos[pdo_type]["pdos"].pop(0)
  1107                             
  1117                     
  1108                     pdo_offset = 0
  1118                     pdo_offset = 0
  1109                     entry_offset = 0
  1119                     entry_offset = 0
  1110                     for sync_manager_infos in sync_managers:
  1120                     for sync_manager_infos in sync_managers:
  1111                         
  1121                     
  1112                         for pdo_infos in sync_manager_infos["pdos"]:
  1122                         for pdo_infos in sync_manager_infos["pdos"]:
  1113                             pdo_infos["offset"] = entry_offset
  1123                             pdo_infos["offset"] = entry_offset
  1114                             pdo_entries = pdo_infos["entries"]
  1124                             pdo_entries = pdo_infos["entries"]
  1115                             pdos_infos["pdos_infos"].append(
  1125                             pdos_infos["pdos_infos"].append(
  1116                                 ("    {0x%(index).4x, %(entries_number)d, " + 
  1126                                 ("    {0x%(index).4x, %(entries_number)d, " + 
  1128                     
  1138                     
  1129                     for element in ["pdos_entries_infos", "pdos_infos", "pdos_sync_infos"]:
  1139                     for element in ["pdos_entries_infos", "pdos_infos", "pdos_sync_infos"]:
  1130                         pdos_infos[element] = "\n".join(pdos_infos[element])
  1140                         pdos_infos[element] = "\n".join(pdos_infos[element])
  1131                     
  1141                     
  1132                     str_completion["pdos_configuration_declaration"] += SLAVE_PDOS_CONFIGURATION_DECLARATION % pdos_infos
  1142                     str_completion["pdos_configuration_declaration"] += SLAVE_PDOS_CONFIGURATION_DECLARATION % pdos_infos
  1133         
  1143                 
       
  1144                 for (index, subindex), entry_declaration in slave_variables.iteritems():
       
  1145                     if not entry_declaration["mapped"]:
       
  1146                         message = _("Entry index 0x%4.4x, subindex 0x%2.2x not mapped for device %s") % \
       
  1147                                         (index, subindex, type_infos["device_type"])
       
  1148                         self.Controler.GetCTRoot().logger.write_warning(_("Warning: ") + message + "\n")
       
  1149                     
  1134         for element in ["used_pdo_entry_offset_variables_declaration", 
  1150         for element in ["used_pdo_entry_offset_variables_declaration", 
  1135                         "used_pdo_entry_configuration", 
  1151                         "used_pdo_entry_configuration", 
  1136                         "located_variables_declaration", 
  1152                         "located_variables_declaration", 
  1137                         "retrieve_variables", 
  1153                         "retrieve_variables", 
  1138                         "publish_variables"]:
  1154                         "publish_variables"]:
  1214                     if content is not None and content["name"] == "SubItem":
  1230                     if content is not None and content["name"] == "SubItem":
  1215                         self.DataTypes[datatype.getName()] = datatype
  1231                         self.DataTypes[datatype.getName()] = datatype
  1216     
  1232     
  1217     setattr(cls, "ExtractDataTypes", ExtractDataTypes)
  1233     setattr(cls, "ExtractDataTypes", ExtractDataTypes)
  1218     
  1234     
  1219     def getInitCmd(self):
  1235     def getCoE(self):
  1220         mailbox = self.getMailbox()
  1236         mailbox = self.getMailbox()
  1221         if mailbox is None:
  1237         if mailbox is not None:
  1222             return []
  1238             return mailbox.getCoE()
  1223         
  1239         return None
  1224         coe = mailbox.getCoE()
  1240     setattr(cls, "getCoE", getCoE)
  1225         if coe is None:
       
  1226             return []
       
  1227 
       
  1228         return coe.getInitCmd()
       
  1229     setattr(cls, "getInitCmd", getInitCmd)
       
  1230 
  1241 
  1231     def GetEntriesList(self):
  1242     def GetEntriesList(self):
  1232         if self.DataTypes is None:
  1243         if self.DataTypes is None:
  1233             self.ExtractDataTypes()
  1244             self.ExtractDataTypes()
  1234         
  1245