From Digi Developer
This module was designed in conjunction with the Digi ConnectPort X5, the first Digi Python-enabled product to offer J1708 bus connectivity. The module is designed to allow scripts to manipulate J1708 messages at a logical level, with the embedded operating system providing support for the encoding/decoding of these messages on the line.
Limited J1587 support is also provided, in order to simplify the interpretation of J1708 messages as J1587 PIDs. Knowledge of individual PID encodings is application specific, and must be supplied by the script.
Help on built-in module digij1708:
digij1708 - Provides Python abstraction for an underlying J1708 bus
The J1708Handle class provides functions to initialize a J1708 bus and transfer raw J1708 messages. It also provides functions to communicate over the J1708 bus via the abstraction of the SAE J1587 protocol.
__builtin__.dict(__builtin__.object) J1587_PIDdict __builtin__.object J1708Handle exceptions.ValueError(exceptions.StandardError) J1587_PID_ListError J1587_PID_PayloadError J1587_PID_ValueError class J1587_PID_ListError(exceptions.ValueError) | Method resolution order: | J1587_PID_ListError | exceptions.ValueError | exceptions.StandardError | exceptions.Exception | | Methods inherited from exceptions.Exception: | | __getitem__(...) | | __init__(...) | | __str__(...) class J1587_PID_PayloadError(exceptions.ValueError) | Method resolution order: | J1587_PID_PayloadError | exceptions.ValueError | exceptions.StandardError | exceptions.Exception | | Methods inherited from exceptions.Exception: | | __getitem__(...) | | __init__(...) | | __str__(...) class J1587_PID_ValueError(exceptions.ValueError) | Method resolution order: | J1587_PID_ValueError | exceptions.ValueError | exceptions.StandardError | exceptions.Exception | | Methods inherited from exceptions.Exception: | | __getitem__(...) | | __init__(...) | | __str__(...) class J1587_PIDdict(__builtin__.dict) | Provides a means to map J1708 payloads to/from a dictionary of J1587 PIDs | | J1587_PIDdict objects are instantiated either with no | parameters (creating an empty PID dictionary to be filled), | or with a J1708 payload string (in which case the PIDs are | automatically parsed out of the string into the PID | dictionary): | | piddict = J1587_PIDdict([payload]) | | The PID dictionary is indexed by PID number. The value | associated with the PID is the corresponding payload | substring from the 1708 payload. | | All standard dictionary operations are supported. | | Method resolution order: | J1587_PIDdict | __builtin__.dict | __builtin__.object | | Methods defined here: | | J1708_payload(...) | J1708_payload([pidlist]) -> j1708_payload_string | | Encode PIDs from the PID dictionary into a string. | | Argument: | pidlist -- A sequence of PID numbers to encode. | | If omitted, an attempt will be made to include | the entire dictionary of PIDs in the output | string, in sorted order of PID. | | If supplied, the PIDs in the sequence, in the | order of the sequence, will be included in the | output string. | | Return Value: | The resulting string is in a form suitable for transmission | in a single J1708 frame. | | Exceptions: | J1587_PID_PayloadError -- invalid payload in PID dictionary | J1587_PID_ValueError -- invalid PID number | J1587_PID_ListError -- invalid PID selection list | | __init__(...) | x.__init__(...) initializes x; see x.__class__.__doc__ for signature | | ---------------------------------------------------------------------- | Methods inherited from __builtin__.dict: | | __cmp__(...) | x.__cmp__(y) <==> cmp(x,y) | | __contains__(...) | D.__contains__(k) -> True if D has a key k, else False | | __delitem__(...) | x.__delitem__(y) <==> del x[y] | | __eq__(...) | x.__eq__(y) <==> x==y | | __ge__(...) | x.__ge__(y) <==> x>=y | | __getattribute__(...) | x.__getattribute__('name') <==> x.name | | __getitem__(...) | x.__getitem__(y) <==> x[y] | | __gt__(...) | x.__gt__(y) <==> x>y | | __hash__(...) | x.__hash__() <==> hash(x) | | __iter__(...) | x.__iter__() <==> iter(x) | | __le__(...) | x.__le__(y) <==> x<=y | | __len__(...) | x.__len__() <==> len(x) | | __lt__(...) | x.__lt__(y) <==> x<y | | __ne__(...) | x.__ne__(y) <==> x!=y | | __repr__(...) | x.__repr__() <==> repr(x) | | __setitem__(...) | x.__setitem__(i, y) <==> x[i]=y | | clear(...) | D.clear() -> None. Remove all items from D. | | copy(...) | D.copy() -> a shallow copy of D | | get(...) | D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None. | | has_key(...) | D.has_key(k) -> True if D has a key k, else False | | items(...) | D.items() -> list of D's (key, value) pairs, as 2-tuples | | iteritems(...) | D.iteritems() -> an iterator over the (key, value) items of D | | iterkeys(...) | D.iterkeys() -> an iterator over the keys of D | | itervalues(...) | D.itervalues() -> an iterator over the values of D | | keys(...) | D.keys() -> list of D's keys | | pop(...) | D.pop(k[,d]) -> v, remove specified key and return the corresponding value | If key is not found, d is returned if given, otherwise KeyError is raised | | popitem(...) | D.popitem() -> (k, v), remove and return some (key, value) pair as a | 2-tuple; but raise KeyError if D is empty | | setdefault(...) | D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D | | update(...) | D.update(E, **F) -> None. Update D from E and F: for k in E: D[k] = E[k] | (if E has keys else: for (k, v) in E: D[k] = v) then: for k in F: D[k] = F[k] | | values(...) | D.values() -> list of D's values | | ---------------------------------------------------------------------- | Data and other attributes inherited from __builtin__.dict: | | __new__ = <built-in method __new__ of type object> | T.__new__(S, ...) -> a new object with type S, a subtype of T | | fromkeys = <built-in method fromkeys of type object> | dict.fromkeys(S[,v]) -> New dict with keys from S and values equal to v. | v defaults to None. class J1708Handle(__builtin__.object) | Provides a programming interface to an underlying J1708 controller | | Instantiating a J1708Handle associates a set of methods with an | internal J1708 bus instance. The methods allow one to request | configuration of the bus, register message receive callbacks, and | submit messages for transmission. | | J1708Handle objects are instantiated with a single "j1708_bus_id" | argument, which is an integer identifier for the desired J1708 bus. | | Methods defined here: | | __init__(...) | x.__init__(...) initializes x; see x.__class__.__doc__ for signature | | configure(...) | configure([options]) -> None | | The J1708 bus will be stopped if running, the bus will be | reconfigured, then restarted with the new configuration. | | With no arguments, the current configuration will be re-applied. | | Options Arguments: | | mid=n -- SAE J1708 message identification character. No two | devices on the bus should share a message identifier, | per specification. 'n' must be between 0 and 255. If | the mid option is left unconfigured, the ability to | send is disabled. | | register_callback(...) | register_callback(method, return_arg) -> None | | Associate a callback 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 method must be a callable object of the form: | | method(mid, payload, return_arg) | | The "return_arg" argument is not examined by the bus | infrastructure. | | An exception is raised if the number of callbacks 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(priority, payload) -> True | False | | Non-blocking transmit of a message on the J1708 bus. The configured | message identifier will be used in the transmission. If the message | identifier is not selected, the send will fail with an exception. | | Arguments: | priority -- 1-8, as defined by the SAE J1708 specification | payload -- a string, and the length should be 19 characters or less | | Return Value: | The function will return a true value if the message was | successfully queued, and false if there is no queue space. | | unregister_callback(...) | unregister_callback(method, return_arg) -> None | | The callback 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. | | Registered callbacks will automatically be unregistered when the | handle goes out of scope, or is otherwise deleted. | | ---------------------------------------------------------------------- | 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
from digicanbus import J1708Handle h = J1708Handle( 0 ) h.configure( mid=117 ) my_priority = 8 h.send( my_priority, "%c%c%c" % (0x1e, 0x10, 0x10) ) h.send( my_priority, "%c%c%c" % (0x1e, 0x10, 0x00) ) def fn( mid, payload, arg ): print "Message of length %d received from module ID %d" % (len(payload), mid) h.register_callback( fn, 'callback 1' )
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.
Products which support this module
Only Digi Python enabled products with a J1708 bus hardware interface support this module, including the ConnectPort X5 family of products.