Supported platforms: CODESYS 3.5, CODESYS 3.5 SAFETY

 

VersionsFromUnits (FB)

Description

This function block (FB) asks versions from units in the given CAN bus (device) to the given node data table.

A rising edge of i_Enable input starts a SDO read sequence.

 

Control unit versions are requested with SDO messages

 

Each used CAN bus needs an instance of the function block.

SDO errors are written to the node data table for each unit separately.

 

Limitations

This function block is included in code template when "Generate Update functionality to codetemplate" is selected in MultiTool Creator. See also Updating Software from Application (6000 series).

 

The application must define the used data tables.

 

Application version is not read from slave control unit (e.g. GL84).

 

 

Inputs

Input variable name

Data type

Range

Description

i_Enable

BOOL

 

Enable operation.

i_pDevice

POINTER TO EPEC_CANopen.Device

 

Used CANopen device.

i_pNodeData

POINTER TO NodeData

 

Pointer to used node data table.

i_NumberOfNodes

UINT

 

Number of nodes in table.

Outputs

Output variable name

Data type

Range

Description

o_Error

EPEC_CANopen.Errors

 

Occurred error

o_Ready

BOOL

 

SDO read sequence ready

 

Example code

At initialization phase

  • extracts update files from zip package.

  • reads local versions from OD.

  • reads packet versions from extracted file versions.csv.

  • reads versions from control units connected to CAN1 and CAN2.

  • defines which units need to be updated.

 

At running phase

  • updates control units connected to CAN1 and CAN2

 

 

Definitions:

 

VAR_GLOBAL

 

    // Systemwide version and name

    System: EPEC_SWD.SystemData;

 

    // Node data table of all nodes in all CANs.

    Nodes: ARRAY [1..4] OF EPEC_SWD.NodeData :=

    [(  CANNumber := BYTE#1,                    (* CAN connection *)

        ProductCode := DWORD#3724,              (* Unit product code, e.g. 5050.  *)

        CODESYSVersion := CODESYSVersions.V2_3, (* Unit's CODESYS version *)

        NodeID := BYTE#3,                       (* Unit's application node-ID is used for version asking *)

        CODESYSNodeID := BYTE#34                (* Unit's CODESYS node-ID is used for SW/FW updating *)

    ),

    (   CANNumber := BYTE#1,                    (* CAN connection *)

        ProductCode := DWORD#5050,              (* Unit product code, e.g. 5050.  *)

        CODESYSVersion := CODESYSVersions.V2_3, (* Unit's CODESYS version *)

        NodeID := BYTE#5,                       (* Unit's application node-ID is used for version asking *)

        CODESYSNodeID := BYTE#126               (* Unit's CODESYS node-ID is used for SW/FW updating *)

    ),

    (   CANNumber := BYTE#2,                    (* CAN connection *)

        ProductCode := DWORD#2024,              (* Unit product code, e.g. 5050.  *)

        CODESYSVersion := CODESYSVersions.V2_3, (* Unit's CODESYS version *)

        NodeID := BYTE#1,                       (* Unit's application node-ID is used for version asking *)

        CODESYSNodeID := BYTE#1                 (* Unit's CODESYS node-ID is used for SW/FW updating *)

    ),

    (   CANNumber := BYTE#1,                    (* CAN connection *)

        ProductCode := DWORD#6107,              (* Unit product code, e.g. 5050.  *)

        CODESYSVersion := CODESYSVersions.V3_5, (* Unit's CODESYS version *)

        NodeID := BYTE#1,                       (* Unit's application node-ID is used for version asking *)

        CODESYSNodeID := BYTE#1                 (* Unit's CODESYS node-ID is used for SW/FW updating *)

    )];

    

    // Version table must have space for

    // - system version

    // - runtime and conf/crc files for all units

    // - application and crc files for all units

    Versions: ARRAY [1..10] OF EPEC_SWD.NodeVersions;

    

    // Version asking instances (CSDO) for each CAN bus

    VersionsFromCAN1: EPEC_SWD.VersionsFromUnits;

    VersionsFromCAN2: EPEC_SWD.VersionsFromUnits;

    VersionError: EPEC_CANopen.Errors;

    VersionDifference: BOOL := FALSE;

 

    // Program loading instances (CSDO) for each CAN bus

    LoadToCAN1: EPEC_SWD.LoadAllUnits;

    LoadToCAN2: EPEC_SWD.LoadAllUnits;

 

END_VAR

 

Init:

 

 

CASE G_VersionQueryState OF

 

VersionQueryStates.HANDLE_PACKET:

    // Extract possible new update package

    EPEC_SWD.UpdatePackageHandler(

        i_Enable := TRUE,

        o_Ready =>

    );

    IF EPEC_SWD.UpdatePackageHandler.o_Ready THEN

        G_VersionQueryState := VersionQueryStates.VERSIONS_FROM_OD;

    END_IF

 

VersionQueryStates.VERSIONS_FROM_OD:

    // Get local versions from OD

    G_VersionInfo.VersionError := EPEC_SWD.VersionsFromLocalOD(

        i_pDevice := ADR(G_CANopen_CAN1.Device),

        i_pNodeData := ADR(G_VersionInfo.Nodes),

        i_NumberOfNodes := SIZEOF(G_VersionInfo.Nodes)/SIZEOF(G_VersionInfo.Nodes[1])

    );

    IF G_VersionInfo.VersionError = EPEC_CANopen.Errors.NoError THEN

        G_VersionQueryState := VersionQueryStates.VERSIONS_FROM_PACKET;

    ELSE

        G_VersionQueryState := VersionQueryStates.SEQUENCE_DONE;

    END_IF

 

VersionQueryStates.VERSIONS_FROM_PACKET:

 

    // Get versions from update packet

    G_VersionInfo.VersionError := EPEC_SWD.VersionsFromPacket(

        i_pNodeData := ADR(G_VersionInfo.Nodes),

        i_NumberOfNodes := SIZEOF(G_VersionInfo.Nodes)/SIZEOF(G_VersionInfo.Nodes[1]),

        i_pNodeVersions := ADR(G_VersionInfo.Versions),

        i_NumberOfVersions := SIZEOF(G_VersionInfo.Versions)/SIZEOF(G_VersionInfo.Versions[1]),

        i_pSystemData := ADR(G_VersionInfo.System)

    );

    IF G_VersionInfo.VersionError = EPEC_CANopen.Errors.NoError THEN

        G_VersionQueryState := VersionQueryStates.VERSIONS_FROM_UNITS;

    ELSE

        G_VersionQueryState := VersionQueryStates.SEQUENCE_DONE;

    END_IF

 

VersionQueryStates.VERSIONS_FROM_UNITS:

    // Get versions from units in CAN 1

    G_VersionInfo.VersionsFromCAN1(

        i_Enable := TRUE,

        i_pDevice := ADR(G_CANopen_CAN1.Device),

        i_pNodeData := ADR(G_VersionInfo.Nodes),

        i_NumberOfNodes := SIZEOF(G_VersionInfo.Nodes)/SIZEOF(G_VersionInfo.Nodes[1]),

        o_Ready =>

    );

    // Get versions from units in CAN 2

    G_VersionInfo.VersionsFromCAN2(

        i_Enable := TRUE,

        i_pDevice := ADR(G_CANopen_CAN2.Device),

        i_pNodeData := ADR(G_VersionInfo.Nodes),

        i_NumberOfNodes := SIZEOF(G_VersionInfo.Nodes)/SIZEOF(G_VersionInfo.Nodes[1]),

        o_Ready =>

    );

 

    IF G_VersionInfo.VersionsFromCAN1.o_Ready AND G_VersionInfo.VersionsFromCAN2.o_Ready THEN

        G_VersionQueryState := VersionQueryStates.DEFINE_UPDATES;

    END_IF

 

VersionQueryStates.DEFINE_UPDATES:

    // Set update statuses if versions differ

    G_VersionInfo.VersionDifference := EPEC_SWD.DefineUpdateNeed(

        i_pNodeData := ADR(G_VersionInfo.Nodes),

        i_NumberOfNodes := SIZEOF(G_VersionInfo.Nodes)/SIZEOF(G_VersionInfo.Nodes[1]),

    );

    G_VersionQueryState := VersionQueryStates.SEQUENCE_DONE;

 

VersionQueryStates.SEQUENCE_DONE:

    G_InitUpdateReady := TRUE;

 

END_CASE

 

 

Code:

 

 

G_VersionInfo.LoadToCAN1(

    i_Enable := TRUE,

    i_pDevice := ADR(G_CANopen_CAN1.Device),

    i_pNodeData := ADR(G_VersionInfo.Nodes),

    i_NumberOfNodes := SIZEOF(G_VersionInfo.Nodes)/SIZEOF(G_VersionInfo.Nodes[1]),

    o_Percentage => ,

    o_UpdateInProgress => ,

    o_Ready => ,

    o_Error => ,

    o_GFCRequest =>

);

G_VersionInfo.LoadToCAN2(

    i_Enable := TRUE,

    i_pDevice := ADR(G_CANopen_CAN2.Device),

    i_pNodeData := ADR(G_VersionInfo.Nodes),

    i_NumberOfNodes := SIZEOF(G_VersionInfo.Nodes)/SIZEOF(G_VersionInfo.Nodes[1]),

    o_Percentage => ,

    o_UpdateInProgress => ,

    o_Ready => ,

    o_Error => ,

    o_GFCRequest =>

);

 

 

See also

 

 

Source file topic100573.htm

Last updated 21-Feb-2025