Skip to content

FanucAdapter

Introduction

FanucAdapter is an application that can be used to get data from Fanuc Series30 devices. It provides data readings from the connected Fanuc controller utilizing Focas½ library. It can serve multiple requests coming from multiple applications or threads.

FanucAdapter Details

FanucAdapter provides basically two types of data sources. First type is the memory address of a specific memory region. The allowed request format for this kind of data is given in the following table. It should be kept in mind that value_type is the enumerated values representing the type of the data. By utilizing this field, the reader side can perform the correct type-casting operation. A detailed explanation of memory reading functionality is provided in PMC read functionality usage

$DATASOURCE Type "value_type"
PMC/MEM/MEM_REGION/PARAMETER unsigned char 3

The second type is the predefined data sources made available through special focas library function calls. The list of the provided data sources is given in the following table:

# $DATASOURCE Type "value_type"
1 SYSTEM_INFO string 11
2 RUN_STATUS int 6
3 MOTION_STATUS int 6
4 ALARM_STATUS int 6
5 MACHINE_PART_COUNT int 6
6 CYCLE_TIME_MIN int 6
7 CYCLE_TIME_MSEC int 6
8 ACT_FEED_RATE double 10
9 ACT_SPINDLE double 10
10 ABSOLUTE_AXIS_{x} double 10
11 MACHINE_AXIS_{x} double 10
12 RELATIVE_AXIS_{x} double 10
13 DISTANCE_AXIS_{x} double 10
14 SERVO_LOADMETER_{y} double 10
15 SERVO_LOADPERCENTAGE_{y} double 10
16 SERVO_LOADCURRENT_{y} double 10
17 SPINDLE_LOADMETER_{z} double 10
18 SPINDLE_MOTORSPEED_{z} double 10
19 SPINDLE_SPEED_{z} double 10
20 EXEC_PRG_NAME string 11
21 TOOL_NUM double 10
22 TOOL_GROUP_NUM int 6
23 TOOL_USEORDER_NUM int 6
24 ACT_TOOL_EDGE double 10
25 CONVERTED_SPINDLE_SPEED double 10
26 SPECIFIED_SURFACE_SPEED double 10
27 CLAMP_MAX_SPINDLE_SPEED double 10
28 PATH_NUMBER int 10
29 PATH_NUMBER_MAX int 10
30 MAINBOARD_ID string 11
31 CPU_ID string 11
32 SPINDLE_COUNT int 10
33 SPINDLE_NAMES string 11
34 TOOL_COUNT_CURR_GROUP double 10
35 MODAL_DATA_M double 10
36 MODAL_INFO_M string 11
37 MODAL_DATA_S double 10
38 MODAL_INFO_S string 11
39 MODAL_DATA_T double 10
40 MODAL_INFO_T string 11
41 TOOL_TYPE_{t} double 10
42 H_CODE_{t} int 6
43 D_CODE_{t} int 6
44 TOOL_EDGE_{t} int 6
45 G_CODE_{t} int 6
46 W_CODE_{t} int 6
47 TOOL_GNO_{t} int 6
48 TOOL_GRP_{t} int 6
49 TOOL_RESERVED1_{t} double 10
50 TOOL_RESERVED2_{t} double 10
51 ACT_PRG_NUM int 6
52 ACT_MAIN_PRG_NUM int 6
53 AUT_STATUS int 6
54 ALARM_LAST_MSG_{t} string 11
55 ALARM_LAST_NUM_{t} double 10

Note-1: {x} is the axis number [1…MAX_AXIS] i.e. ABSOLUTE_AXIS_3

Note-2: {y} is the servo number [1…MAX_AXIS] i.e. SERVO_LOADMETER_2

Note-3: {z} is the spindle number [1…MAX_SPINDLE] i.e. SPINDLE_SPEED_1

Note-4: {t} is the tool number i.e. TOOL_TYPE_1

Description of Parameters

In this section, the pre-defined data sources are explained including their respective sample readings. Moreover, the corresponding focas library function name is provided for those demanding more information.

1. System Info

It returns the system info composed of model, version and max axis information of the system as follows;

31 M G41Z 32

Fanuc 31i-B has 32 supported axes. Please refer to cnc_sysinfo function of Focas Library.

2. Run Status

It returns the run status as one of the following options;

# Status
0 STOP
1 HOLD
2 START
3 MSTR(jog mdi)
4 RESTART(not blinking)
5 PRSR(program restart)
6 NSRC(sequence number search)
7 RESTART(blinking)
8 RESET
9 (Not used)
10 (Not used)
11 (Not used)
12 (Not used)
13 HPCC(during RISC operation)

Please refer to cnc_statinfo function of Focas Library.

3. Motion Status

It returns the motion status as one of the following options;

# Status
0 *
1 MOTION
2 DWELL
3 WAIT (waiting:only TT)

Please refer to cnc_statinfo function of Focas Library.

4. Alarm Status

It returns the alarm status of CNC. Please refer to cnc_alarm2 function of Focas Library.

5. Machine Part Count

It returns the number of current part in progress.

6. Cycle Time - Parameters 6 and 7

Has two parts: minute and millisecond [0…60000). Please refer to cnc_rdparam_ext function of Focas Library.

7. Dynamic Data - Parameters 8 to 13

Depending on the currently controlled axis count, those parameters return run-time values on request. The values are sampled together and it is beneficial to read them together. Please refer to cnc_rddynamic2 function of Focas Library.

8. Axis Data - Parameters 14 to 19

Depending on the currently controlled axis and spindle count, those parameters return run-time values on request. Please refer to cnc_rdaxisdata function of Focas Library.

9. Executed Program Name

Parameter 20 returns the name of the program being executed. "//CNC_MEM/USER/PATH1/SAMPLE" is an example program name returned from the fanuc controller.

Tool Data 1 - Parameter 21 to 24

Returns the tool information of the current tool (number, group number, useorder number, edge number).

Speeds - Parameter 25 to 27

Returns the tool speed data (converted spindle speed, specified surface speed, maximum spindle speed).

Path Data - Parameter 28 and 29

PATH_NUMBER returns the current path the adapter is reading from. PATH_NUMBER_MAX returns the number of available (configured) paths.

Hardware Data - Parameter 30 and 31

Returns the hardware id for the requested source as string.

Spindle Data - Parameter 32 and 33

SPINDLE_COUNT returns the number of spindles for the requested path context. SPINDLE_NAMES returns the names of all spindles in the requested path context.

Tool count current Group - Parameter 34

Returns the amount of tools in the current tool group.

Returns the given modal data. MODAL_DATA_M/S/T returns the last issued M/S/T-command MODAL_INFO_M/S/T returns additional information like "is positive", "is negative", "has decimal point", "no decimal point", "in present block", or "no present block".

Tool Data 2 - Parameter 41 to 50

Returns the requested number of tool management data beginning from the specified index. Example: TOOL_TYPE_2_C4 In this example, the tool type is read from tool 2 to 5. (4 values in total). Unlike the other parameters that can be read as an array, an index must always be specified for these data sources (TOOL_TYPE_1). The usage of (TOOL_TYPE) is not permitted and will lead to an error!

Reading all axis/servo/spindle data at once

In order to receive all the axes/spindle/servo data in one request, you should provide the data source string without the trailing underscore and axes/spindle/servo number. The following table shows the corresponding data sources;

# $DATASOURCE Type "value_type"
1 ABSOLUTE_AXIS double 10
2 MACHINE_AXIS double 10
3 RELATIVE_AXIS double 10
4 DISTANCE_AXIS double 10
5 SERVO_LOADMETER double 10
6 SERVO_LOADPERCENTAGE double 10
7 SERVO_LOADCURRENT double 10
8 SPINDLE_LOADMETER double 10
9 SPINDLE_MOTORSPEED double 10
10 SPINDLE_SPEED double 10

For instance, if the controlled axis count is 3 and ABSOLUTE_AXIS is requested as the data source, the value in the response will be an array containing 3 different axis readings as ["123.456", "456.789", "789.123"].

Reading information from specific path

Some datasources return data in context of the CNC path. To specify the path context the path number can be added to the parameter as a prefix, separated by a vertical line, like "pathnumber|". Example: 1|ABSOLUT_AXIS_1 (this will return the absolute position of axis 1 from path 1). This functionality is supported both in the parameter service and subscription service.

Read data in a specific range

FanucAdapter allows to access slices of arrays to improve the performance of the data transmission. To use this feature the parameter request has to be extended by an index and a count, like this: TOOL_TYPE_5_C5. In this example, the slice will contain a value array starting at tool 5 and containing the 4 following tools. In the event that the number of data to read is greater than the number of actually existing data, the maximum number is read and returned. This method can be used for all parameters that are read as an array.

PMC read functionality usage

FanucAdapter provides PMC memory reading support in one of the formats below. Please refer to section PMC memory read for details.

Formats
PMC/MEM/MEM_REGION/PARAMETER
PMC/MEM/MEM_REGION/PARAMETER.$BIT
PMC/MEM/MEM_REGION/PARAMETER#$LENGTH

Note-1: $MEM_REGION represents the memory region letters (A, B, C, D). Please refer to table below for details.

Note-2: $PARAMETER represents the parameter start address. Please refer to table below for details.

Note-3: $BIT represents the bit number (0..7) when boolean value is requested.

Note-4: $LENGTH represents the number of bytes requested.

The referenceable range of Series 0i-F, 30i/31i/32i/35i-B, PMi-A are given in the following table. It is important to declare that the content of the table is generated by referring the user manual handed over with focas library.

IDcode Kind of PMC address 1st to 5th path PMC DSC PMC
$MEM_REGION $PARAMETER $PARAMETER $PARAMETER $PARAMETER $PARAMETER
PMC Memory-A PMC Memory-B PMC Memory-C PMC Memory-D
0 G (Output signal from PMC to CNC) 0-767 1000-1767 2000-2767 3000-3767 4000-4767 5000-5767 6000-6767 7000-7767 8000-8767 9000-9767 0-767 1000-1767 2000-2767 3000-3767 4000-4767 5000-5767 6000-6767 7000-7767 8000-8767 9000-9767 0-767 1000-1767 2000-2767 3000-3767 4000-4767 5000-5767 6000-6767 7000-7767 8000-8767 9000-9767 0-767 1000-1767 2000-2767 3000-3767 4000-4767 5000-5767 6000-6767 7000-7767 8000-8767 9000-9767 0-767
1 F (Input signal to PMC from CNC) 0-767 1000-1767 2000-2767 3000-3767 4000-4767 5000-5767 6000-6767 7000-7767 8000-8767 9000-9767 0-767 1000-1767 2000-2767 3000-3767 4000-4767 5000-5767 6000-6767 7000-7767 8000-8767 9000-9767 0-767 1000-1767 2000-2767 3000-3767 4000-4767 5000-5767 6000-6767 7000-7767 8000-8767 9000-9767 0-767 1000-1767 2000-2767 3000-3767 4000-4767 5000-5767 6000-6767 7000-7767 8000-8767 9000-9767 0-767
2 Y (Output signal from PMC to machine) 0-127 200-327 400-527 600-727 1000-1127 0-127 200-327 400-527 600-727 1000-1127 0-127 200-327 400-527 600-727 1000-1127 0-127 200-327 400-527 600-727 1000-1127 0-127
3 X (Input signal to PMC from machine) 0-127 200-327 400-527 600-727 1000-1127 0-127 200-327 400-527 600-727 1000-1127 0-127 200-327 400-527 600-727 1000-1127 0-127 200-327 400-527 600-727 1000-1127 0-127
4 A (Message display) *Display request 0-249 0-249 0-499 0-749 0-249
A (Message displsy) Display status 9000-9249 9000-9249 9000-9499 9000-9749 9000-9249
5 R (Internal relay) 0-1499 0-7999 0-15999 0-59999 0-1499
R (System relay) 9000-9499 9000-9499 - - 9000-9499
6 T (Timer) *Variable timer 0-79 0-499 0-999 0-999 0-79
T (Timer) *Variable timer precision 9000-9079 9000-9499 9000-9999 9000-9999 9000-9079
7 K (Keep relay) *User range 0-19 0-99 0-199 0-299 0-19
K (Keep relay) *System range 900-999 900-999 900-999 900-999 900-999
8 C (Counter) *Changeable counter 0-79 0-399 0-799 0-1199 0-79
C (Counter) *Fixed counter 5000-5039 5000-5199 5000-5399 5000-5599 5000-5039
9 D (Data table) 0-2999 0-9999 0-19999 0-59999 0-2999
10 M (Input signal from other PMC path) 0-767 0-767 0-767 0-767 -
11 N (Output signal to other PMC path) 0-767 0-767 0-767 0-767 -
12 E (Extra relay) 0-9999 0-9999 0-9999 0-9999 -
13 Z (System relay) - - 0-499 0-499 -

Client App Development Guide

Data Access Services

Subscriptionservice

With the subscription service, previously defined variables can be subscribed to and will be published continually. The available variables are listed in the table above. All subscribed variables are provided cyclically as a payload on the DataBus and can be read via "consumer". More information can be found in chapter subscription-service. The default publishing cycle is 100 ms. It can be adjusted in the specific config section of the metaconfig. Values >= 100 ms are allowed. If the supplied value is smaller than this, the default value will be used. "min": 100, "max": 2147483647, "default": 100

Example configuration of metaconfig for subscription service

In order to be able to use the subscription service, you must make the following settings in the Metaconfig of your app, in addition to the implementation in the code described in chapter [...].

"datasourceConfig": {
        "requiredDatasource": [
          {
            "datasourceId": "FS30_NCU1",
            "type": "FANUC",
            "services": {
              "subscription-service/v1":{
                "subscriptions":[
                  {
                    "messageId":"fanuc_lf_data",
                    "messageName":"userdata",
                    "quality":"lf",
                    "datapoints":[
                        {
                            "address": "ALARM_STATUS"
                        },
                        {
                            "address": "ACT_FEED_RATE"
                        }
                    ]
                  }
                ]
              }
            }
          }
        ]
    }
According to the settings that you make here, the fanucadaper is automatically parameterized. Entries that you can freely change or add are "address", here you can enter the desired variable name from the table above, and "messageName", this is the name that you must use in your code to read out the desired values.

Parameterservice

With the prameter service, previously defined variables can be read by synchronous request/response communication. More information can be found in chapter parameter-serice

Example configuration of metaconfig for parameter service

The client application should be configured correctly. In the following code snippet, a minimal required data source configuration details are written for utilizing parameter service of FanucAdapter.

"datasourceConfig": {
  "requiredDatasource": [
    {
      "datasourceId": "FS30_NCU1",
      "type": "FANUC",
      "services": {
        "parameter-service/v1": {
          "access": [
            {
              "accessType": "r",
              "datapoints": [
                {
                  "address": ""
                }
              ]
            }
          ]
        }
      }
    }
  ]
}

Read Methods

Single parameter read

For requesting a single data source from the adapter, the following code snippet could be utilized. This is an example for parameter-service read. It is important to note that all the reader application codes are provided in C++ language. For other supported language examples, AppSDK documentation should be examined.

std::vector<std::string> dataSourceNames;
dsaapiNS::DataSourceAccess::GetDataSourceNames("FANUC", dataSourceNames);
std::shared_ptr<dsaapiNS::DataSource> ncu = nullptr;
dsaapiNS::DataSourceAccess::GetDataSource(dataSourceNames[0], ncu);
auto parameterServices = ncu->GetParameterServices();
auto paramDef = std::make_shared<dsaapiNS::ParameterDefinition>($DATASOURCE);
parameterServices[0]->ReadParameter(paramDef);

Note: For example $DATASOURCE is "ACT_FEED_RATE".

The result of the request including the data readings could be extracted by using the following code snippet.

auto pvo = paramDef->GetValueObject();
auto values = pvo.GetValues(); // Return std::vector<std::pair<std::string, int>>
std::string returnedValueAsString = values[0].first; // i.e. "-12.03"
int returnedValueType = values[0].second;  // i.e. 10

Multi parameter read

For reading multi parameter, ReadParameters() method should be called. For detailed information, please refer to the AppSDK documentation.

PMC memory read

Client app can read PMC memory via suppling following patterns for AppSDK ReadParameter function (Multi read ReadParameters is not supported for PMC read).

PMC/MEM/MEM_REGION/PARAMETER

This pattern reads $PARAMETER in the $MEM_REGION region one byte.

Examples:

PMC/MEM/R/1700 from R memory region.
PMC/MEM/D/1500 from D memory region.

Possible Return Values (in the same order above):

["FF"]
["7C"]

PMC/MEM/MEM_REGION/PARAMETER.$BIT

This pattern reads bit number $BIT from address $PARAMETER of the $MEM_REGION and returns.

Note: Valid range for $BIT is 0-7.

Examples:

PMC/MEM/R/1700.0 => Reads 0th bit of address 1700 from R memory region.
PMC/MEM/D/1500.7 => Reads 7th bit of address 1500 from D memory region.

Possible Return Values (in the same order above, single bit value only, LSb first, encoded as string):

["1"]
["0"]

PMC/MEM/MEM_REGION/PARAMETER#$LENGTH

This pattern reads $LENGTH number of bytes starting from address $PARAMETER of the $MEM_REGION and returns it in the format described below.

Examples:

PMC/MEM/R/1700#3 => Reads 1700, 1701, 1702 from R memory region.
PMC/MEM/D/1500#2 => Reads 1500, 1501 from D memory region.

Possible Return Values (in the same order above, LSB first):

["01", "AA", "3F"]
["E1", "24"]

All of these patterns return an object which contains return code and value object. Value object contains value type and value(s) as array of string.

The raw JSON object returned by the function call "ReadParameter" for "PMC/MEM/R/1700#4" address parameter is as follows:

{
  "return_code": 0, /* 0:success, 1:error */
  "return_value": {
    "value_type": 3, /* 0:Invalid, 1:Bool, 3:Uchar, 6:Long, 10:Double, 11:String */
    "value": ["FF", "AA", "01", "89"] /* return values are HEX as string.*/
  }
}

Note-1: Comments are reference only, not valid JSON file.

Note-2: For further details about return codes and value types please refer the AppSDK documents.

For the example above, "value" is a string array that contains "FF", "AA", "01", "89" data. Field "value_type" indicates the type of this hex values. For this request, it is received as 3 (UChar). So cast the data to individual unsigned bytes i.e. 0xFF or cast to 0x8901AAFF in order to use it as uint32_t depending on the application needs.

The following C++ code snippet shows how to access individual values from AppSDK.

auto pvo = paramDef->GetValueObject();
auto values = pvo.GetValues(); // returns std::vector<std::pair<std::string, int>>

Developers check the type of return value and size then must cast the return values correspondingly. For example values[2] in the example above, is equal to "01" as string.

This function supports only PMC Memory-D as a PMC memory region. For valid range of $PARAMETER check related documents from Fanuc Focas Library. For example for R memory region valid range is 0-59999. Below table is a copy of this info from library documents.

Appendix

Configuration Details for FanucReader App

The following parts provide detailed information about the FanucReader client application that is available for installation on Insights Hub.

The provided example reader app polls hard-coded parameters in loop with 1 second intervals. To override the poll time interval (seconds), use the following setting (optional) in specificConfig section of reader app meta config.

"specificConfig": {
  "FanucPollTime": 0.5
}

Example reader app which is provided as demo kit, optionally reads FanucSingleReadParameters and FanucMultiReadParameters arrays written inside specificConfig section of its meta config. If these arrays are provided, the reader app requests the parameters that are found in the arrays only, in a cyclic order, with FanucPollTime intervals, instead of requesting the hard-coded parameters in its code. If you want to use default values which are hard-coded, these fields should be removed in the reader app meta config completely.

An example usage of the mentioned fields are shown below.

"specificConfig": {
  "FanucSingleReadParameters": [
    "PMC/MEM/R/1700",
    "PMC/MEM/R/1700.3",
    "PMC/MEM/R/1700.5",
    "PMC/MEM/R/1700#3",
    "SYSTEM_INFO",
    "RUN_STATUS",
    "EXEC_PRG_NAME",
    "ALARM_STATUS",
    "ACT_FEED_RATE",
    "ACT_SPINDLE",
    "ABSOLUTE_AXIS_1",
    "ABSOLUTE_AXIS_2",
    "ABSOLUTE_AXIS_3",
    "MACHINE_AXIS_1",
    "MACHINE_AXIS_2",
    "MACHINE_AXIS_3",
    "RELATIVE_AXIS_1",
    "RELATIVE_AXIS_2",
    "RELATIVE_AXIS_3",
    "DISTANCE_AXIS_1",
    "DISTANCE_AXIS_2",
    "DISTANCE_AXIS_3",
    "SERVO_LOADMETER_1",
    "SERVO_LOADMETER_2",
    "SERVO_LOADMETER_3",
    "SERVO_LOADPERCENTAGE_1",
    "SERVO_LOADPERCENTAGE_2",
    "SERVO_LOADPERCENTAGE_3",
    "SERVO_LOADCURRENT_1",
    "SERVO_LOADCURRENT_2",
    "SERVO_LOADCURRENT_3",
    "SPINDLE_LOADMETER_1",
    "SPINDLE_MOTORSPEED_1",
    "SPINDLE_SPEED_1",
    "MACHINE_PART_COUNT",
    "CYCLE_TIME_MIN",
    "CYCLE_TIME_MSEC"
  ],
  "FanucMultiReadParameters": [
    "PMC/MEM/R/1700",
    "PMC/MEM/R/1700.3",
    "PMC/MEM/R/1700.5",
    "PMC/MEM/R/1700#3",
    "SYSTEM_INFO",
    "RUN_STATUS",
    "EXEC_PRG_NAME",
    "ALARM_STATUS",
    "ACT_FEED_RATE",
    "ACT_SPINDLE",
    "ABSOLUTE_AXIS_1",
    "ABSOLUTE_AXIS_2",
    "ABSOLUTE_AXIS_3",
    "MACHINE_AXIS_1",
    "MACHINE_AXIS_2",
    "MACHINE_AXIS_3",
    "RELATIVE_AXIS_1",
    "RELATIVE_AXIS_2",
    "RELATIVE_AXIS_3",
    "DISTANCE_AXIS_1",
    "DISTANCE_AXIS_2",
    "DISTANCE_AXIS_3",
    "SERVO_LOADMETER_1",
    "SERVO_LOADMETER_2",
    "SERVO_LOADMETER_3",
    "SERVO_LOADPERCENTAGE_1",
    "SERVO_LOADPERCENTAGE_2",
    "SERVO_LOADPERCENTAGE_3",
    "SERVO_LOADCURRENT_1",
    "SERVO_LOADCURRENT_2",
    "SERVO_LOADCURRENT_3",
    "SPINDLE_LOADMETER_1",
    "SPINDLE_MOTORSPEED_1",
    "SPINDLE_SPEED_1",
    "MACHINE_PART_COUNT",
    "CYCLE_TIME_MIN",
    "CYCLE_TIME_MSEC"
  ]
}

For instance, to request only ACT_SPINDLE with 0.5 second intervals, use the following JSON content with the sample reader app.

"specificConfig": {
  "FanucPollTime": 0.5,
  "FanucSingleReadParameters": ["ACT_SPINDLE"],
  "FanucMultiReadParameters": []
}

Example Apps

This chapter is designed as a guide for developing a reader application that is compatible with AppSDK. Even though examples are in C++, notice that there are other available language options. Please refer to AppSDK documentation for further details.

Using subscriptionservice

Sample metaconfig

{   
    "databusConfig": {
        "permissions":[
            {
                "source": "fanuc_lf_data",
                "quality": "quality_all",
                "permission": "read"
            }
        ],
        "credentials":{
          "username":"",
          "password":""
        }
    },
    "datasourceConfig": {
        "requiredDatasource": [
          {
            "datasourceId": "FS30_NCU1",
            "type": "FANUC",
            "services": {
              "subscription-service/v1":{
                "subscriptions":[
                  {
                    "messageId":"fanuc_lf_data",
                    "messageName":"userdata",
                    "quality":"lf",
                    "datapoints":[
                        {
                            "address": "ALARM_STATUS"
                        },
                        {
                            "address": "ABSOLUTE_AXIS_1"
                        },
                        {
                            "address": "MAINBOARD_ID"
                        },
                        {
                            "address": "PATH_NUMBER"
                        },
                        {
                            "address": "2|PATH_NUMBER"
                        },
                        {
                            "address": "PATH_NUMBER_MAX"
                        }
                    ]
                  }
                ]
              }
            }
          }
        ]
    }
}
This section must be added to the metaconfig of your app to run the program below as expected.

Sample programm

#include "EdgeAPI.h"
#include "Logging.h"
#include "EdgeStatus.h"
#include "Databus.h"

int main()
{
    // inititalize Edge API
    app_sdk::edge_api::Initialize();

    // Create logger instance name has to by unique
    auto logger = app_sdk::log_api::CreateLoggerInstance("fanucsubscriptionconsumer");
    logger->AddAppender(app_sdk::log_api::LoggerAppenderType::CONSOLE);

    // Get databus instance
    sinumerik_edge::databus::DataBus &bus = sinumerik_edge::databus::DataBus::getInstance();
    logger->Error(std::to_string(bus.getDataBusState()));

    // Create a list of message ID's for consumer
    // This is according to messageName in metaconfig or appconfig in section subscription-service/v1
    std::vector<std::string> consumerIdList = {"userdata"};

    // Creating the consumer and register it to the databus.
    sinumerik_edge::databus::Consumer consumer(consumerIdList);
    sinumerik_edge::databus::Status status;
    status = bus.registerConsumer(consumer);

    // Check if consumer is registered succsessfully
    if(status != sinumerik_edge::databus::Status_OK)
    {
        logger->Error("Failed to register consumer");
        exit(1);
    }
    else
    {
        logger->Info("Registered consumer");
    }

    // Trying to get results
    // loops through as long as consumer works as expected
    logger->Info("Trying to get results!");
    sinumerik_edge::databus::MessageStruct result;

    do
    {
        // Get data from consumer
        result = consumer.pop();

        // Check if data read was successful
        logger->Info("Result State: " + std::to_string(result.getStatus()));   

        // Print result
        logger->Info("POP RESULT: " + result.getMessageId() + "," + result.getPayload());

    } while(result.getStatus() == sinumerik_edge::databus::Status_OK);

    return 0;
}

Note: "userdata" added to "consumerIdList" is related to "messageName":"userdata" in metaconfig.

This is the output generated by the sample app:

POP RESULT: userdata,
{
    "header" : {
        "body" : {
            "datapoint" : [
            {
                "address" : "ALARM_STATUS",
                "content" : {
                    "value" : ["0"]
                },
                "period_ms" : -1,
                "quality_mode" : "lf",
                "timestamp" : "2021-06-22 13:33:32.860295"
            },
            {
                "address" : "ABSOLUTE_AXIS_1",
                "content" : {
                    "value" : ["0"]
                },
                "period_ms" : -1,
                "quality_mode" : "lf",
                "timestamp" : "2021-06-22 13:33:32.860295"
            },
            {
                "address" : "MAINBOARD_ID",
                "content" : {
                    "value" : ["Group: 256 HWID: 256 ID1: 0033c400 ID2: 00000000"]
                },
                "period_ms" : -1,
                "quality_mode" : "lf",
                "timestamp" : "2021-06-22 13:33:32.866075"
            },
            {
                "address" : "PATH_NUMBER",
                "content" : {
                    "value" : ["1"]
                },
                "period_ms" : -1,
                "quality_mode" : "lf",
                "timestamp" : "2021-06-22 13:33:32.858684"
            },
            {
                "address" : "PATH_NUMBER_MAX",
                "content" : {
                    "value" : ["2"]
                },
                "period_ms" : -1,
                "quality_mode" : "lf",
                "timestamp" : "2021-06-22 13:33:32.858684"
            },
            {
                "address" : "2|PATH_NUMBER",
                "content" : {
                    "value" : ["2"]
                },
                "period_ms" : -1,
                "quality_mode" : "lf",
                "timestamp" : "2021-06-22 13:33:32.884626"
            }
            ]
        },
        "key" : "dataobject",
        "message_type" : "dataobject",
        "source_id" : "fanuc_adapter"
    }
}

Using parameterservice

Note-1: The below code sample ignores most of the error and exception handling for simplicity.

Note-2: The metaconfig for paramter-service is not parameter dependent, the example prameter-service configuration above can be used.

//////////////////////////////////////////////////////////////////////////////////////////
///
/// @brief FanucReader Client to test FanucAdapter
/// @file fanucreader.cpp
/// @date 2020
/// @copyright Copyright (c) Siemens AG 2020  All Rights Reserved.
///
//////////////////////////////////////////////////////////////////////////////////////////

#include "Databus.h"
#include "EdgeAPI.h"
#include "EdgeStatus.h"
#include "Logging.h"
#include <iostream>
#include <stdlib.h>
#include <string>
#include <thread>
#include <chrono>
#include <vector>

using namespace std;

// Abbreviations for namespaces
namespace edgeapiNS = app_sdk::edge_api;
namespace dsaapiNS = app_sdk::dsa_api;

std::string getTypeAsString(const int &valueType) {
    static const std::vector<std::string> typeNames = {
        "invalid",
        "Bool",
        "Char",
        "UChar",
        "Int",
        "UInt",
        "Long",
        "ULong",
        "LongLong",
        "ULongLong",
        "Double",
        "String",
        "ValueArray",
        "DateTime",
    };

    return typeNames[valueType];
}

void PrintResponse(std::vector<std::shared_ptr<dsaapiNS::ParameterDefinition>>, std::shared_ptr<app_sdk::log_api::Logger>);
void PrintResponse(std::shared_ptr<dsaapiNS::ParameterDefinition>, std::shared_ptr<app_sdk::log_api::Logger>);

int main() {

    // Initialize EdgeAPI for logger with config
    edgeapiNS::Initialize();

    auto logger = app_sdk::log_api::CreateLoggerInstance("fanucreaderapp");
    logger->AddAppender(app_sdk::log_api::LoggerAppenderType::JOURNAL);

    // Below is parameter services common
    dsaapiNS::DataSourceAccess::Initialize();

    // Below is Fanuc datasource list to be tested
    std::vector<std::string> parametersForSingleRead = {
        "ACT_FEED_RATE",
        "ACT_SPINDLE",
        "ABSOLUTE_AXIS",
        "PMC/MEM/R/1700#2",
        "MACHINE_PART_COUNT",
        "CYCLE_TIME_MIN",
        "CYCLE_TIME_MSEC",
        "EXEC_PROG_NAME",
    };

    // Define a parameter vector to be used for Multi Read call of AppSDK
    std::vector<std::string> parametersForMultiRead = parametersForSingleRead;

    auto singleParameterCount = parametersForSingleRead.size();

    // Default polling interval.
    double pollingInterval = 1.00;
    auto ret = edgeapiNS::GetAppSpecificConfigSection("/FanucPollTime");
    if (ret.first.Success()) {
        pollingInterval = std::stod(ret.second); // Can throw exception.
    }

    // Using AppSDK get data source section of run time config of this app
    // First parameter is type of data source.
    std::vector<std::string> dataSourceNames;
    dsaapiNS::DataSourceAccess::GetDataSourceNames("FANUC", dataSourceNames);
    auto defaultDataSource = dataSourceNames[0];
    logger->Info("FANUC Data source name:" + defaultDataSource);

    // Obtain the ncu object to issue the requests.
    std::shared_ptr<dsaapiNS::DataSource> ncu = nullptr;
    dsaapiNS::DataSourceAccess::GetDataSource(defaultDataSource, ncu);

    // Using datasource ncu obtain parameter services which will communicate through adapterframework.
    auto parameterServices = ncu->GetParameterServices();

    // Get the first parameter service, others maybe reserved for future usage.
    auto paramSVC = parameterServices[0];
    logger->Info("FANUC Parameter service name is:" + paramSVC->GetName());

    // Create empty vector of parameter defitinion objects
    std::vector<std::shared_ptr<app_sdk::dsa_api::ParameterDefinition>> multiParamDefs{};
    // Filling the multiParamDefs vector.
    for (const auto &parameterName : parametersForMultiRead) {
        auto paramDef = std::make_shared<dsaapiNS::ParameterDefinition>(parameterName);
        multiParamDefs.push_back(paramDef);
    }

    // The request number.
    size_t requestIndex = 0;

    // loop contains both single and multi parameter read in the order
    while (true) {

        // Single Parameters
        if(requestIndex < singleParameterCount) {

            // Create parameter definition object with its address. (supplied by dataTypes)
            auto paramDef = std::make_shared<dsaapiNS::ParameterDefinition>(parametersForSingleRead[requestIndex]);

            // Try to read parameter with service and parameter definition.
            logger->Info("------------ Single Read " + std::to_string(requestIndex) + " ------------");
            auto res = paramSVC->ReadParameter(paramDef);

            if (res.Success()) {
                // Print the result.
                PrintResponse(paramDef, logger);
            } else {
                // Print error code and message
                logger->Info("FANUC ReadParameter Error-" + std::to_string(res.GetCode()) + ": " + res.GetMessage());
            }

            // Advance the index.
            ++requestIndex;
        }

        // Multi Parameters
        else {

            // Try to read parameter with service and parameter definition.
            auto res = paramSVC->ReadParameters(multiParamDefs);

            logger->Info("------------ Multi Read ------------");
            if (res.Success()) {
                // Print all results.
                PrintResponse(multiParamDefs, logger);
            } else {
                // Print error code and message
                logger->Info("FANUC ReadParameters Error-" + std::to_string(res.GetCode()) + ": " + res.GetMessage());
            }

            // Reset the index.
            requestIndex = 0;
        }

        // Some arbitrary delay for fun.
        std::this_thread::sleep_for(std::chrono::duration<double>(pollingInterval));
    }

    // Should not reach here.
    return EXIT_FAILURE;
}

void PrintResponse(std::vector<std::shared_ptr<dsaapiNS::ParameterDefinition>> response,
    std::shared_ptr<app_sdk::log_api::Logger> logger) {
    for (size_t i = 0; i < response.size(); ++i) {

        auto& paramDef = response[i];
        auto pvo = paramDef->GetValueObject();
        auto values = pvo.GetValues();

        logger->Info("Parameter: " + paramDef->GetParamName());

        if(!values.empty()) {
            logger->Info("   value_type: " + getTypeAsString(values[0].second));
        }

        // Loop through all values
        for (const auto &val : values) {
            logger->Info("   value: " + val.first);
        }
    }
}

void PrintResponse(std::shared_ptr<dsaapiNS::ParameterDefinition> response,
    std::shared_ptr<app_sdk::log_api::Logger> logger) {

    std::vector<std::shared_ptr<dsaapiNS::ParameterDefinition>> responseVector = { response };
    PrintResponse(responseVector, logger);
}

Below is an example output of the code above, working in parallel with FanucAdapter.

------------ Single Read 0 ------------
Parameter: ACT_FEED_RATE
   value_type: Double
   value: 0
------------ Single Read 1 ------------
Parameter: ACT_SPINDLE
   value_type: Double
   value: 1001
------------ Single Read 2 ------------
Parameter: ABSOLUTE_AXIS
   value_type: Double
   value: -40.969
   value: -0.468
   value: -102.863
------------ Single Read 3 ------------
Parameter: PMC/MEM/R/1700#2
   value_type: UChar
   value: 25
   value: 28
------------ Single Read 4 ------------
Parameter: MACHINE_PART_COUNT
   value_type: Long
   value: 3
------------ Single Read 5 ------------
Parameter: CYCLE_TIME_MIN
   value_type: Long
   value: 9023
------------ Single Read 6 ------------
Parameter: CYCLE_TIME_MSEC
   value_type: Long
   value: 11952
------------ Single Read 7 ------------
Parameter: EXEC_PRG_NAME
   value_type: String
   value: //CNC_MEM/USER/PATH1/SAMPLE
------------ Multi Read ------------
Parameter: ACT_FEED_RATE
   value_type: Double
   value: 0
Parameter: ACT_SPINDLE
   value_type: Double
   value: 1001
Parameter: ABSOLUTE_AXIS
   value_type: Double
   value: -40.969
   value: -0.468
   value: -102.863
Parameter: PMC/MEM/R/1700#2
   value_type: UChar
   value: 25
   value: 28
Parameter: MACHINE_PART_COUNT
   value_type: Long
   value: 3
Parameter: CYCLE_TIME_MIN
   value_type: Long
   value: 9023
Parameter: CYCLE_TIME_MSEC
   value_type: Long
   value: 11952
Parameter: EXEC_PRG_NAME
   value_type: String
   value: //CNC_MEM/USER/PATH1/SAMPLE

Reference

For all references above, see Fanuc Focas ½ Library version 4.15 documentation

Also see:

AppSDK

Parameter Service

Any questions left?

Ask the community


Except where otherwise noted, content on this site is licensed under the The Siemens Inner Source License - 1.1.