Skip to content

Commit

Permalink
Merge pull request #3 from danielhrisca/master
Browse files Browse the repository at this point in the history
various changes
  • Loading branch information
christoph2 committed Dec 8, 2018
2 parents 3373f4a + e5b435c commit b4105b8
Show file tree
Hide file tree
Showing 7 changed files with 147 additions and 56 deletions.
4 changes: 4 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
include LICENSE
recursive-include pyxcp *.c
recursive-include pyxcp *.a2l
recursive-include pyxcp *.aml
5 changes: 5 additions & 0 deletions pyxcp/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from .version import __version__
from .master import Master
from .transport import Eth, SxI

__copyright__="""
pySART - Simplified AUTOSAR-Toolkit for Python.
Expand All @@ -23,3 +27,4 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
"""


57 changes: 36 additions & 21 deletions pyxcp/transport/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@

from ..timing import Timing

from datetime import datetime


class BaseTransport(metaclass = abc.ABCMeta):

Expand All @@ -52,7 +54,13 @@ def __init__(self, config = Config({}), loglevel = 'WARN'):
self.daqQueue = queue.Queue()
self.evQueue = queue.Queue()
self.servQueue = queue.Queue()
self.listener = threading.Thread(target = self.listen, args = (), kwargs = {})
self.listener = threading.Thread(
target=self.listen,
args=(),
kwargs={},
)

self.first_daq_timestamp = None

def __del__(self):
self.finishListener()
Expand All @@ -71,16 +79,16 @@ def finishListener(self):

def request(self, cmd, *data):
self.logger.debug(cmd.name)
header = struct.pack("<HH", len(data) + 1, self.counterSend)
header = self.HEADER.pack(len(data) + 1, self.counterSend)
self.counterSend += 1
self.counterSend &= 0xffff
frame = header + bytearray(flatten(cmd, data))
frame = header + bytes(flatten(cmd, data))
self.logger.debug("-> {}".format(hexDump(frame)))
self.timing.start()
self.send(frame)

try:
xcpPDU = self.resQueue.get(timeout = 2.0)
xcpPDU = self.resQueue.get(timeout=2.0)
except queue.Empty:
if PYTHON_VERSION >= (3, 3):
raise types.XcpTimeoutError("Response timed out.") from None
Expand All @@ -91,11 +99,11 @@ def request(self, cmd, *data):

pid = types.Response.parse(xcpPDU).type
if pid == 'ERR' and cmd.name != 'SYNCH':
err = types.XcpError.parse(xcpPDU[1 : ])
err = types.XcpError.parse(xcpPDU[1:])
raise types.XcpResponseError(err)
else:
pass # Und nu??
return xcpPDU[1 : ]
return xcpPDU[1:]


@abc.abstractmethod
Expand All @@ -110,21 +118,28 @@ def closeConnection(self):
def listen(self):
pass

def processResponse(self, response):
if len(response) < self.HEADER_SIZE:
raise types.FrameSizeError("Frame too short.")
self.logger.debug("<- {}\n".format(hexDump(response)))
packetLen, self.counterReceived = struct.unpack(self.HEADER, response[ : 4])
xcpPDU = response[4 : ]
if len(xcpPDU) != packetLen:
def processResponse(self, response, length, counter):
self.counterReceived = counter
response = response
if len(response) != length:
raise types.FrameSizeError("Size mismatch.")
pid = xcpPDU[0]
if pid == 0xff or xcpPDU[0] == 0xfe:
self.resQueue.put(xcpPDU)
elif pid == 0xfd:
self.evQueue.put(xcpPDU)
elif pid == 0xfc:
self.servQueue.put(xcpPDU)
pid = response[0]
if pid >= 0xFC:
self.logger.debug(
"<- L{} C{} {}\n".format(
length,
counter,
hexDump(response),
)
)
if pid >= 0xfe:
self.resQueue.put(response)
elif pid == 0xfd:
self.evQueue.put(response)
elif pid == 0xfc:
self.servQueue.put(response)
else:
self.daqQueue.put(xcpPDU)
if self.first_daq_timestamp is None:
self.first_daq_timestamp = datetime.now()
self.daqQueue.put((response, counter, length))

79 changes: 55 additions & 24 deletions pyxcp/transport/eth.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,14 @@
class Eth(BaseTransport):

MAX_DATAGRAM_SIZE = 512
HEADER = "<HH"
HEADER_SIZE = struct.calcsize(HEADER)
HEADER = struct.Struct("<HH")
HEADER_SIZE = HEADER.size

def __init__(self, ipAddress, port = DEFAULT_XCP_PORT, config = {}, connected = True, loglevel = "WARN"):
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM if connected else socket.SOCK_DGRAM)
def __init__(self, ipAddress, port = DEFAULT_XCP_PORT, config = {}, protocol='TCP', loglevel = "WARN"):
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM if protocol=='TCP' else socket.SOCK_DGRAM)
self.selector = selectors.DefaultSelector()
self.selector.register(self.sock, selectors.EVENT_READ)
self.connected = connected
self.use_tcp = protocol == 'TCP'
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
if hasattr(self.sock, "SO_REUSEPORT"):
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
Expand All @@ -55,27 +55,58 @@ def __init__(self, ipAddress, port = DEFAULT_XCP_PORT, config = {}, connected =
super(Eth, self).__init__(config, loglevel)
self.startListener()

self.status = 1 # connected

def listen(self):
HEADER_UNPACK = self.HEADER.unpack
HEADER_SIZE = self.HEADER_SIZE
use_tcp = self.use_tcp
processResponse = self.processResponse

if use_tcp:
sock_recv = self.sock.recv
else:
sock_recv = self.sock.recvfrom

while True:
if self.closeEvent.isSet() or self.sock.fileno() == -1:
return
sel = self.selector.select(0.1)
for _, events in sel:
if events & selectors.EVENT_READ:
if self.connected:
length = struct.unpack("<H", self.sock.recv(2))[0]
try:
response = self.sock.recv(length + 2)
except Exception as e:
self.logger.error(str(e))
continue
else:
try:
response, server = self.sock.recvfrom(Eth.MAX_DATAGRAM_SIZE)
except Exception as e:
self.logger.error(str(e))
continue
self.processResponse(response)
try:
if self.closeEvent.isSet() or self.sock.fileno() == -1:
return
sel = self.selector.select(0.1)
for _, events in sel:
if events & selectors.EVENT_READ:
if use_tcp:
header = bytearray()

while len(header) < HEADER_SIZE:
new_bytes = sock_recv(HEADER_SIZE - len(header))
header.extend(new_bytes)

length, counter = HEADER_UNPACK(header)

try:
response = bytearray()
while len(response) < length:
new_bytes = sock_recv(length - len(response))
response.extend(new_bytes)

except Exception as e:
self.logger.error(str(e))
continue
else:
try:
response, server = sock_recv(Eth.MAX_DATAGRAM_SIZE)
length, counter = HEADER_UNPACK(response)
response = response[HEADER_SIZE:]
except Exception as e:
self.logger.error(str(e))
continue

processResponse(response, length, counter)
except:
self.status = 0 # disconnected
break


def send(self, frame):
self.sock.send(frame)
Expand Down
13 changes: 6 additions & 7 deletions pyxcp/transport/sxi.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@
class SxI(BaseTransport):

MAX_DATAGRAM_SIZE = 512
HEADER = "<HH"
HEADER_SIZE = struct.calcsize(HEADER)
HEADER = struct.Struct("<HH")
HEADER_SIZE = HEADER.size

def __init__(self, portName, baudrate = 9600, bytesize = 8, parity = 'N', stopbits = 1, timeout = 0.75, config = {}, loglevel = "WARN"):
self.portName = portName
Expand Down Expand Up @@ -83,13 +83,12 @@ def listen(self):
return
if not self.port.inWaiting():
continue
rawLength = self.port.read(2)
length = struct.unpack("<H", rawLength)[0]
response = self.port.read(length + 2)
length, counter = self.HEADER.unpack(self.port.read(HEADER_SIZE))

response = self.port.read(length)
self.timing.stop()
response = rawLength + response

self.processResponse(response)
self.processResponse(response, length, counter)


def send(self, frame):
Expand Down
4 changes: 4 additions & 0 deletions pyxcp/version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
""" pyxcp version module """

__version__ = "0.10.0"
41 changes: 37 additions & 4 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
#!/bin/env python

import os
from codecs import open
from setuptools import setup, find_packages
import sys

with open(os.path.join('pyxcp', 'version.py'), 'r') as f:
for line in f:
if line.startswith('__version__'):
version = line.split('=')[-1].strip().strip('"')
break

def packagez(base):
return ["{0!s}{1!s}{2!s}".format(base, os.path.sep, p) for p in find_packages(base)]

Expand All @@ -14,16 +21,42 @@ def packagez(base):

setup(
name = 'pyxcp',
version = '0.9.0',
version = version,
provides = ['pyxcp'],
description = "Universal Calibration Protocol for Python",
author = 'Christoph Schueler',
author_email = 'cpu12.gems@googlemail.com',
url = 'http://github.com/pySART/pyxcp',
url = 'https://github.com/christoph2/pyxcp',
packages = packagez('pyxcp'),
install_requires = install_reqs,

include_package_data=True,
install_requires = ['enum34', 'construct >= 2.8', 'mako', 'pyserial'],

doc_requires = ['numpydoc', 'sphinxcontrib-napoleon'],
package_dir = {'tests': 'pyxcp/tests'},
test_suite = "pyxcp.tests"
test_suite = "pyxcp.tests",
license='GPLv2',
# See https://pypi.python.org/pypi?%3Aaction=list_classifiers
classifiers=[
# How mature is this project? Common values are
# 3 - Alpha
# 4 - Beta
# 5 - Production/Stable
'Development Status :: 4 - Beta',

# Indicate who your project is intended for
'Intended Audience :: Developers',
'Topic :: Software Development',
'Topic :: Scientific/Engineering',

# Pick your license as you wish (should match "license" above)
'License :: OSI Approved :: GNU General Public License v2 (GPLv2)',

# Specify the Python versions you support here. In particular, ensure
# that you indicate whether you support Python 2, Python 3 or both.
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
],
)

0 comments on commit b4105b8

Please sign in to comment.