31 'ro': 'R', |
31 'ro': 'R', |
32 'wo': 'W', |
32 'wo': 'W', |
33 'rw': 'R/W'} |
33 'rw': 'R/W'} |
34 |
34 |
35 def GetAccessValue(access, pdo_mapping): |
35 def GetAccessValue(access, pdo_mapping): |
36 value = ACCESS_TYPES.get(access, "") |
36 value = "SDO: %s" % ACCESS_TYPES.get(access, "") |
37 if pdo_mapping != "": |
37 if pdo_mapping != "": |
38 value += "/P" |
38 value += ", PDO: %s" % pdo_mapping |
39 return value |
39 return value |
40 |
40 |
41 VARIABLES_FILTERS = [ |
41 VARIABLES_FILTERS = [ |
42 (_("All"), (0x0000, 0xffff)), |
42 (_("All"), (0x0000, 0xffff)), |
43 (_("Communication Parameters"), (0x1000, 0x1fff)), |
43 (_("Communication Parameters"), (0x1000, 0x1fff)), |
44 (_("Manufacturer Specific"), (0x2000, 0x5fff)), |
44 (_("Manufacturer Specific"), (0x2000, 0x5fff)), |
45 (_("Standardized Device Profile"), (0x6000, 0x9fff))] |
45 (_("Standardized Device Profile"), (0x6000, 0x9fff))] |
46 |
46 |
|
47 VARIABLE_INDEX_FILTER_FORMAT = _("Variable Index: #x%4.4X") |
|
48 |
47 ETHERCAT_INDEX_MODEL = re.compile("#x([0-9a-fA-F]{0,4})$") |
49 ETHERCAT_INDEX_MODEL = re.compile("#x([0-9a-fA-F]{0,4})$") |
48 ETHERCAT_SUBINDEX_MODEL = re.compile("#x([0-9a-fA-F]{0,2})$") |
50 ETHERCAT_SUBINDEX_MODEL = re.compile("#x([0-9a-fA-F]{0,2})$") |
49 LOCATION_MODEL = re.compile("(?:%[IQM](?:[XBWLD]?([0-9]+(?:\.[0-9]+)*)))$") |
51 LOCATION_MODEL = re.compile("(?:%[IQM](?:[XBWLD]?([0-9]+(?:\.[0-9]+)*)))$") |
|
52 |
|
53 NAVIGATION_KEYS = [ |
|
54 wx.WXK_END, |
|
55 wx.WXK_HOME, |
|
56 wx.WXK_LEFT, |
|
57 wx.WXK_UP, |
|
58 wx.WXK_RIGHT, |
|
59 wx.WXK_DOWN, |
|
60 wx.WXK_PAGEUP, |
|
61 wx.WXK_PAGEDOWN, |
|
62 wx.WXK_NUMPAD_HOME, |
|
63 wx.WXK_NUMPAD_LEFT, |
|
64 wx.WXK_NUMPAD_UP, |
|
65 wx.WXK_NUMPAD_RIGHT, |
|
66 wx.WXK_NUMPAD_DOWN, |
|
67 wx.WXK_NUMPAD_PAGEUP, |
|
68 wx.WXK_NUMPAD_PAGEDOWN, |
|
69 wx.WXK_NUMPAD_END] |
50 |
70 |
51 class NodeVariablesSizer(wx.FlexGridSizer): |
71 class NodeVariablesSizer(wx.FlexGridSizer): |
52 |
72 |
53 def __init__(self, parent, controler, position_column=False): |
73 def __init__(self, parent, controler, position_column=False): |
54 wx.FlexGridSizer.__init__(self, cols=1, hgap=0, rows=2, vgap=5) |
74 wx.FlexGridSizer.__init__(self, cols=1, hgap=0, rows=2, vgap=5) |
59 self.PositionColumn = position_column |
79 self.PositionColumn = position_column |
60 |
80 |
61 self.VariablesFilter = wx.ComboBox(parent, style=wx.TE_PROCESS_ENTER) |
81 self.VariablesFilter = wx.ComboBox(parent, style=wx.TE_PROCESS_ENTER) |
62 self.VariablesFilter.Bind(wx.EVT_COMBOBOX, self.OnVariablesFilterChanged) |
82 self.VariablesFilter.Bind(wx.EVT_COMBOBOX, self.OnVariablesFilterChanged) |
63 self.VariablesFilter.Bind(wx.EVT_TEXT_ENTER, self.OnVariablesFilterChanged) |
83 self.VariablesFilter.Bind(wx.EVT_TEXT_ENTER, self.OnVariablesFilterChanged) |
|
84 self.VariablesFilter.Bind(wx.EVT_CHAR, self.OnVariablesFilterKeyDown) |
64 self.AddWindow(self.VariablesFilter, flag=wx.GROW) |
85 self.AddWindow(self.VariablesFilter, flag=wx.GROW) |
65 |
86 |
66 self.VariablesGrid = wx.gizmos.TreeListCtrl(parent, |
87 self.VariablesGrid = wx.gizmos.TreeListCtrl(parent, |
67 style=wx.TR_DEFAULT_STYLE | |
88 style=wx.TR_DEFAULT_STYLE | |
68 wx.TR_ROW_LINES | |
89 wx.TR_ROW_LINES | |
78 self.VariablesFilter.Append(desc) |
99 self.VariablesFilter.Append(desc) |
79 self.Filters.append(value) |
100 self.Filters.append(value) |
80 |
101 |
81 self.VariablesFilter.SetSelection(0) |
102 self.VariablesFilter.SetSelection(0) |
82 self.CurrentFilter = self.Filters[0] |
103 self.CurrentFilter = self.Filters[0] |
|
104 self.VariablesFilterFirstCharacter = True |
83 |
105 |
84 if position_column: |
106 if position_column: |
85 for colname, colsize, colalign in zip(GetVariablesTableColnames(position_column), |
107 for colname, colsize, colalign in zip(GetVariablesTableColnames(position_column), |
86 [40, 80, 350, 80, 100, 80, 80], |
108 [40, 80, 350, 80, 100, 80, 150], |
87 [wx.ALIGN_RIGHT, wx.ALIGN_RIGHT, wx.ALIGN_LEFT, |
109 [wx.ALIGN_RIGHT, wx.ALIGN_RIGHT, wx.ALIGN_LEFT, |
88 wx.ALIGN_RIGHT, wx.ALIGN_RIGHT, wx.ALIGN_LEFT, |
110 wx.ALIGN_RIGHT, wx.ALIGN_RIGHT, wx.ALIGN_LEFT, |
89 wx.ALIGN_LEFT]): |
111 wx.ALIGN_LEFT]): |
90 self.VariablesGrid.AddColumn(_(colname), colsize, colalign) |
112 self.VariablesGrid.AddColumn(_(colname), colsize, colalign) |
91 self.VariablesGrid.SetMainColumn(2) |
113 self.VariablesGrid.SetMainColumn(2) |
92 else: |
114 else: |
93 for colname, colsize, colalign in zip(GetVariablesTableColnames(), |
115 for colname, colsize, colalign in zip(GetVariablesTableColnames(), |
94 [40, 350, 80, 100, 80, 80], |
116 [40, 350, 80, 100, 80, 150], |
95 [wx.ALIGN_RIGHT, wx.ALIGN_LEFT, wx.ALIGN_RIGHT, |
117 [wx.ALIGN_RIGHT, wx.ALIGN_LEFT, wx.ALIGN_RIGHT, |
96 wx.ALIGN_RIGHT, wx.ALIGN_LEFT, wx.ALIGN_LEFT]): |
118 wx.ALIGN_RIGHT, wx.ALIGN_LEFT, wx.ALIGN_LEFT]): |
97 self.VariablesGrid.AddColumn(_(colname), colsize, colalign) |
119 self.VariablesGrid.AddColumn(_(colname), colsize, colalign) |
98 self.VariablesGrid.SetMainColumn(1) |
120 self.VariablesGrid.SetMainColumn(1) |
99 |
121 |
150 self.CurrentFilter = self.Filters[filter] |
172 self.CurrentFilter = self.Filters[filter] |
151 self.RefreshView() |
173 self.RefreshView() |
152 else: |
174 else: |
153 try: |
175 try: |
154 value = self.VariablesFilter.GetValue() |
176 value = self.VariablesFilter.GetValue() |
155 result = ETHERCAT_INDEX_MODEL.match(value) |
177 if value == "": |
156 if result is not None: |
178 self.CurrentFilter = self.Filters[0] |
157 value = result.group(1) |
179 self.VariablesFilter.SetSelection(0) |
158 index = int(value, 16) |
180 else: |
159 self.CurrentFilter = (index, index) |
181 result = ETHERCAT_INDEX_MODEL.match(value) |
|
182 if result is not None: |
|
183 value = result.group(1) |
|
184 index = int(value, 16) |
|
185 self.CurrentFilter = (index, index) |
|
186 self.VariablesFilter.SetValue(VARIABLE_INDEX_FILTER_FORMAT % index) |
160 self.RefreshView() |
187 self.RefreshView() |
161 except: |
188 except: |
162 pass |
189 if self.CurrentFilter in self.Filters: |
|
190 self.VariablesFilter.SetSelection(self.Filters.index(self.CurrentFilter)) |
|
191 else: |
|
192 self.VariablesFilter.SetValue(VARIABLE_INDEX_FILTER_FORMAT % self.CurrentFilter[0]) |
|
193 self.VariablesFilterFirstCharacter = True |
163 event.Skip() |
194 event.Skip() |
|
195 |
|
196 def OnVariablesFilterKeyDown(self, event): |
|
197 if self.VariablesFilterFirstCharacter: |
|
198 keycode = event.GetKeyCode() |
|
199 self.VariablesFilterFirstCharacter = False |
|
200 if keycode not in NAVIGATION_KEYS: |
|
201 self.VariablesFilter.SetValue("") |
|
202 if keycode not in [wx.WXK_DELETE, |
|
203 wx.WXK_NUMPAD_DELETE, |
|
204 wx.WXK_BACK]: |
|
205 event.Skip() |
|
206 else: |
|
207 event.Skip() |
164 |
208 |
165 def OnVariablesGridLeftClick(self, event): |
209 def OnVariablesGridLeftClick(self, event): |
166 item, flags, col = self.VariablesGrid.HitTest(event.GetPosition()) |
210 item, flags, col = self.VariablesGrid.HitTest(event.GetPosition()) |
167 if item.IsOk(): |
211 if item.IsOk(): |
168 entry = self.VariablesGrid.GetItemPyData(item) |
212 entry = self.VariablesGrid.GetItemPyData(item) |
501 args = self.CurrentNodesFilter.copy() |
545 args = self.CurrentNodesFilter.copy() |
502 args["limits"] = self.CurrentFilter |
546 args["limits"] = self.CurrentFilter |
503 entries = self.Controler.GetNodesVariables(**args) |
547 entries = self.Controler.GetNodesVariables(**args) |
504 self.RefreshVariablesGrid(entries) |
548 self.RefreshVariablesGrid(entries) |
505 |
549 |
|
550 NODE_POSITION_FILTER_FORMAT = _("Node Position: %d") |
|
551 |
506 class MasterEditor(ConfTreeNodeEditor): |
552 class MasterEditor(ConfTreeNodeEditor): |
507 |
553 |
508 CONFNODEEDITOR_TABS = [ |
554 CONFNODEEDITOR_TABS = [ |
509 (_("Network"), "_create_EthercatMasterEditor")] |
555 (_("Network"), "_create_EthercatMasterEditor")] |
510 |
556 |
517 |
563 |
518 self.NodesFilter = wx.ComboBox(self.EthercatMasterEditor, |
564 self.NodesFilter = wx.ComboBox(self.EthercatMasterEditor, |
519 style=wx.TE_PROCESS_ENTER) |
565 style=wx.TE_PROCESS_ENTER) |
520 self.Bind(wx.EVT_COMBOBOX, self.OnNodesFilterChanged, self.NodesFilter) |
566 self.Bind(wx.EVT_COMBOBOX, self.OnNodesFilterChanged, self.NodesFilter) |
521 self.Bind(wx.EVT_TEXT_ENTER, self.OnNodesFilterChanged, self.NodesFilter) |
567 self.Bind(wx.EVT_TEXT_ENTER, self.OnNodesFilterChanged, self.NodesFilter) |
|
568 self.NodesFilter.Bind(wx.EVT_CHAR, self.OnNodesFilterKeyDown) |
522 |
569 |
523 process_variables_header = wx.BoxSizer(wx.HORIZONTAL) |
570 process_variables_header = wx.BoxSizer(wx.HORIZONTAL) |
524 |
571 |
525 process_variables_label = wx.StaticText(self.EthercatMasterEditor, |
572 process_variables_label = wx.StaticText(self.EthercatMasterEditor, |
526 label=_("Process variables mapped between nodes:")) |
573 label=_("Process variables mapped between nodes:")) |
577 self.NodesVariables = MasterNodesVariablesSizer(self.EthercatMasterEditor, self.Controler) |
624 self.NodesVariables = MasterNodesVariablesSizer(self.EthercatMasterEditor, self.Controler) |
578 second_staticbox_sizer.AddSizer(self.NodesVariables, 1, border=5, flag=wx.GROW|wx.ALL) |
625 second_staticbox_sizer.AddSizer(self.NodesVariables, 1, border=5, flag=wx.GROW|wx.ALL) |
579 |
626 |
580 main_staticbox = wx.StaticBox(self.EthercatMasterEditor, label=_("Node filter:")) |
627 main_staticbox = wx.StaticBox(self.EthercatMasterEditor, label=_("Node filter:")) |
581 staticbox_sizer = wx.StaticBoxSizer(main_staticbox, wx.VERTICAL) |
628 staticbox_sizer = wx.StaticBoxSizer(main_staticbox, wx.VERTICAL) |
582 main_sizer.AddSizer(staticbox_sizer, 1, border=10, flag=wx.GROW|wx.ALL) |
629 main_sizer.AddSizer(staticbox_sizer, 0, border=10, flag=wx.GROW|wx.ALL) |
583 main_staticbox_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=6, vgap=0) |
630 main_staticbox_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=6, vgap=0) |
584 main_staticbox_sizer.AddGrowableCol(0) |
631 main_staticbox_sizer.AddGrowableCol(0) |
585 main_staticbox_sizer.AddGrowableRow(2) |
632 main_staticbox_sizer.AddGrowableRow(2) |
586 main_staticbox_sizer.AddGrowableRow(4) |
633 main_staticbox_sizer.AddGrowableRow(4) |
587 main_staticbox_sizer.AddGrowableRow(5) |
634 main_staticbox_sizer.AddGrowableRow(5) |
605 def __init__(self, parent, controler, window): |
652 def __init__(self, parent, controler, window): |
606 ConfTreeNodeEditor.__init__(self, parent, controler, window) |
653 ConfTreeNodeEditor.__init__(self, parent, controler, window) |
607 |
654 |
608 self.ProcessVariables = [] |
655 self.ProcessVariables = [] |
609 self.CellShown = None |
656 self.CellShown = None |
|
657 self.NodesFilterFirstCharacter = True |
610 |
658 |
611 self.ProcessVariablesDefaultValue = {"Name": "", "ReadFrom": "", "WriteTo": "", "Description": ""} |
659 self.ProcessVariablesDefaultValue = {"Name": "", "ReadFrom": "", "WriteTo": "", "Description": ""} |
612 self.ProcessVariablesTable = ProcessVariablesTable(self, [], GetProcessVariablesTableColnames()) |
660 self.ProcessVariablesTable = ProcessVariablesTable(self, [], GetProcessVariablesTableColnames()) |
613 self.ProcessVariablesColSizes = [40, 100, 150, 150, 200] |
661 self.ProcessVariablesColSizes = [40, 100, 150, 150, 200] |
614 self.ProcessVariablesColAlignements = [wx.ALIGN_CENTER, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT] |
662 self.ProcessVariablesColAlignements = [wx.ALIGN_CENTER, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT] |
742 filter = self.NodesFilter.GetSelection() |
790 filter = self.NodesFilter.GetSelection() |
743 if filter != -1: |
791 if filter != -1: |
744 self.CurrentNodesFilter = self.NodesFilterValues[filter] |
792 self.CurrentNodesFilter = self.NodesFilterValues[filter] |
745 else: |
793 else: |
746 try: |
794 try: |
747 self.CurrentNodesFilter = {"slave_pos": int(self.NodesFilter.GetValue())} |
795 value = self.NodesFilter.GetValue() |
|
796 if value == "": |
|
797 self.CurrentNodesFilter = self.NodesFilterValues[0] |
|
798 self.NodesFilter.SetSelection(0) |
|
799 else: |
|
800 position = int(self.NodesFilter.GetValue()) |
|
801 self.CurrentNodesFilter = {"slave_pos": position} |
|
802 self.NodesFilter.SetValue(NODE_POSITION_FILTER_FORMAT % position) |
748 except: |
803 except: |
749 self.CurrentNodesFilter = None |
804 if self.CurrentNodesFilter in self.NodesFilterValues: |
|
805 self.NodesFilter.SetSelection(self.NodesFilterValues.index(self.CurrentNodesFilter)) |
|
806 else: |
|
807 self.NodesFilter.SetValue(NODE_POSITION_FILTER_FORMAT % self.CurrentNodesFilter["slave_pos"]) |
|
808 self.NodesFilterFirstCharacter = True |
750 self.NodesVariables.SetCurrentNodesFilter(self.CurrentNodesFilter) |
809 self.NodesVariables.SetCurrentNodesFilter(self.CurrentNodesFilter) |
751 |
810 |
752 def RefreshProcessVariables(self): |
811 def RefreshProcessVariables(self): |
753 if self.CurrentNodesFilter is not None: |
812 if self.CurrentNodesFilter is not None: |
754 self.ProcessVariables = self.Controler.GetProcessVariables() |
813 self.ProcessVariables = self.Controler.GetProcessVariables() |
801 if self.CurrentNodesFilter is not None: |
860 if self.CurrentNodesFilter is not None: |
802 self.RefreshProcessVariables() |
861 self.RefreshProcessVariables() |
803 self.RefreshStartupCommands() |
862 self.RefreshStartupCommands() |
804 self.NodesVariables.RefreshView() |
863 self.NodesVariables.RefreshView() |
805 event.Skip() |
864 event.Skip() |
|
865 |
|
866 def OnNodesFilterKeyDown(self, event): |
|
867 if self.NodesFilterFirstCharacter: |
|
868 keycode = event.GetKeyCode() |
|
869 self.NodesFilterFirstCharacter = False |
|
870 if keycode not in NAVIGATION_KEYS: |
|
871 self.NodesFilter.SetValue("") |
|
872 if keycode not in [wx.WXK_DELETE, |
|
873 wx.WXK_NUMPAD_DELETE, |
|
874 wx.WXK_BACK]: |
|
875 event.Skip() |
|
876 else: |
|
877 event.Skip() |
806 |
878 |
807 def OnProcessVariablesGridCellChange(self, event): |
879 def OnProcessVariablesGridCellChange(self, event): |
808 row, col = event.GetRow(), event.GetCol() |
880 row, col = event.GetRow(), event.GetCol() |
809 colname = self.ProcessVariablesTable.GetColLabelValue(col, False) |
881 colname = self.ProcessVariablesTable.GetColLabelValue(col, False) |
810 value = self.ProcessVariablesTable.GetValue(row, col) |
882 value = self.ProcessVariablesTable.GetValue(row, col) |