J1939 Driver

The J1939 driver allows to receive and extract information from the messages sent on a J1939 bus using the Wires and Asset models.

Download

The J1939 driver is available in the Official ESF Downloads page and in the Eclipse Kura Marketplace.
The driver is available for ARM v7+, x86-64 and aarch64 based gateways.

Features:

  • Allows to receive messages from a J1939 bus filtering by PGN and optionally by CAN source address.

  • Supports extraction of data from the message payloads, the following data formats are supported:

    • Raw byte arrays.
    • ASCII strings.
    • Single bits as booleans.
    • Unsigned integers of various size (not necessarily a multiple of 2).
  • Allows to apply a scale factor and an offset to numeric data.

  • Supports active requests for parameter transmission, allowing to read on-demand data.

  • Supports message filtering by device NAME or source address.

  • Supports emitting channel data in JSON format, optionally including also the sender source address and/or NAME parts.

CAN interface configuration

Before using the driver it is necessary to manually configure the CAN interface.
This can be done on Linux with the following commands:

ip link set ${interface} down
ip link set ${interface} type can bitrate 250000 triple-sampling on
ip link set ${interface} up

where ${interface} is the name of the CAN interface to be used (e.g. can0).
Automatic interface configuration might be added in the future.

Driver configuration

The driver configuration allows to specify:

  • The CAN interface to be used.
  • The device NAME.
  • The driver log level on the standard output.
  • Some parameters related to the source address to NAME mapping.
  • The informations to be included in JSON output.

Driver usage

The driver provides full support for event driven mode and partial support for read mode since version 1.0.100.

  • Event driven mode can be used for example by registering ChannelListeners using the Driver API, or by creating Asset channels with the listen flag set. In this case, channel data will be produced by the driver every time a new message that matches channel configuration is received.

  • Read mode is supported only through the PreparedRead APIs. In this case, the driver will emit data originating from the last received message that matches the channel configuration.

    If the ESF REST APIs or ASSET-V1 cloud request handler are used to read data from a J1939 Asset, only requests for all the asset channels will be supported. Using J1939 Assets inside a Wire Graph in polling mode is supported.

    The driver currently only supports using a single CAN interface. In order to enforce this, it is possible to create at most one driver instance per ESF runtime. Additional instances will not be activated.\nThis limitation might be removed in the future."

The following channel configuration parameters are relevant for all data formats:

  • json: Enables Json format output. If this parameter is set, the value.type parameter must be set to STRING.
  • json.type: This parameter is only relevant if json is set to true. In this case, it determines the kind of data to be read.
  • pgn: Must be set to the PGN of the message containing the data. If multiple parameters need to be extracted from the same message, multiple channels must be defined with the same value for the pgn parameter.
  • source.address: The driver allows to optionally filter basing on source CAN address, in order to enable this functionality, the source CAN address must be specified as the source.address field. Filtering basing on PGN is always performed.
  • source.name: Allows to enable NAME based filtering. It must contain a Json object containing the NAME parts to be matched, see below for more details.
  • parameter.position: Must be set to the start offset in bits of the parameter data.
  • parameter.size: Must be set to the size in bits of the parameter data.
  • request.transmission: The driver is capable of actively request parameter transmission at regular intervals, this is useful for reading on-demand parameters that are not transmitted spontaneously. In order to enable parameter requests, request.transmission must be set to true.
  • request.transmission.interval: If request.transmission is set to true, this parameter allows to specify the interval in milliseconds between two consecutive requests for the same parameter.

Reading numeric values

In order to read numeric values, the following channel configuration parameters should be used:

  • value.type: INTEGER, LONG, FLOAT or DOUBLE if the Json format is not used. STRING otherwise.
  • json.type: NUMERIC. Only necessary if the Json format is used.
  • resolution: The value of this parameter will be multiplied by the raw data. It represents a scale factor. Can be a real value.
  • offset: The value of this parameter will be added to the raw value, after multiplying by resolution. Can be a real value.

The conversion is performed as follows:

((rawData as double) * (resolution as double) + (offset as double)) as value.type

Where rawData is the value of raw data from the payload interpreted as a little-endian unsigned integer. Rounding errors might occur due to the conversion of the result from double to the value.type defined in channel configuration.

Reading byte arrays or ASCII strings

In order to extract byte arrays or ASCII strings, the following channel configuration parameters should be used:

  • value.type: STRING for ASCII strings or BYTE_ARRAY for raw byte arrays, if the Json format is not used. STRING otherwise.
  • json.type: BYTE_ARRAY or STRING. Only necessary if the Json format is used.
  • parameter.size and parameter.position: must be multiples of 8. If these two parameters define a byte range not entirely contained in the received payload, the driver will read until the payload end.
  • delimiter: Can be set to an integer value from 0 to 255. If this parameter is not empty, the driver will read until the delimiter is encountered or the end of the payload is reached. The driver will always read at most parameter.size bytes. In case of ASCII strings, the value of delimiter must be set as the byte representation of the delimiter character as as an integer, as defined by the ASCII encoding.

Reading boolean values

Reading boolean values involves the same parameters as reading numeric data, but value.type must be set to BOOLEAN. The driver will first interpret the raw data as a number as shown above, and then will produce false if the result is 0, and true otherwise. It is possible to read single bits by setting parameter.size to 1.

Json format

The driver supports emitting data using the Json format. This allows enrich the channel value with some metadata such as the source address and/or the NAME of the sender device.

The value of the source.name configuration parameter must also be specified in Json format.

If JSON output is enabled, the driver will emit a Json object encoded as a string.
The fields included in Json representation can be configured by some parameters in global driver configuration.

The emitted JSON object contains the following properties:

  • v: The channel value. Its type depends on the value of the json.type parameter:

    • NUMERIC -> Json number.
    {
    "v": 0
    }
    
    • STRING -> Json string.
    {
    "v": "string"
    }
    
    • BYTE_ARRAY -> Json array containing the data bytes represented as unsigned decimal numbers.
    {
    "v": [1,2,3,4]
    }
    
    • ADDRESS_TABLE -> A JSON description of the contents of the source address to NAME mapping table. See below for the format.
  • s: The source address of the message containing the parameter, represented as a decimal number. This field is present only if the Add source address to Json global parameter is set to true.

    {
    "v": [1,2,3,4],
    "s": 4
    }
    
  • n: The NAME of the source device as a Json object, if known. See below for more details

NAME representation as JSON

The n property value is a Json object can contain the following proeprties, reporting some parts of the NAME of sender device. The properties below will be present only if the corresponding global configuration parameters are enabled.

  • aac: The value of the "Arbitrary address capable parameter". Either 1 or 0.
  • indGrp: The value of the "Industry group" prarameter, as a decimal number.
  • vehSys: The value of the "Vehicle system" prarameter, as a decimal number.
  • vehSysInst: The value of the "Vehicle system instance" prarameter, as a decimal number.
  • func: The value of the "Function" prarameter, as a decimal number.
  • funcInst: The value of the "Function instance" prarameter, as a decimal number.
  • ecuInst: The value of the "ECU instance" prarameter, as a decimal number.
  • mfgCode: The value of the "Manufacturer group code" prarameter, as a decimal number.
  • identyNum: The value of the "Identity number" prarameter, as a decimal number.

The example below illustrates a Json output with all NAME properties enabled:

{
  "v": [1, 2, 3, 4],
  "s": 4,
  "n": {
    "aac": 0,
    "indGrp": 0,
    "vehSysInst": 0,
    "vehSys": 0,
    "func": 0,
    "funcInst": 0,
    "ecuInst": 0,
    "mfgCode": 0,
    "identyNum": 0
  }
}

In order to enable NAME base filtering. The value of the source.name configuration parameter must be a Json object containing some of the properties above.
It is not necessary to specify all the properties. A message will match the filter if the values of all of the properties included in source.name match the corresponding properties of the NAME of the sender device (logic AND match).

For example, to match only messages coming from a device with identity number 10, the following JSON can be specified as value for the source.name parameter;

{
  "identyNum": 10
}

Source address to NAME mapping

In order to support NAME based filter and producing NAME related information, the driver maintains a mapping table between remote device source address and NAME.

The mapping is updated when a PGN 60928 (Address Claim) is received. The driver may also actively request the transmission of PGN 60928.

The logic responsible of updating the table operates in one of the following two states:

  • ACTIVE

    • In this state the driver will send a request for PGN 60928 periodically. The interval between two requests is defined by the value of the Address claim request interval (seconds) parameter in global driver configuration.
    • If a PGN 60928 is received the mapping will be updated and the driver will switch to the PASSIVE state.
  • PASSIVE

    • Periodic requests for PGN 60928 are not performed in this state.
    • If a PGN 60928 is received the mapping will be updated.
    • If a message is received from a device whose NAME is not tracked in the mapping table, the driver will switch back to the ACTIVE state.
    • If the Address table switch to active interval (seconds) global parameter is set to a non zero value, the driver will switch to ACTIVE mode after the configured time interval.

In both states, if no data is received on the bus for a time interval greater than the value of the Address table clear on inactivity interval (seconds) global parameter, the mapping table will be dropped and rebuilt, if this happens the driver will switch back to the ACTIVE state.

If the NAME of a device is not known, its messages will not match any NAME filter, and NAME information will not be included in the produced Json objects.

Reading the contents of the address table

The contents of the source address to NAME mapping can be accessed using a channel in read mode with the following configuration:

  • json: true.
  • json.type: ADDRESS_TABLE.

The driver will emit the current table as a JSON object, using the following format:

{
  "v": [
    {
      "s": 1,
      "n": {
        "aac": 1,
        "indGrp": 0,
        "vehSysInst": 0,
        "vehSys": 0,
        "func": 0,
        "funcInst": 0,
        "ecuInst": 0,
        "mfgCode": 0,
        "identyNum": 0
      }
    },
    {
      "s": 2,
      "n": {
        "aac": 0,
        "indGrp": 7,
        "vehSysInst": 0,
        "vehSys": 0,
        "func": 0,
        "funcInst": 0,
        "ecuInst": 0,
        "mfgCode": 0,
        "identyNum": 0
      }
    }
  ]
}

The v property of the output object will contain an array of objects, one per device containing the following fields:

  • s: the source address of the device
  • n: the NAME of the device, with all of the properties of the representation described above.

Using the Driver programmatically

In order to use the driver programmatically, the high level Driver or Asset APIs can be used.

The com.eurotech.addons.esf.j1939.core bundle also provides a lower level API for receiving j1939 frames, the documentation of this API can be provided on request in form of Javadoc.