diff --git a/can/io/logger.py b/can/io/logger.py index af75aadf1..8d4e1f719 100755 --- a/can/io/logger.py +++ b/can/io/logger.py @@ -1,27 +1,3 @@ -#!/usr/bin/env python -""" -logger.py logs CAN traffic to the terminal and to a file on disk. - - logger.py can0 - -See candump in the can-utils package for a C implementation. -Efficient filtering has been implemented for the socketcan backend. -For example the command - - logger.py can0 F03000:FFF000 - -Will filter for can frames with a can_id containing XXF03XXX. - -Dynamic Controls 2010 -""" -from __future__ import print_function -import datetime -import argparse -import time -import socket - -import can - from .asc import ASCWriter from .blf import BLFWriter from .csv import CSVWriter @@ -59,75 +35,3 @@ def __new__(cls, other, filename): return SqliteWriter(filename) else: return Printer(filename) - - -def main(): - parser = argparse.ArgumentParser(description="Log CAN traffic, printing messages to stdout or to a given file") - - parser.add_argument("-f", "--file_name", dest="log_file", - help="""Path and base log filename, extension can be .txt, .asc, .csv, .db, .npz""", - default=None) - - parser.add_argument("-v", action="count", dest="verbosity", - help='''How much information do you want to see at the command line? - You can add several of these e.g., -vv is DEBUG''', default=2) - - parser.add_argument('-c', '--channel', help='''Most backend interfaces require some sort of channel. - For example with the serial interface the channel might be a rfcomm device: "/dev/rfcomm0" - With the socketcan interfaces valid channel examples include: "can0", "vcan0"''') - - parser.add_argument('-i', '--interface', dest="interface", - help='''Specify the backend CAN interface to use. If left blank, - fall back to reading from configuration files.''', - choices=can.VALID_INTERFACES) - - parser.add_argument('--filter', help='''Comma separated filters can be specified for the given CAN interface: - : (matches when & mask == can_id & mask) - ~ (matches when & mask != can_id & mask) - ''', nargs=argparse.REMAINDER, default='') - - parser.add_argument('-b', '--bitrate', type=int, - help='''Bitrate to use for the CAN bus.''') - - results = parser.parse_args() - - verbosity = results.verbosity - - logging_level_name = ['critical', 'error', 'warning', 'info', 'debug', 'subdebug'][min(5, verbosity)] - can.set_logging_level(logging_level_name) - - can_filters = [] - if len(results.filter) > 0: - print('Adding filter/s', results.filter) - for filt in results.filter: - if ':' in filt: - _ = filt.split(":") - can_id, can_mask = int(_[0], base=16), int(_[1], base=16) - elif "~" in filt: - can_id, can_mask = filt.split("~") - can_id = int(can_id, base=16) | 0x20000000 # CAN_INV_FILTER - can_mask = int(can_mask, base=16) & socket.CAN_ERR_FLAG - can_filters.append({"can_id": can_id, "can_mask": can_mask}) - - config = {"can_filters": can_filters} - if results.interface: - config["bustype"] = results.interface - if results.bitrate: - config["bitrate"] = results.bitrate - bus = can.interface.Bus(results.channel, **config) - print('Can Logger (Started on {})\n'.format(datetime.datetime.now())) - logger = Logger(results.log_file) - - try: - while True: - msg = bus.recv(1) - if msg is not None: - logger(msg) - except KeyboardInterrupt: - pass - finally: - bus.shutdown() - logger.stop() - -if __name__ == "__main__": - main() diff --git a/can/io/player.py b/can/io/player.py index 22314be41..1bfd627f8 100755 --- a/can/io/player.py +++ b/can/io/player.py @@ -1,17 +1,7 @@ -#!/usr/bin/env python -""" -player.py replays CAN traffic saved with logger.py back -to a CAN bus. - -Similar to canplayer in the can-utils package. -""" from __future__ import print_function -import datetime import time -import argparse import logging -import can from .blf import BLFReader from .sqlite import SqlReader @@ -84,75 +74,3 @@ def __iter__(self): time.sleep(sleep_period) yield m - - -def main(): - parser = argparse.ArgumentParser(description="Replay CAN traffic") - - parser.add_argument("-f", "--file_name", dest="log_file", - help="""Path and base log filename, extension can be .txt, .asc, .csv, .db, .npz""", - default=None) - - parser.add_argument("-v", action="count", dest="verbosity", - help='''Also print can frames to stdout. - You can add several of these to enable debugging''', default=2) - - parser.add_argument('-c', '--channel', - help='''Most backend interfaces require some sort of channel. - For example with the serial interface the channel might be a rfcomm device: "/dev/rfcomm0" - With the socketcan interfaces valid channel examples include: "can0", "vcan0"''') - - parser.add_argument('-i', '--interface', dest="interface", - help='''Specify the backend CAN interface to use. If left blank, - fall back to reading from configuration files.''', - choices=can.VALID_INTERFACES) - - parser.add_argument('-b', '--bitrate', type=int, - help='''Bitrate to use for the CAN bus.''') - - parser.add_argument('--ignore-timestamps', dest='timestamps', - help='''Ignore timestamps (send all frames immediately with minimum gap between - frames)''', action='store_false') - - parser.add_argument('-g', '--gap', type=float, help=''' minimum time between replayed frames''') - parser.add_argument('-s', '--skip', type=float, default=60*60*24, - help=''' skip gaps greater than 's' seconds''') - - parser.add_argument('infile', metavar='input-file', type=str, - help='The file to replay. Supported types: .db, .blf') - - results = parser.parse_args() - - verbosity = results.verbosity - gap = 0.0001 if results.gap is None else results.gap - - logging_level_name = ['critical', 'error', 'warning', 'info', 'debug', 'subdebug'][min(5, verbosity)] - can.set_logging_level(logging_level_name) - - config = {} - if results.interface: - config["bustype"] = results.interface - if results.bitrate: - config["bitrate"] = results.bitrate - bus = can.interface.Bus(results.channel, **config) - - player = LogReader(results.infile) - - in_sync = MessageSync(player, timestamps=True, skip=results.skip) - - print('Can LogReader (Started on {})'.format( - datetime.datetime.now())) - - try: - for m in in_sync: - if verbosity >= 3: - print(m) - bus.send(m) - except KeyboardInterrupt: - pass - finally: - bus.shutdown() - - -if __name__ == "__main__": - main() diff --git a/can/logger.py b/can/logger.py new file mode 100644 index 000000000..b2e9f5b31 --- /dev/null +++ b/can/logger.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python +""" +logger.py logs CAN traffic to the terminal and to a file on disk. + + logger.py can0 + +See candump in the can-utils package for a C implementation. +Efficient filtering has been implemented for the socketcan backend. +For example the command + + logger.py can0 F03000:FFF000 + +Will filter for can frames with a can_id containing XXF03XXX. + +Dynamic Controls 2010 +""" +from __future__ import print_function +import datetime +import argparse +import socket + +import can +from can.io.logger import Logger + + +def main(): + parser = argparse.ArgumentParser(description="Log CAN traffic, printing messages to stdout or to a given file") + + parser.add_argument("-f", "--file_name", dest="log_file", + help="""Path and base log filename, extension can be .txt, .asc, .csv, .db, .npz""", + default=None) + + parser.add_argument("-v", action="count", dest="verbosity", + help='''How much information do you want to see at the command line? + You can add several of these e.g., -vv is DEBUG''', default=2) + + parser.add_argument('-c', '--channel', help='''Most backend interfaces require some sort of channel. + For example with the serial interface the channel might be a rfcomm device: "/dev/rfcomm0" + With the socketcan interfaces valid channel examples include: "can0", "vcan0"''') + + parser.add_argument('-i', '--interface', dest="interface", + help='''Specify the backend CAN interface to use. If left blank, + fall back to reading from configuration files.''', + choices=can.VALID_INTERFACES) + + parser.add_argument('--filter', help='''Comma separated filters can be specified for the given CAN interface: + : (matches when & mask == can_id & mask) + ~ (matches when & mask != can_id & mask) + ''', nargs=argparse.REMAINDER, default='') + + parser.add_argument('-b', '--bitrate', type=int, + help='''Bitrate to use for the CAN bus.''') + + results = parser.parse_args() + + verbosity = results.verbosity + + logging_level_name = ['critical', 'error', 'warning', 'info', 'debug', 'subdebug'][min(5, verbosity)] + can.set_logging_level(logging_level_name) + + can_filters = [] + if len(results.filter) > 0: + print('Adding filter/s', results.filter) + for filt in results.filter: + if ':' in filt: + _ = filt.split(":") + can_id, can_mask = int(_[0], base=16), int(_[1], base=16) + elif "~" in filt: + can_id, can_mask = filt.split("~") + can_id = int(can_id, base=16) | 0x20000000 # CAN_INV_FILTER + can_mask = int(can_mask, base=16) & socket.CAN_ERR_FLAG + can_filters.append({"can_id": can_id, "can_mask": can_mask}) + + config = {"can_filters": can_filters} + if results.interface: + config["bustype"] = results.interface + if results.bitrate: + config["bitrate"] = results.bitrate + bus = can.interface.Bus(results.channel, **config) + print('Can Logger (Started on {})\n'.format(datetime.datetime.now())) + logger = Logger(results.log_file) + + try: + while True: + msg = bus.recv(1) + if msg is not None: + logger(msg) + except KeyboardInterrupt: + pass + finally: + bus.shutdown() + logger.stop() + +if __name__ == "__main__": + main() diff --git a/can/player.py b/can/player.py new file mode 100644 index 000000000..27257ab93 --- /dev/null +++ b/can/player.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python +""" +Replays CAN traffic saved with can.logger back +to a CAN bus. + +Similar to canplayer in the can-utils package. +""" +from __future__ import print_function +import argparse +import datetime + +import can +from can.io.player import LogReader, MessageSync + + +def main(): + parser = argparse.ArgumentParser(description="Replay CAN traffic") + + parser.add_argument("-f", "--file_name", dest="log_file", + help="""Path and base log filename, extension can be .txt, .asc, .csv, .db, .npz""", + default=None) + + parser.add_argument("-v", action="count", dest="verbosity", + help='''Also print can frames to stdout. + You can add several of these to enable debugging''', default=2) + + parser.add_argument('-c', '--channel', + help='''Most backend interfaces require some sort of channel. + For example with the serial interface the channel might be a rfcomm device: "/dev/rfcomm0" + With the socketcan interfaces valid channel examples include: "can0", "vcan0"''') + + parser.add_argument('-i', '--interface', dest="interface", + help='''Specify the backend CAN interface to use. If left blank, + fall back to reading from configuration files.''', + choices=can.VALID_INTERFACES) + + parser.add_argument('-b', '--bitrate', type=int, + help='''Bitrate to use for the CAN bus.''') + + parser.add_argument('--ignore-timestamps', dest='timestamps', + help='''Ignore timestamps (send all frames immediately with minimum gap between + frames)''', action='store_false') + + parser.add_argument('-g', '--gap', type=float, help=''' minimum time between replayed frames''') + parser.add_argument('-s', '--skip', type=float, default=60*60*24, + help=''' skip gaps greater than 's' seconds''') + + parser.add_argument('infile', metavar='input-file', type=str, + help='The file to replay. Supported types: .db, .blf') + + results = parser.parse_args() + + verbosity = results.verbosity + gap = 0.0001 if results.gap is None else results.gap + + logging_level_name = ['critical', 'error', 'warning', 'info', 'debug', 'subdebug'][min(5, verbosity)] + can.set_logging_level(logging_level_name) + + config = {} + if results.interface: + config["bustype"] = results.interface + if results.bitrate: + config["bitrate"] = results.bitrate + bus = can.interface.Bus(results.channel, **config) + + player = LogReader(results.infile) + + in_sync = MessageSync(player, timestamps=True, skip=results.skip) + + print('Can LogReader (Started on {})'.format( + datetime.datetime.now())) + + try: + for m in in_sync: + if verbosity >= 3: + print(m) + bus.send(m) + except KeyboardInterrupt: + pass + finally: + bus.shutdown() + + +if __name__ == "__main__": + main() diff --git a/can/interfaces/remote/__main__.py b/can/server.py similarity index 100% rename from can/interfaces/remote/__main__.py rename to can/server.py diff --git a/doc/bin.rst b/doc/bin.rst index 6a18eb05f..92d1deb77 100644 --- a/doc/bin.rst +++ b/doc/bin.rst @@ -1,12 +1,12 @@ Scripts ======= -The following scripts are installed along with python-can. +The following modules are callable from python-can. -canlogger ---------- +can.logger +---------- -Command line help (``canlogger --help`` or ``python -m can.io.logger --help``):: +Command line help (``python -m can.logger --help``):: usage: canlogger [-h] [-f LOG_FILE] [-v] [-c CHANNEL] [-i {pcan,remote,ixxat,socketcan_ctypes,virtual,usb2can,nican,serial,kvaser,socketcan,socketcan_native}] @@ -37,10 +37,10 @@ Command line help (``canlogger --help`` or ``python -m can.io.logger --help``):: mask != can_id & mask) -canplayer ---------- +can.player +---------- -Command line help (``canplayer --help`` or ``python -m can.io.player --help``):: +Command line help (``python -m can.player --help``):: usage: canplayer [-h] [-f LOG_FILE] [-v] [-c CHANNEL] [-i {pcan,remote,ixxat,socketcan_ctypes,virtual,usb2can,nican,serial,kvaser,socketcan,socketcan_native}] @@ -75,10 +75,10 @@ Command line help (``canplayer --help`` or ``python -m can.io.player --help``):: -canserver ---------- +can.server +---------- -Command line help (``canserver --help`` or ``python -m can.interfaces.remote --help``):: +Command line help (``python -m can.server --help``):: usage: canserver [-h] [-v] [-c CHANNEL] [-i {pcan,remote,ixxat,socketcan_ctypes,virtual,usb2can,nican,serial,kvaser,socketcan,socketcan_native}] diff --git a/setup.py b/setup.py index ad0232e1d..eb8e52d01 100644 --- a/setup.py +++ b/setup.py @@ -26,12 +26,6 @@ "": ["CONTRIBUTORS.txt", "LICENSE.txt"], "doc": ["*.*"] }, - entry_points={"console_scripts": [ - "canlogger = can.io.logger:main", - "canplayer = can.io.player:main", - "canserver = can.interfaces.remote.__main__:main" - ]}, - # Tests can be run using `python setup.py test` test_suite="nose.collector", tests_require=['mock', 'nose']