etherlab/EtherCATManagementEditor.py
changeset 2152 e6946c298a42
child 2165 02a2b5dee5e3
equal deleted inserted replaced
2151:015dab6a915f 2152:e6946c298a42
       
     1 #!/usr/bin/env python
       
     2 # -*- coding: utf-8 -*-
       
     3 
       
     4 #This file is part of Beremiz, a Integrated Development Environment for
       
     5 #programming IEC 61131-3 automates supporting EtherCAT. 
       
     6 #
       
     7 #Copyright (C) 2013: Real-Time & Embedded Systems (RTES) Lab., University of Seoul
       
     8 #
       
     9 #See COPYING file for copyrights details.
       
    10 #
       
    11 #This library is free software; you can redistribute it and/or
       
    12 #modify it under the terms of the GNU General Public
       
    13 #License as published by the Free Software Foundation; either
       
    14 #version 2.1 of the License, or (at your option) any later version.
       
    15 #
       
    16 #This library is distributed in the hope that it will be useful,
       
    17 #but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    18 #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
       
    19 #General Public License for more details.
       
    20 #
       
    21 #You should have received a copy of the GNU General Public
       
    22 #License along with this library; if not, write to the Free Software
       
    23 #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
       
    24 
       
    25 
       
    26 import os
       
    27 
       
    28 import wx
       
    29 import wx.grid
       
    30 import wx.gizmos
       
    31 import wx.lib.buttons
       
    32 
       
    33 # --------------------------------------------------------------------
       
    34 from controls import CustomGrid, CustomTable
       
    35 # --------------------------------------------------------------------
       
    36 
       
    37 # ------------ for SDO Management --------------------
       
    38 import string
       
    39 import wx.grid as gridlib
       
    40 #-------------------------------------------------------------
       
    41 
       
    42 # ------------ for register management --------------- 
       
    43 from xml.dom import minidom
       
    44 #-------------------------------------------------------------
       
    45 
       
    46 # ----------------------------- For Sync Manager Table -----------------------------------
       
    47 def GetSyncManagersTableColnames():
       
    48     """
       
    49     Returns column names of SyncManager Table in Slave state panel.
       
    50     """
       
    51     _ = lambda x : x
       
    52     return ["#", _("Name"), _("Start Address"), _("Default Size"), _("Control Byte"), _("Enable")]
       
    53 
       
    54 #-------------------------------------------------------------------------------
       
    55 #                    Sync Managers Table
       
    56 #-------------------------------------------------------------------------------
       
    57 class SyncManagersTable(CustomTable):
       
    58     def GetValue(self, row, col): 
       
    59         if row < self.GetNumberRows():
       
    60             if col == 0:
       
    61                 return row
       
    62             return self.data[row].get(self.GetColLabelValue(col, False), "")
       
    63 
       
    64 #-------------------------------------------------------------------------------
       
    65 #                    EtherCAT Management Treebook
       
    66 #-------------------------------------------------------------------------------
       
    67 class EtherCATManagementTreebook(wx.Treebook):
       
    68     def __init__(self, parent, controler, node_editor):
       
    69         """
       
    70         Constructor
       
    71         @param parent: Reference to the parent wx.ScrolledWindow object
       
    72         @param controler: _EthercatSlaveCTN class in EthercatSlave.py
       
    73         @param node_editor: Reference to Beremiz frame
       
    74         """
       
    75         wx.Treebook.__init__(self, parent, -1, size=wx.DefaultSize, style=wx.BK_DEFAULT)
       
    76         self.parent = parent
       
    77         self.Controler = controler
       
    78         self.NodeEditor = node_editor
       
    79         
       
    80         self.EtherCATManagementClassObject = {}
       
    81         
       
    82         # fill EtherCAT Management Treebook
       
    83         for pname, pclass, subs in [
       
    84             ("Slave State",        SlaveStatePanelClass, []),
       
    85             ("SDO Management",     SDOPanelClass, []),
       
    86             ("PDO Monitoring",     PDOPanelClass, []),
       
    87             ("ESC Management",     EEPROMAccessPanel, [        
       
    88                     ("Smart View", SlaveSiiSmartView),
       
    89                     ("Hex View", HexView)]),
       
    90             ("Register Access",     RegisterAccessPanel, [])]:
       
    91                 self.AddPage(pclass(self, self.Controler), pname)
       
    92                 for spname, spclass in subs:
       
    93                     self.AddSubPage(spclass(self, self.Controler), spname)
       
    94 
       
    95         self.Bind(wx.EVT_TREEBOOK_PAGE_CHANGED, self.OnPageChanged)
       
    96         self.Bind(wx.EVT_TREEBOOK_PAGE_CHANGING, self.OnPageChanging)
       
    97         
       
    98     def OnPageChanged(self, event):
       
    99         old = event.GetOldSelection()
       
   100         new = event.GetSelection()
       
   101         sel = event.GetSelection()
       
   102         event.Skip()
       
   103         
       
   104     def OnPageChanging(self, event):
       
   105         old = event.GetOldSelection()
       
   106         new = event.GetSelection()
       
   107         sel = event.GetSelection()
       
   108         event.Skip()    
       
   109         
       
   110 #-------------------------------------------------------------------------------
       
   111 #                    For SlaveState Panel
       
   112 #-------------------------------------------------------------------------------        
       
   113 class SlaveStatePanelClass(wx.Panel):
       
   114     def __init__(self, parent, controler):
       
   115         """
       
   116         Constructor
       
   117         @param parent: Reference to the parent EtherCATManagementTreebook class
       
   118         @param controler: _EthercatSlaveCTN class in EthercatSlave.py
       
   119         """
       
   120         wx.Panel.__init__(self, parent, -1, (0, 0), size=wx.DefaultSize, style = wx.SUNKEN_BORDER)
       
   121         self.Controler = controler
       
   122         self.parent = parent
       
   123         
       
   124         # initialize SlaveStatePanel UI dictionaries
       
   125         self.StaticBoxDic = {}
       
   126         self.StaticTextDic = {}
       
   127         self.TextCtrlDic = {}
       
   128         self.ButtonDic = {}
       
   129         
       
   130         # iniitalize BoxSizer and FlexGridSizer
       
   131         self.SizerDic = {
       
   132             "SlaveState_main_sizer" : wx.BoxSizer(wx.VERTICAL),
       
   133             "SlaveState_inner_main_sizer" : wx.FlexGridSizer(cols=1, hgap=50, rows=3, vgap=10),
       
   134             "SlaveInfosDetailsInnerSizer" : wx.FlexGridSizer(cols=4, hgap=10, rows=2, vgap=10),
       
   135             "SyncManagerInnerSizer" : wx.FlexGridSizer(cols=1, hgap=5, rows=1, vgap=5),
       
   136             "SlaveState_sizer" : wx.FlexGridSizer(cols=1, hgap=10, rows=2, vgap=10),
       
   137             "SlaveState_up_sizer" : wx.FlexGridSizer(cols=4, hgap=10, rows=2, vgap=10),
       
   138             "SlaveState_down_sizer" : wx.FlexGridSizer(cols=2, hgap=10, rows=1, vgap=10)}
       
   139         
       
   140         # initialize StaticBox and StaticBoxSizer
       
   141         for box_name, box_label in [
       
   142                 ("SlaveInfosDetailsBox", "Slave Informations"),
       
   143                 ("SyncManagerBox", "Sync Manager"),
       
   144                 ("SlaveStateBox", "Slave State Transition && Monitoring")]:
       
   145             self.StaticBoxDic[box_name] = wx.StaticBox(self, label=_(box_label))
       
   146             self.SizerDic[box_name] = wx.StaticBoxSizer(self.StaticBoxDic[box_name])  
       
   147         
       
   148         for statictext_name, statictext_label, textctrl_name in [
       
   149                 ("VendorLabel", "Vendor:", "vendor"),
       
   150                 ("ProductcodeLabel", "Product code:", "product_code"),
       
   151                 ("RevisionnumberLabel", "Slave Count:", "revision_number"),
       
   152                 ("PhysicsLabel", "Physics:", "physics")]:
       
   153             self.StaticTextDic[statictext_name] = wx.StaticText(self, label=_(statictext_label))
       
   154             self.TextCtrlDic[textctrl_name] = wx.TextCtrl(self, size=wx.Size(130, 24), style=wx.TE_READONLY)
       
   155             self.SizerDic["SlaveInfosDetailsInnerSizer"].AddMany([self.StaticTextDic[statictext_name], 
       
   156                                                                self.TextCtrlDic[textctrl_name]])    
       
   157         
       
   158         self.SizerDic["SlaveInfosDetailsBox"].AddSizer(self.SizerDic["SlaveInfosDetailsInnerSizer"])
       
   159         
       
   160         self.SyncManagersGrid = CustomGrid(self, size=wx.Size(605,155), style=wx.VSCROLL)      
       
   161                
       
   162         self.SizerDic["SyncManagerInnerSizer"].Add(self.SyncManagersGrid)    
       
   163         self.SizerDic["SyncManagerBox"].Add(self.SizerDic["SyncManagerInnerSizer"])
       
   164         
       
   165         for button_name, button_id, button_label, button_tooltipstring, event_method, sub_item in [
       
   166                 ("InitButton",   0, "INIT", "State Transition to \"Init\" State",     self.OnButtonClick, []),
       
   167                 ("PreOPButton",  1, "PREOP", "State Transition to \"PreOP\" State",   self.OnButtonClick, [
       
   168                         ("TargetStateLabel", "Target State:" , "TargetState")]),
       
   169                 ("SafeOPButton", 2, "SAFEOP", "State Transition to \"SafeOP\" State", self.OnButtonClick, []),
       
   170                 ("OPButton",     3, "OP",  "State Transition to \"OP\" State",        self.OnButtonClick, [
       
   171                         ("CurrentStateLabel", "Current State:", "CurrentState")])]:
       
   172             self.ButtonDic[button_name] = wx.Button(self, id=button_id ,label=_(button_label))
       
   173             self.ButtonDic[button_name].Bind(wx.EVT_BUTTON, event_method)
       
   174             self.ButtonDic[button_name].SetToolTipString(button_tooltipstring)
       
   175             self.SizerDic["SlaveState_up_sizer"].Add(self.ButtonDic[button_name])
       
   176             for statictext_name, statictext_label, textctrl_name in sub_item :
       
   177                 self.StaticTextDic[statictext_name] = wx.StaticText(self, label=_(statictext_label))
       
   178                 self.TextCtrlDic[textctrl_name] = wx.TextCtrl(self, size=wx.DefaultSize, style=wx.TE_READONLY)
       
   179                 self.SizerDic["SlaveState_up_sizer"].AddMany([self.StaticTextDic[statictext_name], 
       
   180                                                                self.TextCtrlDic[textctrl_name]])
       
   181                 
       
   182         for button_name, button_label, button_tooltipstring, event_method in [
       
   183                 ("StartTimerButton", "Start State Monitoring", "Slave State Update Restart", self.StartTimer),
       
   184                 ("StopTimerButton", "Stop State Monitoring", "Slave State Update Stop", self.CurrentStateThreadStop)]:
       
   185             self.ButtonDic[button_name] = wx.Button(self, label=_(button_label))
       
   186             self.ButtonDic[button_name].Bind(wx.EVT_BUTTON, event_method)
       
   187             self.ButtonDic[button_name].SetToolTipString(button_tooltipstring)
       
   188             self.SizerDic["SlaveState_down_sizer"].Add(self.ButtonDic[button_name])   
       
   189         
       
   190         self.SizerDic["SlaveState_sizer"].AddMany([self.SizerDic["SlaveState_up_sizer"], 
       
   191             self.SizerDic["SlaveState_down_sizer"]])
       
   192         
       
   193         self.SizerDic["SlaveStateBox"].Add(self.SizerDic["SlaveState_sizer"])
       
   194         
       
   195         self.SizerDic["SlaveState_inner_main_sizer"].AddMany([
       
   196             self.SizerDic["SlaveInfosDetailsBox"], self.SizerDic["SyncManagerBox"],
       
   197             self.SizerDic["SlaveStateBox"]])
       
   198         
       
   199         self.SizerDic["SlaveState_main_sizer"].Add(self.SizerDic["SlaveState_inner_main_sizer"])
       
   200         
       
   201         self.SetSizer(self.SizerDic["SlaveState_main_sizer"])
       
   202         
       
   203         # register a timer for periodic exectuion of slave state update (period: 1000 ms)
       
   204         self.Bind(wx.EVT_TIMER, self.GetCurrentState)
       
   205         
       
   206         self.CreateSyncManagerTable()
       
   207         
       
   208         self.Centre()
       
   209     
       
   210     def CreateSyncManagerTable(self):
       
   211         """
       
   212         Create grid for "SyncManager"
       
   213         """
       
   214         # declare Table object 
       
   215         self.SyncManagersTable = SyncManagersTable(self, [], GetSyncManagersTableColnames())
       
   216         self.SyncManagersGrid.SetTable(self.SyncManagersTable)
       
   217         # set grid alignment attr. (CENTER)
       
   218         self.SyncManagersGridColAlignements = [wx.ALIGN_CENTRE, wx.ALIGN_CENTRE, wx.ALIGN_CENTRE, 
       
   219                                                wx.ALIGN_CENTRE, wx.ALIGN_CENTRE, wx.ALIGN_CENTRE]
       
   220         # set grid size
       
   221         self.SyncManagersGridColSizes = [40, 150, 100, 100, 100, 100]
       
   222         self.SyncManagersGrid.SetRowLabelSize(0)
       
   223         for col in range(self.SyncManagersTable.GetNumberCols()):
       
   224             attr = wx.grid.GridCellAttr()
       
   225             attr.SetAlignment(self.SyncManagersGridColAlignements[col], wx.ALIGN_CENTRE)
       
   226             self.SyncManagersGrid.SetColAttr(col, attr)
       
   227             self.SyncManagersGrid.SetColMinimalWidth(col, self.SyncManagersGridColSizes[col])
       
   228             self.SyncManagersGrid.AutoSizeColumn(col, False) 
       
   229         
       
   230         self.RefreshSlaveInfos()
       
   231         
       
   232     def RefreshSlaveInfos(self):
       
   233         """
       
   234         Fill data in "Slave Information" and "SyncManager"
       
   235         """
       
   236         slave_infos = self.Controler.GetSlaveInfos()
       
   237         sync_manager_section = ["vendor", "product_code", "revision_number", "physics"]
       
   238         if slave_infos is not None:
       
   239             # this method is same as "TextCtrl.SetValue" 
       
   240             for textctrl_name in sync_manager_section:
       
   241                 self.TextCtrlDic[textctrl_name].SetValue(slave_infos[textctrl_name])
       
   242             self.SyncManagersTable.SetData(slave_infos["sync_managers"])
       
   243             self.SyncManagersTable.ResetView(self.SyncManagersGrid)
       
   244         else:
       
   245             for textctrl_name in sync_manager_section:
       
   246                 self.TextCtrlDic[textctrl_name].SetValue("")
       
   247             self.SyncManagersTable.SetData([])
       
   248             self.SyncManagersTable.ResetView(self.SyncManagersGrid)
       
   249         
       
   250     def OnButtonClick(self, event):
       
   251         """
       
   252         Event handler for slave state transition button click (Init, PreOP, SafeOP, OP button)
       
   253         @param event : wx.EVT_BUTTON object
       
   254         """
       
   255         check_connect_flag = self.Controler.CommonMethod.CheckConnect(False)
       
   256         if check_connect_flag :
       
   257             state_dic = ["INIT", "PREOP", "SAFEOP", "OP"]
       
   258               
       
   259             # If target state is one of {INIT, PREOP, SAFEOP}, request slave state transition immediately.
       
   260             if event.GetId() < 3 :
       
   261                 self.Controler.CommonMethod.RequestSlaveState(state_dic[event.GetId()])
       
   262                 self.TextCtrlDic["TargetState"].SetValue(state_dic[event.GetId()])
       
   263 
       
   264             # If target state is OP, first check "PLC status".
       
   265             #  (1) If current PLC status is "Started", then request slave state transition
       
   266             #  (2) Otherwise, show error message and return
       
   267             else :
       
   268                 status, count = self.Controler.GetCTRoot()._connector.GetPLCstatus()
       
   269                 if status == "Started" :
       
   270                     self.Controler.CommonMethod.RequestSlaveState("OP")
       
   271                     self.TextCtrlDic["TargetState"].SetValue("OP")
       
   272                 else :
       
   273                     self.Controler.CommonMethod.CreateErrorDialog("PLC is Not Started")  
       
   274      
       
   275     def GetCurrentState(self, event):
       
   276         """
       
   277         Timer event handler for periodic slave state monitoring (Default period: 1 sec = 1000 msec).
       
   278         @param event : wx.TIMER object
       
   279         """
       
   280         check_connect_flag = self.Controler.CommonMethod.CheckConnect(True)
       
   281         if check_connect_flag:
       
   282             returnVal = self.Controler.CommonMethod.GetSlaveStateFromSlave()
       
   283             line = returnVal.split("\n")
       
   284             try :
       
   285                 self.SetCurrentState(line[self.Controler.GetSlavePos()])
       
   286             except :
       
   287                 pass  
       
   288             
       
   289     def SetCurrentState(self, line):
       
   290         """
       
   291         Show current slave state using the executiob result of "ethercat slaves" command.
       
   292         @param line : result of "ethercat slaves" command
       
   293         """
       
   294         state_array = ["INIT", "PREOP", "SAFEOP", "OP"]
       
   295         try :
       
   296             # parse the execution result of  "ethercat slaves" command
       
   297             # Result example : 0  0:0  PREOP  +  EL9800 (V4.30) (PIC24, SPI, ET1100)
       
   298             token = line.split("  ")
       
   299             if token[2] in state_array:
       
   300                 self.TextCtrlDic["CurrentState"].SetValue(token[2])           
       
   301         except :
       
   302             pass     
       
   303         
       
   304     def StartTimer(self, event):
       
   305         """
       
   306         Event handler for "Start State Monitoring" button.
       
   307           - start slave state monitoring thread
       
   308         @param event : wx.EVT_BUTTON object
       
   309         """
       
   310         self.SlaveStateThread = wx.Timer(self)
       
   311         # set timer period (1000 ms)
       
   312         self.SlaveStateThread.Start(1000)
       
   313         
       
   314     def CurrentStateThreadStop(self, event):
       
   315         """
       
   316         Event handler for "Stop State Monitoring" button.
       
   317           - stop slave state monitoring thread
       
   318         @param event : wx.EVT_BUTTON object
       
   319         """
       
   320         try:
       
   321             self.SlaveStateThread.Stop()
       
   322         except:
       
   323             pass
       
   324         
       
   325 #-------------------------------------------------------------------------------
       
   326 #                    For SDO Management Panel
       
   327 #-------------------------------------------------------------------------------  
       
   328 class SDOPanelClass(wx.Panel):
       
   329     def __init__(self, parent, controler):
       
   330         """
       
   331         Constructor
       
   332         @param parent: Reference to the parent EtherCATManagementTreebook class
       
   333         @param controler: _EthercatSlaveCTN class in EthercatSlave.py
       
   334         """
       
   335         wx.Panel.__init__(self, parent, -1)
       
   336         
       
   337         self.DatatypeDescription, self.CommunicationObject, self.ManufacturerSpecific, \
       
   338         self.ProfileSpecific, self.Reserved, self.AllSDOData = range(6)
       
   339         
       
   340         self.Controler = controler
       
   341         
       
   342         self.SDOManagementMainSizer = wx.BoxSizer(wx.VERTICAL)
       
   343         self.SDOManagementInnerMainSizer = wx.FlexGridSizer(cols=1, hgap=10, rows=2, vgap=10)
       
   344              
       
   345         self.SDOUpdate = wx.Button(self, label=_('update'))          
       
   346         self.SDOUpdate.Bind(wx.EVT_BUTTON, self.SDOInfoUpdate)
       
   347         
       
   348         self.CallSDONoteBook = SDONoteBook(self, controler=self.Controler)
       
   349         self.SDOManagementInnerMainSizer.Add(self.SDOUpdate)
       
   350         self.SDOManagementInnerMainSizer.Add(self.CallSDONoteBook, wx.ALL | wx.EXPAND)           
       
   351 
       
   352         self.SDOManagementMainSizer.Add(self.SDOManagementInnerMainSizer)
       
   353         
       
   354         self.SetSizer(self.SDOManagementMainSizer)
       
   355         
       
   356     def SDOInfoUpdate(self, event):
       
   357         """
       
   358         Evenet handler for SDO "update" button.
       
   359           - Load SDO data from current slave 
       
   360         @param event : wx.EVT_BUTTON object
       
   361         """     
       
   362         self.Controler.CommonMethod.SaveSDOData = []
       
   363         self.Controler.CommonMethod.ClearSDODataSet()
       
   364         self.SDOFlag = False
       
   365         
       
   366         # Check whether beremiz connected or not.
       
   367         check_connect_flag = self.Controler.CommonMethod.CheckConnect(False)
       
   368         if check_connect_flag:
       
   369             self.SDOs = self.Controler.CommonMethod.GetSlaveSDOFromSlave()
       
   370             # SDOFlag is "False", user click "Cancel" button
       
   371             self.SDOFlag = self.SDOParser() 
       
   372 
       
   373             if self.SDOFlag :
       
   374                 self.CallSDONoteBook.CreateNoteBook()      
       
   375                 self.Refresh()
       
   376     
       
   377     def SDOParser(self):  
       
   378         """
       
   379         Parse SDO data set that obtain "SDOInfoUpdate" Method
       
   380         @return True or False 
       
   381         """       
       
   382 
       
   383         slaveSDO_progress = wx.ProgressDialog("Slave SDO Monitoring", "Now Uploading...",
       
   384                                maximum = len(self.SDOs.splitlines()), parent=self,
       
   385                                style = wx.PD_CAN_ABORT | wx.PD_APP_MODAL | wx.PD_ELAPSED_TIME | 
       
   386                                        wx.PD_ESTIMATED_TIME | wx.PD_REMAINING_TIME | 
       
   387                                        wx.PD_AUTO_HIDE | wx.PD_SMOOTH)        
       
   388         
       
   389         # If keep_going flag is False, SDOParser method is stop and return "False".
       
   390         keep_going = True
       
   391         count = 0
       
   392              
       
   393         # SDO data example 
       
   394         # SDO 0x1000, "Device type"
       
   395         # 0x1000:00,r-r-r-,uint32,32 bit,"Device type",0x00020192, 131474
       
   396         for details_line in self.SDOs.splitlines():
       
   397             count += 1
       
   398             line_token = details_line.split("\"")
       
   399             # len(line_token[2]) case : SDO 0x1000, "Device type"
       
   400             if len(line_token[2]) == 0:
       
   401                 title_name = line_token[1]
       
   402             # else case : 0x1000:00,r-r-r-,uint32,32 bit,"Device type",0x00020192, 131474
       
   403             else :
       
   404                 # line_token = ['0x1000:00,r-r-r-,uint32,32 bit,', 'Device type', ',0x00020192, 131474']
       
   405                 token_head, name, token_tail = line_token
       
   406                 
       
   407                 # token_head = ['0x1000:00', 'r-r-r-', 'uint32', '32 bit', '']
       
   408                 token_head = token_head.split(",")
       
   409                 ful_idx, access, type, size, empty = token_head
       
   410                 # ful_idx.split(":") = ['0x1000', '00']
       
   411                 idx, sub_idx = ful_idx.split(":")
       
   412                 
       
   413                 # token_tail = ['', '0x00020192', '131474']
       
   414                 token_tail = token_tail.split(",")
       
   415                 try :
       
   416                     empty, hex_val, dec_val = token_tail
       
   417                     
       
   418                 # SDO data is not return "dec value"
       
   419                 # line example : 
       
   420                 # 0x1702:01,rwr-r-,uint32,32 bit," 1st mapping", ---- 
       
   421                 except :
       
   422                     empty, hex_val = token_tail
       
   423                 
       
   424                 name_after_check = self.StringTest(name)
       
   425                 
       
   426                 # convert hex type
       
   427                 sub_idx = "0x" + sub_idx
       
   428 
       
   429                 if type == "octet_string":
       
   430                     hex_val = ' ---- '
       
   431             
       
   432                 # SResult of SlaveSDO data parsing. (data type : dictionary)
       
   433                 self.Data = {'idx':idx.strip(), 'subIdx':sub_idx.strip(), 'access':access.strip(), 
       
   434                              'type':type.strip(), 'size':size.strip(),  'name':name_after_check.strip("\""), 
       
   435                              'value':hex_val.strip(), "category":title_name.strip("\"")}
       
   436                 
       
   437                 category_divide_value = [0x1000, 0x2000, 0x6000, 0xa000, 0xffff]
       
   438 
       
   439                 for count in range(len(category_divide_value)) :
       
   440                     if int(idx, 0) < category_divide_value[count]:
       
   441                         self.Controler.CommonMethod.SaveSDOData[count].append(self.Data)
       
   442                         break
       
   443                 
       
   444                 self.Controler.CommonMethod.SaveSDOData[self.AllSDOData].append(self.Data)
       
   445                       
       
   446             if count >= len(self.SDOs.splitlines()) / 2:
       
   447                 (keep_going, skip) = slaveSDO_progress.Update(count, "Please waiting a moment!!")
       
   448             else:
       
   449                 (keep_going, skip) = slaveSDO_progress.Update(count)
       
   450                 
       
   451             # If user click "Cancel" loop suspend immediately 
       
   452             if (keep_going == False):
       
   453                 break
       
   454             
       
   455         slaveSDO_progress.Destroy()      
       
   456         return keep_going  
       
   457 
       
   458     def StringTest(self, check_string):
       
   459         """
       
   460         Test value 'name' is alphanumeric  
       
   461         @param check_string : input data for check 
       
   462         @return result : output data after check
       
   463         """  
       
   464         # string.printable is print this result
       
   465         #'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
       
   466         #!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c
       
   467         allow_range = string.printable
       
   468         result = check_string
       
   469         for i in range(0, len(check_string)):
       
   470             # string.isalnum() is check whether string is alphanumeric or not
       
   471             if check_string[len(check_string)-1-i:len(check_string)-i] in allow_range :
       
   472                 result = check_string[:len(check_string) - i]
       
   473                 break
       
   474         return result
       
   475     
       
   476     
       
   477 #-------------------------------------------------------------------------------
       
   478 #                    For SDO Notebook (divide category)
       
   479 #-------------------------------------------------------------------------------  
       
   480 class SDONoteBook(wx.Notebook):
       
   481     def __init__(self, parent, controler):
       
   482         """
       
   483         Constructor
       
   484         @param parent: Reference to the parent SDOPanelClass class
       
   485         @param controler: _EthercatSlaveCTN class in EthercatSlave.py
       
   486         """
       
   487         wx.Notebook.__init__(self, parent, id = -1, size=(850,500))      
       
   488         self.Controler = controler
       
   489         self.parent = parent
       
   490         
       
   491         self.CreateNoteBook()
       
   492         
       
   493         self.Bind(wx.EVT_CHOICEBOOK_PAGE_CHANGED, self.OnPageChanged)
       
   494         self.Bind(wx.EVT_CHOICEBOOK_PAGE_CHANGING, self.OnPageChanging)
       
   495         
       
   496     def CreateNoteBook(self): 
       
   497         """
       
   498         Create each NoteBook page, divided SDO index
       
   499         According to EtherCAT Communication(03/2011), 158p
       
   500         """   
       
   501         self.Data = []
       
   502         count = 1
       
   503         
       
   504         page_texts = [("all", self.parent.AllSDOData),
       
   505                      ("0x0000 - 0x0ff", self.parent.DatatypeDescription),
       
   506                      ("0x1000 - 0x1fff", self.parent.CommunicationObject),
       
   507                      ("0x2000 - 0x5fff", self.parent.ManufacturerSpecific),
       
   508                      ("0x6000 - 0x9fff", self.parent.ProfileSpecific),
       
   509                      ("0xa000 - 0xffff", self.parent.Reserved)]
       
   510 
       
   511         page_tooltip_string = ["SDO Index 0x0000 - 0x0fff : Data Type Description",
       
   512                                "SDO Index 0x1000 - 0x1fff : Communication object",
       
   513                                "SDO Index 0x2000 - 0x5fff : Manufacturer specific",
       
   514                                "SDO Index 0x6000 - 0x9fff : Profile specific",
       
   515                                "SDO Index 0xa000 - 0xffff : Reserved",
       
   516                                "All SDO Object"]
       
   517 
       
   518         self.DeleteAllPages()
       
   519         
       
   520         for txt, count in page_texts:
       
   521             self.Data = self.Controler.CommonMethod.SaveSDOData[count]
       
   522             self.Win = SlaveSDOTable(self, self.Data) 
       
   523             self.AddPage(self.Win, txt)
       
   524         
       
   525     def OnPageChanged(self, event):
       
   526         old = event.GetOldSelection()
       
   527         new = event.GetSelection()
       
   528         sel = self.GetSelection()
       
   529         event.Skip()
       
   530 
       
   531     def OnPageChanging(self, event):
       
   532         old = event.GetOldSelection()
       
   533         new = event.GetSelection()
       
   534         sel = self.GetSelection()
       
   535         event.Skip()
       
   536 
       
   537 #-------------------------------------------------------------------------------
       
   538 #                    For SDO Grid (fill index, subindex, etc...)
       
   539 #-------------------------------------------------------------------------------  
       
   540 class SlaveSDOTable(wx.grid.Grid):  
       
   541     def __init__(self, parent, data):
       
   542         """
       
   543         Constructor
       
   544         @param parent: Reference to the parent SDOPanelClass class
       
   545         @param data: SDO data after parsing "SDOParser" method
       
   546         """
       
   547         wx.grid.Grid.__init__(self, parent, -1, size=(830,490), 
       
   548                               style=wx.EXPAND|wx.ALIGN_CENTRE_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)
       
   549         
       
   550         self.Controler = parent.Controler
       
   551         self.parent = parent
       
   552         self.SDOFlag = True
       
   553         if data is None :
       
   554             self.SDOs = []
       
   555         else :
       
   556             self.SDOs = data
       
   557         
       
   558         self.CreateGrid(len(self.SDOs), 8)
       
   559         SDOCellSize = [(0, 65), (1, 65), (2, 50), (3, 55), 
       
   560                          (4, 40), (5, 200), (6, 250), (7, 85)]
       
   561         
       
   562         for (index, size) in SDOCellSize:
       
   563             self.SetColSize(index, size)
       
   564         
       
   565         self.SetRowLabelSize(0)
       
   566         
       
   567         SDOTableLabel = [(0, "Index"), (1, "Subindex"), (2, "Access"),
       
   568                          (3, "Type"), (4, "Size"), (5, "Category"),
       
   569                          (6, "Name"), (7, "Value")]
       
   570         
       
   571         for (index, label) in SDOTableLabel:
       
   572             self.SetColLabelValue(index, label)
       
   573             self.SetColLabelAlignment(index, wx.ALIGN_CENTRE)
       
   574             
       
   575         attr = wx.grid.GridCellAttr()
       
   576 
       
   577         # for SDO download 
       
   578         self.Bind(gridlib.EVT_GRID_CELL_LEFT_DCLICK, self.SDOModifyDialog)
       
   579         
       
   580         for i in range(7): 
       
   581             self.SetColAttr(i,attr)                   
       
   582         
       
   583         self.SetColLabelAlignment(wx.ALIGN_CENTER, wx.ALIGN_CENTER)
       
   584             
       
   585         self.SetTableValue()  
       
   586              
       
   587     def SetTableValue(self):
       
   588         """
       
   589         Cell is filled by new parsing data
       
   590         """
       
   591         sdo_list = ['idx', 'subIdx', 'access', 'type', 'size', 'category', 'name', 'value']
       
   592         for row_idx in range(len(self.SDOs)):
       
   593             for col_idx in range(len(self.SDOs[row_idx])):          
       
   594                 self.SetCellValue(row_idx, col_idx, self.SDOs[row_idx][sdo_list[col_idx]])
       
   595                 self.SetReadOnly(row_idx, col_idx, True)
       
   596                 if col_idx < 5 :
       
   597                     self.SetCellAlignment(row_idx, col_idx, wx.ALIGN_CENTRE, wx.ALIGN_CENTRE)
       
   598         
       
   599     def CheckSDODataAccess(self, row):
       
   600         """
       
   601         CheckSDODataAccess method is checking that access data has "w"
       
   602         Access field consist 6 char, if mean
       
   603            rw      rw     rw
       
   604         (preop) (safeop) (op) 
       
   605         Example Access field : rwrwrw, rwrw-- 
       
   606         @param row : Selected cell by user
       
   607         @return Write_flag : If data has "w", flag is true
       
   608         """
       
   609         write_flag = False
       
   610         check = self.SDOs[row]['access']
       
   611         if check[1:2] == 'w' :
       
   612             self.Controler.CommonMethod.Check_PREOP = True
       
   613             write_flag = True
       
   614         if check[3:4] == 'w' : 
       
   615             self.Controler.CommonMethod.Check_SAFEOP = True
       
   616             write_flag = True
       
   617         if check[5:] =='w' :
       
   618             self.Controler.CommonMethod.Check_OP = True
       
   619             write_flag = True
       
   620             
       
   621         return write_flag
       
   622     
       
   623     def DecideSDODownload(self, state):
       
   624         """
       
   625         compare current state and "access" field, 
       
   626         result notify SDOModifyDialog method
       
   627         @param state : current slave state
       
   628         @return True or False
       
   629         """
       
   630         # Example of 'state' parameter : "0  0:0  PREOP  +  EL9800 (V4.30) (PIC24, SPI, ET1100)" 
       
   631         state = state[self.Controler.GetSlavePos()].split("  ")[2]
       
   632         if state == "PREOP" and self.Controler.CommonMethod.Check_PREOP :
       
   633             return True
       
   634         elif state == "SAFEOP" and self.Controler.CommonMethod.Check_SAFEOP :
       
   635             return True
       
   636         elif state == "OP" and self.Controler.CommonMethod.Check_OP :
       
   637             return True
       
   638         
       
   639         return False
       
   640     
       
   641     def ClearStateFlag(self):
       
   642         """
       
   643         Initialize StateFlag
       
   644         StateFlag is notice SDOData access each slave state
       
   645         """
       
   646         self.Controler.CommonMethod.Check_PREOP = False
       
   647         self.Controler.CommonMethod.Check_SAFEOP = False
       
   648         self.Controler.CommonMethod.Check_OP = False
       
   649     
       
   650     def SDOModifyDialog (self, event):
       
   651         """
       
   652         Create dialog for SDO value modify
       
   653         if user enter data, perform command "ethercat download"  
       
   654         @param event : gridlib.EVT_GRID_CELL_LEFT_DCLICK object
       
   655         """
       
   656         self.ClearStateFlag()
       
   657         
       
   658         # CheckSDODataAccess is checking that OD(Object Dictionary) has "w" 
       
   659         if event.GetCol() == 7 and self.CheckSDODataAccess(event.GetRow()) :    
       
   660             dlg = wx.TextEntryDialog (self, "Enter hex or dec value (if enter dec value, it automatically conversed hex value)",
       
   661                                       "SDOModifyDialog", style = wx.OK | wx.CANCEL)
       
   662 
       
   663             start_value = self.GetCellValue(event.GetRow(), event.GetCol()) 
       
   664             dlg.SetValue(start_value)
       
   665             
       
   666             if dlg.ShowModal() == wx.ID_OK:
       
   667                 try :
       
   668                     int(dlg.GetValue(), 0)
       
   669                     # check "Access" field
       
   670                     if self.DecideSDODownload(self.Controler.CommonMethod.SlaveState[self.Controler.GetSlavePos()]) :
       
   671                         # Request "SDODownload"
       
   672                         self.Controler.CommonMethod.SDODownload(self.SDOs[event.GetRow()]['type'], self.SDOs[event.GetRow()]['idx'], 
       
   673                                                    self.SDOs[event.GetRow()]['subIdx'], dlg.GetValue())
       
   674                         self.SetCellValue(event.GetRow(), event.GetCol(), hex(int(dlg.GetValue(), 0)))
       
   675                     else :
       
   676                         self.Controler.CommonMethod.CreateErrorDialog('You cannot SDO download this state')                  
       
   677                 # Error occured process of "int(variable)"
       
   678                 # User input is not hex, dec value
       
   679                 except ValueError:
       
   680                     self.Controler.CommonMethod.CreateErrorDialog('You can input only hex, dec value')    
       
   681 
       
   682 
       
   683 #-------------------------------------------------------------------------------
       
   684 #                 For PDO Monitoring Panel
       
   685 # PDO Class UI  : Panel -> Choicebook (RxPDO, TxPDO) -> 
       
   686 #                 Notebook (PDO Index) -> Grid (PDO entry)
       
   687 #-------------------------------------------------------------------------------  
       
   688 class PDOPanelClass(wx.Panel):
       
   689     def __init__(self, parent, controler):
       
   690         """
       
   691         Constructor
       
   692         @param parent: Reference to the parent EtherCATManagementTreebook class
       
   693         @param controler: _EthercatSlaveCTN class in EthercatSlave.py
       
   694         """
       
   695         wx.Panel.__init__(self, parent, -1)
       
   696         self.Controler = controler
       
   697 
       
   698         self.PDOMonitoringEditorMainSizer = wx.BoxSizer(wx.VERTICAL)
       
   699         self.PDOMonitoringEditorInnerMainSizer = wx.FlexGridSizer(cols=1, hgap=10, rows=2, vgap=10)
       
   700         
       
   701         self.CallPDOChoicebook = PDOChoicebook(self, controler=self.Controler)   
       
   702         self.PDOMonitoringEditorInnerMainSizer.Add(self.CallPDOChoicebook, wx.ALL)    
       
   703         
       
   704         self.PDOMonitoringEditorMainSizer.Add(self.PDOMonitoringEditorInnerMainSizer)
       
   705         
       
   706         self.SetSizer(self.PDOMonitoringEditorMainSizer)
       
   707 
       
   708     def PDOInfoUpdate(self):
       
   709         """
       
   710         Call RequestPDOInfo method and create Choicebook
       
   711         """
       
   712         self.Controler.CommonMethod.RequestPDOInfo()
       
   713         self.CallPDOChoicebook.Destroy()
       
   714         self.CallPDOChoicebook = PDOChoicebook(self, controler=self.Controler)
       
   715         self.Refresh()
       
   716 
       
   717 
       
   718 #-------------------------------------------------------------------------------
       
   719 #                    For PDO Choicebook (divide Tx, Rx PDO)
       
   720 #-------------------------------------------------------------------------------  
       
   721 class PDOChoicebook(wx.Choicebook):
       
   722     def __init__(self, parent, controler):
       
   723         """
       
   724         Constructor
       
   725         @param parent: Reference to the parent PDOPanelClass class
       
   726         @param controler: _EthercatSlaveCTN class in EthercatSlave.py
       
   727         """
       
   728         wx.Choicebook.__init__(self, parent, id=-1, size=(500, 500), style=wx.CHB_DEFAULT)
       
   729         self.Controler = controler
       
   730         
       
   731         RxWin = PDONoteBook(self, controler=self.Controler, name="Rx")
       
   732         TxWin = PDONoteBook(self, controler=self.Controler, name="Tx")
       
   733         self.AddPage(RxWin, "RxPDO")
       
   734         self.AddPage(TxWin, "TxPDO")
       
   735         
       
   736         self.Bind(wx.EVT_CHOICEBOOK_PAGE_CHANGED, self.OnPageChanged)
       
   737         self.Bind(wx.EVT_CHOICEBOOK_PAGE_CHANGING, self.OnPageChanging)
       
   738         
       
   739     def OnPageChanged(self, event):
       
   740         old = event.GetOldSelection()
       
   741         new = event.GetSelection()
       
   742         sel = self.GetSelection()
       
   743         event.Skip()
       
   744 
       
   745     def OnPageChanging(self, event):
       
   746         old = event.GetOldSelection()
       
   747         new = event.GetSelection()
       
   748         sel = self.GetSelection()
       
   749         event.Skip()     
       
   750 
       
   751 
       
   752 #-------------------------------------------------------------------------------
       
   753 #                    For PDO Notebook (divide PDO index)
       
   754 #-------------------------------------------------------------------------------  
       
   755 class PDONoteBook(wx.Notebook):
       
   756     def __init__(self, parent, name, controler):
       
   757         """
       
   758         Constructor
       
   759         @param parent: Reference to the parent PDOChoicebook class
       
   760         @param name: identifier whether RxPDO or TxPDO
       
   761         @param controler: _EthercatSlaveCTN class in EthercatSlave.py
       
   762         """
       
   763         wx.Notebook.__init__(self, parent, id=-1, size=(640, 400))
       
   764         self.Controler = controler
       
   765         
       
   766         count = 0
       
   767         page_texts = []
       
   768         
       
   769         self.Controler.CommonMethod.RequestPDOInfo()
       
   770         
       
   771         if name == "Tx" :
       
   772             # obtain pdo_info and pdo_entry
       
   773             # pdo_info include (PDO index, name, number of entry)
       
   774             pdo_info =  self.Controler.CommonMethod.GetTxPDOCategory()
       
   775             pdo_entry = self.Controler.CommonMethod.GetTxPDOInfo()
       
   776             for tmp in pdo_info :
       
   777                 title = str(hex(tmp['pdo_index']))
       
   778                 page_texts.append(title)
       
   779         # RX PDO case
       
   780         else :  
       
   781             pdo_info = self.Controler.CommonMethod.GetRxPDOCategory()
       
   782             pdo_entry = self.Controler.CommonMethod.GetRxPDOInfo()
       
   783             for tmp in pdo_info :
       
   784                 title = str(hex(tmp['pdo_index']))
       
   785                 page_texts.append(title)
       
   786                
       
   787         # Add page depending on the number of pdo_info
       
   788         for txt in page_texts:
       
   789             win = PDOEntryTable(self, pdo_info, pdo_entry, count)
       
   790             self.AddPage(win, txt)
       
   791             count += 1  
       
   792 
       
   793         self.Bind(wx.EVT_CHOICEBOOK_PAGE_CHANGED, self.OnPageChanged)
       
   794         self.Bind(wx.EVT_CHOICEBOOK_PAGE_CHANGING, self.OnPageChanging)
       
   795         
       
   796     def OnPageChanged(self, event):
       
   797         old = event.GetOldSelection()
       
   798         new = event.GetSelection()
       
   799         sel = self.GetSelection()
       
   800         event.Skip()
       
   801 
       
   802     def OnPageChanging(self, event):
       
   803         old = event.GetOldSelection()
       
   804         new = event.GetSelection()
       
   805         sel = self.GetSelection()
       
   806         event.Skip()     
       
   807 
       
   808 
       
   809 #-------------------------------------------------------------------------------
       
   810 #                    For PDO Grid (fill entry index, subindex etc...)
       
   811 #-------------------------------------------------------------------------------  
       
   812 class PDOEntryTable(wx.grid.Grid):
       
   813     def __init__(self, parent, info, entry, count):
       
   814         """
       
   815         Constructor
       
   816         @param parent: Reference to the parent PDONoteBook class
       
   817         @param info : data structure including entry index, sub index, name, length, type
       
   818         @param entry : data structure including index, name, entry number
       
   819         @param count : page number
       
   820         """
       
   821         wx.grid.Grid.__init__(self, parent, -1, size=(500, 400), pos=wx.Point(0,0), 
       
   822                               style=wx.EXPAND|wx.ALIGN_CENTRE_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)
       
   823         
       
   824         self.Controler = parent.Controler
       
   825         
       
   826         self.PDOInfo = info
       
   827         self.PDOEntry = entry
       
   828         self.Count = count
       
   829         
       
   830         self.CreateGrid(self.PDOInfo[self.Count]['number_of_entry'], 5)
       
   831         self.SetColLabelSize(25)   
       
   832         self.SetRowLabelSize(0)
       
   833         
       
   834         PDOTableLabel = [(0, "Index"), (1, "Subindex"), (2, "Length"),
       
   835                          (3, "Type"), (4, "Name")]
       
   836         
       
   837         for (index, label) in PDOTableLabel:
       
   838             self.SetColLabelValue(index, label)
       
   839         
       
   840         PDOCellSize = [(0, 45), (1, 65), (2, 55), (3, 40), (4, 300)]
       
   841         
       
   842         for (index, size) in PDOCellSize:
       
   843             self.SetColSize(index, size)
       
   844             self.SetColLabelAlignment(index, wx.ALIGN_LEFT)
       
   845         
       
   846         attr = wx.grid.GridCellAttr()
       
   847         
       
   848         for i in range(5):
       
   849             self.SetColAttr(i, attr)
       
   850          
       
   851         self.SetTableValue()
       
   852             
       
   853     def SetTableValue(self):
       
   854         """
       
   855         Cell is filled by new parsing data in XML
       
   856         """
       
   857         list_index = 0
       
   858         # number of entry
       
   859         for i in range(self.Count + 1) :
       
   860             list_index += self.PDOInfo[i]['number_of_entry']
       
   861 
       
   862         start_value = list_index - self.PDOInfo[self.Count]['number_of_entry']
       
   863         
       
   864         pdo_list = ['entry_index', 'subindex', 'bitlen', 'type', 'name']
       
   865         for row_idx in range(self.PDOInfo[self.Count]['number_of_entry']):
       
   866             for col_idx in range(len(self.PDOEntry[row_idx])):
       
   867                 # entry index is converted hex value.
       
   868                 if col_idx == 0 :
       
   869                     self.SetCellValue(row_idx, col_idx, hex(self.PDOEntry[start_value][pdo_list[col_idx]]))
       
   870                 else :
       
   871                     self.SetCellValue(row_idx, col_idx, str(self.PDOEntry[start_value][pdo_list[col_idx]]))
       
   872                 if col_idx != 4 :
       
   873                     self.SetCellAlignment(row_idx, col_idx, wx.ALIGN_CENTRE, wx.ALIGN_CENTRE)
       
   874                 else :
       
   875                     self.SetCellAlignment(row_idx, col_idx, wx.ALIGN_LEFT, wx.ALIGN_CENTRE)
       
   876                 self.SetReadOnly(row_idx, col_idx, True)
       
   877                 self.SetRowSize(row_idx, 25)
       
   878             start_value += 1
       
   879 
       
   880 
       
   881 #-------------------------------------------------------------------------------
       
   882 #                    For EEPROM Access Main Panel 
       
   883 #                 (This class explain EEPROM Access)
       
   884 #-------------------------------------------------------------------------------  
       
   885 class EEPROMAccessPanel(wx.Panel):
       
   886     def __init__(self, parent, controler):
       
   887         """
       
   888         Constructor
       
   889         @param parent: Reference to the parent EtherCATManagementTreebook class
       
   890         @param controler: _EthercatSlaveCTN class in EthercatSlave.py
       
   891         """
       
   892         wx.Panel.__init__(self, parent, -1)
       
   893         sizer = wx.FlexGridSizer(cols=1, hgap=20,rows=3, vgap=20)
       
   894         
       
   895         line = wx.StaticText(self, -1, "\n  EEPROM Access is composed to SmartView and HexView. \
       
   896                                               \n\n   - SmartView shows Config Data, Device Identity, Mailbox settings, etc. \
       
   897                                               \n\n   - HexView shows EEPROM's contents.")
       
   898         
       
   899         sizer.Add(line)
       
   900         
       
   901         self.SetSizer(sizer)
       
   902 
       
   903 
       
   904 #-------------------------------------------------------------------------------
       
   905 #                    For Smart View Panel 
       
   906 #-------------------------------------------------------------------------------  
       
   907 class SlaveSiiSmartView(wx.Panel):
       
   908     def __init__(self, parent, controler):
       
   909         """
       
   910         Constructor
       
   911         @param parent: Reference to the parent EtherCATManagementTreebook class
       
   912         @param controler: _EthercatSlaveCTN class in EthercatSlave.py
       
   913         """
       
   914         wx.Panel.__init__(self, parent, -1)
       
   915         self.parent = parent
       
   916         self.Controler = controler
       
   917         
       
   918         self.PDIType = {0  :['none', '00000000'], 
       
   919                         4  :['Digital I/O', '00000100'],
       
   920                         5  :['SPI Slave', '00000101'],
       
   921                         7  :['EtherCAT Bridge (port3)', '00000111'],
       
   922                         8  :['uC async. 16bit', '00001000'],
       
   923                         9  :['uC async. 8bit', '00001001'],
       
   924                         10 :['uC sync. 16bit', '00001010'],
       
   925                         11 :['uC sync. 8bit', '00001011'],
       
   926                         16 :['32 Digtal Input and 0 Digital Output', '00010000'],
       
   927                         17 :['24 Digtal Input and 8 Digital Output', '00010001'],
       
   928                         18 :['16 Digtal Input and 16 Digital Output','00010010'],
       
   929                         19 :['8 Digtal Input and 24 Digital Output', '00010011'],
       
   930                         20 :['0 Digtal Input and 32 Digital Output', '00010100'],
       
   931                         128:['On-chip bus', '11111111']
       
   932                         }
       
   933         
       
   934         sizer = wx.FlexGridSizer(cols=1, hgap=5, rows=2, vgap=5)
       
   935         button_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=1, vgap=5)
       
   936 
       
   937         for button, mapping_method in [("Write EEPROM", self.WriteToEEPROM),
       
   938                                        ("Read EEPROM", self.ReadFromEEPROM)]:
       
   939             btn = wx.Button(self, -1, button, size=(150, 40))
       
   940             button_sizer.Add(btn, border=10, flag=wx.ALL)
       
   941             btn.Bind(wx.EVT_BUTTON, mapping_method)
       
   942         
       
   943         self.TreeListCtrl = SmartViewTreeListCtrl(self, self.Controler)
       
   944         
       
   945         sizer.Add(button_sizer, border=10, flag=wx.ALL)
       
   946         sizer.Add(self.TreeListCtrl, border=10, flag=wx.ALL)
       
   947         self.SetSizer(sizer)
       
   948         
       
   949         self.Create_SmartView()
       
   950         
       
   951     def Create_SmartView(self):
       
   952         """
       
   953         SmartView shows information based on XML as initial value.
       
   954         """  
       
   955         self.Controler.CommonMethod.SmartViewInfosFromXML = self.Controler.CommonMethod.GetSmartViewInfos()
       
   956         self.SetXMLData()
       
   957                 
       
   958     def WriteToEEPROM(self, event):
       
   959         """
       
   960         Open binary file (user select) and write the selected binary data to EEPROM
       
   961         @param event : wx.EVT_BUTTON object
       
   962         """  
       
   963         # Check whether beremiz connected or not, and whether status is "Started" or not.
       
   964         check_connect_flag = self.Controler.CommonMethod.CheckConnect(False)
       
   965         if check_connect_flag:
       
   966             status, count = self.Controler.GetCTRoot()._connector.GetPLCstatus()
       
   967             if status is not "Started":
       
   968                 dialog = wx.FileDialog(self, _("Choose a binary file"), os.getcwd(), "",  _("bin files (*.bin)|*.bin"), wx.OPEN)
       
   969                 
       
   970                 if dialog.ShowModal() == wx.ID_OK:
       
   971                     filepath = dialog.GetPath()
       
   972                     try:
       
   973                         binfile = open(filepath,"rb")
       
   974                         self.SiiBinary = binfile.read()
       
   975                         dialog.Destroy()
       
   976                         
       
   977                         self.Controler.CommonMethod.SiiWrite(self.SiiBinary)
       
   978                         # refresh data structure kept by master
       
   979                         self.Controler.CommonMethod.Rescan()
       
   980                         # save binary data as inner global data of beremiz 
       
   981                         # for fast loading when slave plugin node is reopened.
       
   982                         self.Controler.CommonMethod.SiiData = self.SiiBinary
       
   983                         self.SetEEPROMData()
       
   984                     except:
       
   985                         self.Controler.CommonMethod.CreateErrorDialog('The file does not exist!')
       
   986                         dialog.Destroy()
       
   987     
       
   988     def ReadFromEEPROM(self, event):
       
   989         """
       
   990         Refresh displayed data based on slave EEPROM and save binary file through dialog
       
   991         @param event : wx.EVT_BUTTON object
       
   992         """  
       
   993         # Check whether beremiz connected or not.
       
   994         check_connect_flag = self.Controler.CommonMethod.CheckConnect(False)
       
   995         if check_connect_flag:
       
   996             self.SiiBinary = self.Controler.CommonMethod.LoadData()
       
   997             self.SetEEPROMData()
       
   998             dialog = wx.FileDialog(self, _("Save as..."), os.getcwd(), 
       
   999                                    "slave0.bin",  _("bin files (*.bin)|*.bin|All files|*.*"), 
       
  1000                                    wx.SAVE|wx.OVERWRITE_PROMPT)
       
  1001         
       
  1002             if dialog.ShowModal() == wx.ID_OK:
       
  1003                 filepath = dialog.GetPath()
       
  1004                 binfile = open(filepath,"wb")
       
  1005                 binfile.write(self.SiiBinary)
       
  1006                 binfile.close()
       
  1007     
       
  1008             dialog.Destroy()
       
  1009     
       
  1010     def SetXMLData(self):
       
  1011         """
       
  1012         Set data based on XML initially
       
  1013         """  
       
  1014         # Config Data: EEPROM Size, PDI Type, Device Emulation
       
  1015         # Find PDI Type in pdiType dictionary
       
  1016         cnt_pdi_type = self.Controler.CommonMethod.SmartViewInfosFromXML["pdi_type"]
       
  1017         for i in self.PDIType.keys():
       
  1018             if cnt_pdi_type == i:
       
  1019                 cnt_pdi_type = self.PDIType[i][0]
       
  1020                 break
       
  1021         #  Set Config Data
       
  1022         for treelist, data in [("EEPROM Size (Bytes)", 
       
  1023                                 str(self.Controler.CommonMethod.SmartViewInfosFromXML["eeprom_size"])),
       
  1024                                ("PDI Type", 
       
  1025                                 cnt_pdi_type),
       
  1026                                ("Device Emulation", 
       
  1027                                 self.Controler.CommonMethod.SmartViewInfosFromXML["device_emulation"])]:
       
  1028             self.TreeListCtrl.Tree.SetItemText(self.TreeListCtrl.ConfigData[treelist], data, 1)
       
  1029         
       
  1030         # Device Identity: Vendor ID, Product Code, Revision No., Serial No.
       
  1031         #  Set Device Identity
       
  1032         for treelist, data in [("Vendor ID", self.Controler.CommonMethod.SmartViewInfosFromXML["vendor_id"]),
       
  1033                                ("Product Code", self.Controler.CommonMethod.SmartViewInfosFromXML["product_code"]),
       
  1034                                ("Revision No.", self.Controler.CommonMethod.SmartViewInfosFromXML["revision_no"]),
       
  1035                                ("Serial No.", self.Controler.CommonMethod.SmartViewInfosFromXML["serial_no"])]:
       
  1036             self.TreeListCtrl.Tree.SetItemText(self.TreeListCtrl.DeviceIdentity[treelist], data, 1)
       
  1037              
       
  1038         # Mailbox: Supported Mailbox, Bootstrap Configuration, Standard Configuration
       
  1039         #  Set Mailbox
       
  1040         for treelist, data in [("Supported Mailbox", self.Controler.CommonMethod.SmartViewInfosFromXML["supported_mailbox"]),
       
  1041                                ("Bootstrap Configuration", ""),
       
  1042                                ("Standard Configuration", "")]:
       
  1043             self.TreeListCtrl.Tree.SetItemText(self.TreeListCtrl.Mailbox[treelist], data, 1)       
       
  1044         #  Set Bootstrap Configuration: Receive Offset, Receive Size, Send Offset, Send Size
       
  1045         for treelist, data in [("Receive Offset", self.Controler.CommonMethod.SmartViewInfosFromXML["mailbox_bootstrapconf_outstart"]),
       
  1046                                ("Receive Size", self.Controler.CommonMethod.SmartViewInfosFromXML["mailbox_bootstrapconf_outlength"]),
       
  1047                                ("Send Offset", self.Controler.CommonMethod.SmartViewInfosFromXML["mailbox_bootstrapconf_instart"]),
       
  1048                                ("Send Size", self.Controler.CommonMethod.SmartViewInfosFromXML["mailbox_bootstrapconf_inlength"])]:
       
  1049             self.TreeListCtrl.Tree.SetItemText(self.TreeListCtrl.BootstrapConfig[treelist], data, 1)      
       
  1050         #  Set Standard Configuration: Receive Offset, Receive Size, Send Offset, Send Size
       
  1051         for treelist, data in [("Receive Offset", self.Controler.CommonMethod.SmartViewInfosFromXML["mailbox_standardconf_outstart"]),
       
  1052                                ("Receive Size", self.Controler.CommonMethod.SmartViewInfosFromXML["mailbox_standardconf_outlength"]),
       
  1053                                ("Send Offset", self.Controler.CommonMethod.SmartViewInfosFromXML["mailbox_standardconf_instart"]),
       
  1054                                ("Send Size", self.Controler.CommonMethod.SmartViewInfosFromXML["mailbox_standardconf_inlength"])]:
       
  1055             self.TreeListCtrl.Tree.SetItemText(self.TreeListCtrl.StandardConfig[treelist], data, 1)
       
  1056         
       
  1057     def SetEEPROMData(self):
       
  1058         """
       
  1059         Set data based on slave EEPROM.
       
  1060         """  
       
  1061         # sii_dict = { Parameter : (WordAddress, WordSize) }
       
  1062         sii_dict= { 'PDIControl' :                          ( '0', 1),
       
  1063                     'PDIConfiguration' :                    ( '1', 1),
       
  1064                     'PulseLengthOfSYNCSignals' :            ( '2', 1),
       
  1065                     'ExtendedPDIConfiguration' :            ( '3', 1),
       
  1066                     'ConfiguredStationAlias' :              ( '4', 1),
       
  1067                     'Checksum' :                            ( '7', 1),
       
  1068                     'VendorID' :                            ( '8', 2),
       
  1069                     'ProductCode' :                         ( 'a', 2),
       
  1070                     'RevisionNumber' :                      ( 'c', 2),
       
  1071                     'SerialNumber' :                        ( 'e', 2),
       
  1072                     'Execution Delay' :                     ('10', 1),
       
  1073                     'Port0Delay' :                          ('11', 1),
       
  1074                     'Port1Delay' :                          ('12', 1),
       
  1075                     'BootstrapReceiveMailboxOffset' :       ('14', 1),
       
  1076                     'BootstrapReceiveMailboxSize' :         ('15', 1),
       
  1077                     'BootstrapSendMailboxOffset' :          ('16', 1),
       
  1078                     'BootstrapSendMailboxSize' :            ('17', 1),
       
  1079                     'StandardReceiveMailboxOffset' :        ('18', 1),
       
  1080                     'StandardReceiveMailboxSize' :          ('19', 1),
       
  1081                     'StandardSendMailboxOffset' :           ('1a', 1),
       
  1082                     'StandardSendMailboxSize' :             ('1b', 1),
       
  1083                     'MailboxProtocol' :                     ('1c', 1),
       
  1084                     'Size' :                                ('3e', 1),
       
  1085                     'Version' :                             ('3f', 1),
       
  1086                     'First Category Type/Vendor Specific' : ('40', 1),
       
  1087                     'Following Category Word Size' :        ('41', 1),
       
  1088                     'Category Data' :                       ('42', 1),
       
  1089                 }
       
  1090         
       
  1091         # Config Data: EEPROM Size, PDI Type, Device Emulation
       
  1092         # EEPROM's data in address '0x003f' is Size of EEPROM in KBit-1
       
  1093         eeprom_size = str((int(self.GetWordAddressData( sii_dict.get('Size'),10 ))+1)/8*1024)
       
  1094         # Find PDI Type in pdiType dictionary
       
  1095         cnt_pdi_type = int(self.GetWordAddressData( sii_dict.get('PDIControl'),16 ).split('x')[1][2:4], 16)
       
  1096         for i in self.PDIType.keys():
       
  1097             if cnt_pdi_type == i:
       
  1098                 cnt_pdi_type = self.PDIType[i][0]
       
  1099                 break
       
  1100         #  Get Device Emulation
       
  1101         device_emulation = str(bool(int("{:0>16b}".format(int(self.GetWordAddressData( sii_dict.get('PDIControl'),16 ), 16))[7])))    
       
  1102         #  Set Config Data
       
  1103         for treelist, data in [("EEPROM Size (Bytes)", eeprom_size),
       
  1104                                ("PDI Type", cnt_pdi_type),
       
  1105                                ("Device Emulation", device_emulation)]:
       
  1106             self.TreeListCtrl.Tree.SetItemText(self.TreeListCtrl.ConfigData[treelist], data, 1)
       
  1107         
       
  1108         # Device Identity: Vendor ID, Product Code, Revision No., Serial No.
       
  1109         #  Set Device Identity
       
  1110         for treelist, data in [("Vendor ID", self.GetWordAddressData( sii_dict.get('VendorID'),16 )),
       
  1111                                ("Product Code", self.GetWordAddressData( sii_dict.get('ProductCode'),16 )),
       
  1112                                ("Revision No.", self.GetWordAddressData( sii_dict.get('RevisionNumber'),16 )),
       
  1113                                ("Serial No.", self.GetWordAddressData( sii_dict.get('SerialNumber'),16 ))]:
       
  1114             self.TreeListCtrl.Tree.SetItemText(self.TreeListCtrl.DeviceIdentity[treelist], data, 1)
       
  1115       
       
  1116         # Mailbox
       
  1117         # EEORPOM's word address '1c' indicates supported mailbox protocol.
       
  1118         # each value of mailbox protocol : 
       
  1119         # VoE(0x0020), SoE(0x0010), FoE(0x0008), CoE(0x0004), EoE(0x0002), AoE(0x0001)
       
  1120         supported_mailbox = ""
       
  1121         mailbox_protocol=["VoE,  ", "SoE,  ", "FoE,  ", "CoE,  ", "EoE,  ", "AoE,  "]
       
  1122         mailbox_data = "{:0>8b}".format(int(self.GetWordAddressData( sii_dict.get('MailboxProtocol'),16 ), 16))
       
  1123         for protocol in range(6):
       
  1124             if mailbox_data[protocol+2] == '1':
       
  1125                 supported_mailbox += mailbox_protocol[protocol]
       
  1126         supported_mailbox = supported_mailbox.strip(",  ")
       
  1127         #  Set Mailbox
       
  1128         for treelist, data in [("Supported Mailbox", supported_mailbox),
       
  1129                                ("Bootstrap Configuration", ""),
       
  1130                                ("Standard Configuration", "")]:
       
  1131             self.TreeListCtrl.Tree.SetItemText(self.TreeListCtrl.Mailbox[treelist], data, 1)       
       
  1132         #  Set Bootstrap Configuration: Receive Offset, Receive Size, Send Offset, Send Size
       
  1133         for treelist, data in [("Receive Offset", self.GetWordAddressData( sii_dict.get('BootstrapReceiveMailboxOffset'),10 )),
       
  1134                                ("Receive Size", self.GetWordAddressData( sii_dict.get('BootstrapReceiveMailboxSize'),10 )),
       
  1135                                ("Send Offset", self.GetWordAddressData( sii_dict.get('BootstrapSendMailboxOffset'),10 )),
       
  1136                                ("Send Size", self.GetWordAddressData( sii_dict.get('BootstrapSendMailboxSize'),10 ))]:
       
  1137             self.TreeListCtrl.Tree.SetItemText(self.TreeListCtrl.BootstrapConfig[treelist], data, 1)      
       
  1138         #  Set Standard Configuration: Receive Offset, Receive Size, Send Offset, Send Size
       
  1139         for treelist, data in [("Receive Offset", self.GetWordAddressData( sii_dict.get('StandardReceiveMailboxOffset'),10 )),
       
  1140                                ("Receive Size", self.GetWordAddressData( sii_dict.get('StandardReceiveMailboxSize'),10 )),
       
  1141                                ("Send Offset", self.GetWordAddressData( sii_dict.get('StandardSendMailboxOffset'),10 )),
       
  1142                                ("Send Size", self.GetWordAddressData( sii_dict.get('StandardSendMailboxSize'),10 ))]:
       
  1143             self.TreeListCtrl.Tree.SetItemText(self.TreeListCtrl.StandardConfig[treelist], data, 1)         
       
  1144                 
       
  1145     def MakeStaticBoxSizer(self, boxlabel):
       
  1146         """
       
  1147         Make StaticBoxSizer
       
  1148         @param boxlabel : label of box sizer
       
  1149         @return sizer : the StaticBoxSizer labeled 'boxlabel'
       
  1150         """
       
  1151         box = wx.StaticBox(self, -1, boxlabel)
       
  1152         sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
       
  1153 
       
  1154         return sizer
       
  1155         
       
  1156     def GetWordAddressData(self, dict_tuple, format):
       
  1157         """
       
  1158         This method converts word address data from EEPROM binary.
       
  1159         @param dict_tuple : element of 'sii_dict' dictionary in SetEEPROMData()
       
  1160         @param format : format of data. It can be 16(hex), 10(decimal) and 2(binary).
       
  1161         @return formatted value
       
  1162         """  
       
  1163         offset = int(str(dict_tuple[0]), 16) * 2
       
  1164         length = int(str(dict_tuple[1]), 16) * 2
       
  1165         list = []
       
  1166         data = ''
       
  1167         for index in range(length):
       
  1168             hexdata = hex(ord(self.SiiBinary[offset + index]))[2:]
       
  1169             list.append(hexdata.zfill(2))
       
  1170             
       
  1171         list.reverse()
       
  1172         data = list[0:length]
       
  1173 
       
  1174         if format == 16:
       
  1175             return '0x' + ''.join(data) 
       
  1176         elif format == 10:
       
  1177             return str(int(str(''.join(data)), 16))
       
  1178         elif format == 2: 
       
  1179             ''.join(data)           
       
  1180 
       
  1181 
       
  1182 #-------------------------------------------------------------------------------
       
  1183 #                    For Smart View TreeListCtrl
       
  1184 #-------------------------------------------------------------------------------  
       
  1185 class SmartViewTreeListCtrl(wx.Panel):
       
  1186     def __init__(self, parent, Controler):
       
  1187         """
       
  1188         Constructor
       
  1189         @param parent: Reference to the parent SlaveSiiSmartView class
       
  1190         @param controler: _EthercatSlaveCTN class in EthercatSlave.py
       
  1191         """
       
  1192 
       
  1193         wx.Panel.__init__(self, parent, -1, size=(350, 500))
       
  1194         
       
  1195         self.Tree = wx.gizmos.TreeListCtrl(self, -1, size=(350, 500), 
       
  1196                                            style=wx.TR_DEFAULT_STYLE
       
  1197                                                 |wx.TR_FULL_ROW_HIGHLIGHT
       
  1198                                                 |wx.TR_HIDE_ROOT
       
  1199                                                 |wx.TR_COLUMN_LINES
       
  1200                                                 |wx.TR_ROW_LINES)
       
  1201         
       
  1202         self.Tree.AddColumn("Description", width=200)
       
  1203         self.Tree.AddColumn("Value", width=140)
       
  1204         self.Tree.SetMainColumn(0)
       
  1205         
       
  1206         self.Root = self.Tree.AddRoot("")
       
  1207         
       
  1208         # Add item
       
  1209         #  Level 1 nodes
       
  1210         self.Level1Nodes = {}
       
  1211         for lv1 in ["Config Data", "Device Identity", "Mailbox"]:
       
  1212             self.Level1Nodes[lv1] = self.Tree.AppendItem(self.Root, lv1)
       
  1213         
       
  1214         #  Level 2 nodes
       
  1215         #   Config Data
       
  1216         self.ConfigData = {}
       
  1217         for lv2 in ["EEPROM Size (Bytes)", "PDI Type", "Device Emulation"]:
       
  1218             self.ConfigData[lv2] = self.Tree.AppendItem(self.Level1Nodes["Config Data"], lv2)
       
  1219         #   Device Identity
       
  1220         self.DeviceIdentity = {}
       
  1221         for lv2 in ["Vendor ID", "Product Code", "Revision No.", "Serial No."]:
       
  1222             self.DeviceIdentity[lv2] = self.Tree.AppendItem(self.Level1Nodes["Device Identity"], lv2)
       
  1223         #   Mailbox
       
  1224         self.Mailbox = {}
       
  1225         for lv2 in ["Supported Mailbox", "Bootstrap Configuration", "Standard Configuration"]:
       
  1226             self.Mailbox[lv2] = self.Tree.AppendItem(self.Level1Nodes["Mailbox"], lv2)
       
  1227         
       
  1228         #  Level 3 nodes
       
  1229         #   Children of Bootstrap Configuration
       
  1230         self.BootstrapConfig = {}
       
  1231         for lv3 in ["Receive Offset", "Receive Size", "Send Offset", "Send Size"]:
       
  1232             self.BootstrapConfig[lv3] = self.Tree.AppendItem(self.Mailbox["Bootstrap Configuration"], lv3)
       
  1233         #   Children of Standard Configuration
       
  1234         self.StandardConfig = {}
       
  1235         for lv3 in ["Receive Offset", "Receive Size", "Send Offset", "Send Size"]:
       
  1236             self.StandardConfig[lv3] = self.Tree.AppendItem(self.Mailbox["Standard Configuration"], lv3)
       
  1237         
       
  1238         # Expand Tree
       
  1239         for tree in [self.Root, 
       
  1240                      self.Level1Nodes["Config Data"], 
       
  1241                      self.Level1Nodes["Device Identity"], 
       
  1242                      self.Level1Nodes["Mailbox"],
       
  1243                      self.Mailbox["Bootstrap Configuration"], 
       
  1244                      self.Mailbox["Standard Configuration"]]:
       
  1245             self.Tree.Expand(tree)
       
  1246 
       
  1247 
       
  1248 #-------------------------------------------------------------------------------
       
  1249 #                         For Hex View Panel
       
  1250 #            shows EEPROM binary as hex data and characters.
       
  1251 #-------------------------------------------------------------------------------  
       
  1252 class HexView(wx.Panel):
       
  1253     def __init__(self, parent, controler):
       
  1254         """
       
  1255         Constructor
       
  1256         @param parent: Reference to the parent EtherCATManagementTreebook class
       
  1257         @param controler: _EthercatSlaveCTN class in EthercatSlave.py
       
  1258         """
       
  1259         wx.Panel.__init__(self, parent, -1)
       
  1260         self.parent = parent
       
  1261         self.Controler = controler
       
  1262                 
       
  1263         self.HexRow = 8
       
  1264         self.HexCol = 17
       
  1265         
       
  1266         self.HexViewSizer = {"view" : wx.FlexGridSizer(cols=1, hgap=10, rows=2, vgap=10),
       
  1267                              "siiButton" : wx.BoxSizer()}
       
  1268         self.HexViewButton = {}
       
  1269 
       
  1270         for key, evt_handler in [("Sii Upload", self.OnButtonSiiUpload),
       
  1271                                 ("Sii Download", self.OnButtonSiiDownload),
       
  1272                                 ("Write to File", self.OnButtonWriteToBinFile),
       
  1273                                 ("Read from File", self.OnButtonReadFromBinFile),
       
  1274                                 ("XML to EEPROM Image", self.OnButtonXmlToEEPROMImg)]:
       
  1275             self.HexViewButton[key] = wx.Button(self, -1, key) 
       
  1276             self.HexViewButton[key].Bind(wx.EVT_BUTTON, evt_handler)
       
  1277             self.HexViewSizer["siiButton"].Add(self.HexViewButton[key])
       
  1278 
       
  1279         self.SiiBinary = self.Controler.CommonMethod.XmlToEeprom()
       
  1280         self.HexCode, self.HexRow, self.HexCol = self.Controler.CommonMethod.HexRead(self.SiiBinary)
       
  1281         self.SiiGrid = SiiGridTable(self, self.Controler, self.HexRow, self.HexCol)
       
  1282         self.HexViewSizer["view"].AddMany([self.HexViewSizer["siiButton"], self.SiiGrid]) 
       
  1283         self.SiiGrid.CreateGrid(self.HexRow, self.HexCol)
       
  1284         self.SetSizer(self.HexViewSizer["view"])     
       
  1285         self.HexViewSizer["view"].FitInside(self.parent.parent)
       
  1286         self.parent.parent.FitInside()
       
  1287         self.SiiGrid.SetValue(self.HexCode)
       
  1288         self.SiiGrid.Update()
       
  1289 
       
  1290     def UpdateSiiGridTable(self, row, col):
       
  1291         """
       
  1292         Destroy existing grid and recreate
       
  1293         @param row, col : Hex View grid size
       
  1294         """  
       
  1295         self.HexViewSizer["view"].Detach(self.SiiGrid)
       
  1296         self.SiiGrid.Destroy()
       
  1297         self.SiiGrid = SiiGridTable(self, self.Controler, row, col)
       
  1298         self.HexViewSizer["view"].Add(self.SiiGrid)
       
  1299         self.SiiGrid.CreateGrid(row, col)
       
  1300         self.SetSizer(self.HexViewSizer["view"])
       
  1301         self.HexViewSizer["view"].FitInside(self.parent.parent)
       
  1302         self.parent.parent.FitInside()
       
  1303 
       
  1304     def OnButtonSiiUpload(self, event):
       
  1305         """
       
  1306         Load EEPROM data from slave and refresh Hex View grid
       
  1307         Binded to 'Sii Upload' button.
       
  1308         @param event : wx.EVT_BUTTON object
       
  1309         """  
       
  1310         # Check whether beremiz connected or not.
       
  1311         check_connect_flag = self.Controler.CommonMethod.CheckConnect(False)
       
  1312         if check_connect_flag:
       
  1313             # load from EEPROM data and parsing
       
  1314             self.SiiBinary = self.Controler.CommonMethod.LoadData()
       
  1315             self.HexCode, self.HexRow, self.HexCol = self.Controler.CommonMethod.HexRead(self.SiiBinary)
       
  1316             self.UpdateSiiGridTable(self.HexRow, self.HexCol)
       
  1317             self.SiiGrid.SetValue(self.HexCode)
       
  1318             self.SiiGrid.Update()
       
  1319             
       
  1320     def OnButtonSiiDownload(self, event):
       
  1321         """
       
  1322         Write current EEPROM data to slave and refresh data structure kept by master 
       
  1323         Binded to 'Sii Download' button.
       
  1324         @param event : wx.EVT_BUTTON object
       
  1325         """  
       
  1326         # Check whether beremiz connected or not, 
       
  1327         # and whether status is "Started" or not. 
       
  1328         check_connect_flag = self.Controler.CommonMethod.CheckConnect(False)
       
  1329         if check_connect_flag:
       
  1330             status, count = self.Controler.GetCTRoot()._connector.GetPLCstatus()
       
  1331             if status is not "Started":
       
  1332                 self.Controler.CommonMethod.SiiWrite(self.SiiBinary)
       
  1333                 self.Controler.CommonMethod.Rescan()
       
  1334         
       
  1335     def OnButtonWriteToBinFile(self, event):
       
  1336         """ 
       
  1337         Save current EEPROM data to binary file through FileDialog
       
  1338         Binded to 'Write to File' button.
       
  1339         @param event : wx.EVT_BUTTON object
       
  1340         """ 
       
  1341         dialog = wx.FileDialog(self, _("Save as..."), os.getcwd(), "slave0.bin",  
       
  1342                                _("bin files (*.bin)|*.bin|All files|*.*"), wx.SAVE|wx.OVERWRITE_PROMPT)
       
  1343 
       
  1344         if dialog.ShowModal() == wx.ID_OK:
       
  1345             filepath = dialog.GetPath()
       
  1346             binfile = open(filepath,"wb")
       
  1347             binfile.write(self.SiiBinary)
       
  1348             binfile.close()
       
  1349     
       
  1350         dialog.Destroy()  
       
  1351     
       
  1352     def OnButtonReadFromBinFile(self, event):
       
  1353         """
       
  1354         Load binary file through FileDialog
       
  1355         Binded to 'Read from File' button.
       
  1356         @param event : wx.EVT_BUTTON object
       
  1357         """
       
  1358         dialog = wx.FileDialog(self, _("Choose a binary file"), os.getcwd(), "",  
       
  1359                                _("bin files (*.bin)|*.bin"), wx.OPEN)
       
  1360         
       
  1361         if dialog.ShowModal() == wx.ID_OK:
       
  1362             filepath = dialog.GetPath()
       
  1363             
       
  1364             try:
       
  1365                 binfile = open(filepath, "rb")
       
  1366                 self.SiiBinary = binfile.read()
       
  1367                 self.HexCode, self.HexRow, self.HexCol = self.Controler.CommonMethod.HexRead(self.SiiBinary)
       
  1368                 self.UpdateSiiGridTable(self.HexRow, self.HexCol)
       
  1369                 self.SiiGrid.SetValue(self.HexCode)
       
  1370                 self.SiiGrid.Update()
       
  1371             except:
       
  1372                 self.Controler.CommonMethod.CreateErrorDialog('The file does not exist!')
       
  1373             
       
  1374         dialog.Destroy()
       
  1375             
       
  1376     def OnButtonXmlToEEPROMImg(self, event):
       
  1377         """
       
  1378         Create EEPROM data based XML data that current imported
       
  1379         Binded to 'XML to EEPROM' button.
       
  1380         @param event : wx.EVT_BUTTON object
       
  1381         """
       
  1382         self.SiiBinary = self.Controler.CommonMethod.XmlToEeprom()
       
  1383         self.HexCode, self.HexRow, self.HexCol = self.Controler.CommonMethod.HexRead(self.SiiBinary)
       
  1384         self.UpdateSiiGridTable(self.HexRow, self.HexCol)
       
  1385         self.SiiGrid.SetValue(self.HexCode)
       
  1386         self.SiiGrid.Update()
       
  1387 
       
  1388 
       
  1389 #-------------------------------------------------------------------------------
       
  1390 #                    For Hex View grid (fill hex data)
       
  1391 #-------------------------------------------------------------------------------  
       
  1392 class SiiGridTable(wx.grid.Grid):  
       
  1393     def __init__(self, parent, controler, row, col):
       
  1394         """
       
  1395         Constructor
       
  1396         @param parent: Reference to the parent HexView class
       
  1397         @param controler: _EthercatSlaveCTN class in EthercatSlave.py
       
  1398         @param row, col: Hex View grid size
       
  1399         """
       
  1400         self.parent = parent
       
  1401         self.Controler = controler
       
  1402         self.Row = row
       
  1403         self.Col = col    
       
  1404         
       
  1405         wx.grid.Grid.__init__(self, parent, -1, size=(830,450), 
       
  1406                               style=wx.ALIGN_CENTRE_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)        
       
  1407 
       
  1408     def SetValue(self, value):
       
  1409         """
       
  1410         Set data in the table
       
  1411         @param value: EEPROM data list of which element is 1 Byte hex data
       
  1412         """
       
  1413         # set label name and size
       
  1414         self.SetRowLabelSize(100)
       
  1415         for col in range(self.Col):
       
  1416             if col == 16:
       
  1417                 self.SetColLabelValue(16, "Text View")
       
  1418                 self.SetColSize(16, (self.GetSize().x-120)*4/20)
       
  1419             else:
       
  1420                 self.SetColLabelValue(col, '%s'%col)
       
  1421                 self.SetColSize(col, (self.GetSize().x-120)/20)
       
  1422             
       
  1423         # set data into table
       
  1424         row = col = 0
       
  1425         for row_idx in value: 
       
  1426             col = 0
       
  1427             self.SetRowLabelValue(row, "0x"+"{:0>4x}".format(row*(self.Col-1)))
       
  1428             for hex in row_idx:
       
  1429                 self.SetCellValue(row, col, hex)
       
  1430                 
       
  1431                 if col == 16: 
       
  1432                     self.SetCellAlignment(row, col, wx.ALIGN_LEFT, wx.ALIGN_CENTER)
       
  1433                 else:
       
  1434                     self.SetCellAlignment(row, col, wx.ALIGN_CENTRE, wx.ALIGN_CENTER)
       
  1435                     
       
  1436                 self.SetReadOnly(row, col, True)
       
  1437                 col = col + 1
       
  1438             row = row + 1
       
  1439         
       
  1440 
       
  1441 #-------------------------------------------------------------------------------
       
  1442 #                    For Register Access Panel
       
  1443 #-------------------------------------------------------------------------------  
       
  1444 class RegisterAccessPanel(wx.Panel):
       
  1445     def __init__(self, parent, controler):
       
  1446         """
       
  1447 	    Constructor
       
  1448 	    @param parent: EEPROMAccessPanel object
       
  1449 	    @param controler: _EthercatSlaveCTN class in EthercatSlave.py
       
  1450 	    """
       
  1451         self.parent = parent
       
  1452         self.Controler = controler
       
  1453         self.__init_data()
       
  1454         
       
  1455         wx.Panel.__init__(self, parent, -1)
       
  1456         
       
  1457         sizer = wx.FlexGridSizer(cols=1, hgap=20, rows=2, vgap=5)
       
  1458         button_sizer = wx.FlexGridSizer(cols=2, hgap=10, rows=1, vgap=10)
       
  1459         
       
  1460         self.ReloadButton = wx.Button(self, -1, "Reload")
       
  1461         self.CompactViewCheckbox = wx.CheckBox(self, -1, "Compact View")        
       
  1462         self.RegisterNotebook = RegisterNotebook(self, self.Controler)
       
  1463         
       
  1464         button_sizer.AddMany([self.ReloadButton, self.CompactViewCheckbox])
       
  1465         sizer.AddMany([button_sizer, self.RegisterNotebook])
       
  1466         self.SetSizer(sizer)
       
  1467         
       
  1468         self.ReloadButton.Bind(wx.EVT_BUTTON, self.OnReloadButton)
       
  1469         self.CompactViewCheckbox.Bind(wx.EVT_CHECKBOX, self.ToggleCompactViewCheckbox)
       
  1470         
       
  1471         for index in range(4):
       
  1472             self.RegisterNotebook.RegPage[index].MainTable.CreateGrid(self.MainRow[index], self.MainCol)
       
  1473             self.RegisterNotebook.RegPage[index].MainTable.SetValue(self, 0, index*512, (index+1)*512)
       
  1474         
       
  1475         # data default setting
       
  1476         if self.Controler.CommonMethod.RegData == "": 
       
  1477             self.CompactViewCheckbox.Disable() 
       
  1478             for index in range(4): 
       
  1479                 self.RegisterNotebook.RegPage[index].MainTable.SetValue(self, 0, index*512, (index+1)*512)
       
  1480         else: # If data was saved,
       
  1481             self.BasicSetData()
       
  1482             self.ParseData()
       
  1483             for index in range(4):
       
  1484                 self.RegisterNotebook.RegPage[index].MainTable.SetValue(self, self.RegMonitorData, index*512, (index+1)*512)
       
  1485 
       
  1486     def __init_data(self):
       
  1487         """
       
  1488 	    Declare initial data.
       
  1489 	    """
       
  1490         # flag for compact view
       
  1491         self.CompactFlag = False
       
  1492         
       
  1493         # main grid의 rows and cols
       
  1494         self.MainRow = [512, 512, 512, 512]
       
  1495         self.MainCol = 4
       
  1496         
       
  1497         # main grids' data range
       
  1498         self.PageRange = []
       
  1499         for index in range(4):
       
  1500             self.PageRange.append([512*index, 512*(index+1)])
       
  1501         
       
  1502         #  Previous value of register data for register description configuration
       
  1503         self.PreRegSpec = {"ESCType": "",
       
  1504                            "FMMUNumber": "",
       
  1505                            "SMNumber": "",
       
  1506                            "PDIType": ""}
       
  1507         
       
  1508     def LoadData(self):
       
  1509         """
       
  1510         Get data from the register.
       
  1511         """
       
  1512         self.Controler.CommonMethod.RegData = ""
       
  1513         #ethercat reg_read
       
  1514         #ex : ethercat reg_read -p 0 0x0000 0x0001
       
  1515         #return value : 0x11
       
  1516         for index in range(4):
       
  1517             self.Controler.CommonMethod.RegData = self.Controler.CommonMethod.RegData + " " + self.Controler.CommonMethod.RegRead("0x"+"{:0>4x}".format(index*1024), "0x0400")
       
  1518         
       
  1519         # store previous value 
       
  1520         # (ESC type, port number of FMMU, port number of SM, and PDI type))
       
  1521         for reg_spec in ["ESCType","FMMUNumber","SMNumber", "PDIType"]:
       
  1522             self.PreRegSpec[reg_spec] = self.Controler.CommonMethod.CrtRegSpec[reg_spec]
       
  1523         
       
  1524         # update registers' description 
       
  1525         # (ESC type, port number of FMMU, port number of SM, and PDI type)
       
  1526         for reg_spec, address in [("ESCType", "0x0000"),
       
  1527                                   ("FMMUNumber", "0x0004"),
       
  1528                                   ("SMNumber", "0x0005"),
       
  1529                                   ("PDIType", "0x0140")]:
       
  1530             self.Controler.CommonMethod.CrtRegSpec[reg_spec] = self.Controler.CommonMethod.RegRead(address, "0x0001")
       
  1531                  
       
  1532         # Enable compactView checkbox
       
  1533         self.CompactViewCheckbox.Enable()
       
  1534     
       
  1535     def BasicSetData(self):
       
  1536         """
       
  1537         Get and save the description of registers. 
       
  1538         It's done by parsing register_information.xml.
       
  1539         """
       
  1540         # parse the above register's value
       
  1541         # If the value is 0x12, the result is 12
       
  1542         self.ESCType = self.Controler.CommonMethod.CrtRegSpec["ESCType"].split('x')[1]
       
  1543         self.PDIType = self.Controler.CommonMethod.CrtRegSpec["PDIType"].split('x')[1]
       
  1544         # If the value is 0x12, the result is 18 (It's converted to decimal value)
       
  1545         self.FMMUNumber = int(self.Controler.CommonMethod.CrtRegSpec["FMMUNumber"], 16)
       
  1546         self.SMNumber = int(self.Controler.CommonMethod.CrtRegSpec["SMNumber"], 16)
       
  1547         
       
  1548         # initialize description dictionary of register main table and register sub table.
       
  1549         self.RegisterDescriptionDict = {}
       
  1550         self.RegisterSubGridDict = {}
       
  1551         
       
  1552         # ./EthercatMaster/register_information.xml contains register description.
       
  1553         if wx.Platform == '__WXMSW__':
       
  1554             reg_info_file = open("../../EthercatMaster/register_information.xml", 'r')
       
  1555         else:
       
  1556             reg_info_file = open("./EthercatMaster/register_information.xml", 'r')
       
  1557         reg_info_tree = minidom.parse(reg_info_file)
       
  1558         reg_info_file.close()
       
  1559         
       
  1560         # parse register description
       
  1561         for register_info in reg_info_tree.childNodes:
       
  1562             for register in register_info.childNodes:
       
  1563                 if register.nodeType == reg_info_tree.ELEMENT_NODE and register.nodeName == "Register":
       
  1564                     # If it depends on the property(ESC type, PDI type, FMMU number, SM number)
       
  1565                     for property, type, value in [("esc", "type", self.ESCType),
       
  1566                                                   ("pdi", "type", self.PDIType),
       
  1567                                                   ("fmmu", "number", self.FMMUNumber),
       
  1568                                                   ("sm", "number", self.SMNumber)]:
       
  1569                         if property in register.attributes.keys(): 
       
  1570                             if type == "type":
       
  1571                                 if register.attributes[property].value == value:
       
  1572                                     self.GetRegisterInfo(reg_info_tree, register)
       
  1573                                     break
       
  1574                             else: # type == "number"
       
  1575                                 if register.attributes[property].value < value:
       
  1576                                     self.GetRegisterInfo(reg_info_tree, register)
       
  1577                                     break
       
  1578                         else:
       
  1579                             self.GetRegisterInfo(reg_info_tree, register)
       
  1580                             break
       
  1581                             
       
  1582     def GetRegisterInfo(self, reg_info_tree, register):
       
  1583         """
       
  1584         Save the register's description into the dictionary.
       
  1585         reg_info_tree is based on the register_information.xml.
       
  1586         @param reg_info_tree: XML tree
       
  1587         @param register: register which you want to get the description
       
  1588         """
       
  1589         # temporary variables for register main table idescription dictionary
       
  1590         reg_index = ""
       
  1591         reg_main_description = ""
       
  1592         
       
  1593         for data in register.childNodes:
       
  1594             if data.nodeType == reg_info_tree.ELEMENT_NODE and data.nodeName == "Index":
       
  1595                 for index in data.childNodes:
       
  1596                     reg_index = index.nodeValue
       
  1597             if data.nodeType == reg_info_tree.ELEMENT_NODE and data.nodeName == "Description":
       
  1598                 for description in data.childNodes:
       
  1599                     reg_main_description = description.nodeValue
       
  1600                     
       
  1601             # Add description for register main table 
       
  1602             if reg_index is not "" and reg_main_description is not "":
       
  1603                 self.RegisterDescriptionDict[reg_index] = reg_main_description
       
  1604                     
       
  1605             if data.nodeType == reg_info_tree.ELEMENT_NODE and data.nodeName == "Details":
       
  1606                 # declare register sub table description dictionary about this index
       
  1607                 self.RegisterSubGridDict[reg_index] = []
       
  1608                 
       
  1609                 for detail in data.childNodes:
       
  1610                     if detail.nodeType == reg_info_tree.ELEMENT_NODE and detail.nodeName == "Detail":
       
  1611                         # If it depends on the property(ESC type, PDI type, FMMU number, SM number)
       
  1612                         for property, type, value in [("esc", "type", self.ESCType),
       
  1613                                                       ("pdi", "type", self.PDIType),
       
  1614                                                       ("fmmu", "number", self.FMMUNumber),
       
  1615                                                       ("sm", "number", self.SMNumber)]:
       
  1616                             if property in detail.attributes.keys(): 
       
  1617                                 if type == "type":
       
  1618                                     if detail.attributes[property].value == value:
       
  1619                                         self.GetRegisterDetailInfo(reg_info_tree, reg_index, detail)
       
  1620                                         break
       
  1621                                 else: # type == "number"
       
  1622                                     if detail.attributes[property].value < value:
       
  1623                                         self.GetRegisterDetailInfo(reg_info_tree, reg_index, detail)
       
  1624                                         break
       
  1625                             else:
       
  1626                                 self.GetRegisterDetailInfo(reg_info_tree, reg_index, detail)
       
  1627                                 break
       
  1628                                           
       
  1629     def GetRegisterDetailInfo(self, reg_info_tree, reg_index, detail):
       
  1630         """
       
  1631         Get the resgister's detailed description(for sub table) from the reg_info_tree.
       
  1632         @param reg_info_tree: XML tree (register_information.xml)
       
  1633         @param reg_index: index of the register
       
  1634         @param detail: description of the register
       
  1635         """
       
  1636         # temporary variables for register sub table description dictionary 
       
  1637         # - It is initialized in every sub description 
       
  1638         reg_bit_range = ""
       
  1639         reg_sub_description = ""
       
  1640         reg_enum_dictionary = {}
       
  1641         
       
  1642         for detail_data in detail.childNodes:
       
  1643             if detail_data.nodeType == reg_info_tree.ELEMENT_NODE and detail_data.nodeName == "Range":                                            
       
  1644                 for range in detail_data.childNodes:
       
  1645                     reg_bit_range = range.nodeValue
       
  1646             if detail_data.nodeType == reg_info_tree.ELEMENT_NODE and detail_data.nodeName == "Description":
       
  1647                 for description in detail_data.childNodes:
       
  1648                     reg_sub_description = description.nodeValue
       
  1649                     
       
  1650             if detail_data.nodeType == reg_info_tree.ELEMENT_NODE and detail_data.nodeName == "Enum":
       
  1651                 for enum in detail_data.childNodes:
       
  1652                     if enum.nodeType == reg_info_tree.ELEMENT_NODE and enum.nodeName == "item":
       
  1653                         
       
  1654                         # temporary variables for a description of each value 
       
  1655                         # For example, if the bit is 1, it is 'enabled'('On', 'True', etc.), 
       
  1656                         # otherwise 'disabled'('Off', 'False', etc.). 
       
  1657                         reg_sub_value = ""
       
  1658                         reg_sub_value_description = ""
       
  1659                         
       
  1660                         for item in enum.childNodes:
       
  1661                             if item.nodeType == reg_info_tree.ELEMENT_NODE and item.nodeName == "value":
       
  1662                                 for value in item.childNodes:
       
  1663                                     reg_sub_value = value.nodeValue
       
  1664                             if item.nodeType == reg_info_tree.ELEMENT_NODE and item.nodeName == "Description":
       
  1665                                 for description in item.childNodes:
       
  1666                                     reg_sub_value_description = description.nodeValue
       
  1667                                     
       
  1668                             # Add a description of each value to register enum dictionary
       
  1669                             if reg_sub_value is not "" and reg_sub_value_description is not "":
       
  1670                                 reg_enum_dictionary[reg_sub_value] = reg_sub_value_description
       
  1671                             
       
  1672         # add a description to register sub table description dictionary
       
  1673         if reg_bit_range is not "" and reg_sub_description is not "":
       
  1674             self.RegisterSubGridDict[reg_index].append([reg_bit_range, 
       
  1675                                                          reg_sub_description, reg_enum_dictionary])
       
  1676     
       
  1677     def ParseData(self):
       
  1678         """
       
  1679         Transform the data into dec, hex, string, and description
       
  1680         """
       
  1681         row_data = []
       
  1682         self.RegMonitorData = []
       
  1683         reg_word = ""
       
  1684         
       
  1685         reg_data = self.Controler.CommonMethod.RegData.split()
       
  1686         
       
  1687         # loop for register(0x0000:0x0fff)
       
  1688         for address in range(0x1000):
       
  1689             # arrange 2 Bytes of register data 
       
  1690             reg_word = reg_data[address].split('x')[1] + reg_word
       
  1691             if (address%2) == 1:
       
  1692                 # append address
       
  1693                 hex_address = "{:0>4x}".format(address-1)
       
  1694                 row_data.append(hex_address)
       
  1695                 
       
  1696                 # append description
       
  1697                 if self.RegisterDescriptionDict.has_key(hex_address):
       
  1698                     row_data.append(self.RegisterDescriptionDict[hex_address])
       
  1699                 else:
       
  1700                     row_data.append("")
       
  1701                     
       
  1702                 # append Decimal value
       
  1703                 row_data.append(str(int(reg_word, 16)))
       
  1704                 
       
  1705                 # append Hex value
       
  1706                 row_data.append('0x'+reg_word)
       
  1707                 
       
  1708                 # append ASCII value
       
  1709                 char_data = ""
       
  1710                 for iter in range(2):
       
  1711                     if int(reg_word[iter*2:iter*2+2], 16)>=32 and int(reg_word[iter*2:iter*2+2], 16)<=126:
       
  1712                         char_data = char_data + chr(int(reg_word[iter*2:iter*2+2], 16))
       
  1713                     else:
       
  1714                         char_data = char_data + "."
       
  1715                 row_data.append(char_data)
       
  1716                 
       
  1717                 self.RegMonitorData.append(row_data)
       
  1718                 reg_word = "" # initialize regWord
       
  1719                 row_data = []
       
  1720     
       
  1721     def OnReloadButton(self, event):
       
  1722         """
       
  1723         Handle the click event of the 'Reload' button.
       
  1724         Get the data from registers again, and update the table.
       
  1725         @param event: wx.EVT_BUTTON object
       
  1726         """
       
  1727         # Check whether beremiz connected or not.
       
  1728         check_connect_flag = self.Controler.CommonMethod.CheckConnect(False)
       
  1729         if check_connect_flag:
       
  1730             self.LoadData()
       
  1731             self.BasicSetData()
       
  1732             self.ParseData()
       
  1733             # set data into UI
       
  1734             if self.CompactFlag:
       
  1735                 self.ToggleCompactViewCheckbox(True)
       
  1736             else : 
       
  1737                 for index in range(4):
       
  1738                     self.RegisterNotebook.RegPage[index].UpdateMainTable(self.MainRow[index], self.MainCol, 
       
  1739                                                                          self.PageRange[index][0], self.PageRange[index][1], 
       
  1740                                                                          self.RegMonitorData)
       
  1741 
       
  1742     def ToggleCompactViewCheckbox(self, event):
       
  1743         """
       
  1744         Handles the event of the 'Compact view' check box.
       
  1745         If it's checked, show only the registers that have a description.
       
  1746         If not, show all the registers.
       
  1747         @param event: wx.EVT_CHECKBOX object
       
  1748         """
       
  1749         
       
  1750         # If "Compact View" Checkbox is True
       
  1751         ## 'event' is argument of this method or event of checkbox.
       
  1752         if event==True or event.GetEventObject().GetValue():
       
  1753             self.CompactFlag = True
       
  1754             
       
  1755             reg_compact_data = []
       
  1756             page_row = [0, 0, 0, 0]
       
  1757             for index in range(4):
       
  1758                 self.PageRange[index] = [0, 0]
       
  1759 
       
  1760             for reg_row_data in self.RegMonitorData:
       
  1761                 if reg_row_data[1] is not "":
       
  1762                     # data structure for "compact view"
       
  1763                     reg_compact_data.append(reg_row_data)
       
  1764                     # count for each register notebooks' row
       
  1765                     # It compare with register's address.
       
  1766                     for index in range(4):
       
  1767                         if int('0x'+reg_row_data[0], 16) < (index+1)*1024:
       
  1768                             page_row[index] += 1
       
  1769                             break
       
  1770 
       
  1771             # Setting tables' rows and cols, range for compact view
       
  1772             for index in range(4):
       
  1773                 self.MainRow[index] = page_row[index]
       
  1774                 self.PageRange[index][1] = page_row[index]
       
  1775                 for iter in range(index):
       
  1776                     self.PageRange[index][0] += page_row[iter]
       
  1777                     self.PageRange[index][1] += page_row[iter] 
       
  1778                           
       
  1779             # Update table
       
  1780             for index in range(4):
       
  1781                 self.RegisterNotebook.RegPage[index].UpdateMainTable(self.MainRow[index], self.MainCol, 
       
  1782                                                                       self.PageRange[index][0], self.PageRange[index][1], 
       
  1783                                                                       reg_compact_data)
       
  1784             
       
  1785         # Compact View Checkbox is False    
       
  1786         else:
       
  1787             self.CompactFlag = False
       
  1788             # Setting original rows, cols and range
       
  1789             self.MainRow = [512, 512, 512, 512]
       
  1790             self.PageRange = []
       
  1791             
       
  1792             for index in range(4):
       
  1793                 self.PageRange.append([512*index, 512*(index+1)])
       
  1794             
       
  1795             # Update table 
       
  1796             for index in range(4):
       
  1797                 self.RegisterNotebook.RegPage[index].UpdateMainTable(self.MainRow[index], self.MainCol, 
       
  1798                                                                       self.PageRange[index][0], self.PageRange[index][1], 
       
  1799                                                                       self.RegMonitorData)
       
  1800                 
       
  1801 
       
  1802 #-------------------------------------------------------------------------------
       
  1803 #                    For Register Access Notebook (divide index range)
       
  1804 #-------------------------------------------------------------------------------  
       
  1805 class RegisterNotebook(wx.Notebook):
       
  1806     def __init__(self, parent, controler):
       
  1807         """
       
  1808         Constructor
       
  1809         @param parent: RegisterAccessPanel object
       
  1810         @param controler: _EthercatSlaveCTN class in EthercatSlave.py
       
  1811         """
       
  1812         wx.Notebook.__init__(self, parent, id = -1)
       
  1813         
       
  1814         self.parent = parent
       
  1815         self.Controler = controler
       
  1816         
       
  1817         # Initialize pages
       
  1818         self.RegPage = []
       
  1819         for iter in range(4):
       
  1820             self.RegPage.append(None)
       
  1821         
       
  1822         for index in range(4):
       
  1823             self.RegPage[index] = RegisterNotebookPanel(self, self.Controler, 
       
  1824                                                     parent.MainRow[index], parent.MainCol)
       
  1825             self.AddPage(self.RegPage[index], 
       
  1826                          "0x"+"{:0>4x}".format(index*1024)+" - 0x"+"{:0>4x}".format((index+1)*1024-1))
       
  1827         
       
  1828         self.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.OnPageChanged)
       
  1829         self.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGING, self.OnPageChanging)
       
  1830 
       
  1831     def OnPageChanged(self, event):
       
  1832         old = event.GetOldSelection()
       
  1833         new = event.GetSelection()
       
  1834         sel = self.GetSelection()
       
  1835         event.Skip()
       
  1836 
       
  1837     def OnPageChanging(self, event):
       
  1838         old = event.GetOldSelection()
       
  1839         new = event.GetSelection()
       
  1840         sel = self.GetSelection()
       
  1841         event.Skip()
       
  1842 
       
  1843 
       
  1844 #-------------------------------------------------------------------------------
       
  1845 #                    For Register Access Notebook Panel 
       
  1846 #                  (Main UI : including main, sub table)
       
  1847 #-------------------------------------------------------------------------------  
       
  1848 class RegisterNotebookPanel(wx.Panel):
       
  1849     def __init__(self, parent, controler, row, col):
       
  1850         """
       
  1851         Constructor
       
  1852         @param parent: RegisterAccessPanel object
       
  1853         @param controler: _EthercatSlaveCTN class in EthercatSlave.py
       
  1854         @param row, col: size of the table
       
  1855     	"""
       
  1856         wx.Panel.__init__(self, parent, -1)
       
  1857         
       
  1858         self.parent = parent
       
  1859         self.Controler = controler
       
  1860         self.Row = row
       
  1861         self.Col = col
       
  1862         sub_row = 0
       
  1863         sub_col = 4
       
  1864         
       
  1865         self.Sizer = wx.FlexGridSizer(cols=1, hgap=10, rows=2, vgap=30)
       
  1866         
       
  1867         self.MainTable = RegisterMainTable(self, self.Row, self.Col, self.Controler)
       
  1868         self.SubTable = RegisterSubTable(self, sub_row, sub_col)
       
  1869         
       
  1870         self.SubTable.CreateGrid(sub_row, sub_col)
       
  1871         self.SubTable.SetValue(self, [])
       
  1872         
       
  1873         self.Sizer.AddMany([self.MainTable, self.SubTable])
       
  1874         
       
  1875         self.SetSizer(self.Sizer)
       
  1876      
       
  1877     def UpdateMainTable(self, row, col, low_index, high_index, data):
       
  1878         """
       
  1879         Updates main table.
       
  1880         It's done by deleting the main table and creating it again.
       
  1881         @param row, col: size of the table
       
  1882         @param low_index: the lowest index of the page
       
  1883         @param high_index: the highest index of the page
       
  1884         @param data: data
       
  1885     	"""
       
  1886         self.MainTable.Destroy()
       
  1887         self.MainTable = RegisterMainTable(self, row, col, self.Controler)
       
  1888         self.Sizer.Detach(self.SubTable)
       
  1889         self.Sizer.AddMany([self.MainTable, self.SubTable])
       
  1890         self.SetSizer(self.Sizer)
       
  1891         self.MainTable.CreateGrid(row, col)
       
  1892         self.MainTable.SetValue(self, data, low_index, high_index)
       
  1893         self.MainTable.Update()
       
  1894 
       
  1895     def UpdateSubTable(self, row, col, data):
       
  1896         """
       
  1897         Updates sub table.
       
  1898         It's done by deleting the sub table and creating it again.
       
  1899         @param row, col: size of the table
       
  1900         @param data: data
       
  1901     	"""
       
  1902         self.SubTable.Destroy()
       
  1903         self.SubTable = RegisterSubTable(self, row, col)
       
  1904         self.Sizer.Detach(self.MainTable)
       
  1905         self.Sizer.AddMany([self.MainTable, self.SubTable])
       
  1906         self.Sizer.Layout()
       
  1907         self.SetSizer(self.Sizer)
       
  1908         self.SubTable.CreateGrid(row, col)
       
  1909         self.SubTable.SetValue(self, data)
       
  1910         self.SubTable.Update()
       
  1911         
       
  1912 
       
  1913 #-------------------------------------------------------------------------------
       
  1914 #                    For Register Access Notebook Panel (Main Table)
       
  1915 #-------------------------------------------------------------------------------  
       
  1916 class RegisterMainTable(wx.grid.Grid):
       
  1917     def __init__(self, parent, row, col, controler):        
       
  1918         """
       
  1919 	    Constructor
       
  1920 	    @param parent: RegisterNotebook object
       
  1921 	    @param row, col: size of the table
       
  1922 	    @param controler: _EthercatSlaveCTN class in EthercatSlave.py
       
  1923 	    """
       
  1924         self.parent = parent
       
  1925         self.Data = {}
       
  1926         self.Row = row
       
  1927         self.Col = col
       
  1928         self.Controler = controler
       
  1929         self.RegisterAccessPanel = self.parent.parent.parent
       
  1930         
       
  1931         wx.grid.Grid.__init__(self, parent, -1, size=(820,300), 
       
  1932                               style=wx.EXPAND|wx.ALIGN_CENTRE_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)        
       
  1933         
       
  1934         for evt, mapping_method in [(gridlib.EVT_GRID_CELL_LEFT_CLICK, self.OnSelectCell),
       
  1935                                     (gridlib.EVT_GRID_CELL_LEFT_CLICK, self.OnSelectCell),
       
  1936                                     (gridlib.EVT_GRID_CELL_LEFT_DCLICK, self.OnRegModifyDialog)]:
       
  1937             self.Bind(evt, mapping_method)
       
  1938        
       
  1939     def SetValue(self, parent, reg_monitor_data, low_index, high_index):  
       
  1940         """
       
  1941 	    Set the RegMonitorData into the main table.
       
  1942 	    @param parent: RegisterNotebook object
       
  1943 	    @param reg_monitor_data: data
       
  1944 	    @param low_index: the lowest index of the page
       
  1945 	    @param high_index: the highest index of the page
       
  1946 	    """
       
  1947         self.RegMonitorData = reg_monitor_data
       
  1948         
       
  1949         # set label name and size
       
  1950         register_maintable_label = [(0, "Description"), (1, "Dec"), 
       
  1951                                     (2, "Hex"), (3, "Char")]
       
  1952         
       
  1953         for (index, label) in register_maintable_label:
       
  1954             self.SetColLabelValue(index, label)
       
  1955         
       
  1956         self.SetColSize(0, 200)
       
  1957     
       
  1958         # if reg_monitor_data is 0, it is initialization of register access.
       
  1959         if reg_monitor_data == 0:
       
  1960             return 0
       
  1961     
       
  1962         # set data into UI 
       
  1963         row = col = 0
       
  1964         for row_index in reg_monitor_data[low_index:high_index]:
       
  1965             col = 0
       
  1966             self.SetRowLabelValue(row, row_index[0])
       
  1967             for data_index in range(4):
       
  1968                 self.SetCellValue(row, col, row_index[data_index+1])
       
  1969                 self.SetCellAlignment(row, col, wx.ALIGN_CENTRE, wx.ALIGN_CENTER)
       
  1970                 self.SetReadOnly(row, col, True)
       
  1971                 col = col + 1
       
  1972             row = row + 1
       
  1973     
       
  1974     def OnSelectCell(self, event): 
       
  1975         """
       
  1976 	    Handles the event of the cell of the main table.
       
  1977 	    @param event: gridlib object (left click)
       
  1978 	    """
       
  1979         # if reg_monitor_data is 0, it is initialization of register access.
       
  1980         if self.RegMonitorData == 0:
       
  1981             event.Skip()
       
  1982             return 0
       
  1983         
       
  1984         sub_row = 0
       
  1985         sub_col = 4
       
  1986         
       
  1987         address = self.GetRowLabelValue(event.GetRow())
       
  1988         
       
  1989         reg_sub_grid_data = []
       
  1990         
       
  1991         BIT_RANGE, NAME, DESCRIPTIONS = range(3)
       
  1992         
       
  1993         # Check if this register's detail description is exist or not, 
       
  1994         # and create data structure for the detail description table ; sub grid
       
  1995         if address in self.RegisterAccessPanel.RegisterSubGridDict:
       
  1996             for element in self.RegisterAccessPanel.RegisterSubGridDict[address]:
       
  1997                 row_data =[]
       
  1998                 row_data.append(element[BIT_RANGE])
       
  1999                 row_data.append(element[NAME])
       
  2000                 bin_data = "{:0>16b}".format(int(self.GetCellValue(event.GetRow(), 1)))
       
  2001                 value_range = element[BIT_RANGE].split('-')
       
  2002                 value = (bin_data[8:16][::-1]+bin_data[0:8][::-1])[int(value_range[0]):(int(value_range[-1])+1)][::-1]
       
  2003                 row_data.append(str(int(('0b'+str(value)), 2)))
       
  2004                 if value in element[DESCRIPTIONS]:
       
  2005                     row_data.append(element[DESCRIPTIONS][value])
       
  2006                 else:
       
  2007                     row_data.append('')
       
  2008                 reg_sub_grid_data.append(row_data)
       
  2009                 sub_row = sub_row + 1
       
  2010         
       
  2011         self.parent.UpdateSubTable(sub_row, sub_col, reg_sub_grid_data)
       
  2012         # event.Skip() updates UI of selecting cell
       
  2013         event.Skip()
       
  2014     
       
  2015     def OnRegModifyDialog(self, event):
       
  2016         """
       
  2017         Handle the event of the cell of the main table.
       
  2018         Display the window where the user modifies the value of the cell.
       
  2019         @param event: gridlib object (double click)
       
  2020 	    """
       
  2021         # user can enter a value in case that user double-clicked 'Dec' or 'Hex' value.
       
  2022         if event.GetCol() == 1 or event.GetCol() == 2:
       
  2023             dlg = wx.TextEntryDialog(self, "Enter hex(0xnnnn) or dec(n) value", 
       
  2024                                      "Register Modify Dialog", style = wx.OK|wx.CANCEL)
       
  2025             
       
  2026             # Setting value in initial dialog value
       
  2027             start_value = self.GetCellValue(event.GetRow(), event.GetCol())
       
  2028             dlg.SetValue(start_value)
       
  2029         
       
  2030             if dlg.ShowModal() == wx.ID_OK:
       
  2031                 try:
       
  2032                     # It int(input) success, this input is dev or hex value. 
       
  2033                     # Otherwise, it's error, so it goes except.
       
  2034                     int(dlg.GetValue(), 0)
       
  2035 
       
  2036                     # reg_write
       
  2037                     # ex) ethercat reg_write -p 0 -t uint16 0x0000 0x0000
       
  2038                     return_val = self.Controler.CommonMethod.RegWrite('0x'+self.GetRowLabelValue(event.GetRow()), dlg.GetValue())
       
  2039 
       
  2040                     if len(return_val)==0:
       
  2041                         # set dec
       
  2042                         self.SetCellValue(event.GetRow(), 1, str(int(dlg.GetValue(), 0))) 
       
  2043                         # set hex
       
  2044                         hex_data = '0x'+"{:0>4x}".format(int(dlg.GetValue(), 0))
       
  2045                         self.SetCellValue(event.GetRow(), 2, hex_data)
       
  2046                         # set char
       
  2047                         char_data = ""
       
  2048                         # If hex_data is been able to convert to ascii code, append ascii code.
       
  2049                         for iter in range(2):
       
  2050                             if int(hex_data[(iter+1)*2:(iter+2)*2], 16)>=32 and int(hex_data[(iter+1)*2:(iter+2)*2], 16)<=126:
       
  2051                                 char_data = char_data + chr(int(hex_data[(iter+1)*2:(iter+2)*2], 16))
       
  2052                             else:
       
  2053                                 char_data = char_data + "."
       
  2054                             
       
  2055                         self.SetCellValue(event.GetRow(), 3, char_data) 
       
  2056                     
       
  2057                     else:
       
  2058                         self.Controler.CommonMethod.CreateErrorDialog('You can\'t modify it. This register is read-only or it\'s not connected.')
       
  2059                 
       
  2060                 except ValueError:
       
  2061                     self.Controler.CommonMethod.CreateErrorDialog('You entered wrong value. You can enter dec or hex value only.')
       
  2062         
       
  2063     
       
  2064 #-------------------------------------------------------------------------------
       
  2065 #                    For Register Access Notebook Panel (Sub Table)
       
  2066 #-------------------------------------------------------------------------------  
       
  2067 class RegisterSubTable(wx.grid.Grid):
       
  2068     def __init__(self, parent, row, col):
       
  2069         """
       
  2070     	 Constructor
       
  2071     	 @param parent: RegisterNotebook object
       
  2072     	 @param row, col: size of the table
       
  2073     	"""
       
  2074         self.parent = parent
       
  2075         self.Data = {}
       
  2076         self.Row = row
       
  2077         self.Col = col
       
  2078 
       
  2079         wx.grid.Grid.__init__(self, parent, -1, size=(820,150), 
       
  2080                               style=wx.EXPAND|wx.ALIGN_CENTRE_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL)        
       
  2081 
       
  2082     def SetValue(self, parent, data):
       
  2083         """
       
  2084 	    Set the data into the subtable.
       
  2085 	    @param parent: RegisterNotebook object
       
  2086 	    @param data: data
       
  2087 	    """
       
  2088         # lset label name and size
       
  2089         Register_SubTable_Label = [(0, "Bits"), (1, "Name"), 
       
  2090                                     (2, "Value"), (3, "Enum")]
       
  2091         
       
  2092         for (index, label) in Register_SubTable_Label:
       
  2093             self.SetColLabelValue(index, label)
       
  2094         
       
  2095         self.SetColSize(1, 200)
       
  2096         self.SetColSize(3, 200)
       
  2097             
       
  2098         # set data into table
       
  2099         row = col = 0
       
  2100         for rowData in data: 
       
  2101             col = 0     
       
  2102             for element in rowData:
       
  2103                 self.SetCellValue(row, col, element)
       
  2104                 self.SetCellAlignment(row, col, wx.ALIGN_CENTRE, wx.ALIGN_CENTER)
       
  2105                 self.SetReadOnly(row, col, True)
       
  2106                 col = col + 1
       
  2107             row = row + 1
       
  2108                 
       
  2109 
       
  2110 #-------------------------------------------------------------------------------
       
  2111 #                    For Master State Panel
       
  2112 #-------------------------------------------------------------------------------  
       
  2113 class MasterStatePanelClass(wx.Panel):
       
  2114     def __init__(self, parent, controler):
       
  2115         """
       
  2116         Constructor
       
  2117         @param parent: wx.ScrollWindow object
       
  2118         @Param controler: _EthercatSlaveCTN class in EthercatSlave.py
       
  2119         """
       
  2120         wx.Panel.__init__(self, parent, -1, (0, 0), 
       
  2121                           size=wx.DefaultSize, style = wx.SUNKEN_BORDER)
       
  2122         self.Controler = controler
       
  2123         self.parent = parent
       
  2124         self.StaticBox = {}
       
  2125         self.StaticText = {}
       
  2126         self.TextCtrl = {}
       
  2127           
       
  2128         # ----------------------- Main Sizer and Update Button --------------------------------------------
       
  2129         self.MasterStateSizer = {"main" : wx.BoxSizer(wx.VERTICAL)}
       
  2130         for key, attr in [
       
  2131             ("innerMain",           [1, 10, 2, 10]),
       
  2132             ("innerTopHalf",        [2, 10, 1, 10]),
       
  2133             ("innerBottomHalf",     [2, 10, 1, 10]),
       
  2134             ("innerMasterState",    [2, 10, 3, 10]),
       
  2135             ("innerDeviceInfo",     [4, 10, 3, 10]),
       
  2136             ("innerFrameInfo",      [4, 10, 5, 10])]:
       
  2137             self.MasterStateSizer[key] = wx.FlexGridSizer(cols=attr[0], hgap=attr[1], rows=attr[2], vgap=attr[3])
       
  2138 
       
  2139 
       
  2140         self.UpdateButton = wx.Button(self, label=_('Update'))
       
  2141         self.UpdateButton.Bind(wx.EVT_BUTTON, self.OnButtonClick)
       
  2142        
       
  2143         for key, label in [                
       
  2144             ('masterState', 'EtherCAT Master State'),
       
  2145             ('deviceInfo', 'Ethernet Network Card Information'),
       
  2146             ('frameInfo', 'Network Frame Information')]:
       
  2147             self.StaticBox[key] = wx.StaticBox(self, label=_(label))
       
  2148             self.MasterStateSizer[key] = wx.StaticBoxSizer(self.StaticBox[key])
       
  2149         
       
  2150         
       
  2151         # ----------------------- Master State -----------------------------------------------------------
       
  2152         for key, label in [
       
  2153             ('Phase', 'Phase:'),
       
  2154             ('Active', 'Active:'),
       
  2155             ('Slaves', 'Slave Count:')]:
       
  2156             self.StaticText[key] = wx.StaticText(self, label=_(label))
       
  2157             self.TextCtrl[key] = wx.TextCtrl(self, size=wx.Size(130, 24), style=wx.TE_READONLY)
       
  2158             self.MasterStateSizer['innerMasterState'].AddMany([self.StaticText[key], self.TextCtrl[key]])    
       
  2159         
       
  2160         self.MasterStateSizer['masterState'].AddSizer(self.MasterStateSizer['innerMasterState'])
       
  2161         
       
  2162         # ----------------------- Ethernet Network Card Information --------------------------------------- 
       
  2163         for key, label in [
       
  2164             ('Main', 'MAC Address:'),
       
  2165             ('Link', 'Link State:'),
       
  2166             ('Tx frames', 'Tx Frames:'),
       
  2167             ('Rx frames', 'Rx Frames:'),
       
  2168             ('Lost frames', 'Lost Frames:')]:
       
  2169             self.StaticText[key] = wx.StaticText(self, label=_(label))
       
  2170             self.TextCtrl[key] = wx.TextCtrl(self, size=wx.Size(130, 24), style=wx.TE_READONLY)
       
  2171             self.MasterStateSizer['innerDeviceInfo'].AddMany([self.StaticText[key], self.TextCtrl[key]])
       
  2172         
       
  2173         self.MasterStateSizer['deviceInfo'].AddSizer(self.MasterStateSizer['innerDeviceInfo'])
       
  2174         
       
  2175         # ----------------------- Network Frame Information -----------------------------------------------
       
  2176         for key, label in [
       
  2177             ('Tx frame rate [1/s]', 'Tx Frame Rate [1/s]:'), 
       
  2178             ('Rx frame rate [1/s]', 'Tx Rate [kByte/s]:'), 
       
  2179             ('Loss rate [1/s]', 'Loss Rate [1/s]:'),
       
  2180             ('Frame loss [%]', 'Frame Loss [%]:')]:
       
  2181             self.StaticText[key] = wx.StaticText(self, label=_(label))
       
  2182             self.MasterStateSizer['innerFrameInfo'].Add(self.StaticText[key])
       
  2183             self.TextCtrl[key] = {} 
       
  2184             for index in ['0', '1', '2']:                
       
  2185                 self.TextCtrl[key][index] = wx.TextCtrl(self, size=wx.Size(130, 24), style=wx.TE_READONLY)
       
  2186                 self.MasterStateSizer['innerFrameInfo'].Add(self.TextCtrl[key][index])
       
  2187         
       
  2188         self.MasterStateSizer['frameInfo'].AddSizer(self.MasterStateSizer['innerFrameInfo'])
       
  2189         
       
  2190         # --------------------------------- Main Sizer ----------------------------------------------------
       
  2191         for key, sub, in [
       
  2192             ('innerTopHalf', [
       
  2193                     'masterState', 'deviceInfo']),
       
  2194             ('innerBottomHalf', [
       
  2195                     'frameInfo']),
       
  2196             ('innerMain', [
       
  2197                     'innerTopHalf', 'innerBottomHalf'])]:
       
  2198             for key2 in sub:
       
  2199                 self.MasterStateSizer[key].AddSizer(self.MasterStateSizer[key2])
       
  2200 
       
  2201         self.MasterStateSizer['main'].AddSizer(self.UpdateButton)
       
  2202         self.MasterStateSizer['main'].AddSizer(self.MasterStateSizer['innerMain'])
       
  2203         
       
  2204         self.SetSizer(self.MasterStateSizer['main'])
       
  2205 
       
  2206     def OnButtonClick(self, event):
       
  2207         """
       
  2208         Handle the event of the 'Update' button.
       
  2209         Update the data of the master state.
       
  2210         @param event: wx.EVT_BUTTON object
       
  2211         """
       
  2212         if self.Controler.GetCTRoot()._connector is not None:
       
  2213             self.MasterState = self.Controler.CommonMethod.GetMasterState()
       
  2214             # Update each TextCtrl
       
  2215             if self.MasterState:
       
  2216                 for key in self.TextCtrl:
       
  2217                     if isinstance(self.TextCtrl[key], dict):
       
  2218                         for index in self.TextCtrl[key]:
       
  2219                             self.TextCtrl[key][index].SetValue(self.MasterState[key][int(index)])
       
  2220                     else:
       
  2221                         self.TextCtrl[key].SetValue(self.MasterState[key][0])
       
  2222         else :
       
  2223             self.Controler.CommonMethod.CreateErrorDialog('PLC not connected!')