LPCBeremiz.py
changeset 734 5c42cafaee15
parent 733 915be999f3f0
child 735 d9f4ecee761d
equal deleted inserted replaced
733:915be999f3f0 734:5c42cafaee15
     1 #!/usr/bin/env python
       
     2 # -*- coding: utf-8 -*-
       
     3 import shutil
       
     4 import socket
       
     5 
       
     6 __version__ = "$Revision$"
       
     7 
       
     8 import os, sys, getopt, wx, tempfile
       
     9 import __builtin__
       
    10 from types import TupleType, StringType, UnicodeType
       
    11 
       
    12 CWD = os.path.split(os.path.realpath(__file__))[0]
       
    13 
       
    14 def Bpath(*args):
       
    15     return os.path.join(CWD,*args)
       
    16 
       
    17 if __name__ == '__main__':
       
    18     def usage():
       
    19         print "\nUsage of LPCBeremiz.py :"
       
    20         print "\n   %s Projectpath Buildpath port\n"%sys.argv[0]
       
    21     
       
    22     try:
       
    23         opts, args = getopt.getopt(sys.argv[1:], "h", ["help"])
       
    24     except getopt.GetoptError:
       
    25         # print help information and exit:
       
    26         usage()
       
    27         sys.exit(2)
       
    28     
       
    29     for o, a in opts:
       
    30         if o in ("-h", "--help"):
       
    31             usage()
       
    32             sys.exit()
       
    33     
       
    34     if len(args) != 3:
       
    35         usage()
       
    36         sys.exit()
       
    37     else:
       
    38         projectOpen = args[0]
       
    39         buildpath = args[1]
       
    40         try:
       
    41             port = int(args[2])
       
    42         except:
       
    43             usage()
       
    44             sys.exit()
       
    45 
       
    46     if os.path.exists("LPC_DEBUG"):
       
    47         __builtin__.__dict__["BMZ_DBG"] = True
       
    48     else :
       
    49         __builtin__.__dict__["BMZ_DBG"] = False
       
    50 
       
    51 app = wx.PySimpleApp(redirect=BMZ_DBG)
       
    52 app.SetAppName('beremiz')
       
    53 wx.InitAllImageHandlers()
       
    54 
       
    55 # Import module for internationalization
       
    56 import gettext
       
    57 
       
    58 if __name__ == '__main__':
       
    59     __builtin__.__dict__['_'] = wx.GetTranslation#unicode_translation
       
    60 
       
    61 from Beremiz import *
       
    62 from ProjectController import ProjectController
       
    63 from ConfigTreeNode import ConfigTreeNode
       
    64 import connectors
       
    65 from util import opjimg
       
    66 from plcopen.structures import LOCATIONDATATYPES
       
    67 from PLCControler import LOCATION_CONFNODE, LOCATION_MODULE, LOCATION_GROUP,\
       
    68                          LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY
       
    69 from PLCOpenEditor import IDEFrame, ProjectDialog
       
    70 
       
    71 havecanfestival = False
       
    72 try:
       
    73     from canfestival import RootClass as CanOpenRootClass
       
    74     from canfestival.canfestival import _SlaveCTN, _NodeListCTN, NodeManager
       
    75     havecanfestival = True
       
    76 except:
       
    77     havecanfestival = False
       
    78     
       
    79 
       
    80 #-------------------------------------------------------------------------------
       
    81 #                          CANFESTIVAL CONFNODE HACK
       
    82 #-------------------------------------------------------------------------------
       
    83 # from canfestival import canfestival
       
    84 # class LPC_canfestival_config:
       
    85 #     def getCFLAGS(self, *args):
       
    86 #         return ""
       
    87 # 
       
    88 #     def getLDFLAGS(self, *args):
       
    89 #         return ""
       
    90 #         
       
    91 # canfestival.local_canfestival_config = LPC_canfestival_config() 
       
    92 #-------------------------------------------------------------------------------
       
    93 #                              LPCModule Class
       
    94 #-------------------------------------------------------------------------------
       
    95 
       
    96 LOCATION_TYPES = {"I": LOCATION_VAR_INPUT,
       
    97                   "Q": LOCATION_VAR_OUTPUT,
       
    98                   "M": LOCATION_VAR_MEMORY}
       
    99 
       
   100 LOCATION_DIRS = dict([(dir, size) for size, dir in LOCATION_TYPES.iteritems()])
       
   101 
       
   102 LOCATION_SIZES = {}
       
   103 for size, types in LOCATIONDATATYPES.iteritems():
       
   104     for type in types:
       
   105         LOCATION_SIZES[type] = size
       
   106 
       
   107 def _GetModuleChildren(module):
       
   108     children = []
       
   109     for child in module["children"]:
       
   110         if child["type"] == LOCATION_GROUP:
       
   111             children.extend(child["children"])
       
   112         else:
       
   113             children.append(child)
       
   114     return children
       
   115 
       
   116 def _GetVariables(module):
       
   117     variables = []
       
   118     for child in module["children"]:
       
   119         if child["type"] in [LOCATION_GROUP, LOCATION_MODULE]:
       
   120             variables.extend(_GetVariables(child))
       
   121         else:
       
   122             variables.append(child)
       
   123     return variables
       
   124 
       
   125 def _GetLastModuleGroup(module):
       
   126     group = module
       
   127     for child in module["children"]:
       
   128         if child["type"] == LOCATION_GROUP:
       
   129             group = child
       
   130     return group["children"]
       
   131 
       
   132 def _GetModuleBySomething(module, something, toks):
       
   133     for child in _GetModuleChildren(module):
       
   134         if child.get(something) == toks[0]:
       
   135             if len(toks) > 1:
       
   136                 return _GetModuleBySomething(child, something, toks[1:])
       
   137             return child
       
   138     return None
       
   139 
       
   140 def _GetModuleVariable(module, location, direction):
       
   141     for child in _GetModuleChildren(module):
       
   142         if child["location"] == location and child["type"] == LOCATION_TYPES[direction]:
       
   143             return child
       
   144     return None
       
   145 
       
   146 def _RemoveModuleChild(module, child):
       
   147     if child in module["children"]:
       
   148         module["children"].remove(child)
       
   149     else:
       
   150         for group in module["children"]:
       
   151             if group["type"] == LOCATION_GROUP and child in group["children"]:
       
   152                 group["children"].remove(child)
       
   153 
       
   154 BUS_TEXT = """/* Code generated by LPCBus confnode */
       
   155 
       
   156 /* LPCBus confnode includes */
       
   157 #include "app_glue.h"
       
   158 #ifdef _WINDOWS_H
       
   159   #include "iec_types.h"
       
   160 #else
       
   161   #include "iec_std_lib.h"
       
   162 #endif
       
   163 
       
   164 %(declare_code)s
       
   165 
       
   166 /* LPCBus confnode user variables definition */
       
   167 %(var_decl)s
       
   168 
       
   169 /* LPCBus confnode functions */
       
   170 int __init_%(location_str)s(int argc,char **argv)
       
   171 {
       
   172 %(init_code)s
       
   173   return 0;
       
   174 }
       
   175 
       
   176 void __cleanup_%(location_str)s(void)
       
   177 {
       
   178 }
       
   179 
       
   180 void __retrieve_%(location_str)s(void)
       
   181 {
       
   182 %(retrieve_code)s
       
   183 }
       
   184         
       
   185 void __publish_%(location_str)s(void)
       
   186 {
       
   187 %(publish_code)s
       
   188 }
       
   189 """
       
   190 
       
   191 class LPCBus(object):
       
   192     
       
   193     def __init__(self):
       
   194         self.VariableLocationTree = []
       
   195         self.ResetUsedLocations()
       
   196         self.Icon = None
       
   197     
       
   198     def __getitem__(self, key):
       
   199         if key == "children":
       
   200             return self.VariableLocationTree
       
   201         raise KeyError, "Only 'children' key is available"
       
   202     
       
   203     def CTNEnabled(self):
       
   204         return None
       
   205     
       
   206     def SetIcon(self, icon):
       
   207         self.Icon = icon
       
   208     
       
   209     def _GetChildBySomething(self, something, toks):
       
   210         return _GetModuleBySomething({"children" : self.VariableLocationTree}, something, toks)
       
   211     
       
   212     def GetBaseTypes(self):
       
   213         return self.GetCTRoot().GetBaseTypes()
       
   214 
       
   215     def GetSizeOfType(self, type):
       
   216         return LOCATION_SIZES[self.GetCTRoot().GetBaseType(type)]
       
   217     
       
   218     def _GetVariableLocationTree(self, current_location, infos):
       
   219         if infos["type"] == LOCATION_MODULE:
       
   220             location = current_location + (infos["IEC_Channel"],)
       
   221             return {"name": infos["name"],
       
   222                     "type": infos["type"],
       
   223                     "location": ".".join(map(str, location + ("x",))), 
       
   224                     "icon": infos["icon"], 
       
   225                     "children": [self._GetVariableLocationTree(location, child) for child in infos["children"]]}
       
   226         elif infos["type"] == LOCATION_GROUP:
       
   227             return {"name": infos["name"],
       
   228                     "type": infos["type"],
       
   229                     "location": "", 
       
   230                     "icon": infos["icon"], 
       
   231                     "children": [self._GetVariableLocationTree(current_location, child) for child in infos["children"]]}
       
   232         else:
       
   233             size = self.GetSizeOfType(infos["IEC_type"])
       
   234             location = "%" + LOCATION_DIRS[infos["type"]] + size + ".".join(map(str, current_location + infos["location"]))
       
   235             return {"name": infos["name"],
       
   236                     "type": infos["type"],
       
   237                     "size": size,
       
   238                     "IEC_type": infos["IEC_type"],
       
   239                     "var_name": infos["name"],
       
   240                     "location": location,
       
   241                     "description": infos["description"],
       
   242                     "children": []}
       
   243     
       
   244     def GetVariableLocationTree(self):
       
   245         return {"name": self.BaseParams.getName(),
       
   246                 "type": LOCATION_CONFNODE,
       
   247                 "location": self.GetFullIEC_Channel(),
       
   248                 "icon": self.Icon, 
       
   249                 "children": [self._GetVariableLocationTree(self.GetCurrentLocation(), child) 
       
   250                              for child in self.VariableLocationTree]}
       
   251     
       
   252     def CTNTestModified(self):
       
   253         return False
       
   254 
       
   255     def CTNMakeDir(self):
       
   256         pass
       
   257 
       
   258     def CTNRequestSave(self):
       
   259         return None
       
   260 
       
   261     def ResetUsedLocations(self):
       
   262         self.UsedLocations = {}
       
   263     
       
   264     def _AddUsedLocation(self, parent, location):
       
   265         num = location.pop(0)
       
   266         if not parent.has_key(num):
       
   267             parent[num] = {"used": False, "children": {}}
       
   268         if len(location) > 0:
       
   269             self._AddUsedLocation(parent[num]["children"], location)
       
   270         else:
       
   271             parent[num]["used"] = True
       
   272         
       
   273     def AddUsedLocation(self, location):
       
   274         if len(location) > 0:
       
   275             self._AddUsedLocation(self.UsedLocations, list(location))
       
   276 
       
   277     def _CheckLocationConflicts(self, parent, location):
       
   278         num = location.pop(0)
       
   279         if not parent.has_key(num):
       
   280             return False
       
   281         if len(location) > 0:
       
   282             if parent[num]["used"]:
       
   283                 return True
       
   284             return self._CheckLocationConflicts(parent[num]["children"], location)
       
   285         elif len(parent[num]["children"]) > 0:
       
   286             return True
       
   287         return False
       
   288 
       
   289     def CheckLocationConflicts(self, location):
       
   290         if len(location) > 0:
       
   291             return self._CheckLocationConflicts(self.UsedLocations, list(location))
       
   292         return False
       
   293 
       
   294     def CTNGenerate_C(self, buildpath, locations):
       
   295         """
       
   296         Generate C code
       
   297         @param current_location: Tupple containing confnode IEC location : %I0.0.4.5 => (0,0,4,5)
       
   298         @param locations: List of complete variables locations \
       
   299             [{"IEC_TYPE" : the IEC type (i.e. "INT", "STRING", ...)
       
   300             "NAME" : name of the variable (generally "__IW0_1_2" style)
       
   301             "DIR" : direction "Q","I" or "M"
       
   302             "SIZE" : size "X", "B", "W", "D", "L"
       
   303             "LOC" : tuple of interger for IEC location (0,1,2,...)
       
   304             }, ...]
       
   305         @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND
       
   306         """
       
   307         current_location = self.GetCurrentLocation()
       
   308         # define a unique name for the generated C file
       
   309         location_str = "_".join(map(str, current_location))
       
   310         
       
   311         code_str = {"location_str": location_str,
       
   312                     "var_decl": "",
       
   313                     "declare_code": "",
       
   314                     "init_code": "",
       
   315                     "retrieve_code": "",
       
   316                     "publish_code": "",
       
   317                    }
       
   318         
       
   319         for module in _GetModuleChildren(self):
       
   320             if module["init"] != "":
       
   321                 code_str["init_code"] += "  %s\n" % module["init"]
       
   322         
       
   323         # Adding variables
       
   324         vars = []
       
   325         self.ResetUsedLocations()
       
   326         for location in locations:
       
   327             loc = location["LOC"][len(current_location):]
       
   328             group = next = self
       
   329             i = 0
       
   330             while next is not None and i < len(loc):
       
   331                 next = self._GetChildBySomething("IEC_Channel", loc[:i + 1])
       
   332                 if next is not None:
       
   333                     i += 1
       
   334                     group = next
       
   335             var_loc = loc[i:]
       
   336             for variable in _GetModuleChildren(group):
       
   337                 if variable["location"] == var_loc and location["DIR"] == LOCATION_DIRS[variable["type"]]:
       
   338 #                    if location["DIR"] != LOCATION_DIRS[variable["type"]]:
       
   339 #                        raise Exception, "Direction conflict in variable definition"
       
   340 #                    if location["IEC_TYPE"] != variable["IEC_type"]:
       
   341 #                        raise Exception, "Type conflict in variable definition"
       
   342                     if location["DIR"] == "Q":
       
   343                         if self.CheckLocationConflicts(location["LOC"]):
       
   344                             raise Exception, "BYTE and BIT from the same BYTE can't be used together"
       
   345                         self.AddUsedLocation(location["LOC"])
       
   346                     vars.append({"location": location["NAME"],
       
   347                                  "Type": variable["IEC_type"],
       
   348                                  "Retrieve": variable["retrieve"],
       
   349                                  "Publish": variable["publish"],
       
   350                                 })
       
   351                     break
       
   352         base_types = self.GetCTRoot().GetBaseTypes()
       
   353         for var in vars:
       
   354             prefix = ""
       
   355             if var["Type"] in base_types:
       
   356                 prefix = "IEC_"
       
   357             code_str["var_decl"] += "%s%s beremiz%s;\n"%(prefix, var["Type"], var["location"])
       
   358             code_str["var_decl"] += "%s%s *%s = &beremiz%s;\n"%(prefix, var["Type"], var["location"], var["location"])
       
   359             if var["Retrieve"] != "":
       
   360                 code_str["retrieve_code"] += "  " + var["Retrieve"] % ("*" + var["location"]) + "\n"
       
   361             if var["Publish"] != "":
       
   362                 code_str["publish_code"] += "  " + var["Publish"] % ("*" + var["location"]) + "\n"
       
   363         
       
   364         Gen_Module_path = os.path.join(buildpath, "Bus_%s.c"%location_str)
       
   365         module = open(Gen_Module_path,'w')
       
   366         module.write(BUS_TEXT % code_str)
       
   367         module.close()
       
   368         
       
   369         matiec_flags = '"-I%s"'%os.path.abspath(self.GetCTRoot().GetIECLibPath())
       
   370         return [(Gen_Module_path, matiec_flags)],"",True
       
   371 
       
   372 #-------------------------------------------------------------------------------
       
   373 #                          LPC CanFestival ConfNode Class
       
   374 #-------------------------------------------------------------------------------
       
   375 
       
   376 if havecanfestival:
       
   377 
       
   378     DEFAULT_SETTINGS = {
       
   379         "CAN_Baudrate": "125K",
       
   380         "Slave_NodeId": 2,
       
   381         "Master_NodeId": 1,
       
   382     }
       
   383     
       
   384     class LPCCanOpenSlave(_SlaveCTN):
       
   385         XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
       
   386         <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
       
   387           <xsd:element name="CanFestivalSlaveNode">
       
   388             <xsd:complexType>
       
   389               <xsd:attribute name="CAN_Baudrate" type="xsd:string" use="optional" default="%(CAN_Baudrate)s"/>
       
   390               <xsd:attribute name="NodeId" type="xsd:string" use="optional" default="%(Slave_NodeId)d"/>
       
   391               <xsd:attribute name="Sync_Align" type="xsd:integer" use="optional" default="0"/>
       
   392               <xsd:attribute name="Sync_Align_Ratio" use="optional" default="50">
       
   393                 <xsd:simpleType>
       
   394                     <xsd:restriction base="xsd:integer">
       
   395                         <xsd:minInclusive value="1"/>
       
   396                         <xsd:maxInclusive value="99"/>
       
   397                     </xsd:restriction>
       
   398                 </xsd:simpleType>
       
   399               </xsd:attribute>
       
   400             </xsd:complexType>
       
   401           </xsd:element>
       
   402         </xsd:schema>
       
   403         """ % DEFAULT_SETTINGS
       
   404         
       
   405         def __init__(self):
       
   406             # TODO change netname when name change
       
   407             NodeManager.__init__(self)
       
   408             odfilepath = self.GetSlaveODPath()
       
   409             if(os.path.isfile(odfilepath)):
       
   410                 self.OpenFileInCurrent(odfilepath)
       
   411             else:
       
   412                 self.CreateNewNode("SlaveNode",  # Name - will be changed at build time
       
   413                                    0x00,         # NodeID - will be changed at build time
       
   414                                    "slave",      # Type
       
   415                                    "",           # description 
       
   416                                    "None",       # profile
       
   417                                    "", # prfile filepath
       
   418                                    "heartbeat",  # NMT
       
   419                                    [])           # options
       
   420                 self.OnCTNSave()
       
   421         
       
   422         def GetCanDevice(self):
       
   423             return str(self.BaseParams.getIEC_Channel())
       
   424         
       
   425     class LPCCanOpenMaster(_NodeListCTN):
       
   426         XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
       
   427         <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
       
   428           <xsd:element name="CanFestivalNode">
       
   429             <xsd:complexType>
       
   430               <xsd:attribute name="CAN_Baudrate" type="xsd:string" use="optional" default="%(CAN_Baudrate)s"/>
       
   431               <xsd:attribute name="NodeId" type="xsd:string" use="optional" default="%(Master_NodeId)d"/>
       
   432               <xsd:attribute name="Sync_TPDOs" type="xsd:boolean" use="optional" default="true"/>
       
   433             </xsd:complexType>
       
   434           </xsd:element>
       
   435         </xsd:schema>
       
   436         """ % DEFAULT_SETTINGS
       
   437     
       
   438         def GetCanDevice(self):
       
   439             return str(self.BaseParams.getIEC_Channel())
       
   440     
       
   441     class LPCCanOpen(CanOpenRootClass):
       
   442         XSD = None
       
   443         CTNChildrenTypes = [("CanOpenNode",LPCCanOpenMaster, "CanOpen Master"),
       
   444                            ("CanOpenSlave",LPCCanOpenSlave, "CanOpen Slave")]
       
   445         
       
   446         def GetCanDriver(self):
       
   447             return ""
       
   448         
       
   449         def LoadChildren(self):
       
   450             ConfigTreeNode.LoadChildren(self)
       
   451             
       
   452             if self.GetChildByName("Master") is None:
       
   453                 master = self.CTNAddChild("Master", "CanOpenNode", 0)
       
   454                 master.BaseParams.setEnabled(False)
       
   455             
       
   456             if self.GetChildByName("Slave") is None:
       
   457                 slave = self.CTNAddChild("Slave", "CanOpenSlave", 1)
       
   458                 slave.BaseParams.setEnabled(False)
       
   459     
       
   460 
       
   461 #-------------------------------------------------------------------------------
       
   462 #                              LPCProjectController Class
       
   463 #-------------------------------------------------------------------------------
       
   464 
       
   465 def mycopytree(src, dst):
       
   466     """
       
   467     Copy content of a directory to an other, omit hidden files
       
   468     @param src: source directory
       
   469     @param dst: destination directory
       
   470     """
       
   471     for i in os.listdir(src):
       
   472         if not i.startswith('.') and i != "pous.xml":
       
   473             srcpath = os.path.join(src,i)
       
   474             dstpath = os.path.join(dst,i)
       
   475             if os.path.isdir(srcpath):
       
   476                 if os.path.exists(dstpath):
       
   477                     shutil.rmtree(dstpath)
       
   478                 os.makedirs(dstpath)
       
   479                 mycopytree(srcpath, dstpath)
       
   480             elif os.path.isfile(srcpath):
       
   481                 shutil.copy2(srcpath, dstpath)
       
   482 
       
   483 [SIMULATION_MODE, TRANSFER_MODE] = range(2)
       
   484 
       
   485 class LPCProjectController(ProjectController):
       
   486 
       
   487     ConfNodeMethods = [
       
   488         {"bitmap" : opjimg("Debug"),
       
   489          "name" : _("Simulate"),
       
   490          "tooltip" : _("Simulate PLC"),
       
   491          "method" : "_Simulate"},
       
   492         {"bitmap" : opjimg("Run"),
       
   493          "name" : _("Run"),
       
   494          "shown" : False,
       
   495          "tooltip" : _("Start PLC"),
       
   496          "method" : "_Run"},
       
   497         {"bitmap" : opjimg("Stop"),
       
   498          "name" : _("Stop"),
       
   499          "shown" : False,
       
   500          "tooltip" : _("Stop Running PLC"),
       
   501          "method" : "_Stop"},
       
   502         {"bitmap" : opjimg("Build"),
       
   503          "name" : _("Build"),
       
   504          "tooltip" : _("Build project into build folder"),
       
   505          "method" : "_Build"},
       
   506         {"bitmap" : opjimg("Transfer"),
       
   507          "name" : _("Transfer"),
       
   508          "shown" : False,
       
   509          "tooltip" : _("Transfer PLC"),
       
   510          "method" : "_Transfer"},
       
   511     ]
       
   512 
       
   513     def __init__(self, frame, logger, buildpath):
       
   514         self.OrigBuildPath = buildpath
       
   515         
       
   516         ProjectController.__init__(self, frame, logger)
       
   517         
       
   518         if havecanfestival:
       
   519             self.CTNChildrenTypes += [("LPCBus", LPCBus, "LPC bus"), ("CanOpen", LPCCanOpen, "CanOpen bus")]
       
   520         else:
       
   521             self.CTNChildrenTypes += [("LPCBus", LPCBus, "LPC bus")]
       
   522         self.CTNType = "LPC"
       
   523         
       
   524         self.OnlineMode = "OFF"
       
   525         self.LPCConnector = None
       
   526         
       
   527         self.CurrentMode = None
       
   528         self.previous_mode = None
       
   529         
       
   530         self.SimulationBuildPath = None
       
   531         
       
   532         self.AbortTransferTimer = None
       
   533     
       
   534     def ConfNodeLibraryFilePath(self):
       
   535         if self.OrigBuildPath is not None:
       
   536             return os.path.join(self.OrigBuildPath, "pous.xml")
       
   537         else:
       
   538             return ProjectController.ConfNodeLibraryFilePath(self)
       
   539     
       
   540     def GetProjectName(self):
       
   541         return self.Project.getname()
       
   542 
       
   543     def GetDefaultTargetName(self):
       
   544         if self.CurrentMode == SIMULATION_MODE:
       
   545             return ProjectController.GetDefaultTargetName(self)
       
   546         else:
       
   547             return "LPC"
       
   548 
       
   549     def GetTarget(self):
       
   550         target = ProjectController.GetTarget(self)
       
   551         if self.CurrentMode != SIMULATION_MODE:
       
   552             target.getcontent()["value"].setBuildPath(self.BuildPath)
       
   553         return target
       
   554     
       
   555     def _getBuildPath(self):
       
   556         if self.CurrentMode == SIMULATION_MODE:
       
   557             if self.SimulationBuildPath is None:
       
   558                 self.SimulationBuildPath = os.path.join(tempfile.mkdtemp(), os.path.basename(self.ProjectPath), "build")
       
   559             return self.SimulationBuildPath
       
   560         else:
       
   561             return ProjectController._getBuildPath(self)
       
   562 
       
   563     def _Build(self):
       
   564         save = self.ProjectTestModified()
       
   565         if save:
       
   566             self.SaveProject()
       
   567             self.AppFrame._Refresh(TITLE, FILEMENU)
       
   568         if self.BuildPath is not None:
       
   569             mycopytree(self.OrigBuildPath, self.BuildPath)
       
   570         ProjectController._Build(self)
       
   571         if save:
       
   572             wx.CallAfter(self.AppFrame.RefreshAll)
       
   573     
       
   574     def SetProjectName(self, name):
       
   575         return self.Project.setname(name)
       
   576 
       
   577     def SetOnlineMode(self, mode, path=None):
       
   578         if self.OnlineMode != mode.upper():
       
   579             self.OnlineMode = mode.upper()
       
   580             
       
   581             if self.OnlineMode != "OFF":
       
   582                 uri = "LPC://%s/%s" % (self.OnlineMode,path)
       
   583                 try:
       
   584                     self.LPCConnector = connectors.ConnectorFactory(uri, self)
       
   585                 except Exception, msg:
       
   586                     self.logger.write_error(_("Exception while connecting %s!\n")%uri)
       
   587                     self.logger.write_error(traceback.format_exc())
       
   588 
       
   589                 # Did connection success ?
       
   590                 if self.LPCConnector is None:
       
   591                     # Oups.
       
   592                     self.logger.write_error(_("Connection failed to %s!\n")%uri)
       
   593                 
       
   594             else:
       
   595                 self.LPCConnector = None
       
   596             
       
   597             self.ApplyOnlineMode()
       
   598 
       
   599     def ApplyOnlineMode(self):
       
   600         if self.CurrentMode != SIMULATION_MODE:
       
   601             self.KillDebugThread()
       
   602             
       
   603             self._connector = self.LPCConnector
       
   604             
       
   605             # Init with actual PLC status and print it
       
   606             self.UpdateMethodsFromPLCStatus()
       
   607                 
       
   608             if self.LPCConnector is not None and self.OnlineMode == "APPLICATION":
       
   609                 
       
   610                 self.CompareLocalAndRemotePLC()
       
   611                             
       
   612                 if self.previous_plcstate is not None:
       
   613                     status = _(self.previous_plcstate)
       
   614                 else:
       
   615                     status = ""
       
   616                 self.logger.write(_("PLC is %s\n")%status)
       
   617                 
       
   618                 #if self.StatusTimer and not self.StatusTimer.IsRunning():
       
   619                 #    # Start the status Timer
       
   620                 #    self.StatusTimer.Start(milliseconds=2000, oneShot=False)
       
   621                 
       
   622                 if self.previous_plcstate=="Started":
       
   623                     if self.DebugAvailable() and self.GetIECProgramsAndVariables():
       
   624                         self.logger.write(_("Debug connect matching running PLC\n"))
       
   625                         self._connect_debug()
       
   626                     else:
       
   627                         self.logger.write_warning(_("Debug do not match PLC - stop/transfert/start to re-enable\n"))
       
   628             
       
   629             elif self.StatusTimer and self.StatusTimer.IsRunning():
       
   630                 self.StatusTimer.Stop()
       
   631             
       
   632             if self.CurrentMode == TRANSFER_MODE:
       
   633                 
       
   634                 if self.OnlineMode == "BOOTLOADER":
       
   635                     self.BeginTransfer()
       
   636                 
       
   637                 elif self.OnlineMode == "APPLICATION":
       
   638                     self.CurrentMode = None
       
   639                     self.AbortTransferTimer.Stop()
       
   640                     self.AbortTransferTimer = None
       
   641                     
       
   642                     self.logger.write(_("PLC transferred successfully\n"))
       
   643     
       
   644     # Update a PLCOpenEditor Pou variable name
       
   645     def UpdateProjectVariableName(self, old_name, new_name):
       
   646         self.Project.updateElementName(old_name, new_name)
       
   647         self.BufferProject()
       
   648 
       
   649     def RemoveProjectVariableByAddress(self, address):
       
   650         self.Project.removeVariableByAddress(address)
       
   651         self.BufferProject()
       
   652 
       
   653     def RemoveProjectVariableByFilter(self, leading):
       
   654         self.Project.removeVariableByFilter(leading)
       
   655         self.BufferProject()
       
   656 
       
   657     def LoadProject(self, ProjectPath, BuildPath=None):
       
   658         """
       
   659         Load a project contained in a folder
       
   660         @param ProjectPath: path of the project folder
       
   661         """
       
   662         if os.path.basename(ProjectPath) == "":
       
   663             ProjectPath = os.path.dirname(ProjectPath)
       
   664         
       
   665         # Verify that project contains a PLCOpen program
       
   666         plc_file = os.path.join(ProjectPath, "plc.xml")
       
   667         if os.path.isfile(plc_file):
       
   668             # Load PLCOpen file
       
   669             result = self.OpenXMLFile(plc_file)
       
   670             if result:
       
   671                 return result
       
   672         else:
       
   673             self.CreateNewProject({"companyName": "",
       
   674                                    "productName": "",
       
   675                                    "productVersion": "",
       
   676                                    "projectName": "",
       
   677                                    "pageSize": (0, 0),
       
   678                                    "scaling": {}})
       
   679         
       
   680         # Change XSD into class members
       
   681         self._AddParamsMembers()
       
   682         self.Children = {}
       
   683         
       
   684         # Keep track of the root confnode (i.e. project path)
       
   685         self.ProjectPath = ProjectPath
       
   686         
       
   687         self.BuildPath = self._getBuildPath()
       
   688         if self.OrigBuildPath is not None:
       
   689             mycopytree(self.OrigBuildPath, self.BuildPath)
       
   690         
       
   691         # If dir have already be made, and file exist
       
   692         if os.path.isdir(self.CTNPath()) and os.path.isfile(self.ConfNodeXmlFilePath()):
       
   693             #Load the confnode.xml file into parameters members
       
   694             result = self.LoadXMLParams()
       
   695             if result:
       
   696                 return result
       
   697             #Load and init all the children
       
   698             self.LoadChildren()
       
   699         
       
   700         if havecanfestival and self.GetChildByName("CanOpen") is None:
       
   701             canopen = self.CTNAddChild("CanOpen", "CanOpen", 0)
       
   702             canopen.BaseParams.setEnabled(False)
       
   703             canopen.LoadChildren()
       
   704         
       
   705         if self.CTNTestModified():
       
   706             self.SaveProject()
       
   707         
       
   708         if wx.GetApp() is None:
       
   709             self.RefreshConfNodesBlockLists()
       
   710         else:
       
   711             wx.CallAfter(self.RefreshConfNodesBlockLists)
       
   712 
       
   713         return None
       
   714 
       
   715     ############# Real PLC object access #############
       
   716     def UpdateMethodsFromPLCStatus(self):
       
   717         # Get PLC state : Running or Stopped
       
   718         # TODO : use explicit status instead of boolean
       
   719         if self.OnlineMode == "OFF":
       
   720             status = "Disconnected"
       
   721         elif self.OnlineMode == "BOOTLOADER":
       
   722             status = "Connected"
       
   723         else:
       
   724             if self._connector is not None:
       
   725                 status = self._connector.GetPLCstatus()
       
   726             else:
       
   727                 status = "Disconnected"
       
   728         if self.previous_plcstate != status or self.previous_mode != self.CurrentMode:
       
   729             simulating = self.CurrentMode == SIMULATION_MODE
       
   730             for args in {
       
   731                      "Started" :     [("_Simulate", False),
       
   732                                       ("_Run", False),
       
   733                                       ("_Stop", True),
       
   734                                       ("_Build", True),
       
   735                                       ("_Transfer", True)],
       
   736                      "Stopped" :     [("_Simulate", False),
       
   737                                       ("_Run", True),
       
   738                                       ("_Stop", False),
       
   739                                       ("_Build", True),
       
   740                                       ("_Transfer", True)],
       
   741                      "Connected" :   [("_Simulate", not simulating),
       
   742                                       ("_Run", True),
       
   743                                       ("_Stop", simulating),
       
   744                                       ("_Build", True),
       
   745                                       ("_Transfer", True)],
       
   746                      "Disconnected" :[("_Simulate", not simulating),
       
   747                                       ("_Run", False),
       
   748                                       ("_Stop", simulating),
       
   749                                       ("_Build", True),
       
   750                                       ("_Transfer", False)],
       
   751                    }.get(status,[]):
       
   752                 self.ShowMethod(*args)
       
   753             self.previous_plcstate = status
       
   754             self.previous_mode = self.CurrentMode
       
   755             return True
       
   756         return False
       
   757 
       
   758     def Generate_plc_declare_locations(self):
       
   759         """
       
   760         Declare used locations in order to simulatePLC in a black box
       
   761         """
       
   762         return """#include "iec_types_all.h"
       
   763 
       
   764 #define __LOCATED_VAR(type, name, ...) \
       
   765 type beremiz_##name;\
       
   766 type *name = &beremiz_##name;
       
   767 
       
   768 #include "LOCATED_VARIABLES.h"
       
   769 
       
   770 #undef __LOCATED_VAR
       
   771 
       
   772 """
       
   773 
       
   774     def Generate_lpc_retain_array_sim(self):
       
   775         """
       
   776         Support for retain array in Simulation
       
   777         """
       
   778         return """/* Support for retain array */
       
   779 #define USER_RETAIN_ARRAY_SIZE 2000
       
   780 #define NUM_OF_COLS    3
       
   781 unsigned char readOK = 0;
       
   782 unsigned int foundIndex = USER_RETAIN_ARRAY_SIZE;
       
   783 unsigned int retainArray[USER_RETAIN_ARRAY_SIZE][NUM_OF_COLS];
       
   784 
       
   785 unsigned int __GetRetainData(unsigned char READ, unsigned int INDEX, unsigned int COLUMN)
       
   786 {
       
   787     if(READ == 1)
       
   788     {
       
   789         if((0<=INDEX) && (INDEX<USER_RETAIN_ARRAY_SIZE) && (0<=COLUMN) && (COLUMN<NUM_OF_COLS))
       
   790         {
       
   791             readOK = 1;
       
   792             return retainArray[INDEX][COLUMN];
       
   793         }
       
   794     }
       
   795 
       
   796     readOK = 0;
       
   797     return 0;
       
   798 }
       
   799 
       
   800 unsigned char __SetRetainData(unsigned char WRITE, unsigned int INDEX, unsigned int WORD1, unsigned int WORD2, unsigned int WORD3)
       
   801 {
       
   802     if(WRITE == 1)
       
   803     {
       
   804         if((0<=INDEX) && (INDEX<USER_RETAIN_ARRAY_SIZE))
       
   805         {
       
   806             retainArray[INDEX][0] = WORD1;
       
   807             retainArray[INDEX][1] = WORD2;
       
   808             retainArray[INDEX][2] = WORD3;
       
   809             return 1;
       
   810         }
       
   811     }
       
   812     
       
   813     return 0;
       
   814 }
       
   815 
       
   816 unsigned char __FindRetainData(unsigned char SEARCH, unsigned int START_IDX, unsigned int END_IDX, unsigned int WORD1, unsigned int WORD2, unsigned int WORD3)
       
   817 {
       
   818     unsigned int i;
       
   819 
       
   820     if((SEARCH==1) && (0<=START_IDX) && (START_IDX<USER_RETAIN_ARRAY_SIZE) && (START_IDX<=END_IDX) && (END_IDX<USER_RETAIN_ARRAY_SIZE))
       
   821     {
       
   822         for(i=START_IDX;i<=END_IDX;i++)
       
   823         {
       
   824             if((retainArray[i][0] == WORD1) && (retainArray[i][1] == WORD2) && (retainArray[i][2] == WORD3))
       
   825             {
       
   826                 foundIndex = i;
       
   827                 return 1;
       
   828             }
       
   829         }
       
   830     }
       
   831 
       
   832     foundIndex = USER_RETAIN_ARRAY_SIZE;    /* Data not found => return index that is out of array bounds */
       
   833     return 0;
       
   834 }
       
   835 
       
   836 /* Since Beremiz debugger doesn't like pointer-by-reference stuff or global varibles, separate function is a must */
       
   837 unsigned char __GetReadStatus(unsigned char dummy)
       
   838 {
       
   839     return readOK;
       
   840 }
       
   841 
       
   842 unsigned int __GetFoundIndex(unsigned char dummy)
       
   843 {
       
   844     return foundIndex;
       
   845 }
       
   846 """
       
   847 
       
   848     def _Simulate(self):
       
   849         """
       
   850         Method called by user to Simulate PLC
       
   851         """
       
   852         self.CurrentMode = SIMULATION_MODE
       
   853         
       
   854         uri = "LOCAL://"
       
   855         try:
       
   856             self._connector = connectors.ConnectorFactory(uri, self)
       
   857         except Exception, msg:
       
   858             self.logger.write_error(_("Exception while connecting %s!\n")%uri)
       
   859             self.logger.write_error(traceback.format_exc())
       
   860 
       
   861         # Did connection success ?
       
   862         if self._connector is None:
       
   863             # Oups.
       
   864             self.logger.write_error(_("Connection failed to %s!\n")%uri)
       
   865             self.StopSimulation()
       
   866             return False
       
   867         
       
   868         buildpath = self._getBuildPath()
       
   869         
       
   870         # Eventually create build dir
       
   871         if not os.path.exists(buildpath):
       
   872             os.makedirs(buildpath)
       
   873         
       
   874         # Generate SoftPLC IEC code
       
   875         IECGenRes = self._Generate_SoftPLC()
       
   876         
       
   877          # If IEC code gen fail, bail out.
       
   878         if not IECGenRes:
       
   879             self.logger.write_error(_("IEC-61131-3 code generation failed !\n"))
       
   880             self.StopSimulation()
       
   881             return False
       
   882 
       
   883         # Reset variable and program list that are parsed from
       
   884         # CSV file generated by IEC2C compiler.
       
   885         self.ResetIECProgramsAndVariables()
       
   886         
       
   887         gen_result = self.CTNGenerate_C(buildpath, self.PLCGeneratedLocatedVars)
       
   888         CTNCFilesAndCFLAGS, CTNLDFLAGS, DoCalls = gen_result[:3]
       
   889         # if some files have been generated put them in the list with their location
       
   890         if CTNCFilesAndCFLAGS:
       
   891             self.LocationCFilesAndCFLAGS = [(self.GetCurrentLocation(), CTNCFilesAndCFLAGS, DoCalls)]
       
   892         else:
       
   893             self.LocationCFilesAndCFLAGS = []
       
   894 
       
   895         # confnode asks for some LDFLAGS
       
   896         if CTNLDFLAGS:
       
   897             # LDFLAGS can be either string
       
   898             if type(CTNLDFLAGS)==type(str()):
       
   899                 self.LDFLAGS=[CTNLDFLAGS]
       
   900             #or list of strings
       
   901             elif type(CTNLDFLAGS)==type(list()):
       
   902                 self.LDFLAGS=CTNLDFLAGS[:]
       
   903         else:
       
   904             self.LDFLAGS=[]
       
   905         
       
   906         # Template based part of C code generation
       
   907         # files are stacked at the beginning, as files of confnode tree root
       
   908         for generator, filename, name in [
       
   909            # debugger code
       
   910            (self.Generate_plc_debugger, "plc_debugger.c", "Debugger"),
       
   911            # init/cleanup/retrieve/publish, run and align code
       
   912            (self.Generate_plc_common_main,"plc_common_main.c","Common runtime"),
       
   913            # declare located variables for simulate in a black box
       
   914            (self.Generate_plc_declare_locations,"plc_declare_locations.c","Declare Locations"),
       
   915            # declare located variables for simulate in a black box
       
   916            (self.Generate_lpc_retain_array_sim,"lpc_retain_array_sim.c","Retain Array for Simulation")]:
       
   917             try:
       
   918                 # Do generate
       
   919                 code = generator()
       
   920                 if code is None:
       
   921                      raise
       
   922                 code_path = os.path.join(buildpath,filename)
       
   923                 open(code_path, "w").write(code)
       
   924                 # Insert this file as first file to be compiled at root confnode
       
   925                 self.LocationCFilesAndCFLAGS[0][1].insert(0,(code_path, self.plcCFLAGS))
       
   926             except Exception, exc:
       
   927                 self.logger.write_error(name+_(" generation failed !\n"))
       
   928                 self.logger.write_error(traceback.format_exc())
       
   929                 self.StopSimulation()
       
   930                 return False
       
   931         
       
   932         # Get simulation builder
       
   933         builder = self.GetBuilder()
       
   934         if builder is None:
       
   935             self.logger.write_error(_("Fatal : cannot get builder.\n"))
       
   936             self.StopSimulation()
       
   937             return False
       
   938 
       
   939         # Build
       
   940         try:
       
   941             if not builder.build() :
       
   942                 self.logger.write_error(_("C Build failed.\n"))
       
   943                 self.StopSimulation()
       
   944                 return False
       
   945         except Exception, exc:
       
   946             self.logger.write_error(_("C Build crashed !\n"))
       
   947             self.logger.write_error(traceback.format_exc())
       
   948             self.StopSimulation()
       
   949             return False
       
   950 
       
   951         data = builder.GetBinaryCode()
       
   952         if data is not None :
       
   953             if self._connector.NewPLC(builder.GetBinaryCodeMD5(), data, []):
       
   954                 self.UnsubscribeAllDebugIECVariable()
       
   955                 self.ProgramTransferred()
       
   956                 if self.AppFrame is not None:
       
   957                     self.AppFrame.CloseObsoleteDebugTabs()
       
   958                 self.logger.write(_("Transfer completed successfully.\n"))
       
   959             else:
       
   960                 self.logger.write_error(_("Transfer failed\n"))
       
   961                 self.StopSimulation()
       
   962                 return False
       
   963         
       
   964         self._Run()
       
   965                 
       
   966         if not self.StatusTimer.IsRunning():
       
   967             # Start the status Timer
       
   968             self.StatusTimer.Start(milliseconds=500, oneShot=False)
       
   969     
       
   970     def StopSimulation(self):
       
   971         self.CurrentMode = None
       
   972         self.ApplyOnlineMode()
       
   973     
       
   974     def _Stop(self):
       
   975         ProjectController._Stop(self)
       
   976         
       
   977         if self.CurrentMode == SIMULATION_MODE:
       
   978             self.StopSimulation()
       
   979 
       
   980     def CompareLocalAndRemotePLC(self):
       
   981         if self.LPCConnector is None:
       
   982             return
       
   983         # We are now connected. Update button status
       
   984         MD5 = self.GetLastBuildMD5()
       
   985         # Check remote target PLC correspondance to that md5
       
   986         if MD5 is not None and self.LPCConnector.MatchMD5(MD5):
       
   987             # warns controller that program match
       
   988             self.ProgramTransferred()
       
   989 
       
   990     def ResetBuildMD5(self):
       
   991         builder=self.GetBuilder()
       
   992         if builder is not None:
       
   993             builder.ResetBinaryCodeMD5(self.OnlineMode)
       
   994         
       
   995     def GetLastBuildMD5(self):
       
   996         builder=self.GetBuilder()
       
   997         if builder is not None:
       
   998             return builder.GetBinaryCodeMD5(self.OnlineMode)
       
   999         else:
       
  1000             return None
       
  1001 
       
  1002     def _Transfer(self):
       
  1003         if self.CurrentMode is None and self.OnlineMode != "OFF":
       
  1004             self.CurrentMode = TRANSFER_MODE
       
  1005             
       
  1006             if ProjectController._Build(self):
       
  1007             
       
  1008                 ID_ABORTTRANSFERTIMER = wx.NewId()
       
  1009                 self.AbortTransferTimer = wx.Timer(self.AppFrame, ID_ABORTTRANSFERTIMER)
       
  1010                 self.AppFrame.Bind(wx.EVT_TIMER, self.AbortTransfer, self.AbortTransferTimer)  
       
  1011                 
       
  1012                 if self.OnlineMode == "BOOTLOADER":
       
  1013                     self.BeginTransfer()
       
  1014                 
       
  1015                 else:
       
  1016                     self.logger.write(_("Resetting PLC\n"))
       
  1017                     #self.StatusTimer.Stop()
       
  1018                     self.LPCConnector.ResetPLC()
       
  1019                     self.AbortTransferTimer.Start(milliseconds=5000, oneShot=True)
       
  1020             
       
  1021             else:
       
  1022                 self.CurrentMode = None
       
  1023     
       
  1024     def BeginTransfer(self):
       
  1025         self.logger.write(_("Start PLC transfer\n"))
       
  1026         
       
  1027         self.AbortTransferTimer.Stop()
       
  1028         ProjectController._Transfer(self)
       
  1029         self.AbortTransferTimer.Start(milliseconds=5000, oneShot=True)
       
  1030     
       
  1031     def AbortTransfer(self, event):
       
  1032         self.logger.write_warning(_("Timeout waiting PLC to recover\n"))
       
  1033         
       
  1034         self.CurrentMode = None
       
  1035         self.AbortTransferTimer.Stop()
       
  1036         self.AbortTransferTimer = None
       
  1037         event.Skip()
       
  1038 
       
  1039     def _Run(self):
       
  1040         """
       
  1041         Start PLC
       
  1042         """
       
  1043         if self.GetIECProgramsAndVariables():
       
  1044             self._connector.StartPLC()
       
  1045             self.logger.write(_("Starting PLC\n"))
       
  1046             self._connect_debug()
       
  1047         else:
       
  1048             self.logger.write_error(_("Couldn't start PLC !\n"))
       
  1049         self.UpdateMethodsFromPLCStatus()
       
  1050 
       
  1051 #-------------------------------------------------------------------------------
       
  1052 #                              LPCBeremiz Class
       
  1053 #-------------------------------------------------------------------------------
       
  1054 lpcberemiz_cmd=None
       
  1055 
       
  1056 class LPCBeremiz(Beremiz):
       
  1057     
       
  1058     def _init_coll_FileMenu_Items(self, parent):
       
  1059         AppendMenu(parent, help='', id=wx.ID_SAVE,
       
  1060               kind=wx.ITEM_NORMAL, text=_(u'Save\tCTRL+S'))
       
  1061         AppendMenu(parent, help='', id=wx.ID_CLOSE,
       
  1062               kind=wx.ITEM_NORMAL, text=_(u'Close Tab\tCTRL+W'))
       
  1063         parent.AppendSeparator()
       
  1064         AppendMenu(parent, help='', id=wx.ID_PAGE_SETUP,
       
  1065               kind=wx.ITEM_NORMAL, text=_(u'Page Setup'))
       
  1066         AppendMenu(parent, help='', id=wx.ID_PREVIEW,
       
  1067               kind=wx.ITEM_NORMAL, text=_(u'Preview'))
       
  1068         AppendMenu(parent, help='', id=wx.ID_PRINT,
       
  1069               kind=wx.ITEM_NORMAL, text=_(u'Print'))
       
  1070         parent.AppendSeparator()
       
  1071         AppendMenu(parent, help='', id=wx.ID_PROPERTIES,
       
  1072               kind=wx.ITEM_NORMAL, text=_(u'Properties'))
       
  1073         parent.AppendSeparator()
       
  1074         AppendMenu(parent, help='', id=wx.ID_EXIT,
       
  1075               kind=wx.ITEM_NORMAL, text=_(u'Quit\tCTRL+Q'))
       
  1076         
       
  1077         self.Bind(wx.EVT_MENU, self.OnSaveProjectMenu, id=wx.ID_SAVE)
       
  1078         self.Bind(wx.EVT_MENU, self.OnCloseTabMenu, id=wx.ID_CLOSE)
       
  1079         self.Bind(wx.EVT_MENU, self.OnPageSetupMenu, id=wx.ID_PAGE_SETUP)
       
  1080         self.Bind(wx.EVT_MENU, self.OnPreviewMenu, id=wx.ID_PREVIEW)
       
  1081         self.Bind(wx.EVT_MENU, self.OnPrintMenu, id=wx.ID_PRINT)
       
  1082         self.Bind(wx.EVT_MENU, self.OnPropertiesMenu, id=wx.ID_PROPERTIES)
       
  1083         self.Bind(wx.EVT_MENU, self.OnQuitMenu, id=wx.ID_EXIT)
       
  1084     
       
  1085         self.AddToMenuToolBar([(wx.ID_SAVE, "save.png", _(u'Save'), None),
       
  1086                                (wx.ID_PRINT, "print.png", _(u'Print'), None)])
       
  1087     
       
  1088     def _init_ctrls(self, prnt):
       
  1089         IDEFrame._init_ctrls(self, prnt)
       
  1090         
       
  1091         self.Bind(wx.EVT_MENU, self.OnOpenWidgetInspector, id=ID_BEREMIZINSPECTOR)
       
  1092         accel = wx.AcceleratorTable([wx.AcceleratorEntry(wx.ACCEL_CTRL|wx.ACCEL_ALT, ord('I'), ID_BEREMIZINSPECTOR)])
       
  1093         self.SetAcceleratorTable(accel)
       
  1094         
       
  1095         self.PLCConfig = wx.ScrolledWindow(id=ID_BEREMIZPLCCONFIG,
       
  1096               name='PLCConfig', parent=self.LeftNoteBook, pos=wx.Point(0, 0),
       
  1097               size=wx.Size(-1, -1), style=wx.TAB_TRAVERSAL|wx.SUNKEN_BORDER|wx.HSCROLL|wx.VSCROLL)
       
  1098         self.PLCConfig.SetBackgroundColour(wx.WHITE)
       
  1099         self.PLCConfig.Bind(wx.EVT_LEFT_DOWN, self.OnPanelLeftDown)
       
  1100         self.PLCConfig.Bind(wx.EVT_SIZE, self.OnMoveWindow)
       
  1101         self.LeftNoteBook.InsertPage(0, self.PLCConfig, _("Topology"), True)
       
  1102         
       
  1103         self.LogConsole = wx.TextCtrl(id=ID_BEREMIZLOGCONSOLE, value='',
       
  1104                   name='LogConsole', parent=self.BottomNoteBook, pos=wx.Point(0, 0),
       
  1105                   size=wx.Size(0, 0), style=wx.TE_MULTILINE|wx.TE_RICH2)
       
  1106         self.LogConsole.Bind(wx.EVT_LEFT_DCLICK, self.OnLogConsoleDClick)
       
  1107         self.BottomNoteBook.AddPage(self.LogConsole, _("Log Console"))
       
  1108         
       
  1109         self._init_beremiz_sizers()
       
  1110 
       
  1111     def OnCloseFrame(self, event):
       
  1112         global frame
       
  1113         
       
  1114         if self.CheckSaveBeforeClosing(_("Close Application")):
       
  1115             
       
  1116             frame.Hide()
       
  1117             
       
  1118             self.CTR.ResetAppFrame(lpcberemiz_cmd.Log)
       
  1119             if self.CTR.OnlineMode == 0:
       
  1120                 self.CTR._connector = None
       
  1121             
       
  1122             self.CTR.KillDebugThread()
       
  1123             self.KillLocalRuntime()
       
  1124             
       
  1125             self.SaveLastState()
       
  1126             
       
  1127             lpcberemiz_cmd.Log.write("Closed\n")
       
  1128             
       
  1129         event.Veto()
       
  1130 
       
  1131     def ShowProperties(self):
       
  1132         old_values = self.Controler.GetProjectProperties()
       
  1133         dialog = ProjectDialog(self ,False)
       
  1134         dialog.SetValues(old_values)
       
  1135         if dialog.ShowModal() == wx.ID_OK:
       
  1136             new_values = dialog.GetValues()
       
  1137             new_values["creationDateTime"] = old_values["creationDateTime"]
       
  1138             if new_values != old_values:
       
  1139                 self.Controler.SetProjectProperties(None, new_values)
       
  1140                 self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU, 
       
  1141                               PROJECTTREE, POUINSTANCEVARIABLESPANEL, SCALING)
       
  1142         dialog.Destroy()
       
  1143 
       
  1144     def RefreshFileMenu(self):
       
  1145         MenuToolBar = self.Panes["MenuToolBar"]
       
  1146         if self.CTR is not None:
       
  1147             selected = self.TabsOpened.GetSelection()
       
  1148             if selected >= 0:
       
  1149                 graphic_viewer = isinstance(self.TabsOpened.GetPage(selected), Viewer)
       
  1150             else:
       
  1151                 graphic_viewer = False
       
  1152             if self.TabsOpened.GetPageCount() > 0:
       
  1153                 self.FileMenu.Enable(wx.ID_CLOSE, True)
       
  1154                 if graphic_viewer:
       
  1155                     self.FileMenu.Enable(wx.ID_PREVIEW, True)
       
  1156                     self.FileMenu.Enable(wx.ID_PRINT, True)
       
  1157                     MenuToolBar.EnableTool(wx.ID_PRINT, True)
       
  1158                 else:
       
  1159                     self.FileMenu.Enable(wx.ID_PREVIEW, False)
       
  1160                     self.FileMenu.Enable(wx.ID_PRINT, False)
       
  1161                     MenuToolBar.EnableTool(wx.ID_PRINT, False)
       
  1162             else:
       
  1163                 self.FileMenu.Enable(wx.ID_CLOSE, False)
       
  1164                 self.FileMenu.Enable(wx.ID_PREVIEW, False)
       
  1165                 self.FileMenu.Enable(wx.ID_PRINT, False)
       
  1166                 MenuToolBar.EnableTool(wx.ID_PRINT, False)
       
  1167             self.FileMenu.Enable(wx.ID_PAGE_SETUP, True)
       
  1168             project_modified = self.CTR.ProjectTestModified()
       
  1169             self.FileMenu.Enable(wx.ID_SAVE, project_modified)
       
  1170             MenuToolBar.EnableTool(wx.ID_SAVE, project_modified)
       
  1171             self.FileMenu.Enable(wx.ID_PROPERTIES, True)
       
  1172         else:
       
  1173             self.FileMenu.Enable(wx.ID_CLOSE, False)
       
  1174             self.FileMenu.Enable(wx.ID_PAGE_SETUP, False)
       
  1175             self.FileMenu.Enable(wx.ID_PREVIEW, False)
       
  1176             self.FileMenu.Enable(wx.ID_PRINT, False)
       
  1177             MenuToolBar.EnableTool(wx.ID_PRINT, False)
       
  1178             self.FileMenu.Enable(wx.ID_SAVE, False)
       
  1179             MenuToolBar.EnableTool(wx.ID_SAVE, False)
       
  1180             self.FileMenu.Enable(wx.ID_PROPERTIES, False)
       
  1181         
       
  1182     def RefreshPLCParams(self):
       
  1183         self.Freeze()
       
  1184         self.ClearSizer(self.PLCParamsSizer)
       
  1185         
       
  1186         if self.CTR is not None:    
       
  1187             plcwindow = wx.Panel(self.PLCConfig, -1, size=wx.Size(-1, -1))
       
  1188             if self.CTR.CTNTestModified():
       
  1189                 bkgdclr = CHANGED_TITLE_COLOUR
       
  1190             else:
       
  1191                 bkgdclr = TITLE_COLOUR
       
  1192                 
       
  1193             if self.CTR not in self.ConfNodeInfos:
       
  1194                 self.ConfNodeInfos[self.CTR] = {"right_visible" : False}
       
  1195             
       
  1196             plcwindow.SetBackgroundColour(TITLE_COLOUR)
       
  1197             plcwindow.Bind(wx.EVT_LEFT_DOWN, self.OnPanelLeftDown)
       
  1198             self.PLCParamsSizer.AddWindow(plcwindow, 0, border=0, flag=wx.GROW)
       
  1199             
       
  1200             plcwindowsizer = wx.BoxSizer(wx.HORIZONTAL)
       
  1201             plcwindow.SetSizer(plcwindowsizer)
       
  1202             
       
  1203             st = wx.StaticText(plcwindow, -1)
       
  1204             st.SetFont(wx.Font(faces["size"], wx.DEFAULT, wx.NORMAL, wx.BOLD, faceName = faces["helv"]))
       
  1205             st.SetLabel(self.CTR.GetProjectName())
       
  1206             plcwindowsizer.AddWindow(st, 0, border=5, flag=wx.ALL|wx.ALIGN_CENTER)
       
  1207             
       
  1208             plcwindowmainsizer = wx.BoxSizer(wx.VERTICAL)
       
  1209             plcwindowsizer.AddSizer(plcwindowmainsizer, 0, border=5, flag=wx.ALL)
       
  1210             
       
  1211             plcwindowbuttonsizer = wx.BoxSizer(wx.HORIZONTAL)
       
  1212             plcwindowmainsizer.AddSizer(plcwindowbuttonsizer, 0, border=0, flag=wx.ALIGN_CENTER)
       
  1213             
       
  1214             msizer = self.GenerateMethodButtonSizer(self.CTR, plcwindow, not self.ConfNodeInfos[self.CTR]["right_visible"])
       
  1215             plcwindowbuttonsizer.AddSizer(msizer, 0, border=0, flag=wx.GROW)
       
  1216             
       
  1217         self.PLCConfigMainSizer.Layout()
       
  1218         self.RefreshScrollBars()
       
  1219         self.Thaw()
       
  1220 
       
  1221     def GenerateTreeBranch(self, confnode):
       
  1222         leftwindow = wx.Panel(self.PLCConfig, -1, size=wx.Size(-1, -1))
       
  1223         if confnode.CTNTestModified():
       
  1224             bkgdclr=CHANGED_WINDOW_COLOUR
       
  1225         else:
       
  1226             bkgdclr=WINDOW_COLOUR
       
  1227 
       
  1228         leftwindow.SetBackgroundColour(bkgdclr)
       
  1229         
       
  1230         if confnode not in self.ConfNodeInfos:
       
  1231             self.ConfNodeInfos[confnode] = {"expanded" : False, "left_visible" : False, "right_visible" : False}
       
  1232             
       
  1233         self.ConfNodeInfos[confnode]["children"] = confnode.IECSortedChildren()
       
  1234         confnode_infos = confnode.GetVariableLocationTree()
       
  1235         confnode_locations = []
       
  1236         if len(self.ConfNodeInfos[confnode]["children"]) == 0:
       
  1237             confnode_locations = confnode_infos["children"]
       
  1238             if not self.ConfNodeInfos[confnode].has_key("locations_infos"):
       
  1239                 self.ConfNodeInfos[confnode]["locations_infos"] = {"root": {"expanded" : False}}
       
  1240             
       
  1241             self.ConfNodeInfos[confnode]["locations_infos"]["root"]["left"] = None
       
  1242             self.ConfNodeInfos[confnode]["locations_infos"]["root"]["right"] = None
       
  1243             self.ConfNodeInfos[confnode]["locations_infos"]["root"]["children"] = []
       
  1244         
       
  1245         self.ConfNodeTreeSizer.AddWindow(leftwindow, 0, border=0, flag=wx.GROW)
       
  1246         
       
  1247         leftwindowvsizer = wx.BoxSizer(wx.VERTICAL)
       
  1248         leftwindow.SetSizer(leftwindowvsizer)
       
  1249         
       
  1250         leftwindowsizer = wx.BoxSizer(wx.HORIZONTAL)
       
  1251         leftwindowvsizer.AddSizer(leftwindowsizer, 0, border=0, flag=0)
       
  1252         
       
  1253         self.GenerateEnableButton(leftwindow, leftwindowsizer, confnode)
       
  1254         
       
  1255         st = wx.StaticText(leftwindow, -1)
       
  1256         st.SetFont(wx.Font(faces["size"], wx.DEFAULT, wx.NORMAL, wx.BOLD, faceName = faces["helv"]))
       
  1257         st.SetLabel(confnode.GetFullIEC_Channel())
       
  1258         leftwindowsizer.AddWindow(st, 0, border=5, flag=wx.RIGHT)
       
  1259         
       
  1260         expandbutton_id = wx.NewId()
       
  1261         expandbutton = wx.lib.buttons.GenBitmapToggleButton(id=expandbutton_id, bitmap=wx.Bitmap(Bpath( 'images', 'plus.png')),
       
  1262               name='ExpandButton', parent=leftwindow, pos=wx.Point(0, 0),
       
  1263               size=wx.Size(13, 13), style=wx.NO_BORDER)
       
  1264         expandbutton.labelDelta = 0
       
  1265         expandbutton.SetBezelWidth(0)
       
  1266         expandbutton.SetUseFocusIndicator(False)
       
  1267         expandbutton.SetBitmapSelected(wx.Bitmap(Bpath( 'images', 'minus.png')))
       
  1268             
       
  1269         if len(self.ConfNodeInfos[confnode]["children"]) > 0:
       
  1270             expandbutton.SetToggle(self.ConfNodeInfos[confnode]["expanded"])
       
  1271             def togglebutton(event):
       
  1272                 if expandbutton.GetToggle():
       
  1273                     self.ExpandConfNode(confnode)
       
  1274                 else:
       
  1275                     self.CollapseConfNode(confnode)
       
  1276                 self.ConfNodeInfos[confnode]["expanded"] = expandbutton.GetToggle()
       
  1277                 self.PLCConfigMainSizer.Layout()
       
  1278                 self.RefreshScrollBars()
       
  1279                 event.Skip()
       
  1280             expandbutton.Bind(wx.EVT_BUTTON, togglebutton, id=expandbutton_id)
       
  1281         elif len(confnode_locations) > 0:
       
  1282             locations_infos = self.ConfNodeInfos[confnode]["locations_infos"]
       
  1283             expandbutton.SetToggle(locations_infos["root"]["expanded"])
       
  1284             def togglebutton(event):
       
  1285                 if expandbutton.GetToggle():
       
  1286                     self.ExpandLocation(locations_infos, "root")
       
  1287                 else:
       
  1288                     self.CollapseLocation(locations_infos, "root")
       
  1289                 self.ConfNodeInfos[confnode]["expanded"] = expandbutton.GetToggle()
       
  1290                 locations_infos["root"]["expanded"] = expandbutton.GetToggle()
       
  1291                 self.PLCConfigMainSizer.Layout()
       
  1292                 self.RefreshScrollBars()
       
  1293                 event.Skip()
       
  1294             expandbutton.Bind(wx.EVT_BUTTON, togglebutton, id=expandbutton_id)
       
  1295         else:
       
  1296             expandbutton.Enable(False)
       
  1297         leftwindowsizer.AddWindow(expandbutton, 0, border=5, flag=wx.RIGHT|wx.ALIGN_CENTER_VERTICAL)
       
  1298         
       
  1299         sb = wx.StaticBitmap(leftwindow, -1)
       
  1300         icon = confnode_infos.get("icon", None)
       
  1301         if icon is None:
       
  1302             icon_bitmap = self.LocationImageList.GetBitmap(self.LocationImageDict[confnode_infos["type"]])
       
  1303         else: 
       
  1304             icon_bitmap = wx.Bitmap(icon)
       
  1305         sb.SetBitmap(icon_bitmap)
       
  1306         leftwindowsizer.AddWindow(sb, 0, border=5, flag=wx.RIGHT|wx.ALIGN_CENTER_VERTICAL)
       
  1307         
       
  1308         st_id = wx.NewId()
       
  1309         st = wx.StaticText(leftwindow, st_id, size=wx.DefaultSize, style=wx.NO_BORDER)
       
  1310         st.SetFont(wx.Font(faces["size"] * 0.75, wx.DEFAULT, wx.NORMAL, wx.BOLD, faceName = faces["helv"]))
       
  1311         st.SetLabel(confnode.MandatoryParams[1].getName())
       
  1312         leftwindowsizer.AddWindow(st, 0, border=5, flag=wx.RIGHT|wx.ALIGN_CENTER_VERTICAL)
       
  1313         
       
  1314         rightwindow = self.GenerateParamsPanel(confnode, bkgdclr)
       
  1315         self.ConfNodeTreeSizer.AddWindow(rightwindow, 0, border=0, flag=wx.GROW)
       
  1316 
       
  1317         self.ConfNodeInfos[confnode]["left"] = leftwindow
       
  1318         self.ConfNodeInfos[confnode]["right"] = rightwindow
       
  1319         for child in self.ConfNodeInfos[confnode]["children"]:
       
  1320             self.GenerateTreeBranch(child)
       
  1321             if not self.ConfNodeInfos[child]["expanded"]:
       
  1322                 self.CollapseConfNode(child)
       
  1323         
       
  1324         if len(confnode_locations) > 0:
       
  1325             locations_infos = self.ConfNodeInfos[confnode]["locations_infos"]
       
  1326             treectrl = wx.TreeCtrl(self.PLCConfig, -1, size=wx.DefaultSize, 
       
  1327                                    style=wx.TR_HAS_BUTTONS|wx.TR_SINGLE|wx.NO_BORDER|wx.TR_HIDE_ROOT|wx.TR_NO_LINES|wx.TR_LINES_AT_ROOT)
       
  1328             treectrl.SetImageList(self.LocationImageList)
       
  1329             treectrl.Bind(wx.EVT_TREE_BEGIN_DRAG, self.GenerateLocationBeginDragFunction(locations_infos))
       
  1330             treectrl.Bind(wx.EVT_TREE_ITEM_EXPANDED, self.GenerateLocationExpandCollapseFunction(locations_infos, True))
       
  1331             treectrl.Bind(wx.EVT_TREE_ITEM_COLLAPSED, self.GenerateLocationExpandCollapseFunction(locations_infos, False))
       
  1332             
       
  1333             treectrl.AddRoot("")
       
  1334             self.ConfNodeTreeSizer.AddWindow(treectrl, 0, border=0, flag=0)
       
  1335             
       
  1336             rightwindow = wx.Panel(self.PLCConfig, -1, size=wx.Size(-1, -1))
       
  1337             rightwindow.SetBackgroundColour(wx.WHITE)
       
  1338             self.ConfNodeTreeSizer.AddWindow(rightwindow, 0, border=0, flag=wx.GROW)
       
  1339             
       
  1340             locations_infos["root"]["left"] = treectrl
       
  1341             locations_infos["root"]["right"] = rightwindow
       
  1342             for location in confnode_locations:
       
  1343                 locations_infos["root"]["children"].append("root.%s" % location["name"])
       
  1344                 self.GenerateLocationTreeBranch(treectrl, treectrl.GetRootItem(), locations_infos, "root", location)
       
  1345             if locations_infos["root"]["expanded"]:
       
  1346                 self.ExpandLocation(locations_infos, "root")
       
  1347 
       
  1348 class StdoutPseudoFile:
       
  1349     
       
  1350     def __init__(self, port):
       
  1351         self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
       
  1352         self.socket.connect(('localhost', port))
       
  1353         self.Buffer = ""
       
  1354     
       
  1355     def __del__(self):
       
  1356         self.socket.close()
       
  1357     
       
  1358     def readline(self):
       
  1359         idx = self.Buffer.find("\n")
       
  1360         if idx == -1:
       
  1361             self.Buffer += self.socket.recv(2048)
       
  1362             idx = self.Buffer.find("\n")
       
  1363         if idx != -1:
       
  1364             line = self.Buffer[:idx+1]
       
  1365             self.Buffer = self.Buffer[idx+1:]
       
  1366             if BMZ_DBG:
       
  1367                 print "command >"+line
       
  1368             return line
       
  1369         return ""
       
  1370     
       
  1371     """ Base class for file like objects to facilitate StdOut for the Shell."""
       
  1372     def write(self, s, style = None):
       
  1373         if s != '':
       
  1374             self.socket.send(s.encode('utf8'))
       
  1375         
       
  1376     def writeyield(self, s):
       
  1377         self.write(s)
       
  1378 
       
  1379     def write_warning(self, s):
       
  1380         self.write(s)
       
  1381 
       
  1382     def write_error(self, s):
       
  1383         self.write(s)
       
  1384 
       
  1385     def flush(self):
       
  1386         pass
       
  1387     
       
  1388     def isatty(self):
       
  1389         return False
       
  1390 
       
  1391 if __name__ == '__main__':
       
  1392     
       
  1393     from threading import Thread, Timer, Semaphore
       
  1394     import cmd
       
  1395 
       
  1396     wx_eval_lock = Semaphore(0)
       
  1397     eval_res = None
       
  1398     def wx_evaluator(callable, *args, **kwargs):
       
  1399         global eval_res
       
  1400         eval_res = None
       
  1401         try:
       
  1402             eval_res=callable(*args,**kwargs)
       
  1403         finally:
       
  1404             wx_eval_lock.release()
       
  1405 
       
  1406     def evaluator(callable, *args, **kwargs):
       
  1407         global eval_res
       
  1408         wx.CallAfter(wx_evaluator,callable,*args,**kwargs)
       
  1409         wx_eval_lock.acquire()
       
  1410         return eval_res
       
  1411 
       
  1412     # Command log for debug, for viewing from wxInspector
       
  1413     if BMZ_DBG:
       
  1414         __builtins__.cmdlog = []
       
  1415 
       
  1416     class LPCBeremiz_Cmd(cmd.Cmd):
       
  1417         
       
  1418         prompt = ""
       
  1419         RefreshTimer = None
       
  1420         
       
  1421         def __init__(self, CTR, Log):
       
  1422             cmd.Cmd.__init__(self, stdin=Log, stdout=Log)
       
  1423             self.use_rawinput = False
       
  1424             self.Log = Log
       
  1425             self.CTR = CTR
       
  1426             
       
  1427         def RestartTimer(self):
       
  1428             if self.RefreshTimer is not None:
       
  1429                 self.RefreshTimer.cancel()
       
  1430             self.RefreshTimer = Timer(0.1, wx.CallAfter, args = [self.Refresh])
       
  1431             self.RefreshTimer.start()
       
  1432         
       
  1433         def Exit(self):
       
  1434             global frame, app
       
  1435             self.Close()
       
  1436             app.ExitMainLoop()
       
  1437             return True
       
  1438         
       
  1439         def do_EOF(self, line):
       
  1440             return self.Exit()
       
  1441         
       
  1442         def Show(self):
       
  1443             global frame
       
  1444             if frame is not None:
       
  1445                 self.CTR.SetAppFrame(frame, frame.Log)
       
  1446                 frame.Show()
       
  1447                 frame.Raise()
       
  1448         
       
  1449         def Refresh(self):
       
  1450             global frame
       
  1451             if frame is not None:
       
  1452                 frame._Refresh(TITLE, POUINSTANCEVARIABLESPANEL, FILEMENU, EDITMENU)
       
  1453                 frame.RefreshEditor()
       
  1454                 frame.RefreshAll()
       
  1455         
       
  1456         def Close(self):
       
  1457             global frame
       
  1458             
       
  1459             self.CTR.ResetAppFrame(self.Log)
       
  1460             if frame is not None:
       
  1461                 frame.Hide()
       
  1462         
       
  1463         def Compile(self):
       
  1464             self.CTR._Build()
       
  1465         
       
  1466         def SetProjectProperties(self, projectname, productname, productversion, companyname):
       
  1467             properties = self.CTR.GetProjectProperties()
       
  1468             new_properties = properties.copy()
       
  1469             new_properties["projectName"] = projectname
       
  1470             new_properties["productName"] = productname
       
  1471             new_properties["productVersion"] = productversion
       
  1472             new_properties["companyName"] = companyname
       
  1473             if new_properties != properties:
       
  1474                 self.CTR.SetProjectProperties(properties=new_properties, buffer=False)
       
  1475                 self.RestartTimer()
       
  1476         
       
  1477         def SetOnlineMode(self, mode, path=None):
       
  1478             self.CTR.SetOnlineMode(mode, path)
       
  1479             self.RestartTimer()
       
  1480         
       
  1481         def AddBus(self, iec_channel, name, icon=None):
       
  1482             for child in self.CTR.IterChildren():
       
  1483                 if child.BaseParams.getName() == name:
       
  1484                     return "Error: A bus named %s already exists\n" % name
       
  1485                 elif child.BaseParams.getIEC_Channel() == iec_channel:
       
  1486                     return "Error: A bus with IEC_channel %d already exists\n" % iec_channel
       
  1487             bus = self.CTR.CTNAddChild(name, "LPCBus", iec_channel)
       
  1488             if bus is None:
       
  1489                 return "Error: Unable to create bus\n"
       
  1490             bus.SetIcon(icon)
       
  1491             self.RestartTimer()
       
  1492         
       
  1493         def RenameBus(self, iec_channel, name):
       
  1494             bus = self.CTR.GetChildByIECLocation((iec_channel,))
       
  1495             if bus is None:
       
  1496                 return "Error: No bus found\n"
       
  1497             for child in self.CTR.IterChildren():
       
  1498                 if child != bus and child.BaseParams.getName() == name:
       
  1499                     return "Error: A bus named %s already exists\n" % name
       
  1500             bus.BaseParams.setName(name)
       
  1501             self.RestartTimer()
       
  1502         
       
  1503         def ChangeBusIECChannel(self, old_iec_channel, new_iec_channel):
       
  1504             bus = self.CTR.GetChildByIECLocation((old_iec_channel,))
       
  1505             if bus is None:
       
  1506                 return "Error: No bus found\n"
       
  1507             for child in self.CTR.IterChildren():
       
  1508                 if child != bus and child.BaseParams.getIEC_Channel() == new_iec_channel:
       
  1509                     return "Error: A bus with IEC_channel %d already exists\n" % new_iec_channel
       
  1510             if wx.GetApp() is None:
       
  1511                 self.CTR.UpdateProjectVariableLocation(str(old_iec_channel), 
       
  1512                                                               str(new_iec_channel))
       
  1513             else:
       
  1514                 self.CTR.UpdateProjectVariableLocation(
       
  1515                              str(old_iec_channel), 
       
  1516                              str(new_iec_channel))
       
  1517             bus.BaseParams.setIEC_Channel(new_iec_channel)
       
  1518             self.RestartTimer()
       
  1519         
       
  1520         def RemoveBus(self, iec_channel):
       
  1521             bus = self.CTR.GetChildByIECLocation((iec_channel,))
       
  1522             if bus is None:
       
  1523                 return "Error: No bus found\n"
       
  1524             self.CTR.RemoveProjectVariableByFilter(str(iec_channel))
       
  1525             self.CTR.Children["LPCBus"].remove(bus)
       
  1526             self.RestartTimer()
       
  1527     
       
  1528         def AddModule(self, parent, iec_channel, name, icode, icon=None):
       
  1529             module = self.CTR.GetChildByIECLocation(parent)
       
  1530             if module is None:
       
  1531                 return "Error: No parent found\n"
       
  1532             for child in _GetModuleChildren(module):
       
  1533                 if child["name"] == name:
       
  1534                     return "Error: A module named %s already exists\n" % name
       
  1535                 elif child["IEC_Channel"] == iec_channel:
       
  1536                     return "Error: A module with IEC_channel %d already exists\n" % iec_channel 
       
  1537             _GetLastModuleGroup(module).append({"name": name, 
       
  1538                                                 "type": LOCATION_MODULE, 
       
  1539                                                 "IEC_Channel": iec_channel, 
       
  1540                                                 "icon": icon, 
       
  1541                                                 "init": icode, 
       
  1542                                                 "children": []})
       
  1543             self.RestartTimer()
       
  1544     
       
  1545         def RenameModule(self, iec_location, name):
       
  1546             module = self.CTR.GetChildByIECLocation(iec_location)
       
  1547             if module is None:
       
  1548                 return "Error: No module found\n"
       
  1549             parent = self.CTR.GetChildByIECLocation(iec_location[:-1])
       
  1550             if parent is self.CTR:
       
  1551                 return "Error: No module found\n"
       
  1552             if module["name"] != name:
       
  1553                 for child in _GetModuleChildren(parent):
       
  1554                     if child["name"] == name:
       
  1555                         return "Error: A module named %s already exists\n" % name
       
  1556                 module["name"] = name
       
  1557             self.RestartTimer()
       
  1558     
       
  1559         def ChangeModuleIECChannel(self, old_iec_location, new_iec_channel):
       
  1560             module = self.CTR.GetChildByIECLocation(old_iec_location)
       
  1561             if module is None:
       
  1562                 return "Error: No module found\n"
       
  1563             parent = self.CTR.GetChildByIECLocation(old_iec_location[:-1])
       
  1564             if parent is self.CTR:
       
  1565                 return "Error: No module found\n"
       
  1566             if module["IEC_Channel"] != new_iec_channel:
       
  1567                 for child in _GetModuleChildren(parent):
       
  1568                     if child["IEC_Channel"] == new_iec_channel:
       
  1569                         return "Error: A module with IEC_channel %d already exists\n" % new_iec_channel
       
  1570             self.CTR.UpdateProjectVariableLocation(".".join(map(str, old_iec_location)), ".".join(map(str, old_iec_location[:1] + (new_iec_channel,))))
       
  1571             module["IEC_Channel"] = new_iec_channel
       
  1572             self.RestartTimer()
       
  1573         
       
  1574         def ChangeModuleInitCode(self, iec_location, icode):
       
  1575             module = self.CTR.GetChildByIECLocation(iec_location)
       
  1576             if module is None:
       
  1577                 return "Error: No module found\n"
       
  1578             module["init"] = icode
       
  1579         
       
  1580         def RemoveModule(self, parent, iec_channel):
       
  1581             module = self.CTR.GetChildByIECLocation(parent)
       
  1582             if module is None:
       
  1583                 return "Error: No parent found\n"
       
  1584             child = _GetModuleBySomething(module, "IEC_Channel", (iec_channel,))
       
  1585             if child is None:
       
  1586                 return "Error: No module found\n"
       
  1587             self.CTR.RemoveProjectVariableByFilter(".".join(map(str, parent + (iec_channel,))))
       
  1588             _RemoveModuleChild(module, child)
       
  1589             self.RestartTimer()
       
  1590         
       
  1591         def StartGroup(self, parent, name, icon=None):
       
  1592             module = self.CTR.GetChildByIECLocation(parent)
       
  1593             if module is None:
       
  1594                 return "Error: No parent found\n"
       
  1595             for child in module["children"]:
       
  1596                 if child["type"] == LOCATION_GROUP and child["name"] == name:
       
  1597                     return "Error: A group named %s already exists\n" % name
       
  1598             module["children"].append({"name": name, 
       
  1599                                       "type": LOCATION_GROUP, 
       
  1600                                       "icon": icon, 
       
  1601                                       "children": []})
       
  1602             self.RestartTimer()
       
  1603     
       
  1604         def AddVariable(self, parent, location, name, direction, type, rcode, pcode, description=""):
       
  1605             module = self.CTR.GetChildByIECLocation(parent)
       
  1606             if module is None:
       
  1607                 return "Error: No parent found\n"
       
  1608             for child in _GetModuleChildren(module):
       
  1609                 if child["name"] == name:
       
  1610                     return "Error: A variable named %s already exists\n" % name
       
  1611                 if child["location"] == location and child["type"] == LOCATION_TYPES[direction]:
       
  1612                     return "Error: A variable with location %s already exists\n" % ".".join(map(str, location))
       
  1613             _GetLastModuleGroup(module).append({"name": name, 
       
  1614                                                 "location": location, 
       
  1615                                                 "type": LOCATION_TYPES[direction], 
       
  1616                                                 "IEC_type": type, 
       
  1617                                                 "description": description, 
       
  1618                                                 "retrieve": rcode, 
       
  1619                                                 "publish": pcode})
       
  1620             self.RestartTimer()
       
  1621 
       
  1622         def ChangeVariableParams(self, parent, location, new_name, new_direction, new_type, new_rcode, new_pcode, new_description=None):
       
  1623             module = self.CTR.GetChildByIECLocation(parent)
       
  1624             if module is None:
       
  1625                 return "Error: No parent found\n"
       
  1626             variable = None
       
  1627             for child in _GetModuleChildren(module):
       
  1628                 if child["location"] == location and child["type"] == LOCATION_TYPES[new_direction]:
       
  1629                     variable = child
       
  1630                 elif child["name"] == new_name:
       
  1631                     return "Error: A variable named %s already exists\n" % new_name
       
  1632             if variable is None:
       
  1633                 return "Error: No variable found\n"
       
  1634             if variable["name"] != new_name:
       
  1635                 self.CTR.UpdateProjectVariableName(variable["name"], new_name)
       
  1636                 variable["name"] = new_name
       
  1637             variable["type"] = LOCATION_TYPES[new_direction]
       
  1638             variable["IEC_type"] = new_type
       
  1639             variable["retrieve"] = new_rcode
       
  1640             variable["publish"] = new_pcode
       
  1641             if new_description is not None:
       
  1642                 variable["description"] = new_description
       
  1643             self.RestartTimer()
       
  1644     
       
  1645         def RemoveVariable(self, parent, location, direction):
       
  1646             module = self.CTR.GetChildByIECLocation(parent)
       
  1647             if module is None:
       
  1648                 return "Error: No parent found\n"
       
  1649             child = _GetModuleVariable(module, location, direction)
       
  1650             if child is None:
       
  1651                 return "Error: No variable found\n"
       
  1652             size = LOCATION_SIZES[self.CTR.GetBaseType(child["IEC_type"])]
       
  1653             address = "%" + LOCATION_DIRS[child["type"]] + size + ".".join(map(str, parent + location))
       
  1654             self.CTR.RemoveProjectVariableByAddress(address)
       
  1655             _RemoveModuleChild(module, child)
       
  1656             self.RestartTimer()
       
  1657         
       
  1658     def location(loc):
       
  1659         return tuple(map(int, loc.split(".")))
       
  1660     
       
  1661     def GetCmdFunction(function, arg_types, opt=0):
       
  1662         arg_number = len(arg_types)
       
  1663         def CmdFunction(self, line):
       
  1664             args_toks = line.split('"')
       
  1665             if len(args_toks) % 2 == 0:
       
  1666                 self.Log.write("Error: Invalid command\n")
       
  1667                 sys.stdout.flush()
       
  1668                 return
       
  1669             args = []
       
  1670             for num, arg in enumerate(args_toks):
       
  1671                 if num % 2 == 0:
       
  1672                     stripped = arg.strip()
       
  1673                     if stripped:
       
  1674                         args.extend(stripped.split(" "))
       
  1675                 else:
       
  1676                     args.append(arg)
       
  1677             number = None
       
  1678             extra = ""
       
  1679             if opt == 0 and len(args) != arg_number:
       
  1680                 number = arg_number
       
  1681             elif len(args) > arg_number:
       
  1682                 number = arg_number
       
  1683                 extra = " at most"
       
  1684             elif len(args) < arg_number - opt:
       
  1685                 number = arg_number - opt
       
  1686                 extra = " at least"
       
  1687             if number is not None:
       
  1688                 if number == 0:
       
  1689                     self.Log.write("Error: No argument%s expected\n" % extra)
       
  1690                 elif number == 1:
       
  1691                     self.Log.write("Error: 1 argument%s expected\n" % extra)
       
  1692                 else:
       
  1693                     self.Log.write("Error: %d arguments%s expected\n" % (number, extra))
       
  1694                 sys.stdout.flush()
       
  1695                 return
       
  1696             for num, arg in enumerate(args):
       
  1697                 try:
       
  1698                     args[num] = arg_types[num](arg)
       
  1699                 except:
       
  1700                     self.Log.write("Error: Invalid value for argument %d\n" % (num + 1))
       
  1701                     sys.stdout.flush()
       
  1702                     return
       
  1703 
       
  1704             func = getattr(self, function)
       
  1705             res = evaluator(func,*args)
       
  1706 
       
  1707             if BMZ_DBG:
       
  1708                 cmdlog.append((function,line,res))
       
  1709                 if len(cmdlog) > 100: #prevent debug log to grow too much
       
  1710                     cmdlog.pop(0) 
       
  1711 
       
  1712             if isinstance(res, (StringType, UnicodeType)):
       
  1713                 self.Log.write(res)
       
  1714                 return False
       
  1715             else:
       
  1716                 return res
       
  1717         return CmdFunction
       
  1718 
       
  1719     def CmdThreadProc(CTR, Log):
       
  1720         global lpcberemiz_cmd
       
  1721         for function, (arg_types, opt) in {"Exit": ([], 0),
       
  1722                                            "Show": ([], 0),
       
  1723                                            "Refresh": ([], 0),
       
  1724                                            "Close": ([], 0),
       
  1725                                            "Compile": ([], 0),
       
  1726                                            "SetProjectProperties": ([str, str, str, str], 0),
       
  1727                                            "SetOnlineMode": ([str, str], 1),
       
  1728                                            "AddBus": ([int, str, str], 1),
       
  1729                                            "RenameBus": ([int, str], 0),
       
  1730                                            "ChangeBusIECChannel": ([int, int], 0),
       
  1731                                            "RemoveBus": ([int], 0),
       
  1732                                            "AddModule": ([location, int, str, str, str], 1), 
       
  1733                                            "RenameModule": ([location, str], 0),
       
  1734                                            "ChangeModuleIECChannel": ([location, int], 0),
       
  1735                                            "ChangeModuleInitCode": ([location, str], 0),
       
  1736                                            "RemoveModule": ([location, int], 0),
       
  1737                                            "StartGroup": ([location, str, str], 1),
       
  1738                                            "AddVariable": ([location, location, str, str, str, str, str, str], 1),
       
  1739                                            "ChangeVariableParams": ([location, location, str, str, str, str, str, str], 1),
       
  1740                                            "RemoveVariable": ([location, location], 0)}.iteritems():
       
  1741             
       
  1742             setattr(LPCBeremiz_Cmd, "do_%s" % function, GetCmdFunction(function, arg_types, opt))
       
  1743         lpcberemiz_cmd = LPCBeremiz_Cmd(CTR, Log)
       
  1744         lpcberemiz_cmd.cmdloop()
       
  1745 
       
  1746     Log = StdoutPseudoFile(port)
       
  1747 
       
  1748     CTR = LPCProjectController(None, Log, buildpath)
       
  1749     if projectOpen is not None and os.path.isdir(projectOpen):
       
  1750         result = CTR.LoadProject(projectOpen)
       
  1751         if result:
       
  1752             Log.write("Error: Invalid project directory", result)
       
  1753     else:
       
  1754         Log.write("Error: No such file or directory")
       
  1755     
       
  1756     cmd_thread=Thread(target=CmdThreadProc, args=[CTR, Log])
       
  1757     cmd_thread.start()
       
  1758 
       
  1759     # Install a exception handle for bug reports
       
  1760     AddExceptHook(os.getcwd(),__version__)
       
  1761     
       
  1762     frame = LPCBeremiz(None, ctr=CTR, debug=True)
       
  1763     
       
  1764     app.MainLoop()
       
  1765