Supported platforms: CODESYS 2.3, CODESYS 3.5
J1939 FB is the main function block of the library. Other main functions of the library are called by instance of function block J1939. The receiving of J1939 messages is handled with callback programs. J1939 handles receiving and sending of both short and multi packet PGN messages.
This function block initializes itself during the first call of J1939 instance. On initialization the J1939_InitVXD is called, which initializes the received PGN messages for the CAN bus. All J1939 application variables and structures must be built up before calling an instance of J1939.
J1939 Configuration is done via PGN and SPN structures, which are connected via pointers to each other and to the actual data (Picture 1). Both received and transmitted PGNs are initialized in the same manner. The PGNs are built by reserving data areas for the received SPN data. This means, declaring a variable for the SPN data (e.g. DslEng1_EngRqedSpeed_SpeedLimit) . Then an array for SPNs must be declared (e.g. DslEng1_PGN_TSC1_SPNs). The size of the array is the number of SPNs in the PGN. The SPN data pointer is set to the SPN array (6). The pointer of the SPN array is given to the PGN (4). Also, the correct size of the SPN must be set to the PGN (5).
Combining of all PGN's for one CAN bus is done after all PGNs and SPN's are initialized. It is suggested that one physical CAN bus uses only one instance of J1939, even though several instances can be used. All PGN's are combined together by an array of PGN pointers, which have all the RX or TX PGN pointers for one physical CAN bus. The PGN structures have the destination and source addressed for all devices used in the J1939. The array of PGN pointers have the pointers to all the PGN's (3). TX and RX PGN's have their own arrays. Both received and transmitted PGNs are connected to instance of J1939 by PGN array pointer (1) and the number of PGNs(2).
It is also possible to add new transmit or receive PGNs after J1939 has been initialized. This is done by using function J1939_AddPgn. In this case only the array of PGN pointers is required and it needs to have empty slots where new PGN pointer can be added.
It is also possible to add new transmit or receive PGNs after J1939 has been initialized. This is done by using J1939 function block's method AddPgn. In this case only the array of PGN pointers is required and it needs to have empty slots where new PGN pointer can be added.
Picture 1. Configuration of received PGNs.
Name of error |
Description |
J1939_ERR_pRxPGNNULL |
i_pRxPGNs pointer null, when number of Rx PGNs > 0 |
J1939_ERR_pSPNNULL |
SPN pointer not initialized. |
J1939_ERR_pRxPGNNULL |
pRxPGN pointer null in pointer array |
J1939_ERR_pSPNDataNULL |
SPN data pointer null. |
J1939 function block calls two functions, J1939_MonitorMessages and J1939_SendHandler, directly every time it is called. All data variables are in the same format as in J1939 SPNs, so no conversion is done in J1939. Only little/big endianness is handled by J1939. The diagnosed result of the target device endian type can be read via boolean variable G_BigEndian. The G_BigEndian variable is true, when the target device is big endian type.
The validity of received data can be checked from the DataValid member of the J1939_PGN structure. If the received message is long (multi packet), the Status member of the J1939_PGN can also be used to diagnose the data transmission.
Receiving of J1939 messages can be monitored via Status and DataValid members of J1939_PGN structure. If there is an error, DataValid is false and Status is negative. When the message is received successfully, Status is J1939_PGN_DataReady and DataValid is true. Receiving of a message sets NewData to true for one program cycle. This can be used for triggering the data conversion from J1939 format to your own value format. On every program cycle, the library checks the timeout of all J1939 received PGNs. If no new PGN message is received after 3 * J1939_PGN.CycleTime is elapsed, the PGN validity for the specific PGN is set as false.
Sending of J1939 messages is done automatically by setting the CycleTime variable, which is the period for sending a new message. Data validity of a sent message is not checked. Sending of messages can also be done "manually" by SendTrigger when CycleTime is set to zero ( 0 ).
Only one type of sending method is possible at a time.
J1939 transport protocol (TP): It is possible to send one broadcast transfer per source address. It is possible to receive one broadcast transfer per source address.
It is possible to send one destination specific transfer per SA-DA connection. It is possible to receive one destination specific transfer per SA-DA connection. |
ISO 11783-3 extended transport protocol (ETP):
It is possible to send one transfer per SA-DA connection.
|
All J1939 variables and structures must be properly initialized before calling J1939 FB. All the used pointers in the structures must be initialized. The given number of PGNs must match the size of array of PGN pointers. |
SPN sizes of 17..32 bits must always have 4 bytes of data buffer. This limitation comes from little/big endian conversion. |
Send interval accuracy depends of the program cycle time. A shorter cycle time gives a more accurate interval to the message sending. Interval accuracy is same as one program cycle time. So, if the program cycle time is 10 ms, the maximum interval can be a little less than 10 ms + CycleTime (Tx PGN transmit interval). |
J1939 handles little / big endianness of the target devices ( IO-module / display ), so the byte order is switched when needed. The SPN size affects the conversion: Sizes of 9..16 bits swap two bytes and sizes of 17..32 bits swap four bytes. Although SPN size of 32 bits is not recommended, the SPN size can be set over 32 bits, but then little/big endian conversion is not done. |
If initialization fails, messages may either drop out completely or partially. Increasing of the values below may help the situation. Default values can be overrun, if needed. G_J1939_MAX_SIZE_OF_LONG_TRANSFER G_J1939_MAX_NUMBER_OF_LONG_TRANSFER |
Value of the G_J1939_MAX_SIZE_OF_LONG_TRANSFER must be greater or equal to the longest DataLength of all J1939 PGN's. |
Input variable name |
Data type |
Range |
Description |
i_DrvNbr |
BYTE |
0..G_NUMBER_OF_LAST_CAN_BUS |
Number of CAN bus to monitor/manage. |
i_pRxPGNs |
POINTER TO J1939_pPGN |
- |
Pointer to the list of PGNs (pointers) to receive. |
i_NumberOfRxPGNs |
WORD |
0...65535 |
Max number of PGNs in the list of PGNs to receive |
i_pTxPGNs |
POINTER TO J1939_pPGN |
- |
Pointer to the list of PGNs (pointers) to transmit. |
i_NumberOfTxPGNs |
WORD |
0...65535 |
Max number of PGNs in the list of PGNs to transmit |
Output variable name |
Data type |
Range |
Description |
Status |
INT |
-32768..0 |
0 = OK, negative = error. |
o_TxPgnCount |
INT |
0.. i_NumberOfTxPGNs |
Amount of defined Tx PGNs |
o_RxPgnCount |
INT |
0.. i_NumberOfRxPGNs |
Amount of defined Rx PGNs |
o_InitReady |
BOOL |
TRUE/FALSE |
J1939 initialized flag |
Input variable name |
Data type |
Range |
Description |
i_CANChannel |
CANVXD_API.ICANVXD |
|
CAN channel interface. |
i_pRxPGNs |
POINTER TO J1939_pPGN |
Pointer to the list of PGNs (pointers) to receive. |
|
i_NumberOfRxPGNs |
WORD |
0...65535 |
Number of PGNs in the list of PGNs to receive. |
i_pTxPGNs |
POINTER TO J1939_pPGN |
|
Pointer to the list of PGNs (pointers) to transmit. |
i_NumberOfTxPGNs |
WORD |
0...65535 |
Number of PGNs in the list of PGNs to transmit. |
Output variable name |
Data type |
Range |
Description |
o_Status |
INT |
-32768..0 |
0 = OK, negative = error. |
o_TxPGNCount |
WORD |
|
Amount of defined Tx PGNs |
o_RxPGNCount |
WORD |
|
Amount of defined Rx PGNs |
EnableRequestPGNsEnableRequestPGNs
This method enables the receiving of RQST PGNs. To enable RQST PGNs, the method must be called in initialization before calling the main J1939 function block.
The method must be called in init before calling the main J1939 function block. |
No inputs
No return value or outputs
Definitions: |
|
VAR
J1939_CAN1: J1939;
END_VAR
|
Init: |
|
J1939_CAN1.EnableRequestPGNs();
|
Separate functions are changed to J1939 FB public methods in CODESYS 3.5:
This method is used to add PGNs on runtime. If PGN is set as received, the method adds COB-ID to CANVXD callback list.
J1939 server must have free PGN slots, otherwise it is not possible to add PGN and method returns error code. |
Input variable name |
Data type |
Range |
Description |
i_RxPGN |
BOOL |
TRUE/FALSE |
Defines if PGN is RX or TX PGN (TRUE = RX , FALSE = TX) |
i_pPGN |
POINTER TO J1939_PGN |
≠ 0 |
Pointer to PGN definition structure. |
Data type |
Range |
Description |
INT |
J1939_ReturnCodes |
Negative number --> error |
Definitions: |
|
VAR
J1939_CAN1: J1939; Tx_PGN: J1939_PGN; Tx_SPNs: ARRAY[1..2] OF J1939_SPN; Tx_Data1: WORD; Tx_Data2: WORD; END_VAR
|
Init: |
|
Tx_PGN.pSPNs:=ADR(Tx_SPNs); Tx_PGN.PGN_Number:=16#FF00; Tx_PGN.SourceAddress:=1; Tx_PGN.Destination:=255; Tx_PGN.CycleTime:=0; Tx_PGN.DataPage:=0; Tx_PGN.NumberOfSPNs:=2; Tx_PGN.Priority:=6; Tx_PGN.DataLength:=4;
Tx_SPNs[1].Size:=16; Tx_SPNs[1].pData:=ADR(Tx_Data1); Tx_SPNs[2].Size:=16; Tx_SPNs[2].pData:=ADR(Tx_Data2);
J1939_CAN1.AddPgn( i_RxPGN := FALSE, i_pPGN := ADR(Tx_PGN) );
|
.
AddRequestPGNCallbackAddRequestPGNCallback
This method adds callback for received EA00h requests. Requested PGN value is compared against EA00h message's data and callback is triggered when PGN is found. Callback is implemented with IRequestPGNCallbackHandler interface.
Pointers to PGN data structure and user specific data can be given as parameters to callback. Callback data is accessed through callback's HandlePGN method.
Amount of callbacks are limited by parameter G_J1939_MAX_NBR_OF_RQST_CALLBACKS.
|
It is required to execute EnableRequestPGNs method to J1939 function block before J1939 initialization. Then J1939 function block will handle the received request PGNs (EA00h).
|
Input variable name |
Data type |
Range |
Description |
i_RequestedPGN |
WORD |
0…65535 |
PGN value which is compared to EA00 data |
i_itfCallback |
IRequestPGNCallbackHandler |
|
Interface to request callback handler |
i_pPGNData |
DWORD |
≠ 0 |
Callback parameter: Pointer to PGN data structure. |
i_pUserData |
DWORD |
≠ 0 |
Callback parameter: Pointer to user specific data |
Data type |
Range |
Description |
INT |
J1939_ReturnCodes |
Negative number --> error |
The following example shows how to add request callback to transmit PGN.
The following shows callback POU that implements IRequestPGNCallbackHandler.
Callback function block
|
|
FUNCTION_BLOCK RequestPGNCallback IMPLEMENTS IRequestPGNCallbackHandler
|
HandlePGN method
|
|
METHOD HandlePGN VAR_INPUT (* Callback data pointer *) i_pData : POINTER TO EPEC_J1939.J1939_RequestedPGNData; END_VAR VAR pPGN:POINTER TO J1939_PGN; pCallbackData:POINTER TO DWORD; DA:BYTE; SA:BYTE; END_VAR
|
Code in HandlePGN |
|
|
|
IF i_pData <> 0 THEN pPGN := i_pData^.pPGNData; pCallbackData := i_pData^.pUserData; DA := i_pData^.DA; SA := i_pData^.SA;
IF 0 <> pPGN AND 0 <> pCallbackData THEN (*do something*) END_IF END_IF |
The following shows how to initialize callback to transmit PGN.
Definitions: |
|
VAR J1939_CAN1: J1939; Tx_PGN:J1939_PGN; Tx_SPNs:ARRAY[1..2] OF J1939_SPN; Tx_Data1: WORD; Tx_Data2: WORD;
CallbackData:DWORD; Callback: RequestPGNCallback; END_VAR
|
Init: |
|
Tx_PGN.pSPNs:=ADR(Tx_SPNs); Tx_PGN.PGN_Number:=16#FF00; Tx_PGN.SourceAddress:=1; Tx_PGN.Destination:=255; Tx_PGN.CycleTime:=0; Tx_PGN.DataPage:=0; Tx_PGN.NumberOfSPNs:=2; Tx_PGN.Priority:=6; Tx_PGN.DataLength:=4; Tx_SPNs[1].Size:=16; Tx_SPNs[1].pData:=ADR(Tx_Data1); Tx_SPNs[2].Size:=16; Tx_SPNs[2].pData:=ADR(Tx_Data2);
J1939_CAN1.AddPgn( i_RxPGN := FALSE, i_pPGN := ADR(Tx_PGN) );
J1939_CAN1.AddRequestPGNCallback( i_RequestedPGN := 16#FF00, i_itfCallback := Callback, i_pPGNData := ADR(Tx_PGN), i_pUserData := ADR(CallbackData) );
|
ChangePGNConfigurationChangePGNConfiguration
This method is used to change the PGN source or destination address (or both) on runtime.
If the PGN is set as received, the function also changes CANVXD callback COB-ID correctly. MASK is not changed.
Input variable name |
Data type |
Range |
Description |
i_RxPGN |
BOOL |
TRUE/FALSE |
Defines if PGN is RX or TX PGN (TRUE = RX , FALSE = TX) |
i_pPGN |
POINTER TO J1939_PGN |
≠ 0 |
Pointer to PGN structure |
i_NewSourceAddress |
WORD |
0…255, 65535 |
0 - 255 Value of the new source address, FFFFh source address is not changed. |
i_NewDestinationAddress |
WORD |
0…255, 65535 |
0 - 255 Value of the new destination address, FFFFh destination address is not changed. |
Data type |
Range |
Description |
INT |
J1939_ReturnCodes |
Negative number --> error |
Definitions: |
|
VAR J1939_CAN1: J1939; Rx_PGN:J1939_PGN; Rx_SPNs:ARRAY[1..2] OF J1939_SPN; Rx_Data1: WORD; Rx_Data2: WORD; address_changed:BOOL; END_VAR |
|
|
Init: |
|
Rx_PGN.pSPNs:=ADR(Rx_SPNs); Rx_PGN.PGN_Number:=16#FF00; Rx_PGN.SourceAddress:=1; Rx_PGN.Destination:=255; Rx_PGN.CycleTime:=0; Rx_PGN.DataPage:=0; Rx_PGN.NumberOfSPNs:=2; Rx_PGN.Priority:=6; Rx_PGN.DataLength:=4;
Rx_SPNs[1].Size:=16; Rx_SPNs[1].pData:=ADR(Rx_Data1); Rx_SPNs[2].Size:=16; Rx_SPNs[2].pData:=ADR(Rx_Data2);
J1939_CAN1.AddPgn( i_RxPGN := TRUE, i_pPGN := ADR(Rx_PGN) );
|
The following changes the source address of PGN and leaves destination address unchanged.
Code: |
|
IF address_changed THEN J1939_CAN1.ChangePGNConfiguration( i_RxPGN := TRUE, i_pPGN := ADR(Rx_PGN), i_NewSourceAddress := 2, i_NewDestinationAddress := 16#FFFF ); END_IF
|
J1939 is automatically initialized in MultiTool Creator code template. See Using J1939 topic for examples of code template structures. |
Using J1939 with Multitool Creator
Data types:
Interfaces (CODESYS 3.5)
IPGNCallbackHandler (ITF)
Source file Topic000442.htm
Last updated 19-Dec-2024