# HG changeset patch # User 'Laurent Bessard ' # Date 1253527928 -7200 # Node ID 31d08063b5d67f36b9a859a7a308c7d215bd5aae # Parent 6a7ff66a811da38a8b87bb5b86a5e78ab79b017a# Parent 9b1801ef99b5ae70379e9b7b5c1ccdaf70b72f71 Changes merged diff -r 9b1801ef99b5 -r 31d08063b5d6 Beremiz.py --- a/Beremiz.py Fri Sep 18 14:58:22 2009 +0200 +++ b/Beremiz.py Mon Sep 21 12:12:08 2009 +0200 @@ -66,7 +66,6 @@ app = wx.PySimpleApp() app.SetAppName('beremiz') - config = wx.ConfigBase.Get() wx.InitAllImageHandlers() bmp = wx.Image(Bpath("images","splash.png")).ConvertToBitmap() @@ -100,15 +99,20 @@ if __name__ == '__main__': __builtin__.__dict__['_'] = wx.GetTranslation#unicode_translation +#Quick hack to be able to find Beremiz IEC tools. Should be config params. +base_folder = os.path.split(sys.path[0])[0] +sys.path.append(base_folder) +sys.path.append(os.path.join(base_folder, "plcopeneditor")) +sys.path.append(os.path.join(base_folder, "docutils")) + import wx.lib.buttons, wx.lib.statbmp import TextCtrlAutoComplete, cPickle import types, time, re, platform, time, traceback, commands from plugger import PluginsRoot, MATIEC_ERROR_MODEL from wxPopen import ProcessLogger -base_folder = os.path.split(sys.path[0])[0] -sys.path.append(base_folder) from docutils import * +from PLCOpenEditor import IDEFrame, Viewer, AppendMenu, TITLE, TOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU, TYPESTREE, INSTANCESTREE, LIBRARYTREE, SCALING SCROLLBAR_UNIT = 10 WINDOW_COLOUR = wx.Colour(240,240,240) @@ -279,61 +283,43 @@ ID_BEREMIZRUNMENURUN, ID_BEREMIZRUNMENUSAVELOG, ] = [wx.NewId() for _init_coll_EditMenu_Items in range(4)] -class Beremiz(wx.Frame): +class Beremiz(IDEFrame): def _init_coll_FileMenu_Items(self, parent): - parent.Append(help='', id=wx.ID_NEW, + AppendMenu(parent, help='', id=wx.ID_NEW, kind=wx.ITEM_NORMAL, text=_(u'New\tCTRL+N')) - parent.Append(help='', id=wx.ID_OPEN, + AppendMenu(parent, help='', id=wx.ID_OPEN, kind=wx.ITEM_NORMAL, text=_(u'Open\tCTRL+O')) - parent.Append(help='', id=wx.ID_SAVE, + AppendMenu(parent, help='', id=wx.ID_SAVE, kind=wx.ITEM_NORMAL, text=_(u'Save\tCTRL+S')) - parent.Append(help='', id=wx.ID_CLOSE_ALL, + AppendMenu(parent, help='', id=wx.ID_CLOSE, + kind=wx.ITEM_NORMAL, text=_(u'Close Tab\tCTRL+W')) + AppendMenu(parent, help='', id=wx.ID_CLOSE_ALL, kind=wx.ITEM_NORMAL, text=_(u'Close Project')) parent.AppendSeparator() - parent.Append(help='', id=wx.ID_PROPERTIES, + AppendMenu(parent, help='', id=wx.ID_PAGE_SETUP, + kind=wx.ITEM_NORMAL, text=_(u'Page Setup')) + AppendMenu(parent, help='', id=wx.ID_PREVIEW, + kind=wx.ITEM_NORMAL, text=_(u'Preview')) + AppendMenu(parent, help='', id=wx.ID_PRINT, + kind=wx.ITEM_NORMAL, text=_(u'Print')) + parent.AppendSeparator() + AppendMenu(parent, help='', id=wx.ID_PROPERTIES, kind=wx.ITEM_NORMAL, text=_(u'Properties')) parent.AppendSeparator() - parent.Append(help='', id=wx.ID_EXIT, + AppendMenu(parent, help='', id=wx.ID_EXIT, kind=wx.ITEM_NORMAL, text=_(u'Quit\tCTRL+Q')) + self.Bind(wx.EVT_MENU, self.OnNewProjectMenu, id=wx.ID_NEW) self.Bind(wx.EVT_MENU, self.OnOpenProjectMenu, id=wx.ID_OPEN) self.Bind(wx.EVT_MENU, self.OnSaveProjectMenu, id=wx.ID_SAVE) + self.Bind(wx.EVT_MENU, self.OnCloseTabMenu, id=wx.ID_CLOSE) self.Bind(wx.EVT_MENU, self.OnCloseProjectMenu, id=wx.ID_CLOSE_ALL) + self.Bind(wx.EVT_MENU, self.OnPageSetupMenu, id=wx.ID_PAGE_SETUP) + self.Bind(wx.EVT_MENU, self.OnPreviewMenu, id=wx.ID_PREVIEW) + self.Bind(wx.EVT_MENU, self.OnPrintMenu, id=wx.ID_PRINT) self.Bind(wx.EVT_MENU, self.OnPropertiesMenu, id=wx.ID_PROPERTIES) self.Bind(wx.EVT_MENU, self.OnQuitMenu, id=wx.ID_EXIT) - - def _init_coll_EditMenu_Items(self, parent): - parent.Append(help='', id=wx.ID_EDIT, - kind=wx.ITEM_NORMAL, text=_(u'Edit PLC\tCTRL+R')) - parent.AppendSeparator() - parent.Append(help='', id=wx.ID_ADD, - kind=wx.ITEM_NORMAL, text=_(u'Add Plugin')) - parent.Append(help='', id=wx.ID_DELETE, - kind=wx.ITEM_NORMAL, text=_(u'Delete Plugin')) - self.Bind(wx.EVT_MENU, self.OnEditPLCMenu, id=wx.ID_EDIT) - self.Bind(wx.EVT_MENU, self.OnAddMenu, id=wx.ID_ADD) - self.Bind(wx.EVT_MENU, self.OnDeleteMenu, id=wx.ID_DELETE) - - def _init_coll_RunMenu_Items(self, parent): - parent.Append(help='', id=ID_BEREMIZRUNMENUBUILD, - kind=wx.ITEM_NORMAL, text=_(u'Build\tCTRL+R')) - parent.AppendSeparator() - parent.Append(help='', id=ID_BEREMIZRUNMENUSIMULATE, - kind=wx.ITEM_NORMAL, text=_(u'Simulate')) - parent.Append(help='', id=ID_BEREMIZRUNMENURUN, - kind=wx.ITEM_NORMAL, text=_(u'Run')) - parent.AppendSeparator() - parent.Append(help='', id=ID_BEREMIZRUNMENUSAVELOG, - kind=wx.ITEM_NORMAL, text=_(u'Save Log')) - self.Bind(wx.EVT_MENU, self.OnBuildMenu, - id=ID_BEREMIZRUNMENUBUILD) - self.Bind(wx.EVT_MENU, self.OnSimulateMenu, - id=ID_BEREMIZRUNMENUSIMULATE) - self.Bind(wx.EVT_MENU, self.OnRunMenu, - id=ID_BEREMIZRUNMENURUN) - self.Bind(wx.EVT_MENU, self.OnSaveLogMenu, - id=ID_BEREMIZRUNMENUSAVELOG) def _init_coll_HelpMenu_Items(self, parent): parent.Append(help='', id=wx.ID_HELP, @@ -343,25 +329,6 @@ self.Bind(wx.EVT_MENU, self.OnBeremizMenu, id=wx.ID_HELP) self.Bind(wx.EVT_MENU, self.OnAboutMenu, id=wx.ID_ABOUT) - def _init_coll_MenuBar_Menus(self, parent): - parent.Append(menu=self.FileMenu, title=_(u'File')) - #parent.Append(menu=self.EditMenu, title=u'Edit') - #parent.Append(menu=self.RunMenu, title=u'Run') - parent.Append(menu=self.HelpMenu, title=_(u'Help')) - - def _init_utils(self): - self.MenuBar = wx.MenuBar() - self.FileMenu = wx.Menu(title=u'') - #self.EditMenu = wx.Menu(title=u'') - #self.RunMenu = wx.Menu(title=u'') - self.HelpMenu = wx.Menu(title=u'') - - self._init_coll_MenuBar_Menus(self.MenuBar) - self._init_coll_FileMenu_Items(self.FileMenu) - #self._init_coll_EditMenu_Items(self.EditMenu) - #self._init_coll_RunMenu_Items(self.RunMenu) - self._init_coll_HelpMenu_Items(self.HelpMenu) - def _init_coll_PLCConfigMainSizer_Items(self, parent): parent.AddSizer(self.PLCParamsSizer, 0, border=10, flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT) parent.AddSizer(self.PluginTreeSizer, 0, border=10, flag=wx.BOTTOM|wx.LEFT|wx.RIGHT) @@ -374,7 +341,7 @@ parent.AddGrowableCol(0) parent.AddGrowableCol(1) - def _init_sizers(self): + def _init_beremiz_sizers(self): self.PLCConfigMainSizer = wx.FlexGridSizer(cols=1, hgap=2, rows=2, vgap=2) self.PLCParamsSizer = wx.BoxSizer(wx.VERTICAL) #self.PluginTreeSizer = wx.FlexGridSizer(cols=3, hgap=0, rows=0, vgap=2) @@ -387,82 +354,68 @@ self.PLCConfig.SetSizer(self.PLCConfigMainSizer) def _init_ctrls(self, prnt): - wx.Frame.__init__(self, id=ID_BEREMIZ, name=u'Beremiz', - parent=prnt, pos=wx.Point(0, 0), size=wx.Size(1000, 600), - style=wx.DEFAULT_FRAME_STYLE|wx.CLIP_CHILDREN, title=_(u'Beremiz')) - self._init_utils() - self.SetClientSize(wx.Size(1000, 600)) - self.SetMenuBar(self.MenuBar) - self.Bind(wx.EVT_ACTIVATE, self.OnFrameActivated) - self.Bind(wx.EVT_CLOSE, self.OnCloseFrame) - + IDEFrame._init_ctrls(self, prnt) + self.Bind(wx.EVT_MENU, self.OnOpenWidgetInspector, id=ID_BEREMIZINSPECTOR) accel = wx.AcceleratorTable([wx.AcceleratorEntry(wx.ACCEL_CTRL|wx.ACCEL_ALT, ord('I'), ID_BEREMIZINSPECTOR)]) self.SetAcceleratorTable(accel) - if wx.VERSION < (2, 8, 0): - self.MainSplitter = wx.SplitterWindow(id=ID_BEREMIZMAINSPLITTER, - name='MainSplitter', parent=self, point=wx.Point(0, 0), - size=wx.Size(0, 0), style=wx.SP_3D) - self.MainSplitter.SetNeedUpdating(True) - self.MainSplitter.SetMinimumPaneSize(1) - - parent = self.MainSplitter - else: - parent = self - self.PLCConfig = wx.ScrolledWindow(id=ID_BEREMIZPLCCONFIG, - name='PLCConfig', parent=parent, pos=wx.Point(0, 0), + name='PLCConfig', parent=self.LeftNoteBook, pos=wx.Point(0, 0), size=wx.Size(-1, -1), style=wx.TAB_TRAVERSAL|wx.SUNKEN_BORDER|wx.HSCROLL|wx.VSCROLL) self.PLCConfig.SetBackgroundColour(wx.WHITE) self.PLCConfig.Bind(wx.EVT_LEFT_DOWN, self.OnPanelLeftDown) self.PLCConfig.Bind(wx.EVT_SIZE, self.OnMoveWindow) + self.LeftNoteBook.AddPage(self.PLCConfig, _("Topology")) self.LogConsole = wx.TextCtrl(id=ID_BEREMIZLOGCONSOLE, value='', - name='LogConsole', parent=parent, pos=wx.Point(0, 0), + name='LogConsole', parent=self.BottomNoteBook, pos=wx.Point(0, 0), size=wx.Size(0, 0), style=wx.TE_MULTILINE|wx.TE_RICH2) self.LogConsole.Bind(wx.EVT_LEFT_DCLICK, self.OnLogConsoleDClick) - - if wx.VERSION < (2, 8, 0): - self.MainSplitter.SplitHorizontally(self.PLCConfig, self.LogConsole, -250) - else: - self.AUIManager = wx.aui.AuiManager(self) - self.AUIManager.SetDockSizeConstraint(0.5, 0.5) - - self.AUIManager.AddPane(self.PLCConfig, wx.aui.AuiPaneInfo().CenterPane()) - - self.AUIManager.AddPane(self.LogConsole, wx.aui.AuiPaneInfo(). - Caption(_("Log Console")).Bottom().Layer(1). - BestSize(wx.Size(800, 200)).CloseButton(False)) - - self.AUIManager.Update() - - self._init_sizers() - - def __init__(self, parent, projectOpen, buildpath): - self._init_ctrls(parent) + self.BottomNoteBook.AddPage(self.LogConsole, _("Log Console")) + + self._init_beremiz_sizers() + + def __init__(self, parent, projectOpen, buildpath, debug=True): + IDEFrame.__init__(self, parent, debug) + self.Config = wx.ConfigBase.Get() self.Log = LogPseudoFile(self.LogConsole) - + self.local_runtime = None self.runtime_port = None self.local_runtime_tmpdir = None - # Add beremiz's icon in top left corner of the frame - self.SetIcon(wx.Icon(Bpath( "images", "brz.ico"), wx.BITMAP_TYPE_ICO)) - self.DisableEvents = False self.PluginInfos = {} if projectOpen: self.PluginRoot = PluginsRoot(self, self.Log) + self.Controler = self.PluginRoot self.PluginRoot.LoadProject(projectOpen, buildpath) + self._Refresh(TYPESTREE, INSTANCESTREE, LIBRARYTREE) self.RefreshAll() else: self.PluginRoot = None - - self.RefreshMainMenu() + self.Controler = None + + # Add beremiz's icon in top left corner of the frame + self.SetIcon(wx.Icon(Bpath( "images", "brz.ico"), wx.BITMAP_TYPE_ICO)) + + self.Bind(wx.EVT_CLOSE, self.OnCloseFrame) + + self._Refresh(TITLE, TOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU) + + def RefreshTitle(self): + name = _("Beremiz") + if self.PluginRoot is not None: + projectname = self.PluginRoot.GetProjectName() + if self.PluginRoot.PlugTestModified(): + projectname = "~%s~" % projectname + self.SetTitle("%s - %s" % (name, projectname)) + else: + self.SetTitle(name) def StartLocalRuntime(self, taskbaricon = True): if self.local_runtime is None or self.local_runtime.finished: @@ -544,29 +497,45 @@ self.RefreshScrollBars() event.Skip() - def OnFrameActivated(self, event): - if not event.GetActive() and self.PluginRoot is not None: - self.PluginRoot.RefreshPluginsBlockLists() - def OnPanelLeftDown(self, event): focused = self.FindFocus() if isinstance(focused, TextCtrlAutoComplete.TextCtrlAutoComplete): focused._showDropDown(False) event.Skip() - def RefreshMainMenu(self): + def RefreshFileMenu(self): if self.PluginRoot is not None: -## self.MenuBar.EnableTop(1, True) -## self.MenuBar.EnableTop(2, True) + selected = self.TabsOpened.GetSelection() + if selected >= 0: + graphic_viewer = isinstance(self.TabsOpened.GetPage(selected), Viewer) + else: + graphic_viewer = False + if self.TabsOpened.GetPageCount() > 0: + self.FileMenu.Enable(wx.ID_CLOSE, True) + if graphic_viewer: + self.FileMenu.Enable(wx.ID_PREVIEW, True) + self.FileMenu.Enable(wx.ID_PRINT, True) + else: + self.FileMenu.Enable(wx.ID_PREVIEW, False) + self.FileMenu.Enable(wx.ID_PRINT, False) + else: + self.FileMenu.Enable(wx.ID_CLOSE, False) + self.FileMenu.Enable(wx.ID_PREVIEW, False) + self.FileMenu.Enable(wx.ID_PRINT, False) + self.FileMenu.Enable(wx.ID_PAGE_SETUP, True) self.FileMenu.Enable(wx.ID_SAVE, True) + self.FileMenu.Enable(wx.ID_PROPERTIES, True) self.FileMenu.Enable(wx.ID_CLOSE_ALL, True) - self.FileMenu.Enable(wx.ID_PROPERTIES, True) + self.FileMenu.Enable(wx.ID_SAVEAS, True) else: -## self.MenuBar.EnableTop(1, False) -## self.MenuBar.EnableTop(2, False) + self.FileMenu.Enable(wx.ID_CLOSE, False) + self.FileMenu.Enable(wx.ID_PAGE_SETUP, False) + self.FileMenu.Enable(wx.ID_PREVIEW, False) + self.FileMenu.Enable(wx.ID_PRINT, False) self.FileMenu.Enable(wx.ID_SAVE, False) + self.FileMenu.Enable(wx.ID_PROPERTIES, False) self.FileMenu.Enable(wx.ID_CLOSE_ALL, False) - self.FileMenu.Enable(wx.ID_PROPERTIES, False) + self.FileMenu.Enable(wx.ID_SAVEAS, False) def RefreshScrollBars(self): xstart, ystart = self.PLCConfig.GetViewStart() @@ -1225,7 +1194,7 @@ spinctrl.SetValue(element_infos["value"]) spinctrl.Bind(wx.EVT_SPINCTRL, self.GetTextCtrlCallBackFunction(spinctrl, plugin, element_path), id=id) else: - choices = cPickle.loads(str(config.Read(element_path, cPickle.dumps([""])))) + choices = cPickle.loads(str(self.Config.Read(element_path, cPickle.dumps([""])))) textctrl = TextCtrlAutoComplete.TextCtrlAutoComplete(id=id, name=element_infos["name"], parent=parent, @@ -1240,60 +1209,63 @@ textctrl.Bind(wx.EVT_TEXT, self.GetTextCtrlCallBackFunction(textctrl, plugin, element_path)) first = False + def ResetView(self): + IDEFrame.ResetView(self) + self.PluginInfos = {} + self.PluginRoot = None + self.Log.flush() + self.DebugVariablePanel.SetDataProducer(None) + def OnNewProjectMenu(self, event): - if not config.HasEntry("lastopenedfolder"): + if not self.Config.HasEntry("lastopenedfolder"): defaultpath = os.path.expanduser("~") else: - defaultpath = config.Read("lastopenedfolder") + defaultpath = self.Config.Read("lastopenedfolder") dialog = wx.DirDialog(self , _("Choose a project"), defaultpath, wx.DD_NEW_DIR_BUTTON) if dialog.ShowModal() == wx.ID_OK: projectpath = dialog.GetPath() dialog.Destroy() - config.Write("lastopenedfolder", os.path.dirname(projectpath)) - config.Flush() - self.PluginInfos = {} - if self.PluginRoot is not None: - self.PluginRoot.CloseProject() + self.Config.Write("lastopenedfolder", os.path.dirname(projectpath)) + self.Config.Flush() + self.ResetView() self.PluginRoot = PluginsRoot(self, self.Log) - res = self.PluginRoot.NewProject(projectpath) - if not res : + self.Controler = self.PluginRoot + result = self.PluginRoot.NewProject(projectpath) + if not result: + self.DebugVariablePanel.SetDataProducer(self.PluginRoot) + self._Refresh(TYPESTREE, INSTANCESTREE, LIBRARYTREE) self.RefreshAll() - self.RefreshMainMenu() else: - message = wx.MessageDialog(self, res, _("ERROR"), wx.OK|wx.ICON_ERROR) - message.ShowModal() - message.Destroy() + self.ShowErrorMessage(result) + self._Refresh(TITLE, TOOLBAR, FILEMENU, EDITMENU) event.Skip() def OnOpenProjectMenu(self, event): - if not config.HasEntry("lastopenedfolder"): + if not self.Config.HasEntry("lastopenedfolder"): defaultpath = os.path.expanduser("~") else: - defaultpath = config.Read("lastopenedfolder") + defaultpath = self.Config.Read("lastopenedfolder") dialog = wx.DirDialog(self , _("Choose a project"), defaultpath, wx.DD_NEW_DIR_BUTTON) if dialog.ShowModal() == wx.ID_OK: projectpath = dialog.GetPath() if os.path.isdir(projectpath): - config.Write("lastopenedfolder", os.path.dirname(projectpath)) - config.Flush() - self.PluginInfos = {} - if self.PluginRoot is not None: - self.PluginRoot.CloseProject() + self.Config.Write("lastopenedfolder", os.path.dirname(projectpath)) + self.Config.Flush() + self.ResetView() self.PluginRoot = PluginsRoot(self, self.Log) + self.Controler = self.PluginRoot result = self.PluginRoot.LoadProject(projectpath) if not result: + self.DebugVariablePanel.SetDataProducer(self.PluginRoot) + self._Refresh(TYPESTREE, INSTANCESTREE, LIBRARYTREE) self.RefreshAll() - self.RefreshMainMenu() else: - message = wx.MessageDialog(self, result, _("Error"), wx.OK|wx.ICON_ERROR) - message.ShowModal() - message.Destroy() + self.ShowErrorMessage(result) else: - message = wx.MessageDialog(self, _("\"%s\" folder is not a valid Beremiz project\n")%projectpath, _("Error"), wx.OK|wx.ICON_ERROR) - message.ShowModal() - message.Destroy() + self.ShowErrorMessage(_("\"%s\" folder is not a valid Beremiz project\n") % projectpath) + self._Refresh(TITLE, TOOLBAR, FILEMENU, EDITMENU) dialog.Destroy() event.Skip() @@ -1310,18 +1282,16 @@ self.PluginRoot.SaveProject() elif answer == wx.ID_CANCEL: return - self.PluginInfos = {} - self.PluginRoot.CloseProject() - self.PluginRoot = None - self.Log.flush() + self.ResetView() + self._Refresh(TITLE, TOOLBAR, FILEMENU, EDITMENU) self.RefreshAll() - self.RefreshMainMenu() event.Skip() def OnSaveProjectMenu(self, event): if self.PluginRoot is not None: self.PluginRoot.SaveProject() self.RefreshAll() + self.RefreshTitle() event.Skip() def OnPropertiesMenu(self, event): @@ -1330,32 +1300,7 @@ def OnQuitMenu(self, event): self.Close() event.Skip() - - def OnEditPLCMenu(self, event): - self.EditPLC() - event.Skip() - - def OnAddMenu(self, event): - self.AddPlugin() - event.Skip() - - def OnDeleteMenu(self, event): - self.DeletePlugin() - event.Skip() - - def OnBuildMenu(self, event): - #self.BuildAutom() - event.Skip() - - def OnSimulateMenu(self, event): - event.Skip() - - def OnRunMenu(self, event): - event.Skip() - - def OnSaveLogMenu(self, event): - event.Skip() - + def OnBeremizMenu(self, event): open_pdf(Bpath( "doc", "manual_beremiz.pdf")) event.Skip() @@ -1364,16 +1309,6 @@ OpenHtmlFrame(self,_("About Beremiz"), Bpath("doc","about.html"), wx.Size(550, 500)) event.Skip() - def OnAddButton(self, event): - PluginType = self.PluginChilds.GetStringSelection() - if PluginType != "": - self.AddPlugin(PluginType) - event.Skip() - - def OnDeleteButton(self, event): - self.DeletePlugin() - event.Skip() - def GetAddButtonFunction(self, plugin, window): def AddButtonFunction(event): if plugin and len(plugin.PlugChildsTypes) > 0: @@ -1399,6 +1334,7 @@ PluginName = dialog.GetValue() plugin.PlugAddChild(PluginName, PluginType) self.RefreshPluginTree() + self.PluginRoot.RefreshPluginsBlockLists() dialog.Destroy() def DeletePlugin(self, plugin): @@ -1407,6 +1343,7 @@ self.PluginInfos.pop(plugin) plugin.PlugRemove() del plugin + self.PluginRoot.RefreshPluginsBlockLists() self.RefreshPluginTree() dialog.Destroy() diff -r 9b1801ef99b5 -r 31d08063b5d6 Beremiz_service.py --- a/Beremiz_service.py Fri Sep 18 14:58:22 2009 +0200 +++ b/Beremiz_service.py Mon Sep 21 12:12:08 2009 +0200 @@ -526,9 +526,9 @@ class PLCStoppedHMI(PLCHMI): docFactory = loaders.stan(tags.div(render=tags.directive('liveElement'))[ - tags.h1["PLC IS STOPPED"] + tags.h1["PLC IS STOPPED"], ]) - + class MainPage(athena.LiveElement): jsClass = u"WebInterface.PLC" docFactory = loaders.stan(tags.div(render=tags.directive('liveElement'))[ @@ -582,7 +582,7 @@ def detachFragmentChildren(self): for child in self.liveFragmentChildren[:]: child.detach() - + class WebInterface(athena.LivePage): docFactory = loaders.stan([tags.raw(xhtml_header), @@ -594,7 +594,7 @@ ]]]]) MainPage = MainPage() PLCHMI = PLCHMI - + def __init__(self, plcState=False, *a, **kw): super(WebInterface, self).__init__(*a, **kw) self.jsModules.mapping[u'WebInterface'] = util.sibpath(__file__, 'webinterface.js') @@ -645,7 +645,7 @@ self.MainPage.resetHMI() #print reason #print "We will be called back when the client disconnects" - + if havewx: reactor.registerWxApp(app) res = WebInterface() diff -r 9b1801ef99b5 -r 31d08063b5d6 discovery.py --- a/discovery.py Fri Sep 18 14:58:22 2009 +0200 +++ b/discovery.py Mon Sep 21 12:12:08 2009 +0200 @@ -27,188 +27,185 @@ import wx.lib.mixins.listctrl as listmix class AutoWidthListCtrl(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin): - def __init__(self, parent, ID, pos=wx.DefaultPosition, + def __init__(self, parent, id, name, pos=wx.DefaultPosition, size=wx.DefaultSize, style=0): - wx.ListCtrl.__init__(self, parent, ID, pos, size, style) + wx.ListCtrl.__init__(self, parent, id, pos, size, style, name=name) listmix.ListCtrlAutoWidthMixin.__init__(self) +[ID_DISCOVERYDIALOG, ID_DISCOVERYDIALOGSTATICTEXT1, + ID_DISCOVERYDIALOGSERVICESLIST, ID_DISCOVERYDIALOGREFRESHBUTTON, + ID_DISCOVERYDIALOGLOCALBUTTON, +] = [wx.NewId() for _init_ctrls in range(5)] + class DiscoveryDialog(wx.Dialog, listmix.ColumnSorterMixin): - def __init__(self, parent, id=-1, title=_('Service Discovery')): - self.my_result=None - wx.Dialog.__init__(self, parent, id, title, size=(600,600), style=wx.DEFAULT_DIALOG_STYLE) - - # set up dialog sizer - - sizer = wx.FlexGridSizer(2, 1, 2, 2) # rows, cols, vgap, hgap - sizer.AddGrowableRow(0) - sizer.AddGrowableCol(0) - - # set up list control - - self.list = AutoWidthListCtrl(self, -1, - #pos=(50,20), - #size=(500,300), - style=wx.LC_REPORT - | wx.LC_EDIT_LABELS - | wx.LC_SORT_ASCENDING - | wx.LC_SINGLE_SEL - ) - sizer.Add(self.list, 1, wx.EXPAND) - - btsizer = wx.FlexGridSizer(1, 6, 2, 2) # rows, cols, vgap, hgap - - sizer.Add(btsizer, 1, wx.EXPAND) - - self.PopulateList() - - self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected, self.list) - self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnItemActivated, self.list) - - # set up buttons - - local_id = wx.NewId() - b = wx.Button(self, local_id, _("Refresh")) - self.Bind(wx.EVT_BUTTON, self.OnRefreshButton, b) - btsizer.Add(b) - - btsizer.AddSpacer(0) - btsizer.AddGrowableCol(1) - - local_id = wx.NewId() - b = wx.Button(self, local_id, _("Local")) - self.Bind(wx.EVT_BUTTON, self.ChooseLocalID, b) - btsizer.Add(b) - - btsizer.AddSpacer(0) - btsizer.AddGrowableCol(3) - - b = wx.Button(self, wx.ID_CANCEL, _("Cancel")) - self.Bind(wx.EVT_BUTTON, self.OnCancel, b) - btsizer.Add(b) - - b = wx.Button(self, wx.ID_OK, _("OK")) - self.Bind(wx.EVT_BUTTON, self.OnOk, b) - b.SetDefault() - btsizer.Add(b) - - self.SetSizer(sizer) - + + def _init_coll_MainSizer_Items(self, parent): + parent.AddWindow(self.staticText1, 0, border=20, flag=wx.TOP|wx.LEFT|wx.RIGHT|wx.GROW) + parent.AddWindow(self.ServicesList, 0, border=20, flag=wx.LEFT|wx.RIGHT|wx.GROW) + parent.AddSizer(self.ButtonGridSizer, 0, border=20, flag=wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.GROW) + + def _init_coll_MainSizer_Growables(self, parent): + parent.AddGrowableCol(0) + parent.AddGrowableRow(1) + + def _init_coll_ButtonGridSizer_Items(self, parent): + parent.AddWindow(self.RefreshButton, 0, border=0, flag=0) + parent.AddWindow(self.LocalButton, 0, border=0, flag=0) + parent.AddSizer(self.ButtonSizer, 0, border=0, flag=0) + + def _init_coll_ButtonGridSizer_Growables(self, parent): + parent.AddGrowableCol(0) + parent.AddGrowableCol(1) + parent.AddGrowableRow(1) + + def _init_sizers(self): + self.MainSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=3, vgap=10) + self.ButtonGridSizer = wx.FlexGridSizer(cols=3, hgap=5, rows=1, vgap=0) + + self._init_coll_MainSizer_Items(self.MainSizer) + self._init_coll_MainSizer_Growables(self.MainSizer) + self._init_coll_ButtonGridSizer_Items(self.ButtonGridSizer) + self._init_coll_ButtonGridSizer_Growables(self.ButtonGridSizer) + + self.SetSizer(self.MainSizer) + + def _init_ctrls(self, prnt): + wx.Dialog.__init__(self, id=ID_DISCOVERYDIALOG, + name='DiscoveryDialog', parent=prnt, + size=wx.Size(600, 600), style=wx.DEFAULT_DIALOG_STYLE, + title='Service Discovery') + + self.staticText1 = wx.StaticText(id=ID_DISCOVERYDIALOGSTATICTEXT1, + label=_('Services available:'), name='staticText1', parent=self, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) + + # Set up list control + self.ServicesList = AutoWidthListCtrl(id=ID_DISCOVERYDIALOGSERVICESLIST, + name='ServicesList', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 0), + style=wx.LC_REPORT|wx.LC_EDIT_LABELS|wx.LC_SORT_ASCENDING|wx.LC_SINGLE_SEL) + self.ServicesList.InsertColumn(0, 'NAME') + self.ServicesList.InsertColumn(1, 'TYPE') + self.ServicesList.InsertColumn(2, 'IP') + self.ServicesList.InsertColumn(3, 'PORT') + self.ServicesList.SetColumnWidth(0, 150) + self.ServicesList.SetColumnWidth(1, 150) + self.ServicesList.SetColumnWidth(2, 150) + self.ServicesList.SetColumnWidth(3, 150) + self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected, id=ID_DISCOVERYDIALOGSERVICESLIST) + self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnItemActivated, id=ID_DISCOVERYDIALOGSERVICESLIST) + listmix.ColumnSorterMixin.__init__(self, 4) - - # Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py + + self.RefreshButton = wx.Button(id=ID_DISCOVERYDIALOGREFRESHBUTTON, + label=_('Refresh'), name='RefreshButton', parent=self, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) + self.Bind(wx.EVT_BUTTON, self.OnRefreshButton, id=ID_DISCOVERYDIALOGREFRESHBUTTON) + + self.LocalButton = wx.Button(id=ID_DISCOVERYDIALOGLOCALBUTTON, + label=_('Local'), name='LocalButton', parent=self, + pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) + self.Bind(wx.EVT_BUTTON, self.OnLocalButton, id=ID_DISCOVERYDIALOGLOCALBUTTON) + + self.ButtonSizer = self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.CENTER) + + self._init_sizers() + + def __init__(self, parent): + self._init_ctrls(parent) + self.itemDataMap = {} - - # a counter used to assign a unique id to each listctrl item self.nextItemId = 0 - - self.browser = None - self.zConfInstance = Zeroconf() + + self.URI = None + self.Browser = None + + self.ZeroConfInstance = Zeroconf() self.RefreshList() - - self.Bind(wx.EVT_CLOSE, self.OnClose) - + + def __del__(self): + self.Browser.cancel() + self.ZeroConfInstance.close() + def RefreshList(self): - type = "_PYRO._tcp.local." - self.browser = ServiceBrowser(self.zConfInstance, type, self) + self.Browser = ServiceBrowser(self.ZeroConfInstance, "_PYRO._tcp.local.", self) def OnRefreshButton(self, event): - self.list.DeleteAllItems() - self.browser.cancel() + self.ServicesList.DeleteAllItems() + self.Browser.cancel() self.RefreshList() - def OnClose(self, event): - self.zConfInstance.close() - event.Skip() - - def OnCancel(self, event): - self.zConfInstance.close() - event.Skip() - - def OnOk(self, event): - self.zConfInstance.close() + def OnLocalButton(self, event): + self.URI = "LOCAL://" + self.EndModal(wx.ID_OK) event.Skip() # Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py def GetListCtrl(self): - return self.list - - def PopulateList(self): - self.list.InsertColumn(0, 'NAME') - self.list.InsertColumn(1, 'TYPE') - self.list.InsertColumn(2, 'IP') - self.list.InsertColumn(3, 'PORT') - self.list.SetColumnWidth(0, 150) - self.list.SetColumnWidth(1, 150) - self.list.SetColumnWidth(2, 150) - self.list.SetColumnWidth(3, 150) + return self.ServicesList def getColumnText(self, index, col): - item = self.list.GetItem(index, col) + item = self.ServicesList.GetItem(index, col) return item.GetText() def OnItemSelected(self, event): - self.currentItem = event.m_itemIndex - self.setresult() + self.SetURI(event.m_itemIndex) event.Skip() def OnItemActivated(self, event): - self.currentItem = event.m_itemIndex - self.setresult() - self.Close() + self.SetURI(event.m_itemIndex) + self.EndModal(wx.ID_OK) event.Skip() - def setresult(self): - connect_type = self.getColumnText(self.currentItem, 1) - connect_address = self.getColumnText(self.currentItem, 2) - connect_port = self.getColumnText(self.currentItem, 3) - - uri = self.CreateURI(connect_type, connect_address, connect_port) - self.my_result=uri - - def GetResult(self): - return self.my_result + def SetURI(self, idx): + connect_type = self.getColumnText(idx, 1) + connect_address = self.getColumnText(idx, 2) + connect_port = self.getColumnText(idx, 3) + + self.URI = "%s://%s:%s"%(connect_type, connect_address, connect_port) + + def GetURI(self): + return self.URI def removeService(self, zeroconf, type, name): ''' called when a service with the desired type goes offline. ''' - + # loop through the list items looking for the service that went offline - for idx in xrange(self.list.GetItemCount()): + for idx in xrange(self.ServicesList.GetItemCount()): # this is the unique identifier assigned to the item - item_id = self.list.GetItemData(idx) + item_id = self.ServicesList.GetItemData(idx) # this is the full typename that was received by addService item_name = self.itemDataMap[item_id][4] if item_name == name: - self.list.DeleteItem(idx) + self.ServicesList.DeleteItem(idx) break - + def addService(self, zeroconf, type, name): ''' called when a service with the desired type is discovered. ''' - - info = self.zConfInstance.getServiceInfo(type, name) + info = self.ZeroConfInstance.getServiceInfo(type, name) svcname = name.split(".")[0] typename = type.split(".")[0][1:] ip = str(socket.inet_ntoa(info.getAddress())) port = info.getPort() - num_items = self.list.GetItemCount() + num_items = self.ServicesList.GetItemCount() # display the new data in the list - new_item = self.list.InsertStringItem(num_items, svcname) - self.list.SetStringItem(new_item, 1, "%s" % typename) - self.list.SetStringItem(new_item, 2, "%s" % ip) - self.list.SetStringItem(new_item, 3, "%s" % port) + new_item = self.ServicesList.InsertStringItem(num_items, svcname) + self.ServicesList.SetStringItem(new_item, 1, "%s" % typename) + self.ServicesList.SetStringItem(new_item, 2, "%s" % ip) + self.ServicesList.SetStringItem(new_item, 3, "%s" % port) # record the new data for the ColumnSorterMixin # we assign every list item a unique id (that won't change when items # are added or removed) - self.list.SetItemData(new_item, self.nextItemId) + self.ServicesList.SetItemData(new_item, self.nextItemId) # the value of each column has to be stored in the itemDataMap # so that ColumnSorterMixin knows how to sort the column. @@ -218,11 +215,4 @@ self.itemDataMap[self.nextItemId] = [ svcname, typename, ip, port, name ] self.nextItemId += 1 - - def CreateURI(self, connect_type, connect_address, connect_port): - uri = "%s://%s:%s"%(connect_type, connect_address, connect_port) - return uri - - def ChooseLocalID(self, event): - self.my_result = "LOCAL://" - self.Close() + \ No newline at end of file diff -r 9b1801ef99b5 -r 31d08063b5d6 plugger.py --- a/plugger.py Fri Sep 18 14:58:22 2009 +0200 +++ b/plugger.py Mon Sep 21 12:12:08 2009 +0200 @@ -11,8 +11,6 @@ #Quick hack to be able to find Beremiz IEC tools. Should be config params. base_folder = os.path.split(sys.path[0])[0] -sys.path.append(os.path.join(base_folder, "plcopeneditor")) -sys.path.append(os.path.join(base_folder, "docutils")) from docpdf import * from xmlclass import GenerateClassesFromXSDstring @@ -178,6 +176,9 @@ self.PlugParams[1].setElementValue(parts[1], value) return value, False + def PlugMakeDir(self): + os.mkdir(self.PlugPath()) + def PlugRequestSave(self): # If plugin do not have corresponding directory plugpath = self.PlugPath() @@ -533,7 +534,7 @@ _self.ChangesToSave = False else: # If plugin do not have corresponding file/dirs - they will be created on Save - os.mkdir(_self.PlugPath()) + _self.PlugMakeDir() # Find an IEC number _self.FindNewIEC_Channel(0) # Call the plugin real __init__ @@ -722,6 +723,7 @@ self.logger = logger self._builder = None self._connector = None + self.Deleting = False # Setup debug information self.IECdebug_datas = {} @@ -748,8 +750,6 @@ # After __init__ root plugin is not valid self.ProjectPath = None self.BuildPath = None - self.PLCEditor = None - self.PLCDebug = None self.DebugThread = None self.debug_break = False self.previous_plcstate = None @@ -759,6 +759,9 @@ self.PluginMethods = [dic.copy() for dic in self.PluginMethods] self.LoadSTLibrary() + def __del__(self): + self.Deleting = True + def PluginLibraryFilePath(self): return os.path.join(os.path.split(__file__)[0], "pous.xml") @@ -864,26 +867,18 @@ def SaveProject(self): if not self.SaveXMLFile(): self.SaveXMLFile(os.path.join(self.ProjectPath, 'plc.xml')) - if self.PLCEditor: - self.PLCEditor.RefreshTitle() result = self.PlugRequestSave() if result: self.logger.write_error(result) - def CloseProject(self): - if self.PLCEditor is not None: - self.PLCEditor.Close() - if self.PLCDebug is not None: - self.PLCDebug.Close() - - # Update PLCOpenEditor Plugin Block types from loaded plugins def RefreshPluginsBlockLists(self): if getattr(self, "PluggedChilds", None) is not None: self.ClearPluginTypes() self.AddPluginBlockList(self.PluginsBlockTypesFactory()) - if self.PLCEditor is not None: - self.PLCEditor.RefreshEditor() + if self.AppFrame is not None: + self.AppFrame.RefreshLibraryTree() + self.AppFrame.RefreshEditor() def PluginPath(self): return os.path.join(os.path.split(__file__)[0], "plugins") @@ -1233,8 +1228,8 @@ """ Method called by user to (re)build SoftPLC and plugin tree """ - if self.PLCEditor is not None: - self.PLCEditor.ClearErrors() + if self.AppFrame is not None: + self.AppFrame.ClearErrors() buildpath = self._getBuildPath() @@ -1330,11 +1325,11 @@ def ShowError(self, logger, from_location, to_location): chunk_infos = self.GetChunkInfos(from_location, to_location) - self._EditPLC() for infos, (start_row, start_col) in chunk_infos: start = (from_location[0] - start_row, from_location[1] - start_col) end = (to_location[0] - start_row, to_location[1] - start_col) - self.PLCEditor.ShowError(infos, start, end) + if self.AppFrame is not None: + self.AppFrame.ShowError(infos, start, end) def _showIECcode(self): plc_file = self._getIECcodepath() @@ -1361,18 +1356,6 @@ new_dialog.Show() - def _EditPLC(self): - if self.PLCEditor is None: - self.RefreshPluginsBlockLists() - def _onclose(): - self.PLCEditor = None - def _onsave(): - self.SaveProject() - self.PLCEditor = PLCOpenEditor(self.AppFrame, self) - self.PLCEditor._onclose = _onclose - self.PLCEditor._onsave = _onsave - self.PLCEditor.Show() - def _Clean(self): if os.path.isdir(os.path.join(self._getBuildPath())): self.logger.write(_("Cleaning the build directory\n")) @@ -1475,11 +1458,12 @@ if self.DebugTimer is not None: self.DebugTimer.cancel() - # Timer to prevent rapid-fire when registering many variables - # use wx.CallAfter use keep using same thread. TODO : use wx.Timer instead - self.DebugTimer=Timer(0.5,wx.CallAfter,args = [self.RegisterDebugVarToConnector]) - # Rearm anti-rapid-fire timer - self.DebugTimer.start() + if not self.Deleting: + # Timer to prevent rapid-fire when registering many variables + # use wx.CallAfter use keep using same thread. TODO : use wx.Timer instead + self.DebugTimer=Timer(0.5,wx.CallAfter,args = [self.RegisterDebugVarToConnector]) + # Rearm anti-rapid-fire timer + self.DebugTimer.start() def SubscribeDebugIECVariable(self, IECPath, callableobj, *args, **kwargs): @@ -1579,15 +1563,8 @@ if self.GetIECProgramsAndVariables(): self._connector.StartPLC(debug=True) self.logger.write(_("Starting PLC (debug mode)\n")) - if self.PLCDebug is None: - self.RefreshPluginsBlockLists() - def _onclose(): - self.PLCDebug = None - self.PLCDebug = PLCOpenEditor(self.AppFrame, self, debug=True) - self.PLCDebug._onclose = _onclose - self.PLCDebug.Show() - else: - self.PLCDebug.ResetGraphicViewers() + if self.AppFrame: + self.AppFrame.ResetGraphicViewers() self.DebugThread = Thread(target=self.DebugThreadProc) self.DebugThread.start() else: @@ -1639,11 +1616,14 @@ # if uri is empty launch discovery dialog if uri == "": # Launch Service Discovery dialog - dia = DiscoveryDialog(self.AppFrame) - dia.ShowModal() - uri = dia.GetResult() + dialog = DiscoveryDialog(self.AppFrame) + answer = dialog.ShowModal() + uri = dialog.GetURI() + dialog.Destroy() + # Nothing choosed or cancel button - if uri is None: + if uri is None or answer == wx.ID_CANCEL: + self.logger.write_error(_("Connection canceled!\n")) return else: self.\ @@ -1733,9 +1713,9 @@ data = builder.GetBinaryCode() if data is not None : if self._connector.NewPLC(MD5, data, extrafiles): - if self.PLCDebug is not None: - self.PLCDebug.Close() - self.PLCDebug = None + if self.AppFrame is not None: + self.AppFrame.CloseDebugTabs() + self.AppFrame.RefreshInstanceTree() self.UnsubscribeAllDebugIECVariable() self.ProgramTransferred() self.logger.write(_("Transfer completed successfully.\n")) @@ -1746,10 +1726,6 @@ self.UpdateMethodsFromPLCStatus() PluginMethods = [ - {"bitmap" : opjimg("editPLC"), - "name" : _("Edit PLC"), - "tooltip" : _("Edit PLC program with PLCOpenEditor"), - "method" : "_EditPLC"}, {"bitmap" : opjimg("Build"), "name" : _("Build"), "tooltip" : _("Build project into build folder"), diff -r 9b1801ef99b5 -r 31d08063b5d6 runtime/PLCObject.py --- a/runtime/PLCObject.py Fri Sep 18 14:58:22 2009 +0200 +++ b/runtime/PLCObject.py Mon Sep 21 12:12:08 2009 +0200 @@ -111,6 +111,7 @@ else: def DummyIterator(res): self.DummyIteratorLock.acquire() + self.DummyIteratorLock.release() return None self._PythonIterator = DummyIterator @@ -171,36 +172,10 @@ self.PLClibraryHandle = None # Unload library explicitely if getattr(self,"_PLClibraryHandle",None) is not None: - PLCprint("Unload PLC") dlclose(self._PLClibraryHandle) - res = self._DetectDirtyLibs() - else: - res = False - - self._PLClibraryHandle = None + self._PLClibraryHandle = None + self.PLClibraryLock.release() - return res - - def _DetectDirtyLibs(self): - # Detect dirty libs - # Get lib dependencies (for dirty lib detection) - if os.name == "posix": - # parasiting libs listed with ldd - badlibs = [ toks.split()[0] for toks in commands.getoutput( - "ldd "+self._GetLibFileName()).splitlines() ] - for badlib in badlibs: - if badlib[:6] in ["libwx_", - "libwxs", - "libgtk", - "libgdk", - "libatk", - "libpan", - "libX11", - ]: - #badhandle = dlopen(badlib, dl.RTLD_NOLOAD) - PLCprint("Dirty lib detected :" + badlib) - #dlclose(badhandle) - return True return False def PrepareRuntimePy(self): @@ -308,7 +283,7 @@ def NewPLC(self, md5sum, data, extrafiles): PLCprint("NewPLC (%s)"%md5sum) - if self.PLCStatus in ["Stopped", "Empty", "Dirty", "Broken"]: + if self.PLCStatus in ["Stopped", "Empty", "Broken"]: NewFileName = md5sum + lib_ext extra_files_log = os.path.join(self.workingdir,"extra_files.txt") try: diff -r 9b1801ef99b5 -r 31d08063b5d6 targets/Linux/plc_Linux_main.c --- a/targets/Linux/plc_Linux_main.c Fri Sep 18 14:58:22 2009 +0200 +++ b/targets/Linux/plc_Linux_main.c Mon Sep 21 12:12:08 2009 +0200 @@ -64,7 +64,7 @@ } -static int __debug_tick; +static unsigned long __debug_tick; static pthread_mutex_t python_wait_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t python_mutex = PTHREAD_MUTEX_INITIALIZER; @@ -75,8 +75,8 @@ int startPLC(int argc,char **argv) { struct sigevent sigev; - /* Translate PLC's microseconds to Ttick nanoseconds */ - Ttick = 1000000 * maxval(common_ticktime__,1); + /* Define Ttick to 1ms if common_ticktime not defined */ + Ttick = common_ticktime__?common_ticktime__:1000000; memset (&sigev, 0, sizeof (struct sigevent)); sigev.sigev_value.sival_int = 0; @@ -97,6 +97,8 @@ /* install signal handler for manual break */ // signal(SIGTERM, catch_signal); signal(SIGINT, catch_signal); + + pthread_mutex_trylock(&debug_mutex); }else{ return 1; } @@ -120,6 +122,7 @@ timer_delete (PLC_timer); __cleanup(); __debug_tick = -1; + pthread_mutex_unlock(&debug_mutex); pthread_mutex_unlock(&debug_wait_mutex); pthread_mutex_destroy(&debug_wait_mutex); pthread_mutex_unlock(&python_wait_mutex); @@ -127,9 +130,9 @@ return 0; } -extern int __tick; +extern unsigned long __tick; /* from plc_debugger.c */ -int WaitDebugData() +unsigned long WaitDebugData() { /* Wait signal from PLC thread */ if(pthread_mutex_lock(&debug_wait_mutex)) return -1; diff -r 9b1801ef99b5 -r 31d08063b5d6 targets/Win32/plc_Win32_main.c --- a/targets/Win32/plc_Win32_main.c Fri Sep 18 14:58:22 2009 +0200 +++ b/targets/Win32/plc_Win32_main.c Mon Sep 21 12:12:08 2009 +0200 @@ -8,7 +8,7 @@ #include /* provided by POUS.C */ -extern int common_ticktime__; +extern unsigned long common_ticktime__; long AtomicCompareExchange(long* atomicvar, long compared, long exchange) { @@ -74,8 +74,8 @@ int startPLC(int argc,char **argv) { unsigned long thread_id = 0; - /* Translate PLC's microseconds to Ttick nanoseconds */ - Ttick = 1000000 * maxval(common_ticktime__,1); + /* Define Ttick to 1ms if common_ticktime not defined */ + Ttick = common_ticktime__?common_ticktime__:1000000; debug_sem = CreateSemaphore( NULL, // default security attributes @@ -142,7 +142,7 @@ } return 0; } -static int __debug_tick; +static unsigned long __debug_tick; int TryEnterDebugSection(void) { @@ -170,7 +170,7 @@ } /* from plc_debugger.c */ -int WaitDebugData() +unsigned long WaitDebugData() { if(WaitForSingleObject(debug_wait_sem, INFINITE) != WAIT_OBJECT_0) return -1; return __debug_tick; diff -r 9b1801ef99b5 -r 31d08063b5d6 targets/Xenomai/plc_Xenomai_main.c --- a/targets/Xenomai/plc_Xenomai_main.c Fri Sep 18 14:58:22 2009 +0200 +++ b/targets/Xenomai/plc_Xenomai_main.c Mon Sep 21 12:12:08 2009 +0200 @@ -29,7 +29,7 @@ #define WAITDEBUG_PIPE_SIZE 500 /* provided by POUS.C */ -extern int common_ticktime__; +extern unsigned long common_ticktime__; long AtomicCompareExchange(long* atomicvar,long compared, long exchange) { @@ -72,7 +72,7 @@ } } -static int __debug_tick; +static unsigned long __debug_tick; RT_SEM python_wait_sem; RT_MUTEX python_mutex; @@ -142,8 +142,8 @@ /* ne-memory-swapping for this program */ mlockall(MCL_CURRENT | MCL_FUTURE); - /* Translate PLC's microseconds to Ttick nanoseconds */ - Ttick = 1000000 * max_val(common_ticktime__,1); + /* Define Ttick to 1ms if common_ticktime not defined */ + Ttick = common_ticktime__?common_ticktime__:1000000; /* create python_wait_sem */ ret = rt_sem_create(&python_wait_sem, "python_wait_sem", 0, S_FIFO); @@ -203,9 +203,9 @@ rt_mutex_release(&debug_mutex); } -extern int __tick; +extern unsigned long __tick; /* from plc_debugger.c */ -int WaitDebugData() +unsigned long WaitDebugData() { char message; int res; diff -r 9b1801ef99b5 -r 31d08063b5d6 targets/plc_common_main.c --- a/targets/plc_common_main.c Fri Sep 18 14:58:22 2009 +0200 +++ b/targets/plc_common_main.c Mon Sep 21 12:12:08 2009 +0200 @@ -5,13 +5,13 @@ #include #include "iec_types.h" /* - * Prototypes of functions provied by generated C softPLC + * Prototypes of functions provided by generated C softPLC **/ -void config_run__(int tick); +void config_run__(unsigned long tick); void config_init__(void); /* - * Prototypes of functions provied by generated target C code + * Prototypes of functions provided by generated target C code * */ void __init_debug(void); void __cleanup_debug(void); @@ -22,8 +22,13 @@ * Variables used by generated C softPLC and plugins **/ IEC_TIME __CURRENT_TIME; -IEC_BOOL __DEBUG; -int __tick = -1; +IEC_BOOL __DEBUG = 0; +unsigned long __tick = -1; + +/* + * Variable generated by C softPLC and plugins + **/ +extern unsigned long greatest_tick_count__; /* Help to quit cleanly when init fail at a certain level */ static int init_level = 0; @@ -39,6 +44,8 @@ void __run() { __tick++; + if (greatest_tick_count__) + __tick %%= greatest_tick_count__; %(retrieve_calls)s @@ -53,7 +60,7 @@ } /* - * Initialize variables according to PLC's defalut values, + * Initialize variables according to PLC's default values, * and then init plugins with that values **/ int __init(int argc,char **argv) @@ -85,7 +92,7 @@ static long long Tsync = 0; static long long FreqCorr = 0; static int Nticks = 0; -static int last_tick = 0; +static unsigned long last_tick = 0; static long long Ttick = 0; #define mod %% /* diff -r 9b1801ef99b5 -r 31d08063b5d6 targets/plc_debug.c --- a/targets/plc_debug.c Fri Sep 18 14:58:22 2009 +0200 +++ b/targets/plc_debug.c Mon Sep 21 12:12:08 2009 +0200 @@ -70,7 +70,7 @@ extern long AtomicCompareExchange(long*, long, long); extern void InitiateDebugTransfer(void); -extern int __tick; +extern unsigned long __tick; void __publish_debug() { /* Check there is no running debugger re-configuration */ @@ -102,7 +102,7 @@ /* compute next cursor positon*/ next_cursor = buffer_cursor + size; /* if buffer not full */ - if(next_cursor < debug_buffer + BUFFER_SIZE) + if(next_cursor <= debug_buffer + BUFFER_SIZE) { /* copy data to the buffer */ memcpy(buffer_cursor, my_var->ptrvalue, size);