Application description

Introduction

The unified GOAL PROFINET layer provides a common interface to all adapted PROFINET stacks by using the same API in single core mode and also via GOALs Core To Core for multiple cores.

Application description

The GOAL PROFINET stack comes with ready to run examples in the folder appl. The matching GSDML file can be found in gsdml.

appl/goal_pnio/00_rpc_cc (only available for Core To Core)

This application must be run on the communication core of a device. It provides the functionality for all other examples to the application core. It is not restricted to the examples but also provides the full GOAL PROFINET functionality to the user application.

appl/goal_pnio/01_simple_io

The example 01_simple_io is setup with two modules. First module is a 64 byte input module, second module is 64 byte output. It copies the received data from the output module to the input module every time the integrated cnt variable reaches a multiple of 1000. The counting speed depends heavily on the used platform.
The device setup can edit by changing the goal_pnioSubmodPlug lines in the function appl_setup in the file goal_appl.c.

appl/goal_pnio/02_io_demo

This example is an enhanced version of the 01_simple_io example that has two counters and includes LED and button mapping if they are available on the selected platform.
Slot 1 contains a 64 byte input module, slot 2 contains a 64 byte output module. To match the configuration of the PLC the following tables show the inner values of the data stream.
The LEDs, buttons and counters are in big endian format.

Bytes

Function

0-3

Button state.

4-7

Mirror output data bytes 4 - 7.

8 - 11

32-bit counter.

12 - 15

32-bit counter that only counts when at least 1 button is pressed.

16 - 63

Bit shift from bit 0 (at byte 16) to bit 7 (at byte 63).

Table: Input data - 64 bytes

Bytes

Function

0-3

Set LED state.

4-7

Data that is mirrored to input data bytes 4 - 7.

8 - 63

Unused.

Table: Output data - 64 bytes

appl/goal_pnio/03_record_write

This example is configured with the 64 byte input and the 64 byte output module. Whenever a record write request is received and can’t be handled by the PROFINET Stack itself, the callback GOAL_PNIO_CB_ID_WRITE_RECORD is triggered. In this example it calls the function processWriteRequest which shows some information about the request and if the record data length defined in the define RECORD_DATA_LENGTH matches, it returns GOAL_OK_SUPPORTED. Otherwise the request will fail with GOAL_ERR_NOT_FOUND.

appl/goal_pnio/05_ioxs_states

This example is configured with the 64 byte input and the 64 byte output module. It demonstrates how to read the IOCS state and provides a function called show_io_state which shows the state as human readable string.

appl/goal_pnio/06_apdu_status

This example is configured with the 64 byte input and the 64 byte output module. It demonstrates how to read the overall frame status, called GOAL_PNIO_APDU_STATUS_T. This contains the cycle counter, the data status and the transfer status.

appl/goal_pnio/07_alarm_button

This example is configured with the 64 byte input and the 64 byte output module. It demonstrates how to send and receive AlarmNotification alarms to and from the PLC and also shows how to read AlarmNotification ACKs. In this example an alarm is triggered by pressing a button which only works if your platform supports it.

appl/goal_pnio/08_dynamic_modules

This example demonstrates how to handle the dynamic module configuration when a Connect Request from the PLC is received. It connects the two callbacks GOAL_PNIO_CB_ID_CONNECT_REQUEST_EXP_START and GOAL_PNIO_CB_ID_EXP_SUBMOD. The first callback GOAL_PNIO_CB_ID_CONNECT_REQUEST_EXP_START removes all modules from all slots but the DAP slot. The second callback GOAL_PNIO_CB_ID_EXP_SUBMOD then tries to plug all modules/submodules from the ExpectedSubmoduleBlock. Only the DAP is left out because in this example the DAP configuration is hardwired. If a module/submodule combination isn’t found then the plug will fail and give an error message. After all ExpectedSubmoduleBlock requests are handled, the internal stack logic will check if all slots are match the requested setup from the PLC and if not, it will create a ModuleDiffBlock in the response, saying what modules/submodules aren’t matching the configuration. Then the PLC can decide whether to accept this or to cancel the connection.

appl/goal_pnio/09_busy_records

This example shows how to handle a record read and write request if the result for the caller isn’t available in the callback. For example when a write request needs some time to be stored to the non volatile storage and it is necessary to check if the write was ok then the busy handling functionality must be used.

To demonstrate the functionality, configure the modules as following:

  • Slot 1: Module 0x33, Submodule 0x01

  • Slot 2: Module 0x31, Submodule 0x01

During the Connect Request the PLC will write the parameters of module 0x33 which you should see in the debug output. Each time a write is requested the application will store it and wait for 10 seconds. After this time the write request is answered with a positive response status.

appl/goal_pnio/10_led_demo

This example shows how to take care about the connection and DCP signal LED. It works only for architectures that support the generic OAL_setLedsimplementation. In the example the callbacks GOAL_PNIO_CB_ID_APPL_READY and GOAL_PNIO_CB_ID_RELEASE_AR toggle an LED showing the connection state and the callback GOAL_PNIO_CB_ID_BLINK toggles an LED for the DCP state.

appl/goal_pnio/11_multiple_write

This example shows how to handle a multiple write request (index 0xe040) with busy mode. For all sub-requests that are not handled within the stack, the callback GOAL_PNIO_CB_ID_WRITE_RECORD is called. It is possible that the successive calls of the callback are faster than their processing. Therefore, the callback data are stored and answered later.

If the application returns the value GOAL_OK_SUPPORTED from the callback the multiple write response won’t be sent until the function goal_pnioRecWriteFinish is called and processed.

appl/goal_pnio/12_diag_entry

This example shows how to set and clear a diagnostic entry. In the GSDML you can add a free text with up to four placeholders for dynamic values. The parameter errorNumber of the function goal_pnioDiagExtChanDiagAdd sets this values. The configured text is readable in the diagnosis buffer of the controller.

appl/goal_pnio/13_pnio_snmp

This example shows how to switch from PROFINET CC-A to PROFINET CC-B by adding SNMP support. Additionally, it periodically copies data from the output to the input module and supports the DCP blink command.

appl/goal_pnio/14_info_set

This example shows how to update the device identification. In the function appl_setup it is possible to set different device information, like e.g. vendor Id, device ID or vendor name.

appl/goal_pnio/15_config_set

This example is similar to the previous example. The difference is, that the values are written in variables of the goal configuration manager. The example application shows how to set the most common PROFINET configuration variables e.g. vendor id, vendor name, hardware revision, I&M tag function etc. In the function appl_setup it is possible to set these PROFINET configuration values before a new PROFINET instance is created.

appl/goal_pnio/16_device_name

This example shows how to update the device name from the application. Be aware that this is not specification conform and must only be used (if necessary) during development.

appl/goal_pnio/17_process_alert

This example shows how to send an process alarm cyclically. This transfers additional user specific data to the controller. In the appl_setup function, the total length of the alarm payload is adjusted before a new PROFINET instance is created.

appl/goal_pnio/18_dyn_mod_postpone

This example demonstrate how postponing the ExpectedSubmoduleBlock processing works. After the ExpectedSubmoduleBlock request is signaled via its callback, the stack is informed that the processing can be continued later.

appl/goal_pnio/19_subst_val

This examples cyclically monitors the APDU status and the IOPS of the output module. If a status changes the output data buffer is shown. Enabled logging is recommended for this application by defining GOAL_CONFIG_LOGGING and GOAL_CONFIG_LOGGING_TARGET_RAW to 1.

appl/goal_pnio/20_subst_mod

This example shows how to accept a wrong submodule with the same characteristic by using the substitute flag as subslot state.

appl/goal_pnio/21_pnio_snmp_dm

This example is equivalent to application appl/goal_pnio/13_pnio_snmp. But due to Data Mapper usage, process data can be mirrored at Profinet Callback Handler appl_pnioCb.

appl/goal_pnio/22_process_alarm_buf

Cyclically sends process alarms from two threads that additionally transmit user specific data to the controller. The transmitted user specific data can be used to check that the process alarms are sent in order of occurrence.

appl/goal_pnio/24_pnio_snmp_mrp

This example expands the application appl/goal_pnio/13_pnio_snmp by media redundancy protocol (MRP).

appl/goal_pnio/25_dynamic_modules_rpc

This example expands the application 08_dynamic_modules and is designed for multi-core targets.
While the basic behavior of both applications is equal, this example provides 4 instead of 2 slots for dynamically configuration by a PLC.
Plugging submodules into the first two slots will cause their data exchange between communication and application core by Remote Procedure Call.
Plugging submodules into the first two slots will cause their data exchange between communication and application core by Micro Core To Core.

Running the example on single-core targets is possible too. But the behavior of all 4 slots will be the same.

appl/goal_pnio/26_no_simple_dap

This example is similiar to the application 01_simple_io - but it configures and creates the device access point (DAP) by it’s own.

The function goal_pnioCfgDevDapSimpleSet(GOAL_FALSE) deactivates the automatic DAP creation at the GOAL PROFINET stack. In consequence the used module and slots must be configured by the functions goal_pnioCfgDevDapModuleSet, goal_pnioCfgDevDapSlotSet and goal_pnioCfgDevDapSubslotSet.

The application then creates submodules and subslots for the DAP, interface and for each port and plug those. Please refer to following table:

item

slot

subslot

module

submodule

device access point

0x0

0x1

0x11

0x1

interface

0x0

0x8000

0x11

0x2

ports

0x0

0x8001

0x11

0x3

The “ModuleIdentNumber” for each “DeviceAccessPointItem” at the GSD file is also modified to be compliant with the application.

The subslot for the interface must be at least 0x8000 according to the specification.

Initialization

GOAL PROFINET has two fixed steps to create a running instance. These are shown in the following example code. First goal_pnioInit must be called to register the GOAL PROFINET stack in GOAL. After that an instance can be created with goal_pnioNew. The GOAL PROFINET stack configuration is done by two configuration steps. The static configuration like how much slot memory should be reserved and which vendor id should be used must be done between goal_pnioInit and goal_pnioNew. This API starts with goal_pnioCfg. After goal_pnioNew all other APIs can be used like creating a slot or a module.

In GOAL this functionality matches the appl_* pattern. The function goal_pnioInit must be called from appl_init whereas the later init functionality like goal_pnioCfg, goal_pnioNew and setting up the device structure must be put into appl_setup. After the GOAL initialization has finished the data handling has to be done in appl_loop or by registering an own main loop handler in GOAL. Also using an external thread is possible as most of the GOAL PROFINET functionality is thread-safe.

static GOAL_PNIO_T *pPnio; /**< GOAL PROFINET handle */ GOAL_STATUS_T appl_init( void ) { GOAL_STATUS_T res; /* GOAL result */ /* initialize GOAL PROFINET */ res = goal_pnioInit(); if (GOAL_RES_ERR(res)) { goal_logErr("failed to initialize GOAL PROFINET"); } return res; } GOAL_STATUS_T appl_setup( void ) { GOAL_STATUS_T res; /* GOAL result */ /* set default values for all GOAL PROFINET instances */ /* (these can be overwritten as often as needed, as each instance creates a copy) */ /* vendor id = 0x1234 */ res = goal_pnioCfgVendorIdSet(0x1234); if (GOAL_RES_ERR(res)) { goal_logErr("failed to set the GOAL PROFINET vendor id"); return res; } /* create a new GOAL PROFINET instance */ res = goal_pnioNew(&pPnio, /* GOAL PROFINET instance */ 0, /* GOAL PROFINET instance id */ appl_pnioCb /* GOAL PROFINET callback */ ); if (GOAL_RES_ERR(res)) { goal_logErr("failed to create a new PROFINET instance"); return res; } /* create slots, subslots, modules, submodules, link them together ... */ } void appl_loop( void ) { /* check if a GOAL PROFINET connection is established (see callback API) */ /* handle module data */ }