Skip to content

Commit

Permalink
Merge branch 'develop' into pcan_mac
Browse files Browse the repository at this point in the history
  • Loading branch information
Lauszus committed Aug 9, 2018
2 parents c0b8700 + 95c5c1a commit 6118964
Show file tree
Hide file tree
Showing 25 changed files with 1,050 additions and 555 deletions.
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
# https://github.com/github/gitignore/blob/da00310ccba9de9a988cc973ef5238ad2c1460e9/Python.gitignore
test/__tempdir__/
.pytest_cache/

# -------------------------
# below: https://github.com/github/gitignore/blob/da00310ccba9de9a988cc973ef5238ad2c1460e9/Python.gitignore

# Byte-compiled / optimized / DLL files
__pycache__/
Expand Down
2 changes: 1 addition & 1 deletion can/interfaces/ics_neovi/neovi_bus.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ def _recv_internal(self, timeout=0.1):
return msg, False

def send(self, msg, timeout=None):
if not self.dev.IsOpen:
if not ics.validate_hobject(self.dev):
raise CanError("bus not open")

flags = 0
Expand Down
11 changes: 6 additions & 5 deletions can/interfaces/slcan.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,6 @@ def __init__(self, channel, ttyBaudrate=115200, timeout=1, bitrate=None, **kwarg
(channel, ttyBaudrate) = channel.split('@')

self.serialPortOrig = serial.Serial(channel, baudrate=ttyBaudrate, timeout=timeout)
self.serialPort = io.TextIOWrapper(io.BufferedRWPair(self.serialPortOrig, self.serialPortOrig, 1),
newline='\r', line_buffering=True)

time.sleep(self._SLEEP_AFTER_SERIAL_OPEN)

Expand All @@ -86,8 +84,8 @@ def __init__(self, channel, ttyBaudrate=115200, timeout=1, bitrate=None, **kwarg
def write(self, string):
if not string.endswith('\r'):
string += '\r'
self.serialPort.write(string.decode())
self.serialPort.flush()
self.serialPortOrig.write(string.encode())
self.serialPortOrig.flush()

def open(self):
self.write('O')
Expand All @@ -103,10 +101,13 @@ def _recv_internal(self, timeout):
remote = False
extended = False
frame = []
readStr = self.serialPort.readline()

readStr = self.serialPortOrig.read_until(b'\r')

if not readStr:
return None, False
else:
readStr = readStr.decode()
if readStr[0] == 'T':
# extended frame
canId = int(readStr[1:9], 16)
Expand Down
5 changes: 5 additions & 0 deletions can/interfaces/socketcan/socketcan.py
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,11 @@ def __init__(self, channel="", receive_own_messages=False, fd=False, **kwargs):
CAN_RAW_FD_FRAMES,
1)

# Enable error frames
self.socket.setsockopt(SOL_CAN_RAW,
CAN_RAW_ERR_FILTER,
0x1FFFFFFF)

bind_socket(self.socket, channel)

kwargs.update({'receive_own_messages': receive_own_messages, 'fd': fd})
Expand Down
2 changes: 1 addition & 1 deletion can/io/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@
from .canutils import CanutilsLogReader, CanutilsLogWriter
from .csv import CSVWriter, CSVReader
from .sqlite import SqliteReader, SqliteWriter
from .stdout import Printer
from .printer import Printer
94 changes: 52 additions & 42 deletions can/io/asc.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
"""
Contains handling of ASC logging files.
Example .asc file: https://bitbucket.org/tobylorenz/vector_asc/src/47556e1a6d32c859224ca62d075e1efcc67fa690/src/Vector/ASC/tests/unittests/data/CAN_Log_Trigger_3_2.asc?at=master&fileviewer=file-view-default
Example .asc files:
- https://bitbucket.org/tobylorenz/vector_asc/src/47556e1a6d32c859224ca62d075e1efcc67fa690/src/Vector/ASC/tests/unittests/data/CAN_Log_Trigger_3_2.asc?at=master&fileviewer=file-view-default
- under `test/data/logfile.asc`
"""

from __future__ import absolute_import
Expand All @@ -16,22 +18,28 @@
from ..message import Message
from ..listener import Listener
from ..util import channel2int
from .generic import BaseIOHandler

CAN_MSG_EXT = 0x80000000
CAN_ID_MASK = 0x1FFFFFFF

logger = logging.getLogger('can.io.asc')


class ASCReader(object):
class ASCReader(BaseIOHandler):
"""
Iterator of CAN messages from a ASC logging file.
TODO: turn relative timestamps back to absolute form
"""

def __init__(self, filename):
self.file = open(filename, 'r')
def __init__(self, file):
"""
:param file: a path-like object or as file-like object to read from
If this is a file-like object, is has to opened in text
read mode, not binary read mode.
"""
super(ASCReader, self).__init__(file, mode='r')

@staticmethod
def _extract_can_id(str_can_id):
Expand All @@ -41,19 +49,19 @@ def _extract_can_id(str_can_id):
else:
is_extended = False
can_id = int(str_can_id, 16)
logging.debug('ASCReader: _extract_can_id("%s") -> %x, %r', str_can_id, can_id, is_extended)
return (can_id, is_extended)
#logging.debug('ASCReader: _extract_can_id("%s") -> %x, %r', str_can_id, can_id, is_extended)
return can_id, is_extended

def __iter__(self):
for line in self.file:
logger.debug("ASCReader: parsing line: '%s'", line.splitlines()[0])
#logger.debug("ASCReader: parsing line: '%s'", line.splitlines()[0])

temp = line.strip()
if not temp or not temp[0].isdigit():
continue

try:
(timestamp, channel, dummy) = temp.split(None, 2) # , frameType, dlc, frameData
timestamp, channel, dummy = temp.split(None, 2) # , frameType, dlc, frameData
except ValueError:
# we parsed an empty comment
continue
Expand All @@ -74,8 +82,8 @@ def __iter__(self):
pass

elif dummy[-1:].lower() == 'r':
(can_id_str, _) = dummy.split(None, 1)
(can_id_num, is_extended_id) = self._extract_can_id(can_id_str)
can_id_str, _ = dummy.split(None, 1)
can_id_num, is_extended_id = self._extract_can_id(can_id_str)
msg = Message(timestamp=timestamp,
arbitration_id=can_id_num & CAN_ID_MASK,
extended_id=is_extended_id,
Expand All @@ -86,10 +94,10 @@ def __iter__(self):
else:
try:
# this only works if dlc > 0 and thus data is availabe
(can_id_str, _, _, dlc, data) = dummy.split(None, 4)
can_id_str, _, _, dlc, data = dummy.split(None, 4)
except ValueError:
# but if not, we only want to get the stuff up to the dlc
(can_id_str, _, _, dlc ) = dummy.split(None, 3)
can_id_str, _, _, dlc = dummy.split(None, 3)
# and we set data to an empty sequence manually
data = ''

Expand All @@ -99,24 +107,26 @@ def __iter__(self):
for byte in data[0:dlc]:
frame.append(int(byte, 16))

(can_id_num, is_extended_id) = self._extract_can_id(can_id_str)
can_id_num, is_extended_id = self._extract_can_id(can_id_str)

msg = Message(
timestamp=timestamp,
arbitration_id=can_id_num & CAN_ID_MASK,
extended_id=is_extended_id,
is_remote_frame=False,
dlc=dlc,
data=frame,
channel=channel)
yield msg
yield Message(
timestamp=timestamp,
arbitration_id=can_id_num & CAN_ID_MASK,
extended_id=is_extended_id,
is_remote_frame=False,
dlc=dlc,
data=frame,
channel=channel
)

self.stop()


class ASCWriter(Listener):
class ASCWriter(BaseIOHandler, Listener):
"""Logs CAN data to an ASCII log file (.asc).
The measurement starts with the timestamp of the first registered message.
If a message has a timestamp smaller than the previous one (or 0 or None),
If a message has a timestamp smaller than the previous one or None,
it gets assigned the timestamp that was written for the last message.
It the first message does not have a timestamp, it is set to zero.
"""
Expand All @@ -125,27 +135,32 @@ class ASCWriter(Listener):
FORMAT_DATE = "%a %b %m %I:%M:%S %p %Y"
FORMAT_EVENT = "{timestamp: 9.4f} {message}\n"

def __init__(self, filename, channel=1):
# setup
def __init__(self, file, channel=1):
"""
:param file: a path-like object or as file-like object to write to
If this is a file-like object, is has to opened in text
write mode, not binary write mode.
:param channel: a default channel to use when the message does not
have a channel set
"""
super(ASCWriter, self).__init__(file, mode='w')
self.channel = channel
self.log_file = open(filename, 'w')

# write start of file header
now = datetime.now().strftime("%a %b %m %I:%M:%S %p %Y")
self.log_file.write("date %s\n" % now)
self.log_file.write("base hex timestamps absolute\n")
self.log_file.write("internal events logged\n")
self.file.write("date %s\n" % now)
self.file.write("base hex timestamps absolute\n")
self.file.write("internal events logged\n")

# the last part is written with the timestamp of the first message
self.header_written = False
self.last_timestamp = None
self.started = None

def stop(self):
"""Stops logging and closes the file."""
if not self.log_file.closed:
self.log_file.write("End TriggerBlock\n")
self.log_file.close()
if not self.file.closed:
self.file.write("End TriggerBlock\n")
super(ASCWriter, self).stop()

def log_event(self, message, timestamp=None):
"""Add a message to the log file.
Expand All @@ -163,10 +178,9 @@ def log_event(self, message, timestamp=None):
self.last_timestamp = (timestamp or 0.0)
self.started = self.last_timestamp
formatted_date = time.strftime(self.FORMAT_DATE, time.localtime(self.last_timestamp))
self.log_file.write("base hex timestamps absolute\n")
self.log_file.write("Begin Triggerblock %s\n" % formatted_date)
self.file.write("Begin Triggerblock %s\n" % formatted_date)
self.header_written = True
self.log_event("Start of measurement") # recursive call
self.log_event("Start of measurement") # caution: this is a recursive call!

# figure out the correct timestamp
if timestamp is None or timestamp < self.last_timestamp:
Expand All @@ -177,11 +191,7 @@ def log_event(self, message, timestamp=None):
timestamp -= self.started

line = self.FORMAT_EVENT.format(timestamp=timestamp, message=message)

if self.log_file.closed:
logger.warn("ASCWriter: ignoring write call to closed file")
else:
self.log_file.write(line)
self.file.write(line)

def on_message_received(self, msg):

Expand Down
Loading

0 comments on commit 6118964

Please sign in to comment.