--- a/ProjectController.py Tue May 13 00:43:06 2014 +0200
+++ b/ProjectController.py Wed May 21 18:43:54 2014 +0200
@@ -1,5 +1,5 @@
"""
-Beremiz Project Controller
+Beremiz Project Controller
"""
import os,sys,traceback
import time
@@ -63,14 +63,14 @@
class ProjectController(ConfigTreeNode, PLCControler):
"""
- This class define Root object of the confnode tree.
+ This class define Root object of the confnode tree.
It is responsible of :
- Managing project directory
- Building project
- Handling PLCOpenEditor controler and view
- Loading user confnodes and instanciante them as children
- ...
-
+
"""
# For root object, available Children Types are modules of the confnode packages.
@@ -92,7 +92,7 @@
<xsd:complexType>
"""+"\n".join(['<xsd:attribute name='+
'"Enable_'+ libname + '_Library" '+
- 'type="xsd:boolean" use="optional" default="true"/>'
+ 'type="xsd:boolean" use="optional" default="true"/>'
for libname,lib in features.libraries])+"""
</xsd:complexType>""") if len(features.libraries)>0 else '<xsd:complexType/>') + """
</xsd:element>
@@ -104,7 +104,7 @@
</xsd:schema>
"""
EditorType = ProjectNodeEditor
-
+
def __init__(self, frame, logger):
PLCControler.__init__(self)
@@ -115,10 +115,10 @@
self.DebugValuesBuffers = []
self.DebugTicks = []
self.SetAppFrame(frame, logger)
-
+
self.iec2c_path = os.path.join(base_folder, "matiec", "iec2c"+(".exe" if wx.Platform == '__WXMSW__' else ""))
self.ieclib_path = os.path.join(base_folder, "matiec", "lib")
-
+
# Setup debug information
self.IECdebug_datas = {}
self.IECdebug_lock = Lock()
@@ -147,7 +147,7 @@
if self.DebugTimer:
self.DebugTimer.cancel()
self.KillDebugThread()
-
+
def LoadLibraries(self):
self.Libraries = []
TypeStack=[]
@@ -156,7 +156,7 @@
Lib = GetClassImporter(clsname)()(self, libname, TypeStack)
TypeStack.append(Lib.GetTypes())
self.Libraries.append(Lib)
-
+
def SetAppFrame(self, frame, logger):
self.AppFrame = frame
self.logger = logger
@@ -164,23 +164,23 @@
if self.DispatchDebugValuesTimer is not None:
self.DispatchDebugValuesTimer.Stop()
self.DispatchDebugValuesTimer = None
-
+
if frame is not None:
-
+
# Timer to pull PLC status
self.StatusTimer = wx.Timer(self.AppFrame, -1)
- self.AppFrame.Bind(wx.EVT_TIMER,
+ self.AppFrame.Bind(wx.EVT_TIMER,
self.PullPLCStatusProc, self.StatusTimer)
if self._connector is not None:
frame.LogViewer.SetLogSource(self._connector)
self.StatusTimer.Start(milliseconds=500, oneShot=False)
-
+
# Timer to dispatch debug values to consumers
self.DispatchDebugValuesTimer = wx.Timer(self.AppFrame, -1)
- self.AppFrame.Bind(wx.EVT_TIMER,
+ self.AppFrame.Bind(wx.EVT_TIMER,
self.DispatchDebugValuesProc, self.DispatchDebugValuesTimer)
-
+
self.RefreshConfNodesBlockLists()
def ResetAppFrame(self, logger):
@@ -188,7 +188,7 @@
self.AppFrame.Unbind(wx.EVT_TIMER, self.StatusTimer)
self.StatusTimer = None
self.AppFrame = None
-
+
self.logger = logger
def CTNName(self):
@@ -205,16 +205,16 @@
def GetIECLibPath(self):
return self.ieclib_path
-
+
def GetIEC2cPath(self):
return self.iec2c_path
-
+
def GetCurrentLocation(self):
return ()
def GetCurrentName(self):
return ""
-
+
def _GetCurrentName(self):
return ""
@@ -223,10 +223,10 @@
def GetProjectName(self):
return os.path.split(self.ProjectPath)[1]
-
+
def GetIconName(self):
return "PROJECT"
-
+
def GetDefaultTargetName(self):
if wx.Platform == '__WXMSW__':
return "Win32"
@@ -242,15 +242,15 @@
target_name = self.GetDefaultTargetName()
target.setcontent(self.Parser.CreateElement(target_name, "TargetType"))
return target
-
+
def GetParamsAttributes(self, path = None):
params = ConfigTreeNode.GetParamsAttributes(self, path)
if params[0]["name"] == "BeremizRoot":
for child in params[0]["children"]:
if child["name"] == "TargetType" and child["value"] == '':
- child.update(self.GetTarget().getElementInfos("TargetType"))
+ child.update(self.GetTarget().getElementInfos("TargetType"))
return params
-
+
def SetParamsAttribute(self, path, value):
if path.startswith("BeremizRoot.TargetType.") and self.BeremizRoot.getTargetType().getcontent() is None:
self.BeremizRoot.setTargetType(self.GetTarget())
@@ -258,15 +258,15 @@
if path.startswith("BeremizRoot.Libraries."):
wx.CallAfter(self.RefreshConfNodesBlockLists)
return res
-
+
# helper func to check project path write permission
def CheckProjectPathPerm(self, dosave=True):
if CheckPathPerm(self.ProjectPath):
return True
if self.AppFrame is not None:
- dialog = wx.MessageDialog(self.AppFrame,
+ dialog = wx.MessageDialog(self.AppFrame,
_('You must have permission to work on the project\nWork on a project copy ?'),
- _('Error'),
+ _('Error'),
wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
answer = dialog.ShowModal()
dialog.Destroy()
@@ -277,7 +277,7 @@
self.AppFrame.RefreshPageTitles()
return True
return False
-
+
def _getProjectFilesPath(self, project_path=None):
if project_path is not None:
return os.path.join(project_path, "project_files")
@@ -285,7 +285,7 @@
if not os.path.exists(projectfiles_path):
os.mkdir(projectfiles_path)
return projectfiles_path
-
+
def AddProjectDefaultConfiguration(self, config_name="config", res_name="resource1"):
self.ProjectAddConfiguration(config_name)
self.ProjectAddConfigurationResource(config_name, res_name)
@@ -299,7 +299,7 @@
# Verify that chosen folder is empty
if not os.path.isdir(ProjectPath) or len(os.listdir(ProjectPath)) > 0:
return _("Chosen folder isn't empty. You can't use it for a new project!")
-
+
# Create PLCOpen program
self.CreateNewProject(
{"projectName": _("Unnamed"),
@@ -308,7 +308,7 @@
"companyName": _("Unknown"),
"creationDateTime": datetime(*localtime()[:6])})
self.AddProjectDefaultConfiguration()
-
+
# Change XSD into class members
self._AddParamsMembers()
self.Children = {}
@@ -320,7 +320,7 @@
# this will create files base XML files
self.SaveProject()
return None
-
+
def LoadProject(self, ProjectPath, BuildPath=None):
"""
Load a project contained in a folder
@@ -357,30 +357,30 @@
#Load and init all the children
self.LoadChildren()
self.RefreshConfNodesBlockLists()
-
+
if os.path.exists(self._getBuildPath()):
self.EnableMethod("_Clean", True)
if os.path.isfile(self._getIECcodepath()):
self.ShowMethod("_showIECcode", True)
-
+
self.UpdateMethodsFromPLCStatus()
-
+
return None
-
+
def RecursiveConfNodeInfos(self, confnode):
values = []
for CTNChild in confnode.IECSortedChildren():
values.append(
{"name": "%s: %s" % (CTNChild.GetFullIEC_Channel(),
- CTNChild.CTNName()),
+ CTNChild.CTNName()),
"tagname": CTNChild.CTNFullName(),
- "type": ITEM_CONFNODE,
+ "type": ITEM_CONFNODE,
"confnode": CTNChild,
"icon": CTNChild.GetIconName(),
"values": self.RecursiveConfNodeInfos(CTNChild)})
return values
-
+
def GetProjectInfos(self):
infos = PLCControler.GetProjectInfos(self)
configurations = infos["values"].pop(-1)
@@ -394,23 +394,23 @@
infos["values"].append(resources)
infos["values"].extend(self.RecursiveConfNodeInfos(self))
return infos
-
+
def CloseProject(self):
self.ClearChildren()
self.ResetAppFrame(None)
-
+
def SaveProject(self, from_project_path=None):
if self.CheckProjectPathPerm(False):
if from_project_path is not None:
old_projectfiles_path = self._getProjectFilesPath(from_project_path)
if os.path.isdir(old_projectfiles_path):
- shutil.copytree(old_projectfiles_path,
+ shutil.copytree(old_projectfiles_path,
self._getProjectFilesPath(self.ProjectPath))
self.SaveXMLFile(os.path.join(self.ProjectPath, 'plc.xml'))
result = self.CTNRequestSave(from_project_path)
if result:
self.logger.write_error(result)
-
+
def SaveProjectAs(self):
# Ask user to choose a path with write permissions
if wx.Platform == '__WXMSW__':
@@ -444,12 +444,12 @@
LocatedCCodeAndFlags=[]
Extras=[]
for lib in self.Libraries:
- res=lib.Generate_C(buildpath,self._VariablesList,LibIECCflags)
+ res=lib.Generate_C(buildpath,self._VariablesList,LibIECCflags)
LocatedCCodeAndFlags.append(res[:2])
if len(res)>2:
Extras.extend(res[2:])
return map(list,zip(*LocatedCCodeAndFlags))+[tuple(Extras)]
-
+
# Update PLCOpenEditor ConfNode Block types from loaded confnodes
def RefreshConfNodesBlockLists(self):
if getattr(self, "Children", None) is not None:
@@ -458,7 +458,7 @@
if self.AppFrame is not None:
self.AppFrame.RefreshLibraryPanel()
self.AppFrame.RefreshEditor()
-
+
# Update a PLCOpenEditor Pou variable location
def UpdateProjectVariableLocation(self, old_leading, new_leading):
self.Project.updateElementAddress(old_leading, new_leading)
@@ -469,13 +469,13 @@
self.AppFrame.RefreshFileMenu()
self.AppFrame.RefreshEditMenu()
wx.CallAfter(self.AppFrame.RefreshEditor)
-
+
def GetVariableLocationTree(self):
'''
This function is meant to be overridden by confnodes.
It should returns an list of dictionaries
-
+
- IEC_type is an IEC type like BOOL/BYTE/SINT/...
- location is a string of this variable's location, like "%IX0.0.0"
'''
@@ -483,13 +483,13 @@
for child in self.IECSortedChildren():
children.append(child.GetVariableLocationTree())
return children
-
+
def ConfNodePath(self):
return os.path.split(__file__)[0]
-
+
def CTNPath(self, CTNName=None):
return self.ProjectPath
-
+
def ConfNodeXmlFilePath(self, CTNName=None):
return os.path.join(self.CTNPath(CTNName), "beremiz.xml")
@@ -515,26 +515,26 @@
# Create a build path in temp folder
else:
self.DefaultBuildPath = os.path.join(tempfile.mkdtemp(), os.path.basename(self.ProjectPath), "build")
-
+
if not os.path.exists(self.DefaultBuildPath):
os.makedirs(self.DefaultBuildPath)
return self.DefaultBuildPath
-
+
def _getExtraFilesPath(self):
return os.path.join(self._getBuildPath(), "extra_files")
def _getIECcodepath(self):
# define name for IEC code file
return os.path.join(self._getBuildPath(), "plc.st")
-
+
def _getIECgeneratedcodepath(self):
# define name for IEC generated code file
return os.path.join(self._getBuildPath(), "generated_plc.st")
-
+
def _getIECrawcodepath(self):
# define name for IEC raw code file
return os.path.join(self.CTNPath(), "raw_plc.st")
-
+
def GetLocations(self):
locations = []
filepath = os.path.join(self._getBuildPath(),"LOCATED_VARIABLES.h")
@@ -546,24 +546,29 @@
# This regular expression parses the lines genereated by IEC2C
LOCATED_MODEL = re.compile("__LOCATED_VAR\((?P<IEC_TYPE>[A-Z]*),(?P<NAME>[_A-Za-z0-9]*),(?P<DIR>[QMI])(?:,(?P<SIZE>[XBWDL]))?,(?P<LOC>[,0-9]*)\)")
for line in lines:
- # If line match RE,
+ # If line match RE,
result = LOCATED_MODEL.match(line)
if result:
# Get the resulting dict
resdict = result.groupdict()
# rewrite string for variadic location as a tuple of integers
resdict['LOC'] = tuple(map(int,resdict['LOC'].split(',')))
- # set located size to 'X' if not given
+ # set located size to 'X' if not given
if not resdict['SIZE']:
resdict['SIZE'] = 'X'
# finally store into located variable list
locations.append(resdict)
return locations
-
+
def GetConfNodeGlobalInstances(self):
return self._GlobalInstances()
-
+
def _Generate_SoftPLC(self):
+ if self._Generate_PLC_ST():
+ return self._Compile_ST_to_SoftPLC()
+ return False
+
+ def _Generate_PLC_ST(self):
"""
Generate SoftPLC ST/IL/SFC code out of PLCOpenEditor controller, and compile it with IEC2C
@param buildpath: path where files should be created
@@ -571,9 +576,8 @@
# Update PLCOpenEditor ConfNode Block types before generate ST code
self.RefreshConfNodesBlockLists()
-
+
self.logger.write(_("Generating SoftPLC IEC-61131 ST/IL/SFC code...\n"))
- buildpath = self._getBuildPath()
# ask PLCOpenEditor controller to write ST/IL/SFC code file
program, errors, warnings = self.GenerateProgram(self._getIECgeneratedcodepath())
if len(warnings) > 0:
@@ -599,22 +603,25 @@
plc_file = open(self._getIECcodepath(), "a")
plc_file.write(open(self._getIECgeneratedcodepath(), "r").read())
plc_file.close()
-
+ return True
+
+ def _Compile_ST_to_SoftPLC(self):
self.logger.write(_("Compiling IEC Program into C code...\n"))
+ buildpath = self._getBuildPath()
# Now compile IEC code into many C files
- # files are listed to stdout, and errors to stderr.
+ # files are listed to stdout, and errors to stderr.
status, result, err_result = ProcessLogger(
self.logger,
"\"%s\" -f -I \"%s\" -T \"%s\" \"%s\""%(
self.iec2c_path,
- self.ieclib_path,
+ self.ieclib_path,
buildpath,
self._getIECcodepath()),
no_stdout=True, no_stderr=True).spin()
if status:
# Failed !
-
+
# parse iec2c's error message. if it contains a line number,
# then print those lines from the generated IEC file.
for err_line in err_result.split('\n'):
@@ -624,7 +631,7 @@
if m_result is not None:
first_line, first_column, last_line, last_column, error = m_result.groups()
first_line, last_line = int(first_line), int(last_line)
-
+
last_section = None
f = open(self._getIECcodepath())
@@ -640,10 +647,10 @@
self.logger.write_warning("%04d: %s" % (i, line))
f.close()
-
+
self.logger.write_error(_("Error : IEC to C compiler returned %d\n")%status)
return False
-
+
# Now extract C files of stdout
C_files = [ fname for fname in result.splitlines() if fname[-2:]==".c" or fname[-2:]==".C" ]
# remove those that are not to be compiled because included by others
@@ -679,7 +686,7 @@
targetname = self.GetTarget().getcontent().getLocalTag()
targetclass = targets.GetBuilder(targetname)
- # if target already
+ # if target already
if self._builder is None or not isinstance(self._builder,targetclass):
# Get classname instance
self._builder = targetclass(self)
@@ -703,20 +710,20 @@
# C CODE GENERATION METHODS
#
#######################################################################
-
+
def CTNGenerate_C(self, buildpath, locations):
"""
- Return C code generated by iec2c compiler
+ Return C code generated by iec2c compiler
when _generate_softPLC have been called
@param locations: ignored
@return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND
"""
- return ([(C_file_name, self.plcCFLAGS)
- for C_file_name in self.PLCGeneratedCFiles ],
+ return ([(C_file_name, self.plcCFLAGS)
+ for C_file_name in self.PLCGeneratedCFiles ],
"", # no ldflags
False) # do not expose retreive/publish calls
-
+
def ResetIECProgramsAndVariables(self):
"""
Reset variable and program list that are parsed from
@@ -743,7 +750,7 @@
self._ProgramList = []
self._VariablesList = []
self._IECPathToIdx = {}
-
+
# Separate sections
ListGroup = []
for line in open(csvfile,'r').xreadlines():
@@ -754,7 +761,7 @@
elif len(strippedline) > 0 and len(ListGroup) > 0:
# append to this section
ListGroup[-1].append(strippedline)
-
+
# first section contains programs
for line in ListGroup[0]:
# Split and Maps each field to dictionnary entries
@@ -763,7 +770,7 @@
attrs["C_path"] = '__'.join(attrs["C_path"].split(".",2)[1:])
# Push this dictionnary into result.
self._ProgramList.append(attrs)
-
+
# second section contains all variables
config_FBs = {}
for line in ListGroup[1]:
@@ -776,7 +783,7 @@
if config_FB:
parts = [config_FB] + parts[2:]
attrs["C_path"] = '.'.join(parts)
- else:
+ else:
attrs["C_path"] = '__'.join(parts[1:])
else:
attrs["C_path"] = '__'.join(parts)
@@ -788,11 +795,11 @@
IEC_path=attrs["IEC_path"]
Idx=int(attrs["num"])
self._IECPathToIdx[IEC_path]=(Idx, attrs["type"])
-
+
# third section contains ticktime
if len(ListGroup) > 2:
- self._Ticktime = int(ListGroup[2][0])
-
+ self._Ticktime = int(ListGroup[2][0])
+
except Exception,e:
self.logger.write_error(_("Cannot open/parse VARIABLES.csv!\n"))
self.logger.write_error(traceback.format_exc())
@@ -818,7 +825,7 @@
"MEM":"extern __IEC_%(type)s_p %(C_path)s;",
"OUT":"extern __IEC_%(type)s_p %(C_path)s;",
"VAR":"extern __IEC_%(type)s_t %(C_path)s;",
- "FB":"extern %(type)s %(C_path)s;"}[v["vartype"]]%v
+ "FB":"extern %(type)s %(C_path)s;"}[v["vartype"]]%v
for v in self._VariablesList if v["C_path"].find('.')<0]),
"for_each_variable_do_code":"\n".join([
{"EXT":" (*fp)((void*)&(%(C_path)s),%(type)s_P_ENUM);\n",
@@ -836,9 +843,9 @@
"OUT":" return %(type)s_O_ENUM;\n",
"VAR":" return %(type)s_ENUM;\n"}[v["vartype"]]%v
for v in self._VariablesList if v["vartype"] != "FB" and v["type"] in DebugTypesSize ])}
-
+
return debug_code
-
+
def Generate_plc_main(self):
"""
Use confnodes layout given in LocationCFilesAndCFLAGS to
@@ -848,7 +855,7 @@
# in retreive, publish, init, cleanup
locstrs = map(lambda x:"_".join(map(str,x)),
[loc for loc,Cfiles,DoCalls in self.LocationCFilesAndCFLAGS if loc and DoCalls])
-
+
# Generate main, based on template
if not self.BeremizRoot.getDisable_Extensions():
plc_main_code = targets.GetCode("plc_main_head") % {
@@ -882,7 +889,7 @@
plc_main_code += targets.GetCode("plc_main_tail")
return plc_main_code
-
+
def _Build(self):
"""
Method called by user to (re)build SoftPLC and confnode tree
@@ -890,7 +897,7 @@
if self.AppFrame is not None:
self.AppFrame.ClearErrors()
self._CloseView(self._IECCodeView)
-
+
buildpath = self._getBuildPath()
# Eventually create build dir
@@ -908,21 +915,52 @@
# If IEC code gen fail, bail out.
if not IECGenRes:
- self.logger.write_error(_("IEC-61131-3 code generation failed !\n"))
+ self.logger.write_error(_("PLC code generation failed !\n"))
self.ResetBuildMD5()
return False
# Reset variable and program list that are parsed from
# CSV file generated by IEC2C compiler.
self.ResetIECProgramsAndVariables()
-
+
+ # Collect platform specific C code
+ # Code and other files from extension
+ if not self._Generate_runtime():
+ return False
+
+ # Get current or fresh builder
+ builder = self.GetBuilder()
+ if builder is None:
+ self.logger.write_error(_("Fatal : cannot get builder.\n"))
+ self.ResetBuildMD5()
+ return False
+
+ # Build
+ try:
+ if not builder.build() :
+ self.logger.write_error(_("C Build failed.\n"))
+ return False
+ except Exception, exc:
+ self.logger.write_error(_("C Build crashed !\n"))
+ self.logger.write_error(traceback.format_exc())
+ self.ResetBuildMD5()
+ return False
+
+ self.logger.write(_("Successfully built.\n"))
+ # Update GUI status about need for transfer
+ self.CompareLocalAndRemotePLC()
+ return True
+
+ def _Generate_runtime(self):
+ buildpath = self._getBuildPath()
+
# Generate C code and compilation params from confnode hierarchy
try:
CTNLocationCFilesAndCFLAGS, CTNLDFLAGS, CTNExtraFiles = self._Generate_C(
- buildpath,
+ buildpath,
self.PLCGeneratedLocatedVars)
except Exception, exc:
- self.logger.write_error(_("Runtime extensions C code generation failed !\n"))
+ self.logger.write_error(_("Runtime IO extensions C code generation failed !\n"))
self.logger.write_error(traceback.format_exc())
self.ResetBuildMD5()
return False
@@ -931,7 +969,7 @@
try:
LibCFilesAndCFLAGS, LibLDFLAGS, LibExtraFiles = self.GetLibrariesCCode(buildpath)
except Exception, exc:
- self.logger.write_error(_("Runtime extensions C code generation failed !\n"))
+ self.logger.write_error(_("Runtime library extensions C code generation failed !\n"))
self.logger.write_error(traceback.format_exc())
self.ResetBuildMD5()
return False
@@ -939,7 +977,7 @@
self.LocationCFilesAndCFLAGS = CTNLocationCFilesAndCFLAGS + LibCFilesAndCFLAGS
self.LDFLAGS = CTNLDFLAGS + LibLDFLAGS
ExtraFiles = CTNExtraFiles + LibExtraFiles
-
+
# Get temporary directory path
extrafilespath = self._getExtraFilesPath()
# Remove old directory
@@ -953,7 +991,7 @@
open(fpath, "wb").write(fobject.read())
# Now we can forget ExtraFiles (will close files object)
del ExtraFiles
-
+
# Header file for extensions
open(os.path.join(buildpath,"beremiz.h"), "w").write(targets.GetHeader())
@@ -978,32 +1016,9 @@
self.logger.write_error(traceback.format_exc())
self.ResetBuildMD5()
return False
-
self.logger.write(_("C code generated successfully.\n"))
-
- # Get current or fresh builder
- builder = self.GetBuilder()
- if builder is None:
- self.logger.write_error(_("Fatal : cannot get builder.\n"))
- self.ResetBuildMD5()
- return False
-
- # Build
- try:
- if not builder.build() :
- self.logger.write_error(_("C Build failed.\n"))
- return False
- except Exception, exc:
- self.logger.write_error(_("C Build crashed !\n"))
- self.logger.write_error(traceback.format_exc())
- self.ResetBuildMD5()
- return False
-
- self.logger.write(_("Successfully built.\n"))
- # Update GUI status about need for transfer
- self.CompareLocalAndRemotePLC()
return True
-
+
def ShowError(self, logger, from_location, to_location):
chunk_infos = self.GetChunkInfos(from_location, to_location)
for infos, (start_row, start_col) in chunk_infos:
@@ -1011,7 +1026,7 @@
end = (to_location[0] - start_row, to_location[1] - start_col)
if self.AppFrame is not None:
self.AppFrame.ShowError(infos, start, end)
-
+
_IECCodeView = None
def _showIECcode(self):
self._OpenView("IEC code")
@@ -1019,20 +1034,20 @@
_IECRawCodeView = None
def _editIECrawcode(self):
self._OpenView("IEC raw code")
-
+
_ProjectFilesView = None
def _OpenProjectFiles(self):
self._OpenView("Project Files")
-
+
_FileEditors = {}
def _OpenFileEditor(self, filepath):
self._OpenView(filepath)
-
+
def _OpenView(self, name=None, onlyopened=False):
if name == "IEC code":
if self._IECCodeView is None:
plc_file = self._getIECcodepath()
-
+
self._IECCodeView = IECCodeViewer(self.AppFrame.TabsOpened, "", self.AppFrame, None, instancepath=name)
self._IECCodeView.SetTextSyntax("ALL")
self._IECCodeView.SetKeywords(IEC_KEYWORDS)
@@ -1043,78 +1058,78 @@
self._IECCodeView.SetText(text = text)
self._IECCodeView.SetIcon(GetBitmap("ST"))
setattr(self._IECCodeView, "_OnClose", self.OnCloseEditor)
-
+
if self._IECCodeView is not None:
self.AppFrame.EditProjectElement(self._IECCodeView, name)
-
+
return self._IECCodeView
-
+
elif name == "IEC raw code":
if self._IECRawCodeView is None:
controler = MiniTextControler(self._getIECrawcodepath(), self)
-
+
self._IECRawCodeView = IECCodeViewer(self.AppFrame.TabsOpened, "", self.AppFrame, controler, instancepath=name)
self._IECRawCodeView.SetTextSyntax("ALL")
self._IECRawCodeView.SetKeywords(IEC_KEYWORDS)
self._IECRawCodeView.RefreshView()
self._IECRawCodeView.SetIcon(GetBitmap("ST"))
setattr(self._IECRawCodeView, "_OnClose", self.OnCloseEditor)
-
+
if self._IECRawCodeView is not None:
self.AppFrame.EditProjectElement(self._IECRawCodeView, name)
-
+
return self._IECRawCodeView
-
+
elif name == "Project Files":
if self._ProjectFilesView is None:
self._ProjectFilesView = FileManagementPanel(self.AppFrame.TabsOpened, self, name, self._getProjectFilesPath(), True)
-
+
extensions = []
for extension, name, editor in features.file_editors:
if extension not in extensions:
extensions.append(extension)
- self._ProjectFilesView.SetEditableFileExtensions(extensions)
-
+ self._ProjectFilesView.SetEditableFileExtensions(extensions)
+
if self._ProjectFilesView is not None:
self.AppFrame.EditProjectElement(self._ProjectFilesView, name)
-
+
return self._ProjectFilesView
-
+
elif name is not None and name.find("::") != -1:
filepath, editor_name = name.split("::")
if not self._FileEditors.has_key(filepath):
if os.path.isfile(filepath):
file_extension = os.path.splitext(filepath)[1]
-
+
editors = dict([(edit_name, edit_class)
for extension, edit_name, edit_class in features.file_editors
if extension == file_extension])
-
+
if editor_name == "":
if len(editors) == 1:
editor_name = editors.keys()[0]
elif len(editors) > 0:
names = editors.keys()
- dialog = wx.SingleChoiceDialog(self.AppFrame,
- _("Select an editor:"), _("Editor selection"),
+ dialog = wx.SingleChoiceDialog(self.AppFrame,
+ _("Select an editor:"), _("Editor selection"),
names, wx.DEFAULT_DIALOG_STYLE|wx.OK|wx.CANCEL)
if dialog.ShowModal() == wx.ID_OK:
editor_name = names[dialog.GetSelection()]
dialog.Destroy()
-
+
if editor_name != "":
name = "::".join([filepath, editor_name])
-
+
editor = editors[editor_name]()
self._FileEditors[filepath] = editor(self.AppFrame.TabsOpened, self, name, self.AppFrame)
self._FileEditors[filepath].SetIcon(GetBitmap("FILE"))
if isinstance(self._FileEditors[filepath], DebugViewer):
self._FileEditors[filepath].SetDataProducer(self)
-
+
if self._FileEditors.has_key(filepath):
editor = self._FileEditors[filepath]
self.AppFrame.EditProjectElement(editor, editor.GetTagName())
-
+
return self._FileEditors.get(filepath)
else:
return ConfigTreeNode._OpenView(self, self.CTNName(), onlyopened)
@@ -1147,7 +1162,7 @@
if log_count:
if self.AppFrame is not None:
self.AppFrame.LogViewer.SetLogCounters(log_count)
-
+
def UpdateMethodsFromPLCStatus(self):
status = None
if self._connector is not None:
@@ -1184,16 +1199,16 @@
self.AppFrame.ConnectionStatusBar.SetStatusText(
_("Connected to URI: %s") % self.BeremizRoot.getURI_location().strip(), 1)
self.AppFrame.ConnectionStatusBar.SetStatusText(_(status), 2)
-
+
def PullPLCStatusProc(self, event):
self.UpdateMethodsFromPLCStatus()
-
+
def SnapshotAndResetDebugValuesBuffers(self):
- buffers, self.DebugValuesBuffers = (self.DebugValuesBuffers,
+ buffers, self.DebugValuesBuffers = (self.DebugValuesBuffers,
[list() for iec_path in self.TracedIECPath])
ticks, self.DebugTicks = self.DebugTicks, []
return ticks, buffers
-
+
def RegisterDebugVarToConnector(self):
self.DebugTimer=None
Idxs = []
@@ -1208,10 +1223,10 @@
# This variable is not needed anymore!
IECPathsToPop.append(IECPath)
elif IECPath != "__tick__":
- # Convert
+ # Convert
Idx, IEC_Type = self._IECPathToIdx.get(IECPath,(None,None))
if Idx is not None:
- if IEC_Type in DebugTypesSize:
+ if IEC_Type in DebugTypesSize:
Idxs.append((Idx, IEC_Type, fvalue, IECPath))
else:
self.logger.write_warning(_("Debug: Unsupported type to debug '%s'\n")%IEC_Type)
@@ -1229,14 +1244,14 @@
self._connector.SetTraceVariablesList([])
self.SnapshotAndResetDebugValuesBuffers()
self.IECdebug_lock.release()
-
+
def IsPLCStarted(self):
return self.previous_plcstate == "Started"
-
+
def ReArmDebugRegisterTimer(self):
if self.DebugTimer is not None:
self.DebugTimer.cancel()
-
+
# Prevent to call RegisterDebugVarToConnector when PLC is not started
# If an output location var is forced it's leads to segmentation fault in runtime
# Links between PLC located variables and real variables are not ready
@@ -1250,16 +1265,16 @@
def GetDebugIECVariableType(self, IECPath):
Idx, IEC_Type = self._IECPathToIdx.get(IECPath,(None,None))
return IEC_Type
-
+
def SubscribeDebugIECVariable(self, IECPath, callableobj, buffer_list=False, *args, **kwargs):
"""
Dispatching use a dictionnary linking IEC variable paths
- to a WeakKeyDictionary linking
+ to a WeakKeyDictionary linking
weakly referenced callables to optionnal args
"""
if IECPath != "__tick__" and not self._IECPathToIdx.has_key(IECPath):
return None
-
+
self.IECdebug_lock.acquire()
# If no entry exist, create a new one with a fresh WeakKeyDictionary
IECdebug_data = self.IECdebug_datas.get(IECPath, None)
@@ -1273,13 +1288,13 @@
self.IECdebug_datas[IECPath] = IECdebug_data
else:
IECdebug_data[4] |= buffer_list
-
+
IECdebug_data[0][callableobj]=(buffer_list, args, kwargs)
self.IECdebug_lock.release()
-
+
self.ReArmDebugRegisterTimer()
-
+
return IECdebug_data[1]
def UnsubscribeDebugIECVariable(self, IECPath, callableobj):
@@ -1292,7 +1307,7 @@
else:
IECdebug_data[4] = reduce(
lambda x, y: x|y,
- [buffer_list for buffer_list,args,kwargs
+ [buffer_list for buffer_list,args,kwargs
in IECdebug_data[0].itervalues()],
False)
self.IECdebug_lock.release()
@@ -1309,33 +1324,33 @@
def ForceDebugIECVariable(self, IECPath, fvalue):
if not self.IECdebug_datas.has_key(IECPath):
return
-
+
self.IECdebug_lock.acquire()
-
+
# If no entry exist, create a new one with a fresh WeakKeyDictionary
IECdebug_data = self.IECdebug_datas.get(IECPath, None)
IECdebug_data[2] = "Forced"
IECdebug_data[3] = fvalue
-
+
self.IECdebug_lock.release()
-
+
self.ReArmDebugRegisterTimer()
-
+
def ReleaseDebugIECVariable(self, IECPath):
if not self.IECdebug_datas.has_key(IECPath):
return
-
+
self.IECdebug_lock.acquire()
-
+
# If no entry exist, create a new one with a fresh WeakKeyDictionary
IECdebug_data = self.IECdebug_datas.get(IECPath, None)
IECdebug_data[2] = "Registered"
IECdebug_data[3] = None
-
+
self.IECdebug_lock.release()
-
+
self.ReArmDebugRegisterTimer()
-
+
def CallWeakcallables(self, IECPath, function_name, *cargs):
data_tuple = self.IECdebug_datas.get(IECPath, None)
if data_tuple is not None:
@@ -1415,7 +1430,7 @@
self.CallWeakcallables(IECPath, "NewValues", debug_ticks, values)
if len(debug_ticks) > 0:
self.CallWeakcallables("__tick__", "NewDataAvailable", debug_ticks)
-
+
delay = time.time() - start_time
next_refresh = max(REFRESH_PERIOD - delay, 0.2 * delay)
if self.DispatchDebugValuesTimer is not None and self.DebugThread is not None:
@@ -1437,7 +1452,7 @@
if self.DispatchDebugValuesTimer is not None:
self.DispatchDebugValuesTimer.Stop()
- def _connect_debug(self):
+ def _connect_debug(self):
self.previous_plcstate = None
if self.AppFrame:
self.AppFrame.ResetGraphicViewers()
@@ -1448,7 +1463,7 @@
if self.DebugThread is None:
self.DebugThread = Thread(target=self.DebugThreadProc)
self.DebugThread.start()
-
+
def _Run(self):
"""
Start PLC
@@ -1460,7 +1475,7 @@
else:
self.logger.write_error(_("Couldn't start PLC !\n"))
wx.CallAfter(self.UpdateMethodsFromPLCStatus)
-
+
def _Stop(self):
"""
Stop PLC
@@ -1470,7 +1485,7 @@
# debugthread should die on his own
#self.KillDebugThread()
-
+
wx.CallAfter(self.UpdateMethodsFromPLCStatus)
def _SetConnector(self, connector, update_status=True):
@@ -1493,7 +1508,7 @@
if self._connector is not None:
self.logger.write_error(_("Already connected. Please disconnect\n"))
return
-
+
# Get connector uri
uri = self.\
BeremizRoot.\
@@ -1512,7 +1527,7 @@
self.logger.write_error(_("Local service discovery failed!\n"))
self.logger.write_error(traceback.format_exc())
uri = None
-
+
# Nothing choosed or cancel button
if uri is None or answer == wx.ID_CANCEL:
self.logger.write_error(_("Connection canceled!\n"))
@@ -1529,7 +1544,7 @@
self.AppFrame.RefreshFileMenu()
self.AppFrame.RefreshEditMenu()
self.AppFrame.RefreshPageTitles()
-
+
# Get connector from uri
try:
self._SetConnector(connectors.ConnectorFactory(uri, self))
@@ -1547,7 +1562,7 @@
self.ShowMethod("_Transfer", True)
self.CompareLocalAndRemotePLC()
-
+
# Init with actual PLC status and print it
self.UpdateMethodsFromPLCStatus()
if self.previous_plcstate is not None:
@@ -1556,7 +1571,7 @@
status = ""
#self.logger.write(_("PLC is %s\n")%status)
-
+
if self.previous_plcstate in ["Started","Stopped"]:
if self.DebugAvailable() and self.GetIECProgramsAndVariables():
self.logger.write(_("Debugger ready\n"))
@@ -1590,12 +1605,12 @@
def _Disconnect(self):
self._SetConnector(None)
-
+
def _Transfer(self):
- # Get the last build PLC's
+ # Get the last build PLC's
MD5 = self.GetLastBuildMD5()
-
- # Check if md5 file is empty : ask user to build PLC
+
+ # Check if md5 file is empty : ask user to build PLC
if MD5 is None :
self.logger.write_error(_("Failed : Must build before transfer.\n"))
return False
@@ -1609,12 +1624,12 @@
extrafiles = []
for extrafilespath in [self._getExtraFilesPath(),
self._getProjectFilesPath()]:
-
+
extrafiles.extend(
- [(name, open(os.path.join(extrafilespath, name),
+ [(name, open(os.path.join(extrafilespath, name),
'rb').read()) \
for name in os.listdir(extrafilespath)])
-
+
# Send PLC on target
builder = self.GetBuilder()
if builder is not None: