/********************************************************************* * _ _ _ * _ __ | |_ _ | | __ _ | |__ ___ * | '__|| __|(_)| | / _` || '_ \ / __| * | | | |_ _ | || (_| || |_) |\__ \ * |_| \__|(_)|_| \__,_||_.__/ |___/ * * www.rt-labs.com * Copyright 2021 rt-labs AB, Sweden. * * This software is dual-licensed under GPLv3 and a commercial * license. See the file LICENSE.md distributed with this software for * full license information. ********************************************************************/ #include "app_data.h" #include "app_utils.h" #include "app_gsdml.h" #include "app_log.h" #include "sampleapp_common.h" #include "osal.h" #include "pnal.h" #include #include #include #include #define APP_DATA_DEFAULT_OUTPUT_DATA 0 /* Parameter data for digital submodules * The stored value is shared between all digital submodules in this example. * * Todo: Data is always in pnio data format. Add conversion to uint32_t. */ static uint32_t app_param_1 = 0; /* Network endianness */ static uint32_t app_param_2 = 0; /* Network endianness */ /* Parameter data for echo submodules * The stored value is shared between all echo submodules in this example. * * Todo: Data is always in pnio data format. Add conversion to uint32_t. */ static uint32_t app_param_echo_gain = 1; /* Network endianness */ /* Digital submodule process data * The stored value is shared between all digital submodules in this example. */ static uint8_t inputdata[APP_GSDML_INPUT_DATA_DIGITAL_SIZE] = {0}; static uint8_t outputdata[APP_GSDML_OUTPUT_DATA_DIGITAL_SIZE] = {0}; static uint8_t counter = 0; /* Network endianness */ static uint8_t echo_inputdata[APP_GSDML_INPUT_DATA_ECHO_SIZE] = {0}; static uint8_t echo_outputdata[APP_GSDML_OUTPUT_DATA_ECHO_SIZE] = {0}; CC_PACKED_BEGIN typedef struct CC_PACKED app_echo_data { /* Network endianness. Used as a float, but we model it as a 4-byte integer to easily do endianness conversion */ uint32_t echo_float_bytes; /* Network endianness */ uint32_t echo_int; } app_echo_data_t; CC_PACKED_END CC_STATIC_ASSERT (sizeof (app_echo_data_t) == APP_GSDML_INPUT_DATA_ECHO_SIZE); CC_STATIC_ASSERT (sizeof (app_echo_data_t) == APP_GSDML_OUTPUT_DATA_ECHO_SIZE); /** * Set LED state. * * Compares new state with previous state, to minimize system calls. * * Uses the hardware specific app_set_led() function. * * @param led_state In: New LED state */ static void app_handle_data_led_state (bool led_state) { static bool previous_led_state = false; if (led_state != previous_led_state) { app_set_led (APP_DATA_LED_ID, led_state); } previous_led_state = led_state; } uint8_t * app_data_get_input_data ( uint16_t slot_nbr, uint16_t subslot_nbr, uint32_t submodule_id, bool button_pressed, uint16_t * size, uint8_t * iops) { float inputfloat; float outputfloat; uint32_t hostorder_inputfloat_bytes; uint32_t hostorder_outputfloat_bytes; app_echo_data_t * p_echo_inputdata = (app_echo_data_t *)&echo_inputdata; app_echo_data_t * p_echo_outputdata = (app_echo_data_t *)&echo_outputdata; if (size == NULL || iops == NULL) { return NULL; } if ( submodule_id == APP_GSDML_SUBMOD_ID_DIGITAL_IN || submodule_id == APP_GSDML_SUBMOD_ID_DIGITAL_IN_OUT) { /* Prepare digital input data * Lowest 7 bits: Counter Most significant bit: Button */ inputdata[0] = counter++; if (button_pressed) { inputdata[0] |= 0x80; } else { inputdata[0] &= 0x7F; } *size = APP_GSDML_INPUT_DATA_DIGITAL_SIZE; *iops = PNET_IOXS_GOOD; return inputdata; } if (submodule_id == APP_GSDML_SUBMOD_ID_ECHO) { /* Calculate echodata input (to the PLC) * by multiplying the output (from the PLC) with a gain factor */ /* Integer */ p_echo_inputdata->echo_int = CC_TO_BE32 ( CC_FROM_BE32 (p_echo_outputdata->echo_int) * CC_FROM_BE32 (app_param_echo_gain)); /* Float */ /* Use memcopy to avoid strict-aliasing rule warnings */ hostorder_outputfloat_bytes = CC_FROM_BE32 (p_echo_outputdata->echo_float_bytes); memcpy (&outputfloat, &hostorder_outputfloat_bytes, sizeof (outputfloat)); inputfloat = outputfloat * CC_FROM_BE32 (app_param_echo_gain); memcpy (&hostorder_inputfloat_bytes, &inputfloat, sizeof (outputfloat)); p_echo_inputdata->echo_float_bytes = CC_TO_BE32 (hostorder_inputfloat_bytes); *size = APP_GSDML_INPUT_DATA_ECHO_SIZE; *iops = PNET_IOXS_GOOD; return echo_inputdata; } /* Automated RT Tester scenario 2 - unsupported (sub)module */ return NULL; } int app_data_set_output_data ( uint16_t slot_nbr, uint16_t subslot_nbr, uint32_t submodule_id, uint8_t * data, uint16_t size) { bool led_state; if (data == NULL) { return -1; } if ( submodule_id == APP_GSDML_SUBMOD_ID_DIGITAL_OUT || submodule_id == APP_GSDML_SUBMOD_ID_DIGITAL_IN_OUT) { if (size == APP_GSDML_OUTPUT_DATA_DIGITAL_SIZE) { memcpy (outputdata, data, size); /* Most significant bit: LED */ led_state = (outputdata[0] & 0x80) > 0; app_handle_data_led_state (led_state); return 0; } } else if (submodule_id == APP_GSDML_SUBMOD_ID_ECHO) { if (size == APP_GSDML_OUTPUT_DATA_ECHO_SIZE) { memcpy (echo_outputdata, data, size); return 0; } } return -1; } int app_data_set_default_outputs (void) { outputdata[0] = APP_DATA_DEFAULT_OUTPUT_DATA; app_handle_data_led_state (false); return 0; } int app_data_write_parameter ( uint16_t slot_nbr, uint16_t subslot_nbr, uint32_t submodule_id, uint32_t index, const uint8_t * data, uint16_t length) { const app_gsdml_param_t * par_cfg; par_cfg = app_gsdml_get_parameter_cfg (submodule_id, index); if (par_cfg == NULL) { APP_LOG_WARNING ( "PLC write request unsupported submodule/parameter. " "Submodule id: %u Index: %u\n", (unsigned)submodule_id, (unsigned)index); return -1; } if (length != par_cfg->length) { APP_LOG_WARNING ( "PLC write request unsupported length. " "Index: %u Length: %u Expected length: %u\n", (unsigned)index, (unsigned)length, par_cfg->length); return -1; } if (index == APP_GSDML_PARAMETER_1_IDX) { memcpy (&app_param_1, data, length); } else if (index == APP_GSDML_PARAMETER_2_IDX) { memcpy (&app_param_2, data, length); } else if (index == APP_GSDML_PARAMETER_ECHO_IDX) { memcpy (&app_param_echo_gain, data, length); } APP_LOG_DEBUG (" Writing parameter \"%s\"\n", par_cfg->name); app_log_print_bytes (APP_LOG_LEVEL_DEBUG, data, length); return 0; } int app_data_read_parameter ( uint16_t slot_nbr, uint16_t subslot_nbr, uint32_t submodule_id, uint32_t index, uint8_t ** data, uint16_t * length) { const app_gsdml_param_t * par_cfg; par_cfg = app_gsdml_get_parameter_cfg (submodule_id, index); if (par_cfg == NULL) { APP_LOG_WARNING ( "PLC read request unsupported submodule/parameter. " "Submodule id: %u Index: %u\n", (unsigned)submodule_id, (unsigned)index); return -1; } if (*length < par_cfg->length) { APP_LOG_WARNING ( "PLC read request unsupported length. " "Index: %u Length: %u Expected length: %u\n", (unsigned)index, (unsigned)*length, par_cfg->length); return -1; } APP_LOG_DEBUG (" Reading \"%s\"\n", par_cfg->name); if (index == APP_GSDML_PARAMETER_1_IDX) { *data = (uint8_t *)&app_param_1; *length = sizeof (app_param_1); } else if (index == APP_GSDML_PARAMETER_2_IDX) { *data = (uint8_t *)&app_param_2; *length = sizeof (app_param_2); } else if (index == APP_GSDML_PARAMETER_ECHO_IDX) { *data = (uint8_t *)&app_param_echo_gain; *length = sizeof (app_param_echo_gain); } app_log_print_bytes (APP_LOG_LEVEL_DEBUG, *data, *length); return 0; }