Adding support for displaying slave sync managers and profile object dictionary and for arbitrarily mapping variable through variable location
authorlaurent
Tue, 17 Jan 2012 17:24:53 +0100
changeset 2029 7c848efa21c6
parent 2028 5132c497918c
child 2030 7147f20c23e3
Adding support for displaying slave sync managers and profile object dictionary and for arbitrarily mapping variable through variable location
etherlab/ConfigEditor.py
etherlab/etherlab.py
--- a/etherlab/ConfigEditor.py	Tue Jan 10 15:11:22 2012 +0100
+++ b/etherlab/ConfigEditor.py	Tue Jan 17 17:24:53 2012 +0100
@@ -96,23 +96,22 @@
         else:
             self.EndModal(wx.ID_OK)
 
+def GetSyncManagersTableColnames():
+    _ = lambda x : x
+    return ["#", _("Name"), _("Start Address"), _("Default Size"), _("Control Byte"), _("Enable")]
+
+class SyncManagersTable(CustomTable):
+    
+    def GetValue(self, row, col):
+        if row < self.GetNumberRows():
+            if col == 0:
+                return row
+            return self.data[row].get(self.GetColLabelValue(col, False), "")
 
 def GetVariablesTableColnames():
     _ = lambda x : x
     return ["#", _("Index"), _("SubIndex"), _("Name"), _("Type"), _("PDO index"), _("PDO name"), _("PDO type")]
 
-class PDOsTable(CustomTable):
-    
-    def GetValue(self, row, col):
-        if row < self.GetNumberRows():
-            if col == 0:
-                return row + 1
-            colname = self.GetColLabelValue(col, False)
-            value = self.data[row].get(colname, "")
-            if colname == "Type":
-                value = _(value)
-            return value
-
 class VariablesTable(CustomTable):
     
     def GetValue(self, row, col):
@@ -121,6 +120,31 @@
                 return row + 1
             return self.data[row].get(self.GetColLabelValue(col, False), "")
 
+    def _updateColAttrs(self, grid):
+        """
+        wx.grid.Grid -> update the column attributes to add the
+        appropriate renderer given the column name.
+
+        Otherwise default to the default renderer.
+        """
+        for row in range(self.GetNumberRows()):
+            row_highlights = self.Highlights.get(row, {})
+            access = self.GetValueByName(row, "Access")
+            for col in range(self.GetNumberCols()):
+                colname = self.GetColLabelValue(col, False)
+                
+                if colname in ["PDO index", "PDO name", "PDO type"] and access == "":
+                    highlight_colours = (wx.LIGHT_GREY, wx.WHITE)
+                else:
+                    highlight_colours = row_highlights.get(colname.lower(), [(wx.WHITE, wx.BLACK)])[-1]
+                grid.SetReadOnly(row, col, True)
+                grid.SetCellEditor(row, col, None)
+                grid.SetCellRenderer(row, col, None)
+                
+                grid.SetCellBackgroundColour(row, col, highlight_colours[0])
+                grid.SetCellTextColour(row, col, highlight_colours[1])
+            self.ResizeRow(grid, row)
+
 [ID_SLAVEPANEL, ID_SLAVEPANELTYPELABEL,
  ID_SLAVEPANELTYPE, ID_SLAVEPANELTYPEBROWSE, 
  ID_SLAVEPANELALIASLABEL, ID_SLAVEPANELALIAS, 
@@ -129,8 +153,8 @@
  ID_SLAVEPANELVENDOR, ID_SLAVEPANELPRODUCTCODELABEL, 
  ID_SLAVEPANELPRODUCTCODE, ID_SLAVEPANELREVISIONNUMBERLABEL, 
  ID_SLAVEPANELREVISIONNUMBER, ID_SLAVEPANELPHYSICSLABEL, 
- ID_SLAVEPANELPHYSICS, ID_SLAVEPANELPDOSLABEL, 
- ID_SLAVEPANELPDOSGRID, ID_SLAVEPANELVARIABLESLABEL, 
+ ID_SLAVEPANELPHYSICS, ID_SLAVEPANELSYNCMANAGERSLABEL, 
+ ID_SLAVEPANELSYNCMANAGERSGRID, ID_SLAVEPANELVARIABLESLABEL, 
  ID_SLAVEPANELVARIABLESGRID, 
 ] = [wx.NewId() for _init_ctrls in range(21)]
 
@@ -174,12 +198,15 @@
     
     def _init_coll_SlaveInfosSizer_Items(self, parent):
         parent.AddSizer(self.SlaveInfosDetailsSizer, 0, border=0, flag=wx.GROW)
+        parent.AddWindow(self.SyncManagersLabel, 0, border=0, flag=wx.GROW)
+        parent.AddWindow(self.SyncManagersGrid, 0, border=0, flag=wx.GROW)
         parent.AddWindow(self.VariablesLabel, 0, border=0, flag=wx.GROW)
         parent.AddWindow(self.VariablesGrid, 0, border=0, flag=wx.GROW)
         
     def _init_coll_SlaveInfosSizer_Growables(self, parent):
         parent.AddGrowableCol(0)
-        parent.AddGrowableRow(2)
+        parent.AddGrowableRow(2, 1)
+        parent.AddGrowableRow(4, 2)
         
     def _init_coll_SlaveInfosDetailsSizer_Items(self, parent):
         parent.AddWindow(self.VendorLabel, 0, border=0, flag=wx.ALIGN_CENTER_VERTICAL|wx.GROW)
@@ -200,7 +227,7 @@
         self.PositionSizer = wx.FlexGridSizer(cols=6, hgap=5, rows=1, vgap=0)
         self.TypeSizer = wx.BoxSizer(wx.HORIZONTAL)
         self.SlaveInfosBoxSizer = wx.StaticBoxSizer(self.SlaveInfosStaticBox, wx.VERTICAL)
-        self.SlaveInfosSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=3, vgap=5)
+        self.SlaveInfosSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=5, vgap=5)
         self.SlaveInfosDetailsSizer = wx.FlexGridSizer(cols=4, hgap=5, rows=2, vgap=5)
         
         self._init_coll_MainSizer_Growables(self.MainSizer)
@@ -287,12 +314,20 @@
               name='Physics', parent=self, pos=wx.Point(0, 0),
               size=wx.Size(0, 24), style=wx.TE_READONLY)
         
+        self.SyncManagersLabel =  wx.StaticText(id=ID_SLAVEPANELSYNCMANAGERSLABEL,
+              label=_('Sync managers:'), name='SyncManagersLabel', parent=self,
+              pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
+        
+        self.SyncManagersGrid = CustomGrid(id=ID_SLAVEPANELSYNCMANAGERSGRID,
+              name='SyncManagersGrid', parent=self, pos=wx.Point(0, 0), 
+              size=wx.Size(0, 0), style=wx.VSCROLL)
+        
         self.VariablesLabel =  wx.StaticText(id=ID_SLAVEPANELVARIABLESLABEL,
               label=_('Variable entries:'), name='VariablesLabel', parent=self,
               pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
         
-        self.VariablesGrid = CustomGrid(id=ID_SLAVEPANELPDOSGRID,
-              name='PDOsGrid', parent=self, pos=wx.Point(0, 0), 
+        self.VariablesGrid = CustomGrid(id=ID_SLAVEPANELVARIABLESGRID,
+              name='VariablesGrid', parent=self, pos=wx.Point(0, 0), 
               size=wx.Size(0, 0), style=wx.VSCROLL)
         if wx.VERSION >= (2, 5, 0):
             self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.OnVariablesGridCellLeftClick)
@@ -308,6 +343,19 @@
         self.ParentWindow = window
         self.Slave = slave
         
+        self.SyncManagersTable = SyncManagersTable(self, [], GetSyncManagersTableColnames())
+        self.SyncManagersGrid.SetTable(self.SyncManagersTable)
+        self.SyncManagersGridColAlignements = [wx.ALIGN_RIGHT, wx.ALIGN_LEFT, wx.ALIGN_RIGHT, 
+                                               wx.ALIGN_RIGHT, wx.ALIGN_RIGHT, wx.ALIGN_RIGHT]
+        self.SyncManagersGridColSizes = [40, 150, 100, 100, 100, 100]
+        self.SyncManagersGrid.SetRowLabelSize(0)
+        for col in range(self.SyncManagersTable.GetNumberCols()):
+            attr = wx.grid.GridCellAttr()
+            attr.SetAlignment(self.SyncManagersGridColAlignements[col], wx.ALIGN_CENTRE)
+            self.SyncManagersGrid.SetColAttr(col, attr)
+            self.SyncManagersGrid.SetColMinimalWidth(col, self.SyncManagersGridColSizes[col])
+            self.SyncManagersGrid.AutoSizeColumn(col, False)
+        
         self.VariablesTable = VariablesTable(self, [], GetVariablesTableColnames())
         self.VariablesGrid.SetTable(self.VariablesTable)
         self.VariablesGridColAlignements = [wx.ALIGN_RIGHT, wx.ALIGN_RIGHT, wx.ALIGN_RIGHT, 
@@ -346,7 +394,9 @@
             self.ProductCode.SetValue(slave_infos["product_code"])
             self.RevisionNumber.SetValue(slave_infos["revision_number"])
             self.Physics.SetValue(slave_infos["physics"])
-            self.VariablesTable.SetData(slave_infos["variables"])
+            self.SyncManagersTable.SetData(slave_infos["sync_managers"])
+            self.SyncManagersTable.ResetView(self.SyncManagersGrid)
+            self.VariablesTable.SetData(slave_infos["entries"])
             self.VariablesTable.ResetView(self.VariablesGrid)
         else:
             type_infos = self.Controler.GetSlaveType(self.Slave)
@@ -394,22 +444,28 @@
         event.Skip()
 
     def OnVariablesGridCellLeftClick(self, event):
-        if event.GetCol() == 0:
-            row = event.GetRow()
-            data_type = self.VariablesTable.GetValueByName(row, "Type")
-            var_name = self.VariablesTable.GetValueByName(row, "Name")
+        row = event.GetRow()
+        
+        data_type = self.VariablesTable.GetValueByName(row, "Type")
+        access = self.VariablesTable.GetValueByName(row, "Access")
+        if (event.GetCol() == 0 and access != "" and
+            self.Controler.GetSizeOfType(data_type) is not None):
+            
             entry_index = self.Controler.ExtractHexDecValue(self.VariablesTable.GetValueByName(row, "Index"))
-            entry_subindex = self.VariablesTable.GetValueByName(row, "SubIndex")
-            if self.VariablesTable.GetValueByName(row, "PDO type") == "Transmit":
+            entry_subindex = self.Controler.ExtractHexDecValue(self.VariablesTable.GetValueByName(row, "SubIndex"))
+            var_name = "%s_%4.4x_%2.2x" % (self.Type.GetValue(), entry_index, entry_subindex)
+            if access in ["ro"]:
                 dir = "%I"
             else:
                 dir = "%Q"
             location = "%s%s" % (dir, self.Controler.GetSizeOfType(data_type)) + \
                        ".".join(map(lambda x:str(x), self.Controler.GetCurrentLocation() + self.Slave + (entry_index, entry_subindex)))
+            
             data = wx.TextDataObject(str((location, "location", data_type, var_name, "")))
             dragSource = wx.DropSource(self.VariablesGrid)
             dragSource.SetData(data)
             dragSource.DoDragDrop()
+        
         event.Skip()
 
 [ID_CONFIGEDITOR, ID_CONFIGEDITORADDSLAVEBUTTON,
--- a/etherlab/etherlab.py	Tue Jan 10 15:11:22 2012 +0100
+++ b/etherlab/etherlab.py	Tue Jan 17 17:24:53 2012 +0100
@@ -16,6 +16,8 @@
     "USINT" : "U8", "UINT" : "U16", "UDINT" : "U32", "ULINT" : "U64", 
     "BYTE" : "U8", "WORD" : "U16", "DWORD" : "U32", "LWORD" : "U64"}
 
+VARCLASSCONVERSION = {"ro": LOCATION_VAR_INPUT, "wo": LOCATION_VAR_OUTPUT, "rw": LOCATION_VAR_MEMORY}
+
 #--------------------------------------------------
 #                 Ethercat MASTER
 #--------------------------------------------------
@@ -30,7 +32,7 @@
     try:
         return int(value.replace("#", "0"), 16)
     except:
-        raise "Invalid value for HexDecValue \"%s\"" % value
+        raise ValueError, "Invalid value for HexDecValue \"%s\"" % value
 
 def GenerateHexDecValue(value, base=10):
     if base == 10:
@@ -38,7 +40,7 @@
     elif base == 16:
         return "#x%.8x" % value
     else:
-        raise "Not supported base"
+        raise ValueError, "Not supported base"
 
 cls = EtherCATConfigClasses.get("Config_Slave", None)
 if cls:
@@ -186,12 +188,12 @@
             device = self.GetModuleInfos(type_infos)
             if device is not None:
                 infos = type_infos.copy()
+                entries = device.GetEntriesList()
+                entries_list = entries.items()
+                entries_list.sort()
                 infos.update({"physics": device.getPhysics(),
-                              "variables": []})
-                for TxPdo in device.getTxPdo():
-                    ExtractPdoInfos(TxPdo, "Transmit", infos)
-                for RxPdo in device.getRxPdo():
-                    ExtractPdoInfos(RxPdo, "Receive", infos)
+                              "sync_managers": device.GetSyncManagers(),
+                              "entries": [entry[1] for entry in entries_list]})
                 return infos
         return None
     
@@ -226,26 +228,22 @@
                         else:
                             sync_managers.append(LOCATION_VAR_INPUT)
                     
-                    for pdo in device.getTxPdo() + device.getRxPdo():
-                        var_class = sync_managers[pdo.getSm()]
-                        
-                        for entry in pdo.getEntry():
-                            index = ExtractHexDecValue(entry.getIndex().getcontent())
-                            subindex = ExtractHexDecValue(entry.getSubIndex())
-                            var_type = entry.getDataType().getcontent()
-                            var_size = self.GetSizeOfType(var_type)
+                    entries = device.GetEntriesList().items()
+                    entries.sort()
+                    for (index, subindex), entry in entries:
+                        var_size = self.GetSizeOfType(entry["Type"])
+                        if var_size is not None:
+                            var_class = VARCLASSCONVERSION.get(entry["Access"], LOCATION_VAR_MEMORY)
                             if var_class == LOCATION_VAR_INPUT:
                                 var_dir = "%I"
                             else:
                                 var_dir = "%Q"    
                             
-                            pdo_name = ExtractName(pdo.getName())
-                            entry_name = ExtractName(entry.getName())
-                            vars.append({"name": "%s - %s" % (pdo_name, entry_name),
+                            vars.append({"name": "0x%4.4x-0x%2.2x: %s" % (index, subindex, entry["Name"]),
                                          "type": var_class,
                                          "size": var_size,
-                                         "IEC_type": var_type,
-                                         "var_name": "%s_%s" % (type_infos["device_type"], "_".join(pdo_name.split())),
+                                         "IEC_type": entry["Type"],
+                                         "var_name": "%s_%4.4x_%2.2x" % (type_infos["device_type"], index, subindex),
                                          "location": "%s%s%s"%(var_dir, var_size, ".".join(map(str, current_location + 
                                                                                                     slave_pos + 
                                                                                                     (index, subindex)))),
@@ -383,6 +381,54 @@
     }
 """
 
+def ConfigureVariable(entry_infos, str_completion):
+    data_type = DATATYPECONVERSION.get(entry_infos["var_type"], None)
+    if data_type is None:
+        raise ValueError, _("Type of location \"%s\" not yet supported!") % entry_infos["var_name"]
+                                
+    str_completion["located_variables_declaration"].extend(
+        ["IEC_%(var_type)s beremiz%(var_name)s;" % entry_infos,
+         "IEC_%(var_type)s *%(var_name)s = &beremiz%(var_name)s;" % entry_infos])
+    
+    if data_type == "BIT":
+        str_completion["used_pdo_entry_offset_variables_declaration"].extend(
+            ["static unsigned int slave%(slave)d_%(index).4x_%(subindex).2x;" % entry_infos,
+             "static unsigned int slave%(slave)d_%(index).4x_%(subindex).2x_bit;" % entry_infos])
+        
+        str_completion["used_pdo_entry_configuration"].append(
+             ("    {%(alias)d, %(position)d, 0x%(vendor).8x, 0x%(product_code).8x, " + 
+              "0x%(index).4x, %(subindex)d, &slave%(slave)d_%(index).4x_%(subindex).2x, " + 
+              "&slave%(slave)d_%(index).4x_%(subindex).2x_bit},") % entry_infos)
+        
+        if entry_infos["dir"] == "I":
+            str_completion["retrieve_variables"].append(
+              ("    beremiz%(name)s = EC_READ_BIT(domain1_pd + slave%(slave)d_%(index).4x_%(subindex).2x, " + 
+               "slave%(slave)d_%(index).4x_%(subindex).2x_bit);") % entry_infos)
+        elif entry_infos["dir"] == "Q":
+            str_completion["publish_variables"].append(
+              ("    EC_WRITE_BIT(domain1_pd + slave%(slave)d_%(index).4x_%(subindex).2x, " + 
+               "slave%(slave)d_%(index).4x_%(subindex).2x_bit, beremiz%(var_name)s);") % entry_infos)
+    
+    else:
+        entry_infos["data_type"] = data_type
+        
+        str_completion["used_pdo_entry_offset_variables_declaration"].append(
+            "static unsigned int slave%(slave)d_%(index).4x_%(subindex).2x;" % entry_infos)
+        
+        str_completion["used_pdo_entry_configuration"].append(
+            ("    {%(alias)d, %(position)d, 0x%(vendor).8x, 0x%(product_code).8x, 0x%(index).4x, " + 
+             "%(subindex)d, &slave%(slave)d_%(index).4x_%(subindex).2x},") % entry_infos)
+        
+        if entry_infos["dir"] == "I":
+            str_completion["retrieve_variables"].append(
+                ("    beremiz%(var_name)s = EC_READ_BIT(domain1_pd + " + 
+                 "slave%(slave)d_%(index).4x_%(subindex).2x);") % entry_infos)
+        elif entry_infos["dir"] == "Q":
+            str_completion["publish_variables"].append(
+                ("    EC_WRITE_BIT(domain1_pd + slave%(slave)d_%(index).4x_%(subindex).2x, " + 
+                 "beremiz%(var_name)s);") % entry_infos)
+        
+
 class _EthercatCFileGenerator:
     
     def __init__(self, controler, filepath):
@@ -399,10 +445,12 @@
         
         entry_infos = slave_variables.get((index, subindex), None)
         if entry_infos is None:
-            slave_variables[(index, subindex)] = (iec_type, dir, name)
-        elif entry_infos != (iec_type, dir, name):
+            slave_variables[(index, subindex)] = {
+                "infos": (iec_type, dir, name),
+                "mapped": False}
+        elif entry_infos["infos"] != (iec_type, dir, name):
             raise ValueError, _("Definition conflict for location \"%s\"") % name 
-    
+        
     def GenerateCFile(self):
         
         current_location = self.Controler.GetCurrentLocation()
@@ -428,6 +476,10 @@
             "publish_variables": [],
         }
         
+        for slave_entries in self.UsedVariables.itervalues():
+            for entry_infos in slave_entries.itervalues():
+                entry_infos["mapped"] = False
+        
         for slave_idx, slave_pos in enumerate(self.Controler.GetSlaves()):
             
             slave = self.Controler.GetSlave(slave_pos)
@@ -436,10 +488,10 @@
                 
                 device = self.Controler.GetModuleInfos(type_infos)
                 if device is not None:
+                    slave_variables = self.UsedVariables.get(slave_pos, {})
+                    device_entries = device.GetEntriesList()
                     
-                    pdos = device.getTxPdo() + device.getRxPdo()
-                    if len(pdos) > 0:
-                        slave_variables = self.UsedVariables.get(slave_pos, {})
+                    if len(device.getTxPdo() + device.getRxPdo()) > 0 or len(slave_variables) > 0:
                         
                         for element in ["vendor", "product_code", "revision_number"]:
                             type_infos[element] = ExtractHexDecValue(type_infos[element])
@@ -459,7 +511,9 @@
                         for sync_manager_idx, sync_manager in enumerate(device.getSm()):
                             sync_manager_infos = {
                                 "index": sync_manager_idx, 
+                                "name": sync_manager.getcontent(),
                                 "slave": slave_idx,
+                                "pdos": [], 
                                 "pdos_number": 0,
                             }
                             
@@ -477,11 +531,14 @@
                             
                             sync_managers.append(sync_manager_infos)
                         
-                        entry_offset = 0
-                        for pdo in pdos:
+                        pdos_index = []
+                        for pdo, pdo_type in ([(pdo, "Inputs") for pdo in device.getTxPdo()] +
+                                              [(pdo, "Outputs") for pdo in device.getRxPdo()]):
                             entries = pdo.getEntry()
                             
                             pdo_needed = pdo.getMandatory()
+                            pdo_index = ExtractHexDecValue(pdo.getIndex().getcontent())
+                            pdos_index.append(pdo_index)
                             entries_infos = []
                             
                             for entry in entries:
@@ -499,79 +556,126 @@
                                 entry_declaration = slave_variables.get((index, subindex), None)
                                 if entry_declaration is not None:
                                     pdo_needed = True
-                                    entry_infos.update(dict(zip(["var_type", "dir", "var_name"], entry_declaration)))
+                                    
+                                    entry_infos.update(dict(zip(["var_type", "dir", "var_name"], entry_declaration["infos"])))
+                                    entry_declaration["mapped"] = True
                                     
                                     if entry_infos["var_type"] != entry.getDataType().getcontent():
                                         raise ValueError, _("Wrong type for location \"%s\"!") % entry_infos["var_name"]
                                     
-                                    data_type = DATATYPECONVERSION.get(entry_infos["var_type"], None)
-                                    if data_type is None:
-                                        raise ValueError, _("Type of location \"%s\" not yet supported!") % entry_infos["var_name"]
-                                    
-                                    if (entry_infos["dir"] == "I" and sync_managers[pdo.getSm()]["sync_manager_type"] != "EC_DIR_INPUT" or 
-                                        entry_infos["dir"] == "Q" and sync_managers[pdo.getSm()]["sync_manager_type"] != "EC_DIR_OUTPUT"):
+                                    if (entry_infos["dir"] == "I" and pdo_type != "Inputs" or 
+                                        entry_infos["dir"] == "Q" and pdo_type != "Outputs"):
                                         raise ValueError, _("Wrong direction for location \"%s\"!") % entry_infos["var_name"]
                                     
-                                    str_completion["located_variables_declaration"].extend(
-                                        ["IEC_%(var_type)s beremiz%(var_name)s;" % entry_infos,
-                                         "IEC_%(var_type)s *%(var_name)s = &beremiz%(var_name)s;" % entry_infos])
-                                    
-                                    if data_type == "BIT":
-                                        str_completion["used_pdo_entry_offset_variables_declaration"].extend(
-                                            ["static unsigned int slave%(slave)d_%(index).4x_%(subindex).2x;" % entry_infos,
-                                             "static unsigned int slave%(slave)d_%(index).4x_%(subindex).2x_bit;" % entry_infos])
-                                        
-                                        str_completion["used_pdo_entry_configuration"].append(
-                                             ("    {%(alias)d, %(position)d, 0x%(vendor).8x, 0x%(product_code).8x, " + 
-                                              "0x%(index).4x, %(subindex)d, &slave%(slave)d_%(index).4x_%(subindex).2x, " + 
-                                              "&slave%(slave)d_%(index).4x_%(subindex).2x_bit},") % entry_infos)
-                                        
-                                        if entry_infos["dir"] == "I":
-                                            str_completion["retrieve_variables"].append(
-                                              ("    beremiz%(name)s = EC_READ_BIT(domain1_pd + slave%(slave)d_%(index).4x_%(subindex).2x, " + 
-                                               "slave%(slave)d_%(index).4x_%(subindex).2x_bit);") % entry_infos)
-                                        elif entry_infos["dir"] == "Q":
-                                            str_completion["publish_variables"].append(
-                                              ("    EC_WRITE_BIT(domain1_pd + slave%(slave)d_%(index).4x_%(subindex).2x, " + 
-                                               "slave%(slave)d_%(index).4x_%(subindex).2x_bit, beremiz%(var_name)s);") % entry_infos)
-                                    
-                                    else:
-                                        entry_infos["data_type"] = data_type
-                                        
-                                        str_completion["used_pdo_entry_offset_variables_declaration"].append(
-                                            "static unsigned int slave%(slave)d_%(index).4x_%(subindex).2x;" % entry_infos)
-                                        
-                                        str_completion["used_pdo_entry_configuration"].append(
-                                            ("    {%(alias)d, %(position)d, 0x%(vendor).8x, 0x%(product_code).8x, 0x%(index).4x, " + 
-                                             "%(subindex)d, &slave%(slave)d_%(index).4x_%(subindex).2x},") % entry_infos)
-                                        
-                                        if entry_infos["dir"] == "I":
-                                            str_completion["retrieve_variables"].append(
-                                                ("    beremiz%(name)s = EC_READ_BIT(domain1_pd + " + 
-                                                 "slave%(slave)d_%(index).4x_%(subindex).2x);") % entry_infos)
-                                        elif entry_infos["dir"] == "Q":
-                                            str_completion["publish_variables"].append(
-                                                ("    EC_WRITE_BIT(domain1_pd + slave%(slave)d_%(index).4x_%(subindex).2x, " + 
-                                                 "beremiz%(var_name)s);") % entry_infos)
+                                    ConfigureVariable(entry_infos, str_completion)
                             
                             if pdo_needed:
-                                sync_managers[pdo.getSm()]["pdos_number"] += 1
-                                pdo_infos = {
-                                    "slave": slave_idx,
-                                    "index": ExtractHexDecValue(pdo.getIndex().getcontent()),
-                                    "name": ExtractName(pdo.getName()),
-                                    "offset": entry_offset,
-                                    "entries_number": len(entries)
+                                sm = pdo.getSm()
+                                if sm is None:
+                                    for sm_idx, sync_manager in enumerate(sync_managers):
+                                        if sync_manager["Name"] == pdo_type:
+                                            sm = sm_idx
+                                if sm is None:
+                                    raise ValueError, _("No sync manager available for %s pdo!") % pdo_type
+                                    
+                                sync_managers[sm]["pdos_number"] += 1
+                                sync_managers[sm]["pdos"].append(
+                                    {"slave": slave_idx,
+                                     "index": pdo_index,
+                                     "name": ExtractName(pdo.getName()),
+                                     "type": pdo_type, 
+                                     "entries": entries_infos,
+                                     "entries_number": len(entries_infos),
+                                     "fixed": pdo.getFixed() == True})
+                        
+                        dynamic_pdos = {}
+                        dynamic_pdos_number = 0
+                        for category, min_index, max_index in [("Inputs", 0x1600, 0x1800), 
+                                                               ("Outputs", 0x1a00, 0x1C00)]:
+                            for sync_manager in sync_managers:
+                                if sync_manager["name"] == category:
+                                    category_infos = dynamic_pdos.setdefault(category, {})
+                                    category_infos["sync_manager"] = sync_manager
+                                    category_infos["pdos"] = [pdo for pdo in category_infos["sync_manager"]["pdos"] 
+                                                              if not pdo["fixed"] and pdo["type"] == category]
+                                    category_infos["current_index"] = min_index
+                                    category_infos["max_index"] = max_index
+                                    break
+                        
+                        for (index, subindex), entry_declaration in slave_variables.iteritems():
+                            
+                            if not entry_declaration["mapped"]:
+                                entry = device_entries.get((index, subindex), None)
+                                if entry is None:
+                                    raise ValueError, _("Unknown entry index 0x%4.4x, subindex 0x%2.2x for device %s") % \
+                                                     (index, subindex, type_infos["device_type"])
+                                
+                                entry_infos = {
+                                    "index": index,
+                                    "subindex": subindex,
+                                    "name": entry["Name"],
+                                    "bitlen": entry["BitSize"],
                                 }
+                                entry_infos.update(type_infos)
+                                
+                                entry_infos.update(dict(zip(["var_type", "dir", "var_name"], entry_declaration["infos"])))
+                                entry_declaration["mapped"] = True
+                                
+                                if entry_infos["var_type"] != entry["Type"]:
+                                    raise ValueError, _("Wrong type for location \"%s\"!") % entry_infos["var_name"]
+                                
+                                if entry_infos["dir"] == "I" and entry["Access"] in ["ro", "rw"]:
+                                    pdo_type = "Inputs"
+                                elif entry_infos["dir"] == "Q" and entry["Access"] in ["wo", "rw"]:
+                                    pdo_type = "Outputs"
+                                else:
+                                    raise ValueError, _("Wrong direction for location \"%s\"!") % entry_infos["var_name"]
+                                
+                                if not dynamic_pdos.has_key(pdo_type):
+                                    raise ValueError, _("No Sync manager defined for %s!") % pdo_type
+                                
+                                ConfigureVariable(entry_infos, str_completion)
+                                
+                                if len(dynamic_pdos[pdo_type]["pdos"]) > 0:
+                                    pdo = dynamic_pdos[pdo_type]["pdos"][0]
+                                else:
+                                    while dynamic_pdos[pdo_type]["current_index"] in pdos_index:
+                                        dynamic_pdos[pdo_type]["current_index"] += 1
+                                    if dynamic_pdos[pdo_type]["current_index"] >= dynamic_pdos[pdo_type]["max_index"]:
+                                        raise ValueError, _("No more free PDO index available for %s!") % pdo_type
+                                    pdos_index.append(dynamic_pdos[pdo_type]["current_index"])
+                                    
+                                    dynamic_pdos_number += 1
+                                    pdo = {"slave": slave_idx,
+                                           "index": dynamic_pdos[pdo_type]["current_index"],
+                                           "name": "Dynamic PDO %d" % dynamic_pdos_number,
+                                           "type": pdo_type, 
+                                           "entries": [],
+                                           "entries_number": 0,
+                                           "fixed": False}
+                                    dynamic_pdos[pdo_type]["sync_manager"]["pdos_number"] += 1
+                                    dynamic_pdos[pdo_type]["sync_manager"]["pdos"].append(pdo)
+                                    dynamic_pdos[pdo_type]["pdos"].append(pdo)
+                                
+                                pdo["entries"].append("    {0x%(index).4x, 0x%(subindex).2x, %(bitlen)d}, /* %(name)s */" % entry_infos)
+                                pdo["entries_number"] += 1
+                                
+                                if pdo["entries_number"] == 255:
+                                    dynamic_pdos[pdo_type]["pdos"].pop(0)
+                                
+                        pdo_offset = 0
+                        entry_offset = 0
+                        for sync_manager_infos in sync_managers:
+                            
+                            for pdo_infos in sync_manager_infos["pdos"]:
+                                pdo_infos["offset"] = entry_offset
+                                pdo_entries = pdo_infos["entries"]
                                 pdos_infos["pdos_infos"].append(
                                     ("    {0x%(index).4x, %(entries_number)d, " + 
                                      "slave_%(slave)d_pdo_entries + %(offset)d}, /* %(name)s */") % pdo_infos)
-                                entry_offset += len(entries)
-                                pdos_infos["pdos_entries_infos"].extend(entries_infos)
-                                
-                                
-                        pdo_offset = 0
-                        for sync_manager_infos in sync_managers:
+                                entry_offset += len(pdo_entries)
+                                pdos_infos["pdos_entries_infos"].extend(pdo_entries)
+                            
                             sync_manager_infos["offset"] = pdo_offset
                             pdos_infos["pdos_sync_infos"].append(
                                 ("    {%(index)d, %(sync_manager_type)s, %(pdos_number)d, " + 
@@ -600,6 +704,126 @@
 
 EtherCATInfoClasses = GenerateClassesFromXSD(os.path.join(os.path.dirname(__file__), "EtherCATInfo.xsd")) 
 
+cls = EtherCATInfoClasses["EtherCATInfo.xsd"].get("DeviceType", None)
+if cls:
+    cls.DataTypes = None
+    
+    def GetProfileDictionaries(self):
+        dictionaries = []
+        
+        for profile in self.getProfile():
+        
+            profile_content = profile.getcontent()
+            if profile_content is None:
+                return None
+            
+            for content_element in profile_content["value"]:
+                if content_element["name"] == "Dictionary":
+                    dictionaries.append(content_element["value"])
+                elif content_element["name"] == "DictionaryFile":
+                    raise ValueError, "DictionaryFile for defining Device Profile is not yet supported!"
+                
+        return dictionaries
+    setattr(cls, "GetProfileDictionaries", GetProfileDictionaries)
+    
+    def ExtractDataTypes(self):
+        self.DataTypes = {}
+        
+        for dictionary in self.GetProfileDictionaries():
+            
+            datatypes = dictionary.getDataTypes()
+            if datatypes is not None:
+                
+                for datatype in datatypes.getDataType():
+                    content = datatype.getcontent()
+                    if content is not None and content["name"] == "SubItem":
+                        self.DataTypes[datatype.getName()] = datatype
+    
+    setattr(cls, "ExtractDataTypes", ExtractDataTypes)
+    
+    def GetEntriesList(self):
+        if self.DataTypes is None:
+            self.ExtractDataTypes()
+        
+        entries = {}
+        
+        for dictionary in self.GetProfileDictionaries():
+            
+            for object in dictionary.getObjects().getObject():
+                entry_index = object.getIndex().getcontent()
+                index = ExtractHexDecValue(entry_index)
+                entry_type = object.getType()
+                entry_name = ExtractName(object.getName())
+                
+                entry_type_infos = self.DataTypes.get(entry_type, None)
+                if entry_type_infos is not None:
+                    content = entry_type_infos.getcontent()
+                    for subitem in content["value"]:
+                        entry_subidx = subitem.getSubIdx()
+                        if entry_subidx is None:
+                            entry_subidx = "0"
+                        subidx = ExtractHexDecValue(entry_subidx)
+                        subitem_access = ""
+                        subitem_flags = subitem.getFlags()
+                        if subitem_flags is not None:
+                            access = subitem_flags.getAccess()
+                            if access is not None:
+                                subitem_access = access.getcontent()
+                        entries[(index, subidx)] = {
+                            "Index": entry_index,
+                            "SubIndex": entry_subidx,
+                            "Name": "%s - %s" % 
+                                    (entry_name.decode("utf-8"),
+                                     ExtractName(subitem.getDisplayName(), 
+                                                 subitem.getName()).decode("utf-8")),
+                            "Type": subitem.getType(),
+                            "BitSize": subitem.getBitSize(),
+                            "Access": subitem_access, 
+                            "PDO index": "", 
+                            "PDO name": "", 
+                            "PDO type": ""}
+                else:
+                    entry_access = ""
+                    entry_flags = object.getFlags()
+                    if entry_flags is not None:
+                        access = entry_flags.getAccess()
+                        if access is not None:
+                            entry_access = access.getcontent()
+                    entries[(index, 0)] = {
+                         "Index": entry_index,
+                         "SubIndex": "0",
+                         "Name": entry_name,
+                         "Type": entry_type,
+                         "BitSize": object.getBitSize(),
+                         "Access": entry_access,
+                         "PDO index": "", 
+                         "PDO name": "", 
+                         "PDO type": ""}
+        
+        for TxPdo in self.getTxPdo():
+            ExtractPdoInfos(TxPdo, "Transmit", entries)
+        for RxPdo in self.getRxPdo():
+            ExtractPdoInfos(RxPdo, "Receive", entries)
+        
+        return entries
+    setattr(cls, "GetEntriesList", GetEntriesList)
+
+    def GetSyncManagers(self):
+        sync_managers = []
+        for sync_manager in self.getSm():
+            sync_manager_infos = {}
+            for name, value in [("Name", sync_manager.getcontent()),
+                                ("Start Address", sync_manager.getStartAddress()),
+                                ("Default Size", sync_manager.getDefaultSize()),
+                                ("Control Byte", sync_manager.getControlByte()),
+                                ("Enable", sync_manager.getEnable())]:
+                if value is None:
+                    value =""
+                sync_manager_infos[name] = value
+            sync_managers.append(sync_manager_infos)
+        return sync_managers
+    setattr(cls, "GetSyncManagers", GetSyncManagers)
+
 def GroupItemCompare(x, y):
     if x["type"] == y["type"]:
         if x["type"] == ETHERCAT_GROUP:
@@ -625,16 +849,34 @@
                 return name.getcontent()
     return default
 
-def ExtractPdoInfos(pdo, pdo_type, infos):
+def ExtractPdoInfos(pdo, pdo_type, entries):
     pdo_index = pdo.getIndex().getcontent()
-    for entry in pdo.getEntry():
-        infos["variables"].append({"Index": entry.getIndex().getcontent(),
-                                   "SubIndex": entry.getSubIndex(),
-                                   "Name": ExtractName(entry.getName()),
-                                   "Type": entry.getDataType().getcontent(),
-                                   "PDO index": pdo_index, 
-                                   "PDO name": ExtractName(pdo.getName()), 
-                                   "PDO type": pdo_type})
+    pdo_name = ExtractName(pdo.getName())
+    for pdo_entry in pdo.getEntry():
+        entry_index = pdo_entry.getIndex().getcontent()
+        entry_subindex = pdo_entry.getSubIndex()
+        index = ExtractHexDecValue(entry_index)
+        subindex = ExtractHexDecValue(entry_subindex)
+        
+        entry = entries.get((index, subindex), None)
+        if entry is not None:
+            entry["PDO index"] = pdo_index
+            entry["PDO name"] = pdo_name
+            entry["PDO type"] = pdo_type
+        else:
+            if pdo_type == "Transmit":
+                access = "ro"
+            else:
+                access = "wo"
+            entries[(index, subindex)] = {
+                "Index": entry_index,
+                "SubIndex": entry_subindex,
+                "Name": ExtractName(pdo_entry.getName()),
+                "Type": pdo_entry.getDataType().getcontent(),
+                "Access": access,
+                "PDO index": pdo_index, 
+                "PDO name": pdo_name, 
+                "PDO type": pdo_type}
 
 class RootClass:
     
@@ -750,11 +992,11 @@
         if vendor is not None:
             for group_name, group in vendor["groups"].iteritems():
                 for device_type, device in group["devices"]:
-                    product_code = device.getType().getProductCode()
-                    revision_number = device.getType().getRevisionNo()
+                    product_code = ExtractHexDecValue(device.getType().getProductCode())
+                    revision_number = ExtractHexDecValue(device.getType().getRevisionNo())
                     if (device_type == type_infos["device_type"] and
-                        product_code == type_infos["product_code"] and
-                        revision_number == type_infos["revision_number"]):
+                        product_code == ExtractHexDecValue(type_infos["product_code"]) and
+                        revision_number == ExtractHexDecValue(type_infos["revision_number"])):
                         return device
         return None