From 57a9201b2027f16d7407b666d08f6c826e855e56 Mon Sep 17 00:00:00 2001 From: Miller Lowe Date: Mon, 20 Mar 2017 22:16:17 -0700 Subject: [PATCH 01/80] minor changes, still working on memoty object query --- bin/j1939_logger.py | 2 +- j1939/__init__.py | 14 ++++++++++---- j1939/arbitrationid.py | 20 ++++++++++++++++++-- 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/bin/j1939_logger.py b/bin/j1939_logger.py index d81329b..ea9e408 100644 --- a/bin/j1939_logger.py +++ b/bin/j1939_logger.py @@ -44,7 +44,7 @@ def parse_arguments(): 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('-x', '--hex-out', + parser.add_argument('-x', '--hex-out', action='store_true', help=textwrap.dedent('''\ hex data in output diff --git a/j1939/__init__.py b/j1939/__init__.py index 336b142..c39e58b 100644 --- a/j1939/__init__.py +++ b/j1939/__init__.py @@ -128,13 +128,13 @@ def notification(self, inboundMessage): logger.info('Message is j1939 msg') # - # Need to determine if it's a broadcase message or + # Need to determine if it's a broadcase message or # limit to listening nodes only # arbitration_id = ArbitrationID() arbitration_id.can_id = inboundMessage.arbitration_id - # redirect the AC stuff to the node processors. the rest can go + # redirect the AC stuff to the node processors. the rest can go # to the main queue. for (node, l_notifier) in self.node_queue_list: logger.info("node=%s, notifier=%s" % (node, l_notifier)) @@ -164,8 +164,8 @@ def connect(self, node): def recv(self, timeout=None): - logger.debug("Waiting for new message") - logger.debug("Timeout is {}".format(timeout)) + #logger.debug("Waiting for new message") + #logger.debug("Timeout is {}".format(timeout)) try: #m = self.rx_can_message_queue.get(timeout=timeout) rx_pdu = self.queue.get(timeout=timeout) @@ -275,6 +275,12 @@ def send(self, msg): # for receiving devices to acknowledge self._long_message_segment_queue.put_nowait(message) else: + logger.info("j1939.send: smaller than 8 bytes: \n %s" % msg) + logger.info("j1939.send: arbitration_id=%s" % msg.arbitration_id) + logger.info("j1939.send: arbitration_id.can_id=0x%08x" % msg.arbitration_id.can_id) + logger.info("j1939.send: extended_id=%s" % True) + logger.info("j1939.send: dlc=%s" % len(msg.data)) + logger.info("j1939.send: data=%s" % msg.data) can_message = Message(arbitration_id=msg.arbitration_id.can_id, extended_id=True, dlc=len(msg.data), diff --git a/j1939/arbitrationid.py b/j1939/arbitrationid.py index cebb654..f395930 100644 --- a/j1939/arbitrationid.py +++ b/j1939/arbitrationid.py @@ -1,6 +1,9 @@ +import logging + from j1939.pgn import PGN from j1939.constants import * +logger = logging.getLogger(__name__) class ArbitrationID(object): @@ -35,8 +38,21 @@ def __init__(self, priority=7, pgn=None, source_address=0, destination_address=N @property def can_id(self): + logger.info("j1939.arbitrationid.can_id: self.pgn.is_destination_specific") + logger.info(" self.pgn.is_destination_specific=%s" % self.pgn.is_destination_specific) + logger.info(" self.source_address=%s" % self.source_address) + logger.info(" self.destination_address_value=%s" % self.destination_address_value) + logger.info(" self.pgn.value=0x%08x" % self.pgn.value) + logger.info(" self.priority=%s" % self.priority) + if self.pgn.is_destination_specific: - return (self.source_address + (self.destination_address_value << 8) + (self.pgn.value << 8) + (self.priority << 26)) + # TODO: Not sure why I get the dest address in both the PGN and dest_addr... In + # any case if it's dest specificx and I have it in both, remove it from the pgn before + # building the CAN ID + if self.pgn.value & 0x00ff: + return (self.source_address + (self.destination_address_value << 8) + ((self.pgn.value & 0xff00) << 8) + (self.priority << 26)) + else: + return (self.source_address + (self.destination_address_value << 8) + (self.pgn.value << 8) + (self.priority << 26)) else: return (self.source_address + (self.pgn.value << 8) + (self.priority << 26)) @@ -64,7 +80,7 @@ def destination_address(self, addr): raise ValueError("PGN is not dest specific: {:04x}".format(self.pgn)) else: self.destination_address_value = addr - + @property def pgn(self): From e1894f0d9994ca4aeda22d73e65dee4f653c331e Mon Sep 17 00:00:00 2001 From: Jack Morgan Date: Thu, 8 Jun 2017 14:25:11 -0400 Subject: [PATCH 02/80] Fixed broken import and variable reference due to changes in the file structure of the python-can package --- bin/j1939_logger.py | 4 ++-- j1939/__init__.py | 2 +- setup.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bin/j1939_logger.py b/bin/j1939_logger.py index f83f68b..20e8928 100644 --- a/bin/j1939_logger.py +++ b/bin/j1939_logger.py @@ -95,7 +95,7 @@ def parse_arguments(): ''')) parser.add_argument('-i', '--interface', dest="interface", - #choices=can.interface.VALID_INTERFACES, + #choices=can.interfaces.VALID_INTERFACES, help=textwrap.dedent('''\ Specify the backend CAN interface to use. @@ -103,7 +103,7 @@ def parse_arguments(): {} Alternatively the CAN_INTERFACE environment variable can be set. - '''.format(can.interface.VALID_INTERFACES))) + '''.format(can.interfaces.VALID_INTERFACES))) return parser.parse_args() diff --git a/j1939/__init__.py b/j1939/__init__.py index bd1fb7e..b19baec 100644 --- a/j1939/__init__.py +++ b/j1939/__init__.py @@ -23,7 +23,7 @@ # By this stage the can.rc should have been set up from can import Message -from can.interfaces.interface import Bus as RawCanBus +from can.interface import Bus as RawCanBus from can.notifier import Notifier as canNotifier from can.bus import BusABC diff --git a/setup.py b/setup.py index 9cf87f0..e6ae81f 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ import logging from setuptools import setup, find_packages -__version__ = "0.1.0-alpha.1" +__version__ = "0.1.0-alpha.2" logging.basicConfig(level=logging.WARNING) From 4304ec21e720ece704a841b5b930bbaed984f652 Mon Sep 17 00:00:00 2001 From: Jack Morgan Date: Thu, 8 Jun 2017 14:47:05 -0400 Subject: [PATCH 03/80] Fixed a few comparison operator typos and whitespace cleanup --- bin/j1939_logger.py | 2 -- j1939/__init__.py | 44 +++++++++++++++++--------------------------- 2 files changed, 17 insertions(+), 29 deletions(-) diff --git a/bin/j1939_logger.py b/bin/j1939_logger.py index 20e8928..02ededf 100644 --- a/bin/j1939_logger.py +++ b/bin/j1939_logger.py @@ -21,7 +21,6 @@ logger.addHandler(ch) - def parse_arguments(): parser = argparse.ArgumentParser( description=textwrap.dedent("""\ @@ -135,7 +134,6 @@ def parse_arguments(): filters = json.load(args.filter) print("Loaded filters from file: ", filters) - print("args.channel : ", args.channel) print("args.interface: ", args.interface) print("filter PGN's : ", args.pgn) diff --git a/j1939/__init__.py b/j1939/__init__.py index b19baec..686beb2 100644 --- a/j1939/__init__.py +++ b/j1939/__init__.py @@ -12,13 +12,11 @@ import logging import pprint - try: from queue import Queue, Empty except ImportError: from Queue import Queue, Empty -import time import copy # By this stage the can.rc should have been set up @@ -41,9 +39,7 @@ #logger.setLevel(logging.DEBUG) - class Bus(BusABC): - """ A CAN Bus that implements the J1939 Protocol. @@ -64,12 +60,11 @@ def __init__(self, pdu_type=PDU, broadcast=True, *args, **kwargs): #self.rx_can_message_queue = Queue() self.queue = Queue() - self.node_queue_list = [] # Start with nothing - + self.node_queue_list = [] # Start with nothing super(Bus, self).__init__() self._pdu_type = pdu_type - self.timeout=1 + self.timeout = 1 self._long_message_throttler = threading.Thread(target=self._throttler_function) #self._long_message_throttler.daemon = True @@ -79,8 +74,7 @@ def __init__(self, pdu_type=PDU, broadcast=True, *args, **kwargs): self._long_message_segment_queue = Queue(0) if broadcast: - self.node_queue_list = [(None, self)] # Start with default logger Queue - # which will receive everything + self.node_queue_list = [(None, self)] # Start with default logger Queue which will receive everything # Convert J1939 filters into Raw Can filters @@ -112,7 +106,7 @@ def __init__(self, pdu_type=PDU, broadcast=True, *args, **kwargs): if 'timeout' in kwargs and kwargs['timeout'] is not None: if isinstance(kwargs['timeout'], (int, float)): - self.timeout=kwargs['timeout'] + self.timeout = kwargs['timeout'] else: raise ValueError("Bad timeout type") @@ -163,12 +157,12 @@ def notification(self, inboundMessage): rx_pdu = self._process_incoming_message(inboundMessage) self.queue.put(rx_pdu) - elif node and (arbitration_id.destination_address == None): + elif node and (arbitration_id.destination_address is None): logger.info("notification: sending broadcast to general queue") rx_pdu = self._process_incoming_message(inboundMessage) self.queue.put(rx_pdu) - elif node==None: + elif node is None: # always send the message to the logging queue logger.info("notification: sending to general queue") rx_pdu = self._process_incoming_message(inboundMessage) @@ -191,7 +185,6 @@ def connect(self, node): notifier = Notifier(Queue(), node.on_message_received, timeout=None) self.node_queue_list.append((node, notifier)) - def recv(self, timeout=None): #logger.debug("Waiting for new message") #logger.debug("Timeout is {}".format(timeout)) @@ -203,19 +196,17 @@ def recv(self, timeout=None): return None # TODO: Decide what to do with CAN errors - if None and m.is_error_frame: - logger.warning("Appears we got an error frame!") - - rx_error = CANError(timestamp=m.timestamp) - if rx_error is not None: - logger.info('Sending error "%s" to registered listeners.' % rx_error) - for listener in self.listeners: - if hasattr(listener, 'on_error_received'): - listener.on_error_received(rx_error) - - - - def send(self, msg): + # if m.is_error_frame: + # logger.warning("Appears we got an error frame!") + # + # rx_error = CANError(timestamp=m.timestamp) + # if rx_error is not None: + # logger.info('Sending error "%s" to registered listeners.' % rx_error) + # for listener in self.listeners: + # if hasattr(listener, 'on_error_received'): + # listener.on_error_received(rx_error) + + def send(self, msg, timeout=None): logger.info("j1939.send: msg=%s" % msg) messages = [] if len(msg.data) > 8: @@ -316,7 +307,6 @@ def send(self, msg): logger.info("j1939.send: calling can_bus_send: can-msg: %s" % can_message) self.can_bus.send(can_message) - def shutdown(self): self.can_notifier.running.clear() self.can_bus.shutdown() From d0b402dca5d576f5f221f0fce963cf6b2274b5b2 Mon Sep 17 00:00:00 2001 From: Miller Lowe Date: Tue, 20 Jun 2017 18:03:30 -0700 Subject: [PATCH 04/80] have mem-query working! Way slow but operational --- bin/j1939_mem_query.py | 85 +++++++++++++++++++++--------------- j1939/__init__.py | 99 +++++++++++++++++++++++++++++++++--------- j1939/arbitrationid.py | 24 +++++----- j1939/constants.py | 4 +- j1939/pdu.py | 24 ++++++++-- j1939/pgn.py | 8 ++-- 6 files changed, 166 insertions(+), 78 deletions(-) diff --git a/bin/j1939_mem_query.py b/bin/j1939_mem_query.py index 98afca2..b0d807d 100644 --- a/bin/j1939_mem_query.py +++ b/bin/j1939_mem_query.py @@ -7,7 +7,7 @@ import logging -lLevel = logging.DEBUG +lLevel = logging.WARN logger = logging.getLogger() logger.setLevel(lLevel) @@ -22,50 +22,63 @@ logger.addHandler(ch) logger.addHandler(fh) - -if __name__ == "__main__": - +def get_mem_object(channel='can0', bustype='socketcan', length=4, src=0, dest=0x17, pointer=0, extension=0): #from can.interfaces.interface import * - filters = [{'pgn':0xd900},{'pgn':0xd800},{'pgn':0xd700},{'pgn':0xd400}] - - bus = j1939.Bus(channel='can0', bustype='socketcan', j1939_filters=filters, timeout=0.01) - node = j1939.Node(bus, j1939.NodeName(), [19]) - bus.connect(node) - - node.start_address_claim() - node.claim_address(19) + countdown = 5 + result = -1 - time.sleep(5) - + bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01) pgn = j1939.PGN() - pgn.value = 0xd900 - logger.info("pgn: %s" % pgn) - aid = j1939.ArbitrationID(priority=7, pgn=pgn, source_address=0x19, destination_address=0x17) - logger.info("aid: %s" % aid) - if pgn.is_destination_specific: - logger.info("Destination Specific. dest=0x{:02x}".format(aid.destination_address)) - - - - data = [0x10, 0x13, 0x11, 0x00, 0x00, 0xe9, 0xff, 0xff] + pgn.value = 0xd917 + #logger.info("pgn: %s" % pgn) + aid = j1939.ArbitrationID(pgn=pgn, source_address=src, destination_address=dest) + #logger.info("aid: %s" % aid) + #if pgn.is_destination_specific: + # logger.info("Destination Specific. dest=0x{:02x}".format(aid.destination_address)) + +# PRI=6 PGN=0xd917 DST=0x17 SRC=0x00 08 13 15 00 00 e9 ff ff +# PRI=6 PGN=0xd800 DST=0x00 SRC=0x17 02 11 ff ff ff ff ff ff +# PRI=7 PGN=0xd700 DST=0x00 SRC=0x17 02 00 01 ff ff ff ff ff +# PRI=6 PGN=0xd800 DST=0x00 SRC=0x17 00 19 ff ff ff ff ff ff + + data = [length, 0x13, pointer, 0x00, 0x00, extension, 0xff, 0xff] pdu = j1939.PDU(timestamp=0.0, arbitration_id=aid, data=data, info_strings=None) pdu.display_radix='hex' logger.info("pdu: %s" % pdu) - logger.info("can Id: 0x{:08x}".format(pdu.arbitration_id.can_id)) + #logger.info("can Id: 0x{:08x}".format(pdu.arbitration_id.can_id)) bus.send(pdu) - - if 0: - try: - for msg in bus: - msg.display_radix = 'hex' - logger.info(msg) - except KeyboardInterrupt: - bus.shutdown() - logger.info() - - time.sleep(2) + + while countdown: + #print("Waiting for PDU") + pdu = bus.recv() + #print("received pdu: %s, pgn = 0x%04x" % (pdu, pdu.pgn)) + if pdu.pgn == 0xd700: + value = list(pdu.data) + length = value[0] + if length == 1: + result = value[1] + if length == 2: + result = (value[2] << 8) + value[1] + if length == 4: + result = (value[4] << 24) + (value[3] << 16) + (value[2] << 8) + value[1] + #print("length = %d" % length) + #print("value = %s" % value) + #rint("decoded value = %d" % (result)) + + + + + countdown -= 1 + bus.shutdown() + return result + +if __name__ == "__main__": + + for p, e in [(0x15, 0xe9), (0x00, 0xf1), (0x50, 0xe9), (0x75, 0xe9)]: + val = get_mem_object(length=4, src=0, dest=0x17, pointer=p, extension=e) + print("0x%02x-0x%02x = %d" % (p, e, val)) diff --git a/j1939/__init__.py b/j1939/__init__.py index bd1fb7e..cf6768e 100644 --- a/j1939/__init__.py +++ b/j1939/__init__.py @@ -23,10 +23,13 @@ # By this stage the can.rc should have been set up from can import Message +from can import set_logging_level as can_set_logging_level from can.interfaces.interface import Bus as RawCanBus from can.notifier import Notifier as canNotifier from can.bus import BusABC + + # Import our new message type from j1939.pdu import PDU from j1939.pgn import PGN @@ -38,9 +41,9 @@ logger = logging.getLogger(__name__) -#logger.setLevel(logging.DEBUG) - +logger.setLevel(logging.WARNING) +can_set_logging_level('warning') class Bus(BusABC): @@ -63,9 +66,14 @@ def __init__(self, pdu_type=PDU, broadcast=True, *args, **kwargs): logger.debug("Creating a new j1939 bus") #self.rx_can_message_queue = Queue() + self.queue = Queue() - self.node_queue_list = [] # Start with nothing + if 'name' in kwargs and kwargs['name'] is not None: + logger.info("J1939 Bus Q, %s, QQ=%s" % (kwargs['name'], self.queue) ) + else: + logger.info("J1939 Bus Q, UNNAMED, QQ=%s" % (self.queue) ) + self.node_queue_list = [] # Start with nothing super(Bus, self).__init__() self._pdu_type = pdu_type @@ -77,6 +85,10 @@ def __init__(self, pdu_type=PDU, broadcast=True, *args, **kwargs): self._incomplete_received_pdu_lengths = {} self._incomplete_transmitted_pdus = {} self._long_message_segment_queue = Queue(0) + self._key_generation_fcn = None + if 'keygen' in kwargs and kwargs['keygen'] is not None: + self._key_generation_fcn = kwargs['keygen'] + if broadcast: self.node_queue_list = [(None, self)] # Start with default logger Queue @@ -133,7 +145,7 @@ def notification(self, inboundMessage): # Only J1939 messages (i.e. 29-bit IDs) should go further than this point. # Non-J1939 systems can co-exist with J1939 systems, but J1939 doesn't care # about the content of their messages. - logger.info('notification: Message is j1939 msg') + logger.debug('notification: Message is j1939 msg') # # Need to determine if it's a broadcase message or @@ -144,10 +156,10 @@ def notification(self, inboundMessage): logger.debug('notification: ArbitrationID = %s' % (arbitration_id)) for (node, l_notifier) in self.node_queue_list: - logger.info("notification: node=%s" % (node)) - logger.info(" notifier=%s" % (l_notifier)) - logger.info(" arbitration_id.pgn=%s" % (arbitration_id.pgn)) - logger.info(" destination_address=%s" % (arbitration_id.destination_address)) + logger.debug("notification: node=%s" % (node)) + logger.debug(" notifier=%s" % (l_notifier)) + logger.debug(" arbitration_id.pgn=%s" % (arbitration_id.pgn)) + logger.debug(" destination_address=%s" % (arbitration_id.destination_address)) # redirect the AC stuff to the node processors. the rest can go # to the main queue. @@ -159,23 +171,26 @@ def notification(self, inboundMessage): # if node has the destination address, do something with the PDU # elif node and (arbitration_id.destination_address in node.address_list): - logger.info("notification: sending to general queue") rx_pdu = self._process_incoming_message(inboundMessage) - self.queue.put(rx_pdu) + if rx_pdu: + logger.info("WP02: notification: sent to general queue: %s QQ=%s" % (rx_pdu, self.queue)) + self.queue.put(rx_pdu) elif node and (arbitration_id.destination_address == None): logger.info("notification: sending broadcast to general queue") rx_pdu = self._process_incoming_message(inboundMessage) + logger.info("WP01: notification: sent broadcast to general queue: %s QQ=%s" % (rx_pdu, self.queue)) self.queue.put(rx_pdu) elif node==None: # always send the message to the logging queue logger.info("notification: sending to general queue") rx_pdu = self._process_incoming_message(inboundMessage) + logger.info("WP03: notification: sent 'none' to general queue") self.queue.put(rx_pdu) else: - logger.info("notification: pdu dropped: %s\n\n" % inboundMessage) + logger.info("WP04: notification: pdu dropped: %s\n\n" % inboundMessage) else: logger.info("Received non J1939 message (ignoring)") @@ -195,11 +210,14 @@ def connect(self, node): def recv(self, timeout=None): #logger.debug("Waiting for new message") #logger.debug("Timeout is {}".format(timeout)) + logger.debug('J1939 Bus recv(), waiting on QQ=%s with timeout %s' % (self.queue, timeout)) try: #m = self.rx_can_message_queue.get(timeout=timeout) rx_pdu = self.queue.get(timeout=timeout) + logger.info('J1939 Bus recv() successful QQ=%s, pdu:%s' % (self.queue, rx_pdu)) return rx_pdu except Empty: + logger.debug('J1939 Bus recv() timed out' % ()) return None # TODO: Decide what to do with CAN errors @@ -306,14 +324,14 @@ def send(self, msg): self._long_message_segment_queue.put_nowait(message) else: msg.display_radix = 'hex' - logger.info("j1939.send: calling can_bus_send: j1939-msg: %s" % (msg)) - logger.info("j1939.send: calling can_bus_send: can_id %x" % (msg.arbitration_id.can_id)) + logger.debug("j1939.send: calling can_bus_send: j1939-msg: %s" % (msg)) + logger.debug("j1939.send: calling can_bus_send: can_id %x" % (msg.arbitration_id.can_id)) can_message = Message(arbitration_id=msg.arbitration_id.can_id, extended_id=True, dlc=len(msg.data), data=msg.data) - logger.info("j1939.send: calling can_bus_send: can-msg: %s" % can_message) + logger.debug("j1939.send: calling can_bus_send: can-msg: %s" % can_message) self.can_bus.send(can_message) @@ -323,29 +341,68 @@ def shutdown(self): #self.j1939_notifier.running.clear() super(Bus, self).shutdown() + def _send_key_response(self, pdu): + logger.info("PI04: _send_key_response src=%d, pdu=%s" % (pdu.source, pdu)) + src = pdu.destination + dest = pdu.source + logger.info("PI05: new PDU, src=%d, dest=%d" % (src, dest)) + pdu.destination = dest + logger.info("PI05: new PDU.dest = %d" % (pdu.destination)) + pdu.source = src + logger.info("PI06: newPDU = %s" % (pdu)) + + logger.info("PI04: _send_key_response src/dest flipped pdu=%s" % (pdu)) + assert(pdu.data[0] == 4) # only support long key for now + + data = pdu.data + assert(len(data) == 8) + + seed = (data[5] << 24) + (data[4] << 16) + (data[3] << 8) + data[2] + key = self._key_generation_fcn(seed) + + logger.info("PI03: _send_key_response Seed: 0x%08x yields key: 0x%08x" % (seed, key)) + + data[5] = (key >> 24) & 0xff + data[4] = (key >> 16) & 0xff + data[3] = (key >> 8) & 0xff + data[2] = (key) & 0xff + data[1] = 1 + + pdu.data = data + + self.send(pdu) + + return None + + + def _process_incoming_message(self, msg): - logger.debug("Processing incoming message: \n %s" % (msg)) + logger.info("PI01: Processing incoming message: \n msg= %s" % (msg)) arbitration_id = ArbitrationID() arbitration_id.can_id = msg.arbitration_id if arbitration_id.pgn.is_destination_specific: arbitration_id.pgn.value -= arbitration_id.pgn.pdu_specific + pdu = self._pdu_type(timestamp=msg.timestamp, data=msg.data, info_strings=[]) pdu.arbitration_id.can_id = msg.arbitration_id pdu.info_strings = [] - logging.debug(pdu) + + logger.info("PI02: arbitration_id.pgn.value == 0x%04x" % arbitration_id.pgn.value) if arbitration_id.pgn.value == PGN_TP_CONNECTION_MANAGEMENT: - logger.debug("PGN_TP_CONNECTION_MANAGEMENT") + logger.info("PGN_TP_CONNECTION_MANAGEMENT") retval = self._connection_management_handler(pdu) elif arbitration_id.pgn.value == PGN_TP_DATA_TRANSFER: - logger.debug("PGN_TP_DATA_TRANSFER") + logger.info("PGN_TP_DATA_TRANSFER") retval = self._data_transfer_handler(pdu) + elif arbitration_id.pgn.value == PGN_TP_SEED_REQUEST: + logger.info("PGN_TP_SEED_REQUEST") + retval = self._send_key_response(pdu) else: - logger.debug("PGN_PDU") + logger.info("PGN_PDU") retval = pdu - logger.debug("\n") - logging.debug("_process_incoming_message: returning %s" % (retval)) + logger.info("_process_incoming_message: returning %s" % (retval)) return retval def _connection_management_handler(self, msg): diff --git a/j1939/arbitrationid.py b/j1939/arbitrationid.py index 5583430..2cab26e 100644 --- a/j1939/arbitrationid.py +++ b/j1939/arbitrationid.py @@ -41,7 +41,7 @@ def __init__(self, priority=7, pgn=None, source_address=0, destination_address=N if destination_address >= 0 and destination_address <= 255: self.destination_address_value = destination_address if self.destination_address_value != pgn.pdu_specific: - logger.info("self.destination_address_value = %x, pgn.pdu_specific = %x" % + logger.debug("self.destination_address_value = %x, pgn.pdu_specific = %x" % (self.destination_address_value, pgn.pdu_specific)) assert( self.destination_address_value == pgn.pdu_specific) @@ -52,10 +52,10 @@ def __init__(self, priority=7, pgn=None, source_address=0, destination_address=N @property def can_id(self): - logger.info("can_id property: self.pgn.is_destination_specific=%s" % self.pgn.is_destination_specific) + logger.debug("can_id property: self.pgn.is_destination_specific=%s" % self.pgn.is_destination_specific) if self.pgn.is_destination_specific: - logger.info("can_id: self.pgn.is_destination_specific, dest=%x, pgn_value=%x, pdu_format=0x%x, pdu_specific=0x%x, pri=%x" % + logger.debug("can_id: self.pgn.is_destination_specific, dest=%x, pgn_value=%x, pdu_format=0x%x, pdu_specific=0x%x, pri=%x" % (self.destination_address_value, self.pgn.value, self.pgn.pdu_format, @@ -65,10 +65,10 @@ def can_id(self): retval = (self.source_address + ((self.pgn.value & 0xff00) + (self.destination_address_value) << 8)+ (self.priority << 26)) - logger.info("can_id: retval=0x%08x" % (retval)) + logger.debug("can_id: retval=0x%08x" % (retval)) return retval else: - logger.info("can_id: NOT! self.pgn.is_destination_specific") + logger.debug("can_id: NOT! self.pgn.is_destination_specific") return (self.source_address + (self.pgn.value << 8) + (self.priority << 26)) @can_id.setter @@ -76,7 +76,7 @@ def can_id(self, canid): """ Int between 0 and (2**29) - 1 """ - logger.info("can_id setter: canid=0x%08x" % (canid)) + logger.debug("can_id setter: canid=0x%08x" % (canid)) self.priority = (canid & 0x1C000000) >> 26 self.pgn = PGN().from_can_id(canid) self.source_address = canid & 0x000000FF @@ -84,7 +84,7 @@ def can_id(self, canid): self.destination_address_value = (canid & 0x0000FF00) >> 8 - logger.info("can_id: canid=0x%08x, priority=%x, pdu_format=%x, pdu_specific=%x, src=%x" % + logger.debug("can_id: canid=0x%08x, priority=%x, pdu_format=%x, pdu_specific=%x, src=%x" % (canid, self.priority, self.pgn.pdu_format, @@ -98,11 +98,11 @@ def destination_address(self): return None @destination_address.setter - def destination_address(self, addr): + def destination_address(self, value): if not self.pgn.is_destination_specific: raise ValueError("PGN is not dest specific: {:04x}".format(self.pgn)) else: - self.destination_address_value = addr + self.destination_address_value = value @property @@ -119,11 +119,11 @@ def pgn(self, other): self._pgn = other def __str__(self): - logger.info("arbitrationid.__str__: pri:%s, pgn:%s, dest:%s, src:%s" % - (self.priority, self.pgn, self.destination_address_value, self.source_address)) + logger.debug("arbitrationid.__str__: ids:%d, pri:%s, pgn:%s, dest:%s, src:%s" % + (self.pgn.is_destination_specific, self.priority, self.pgn, self.destination_address_value, self.source_address)) if self.pgn.is_destination_specific: retval = "PRI=%d PGN=%6s DST=0x%.2x SRC=0x%.2x" % ( self.priority, self.pgn, self.destination_address_value, self.source_address) else: - retval = "PRI=%d PGN=%6s SRC=0x%.2x " % (self.priority, self.pgn, self.source_address) + retval = "PRI=%d PGN=%6s SRC=0x%.2x" % (self.priority, self.pgn, self.source_address) return retval diff --git a/j1939/constants.py b/j1939/constants.py index 4f4e34c..c68f3ca 100644 --- a/j1939/constants.py +++ b/j1939/constants.py @@ -1,6 +1,7 @@ # transport protocol PGNs PGN_TP_CONNECTION_MANAGEMENT = 0xec00 PGN_TP_DATA_TRANSFER = 0xeb00 +PGN_TP_SEED_REQUEST = 0xd400 # address claim PGNs PGN_AC_ADDRESS_CLAIMED = 0xee00 @@ -13,7 +14,8 @@ PGN_TP_DATA_TRANSFER: "PGN_TP_DATA_TRANSFER", PGN_AC_ADDRESS_CLAIMED: "PGN_AC_ADDRESS_CLAIMED", PGN_AC_COMMANDED_ADDRESS: "PGN_AC_COMMANDED_ADDRESS", - PGN_REQUEST_FOR_PGN: "PGN_REQUEST_FOR_PGN" + PGN_REQUEST_FOR_PGN: "PGN_REQUEST_FOR_PGN", + PGN_TP_SEED_REQUEST: "PGN_TP_SEED_REQUEST" } DESTINATION_ADDRESS_NULL = 254 diff --git a/j1939/pdu.py b/j1939/pdu.py index 1e7253a..a0ddb4e 100644 --- a/j1939/pdu.py +++ b/j1939/pdu.py @@ -34,7 +34,7 @@ def __init__(self, timestamp=0.0, arbitration_id=None, data=None, info_strings=N if arbitration_id: assert(isinstance(arbitration_id, ArbitrationID)) self.arbitration_id = arbitration_id - self.data = self._check_data(data) + self._data = self._check_data(data) self.info_strings = info_strings self.radix=RADIX_DECIMAL @@ -44,7 +44,7 @@ def __eq__(self, other): return False if self.pgn != other.pgn: return False - if self.data != other.data: + if self._data != other.data: return False if self.source != other.source: return False @@ -53,8 +53,12 @@ def __eq__(self, other): return True @property - def dat(self): - return self.data + def data(self): + return self._data + + @data.setter + def data(self, data): + self._data = data @property def pgn(self): @@ -68,11 +72,21 @@ def destination(self): """Destination address of the message""" return self.arbitration_id.destination_address + @destination.setter + def destination(self, destination): + """Destination address of the message""" + self.arbitration_id.destination_address = destination + @property def source(self): """Source address of the message""" return self.arbitration_id.source_address + @source.setter + def source(self, source): + """Source address of the message""" + self.arbitration_id.source_address = source + @property def is_address_claim(self): return self.pgn == PGN_AC_ADDRESS_CLAIMED @@ -160,6 +174,8 @@ def __str__(self): :return: A string representation of this message. """ + #logger.info("PI07: stringify PDU") + if self.radix == RADIX_HEX: data_string = " ".join("{:02x}".format(byte) for byte in self.data) else: diff --git a/j1939/pgn.py b/j1939/pgn.py index e701539..9931559 100644 --- a/j1939/pgn.py +++ b/j1939/pgn.py @@ -38,7 +38,7 @@ def value(self, value): @staticmethod def from_value(pgn_value): - logger.info("PGN.@from_value, pgn_value=0x%08x" % (pgn_value)) + logger.debug("PGN.@from_value, pgn_value=0x%08x" % (pgn_value)) pgn = PGN() pgn.reserved_flag = (pgn_value & 0x020000) >> 17 pgn.data_page_flag = (pgn_value & 0x010000) >> 16 @@ -48,15 +48,15 @@ def from_value(pgn_value): @staticmethod def from_can_id(canid): - logger.info("PGN.@from_can_id, value=0x%08x" % (canid)) + #logger.debug("PGN.@from_can_id, value=0x%08x" % (canid)) canid = canid>>8 pgn = PGN() - logger.info("PGN.@from_can_id, value=0x%08x" % (canid)) + #logger.debug("PGN.@from_can_id, value=0x%08x" % (canid)) pgn.reserved_flag = (canid & 0x020000) >> 17 pgn.data_page_flag = (canid & 0x010000) >> 16 pgn.pdu_format = (canid & 0x00FF00) >> 8 pgn.pdu_specific = canid & 0x0000FF - logger.info("PGN.@from_can_id, res=%d, dp=%d, pdu_format=0x%02x, pdu_specific=0x%02x" % + logger.debug("PGN.@from_can_id, res=%d, dp=%d, pdu_format=0x%02x, pdu_specific=0x%02x" % (pgn.reserved_flag, pgn.data_page_flag, pgn.pdu_format, pgn.pdu_specific)) return pgn From be06691fca54e4e9dd745e64670fb7ac76ea9598 Mon Sep 17 00:00:00 2001 From: Miller Lowe Date: Wed, 21 Jun 2017 10:26:16 -0700 Subject: [PATCH 05/80] Mem-Query script is working. OK to be included in another script to query J1939 gauge elements. --- bin/j1939_mem_query.py | 107 ++++++++++++++++++++++++---------------- examples/j1939_nodes.py | 14 +----- j1939/__init__.py | 1 - 3 files changed, 65 insertions(+), 57 deletions(-) diff --git a/bin/j1939_mem_query.py b/bin/j1939_mem_query.py index b0d807d..18a2ebb 100644 --- a/bin/j1939_mem_query.py +++ b/bin/j1939_mem_query.py @@ -1,60 +1,31 @@ from __future__ import print_function -import can import j1939 -import time -import threading - -import logging - -lLevel = logging.WARN - -logger = logging.getLogger() -logger.setLevel(lLevel) -ch = logging.StreamHandler() -fh = logging.FileHandler('/tmp/j1939_nodes.log') -fh.setLevel(lLevel) -ch.setLevel(lLevel) -formatter = logging.Formatter('%(asctime)s | %(name)20s | %(threadName)20s | %(levelname)5s | %(message)s') -chformatter = logging.Formatter('%(name)25s | %(threadName)10s | %(levelname)5s | %(message)s') -fh.setFormatter(formatter) -ch.setFormatter(chformatter) -logger.addHandler(ch) -logger.addHandler(fh) - -def get_mem_object(channel='can0', bustype='socketcan', length=4, src=0, dest=0x17, pointer=0, extension=0): + +if __name__ == "__main__": + import traceback + import timeit + import time + +def get_mem_object_single(channel='can0', bustype='socketcan', length=4, src=0, dest=0x17, pointer=0, extension=0): #from can.interfaces.interface import * - countdown = 5 + countdown = 10 result = -1 bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01) pgn = j1939.PGN() pgn.value = 0xd917 - #logger.info("pgn: %s" % pgn) aid = j1939.ArbitrationID(pgn=pgn, source_address=src, destination_address=dest) - #logger.info("aid: %s" % aid) - #if pgn.is_destination_specific: - # logger.info("Destination Specific. dest=0x{:02x}".format(aid.destination_address)) - -# PRI=6 PGN=0xd917 DST=0x17 SRC=0x00 08 13 15 00 00 e9 ff ff -# PRI=6 PGN=0xd800 DST=0x00 SRC=0x17 02 11 ff ff ff ff ff ff -# PRI=7 PGN=0xd700 DST=0x00 SRC=0x17 02 00 01 ff ff ff ff ff -# PRI=6 PGN=0xd800 DST=0x00 SRC=0x17 00 19 ff ff ff ff ff ff data = [length, 0x13, pointer, 0x00, 0x00, extension, 0xff, 0xff] pdu = j1939.PDU(timestamp=0.0, arbitration_id=aid, data=data, info_strings=None) pdu.display_radix='hex' - logger.info("pdu: %s" % pdu) - - #logger.info("can Id: 0x{:08x}".format(pdu.arbitration_id.can_id)) bus.send(pdu) while countdown: - #print("Waiting for PDU") pdu = bus.recv() - #print("received pdu: %s, pgn = 0x%04x" % (pdu, pdu.pgn)) if pdu.pgn == 0xd700: value = list(pdu.data) length = value[0] @@ -64,21 +35,71 @@ def get_mem_object(channel='can0', bustype='socketcan', length=4, src=0, dest=0x result = (value[2] << 8) + value[1] if length == 4: result = (value[4] << 24) + (value[3] << 16) + (value[2] << 8) + value[1] - #print("length = %d" % length) - #print("value = %s" % value) - #rint("decoded value = %d" % (result)) + break # got what I was waiting for + countdown -= 1 + bus.shutdown() + return result - countdown -= 1 +def get_mem_object(bus=None, length=4, src=0, dest=0x17, pointer=0, extension=0): + countdown = 10 + result = -1 - bus.shutdown() + pgn = j1939.PGN() + pgn.value = 0xd917 + aid = j1939.ArbitrationID(pgn=pgn, source_address=src, destination_address=dest) + + data = [length, 0x13, pointer, 0x00, 0x00, extension, 0xff, 0xff] + pdu = j1939.PDU(timestamp=0.0, arbitration_id=aid, data=data, info_strings=None) + pdu.display_radix='hex' + + bus.send(pdu) + + while countdown: + pdu = bus.recv() + if pdu.pgn == 0xd700: + value = list(pdu.data) + length = value[0] + if length == 1: + result = value[1] + if length == 2: + result = (value[2] << 8) + value[1] + if length == 4: + result = (value[4] << 24) + (value[3] << 16) + (value[2] << 8) + value[1] + break # got what I was waiting for + + countdown -= 1 return result if __name__ == "__main__": + # queries a couple objects but setting up the full stack and bus for + # each takes a long time. + start = timeit.default_timer() for p, e in [(0x15, 0xe9), (0x00, 0xf1), (0x50, 0xe9), (0x75, 0xe9)]: - val = get_mem_object(length=4, src=0, dest=0x17, pointer=p, extension=e) + val = get_mem_object_single(length=4, src=0, dest=0x17, pointer=p, extension=e) print("0x%02x-0x%02x = %d" % (p, e, val)) + print("elapsed = %s s" % (timeit.default_timer() - start)) + + + # queries the same objects but in a single bus instance, should be a tad faster. + start = timeit.default_timer() + try: + jbus = j1939.Bus(channel='can0', bustype='socketcan', timeout=0.01) + for p, e in [(0x15, 0xe9), (0x00, 0xf1), (0x50, 0xe9), (0x75, 0xe9)]: + val = get_mem_object(jbus, length=4, src=0, dest=0x17, pointer=p, extension=e) + print("0x%02x-0x%02x = %d" % (p, e, val)) + except: + traceback.print_exc() + + pass + jbus.shutdown() + print("elapsed = %s s" % (timeit.default_timer() - start)) + + + start = timeit.default_timer() + time.sleep(5) + print("elapsed = %s s" % (timeit.default_timer() - start)) diff --git a/examples/j1939_nodes.py b/examples/j1939_nodes.py index 5f0a32b..931ba41 100644 --- a/examples/j1939_nodes.py +++ b/examples/j1939_nodes.py @@ -1,12 +1,10 @@ from __future__ import print_function -from time import sleep - import can import j1939 import logging -lLevel = logging.DEBUG +lLevel = logging.WARNING logger = logging.getLogger() logger.setLevel(lLevel) @@ -52,18 +50,8 @@ def send_j1939(): msg = j1939.PDU(arbitration_id=arbitration_id, data=[0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80]) - sleep(0.5) node1.start_address_claim() - sleep(0.5) - - if 0: - try: - bus.send(msg) - logging.debug("Message sent on {}".format(bus.channel_info)) - except can.CanError: - logging.debug("Message NOT sent") - sleep(1) bus.flush_tx_buffer() bus.shutdown() diff --git a/j1939/__init__.py b/j1939/__init__.py index cf6768e..f30e736 100644 --- a/j1939/__init__.py +++ b/j1939/__init__.py @@ -18,7 +18,6 @@ except ImportError: from Queue import Queue, Empty -import time import copy # By this stage the can.rc should have been set up From 2133c439601c2d56f81d3f934641cae0d9446163 Mon Sep 17 00:00:00 2001 From: Miller Lowe Date: Wed, 21 Jun 2017 11:36:11 -0700 Subject: [PATCH 06/80] Reduce time for demo wait --- bin/j1939_mem_query.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/j1939_mem_query.py b/bin/j1939_mem_query.py index 18a2ebb..b0316d9 100644 --- a/bin/j1939_mem_query.py +++ b/bin/j1939_mem_query.py @@ -100,6 +100,7 @@ def get_mem_object(bus=None, length=4, src=0, dest=0x17, pointer=0, extension=0) print("elapsed = %s s" % (timeit.default_timer() - start)) + # just a blurb to see start = timeit.default_timer() - time.sleep(5) + time.sleep(1) print("elapsed = %s s" % (timeit.default_timer() - start)) From 3ed64f4b260b58f86bdf4e3b4b552d9806f2539f Mon Sep 17 00:00:00 2001 From: Miller Lowe Date: Wed, 21 Jun 2017 13:18:49 -0700 Subject: [PATCH 07/80] If a seed to key funciton is not registered, don't try to convert and provide a key. Broke the logger trying to provide keys for an ECU! (oops) --- j1939/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/j1939/__init__.py b/j1939/__init__.py index e14fccd..10e8372 100644 --- a/j1939/__init__.py +++ b/j1939/__init__.py @@ -348,6 +348,8 @@ def _send_key_response(self, pdu): assert(len(data) == 8) seed = (data[5] << 24) + (data[4] << 16) + (data[3] << 8) + data[2] + if self._key_generation_fcn == None: + return None key = self._key_generation_fcn(seed) logger.info("PI03: _send_key_response Seed: 0x%08x yields key: 0x%08x" % (seed, key)) From 1770bbc83301ed70d30c98c88564bc35d002dba8 Mon Sep 17 00:00:00 2001 From: Miller Lowe Date: Wed, 21 Jun 2017 16:20:32 -0700 Subject: [PATCH 08/80] replace a couple '==' comparisins to 'is' for form's sake. (and performance) --- j1939/__init__.py | 2 +- j1939/arbitrationid.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/j1939/__init__.py b/j1939/__init__.py index 10e8372..fa8d47e 100644 --- a/j1939/__init__.py +++ b/j1939/__init__.py @@ -348,7 +348,7 @@ def _send_key_response(self, pdu): assert(len(data) == 8) seed = (data[5] << 24) + (data[4] << 16) + (data[3] << 8) + data[2] - if self._key_generation_fcn == None: + if self._key_generation_fcn is None: return None key = self._key_generation_fcn(seed) diff --git a/j1939/arbitrationid.py b/j1939/arbitrationid.py index 2cab26e..153f1f9 100644 --- a/j1939/arbitrationid.py +++ b/j1939/arbitrationid.py @@ -5,8 +5,6 @@ import logging logger = logging.getLogger(__name__) -logger = logging.getLogger(__name__) - class ArbitrationID(object): def __init__(self, priority=7, pgn=None, source_address=0, destination_address=None): @@ -25,7 +23,7 @@ def __init__(self, priority=7, pgn=None, source_address=0, destination_address=N """ self.priority = priority - if pgn == None: + if pgn is None: pgn = PGN() if pgn and (not isinstance(pgn, PGN)): @@ -44,6 +42,8 @@ def __init__(self, priority=7, pgn=None, source_address=0, destination_address=N logger.debug("self.destination_address_value = %x, pgn.pdu_specific = %x" % (self.destination_address_value, pgn.pdu_specific)) + print("self.destination_address_value = %x, pgn.pdu_specific = %x" % + (self.destination_address_value, pgn.pdu_specific)) assert( self.destination_address_value == pgn.pdu_specific) else: raise ValueError("desttiantion address must be in range (0-255)") From 7cd8bca1373b726f0d26f5bfd9a908b249f8d908 Mon Sep 17 00:00:00 2001 From: Miller Lowe Date: Thu, 22 Jun 2017 11:31:09 -0700 Subject: [PATCH 09/80] First cut at example memory object writer. --- bin/j1939_mem_set.py | 139 +++++++++++++++++++++++++++++++++++++++++ j1939/__init__.py | 2 +- j1939/arbitrationid.py | 4 +- 3 files changed, 141 insertions(+), 4 deletions(-) create mode 100644 bin/j1939_mem_set.py diff --git a/bin/j1939_mem_set.py b/bin/j1939_mem_set.py new file mode 100644 index 0000000..0472ccb --- /dev/null +++ b/bin/j1939_mem_set.py @@ -0,0 +1,139 @@ +from __future__ import print_function + + +_name = "J1939 Memory-Object Writer" +__version__ = "1.0.0" +__date__ = "06/22/2017" +__exp__ = "(sabot)" # (Release Version) +title = "%s Version: %s %s %s" % (_name, __version__, __date__, __exp__) + + + +import j1939 + +# +# for responding to seed/key requests provide your own keyGenerator +# class.. +# mine is returned in a SeedToKey meghod of a Genkey class that sits elsewhere +# on my PYTHONPATH +# +# TODO: use a better baseclass override model. +# +try: + import genkey + security = genkey.GenKey() + print("Genkey Loaded") +except: + # Stuff in a fake genKey responder. Pretty much just needs a + # reference to any class that can convert a Seed to a Key.. For + # obvious reasons I'm not posting mine + print("Genkey Not loaded, This one will generate garbage keys") + class Genkey: + def SeedToKey(self, seed): + return 0x12345678; + + security = Genkey() + +def set_mem_object_single(channel='can0', bustype='socketcan', length=4, src=0, dest=0x17, pointer=0, extension=0, value=0): + #from can.interfaces.interface import * + + countdown = 10 + result = -1 + + bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01, keygen=security.SeedToKey) + + #dm14pgn = j1939.PGN() + dm14data = [length, 0x15, pointer, 0x00, 0x00, extension, 0xff, 0xff] + + dm14pgn = j1939.PGN(pdu_format=0xd9, pdu_specific=dest) + #dm14pgn = j1939.PGN().value = 0xd917 + #print ("dm14pgn=", dm14pgn) + #print ("dm14pgn.destination_address_value=", dm14pgn.destination_address_value) + #print ("dm14pgn.pdu_specific=", dm14pgn.pdu_specific) + dm14aid = j1939.ArbitrationID(pgn=dm14pgn, source_address=src, destination_address=dest) + dm14pdu = j1939.PDU(timestamp=0.0, arbitration_id=dm14aid, data=dm14data, info_strings=None) + dm14pdu.display_radix='hex' + + + bus.send(dm14pdu) + + sendBuffer = [length, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff] + if length == 1: + sendBuffer[1] = value; + elif length == 2: + sendBuffer[1] = value & 0xff + sendBuffer[2] = (value >> 8) & 0xff + elif length == 3: + sendBuffer[1] = value & 0xff + sendBuffer[2] = (value >> 8) & 0xff + sendBuffer[3] = (value >> 16) & 0xff + elif length == 4: + sendBuffer[1] = value & 0xff + sendBuffer[2] = (value >> 8) & 0xff + sendBuffer[3] = (value >> 16) & 0xff + sendBuffer[4] = (value >> 24) & 0xff + else: + raise ValueError("Don't know how to send a %d byte object" % length) + + dm16pgn = j1939.PGN(pdu_format=0xd7, pdu_specific=dest) + dm16aid = j1939.ArbitrationID(pgn=dm16pgn, source_address=src, destination_address=dest) + dm16pdu = j1939.PDU(timestamp=0.0, arbitration_id=dm16aid, data=sendBuffer) + dm16pdu.display_radix='hex' + + + # Wait around for a while looking for the second proceed + + countdown=10 + proceedCount = 0; + while countdown: + countdown -= 1 + rcvPdu = bus.recv(2) + if rcvPdu: + rcvPdu.display_radix='hex' + print("received PDU: %s", rcvPdu) + if rcvPdu.pgn == 0xd800: + if rcvPdu.data[0]==1 and rcvPdu.data[1]==0x11: + proceedCount += 1 + if proceedCount == 2: + bus.send(dm16pdu) + if rcvPdu.data[0]==0 and rcvPdu.data[1]==0x19: + print("Value Sent") + break; + + + bus.shutdown() + + return result + + +if __name__ == "__main__": + + import timeit + import argparse + + parser = argparse.ArgumentParser(description=title) + + parser.add_argument("-l", "--length", default="1", help="number of bytes in the object (1-4) default=1") + parser.add_argument("-s", "--source", default="0", help="source address (0-254) default=0") + parser.add_argument("-d", "--destination", default="0x17", help="destination address (0-254) default=17") + parser.add_argument("-p", "--pointer", default="0x58", help="j1939 pointer (0-0xffffff) default=0x58") + parser.add_argument("-e", "--extension", default="0xe9", help="j1939 pointer extension (0-0xffffff) default=0x58") + parser.add_argument('value') + args = parser.parse_args() + + length = int(args.length,0) + src = int(args.source,0) + dest = int(args.destination,0) + ext = int(args.extension,0) + ptr = int(args.pointer,0) + value = int(args.value,0) + + print("Attepting to set %2X/%02X to %d" % (ext, ptr, value)) + #value = hex(int(args.value,0)) + + # queries a couple objects but setting up the full stack and bus for + # each takes a long time. + start = timeit.default_timer() + val = set_mem_object_single(length=length, src=src, dest=dest, pointer=ptr, extension=ext, value=value) + #set_mem_object_single(length=1, src=0, dest=0x17, pointer=0x66, extension=0xea, value=127) + print("elapsed = %s s" % (timeit.default_timer() - start)) diff --git a/j1939/__init__.py b/j1939/__init__.py index fa8d47e..5e572f1 100644 --- a/j1939/__init__.py +++ b/j1939/__init__.py @@ -387,7 +387,7 @@ def _process_incoming_message(self, msg): elif arbitration_id.pgn.value == PGN_TP_DATA_TRANSFER: logger.info("PGN_TP_DATA_TRANSFER") retval = self._data_transfer_handler(pdu) - elif arbitration_id.pgn.value == PGN_TP_SEED_REQUEST: + elif (arbitration_id.pgn.value == PGN_TP_SEED_REQUEST) and (self._key_generation_fcn is not None): logger.info("PGN_TP_SEED_REQUEST") retval = self._send_key_response(pdu) else: diff --git a/j1939/arbitrationid.py b/j1939/arbitrationid.py index 153f1f9..d24c95f 100644 --- a/j1939/arbitrationid.py +++ b/j1939/arbitrationid.py @@ -23,7 +23,7 @@ def __init__(self, priority=7, pgn=None, source_address=0, destination_address=N """ self.priority = priority - if pgn is None: + if pgn is None: pgn = PGN() if pgn and (not isinstance(pgn, PGN)): @@ -42,8 +42,6 @@ def __init__(self, priority=7, pgn=None, source_address=0, destination_address=N logger.debug("self.destination_address_value = %x, pgn.pdu_specific = %x" % (self.destination_address_value, pgn.pdu_specific)) - print("self.destination_address_value = %x, pgn.pdu_specific = %x" % - (self.destination_address_value, pgn.pdu_specific)) assert( self.destination_address_value == pgn.pdu_specific) else: raise ValueError("desttiantion address must be in range (0-255)") From e3e99e6daba12a74cd42bd85e372e1c960e2314e Mon Sep 17 00:00:00 2001 From: Miller Lowe Date: Thu, 22 Jun 2017 12:02:00 -0700 Subject: [PATCH 10/80] Don't print the received PDU's --- bin/j1939_mem_set.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/j1939_mem_set.py b/bin/j1939_mem_set.py index 0472ccb..05e182a 100644 --- a/bin/j1939_mem_set.py +++ b/bin/j1939_mem_set.py @@ -90,7 +90,7 @@ def set_mem_object_single(channel='can0', bustype='socketcan', length=4, src=0, rcvPdu = bus.recv(2) if rcvPdu: rcvPdu.display_radix='hex' - print("received PDU: %s", rcvPdu) + #print("received PDU: %s", rcvPdu) if rcvPdu.pgn == 0xd800: if rcvPdu.data[0]==1 and rcvPdu.data[1]==0x11: proceedCount += 1 From aab97ca4b2613b4abab8c30cbb61bb7da467200d Mon Sep 17 00:00:00 2001 From: Miller Lowe Date: Fri, 30 Jun 2017 15:39:29 -0700 Subject: [PATCH 11/80] changes to support reading and writing of mem-objects.. Not really ready for prime time --- bin/j1939_mem_set.py | 1 + j1939/__init__.py | 31 ++++++++++++++++++++++++++++--- j1939/arbitrationid.py | 29 +++++++++++++++++++++-------- j1939/node.py | 4 ++++ j1939/pgn.py | 7 +++++++ 5 files changed, 61 insertions(+), 11 deletions(-) diff --git a/bin/j1939_mem_set.py b/bin/j1939_mem_set.py index 05e182a..4ded432 100644 --- a/bin/j1939_mem_set.py +++ b/bin/j1939_mem_set.py @@ -42,6 +42,7 @@ def set_mem_object_single(channel='can0', bustype='socketcan', length=4, src=0, bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01, keygen=security.SeedToKey) + #dm14pgn = j1939.PGN() dm14data = [length, 0x15, pointer, 0x00, 0x00, extension, 0xff, 0xff] diff --git a/j1939/__init__.py b/j1939/__init__.py index 5e572f1..f9bd70a 100644 --- a/j1939/__init__.py +++ b/j1939/__init__.py @@ -316,7 +316,6 @@ def send(self, msg, timeout=None): else: msg.display_radix = 'hex' logger.debug("j1939.send: calling can_bus_send: j1939-msg: %s" % (msg)) - logger.debug("j1939.send: calling can_bus_send: can_id %x" % (msg.arbitration_id.can_id)) can_message = Message(arbitration_id=msg.arbitration_id.can_id, extended_id=True, dlc=len(msg.data), @@ -369,7 +368,7 @@ def _send_key_response(self, pdu): def _process_incoming_message(self, msg): - logger.info("PI01: Processing incoming message: \n msg= %s" % (msg)) + logger.info("PI01: Processing incoming message: instance=%s\n msg= %s" % (self, msg)) arbitration_id = ArbitrationID() arbitration_id.can_id = msg.arbitration_id if arbitration_id.pgn.is_destination_specific: @@ -398,7 +397,7 @@ def _process_incoming_message(self, msg): return retval def _connection_management_handler(self, msg): - logger.debug("_connection_management_handler: %s" % (msg)) + logger.debug("MP00: _connection_management_handler: %s, cmd=%s" % (msg, msg.data[0])) if len(msg.data) == 0: msg.info_strings.append("Invalid connection management message - no data bytes") return msg @@ -543,6 +542,7 @@ def _process_rts(self, msg): #for _listener in self.can_notifier.listeners: for (_listener, l_notifier) in self.node_queue_list: + logger.debug("MIL2: _listner/l_notifier = %s/%s" % (_listener, l_notifier)) if isinstance(_listener, Node): logger.debug("6, dest=0x%x" % (msg.arbitration_id.source_address)) # find a Node object so we can search its list of known node addresses @@ -564,6 +564,31 @@ def _process_rts(self, msg): self.can_bus.send(cts_msg) return + """ + # + # MIL: This is the wrong way around this, I should have a node assigned. + # + elif _listener is None and l_notifier is not None: + logger.debug("7, dest=0x%x" % (msg.arbitration_id.source_address)) + # find a Node object so we can search its list of known node addresses + # for this node - if we find it we are responsible for sending the CTS message + if msg.arbitration_id.pgn.pdu_specific : + _cts_arbitration_id = ArbitrationID(source_address=msg.arbitration_id.pgn.pdu_specific) + _cts_arbitration_id.pgn.value = PGN_TP_CONNECTION_MANAGEMENT + _cts_arbitration_id.pgn.pdu_specific = msg.arbitration_id.source_address + _cts_arbitration_id.destination_address = msg.arbitration_id.source_address + _data = [0x11, msg.data[4], 0x01, 0xFF, 0xFF] + _data.extend(msg.data[5:]) + logger.debug("send CTS: AID: %s" % _cts_arbitration_id) + cts_msg = Message(extended_id=True, arbitration_id=_cts_arbitration_id.can_id, data=_data, + dlc=8) + + # send clear to send + logger.debug("send CTS: %s" % cts_msg) + self.can_bus.send(cts_msg) + return + """ + def _process_cts(self, msg): logger.debug("_process_cts") if msg.arbitration_id.pgn.pdu_specific in self._incomplete_transmitted_pdus: diff --git a/j1939/arbitrationid.py b/j1939/arbitrationid.py index d24c95f..250f94b 100644 --- a/j1939/arbitrationid.py +++ b/j1939/arbitrationid.py @@ -22,15 +22,21 @@ def __init__(self, priority=7, pgn=None, source_address=0, destination_address=N Between 0 and 255. Will trrow a ValueError if PGN does not allow a dest """ + self.pgn = None self.priority = priority + self.destination_address_value = None + if pgn is None: - pgn = PGN() + self.pgn = PGN() + elif pgn and isinstance(pgn, int): + self.pgn = PGN.from_value(pgn) + elif pgn and isinstance(pgn, PGN): + self.pgn = pgn + else: + ValueError("pgn must have convertable type") - if pgn and (not isinstance(pgn, PGN)): - ValueError("pgn must have PGN type") self.pgn = pgn - self.destination_address_value = None if pgn: if self.pgn.is_destination_specific: if destination_address is None: @@ -50,10 +56,10 @@ def __init__(self, priority=7, pgn=None, source_address=0, destination_address=N @property def can_id(self): - logger.debug("can_id property: self.pgn.is_destination_specific=%s" % self.pgn.is_destination_specific) + logger.debug("can_id property: self.pgn.is_destination_specific=%s\npgn=%s" % (self.pgn.is_destination_specific, self.pgn)) if self.pgn.is_destination_specific: - logger.debug("can_id: self.pgn.is_destination_specific, dest=%x, pgn_value=%x, pdu_format=0x%x, pdu_specific=0x%x, pri=%x" % + logger.debug("can_id: self.pgn.is_destination_specific, dest=%s, pgn_value=%s, pdu_format=0x%x, pdu_specific=0x%x, pri=%s" % (self.destination_address_value, self.pgn.value, self.pgn.pdu_format, @@ -117,11 +123,18 @@ def pgn(self, other): self._pgn = other def __str__(self): + + logger.debug("arbitrationid.__str__: ids:%d, pri:%s, pgn:%s, dest:%s, src:%s" % (self.pgn.is_destination_specific, self.priority, self.pgn, self.destination_address_value, self.source_address)) + if self.pgn.is_destination_specific: - retval = "PRI=%d PGN=%6s DST=0x%.2x SRC=0x%.2x" % ( - self.priority, self.pgn, self.destination_address_value, self.source_address) + if self.destination_address_value is not None: + retval = "PRI=%d PGN=%6s DST=0x%.2x SRC=0x%.2x" % ( + self.priority, self.pgn, self.destination_address_value, self.source_address) + else: + retval = "PRI=%d PGN=%6s DST=NONE(error) SRC=0x%.2x" % ( + self.priority, self.pgn, self.source_address) else: retval = "PRI=%d PGN=%6s SRC=0x%.2x" % (self.priority, self.pgn, self.source_address) return retval diff --git a/j1939/node.py b/j1939/node.py index 934a891..bba9564 100644 --- a/j1939/node.py +++ b/j1939/node.py @@ -68,8 +68,12 @@ def claim_address(self, address): claimed_address_pdu.arbitration_id.priority = 4 claimed_address_pdu.arbitration_id.pgn.pdu_specific = 0xff claimed_address_pdu.arbitration_id.source_address = address + claimed_address_pdu.arbitration_id.destination_address_value = 0xff + claimed_address_pdu.data = self.node_name.bytes self.known_node_addresses[self.node_name.value] = address + log.info('MIL:') + log.info('claimed_address_pdu: %s' % claimed_address_pdu) self.bus.send(claimed_address_pdu) def on_message_received(self, pdu): diff --git a/j1939/pgn.py b/j1939/pgn.py index 9931559..28dd915 100644 --- a/j1939/pgn.py +++ b/j1939/pgn.py @@ -67,9 +67,16 @@ def __str__(self): retval += "R " else: retval += " " + if self.data_page_flag: retval += "P " else: retval += " " + if 0: + if self.is_destination_specific: + retval += "DS " + else: + retval += "!DS" + return retval From 1c1b48b06f13fe1943db58ac7cb6ec534338ab6d Mon Sep 17 00:00:00 2001 From: jackm Date: Sun, 16 Jul 2017 13:27:32 -0400 Subject: [PATCH 12/80] Whitespace cleanup --- bin/j1939_logger.py | 2 -- j1939/__init__.py | 14 +------------- j1939/arbitrationid.py | 2 -- 3 files changed, 1 insertion(+), 17 deletions(-) diff --git a/bin/j1939_logger.py b/bin/j1939_logger.py index 8f34ac3..17c537c 100644 --- a/bin/j1939_logger.py +++ b/bin/j1939_logger.py @@ -107,7 +107,6 @@ def parse_arguments(): if __name__ == "__main__": - args = parse_arguments() verbosity = args.verbosity @@ -122,7 +121,6 @@ def parse_arguments(): for pgn in args.pgn: if pgn.startswith('0x'): pgn = int(pgn[2:], base=16) - filters.append({'pgn': int(pgn)}) if args.source is not None: for src in args.source: diff --git a/j1939/__init__.py b/j1939/__init__.py index f9bd70a..29f1782 100644 --- a/j1939/__init__.py +++ b/j1939/__init__.py @@ -21,15 +21,11 @@ # By this stage the can.rc should have been set up from can import Message - from can import set_logging_level as can_set_logging_level from can.interfaces.interface import Bus as RawCanBus - from can.notifier import Notifier as canNotifier from can.bus import BusABC - - # Import our new message type from j1939.pdu import PDU from j1939.pgn import PGN @@ -84,7 +80,6 @@ def __init__(self, pdu_type=PDU, broadcast=True, *args, **kwargs): if 'keygen' in kwargs and kwargs['keygen'] is not None: self._key_generation_fcn = kwargs['keygen'] - if broadcast: self.node_queue_list = [(None, self)] # Start with default logger Queue which will receive everything @@ -163,29 +158,24 @@ def notification(self, inboundMessage): l_notifier.queue.put(inboundMessage) # if node has the destination address, do something with the PDU - # elif node and (arbitration_id.destination_address in node.address_list): rx_pdu = self._process_incoming_message(inboundMessage) if rx_pdu: logger.info("WP02: notification: sent to general queue: %s QQ=%s" % (rx_pdu, self.queue)) self.queue.put(rx_pdu) - elif node and (arbitration_id.destination_address is None): logger.info("notification: sending broadcast to general queue") rx_pdu = self._process_incoming_message(inboundMessage) logger.info("WP01: notification: sent broadcast to general queue: %s QQ=%s" % (rx_pdu, self.queue)) self.queue.put(rx_pdu) - elif node is None: # always send the message to the logging queue logger.info("notification: sending to general queue") rx_pdu = self._process_incoming_message(inboundMessage) logger.info("WP03: notification: sent 'none' to general queue") self.queue.put(rx_pdu) - else: logger.info("WP04: notification: pdu dropped: %s\n\n" % inboundMessage) - else: logger.info("Received non J1939 message (ignoring)") @@ -365,8 +355,6 @@ def _send_key_response(self, pdu): return None - - def _process_incoming_message(self, msg): logger.info("PI01: Processing incoming message: instance=%s\n msg= %s" % (self, msg)) arbitration_id = ArbitrationID() @@ -443,7 +431,7 @@ def _data_transfer_handler(self, msg): # Find a Node object so we can search its list of known node addresses for this node # so we can find if we are responsible for sending the EOM ACK message - # TODO: Was self.j1939_notifier.listeners + # TODO: Was self.j1939_notifier.listeners send_ack = any(True for (_listener, l_notifier) in self.node_queue_list if isinstance(_listener, Node) and diff --git a/j1939/arbitrationid.py b/j1939/arbitrationid.py index 250f94b..c470be7 100644 --- a/j1939/arbitrationid.py +++ b/j1939/arbitrationid.py @@ -123,8 +123,6 @@ def pgn(self, other): self._pgn = other def __str__(self): - - logger.debug("arbitrationid.__str__: ids:%d, pri:%s, pgn:%s, dest:%s, src:%s" % (self.pgn.is_destination_specific, self.priority, self.pgn, self.destination_address_value, self.source_address)) From e29fd023d594596d636a5ccc7a788e2606fdd074 Mon Sep 17 00:00:00 2001 From: jackm Date: Sun, 16 Jul 2017 13:34:02 -0400 Subject: [PATCH 13/80] Fixed broken import and variable reference Recent changes to the [python-can](https://github.com/hardbyte/python-can) package moved the location of module code around and modified the file structure, breaking imports that worked with the older version. Also updated this package's version number to signify this important change. --- bin/j1939_logger.py | 4 +--- j1939/__init__.py | 2 +- setup.py | 4 ++-- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/bin/j1939_logger.py b/bin/j1939_logger.py index 17c537c..1a5c213 100644 --- a/bin/j1939_logger.py +++ b/bin/j1939_logger.py @@ -101,7 +101,7 @@ def parse_arguments(): {} Alternatively the CAN_INTERFACE environment variable can be set. - '''.format(can.interfaces.interface.VALID_INTERFACES))) + '''.format(can.interfaces.VALID_INTERFACES))) return parser.parse_args() @@ -113,8 +113,6 @@ def parse_arguments(): logging_level_name = ['critical', 'error', 'warning', 'info', 'debug', 'subdebug'][min(5, verbosity)] can.set_logging_level(logging_level_name) - from can.interfaces.interface import * - filters = [] if args.pgn is not None: print('Have to filter pgns: ', args.pgn) diff --git a/j1939/__init__.py b/j1939/__init__.py index 29f1782..e47a70c 100644 --- a/j1939/__init__.py +++ b/j1939/__init__.py @@ -22,7 +22,7 @@ # By this stage the can.rc should have been set up from can import Message from can import set_logging_level as can_set_logging_level -from can.interfaces.interface import Bus as RawCanBus +from can.interface import Bus as RawCanBus from can.notifier import Notifier as canNotifier from can.bus import BusABC diff --git a/setup.py b/setup.py index e6ae81f..3cf2c8d 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ import logging from setuptools import setup, find_packages -__version__ = "0.1.0-alpha.2" +__version__ = "0.1.0-alpha.3" logging.basicConfig(level=logging.WARNING) @@ -24,7 +24,7 @@ "doc": ["*.*"] }, - install_requires=["python-can>=1.5"], + install_requires=["python-can>=2.0.0a2"], scripts=["./bin/j1939_logger.py"], From fa83508fd4a3eb07650557fbd14068efef5d92af Mon Sep 17 00:00:00 2001 From: jackm Date: Sun, 16 Jul 2017 13:50:35 -0400 Subject: [PATCH 14/80] Print channel info in j1939_logger.py script This is helpful to identify which interface the scirpt is using in the case when you have multiple interfaces available --- bin/j1939_logger.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/j1939_logger.py b/bin/j1939_logger.py index 1a5c213..3389cd4 100644 --- a/bin/j1939_logger.py +++ b/bin/j1939_logger.py @@ -136,6 +136,7 @@ def parse_arguments(): print("filters : ", filters) bus = j1939.Bus(channel=args.channel, bustype=args.interface, j1939_filters=filters, timeout=0.1) + print("channel info : ", bus.can_bus.channel_info) log_start_time = datetime.datetime.now() print('can.j1939 logger started on {}\n'.format(log_start_time)) logger.info('can.j1939 logger started on {}\n'.format(log_start_time)) From 3e93a489e1557a48c25214aaaee52786d5e5bf2d Mon Sep 17 00:00:00 2001 From: Miller Lowe Date: Tue, 26 Sep 2017 11:52:31 -0700 Subject: [PATCH 15/80] This commit adds a keyword argument ignoreCanSendError={True|False} to the j1939.Bus() method. In the test harness that I use for J1939, I need to be able to have messages fall on floor if the destination is not there. Without this feature a can.CanError exception will abort the script as soon as the message send queue is full. --- j1939/__init__.py | 54 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 47 insertions(+), 7 deletions(-) diff --git a/j1939/__init__.py b/j1939/__init__.py index e47a70c..c7c3a4f 100644 --- a/j1939/__init__.py +++ b/j1939/__init__.py @@ -20,6 +20,7 @@ import copy # By this stage the can.rc should have been set up +from can import CanError from can import Message from can import set_logging_level as can_set_logging_level from can.interface import Bus as RawCanBus @@ -77,9 +78,13 @@ def __init__(self, pdu_type=PDU, broadcast=True, *args, **kwargs): self._incomplete_transmitted_pdus = {} self._long_message_segment_queue = Queue(0) self._key_generation_fcn = None + if 'keygen' in kwargs and kwargs['keygen'] is not None: self._key_generation_fcn = kwargs['keygen'] + if 'ignoreCanSendError' in kwargs and kwargs['ignoreCanSendError'] is not None: + self._ignore_can_send_error = kwargs['ignoreCanSendError'] + if broadcast: self.node_queue_list = [(None, self)] # Start with default logger Queue which will receive everything @@ -283,7 +288,12 @@ def send(self, msg, timeout=None): pgn_middle, pgn_msb], dlc=8) - self.can_bus.send(rts_msg) + try: + self.can_bus.send(rts_msg) + except CanError: + if self._ignore_can_send_error: + pass + raise else: rts_arbitration_id.pgn.pdu_specific = DESTINATION_ADDRESS_GLOBAL bam_msg = Message(extended_id=True, @@ -297,7 +307,12 @@ def send(self, msg, timeout=None): pgn_msb], dlc=8) # send BAM - self.can_bus.send(bam_msg) + try: + self.can_bus.send(bam_msg) + except CanError: + if self._ignore_can_send_error: + pass + raise for message in messages: # send data messages - no flow control, so no need to wait @@ -312,7 +327,12 @@ def send(self, msg, timeout=None): data=msg.data) logger.debug("j1939.send: calling can_bus_send: can-msg: %s" % can_message) - self.can_bus.send(can_message) + try: + self.can_bus.send(can_message) + except CanError: + if self._ignore_can_send_error: + pass + raise def shutdown(self): self.can_notifier.running.clear() @@ -470,7 +490,12 @@ def _data_transfer_handler(self, msg): _pgn_lsb, _pgn_middle, pgn_msb]) - self.can_bus.send(can_message) + try: + self.can_bus.send(can_message) + except CanError: + if self._ignore_can_send_error: + pass + raise logger.debug("_data_transfer_handler: returning %s" % (msg)) return self._process_eom_ack(msg) @@ -549,7 +574,12 @@ def _process_rts(self, msg): # send clear to send logger.debug("send CTS: %s" % cts_msg) - self.can_bus.send(cts_msg) + try: + self.can_bus.send(cts_msg) + except CanError: + if self._ignore_can_send_error: + pass + raise return """ @@ -588,7 +618,12 @@ def _process_cts(self, msg): end_index = start_index + msg.data[1] for _msg in self._incomplete_transmitted_pdus[msg.arbitration_id.pgn.pdu_specific][ msg.arbitration_id.source_address][start_index:end_index]: - self.can_bus.send(_msg) + try: + self.can_bus.send(msg) + except CanError: + if self._ignore_can_send_error: + pass + raise def _process_eom_ack(self, msg): logger.debug("_process_eom_ack") @@ -649,7 +684,12 @@ def _throttler_function(self): except Empty: pass if _msg is not None: - self.can_bus.send(_msg) + try: + self.can_bus.send(msg) + except CanError: + if self._ignore_can_send_error: + pass + raise @property def transmissions_in_progress(self): From 94cb191aff81b3e0443cf32960903710a8cd8511 Mon Sep 17 00:00:00 2001 From: Miller Lowe Date: Wed, 20 Dec 2017 13:46:05 -0800 Subject: [PATCH 16/80] Got the mem-query examle script to wor by properly defining a listener. --- bin/j1939_mem_query.py | 40 +++++++++---------- bin/j1939_request_pgn.py | 85 ++++++++++++++++++++++++++++++++++++++++ j1939/__init__.py | 23 ++++++++++- 3 files changed, 125 insertions(+), 23 deletions(-) create mode 100644 bin/j1939_request_pgn.py diff --git a/bin/j1939_mem_query.py b/bin/j1939_mem_query.py index b0316d9..f741d33 100644 --- a/bin/j1939_mem_query.py +++ b/bin/j1939_mem_query.py @@ -78,29 +78,27 @@ def get_mem_object(bus=None, length=4, src=0, dest=0x17, pointer=0, extension=0) # queries a couple objects but setting up the full stack and bus for # each takes a long time. - start = timeit.default_timer() - for p, e in [(0x15, 0xe9), (0x00, 0xf1), (0x50, 0xe9), (0x75, 0xe9)]: - val = get_mem_object_single(length=4, src=0, dest=0x17, pointer=p, extension=e) - print("0x%02x-0x%02x = %d" % (p, e, val)) - print("elapsed = %s s" % (timeit.default_timer() - start)) - - - # queries the same objects but in a single bus instance, should be a tad faster. - start = timeit.default_timer() - try: - jbus = j1939.Bus(channel='can0', bustype='socketcan', timeout=0.01) + if 1: + start = timeit.default_timer() for p, e in [(0x15, 0xe9), (0x00, 0xf1), (0x50, 0xe9), (0x75, 0xe9)]: - val = get_mem_object(jbus, length=4, src=0, dest=0x17, pointer=p, extension=e) + val = get_mem_object_single(length=4, src=0, dest=0x17, pointer=p, extension=e) print("0x%02x-0x%02x = %d" % (p, e, val)) - except: - traceback.print_exc() + print("elapsed = %s s" % (timeit.default_timer() - start)) + + + if 1: + # queries the same objects but in a single bus instance, should be a tad faster. + start = timeit.default_timer() + try: + jbus = j1939.Bus(channel='can0', bustype='socketcan', timeout=0.01) + for p, e in [(0x15, 0xe9), (0x00, 0xf1), (0x50, 0xe9), (0x75, 0xe9)]: + val = get_mem_object(jbus, length=4, src=0, dest=0x17, pointer=p, extension=e) + print("0x%02x-0x%02x = %d" % (p, e, val)) + except: + traceback.print_exc() + pass - pass - jbus.shutdown() - print("elapsed = %s s" % (timeit.default_timer() - start)) + jbus.shutdown() + print("elapsed = %s s" % (timeit.default_timer() - start)) - # just a blurb to see - start = timeit.default_timer() - time.sleep(1) - print("elapsed = %s s" % (timeit.default_timer() - start)) diff --git a/bin/j1939_request_pgn.py b/bin/j1939_request_pgn.py new file mode 100644 index 0000000..7fc0cd9 --- /dev/null +++ b/bin/j1939_request_pgn.py @@ -0,0 +1,85 @@ +from __future__ import print_function + +import j1939 + +import logging + +lLevel = logging.DEBUG + +logger = logging.getLogger() +logger.setLevel(lLevel) +ch = logging.StreamHandler() +fh = logging.FileHandler('/tmp/j1939_request_pgn.log') +fh.setLevel(lLevel) +ch.setLevel(lLevel) +formatter = logging.Formatter('%(asctime)s | %(name)20s | %(threadName)20s | %(levelname)5s | %(message)s') +chformatter = logging.Formatter('%(name)25s | %(threadName)10s | %(levelname)5s | %(message)s') +fh.setFormatter(formatter) +ch.setFormatter(chformatter) +logger.addHandler(ch) +logger.addHandler(fh) + + + + +if __name__ == "__main__": + import traceback + import timeit + import time + + +def request_pgn(channel='can0', bustype='socketcan', src=0, dest=0x17, reqPGN=0x00feda): + #from can.interfaces.interface import * + + countdown = 10 + result = -1 + + bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01) + + nodename = j1939.NodeName(0) + nodename.arbitrary_address_capable = 1 + + node1 = j1939.Node(bus, j1939.NodeName(0), [0]) + bus.connect(node1) + + + pgn = j1939.PGN() + pgn.value = 0xea00 | dest + aid = j1939.ArbitrationID(pgn=pgn, source_address=src, destination_address=dest) + + data = [((reqPGN>>0)&0xff), ((reqPGN>>8)&0xff), ((reqPGN>>16)&0xff)] + pdu = j1939.PDU(timestamp=0.0, arbitration_id=aid, data=data, info_strings=None) + pdu.display_radix='hex' + + bus.send(pdu) + + while countdown: + pdu = bus.recv() + if pdu and pdu.pgn == reqPGN: + return pdu; + break # got what I was waiting for + + countdown -= 1 + + bus.shutdown() + + return None + +if __name__ == "__main__": + + # queries a couple objects but setting up the full stack and bus for + # each takes a long time. + start = timeit.default_timer() + if request_pgn(src=0, dest=0x27): + print("Returned Success!") + else: + print("Returned None!") + + print("elapsed = %s s" % (timeit.default_timer() - start)) + + + + # just a blurb to see + start = timeit.default_timer() + time.sleep(1) + print("elapsed = %s s" % (timeit.default_timer() - start)) diff --git a/j1939/__init__.py b/j1939/__init__.py index c7c3a4f..16d5e1d 100644 --- a/j1939/__init__.py +++ b/j1939/__init__.py @@ -25,6 +25,7 @@ from can import set_logging_level as can_set_logging_level from can.interface import Bus as RawCanBus from can.notifier import Notifier as canNotifier +from can.listener import Listener as canListener from can.bus import BusABC # Import our new message type @@ -42,6 +43,17 @@ can_set_logging_level('warning') +class j1939Listner(canListener): + + def __init__(self, handler): + self.handler = handler + + def on_message_received(self, msg): + self.handler(msg) + + def stop(self): + pass + class Bus(BusABC): """ @@ -124,11 +136,13 @@ def __init__(self, pdu_type=PDU, broadcast=True, *args, **kwargs): logger.debug("Creating a new can bus") self.can_bus = RawCanBus(*args, **kwargs) - self.can_notifier = canNotifier(self.can_bus, [self.notification], timeout=self.timeout) - ###########self.j1939_notifier = Notifier(self, []) + + canListener = j1939Listner(self.notification) + self.can_notifier = canNotifier(self.can_bus, [canListener], timeout=self.timeout) self._long_message_throttler.start() + def notification(self, inboundMessage): #self.rx_can_message_queue.put(inboundMessage) @@ -204,6 +218,7 @@ def recv(self, timeout=None): rx_pdu = self.queue.get(timeout=timeout) logger.info('J1939 Bus recv() successful QQ=%s, pdu:%s' % (self.queue, rx_pdu)) return rx_pdu + except Empty: logger.debug('J1939 Bus recv() timed out' % ()) return None @@ -560,6 +575,10 @@ def _process_rts(self, msg): logger.debug("6, dest=0x%x" % (msg.arbitration_id.source_address)) # find a Node object so we can search its list of known node addresses # for this node - if we find it we are responsible for sending the CTS message + logger.debug("MIL3: Node: %s" % (Node)) + logger.debug("MIL3: _listener.address: %s" % (_listener.address)) + logger.debug("MIL3: msg.arbitration_id.pgn.pdu_specific: %s" % (msg.arbitration_id.pgn.pdu_specific)) + logger.debug("MIL3: _listener.address_list: %s" % (_listener.address_list)) if _listener.address == msg.arbitration_id.pgn.pdu_specific or \ msg.arbitration_id.pgn.pdu_specific in _listener.address_list: _cts_arbitration_id = ArbitrationID(source_address=msg.arbitration_id.pgn.pdu_specific) From 93e5d8c770b6659a4b82d31ab147e6d4cd66dfa1 Mon Sep 17 00:00:00 2001 From: Miller Lowe Date: Thu, 21 Dec 2017 14:40:33 -0800 Subject: [PATCH 17/80] Have sme more mem_get functioning.. THere are still lots of weird interactions in the transport layers still --- bin/j1939_mem_query.py | 130 +++++++++++++++++++++++++++++-------- bin/j1939_request_pgn.py | 135 +++++++++++++++++++++++---------------- j1939/__init__.py | 4 +- j1939/arbitrationid.py | 8 +-- 4 files changed, 191 insertions(+), 86 deletions(-) diff --git a/bin/j1939_mem_query.py b/bin/j1939_mem_query.py index f741d33..99bd6cd 100644 --- a/bin/j1939_mem_query.py +++ b/bin/j1939_mem_query.py @@ -1,21 +1,34 @@ +#!/usr/bin/python +# from __future__ import print_function +_name = "Simple J1939 memory object query" +__version__ = "1.0.0" +__date__ = "12/20/2017" +__exp__ = "(expirimental)" # (Release Version) +title = "%s Version: %s %s %s" % (_name, __version__, __date__, __exp__) + import j1939 + if __name__ == "__main__": import traceback import timeit import time + import argparse + import logging + import textwrap + def get_mem_object_single(channel='can0', bustype='socketcan', length=4, src=0, dest=0x17, pointer=0, extension=0): #from can.interfaces.interface import * countdown = 10 - result = -1 + result = None bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01) pgn = j1939.PGN() - pgn.value = 0xd917 + pgn.value = 0xd900 + dest # Request a DM14 mem-object aid = j1939.ArbitrationID(pgn=pgn, source_address=src, destination_address=dest) data = [length, 0x13, pointer, 0x00, 0x00, extension, 0xff, 0xff] @@ -25,7 +38,7 @@ def get_mem_object_single(channel='can0', bustype='socketcan', length=4, src=0, bus.send(pdu) while countdown: - pdu = bus.recv() + pdu = bus.recv(timeout=1) if pdu.pgn == 0xd700: value = list(pdu.data) length = value[0] @@ -41,11 +54,15 @@ def get_mem_object_single(channel='can0', bustype='socketcan', length=4, src=0, bus.shutdown() + if not result: + raise IOError(" no CAN response") + + return result def get_mem_object(bus=None, length=4, src=0, dest=0x17, pointer=0, extension=0): countdown = 10 - result = -1 + result = None pgn = j1939.PGN() pgn.value = 0xd917 @@ -72,33 +89,96 @@ def get_mem_object(bus=None, length=4, src=0, dest=0x17, pointer=0, extension=0) countdown -= 1 + if not result: + raise IOError(" no CAN response") + return result +def getStringVal(s): + if s.startswith("0x"): + return int(s[2:],base=16) + else: + return int(s, base=10) + + + if __name__ == "__main__": - # queries a couple objects but setting up the full stack and bus for - # each takes a long time. - if 1: - start = timeit.default_timer() - for p, e in [(0x15, 0xe9), (0x00, 0xf1), (0x50, 0xe9), (0x75, 0xe9)]: - val = get_mem_object_single(length=4, src=0, dest=0x17, pointer=p, extension=e) - print("0x%02x-0x%02x = %d" % (p, e, val)) - print("elapsed = %s s" % (timeit.default_timer() - start)) - - - if 1: - # queries the same objects but in a single bus instance, should be a tad faster. - start = timeit.default_timer() - try: - jbus = j1939.Bus(channel='can0', bustype='socketcan', timeout=0.01) + lLevel = logging.WARNING + jlogger = logging.getLogger("j1939") + ch = logging.StreamHandler() + ch.setLevel(lLevel) + jlogger.addHandler(ch) + + parser = argparse.ArgumentParser(description='''\ + example: %(prog)s -d 0x21 -e 0xe9 -p 0x15 + + will query a E9_15 Memory value ''' + ,epilog=title) + + parser.add_argument("-t", "--test", + action="store_true", default=False, + help="run the test cases and ignore input parameters") + + parser.add_argument("-s", "--src", + default="0", + help="j1939 source address decimal or hex, default is 0") + + parser.add_argument("-d", "--dest", + default="0x17", + help="CAN destination, default is 0x17") + + parser.add_argument("-p", "--pointer", + default=None, + help="mem object offset within the exension block (REQUIRED)") + + parser.add_argument("-e", "--extension", + default=None, + help="mem object offset within the exension block (REQUIRED)") + + args = parser.parse_args() + + + if args.test: + # queries a couple objects but setting up the full stack and bus for + # each takes a long time. + if 1: + start = timeit.default_timer() for p, e in [(0x15, 0xe9), (0x00, 0xf1), (0x50, 0xe9), (0x75, 0xe9)]: - val = get_mem_object(jbus, length=4, src=0, dest=0x17, pointer=p, extension=e) + val = get_mem_object_single(length=4, src=0, dest=0x17, pointer=p, extension=e) print("0x%02x-0x%02x = %d" % (p, e, val)) - except: - traceback.print_exc() - pass + print("elapsed = %s s" % (timeit.default_timer() - start)) + + + if 1: + # queries the same objects but in a single bus instance, should be a tad faster. + start = timeit.default_timer() + try: + jbus = j1939.Bus(channel='can0', bustype='socketcan', timeout=0.01) + for p, e in [(0x15, 0xe9), (0x00, 0xf1), (0x50, 0xe9), (0x75, 0xe9)]: + val = get_mem_object(jbus, length=4, src=0, dest=0x17, pointer=p, extension=e) + print("0x%02x-0x%02x = %d" % (p, e, val)) + except: + traceback.print_exc() + pass + + jbus.shutdown() + + print("elapsed = %s s" % (timeit.default_timer() - start)) + + else: + + if (args.pointer==None or args.extension==None): + raise ValueError("pointer and extension are required!") + + source = getStringVal(args.src) + dest = getStringVal(args.dest) + ptr = getStringVal(args.pointer) + ext = getStringVal(args.extension) + + print ("get_mem_object_single(src=0x%02x, dest=0x%02x, pointer=0x%02x, extension=0x%02x" % (source, dest, ptr, ext)) - jbus.shutdown() + val = get_mem_object_single(length=4, src=source, dest=dest, pointer=ptr, extension=ext) - print("elapsed = %s s" % (timeit.default_timer() - start)) + print("0x%02x-0x%02x = %d (0x%08x)" % (ptr, ext, val, val)) diff --git a/bin/j1939_request_pgn.py b/bin/j1939_request_pgn.py index 7fc0cd9..2b6bc1a 100644 --- a/bin/j1939_request_pgn.py +++ b/bin/j1939_request_pgn.py @@ -1,85 +1,110 @@ +#!/usr/bin/python +# from __future__ import print_function -import j1939 - -import logging - -lLevel = logging.DEBUG - -logger = logging.getLogger() -logger.setLevel(lLevel) -ch = logging.StreamHandler() -fh = logging.FileHandler('/tmp/j1939_request_pgn.log') -fh.setLevel(lLevel) -ch.setLevel(lLevel) -formatter = logging.Formatter('%(asctime)s | %(name)20s | %(threadName)20s | %(levelname)5s | %(message)s') -chformatter = logging.Formatter('%(name)25s | %(threadName)10s | %(levelname)5s | %(message)s') -fh.setFormatter(formatter) -ch.setFormatter(chformatter) -logger.addHandler(ch) -logger.addHandler(fh) - +_name = "" +__version__ = "1.0.0" +__date__ = "12/21/2017" +__exp__ = "(expirimental)" # (Release Version) +title = "%s Version: %s %s %s" % (_name, __version__, __date__, __exp__) +import j1939 -if __name__ == "__main__": - import traceback - import timeit - import time - - -def request_pgn(channel='can0', bustype='socketcan', src=0, dest=0x17, reqPGN=0x00feda): - #from can.interfaces.interface import * +def request_pgn_single(requested_pgn, channel='can0', bustype='socketcan', length=4, src=0, dest=0x17): countdown = 10 - result = -1 - - bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01) - - nodename = j1939.NodeName(0) - nodename.arbitrary_address_capable = 1 - - node1 = j1939.Node(bus, j1939.NodeName(0), [0]) - bus.connect(node1) + result = None + if not isinstance(requested_pgn, int): + raise ValueError("pgn must be an integer.") + bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01) pgn = j1939.PGN() - pgn.value = 0xea00 | dest + pgn.value = 0xea00 + dest # request_pgn mem-object aid = j1939.ArbitrationID(pgn=pgn, source_address=src, destination_address=dest) - data = [((reqPGN>>0)&0xff), ((reqPGN>>8)&0xff), ((reqPGN>>16)&0xff)] + pgn0 = requested_pgn & 0xff + pgn1 = (requested_pgn >> 8) & 0xff + pgn2 = (requested_pgn >> 16) & 0xff + + data = [pgn0, pgn1, pgn2] pdu = j1939.PDU(timestamp=0.0, arbitration_id=aid, data=data, info_strings=None) + pdu.display_radix='hex' bus.send(pdu) while countdown: - pdu = bus.recv() - if pdu and pdu.pgn == reqPGN: - return pdu; + pdu = bus.recv(timeout=1) + if pdu and (pdu.pgn == 0xe800 or pdu.pgn == requested_pgn): + result = list(pdu.data) break # got what I was waiting for - countdown -= 1 + if pdu: + countdown -= 1 bus.shutdown() - return None + if not result: + raise IOError(" no CAN response") + + + return result + if __name__ == "__main__": - # queries a couple objects but setting up the full stack and bus for - # each takes a long time. - start = timeit.default_timer() - if request_pgn(src=0, dest=0x27): - print("Returned Success!") - else: - print("Returned None!") + import traceback + import timeit + import time + import argparse + import logging + import textwrap + + def getStringValAsInt(s): + if s.startswith("0x"): + return int(s[2:],base=16) + else: + return int(s, base=10) + + + + + lLevel = logging.DEBUG + jlogger = logging.getLogger("j1939") + ch = logging.StreamHandler() + ch.setLevel(lLevel) + jlogger.addHandler(ch) + + parser = argparse.ArgumentParser(description='''\ + example: %(prog)s -d 0x21 65223 + + will request a specific PGN 65223 from dest ''' + ,epilog=title) + + parser.add_argument("-s", "--src", + default="0", + help="j1939 source address decimal or hex, default is 0") + + parser.add_argument("-d", "--dest", + default="0x17", + help="CAN destination, default is 0x17") + + parser.add_argument("pgn", + default=None, + help="pgn to request in decimal or 0xHex") + + args = parser.parse_args() + + + source = getStringValAsInt(args.src) + dest = getStringValAsInt(args.dest) + pgn = getStringValAsInt(args.pgn) - print("elapsed = %s s" % (timeit.default_timer() - start)) + print ("request_pgn_single(pgn=0x%04x (%d), src=0x%02x, dest=0x%02x)" % (pgn, pgn, source, dest)) + val = request_pgn_single(pgn, length=4, src=source, dest=dest) + print("returned PGN = %s" % val) - # just a blurb to see - start = timeit.default_timer() - time.sleep(1) - print("elapsed = %s s" % (timeit.default_timer() - start)) diff --git a/j1939/__init__.py b/j1939/__init__.py index 16d5e1d..6bc3891 100644 --- a/j1939/__init__.py +++ b/j1939/__init__.py @@ -38,7 +38,7 @@ from j1939.arbitrationid import ArbitrationID -logger = logging.getLogger(__name__) +logger = logging.getLogger("j1939") logger.setLevel(logging.WARNING) can_set_logging_level('warning') @@ -191,7 +191,7 @@ def notification(self, inboundMessage): # always send the message to the logging queue logger.info("notification: sending to general queue") rx_pdu = self._process_incoming_message(inboundMessage) - logger.info("WP03: notification: sent 'none' to general queue") + logger.info("WP03: notification: sent pdu [%s] to general queue" % rx_pdu) self.queue.put(rx_pdu) else: logger.info("WP04: notification: pdu dropped: %s\n\n" % inboundMessage) diff --git a/j1939/arbitrationid.py b/j1939/arbitrationid.py index c470be7..1479ca6 100644 --- a/j1939/arbitrationid.py +++ b/j1939/arbitrationid.py @@ -45,12 +45,12 @@ def __init__(self, priority=7, pgn=None, source_address=0, destination_address=N if destination_address >= 0 and destination_address <= 255: self.destination_address_value = destination_address if self.destination_address_value != pgn.pdu_specific: - logger.debug("self.destination_address_value = %x, pgn.pdu_specific = %x" % - (self.destination_address_value, pgn.pdu_specific)) + logger.debug("self.pgn=%s, self.destination_address_value = %x, pgn.pdu_specific = %x" % + (self.pgn, self.destination_address_value, pgn.pdu_specific)) - assert( self.destination_address_value == pgn.pdu_specific) +# assert( self.destination_address_value == pgn.pdu_specific) else: - raise ValueError("desttiantion address must be in range (0-255)") + raise ValueError("destination address must be in range (0-255)") self.source_address = source_address From 8da80d99ce613bc459a2423936cd12089dd11f7d Mon Sep 17 00:00:00 2001 From: Miller Lowe Date: Fri, 22 Dec 2017 11:19:58 -0800 Subject: [PATCH 18/80] request_pgn working... --- bin/j1939_request_pgn.py | 9 +++------ examples/get_ecu_block.py | 30 ++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 6 deletions(-) create mode 100644 examples/get_ecu_block.py diff --git a/bin/j1939_request_pgn.py b/bin/j1939_request_pgn.py index 2b6bc1a..b4fd5e3 100644 --- a/bin/j1939_request_pgn.py +++ b/bin/j1939_request_pgn.py @@ -69,13 +69,10 @@ def getStringValAsInt(s): return int(s, base=10) - - - lLevel = logging.DEBUG - jlogger = logging.getLogger("j1939") + logger = logging.getLogger("j1939") ch = logging.StreamHandler() - ch.setLevel(lLevel) - jlogger.addHandler(ch) + ch.setLevel(logging.WARNING) + logger.addHandler(ch) parser = argparse.ArgumentParser(description='''\ example: %(prog)s -d 0x21 65223 diff --git a/examples/get_ecu_block.py b/examples/get_ecu_block.py new file mode 100644 index 0000000..5fa9e58 --- /dev/null +++ b/examples/get_ecu_block.py @@ -0,0 +1,30 @@ +from __future__ import print_function + +import j1939_request_pgn + +val = j1939_request_pgn.request_pgn_single(0xfeda, src=0xff) +fieldCount = val[0] +print ("%d elements in list" % fieldCount) + +res="" +for c in val[1:]: + res += chr(c) + +res2=res.split('*') +print (res2) + +print("Destination Address: %d (0x%x)" % (23, 23)) +print("Number of ID items: %d (0x%x)" % (fieldCount, fieldCount)) +print("Model Number: %s " % (res2[0])) +print("Vendor Part Number: %s" % (res2[1])) +print("Hardware Serial Number: %s" % (res2[2])) +print("VIN: %s" % (res2[3])) +print("Hardware Part Number: %s" % (res2[4])) +print("ECU Part Number: %s" % (res2[5])) +print("Program Version: %s" % (res2[6])) +print("Software Version Number: %s" % (res2[7])) +print("Software Part Number: %s" % (res2[8])) +print("Checksum: 0x%s" % (res2[9])) + + + From accbaf328bf174a4f63ad4f9c3af0732ef064d29 Mon Sep 17 00:00:00 2001 From: Miller Lowe Date: Thu, 15 Feb 2018 09:06:01 -0800 Subject: [PATCH 19/80] updated some documention and arg parsing rules --- bin/j1939_mem_query.py | 23 +++++++++++++---------- bin/j1939_mem_set.py | 13 +++++++++++-- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/bin/j1939_mem_query.py b/bin/j1939_mem_query.py index 99bd6cd..6c5a9d1 100644 --- a/bin/j1939_mem_query.py +++ b/bin/j1939_mem_query.py @@ -33,13 +33,14 @@ def get_mem_object_single(channel='can0', bustype='socketcan', length=4, src=0, data = [length, 0x13, pointer, 0x00, 0x00, extension, 0xff, 0xff] pdu = j1939.PDU(timestamp=0.0, arbitration_id=aid, data=data, info_strings=None) + assert(pdu != None) pdu.display_radix='hex' bus.send(pdu) while countdown: pdu = bus.recv(timeout=1) - if pdu.pgn == 0xd700: + if pdu and pdu.pgn == 0xd700: value = list(pdu.data) length = value[0] if length == 1: @@ -104,14 +105,14 @@ def getStringVal(s): if __name__ == "__main__": - lLevel = logging.WARNING + lLevel = logging.WARN jlogger = logging.getLogger("j1939") + jlogger.setLevel(lLevel) ch = logging.StreamHandler() - ch.setLevel(lLevel) jlogger.addHandler(ch) parser = argparse.ArgumentParser(description='''\ - example: %(prog)s -d 0x21 -e 0xe9 -p 0x15 + example: %(prog)s -d 0x21 0xe9 -p 0x15 will query a E9_15 Memory value ''' ,epilog=title) @@ -128,13 +129,15 @@ def getStringVal(s): default="0x17", help="CAN destination, default is 0x17") - parser.add_argument("-p", "--pointer", - default=None, - help="mem object offset within the exension block (REQUIRED)") + parser.add_argument("extension", + default=None, + help="Memory object extension prefix to request in decimal or 0xHex") + + parser.add_argument("pointer", + default=None, + help="Memory object pointer offset to request in decimal or 0xHex") + - parser.add_argument("-e", "--extension", - default=None, - help="mem object offset within the exension block (REQUIRED)") args = parser.parse_args() diff --git a/bin/j1939_mem_set.py b/bin/j1939_mem_set.py index 4ded432..6b8e959 100644 --- a/bin/j1939_mem_set.py +++ b/bin/j1939_mem_set.py @@ -117,9 +117,18 @@ def set_mem_object_single(channel='can0', bustype='socketcan', length=4, src=0, parser.add_argument("-l", "--length", default="1", help="number of bytes in the object (1-4) default=1") parser.add_argument("-s", "--source", default="0", help="source address (0-254) default=0") parser.add_argument("-d", "--destination", default="0x17", help="destination address (0-254) default=17") - parser.add_argument("-p", "--pointer", default="0x58", help="j1939 pointer (0-0xffffff) default=0x58") - parser.add_argument("-e", "--extension", default="0xe9", help="j1939 pointer extension (0-0xffffff) default=0x58") + + parser.add_argument("extension", + default=None, + help="Memory object extension prefix to request in decimal or 0xHex") + + parser.add_argument("pointer", + default=None, + help="Memory object pointer offset to request in decimal or 0xHex") + + parser.add_argument('value') + args = parser.parse_args() length = int(args.length,0) From 1aadfdd86432b4a610dcd113c53ca4dee91c5fc7 Mon Sep 17 00:00:00 2001 From: Miller Lowe Date: Tue, 27 Feb 2018 13:30:55 -0800 Subject: [PATCH 20/80] Updated the example j1939_mem_set.py Added pacing of 50 ms on block protocol transfers --- bin/j1939_mem_set.py | 93 +++++++++++++++++++++++++++++------------- j1939/__init__.py | 41 +++++++++++++++++-- j1939/arbitrationid.py | 70 ++++++++++++++++--------------- 3 files changed, 141 insertions(+), 63 deletions(-) diff --git a/bin/j1939_mem_set.py b/bin/j1939_mem_set.py index 6b8e959..039be5d 100644 --- a/bin/j1939_mem_set.py +++ b/bin/j1939_mem_set.py @@ -2,9 +2,9 @@ _name = "J1939 Memory-Object Writer" -__version__ = "1.0.0" -__date__ = "06/22/2017" -__exp__ = "(sabot)" # (Release Version) +__version__ = "1.0.1" +__date__ = "02/27/2018" +__exp__ = "()" # (Release Version) title = "%s Version: %s %s %s" % (_name, __version__, __date__, __exp__) @@ -15,14 +15,14 @@ # for responding to seed/key requests provide your own keyGenerator # class.. # mine is returned in a SeedToKey meghod of a Genkey class that sits elsewhere -# on my PYTHONPATH +# on my PYTHONPATH and is propriatiry # # TODO: use a better baseclass override model. # try: import genkey security = genkey.GenKey() - print("Genkey Loaded") + print("Private Genkey Loaded") except: # Stuff in a fake genKey responder. Pretty much just needs a # reference to any class that can convert a Seed to a Key.. For @@ -59,22 +59,31 @@ def set_mem_object_single(channel='can0', bustype='socketcan', length=4, src=0, bus.send(dm14pdu) sendBuffer = [length, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff] - if length == 1: - sendBuffer[1] = value; - elif length == 2: - sendBuffer[1] = value & 0xff - sendBuffer[2] = (value >> 8) & 0xff - elif length == 3: - sendBuffer[1] = value & 0xff - sendBuffer[2] = (value >> 8) & 0xff - sendBuffer[3] = (value >> 16) & 0xff - elif length == 4: - sendBuffer[1] = value & 0xff - sendBuffer[2] = (value >> 8) & 0xff - sendBuffer[3] = (value >> 16) & 0xff - sendBuffer[4] = (value >> 24) & 0xff - else: - raise ValueError("Don't know how to send a %d byte object" % length) + if isinstance(value, int): + if length == 1: + sendBuffer[1] = value; + elif length == 2: + sendBuffer[1] = value & 0xff + sendBuffer[2] = (value >> 8) & 0xff + elif length == 3: + sendBuffer[1] = value & 0xff + sendBuffer[2] = (value >> 8) & 0xff + sendBuffer[3] = (value >> 16) & 0xff + elif length == 4: + sendBuffer[1] = value & 0xff + sendBuffer[2] = (value >> 8) & 0xff + sendBuffer[3] = (value >> 16) & 0xff + sendBuffer[4] = (value >> 24) & 0xff + else: + raise ValueError("Don't know how to send a %d byte integer" % length) + + elif isinstance(value, list): + for i in range(1,len(value)+1): + sendBuffer[i] = value[i-1] + + + + dm16pgn = j1939.PGN(pdu_format=0xd7, pdu_specific=dest) dm16aid = j1939.ArbitrationID(pgn=dm16pgn, source_address=src, destination_address=dest) @@ -98,7 +107,7 @@ def set_mem_object_single(channel='can0', bustype='socketcan', length=4, src=0, if proceedCount == 2: bus.send(dm16pdu) if rcvPdu.data[0]==0 and rcvPdu.data[1]==0x19: - print("Value Sent") + #print("Value Sent") break; @@ -109,10 +118,26 @@ def set_mem_object_single(channel='can0', bustype='socketcan', length=4, src=0, if __name__ == "__main__": + examples = """ +examples: + # write the characters 'ERASE' to extension E9 ponter ED + $ python j1939_mem_set.py -d 0x17 0xe9 0xed ERASE + + # Illuminate 'N' Telltale, write a byte (1) to extension EA pointer 6B + $ python j1939_mem_set.py -d 0x17 0xea 0x6b 1 + + # extinguish 'N' Telltale, + $ python j1939_mem_set.py -d 0x17 0xea 0x6b 0 + + # Set B1/C4 Odometer to 200km (200=1km) + $ python j1939_mem_set.py --destination=0x17 --length=4 0xf1 0x00 20000 + +""" + import timeit import argparse - parser = argparse.ArgumentParser(description=title) + parser = argparse.ArgumentParser(description=title, formatter_class=argparse.RawDescriptionHelpFormatter, epilog=examples) parser.add_argument("-l", "--length", default="1", help="number of bytes in the object (1-4) default=1") parser.add_argument("-s", "--source", default="0", help="source address (0-254) default=0") @@ -120,14 +145,16 @@ def set_mem_object_single(channel='can0', bustype='socketcan', length=4, src=0, parser.add_argument("extension", default=None, - help="Memory object extension prefix to request in decimal or 0xHex") + help="Memory object extension prefix to request in decimal or 0xhex") parser.add_argument("pointer", default=None, - help="Memory object pointer offset to request in decimal or 0xHex") + help="Memory object pointer offset to request in decimal or 0xhex") - parser.add_argument('value') + parser.add_argument('value', + default=None, + help="numeric or string value, if not a single byte, be sure to specify length.") args = parser.parse_args() @@ -136,9 +163,19 @@ def set_mem_object_single(channel='can0', bustype='socketcan', length=4, src=0, dest = int(args.destination,0) ext = int(args.extension,0) ptr = int(args.pointer,0) - value = int(args.value,0) - print("Attepting to set %2X/%02X to %d" % (ext, ptr, value)) + # + # Try first to pull out a numeric argument, otherwise set it as a string. + # + try: + value = int(args.value,0) + except ValueError: + strValue = [ord(c) for c in args.value] + value = strValue + length = len(strValue) + + + print("Attepting to set %2X/%02X to %s" % (ext, ptr, value)) #value = hex(int(args.value,0)) # queries a couple objects but setting up the full stack and bus for diff --git a/j1939/__init__.py b/j1939/__init__.py index 6bc3891..a0bbf21 100644 --- a/j1939/__init__.py +++ b/j1939/__init__.py @@ -11,6 +11,7 @@ import threading import logging import pprint +import time try: from queue import Queue, Empty @@ -244,40 +245,66 @@ def send(self, msg, timeout=None): pdu = copy.deepcopy(msg) pdu.data = bytearray(pdu.data) + logger.info("j1939.send: Copied msg = %s" % pdu) pdu_length_lsb, pdu_length_msb = divmod(len(pdu.data), 256) while len(pdu.data) % 7 != 0: pdu.data += b'\xFF' + + # + # segment the longer message into 7 byte segments. We need to prefix each + # data[0] with a sequence number for the transfer + # for i, segment in enumerate(pdu.data_segments(segment_length=7)): arbitration_id = copy.deepcopy(pdu.arbitration_id) arbitration_id.pgn.value = PGN_TP_DATA_TRANSFER + + logger.info("j1939.send: i=%d, pdu.arbitration_id.pgn.is_destination_specific=%d, data=%s" % + (i,pdu.arbitration_id.pgn.is_destination_specific, segment)) + if pdu.arbitration_id.pgn.is_destination_specific and \ pdu.arbitration_id.destination_address != DESTINATION_ADDRESS_GLOBAL: + arbitration_id.pgn.pdu_specific = pdu.arbitration_id.pgn.pdu_specific else: arbitration_id.pgn.pdu_specific = DESTINATION_ADDRESS_GLOBAL + arbitration_id.destination_address = DESTINATION_ADDRESS_GLOBAL + logger.info("j1939.send: segment=%d, arb = %s" % (i, arbitration_id)) message = Message(arbitration_id=arbitration_id.can_id, extended_id=True, dlc=(len(segment) + 1), data=(bytearray([i + 1]) + segment)) messages.append(message) + # + # At this point we have the queued messages sequenced in 'messages' + # + logger.info("j1939.send: is_destination_specific=%d, destAddr=%s" % + (pdu.arbitration_id.pgn.is_destination_specific, + pdu.arbitration_id.destination_address)) + logger.info("j1939.send: messages=%s" % messages) + if pdu.arbitration_id.pgn.is_destination_specific and \ pdu.arbitration_id.destination_address != DESTINATION_ADDRESS_GLOBAL: + destination_address = pdu.arbitration_id.pgn.pdu_specific + if pdu.arbitration_id.source_address in self._incomplete_transmitted_pdus: if destination_address in self._incomplete_transmitted_pdus[pdu.arbitration_id.source_address]: logger.warning("Duplicate transmission of PDU:\n{}".format(pdu)) else: self._incomplete_transmitted_pdus[pdu.arbitration_id.source_address] = {} + + # append the messages to the 'incomplete' list self._incomplete_transmitted_pdus[pdu.arbitration_id.source_address][destination_address] = messages + else: destination_address = DESTINATION_ADDRESS_GLOBAL - logger.warning("rts arbitration id: src=%s, dest=%s" % (pdu.source, pdu.arbitration_id.destination_address)) - rts_arbitration_id = ArbitrationID(source_address=pdu.source, destination_address=pdu.arbitration_id.destination_address) + logger.warning("rts arbitration id: src=%s, dest=%s" % (pdu.source, destination_address)) + rts_arbitration_id = ArbitrationID(source_address=pdu.source, destination_address=destination_address) rts_arbitration_id.pgn.value = PGN_TP_CONNECTION_MANAGEMENT rts_arbitration_id.pgn.pdu_specific = pdu.arbitration_id.pgn.pdu_specific @@ -304,6 +331,7 @@ def send(self, msg, timeout=None): pgn_msb], dlc=8) try: + logger.info("j1939.send: sending TP.CTS to %s: %s" % (destination_address, rts_msg)) self.can_bus.send(rts_msg) except CanError: if self._ignore_can_send_error: @@ -311,6 +339,7 @@ def send(self, msg, timeout=None): raise else: rts_arbitration_id.pgn.pdu_specific = DESTINATION_ADDRESS_GLOBAL + rts_arbitration_id.destination_address = DESTINATION_ADDRESS_GLOBAL bam_msg = Message(extended_id=True, arbitration_id=rts_arbitration_id.can_id, data=[CM_MSG_TYPE_BAM, @@ -321,9 +350,13 @@ def send(self, msg, timeout=None): pgn_middle, pgn_msb], dlc=8) + bam_msg.destination_address = DESTINATION_ADDRESS_GLOBAL + # bam_msg.arbitration_id.destination_address = DESTINATION_ADDRESS_GLOBAL # send BAM try: + logger.info("j1939.send: sending TP.BAM to %s: %s" % (destination_address, bam_msg)) self.can_bus.send(bam_msg) + time.sleep(0.05) except CanError: if self._ignore_can_send_error: pass @@ -332,6 +365,7 @@ def send(self, msg, timeout=None): for message in messages: # send data messages - no flow control, so no need to wait # for receiving devices to acknowledge + logger.info("j1939.send: queue TP.BAM data to %s: %s" % (destination_address, message)) self._long_message_segment_queue.put_nowait(message) else: msg.display_radix = 'hex' @@ -704,7 +738,8 @@ def _throttler_function(self): pass if _msg is not None: try: - self.can_bus.send(msg) + self.can_bus.send(_msg) + time.sleep(0.05) except CanError: if self._ignore_can_send_error: pass diff --git a/j1939/arbitrationid.py b/j1939/arbitrationid.py index 1479ca6..499603a 100644 --- a/j1939/arbitrationid.py +++ b/j1939/arbitrationid.py @@ -22,31 +22,31 @@ def __init__(self, priority=7, pgn=None, source_address=0, destination_address=N Between 0 and 255. Will trrow a ValueError if PGN does not allow a dest """ - self.pgn = None + self._pgn = None self.priority = priority self.destination_address_value = None if pgn is None: - self.pgn = PGN() + self._pgn = PGN() elif pgn and isinstance(pgn, int): - self.pgn = PGN.from_value(pgn) + self._pgn = PGN.from_value(pgn) elif pgn and isinstance(pgn, PGN): - self.pgn = pgn + self._pgn = pgn else: ValueError("pgn must have convertable type") - self.pgn = pgn + #self.pgn = pgn if pgn: - if self.pgn.is_destination_specific: + if self._pgn.is_destination_specific: if destination_address is None: self.destination_address_value = DESTINATION_ADDRESS_GLOBAL else: if destination_address >= 0 and destination_address <= 255: self.destination_address_value = destination_address if self.destination_address_value != pgn.pdu_specific: - logger.debug("self.pgn=%s, self.destination_address_value = %x, pgn.pdu_specific = %x" % - (self.pgn, self.destination_address_value, pgn.pdu_specific)) + logger.debug("self._pgn=%s, self.destination_address_value = %x, pgn.pdu_specific = %x" % + (self._pgn, self.destination_address_value, pgn.pdu_specific)) # assert( self.destination_address_value == pgn.pdu_specific) else: @@ -56,24 +56,30 @@ def __init__(self, priority=7, pgn=None, source_address=0, destination_address=N @property def can_id(self): - logger.debug("can_id property: self.pgn.is_destination_specific=%s\npgn=%s" % (self.pgn.is_destination_specific, self.pgn)) + logger.debug("can_id property: self._pgn.is_destination_specific=%s\npgn=%s" % (self._pgn.is_destination_specific, self._pgn)) - if self.pgn.is_destination_specific: - logger.debug("can_id: self.pgn.is_destination_specific, dest=%s, pgn_value=%s, pdu_format=0x%x, pdu_specific=0x%x, pri=%s" % + if self._pgn.is_destination_specific: + logger.debug("can_id: self._pgn.is_destination_specific, dest=%s, pgn_value=%s, pdu_format=0x%x, pdu_specific=0x%x, pri=%s" % (self.destination_address_value, - self.pgn.value, - self.pgn.pdu_format, - self.pgn.pdu_specific, + self._pgn.value, + self._pgn.pdu_format, + self._pgn.pdu_specific, self.priority)) - retval = (self.source_address + - ((self.pgn.value & 0xff00) + (self.destination_address_value) << 8)+ - (self.priority << 26)) + if self.destination_address_value: + retval = (self.source_address + + ((self._pgn.value & 0xff00) + (self.destination_address_value) << 8)+ + (self.priority << 26)) + else: + retval = (self.source_address + + ((self._pgn.value & 0xff00) << 8)+ + (self.priority << 26)) + logger.debug("can_id: retval=0x%08x" % (retval)) return retval else: - logger.debug("can_id: NOT! self.pgn.is_destination_specific") - return (self.source_address + (self.pgn.value << 8) + (self.priority << 26)) + logger.debug("can_id: NOT! self._pgn.is_destination_specific") + return (self.source_address + (self._pgn.value << 8) + (self.priority << 26)) @can_id.setter def can_id(self, canid): @@ -82,29 +88,29 @@ def can_id(self, canid): """ logger.debug("can_id setter: canid=0x%08x" % (canid)) self.priority = (canid & 0x1C000000) >> 26 - self.pgn = PGN().from_can_id(canid) + self._pgn = PGN().from_can_id(canid) self.source_address = canid & 0x000000FF - if self.pgn.is_destination_specific: + if self._pgn.is_destination_specific: self.destination_address_value = (canid & 0x0000FF00) >> 8 logger.debug("can_id: canid=0x%08x, priority=%x, pdu_format=%x, pdu_specific=%x, src=%x" % (canid, self.priority, - self.pgn.pdu_format, - self.pgn.pdu_specific, + self._pgn.pdu_format, + self._pgn.pdu_specific, self.source_address)) @property def destination_address(self): - if self.pgn.is_destination_specific: + if self._pgn.is_destination_specific: return self.destination_address_value else: return None @destination_address.setter def destination_address(self, value): - if not self.pgn.is_destination_specific: - raise ValueError("PGN is not dest specific: {:04x}".format(self.pgn)) + if not self._pgn.is_destination_specific: + raise ValueError("PGN is not dest specific: {:04x}".format(self._pgn)) else: self.destination_address_value = value @@ -123,16 +129,16 @@ def pgn(self, other): self._pgn = other def __str__(self): - logger.debug("arbitrationid.__str__: ids:%d, pri:%s, pgn:%s, dest:%s, src:%s" % - (self.pgn.is_destination_specific, self.priority, self.pgn, self.destination_address_value, self.source_address)) + logger.debug("arbitrationid.__str__: ids:%d, pri:%s, pgn:%s, dest:%s, src:%s, ids:%d" % + (self._pgn.is_destination_specific, self.priority, self._pgn, self.destination_address_value, self.source_address, self._pgn.is_destination_specific)) - if self.pgn.is_destination_specific: + if self._pgn.is_destination_specific: if self.destination_address_value is not None: retval = "PRI=%d PGN=%6s DST=0x%.2x SRC=0x%.2x" % ( - self.priority, self.pgn, self.destination_address_value, self.source_address) + self.priority, self._pgn, self.destination_address_value, self.source_address) else: retval = "PRI=%d PGN=%6s DST=NONE(error) SRC=0x%.2x" % ( - self.priority, self.pgn, self.source_address) + self.priority, self._pgn, self.source_address) else: - retval = "PRI=%d PGN=%6s SRC=0x%.2x" % (self.priority, self.pgn, self.source_address) + retval = "PRI=%d PGN=%6s SRC=0x%.2x" % (self.priority, self._pgn, self.source_address) return retval From 9b1cf885c7fcb12f0b3bf7e2ed1def0a7a51bcee Mon Sep 17 00:00:00 2001 From: Miller Lowe Date: Wed, 4 Apr 2018 14:27:44 -0700 Subject: [PATCH 21/80] Updates to account for some python-can changes. --- j1939/__init__.py | 4 ++-- j1939/pdu.py | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/j1939/__init__.py b/j1939/__init__.py index a0bbf21..51102ef 100644 --- a/j1939/__init__.py +++ b/j1939/__init__.py @@ -384,7 +384,7 @@ def send(self, msg, timeout=None): raise def shutdown(self): - self.can_notifier.running.clear() + self.can_notifier._running.clear() self.can_bus.shutdown() #self.j1939_notifier.running.clear() super(Bus, self).shutdown() @@ -730,7 +730,7 @@ def _process_abort(self, msg): msg.arbitration_id.source_address] def _throttler_function(self): - while self.can_notifier.running.is_set(): + while self.can_notifier._running.is_set(): _msg = None try: _msg = self._long_message_segment_queue.get(timeout=0.1) diff --git a/j1939/pdu.py b/j1939/pdu.py index a0ddb4e..e009606 100644 --- a/j1939/pdu.py +++ b/j1939/pdu.py @@ -111,6 +111,7 @@ def _check_data(self, value): for element in value: if isinstance(element, str): element = int(element) + #logger.warn("!!! element=%s type(element)=%s" % (element, type(element))) assert element >= 0, 'Data values must be between 0 and 255, element={}'.format(element) assert element <= 255, 'Data values must be between 0 and 255' return value From 23fce96b9c42edcd6d37784cc7a29d8be261167f Mon Sep 17 00:00:00 2001 From: Miller Lowe Date: Tue, 10 Apr 2018 11:31:56 -0700 Subject: [PATCH 22/80] Johns changes to support a query of a zero value --- bin/j1939_mem_query.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/j1939_mem_query.py b/bin/j1939_mem_query.py index 6c5a9d1..bb8e922 100644 --- a/bin/j1939_mem_query.py +++ b/bin/j1939_mem_query.py @@ -55,7 +55,7 @@ def get_mem_object_single(channel='can0', bustype='socketcan', length=4, src=0, bus.shutdown() - if not result: + if (result == None): raise IOError(" no CAN response") @@ -90,7 +90,7 @@ def get_mem_object(bus=None, length=4, src=0, dest=0x17, pointer=0, extension=0) countdown -= 1 - if not result: + if (result == None): raise IOError(" no CAN response") return result From 972ab166f71c0821982386c49b93c41b4edbebb3 Mon Sep 17 00:00:00 2001 From: rsmssnpdr Date: Thu, 17 May 2018 11:55:21 -0700 Subject: [PATCH 23/80] Send PGN | Install all bin files --- bin/j1939_send_pgn.py | 145 ++++++++++++++++++++++++++++++++++++++++++ setup.py | 8 ++- 2 files changed, 152 insertions(+), 1 deletion(-) create mode 100644 bin/j1939_send_pgn.py diff --git a/bin/j1939_send_pgn.py b/bin/j1939_send_pgn.py new file mode 100644 index 0000000..9ecb2bc --- /dev/null +++ b/bin/j1939_send_pgn.py @@ -0,0 +1,145 @@ +#!/usr/bin/python +# +from __future__ import print_function + +_name = "" +__version__ = "1.0.0" +__date__ = "12/21/2017" +__exp__ = "(expirimental)" # (Release Version) +title = "%s Version: %s %s %s" % (_name, __version__, __date__, __exp__) + +import j1939 + +try: + import genkey + security = genkey.GenKey() + print("Private Genkey Loaded") +except: + # Stuff in a fake genKey responder. Pretty much just needs a + # reference to any class that can convert a Seed to a Key.. For + # obvious reasons I'm not posting mine + print("Genkey Not loaded, This one will generate garbage keys") + class Genkey: + def SeedToKey(self, seed): + return 0x12345678 + + security = Genkey() + +def send_pgn(requested_pgn, data, channel='can0', bustype='socketcan', length=4, src=0, dest=0x17, bus=None): + + countdown = 10 + result = None + + if not isinstance(requested_pgn, int): + raise ValueError("pgn must be an integer.") + if bus is None: + bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01, keygen=security.SeedToKey) + close = True + else: + close = False + pgn = j1939.PGN() + if requested_pgn < 0xf000: + requested_pgn |= dest + pgn.value = requested_pgn#0xea00 + dest # request_pgn mem-object + aid = j1939.ArbitrationID(pgn=pgn, source_address=src, destination_address=dest) + + print(data) + pdu = j1939.PDU(timestamp=0.0, arbitration_id=aid, data=data, info_strings=None) + + pdu.display_radix='hex' + + bus.send(pdu) + if close: + bus.shutdown() + if 0: + while countdown: + pdu = bus.recv(timeout=1) + if pdu and (pdu.pgn == 0xe800 or pdu.pgn == requested_pgn): + result = list(pdu.data) + break # got what I was waiting for + + if pdu: + countdown -= 1 + + + if not result: + raise IOError(" no CAN response") + + + return result + + +if __name__ == "__main__": + + import traceback + import timeit + import time + import argparse + import logging + import textwrap + + def getStringValAsInt(s): + if s.startswith("0x"): + return int(s[2:],base=16) + else: + return int(s, base=10) + + + logger = logging.getLogger("j1939") + ch = logging.StreamHandler() + ch.setLevel(logging.WARNING) + logger.addHandler(ch) + + parser = argparse.ArgumentParser(description='''\ + example: %(prog)s -d 0x21 65223 + + will request a specific PGN 65223 from dest ''' + ,epilog=title) + + parser.add_argument("-s", "--src", + default="0", + help="j1939 source address decimal or hex, default is 0") + + parser.add_argument("-d", "--dest", + default="0x17", + help="CAN destination, default is 0x17") + + parser.add_argument("pgn", + default=None, + help="pgn to request in decimal or 0xHex") + parser.add_argument("data", + nargs='*', + default=[], + help='''Data to be sent with pgn. + Accepts: int/hex values or a single string''') + args = parser.parse_args() + + + source = getStringValAsInt(args.src) + dest = getStringValAsInt(args.dest) + pgn = getStringValAsInt(args.pgn) + data = args.data + print(data) + if len(data) == 1: + try: + value = getStringValAsInt(data[0]) + data = [value] + except ValueError: + data = [ord(c) for c in data[0]] + print(data) + elif len(data) > 1: + data = [getStringValAsInt(x) for x in data] + + if len(data) > 8: + print("Unable to send {} buffer of size: {}".format(data, len(data))) + exit() + + while len(data) > 8: + data.append(0xff) + + print ("Sending PGN: (pgn=0x%04x (%d), src=0x%02x, dest=0x%02x)" % (pgn, pgn, source, dest)) + + val = send_pgn(pgn, data, length=len(data), src=source, dest=dest) + + print("returned PGN = %s" % val) + diff --git a/setup.py b/setup.py index 3cf2c8d..56c5161 100644 --- a/setup.py +++ b/setup.py @@ -26,7 +26,13 @@ install_requires=["python-can>=2.0.0a2"], - scripts=["./bin/j1939_logger.py"], + scripts=[ + "./bin/j1939_logger.py", + "./bin/j1939_mem_query.py", + "./bin/j1939_mem_set.py", + "./bin/j1939_request_pgn.py", + "./bin/j1939_send_pgn.py" + ], # Tests can be run using `python setup.py test` test_suite="nose.collector", From f4383e8f87bf9ca46bd6fc5b5537c5bd64b22133 Mon Sep 17 00:00:00 2001 From: rsmssnpdr Date: Mon, 21 May 2018 09:23:30 -0700 Subject: [PATCH 24/80] Fix broken loop | Convert int inputs --- bin/j1939_send_pgn.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/bin/j1939_send_pgn.py b/bin/j1939_send_pgn.py index 9ecb2bc..49329f5 100644 --- a/bin/j1939_send_pgn.py +++ b/bin/j1939_send_pgn.py @@ -82,7 +82,11 @@ def getStringValAsInt(s): if s.startswith("0x"): return int(s[2:],base=16) else: - return int(s, base=10) + temp = int(s, base=10) + # 4 bit numbers need to not have a preceding 0 + if temp < 0xf0: + temp = temp << 8 + return temp logger = logging.getLogger("j1939") @@ -134,8 +138,6 @@ def getStringValAsInt(s): print("Unable to send {} buffer of size: {}".format(data, len(data))) exit() - while len(data) > 8: - data.append(0xff) print ("Sending PGN: (pgn=0x%04x (%d), src=0x%02x, dest=0x%02x)" % (pgn, pgn, source, dest)) From 6c4c99e8b923aeca1af9b987205d016dd5bd5527 Mon Sep 17 00:00:00 2001 From: Miller Lowe Date: Fri, 6 Jul 2018 10:40:31 -0700 Subject: [PATCH 25/80] merge conflicts --- bin/j1939_mem_query.py | 9 +++++++-- bin/j1939_mem_set.py | 25 ++++++++++++++++++++----- j1939/__init__.py | 2 +- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/bin/j1939_mem_query.py b/bin/j1939_mem_query.py index bb8e922..8be6107 100644 --- a/bin/j1939_mem_query.py +++ b/bin/j1939_mem_query.py @@ -129,6 +129,10 @@ def getStringVal(s): default="0x17", help="CAN destination, default is 0x17") + parser.add_argument("-l", "--length", + default="4", + help="length in bytes (default: 4)") + parser.add_argument("extension", default=None, help="Memory object extension prefix to request in decimal or 0xHex") @@ -177,11 +181,12 @@ def getStringVal(s): source = getStringVal(args.src) dest = getStringVal(args.dest) ptr = getStringVal(args.pointer) + length = getStringVal(args.length) ext = getStringVal(args.extension) - print ("get_mem_object_single(src=0x%02x, dest=0x%02x, pointer=0x%02x, extension=0x%02x" % (source, dest, ptr, ext)) + print ("get_mem_object_single(src=0x%02x, dest=0x%02x, pointer=0x%02x, extension/space=0x%02x, len=%d" % (source, dest, ptr, ext, length)) - val = get_mem_object_single(length=4, src=source, dest=dest, pointer=ptr, extension=ext) + val = get_mem_object_single(length=length, src=source, dest=dest, pointer=ptr, extension=ext) print("0x%02x-0x%02x = %d (0x%08x)" % (ptr, ext, val, val)) diff --git a/bin/j1939_mem_set.py b/bin/j1939_mem_set.py index 039be5d..1d37239 100644 --- a/bin/j1939_mem_set.py +++ b/bin/j1939_mem_set.py @@ -58,7 +58,14 @@ def set_mem_object_single(channel='can0', bustype='socketcan', length=4, src=0, bus.send(dm14pdu) - sendBuffer = [length, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff] + sendBuffer = [] + sendBuffer.append(length) + for i in range(0, length): + sendBuffer.append(0xff) + + #sendBuffer = [length, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff] + + print("## length=%d, value=%s " % (length, value)) if isinstance(value, int): if length == 1: sendBuffer[1] = value; @@ -81,6 +88,14 @@ def set_mem_object_single(channel='can0', bustype='socketcan', length=4, src=0, for i in range(1,len(value)+1): sendBuffer[i] = value[i-1] + elif isinstance(value, str): + for i in range(1,len(value)+1): + sendBuffer[i] = ord(value[i-1]) + + print("## sendBuffer=%s " % (sendBuffer)) + + + @@ -90,6 +105,7 @@ def set_mem_object_single(channel='can0', bustype='socketcan', length=4, src=0, dm16pdu = j1939.PDU(timestamp=0.0, arbitration_id=dm16aid, data=sendBuffer) dm16pdu.display_radix='hex' + print("## PDU=%s " % (dm16pdu)) # Wait around for a while looking for the second proceed @@ -163,19 +179,18 @@ def set_mem_object_single(channel='can0', bustype='socketcan', length=4, src=0, dest = int(args.destination,0) ext = int(args.extension,0) ptr = int(args.pointer,0) + value = args.value # # Try first to pull out a numeric argument, otherwise set it as a string. # try: value = int(args.value,0) + print("Attepting to set %2X/%02X to %s" % (ext, ptr, value)) except ValueError: - strValue = [ord(c) for c in args.value] - value = strValue - length = len(strValue) + length = len(value) - print("Attepting to set %2X/%02X to %s" % (ext, ptr, value)) #value = hex(int(args.value,0)) # queries a couple objects but setting up the full stack and bus for diff --git a/j1939/__init__.py b/j1939/__init__.py index 51102ef..d90a537 100644 --- a/j1939/__init__.py +++ b/j1939/__init__.py @@ -303,7 +303,7 @@ def send(self, msg, timeout=None): else: destination_address = DESTINATION_ADDRESS_GLOBAL - logger.warning("rts arbitration id: src=%s, dest=%s" % (pdu.source, destination_address)) + logger.debug("rts arbitration id: src=%s, dest=%s" % (pdu.source, destination_address)) rts_arbitration_id = ArbitrationID(source_address=pdu.source, destination_address=destination_address) rts_arbitration_id.pgn.value = PGN_TP_CONNECTION_MANAGEMENT rts_arbitration_id.pgn.pdu_specific = pdu.arbitration_id.pgn.pdu_specific From dcc26a9aae63cad4d90e3c2b40cf332bddaa2015 Mon Sep 17 00:00:00 2001 From: rsmssnpdr Date: Tue, 24 Jul 2018 13:32:43 -0700 Subject: [PATCH 26/80] more formatting fixes --- bin/j1939_mem_set.py | 8 ++++---- bin/j1939_request_pgn.py | 2 +- j1939/arbitrationid.py | 1 - 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/bin/j1939_mem_set.py b/bin/j1939_mem_set.py index 039be5d..bd1041f 100644 --- a/bin/j1939_mem_set.py +++ b/bin/j1939_mem_set.py @@ -30,7 +30,7 @@ print("Genkey Not loaded, This one will generate garbage keys") class Genkey: def SeedToKey(self, seed): - return 0x12345678; + return 0x12345678 security = Genkey() @@ -61,7 +61,7 @@ def set_mem_object_single(channel='can0', bustype='socketcan', length=4, src=0, sendBuffer = [length, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff] if isinstance(value, int): if length == 1: - sendBuffer[1] = value; + sendBuffer[1] = value elif length == 2: sendBuffer[1] = value & 0xff sendBuffer[2] = (value >> 8) & 0xff @@ -94,7 +94,7 @@ def set_mem_object_single(channel='can0', bustype='socketcan', length=4, src=0, # Wait around for a while looking for the second proceed countdown=10 - proceedCount = 0; + proceedCount = 0 while countdown: countdown -= 1 rcvPdu = bus.recv(2) @@ -108,7 +108,7 @@ def set_mem_object_single(channel='can0', bustype='socketcan', length=4, src=0, bus.send(dm16pdu) if rcvPdu.data[0]==0 and rcvPdu.data[1]==0x19: #print("Value Sent") - break; + break bus.shutdown() diff --git a/bin/j1939_request_pgn.py b/bin/j1939_request_pgn.py index b4fd5e3..da138e9 100644 --- a/bin/j1939_request_pgn.py +++ b/bin/j1939_request_pgn.py @@ -46,7 +46,7 @@ def request_pgn_single(requested_pgn, channel='can0', bustype='socketcan', lengt bus.shutdown() - if not result: + if not result: raise IOError(" no CAN response") diff --git a/j1939/arbitrationid.py b/j1939/arbitrationid.py index 499603a..147b74f 100644 --- a/j1939/arbitrationid.py +++ b/j1939/arbitrationid.py @@ -47,7 +47,6 @@ def __init__(self, priority=7, pgn=None, source_address=0, destination_address=N if self.destination_address_value != pgn.pdu_specific: logger.debug("self._pgn=%s, self.destination_address_value = %x, pgn.pdu_specific = %x" % (self._pgn, self.destination_address_value, pgn.pdu_specific)) - # assert( self.destination_address_value == pgn.pdu_specific) else: raise ValueError("destination address must be in range (0-255)") From c4e70fa2ac163d5fea5d3fa9f93c9c87a428a6cf Mon Sep 17 00:00:00 2001 From: Miller Lowe Date: Fri, 6 Jul 2018 10:40:31 -0700 Subject: [PATCH 27/80] merge conflicts --- bin/j1939_mem_query.py | 9 +++++++-- bin/j1939_mem_set.py | 25 ++++++++++++++++++++----- j1939/__init__.py | 2 +- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/bin/j1939_mem_query.py b/bin/j1939_mem_query.py index bb8e922..8be6107 100644 --- a/bin/j1939_mem_query.py +++ b/bin/j1939_mem_query.py @@ -129,6 +129,10 @@ def getStringVal(s): default="0x17", help="CAN destination, default is 0x17") + parser.add_argument("-l", "--length", + default="4", + help="length in bytes (default: 4)") + parser.add_argument("extension", default=None, help="Memory object extension prefix to request in decimal or 0xHex") @@ -177,11 +181,12 @@ def getStringVal(s): source = getStringVal(args.src) dest = getStringVal(args.dest) ptr = getStringVal(args.pointer) + length = getStringVal(args.length) ext = getStringVal(args.extension) - print ("get_mem_object_single(src=0x%02x, dest=0x%02x, pointer=0x%02x, extension=0x%02x" % (source, dest, ptr, ext)) + print ("get_mem_object_single(src=0x%02x, dest=0x%02x, pointer=0x%02x, extension/space=0x%02x, len=%d" % (source, dest, ptr, ext, length)) - val = get_mem_object_single(length=4, src=source, dest=dest, pointer=ptr, extension=ext) + val = get_mem_object_single(length=length, src=source, dest=dest, pointer=ptr, extension=ext) print("0x%02x-0x%02x = %d (0x%08x)" % (ptr, ext, val, val)) diff --git a/bin/j1939_mem_set.py b/bin/j1939_mem_set.py index bd1041f..d57196f 100644 --- a/bin/j1939_mem_set.py +++ b/bin/j1939_mem_set.py @@ -58,7 +58,14 @@ def set_mem_object_single(channel='can0', bustype='socketcan', length=4, src=0, bus.send(dm14pdu) - sendBuffer = [length, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff] + sendBuffer = [] + sendBuffer.append(length) + for i in range(0, length): + sendBuffer.append(0xff) + + #sendBuffer = [length, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff] + + print("## length=%d, value=%s " % (length, value)) if isinstance(value, int): if length == 1: sendBuffer[1] = value @@ -81,6 +88,14 @@ def set_mem_object_single(channel='can0', bustype='socketcan', length=4, src=0, for i in range(1,len(value)+1): sendBuffer[i] = value[i-1] + elif isinstance(value, str): + for i in range(1,len(value)+1): + sendBuffer[i] = ord(value[i-1]) + + print("## sendBuffer=%s " % (sendBuffer)) + + + @@ -90,6 +105,7 @@ def set_mem_object_single(channel='can0', bustype='socketcan', length=4, src=0, dm16pdu = j1939.PDU(timestamp=0.0, arbitration_id=dm16aid, data=sendBuffer) dm16pdu.display_radix='hex' + print("## PDU=%s " % (dm16pdu)) # Wait around for a while looking for the second proceed @@ -163,19 +179,18 @@ def set_mem_object_single(channel='can0', bustype='socketcan', length=4, src=0, dest = int(args.destination,0) ext = int(args.extension,0) ptr = int(args.pointer,0) + value = args.value # # Try first to pull out a numeric argument, otherwise set it as a string. # try: value = int(args.value,0) + print("Attepting to set %2X/%02X to %s" % (ext, ptr, value)) except ValueError: - strValue = [ord(c) for c in args.value] - value = strValue - length = len(strValue) + length = len(value) - print("Attepting to set %2X/%02X to %s" % (ext, ptr, value)) #value = hex(int(args.value,0)) # queries a couple objects but setting up the full stack and bus for diff --git a/j1939/__init__.py b/j1939/__init__.py index 51102ef..d90a537 100644 --- a/j1939/__init__.py +++ b/j1939/__init__.py @@ -303,7 +303,7 @@ def send(self, msg, timeout=None): else: destination_address = DESTINATION_ADDRESS_GLOBAL - logger.warning("rts arbitration id: src=%s, dest=%s" % (pdu.source, destination_address)) + logger.debug("rts arbitration id: src=%s, dest=%s" % (pdu.source, destination_address)) rts_arbitration_id = ArbitrationID(source_address=pdu.source, destination_address=destination_address) rts_arbitration_id.pgn.value = PGN_TP_CONNECTION_MANAGEMENT rts_arbitration_id.pgn.pdu_specific = pdu.arbitration_id.pgn.pdu_specific From f9ec204b3829f2e95dd87539119423c07607c6a0 Mon Sep 17 00:00:00 2001 From: rsmssnpdr Date: Tue, 24 Jul 2018 16:27:41 -0700 Subject: [PATCH 28/80] fix for current py-CAN --- .gitignore | 3 +++ bin/j1939_logger.py | 1 + j1939/__init__.py | 6 +++--- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index e2fc363..0379983 100644 --- a/.gitignore +++ b/.gitignore @@ -67,3 +67,6 @@ target/ *.swp *.swo */*.swo + +# ignore moved examples +bin/get_ecu_block.py diff --git a/bin/j1939_logger.py b/bin/j1939_logger.py index 3389cd4..538e949 100644 --- a/bin/j1939_logger.py +++ b/bin/j1939_logger.py @@ -93,6 +93,7 @@ def parse_arguments(): ''')) parser.add_argument('-i', '--interface', dest="interface", + default='socketcan', #choices=can.interfaces.VALID_INTERFACES, help=textwrap.dedent('''\ Specify the backend CAN interface to use. diff --git a/j1939/__init__.py b/j1939/__init__.py index d90a537..2ed1909 100644 --- a/j1939/__init__.py +++ b/j1939/__init__.py @@ -80,7 +80,7 @@ def __init__(self, pdu_type=PDU, broadcast=True, *args, **kwargs): self.queue = Queue() self.node_queue_list = [] # Start with nothing - super(Bus, self).__init__() + super(Bus, self).__init__(kwargs.get('channel'), kwargs.get('can_filters')) self._pdu_type = pdu_type self.timeout = 1 self._long_message_throttler = threading.Thread(target=self._throttler_function) @@ -384,7 +384,7 @@ def send(self, msg, timeout=None): raise def shutdown(self): - self.can_notifier._running.clear() + self.can_notifier._running = False self.can_bus.shutdown() #self.j1939_notifier.running.clear() super(Bus, self).shutdown() @@ -730,7 +730,7 @@ def _process_abort(self, msg): msg.arbitration_id.source_address] def _throttler_function(self): - while self.can_notifier._running.is_set(): + while self.can_notifier._running: _msg = None try: _msg = self._long_message_segment_queue.get(timeout=0.1) From 7fd9f28020a591b4ebbf1913dfc48f9f6e3370ee Mon Sep 17 00:00:00 2001 From: rsmssnpdr Date: Tue, 24 Jul 2018 17:03:48 -0700 Subject: [PATCH 29/80] No longer hangs when killed --- j1939/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/j1939/__init__.py b/j1939/__init__.py index 2ed1909..84f7f65 100644 --- a/j1939/__init__.py +++ b/j1939/__init__.py @@ -84,7 +84,7 @@ def __init__(self, pdu_type=PDU, broadcast=True, *args, **kwargs): self._pdu_type = pdu_type self.timeout = 1 self._long_message_throttler = threading.Thread(target=self._throttler_function) - #self._long_message_throttler.daemon = True + self._long_message_throttler.daemon = True self._incomplete_received_pdus = {} self._incomplete_received_pdu_lengths = {} From 7019fcf09589128229e3548c5b31476c1b8f872b Mon Sep 17 00:00:00 2001 From: rsmssnpdr Date: Wed, 25 Jul 2018 16:54:31 -0700 Subject: [PATCH 30/80] trying to get CAN to talk --- bin/j1939_logger.py | 2 +- bin/j1939_mem_query.py | 33 ++++++++++++++++++++++++++++++--- bin/j1939_send_pgn.py | 4 ++-- j1939/__init__.py | 4 ++-- 4 files changed, 35 insertions(+), 8 deletions(-) diff --git a/bin/j1939_logger.py b/bin/j1939_logger.py index 538e949..367f52d 100644 --- a/bin/j1939_logger.py +++ b/bin/j1939_logger.py @@ -9,7 +9,7 @@ import j1939 import logging -lLevel = logging.WARNING +lLevel = logging.DEBUG logger = logging.getLogger() if 1: diff --git a/bin/j1939_mem_query.py b/bin/j1939_mem_query.py index 8be6107..939edf3 100644 --- a/bin/j1939_mem_query.py +++ b/bin/j1939_mem_query.py @@ -19,6 +19,18 @@ import logging import textwrap +''' +1532554003.434215 PRI=7 PGN=0xff9a SRC=0x17 d3 ff ff ff ff ff ff ff +1532554003.434771 PRI=6 PGN=0xd041 DST=0x41 SRC=0x17 a1 ff ff ff ff ff ff ff +1532554003.863598 PRI=7 PGN=0xd917 DST=0x17 SRC=0x18 0a 13 11 00 00 e9 ff ff +1532554003.868833 PRI=6 PGN=0xd818 DST=0x18 SRC=0x17 0a 11 ff ff ff ff ff ff +1532554003.901772 PRI=7 PGN=0xd718 DST=NONE(error) SRC=0x17 ff 59 30 31 2e 30 34 2e 32 30 00 +1532554003.908125 PRI=7 PGN=0xd917 DST=0x17 SRC=0x18 ff 09 00 00 00 00 ff ff +1532554003.939402 PRI=7 PGN=0xff9a SRC=0x17 d3 ff ff ff ff ff ff ff +1532554003.939959 PRI=6 PGN=0xd041 DST=0x41 SRC=0x17 9c ff ff ff ff ff ff ff +1532554003.940621 PRI=6 PGN=0xfec1 SRC=0x17 00 00 00 00 00 00 00 00 +1532554003.941260 PRI=6 PGN=0xfefc SRC=0x17 ff ff ff ff ff ff ff ff +''' def get_mem_object_single(channel='can0', bustype='socketcan', length=4, src=0, dest=0x17, pointer=0, extension=0): #from can.interfaces.interface import * @@ -27,6 +39,8 @@ def get_mem_object_single(channel='can0', bustype='socketcan', length=4, src=0, result = None bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01) + node = j1939.Node(bus, j1939.NodeName(), [src]) + bus.connect(node) pgn = j1939.PGN() pgn.value = 0xd900 + dest # Request a DM14 mem-object aid = j1939.ArbitrationID(pgn=pgn, source_address=src, destination_address=dest) @@ -38,9 +52,20 @@ def get_mem_object_single(channel='can0', bustype='socketcan', length=4, src=0, bus.send(pdu) + '''dm16pgn = j1939.PGN(pdu_format=0xd9, pdu_specific=dest) + dm16aid = j1939.ArbitrationID(pgn=dm16pgn, source_address=src, destination_address=dest) + dm16pdu = j1939.PDU(timestamp=0.0, arbitration_id=dm16aid, data=[0xff, 0x09, 0, 0, 0, 0, 0xff, 0xff]) + dm16pdu.display_radix='hex' + + print("## PDU=%s " % (dm16pdu))''' + + while countdown: pdu = bus.recv(timeout=1) - if pdu and pdu.pgn == 0xd700: + if pdu is None: + continue + print(pdu) + if pdu.pgn == 0xd700: value = list(pdu.data) length = value[0] if length == 1: @@ -50,12 +75,14 @@ def get_mem_object_single(channel='can0', bustype='socketcan', length=4, src=0, if length == 4: result = (value[4] << 24) + (value[3] << 16) + (value[2] << 8) + value[1] break # got what I was waiting for - + elif pdu.pgn == 0xd800: + #bus.send(dm16pdu) + pass countdown -= 1 bus.shutdown() - if (result == None): + if result is None: raise IOError(" no CAN response") diff --git a/bin/j1939_send_pgn.py b/bin/j1939_send_pgn.py index 49329f5..402ca7b 100644 --- a/bin/j1939_send_pgn.py +++ b/bin/j1939_send_pgn.py @@ -84,8 +84,8 @@ def getStringValAsInt(s): else: temp = int(s, base=10) # 4 bit numbers need to not have a preceding 0 - if temp < 0xf0: - temp = temp << 8 + #if temp < 0xf0: + # temp = temp << 8 return temp diff --git a/j1939/__init__.py b/j1939/__init__.py index 84f7f65..b452d26 100644 --- a/j1939/__init__.py +++ b/j1939/__init__.py @@ -40,9 +40,9 @@ logger = logging.getLogger("j1939") -logger.setLevel(logging.WARNING) +logger.setLevel(logging.DEBUG) -can_set_logging_level('warning') +can_set_logging_level('debug') class j1939Listner(canListener): From 7aabefc81cd0b3d01cef74e9476af40db5463bba Mon Sep 17 00:00:00 2001 From: rsmssnpdr Date: Thu, 26 Jul 2018 11:00:22 -0700 Subject: [PATCH 31/80] mem_query can recieve large data --- bin/j1939_mem_query.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/bin/j1939_mem_query.py b/bin/j1939_mem_query.py index 939edf3..e6f138a 100644 --- a/bin/j1939_mem_query.py +++ b/bin/j1939_mem_query.py @@ -38,7 +38,7 @@ def get_mem_object_single(channel='can0', bustype='socketcan', length=4, src=0, countdown = 10 result = None - bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01) + bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01, broadcast=False) node = j1939.Node(bus, j1939.NodeName(), [src]) bus.connect(node) pgn = j1939.PGN() @@ -70,10 +70,12 @@ def get_mem_object_single(channel='can0', bustype='socketcan', length=4, src=0, length = value[0] if length == 1: result = value[1] - if length == 2: + elif length == 2: result = (value[2] << 8) + value[1] - if length == 4: + elif length == 4: result = (value[4] << 24) + (value[3] << 16) + (value[2] << 8) + value[1] + else: + result = value[1:] break # got what I was waiting for elif pdu.pgn == 0xd800: #bus.send(dm16pdu) @@ -215,5 +217,9 @@ def getStringVal(s): val = get_mem_object_single(length=length, src=source, dest=dest, pointer=ptr, extension=ext) - print("0x%02x-0x%02x = %d (0x%08x)" % (ptr, ext, val, val)) + out = '' + for x in val: + out+=chr(x) + print(out) + #print("0x%02x-0x%02x = %d (0x%08x)" % (ptr, ext, val, val)) From efeb56eb10ff922f7be2d04dbfeb5809cc6900aa Mon Sep 17 00:00:00 2001 From: Miller Lowe Date: Thu, 26 Jul 2018 11:14:16 -0700 Subject: [PATCH 32/80] Re writing history From 9093f0d88dcdb974785dc4aa108af724176d206a Mon Sep 17 00:00:00 2001 From: rsmssnpdr Date: Thu, 26 Jul 2018 14:25:09 -0700 Subject: [PATCH 33/80] updated git ignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 0379983..4dedbc4 100644 --- a/.gitignore +++ b/.gitignore @@ -70,3 +70,5 @@ target/ # ignore moved examples bin/get_ecu_block.py + +*/genkey.py From a32f36279dcab6d3f707ec9cc49a2817ea331634 Mon Sep 17 00:00:00 2001 From: rsmssnpdr Date: Thu, 26 Jul 2018 16:49:41 -0700 Subject: [PATCH 34/80] debugging mem set --- bin/j1939_mem_query.py | 2 +- bin/j1939_mem_set.py | 13 +++++++++---- j1939/__init__.py | 17 +++++++++++++++++ 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/bin/j1939_mem_query.py b/bin/j1939_mem_query.py index e6f138a..87e60c6 100644 --- a/bin/j1939_mem_query.py +++ b/bin/j1939_mem_query.py @@ -216,7 +216,7 @@ def getStringVal(s): print ("get_mem_object_single(src=0x%02x, dest=0x%02x, pointer=0x%02x, extension/space=0x%02x, len=%d" % (source, dest, ptr, ext, length)) val = get_mem_object_single(length=length, src=source, dest=dest, pointer=ptr, extension=ext) - + print(val) out = '' for x in val: out+=chr(x) diff --git a/bin/j1939_mem_set.py b/bin/j1939_mem_set.py index d57196f..5528fae 100644 --- a/bin/j1939_mem_set.py +++ b/bin/j1939_mem_set.py @@ -40,8 +40,9 @@ def set_mem_object_single(channel='can0', bustype='socketcan', length=4, src=0, countdown = 10 result = -1 - bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01, keygen=security.SeedToKey) - + bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01, keygen=security.SeedToKey, broadcast=False) + node = j1939.Node(bus, j1939.NodeName(), [src]) + bus.connect(node) #dm14pgn = j1939.PGN() dm14data = [length, 0x15, pointer, 0x00, 0x00, extension, 0xff, 0xff] @@ -116,14 +117,15 @@ def set_mem_object_single(channel='can0', bustype='socketcan', length=4, src=0, rcvPdu = bus.recv(2) if rcvPdu: rcvPdu.display_radix='hex' - #print("received PDU: %s", rcvPdu) + print("received PDU: %s", rcvPdu) if rcvPdu.pgn == 0xd800: if rcvPdu.data[0]==1 and rcvPdu.data[1]==0x11: proceedCount += 1 if proceedCount == 2: bus.send(dm16pdu) + print('Sent ', dm16pdu) if rcvPdu.data[0]==0 and rcvPdu.data[1]==0x19: - #print("Value Sent") + print("Value Sent") break @@ -153,6 +155,9 @@ def set_mem_object_single(channel='can0', bustype='socketcan', length=4, src=0, import timeit import argparse + import logging + import logging.handlers + parser = argparse.ArgumentParser(description=title, formatter_class=argparse.RawDescriptionHelpFormatter, epilog=examples) parser.add_argument("-l", "--length", default="1", help="number of bytes in the object (1-4) default=1") diff --git a/j1939/__init__.py b/j1939/__init__.py index b452d26..5f5dc17 100644 --- a/j1939/__init__.py +++ b/j1939/__init__.py @@ -10,6 +10,7 @@ import threading import logging +import logging.handlers import pprint import time @@ -42,6 +43,21 @@ logger = logging.getLogger("j1939") logger.setLevel(logging.DEBUG) +lLevel = logging.DEBUG +logger.setLevel(lLevel) +ch = logging.StreamHandler() +ch.setLevel(lLevel) +chformatter = logging.Formatter('%(name)25s | %(threadName)10s | %(levelname)5s | %(message)s') +ch.setFormatter(chformatter) +#logger.addHandler(ch) + +fileHandler = logging.handlers.RotatingFileHandler('/tmp/j1939.log', \ + maxBytes = (1024*1024*20), \ + backupCount = 4) +fileHandler.setFormatter(chformatter) +fileHandler.setLevel(lLevel) +logger.addHandler(fileHandler) + can_set_logging_level('debug') class j1939Listner(canListener): @@ -434,6 +450,7 @@ def _process_incoming_message(self, msg): pdu = self._pdu_type(timestamp=msg.timestamp, data=msg.data, info_strings=[]) pdu.arbitration_id.can_id = msg.arbitration_id pdu.info_strings = [] + pdu.radix = 16 logger.info("PI02: arbitration_id.pgn.value == 0x%04x" % arbitration_id.pgn.value) From 8fbd36dc03fdd7daf6ab3bad54ab8694aac38ae8 Mon Sep 17 00:00:00 2001 From: Miller Lowe Date: Fri, 27 Jul 2018 11:30:43 -0700 Subject: [PATCH 35/80] Cleaned up some of the larger RTS/CTS issues so that the set and query utilities work --- j1939/__init__.py | 50 +++++++++++++++++++++++++++--------------- j1939/arbitrationid.py | 10 ++++++--- 2 files changed, 39 insertions(+), 21 deletions(-) diff --git a/j1939/__init__.py b/j1939/__init__.py index 5f5dc17..aa6050a 100644 --- a/j1939/__init__.py +++ b/j1939/__init__.py @@ -41,7 +41,7 @@ logger = logging.getLogger("j1939") -logger.setLevel(logging.DEBUG) +logger.setLevel(logging.WARNING) lLevel = logging.DEBUG logger.setLevel(lLevel) @@ -51,14 +51,15 @@ ch.setFormatter(chformatter) #logger.addHandler(ch) -fileHandler = logging.handlers.RotatingFileHandler('/tmp/j1939.log', \ - maxBytes = (1024*1024*20), \ - backupCount = 4) -fileHandler.setFormatter(chformatter) -fileHandler.setLevel(lLevel) -logger.addHandler(fileHandler) +if 0: + fileHandler = logging.handlers.RotatingFileHandler('/tmp/j1939.log', \ + maxBytes = (1024*1024*20), \ + backupCount = 4) + fileHandler.setFormatter(chformatter) + fileHandler.setLevel(lLevel) + logger.addHandler(fileHandler) -can_set_logging_level('debug') + can_set_logging_level('debug') class j1939Listner(canListener): @@ -267,6 +268,8 @@ def send(self, msg, timeout=None): while len(pdu.data) % 7 != 0: pdu.data += b'\xFF' + logger.info("j1939.send: padded msg (mod 7) = %s" % pdu) + logger.info("MIL8:---------------------") # # segment the longer message into 7 byte segments. We need to prefix each @@ -276,7 +279,7 @@ def send(self, msg, timeout=None): arbitration_id = copy.deepcopy(pdu.arbitration_id) arbitration_id.pgn.value = PGN_TP_DATA_TRANSFER - logger.info("j1939.send: i=%d, pdu.arbitration_id.pgn.is_destination_specific=%d, data=%s" % + logger.info("MIL8: j1939.send: i=%d, pdu.arbitration_id.pgn.is_destination_specific=%d, data=%s" % (i,pdu.arbitration_id.pgn.is_destination_specific, segment)) if pdu.arbitration_id.pgn.is_destination_specific and \ @@ -287,7 +290,7 @@ def send(self, msg, timeout=None): arbitration_id.pgn.pdu_specific = DESTINATION_ADDRESS_GLOBAL arbitration_id.destination_address = DESTINATION_ADDRESS_GLOBAL - logger.info("j1939.send: segment=%d, arb = %s" % (i, arbitration_id)) + logger.info("MIL8: j1939.send: segment=%d, arb = %s" % (i, arbitration_id)) message = Message(arbitration_id=arbitration_id.can_id, extended_id=True, dlc=(len(segment) + 1), @@ -297,10 +300,10 @@ def send(self, msg, timeout=None): # # At this point we have the queued messages sequenced in 'messages' # - logger.info("j1939.send: is_destination_specific=%d, destAddr=%s" % + logger.info("MIL8: j1939.send: is_destination_specific=%d, destAddr=%s" % (pdu.arbitration_id.pgn.is_destination_specific, pdu.arbitration_id.destination_address)) - logger.info("j1939.send: messages=%s" % messages) + logger.info("MIL8: j1939.send: messages=%s" % messages) if pdu.arbitration_id.pgn.is_destination_specific and \ pdu.arbitration_id.destination_address != DESTINATION_ADDRESS_GLOBAL: @@ -319,9 +322,8 @@ def send(self, msg, timeout=None): else: destination_address = DESTINATION_ADDRESS_GLOBAL - logger.debug("rts arbitration id: src=%s, dest=%s" % (pdu.source, destination_address)) - rts_arbitration_id = ArbitrationID(source_address=pdu.source, destination_address=destination_address) - rts_arbitration_id.pgn.value = PGN_TP_CONNECTION_MANAGEMENT + logger.debug("MIL8: rts arbitration id: src=%s, dest=%s" % (pdu.source, destination_address)) + rts_arbitration_id = ArbitrationID(pgn=PGN_TP_CONNECTION_MANAGEMENT, source_address=pdu.source, destination_address=destination_address) rts_arbitration_id.pgn.pdu_specific = pdu.arbitration_id.pgn.pdu_specific temp_pgn = copy.deepcopy(pdu.arbitration_id.pgn) @@ -335,6 +337,7 @@ def send(self, msg, timeout=None): if pdu.arbitration_id.pgn.is_destination_specific and \ pdu.arbitration_id.destination_address != DESTINATION_ADDRESS_GLOBAL: # send request to send + logger.debug("MIL8: rts to specific dest: src=%s, dest=%s" % (pdu.source, destination_address)) rts_msg = Message(extended_id=True, arbitration_id=rts_arbitration_id.can_id, data=[CM_MSG_TYPE_RTS, @@ -347,7 +350,7 @@ def send(self, msg, timeout=None): pgn_msb], dlc=8) try: - logger.info("j1939.send: sending TP.CTS to %s: %s" % (destination_address, rts_msg)) + logger.info("MIL08: j1939.send: sending TP.RTS to %s: %s" % (destination_address, rts_msg)) self.can_bus.send(rts_msg) except CanError: if self._ignore_can_send_error: @@ -356,8 +359,9 @@ def send(self, msg, timeout=None): else: rts_arbitration_id.pgn.pdu_specific = DESTINATION_ADDRESS_GLOBAL rts_arbitration_id.destination_address = DESTINATION_ADDRESS_GLOBAL + logger.debug("MIL8: rts to Global dest: src=%s, dest=%s" % (pdu.source, destination_address)) bam_msg = Message(extended_id=True, - arbitration_id=rts_arbitration_id.can_id, + arbitration_id=rts_arbitration_id.can_id | destination_address, data=[CM_MSG_TYPE_BAM, pdu_length_msb, pdu_length_lsb, len(messages), @@ -679,6 +683,10 @@ def _process_rts(self, msg): def _process_cts(self, msg): logger.debug("_process_cts") + logger.debug("MIL8: cts message is: %s" % msg) + logger.debug("MIL8: len(pdu-send-buffer) = %d" % len(self._incomplete_transmitted_pdus[0][23])) + + if msg.arbitration_id.pgn.pdu_specific in self._incomplete_transmitted_pdus: if msg.arbitration_id.source_address in self._incomplete_transmitted_pdus[ msg.arbitration_id.pgn.pdu_specific]: @@ -688,12 +696,18 @@ def _process_cts(self, msg): end_index = start_index + msg.data[1] for _msg in self._incomplete_transmitted_pdus[msg.arbitration_id.pgn.pdu_specific][ msg.arbitration_id.source_address][start_index:end_index]: + logger.debug("MIL8: msg=%s" % (_msg)) + # TODO: Needs to be pacing if we get this working... try: - self.can_bus.send(msg) + # Shouldent send a J1939 PDU as a CAN Message unless we are careful + canMessage = Message(arbitration_id=_msg.arbitration_id, data=_msg.data) + self.can_bus.send(canMessage) except CanError: + if self._ignore_can_send_error: pass raise + logger.debug("MIL8: _process_cts complete") def _process_eom_ack(self, msg): logger.debug("_process_eom_ack") diff --git a/j1939/arbitrationid.py b/j1939/arbitrationid.py index 147b74f..31ae351 100644 --- a/j1939/arbitrationid.py +++ b/j1939/arbitrationid.py @@ -26,6 +26,8 @@ def __init__(self, priority=7, pgn=None, source_address=0, destination_address=N self.priority = priority self.destination_address_value = None + logger.debug("ArbitrationID:__init__: self._pgn=%s, type %s" % (pgn, type(pgn))) + if pgn is None: self._pgn = PGN() elif pgn and isinstance(pgn, int): @@ -35,18 +37,20 @@ def __init__(self, priority=7, pgn=None, source_address=0, destination_address=N else: ValueError("pgn must have convertable type") + #self.pgn = pgn - if pgn: + logger.debug("ArbitrationID:__init__: self._pgn=%s, type %s" % (self._pgn, type(self._pgn))) + if self._pgn: if self._pgn.is_destination_specific: if destination_address is None: self.destination_address_value = DESTINATION_ADDRESS_GLOBAL else: if destination_address >= 0 and destination_address <= 255: self.destination_address_value = destination_address - if self.destination_address_value != pgn.pdu_specific: + if self.destination_address_value != self._pgn.pdu_specific: logger.debug("self._pgn=%s, self.destination_address_value = %x, pgn.pdu_specific = %x" % - (self._pgn, self.destination_address_value, pgn.pdu_specific)) + (self._pgn, self.destination_address_value, self._pgn.pdu_specific)) # assert( self.destination_address_value == pgn.pdu_specific) else: raise ValueError("destination address must be in range (0-255)") From 8ba722b32a0d07ebe0e7515da2a390c9cd8ed5c2 Mon Sep 17 00:00:00 2001 From: rsmssnpdr Date: Fri, 27 Jul 2018 16:25:51 -0700 Subject: [PATCH 36/80] move funtions to util.py --- bin/j1939_mem_query.py | 61 +--------- bin/j1939_mem_set.py | 127 +------------------- bin/j1939_request_pgn.py | 43 +------ bin/j1939_send_pgn.py | 60 +--------- j1939/utils.py | 249 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 256 insertions(+), 284 deletions(-) create mode 100644 j1939/utils.py diff --git a/bin/j1939_mem_query.py b/bin/j1939_mem_query.py index 87e60c6..37c3f10 100644 --- a/bin/j1939_mem_query.py +++ b/bin/j1939_mem_query.py @@ -32,63 +32,6 @@ 1532554003.941260 PRI=6 PGN=0xfefc SRC=0x17 ff ff ff ff ff ff ff ff ''' -def get_mem_object_single(channel='can0', bustype='socketcan', length=4, src=0, dest=0x17, pointer=0, extension=0): - #from can.interfaces.interface import * - - countdown = 10 - result = None - - bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01, broadcast=False) - node = j1939.Node(bus, j1939.NodeName(), [src]) - bus.connect(node) - pgn = j1939.PGN() - pgn.value = 0xd900 + dest # Request a DM14 mem-object - aid = j1939.ArbitrationID(pgn=pgn, source_address=src, destination_address=dest) - - data = [length, 0x13, pointer, 0x00, 0x00, extension, 0xff, 0xff] - pdu = j1939.PDU(timestamp=0.0, arbitration_id=aid, data=data, info_strings=None) - assert(pdu != None) - pdu.display_radix='hex' - - bus.send(pdu) - - '''dm16pgn = j1939.PGN(pdu_format=0xd9, pdu_specific=dest) - dm16aid = j1939.ArbitrationID(pgn=dm16pgn, source_address=src, destination_address=dest) - dm16pdu = j1939.PDU(timestamp=0.0, arbitration_id=dm16aid, data=[0xff, 0x09, 0, 0, 0, 0, 0xff, 0xff]) - dm16pdu.display_radix='hex' - - print("## PDU=%s " % (dm16pdu))''' - - - while countdown: - pdu = bus.recv(timeout=1) - if pdu is None: - continue - print(pdu) - if pdu.pgn == 0xd700: - value = list(pdu.data) - length = value[0] - if length == 1: - result = value[1] - elif length == 2: - result = (value[2] << 8) + value[1] - elif length == 4: - result = (value[4] << 24) + (value[3] << 16) + (value[2] << 8) + value[1] - else: - result = value[1:] - break # got what I was waiting for - elif pdu.pgn == 0xd800: - #bus.send(dm16pdu) - pass - countdown -= 1 - - bus.shutdown() - - if result is None: - raise IOError(" no CAN response") - - - return result def get_mem_object(bus=None, length=4, src=0, dest=0x17, pointer=0, extension=0): countdown = 10 @@ -181,7 +124,7 @@ def getStringVal(s): if 1: start = timeit.default_timer() for p, e in [(0x15, 0xe9), (0x00, 0xf1), (0x50, 0xe9), (0x75, 0xe9)]: - val = get_mem_object_single(length=4, src=0, dest=0x17, pointer=p, extension=e) + val = j1939.utils.get_mem_object_single(length=4, src=0, dest=0x17, pointer=p, extension=e) print("0x%02x-0x%02x = %d" % (p, e, val)) print("elapsed = %s s" % (timeit.default_timer() - start)) @@ -215,7 +158,7 @@ def getStringVal(s): print ("get_mem_object_single(src=0x%02x, dest=0x%02x, pointer=0x%02x, extension/space=0x%02x, len=%d" % (source, dest, ptr, ext, length)) - val = get_mem_object_single(length=length, src=source, dest=dest, pointer=ptr, extension=ext) + val = j1939.utils.get_mem_object_single(length=length, src=source, dest=dest, pointer=ptr, extension=ext) print(val) out = '' for x in val: diff --git a/bin/j1939_mem_set.py b/bin/j1939_mem_set.py index 5528fae..ce301f4 100644 --- a/bin/j1939_mem_set.py +++ b/bin/j1939_mem_set.py @@ -11,128 +11,6 @@ import j1939 -# -# for responding to seed/key requests provide your own keyGenerator -# class.. -# mine is returned in a SeedToKey meghod of a Genkey class that sits elsewhere -# on my PYTHONPATH and is propriatiry -# -# TODO: use a better baseclass override model. -# -try: - import genkey - security = genkey.GenKey() - print("Private Genkey Loaded") -except: - # Stuff in a fake genKey responder. Pretty much just needs a - # reference to any class that can convert a Seed to a Key.. For - # obvious reasons I'm not posting mine - print("Genkey Not loaded, This one will generate garbage keys") - class Genkey: - def SeedToKey(self, seed): - return 0x12345678 - - security = Genkey() - -def set_mem_object_single(channel='can0', bustype='socketcan', length=4, src=0, dest=0x17, pointer=0, extension=0, value=0): - #from can.interfaces.interface import * - - countdown = 10 - result = -1 - - bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01, keygen=security.SeedToKey, broadcast=False) - node = j1939.Node(bus, j1939.NodeName(), [src]) - bus.connect(node) - - #dm14pgn = j1939.PGN() - dm14data = [length, 0x15, pointer, 0x00, 0x00, extension, 0xff, 0xff] - - dm14pgn = j1939.PGN(pdu_format=0xd9, pdu_specific=dest) - #dm14pgn = j1939.PGN().value = 0xd917 - #print ("dm14pgn=", dm14pgn) - #print ("dm14pgn.destination_address_value=", dm14pgn.destination_address_value) - #print ("dm14pgn.pdu_specific=", dm14pgn.pdu_specific) - dm14aid = j1939.ArbitrationID(pgn=dm14pgn, source_address=src, destination_address=dest) - dm14pdu = j1939.PDU(timestamp=0.0, arbitration_id=dm14aid, data=dm14data, info_strings=None) - dm14pdu.display_radix='hex' - - - bus.send(dm14pdu) - - sendBuffer = [] - sendBuffer.append(length) - for i in range(0, length): - sendBuffer.append(0xff) - - #sendBuffer = [length, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff] - - print("## length=%d, value=%s " % (length, value)) - if isinstance(value, int): - if length == 1: - sendBuffer[1] = value - elif length == 2: - sendBuffer[1] = value & 0xff - sendBuffer[2] = (value >> 8) & 0xff - elif length == 3: - sendBuffer[1] = value & 0xff - sendBuffer[2] = (value >> 8) & 0xff - sendBuffer[3] = (value >> 16) & 0xff - elif length == 4: - sendBuffer[1] = value & 0xff - sendBuffer[2] = (value >> 8) & 0xff - sendBuffer[3] = (value >> 16) & 0xff - sendBuffer[4] = (value >> 24) & 0xff - else: - raise ValueError("Don't know how to send a %d byte integer" % length) - - elif isinstance(value, list): - for i in range(1,len(value)+1): - sendBuffer[i] = value[i-1] - - elif isinstance(value, str): - for i in range(1,len(value)+1): - sendBuffer[i] = ord(value[i-1]) - - print("## sendBuffer=%s " % (sendBuffer)) - - - - - - - - dm16pgn = j1939.PGN(pdu_format=0xd7, pdu_specific=dest) - dm16aid = j1939.ArbitrationID(pgn=dm16pgn, source_address=src, destination_address=dest) - dm16pdu = j1939.PDU(timestamp=0.0, arbitration_id=dm16aid, data=sendBuffer) - dm16pdu.display_radix='hex' - - print("## PDU=%s " % (dm16pdu)) - - # Wait around for a while looking for the second proceed - - countdown=10 - proceedCount = 0 - while countdown: - countdown -= 1 - rcvPdu = bus.recv(2) - if rcvPdu: - rcvPdu.display_radix='hex' - print("received PDU: %s", rcvPdu) - if rcvPdu.pgn == 0xd800: - if rcvPdu.data[0]==1 and rcvPdu.data[1]==0x11: - proceedCount += 1 - if proceedCount == 2: - bus.send(dm16pdu) - print('Sent ', dm16pdu) - if rcvPdu.data[0]==0 and rcvPdu.data[1]==0x19: - print("Value Sent") - break - - - bus.shutdown() - - return result - if __name__ == "__main__": @@ -193,7 +71,8 @@ def set_mem_object_single(channel='can0', bustype='socketcan', length=4, src=0, value = int(args.value,0) print("Attepting to set %2X/%02X to %s" % (ext, ptr, value)) except ValueError: - length = len(value) + if length < len(value): + length = len(value) #value = hex(int(args.value,0)) @@ -201,6 +80,6 @@ def set_mem_object_single(channel='can0', bustype='socketcan', length=4, src=0, # queries a couple objects but setting up the full stack and bus for # each takes a long time. start = timeit.default_timer() - val = set_mem_object_single(length=length, src=src, dest=dest, pointer=ptr, extension=ext, value=value) + val = j1939.utils.set_mem_object_single(length=length, src=src, dest=dest, pointer=ptr, extension=ext, value=value) #set_mem_object_single(length=1, src=0, dest=0x17, pointer=0x66, extension=0xea, value=127) print("elapsed = %s s" % (timeit.default_timer() - start)) diff --git a/bin/j1939_request_pgn.py b/bin/j1939_request_pgn.py index da138e9..f1db306 100644 --- a/bin/j1939_request_pgn.py +++ b/bin/j1939_request_pgn.py @@ -11,47 +11,6 @@ import j1939 -def request_pgn_single(requested_pgn, channel='can0', bustype='socketcan', length=4, src=0, dest=0x17): - - countdown = 10 - result = None - - if not isinstance(requested_pgn, int): - raise ValueError("pgn must be an integer.") - - bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01) - pgn = j1939.PGN() - pgn.value = 0xea00 + dest # request_pgn mem-object - aid = j1939.ArbitrationID(pgn=pgn, source_address=src, destination_address=dest) - - pgn0 = requested_pgn & 0xff - pgn1 = (requested_pgn >> 8) & 0xff - pgn2 = (requested_pgn >> 16) & 0xff - - data = [pgn0, pgn1, pgn2] - pdu = j1939.PDU(timestamp=0.0, arbitration_id=aid, data=data, info_strings=None) - - pdu.display_radix='hex' - - bus.send(pdu) - - while countdown: - pdu = bus.recv(timeout=1) - if pdu and (pdu.pgn == 0xe800 or pdu.pgn == requested_pgn): - result = list(pdu.data) - break # got what I was waiting for - - if pdu: - countdown -= 1 - - bus.shutdown() - - if not result: - raise IOError(" no CAN response") - - - return result - if __name__ == "__main__": @@ -101,7 +60,7 @@ def getStringValAsInt(s): print ("request_pgn_single(pgn=0x%04x (%d), src=0x%02x, dest=0x%02x)" % (pgn, pgn, source, dest)) - val = request_pgn_single(pgn, length=4, src=source, dest=dest) + val = j1939.utils.request_pgn_single(pgn, length=4, src=source, dest=dest) print("returned PGN = %s" % val) diff --git a/bin/j1939_send_pgn.py b/bin/j1939_send_pgn.py index 402ca7b..e7a2acd 100644 --- a/bin/j1939_send_pgn.py +++ b/bin/j1939_send_pgn.py @@ -10,64 +10,6 @@ import j1939 -try: - import genkey - security = genkey.GenKey() - print("Private Genkey Loaded") -except: - # Stuff in a fake genKey responder. Pretty much just needs a - # reference to any class that can convert a Seed to a Key.. For - # obvious reasons I'm not posting mine - print("Genkey Not loaded, This one will generate garbage keys") - class Genkey: - def SeedToKey(self, seed): - return 0x12345678 - - security = Genkey() - -def send_pgn(requested_pgn, data, channel='can0', bustype='socketcan', length=4, src=0, dest=0x17, bus=None): - - countdown = 10 - result = None - - if not isinstance(requested_pgn, int): - raise ValueError("pgn must be an integer.") - if bus is None: - bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01, keygen=security.SeedToKey) - close = True - else: - close = False - pgn = j1939.PGN() - if requested_pgn < 0xf000: - requested_pgn |= dest - pgn.value = requested_pgn#0xea00 + dest # request_pgn mem-object - aid = j1939.ArbitrationID(pgn=pgn, source_address=src, destination_address=dest) - - print(data) - pdu = j1939.PDU(timestamp=0.0, arbitration_id=aid, data=data, info_strings=None) - - pdu.display_radix='hex' - - bus.send(pdu) - if close: - bus.shutdown() - if 0: - while countdown: - pdu = bus.recv(timeout=1) - if pdu and (pdu.pgn == 0xe800 or pdu.pgn == requested_pgn): - result = list(pdu.data) - break # got what I was waiting for - - if pdu: - countdown -= 1 - - - if not result: - raise IOError(" no CAN response") - - - return result - if __name__ == "__main__": @@ -141,7 +83,7 @@ def getStringValAsInt(s): print ("Sending PGN: (pgn=0x%04x (%d), src=0x%02x, dest=0x%02x)" % (pgn, pgn, source, dest)) - val = send_pgn(pgn, data, length=len(data), src=source, dest=dest) + val = j1939.utils.send_pgn(pgn, data, length=len(data), src=source, dest=dest) print("returned PGN = %s" % val) diff --git a/j1939/utils.py b/j1939/utils.py new file mode 100644 index 0000000..6ab98f7 --- /dev/null +++ b/j1939/utils.py @@ -0,0 +1,249 @@ +from __future__ import print_function +import j1939 + +# +# for responding to seed/key requests provide your own keyGenerator +# class.. +# mine is returned in a SeedToKey meghod of a Genkey class that sits elsewhere +# on my PYTHONPATH and is propriatiry +# +# TODO: use a better baseclass override model. +# +try: + import genkey + security = genkey.GenKey() + print("Private Genkey Loaded") +except: + # Stuff in a fake genKey responder. Pretty much just needs a + # reference to any class that can convert a Seed to a Key.. For + # obvious reasons I'm not posting mine + print("Genkey Not loaded, This one will generate garbage keys") + class Genkey: + def SeedToKey(self, seed): + return 0x12345678 + + security = Genkey() + +def set_mem_object_single(channel='can0', bustype='socketcan', length=4, src=0, dest=0x17, pointer=0, extension=0, value=0): + #from can.interfaces.interface import * + + countdown = 10 + result = -1 + + bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01, keygen=security.SeedToKey, broadcast=False) + node = j1939.Node(bus, j1939.NodeName(), [src]) + bus.connect(node) + + #dm14pgn = j1939.PGN() + dm14data = [length, 0x15, pointer, 0x00, 0x00, extension, 0xff, 0xff] + + dm14pgn = j1939.PGN(pdu_format=0xd9, pdu_specific=dest) + #dm14pgn = j1939.PGN().value = 0xd917 + #print ("dm14pgn=", dm14pgn) + #print ("dm14pgn.destination_address_value=", dm14pgn.destination_address_value) + #print ("dm14pgn.pdu_specific=", dm14pgn.pdu_specific) + dm14aid = j1939.ArbitrationID(pgn=dm14pgn, source_address=src, destination_address=dest) + dm14pdu = j1939.PDU(timestamp=0.0, arbitration_id=dm14aid, data=dm14data, info_strings=None) + dm14pdu.display_radix='hex' + + + bus.send(dm14pdu) + + sendBuffer = [] + sendBuffer.append(length) + for i in range(0, length): + sendBuffer.append(0) + + #sendBuffer = [length, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff] + + print("## length=%d, value=%s " % (length, value)) + if isinstance(value, int): + if length == 1: + sendBuffer[1] = value + elif length == 2: + sendBuffer[1] = value & 0xff + sendBuffer[2] = (value >> 8) & 0xff + elif length == 3: + sendBuffer[1] = value & 0xff + sendBuffer[2] = (value >> 8) & 0xff + sendBuffer[3] = (value >> 16) & 0xff + elif length == 4: + sendBuffer[1] = value & 0xff + sendBuffer[2] = (value >> 8) & 0xff + sendBuffer[3] = (value >> 16) & 0xff + sendBuffer[4] = (value >> 24) & 0xff + else: + raise ValueError("Don't know how to send a %d byte integer" % length) + + elif isinstance(value, list): + for i in range(len(value)): + sendBuffer[i+1] = value[i] + + elif isinstance(value, str): + sendBuffer[0] = length+1 + for i in range(len(value)): + sendBuffer[i+1] = ord(value[i]) + + print("## sendBuffer=%s " % (sendBuffer)) + + dm16pgn = j1939.PGN(pdu_format=0xd7, pdu_specific=dest) + dm16aid = j1939.ArbitrationID(pgn=dm16pgn, source_address=src, destination_address=dest) + dm16pdu = j1939.PDU(timestamp=0.0, arbitration_id=dm16aid, data=sendBuffer) + dm16pdu.display_radix='hex' + + print("## PDU=%s " % (dm16pdu)) + + # Wait around for a while looking for the second proceed + + countdown=10 + proceedCount = 0 + while countdown: + countdown -= 1 + rcvPdu = bus.recv(2) + if rcvPdu: + rcvPdu.display_radix='hex' + print("received PDU: %s", rcvPdu) + if rcvPdu.pgn == 0xd800: + if rcvPdu.data[0]==1 and rcvPdu.data[1]==0x11: + proceedCount += 1 + if proceedCount == 2: + bus.send(dm16pdu) + print('Sent ', dm16pdu) + if rcvPdu.data[0]==0 and rcvPdu.data[1]==0x19: + print("Value Sent") + break + + + bus.shutdown() + + return result + + + + +def get_mem_object_single(channel='can0', bustype='socketcan', length=4, src=0, dest=0x17, pointer=0, extension=0): + #from can.interfaces.interface import * + + countdown = 10 + result = None + + bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01, broadcast=False) + node = j1939.Node(bus, j1939.NodeName(), [src]) + bus.connect(node) + pgn = j1939.PGN() + pgn.value = 0xd900 + dest # Request a DM14 mem-object + aid = j1939.ArbitrationID(pgn=pgn, source_address=src, destination_address=dest) + + data = [length, 0x13, pointer, 0x00, 0x00, extension, 0xff, 0xff] + pdu = j1939.PDU(timestamp=0.0, arbitration_id=aid, data=data, info_strings=None) + assert(pdu != None) + pdu.display_radix='hex' + bus.send(pdu) + while countdown: + pdu = bus.recv(timeout=1) + if pdu is None: + continue + print(pdu) + if pdu.pgn == 0xd700: + value = list(pdu.data) + length = value[0] + if length == 1: + result = value[1] + elif length == 2: + result = (value[2] << 8) + value[1] + elif length == 4: + result = (value[4] << 24) + (value[3] << 16) + (value[2] << 8) + value[1] + else: + result = value[1:] + break # got what I was waiting for + countdown -= 1 + bus.shutdown() + if result is None: + raise IOError(" no CAN response") + return result + +def request_pgn_single(requested_pgn, channel='can0', bustype='socketcan', length=4, src=0, dest=0x17): + + countdown = 10 + result = None + + if not isinstance(requested_pgn, int): + raise ValueError("pgn must be an integer.") + + bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01) + pgn = j1939.PGN() + pgn.value = 0xea00 + dest # request_pgn mem-object + aid = j1939.ArbitrationID(pgn=pgn, source_address=src, destination_address=dest) + + pgn0 = requested_pgn & 0xff + pgn1 = (requested_pgn >> 8) & 0xff + pgn2 = (requested_pgn >> 16) & 0xff + + data = [pgn0, pgn1, pgn2] + pdu = j1939.PDU(timestamp=0.0, arbitration_id=aid, data=data, info_strings=None) + + pdu.display_radix='hex' + + bus.send(pdu) + + while countdown: + pdu = bus.recv(timeout=1) + if pdu and (pdu.pgn == 0xe800 or pdu.pgn == requested_pgn): + result = list(pdu.data) + break # got what I was waiting for + + if pdu: + countdown -= 1 + + bus.shutdown() + + if not result: + raise IOError(" no CAN response") + + + return result + + +def send_pgn(requested_pgn, data, channel='can0', bustype='socketcan', length=4, src=0, dest=0x17, bus=None): + + countdown = 10 + result = None + + if not isinstance(requested_pgn, int): + raise ValueError("pgn must be an integer.") + if bus is None: + bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01, keygen=security.SeedToKey) + close = True + else: + close = False + pgn = j1939.PGN() + if requested_pgn < 0xf000: + requested_pgn |= dest + pgn.value = requested_pgn#0xea00 + dest # request_pgn mem-object + aid = j1939.ArbitrationID(pgn=pgn, source_address=src, destination_address=dest) + + print(data) + pdu = j1939.PDU(timestamp=0.0, arbitration_id=aid, data=data, info_strings=None) + + pdu.display_radix='hex' + + bus.send(pdu) + if close: + bus.shutdown() + if 0: + while countdown: + pdu = bus.recv(timeout=1) + if pdu and (pdu.pgn == 0xe800 or pdu.pgn == requested_pgn): + result = list(pdu.data) + break # got what I was waiting for + + if pdu: + countdown -= 1 + + + if not result: + raise IOError(" no CAN response") + + + return result + From 986014f8436fc7cf6036dc98aa9e5a394ae0e6ac Mon Sep 17 00:00:00 2001 From: rsmssnpdr Date: Fri, 27 Jul 2018 16:27:52 -0700 Subject: [PATCH 37/80] correct utils formatting --- bin/j1939_mem_query.py | 2 +- bin/j1939_mem_set.py | 2 +- bin/j1939_request_pgn.py | 2 +- bin/j1939_send_pgn.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bin/j1939_mem_query.py b/bin/j1939_mem_query.py index 37c3f10..187a2f0 100644 --- a/bin/j1939_mem_query.py +++ b/bin/j1939_mem_query.py @@ -8,7 +8,7 @@ __exp__ = "(expirimental)" # (Release Version) title = "%s Version: %s %s %s" % (_name, __version__, __date__, __exp__) -import j1939 +import j1939.utils if __name__ == "__main__": diff --git a/bin/j1939_mem_set.py b/bin/j1939_mem_set.py index ce301f4..482bced 100644 --- a/bin/j1939_mem_set.py +++ b/bin/j1939_mem_set.py @@ -9,7 +9,7 @@ -import j1939 +import j1939.utils if __name__ == "__main__": diff --git a/bin/j1939_request_pgn.py b/bin/j1939_request_pgn.py index f1db306..37ac4e4 100644 --- a/bin/j1939_request_pgn.py +++ b/bin/j1939_request_pgn.py @@ -8,7 +8,7 @@ __exp__ = "(expirimental)" # (Release Version) title = "%s Version: %s %s %s" % (_name, __version__, __date__, __exp__) -import j1939 +import j1939.utils diff --git a/bin/j1939_send_pgn.py b/bin/j1939_send_pgn.py index e7a2acd..ade24d7 100644 --- a/bin/j1939_send_pgn.py +++ b/bin/j1939_send_pgn.py @@ -8,7 +8,7 @@ __exp__ = "(expirimental)" # (Release Version) title = "%s Version: %s %s %s" % (_name, __version__, __date__, __exp__) -import j1939 +import j1939.utils if __name__ == "__main__": From 40865e70e40222fdf96beaf3cd7de50d44150d16 Mon Sep 17 00:00:00 2001 From: rsmssnpdr Date: Mon, 30 Jul 2018 11:55:32 -0700 Subject: [PATCH 38/80] utils can re-use a bus | improve formatting --- bin/j1939_mem_query.py | 14 +++--- bin/j1939_mem_set.py | 2 +- bin/j1939_request_pgn.py | 2 +- j1939/utils.py | 95 +++++++++++++++++----------------------- 4 files changed, 48 insertions(+), 65 deletions(-) diff --git a/bin/j1939_mem_query.py b/bin/j1939_mem_query.py index 187a2f0..93acc57 100644 --- a/bin/j1939_mem_query.py +++ b/bin/j1939_mem_query.py @@ -77,11 +77,11 @@ def getStringVal(s): if __name__ == "__main__": - lLevel = logging.WARN - jlogger = logging.getLogger("j1939") - jlogger.setLevel(lLevel) - ch = logging.StreamHandler() - jlogger.addHandler(ch) + #lLevel = logging.WARN + #jlogger = logging.getLogger("j1939") + #jlogger.setLevel(lLevel) + #ch = logging.StreamHandler() + #jlogger.addHandler(ch) parser = argparse.ArgumentParser(description='''\ example: %(prog)s -d 0x21 0xe9 -p 0x15 @@ -124,7 +124,7 @@ def getStringVal(s): if 1: start = timeit.default_timer() for p, e in [(0x15, 0xe9), (0x00, 0xf1), (0x50, 0xe9), (0x75, 0xe9)]: - val = j1939.utils.get_mem_object_single(length=4, src=0, dest=0x17, pointer=p, extension=e) + val = j1939.utils.get_mem_object(length=4, src=0, dest=0x17, pointer=p, extension=e) print("0x%02x-0x%02x = %d" % (p, e, val)) print("elapsed = %s s" % (timeit.default_timer() - start)) @@ -158,7 +158,7 @@ def getStringVal(s): print ("get_mem_object_single(src=0x%02x, dest=0x%02x, pointer=0x%02x, extension/space=0x%02x, len=%d" % (source, dest, ptr, ext, length)) - val = j1939.utils.get_mem_object_single(length=length, src=source, dest=dest, pointer=ptr, extension=ext) + val = j1939.utils.get_mem_object(ptr, ext, length=length, src=source, dest=dest) print(val) out = '' for x in val: diff --git a/bin/j1939_mem_set.py b/bin/j1939_mem_set.py index 482bced..123113b 100644 --- a/bin/j1939_mem_set.py +++ b/bin/j1939_mem_set.py @@ -80,6 +80,6 @@ # queries a couple objects but setting up the full stack and bus for # each takes a long time. start = timeit.default_timer() - val = j1939.utils.set_mem_object_single(length=length, src=src, dest=dest, pointer=ptr, extension=ext, value=value) + val = j1939.utils.set_mem_object(ptr, ext, value, length=length, src=src, dest=dest) #set_mem_object_single(length=1, src=0, dest=0x17, pointer=0x66, extension=0xea, value=127) print("elapsed = %s s" % (timeit.default_timer() - start)) diff --git a/bin/j1939_request_pgn.py b/bin/j1939_request_pgn.py index 37ac4e4..9151b78 100644 --- a/bin/j1939_request_pgn.py +++ b/bin/j1939_request_pgn.py @@ -60,7 +60,7 @@ def getStringValAsInt(s): print ("request_pgn_single(pgn=0x%04x (%d), src=0x%02x, dest=0x%02x)" % (pgn, pgn, source, dest)) - val = j1939.utils.request_pgn_single(pgn, length=4, src=source, dest=dest) + val = j1939.utils.request_pgn(pgn, length=4, src=source, dest=dest) print("returned PGN = %s" % val) diff --git a/j1939/utils.py b/j1939/utils.py index 6ab98f7..d91e971 100644 --- a/j1939/utils.py +++ b/j1939/utils.py @@ -1,6 +1,8 @@ from __future__ import print_function import j1939 +import logging +logger = logging.getLogger('j1939') # # for responding to seed/key requests provide your own keyGenerator # class.. @@ -12,36 +14,30 @@ try: import genkey security = genkey.GenKey() - print("Private Genkey Loaded") + logger.info("Private Genkey Loaded") except: # Stuff in a fake genKey responder. Pretty much just needs a # reference to any class that can convert a Seed to a Key.. For # obvious reasons I'm not posting mine - print("Genkey Not loaded, This one will generate garbage keys") + logger.info("Genkey Not loaded, This one will generate garbage keys") class Genkey: def SeedToKey(self, seed): return 0x12345678 security = Genkey() -def set_mem_object_single(channel='can0', bustype='socketcan', length=4, src=0, dest=0x17, pointer=0, extension=0, value=0): - #from can.interfaces.interface import * - +def set_mem_object(pointer, extension, value, channel='can0', bustype='socketcan', length=4, src=0, dest=0x17, bus=None): countdown = 10 result = -1 - - bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01, keygen=security.SeedToKey, broadcast=False) - node = j1939.Node(bus, j1939.NodeName(), [src]) - bus.connect(node) - - #dm14pgn = j1939.PGN() + close = False + if bus is None: + bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01, keygen=security.SeedToKey, broadcast=False) + node = j1939.Node(bus, j1939.NodeName(), [src]) + bus.connect(node) + close = True dm14data = [length, 0x15, pointer, 0x00, 0x00, extension, 0xff, 0xff] dm14pgn = j1939.PGN(pdu_format=0xd9, pdu_specific=dest) - #dm14pgn = j1939.PGN().value = 0xd917 - #print ("dm14pgn=", dm14pgn) - #print ("dm14pgn.destination_address_value=", dm14pgn.destination_address_value) - #print ("dm14pgn.pdu_specific=", dm14pgn.pdu_specific) dm14aid = j1939.ArbitrationID(pgn=dm14pgn, source_address=src, destination_address=dest) dm14pdu = j1939.PDU(timestamp=0.0, arbitration_id=dm14aid, data=dm14data, info_strings=None) dm14pdu.display_radix='hex' @@ -54,9 +50,7 @@ def set_mem_object_single(channel='can0', bustype='socketcan', length=4, src=0, for i in range(0, length): sendBuffer.append(0) - #sendBuffer = [length, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff] - - print("## length=%d, value=%s " % (length, value)) + logger.info("## length=%d, value=%s " % (length, value)) if isinstance(value, int): if length == 1: sendBuffer[1] = value @@ -80,21 +74,21 @@ def set_mem_object_single(channel='can0', bustype='socketcan', length=4, src=0, sendBuffer[i+1] = value[i] elif isinstance(value, str): + assert(len(value) <= length) sendBuffer[0] = length+1 for i in range(len(value)): sendBuffer[i+1] = ord(value[i]) - print("## sendBuffer=%s " % (sendBuffer)) + logger.info("## sendBuffer=%s ", sendBuffer) dm16pgn = j1939.PGN(pdu_format=0xd7, pdu_specific=dest) dm16aid = j1939.ArbitrationID(pgn=dm16pgn, source_address=src, destination_address=dest) dm16pdu = j1939.PDU(timestamp=0.0, arbitration_id=dm16aid, data=sendBuffer) dm16pdu.display_radix='hex' - print("## PDU=%s " % (dm16pdu)) + logger.info("## PDU=%s ", dm16pdu) # Wait around for a while looking for the second proceed - countdown=10 proceedCount = 0 while countdown: @@ -102,34 +96,30 @@ def set_mem_object_single(channel='can0', bustype='socketcan', length=4, src=0, rcvPdu = bus.recv(2) if rcvPdu: rcvPdu.display_radix='hex' - print("received PDU: %s", rcvPdu) + logger.debug("received PDU: %s", rcvPdu) if rcvPdu.pgn == 0xd800: if rcvPdu.data[0]==1 and rcvPdu.data[1]==0x11: proceedCount += 1 if proceedCount == 2: bus.send(dm16pdu) - print('Sent ', dm16pdu) + logger.info('Sent %s', dm16pdu) if rcvPdu.data[0]==0 and rcvPdu.data[1]==0x19: - print("Value Sent") + logger.info("Value Sent") break - - - bus.shutdown() - + if close: + bus.shutdown() return result - - - -def get_mem_object_single(channel='can0', bustype='socketcan', length=4, src=0, dest=0x17, pointer=0, extension=0): - #from can.interfaces.interface import * - +def get_mem_object(pointer, extension, channel='can0', bustype='socketcan', length=4, src=0, dest=0x17, bus=None): countdown = 10 result = None + close = False - bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01, broadcast=False) - node = j1939.Node(bus, j1939.NodeName(), [src]) - bus.connect(node) + if bus is None: + bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01, broadcast=False) + node = j1939.Node(bus, j1939.NodeName(), [src]) + bus.connect(node) + close = True pgn = j1939.PGN() pgn.value = 0xd900 + dest # Request a DM14 mem-object aid = j1939.ArbitrationID(pgn=pgn, source_address=src, destination_address=dest) @@ -143,7 +133,7 @@ def get_mem_object_single(channel='can0', bustype='socketcan', length=4, src=0, pdu = bus.recv(timeout=1) if pdu is None: continue - print(pdu) + logger.info(pdu) if pdu.pgn == 0xd700: value = list(pdu.data) length = value[0] @@ -157,20 +147,22 @@ def get_mem_object_single(channel='can0', bustype='socketcan', length=4, src=0, result = value[1:] break # got what I was waiting for countdown -= 1 - bus.shutdown() + if close: + bus.shutdown() if result is None: raise IOError(" no CAN response") return result -def request_pgn_single(requested_pgn, channel='can0', bustype='socketcan', length=4, src=0, dest=0x17): - +def request_pgn(requested_pgn, channel='can0', bustype='socketcan', length=4, src=0, dest=0x17, bus=None): countdown = 10 result = None + close = False if not isinstance(requested_pgn, int): raise ValueError("pgn must be an integer.") - - bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01) + if bus is None: + bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01) + close = True pgn = j1939.PGN() pgn.value = 0xea00 + dest # request_pgn mem-object aid = j1939.ArbitrationID(pgn=pgn, source_address=src, destination_address=dest) @@ -194,18 +186,14 @@ def request_pgn_single(requested_pgn, channel='can0', bustype='socketcan', lengt if pdu: countdown -= 1 - - bus.shutdown() - + if close: + bus.shutdown() if not result: raise IOError(" no CAN response") - - return result def send_pgn(requested_pgn, data, channel='can0', bustype='socketcan', length=4, src=0, dest=0x17, bus=None): - countdown = 10 result = None @@ -222,7 +210,7 @@ def send_pgn(requested_pgn, data, channel='can0', bustype='socketcan', length=4, pgn.value = requested_pgn#0xea00 + dest # request_pgn mem-object aid = j1939.ArbitrationID(pgn=pgn, source_address=src, destination_address=dest) - print(data) + logger.info(data) pdu = j1939.PDU(timestamp=0.0, arbitration_id=aid, data=data, info_strings=None) pdu.display_radix='hex' @@ -230,20 +218,15 @@ def send_pgn(requested_pgn, data, channel='can0', bustype='socketcan', length=4, bus.send(pdu) if close: bus.shutdown() - if 0: + if 0: #leaving in miller's if 0 while countdown: pdu = bus.recv(timeout=1) if pdu and (pdu.pgn == 0xe800 or pdu.pgn == requested_pgn): result = list(pdu.data) break # got what I was waiting for - if pdu: countdown -= 1 - - if not result: raise IOError(" no CAN response") - - return result From 408da8de144189e0e54e3bed0f82b6ecdc30f6e9 Mon Sep 17 00:00:00 2001 From: Miller Lowe Date: Mon, 30 Jul 2018 17:09:04 -0700 Subject: [PATCH 39/80] Reduce logger debug info to WARN --- bin/j1939_logger.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/j1939_logger.py b/bin/j1939_logger.py index 367f52d..8acb782 100644 --- a/bin/j1939_logger.py +++ b/bin/j1939_logger.py @@ -9,7 +9,7 @@ import j1939 import logging -lLevel = logging.DEBUG +lLevel = logging.WARN logger = logging.getLogger() if 1: From 61d08cc7c1958b55b1f50603c9b89d9c4462bda8 Mon Sep 17 00:00:00 2001 From: rsmssnpdr Date: Tue, 31 Jul 2018 08:06:27 -0700 Subject: [PATCH 40/80] fix logger name --- j1939/utils.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/j1939/utils.py b/j1939/utils.py index d91e971..746b62b 100644 --- a/j1939/utils.py +++ b/j1939/utils.py @@ -2,7 +2,7 @@ import j1939 import logging -logger = logging.getLogger('j1939') +logger = logging.getLogger(__name__) # # for responding to seed/key requests provide your own keyGenerator # class.. @@ -222,9 +222,9 @@ def send_pgn(requested_pgn, data, channel='can0', bustype='socketcan', length=4, while countdown: pdu = bus.recv(timeout=1) if pdu and (pdu.pgn == 0xe800 or pdu.pgn == requested_pgn): - result = list(pdu.data) + result = list(pdu.data) break # got what I was waiting for - if pdu: + if pdu: countdown -= 1 if not result: raise IOError(" no CAN response") From f6c16c69a4db50871d7f3883f31daa171891bdd8 Mon Sep 17 00:00:00 2001 From: rsmssnpdr Date: Tue, 31 Jul 2018 09:12:47 -0700 Subject: [PATCH 41/80] BB fixes for differeing can bus | threading gixes --- bin/j1939_mem_query.py | 16 ++++++++++------ j1939/__init__.py | 5 +++-- j1939/utils.py | 2 +- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/bin/j1939_mem_query.py b/bin/j1939_mem_query.py index 93acc57..9851a21 100644 --- a/bin/j1939_mem_query.py +++ b/bin/j1939_mem_query.py @@ -105,6 +105,10 @@ def getStringVal(s): default="4", help="length in bytes (default: 4)") + parser.add_argument("-c", "--channel", + default="can0", + help="Memory object pointer offset to request in decimal or 0xHex") + parser.add_argument("extension", default=None, help="Memory object extension prefix to request in decimal or 0xHex") @@ -114,7 +118,6 @@ def getStringVal(s): help="Memory object pointer offset to request in decimal or 0xHex") - args = parser.parse_args() @@ -155,14 +158,15 @@ def getStringVal(s): ptr = getStringVal(args.pointer) length = getStringVal(args.length) ext = getStringVal(args.extension) - + channel = args.channel print ("get_mem_object_single(src=0x%02x, dest=0x%02x, pointer=0x%02x, extension/space=0x%02x, len=%d" % (source, dest, ptr, ext, length)) - val = j1939.utils.get_mem_object(ptr, ext, length=length, src=source, dest=dest) + val = j1939.utils.get_mem_object(ptr, ext, length=length, src=source, dest=dest, channel=channel) print(val) out = '' - for x in val: - out+=chr(x) - print(out) + if isinstance(val, list): + for x in val: + out+=chr(x) + print(out) #print("0x%02x-0x%02x = %d (0x%08x)" % (ptr, ext, val, val)) diff --git a/j1939/__init__.py b/j1939/__init__.py index aa6050a..1f72e09 100644 --- a/j1939/__init__.py +++ b/j1939/__init__.py @@ -38,7 +38,7 @@ from j1939.node import Node from j1939.nodename import NodeName from j1939.arbitrationid import ArbitrationID - +from j1939.utils import * logger = logging.getLogger("j1939") logger.setLevel(logging.WARNING) @@ -163,7 +163,8 @@ def __init__(self, pdu_type=PDU, broadcast=True, *args, **kwargs): def notification(self, inboundMessage): #self.rx_can_message_queue.put(inboundMessage) - + if self.can_notifier._running is False: + logger.info('Aborting message %s bus is not running', inboundMessage) if isinstance(inboundMessage, Message): logger.info('\n\nnotification: Got a Message from CAN: %s' % inboundMessage) if inboundMessage.id_type: diff --git a/j1939/utils.py b/j1939/utils.py index d91e971..0b94f04 100644 --- a/j1939/utils.py +++ b/j1939/utils.py @@ -2,7 +2,7 @@ import j1939 import logging -logger = logging.getLogger('j1939') +logger = logging.getLogger(__name__) # # for responding to seed/key requests provide your own keyGenerator # class.. From 7265742ffae45f639a60902da91c924b6abc4963 Mon Sep 17 00:00:00 2001 From: rsmssnpdr Date: Wed, 1 Aug 2018 08:38:08 -0700 Subject: [PATCH 42/80] patch to supress errors after close --- j1939/__init__.py | 3 +-- j1939/notifier.py | 20 +++++++++++++++++++- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/j1939/__init__.py b/j1939/__init__.py index 1f72e09..16e8fb8 100644 --- a/j1939/__init__.py +++ b/j1939/__init__.py @@ -26,7 +26,6 @@ from can import Message from can import set_logging_level as can_set_logging_level from can.interface import Bus as RawCanBus -from can.notifier import Notifier as canNotifier from can.listener import Listener as canListener from can.bus import BusABC @@ -34,7 +33,7 @@ from j1939.pdu import PDU from j1939.pgn import PGN from j1939.constants import * -from j1939.notifier import Notifier +from j1939.notifier import Notifier, CanNotifier as canNotifier from j1939.node import Node from j1939.nodename import NodeName from j1939.arbitrationid import ArbitrationID diff --git a/j1939/notifier.py b/j1939/notifier.py index b6c0506..fe70b72 100644 --- a/j1939/notifier.py +++ b/j1939/notifier.py @@ -3,6 +3,9 @@ import queue except ImportError: import Queue as queue + +from can.notifier import Notifier as canNotifier +import socket #same as a CAN Notifier but will listen to a queue #recv function. @@ -45,4 +48,19 @@ def rx_thread(self): for listener in self.listeners: listener.stop() - +class CanNotifier(canNotifier): + def _rx_thread(self, bus): + msg = None + try: + while self._running: + if msg is not None: + with self._lock: + for callback in self.listeners: + callback(msg) + msg = bus.recv(self.timeout) + except socket.error as err: + if self._runnung: + raise + except Exception as exc: + self.exception = exc + raise From dfc0cfa02b4ef029ec8a5908b63d4bff377e2505 Mon Sep 17 00:00:00 2001 From: rsmssnpdr Date: Wed, 1 Aug 2018 09:03:31 -0700 Subject: [PATCH 43/80] fix logger error | bus shutdown error --- j1939/__init__.py | 2 +- j1939/notifier.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/j1939/__init__.py b/j1939/__init__.py index 16e8fb8..8128f4d 100644 --- a/j1939/__init__.py +++ b/j1939/__init__.py @@ -50,7 +50,7 @@ ch.setFormatter(chformatter) #logger.addHandler(ch) -if 0: +if 1: fileHandler = logging.handlers.RotatingFileHandler('/tmp/j1939.log', \ maxBytes = (1024*1024*20), \ backupCount = 4) diff --git a/j1939/notifier.py b/j1939/notifier.py index fe70b72..3dacd2c 100644 --- a/j1939/notifier.py +++ b/j1939/notifier.py @@ -4,6 +4,7 @@ except ImportError: import Queue as queue +from can import CanError from can.notifier import Notifier as canNotifier import socket @@ -58,8 +59,8 @@ def _rx_thread(self, bus): for callback in self.listeners: callback(msg) msg = bus.recv(self.timeout) - except socket.error as err: - if self._runnung: + except CanError as err: + if self._running: raise except Exception as exc: self.exception = exc From cabe87c43c2ec112a00d45eee8a4638a666fe9aa Mon Sep 17 00:00:00 2001 From: rsmssnpdr Date: Wed, 1 Aug 2018 15:51:31 -0700 Subject: [PATCH 44/80] fix no-exit bug in mem-get --- j1939/utils.py | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/j1939/utils.py b/j1939/utils.py index 746b62b..dd24d68 100644 --- a/j1939/utils.py +++ b/j1939/utils.py @@ -103,8 +103,13 @@ def set_mem_object(pointer, extension, value, channel='can0', bustype='socketcan if proceedCount == 2: bus.send(dm16pdu) logger.info('Sent %s', dm16pdu) - if rcvPdu.data[0]==0 and rcvPdu.data[1]==0x19: + elif rcvPdu.data[0]==0 and rcvPdu.data[1]==0x19: logger.info("Value Sent") + result = 1 + break + elif rcvPdu.data[0]==0 and rcvPdu.data[1]==0x1B: + logger.info("Rejected") + result = 0 break if close: bus.shutdown() @@ -131,21 +136,20 @@ def get_mem_object(pointer, extension, channel='can0', bustype='socketcan', leng bus.send(pdu) while countdown: pdu = bus.recv(timeout=1) - if pdu is None: - continue - logger.info(pdu) - if pdu.pgn == 0xd700: - value = list(pdu.data) - length = value[0] - if length == 1: - result = value[1] - elif length == 2: - result = (value[2] << 8) + value[1] - elif length == 4: - result = (value[4] << 24) + (value[3] << 16) + (value[2] << 8) + value[1] - else: - result = value[1:] - break # got what I was waiting for + if pdu is not None: + logger.info(pdu) + if pdu.pgn == 0xd700: + value = list(pdu.data) + length = value[0] + if length == 1: + result = value[1] + elif length == 2: + result = (value[2] << 8) + value[1] + elif length == 4: + result = (value[4] << 24) + (value[3] << 16) + (value[2] << 8) + value[1] + else: + result = value[1:] + break # got what I was waiting for countdown -= 1 if close: bus.shutdown() From d6bfe662b4ba373c73cc7eedee5a299d436add89 Mon Sep 17 00:00:00 2001 From: Miller Lowe Date: Thu, 2 Aug 2018 09:22:29 -0700 Subject: [PATCH 45/80] correct a BAM source address issue where I had mistakenly used the Destination address. --- j1939/__init__.py | 2 +- j1939/notifier.py | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/j1939/__init__.py b/j1939/__init__.py index 8128f4d..c22b5fd 100644 --- a/j1939/__init__.py +++ b/j1939/__init__.py @@ -361,7 +361,7 @@ def send(self, msg, timeout=None): rts_arbitration_id.destination_address = DESTINATION_ADDRESS_GLOBAL logger.debug("MIL8: rts to Global dest: src=%s, dest=%s" % (pdu.source, destination_address)) bam_msg = Message(extended_id=True, - arbitration_id=rts_arbitration_id.can_id | destination_address, + arbitration_id=rts_arbitration_id.can_id | pdu.source, data=[CM_MSG_TYPE_BAM, pdu_length_msb, pdu_length_lsb, len(messages), diff --git a/j1939/notifier.py b/j1939/notifier.py index 3dacd2c..23c4f56 100644 --- a/j1939/notifier.py +++ b/j1939/notifier.py @@ -59,9 +59,17 @@ def _rx_thread(self, bus): for callback in self.listeners: callback(msg) msg = bus.recv(self.timeout) + + # + # The next two handlers are intended to mask race conditions that can occur when + # we are blocked on a can-receive and close the bus. except CanError as err: if self._running: raise + except ValueError as err: + if self._running: + raise + except Exception as exc: self.exception = exc raise From 28a1525697bde5e2baaa077d756ae7a7d802a31f Mon Sep 17 00:00:00 2001 From: Miller Lowe Date: Thu, 2 Aug 2018 09:45:02 -0700 Subject: [PATCH 46/80] fix get_ecu_block example to work with the new utils structure. --- bin/j1939_request_pgn.py | 2 +- examples/get_ecu_block.py | 4 ++-- examples/j1939_nodes.py | 8 ++++++++ 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/bin/j1939_request_pgn.py b/bin/j1939_request_pgn.py index 9151b78..afd3ff5 100644 --- a/bin/j1939_request_pgn.py +++ b/bin/j1939_request_pgn.py @@ -58,7 +58,7 @@ def getStringValAsInt(s): dest = getStringValAsInt(args.dest) pgn = getStringValAsInt(args.pgn) - print ("request_pgn_single(pgn=0x%04x (%d), src=0x%02x, dest=0x%02x)" % (pgn, pgn, source, dest)) + print ("j1939.utils.request_pgn(pgn=0x%04x (%d), src=0x%02x, dest=0x%02x)" % (pgn, pgn, source, dest)) val = j1939.utils.request_pgn(pgn, length=4, src=source, dest=dest) diff --git a/examples/get_ecu_block.py b/examples/get_ecu_block.py index 5fa9e58..d7b030f 100644 --- a/examples/get_ecu_block.py +++ b/examples/get_ecu_block.py @@ -1,8 +1,8 @@ from __future__ import print_function -import j1939_request_pgn +import j1939.utils -val = j1939_request_pgn.request_pgn_single(0xfeda, src=0xff) +val = j1939.utils.request_pgn(0xfeda, src=0xff) fieldCount = val[0] print ("%d elements in list" % fieldCount) diff --git a/examples/j1939_nodes.py b/examples/j1939_nodes.py index 931ba41..acb8927 100644 --- a/examples/j1939_nodes.py +++ b/examples/j1939_nodes.py @@ -1,3 +1,11 @@ +# +# This example is an attempt to operate two address endpoints concurrently. +# +# Currently it's not tested and I suspect it's not handling the address claims correctly +# among other things +# + + from __future__ import print_function import can From d7604bad0951b1950a2fc69423baa3ae7292c59c Mon Sep 17 00:00:00 2001 From: Miller Lowe Date: Thu, 2 Aug 2018 11:45:52 -0700 Subject: [PATCH 47/80] cleaned up some documentation and have the get_ecu_block examople working via BAM if you set your address as 0xff or uses RTS-CTS if requeting from a specific address --- bin/j1939_request_pgn.py | 2 +- examples/get_ecu_block.py | 33 ++++++++++++++++++++++++++++++++- j1939/utils.py | 8 +++++++- 3 files changed, 40 insertions(+), 3 deletions(-) diff --git a/bin/j1939_request_pgn.py b/bin/j1939_request_pgn.py index afd3ff5..bc3cb97 100644 --- a/bin/j1939_request_pgn.py +++ b/bin/j1939_request_pgn.py @@ -2,7 +2,7 @@ # from __future__ import print_function -_name = "" +_name = "j1939_request_pgn" __version__ = "1.0.0" __date__ = "12/21/2017" __exp__ = "(expirimental)" # (Release Version) diff --git a/examples/get_ecu_block.py b/examples/get_ecu_block.py index d7b030f..fb34993 100644 --- a/examples/get_ecu_block.py +++ b/examples/get_ecu_block.py @@ -1,8 +1,39 @@ +#!/usr/bin/python +# from __future__ import print_function +_name = "get_ecu_block" +__version__ = "1.1.0" +__date__ = "8/2/2018" +__exp__ = "(expirimental)" # (Release Version) +title = "%s Version: %s %s %s" % (_name, __version__, __date__, __exp__) + +import argparse import j1939.utils -val = j1939.utils.request_pgn(0xfeda, src=0xff) +parser = argparse.ArgumentParser(description='''\ + example: %(prog)s -d 0x17 + + will request ecu block from destination ''' + ,epilog=title) + +parser.add_argument("-s", "--src", + default="0xff", + help="j1939 source address decimal or hex, default is 0") + +parser.add_argument("-d", "--dest", + default="0x17", + help="CAN destination, default is 0x17") + +args = parser.parse_args() + + +source = int(args.src, 0) +dest = int(args.dest, 0) + +#expects a BAM back pretty +val = j1939.utils.request_pgn(0xfeda, src=source, dest=dest) + fieldCount = val[0] print ("%d elements in list" % fieldCount) diff --git a/j1939/utils.py b/j1939/utils.py index dd24d68..8646772 100644 --- a/j1939/utils.py +++ b/j1939/utils.py @@ -164,9 +164,15 @@ def request_pgn(requested_pgn, channel='can0', bustype='socketcan', length=4, sr if not isinstance(requested_pgn, int): raise ValueError("pgn must be an integer.") +# if bus is None: +# bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01) +# close = True if bus is None: - bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01) + bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01, keygen=security.SeedToKey, broadcast=False) + node = j1939.Node(bus, j1939.NodeName(), [src]) + bus.connect(node) close = True + pgn = j1939.PGN() pgn.value = 0xea00 + dest # request_pgn mem-object aid = j1939.ArbitrationID(pgn=pgn, source_address=src, destination_address=dest) From 4d6121c886ef33afda7d34b33dfa5521c8d31cd3 Mon Sep 17 00:00:00 2001 From: Miller Lowe Date: Fri, 10 Aug 2018 10:35:10 -0700 Subject: [PATCH 48/80] Allow passage of timeout into the Utils functions --- bin/j1939_mem_query.py | 2 +- examples/get_ecu_block.py | 7 ++++++- j1939/utils.py | 17 ++++++++--------- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/bin/j1939_mem_query.py b/bin/j1939_mem_query.py index 9851a21..cba3774 100644 --- a/bin/j1939_mem_query.py +++ b/bin/j1939_mem_query.py @@ -158,7 +158,7 @@ def getStringVal(s): ptr = getStringVal(args.pointer) length = getStringVal(args.length) ext = getStringVal(args.extension) - channel = args.channel + channel = args.channel print ("get_mem_object_single(src=0x%02x, dest=0x%02x, pointer=0x%02x, extension/space=0x%02x, len=%d" % (source, dest, ptr, ext, length)) val = j1939.utils.get_mem_object(ptr, ext, length=length, src=source, dest=dest, channel=channel) diff --git a/examples/get_ecu_block.py b/examples/get_ecu_block.py index fb34993..c107d16 100644 --- a/examples/get_ecu_block.py +++ b/examples/get_ecu_block.py @@ -25,14 +25,19 @@ default="0x17", help="CAN destination, default is 0x17") +parser.add_argument("-t", "--timeout", + default="10", + help="larger numbers give the dest more time to respond") + args = parser.parse_args() source = int(args.src, 0) dest = int(args.dest, 0) +timeout = int(args.timeout, 0) #expects a BAM back pretty -val = j1939.utils.request_pgn(0xfeda, src=source, dest=dest) +val = j1939.utils.request_pgn(0xfeda, src=source, dest=dest, timeout=timeout) fieldCount = val[0] print ("%d elements in list" % fieldCount) diff --git a/j1939/utils.py b/j1939/utils.py index 8646772..073049e 100644 --- a/j1939/utils.py +++ b/j1939/utils.py @@ -26,8 +26,8 @@ def SeedToKey(self, seed): security = Genkey() -def set_mem_object(pointer, extension, value, channel='can0', bustype='socketcan', length=4, src=0, dest=0x17, bus=None): - countdown = 10 +def set_mem_object(pointer, extension, value, channel='can0', bustype='socketcan', length=4, src=0, dest=0x17, bus=None, timeout=10): + countdown = timeout result = -1 close = False if bus is None: @@ -89,7 +89,6 @@ def set_mem_object(pointer, extension, value, channel='can0', bustype='socketcan logger.info("## PDU=%s ", dm16pdu) # Wait around for a while looking for the second proceed - countdown=10 proceedCount = 0 while countdown: countdown -= 1 @@ -115,8 +114,8 @@ def set_mem_object(pointer, extension, value, channel='can0', bustype='socketcan bus.shutdown() return result -def get_mem_object(pointer, extension, channel='can0', bustype='socketcan', length=4, src=0, dest=0x17, bus=None): - countdown = 10 +def get_mem_object(pointer, extension, channel='can0', bustype='socketcan', length=4, src=0, dest=0x17, bus=None, timeout=10): + countdown = timeout result = None close = False @@ -157,8 +156,8 @@ def get_mem_object(pointer, extension, channel='can0', bustype='socketcan', leng raise IOError(" no CAN response") return result -def request_pgn(requested_pgn, channel='can0', bustype='socketcan', length=4, src=0, dest=0x17, bus=None): - countdown = 10 +def request_pgn(requested_pgn, channel='can0', bustype='socketcan', length=4, src=0, dest=0x17, bus=None, timeout=10): + countdown = timeout result = None close = False @@ -203,8 +202,8 @@ def request_pgn(requested_pgn, channel='can0', bustype='socketcan', length=4, sr return result -def send_pgn(requested_pgn, data, channel='can0', bustype='socketcan', length=4, src=0, dest=0x17, bus=None): - countdown = 10 +def send_pgn(requested_pgn, data, channel='can0', bustype='socketcan', length=4, src=0, dest=0x17, bus=None, timeout=10): + countdown = timeout result = None if not isinstance(requested_pgn, int): From cede23ef8622b1c69ad6ff5b8d8e0f8b064c25fb Mon Sep 17 00:00:00 2001 From: Miller Lowe Date: Thu, 16 Aug 2018 14:59:00 -0700 Subject: [PATCH 49/80] some short term fizes for use on Windows --- j1939/utils.py | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/j1939/utils.py b/j1939/utils.py index 8646772..2790980 100644 --- a/j1939/utils.py +++ b/j1939/utils.py @@ -1,6 +1,7 @@ from __future__ import print_function import j1939 import logging +import sys logger = logging.getLogger(__name__) # @@ -30,11 +31,20 @@ def set_mem_object(pointer, extension, value, channel='can0', bustype='socketcan countdown = 10 result = -1 close = False - if bus is None: - bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01, keygen=security.SeedToKey, broadcast=False) - node = j1939.Node(bus, j1939.NodeName(), [src]) - bus.connect(node) - close = True + + if sys.platform == 'win32': + if bus is None: + bus = j1939.Bus(timeout=0.01, keygen=security.SeedToKey, broadcast=None, name='j1939StartGeneral', ignoreCanSendError=True) + node = j1939.Node(bus, j1939.NodeName(), [src]) + bus.connect(node) + close = True + else: + if bus is None: + bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01, keygen=security.SeedToKey, broadcast=False) + node = j1939.Node(bus, j1939.NodeName(), [src]) + bus.connect(node) + close = True + dm14data = [length, 0x15, pointer, 0x00, 0x00, extension, 0xff, 0xff] dm14pgn = j1939.PGN(pdu_format=0xd9, pdu_specific=dest) From dc3726ede264fc75cacfa5377e707e60217aa63c Mon Sep 17 00:00:00 2001 From: Miller Lowe Date: Thu, 30 Aug 2018 09:04:05 -0700 Subject: [PATCH 50/80] fix indention errors --- j1939/utils.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/j1939/utils.py b/j1939/utils.py index 2f8a330..8a41be5 100644 --- a/j1939/utils.py +++ b/j1939/utils.py @@ -33,17 +33,17 @@ def set_mem_object(pointer, extension, value, channel='can0', bustype='socketcan close = False if sys.platform == 'win32': - if bus is None: - bus = j1939.Bus(timeout=0.01, keygen=security.SeedToKey, broadcast=None, name='j1939StartGeneral', ignoreCanSendError=True) - node = j1939.Node(bus, j1939.NodeName(), [src]) - bus.connect(node) - close = True - else: - if bus is None: - bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01, keygen=security.SeedToKey, broadcast=False) - node = j1939.Node(bus, j1939.NodeName(), [src]) - bus.connect(node) - close = True + if bus is None: + bus = j1939.Bus(timeout=0.01, keygen=security.SeedToKey, broadcast=None, name='j1939StartGeneral', ignoreCanSendError=True) + node = j1939.Node(bus, j1939.NodeName(), [src]) + bus.connect(node) + close = True + else: + if bus is None: + bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01, keygen=security.SeedToKey, broadcast=False) + node = j1939.Node(bus, j1939.NodeName(), [src]) + bus.connect(node) + close = True dm14data = [length, 0x15, pointer, 0x00, 0x00, extension, 0xff, 0xff] From 765e73a10afef3084d248f92a1087579b7aeeea1 Mon Sep 17 00:00:00 2001 From: Rick Klaus Date: Tue, 11 Sep 2018 15:53:15 -0700 Subject: [PATCH 51/80] Add pgn and src filtering to set_mem_object bus --- j1939/utils.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/j1939/utils.py b/j1939/utils.py index 8a41be5..fc3d363 100644 --- a/j1939/utils.py +++ b/j1939/utils.py @@ -32,15 +32,18 @@ def set_mem_object(pointer, extension, value, channel='can0', bustype='socketcan result = -1 close = False + # only watch for the memory object pgn's + filt = [{'pgn':0xd800, 'source':dest},{'pgn':0xd400, 'source':dest}] + if sys.platform == 'win32': if bus is None: - bus = j1939.Bus(timeout=0.01, keygen=security.SeedToKey, broadcast=None, name='j1939StartGeneral', ignoreCanSendError=True) + bus = j1939.Bus(timeout=0.01, keygen=security.SeedToKey, broadcast=None, name='j1939StartGeneral', ignoreCanSendError=True, j1939_filters=filt) node = j1939.Node(bus, j1939.NodeName(), [src]) bus.connect(node) close = True else: if bus is None: - bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01, keygen=security.SeedToKey, broadcast=False) + bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01, keygen=security.SeedToKey, broadcast=False, j1939_filters=filt) node = j1939.Node(bus, j1939.NodeName(), [src]) bus.connect(node) close = True From 5039bca357637426a853221db883fa83932881cc Mon Sep 17 00:00:00 2001 From: rsmssnpdr Date: Tue, 11 Dec 2018 08:21:34 -0800 Subject: [PATCH 52/80] pgn request errors on dead/busy bus --- j1939/utils.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/j1939/utils.py b/j1939/utils.py index fc3d363..108a92d 100644 --- a/j1939/utils.py +++ b/j1939/utils.py @@ -199,15 +199,21 @@ def request_pgn(requested_pgn, channel='can0', bustype='socketcan', length=4, sr pdu.display_radix='hex' bus.send(pdu) - + maxPdu = 50 while countdown: pdu = bus.recv(timeout=1) if pdu and (pdu.pgn == 0xe800 or pdu.pgn == requested_pgn): result = list(pdu.data) break # got what I was waiting for - if pdu: + elif pdu: + maxPdu -=1 + if maxPdu <= 0: + raise IOError('Bus too busy') + elif pdu is None: countdown -= 1 + else: + raise Exception('WHAT HAPPENED') if close: bus.shutdown() if not result: From 86de4e7bb127eb87cae8eeecf9c7f0fcaa7663c2 Mon Sep 17 00:00:00 2001 From: Rick Klaus Date: Tue, 5 Mar 2019 13:22:36 -0800 Subject: [PATCH 53/80] Add support for multibyte pointers in memory objects This is used for Mode B transmission changes --- j1939/utils.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/j1939/utils.py b/j1939/utils.py index 108a92d..a1226b6 100644 --- a/j1939/utils.py +++ b/j1939/utils.py @@ -141,7 +141,12 @@ def get_mem_object(pointer, extension, channel='can0', bustype='socketcan', leng pgn.value = 0xd900 + dest # Request a DM14 mem-object aid = j1939.ArbitrationID(pgn=pgn, source_address=src, destination_address=dest) - data = [length, 0x13, pointer, 0x00, 0x00, extension, 0xff, 0xff] + # Get the 3 bytes of the pointer and put them in the correct locations + pointer0 = pointer & 0xff + pointer1 = (pointer & 0xff00) >> 8 + pointer2 = (pointer & 0xff0000) >> 16 + + data = [length, 0x13, pointer0, pointer1, pointer2, extension, 0xff, 0xff] pdu = j1939.PDU(timestamp=0.0, arbitration_id=aid, data=data, info_strings=None) assert(pdu != None) pdu.display_radix='hex' From 58aab6f1bdbe0a90568afa6bf3fcff075cb27c79 Mon Sep 17 00:00:00 2001 From: Rick Klaus Date: Tue, 5 Mar 2019 13:23:42 -0800 Subject: [PATCH 54/80] Add functions to get modem ID and status --- examples/get_modem_block.py | 58 ++++++++++++++++++++++++++++++++++ examples/get_modem_status.py | 60 ++++++++++++++++++++++++++++++++++++ 2 files changed, 118 insertions(+) create mode 100644 examples/get_modem_block.py create mode 100644 examples/get_modem_status.py diff --git a/examples/get_modem_block.py b/examples/get_modem_block.py new file mode 100644 index 0000000..ee79d98 --- /dev/null +++ b/examples/get_modem_block.py @@ -0,0 +1,58 @@ +#!/usr/bin/python +# +from __future__ import print_function + +_name = "get_modem_block" +__version__ = "1.0.0" +__date__ = "2/18/2019" +__exp__ = "(experimental)" # (Release Version) +title = "%s Version: %s %s %s" % (_name, __version__, __date__, __exp__) + +import argparse +import j1939.utils + +parser = argparse.ArgumentParser(description='''\ + example: %(prog)s -d 0x17 + + will request ecu block from destination ''' + ,epilog=title) + +parser.add_argument("-s", "--src", + default="0xff", + help="j1939 source address decimal or hex, default is 0") + +parser.add_argument("-d", "--dest", + default="0x41", + help="CAN destination, default is 0x41") + +parser.add_argument("-t", "--timeout", + default="20", + help="larger numbers give the dest more time to respond") + +args = parser.parse_args() + + +source = int(args.src, 0) +dest = int(args.dest, 0) +timeout = int(args.timeout, 0) + +#expects a BAM back pretty +val = j1939.utils.request_pgn(0xffb2, src=source, dest=dest, timeout=timeout) + +fieldCount = val[0] +print ("%d elements in list" % fieldCount) + +res="" +for c in val[1:]: + res += chr(c) + +res2=res.split('*') +#print (res2) + +print("Destination Address: %d (0x%x)" % (dest, dest)) +print("Number of ID items: %d (0x%x)" % (fieldCount, fieldCount)) +print("Modem IMEI: %s" % (res2[0])) +print("Modem ICCID: %s" % (res2[1])) + + + diff --git a/examples/get_modem_status.py b/examples/get_modem_status.py new file mode 100644 index 0000000..a3dff61 --- /dev/null +++ b/examples/get_modem_status.py @@ -0,0 +1,60 @@ +#!/usr/bin/python +# +from __future__ import print_function + +_name = "get_modem_block" +__version__ = "1.0.0" +__date__ = "2/18/2019" +__exp__ = "(experimental)" # (Release Version) +title = "%s Version: %s %s %s" % (_name, __version__, __date__, __exp__) + +import argparse +import j1939.utils + +parser = argparse.ArgumentParser(description='''\ + example: %(prog)s -d 0x17 + + will request ecu block from destination ''' + ,epilog=title) + +parser.add_argument("-s", "--src", + default="0xff", + help="j1939 source address decimal or hex, default is 0") + +parser.add_argument("-d", "--dest", + default="0x41", + help="CAN destination, default is 0x41") + +parser.add_argument("-t", "--timeout", + default="20", + help="larger numbers give the dest more time to respond") + +args = parser.parse_args() + + +source = int(args.src, 0) +dest = int(args.dest, 0) +timeout = int(args.timeout, 0) + +#expects a BAM back pretty +val = j1939.utils.request_pgn(0xffb8, src=source, dest=dest, timeout=timeout) + +#print(val) + +print("Destination Address: %d (0x%x)" % (dest, dest)) +print("Modem ping status: %d" % (val[0] & 0xF)) +print("Modem registration status: %d" % ((val[0] & 0xF0) >> 4)) +print("Modem signal strength: %d" % (val[1] & 0x7)) +print("Modem responding: %s" % ("true" if (((val[1] & 0x18) >> 3) == 1) else "false")) +if val[2] == 255: + print("Modem RSRQ: Not available") +else: + print("Modem RSRQ: %0.1f dB" % (val[2]/2 - 20.0)) + +if val[3] == 255: + print("Modem RSRP: Not available") +else: + print("Modem RSRP: %0.1f dBm" % (val[3] - 140.0)) + + + From d076e7a95861fd2cd361ffdc51358c6684310f9d Mon Sep 17 00:00:00 2001 From: rsmssnpdr Date: Fri, 8 Mar 2019 09:32:35 -0800 Subject: [PATCH 55/80] Add default value for _ignore_can_send_error Stops masking CAN errors as Attribute errors --- j1939/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/j1939/__init__.py b/j1939/__init__.py index c22b5fd..1d2aa86 100644 --- a/j1939/__init__.py +++ b/j1939/__init__.py @@ -107,6 +107,7 @@ def __init__(self, pdu_type=PDU, broadcast=True, *args, **kwargs): self._incomplete_transmitted_pdus = {} self._long_message_segment_queue = Queue(0) self._key_generation_fcn = None + self._ignore_can_send_error = False if 'keygen' in kwargs and kwargs['keygen'] is not None: self._key_generation_fcn = kwargs['keygen'] From 64b1378dd91cbbbf2747c2ecbff3f25e98dde109 Mon Sep 17 00:00:00 2001 From: rsmssnpdr Date: Mon, 22 Apr 2019 08:49:37 -0700 Subject: [PATCH 56/80] fix formatting error --- j1939/node.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/j1939/node.py b/j1939/node.py index bba9564..cf9b647 100644 --- a/j1939/node.py +++ b/j1939/node.py @@ -9,7 +9,7 @@ from j1939.nodename import NodeName logger = logging.getLogger(__name__) -logger.debug("loading ", __name__) +logger.debug("loading %s", __name__) From b86551e0fb5ea6ef8c4e95c2fdd832cfe2ad7f56 Mon Sep 17 00:00:00 2001 From: Miller Lowe Date: Tue, 3 Sep 2019 16:38:28 -0700 Subject: [PATCH 57/80] Update README.rst --- README.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.rst b/README.rst index 651549d..424c348 100644 --- a/README.rst +++ b/README.rst @@ -12,6 +12,8 @@ physical layer is used between the tractor and trailer, specified in ISO 11992. This package is dependent on, was a part of, and broken out from, the `python-can `__ project that Brian Thorne has maintained for years.. +This codce currently is compatable with the python-can version 3.3.2. After you clone the python-can repo be sure to checkout the 'release-3.3.2' branch + The **C**\ ontroller **A**\ rea **N**\ etwork is a bus standard designed to allow microcontrollers and devices to communicate with each other. It has priority based bus arbitration, reliable deterministic From 9b49acd7f701615faac50a0ebf05d0610f22e078 Mon Sep 17 00:00:00 2001 From: Arie Kraayenbrink <20170212+akraa@users.noreply.github.com> Date: Thu, 16 Jan 2020 13:27:22 -0500 Subject: [PATCH 58/80] Update python-can link Change https://bitbucket.org/hardbyte/python-can to https://github.com/hardbyte/python-can/ --- bin/j1939_logger.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/j1939_logger.py b/bin/j1939_logger.py index 8acb782..0662345 100644 --- a/bin/j1939_logger.py +++ b/bin/j1939_logger.py @@ -32,7 +32,7 @@ def parse_arguments(): a configuration file - see the README for detail. """), epilog="""Pull requests and issues - https://bitbucket.org/hardbyte/python-can""", + https://github.com/hardbyte/python-can""", formatter_class=argparse.RawTextHelpFormatter ) From f9bdf3df741ac57685be888a801118a79ca642c9 Mon Sep 17 00:00:00 2001 From: jonenz Date: Thu, 16 Jan 2020 15:43:37 -0800 Subject: [PATCH 59/80] Increase the size of memset. --- j1939/utils.py | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/j1939/utils.py b/j1939/utils.py index a1226b6..4ec3529 100644 --- a/j1939/utils.py +++ b/j1939/utils.py @@ -64,21 +64,10 @@ def set_mem_object(pointer, extension, value, channel='can0', bustype='socketcan sendBuffer.append(0) logger.info("## length=%d, value=%s " % (length, value)) - if isinstance(value, int): - if length == 1: - sendBuffer[1] = value - elif length == 2: - sendBuffer[1] = value & 0xff - sendBuffer[2] = (value >> 8) & 0xff - elif length == 3: - sendBuffer[1] = value & 0xff - sendBuffer[2] = (value >> 8) & 0xff - sendBuffer[3] = (value >> 16) & 0xff - elif length == 4: - sendBuffer[1] = value & 0xff - sendBuffer[2] = (value >> 8) & 0xff - sendBuffer[3] = (value >> 16) & 0xff - sendBuffer[4] = (value >> 24) & 0xff + if isinstance(value, int) and length < 8: + if length < 8: + for i in range(0, length): + sendBuffer[i] = (value >> (8*i)) & 0xff else: raise ValueError("Don't know how to send a %d byte integer" % length) @@ -92,6 +81,9 @@ def set_mem_object(pointer, extension, value, channel='can0', bustype='socketcan for i in range(len(value)): sendBuffer[i+1] = ord(value[i]) + else: + raise ValueError("Data type not supported.") + logger.info("## sendBuffer=%s ", sendBuffer) dm16pgn = j1939.PGN(pdu_format=0xd7, pdu_specific=dest) From 6c50cfa895f3285cc27a8cde6c059c1b34b0707c Mon Sep 17 00:00:00 2001 From: wang701 Date: Tue, 12 May 2020 18:35:36 -0400 Subject: [PATCH 60/80] Fix: log file path Old path does not work in Windows. Quick fix to enable cross platform support. --- j1939/__init__.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/j1939/__init__.py b/j1939/__init__.py index 1d2aa86..636ee0d 100644 --- a/j1939/__init__.py +++ b/j1939/__init__.py @@ -13,6 +13,8 @@ import logging.handlers import pprint import time +import tempfile +import os try: from queue import Queue, Empty @@ -51,9 +53,10 @@ #logger.addHandler(ch) if 1: - fileHandler = logging.handlers.RotatingFileHandler('/tmp/j1939.log', \ - maxBytes = (1024*1024*20), \ - backupCount = 4) + fileHandler = logging.handlers.RotatingFileHandler(os.path.join(tempfile.gettempdir(), \ + os.urandom(24).hex()), \ + maxBytes = (1024*1024*20), \ + backupCount = 4) fileHandler.setFormatter(chformatter) fileHandler.setLevel(lLevel) logger.addHandler(fileHandler) From 05dc9623d0133e7b71e0616be75640c469d96d23 Mon Sep 17 00:00:00 2001 From: wang701 Date: Tue, 12 May 2020 18:47:32 -0400 Subject: [PATCH 61/80] Change random filename to a sensible name --- j1939/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/j1939/__init__.py b/j1939/__init__.py index 636ee0d..9ddbf9d 100644 --- a/j1939/__init__.py +++ b/j1939/__init__.py @@ -54,7 +54,7 @@ if 1: fileHandler = logging.handlers.RotatingFileHandler(os.path.join(tempfile.gettempdir(), \ - os.urandom(24).hex()), \ + 'j1939.log'), \ maxBytes = (1024*1024*20), \ backupCount = 4) fileHandler.setFormatter(chformatter) From e94ab9e5aca3d820a0dc7b2bdbe55942f786b527 Mon Sep 17 00:00:00 2001 From: Miller Lowe Date: Tue, 12 May 2020 16:46:37 -0700 Subject: [PATCH 62/80] Changed the access for node address to addresslist as it copnflicts with another module --- j1939/__init__.py | 16 ++++++++++------ j1939/node.py | 2 +- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/j1939/__init__.py b/j1939/__init__.py index 9ddbf9d..531b829 100644 --- a/j1939/__init__.py +++ b/j1939/__init__.py @@ -53,6 +53,10 @@ #logger.addHandler(ch) if 1: +<<<<<<< Updated upstream +======= + print ("TEMP_FILE: ", os.path.join(tempfile.gettempdir(), 'j1939.log')) +>>>>>>> Stashed changes fileHandler = logging.handlers.RotatingFileHandler(os.path.join(tempfile.gettempdir(), \ 'j1939.log'), \ maxBytes = (1024*1024*20), \ @@ -112,11 +116,8 @@ def __init__(self, pdu_type=PDU, broadcast=True, *args, **kwargs): self._key_generation_fcn = None self._ignore_can_send_error = False - if 'keygen' in kwargs and kwargs['keygen'] is not None: - self._key_generation_fcn = kwargs['keygen'] - - if 'ignoreCanSendError' in kwargs and kwargs['ignoreCanSendError'] is not None: - self._ignore_can_send_error = kwargs['ignoreCanSendError'] + self._key_generation_fcn = kwargs.get('keygen') + self._ignore_can_send_error = kwargs.get('ignoreCanSendError') if broadcast: self.node_queue_list = [(None, self)] # Start with default logger Queue which will receive everything @@ -461,6 +462,9 @@ def _process_incoming_message(self, msg): pdu.radix = 16 logger.info("PI02: arbitration_id.pgn.value == 0x%04x" % arbitration_id.pgn.value) + logger.info("PI02a: arbitration_id.pgn.value = {}".format(arbitration_id.pgn.value)) + logger.info("PI02b: PGN_TP_SEED_REQUEST = {}".format(PGN_TP_SEED_REQUEST)) + logger.info("PI02c: self._key_generation_fcn = {}".format(self._key_generation_fcn)) if arbitration_id.pgn.value == PGN_TP_CONNECTION_MANAGEMENT: logger.info("PGN_TP_CONNECTION_MANAGEMENT") @@ -688,7 +692,7 @@ def _process_rts(self, msg): def _process_cts(self, msg): logger.debug("_process_cts") logger.debug("MIL8: cts message is: %s" % msg) - logger.debug("MIL8: len(pdu-send-buffer) = %d" % len(self._incomplete_transmitted_pdus[0][23])) + #logger.debug("MIL8: len(pdu-send-buffer) = %d" % len(self._incomplete_transmitted_pdus[0][23])) if msg.arbitration_id.pgn.pdu_specific in self._incomplete_transmitted_pdus: diff --git a/j1939/node.py b/j1939/node.py index cf9b647..c56e5dd 100644 --- a/j1939/node.py +++ b/j1939/node.py @@ -54,7 +54,7 @@ def address(self): return self.known_node_addresses[self.node_name.value] @property - def address(self): + def addressList(self): return self.address_list def start_address_claim(self): From 7202d9efe7285241858f521e918d2499261ddac4 Mon Sep 17 00:00:00 2001 From: Miller Lowe Date: Tue, 12 May 2020 16:48:46 -0700 Subject: [PATCH 63/80] remove a debugging conflict.. Oops --- j1939/__init__.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/j1939/__init__.py b/j1939/__init__.py index 531b829..531297f 100644 --- a/j1939/__init__.py +++ b/j1939/__init__.py @@ -53,10 +53,6 @@ #logger.addHandler(ch) if 1: -<<<<<<< Updated upstream -======= - print ("TEMP_FILE: ", os.path.join(tempfile.gettempdir(), 'j1939.log')) ->>>>>>> Stashed changes fileHandler = logging.handlers.RotatingFileHandler(os.path.join(tempfile.gettempdir(), \ 'j1939.log'), \ maxBytes = (1024*1024*20), \ From f5f22a74eca538ef592e27be13428a16134a5ab8 Mon Sep 17 00:00:00 2001 From: Miller Lowe Date: Tue, 26 May 2020 07:57:57 -0700 Subject: [PATCH 64/80] Added simple DM1 1Hz Send example --- examples/simple-dm1-send.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100755 examples/simple-dm1-send.py diff --git a/examples/simple-dm1-send.py b/examples/simple-dm1-send.py new file mode 100755 index 0000000..69df080 --- /dev/null +++ b/examples/simple-dm1-send.py @@ -0,0 +1,29 @@ +import time +import j1939 + +if __name__ == "__main__": + + # code to broadcast a DM1 message at 1 Hz + # 18FECAFE#FFFF00000000FFFF + + channel = 'can0' + bustype = 'socketcan' + sourceaddr = 0xFE + destaddr = 0xFF + + + bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01, broadcast=False) + + data = [0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF] + pgn = j1939.PGN() + pgn.value = 0xFECA # DM1 + aid = j1939.ArbitrationID(pgn=pgn, source_address=sourceaddr, destination_address=destaddr) + pdu = j1939.PDU(timestamp=0.0, arbitration_id=aid, data=data, info_strings=None) + + while True: + bus.send(pdu) + time.sleep(1) + + + + From acc9f8dbbf1cd260089c7450a0c4669749668e7f Mon Sep 17 00:00:00 2001 From: Miller Lowe Date: Fri, 29 May 2020 08:43:30 -0700 Subject: [PATCH 65/80] Corrected a mem-object-set error in the bin application. If setting a binary object the program was incorrectly building the DM16 object by putting the data, not the length, in the first byte --- bin/j1939_mem_query.py | 6 +++--- bin/j1939_mem_set.py | 17 +++++++++++------ j1939/utils.py | 3 ++- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/bin/j1939_mem_query.py b/bin/j1939_mem_query.py index cba3774..ef0ae2a 100644 --- a/bin/j1939_mem_query.py +++ b/bin/j1939_mem_query.py @@ -77,9 +77,9 @@ def getStringVal(s): if __name__ == "__main__": - #lLevel = logging.WARN - #jlogger = logging.getLogger("j1939") - #jlogger.setLevel(lLevel) + lLevel = logging.WARN + jlogger = logging.getLogger("j1939") + jlogger.setLevel(lLevel) #ch = logging.StreamHandler() #jlogger.addHandler(ch) diff --git a/bin/j1939_mem_set.py b/bin/j1939_mem_set.py index 123113b..5920875 100644 --- a/bin/j1939_mem_set.py +++ b/bin/j1939_mem_set.py @@ -7,12 +7,19 @@ __exp__ = "()" # (Release Version) title = "%s Version: %s %s %s" % (_name, __version__, __date__, __exp__) - - import j1939.utils if __name__ == "__main__": + import logging + import timeit + import argparse + + lLevel = logging.WARN + jlogger = logging.getLogger("j1939") + jlogger.setLevel(lLevel) + clogger = logging.getLogger("can") + clogger.setLevel(lLevel) examples = """ examples: @@ -30,11 +37,9 @@ """ - import timeit - import argparse - import logging - import logging.handlers + #import logging + #import logging.handlers parser = argparse.ArgumentParser(description=title, formatter_class=argparse.RawDescriptionHelpFormatter, epilog=examples) diff --git a/j1939/utils.py b/j1939/utils.py index 4ec3529..db21ba8 100644 --- a/j1939/utils.py +++ b/j1939/utils.py @@ -66,8 +66,9 @@ def set_mem_object(pointer, extension, value, channel='can0', bustype='socketcan logger.info("## length=%d, value=%s " % (length, value)) if isinstance(value, int) and length < 8: if length < 8: + sendBuffer[0] = length for i in range(0, length): - sendBuffer[i] = (value >> (8*i)) & 0xff + sendBuffer[i+1] = (value >> (8*i)) & 0xff else: raise ValueError("Don't know how to send a %d byte integer" % length) From fe8dc3a4c73c3246bf934b314ae23eaf429990c4 Mon Sep 17 00:00:00 2001 From: Johan Brus <69041456+johanbrus@users.noreply.github.com> Date: Fri, 21 Aug 2020 16:36:19 +0200 Subject: [PATCH 66/80] Update __init__.py Taken from the python-can project, seems this should add the possibility to pull up the version number by j1939.__version__ Though not sure if I added it at the right position and also whether the version number is correct. Feel free to correct. --- j1939/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/j1939/__init__.py b/j1939/__init__.py index 531297f..8327d54 100644 --- a/j1939/__init__.py +++ b/j1939/__init__.py @@ -52,6 +52,8 @@ ch.setFormatter(chformatter) #logger.addHandler(ch) +__version__ = "1.0.0" + if 1: fileHandler = logging.handlers.RotatingFileHandler(os.path.join(tempfile.gettempdir(), \ 'j1939.log'), \ From 021a4cb274a3431af25e9b9181cafa11bb1d79cf Mon Sep 17 00:00:00 2001 From: Demo User Date: Fri, 20 Nov 2020 16:37:23 +0000 Subject: [PATCH 67/80] Added speed parameter to memset and memquery so that genkey gets setup properly --- bin/j1939_mem_set.py | 3 ++- j1939/utils.py | 35 +++++++++++++++++++++++++++-------- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/bin/j1939_mem_set.py b/bin/j1939_mem_set.py index 123113b..20aea95 100644 --- a/bin/j1939_mem_set.py +++ b/bin/j1939_mem_set.py @@ -41,6 +41,7 @@ parser.add_argument("-l", "--length", default="1", help="number of bytes in the object (1-4) default=1") parser.add_argument("-s", "--source", default="0", help="source address (0-254) default=0") parser.add_argument("-d", "--destination", default="0x17", help="destination address (0-254) default=17") + parser.add_argument("-c", "--channel", default="can0", help="Generally can0 on workstations or can1 on bbb/pbb targets") parser.add_argument("extension", default=None, @@ -80,6 +81,6 @@ # queries a couple objects but setting up the full stack and bus for # each takes a long time. start = timeit.default_timer() - val = j1939.utils.set_mem_object(ptr, ext, value, length=length, src=src, dest=dest) + val = j1939.utils.set_mem_object(ptr, ext, value, channel=args.channel, length=length, src=src, dest=dest) #set_mem_object_single(length=1, src=0, dest=0x17, pointer=0x66, extension=0xea, value=127) print("elapsed = %s s" % (timeit.default_timer() - start)) diff --git a/j1939/utils.py b/j1939/utils.py index 4ec3529..ddd0899 100644 --- a/j1939/utils.py +++ b/j1939/utils.py @@ -14,7 +14,8 @@ # try: import genkey - security = genkey.GenKey() + security250 = genkey.GenKey() + security500 = genkey.GenKey(speed=500) logger.info("Private Genkey Loaded") except: # Stuff in a fake genKey responder. Pretty much just needs a @@ -27,23 +28,29 @@ def SeedToKey(self, seed): security = Genkey() -def set_mem_object(pointer, extension, value, channel='can0', bustype='socketcan', length=4, src=0, dest=0x17, bus=None, timeout=10): +def set_mem_object(pointer, extension, value, channel='can0', bustype='socketcan', length=4, src=0, dest=0x17, speed=250, bus=None, timeout=10): countdown = timeout result = -1 close = False + keygenFunction = None + if speed == 250: + keygetFunction = security250.SeedToKey + if speed == 500 + keygetFunction = security500.SeedToKey + # only watch for the memory object pgn's filt = [{'pgn':0xd800, 'source':dest},{'pgn':0xd400, 'source':dest}] if sys.platform == 'win32': if bus is None: - bus = j1939.Bus(timeout=0.01, keygen=security.SeedToKey, broadcast=None, name='j1939StartGeneral', ignoreCanSendError=True, j1939_filters=filt) + bus = j1939.Bus(timeout=0.01, keygen=keygetFunction, broadcast=None, name='j1939StartGeneral', ignoreCanSendError=True, j1939_filters=filt) node = j1939.Node(bus, j1939.NodeName(), [src]) bus.connect(node) close = True else: if bus is None: - bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01, keygen=security.SeedToKey, broadcast=False, j1939_filters=filt) + bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01, keygen=keygetFunction, broadcast=False, j1939_filters=filt) node = j1939.Node(bus, j1939.NodeName(), [src]) bus.connect(node) close = True @@ -166,18 +173,24 @@ def get_mem_object(pointer, extension, channel='can0', bustype='socketcan', leng raise IOError(" no CAN response") return result -def request_pgn(requested_pgn, channel='can0', bustype='socketcan', length=4, src=0, dest=0x17, bus=None, timeout=10): +def request_pgn(requested_pgn, channel='can0', speed=250, bustype='socketcan', length=4, src=0, dest=0x17, bus=None, timeout=10): countdown = timeout result = None close = False + keygenFunction = None + if speed == 250: + keygetFunction = security250.SeedToKey + if speed == 500 + keygetFunction = security500.SeedToKey + if not isinstance(requested_pgn, int): raise ValueError("pgn must be an integer.") # if bus is None: # bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01) # close = True if bus is None: - bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01, keygen=security.SeedToKey, broadcast=False) + bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01, keygen=keygetFunction, broadcast=False) node = j1939.Node(bus, j1939.NodeName(), [src]) bus.connect(node) close = True @@ -218,14 +231,20 @@ def request_pgn(requested_pgn, channel='can0', bustype='socketcan', length=4, sr return result -def send_pgn(requested_pgn, data, channel='can0', bustype='socketcan', length=4, src=0, dest=0x17, bus=None, timeout=10): +def send_pgn(requested_pgn, data, channel='can0', speed=250, bustype='socketcan', length=4, src=0, dest=0x17, bus=None, timeout=10): countdown = timeout result = None + keygenFunction = None + if speed == 250: + keygetFunction = security250.SeedToKey + if speed == 500 + keygetFunction = security500.SeedToKey + if not isinstance(requested_pgn, int): raise ValueError("pgn must be an integer.") if bus is None: - bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01, keygen=security.SeedToKey) + bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01, keygen=keygetFunction) close = True else: close = False From 745a43f141c2acf7b9421b3384ce3e486c145b14 Mon Sep 17 00:00:00 2001 From: Miller Lowe Date: Sun, 22 Nov 2020 22:45:01 -0800 Subject: [PATCH 68/80] Modified up some of the memSet/memQuery commands to handle a --speed parameter to generate the proper keys without screwing with genkey --- bin/j1939_mem_set.py | 23 ++++++++++++++++------- bin/j1939_request_pgn.py | 2 +- bin/j1939_send_pgn.py | 2 +- examples/j1939_nodes.py | 2 +- j1939/__init__.py | 16 ++++++++++------ j1939/utils.py | 28 +++++++++++++++++++--------- setup.py | 2 +- 7 files changed, 49 insertions(+), 26 deletions(-) diff --git a/bin/j1939_mem_set.py b/bin/j1939_mem_set.py index 2140d9b..e8c4f72 100644 --- a/bin/j1939_mem_set.py +++ b/bin/j1939_mem_set.py @@ -7,6 +7,7 @@ __exp__ = "()" # (Release Version) title = "%s Version: %s %s %s" % (_name, __version__, __date__, __exp__) +import genkey import j1939.utils @@ -15,12 +16,6 @@ import timeit import argparse - lLevel = logging.WARN - jlogger = logging.getLogger("j1939") - jlogger.setLevel(lLevel) - clogger = logging.getLogger("can") - clogger.setLevel(lLevel) - examples = """ examples: # write the characters 'ERASE' to extension E9 ponter ED @@ -47,6 +42,8 @@ parser.add_argument("-s", "--source", default="0", help="source address (0-254) default=0") parser.add_argument("-d", "--destination", default="0x17", help="destination address (0-254) default=17") parser.add_argument("-c", "--channel", default="can0", help="Generally can0 on workstations or can1 on bbb/pbb targets") + parser.add_argument("-v", "--verbose", action="store_true", default=False, help="Generate debugging output") + parser.add_argument("--speed", default=250, help="CAN baudrate 250 or 500, (default 250)") parser.add_argument("extension", default=None, @@ -63,6 +60,18 @@ args = parser.parse_args() + if args.verbose: + lLevel = logging.DEBUG + else: + lLevel = logging.WARN + + jlogger = logging.getLogger("j1939") + jlogger.setLevel(lLevel) + ulogger = logging.getLogger("utils") + ulogger.setLevel(lLevel) + clogger = logging.getLogger("can") + clogger.setLevel(lLevel) + length = int(args.length,0) src = int(args.source,0) dest = int(args.destination,0) @@ -86,6 +95,6 @@ # queries a couple objects but setting up the full stack and bus for # each takes a long time. start = timeit.default_timer() - val = j1939.utils.set_mem_object(ptr, ext, value, channel=args.channel, length=length, src=src, dest=dest) + val = j1939.utils.set_mem_object(ptr, ext, value, speed=args.speed, channel=args.channel, length=length, src=src, dest=dest) #set_mem_object_single(length=1, src=0, dest=0x17, pointer=0x66, extension=0xea, value=127) print("elapsed = %s s" % (timeit.default_timer() - start)) diff --git a/bin/j1939_request_pgn.py b/bin/j1939_request_pgn.py index bc3cb97..6657bd4 100644 --- a/bin/j1939_request_pgn.py +++ b/bin/j1939_request_pgn.py @@ -30,7 +30,7 @@ def getStringValAsInt(s): logger = logging.getLogger("j1939") ch = logging.StreamHandler() - ch.setLevel(logging.WARNING) + ch.setLevel(logging.warning) logger.addHandler(ch) parser = argparse.ArgumentParser(description='''\ diff --git a/bin/j1939_send_pgn.py b/bin/j1939_send_pgn.py index ade24d7..d6fdb68 100644 --- a/bin/j1939_send_pgn.py +++ b/bin/j1939_send_pgn.py @@ -33,7 +33,7 @@ def getStringValAsInt(s): logger = logging.getLogger("j1939") ch = logging.StreamHandler() - ch.setLevel(logging.WARNING) + ch.setLevel(logging.warning) logger.addHandler(ch) parser = argparse.ArgumentParser(description='''\ diff --git a/examples/j1939_nodes.py b/examples/j1939_nodes.py index acb8927..b719bba 100644 --- a/examples/j1939_nodes.py +++ b/examples/j1939_nodes.py @@ -12,7 +12,7 @@ import j1939 import logging -lLevel = logging.WARNING +lLevel = logging.warning logger = logging.getLogger() logger.setLevel(lLevel) diff --git a/j1939/__init__.py b/j1939/__init__.py index 531297f..2edc39b 100644 --- a/j1939/__init__.py +++ b/j1939/__init__.py @@ -41,10 +41,11 @@ from j1939.arbitrationid import ArbitrationID from j1939.utils import * +lLevel = logging.WARNING + logger = logging.getLogger("j1939") -logger.setLevel(logging.WARNING) +logger.setLevel(lLevel) -lLevel = logging.DEBUG logger.setLevel(lLevel) ch = logging.StreamHandler() ch.setLevel(lLevel) @@ -113,6 +114,9 @@ def __init__(self, pdu_type=PDU, broadcast=True, *args, **kwargs): self._ignore_can_send_error = False self._key_generation_fcn = kwargs.get('keygen') + logger.debug("----PI01d: self._key_generation_fcn={}".format(self._key_generation_fcn)) + + self._ignore_can_send_error = kwargs.get('ignoreCanSendError') if broadcast: @@ -457,10 +461,10 @@ def _process_incoming_message(self, msg): pdu.info_strings = [] pdu.radix = 16 - logger.info("PI02: arbitration_id.pgn.value == 0x%04x" % arbitration_id.pgn.value) - logger.info("PI02a: arbitration_id.pgn.value = {}".format(arbitration_id.pgn.value)) - logger.info("PI02b: PGN_TP_SEED_REQUEST = {}".format(PGN_TP_SEED_REQUEST)) - logger.info("PI02c: self._key_generation_fcn = {}".format(self._key_generation_fcn)) + logger.debug("PI02a: arbitration_id.pgn.value = 0x{:04x} ({})".format(arbitration_id.pgn.value, arbitration_id.pgn.value)) + logger.debug("PI02b: PGN_TP_SEED_REQUEST = {}".format(PGN_TP_SEED_REQUEST)) + + logger.debug("PI02c: self._key_generation_fcn = {}".format(self._key_generation_fcn)) if arbitration_id.pgn.value == PGN_TP_CONNECTION_MANAGEMENT: logger.info("PGN_TP_CONNECTION_MANAGEMENT") diff --git a/j1939/utils.py b/j1939/utils.py index 049c60a..7dd33e5 100644 --- a/j1939/utils.py +++ b/j1939/utils.py @@ -14,14 +14,14 @@ # try: import genkey - security250 = genkey.GenKey() + security250 = genkey.GenKey(speed=250) security500 = genkey.GenKey(speed=500) logger.info("Private Genkey Loaded") except: # Stuff in a fake genKey responder. Pretty much just needs a # reference to any class that can convert a Seed to a Key.. For # obvious reasons I'm not posting mine - logger.info("Genkey Not loaded, This one will generate garbage keys") + logger.warning("Genkey Not loaded, This one will generate garbage keys") class Genkey: def SeedToKey(self, seed): return 0x12345678 @@ -33,11 +33,21 @@ def set_mem_object(pointer, extension, value, channel='can0', bustype='socketcan result = -1 close = False - keygenFunction = None - if speed == 250: + #print("------------------------------- Set Mem Object: speed={}, security250={}, security500={}".format(speed, security250, security500)) + + keygetFunction = None + + if int(speed) == 250: keygetFunction = security250.SeedToKey - if speed == 500 + #print("PI02f speed=500, keygetFunction={}".format(keygetFunction)) + elif int(speed) == 500: keygetFunction = security500.SeedToKey + #print("PI02f speed=500, keygetFunction={}".format(keygetFunction)) + else: + #print("PI02f speed=Unknown, keygetFunction={}".format(keygetFunction)) + pass + + print("------------------------------- keygetFunction={}".format(keygetFunction)) # only watch for the memory object pgn's filt = [{'pgn':0xd800, 'source':dest},{'pgn':0xd400, 'source':dest}] @@ -179,10 +189,10 @@ def request_pgn(requested_pgn, channel='can0', speed=250, bustype='socketcan', l result = None close = False - keygenFunction = None + keygetFunction = None if speed == 250: keygetFunction = security250.SeedToKey - if speed == 500 + if speed == 500: keygetFunction = security500.SeedToKey if not isinstance(requested_pgn, int): @@ -236,10 +246,10 @@ def send_pgn(requested_pgn, data, channel='can0', speed=250, bustype='socketcan' countdown = timeout result = None - keygenFunction = None + keygetFunction = None if speed == 250: keygetFunction = security250.SeedToKey - if speed == 500 + if speed == 500: keygetFunction = security500.SeedToKey if not isinstance(requested_pgn, int): diff --git a/setup.py b/setup.py index 56c5161..27c1eb5 100644 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ __version__ = "0.1.0-alpha.3" -logging.basicConfig(level=logging.WARNING) +logging.basicConfig(level=logging.warning) setup( name="python-j1939", From 52215894f5596b2381c2e69d8be4eec6cd98f4d2 Mon Sep 17 00:00:00 2001 From: Miller Lowe Date: Mon, 23 Nov 2020 19:50:43 -0800 Subject: [PATCH 69/80] somehow I had logging.warning entered as a parameter set for logging.setlevel() the parameter should be logging.WARNING if used as a level and use logging.warning() if actually entering a warning log message --- examples/j1939_nodes.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/j1939_nodes.py b/examples/j1939_nodes.py index b719bba..acb8927 100644 --- a/examples/j1939_nodes.py +++ b/examples/j1939_nodes.py @@ -12,7 +12,7 @@ import j1939 import logging -lLevel = logging.warning +lLevel = logging.WARNING logger = logging.getLogger() logger.setLevel(lLevel) diff --git a/setup.py b/setup.py index 27c1eb5..56c5161 100644 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ __version__ = "0.1.0-alpha.3" -logging.basicConfig(level=logging.warning) +logging.basicConfig(level=logging.WARNING) setup( name="python-j1939", From 10561053afac42d370973a6b23e2cf90f0cd768a Mon Sep 17 00:00:00 2001 From: Miller Lowe Date: Tue, 15 Dec 2020 18:20:32 -0800 Subject: [PATCH 70/80] allow mem-query to have a speed command line option. In the future I'll add code to verify this matches current CAN speed --- bin/j1939_mem_query.py | 7 ++++++- j1939/utils.py | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/bin/j1939_mem_query.py b/bin/j1939_mem_query.py index ef0ae2a..2c210be 100644 --- a/bin/j1939_mem_query.py +++ b/bin/j1939_mem_query.py @@ -101,6 +101,10 @@ def getStringVal(s): default="0x17", help="CAN destination, default is 0x17") + parser.add_argument("--speed", + default="250", + help="CAN bitrate {250|500}, default is 250") + parser.add_argument("-l", "--length", default="4", help="length in bytes (default: 4)") @@ -158,10 +162,11 @@ def getStringVal(s): ptr = getStringVal(args.pointer) length = getStringVal(args.length) ext = getStringVal(args.extension) + speed = getStringVal(args.speed) channel = args.channel print ("get_mem_object_single(src=0x%02x, dest=0x%02x, pointer=0x%02x, extension/space=0x%02x, len=%d" % (source, dest, ptr, ext, length)) - val = j1939.utils.get_mem_object(ptr, ext, length=length, src=source, dest=dest, channel=channel) + val = j1939.utils.get_mem_object(ptr, ext, length=length, src=source, dest=dest, channel=channel, speed=speed) print(val) out = '' if isinstance(val, list): diff --git a/j1939/utils.py b/j1939/utils.py index 7dd33e5..896cf19 100644 --- a/j1939/utils.py +++ b/j1939/utils.py @@ -137,7 +137,7 @@ def set_mem_object(pointer, extension, value, channel='can0', bustype='socketcan bus.shutdown() return result -def get_mem_object(pointer, extension, channel='can0', bustype='socketcan', length=4, src=0, dest=0x17, bus=None, timeout=10): +def get_mem_object(pointer, extension, channel='can0', bustype='socketcan', length=4, src=0, dest=0x17, bus=None, speed=250, timeout=10): countdown = timeout result = None close = False From ca2a36f24eb94ac274bf18dc9d696d63de3d3c5e Mon Sep 17 00:00:00 2001 From: Miller Lowe Date: Thu, 31 Dec 2020 12:10:47 -0800 Subject: [PATCH 71/80] Better processing of string and array objects --- bin/j1939_mem_set.py | 30 ++++++++++++++++++++++++++---- j1939/utils.py | 26 ++++++++++++++++---------- 2 files changed, 42 insertions(+), 14 deletions(-) diff --git a/bin/j1939_mem_set.py b/bin/j1939_mem_set.py index e8c4f72..502bec9 100644 --- a/bin/j1939_mem_set.py +++ b/bin/j1939_mem_set.py @@ -7,6 +7,7 @@ __exp__ = "()" # (Release Version) title = "%s Version: %s %s %s" % (_name, __version__, __date__, __exp__) +import sys import genkey import j1939.utils @@ -30,6 +31,11 @@ # Set B1/C4 Odometer to 200km (200=1km) $ python j1939_mem_set.py --destination=0x17 --length=4 0xf1 0x00 20000 + # Write 7 bytes of Backlight Settings. Note the array has to have no spaces + $ python j1939_mem_set.py -d 0x17 0xe9 0x01 [0x85,0x00,0x00,0x20,0x01,0x80,0x69] + # ptr off b0 b1 b2 b3 b4 b5 b6 + + """ @@ -39,6 +45,7 @@ parser = argparse.ArgumentParser(description=title, formatter_class=argparse.RawDescriptionHelpFormatter, epilog=examples) parser.add_argument("-l", "--length", default="1", help="number of bytes in the object (1-4) default=1") + parser.add_argument("-t", "--timeout", default="1000", help="ms before the request times out (default=1000 or 1s)") parser.add_argument("-s", "--source", default="0", help="source address (0-254) default=0") parser.add_argument("-d", "--destination", default="0x17", help="destination address (0-254) default=17") parser.add_argument("-c", "--channel", default="can0", help="Generally can0 on workstations or can1 on bbb/pbb targets") @@ -77,24 +84,39 @@ dest = int(args.destination,0) ext = int(args.extension,0) ptr = int(args.pointer,0) + timeout = int(args.timeout,0) value = args.value # - # Try first to pull out a numeric argument, otherwise set it as a string. + # Try first to pull out a numeric ir byte list argument, otherwise set it as a string. # try: - value = int(args.value,0) - print("Attepting to set %2X/%02X to %s" % (ext, ptr, value)) + if args.value.startswith('['): + print ("processing array") + ar = args.value[1:-1] + print ("array = {}".format(ar)) + elements = ar.split(',') + print ("elements = {}".format(elements)) + value = [int(s,0) for s in elements] + print ("elements = {}".format(elements)) + length = len(value) + + else: + value = int(args.value,0) + except ValueError: if length < len(value): length = len(value) + print("Attepting to set 0x{:02x}/0x{:02x} to {}, dlc={}".format(ext, ptr, value, len(value))) #value = hex(int(args.value,0)) # queries a couple objects but setting up the full stack and bus for # each takes a long time. start = timeit.default_timer() - val = j1939.utils.set_mem_object(ptr, ext, value, speed=args.speed, channel=args.channel, length=length, src=src, dest=dest) + val = j1939.utils.set_mem_object(ptr, ext, value, speed=args.speed, channel=args.channel, length=length, src=src, dest=dest, timeout=timeout) #set_mem_object_single(length=1, src=0, dest=0x17, pointer=0x66, extension=0xea, value=127) print("elapsed = %s s" % (timeit.default_timer() - start)) + print("return val = {}".format(int(val!=1))) + sys.exit(val!=1) diff --git a/j1939/utils.py b/j1939/utils.py index 896cf19..33c77d7 100644 --- a/j1939/utils.py +++ b/j1939/utils.py @@ -76,46 +76,52 @@ def set_mem_object(pointer, extension, value, channel='can0', bustype='socketcan bus.send(dm14pdu) sendBuffer = [] - sendBuffer.append(length) - for i in range(0, length): - sendBuffer.append(0) + #sendBuffer.append(length) + #for i in range(0, length): + # sendBuffer.append(0) - logger.info("## length=%d, value=%s " % (length, value)) + logger.info("---------------## length=%d, value=%s " % (length, value)) if isinstance(value, int) and length < 8: + logger.info("-----value") if length < 8: sendBuffer[0] = length for i in range(0, length): - sendBuffer[i+1] = (value >> (8*i)) & 0xff + sendBuffer.append((value >> (8*i)) & 0xff) else: raise ValueError("Don't know how to send a %d byte integer" % length) elif isinstance(value, list): + # if sending a list use the exact list elements as the data + logger.info("-----list of {} byte(s)".format(len(value))) + sendBuffer.append(len(value)) for i in range(len(value)): - sendBuffer[i+1] = value[i] + logger.info("---------------## b[{}]=0x{:02x}".format(i, value[i])) + sendBuffer.append(value[i]) elif isinstance(value, str): + logger.info("-----str") assert(len(value) <= length) sendBuffer[0] = length+1 for i in range(len(value)): - sendBuffer[i+1] = ord(value[i]) + sendBuffer.append(ord(value[i])) else: raise ValueError("Data type not supported.") - logger.info("## sendBuffer=%s ", sendBuffer) + logger.info("---------------## sendBuffer=%s ", sendBuffer) dm16pgn = j1939.PGN(pdu_format=0xd7, pdu_specific=dest) dm16aid = j1939.ArbitrationID(pgn=dm16pgn, source_address=src, destination_address=dest) dm16pdu = j1939.PDU(timestamp=0.0, arbitration_id=dm16aid, data=sendBuffer) dm16pdu.display_radix='hex' - logger.info("## PDU=%s ", dm16pdu) + logger.info("----------------## PDU=%s ", dm16pdu) # Wait around for a while looking for the second proceed proceedCount = 0 while countdown: countdown -= 1 - rcvPdu = bus.recv(2) + rcvPdu = bus.recv(timeout=0.25) if rcvPdu: rcvPdu.display_radix='hex' logger.debug("received PDU: %s", rcvPdu) From fe5fec627da316a200c7c56be3e36eddfa048a19 Mon Sep 17 00:00:00 2001 From: Miller Lowe Date: Thu, 7 Jan 2021 13:45:39 -0800 Subject: [PATCH 72/80] two PDU creation cases would write to undefined buffer position.. It was starting empty so I changed the assignments to append() calls --- j1939/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/j1939/utils.py b/j1939/utils.py index 33c77d7..a424765 100644 --- a/j1939/utils.py +++ b/j1939/utils.py @@ -84,7 +84,7 @@ def set_mem_object(pointer, extension, value, channel='can0', bustype='socketcan if isinstance(value, int) and length < 8: logger.info("-----value") if length < 8: - sendBuffer[0] = length + sendBuffer.append(length) for i in range(0, length): sendBuffer.append((value >> (8*i)) & 0xff) else: @@ -101,7 +101,7 @@ def set_mem_object(pointer, extension, value, channel='can0', bustype='socketcan elif isinstance(value, str): logger.info("-----str") assert(len(value) <= length) - sendBuffer[0] = length+1 + sendBuffer.append(length+1) for i in range(len(value)): sendBuffer.append(ord(value[i])) From 798473060633e1d2f4b61f2f6eeb06e68049d0d8 Mon Sep 17 00:00:00 2001 From: Miller Lowe Date: Tue, 9 Feb 2021 16:00:27 -0800 Subject: [PATCH 73/80] Added a --string parameter to mem_set to force the program to intrepret the parameter as a string, previously if it was numeric then the paramater would get converted to a uint32 --- bin/j1939_mem_set.py | 13 +++++++++---- j1939/utils.py | 2 +- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/bin/j1939_mem_set.py b/bin/j1939_mem_set.py index 502bec9..b1c27b6 100644 --- a/bin/j1939_mem_set.py +++ b/bin/j1939_mem_set.py @@ -50,7 +50,8 @@ parser.add_argument("-d", "--destination", default="0x17", help="destination address (0-254) default=17") parser.add_argument("-c", "--channel", default="can0", help="Generally can0 on workstations or can1 on bbb/pbb targets") parser.add_argument("-v", "--verbose", action="store_true", default=False, help="Generate debugging output") - parser.add_argument("--speed", default=250, help="CAN baudrate 250 or 500, (default 250)") + parser.add_argument( "--string", action="store_true", default=False, help="Treat an integer parameter as a string") + parser.add_argument( "--speed", default=250, help="CAN baudrate 250 or 500, (default 250)") parser.add_argument("extension", default=None, @@ -91,7 +92,11 @@ # Try first to pull out a numeric ir byte list argument, otherwise set it as a string. # try: - if args.value.startswith('['): + if args.string: + value = args.value + length = len(value) + print("Attepting to set 0x{:02x}/0x{:02x} to string {}, dlc={}".format(ext, ptr, value, len(value))) + elif args.value.startswith('['): print ("processing array") ar = args.value[1:-1] print ("array = {}".format(ar)) @@ -100,15 +105,15 @@ value = [int(s,0) for s in elements] print ("elements = {}".format(elements)) length = len(value) - + print("Attepting to set 0x{:02x}/0x{:02x} to {}, dlc={}".format(ext, ptr, value, len(value))) else: value = int(args.value,0) + print("Attepting to set 0x{:02x}/0x{:02x} to {}, dlc={}".format(ext, ptr, value, len(value))) except ValueError: if length < len(value): length = len(value) - print("Attepting to set 0x{:02x}/0x{:02x} to {}, dlc={}".format(ext, ptr, value, len(value))) #value = hex(int(args.value,0)) diff --git a/j1939/utils.py b/j1939/utils.py index a424765..d21d96d 100644 --- a/j1939/utils.py +++ b/j1939/utils.py @@ -99,7 +99,7 @@ def set_mem_object(pointer, extension, value, channel='can0', bustype='socketcan sendBuffer.append(value[i]) elif isinstance(value, str): - logger.info("-----str") + logger.info("-----str, value={}, len(value)={}. length={}".format(value, len(value), length)) assert(len(value) <= length) sendBuffer.append(length+1) for i in range(len(value)): From 743ef532d45409fd30f13b5b1515d7a91d9d44e3 Mon Sep 17 00:00:00 2001 From: Miller Lowe Date: Mon, 21 Feb 2022 16:17:18 -0800 Subject: [PATCH 74/80] Updated utils.mem_set to support a memory update that does not require security. Fixed soe other warning levels. --- bin/j1939_request_pgn.py | 2 +- bin/j1939_send_pgn.py | 2 +- j1939/utils.py | 4 +--- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/bin/j1939_request_pgn.py b/bin/j1939_request_pgn.py index 6657bd4..bc3cb97 100644 --- a/bin/j1939_request_pgn.py +++ b/bin/j1939_request_pgn.py @@ -30,7 +30,7 @@ def getStringValAsInt(s): logger = logging.getLogger("j1939") ch = logging.StreamHandler() - ch.setLevel(logging.warning) + ch.setLevel(logging.WARNING) logger.addHandler(ch) parser = argparse.ArgumentParser(description='''\ diff --git a/bin/j1939_send_pgn.py b/bin/j1939_send_pgn.py index d6fdb68..ade24d7 100644 --- a/bin/j1939_send_pgn.py +++ b/bin/j1939_send_pgn.py @@ -33,7 +33,7 @@ def getStringValAsInt(s): logger = logging.getLogger("j1939") ch = logging.StreamHandler() - ch.setLevel(logging.warning) + ch.setLevel(logging.WARNING) logger.addHandler(ch) parser = argparse.ArgumentParser(description='''\ diff --git a/j1939/utils.py b/j1939/utils.py index d21d96d..3e0dfd9 100644 --- a/j1939/utils.py +++ b/j1939/utils.py @@ -118,7 +118,6 @@ def set_mem_object(pointer, extension, value, channel='can0', bustype='socketcan logger.info("----------------## PDU=%s ", dm16pdu) # Wait around for a while looking for the second proceed - proceedCount = 0 while countdown: countdown -= 1 rcvPdu = bus.recv(timeout=0.25) @@ -127,8 +126,7 @@ def set_mem_object(pointer, extension, value, channel='can0', bustype='socketcan logger.debug("received PDU: %s", rcvPdu) if rcvPdu.pgn == 0xd800: if rcvPdu.data[0]==1 and rcvPdu.data[1]==0x11: - proceedCount += 1 - if proceedCount == 2: + if rcvPdu.data[6] == 0xff and rcvPdu.data[7] == 0xff: bus.send(dm16pdu) logger.info('Sent %s', dm16pdu) elif rcvPdu.data[0]==0 and rcvPdu.data[1]==0x19: From 32b75ecd044fa432dd3fbd56ee0fbbd49686dda8 Mon Sep 17 00:00:00 2001 From: Miller Lowe Date: Wed, 23 Mar 2022 10:41:52 -0700 Subject: [PATCH 75/80] repaitr a coupleaces where 18 bit PGN's were not getting through the system. --- examples/simple-17bit-send.py | 44 +++++++++++++++++++++++++++++++++++ j1939/__init__.py | 12 ++++------ j1939/arbitrationid.py | 18 ++++++++------ j1939/notifier.py | 4 ++++ j1939/pdu.py | 2 +- j1939/pgn.py | 32 +++++++++++++++---------- j1939/utils.py | 10 ++++---- 7 files changed, 90 insertions(+), 32 deletions(-) create mode 100755 examples/simple-17bit-send.py diff --git a/examples/simple-17bit-send.py b/examples/simple-17bit-send.py new file mode 100755 index 0000000..c902641 --- /dev/null +++ b/examples/simple-17bit-send.py @@ -0,0 +1,44 @@ +import time +import j1939 + +if __name__ == "__main__": + + # code to broadcast a DM1 message at 1 Hz + # 18FECAFE#FFFF00000000FFFF + + channel = 'can0' + bustype = 'socketcan' + sourceaddr = 0xFE + destaddr = 0xFF + + + bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01, broadcast=False) + + data = [0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF] + pgn = j1939.PGN() + pgn2 = j1939.PGN() + pgn3 = j1939.PGN() + #pgn.value = 0xFECA # DM1 + pgn.value = 0xFF17 # DM1 + pgn2.value = 0x1FF17 # DM1 + pgn3.value = 0x2FF17 # DM1 + print("pgn.values: {}/{}".format(pgn.value, pgn2.value)) + aid = j1939.ArbitrationID(pgn=pgn, source_address=sourceaddr, destination_address=destaddr) + aid2 = j1939.ArbitrationID(pgn=pgn2, source_address=sourceaddr, destination_address=destaddr) + aid3 = j1939.ArbitrationID(pgn=pgn3, source_address=sourceaddr, destination_address=destaddr) + print("aid: {}".format(aid)) + pdu = j1939.PDU(timestamp=0.0, arbitration_id=aid, data=data, info_strings=None) + pdu2 = j1939.PDU(timestamp=0.0, arbitration_id=aid2, data=data, info_strings=None) + pdu3 = j1939.PDU(timestamp=0.0, arbitration_id=aid3, data=data, info_strings=None) + print("pdu: {}".format(pdu)) + + while True: + print("pre send\n {}\n {}\n {}".format(pdu, pdu2, pdu3)) + bus.send(pdu) + bus.send(pdu2) + bus.send(pdu3) + time.sleep(1) + + + + diff --git a/j1939/__init__.py b/j1939/__init__.py index e808b9a..7793498 100644 --- a/j1939/__init__.py +++ b/j1939/__init__.py @@ -260,7 +260,7 @@ def recv(self, timeout=None): # listener.on_error_received(rx_error) def send(self, msg, timeout=None): - logger.info("j1939.send: msg=%s" % msg) + logger.info("j1939.send: msg={}".format(msg)) messages = [] if len(msg.data) > 8: logger.info("j1939.send: message is > than 8 bytes") @@ -269,7 +269,7 @@ def send(self, msg, timeout=None): pdu = copy.deepcopy(msg) pdu.data = bytearray(pdu.data) - logger.info("j1939.send: Copied msg = %s" % pdu) + logger.info("j1939.send: Copied msg = {}".format(pdu)) pdu_length_lsb, pdu_length_msb = divmod(len(pdu.data), 256) while len(pdu.data) % 7 != 0: @@ -307,9 +307,7 @@ def send(self, msg, timeout=None): # # At this point we have the queued messages sequenced in 'messages' # - logger.info("MIL8: j1939.send: is_destination_specific=%d, destAddr=%s" % - (pdu.arbitration_id.pgn.is_destination_specific, - pdu.arbitration_id.destination_address)) + logger.info("MIL8: j1939.send: is_destination_specific={}, destAddr={}".format(pdu.arbitration_id.pgn.is_destination_specific, pdu.arbitration_id.destination_address)) logger.info("MIL8: j1939.send: messages=%s" % messages) if pdu.arbitration_id.pgn.is_destination_specific and \ @@ -396,13 +394,13 @@ def send(self, msg, timeout=None): self._long_message_segment_queue.put_nowait(message) else: msg.display_radix = 'hex' - logger.debug("j1939.send: calling can_bus_send: j1939-msg: %s" % (msg)) + logger.debug("j1939.send: calling can_bus_send: j1939-msg: {}, arb-id: {:08x}".format(msg, msg.arbitration_id.can_id)) can_message = Message(arbitration_id=msg.arbitration_id.can_id, extended_id=True, dlc=len(msg.data), data=msg.data) - logger.debug("j1939.send: calling can_bus_send: can-msg: %s" % can_message) + logger.debug("j1939.send: calling can_bus_send: can-msg: {}".format(can_message)) try: self.can_bus.send(can_message) except CanError: diff --git a/j1939/arbitrationid.py b/j1939/arbitrationid.py index 31ae351..31cc419 100644 --- a/j1939/arbitrationid.py +++ b/j1939/arbitrationid.py @@ -59,26 +59,30 @@ def __init__(self, priority=7, pgn=None, source_address=0, destination_address=N @property def can_id(self): - logger.debug("can_id property: self._pgn.is_destination_specific=%s\npgn=%s" % (self._pgn.is_destination_specific, self._pgn)) + logger.debug("can_id property: self._pgn.is_destination_specific={}/pgn={}".format(self._pgn.is_destination_specific, self._pgn)) if self._pgn.is_destination_specific: - logger.debug("can_id: self._pgn.is_destination_specific, dest=%s, pgn_value=%s, pdu_format=0x%x, pdu_specific=0x%x, pri=%s" % - (self.destination_address_value, + logger.debug("can_id: self._pgn.is_destination_specific, dest={}, pgn_value={}, pdu_format=0x{:04x}, pdu_specific=0x{:02x}, pri={}".format( + self.destination_address_value, self._pgn.value, self._pgn.pdu_format, self._pgn.pdu_specific, self.priority)) if self.destination_address_value: + logger.debug("can_id: self.destination_address_value: pgn_value: {:04x}".format(self._pgn.value)) + logger.debug(" (self._pgn.value & 0x3ff00): {:04x}".format((self._pgn.value & 0x3ff00))) + logger.debug(" (self.destination_address_value): {:04x}".format((self.destination_address_value))) retval = (self.source_address + - ((self._pgn.value & 0xff00) + (self.destination_address_value) << 8)+ + ((self._pgn.value & 0x3ff00) + (self.destination_address_value) << 8) + (self.priority << 26)) else: + logger.debug("can_id: NOT self.destination_address_value:") retval = (self.source_address + - ((self._pgn.value & 0xff00) << 8)+ + ((self._pgn.value & 0x3ff00) << 8)+ (self.priority << 26)) - logger.debug("can_id: retval=0x%08x" % (retval)) + logger.debug("can_id: retval=0x{:08x}".format(retval)) return retval else: logger.debug("can_id: NOT! self._pgn.is_destination_specific") @@ -94,7 +98,7 @@ def can_id(self, canid): self._pgn = PGN().from_can_id(canid) self.source_address = canid & 0x000000FF if self._pgn.is_destination_specific: - self.destination_address_value = (canid & 0x0000FF00) >> 8 + self.destination_address_value = (canid & 0x0003FF00) >> 8 logger.debug("can_id: canid=0x%08x, priority=%x, pdu_format=%x, pdu_specific=%x, src=%x" % diff --git a/j1939/notifier.py b/j1939/notifier.py index 23c4f56..698f0d1 100644 --- a/j1939/notifier.py +++ b/j1939/notifier.py @@ -1,4 +1,5 @@ import threading +import logging try: import queue except ImportError: @@ -11,6 +12,8 @@ #same as a CAN Notifier but will listen to a queue #recv function. +logger = logging.getLogger(__name__) + class Notifier(object): def __init__(self, queue, listeners, timeout=None): @@ -59,6 +62,7 @@ def _rx_thread(self, bus): for callback in self.listeners: callback(msg) msg = bus.recv(self.timeout) + logger.debug('CanNotifier: {}\n'.format(msg)) # # The next two handlers are intended to mask race conditions that can occur when diff --git a/j1939/pdu.py b/j1939/pdu.py index e009606..c495f42 100644 --- a/j1939/pdu.py +++ b/j1939/pdu.py @@ -175,7 +175,7 @@ def __str__(self): :return: A string representation of this message. """ - #logger.info("PI07: stringify PDU") + logger.debug("PI07: stringify PDU") if self.radix == RADIX_HEX: data_string = " ".join("{:02x}".format(byte) for byte in self.data) diff --git a/j1939/pgn.py b/j1939/pgn.py index 28dd915..fe772d0 100644 --- a/j1939/pgn.py +++ b/j1939/pgn.py @@ -14,7 +14,12 @@ def __init__(self, reserved_flag=False, data_page_flag=False, pdu_format=0, pdu_ @property def is_pdu1(self): - return ((self.pdu_format < 240) or self.reserved_flag or self.data_page_flag) + result = (((self.pdu_format & 0xFF) < 240) or self.reserved_flag) + logger.debug("PGN is_pdu1 {:04x}: {}".format(self.pdu_format, result)) + logger.debug(" (self.pdu_format & 0xFF) < 240 {:04x}: {}".format(self.pdu_format, (self.pdu_format & 0xFF) < 240)) + logger.debug(" self.reserved_flag {:04x}: {}".format(self.pdu_format, self.reserved_flag)) + logger.debug(" self.data_page_flag {:04x}: {}".format(self.pdu_format, self.data_page_flag)) + return result @property def is_pdu2(self): @@ -22,7 +27,9 @@ def is_pdu2(self): @property def is_destination_specific(self): - return self.is_pdu1 + result = self.is_pdu1 + logger.debug("PGN is_destination_specific {:04x}: {}".format(self.value, result)) + return result @property def value(self): @@ -31,18 +38,19 @@ def value(self): @value.setter def value(self, value): - self.reserved_flag = (value & 0x020000) >> 17 - self.data_page_flag = (value & 0x010000) >> 16 - self.pdu_format = (value & 0x00FF00) >> 8 + self.reserved_flag = (value & 0x080000) >> 17 + self.data_page_flag = (value & 0x040000) >> 16 + self.pdu_format = (value & 0x03FF00) >> 8 self.pdu_specific = value & 0x0000FF + #MIL logger.debug("PGN.@valueSetter, value=0x%08x, pdu_format=0x%08x" % (value, self.pdu_format)) @staticmethod def from_value(pgn_value): logger.debug("PGN.@from_value, pgn_value=0x%08x" % (pgn_value)) pgn = PGN() - pgn.reserved_flag = (pgn_value & 0x020000) >> 17 - pgn.data_page_flag = (pgn_value & 0x010000) >> 16 - pgn.pdu_format = (pgn_value & 0x00FF00) >> 8 + pgn.reserved_flag = (pgn_value & 0x080000) >> 17 + pgn.data_page_flag = (pgn_value & 0x040000) >> 16 + pgn.pdu_format = (pgn_value & 0x03FF00) >> 8 pgn.pdu_specific = pgn_value & 0x0000FF return pgn @@ -52,16 +60,16 @@ def from_can_id(canid): canid = canid>>8 pgn = PGN() #logger.debug("PGN.@from_can_id, value=0x%08x" % (canid)) - pgn.reserved_flag = (canid & 0x020000) >> 17 - pgn.data_page_flag = (canid & 0x010000) >> 16 - pgn.pdu_format = (canid & 0x00FF00) >> 8 + pgn.reserved_flag = (canid & 0x080000) >> 17 + pgn.data_page_flag = (canid & 0x040000) >> 16 + pgn.pdu_format = (canid & 0x03FF00) >> 8 pgn.pdu_specific = canid & 0x0000FF logger.debug("PGN.@from_can_id, res=%d, dp=%d, pdu_format=0x%02x, pdu_specific=0x%02x" % (pgn.reserved_flag, pgn.data_page_flag, pgn.pdu_format, pgn.pdu_specific)) return pgn def __str__(self): - retval = ("0x%.4x " % ((((self.pdu_format)<<8) | (self.pdu_specific)) & 0xFFFF)) + retval = ("0x%.5x " % ((((self.pdu_format)<<8) | (self.pdu_specific)) & 0x3FFFF)) if self.reserved_flag: retval += "R " diff --git a/j1939/utils.py b/j1939/utils.py index 3e0dfd9..0bd5522 100644 --- a/j1939/utils.py +++ b/j1939/utils.py @@ -33,21 +33,21 @@ def set_mem_object(pointer, extension, value, channel='can0', bustype='socketcan result = -1 close = False - #print("------------------------------- Set Mem Object: speed={}, security250={}, security500={}".format(speed, security250, security500)) + logger.debug("------------------------------- Set Mem Object: speed={}, security250={}, security500={}".format(speed, security250, security500)) keygetFunction = None if int(speed) == 250: keygetFunction = security250.SeedToKey - #print("PI02f speed=500, keygetFunction={}".format(keygetFunction)) + logger.debug("PI02f speed=500, keygetFunction={}".format(keygetFunction)) elif int(speed) == 500: keygetFunction = security500.SeedToKey - #print("PI02f speed=500, keygetFunction={}".format(keygetFunction)) + logger.debug("PI02f speed=500, keygetFunction={}".format(keygetFunction)) else: - #print("PI02f speed=Unknown, keygetFunction={}".format(keygetFunction)) + logger.debug("PI02f speed=Unknown, keygetFunction={}".format(keygetFunction)) pass - print("------------------------------- keygetFunction={}".format(keygetFunction)) + logger.debug("------------------------------- keygetFunction={}".format(keygetFunction)) # only watch for the memory object pgn's filt = [{'pgn':0xd800, 'source':dest},{'pgn':0xd400, 'source':dest}] From 2de1391d8ab3f432277ddac748bd251ac51d8942 Mon Sep 17 00:00:00 2001 From: Miller Lowe Date: Fri, 25 Mar 2022 15:26:29 -0700 Subject: [PATCH 76/80] Cleaned up mem object set/query command lines Allow for MemObject Pointer > 1 byte Added --log command line paramater set all the j1939 logging objects to "j1939" instead of __name__ Repaired a defect that I injected reciently while supporting 17 and 18 bit PGN's --- bin/j1939_mem_query.py | 167 ++++++++++++---------------------------- bin/j1939_mem_set.py | 56 +++++++++----- examples/j1939_nodes.py | 2 +- j1939/__init__.py | 23 +++--- j1939/arbitrationid.py | 28 +++---- j1939/node.py | 22 +++--- j1939/notifier.py | 2 +- j1939/pdu.py | 2 +- j1939/pgn.py | 17 ++-- j1939/utils.py | 26 ++++++- 10 files changed, 162 insertions(+), 183 deletions(-) diff --git a/bin/j1939_mem_query.py b/bin/j1939_mem_query.py index 2c210be..4695f12 100644 --- a/bin/j1939_mem_query.py +++ b/bin/j1939_mem_query.py @@ -1,15 +1,18 @@ #!/usr/bin/python # -from __future__ import print_function _name = "Simple J1939 memory object query" -__version__ = "1.0.0" -__date__ = "12/20/2017" -__exp__ = "(expirimental)" # (Release Version) +__version__ = "1.1.0" +__date__ = "3/25/22" +__exp__ = "()" # (Release Version) title = "%s Version: %s %s %s" % (_name, __version__, __date__, __exp__) -import j1939.utils +import sys +MIN_PYTHON = (3, 5) +if sys.version_info < MIN_PYTHON: + sys.exit("Python %s.%s or later is required.\n" % MIN_PYTHON) +import j1939.utils if __name__ == "__main__": import traceback @@ -18,70 +21,11 @@ import argparse import logging import textwrap - -''' -1532554003.434215 PRI=7 PGN=0xff9a SRC=0x17 d3 ff ff ff ff ff ff ff -1532554003.434771 PRI=6 PGN=0xd041 DST=0x41 SRC=0x17 a1 ff ff ff ff ff ff ff -1532554003.863598 PRI=7 PGN=0xd917 DST=0x17 SRC=0x18 0a 13 11 00 00 e9 ff ff -1532554003.868833 PRI=6 PGN=0xd818 DST=0x18 SRC=0x17 0a 11 ff ff ff ff ff ff -1532554003.901772 PRI=7 PGN=0xd718 DST=NONE(error) SRC=0x17 ff 59 30 31 2e 30 34 2e 32 30 00 -1532554003.908125 PRI=7 PGN=0xd917 DST=0x17 SRC=0x18 ff 09 00 00 00 00 ff ff -1532554003.939402 PRI=7 PGN=0xff9a SRC=0x17 d3 ff ff ff ff ff ff ff -1532554003.939959 PRI=6 PGN=0xd041 DST=0x41 SRC=0x17 9c ff ff ff ff ff ff ff -1532554003.940621 PRI=6 PGN=0xfec1 SRC=0x17 00 00 00 00 00 00 00 00 -1532554003.941260 PRI=6 PGN=0xfefc SRC=0x17 ff ff ff ff ff ff ff ff -''' - - -def get_mem_object(bus=None, length=4, src=0, dest=0x17, pointer=0, extension=0): - countdown = 10 - result = None - - pgn = j1939.PGN() - pgn.value = 0xd917 - aid = j1939.ArbitrationID(pgn=pgn, source_address=src, destination_address=dest) - - data = [length, 0x13, pointer, 0x00, 0x00, extension, 0xff, 0xff] - pdu = j1939.PDU(timestamp=0.0, arbitration_id=aid, data=data, info_strings=None) - pdu.display_radix='hex' - - bus.send(pdu) - - while countdown: - pdu = bus.recv() - if pdu.pgn == 0xd700: - value = list(pdu.data) - length = value[0] - if length == 1: - result = value[1] - if length == 2: - result = (value[2] << 8) + value[1] - if length == 4: - result = (value[4] << 24) + (value[3] << 16) + (value[2] << 8) + value[1] - break # got what I was waiting for - - countdown -= 1 - - if (result == None): - raise IOError(" no CAN response") - - return result - -def getStringVal(s): - if s.startswith("0x"): - return int(s[2:],base=16) - else: - return int(s, base=10) - + import inspect if __name__ == "__main__": - lLevel = logging.WARN - jlogger = logging.getLogger("j1939") - jlogger.setLevel(lLevel) - #ch = logging.StreamHandler() - #jlogger.addHandler(ch) parser = argparse.ArgumentParser(description='''\ example: %(prog)s -d 0x21 0xe9 -p 0x15 @@ -105,6 +49,10 @@ def getStringVal(s): default="250", help="CAN bitrate {250|500}, default is 250") + parser.add_argument("--log", + default="WARNING", + help="Set LogLevel to DEBUG|INFO|(WARNING)|ERROR|CRITICAL for this app, j1939 and can") + parser.add_argument("-l", "--length", default="4", help="length in bytes (default: 4)") @@ -124,54 +72,41 @@ def getStringVal(s): args = parser.parse_args() - - if args.test: - # queries a couple objects but setting up the full stack and bus for - # each takes a long time. - if 1: - start = timeit.default_timer() - for p, e in [(0x15, 0xe9), (0x00, 0xf1), (0x50, 0xe9), (0x75, 0xe9)]: - val = j1939.utils.get_mem_object(length=4, src=0, dest=0x17, pointer=p, extension=e) - print("0x%02x-0x%02x = %d" % (p, e, val)) - print("elapsed = %s s" % (timeit.default_timer() - start)) - - - if 1: - # queries the same objects but in a single bus instance, should be a tad faster. - start = timeit.default_timer() - try: - jbus = j1939.Bus(channel='can0', bustype='socketcan', timeout=0.01) - for p, e in [(0x15, 0xe9), (0x00, 0xf1), (0x50, 0xe9), (0x75, 0xe9)]: - val = get_mem_object(jbus, length=4, src=0, dest=0x17, pointer=p, extension=e) - print("0x%02x-0x%02x = %d" % (p, e, val)) - except: - traceback.print_exc() - pass - - jbus.shutdown() - - print("elapsed = %s s" % (timeit.default_timer() - start)) - - else: - - if (args.pointer==None or args.extension==None): - raise ValueError("pointer and extension are required!") - - source = getStringVal(args.src) - dest = getStringVal(args.dest) - ptr = getStringVal(args.pointer) - length = getStringVal(args.length) - ext = getStringVal(args.extension) - speed = getStringVal(args.speed) - channel = args.channel - print ("get_mem_object_single(src=0x%02x, dest=0x%02x, pointer=0x%02x, extension/space=0x%02x, len=%d" % (source, dest, ptr, ext, length)) - - val = j1939.utils.get_mem_object(ptr, ext, length=length, src=source, dest=dest, channel=channel, speed=speed) - print(val) - out = '' - if isinstance(val, list): - for x in val: - out+=chr(x) - print(out) - #print("0x%02x-0x%02x = %d (0x%08x)" % (ptr, ext, val, val)) - + # assuming loglevel is bound to the string value obtained from the + # command line argument. Convert to upper case to allow the user to + # specify --log=DEBUG or --log=debug + numeric_level = getattr(logging, args.log.upper()) + if not isinstance(numeric_level, int): + raise ValueError('Invalid log level: {}'.format(args.log)) + logging.basicConfig(level=numeric_level) + + logger = logging.getLogger("j1939") + logger.setLevel(numeric_level) + + logger = logging.getLogger("can") + logger.setLevel(numeric_level) + + if (args.pointer==None or args.extension==None): + raise ValueError("pointer and extension are required!") + + source = int(args.src, 0) + dest = int(args.dest, 0) + ptr = int(args.pointer, 0) + length = int(args.length, 0) + ext = int(args.extension, 0) + speed = int(args.speed, 0) + channel = args.channel + logging.info ("get_mem_object_single(src=0x%02x, dest=0x%02x, pointer=0x%02x, extension/space=0x%02x, len=%d" % (source, dest, ptr, ext, length)) + + val = j1939.utils.get_mem_object(ptr, ext, length=length, src=source, dest=dest, channel=channel, speed=speed) + print("{}".format(val)) + out = '' + if isinstance(val, list): + for x in val: + out+=chr(x) + print(out) + +#(1648235377.698487) can0 1CD94100#0413000000F1FFFF +#(1648235377.712659) can0 18D80041#0411FFFFFFFFFFFF +#(1648235377.712660) can0 1CD70041#0400000000FFFFFF +#(1648235377.712661) can0 18D80041#0019FFFFFFFFFFFF \ No newline at end of file diff --git a/bin/j1939_mem_set.py b/bin/j1939_mem_set.py index b1c27b6..8b1f5a0 100644 --- a/bin/j1939_mem_set.py +++ b/bin/j1939_mem_set.py @@ -1,17 +1,21 @@ -from __future__ import print_function - +#!/usr/bin/python3 +# _name = "J1939 Memory-Object Writer" -__version__ = "1.0.1" -__date__ = "02/27/2018" +__version__ = "1.0.2" +__date__ = "03/29/2021" __exp__ = "()" # (Release Version) title = "%s Version: %s %s %s" % (_name, __version__, __date__, __exp__) import sys +MIN_PYTHON = (3, 5) +if sys.version_info < MIN_PYTHON: + sys.exit("Python %s.%s or later is required.\n" % MIN_PYTHON) import genkey import j1939.utils + if __name__ == "__main__": import logging import timeit @@ -19,6 +23,8 @@ examples = """ examples: + # NOTE: if the CAN speed is 500 add --speed 500 + # # write the characters 'ERASE' to extension E9 ponter ED $ python j1939_mem_set.py -d 0x17 0xe9 0xed ERASE @@ -49,9 +55,13 @@ parser.add_argument("-s", "--source", default="0", help="source address (0-254) default=0") parser.add_argument("-d", "--destination", default="0x17", help="destination address (0-254) default=17") parser.add_argument("-c", "--channel", default="can0", help="Generally can0 on workstations or can1 on bbb/pbb targets") + parser.add_argument("-r", "--robot", action="store_true", default=False, help="provide parsable result data to aid robot testing") parser.add_argument("-v", "--verbose", action="store_true", default=False, help="Generate debugging output") parser.add_argument( "--string", action="store_true", default=False, help="Treat an integer parameter as a string") parser.add_argument( "--speed", default=250, help="CAN baudrate 250 or 500, (default 250)") + parser.add_argument("--log", + default="WARNING", + help="Set LogLevel to DEBUG|INFO|(WARNING)|ERROR|CRITICAL for this app, j1939 and can") parser.add_argument("extension", default=None, @@ -61,24 +71,28 @@ default=None, help="Memory object pointer offset to request in decimal or 0xhex") - parser.add_argument('value', default=None, help="numeric or string value, if not a single byte, be sure to specify length.") args = parser.parse_args() - if args.verbose: - lLevel = logging.DEBUG - else: - lLevel = logging.WARN + # assuming loglevel is bound to the string value obtained from the + # command line argument. Convert to upper case to allow the user to + # specify --log=DEBUG or --log=debug + numeric_level = getattr(logging, args.log.upper()) + if not isinstance(numeric_level, int): + raise ValueError('Invalid log level: {}'.format(args.log)) + logging.basicConfig(level=numeric_level) + + logger = logging.getLogger("j1939") + logger.setLevel(numeric_level) - jlogger = logging.getLogger("j1939") - jlogger.setLevel(lLevel) - ulogger = logging.getLogger("utils") - ulogger.setLevel(lLevel) - clogger = logging.getLogger("can") - clogger.setLevel(lLevel) + logger = logging.getLogger("can") + logger.setLevel(numeric_level) + + if (args.pointer==None or args.extension==None or args.value==None): + raise ValueError("pointer, extension and value are required values!") length = int(args.length,0) src = int(args.source,0) @@ -95,7 +109,7 @@ if args.string: value = args.value length = len(value) - print("Attepting to set 0x{:02x}/0x{:02x} to string {}, dlc={}".format(ext, ptr, value, len(value))) + print("Attepting to set extension/pointer 0x{:x}/0x{:x} to string {}, dlc={}".format(ext, ptr, value, len(value))) elif args.value.startswith('['): print ("processing array") ar = args.value[1:-1] @@ -105,16 +119,15 @@ value = [int(s,0) for s in elements] print ("elements = {}".format(elements)) length = len(value) - print("Attepting to set 0x{:02x}/0x{:02x} to {}, dlc={}".format(ext, ptr, value, len(value))) + print("Attepting to set extension/pointer 0x{:x}/0x{:x} to array {}, dlc={}".format(ext, ptr, value, len(value))) else: value = int(args.value,0) - print("Attepting to set 0x{:02x}/0x{:02x} to {}, dlc={}".format(ext, ptr, value, len(value))) + print("Attepting to set extension/pointer 0x{:x}/0x{:x} to integer {}, dlc={}".format(ext, ptr, value, length)) except ValueError: if length < len(value): length = len(value) - #value = hex(int(args.value,0)) # queries a couple objects but setting up the full stack and bus for @@ -124,4 +137,9 @@ #set_mem_object_single(length=1, src=0, dest=0x17, pointer=0x66, extension=0xea, value=127) print("elapsed = %s s" % (timeit.default_timer() - start)) print("return val = {}".format(int(val!=1))) + if args.robot: + if val!=1: + print("RESULT=FAIL") + else: + print("RESULT=SUCCESS") sys.exit(val!=1) diff --git a/examples/j1939_nodes.py b/examples/j1939_nodes.py index acb8927..5a41512 100644 --- a/examples/j1939_nodes.py +++ b/examples/j1939_nodes.py @@ -14,7 +14,7 @@ lLevel = logging.WARNING -logger = logging.getLogger() +logger = logging.getLogger("j1939") logger.setLevel(lLevel) ch = logging.StreamHandler() fh = logging.FileHandler('/tmp/j1939_nodes.log') diff --git a/j1939/__init__.py b/j1939/__init__.py index 7793498..6de336e 100644 --- a/j1939/__init__.py +++ b/j1939/__init__.py @@ -170,23 +170,25 @@ def __init__(self, pdu_type=PDU, broadcast=True, *args, **kwargs): def notification(self, inboundMessage): #self.rx_can_message_queue.put(inboundMessage) if self.can_notifier._running is False: - logger.info('Aborting message %s bus is not running', inboundMessage) + logger.info('{}: Aborting message {} bus is not running'.format(inspect.stack()[0][3], inboundMessage)) + # Should I return or throw exception here. + if isinstance(inboundMessage, Message): - logger.info('\n\nnotification: Got a Message from CAN: %s' % inboundMessage) + logger.info('\n\n{}: Got a Message from CAN: {}'.format(inspect.stack()[0][3],inboundMessage)) if inboundMessage.id_type: # Extended ID # Only J1939 messages (i.e. 29-bit IDs) should go further than this point. # Non-J1939 systems can co-exist with J1939 systems, but J1939 doesn't care # about the content of their messages. - logger.debug('notification: Message is j1939 msg') + logger.info('{}: Message is j1939 msg'.format(inspect.stack()[0][3])) # - # Need to determine if it's a broadcase message or + # Need to determine if it's a broadcast message or # limit to listening nodes only # arbitration_id = ArbitrationID() arbitration_id.can_id = inboundMessage.arbitration_id - logger.debug('notification: ArbitrationID = %s' % (arbitration_id)) + logger.info("{}: ArbitrationID = {}, inboundMessage.arbitration_id: 0x{:08x}".format(inspect.stack()[0][3],arbitration_id, inboundMessage.arbitration_id)) for (node, l_notifier) in self.node_queue_list: logger.debug("notification: node=%s" % (node)) @@ -197,24 +199,25 @@ def notification(self, inboundMessage): # redirect the AC stuff to the node processors. the rest can go # to the main queue. if node and (arbitration_id.pgn in [PGN_AC_ADDRESS_CLAIMED, PGN_AC_COMMANDED_ADDRESS, PGN_REQUEST_FOR_PGN]): - logger.info("notification: sending to notifier queue") + logger.info("{}: sending to notifier queue".format(inspect.stack()[0][3])) # send the PDU to the node processor. l_notifier.queue.put(inboundMessage) # if node has the destination address, do something with the PDU elif node and (arbitration_id.destination_address in node.address_list): + logger.info("{}: sending to process_incoming_message".format(inspect.stack()[0][3])) rx_pdu = self._process_incoming_message(inboundMessage) if rx_pdu: logger.info("WP02: notification: sent to general queue: %s QQ=%s" % (rx_pdu, self.queue)) self.queue.put(rx_pdu) elif node and (arbitration_id.destination_address is None): - logger.info("notification: sending broadcast to general queue") + logger.info("{}: sending broadcast to general queue".format(inspect.stack()[0][3])) rx_pdu = self._process_incoming_message(inboundMessage) logger.info("WP01: notification: sent broadcast to general queue: %s QQ=%s" % (rx_pdu, self.queue)) self.queue.put(rx_pdu) elif node is None: # always send the message to the logging queue - logger.info("notification: sending to general queue") + logger.info("{}: sending to general queue".format(inspect.stack()[0][3])) rx_pdu = self._process_incoming_message(inboundMessage) logger.info("WP03: notification: sent pdu [%s] to general queue" % rx_pdu) self.queue.put(rx_pdu) @@ -450,7 +453,7 @@ def _send_key_response(self, pdu): return None def _process_incoming_message(self, msg): - logger.info("PI01: Processing incoming message: instance=%s\n msg= %s" % (self, msg)) + logger.info("PI01: Processing incoming message: instance={}, msg= {}".format(self, msg)) arbitration_id = ArbitrationID() arbitration_id.can_id = msg.arbitration_id if arbitration_id.pgn.is_destination_specific: @@ -476,7 +479,7 @@ def _process_incoming_message(self, msg): logger.info("PGN_TP_SEED_REQUEST") retval = self._send_key_response(pdu) else: - logger.info("PGN_PDU") + logger.info("PGN_PDU generic") retval = pdu logger.info("_process_incoming_message: returning %s" % (retval)) diff --git a/j1939/arbitrationid.py b/j1939/arbitrationid.py index 31cc419..1c55ad9 100644 --- a/j1939/arbitrationid.py +++ b/j1939/arbitrationid.py @@ -1,9 +1,11 @@ import logging +import inspect + from j1939.pgn import PGN from j1939.constants import * import logging -logger = logging.getLogger(__name__) +logger = logging.getLogger("j1939") class ArbitrationID(object): @@ -59,10 +61,10 @@ def __init__(self, priority=7, pgn=None, source_address=0, destination_address=N @property def can_id(self): - logger.debug("can_id property: self._pgn.is_destination_specific={}/pgn={}".format(self._pgn.is_destination_specific, self._pgn)) + logger.info("{} property: self._pgn.is_destination_specific={}/pgn={}".format(inspect.stack()[0][3], self._pgn.is_destination_specific, self._pgn)) if self._pgn.is_destination_specific: - logger.debug("can_id: self._pgn.is_destination_specific, dest={}, pgn_value={}, pdu_format=0x{:04x}, pdu_specific=0x{:02x}, pri={}".format( + logger.info("can_id: self._pgn.is_destination_specific, dest={}, pgn_value={}, pdu_format=0x{:04x}, pdu_specific=0x{:02x}, pri={}".format( self.destination_address_value, self._pgn.value, self._pgn.pdu_format, @@ -70,22 +72,22 @@ def can_id(self): self.priority)) if self.destination_address_value: - logger.debug("can_id: self.destination_address_value: pgn_value: {:04x}".format(self._pgn.value)) - logger.debug(" (self._pgn.value & 0x3ff00): {:04x}".format((self._pgn.value & 0x3ff00))) - logger.debug(" (self.destination_address_value): {:04x}".format((self.destination_address_value))) + logger.info("can_id: self.destination_address_value: pgn_value: {:04x}".format(self._pgn.value)) + logger.info(" (self._pgn.value & 0x3ff00): {:04x}".format((self._pgn.value & 0x3ff00))) + logger.info(" (self.destination_address_value): {:04x}".format((self.destination_address_value))) retval = (self.source_address + ((self._pgn.value & 0x3ff00) + (self.destination_address_value) << 8) + (self.priority << 26)) else: - logger.debug("can_id: NOT self.destination_address_value:") + logger.info("can_id: NOT self.destination_address_value:") retval = (self.source_address + ((self._pgn.value & 0x3ff00) << 8)+ (self.priority << 26)) - logger.debug("can_id: retval=0x{:08x}".format(retval)) + logger.info("can_id: retval=0x{:08x}".format(retval)) return retval else: - logger.debug("can_id: NOT! self._pgn.is_destination_specific") + logger.info("can_id: NOT! self._pgn.is_destination_specific") return (self.source_address + (self._pgn.value << 8) + (self.priority << 26)) @can_id.setter @@ -93,16 +95,16 @@ def can_id(self, canid): """ Int between 0 and (2**29) - 1 """ - logger.debug("can_id setter: canid=0x%08x" % (canid)) + logger.info("{} setter: canid=0x{:08x}".format(inspect.stack()[0][3], canid)) self.priority = (canid & 0x1C000000) >> 26 self._pgn = PGN().from_can_id(canid) self.source_address = canid & 0x000000FF if self._pgn.is_destination_specific: - self.destination_address_value = (canid & 0x0003FF00) >> 8 + self.destination_address_value = (canid & 0x0000FF00) >> 8 - logger.debug("can_id: canid=0x%08x, priority=%x, pdu_format=%x, pdu_specific=%x, src=%x" % - (canid, + logger.info("{} setter: canid=0x{:08x}, priority={:x}, pdu_format={:x}, pdu_specific={:x}, src={:x}".format(inspect.stack()[0][3], + canid, self.priority, self._pgn.pdu_format, self._pgn.pdu_specific, diff --git a/j1939/node.py b/j1939/node.py index c56e5dd..9ef56d8 100644 --- a/j1939/node.py +++ b/j1939/node.py @@ -1,14 +1,11 @@ import logging -log = logging.getLogger('py1939.node') -log.debug('Loading J1939 node') - from can import Listener, CanError from j1939.constants import * from j1939.pdu import PDU from j1939.nodename import NodeName -logger = logging.getLogger(__name__) +logger = logging.getLogger("j1939") logger.debug("loading %s", __name__) @@ -58,11 +55,11 @@ def addressList(self): return self.address_list def start_address_claim(self): - logging.debug("start_address_claim:") + logger.debug("start_address_claim:") self.claim_address(self.address_list[self._current_address_index]) def claim_address(self, address): - logging.debug("claim_address:") + logger.debug("claim_address:") claimed_address_pdu = self._pdu_type() claimed_address_pdu.arbitration_id.pgn.value = PGN_AC_ADDRESS_CLAIMED claimed_address_pdu.arbitration_id.priority = 4 @@ -72,13 +69,12 @@ def claim_address(self, address): claimed_address_pdu.data = self.node_name.bytes self.known_node_addresses[self.node_name.value] = address - log.info('MIL:') - log.info('claimed_address_pdu: %s' % claimed_address_pdu) + logger.info('claimed_address_pdu: %s' % claimed_address_pdu) self.bus.send(claimed_address_pdu) def on_message_received(self, pdu): if pdu.pgn == PGN_AC_ADDRESS_CLAIMED: - log.debug('got PGN_AC_ADDRESS_CLAIMED pdu') + logger.debug('got PGN_AC_ADDRESS_CLAIMED pdu') if pdu.source != DESTINATION_ADDRESS_NULL: if pdu.data != self.node_name.bytes: if pdu.source != self.address: @@ -101,7 +97,7 @@ def on_message_received(self, pdu): node_name.bytes = pdu.data self.known_node_addresses[node_name.value] = pdu.source elif pdu.pgn == PGN_AC_COMMANDED_ADDRESS: - log.debug('got PGN_AC_COMMANDED_ADDRESS pdu') + logger.debug('got PGN_AC_COMMANDED_ADDRESS pdu') node_name = NodeName() node_name.bytes = pdu.data[:8] new_address = pdu.data[8] @@ -109,7 +105,7 @@ def on_message_received(self, pdu): # if we are the commanded node change our address self.claim_address(new_address) elif pdu.pgn == PGN_REQUEST_FOR_PGN: - log.debug('got PGN_REQUEST_FOR_PGN pdu') + logger.debug('got PGN_REQUEST_FOR_PGN pdu') pgn = int("%.2X%.2X%.2X" % (pdu.data[2], pdu.data[1], pdu.data[0]), 16) if pdu.destination in (self.address, DESTINATION_ADDRESS_GLOBAL): if pgn == PGN_AC_ADDRESS_CLAIMED: @@ -126,10 +122,10 @@ def send_parameter_group(self, pgn, data, destination_device_name=None): :param destination_device_name: Should be None, or an int between 0 and (2 ** 64) - 1 """ - log.debug('send_parameter_group:') + logger.debug('send_parameter_group:') # if we are *allowed* to send data if self.known_node_addresses[self.node_name.value] not in (ADDRESS_UNCLAIMED, DESTINATION_ADDRESS_NULL): - log.debug('send_parameter_group: claimed address') + logger.debug('send_parameter_group: claimed address') pdu = self._pdu_type() pdu.arbitration_id.pgn.value = pgn pdu.arbitration_id.source_address = self.known_node_addresses[self.node_name.value] diff --git a/j1939/notifier.py b/j1939/notifier.py index 698f0d1..bfc3bc4 100644 --- a/j1939/notifier.py +++ b/j1939/notifier.py @@ -12,7 +12,7 @@ #same as a CAN Notifier but will listen to a queue #recv function. -logger = logging.getLogger(__name__) +logger = logging.getLogger("j1939") class Notifier(object): diff --git a/j1939/pdu.py b/j1939/pdu.py index c495f42..f688857 100644 --- a/j1939/pdu.py +++ b/j1939/pdu.py @@ -5,7 +5,7 @@ from .constants import pgn_strings, PGN_AC_ADDRESS_CLAIMED from .nodename import NodeName -logger = logging.getLogger(__name__) +logger = logging.getLogger("j1939") RADIX_DECIMAL=10 RADIX_HEX=16 diff --git a/j1939/pgn.py b/j1939/pgn.py index fe772d0..d9855c0 100644 --- a/j1939/pgn.py +++ b/j1939/pgn.py @@ -1,8 +1,7 @@ import logging -logger = logging.getLogger(__name__) - - +import inspect +logger = logging.getLogger("j1939") class PGN(object): @@ -56,16 +55,20 @@ def from_value(pgn_value): @staticmethod def from_can_id(canid): - #logger.debug("PGN.@from_can_id, value=0x%08x" % (canid)) + logger.info("{} staticmethod: canid=0x{:08x}".format(inspect.stack()[0][3], canid)) canid = canid>>8 pgn = PGN() - #logger.debug("PGN.@from_can_id, value=0x%08x" % (canid)) + pgn.reserved_flag = (canid & 0x080000) >> 17 pgn.data_page_flag = (canid & 0x040000) >> 16 pgn.pdu_format = (canid & 0x03FF00) >> 8 pgn.pdu_specific = canid & 0x0000FF - logger.debug("PGN.@from_can_id, res=%d, dp=%d, pdu_format=0x%02x, pdu_specific=0x%02x" % - (pgn.reserved_flag, pgn.data_page_flag, pgn.pdu_format, pgn.pdu_specific)) + logger.info("{} staticmethod: PGN Creation, res={}, dp={}, pdu_format=0x{:02x}, pdu_specific=0x{:02x}".format(inspect.stack()[0][3], + pgn.reserved_flag, + pgn.data_page_flag, + pgn.pdu_format, + pgn.pdu_specific)) + return pgn def __str__(self): diff --git a/j1939/utils.py b/j1939/utils.py index 0bd5522..fa90a1b 100644 --- a/j1939/utils.py +++ b/j1939/utils.py @@ -1,9 +1,10 @@ from __future__ import print_function import j1939 import logging +import inspect import sys -logger = logging.getLogger(__name__) +logger = logging.getLogger("j1939") # # for responding to seed/key requests provide your own keyGenerator # class.. @@ -64,8 +65,12 @@ def set_mem_object(pointer, extension, value, channel='can0', bustype='socketcan node = j1939.Node(bus, j1939.NodeName(), [src]) bus.connect(node) close = True + + pLow = pointer & 0x0000FF + pMid = (pointer >> 8) & 0x0000FF + pHigh = (pointer >> 16) & 0x0000FF - dm14data = [length, 0x15, pointer, 0x00, 0x00, extension, 0xff, 0xff] + dm14data = [length, 0x15, pLow, pMid, pHigh, extension, 0xff, 0xff] dm14pgn = j1939.PGN(pdu_format=0xd9, pdu_specific=dest) dm14aid = j1939.ArbitrationID(pgn=dm14pgn, source_address=src, destination_address=dest) @@ -142,6 +147,7 @@ def set_mem_object(pointer, extension, value, channel='can0', bustype='socketcan return result def get_mem_object(pointer, extension, channel='can0', bustype='socketcan', length=4, src=0, dest=0x17, bus=None, speed=250, timeout=10): + logger.info("{}: begin".format(inspect.stack()[0][3])) countdown = timeout result = None close = False @@ -151,6 +157,7 @@ def get_mem_object(pointer, extension, channel='can0', bustype='socketcan', leng node = j1939.Node(bus, j1939.NodeName(), [src]) bus.connect(node) close = True + pgn = j1939.PGN() pgn.value = 0xd900 + dest # Request a DM14 mem-object aid = j1939.ArbitrationID(pgn=pgn, source_address=src, destination_address=dest) @@ -164,10 +171,16 @@ def get_mem_object(pointer, extension, channel='can0', bustype='socketcan', leng pdu = j1939.PDU(timestamp=0.0, arbitration_id=aid, data=data, info_strings=None) assert(pdu != None) pdu.display_radix='hex' + logger.info("{}: Sending Request PDU: {}".format(inspect.stack()[0][3], pdu)) bus.send(pdu) + + # + # Wait for the response + # while countdown: pdu = bus.recv(timeout=1) if pdu is not None: + logger.info("{}: Received PDU: {}".format(inspect.stack()[0][3], pdu)) logger.info(pdu) if pdu.pgn == 0xd700: value = list(pdu.data) @@ -180,12 +193,21 @@ def get_mem_object(pointer, extension, channel='can0', bustype='socketcan', leng result = (value[4] << 24) + (value[3] << 16) + (value[2] << 8) + value[1] else: result = value[1:] + + #logger.info("{}: d700 received, result: {}/0x{:08x}".format(inspect.stack()[0][3], result, result)) + break # got what I was waiting for + countdown -= 1 + if close: + logger.info("{}: Closing Bus".format(inspect.stack()[0][3])) bus.shutdown() + if result is None: raise IOError(" no CAN response") + + return result def request_pgn(requested_pgn, channel='can0', speed=250, bustype='socketcan', length=4, src=0, dest=0x17, bus=None, timeout=10): From d76df50c6733c88d89f862d00a0f28be758f147b Mon Sep 17 00:00:00 2001 From: Miller Lowe Date: Tue, 12 Jul 2022 16:47:16 -0700 Subject: [PATCH 77/80] Updated a missing element of the 18-bit PGN work. The PGN for a D400 (Security) PGN was not being truncated to 18 bits which would cause the protocol engine to not recognize it as a security challenge. --- j1939/pgn.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/j1939/pgn.py b/j1939/pgn.py index d9855c0..24611c1 100644 --- a/j1939/pgn.py +++ b/j1939/pgn.py @@ -27,13 +27,18 @@ def is_pdu2(self): @property def is_destination_specific(self): result = self.is_pdu1 - logger.debug("PGN is_destination_specific {:04x}: {}".format(self.value, result)) + logger.debug(f"PGN is_destination_specific {self.value:04x}: {result}") return result @property def value(self): _pgn_flags_byte = ((self.reserved_flag << 1) + self.data_page_flag) - return int("%.2x%.2x%.2x" % (_pgn_flags_byte, self.pdu_format, self.pdu_specific), 16) + # + # Be sure to truncate the PGN at 18 bits + # + result = int("%.2x%.2x%.2x" % (_pgn_flags_byte & 0x03, self.pdu_format, self.pdu_specific), 16) + logger.debug(f"value-result = {result:06x}") + return result @value.setter def value(self, value): From ba859a2f41f6a2190e7ff1b9e37f968b0c64cfd9 Mon Sep 17 00:00:00 2001 From: Brent Earl Date: Mon, 6 Feb 2023 08:46:02 -0700 Subject: [PATCH 78/80] fix 16 and 18 bit masking --- j1939/pgn.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/j1939/pgn.py b/j1939/pgn.py index 24611c1..4305ffc 100644 --- a/j1939/pgn.py +++ b/j1939/pgn.py @@ -42,9 +42,9 @@ def value(self): @value.setter def value(self, value): - self.reserved_flag = (value & 0x080000) >> 17 - self.data_page_flag = (value & 0x040000) >> 16 - self.pdu_format = (value & 0x03FF00) >> 8 + self.reserved_flag = (value & 0x020000) >> 17 + self.data_page_flag = (value & 0x010000) >> 16 + self.pdu_format = (value & 0x00FF00) >> 8 self.pdu_specific = value & 0x0000FF #MIL logger.debug("PGN.@valueSetter, value=0x%08x, pdu_format=0x%08x" % (value, self.pdu_format)) @@ -52,9 +52,9 @@ def value(self, value): def from_value(pgn_value): logger.debug("PGN.@from_value, pgn_value=0x%08x" % (pgn_value)) pgn = PGN() - pgn.reserved_flag = (pgn_value & 0x080000) >> 17 - pgn.data_page_flag = (pgn_value & 0x040000) >> 16 - pgn.pdu_format = (pgn_value & 0x03FF00) >> 8 + pgn.reserved_flag = (pgn_value & 0x020000) >> 17 + pgn.data_page_flag = (pgn_value & 0x010000) >> 16 + pgn.pdu_format = (pgn_value & 0x00FF00) >> 8 pgn.pdu_specific = pgn_value & 0x0000FF return pgn @@ -64,9 +64,9 @@ def from_can_id(canid): canid = canid>>8 pgn = PGN() - pgn.reserved_flag = (canid & 0x080000) >> 17 - pgn.data_page_flag = (canid & 0x040000) >> 16 - pgn.pdu_format = (canid & 0x03FF00) >> 8 + pgn.reserved_flag = (canid & 0x020000) >> 17 + pgn.data_page_flag = (canid & 0x010000) >> 16 + pgn.pdu_format = (canid & 0x00FF00) >> 8 pgn.pdu_specific = canid & 0x0000FF logger.info("{} staticmethod: PGN Creation, res={}, dp={}, pdu_format=0x{:02x}, pdu_specific=0x{:02x}".format(inspect.stack()[0][3], pgn.reserved_flag, From 36c1b81171b203fa373dfd8737112c79953ee915 Mon Sep 17 00:00:00 2001 From: Peter Parks Date: Fri, 25 Aug 2023 09:48:49 -0700 Subject: [PATCH 79/80] changes for allowing j1939 to work with Python 3.11 Had to change the mesage - id_type to is_extended_id, also had to had bustype to mem_set and mem_query. Removed sys.plaform == 'win32' now that we have the bustype, this allows us to use the same bus methods. --- bin/j1939_mem_query.py | 18 ++++++++++++------ bin/j1939_mem_set.py | 5 +++-- j1939/__init__.py | 16 ++++++++-------- j1939/utils.py | 26 ++++++++------------------ 4 files changed, 31 insertions(+), 34 deletions(-) diff --git a/bin/j1939_mem_query.py b/bin/j1939_mem_query.py index 4695f12..e14931f 100644 --- a/bin/j1939_mem_query.py +++ b/bin/j1939_mem_query.py @@ -15,13 +15,14 @@ import j1939.utils if __name__ == "__main__": - import traceback - import timeit - import time + # import traceback + # import timeit + # import time + # import textwrap + # import inspect import argparse import logging - import textwrap - import inspect + if __name__ == "__main__": @@ -60,6 +61,10 @@ parser.add_argument("-c", "--channel", default="can0", help="Memory object pointer offset to request in decimal or 0xHex") + + parser.add_argument("-b", "--bustype", + default="socketcan", + help="This depends on the channel for pcan use PCAN_USBBUS1") parser.add_argument("extension", default=None, @@ -96,9 +101,10 @@ ext = int(args.extension, 0) speed = int(args.speed, 0) channel = args.channel + bustype = args.bustype logging.info ("get_mem_object_single(src=0x%02x, dest=0x%02x, pointer=0x%02x, extension/space=0x%02x, len=%d" % (source, dest, ptr, ext, length)) - val = j1939.utils.get_mem_object(ptr, ext, length=length, src=source, dest=dest, channel=channel, speed=speed) + val = j1939.utils.get_mem_object(ptr, ext, length=length, src=source, dest=dest, channel=channel, bustype=bustype, speed=speed) print("{}".format(val)) out = '' if isinstance(val, list): diff --git a/bin/j1939_mem_set.py b/bin/j1939_mem_set.py index 8b1f5a0..6cf2381 100644 --- a/bin/j1939_mem_set.py +++ b/bin/j1939_mem_set.py @@ -54,7 +54,8 @@ parser.add_argument("-t", "--timeout", default="1000", help="ms before the request times out (default=1000 or 1s)") parser.add_argument("-s", "--source", default="0", help="source address (0-254) default=0") parser.add_argument("-d", "--destination", default="0x17", help="destination address (0-254) default=17") - parser.add_argument("-c", "--channel", default="can0", help="Generally can0 on workstations or can1 on bbb/pbb targets") + parser.add_argument("-c", "--channel", default="can0", help="Generally can0 or PCAN_USBBUS1 on workstations or can1 on bbb/pbb targets") + parser.add_argument("-b", "--bustype", default="socketcan", help="channel bus type i.e. socketcan, pcan") parser.add_argument("-r", "--robot", action="store_true", default=False, help="provide parsable result data to aid robot testing") parser.add_argument("-v", "--verbose", action="store_true", default=False, help="Generate debugging output") parser.add_argument( "--string", action="store_true", default=False, help="Treat an integer parameter as a string") @@ -133,7 +134,7 @@ # queries a couple objects but setting up the full stack and bus for # each takes a long time. start = timeit.default_timer() - val = j1939.utils.set_mem_object(ptr, ext, value, speed=args.speed, channel=args.channel, length=length, src=src, dest=dest, timeout=timeout) + val = j1939.utils.set_mem_object(ptr, ext, value, speed=args.speed, channel=args.channel, bustype=args.bustype, length=length, src=src, dest=dest, timeout=timeout) #set_mem_object_single(length=1, src=0, dest=0x17, pointer=0x66, extension=0xea, value=127) print("elapsed = %s s" % (timeit.default_timer() - start)) print("return val = {}".format(int(val!=1))) diff --git a/j1939/__init__.py b/j1939/__init__.py index 6de336e..d2d8c29 100644 --- a/j1939/__init__.py +++ b/j1939/__init__.py @@ -175,7 +175,7 @@ def notification(self, inboundMessage): if isinstance(inboundMessage, Message): logger.info('\n\n{}: Got a Message from CAN: {}'.format(inspect.stack()[0][3],inboundMessage)) - if inboundMessage.id_type: + if inboundMessage.is_extended_id: # Extended ID # Only J1939 messages (i.e. 29-bit IDs) should go further than this point. # Non-J1939 systems can co-exist with J1939 systems, but J1939 doesn't care @@ -302,7 +302,7 @@ def send(self, msg, timeout=None): logger.info("MIL8: j1939.send: segment=%d, arb = %s" % (i, arbitration_id)) message = Message(arbitration_id=arbitration_id.can_id, - extended_id=True, + is_extended_id=True, dlc=(len(segment) + 1), data=(bytearray([i + 1]) + segment)) messages.append(message) @@ -346,7 +346,7 @@ def send(self, msg, timeout=None): pdu.arbitration_id.destination_address != DESTINATION_ADDRESS_GLOBAL: # send request to send logger.debug("MIL8: rts to specific dest: src=%s, dest=%s" % (pdu.source, destination_address)) - rts_msg = Message(extended_id=True, + rts_msg = Message(is_extended_id=True, arbitration_id=rts_arbitration_id.can_id, data=[CM_MSG_TYPE_RTS, pdu_length_msb, @@ -368,7 +368,7 @@ def send(self, msg, timeout=None): rts_arbitration_id.pgn.pdu_specific = DESTINATION_ADDRESS_GLOBAL rts_arbitration_id.destination_address = DESTINATION_ADDRESS_GLOBAL logger.debug("MIL8: rts to Global dest: src=%s, dest=%s" % (pdu.source, destination_address)) - bam_msg = Message(extended_id=True, + bam_msg = Message(is_extended_id=True, arbitration_id=rts_arbitration_id.can_id | pdu.source, data=[CM_MSG_TYPE_BAM, pdu_length_msb, @@ -399,7 +399,7 @@ def send(self, msg, timeout=None): msg.display_radix = 'hex' logger.debug("j1939.send: calling can_bus_send: j1939-msg: {}, arb-id: {:08x}".format(msg, msg.arbitration_id.can_id)) can_message = Message(arbitration_id=msg.arbitration_id.can_id, - extended_id=True, + is_extended_id=True, dlc=len(msg.data), data=msg.data) @@ -561,7 +561,7 @@ def _data_transfer_handler(self, msg): ()) div, mod = divmod(total_length, 256) can_message = Message(arbitration_id=arbitration_id.can_id, - extended_id=True, + is_extended_id=True, dlc=8, data=[CM_MSG_TYPE_EOM_ACK, mod, # total_length % 256, @@ -654,7 +654,7 @@ def _process_rts(self, msg): _data = [0x11, msg.data[4], 0x01, 0xFF, 0xFF] _data.extend(msg.data[5:]) logger.debug("send CTS: AID: %s" % _cts_arbitration_id) - cts_msg = Message(extended_id=True, arbitration_id=_cts_arbitration_id.can_id, data=_data, + cts_msg = Message(is_extended_id=True, arbitration_id=_cts_arbitration_id.can_id, data=_data, dlc=8) # send clear to send @@ -683,7 +683,7 @@ def _process_rts(self, msg): _data = [0x11, msg.data[4], 0x01, 0xFF, 0xFF] _data.extend(msg.data[5:]) logger.debug("send CTS: AID: %s" % _cts_arbitration_id) - cts_msg = Message(extended_id=True, arbitration_id=_cts_arbitration_id.can_id, data=_data, + cts_msg = Message(is_extended_id=True, arbitration_id=_cts_arbitration_id.can_id, data=_data, dlc=8) # send clear to send diff --git a/j1939/utils.py b/j1939/utils.py index fa90a1b..e04b659 100644 --- a/j1939/utils.py +++ b/j1939/utils.py @@ -53,18 +53,11 @@ def set_mem_object(pointer, extension, value, channel='can0', bustype='socketcan # only watch for the memory object pgn's filt = [{'pgn':0xd800, 'source':dest},{'pgn':0xd400, 'source':dest}] - if sys.platform == 'win32': - if bus is None: - bus = j1939.Bus(timeout=0.01, keygen=keygetFunction, broadcast=None, name='j1939StartGeneral', ignoreCanSendError=True, j1939_filters=filt) - node = j1939.Node(bus, j1939.NodeName(), [src]) - bus.connect(node) - close = True - else: - if bus is None: - bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01, keygen=keygetFunction, broadcast=False, j1939_filters=filt) - node = j1939.Node(bus, j1939.NodeName(), [src]) - bus.connect(node) - close = True + if bus is None: + bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01, keygen=keygetFunction, broadcast=False, j1939_filters=filt) + node = j1939.Node(bus, j1939.NodeName(), [src]) + bus.connect(node) + close = True pLow = pointer & 0x0000FF pMid = (pointer >> 8) & 0x0000FF @@ -77,7 +70,6 @@ def set_mem_object(pointer, extension, value, channel='can0', bustype='socketcan dm14pdu = j1939.PDU(timestamp=0.0, arbitration_id=dm14aid, data=dm14data, info_strings=None) dm14pdu.display_radix='hex' - bus.send(dm14pdu) sendBuffer = [] @@ -223,9 +215,7 @@ def request_pgn(requested_pgn, channel='can0', speed=250, bustype='socketcan', l if not isinstance(requested_pgn, int): raise ValueError("pgn must be an integer.") -# if bus is None: -# bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01) -# close = True + if bus is None: bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01, keygen=keygetFunction, broadcast=False) node = j1939.Node(bus, j1939.NodeName(), [src]) @@ -271,6 +261,7 @@ def request_pgn(requested_pgn, channel='can0', speed=250, bustype='socketcan', l def send_pgn(requested_pgn, data, channel='can0', speed=250, bustype='socketcan', length=4, src=0, dest=0x17, bus=None, timeout=10): countdown = timeout result = None + close = False keygetFunction = None if speed == 250: @@ -283,8 +274,7 @@ def send_pgn(requested_pgn, data, channel='can0', speed=250, bustype='socketcan' if bus is None: bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01, keygen=keygetFunction) close = True - else: - close = False + pgn = j1939.PGN() if requested_pgn < 0xf000: requested_pgn |= dest From bd915f1b4f7774f618cdd09a52ef83503bed741b Mon Sep 17 00:00:00 2001 From: Peter Parks Date: Fri, 15 Sep 2023 14:05:17 -0700 Subject: [PATCH 80/80] updated fix that allows Windows to support 250 CAN speed updated fix that allows Windows to support 250 CAN speed, the issue was BusABC defaults 500000 bitrate and we don't have the override parameter set for what we want the speed and Bitrate to be. I added the following to the function calls j1939.Bus(channel=channel, bustype=bustype, timeout=0.01, speed=speed, bitrate=(int(speed)*1000), keygen=keygetFunction, broadcast=False) --- j1939/utils.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/j1939/utils.py b/j1939/utils.py index e04b659..b1750a4 100644 --- a/j1939/utils.py +++ b/j1939/utils.py @@ -54,7 +54,7 @@ def set_mem_object(pointer, extension, value, channel='can0', bustype='socketcan filt = [{'pgn':0xd800, 'source':dest},{'pgn':0xd400, 'source':dest}] if bus is None: - bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01, keygen=keygetFunction, broadcast=False, j1939_filters=filt) + bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01, keygen=keygetFunction, speed=speed, bitrate=(int(speed)*1000), broadcast=False, j1939_filters=filt) node = j1939.Node(bus, j1939.NodeName(), [src]) bus.connect(node) close = True @@ -73,10 +73,6 @@ def set_mem_object(pointer, extension, value, channel='can0', bustype='socketcan bus.send(dm14pdu) sendBuffer = [] - #sendBuffer.append(length) - #for i in range(0, length): - # sendBuffer.append(0) - logger.info("---------------## length=%d, value=%s " % (length, value)) if isinstance(value, int) and length < 8: logger.info("-----value") @@ -145,7 +141,7 @@ def get_mem_object(pointer, extension, channel='can0', bustype='socketcan', leng close = False if bus is None: - bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01, broadcast=False) + bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01, speed=speed, bitrate=(int(speed)*1000), broadcast=False) node = j1939.Node(bus, j1939.NodeName(), [src]) bus.connect(node) close = True @@ -217,7 +213,7 @@ def request_pgn(requested_pgn, channel='can0', speed=250, bustype='socketcan', l raise ValueError("pgn must be an integer.") if bus is None: - bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01, keygen=keygetFunction, broadcast=False) + bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01, speed=speed, bitrate=(int(speed)*1000), keygen=keygetFunction, broadcast=False) node = j1939.Node(bus, j1939.NodeName(), [src]) bus.connect(node) close = True @@ -272,7 +268,7 @@ def send_pgn(requested_pgn, data, channel='can0', speed=250, bustype='socketcan' if not isinstance(requested_pgn, int): raise ValueError("pgn must be an integer.") if bus is None: - bus = j1939.Bus(channel=channel, bustype=bustype, timeout=0.01, keygen=keygetFunction) + bus = j1939.Bus(channel=channel, bustype=bustype, speed=speed, bitrate=(int(speed)*1000), timeout=0.01, keygen=keygetFunction) close = True pgn = j1939.PGN()