From 97faa145f32a5fb35cfc919fcf32449b662e06f5 Mon Sep 17 00:00:00 2001 From: Brian Thorne Date: Wed, 31 May 2017 21:13:15 +1000 Subject: [PATCH 1/2] Scripts conflicted with can-utils Fixes #162 --- can/logger.py | 3 +++ can/player.py | 3 +++ can/server.py | 3 +++ doc/bin.rst | 20 ++++++++++---------- setup.py | 6 ------ 5 files changed, 19 insertions(+), 16 deletions(-) create mode 100644 can/logger.py create mode 100644 can/player.py create mode 100644 can/server.py diff --git a/can/logger.py b/can/logger.py new file mode 100644 index 000000000..593b76882 --- /dev/null +++ b/can/logger.py @@ -0,0 +1,3 @@ +from can.io import logger + +logger.main() diff --git a/can/player.py b/can/player.py new file mode 100644 index 000000000..ddf041e64 --- /dev/null +++ b/can/player.py @@ -0,0 +1,3 @@ +from can.io import player + +player.main() diff --git a/can/server.py b/can/server.py new file mode 100644 index 000000000..7239e78d1 --- /dev/null +++ b/can/server.py @@ -0,0 +1,3 @@ +from can.interfaces.remote import __main__ + +__main__.main() 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'] From 022b98429747f49ab1a7d2cb29e92384106a80ea Mon Sep 17 00:00:00 2001 From: Brian Thorne Date: Fri, 16 Jun 2017 23:33:49 +1000 Subject: [PATCH 2/2] move the main script functions #162 --- can/interfaces/remote/__main__.py | 64 --------------------- can/io/logger.py | 96 ------------------------------- can/io/player.py | 82 -------------------------- can/logger.py | 96 ++++++++++++++++++++++++++++++- can/player.py | 86 ++++++++++++++++++++++++++- can/server.py | 65 ++++++++++++++++++++- 6 files changed, 241 insertions(+), 248 deletions(-) delete mode 100644 can/interfaces/remote/__main__.py diff --git a/can/interfaces/remote/__main__.py b/can/interfaces/remote/__main__.py deleted file mode 100644 index 187729e24..000000000 --- a/can/interfaces/remote/__main__.py +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/env python -import logging -import argparse -import can -from can.interfaces import remote - -logging.basicConfig(format='%(asctime)-15s %(message)s', level=logging.INFO) - - -def main(): - parser = argparse.ArgumentParser(description="Remote CAN server") - - 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=3) - - 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". - The server will only serve this channel. Start additional servers at different - ports to share more channels.''') - - parser.add_argument('-i', '--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='''Force to use a specific bitrate. - This will override any requested bitrate by the clients.''') - - parser.add_argument('-H', '--host', - help='''Host to listen to (default 0.0.0.0).''', - default='0.0.0.0') - - parser.add_argument('-p', '--port', type=int, - help='''TCP port to listen on (default %d).''' % remote.DEFAULT_PORT, - default=remote.DEFAULT_PORT) - - 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) - - config = {} - if results.channel: - config["channel"] = results.channel - if results.interface: - config["bustype"] = results.interface - if results.bitrate: - config["bitrate"] = results.bitrate - - server = remote.RemoteServer(results.host, results.port, **config) - try: - server.serve_forever() - except KeyboardInterrupt: - pass - logging.info("Closing server") - server.server_close() - - -if __name__ == "__main__": - main() 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 index 593b76882..b2e9f5b31 100644 --- a/can/logger.py +++ b/can/logger.py @@ -1,3 +1,95 @@ -from can.io import logger +#!/usr/bin/env python +""" +logger.py logs CAN traffic to the terminal and to a file on disk. -logger.main() + 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 index ddf041e64..27257ab93 100644 --- a/can/player.py +++ b/can/player.py @@ -1,3 +1,85 @@ -from can.io import player +#!/usr/bin/env python +""" +Replays CAN traffic saved with can.logger back +to a CAN bus. -player.main() +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/server.py b/can/server.py index 7239e78d1..187729e24 100644 --- a/can/server.py +++ b/can/server.py @@ -1,3 +1,64 @@ -from can.interfaces.remote import __main__ +#!/usr/bin/env python +import logging +import argparse +import can +from can.interfaces import remote -__main__.main() +logging.basicConfig(format='%(asctime)-15s %(message)s', level=logging.INFO) + + +def main(): + parser = argparse.ArgumentParser(description="Remote CAN server") + + 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=3) + + 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". + The server will only serve this channel. Start additional servers at different + ports to share more channels.''') + + parser.add_argument('-i', '--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='''Force to use a specific bitrate. + This will override any requested bitrate by the clients.''') + + parser.add_argument('-H', '--host', + help='''Host to listen to (default 0.0.0.0).''', + default='0.0.0.0') + + parser.add_argument('-p', '--port', type=int, + help='''TCP port to listen on (default %d).''' % remote.DEFAULT_PORT, + default=remote.DEFAULT_PORT) + + 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) + + config = {} + if results.channel: + config["channel"] = results.channel + if results.interface: + config["bustype"] = results.interface + if results.bitrate: + config["bitrate"] = results.bitrate + + server = remote.RemoteServer(results.host, results.port, **config) + try: + server.serve_forever() + except KeyboardInterrupt: + pass + logging.info("Closing server") + server.server_close() + + +if __name__ == "__main__": + main()