Module:digicanbus

From Digi Developer

Jump to: navigation, search

Contents

digicanbus.py

This module was designed in conjunction with the Digi ConnectPort X5, the first Digi Python-enabled product to offer CAN bus connectivity. The module is designed to allow scripts to manipulate CAN messages at a logical level, with the embedded operating system providing support for the encoding/decoding of messages on the line.

Limited J1939 support is also provided, in order to simplify the interpretation of CAN messages as J1939 PDUs. Knowledge of individual PDU encodings is application specific, and must be supplied by the script.

Module help

Help on built-in module digicanbus:

NAME

   digicanbus - Provides Python abstraction for an underlying CAN controller

FILE

   (built-in)

DESCRIPTION

   The CANHandle class provides functions to initialize a CAN bus and
   transfer raw CAN messages.  It also provides functions to communicate
   over the CAN bus via the abstraction of the SAE J1939 protocol.
   
   The J1939_PDU class provides methods to convert raw CAN identifiers
   into SAE J1939 identifier fields and vice-versa.  When using the SAE J1939
   abstraction, this class is used directly to represent input and output
   messages.  The class can also be used, however, to transmit and receive
   SAE J1939 messages using the raw CAN interface.

CLASSES

   __builtin__.object
       CANHandle
       J1939_PDU
   
   class CANHandle(__builtin__.object)
    |  Provides a programming interface to an underlying CAN controller
    |  
    |  Instantiating a CANHandle associates a set of methods with an internal
    |  CAN bus instance.  The methods allow one to request configuration of the
    |  bus, register message filters and receive callbacks, and submit messages
    |  for transmission.
    |  
    |  CANHandle objects are instantiated with a single "can_bus_id" argument,
    |  which is an integer identifier for the desired CAN bus.
    |  
    |  Methods defined here:
    |  
    |  __init__(...)
    |      x.__init__(...) initializes x; see x.__class__.__doc__ for signature
    |  
    |  configure(...)
    |      configure([options]) -> None
    |      
    |      The CAN bus will be stopped if running, configuration parameters
    |      will be applied, and the bus will be reinitialized.
    |      
    |      With no arguments, the current configuration will be re-applied.
    |      
    |      Option Arguments:
    |      
    |      bitrate=n -- 'n' defaults to 250000, with a maximum of 1000000
    |  
    |  register_filter(...)
    |      register_filter(width, identifier, mask, method, return_arg) -> None
    |      
    |      Ask bus to accept and deliver messages matching filter via method
    |      
    |      Associate a filter with a reception method function and a return
    |      argument.  Only a single copy of each unique set is stored
    |      internally.  The registration is with the underlying bus
    |      instance, not with the handle.
    |      
    |      The mask parameter must be of the same form as the
    |      identifier, and indicates which bits in the identifier are
    |      significant for matching.
    |      
    |      The method must be a callable object of the form:
    |      
    |      method(width, identifier, remote_frame, payload, return_arg)
    |      
    |      The "return_arg" argument is not examined by the bus
    |      infrastructure.
    |      
    |      An exception is raised if the number of filters is exceeded.
    |      
    |      NOTE: The callback method will be executed in another thread.
    |      Shared data will need to be protected from race conditions due
    |      to concurrent access.
    |  
    |  send(...)
    |      send(width, identifier, remote_frame, payload) -> True | False
    |      
    |      Non-blocking transmit of a message on the CAN bus.
    |      
    |      Arguments:
    |      width -- 11 or 29, referring to the bits in the CAN identifier
    |      identifier -- 11 or 29 bit integer value
    |      remote_frame -- True or False to indicate a remote or data frame.
    |      payload -- If a remote frame, payload is an integer count of the
    |                 expected bytes.  If a data frame, payload is a string
    |                 of length 0 - 8 of the bytes to be transmitted.
    |      
    |      Return Value:
    |      The function will return a true value if the message was
    |      successfully queued, and false if there is no queue space.
    |  
    |  unregister_filter(...)
    |      unregister_filter(width, identifier, mask, method, return_arg) -> None
    |      
    |      Remove filter/method/argument pairing from the bus filter list
    |      
    |      The filter list of the bus is searched for a match of the same
    |      calling parameters.  If a match is found, that registration is
    |      removed from the list.  If no match is found, an exception is
    |      raised.
    |  
    |  ----------------------------------------------------------------------
    |  Data and other attributes defined here:
    |  
    |  __new__ = <built-in method __new__ of type object>
    |      T.__new__(S, ...) -> a new object with type S, a subtype of T
   
   class J1939_PDU(__builtin__.object)
    |  Provides a means to map J1939 PDU fields to a CAN identifier
    |  
    |  J1939_PDU objects are instantiated with no parameters (creating
    |  a template PDU), or with a tuple representing a CAN message:
    |    (width, identifier, remote_frame, payload)
    |  Some fields overlap, per the J1939 specification.  Manipulation of
    |  (for instance) the PGN field modifies most of the fields at once.
    |  
    |  Methods defined here:
    |  
    |  CANMsgTuple(...)
    |      CANMsgTuple() -> (width, identifier, remote_frame, payload)
    |  
    |  PDU1Check(...)
    |      PDU1Check() -> a true value if PDU is in PDU1 format
    |  
    |  PDU2Check(...)
    |      PDU2Check() -> a true value if PDU is in PDU2 format
    |  
    |  __init__(...)
    |      x.__init__(...) initializes x; see x.__class__.__doc__ for signature
    |  
    |  ----------------------------------------------------------------------
    |  Data and other attributes defined here:
    |  
    |  DA = <attribute 'DA' of 'digicanbus.J1939_PDU' objects>
    |      Destination Address (PDU1 format)
    |  
    |  DP = <attribute 'DP' of 'digicanbus.J1939_PDU' objects>
    |      Data Page
    |  
    |  EDP = <attribute 'EDP' of 'digicanbus.J1939_PDU' objects>
    |      Extended Data Page
    |  
    |  GE = <attribute 'GE' of 'digicanbus.J1939_PDU' objects>
    |      Group Extension (PDU2 format)
    |  
    |  PF = <attribute 'PF' of 'digicanbus.J1939_PDU' objects>
    |      PDU Format
    |  
    |  PGN = <attribute 'PGN' of 'digicanbus.J1939_PDU' objects>
    |      Parameter Group Number
    |  
    |  PS = <attribute 'PS' of 'digicanbus.J1939_PDU' objects>
    |      PDU Specific
    |  
    |  SA = <attribute 'SA' of 'digicanbus.J1939_PDU' objects>
    |      Source Address
    |  
    |  __new__ = <built-in method __new__ of type object>
    |      T.__new__(S, ...) -> a new object with type S, a subtype of T
    |  
    |  payload = <attribute 'payload' of 'digicanbus.J1939_PDU' objects>
    |      message payload
    |  
    |  priority = <attribute 'priority' of 'digicanbus.J1939_PDU' objects>

Examples

# 
# Manipulating raw CAN messages
#
from digicanbus import CANHandle
DATA_FRAME=False
REMOTE_FRAME=True
h = CANHandle( 0 )
h.configure( bitrate=125000 )
h.send( 11, 0x500, DATA_FRAME, "%c%c%c" % (0x1e, 0x10, 0x10) )
h.send( 11, 0x500, DATA_FRAME, "%c%c%c" % (0x1e, 0x10, 0x00) )
h.send( 11, 0x280, REMOTE_FRAME, 8 )
 
def fn( width, id, remote, payload, ts, arg ):
  print "Width %d message received to id %x" % (width, id)
 
h.register_filter( 11, 0x500, 0x400, fn, 'filter 1' )
h.register_filter( 11, 0x500, 0x100, fn, 'filter 2' )

Application Developer Notes

Due to the "callback" architecture used in the digij1708 and digicanbus drivers, application developers should be aware of the effects of the code executed in the callback thread context. In particular, if the callback thread executes a significant amount of code or blocks on external resources, this can potentially lead to "falling behind" on bus data. To minimize the possibility of falling behind on data buffers, one should think about the following when writing the callback method which will be executed in the platform callback thread context:

  • Is my callback performing significant processing? The longer your callback is executing, the more likely that data from the bus will back up and, eventually, be dropped. If there is significant processing to be done on the data, the callback should focus on putting the data somewhere where another python thread can process the data.
  • Does my callback block on external resources? Beyond pure CPU processing time, blocking calls (file, socket, logging, etc.) will prevent the callback thread from grabbing and processing the next data item. As a rule, potentially blocking calls should be avoided.
  • Does any code in my callback release the GIL (Global Interpreter Lock)? For optimal throughput, any call which releases the GIL (Global Interpreter Lock) should be avoided. This includes locks, files, and sockets. Efficient, thread-safe alternatives to the Queue module can be constructed by using GIL-atomic (executed in a single bytecode) operations on data structures like python's list or deque. More information on this technique can be here: http://effbot.org/pyfaq/what-kinds-of-global-value-mutation-are-thread-safe.htm.


Availability

Products which support this module

Only Digi Python enabled products with a CAN bus hardware interface support this module, including the ConnectPort X5 family of products.

Personal tools
Wiki Editing