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