J1939
The J1939 protocol definition supports the most important J1939 features. That includes J1939 PGNs sent cyclic or on request as well as reacting on received PGNs with payload and explicitly sending (N)ACK messages.
The header contains the address of the ECU. The name of the field (J1939SourceAddress) is derived from the ISO ComParam CP_J1939SourceAddress.
MyJ1939ECU = {
J1939SourceAddress = 0x03,
}
Defining PGNs
All PGNs are defined in a sub-table called "PGNs". A PGN is defined in reverse order hex. This in the same way it is used via the D-PDU-API (ISO 22900-2).
In particular that means: * PGN 65226 * in hex -> 0x00FECA * reverse definition like ISO22900-2 in lua
["CA FE 00"]
Use case 1: Cyclic sending or responding to request PGN
A J1939 ECU can be configured to send a given PGN periodically or only when it is requested by a tested using the request PGN 59904 (0xEA00) with the PGN to be requested in the payload.
CAN Example: Tester with address 0x81 sends a message (PGN 0xEA00) to request the PGN 0xFECA from the ECU with address 0x01. The ECU subsequently responds with the payload of the requested PGN 0xFECA.
RX 0x18EA0181 CA FE 00
TX 0x18FECA01 AA BB CC DD EE FF 00 01
There are two possible ways to define the payload for a given PGN. * directly as mapping from PGN to payload
["CA FE 00"] = "FF FF FF FF FF FF FF FF",
- as a property named "payload"
["CA FE 00"] = {
payload = "FF FF FF FF FF FF FF FF",
},
In the second case it is also possible to specify a cycle time for periodic sending.
["CA FE 00"] = {
payload = "FF FF FF FF FF FF FF FF",
cycleTime = 50
},
In all cases the payload can be defined as a lua function.
Example
MyJ1939ECU = {
J1939SourceAddress = 0x03,
PGNs = {
-- direct mapping of PGN to payload
["CA FE 00"] = "FF FF FF FF FF FF FF FF",
["CB FE 00"] = function()
return "FF " .. ascii("Foo")
end,
-- using the "payload" property with optional cycleTime
["CC FE 00"] = {
payload = "FF FF FF FF FF FF FF FF",
},
["CD FE 00"] = {
payload = function()
return "FF " .. ascii("Foo")
end,
cycleTime = 50
},
}
}
Use case 2: Responding to a received PGN w/ or w/o payload
In some cases it is necessary to react on a PGN sent by the tester. This is different to use case 1 where the tester requests a specific PGN but always sends on the request PGN 0xEA00.
CAN Example: Tester with address 0x81 sends PGN 0xC300 with payload to ECU 0x01 and the ECU responds back on the same PGN.
RX 0x18C30181 01 FF 99 88 77 66 55 44
TX 0x18C38101 02 FF AA BB CC DD EE FF
This can be defined in the following styles:
["00 C3 00 # 01 FF 99 88 77 66 55 44"] = "00 C3 00 # 02 FF AA BB CC DD EE FF"
["00 C3 00 # 01 FF 99 88 77 66 55 44"] = "02 FF AA BB CC DD EE FF"
["00 C3 00 #"] = "00 C3 00 # 02 FF AA BB CC DD EE FF"
The # character has two purposes: It separates the PGN from the payload and it indicates that the PGN should be interpreted according to use case 2. For that reason the # must also be there if there is no payload.
Likewise in the response the PGN to be responded on can be defined before the # character. If no PGN is defined the ECU will respond on the same PGN as the request. In case the PGN uses PDU1 format the ECU directs the PGN to the address the request came from. If that address is unkown it uses the broadcast address 0xFF.
The simulated ECU will only process a received PGN if: * The PGN uses PDU1 format and is directed to the ECU address (defined in the J1939SourceAddress property) * The PGN uses PDU1 format and is directed to the broadcast address (0xFF) * The PGN uses PDU2 format
As always the payload can be defined as a function. The parameter given to that function will contain the payload part from the request only.
Example
MyJ1939ECU = {
J1939SourceAddress = 0x03,
PGNs = {
-- Responding to a PGN on the same PGN
["00 C3 00 # 01 FF 99 88 77 66 55 44"] = "02 FF AA BB CC DD EE FF",
["00 C4 00 # *"] = function(payload)
return "02 FF AA BB CC DD EE FF"
end,
-- Responding to a PGN on a different PGN
["00 C5 00 # 01 FF 99 88 77 66 55 44"] = "00 D5 00 # 02 FF AA BB CC DD EE FF",
["00 C6 00 # 01 FF 99 88 77 66 55 44"] = function()
return "00 D6 00 # 02 FF AA BB CC DD EE FF"
end,
-- Handling a received PGN without sending a response
["00 C7 00 #"] = function()
pgnReceived = true
return ""
end,
}
}
Acknowledgement
J1939 defines the possiblity to send ACKs and NACKs on the special PGN 59392 (0xE800).
In the Lua simulation this can be performed by using the special response "ACK XX YY" where XX is the (N)ACK code and YY is the group value. All other bytes of the response (such as target address and PGN to be ACKed/NACKed) will be determined automatically by the simulation.
Example
MyJ1939ECU = {
J1939SourceAddress = 0x03,
PGNs = {
["CA FE 00"] = "ACK 02 FF",
["00 C1 00 # 01 FF 99 88 77 66 55 44"] = "ACK 00 00",
["00 C2 00 # *"] = function(payload)
return "ACK 03 00"
end,
}
}