--- a/Beremiz_service.py Mon Mar 18 07:13:04 2019 +0000
+++ b/Beremiz_service.py Mon Mar 18 12:10:36 2019 +0300
@@ -31,7 +31,6 @@
import getopt
import threading
from threading import Thread, Semaphore, Lock, currentThread
-import __builtin__
from builtins import str as text
from past.builtins import execfile
from six.moves import builtins
--- a/README.md Mon Mar 18 07:13:04 2019 +0000
+++ b/README.md Mon Mar 18 12:10:36 2019 +0300
@@ -25,6 +25,9 @@
sudo apt-get install python-nevow python-matplotlib python-lxml python-zeroconf python-cycler
sudo apt-get install python-autobahn python-u-msgpack
+ sudo apt-get install libpython2.7-dev
+ pip2 install --use sslpsk posix_spawn
+
* Prepare
mkdir ~/Beremiz
@@ -66,7 +69,8 @@
cd ~/Beremiz
svn checkout https://svn.code.sf.net/p/bacnet/code/trunk/bacnet-stack/ BACnet
cd BACnet
- make MAKE_DEFINE='-fPIC' all
+ make MAKE_DEFINE='-fPIC' MY_BACNET_DEFINES='-DPRINT_ENABLED=1 -DBACAPP_ALL -DBACFILE -DINTRINSIC_REPORTING -DBACNET_TIME_MASTER -DBACNET_PROPERTY_LISTS=1 -DBACNET_PROTOCOL_REVISION=16' library
+
* Launch Beremiz IDE
--- a/connectors/ConnectorBase.py Mon Mar 18 07:13:04 2019 +0000
+++ b/connectors/ConnectorBase.py Mon Mar 18 12:10:36 2019 +0300
@@ -4,7 +4,7 @@
# See COPYING file for copyrights details.
from __future__ import absolute_import
-import md5
+import hashlib
class ConnectorBase(object):
@@ -12,7 +12,7 @@
chuncksize = 1024*1024
def BlobFromFile(self, filepath, seed):
- s = md5.new()
+ s = hashlib.new('md5')
s.update(seed)
blobID = self.SeedBlob(seed)
with open(filepath, "rb") as f:
--- a/connectors/PYRO/PSK_Adapter.py Mon Mar 18 07:13:04 2019 +0000
+++ b/connectors/PYRO/PSK_Adapter.py Mon Mar 18 12:10:36 2019 +0300
@@ -1,10 +1,40 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# This file is part of Beremiz, a Integrated Development Environment for
+# programming IEC 61131-3 automates supporting plcopen standard and CanFestival.
+#
+# Copyright (C) 2019: Edouard TISSERANT
+#
+# See COPYING file for copyrights details.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+
+"""
+The TLS-PSK adapter that handles SSL connections instead of regular sockets,
+but using Pre Shared Keys instead of Certificates
+"""
+
from __future__ import absolute_import
from __future__ import print_function
import socket
import re
+import ssl
import sslpsk
-import ssl
import Pyro
from Pyro.core import PyroURI
from Pyro.protocol import _connect_socket, TCPConnection, PYROAdapter
@@ -12,13 +42,13 @@
from Pyro.util import Log
-# The TLS-PSK adapter that handles SSL connections instead of regular sockets,
-# but using Pre Shared Keys instead of Certificates
-#
class PYROPSKAdapter(PYROAdapter):
- # This is essentialy the same as in Pyro/protocol.py
- # only raw_sock wrapping into sock through sslpsk.wrap_socket was added
- # Pyro unfortunately doesn't allow cleaner customization
+ """
+ This is essentialy the same as in Pyro/protocol.py
+ only raw_sock wrapping into sock through sslpsk.wrap_socket was added
+ Pyro unfortunately doesn't allow cleaner customization
+ """
+
def bindToURI(self, URI):
with self.lock: # only 1 thread at a time can bind the URI
try:
@@ -37,7 +67,7 @@
# receive the authentication challenge string, and use that to build the actual identification string.
try:
authChallenge = self.recvAuthChallenge(conn)
- except ProtocolError, x:
+ except ProtocolError as x:
# check if we were denied
if hasattr(x, "partialMsg") and x.partialMsg[:len(self.denyMSG)] == self.denyMSG:
raise ConnectionDeniedError(Pyro.constants.deniedReasons[int(x.partialMsg[-1])])
@@ -70,9 +100,6 @@
return _getProtocolAdapter(protocol)
-Pyro.protocol.getProtocolAdapter = getProtocolAdapter
-
-
_processStringURI = Pyro.core.processStringURI
@@ -91,4 +118,13 @@
return _processStringURI(URI)
-Pyro.core.processStringURI = processStringURI
+def setupPSKAdapter():
+ """
+ Add PyroAdapter to the list of available in
+ Pyro adapters and handle new supported protocols
+
+ This function should be called after
+ reimport of Pyro module to enable PYROS:// again.
+ """
+ Pyro.protocol.getProtocolAdapter = getProtocolAdapter
+ Pyro.core.processStringURI = processStringURI
--- a/connectors/PYRO/__init__.py Mon Mar 18 07:13:04 2019 +0000
+++ b/connectors/PYRO/__init__.py Mon Mar 18 12:10:36 2019 +0300
@@ -37,13 +37,19 @@
from Pyro.errors import PyroError
import PSKManagement as PSK
+import connectors.PYRO.PSK_Adapter
from runtime import PlcStatus
-# this module attribute contains a list of DNS-SD (Zeroconf) service types
-# supported by this connector confnode.
-#
-# for connectors that do not support DNS-SD, this attribute can be omitted
-# or set to an empty list.
+
+def switch_pyro_adapter(use_ssl):
+ """
+ Reloads Pyro module with new settings.
+ This is workaround for Pyro, because it doesn't work with SSL wrapper.
+ """
+ # Pyro.config.PYRO_BROKEN_MSGWAITALL = use_ssl
+ reload(Pyro.protocol)
+ if use_ssl:
+ connectors.PYRO.PSK_Adapter.setupPSKAdapter()
def PYRO_connector_factory(uri, confnodesroot):
@@ -53,8 +59,9 @@
confnodesroot.logger.write(_("PYRO connecting to URI : %s\n") % uri)
scheme, location = uri.split("://")
- if scheme == "PYROS":
- import connectors.PYRO.PSK_Adapter # pylint: disable=wrong-import-order,unused-import,wrong-import-position
+ use_ssl = scheme == "PYROS"
+ switch_pyro_adapter(use_ssl)
+ if use_ssl:
schemename = "PYROLOCPSK"
url, ID = location.split('#') # TODO fix exception when # not found
# load PSK from project
@@ -73,10 +80,10 @@
# Try to get the proxy object
try:
RemotePLCObjectProxy = Pyro.core.getAttrProxyForURI(schemename + "://" + location + "/PLCObject")
- except Exception, e:
+ except Exception as e:
confnodesroot.logger.write_error(
_("Connection to {loc} failed with exception {ex}\n").format(
- loc=location, exo=str(e)))
+ loc=location, ex=str(e)))
return None
RemotePLCObjectProxy.adapter.setTimeout(60)
--- a/connectors/PYRO_dialog.py Mon Mar 18 07:13:04 2019 +0000
+++ b/connectors/PYRO_dialog.py Mon Mar 18 12:10:36 2019 +0300
@@ -6,7 +6,6 @@
from __future__ import absolute_import
from itertools import repeat, islice, chain
-import wx
from connectors.SchemeEditor import SchemeEditor
--- a/connectors/SchemeEditor.py Mon Mar 18 07:13:04 2019 +0000
+++ b/connectors/SchemeEditor.py Mon Mar 18 12:10:36 2019 +0300
@@ -26,7 +26,7 @@
self.txtctrls[tag] = txtctrl
for win, flag in [
(wx.StaticText(self, label=label),
- wx.ALIGN_CENTER_VERTICAL),
+ wx.ALIGN_CENTER_VERTICAL),
(txtctrl, wx.GROW)]:
self.fieldsizer.AddWindow(win, flag=flag)
@@ -39,7 +39,7 @@
self, parent.ctr,
# use a callafter, as editor can be deleted by calling SetURI
partial(wx.CallAfter, parent.SetURI),
- self.txtctrls[tag].SetValue)
+ self.txtctrls["ID"].SetValue)
self.mainsizer.AddWindow(self.idselector)
self.SetSizer(self.mainsizer)
else:
--- a/connectors/__init__.py Mon Mar 18 07:13:04 2019 +0000
+++ b/connectors/__init__.py Mon Mar 18 12:10:36 2019 +0300
@@ -29,7 +29,6 @@
from __future__ import absolute_import
from os import listdir, path
from connectors.ConnectorBase import ConnectorBase
-from types import ClassType
connectors_packages = ["PYRO", "WAMP"]
@@ -118,8 +117,8 @@
return None
# new class inheriting from generic and specific connector base classes
- return ClassType(_scheme + "_connector",
- (ConnectorBase, connector_specific_class), {})()
+ return type(_scheme + "_connector",
+ (ConnectorBase, connector_specific_class), {})()
def EditorClassFromScheme(scheme):
--- a/controls/IDBrowser.py Mon Mar 18 07:13:04 2019 +0000
+++ b/controls/IDBrowser.py Mon Mar 18 12:10:36 2019 +0300
@@ -98,8 +98,8 @@
args(_("Last URI"), COL_URI, width=300 if big else 80),
args(_("Description"), COL_DESC, width=300 if big else 200,
mode=dv.DATAVIEW_CELL_EDITABLE
- if self.isManager
- else dv.DATAVIEW_CELL_INERT),
+ if self.isManager
+ else dv.DATAVIEW_CELL_INERT),
args(_("Last connection"), COL_LAST, width=120),
]
--- a/runtime/PLCObject.py Mon Mar 18 07:13:04 2019 +0000
+++ b/runtime/PLCObject.py Mon Mar 18 12:10:36 2019 +0300
@@ -28,14 +28,14 @@
import os
import sys
import traceback
+import shutil
from time import time
-import _ctypes # pylint: disable=wrong-import-order
+import hashlib
+from tempfile import mkstemp
+from functools import wraps, partial
from six.moves import xrange
from past.builtins import execfile
-import md5
-from tempfile import mkstemp
-import shutil
-from functools import wraps, partial
+import _ctypes
from runtime.typemapping import TypeTranslator
from runtime.loglevels import LogLevelsDefault, LogLevelsCount
@@ -465,7 +465,7 @@
@RunInMain
def SeedBlob(self, seed):
- blob = (mkstemp(dir=self.tmpdir) + (md5.new(),))
+ blob = (mkstemp(dir=self.tmpdir) + (hashlib.new('md5'),))
_fobj, _path, md5sum = blob
md5sum.update(seed)
newBlobID = md5sum.digest()
@@ -606,7 +606,7 @@
@RunInMain
def GetTraceVariables(self, DebugToken):
- if (DebugToken is not None and DebugToken == self.DebugToken):
+ if DebugToken is not None and DebugToken == self.DebugToken:
return self.PLCStatus, self._TracesSwap()
return PlcStatus.Broken, []
--- a/runtime/Stunnel.py Mon Mar 18 07:13:04 2019 +0000
+++ b/runtime/Stunnel.py Mon Mar 18 12:10:36 2019 +0300
@@ -1,4 +1,5 @@
from __future__ import absolute_import
+from __future__ import print_function
import os
from binascii import b2a_hqx
try:
@@ -11,6 +12,17 @@
_PSKpath = None
+def restartStunnel():
+ """
+ Restart stunnel service using SysV init stript
+ to apply new generated credentials
+ """
+ try:
+ call(restart_stunnel_cmdline)
+ except OSError:
+ print(_("Couldn't restart stunnel service"))
+
+
def PSKgen(ID, PSKpath):
# b2a_hqx output len is 4/3 input len
@@ -20,7 +32,7 @@
PSKstring = ID+":"+secretstring
with open(PSKpath, 'w') as f:
f.write(PSKstring)
- call(restart_stunnel_cmdline)
+ restartStunnel()
def ensurePSK(ID, PSKpath):
--- a/runtime/WampClient.py Mon Mar 18 07:13:04 2019 +0000
+++ b/runtime/WampClient.py Mon Mar 18 12:10:36 2019 +0300
@@ -135,7 +135,7 @@
self.register(GetCallee(name), u'.'.join((ID, name)), registerOptions)
for name in SubscribedEvents:
- self.subscribe(GetCallee(name), unicode(name))
+ self.subscribe(GetCallee(name), text(name))
for func in DoOnJoin:
func(self)
@@ -151,7 +151,7 @@
def publishWithOwnID(self, eventID, value):
ID = self.config.extra["ID"]
- self.publish(unicode(ID+'.'+eventID), value)
+ self.publish(text(ID+'.'+eventID), value)
class ReconnectingWampWebSocketClientFactory(WampWebSocketClientFactory, ReconnectingClientFactory):
@@ -343,12 +343,12 @@
def PublishEvent(eventID, value):
if getWampStatus() == "Attached":
- _WampSession.publish(unicode(eventID), value)
+ _WampSession.publish(text(eventID), value)
def PublishEventWithOwnID(eventID, value):
if getWampStatus() == "Attached":
- _WampSession.publishWithOwnID(unicode(eventID), value)
+ _WampSession.publishWithOwnID(text(eventID), value)
# WEB CONFIGURATION INTERFACE
--- a/runtime/Worker.py Mon Mar 18 07:13:04 2019 +0000
+++ b/runtime/Worker.py Mon Mar 18 12:10:36 2019 +0300
@@ -9,9 +9,9 @@
from __future__ import absolute_import
import sys
-import thread
from threading import Lock, Condition
import six
+from six.moves import _thread
class job(object):
@@ -51,20 +51,27 @@
self.free = Condition(self.mutex)
self.job = None
+ def reraise(self, job):
+ """
+ reraise exception happend in a job
+ @param job: job where original exception happend
+ """
+ exc_type = job.exc_info[0]
+ exc_value = job.exc_info[1]
+ exc_traceback = job.exc_info[2]
+ six.reraise(exc_type, exc_value, exc_traceback)
+
def runloop(self, *args, **kwargs):
"""
meant to be called by worker thread (blocking)
"""
- self._threadID = thread.get_ident()
+ self._threadID = _thread.get_ident()
self.mutex.acquire()
if args or kwargs:
_job = job(*args, **kwargs)
_job.do()
- if _job.success:
- # result is ignored
- pass
- else:
- raise _job.exc_info[0], _job.exc_info[1], _job.exc_info[2]
+ if not _job.success:
+ self.reraise(_job)
while not self._finish:
self.todo.wait()
@@ -86,7 +93,7 @@
_job = job(*args, **kwargs)
- if self._threadID == thread.get_ident():
+ if self._threadID == _thread.get_ident():
# if caller is worker thread execute immediately
_job.do()
else:
@@ -106,10 +113,7 @@
if _job.success:
return _job.result
else:
- exc_type = _job.exc_info[0]
- exc_value = _job.exc_info[1]
- exc_traceback = _job.exc_info[2]
- six.reraise(exc_type, exc_value, exc_traceback)
+ self.reraise(_job)
def quit(self):
"""
--- a/runtime/spawn_subprocess.py Mon Mar 18 07:13:04 2019 +0000
+++ b/runtime/spawn_subprocess.py Mon Mar 18 12:10:36 2019 +0300
@@ -3,6 +3,7 @@
# subset of subprocess built-in module using posix_spawn rather than fork.
+from __future__ import print_function
from __future__ import absolute_import
import os
import signal
--- a/tests/first_steps/plc.xml Mon Mar 18 07:13:04 2019 +0000
+++ b/tests/first_steps/plc.xml Mon Mar 18 12:10:36 2019 +0300
@@ -1,7 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<project xmlns:ns1="http://www.plcopen.org/xml/tc6_0201" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.plcopen.org/xml/tc6_0201">
<fileHeader companyName="Beremiz" productName="Beremiz" productVersion="1" creationDateTime="2016-10-24T18:09:22"/>
- <contentHeader name="First Steps" modificationDateTime="2019-02-13T10:30:06">
+ <contentHeader name="First Steps" modificationDateTime="2018-09-26T12:52:51">
<coordinateInfo>
<fbd>
<scaling x="0" y="0"/>
@@ -676,11 +676,6 @@
<INT/>
</type>
</variable>
- <variable name="R2">
- <type>
- <BOOL/>
- </type>
- </variable>
</localVars>
<externalVars constant="true">
<variable name="ResetCounterValue">
@@ -813,7 +808,7 @@
<relPosition x="85" y="15"/>
</connectionPointOutAction>
</step>
- <actionBlock localId="8" height="63" width="148" executionOrderId="0">
+ <actionBlock localId="8" height="52" width="164" executionOrderId="0">
<position x="154" y="191"/>
<connectionPointIn>
<relPosition x="0" y="15"/>
@@ -830,14 +825,6 @@
</ST>
</inline>
</action>
- <action localId="0" qualifier="S">
- <relPosition x="0" y="0"/>
- <inline>
- <ST>
- <xhtml:p><![CDATA[ R2 := True;]]></xhtml:p>
- </ST>
- </inline>
- </action>
<action localId="0">
<relPosition x="0" y="0"/>
<inline>
@@ -848,18 +835,18 @@
</action>
</actionBlock>
<selectionConvergence localId="10" height="1" width="431">
- <position x="70" y="657"/>
+ <position x="70" y="273"/>
<connectionPointIn>
<relPosition x="0" y="0"/>
<connection refLocalId="13">
- <position x="70" y="657"/>
+ <position x="70" y="273"/>
<position x="70" y="244"/>
</connection>
</connectionPointIn>
<connectionPointIn>
<relPosition x="431" y="0"/>
<connection refLocalId="14">
- <position x="501" y="657"/>
+ <position x="501" y="273"/>
<position x="501" y="250"/>
</connection>
</connectionPointIn>
@@ -868,12 +855,12 @@
</connectionPointOut>
</selectionConvergence>
<jumpStep localId="12" targetName="Start" height="13" width="12">
- <position x="280" y="701"/>
+ <position x="280" y="317"/>
<connectionPointIn>
<relPosition x="6" y="0"/>
<connection refLocalId="10">
- <position x="286" y="701"/>
- <position x="286" y="658"/>
+ <position x="286" y="317"/>
+ <position x="286" y="274"/>
</connection>
</connectionPointIn>
</jumpStep>
@@ -883,7 +870,7 @@
<relPosition x="10" y="0"/>
<connection refLocalId="7">
<position x="70" y="242"/>
- <position x="70" y="221"/>
+ <position x="70" y="215"/>
</connection>
</connectionPointIn>
<connectionPointOut>
@@ -983,11 +970,6 @@
</variable>
</inputVars>
<outputVars>
- <variable name="Reset0">
- <type>
- <BOOL/>
- </type>
- </variable>
<variable name="Out">
<type>
<INT/>
--- a/tests/tools/check_source.sh Mon Mar 18 07:13:04 2019 +0000
+++ b/tests/tools/check_source.sh Mon Mar 18 12:10:36 2019 +0300
@@ -66,7 +66,7 @@
# remove compiled Python files
find . -name '*.pyc' -exec rm -f {} \;
- for i in $py_files; do
+ for i in $py3_files; do
# echo $i
python3 -m py_compile $i
if [ $? -ne 0 ]; then
@@ -444,6 +444,8 @@
echo "No files to check"
exit 0;
fi
+
+ py3_files=$(echo $py_files | sed 's/ [[:alnum:]_\-\/.]*pyjslib.py//')
}