2426 lines
120 KiB
OpenEdge ABL
2426 lines
120 KiB
OpenEdge ABL
#pragma GCC diagnostic push
|
|
#pragma GCC diagnostic ignored "-Wpedantic"
|
|
|
|
|
|
|
|
|
|
#pragma pack(push,_CRT_PACKING)
|
|
typedef __builtin_va_list __gnuc_va_list;
|
|
typedef __gnuc_va_list va_list;
|
|
#pragma pack(pop)
|
|
void __attribute__((__cdecl__)) __debugbreak(void);
|
|
extern __inline__ __attribute__((__always_inline__,__gnu_inline__)) void __attribute__((__cdecl__)) __debugbreak(void)
|
|
{
|
|
__asm__ __volatile__("int {$}3":);
|
|
}
|
|
void __attribute__((__cdecl__)) __attribute__ ((__noreturn__)) __fastfail(unsigned int _Code);
|
|
extern __inline__ __attribute__((__always_inline__,__gnu_inline__)) void __attribute__((__cdecl__)) __attribute__ ((__noreturn__)) __fastfail(unsigned int _Code)
|
|
{
|
|
__asm__ __volatile__("int {$}0x29"::"c"(_Code));
|
|
__builtin_unreachable();
|
|
}
|
|
const char *__mingw_get_crt_info (void);
|
|
#pragma pack(push,_CRT_PACKING)
|
|
__extension__ typedef unsigned long long size_t;
|
|
__extension__ typedef long long ssize_t;
|
|
typedef size_t rsize_t;
|
|
__extension__ typedef long long intptr_t;
|
|
__extension__ typedef unsigned long long uintptr_t;
|
|
__extension__ typedef long long ptrdiff_t;
|
|
typedef unsigned short wchar_t;
|
|
typedef unsigned short wint_t;
|
|
typedef unsigned short wctype_t;
|
|
typedef int errno_t;
|
|
typedef long __time32_t;
|
|
__extension__ typedef long long __time64_t;
|
|
typedef __time64_t time_t;
|
|
__attribute__ ((__dllimport__)) void __attribute__((__cdecl__)) _invalid_parameter_noinfo(void);
|
|
__attribute__ ((__dllimport__)) __attribute__ ((__noreturn__)) void __attribute__((__cdecl__)) _invalid_parameter_noinfo_noreturn(void);
|
|
__attribute__ ((__dllimport__)) __attribute__ ((__noreturn__)) void __attribute__((__cdecl__)) _invoke_watson(const wchar_t *expression, const wchar_t *function_name, const wchar_t *file_name, unsigned int line_number, long long unsigned int reserved);
|
|
struct threadlocaleinfostruct;
|
|
struct threadmbcinfostruct;
|
|
typedef struct threadlocaleinfostruct *pthreadlocinfo;
|
|
typedef struct threadmbcinfostruct *pthreadmbcinfo;
|
|
struct __lc_time_data;
|
|
typedef struct localeinfo_struct {
|
|
pthreadlocinfo locinfo;
|
|
pthreadmbcinfo mbcinfo;
|
|
} _locale_tstruct,*_locale_t;
|
|
typedef struct tagLC_ID {
|
|
unsigned short wLanguage;
|
|
unsigned short wCountry;
|
|
unsigned short wCodePage;
|
|
} LC_ID,*LPLC_ID;
|
|
typedef struct threadlocaleinfostruct {
|
|
const unsigned short *_locale_pctype;
|
|
int _locale_mb_cur_max;
|
|
unsigned int _locale_lc_codepage;
|
|
} threadlocinfo;
|
|
#pragma pack(pop)
|
|
__attribute__ ((__dllimport__)) extern int *__attribute__((__cdecl__)) _errno(void);
|
|
__attribute__ ((__dllimport__)) errno_t __attribute__((__cdecl__)) _set_errno(int _Value);
|
|
__attribute__ ((__dllimport__)) errno_t __attribute__((__cdecl__)) _get_errno(int *_Value);
|
|
__attribute__ ((__dllimport__)) extern unsigned long __attribute__((__cdecl__)) __threadid(void);
|
|
__attribute__ ((__dllimport__)) extern uintptr_t __attribute__((__cdecl__)) __threadhandle(void);
|
|
typedef struct {
|
|
long long __max_align_ll __attribute__((__aligned__(__alignof__(long long))));
|
|
long double __max_align_ld __attribute__((__aligned__(__alignof__(long double))));
|
|
} max_align_t;
|
|
typedef signed char int8_t;
|
|
typedef unsigned char uint8_t;
|
|
typedef short int16_t;
|
|
typedef unsigned short uint16_t;
|
|
typedef int int32_t;
|
|
typedef unsigned uint32_t;
|
|
__extension__ typedef long long int64_t;
|
|
__extension__ typedef unsigned long long uint64_t;
|
|
typedef signed char int_least8_t;
|
|
typedef unsigned char uint_least8_t;
|
|
typedef short int_least16_t;
|
|
typedef unsigned short uint_least16_t;
|
|
typedef int int_least32_t;
|
|
typedef unsigned uint_least32_t;
|
|
__extension__ typedef long long int_least64_t;
|
|
__extension__ typedef unsigned long long uint_least64_t;
|
|
typedef signed char int_fast8_t;
|
|
typedef unsigned char uint_fast8_t;
|
|
typedef short int_fast16_t;
|
|
typedef unsigned short uint_fast16_t;
|
|
typedef int int_fast32_t;
|
|
typedef unsigned int uint_fast32_t;
|
|
__extension__ typedef long long int_fast64_t;
|
|
__extension__ typedef unsigned long long uint_fast64_t;
|
|
__extension__ typedef long long intmax_t;
|
|
__extension__ typedef unsigned long long uintmax_t;
|
|
#pragma GCC diagnostic pop
|
|
typedef struct {
|
|
int sizeOfTypeId;
|
|
int sizeOfVSQ;
|
|
int sizeOfCOT;
|
|
int originatorAddress;
|
|
int sizeOfCA;
|
|
int sizeOfIOA;
|
|
int maxSizeOfASDU;
|
|
} IEC60870_AppLayerParameters_t;
|
|
typedef struct {
|
|
uint8_t type_id;
|
|
uint8_t object_count;
|
|
uint8_t is_sequence;
|
|
uint8_t cause_of_transmission;
|
|
uint8_t is_negative_confirm;
|
|
uint8_t is_test;
|
|
uint8_t originator_address;
|
|
uint16_t common_address;
|
|
const uint8_t *information_objects;
|
|
uint16_t information_objects_len;
|
|
const IEC60870_AppLayerParameters_t *parameters;
|
|
} IEC60870_AsduInfo_t;
|
|
extern int IEC60870_AppLayerParameters_Valid(const IEC60870_AppLayerParameters_t *parameters);
|
|
extern int IEC60870_Parse_ASDU_Header(const IEC60870_AppLayerParameters_t *parameters,
|
|
const uint8_t *asdu,
|
|
uint16_t asdu_len,
|
|
IEC60870_AsduInfo_t *asdu_info);
|
|
typedef struct {
|
|
uint16_t milliseconds;
|
|
} IEC60870_CP16Time2a_t;
|
|
typedef struct {
|
|
uint16_t milliseconds;
|
|
uint8_t minute;
|
|
uint8_t is_invalid;
|
|
} IEC60870_CP24Time2a_t;
|
|
int IEC60870_Time_To_CP16(const IEC60870_CP16Time2a_t *value, uint8_t *out, size_t capacity);
|
|
int IEC60870_Time_To_CP24(const IEC60870_CP24Time2a_t *value, uint8_t *out, size_t capacity);
|
|
int IEC60870_Time_From_CP16(const uint8_t *in, size_t length, IEC60870_CP16Time2a_t *value);
|
|
int IEC60870_Time_From_CP24(const uint8_t *in, size_t length, IEC60870_CP24Time2a_t *value);
|
|
typedef struct {
|
|
uint16_t year;
|
|
uint8_t month;
|
|
uint8_t day;
|
|
uint8_t hour;
|
|
uint8_t minute;
|
|
uint8_t second;
|
|
uint16_t ms;
|
|
uint8_t weekday;
|
|
} IEC60870_WallTime_t;
|
|
typedef struct {
|
|
IEC60870_WallTime_t time;
|
|
uint8_t is_invalid;
|
|
uint8_t is_summer_time;
|
|
uint8_t has_weekday;
|
|
} IEC60870_CP56Time2a_t;
|
|
int IEC60870_Time_Is_Valid(const IEC60870_WallTime_t *time);
|
|
int IEC60870_Time_Get_Weekday(uint16_t year, uint8_t month, uint8_t day, uint8_t *weekday);
|
|
int IEC60870_Time_To_Seconds(const IEC60870_WallTime_t *time, uint32_t *seconds);
|
|
int IEC60870_Time_From_Seconds(uint32_t seconds, uint16_t ms, IEC60870_WallTime_t *time);
|
|
int IEC60870_Time_Seconds_To_Local(uint32_t utc_seconds, uint16_t ms,
|
|
IEC60870_WallTime_t *local_time);
|
|
int IEC60870_Time_CP56_To_Seconds(const IEC60870_CP56Time2a_t *value,
|
|
int16_t standard_utc_offset_minutes, uint32_t *seconds);
|
|
int IEC60870_Time_CP56_To_Local(const IEC60870_CP56Time2a_t *value,
|
|
int16_t source_standard_utc_offset_minutes,
|
|
IEC60870_WallTime_t *local_time);
|
|
int IEC60870_Time_To_CP56(const IEC60870_CP56Time2a_t *value, uint8_t *out, size_t capacity);
|
|
int IEC60870_Time_From_CP56(const uint8_t *in, size_t length, IEC60870_CP56Time2a_t *value);
|
|
typedef enum {
|
|
IEC60870_ASDU_UNSUPPORTED = -2,
|
|
IEC60870_ASDU_ERROR = -1,
|
|
IEC60870_ASDU_FULL = 0,
|
|
IEC60870_ASDU_OK = 1
|
|
} IEC60870_AsduResult_t;
|
|
typedef enum {
|
|
IEC60870_ASDU_M_SP_NA_1 = 1,
|
|
IEC60870_ASDU_M_SP_TA_1 = 2,
|
|
IEC60870_ASDU_M_DP_NA_1 = 3,
|
|
IEC60870_ASDU_M_DP_TA_1 = 4,
|
|
IEC60870_ASDU_M_ST_NA_1 = 5,
|
|
IEC60870_ASDU_M_ST_TA_1 = 6,
|
|
IEC60870_ASDU_M_BO_NA_1 = 7,
|
|
IEC60870_ASDU_M_BO_TA_1 = 8,
|
|
IEC60870_ASDU_M_ME_NA_1 = 9,
|
|
IEC60870_ASDU_M_ME_TA_1 = 10,
|
|
IEC60870_ASDU_M_ME_NB_1 = 11,
|
|
IEC60870_ASDU_M_ME_TB_1 = 12,
|
|
IEC60870_ASDU_M_ME_NC_1 = 13,
|
|
IEC60870_ASDU_M_ME_TC_1 = 14,
|
|
IEC60870_ASDU_M_IT_NA_1 = 15,
|
|
IEC60870_ASDU_M_IT_TA_1 = 16,
|
|
IEC60870_ASDU_M_EP_TA_1 = 17,
|
|
IEC60870_ASDU_M_EP_TB_1 = 18,
|
|
IEC60870_ASDU_M_EP_TC_1 = 19,
|
|
IEC60870_ASDU_M_PS_NA_1 = 20,
|
|
IEC60870_ASDU_M_ME_ND_1 = 21,
|
|
IEC60870_ASDU_M_SP_TB_1 = 30,
|
|
IEC60870_ASDU_M_DP_TB_1 = 31,
|
|
IEC60870_ASDU_M_ST_TB_1 = 32,
|
|
IEC60870_ASDU_M_BO_TB_1 = 33,
|
|
IEC60870_ASDU_M_ME_TD_1 = 34,
|
|
IEC60870_ASDU_M_ME_TE_1 = 35,
|
|
IEC60870_ASDU_M_ME_TF_1 = 36,
|
|
IEC60870_ASDU_M_IT_TB_1 = 37,
|
|
IEC60870_ASDU_M_EP_TD_1 = 38,
|
|
IEC60870_ASDU_M_EP_TE_1 = 39,
|
|
IEC60870_ASDU_M_EP_TF_1 = 40,
|
|
IEC60870_ASDU_C_SC_NA_1 = 45,
|
|
IEC60870_ASDU_C_DC_NA_1 = 46,
|
|
IEC60870_ASDU_C_RC_NA_1 = 47,
|
|
IEC60870_ASDU_C_SE_NA_1 = 48,
|
|
IEC60870_ASDU_C_SE_NB_1 = 49,
|
|
IEC60870_ASDU_C_SE_NC_1 = 50,
|
|
IEC60870_ASDU_C_BO_NA_1 = 51,
|
|
IEC60870_ASDU_C_SC_TA_1 = 58,
|
|
IEC60870_ASDU_C_DC_TA_1 = 59,
|
|
IEC60870_ASDU_C_RC_TA_1 = 60,
|
|
IEC60870_ASDU_C_SE_TA_1 = 61,
|
|
IEC60870_ASDU_C_SE_TB_1 = 62,
|
|
IEC60870_ASDU_C_SE_TC_1 = 63,
|
|
IEC60870_ASDU_C_BO_TA_1 = 64,
|
|
IEC60870_ASDU_M_EI_NA_1 = 70,
|
|
IEC60870_ASDU_C_IC_NA_1 = 100,
|
|
IEC60870_ASDU_C_CI_NA_1 = 101,
|
|
IEC60870_ASDU_C_RD_NA_1 = 102,
|
|
IEC60870_ASDU_C_CS_NA_1 = 103,
|
|
IEC60870_ASDU_C_TS_NA_1 = 104,
|
|
IEC60870_ASDU_C_RP_NA_1 = 105,
|
|
IEC60870_ASDU_C_CD_NA_1 = 106,
|
|
IEC60870_ASDU_C_TS_TA_1 = 107,
|
|
IEC60870_ASDU_P_ME_NA_1 = 110,
|
|
IEC60870_ASDU_P_ME_NB_1 = 111,
|
|
IEC60870_ASDU_P_ME_NC_1 = 112,
|
|
IEC60870_ASDU_P_AC_NA_1 = 113,
|
|
IEC60870_ASDU_F_FR_NA_1 = 120,
|
|
IEC60870_ASDU_F_SR_NA_1 = 121,
|
|
IEC60870_ASDU_F_SC_NA_1 = 122,
|
|
IEC60870_ASDU_F_LS_NA_1 = 123,
|
|
IEC60870_ASDU_F_AF_NA_1 = 124,
|
|
IEC60870_ASDU_F_SG_NA_1 = 125,
|
|
IEC60870_ASDU_F_DR_TA_1 = 126,
|
|
IEC60870_ASDU_F_SC_NB_1 = 127
|
|
} IEC60870_AsduType_t;
|
|
enum {
|
|
IEC60870_ASDU_QUALITY_OV = 0x01,
|
|
IEC60870_ASDU_QUALITY_EI = 0x08,
|
|
IEC60870_ASDU_QUALITY_BL = 0x10,
|
|
IEC60870_ASDU_QUALITY_SB = 0x20,
|
|
IEC60870_ASDU_QUALITY_NT = 0x40,
|
|
IEC60870_ASDU_QUALITY_IV = 0x80
|
|
};
|
|
typedef struct {
|
|
int32_t value;
|
|
uint8_t sequence_number;
|
|
uint8_t has_carry;
|
|
uint8_t is_adjusted;
|
|
uint8_t is_invalid;
|
|
} IEC60870_BinaryCounterReading_t;
|
|
struct IEC60870_InformationObjectVTable;
|
|
typedef struct {
|
|
uint32_t ioa;
|
|
uint8_t type_id;
|
|
const struct IEC60870_InformationObjectVTable *virtual_function_table;
|
|
} IEC60870_InformationObject_t;
|
|
typedef struct {
|
|
IEC60870_InformationObject_t object;
|
|
uint8_t value;
|
|
uint8_t quality;
|
|
} IEC60870_SinglePointInformation_t;
|
|
typedef struct {
|
|
IEC60870_InformationObject_t object;
|
|
uint8_t value;
|
|
uint8_t quality;
|
|
} IEC60870_DoublePointInformation_t;
|
|
typedef struct {
|
|
IEC60870_InformationObject_t object;
|
|
int16_t value;
|
|
uint8_t quality;
|
|
} IEC60870_MeasuredValueNormalized_t;
|
|
typedef struct {
|
|
IEC60870_InformationObject_t object;
|
|
int16_t value;
|
|
uint8_t quality;
|
|
} IEC60870_MeasuredValueScaled_t;
|
|
typedef struct {
|
|
IEC60870_InformationObject_t object;
|
|
float value;
|
|
uint8_t quality;
|
|
} IEC60870_MeasuredValueShort_t;
|
|
typedef struct {
|
|
IEC60870_InformationObject_t object;
|
|
IEC60870_BinaryCounterReading_t value;
|
|
} IEC60870_IntegratedTotals_t;
|
|
typedef struct {
|
|
IEC60870_SinglePointInformation_t base;
|
|
IEC60870_CP56Time2a_t time;
|
|
} IEC60870_SinglePointWithCP56Time2a_t;
|
|
typedef struct {
|
|
IEC60870_DoublePointInformation_t base;
|
|
IEC60870_CP56Time2a_t time;
|
|
} IEC60870_DoublePointWithCP56Time2a_t;
|
|
typedef struct {
|
|
IEC60870_MeasuredValueNormalized_t base;
|
|
IEC60870_CP56Time2a_t time;
|
|
} IEC60870_MeasuredValueNormalizedWithCP56Time2a_t;
|
|
typedef struct {
|
|
IEC60870_MeasuredValueScaled_t base;
|
|
IEC60870_CP56Time2a_t time;
|
|
} IEC60870_MeasuredValueScaledWithCP56Time2a_t;
|
|
typedef struct {
|
|
IEC60870_MeasuredValueShort_t base;
|
|
IEC60870_CP56Time2a_t time;
|
|
} IEC60870_MeasuredValueShortWithCP56Time2a_t;
|
|
typedef struct {
|
|
IEC60870_IntegratedTotals_t base;
|
|
IEC60870_CP56Time2a_t time;
|
|
} IEC60870_IntegratedTotalsWithCP56Time2a_t;
|
|
typedef struct {
|
|
IEC60870_InformationObject_t object;
|
|
uint8_t state;
|
|
uint8_t is_select;
|
|
uint8_t qualifier;
|
|
} IEC60870_SingleCommand_t;
|
|
typedef struct {
|
|
IEC60870_InformationObject_t object;
|
|
uint8_t state;
|
|
uint8_t is_select;
|
|
uint8_t qualifier;
|
|
} IEC60870_DoubleCommand_t;
|
|
typedef struct {
|
|
IEC60870_InformationObject_t object;
|
|
uint8_t state;
|
|
uint8_t is_select;
|
|
uint8_t qualifier;
|
|
} IEC60870_StepCommand_t;
|
|
typedef struct {
|
|
IEC60870_InformationObject_t object;
|
|
int16_t value;
|
|
uint8_t is_select;
|
|
uint8_t qualifier;
|
|
} IEC60870_SetpointCommandNormalized_t;
|
|
typedef struct {
|
|
IEC60870_InformationObject_t object;
|
|
int16_t value;
|
|
uint8_t is_select;
|
|
uint8_t qualifier;
|
|
} IEC60870_SetpointCommandScaled_t;
|
|
typedef struct {
|
|
IEC60870_InformationObject_t object;
|
|
float value;
|
|
uint8_t is_select;
|
|
uint8_t qualifier;
|
|
} IEC60870_SetpointCommandShort_t;
|
|
typedef struct {
|
|
IEC60870_SingleCommand_t base;
|
|
IEC60870_CP56Time2a_t time;
|
|
} IEC60870_SingleCommandWithCP56Time2a_t;
|
|
typedef struct {
|
|
IEC60870_DoubleCommand_t base;
|
|
IEC60870_CP56Time2a_t time;
|
|
} IEC60870_DoubleCommandWithCP56Time2a_t;
|
|
typedef struct {
|
|
IEC60870_StepCommand_t base;
|
|
IEC60870_CP56Time2a_t time;
|
|
} IEC60870_StepCommandWithCP56Time2a_t;
|
|
typedef struct {
|
|
IEC60870_SetpointCommandNormalized_t base;
|
|
IEC60870_CP56Time2a_t time;
|
|
} IEC60870_SetpointCommandNormalizedWithCP56Time2a_t;
|
|
typedef struct {
|
|
IEC60870_SetpointCommandScaled_t base;
|
|
IEC60870_CP56Time2a_t time;
|
|
} IEC60870_SetpointCommandScaledWithCP56Time2a_t;
|
|
typedef struct {
|
|
IEC60870_SetpointCommandShort_t base;
|
|
IEC60870_CP56Time2a_t time;
|
|
} IEC60870_SetpointCommandShortWithCP56Time2a_t;
|
|
typedef struct {
|
|
IEC60870_InformationObject_t object;
|
|
uint8_t qualifier;
|
|
} IEC60870_InterrogationCommand_t;
|
|
typedef struct {
|
|
IEC60870_InformationObject_t object;
|
|
uint8_t qualifier;
|
|
uint8_t freeze;
|
|
} IEC60870_CounterInterrogationCommand_t;
|
|
typedef struct {
|
|
IEC60870_InformationObject_t object;
|
|
} IEC60870_ReadCommand_t;
|
|
typedef struct {
|
|
IEC60870_InformationObject_t object;
|
|
IEC60870_CP56Time2a_t time;
|
|
} IEC60870_ClockSynchronizationCommand_t;
|
|
typedef struct {
|
|
IEC60870_InformationObject_t object;
|
|
uint8_t qualifier;
|
|
} IEC60870_ResetProcessCommand_t;
|
|
typedef struct {
|
|
IEC60870_InformationObject_t object;
|
|
uint16_t sequence;
|
|
IEC60870_CP56Time2a_t time;
|
|
} IEC60870_TestCommandWithCP56Time2a_t;
|
|
typedef struct {
|
|
IEC60870_InformationObject_t object;
|
|
int8_t value;
|
|
uint8_t is_transient;
|
|
uint8_t quality;
|
|
} IEC60870_StepPositionInformation_t;
|
|
typedef struct {
|
|
IEC60870_InformationObject_t object;
|
|
uint32_t value;
|
|
uint8_t quality;
|
|
} IEC60870_BitString32_t;
|
|
typedef struct {
|
|
IEC60870_SinglePointInformation_t base;
|
|
IEC60870_CP24Time2a_t time;
|
|
} IEC60870_SinglePointWithCP24Time2a_t;
|
|
typedef struct {
|
|
IEC60870_DoublePointInformation_t base;
|
|
IEC60870_CP24Time2a_t time;
|
|
} IEC60870_DoublePointWithCP24Time2a_t;
|
|
typedef struct {
|
|
IEC60870_StepPositionInformation_t base;
|
|
IEC60870_CP24Time2a_t time;
|
|
} IEC60870_StepPositionWithCP24Time2a_t;
|
|
typedef struct {
|
|
IEC60870_BitString32_t base;
|
|
IEC60870_CP24Time2a_t time;
|
|
} IEC60870_Bitstring32WithCP24Time2a_t;
|
|
typedef struct {
|
|
IEC60870_MeasuredValueNormalized_t base;
|
|
IEC60870_CP24Time2a_t time;
|
|
} IEC60870_MeasuredValueNormalizedWithCP24Time2a_t;
|
|
typedef struct {
|
|
IEC60870_MeasuredValueScaled_t base;
|
|
IEC60870_CP24Time2a_t time;
|
|
} IEC60870_MeasuredValueScaledWithCP24Time2a_t;
|
|
typedef struct {
|
|
IEC60870_MeasuredValueShort_t base;
|
|
IEC60870_CP24Time2a_t time;
|
|
} IEC60870_MeasuredValueShortWithCP24Time2a_t;
|
|
typedef struct {
|
|
IEC60870_IntegratedTotals_t base;
|
|
IEC60870_CP24Time2a_t time;
|
|
} IEC60870_IntegratedTotalsWithCP24Time2a_t;
|
|
typedef struct {
|
|
IEC60870_StepPositionInformation_t base;
|
|
IEC60870_CP56Time2a_t time;
|
|
} IEC60870_StepPositionWithCP56Time2a_t;
|
|
typedef struct {
|
|
IEC60870_BitString32_t base;
|
|
IEC60870_CP56Time2a_t time;
|
|
} IEC60870_Bitstring32WithCP56Time2a_t;
|
|
typedef struct {
|
|
IEC60870_InformationObject_t object;
|
|
uint8_t event;
|
|
uint8_t quality;
|
|
IEC60870_CP16Time2a_t elapsed_time;
|
|
IEC60870_CP24Time2a_t time;
|
|
} IEC60870_EventOfProtectionEquipment_t;
|
|
typedef struct {
|
|
IEC60870_InformationObject_t object;
|
|
uint8_t event;
|
|
uint8_t quality;
|
|
IEC60870_CP16Time2a_t elapsed_time;
|
|
IEC60870_CP24Time2a_t time;
|
|
} IEC60870_PackedStartEventsOfProtectionEquipment_t;
|
|
typedef struct {
|
|
IEC60870_InformationObject_t object;
|
|
uint8_t event;
|
|
uint8_t quality;
|
|
IEC60870_CP16Time2a_t elapsed_time;
|
|
IEC60870_CP24Time2a_t time;
|
|
} IEC60870_PackedOutputCircuitInfo_t;
|
|
typedef struct {
|
|
IEC60870_InformationObject_t object;
|
|
uint8_t event;
|
|
uint8_t quality;
|
|
IEC60870_CP16Time2a_t elapsed_time;
|
|
IEC60870_CP56Time2a_t time;
|
|
} IEC60870_EventOfProtectionEquipmentWithCP56Time2a_t;
|
|
typedef struct {
|
|
IEC60870_InformationObject_t object;
|
|
uint8_t event;
|
|
uint8_t quality;
|
|
IEC60870_CP16Time2a_t elapsed_time;
|
|
IEC60870_CP56Time2a_t time;
|
|
} IEC60870_PackedStartEventsOfProtectionEquipmentWithCP56Time2a_t;
|
|
typedef struct {
|
|
IEC60870_InformationObject_t object;
|
|
uint8_t event;
|
|
uint8_t quality;
|
|
IEC60870_CP16Time2a_t elapsed_time;
|
|
IEC60870_CP56Time2a_t time;
|
|
} IEC60870_PackedOutputCircuitInfoWithCP56Time2a_t;
|
|
typedef struct {
|
|
IEC60870_InformationObject_t object;
|
|
uint16_t status;
|
|
uint16_t change;
|
|
uint8_t quality;
|
|
} IEC60870_PackedSinglePointWithSCD_t;
|
|
typedef struct {
|
|
IEC60870_InformationObject_t object;
|
|
int16_t value;
|
|
} IEC60870_MeasuredValueNormalizedWithoutQuality_t;
|
|
typedef struct {
|
|
IEC60870_InformationObject_t object;
|
|
uint32_t value;
|
|
} IEC60870_Bitstring32Command_t;
|
|
typedef struct {
|
|
IEC60870_Bitstring32Command_t base;
|
|
IEC60870_CP56Time2a_t time;
|
|
} IEC60870_Bitstring32CommandWithCP56Time2a_t;
|
|
typedef struct {
|
|
IEC60870_InformationObject_t object;
|
|
uint8_t cause;
|
|
} IEC60870_EndOfInitialization_t;
|
|
typedef struct {
|
|
IEC60870_InformationObject_t object;
|
|
} IEC60870_TestCommand_t;
|
|
typedef struct {
|
|
IEC60870_InformationObject_t object;
|
|
IEC60870_CP16Time2a_t delay;
|
|
} IEC60870_DelayAcquisitionCommand_t;
|
|
typedef struct {
|
|
IEC60870_InformationObject_t object;
|
|
int16_t value;
|
|
uint8_t qualifier;
|
|
} IEC60870_ParameterNormalizedValue_t;
|
|
typedef struct {
|
|
IEC60870_InformationObject_t object;
|
|
int16_t value;
|
|
uint8_t qualifier;
|
|
} IEC60870_ParameterScaledValue_t;
|
|
typedef struct {
|
|
IEC60870_InformationObject_t object;
|
|
float value;
|
|
uint8_t qualifier;
|
|
} IEC60870_ParameterFloatValue_t;
|
|
typedef struct {
|
|
IEC60870_InformationObject_t object;
|
|
uint8_t qualifier;
|
|
} IEC60870_ParameterActivation_t;
|
|
typedef struct {
|
|
IEC60870_InformationObject_t object;
|
|
uint16_t file_name;
|
|
uint32_t file_length;
|
|
uint8_t qualifier;
|
|
} IEC60870_FileReady_t;
|
|
typedef struct {
|
|
IEC60870_InformationObject_t object;
|
|
uint16_t file_name;
|
|
uint8_t section;
|
|
uint32_t section_length;
|
|
uint8_t qualifier;
|
|
} IEC60870_SectionReady_t;
|
|
typedef struct {
|
|
IEC60870_InformationObject_t object;
|
|
uint16_t file_name;
|
|
uint8_t section;
|
|
uint8_t qualifier;
|
|
} IEC60870_FileCallOrSelect_t;
|
|
typedef struct {
|
|
IEC60870_InformationObject_t object;
|
|
uint16_t file_name;
|
|
uint8_t section;
|
|
uint8_t qualifier;
|
|
} IEC60870_FileACK_t;
|
|
typedef struct {
|
|
IEC60870_InformationObject_t object;
|
|
uint16_t file_name;
|
|
uint8_t section;
|
|
uint8_t qualifier;
|
|
uint8_t checksum;
|
|
} IEC60870_FileLastSegmentOrSection_t;
|
|
typedef struct {
|
|
IEC60870_InformationObject_t object;
|
|
uint16_t file_name;
|
|
uint8_t section;
|
|
uint8_t length;
|
|
uint8_t data[255];
|
|
} IEC60870_FileSegment_t;
|
|
typedef struct {
|
|
IEC60870_InformationObject_t object;
|
|
uint16_t file_name;
|
|
uint32_t file_length;
|
|
uint8_t status;
|
|
IEC60870_CP56Time2a_t creation_time;
|
|
} IEC60870_FileDirectory_t;
|
|
typedef struct {
|
|
IEC60870_InformationObject_t object;
|
|
uint16_t file_name;
|
|
IEC60870_CP56Time2a_t start_time;
|
|
IEC60870_CP56Time2a_t stop_time;
|
|
} IEC60870_QueryLog_t;
|
|
IEC60870_AsduResult_t IEC60870_StepPositionInformation_Create(IEC60870_StepPositionInformation_t *self,
|
|
uint32_t ioa, int value, int is_transient, int quality);
|
|
IEC60870_AsduResult_t IEC60870_StepPositionInformation_Get_From_Buffer(IEC60870_StepPositionInformation_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_BitString32_Create(IEC60870_BitString32_t *self,
|
|
uint32_t ioa, uint32_t value, int quality);
|
|
IEC60870_AsduResult_t IEC60870_BitString32_Get_From_Buffer(IEC60870_BitString32_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_SinglePointWithCP24Time2a_Create(IEC60870_SinglePointWithCP24Time2a_t *self,
|
|
uint32_t ioa, int value, int quality, const IEC60870_CP24Time2a_t *time);
|
|
IEC60870_AsduResult_t IEC60870_SinglePointWithCP24Time2a_Get_From_Buffer(IEC60870_SinglePointWithCP24Time2a_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_DoublePointWithCP24Time2a_Create(IEC60870_DoublePointWithCP24Time2a_t *self,
|
|
uint32_t ioa, int value, int quality, const IEC60870_CP24Time2a_t *time);
|
|
IEC60870_AsduResult_t IEC60870_DoublePointWithCP24Time2a_Get_From_Buffer(IEC60870_DoublePointWithCP24Time2a_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_StepPositionWithCP24Time2a_Create(IEC60870_StepPositionWithCP24Time2a_t *self,
|
|
uint32_t ioa, int value, int is_transient, int quality, const IEC60870_CP24Time2a_t *time);
|
|
IEC60870_AsduResult_t IEC60870_StepPositionWithCP24Time2a_Get_From_Buffer(IEC60870_StepPositionWithCP24Time2a_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_Bitstring32WithCP24Time2a_Create(IEC60870_Bitstring32WithCP24Time2a_t *self,
|
|
uint32_t ioa, uint32_t value, int quality, const IEC60870_CP24Time2a_t *time);
|
|
IEC60870_AsduResult_t IEC60870_Bitstring32WithCP24Time2a_Get_From_Buffer(IEC60870_Bitstring32WithCP24Time2a_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_MeasuredValueNormalizedWithCP24Time2a_Create(IEC60870_MeasuredValueNormalizedWithCP24Time2a_t *self,
|
|
uint32_t ioa, int16_t value, int quality, const IEC60870_CP24Time2a_t *time);
|
|
IEC60870_AsduResult_t IEC60870_MeasuredValueNormalizedWithCP24Time2a_Get_From_Buffer(IEC60870_MeasuredValueNormalizedWithCP24Time2a_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_MeasuredValueScaledWithCP24Time2a_Create(IEC60870_MeasuredValueScaledWithCP24Time2a_t *self,
|
|
uint32_t ioa, int16_t value, int quality, const IEC60870_CP24Time2a_t *time);
|
|
IEC60870_AsduResult_t IEC60870_MeasuredValueScaledWithCP24Time2a_Get_From_Buffer(IEC60870_MeasuredValueScaledWithCP24Time2a_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_MeasuredValueShortWithCP24Time2a_Create(IEC60870_MeasuredValueShortWithCP24Time2a_t *self,
|
|
uint32_t ioa, float value, int quality, const IEC60870_CP24Time2a_t *time);
|
|
IEC60870_AsduResult_t IEC60870_MeasuredValueShortWithCP24Time2a_Get_From_Buffer(IEC60870_MeasuredValueShortWithCP24Time2a_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_IntegratedTotalsWithCP24Time2a_Create(IEC60870_IntegratedTotalsWithCP24Time2a_t *self,
|
|
uint32_t ioa, const IEC60870_BinaryCounterReading_t *value, const IEC60870_CP24Time2a_t *time);
|
|
IEC60870_AsduResult_t IEC60870_IntegratedTotalsWithCP24Time2a_Get_From_Buffer(IEC60870_IntegratedTotalsWithCP24Time2a_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_StepPositionWithCP56Time2a_Create(IEC60870_StepPositionWithCP56Time2a_t *self,
|
|
uint32_t ioa, int value, int is_transient, int quality, const IEC60870_CP56Time2a_t *time);
|
|
IEC60870_AsduResult_t IEC60870_StepPositionWithCP56Time2a_Get_From_Buffer(IEC60870_StepPositionWithCP56Time2a_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_Bitstring32WithCP56Time2a_Create(IEC60870_Bitstring32WithCP56Time2a_t *self,
|
|
uint32_t ioa, uint32_t value, int quality, const IEC60870_CP56Time2a_t *time);
|
|
IEC60870_AsduResult_t IEC60870_Bitstring32WithCP56Time2a_Get_From_Buffer(IEC60870_Bitstring32WithCP56Time2a_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_EventOfProtectionEquipment_Create(IEC60870_EventOfProtectionEquipment_t *self,
|
|
uint32_t ioa, int event, int quality, const IEC60870_CP16Time2a_t *elapsed_time, const IEC60870_CP24Time2a_t *time);
|
|
IEC60870_AsduResult_t IEC60870_EventOfProtectionEquipment_Get_From_Buffer(IEC60870_EventOfProtectionEquipment_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_PackedStartEventsOfProtectionEquipment_Create(IEC60870_PackedStartEventsOfProtectionEquipment_t *self,
|
|
uint32_t ioa, int event, int quality, const IEC60870_CP16Time2a_t *elapsed_time, const IEC60870_CP24Time2a_t *time);
|
|
IEC60870_AsduResult_t IEC60870_PackedStartEventsOfProtectionEquipment_Get_From_Buffer(IEC60870_PackedStartEventsOfProtectionEquipment_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_PackedOutputCircuitInfo_Create(IEC60870_PackedOutputCircuitInfo_t *self,
|
|
uint32_t ioa, int event, int quality, const IEC60870_CP16Time2a_t *elapsed_time, const IEC60870_CP24Time2a_t *time);
|
|
IEC60870_AsduResult_t IEC60870_PackedOutputCircuitInfo_Get_From_Buffer(IEC60870_PackedOutputCircuitInfo_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_EventOfProtectionEquipmentWithCP56Time2a_Create(IEC60870_EventOfProtectionEquipmentWithCP56Time2a_t *self,
|
|
uint32_t ioa, int event, int quality, const IEC60870_CP16Time2a_t *elapsed_time, const IEC60870_CP56Time2a_t *time);
|
|
IEC60870_AsduResult_t IEC60870_EventOfProtectionEquipmentWithCP56Time2a_Get_From_Buffer(IEC60870_EventOfProtectionEquipmentWithCP56Time2a_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_PackedStartEventsOfProtectionEquipmentWithCP56Time2a_Create(IEC60870_PackedStartEventsOfProtectionEquipmentWithCP56Time2a_t *self,
|
|
uint32_t ioa, int event, int quality, const IEC60870_CP16Time2a_t *elapsed_time, const IEC60870_CP56Time2a_t *time);
|
|
IEC60870_AsduResult_t IEC60870_PackedStartEventsOfProtectionEquipmentWithCP56Time2a_Get_From_Buffer(IEC60870_PackedStartEventsOfProtectionEquipmentWithCP56Time2a_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_PackedOutputCircuitInfoWithCP56Time2a_Create(IEC60870_PackedOutputCircuitInfoWithCP56Time2a_t *self,
|
|
uint32_t ioa, int event, int quality, const IEC60870_CP16Time2a_t *elapsed_time, const IEC60870_CP56Time2a_t *time);
|
|
IEC60870_AsduResult_t IEC60870_PackedOutputCircuitInfoWithCP56Time2a_Get_From_Buffer(IEC60870_PackedOutputCircuitInfoWithCP56Time2a_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_PackedSinglePointWithSCD_Create(IEC60870_PackedSinglePointWithSCD_t *self,
|
|
uint32_t ioa, uint16_t status, uint16_t change, int quality);
|
|
IEC60870_AsduResult_t IEC60870_PackedSinglePointWithSCD_Get_From_Buffer(IEC60870_PackedSinglePointWithSCD_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_MeasuredValueNormalizedWithoutQuality_Create(IEC60870_MeasuredValueNormalizedWithoutQuality_t *self,
|
|
uint32_t ioa, int16_t value);
|
|
IEC60870_AsduResult_t IEC60870_MeasuredValueNormalizedWithoutQuality_Get_From_Buffer(IEC60870_MeasuredValueNormalizedWithoutQuality_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_Bitstring32Command_Create(IEC60870_Bitstring32Command_t *self,
|
|
uint32_t ioa, uint32_t value);
|
|
IEC60870_AsduResult_t IEC60870_Bitstring32Command_Get_From_Buffer(IEC60870_Bitstring32Command_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_Bitstring32CommandWithCP56Time2a_Create(IEC60870_Bitstring32CommandWithCP56Time2a_t *self,
|
|
uint32_t ioa, uint32_t value, const IEC60870_CP56Time2a_t *time);
|
|
IEC60870_AsduResult_t IEC60870_Bitstring32CommandWithCP56Time2a_Get_From_Buffer(IEC60870_Bitstring32CommandWithCP56Time2a_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_EndOfInitialization_Create(IEC60870_EndOfInitialization_t *self,
|
|
uint32_t ioa, int cause);
|
|
IEC60870_AsduResult_t IEC60870_EndOfInitialization_Get_From_Buffer(IEC60870_EndOfInitialization_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_TestCommand_Create(IEC60870_TestCommand_t *self,
|
|
uint32_t ioa);
|
|
IEC60870_AsduResult_t IEC60870_TestCommand_Get_From_Buffer(IEC60870_TestCommand_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_DelayAcquisitionCommand_Create(IEC60870_DelayAcquisitionCommand_t *self,
|
|
uint32_t ioa, const IEC60870_CP16Time2a_t *delay);
|
|
IEC60870_AsduResult_t IEC60870_DelayAcquisitionCommand_Get_From_Buffer(IEC60870_DelayAcquisitionCommand_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_ParameterNormalizedValue_Create(IEC60870_ParameterNormalizedValue_t *self,
|
|
uint32_t ioa, int16_t value, int qualifier);
|
|
IEC60870_AsduResult_t IEC60870_ParameterNormalizedValue_Get_From_Buffer(IEC60870_ParameterNormalizedValue_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_ParameterScaledValue_Create(IEC60870_ParameterScaledValue_t *self,
|
|
uint32_t ioa, int16_t value, int qualifier);
|
|
IEC60870_AsduResult_t IEC60870_ParameterScaledValue_Get_From_Buffer(IEC60870_ParameterScaledValue_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_ParameterFloatValue_Create(IEC60870_ParameterFloatValue_t *self,
|
|
uint32_t ioa, float value, int qualifier);
|
|
IEC60870_AsduResult_t IEC60870_ParameterFloatValue_Get_From_Buffer(IEC60870_ParameterFloatValue_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_ParameterActivation_Create(IEC60870_ParameterActivation_t *self,
|
|
uint32_t ioa, int qualifier);
|
|
IEC60870_AsduResult_t IEC60870_ParameterActivation_Get_From_Buffer(IEC60870_ParameterActivation_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_FileReady_Create(IEC60870_FileReady_t *self,
|
|
uint32_t ioa, uint16_t file_name, uint32_t file_length, int qualifier);
|
|
IEC60870_AsduResult_t IEC60870_FileReady_Get_From_Buffer(IEC60870_FileReady_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_SectionReady_Create(IEC60870_SectionReady_t *self,
|
|
uint32_t ioa, uint16_t file_name, int section, uint32_t section_length, int qualifier);
|
|
IEC60870_AsduResult_t IEC60870_SectionReady_Get_From_Buffer(IEC60870_SectionReady_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_FileCallOrSelect_Create(IEC60870_FileCallOrSelect_t *self,
|
|
uint32_t ioa, uint16_t file_name, int section, int qualifier);
|
|
IEC60870_AsduResult_t IEC60870_FileCallOrSelect_Get_From_Buffer(IEC60870_FileCallOrSelect_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_FileACK_Create(IEC60870_FileACK_t *self,
|
|
uint32_t ioa, uint16_t file_name, int section, int qualifier);
|
|
IEC60870_AsduResult_t IEC60870_FileACK_Get_From_Buffer(IEC60870_FileACK_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_FileLastSegmentOrSection_Create(IEC60870_FileLastSegmentOrSection_t *self,
|
|
uint32_t ioa, uint16_t file_name, int section, int qualifier, int checksum);
|
|
IEC60870_AsduResult_t IEC60870_FileLastSegmentOrSection_Get_From_Buffer(IEC60870_FileLastSegmentOrSection_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_FileSegment_Create(IEC60870_FileSegment_t *self,
|
|
uint32_t ioa, uint16_t file_name, int section, const uint8_t *data, uint16_t data_length);
|
|
IEC60870_AsduResult_t IEC60870_FileSegment_Get_From_Buffer(IEC60870_FileSegment_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_FileDirectory_Create(IEC60870_FileDirectory_t *self,
|
|
uint32_t ioa, uint16_t file_name, uint32_t file_length, int status, const IEC60870_CP56Time2a_t *creation_time);
|
|
IEC60870_AsduResult_t IEC60870_FileDirectory_Get_From_Buffer(IEC60870_FileDirectory_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_QueryLog_Create(IEC60870_QueryLog_t *self,
|
|
uint32_t ioa, uint16_t file_name, const IEC60870_CP56Time2a_t *start_time, const IEC60870_CP56Time2a_t *stop_time);
|
|
IEC60870_AsduResult_t IEC60870_QueryLog_Get_From_Buffer(IEC60870_QueryLog_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
int IEC60870_FileSegment_Get_Max_Data_Size(const IEC60870_AppLayerParameters_t *parameters);
|
|
uint8_t IEC60870_InformationObject_Get_Type(const IEC60870_InformationObject_t *object);
|
|
IEC60870_AsduResult_t IEC60870_InformationObject_Encode(
|
|
const IEC60870_InformationObject_t *object, const IEC60870_AppLayerParameters_t *parameters,
|
|
int is_sequence, uint8_t *buffer, uint16_t capacity, uint16_t *length);
|
|
IEC60870_AsduResult_t IEC60870_SinglePointInformation_Create(IEC60870_SinglePointInformation_t *self,
|
|
uint32_t ioa, int value, int quality);
|
|
IEC60870_AsduResult_t IEC60870_SinglePointInformation_Get_From_Buffer(IEC60870_SinglePointInformation_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_DoublePointInformation_Create(IEC60870_DoublePointInformation_t *self,
|
|
uint32_t ioa, int value, int quality);
|
|
IEC60870_AsduResult_t IEC60870_DoublePointInformation_Get_From_Buffer(IEC60870_DoublePointInformation_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_MeasuredValueNormalized_Create(IEC60870_MeasuredValueNormalized_t *self,
|
|
uint32_t ioa, int16_t value, int quality);
|
|
IEC60870_AsduResult_t IEC60870_MeasuredValueNormalized_Get_From_Buffer(IEC60870_MeasuredValueNormalized_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_MeasuredValueScaled_Create(IEC60870_MeasuredValueScaled_t *self,
|
|
uint32_t ioa, int16_t value, int quality);
|
|
IEC60870_AsduResult_t IEC60870_MeasuredValueScaled_Get_From_Buffer(IEC60870_MeasuredValueScaled_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_MeasuredValueShort_Create(IEC60870_MeasuredValueShort_t *self,
|
|
uint32_t ioa, float value, int quality);
|
|
IEC60870_AsduResult_t IEC60870_MeasuredValueShort_Get_From_Buffer(IEC60870_MeasuredValueShort_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_IntegratedTotals_Create(IEC60870_IntegratedTotals_t *self,
|
|
uint32_t ioa, const IEC60870_BinaryCounterReading_t *value);
|
|
IEC60870_AsduResult_t IEC60870_IntegratedTotals_Get_From_Buffer(IEC60870_IntegratedTotals_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_SinglePointWithCP56Time2a_Create(IEC60870_SinglePointWithCP56Time2a_t *self,
|
|
uint32_t ioa, int value, int quality, const IEC60870_CP56Time2a_t *time);
|
|
IEC60870_AsduResult_t IEC60870_SinglePointWithCP56Time2a_Get_From_Buffer(IEC60870_SinglePointWithCP56Time2a_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_DoublePointWithCP56Time2a_Create(IEC60870_DoublePointWithCP56Time2a_t *self,
|
|
uint32_t ioa, int value, int quality, const IEC60870_CP56Time2a_t *time);
|
|
IEC60870_AsduResult_t IEC60870_DoublePointWithCP56Time2a_Get_From_Buffer(IEC60870_DoublePointWithCP56Time2a_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_MeasuredValueNormalizedWithCP56Time2a_Create(IEC60870_MeasuredValueNormalizedWithCP56Time2a_t *self,
|
|
uint32_t ioa, int16_t value, int quality, const IEC60870_CP56Time2a_t *time);
|
|
IEC60870_AsduResult_t IEC60870_MeasuredValueNormalizedWithCP56Time2a_Get_From_Buffer(IEC60870_MeasuredValueNormalizedWithCP56Time2a_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_MeasuredValueScaledWithCP56Time2a_Create(IEC60870_MeasuredValueScaledWithCP56Time2a_t *self,
|
|
uint32_t ioa, int16_t value, int quality, const IEC60870_CP56Time2a_t *time);
|
|
IEC60870_AsduResult_t IEC60870_MeasuredValueScaledWithCP56Time2a_Get_From_Buffer(IEC60870_MeasuredValueScaledWithCP56Time2a_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_MeasuredValueShortWithCP56Time2a_Create(IEC60870_MeasuredValueShortWithCP56Time2a_t *self,
|
|
uint32_t ioa, float value, int quality, const IEC60870_CP56Time2a_t *time);
|
|
IEC60870_AsduResult_t IEC60870_MeasuredValueShortWithCP56Time2a_Get_From_Buffer(IEC60870_MeasuredValueShortWithCP56Time2a_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_IntegratedTotalsWithCP56Time2a_Create(IEC60870_IntegratedTotalsWithCP56Time2a_t *self,
|
|
uint32_t ioa, const IEC60870_BinaryCounterReading_t *value, const IEC60870_CP56Time2a_t *time);
|
|
IEC60870_AsduResult_t IEC60870_IntegratedTotalsWithCP56Time2a_Get_From_Buffer(IEC60870_IntegratedTotalsWithCP56Time2a_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_SingleCommand_Create(IEC60870_SingleCommand_t *self,
|
|
uint32_t ioa, int state, int is_select, int qualifier);
|
|
IEC60870_AsduResult_t IEC60870_SingleCommand_Get_From_Buffer(IEC60870_SingleCommand_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_DoubleCommand_Create(IEC60870_DoubleCommand_t *self,
|
|
uint32_t ioa, int state, int is_select, int qualifier);
|
|
IEC60870_AsduResult_t IEC60870_DoubleCommand_Get_From_Buffer(IEC60870_DoubleCommand_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_StepCommand_Create(IEC60870_StepCommand_t *self,
|
|
uint32_t ioa, int state, int is_select, int qualifier);
|
|
IEC60870_AsduResult_t IEC60870_StepCommand_Get_From_Buffer(IEC60870_StepCommand_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_SetpointCommandNormalized_Create(IEC60870_SetpointCommandNormalized_t *self,
|
|
uint32_t ioa, int16_t value, int is_select, int qualifier);
|
|
IEC60870_AsduResult_t IEC60870_SetpointCommandNormalized_Get_From_Buffer(IEC60870_SetpointCommandNormalized_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_SetpointCommandScaled_Create(IEC60870_SetpointCommandScaled_t *self,
|
|
uint32_t ioa, int16_t value, int is_select, int qualifier);
|
|
IEC60870_AsduResult_t IEC60870_SetpointCommandScaled_Get_From_Buffer(IEC60870_SetpointCommandScaled_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_SetpointCommandShort_Create(IEC60870_SetpointCommandShort_t *self,
|
|
uint32_t ioa, float value, int is_select, int qualifier);
|
|
IEC60870_AsduResult_t IEC60870_SetpointCommandShort_Get_From_Buffer(IEC60870_SetpointCommandShort_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_SingleCommandWithCP56Time2a_Create(IEC60870_SingleCommandWithCP56Time2a_t *self,
|
|
uint32_t ioa, int state, int is_select, int qualifier, const IEC60870_CP56Time2a_t *time);
|
|
IEC60870_AsduResult_t IEC60870_SingleCommandWithCP56Time2a_Get_From_Buffer(IEC60870_SingleCommandWithCP56Time2a_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_DoubleCommandWithCP56Time2a_Create(IEC60870_DoubleCommandWithCP56Time2a_t *self,
|
|
uint32_t ioa, int state, int is_select, int qualifier, const IEC60870_CP56Time2a_t *time);
|
|
IEC60870_AsduResult_t IEC60870_DoubleCommandWithCP56Time2a_Get_From_Buffer(IEC60870_DoubleCommandWithCP56Time2a_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_StepCommandWithCP56Time2a_Create(IEC60870_StepCommandWithCP56Time2a_t *self,
|
|
uint32_t ioa, int state, int is_select, int qualifier, const IEC60870_CP56Time2a_t *time);
|
|
IEC60870_AsduResult_t IEC60870_StepCommandWithCP56Time2a_Get_From_Buffer(IEC60870_StepCommandWithCP56Time2a_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_SetpointCommandNormalizedWithCP56Time2a_Create(IEC60870_SetpointCommandNormalizedWithCP56Time2a_t *self,
|
|
uint32_t ioa, int16_t value, int is_select, int qualifier, const IEC60870_CP56Time2a_t *time);
|
|
IEC60870_AsduResult_t IEC60870_SetpointCommandNormalizedWithCP56Time2a_Get_From_Buffer(IEC60870_SetpointCommandNormalizedWithCP56Time2a_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_SetpointCommandScaledWithCP56Time2a_Create(IEC60870_SetpointCommandScaledWithCP56Time2a_t *self,
|
|
uint32_t ioa, int16_t value, int is_select, int qualifier, const IEC60870_CP56Time2a_t *time);
|
|
IEC60870_AsduResult_t IEC60870_SetpointCommandScaledWithCP56Time2a_Get_From_Buffer(IEC60870_SetpointCommandScaledWithCP56Time2a_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_SetpointCommandShortWithCP56Time2a_Create(IEC60870_SetpointCommandShortWithCP56Time2a_t *self,
|
|
uint32_t ioa, float value, int is_select, int qualifier, const IEC60870_CP56Time2a_t *time);
|
|
IEC60870_AsduResult_t IEC60870_SetpointCommandShortWithCP56Time2a_Get_From_Buffer(IEC60870_SetpointCommandShortWithCP56Time2a_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_InterrogationCommand_Create(IEC60870_InterrogationCommand_t *self,
|
|
uint32_t ioa, int qualifier);
|
|
IEC60870_AsduResult_t IEC60870_InterrogationCommand_Get_From_Buffer(IEC60870_InterrogationCommand_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_CounterInterrogationCommand_Create(IEC60870_CounterInterrogationCommand_t *self,
|
|
uint32_t ioa, int qualifier, int freeze);
|
|
IEC60870_AsduResult_t IEC60870_CounterInterrogationCommand_Get_From_Buffer(IEC60870_CounterInterrogationCommand_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_ReadCommand_Create(IEC60870_ReadCommand_t *self,
|
|
uint32_t ioa);
|
|
IEC60870_AsduResult_t IEC60870_ReadCommand_Get_From_Buffer(IEC60870_ReadCommand_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_ClockSynchronizationCommand_Create(IEC60870_ClockSynchronizationCommand_t *self,
|
|
uint32_t ioa, const IEC60870_CP56Time2a_t *time);
|
|
IEC60870_AsduResult_t IEC60870_ClockSynchronizationCommand_Get_From_Buffer(IEC60870_ClockSynchronizationCommand_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_ResetProcessCommand_Create(IEC60870_ResetProcessCommand_t *self,
|
|
uint32_t ioa, int qualifier);
|
|
IEC60870_AsduResult_t IEC60870_ResetProcessCommand_Get_From_Buffer(IEC60870_ResetProcessCommand_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_TestCommandWithCP56Time2a_Create(IEC60870_TestCommandWithCP56Time2a_t *self,
|
|
uint32_t ioa, uint16_t sequence, const IEC60870_CP56Time2a_t *time);
|
|
IEC60870_AsduResult_t IEC60870_TestCommandWithCP56Time2a_Get_From_Buffer(IEC60870_TestCommandWithCP56Time2a_t *self,
|
|
uint32_t ioa, const uint8_t *payload, uint16_t length);
|
|
typedef enum {
|
|
IEC60870_ASDU_COT_PERIODIC = 1,
|
|
IEC60870_ASDU_COT_BACKGROUND = 2,
|
|
IEC60870_ASDU_COT_SPONTANEOUS = 3,
|
|
IEC60870_ASDU_COT_INITIALIZED = 4,
|
|
IEC60870_ASDU_COT_REQUEST = 5,
|
|
IEC60870_ASDU_COT_ACTIVATION = 6,
|
|
IEC60870_ASDU_COT_ACTIVATION_CON = 7,
|
|
IEC60870_ASDU_COT_DEACTIVATION = 8,
|
|
IEC60870_ASDU_COT_DEACTIVATION_CON = 9,
|
|
IEC60870_ASDU_COT_ACTIVATION_TERMINATION = 10,
|
|
IEC60870_ASDU_COT_RETURN_INFO_REMOTE = 11,
|
|
IEC60870_ASDU_COT_RETURN_INFO_LOCAL = 12,
|
|
IEC60870_ASDU_COT_FILE_TRANSFER = 13,
|
|
IEC60870_ASDU_COT_INTERROGATED_BY_STATION = 20,
|
|
IEC60870_ASDU_COT_COUNTER_INTERROGATION = 37,
|
|
IEC60870_ASDU_COT_COUNTER_GROUP_1 = 38,
|
|
IEC60870_ASDU_COT_COUNTER_GROUP_2 = 39,
|
|
IEC60870_ASDU_COT_COUNTER_GROUP_3 = 40,
|
|
IEC60870_ASDU_COT_COUNTER_GROUP_4 = 41,
|
|
IEC60870_ASDU_COT_UNKNOWN_TYPE = 44,
|
|
IEC60870_ASDU_COT_UNKNOWN_CAUSE = 45,
|
|
IEC60870_ASDU_COT_UNKNOWN_COMMON_ADDRESS = 46,
|
|
IEC60870_ASDU_COT_UNKNOWN_IOA = 47
|
|
} IEC60870_AsduCause_t;
|
|
typedef struct {
|
|
uint8_t cause_of_transmission;
|
|
uint8_t is_negative_confirm;
|
|
uint8_t is_test;
|
|
uint8_t originator_address;
|
|
uint16_t common_address;
|
|
} IEC60870_AsduHeader_t;
|
|
typedef struct {
|
|
uint8_t *buffer;
|
|
uint16_t capacity;
|
|
uint16_t length;
|
|
uint8_t type_id;
|
|
uint8_t object_count;
|
|
uint8_t is_sequence;
|
|
uint8_t is_from_buffer;
|
|
uint32_t first_ioa;
|
|
const IEC60870_AppLayerParameters_t *parameters;
|
|
} IEC60870_Asdu_t;
|
|
IEC60870_AsduResult_t IEC60870_Asdu_Create(IEC60870_Asdu_t *self,
|
|
const IEC60870_AppLayerParameters_t *parameters,
|
|
uint8_t *buffer, uint16_t capacity, const IEC60870_AsduHeader_t *header, int is_sequence);
|
|
IEC60870_AsduResult_t IEC60870_Asdu_Create_From_Buffer(IEC60870_Asdu_t *self,
|
|
const IEC60870_AppLayerParameters_t *parameters, uint8_t *buffer, uint16_t length);
|
|
IEC60870_AsduResult_t IEC60870_Asdu_Set_COT(IEC60870_Asdu_t *self, int cause);
|
|
IEC60870_AsduResult_t IEC60870_Asdu_Set_Negative(IEC60870_Asdu_t *self, int is_negative);
|
|
IEC60870_AsduResult_t IEC60870_Asdu_Set_CA(IEC60870_Asdu_t *self, uint16_t common_address);
|
|
IEC60870_AsduResult_t IEC60870_Asdu_Add_InformationObject(IEC60870_Asdu_t *self,
|
|
const IEC60870_InformationObject_t *object);
|
|
IEC60870_AsduResult_t IEC60870_Asdu_Get_Data(const IEC60870_Asdu_t *self,
|
|
const uint8_t **asdu, uint16_t *length);
|
|
IEC60870_AsduResult_t IEC60870_Asdu_Parse(const IEC60870_AppLayerParameters_t *parameters,
|
|
const uint8_t *asdu, uint16_t length, IEC60870_AsduInfo_t *info);
|
|
IEC60870_AsduResult_t IEC60870_Asdu_Get_Element(const IEC60870_AsduInfo_t *info,
|
|
uint8_t index, void *object, size_t object_size);
|
|
IEC60870_AsduResult_t IEC60870_Asdu_Build_Response(const IEC60870_AppLayerParameters_t *parameters,
|
|
const uint8_t *request, uint16_t length,
|
|
int cause, int is_negative, uint8_t *out, uint16_t capacity, uint16_t *out_length);
|
|
typedef struct IEC60870_MasterConnection IEC60870_MasterConnection_t;
|
|
struct IEC60870_MasterConnection {
|
|
void *object;
|
|
_Bool (*send_asdu)(IEC60870_MasterConnection_t *self, IEC60870_Asdu_t *asdu);
|
|
_Bool (*send_act_con)(IEC60870_MasterConnection_t *self, IEC60870_Asdu_t *asdu, _Bool negative);
|
|
_Bool (*send_act_term)(IEC60870_MasterConnection_t *self, IEC60870_Asdu_t *asdu);
|
|
const IEC60870_AppLayerParameters_t *(*get_application_layer_parameters)(
|
|
IEC60870_MasterConnection_t *self);
|
|
};
|
|
_Bool IEC60870_MasterConnection_Send_ASDU(IEC60870_MasterConnection_t *self, IEC60870_Asdu_t *asdu);
|
|
_Bool IEC60870_MasterConnection_Send_ACT_CON(IEC60870_MasterConnection_t *self,
|
|
IEC60870_Asdu_t *asdu, _Bool negative);
|
|
_Bool IEC60870_MasterConnection_Send_ACT_TERM(IEC60870_MasterConnection_t *self,
|
|
IEC60870_Asdu_t *asdu);
|
|
const IEC60870_AppLayerParameters_t *IEC60870_MasterConnection_Get_Application_Layer_Parameters(
|
|
IEC60870_MasterConnection_t *self);
|
|
typedef enum {
|
|
IEC104_ASDU_PRIORITY_HIGH = 0,
|
|
IEC104_ASDU_PRIORITY_NORMAL = 1,
|
|
IEC104_ASDU_PRIORITY_COUNT = 2
|
|
} IEC104_AsduPriority_t;
|
|
typedef struct {
|
|
uint16_t k;
|
|
uint16_t w;
|
|
uint32_t t1_ms;
|
|
uint32_t t2_ms;
|
|
uint32_t t3_ms;
|
|
} IEC104_LinkConfig_t;
|
|
typedef struct {
|
|
IEC104_LinkConfig_t link;
|
|
uint32_t local_send_timeout_ms;
|
|
uint32_t stop_timeout_ms;
|
|
uint16_t high_priority_burst_limit;
|
|
} IEC104_ProtocolConfig_t;
|
|
typedef enum {
|
|
IEC104_TCP_OK = 0,
|
|
IEC104_TCP_INVALID_ARGUMENT = -1,
|
|
IEC104_TCP_INVALID_HANDLE = -2,
|
|
IEC104_TCP_INVALID_CONFIG = -3,
|
|
IEC104_TCP_INVALID_STATE = -4,
|
|
IEC104_TCP_BUSY = -5,
|
|
IEC104_TCP_EVENTS_PENDING = -6,
|
|
IEC104_TCP_NETWORK_ERROR = -7,
|
|
IEC104_TCP_INTERNAL_ERROR = -8,
|
|
IEC104_TCP_GENERATION_EXHAUSTED = -9,
|
|
IEC104_TCP_REGISTRATION_EXHAUSTED = -10,
|
|
IEC104_TCP_NOT_CONNECTED = -11,
|
|
IEC104_TCP_STALE_GENERATION = -12
|
|
} IEC104_TcpResult_t;
|
|
typedef enum {
|
|
IEC104_TCP_STAGE_NONE = 0,
|
|
IEC104_TCP_STAGE_VALIDATE,
|
|
IEC104_TCP_STAGE_LIFECYCLE,
|
|
IEC104_TCP_STAGE_NET_INIT,
|
|
IEC104_TCP_STAGE_LISTEN,
|
|
IEC104_TCP_STAGE_WAIT,
|
|
IEC104_TCP_STAGE_ACCEPT,
|
|
IEC104_TCP_STAGE_GENERATION,
|
|
IEC104_TCP_STAGE_QUEUE_INIT,
|
|
IEC104_TCP_STAGE_QUEUE_STATE,
|
|
IEC104_TCP_STAGE_CONNECTION_INIT,
|
|
IEC104_TCP_STAGE_SCHEDULE,
|
|
IEC104_TCP_STAGE_REGISTRATION
|
|
} IEC104_TcpErrorStage_t;
|
|
typedef struct {
|
|
IEC104_TcpResult_t result;
|
|
IEC104_TcpErrorStage_t stage;
|
|
int socket_error;
|
|
} IEC104_TcpError_t;
|
|
typedef uintptr_t IEC104_TcpSocket_t;
|
|
typedef struct {
|
|
IEC104_TcpSocket_t socket;
|
|
uint64_t token;
|
|
uint32_t events;
|
|
} IEC104_TcpSocketEvent_t;
|
|
typedef struct {
|
|
uint64_t service_token;
|
|
IEC104_TcpSocketEvent_t sockets[2U];
|
|
uint32_t socket_count;
|
|
uint32_t timeout_ms;
|
|
uint16_t pending_event_count;
|
|
uint8_t receive_paused;
|
|
uint8_t timer_active;
|
|
uint8_t need_process;
|
|
} IEC104_TcpWaitInfo_t;
|
|
typedef struct {
|
|
uint64_t service_token;
|
|
IEC104_TcpSocketEvent_t sockets[2U];
|
|
uint32_t socket_count;
|
|
uint8_t timer_expired;
|
|
} IEC104_TcpReady_t;
|
|
typedef enum {
|
|
IEC104_TCP_EVENT_CONNECTED = 1,
|
|
IEC104_TCP_EVENT_I_FRAME,
|
|
IEC104_TCP_EVENT_RECORD,
|
|
IEC104_TCP_EVENT_DISCONNECTED,
|
|
IEC104_TCP_EVENT_ACTIVATED,
|
|
IEC104_TCP_EVENT_DEACTIVATED
|
|
} IEC104_TcpEventType_t;
|
|
typedef enum {
|
|
IEC104_TCP_EVENT_ERROR = -1,
|
|
IEC104_TCP_EVENT_EMPTY = 0,
|
|
IEC104_TCP_EVENT_READY = 1
|
|
} IEC104_TcpEventResult_t;
|
|
typedef enum {
|
|
IEC104_TCP_SUBMIT_FATAL = -2,
|
|
IEC104_TCP_SUBMIT_ERROR = -1,
|
|
IEC104_TCP_SUBMIT_OK = 1,
|
|
IEC104_TCP_SUBMIT_WAIT = 2
|
|
} IEC104_TcpSubmitResult_t;
|
|
typedef enum {
|
|
IEC104_TCP_SESSION_NONE = 0,
|
|
IEC104_TCP_SESSION_ACTIVE,
|
|
IEC104_TCP_SESSION_FAILED,
|
|
IEC104_TCP_SESSION_CLOSED
|
|
} IEC104_TcpSessionPhase_t;
|
|
typedef enum {
|
|
IEC104_TCP_FAULT_NONE = 0,
|
|
IEC104_TCP_FAULT_FRAME,
|
|
IEC104_TCP_FAULT_PROTOCOL,
|
|
IEC104_TCP_FAULT_INTERNAL,
|
|
IEC104_TCP_FAULT_TRANSPORT,
|
|
IEC104_TCP_FAULT_LOCAL_SEND_TIMEOUT,
|
|
IEC104_TCP_FAULT_I_ACK_TIMEOUT,
|
|
IEC104_TCP_FAULT_TESTFR_TIMEOUT,
|
|
IEC104_TCP_FAULT_STOP_TIMEOUT
|
|
} IEC104_TcpFault_t;
|
|
typedef struct {
|
|
IEC104_TcpSessionPhase_t phase;
|
|
IEC104_TcpFault_t fault;
|
|
uint16_t pending_send_records;
|
|
uint8_t data_transfer_started;
|
|
} IEC104_TcpConnectionStatus_t;
|
|
typedef struct {
|
|
uint64_t generation;
|
|
char address[16];
|
|
uint16_t port;
|
|
} IEC104_TcpPeerInfo_t;
|
|
typedef struct {
|
|
uint64_t receive_serial;
|
|
uint16_t apdu_length;
|
|
uint16_t send_number;
|
|
uint16_t receive_number;
|
|
uint8_t apdu[255];
|
|
} IEC104_TcpIFrameEvent_t;
|
|
typedef struct {
|
|
uint64_t frame_serial;
|
|
uint64_t queued_at_ms;
|
|
uint64_t written_at_ms;
|
|
uint16_t send_number;
|
|
uint16_t receive_number;
|
|
uint16_t apdu_length;
|
|
IEC104_AsduPriority_t priority;
|
|
uint8_t local_send_completed;
|
|
uint8_t peer_acknowledged;
|
|
} IEC104_TcpSendRecord_t;
|
|
typedef struct {
|
|
IEC104_TcpSendRecord_t value;
|
|
uint8_t closing;
|
|
} IEC104_TcpRecordEvent_t;
|
|
typedef struct {
|
|
IEC104_TcpConnectionStatus_t status;
|
|
IEC104_TcpPeerInfo_t peer;
|
|
int socket_error;
|
|
uint8_t status_valid;
|
|
} IEC104_TcpConnectionEvent_t;
|
|
typedef struct {
|
|
IEC104_TcpEventType_t type;
|
|
uint64_t generation;
|
|
union {
|
|
IEC104_TcpIFrameEvent_t i_frame;
|
|
IEC104_TcpRecordEvent_t record;
|
|
IEC104_TcpConnectionEvent_t connection;
|
|
} data;
|
|
} IEC104_TcpEvent_t;
|
|
typedef struct {
|
|
char bind_address[16];
|
|
uint16_t port;
|
|
IEC104_ProtocolConfig_t protocol;
|
|
} IEC104_TcpServerConfig_t;
|
|
typedef struct {
|
|
uint32_t pending_asdu_count;
|
|
uint32_t stored_asdu_count;
|
|
uint32_t capacity_bytes;
|
|
uint32_t used_bytes;
|
|
uint32_t free_bytes;
|
|
} IEC104_TcpAsduQueueStatus_t;
|
|
typedef struct {
|
|
uint64_t generation;
|
|
uint16_t bound_port;
|
|
uint16_t pending_event_count;
|
|
uint16_t pending_state_event_count;
|
|
uint8_t receive_paused;
|
|
int last_socket_error;
|
|
uint8_t listening;
|
|
uint8_t connected;
|
|
uint8_t connection_status_valid;
|
|
IEC104_TcpConnectionStatus_t connection;
|
|
uint8_t asdu_queue_status_valid;
|
|
IEC104_TcpAsduQueueStatus_t high_queue;
|
|
IEC104_TcpAsduQueueStatus_t normal_queue;
|
|
uint8_t accept_paused;
|
|
uint32_t accept_retry_remaining_ms;
|
|
int last_accept_error;
|
|
uint32_t consecutive_accept_failures;
|
|
} IEC104_TcpServerStatus_t;
|
|
typedef struct IEC104_Slave IEC104_Slave_t;
|
|
typedef IEC104_TcpServerConfig_t IEC104_SlaveConfig_t;
|
|
typedef struct IEC104_Station {
|
|
struct IEC104_Station *_next;
|
|
IEC104_Slave_t *_owner;
|
|
void *_context;
|
|
uint64_t _id;
|
|
uint32_t _users;
|
|
uint16_t _common_address;
|
|
_Bool _registered;
|
|
} IEC104_Station_t;
|
|
typedef struct IEC104_StationSnapshot {
|
|
IEC104_Slave_t *_owner;
|
|
IEC104_Station_t *_next;
|
|
uint64_t _last_id;
|
|
const struct IEC104_StationSnapshot *_self;
|
|
} IEC104_StationSnapshot_t;
|
|
typedef enum {
|
|
IEC104_STATION_OK = 0,
|
|
IEC104_STATION_INVALID_ARGUMENT,
|
|
IEC104_STATION_DUPLICATE_CA,
|
|
IEC104_STATION_ALREADY_REGISTERED,
|
|
IEC104_STATION_NOT_FOUND,
|
|
IEC104_STATION_BUSY,
|
|
IEC104_STATION_LIMIT
|
|
} IEC104_StationResult_t;
|
|
IEC104_StationResult_t IEC104_Slave_Add_Station(IEC104_Slave_t *self,
|
|
IEC104_Station_t *station, uint16_t common_address, void *context);
|
|
IEC104_StationResult_t IEC104_Slave_Remove_Station(IEC104_Slave_t *self, IEC104_Station_t *station);
|
|
IEC104_Station_t *IEC104_Slave_Get_Station(const IEC104_Slave_t *self, uint16_t common_address);
|
|
size_t IEC104_Slave_Get_Station_Count(const IEC104_Slave_t *self);
|
|
IEC104_Station_t *IEC104_Slave_Get_Station_By_Id(const IEC104_Slave_t *self, uint64_t station_id);
|
|
uint64_t IEC104_Station_Get_Id(const IEC104_Station_t *station);
|
|
_Bool IEC104_Station_Is_Registered(const IEC104_Station_t *station);
|
|
_Bool IEC104_Station_Is_Reusable(const IEC104_Station_t *station);
|
|
IEC104_StationResult_t IEC104_Slave_StationSnapshot_Begin(IEC104_Slave_t *self,
|
|
IEC104_StationSnapshot_t *snapshot);
|
|
IEC104_Station_t *IEC104_Slave_StationSnapshot_Next(IEC104_StationSnapshot_t *snapshot);
|
|
IEC104_StationResult_t IEC104_Slave_StationSnapshot_End(IEC104_StationSnapshot_t *snapshot);
|
|
IEC104_Station_t *IEC104_Slave_Next_Station(const IEC104_Slave_t *self, const IEC104_Station_t *current);
|
|
IEC104_StationResult_t IEC104_Slave_Lock_Stations(IEC104_Slave_t *self);
|
|
IEC104_StationResult_t IEC104_Slave_Unlock_Stations(IEC104_Slave_t *self);
|
|
IEC104_StationResult_t IEC104_Slave_Acquire_Station(IEC104_Slave_t *self, IEC104_Station_t *station);
|
|
IEC104_StationResult_t IEC104_Slave_Release_Station(IEC104_Slave_t *self, IEC104_Station_t *station);
|
|
uint16_t IEC104_Station_Get_Common_Address(const IEC104_Station_t *station);
|
|
void *IEC104_Station_Get_Context(const IEC104_Station_t *station);
|
|
typedef struct {
|
|
IEC104_TcpEvent_t transport;
|
|
IEC60870_Asdu_t asdu;
|
|
IEC60870_AsduResult_t asdu_result;
|
|
IEC60870_MasterConnection_t connection;
|
|
IEC104_Slave_t *_owner;
|
|
uint64_t _owner_serial;
|
|
uint64_t _generation;
|
|
IEC104_TcpSubmitResult_t _last_submit_result;
|
|
} IEC104_SlaveEvent_t;
|
|
typedef struct {
|
|
const IEC104_Slave_t *slave;
|
|
uint64_t instance_id;
|
|
uint64_t generation;
|
|
} IEC104_SlaveEventIdentity_t;
|
|
typedef enum {
|
|
IEC104_SLAVE_REQUEST_ERROR = -1,
|
|
IEC104_SLAVE_REQUEST_STALE = 0,
|
|
IEC104_SLAVE_REQUEST_WAIT_EVENTS = 1,
|
|
IEC104_SLAVE_REQUEST_READY = 2
|
|
} IEC104_SlaveRequestState_t;
|
|
IEC104_Slave_t *IEC104_Slave_Create(void);
|
|
IEC104_TcpResult_t IEC104_Slave_Destroy(IEC104_Slave_t *self, IEC104_TcpError_t *error);
|
|
void IEC104_Slave_Config_Default(IEC104_SlaveConfig_t *config);
|
|
IEC104_TcpResult_t IEC104_Slave_Init(IEC104_Slave_t *self,
|
|
const IEC104_SlaveConfig_t *config, IEC104_TcpError_t *error);
|
|
IEC104_TcpResult_t IEC104_Slave_Prepare(const IEC104_Slave_t *self,
|
|
IEC104_TcpWaitInfo_t *info, IEC104_TcpError_t *error);
|
|
IEC104_TcpResult_t IEC104_Slave_Process(IEC104_Slave_t *self,
|
|
const IEC104_TcpReady_t *ready, IEC104_TcpError_t *error);
|
|
IEC104_TcpResult_t IEC104_Slave_Poll(IEC104_Slave_t *self,
|
|
uint32_t max_wait_ms, IEC104_TcpError_t *error);
|
|
IEC104_TcpEventResult_t IEC104_Slave_NextEvent(IEC104_Slave_t *self, IEC104_SlaveEvent_t *event);
|
|
_Bool IEC104_Slave_Copy_Event(IEC104_SlaveEvent_t *destination, const IEC104_SlaveEvent_t *source);
|
|
_Bool IEC104_Slave_Get_Event_Identity(const IEC104_Slave_t *self,
|
|
const IEC104_SlaveEvent_t *event, IEC104_SlaveEventIdentity_t *identity);
|
|
IEC104_SlaveRequestState_t IEC104_Slave_Check_Request(const IEC104_Slave_t *self,
|
|
const IEC104_SlaveEventIdentity_t *identity);
|
|
IEC104_TcpSubmitResult_t IEC104_Slave_Get_Last_Submit_Result(
|
|
const IEC60870_MasterConnection_t *connection);
|
|
IEC104_TcpSubmitResult_t IEC104_Slave_Try_Send_ASDU(
|
|
IEC60870_MasterConnection_t *connection, const IEC60870_Asdu_t *asdu);
|
|
IEC104_TcpSubmitResult_t IEC104_Slave_Send_Response(IEC104_Slave_t *self,
|
|
const IEC104_SlaveEventIdentity_t *identity, const IEC60870_Asdu_t *asdu);
|
|
IEC104_TcpSubmitResult_t IEC104_Slave_Try_Send_Response(IEC104_Slave_t *self,
|
|
const IEC104_SlaveEventIdentity_t *identity, const IEC60870_Asdu_t *asdu);
|
|
IEC104_TcpSubmitResult_t IEC104_Slave_Reject_Request(IEC104_Slave_t *self,
|
|
const IEC104_SlaveEvent_t *event, int cause);
|
|
const IEC60870_AppLayerParameters_t *IEC104_Slave_Get_Application_Layer_Parameters(
|
|
const IEC104_Slave_t *self);
|
|
IEC104_TcpSubmitResult_t IEC104_Slave_Enqueue_Event(IEC104_Slave_t *self, IEC60870_Asdu_t *asdu);
|
|
IEC104_TcpResult_t IEC104_Slave_Get_Remote_Address(const IEC104_Slave_t *self,
|
|
IEC104_TcpPeerInfo_t *peer, IEC104_TcpError_t *error);
|
|
IEC104_TcpResult_t IEC104_Slave_Close_Connection(IEC104_Slave_t *self,
|
|
const IEC104_SlaveEvent_t *event, IEC104_TcpError_t *error);
|
|
IEC104_TcpResult_t IEC104_Slave_Close_Connection_By_Identity(IEC104_Slave_t *self,
|
|
const IEC104_SlaveEventIdentity_t *identity, IEC104_TcpError_t *error);
|
|
IEC104_TcpResult_t IEC104_Slave_Get_Status(const IEC104_Slave_t *self,
|
|
IEC104_TcpServerStatus_t *status, IEC104_TcpError_t *error);
|
|
IEC104_TcpResult_t IEC104_Slave_Close(IEC104_Slave_t *self, IEC104_TcpError_t *error);
|
|
typedef struct IEC104_Command IEC104_Command_t;
|
|
typedef struct {
|
|
uint16_t type_mask;
|
|
uint16_t select_required_mask;
|
|
uint32_t select_timeout_ms;
|
|
uint32_t decision_timeout_ms;
|
|
uint32_t execute_timeout_ms;
|
|
_Bool send_act_term;
|
|
_Bool act_term_on_failure;
|
|
} IEC104_CommandConfig_t;
|
|
typedef struct {
|
|
uint64_t generation, receive_serial;
|
|
uint64_t station_id;
|
|
uint16_t common_address;
|
|
uint8_t originator_address, type_id;
|
|
uint32_t ioa;
|
|
_Bool is_select, selected;
|
|
uint8_t state, qualifier;
|
|
uint64_t accepted_ms;
|
|
} IEC104_CommandRequest_t;
|
|
typedef enum {
|
|
IEC104_COMMAND_SELECT = 1,
|
|
IEC104_COMMAND_EXECUTE,
|
|
IEC104_COMMAND_FINISHED
|
|
} IEC104_CommandEventType_t;
|
|
typedef enum {
|
|
IEC104_COMMAND_FINISH_NONE = 0,
|
|
IEC104_COMMAND_FINISH_COMPLETED,
|
|
IEC104_COMMAND_FINISH_EXECUTION_FAILED,
|
|
IEC104_COMMAND_FINISH_REJECTED,
|
|
IEC104_COMMAND_FINISH_ACTION_FAILED,
|
|
IEC104_COMMAND_FINISH_MISMATCH,
|
|
IEC104_COMMAND_FINISH_DEACTIVATED,
|
|
IEC104_COMMAND_FINISH_SELECT_TIMEOUT,
|
|
IEC104_COMMAND_FINISH_DECISION_TIMEOUT,
|
|
IEC104_COMMAND_FINISH_EXECUTE_TIMEOUT,
|
|
IEC104_COMMAND_FINISH_CANCELLED,
|
|
IEC104_COMMAND_FINISH_STOPPED,
|
|
IEC104_COMMAND_FINISH_DISCONNECTED,
|
|
IEC104_COMMAND_FINISH_CONNECTION_CHANGED,
|
|
IEC104_COMMAND_FINISH_SEND_ERROR,
|
|
IEC104_COMMAND_FINISH_SERVICE_ERROR
|
|
} IEC104_CommandFinishReason_t;
|
|
typedef struct {
|
|
IEC104_CommandEventType_t type;
|
|
uint64_t instance_id, transaction_id, event_serial;
|
|
IEC104_CommandRequest_t request;
|
|
IEC104_CommandFinishReason_t reason;
|
|
_Bool select_effect, execute_effect;
|
|
} IEC104_CommandEvent_t;
|
|
typedef enum {
|
|
IEC104_COMMAND_ACTION_NOT_STARTED = 0,
|
|
IEC104_COMMAND_ACTION_STARTED,
|
|
IEC104_COMMAND_ACTION_FAILED
|
|
} IEC104_CommandActionResult_t;
|
|
typedef IEC104_CommandActionResult_t (*IEC104_CommandAction_t)(void *context,
|
|
const IEC104_CommandRequest_t *request);
|
|
typedef enum {
|
|
IEC104_COMMAND_RESULT_SUCCEEDED = 1,
|
|
IEC104_COMMAND_RESULT_FAILED
|
|
} IEC104_CommandResult_t;
|
|
typedef enum {
|
|
IEC104_COMMAND_REJECT_NEGATIVE = 1,
|
|
IEC104_COMMAND_REJECT_UNKNOWN_IOA
|
|
} IEC104_CommandRejectCause_t;
|
|
typedef enum {
|
|
IEC104_COMMAND_EVENT_ERROR = -1,
|
|
IEC104_COMMAND_EVENT_IGNORED = 0,
|
|
IEC104_COMMAND_EVENT_HANDLED = 1
|
|
} IEC104_CommandEventResult_t;
|
|
typedef enum {
|
|
IEC104_COMMAND_NEXT_ERROR = -1,
|
|
IEC104_COMMAND_NEXT_EMPTY = 0,
|
|
IEC104_COMMAND_NEXT_READY = 1
|
|
} IEC104_CommandNextResult_t;
|
|
typedef enum {
|
|
IEC104_COMMAND_REPLY_STALE = -2,
|
|
IEC104_COMMAND_REPLY_ERROR = -1,
|
|
IEC104_COMMAND_REPLY_WAIT = 0,
|
|
IEC104_COMMAND_REPLY_OK = 1
|
|
} IEC104_CommandReplyResult_t;
|
|
typedef enum {
|
|
IEC104_COMMAND_PHASE_SELECT_WAIT = 1,
|
|
IEC104_COMMAND_PHASE_SELECTED,
|
|
IEC104_COMMAND_PHASE_EXECUTE_WAIT,
|
|
IEC104_COMMAND_PHASE_EXECUTING,
|
|
IEC104_COMMAND_PHASE_ENDED
|
|
} IEC104_CommandPhase_t;
|
|
typedef struct {
|
|
_Bool active;
|
|
IEC104_CommandPhase_t phase;
|
|
_Bool confirm_submitted;
|
|
_Bool result_reported, completed, term_submitted;
|
|
} IEC104_CommandTransactionInfo_t;
|
|
typedef struct {
|
|
uint64_t generation;
|
|
_Bool active, events_pending, need_process, timer_active;
|
|
_Bool busy;
|
|
uint32_t timeout_remaining_ms;
|
|
unsigned pending_replies, pending_events;
|
|
unsigned long accepted, selected, executed, completed, execution_failed, action_failed;
|
|
unsigned long submitted, negative_submitted, return_info_submitted, waits;
|
|
unsigned long rejected, app_rejected, busy_rejected, overloads, dropped_requests, cancelled;
|
|
unsigned long deactivated, mismatches, select_timeouts, decision_timeouts, execute_timeouts;
|
|
unsigned long clock_errors;
|
|
} IEC104_CommandStatus_t;
|
|
void IEC104_Command_Config_Default(IEC104_CommandConfig_t *config);
|
|
IEC104_Command_t *IEC104_Command_Create(IEC104_Slave_t *slave, const IEC104_CommandConfig_t *config);
|
|
_Bool IEC104_Command_Destroy(IEC104_Command_t *self);
|
|
void IEC104_Command_Cancel(IEC104_Command_t *self);
|
|
IEC104_CommandEventResult_t IEC104_Command_Handle_Event(IEC104_Command_t *self,
|
|
const IEC104_SlaveEvent_t *event);
|
|
_Bool IEC104_Command_Process(IEC104_Command_t *self);
|
|
IEC104_CommandNextResult_t IEC104_Command_NextEvent(IEC104_Command_t *self,
|
|
IEC104_CommandEvent_t *event);
|
|
IEC104_CommandReplyResult_t IEC104_Command_Accept(IEC104_Command_t *self,
|
|
const IEC104_CommandEvent_t *event, IEC104_CommandAction_t action, void *context);
|
|
IEC104_CommandReplyResult_t IEC104_Command_Reject(IEC104_Command_t *self,
|
|
const IEC104_CommandEvent_t *event, IEC104_CommandRejectCause_t cause);
|
|
IEC104_CommandReplyResult_t IEC104_Command_Report_Result(IEC104_Command_t *self,
|
|
const IEC104_CommandEvent_t *event, IEC104_CommandResult_t result);
|
|
IEC104_CommandReplyResult_t IEC104_Command_Submit_Return_Info(IEC104_Command_t *self,
|
|
const IEC104_CommandEvent_t *event, const IEC60870_Asdu_t *asdu);
|
|
IEC104_CommandReplyResult_t IEC104_Command_Complete(IEC104_Command_t *self,
|
|
const IEC104_CommandEvent_t *event);
|
|
_Bool IEC104_Command_Get_Transaction(const IEC104_Command_t *self,
|
|
const IEC104_CommandEvent_t *event, IEC104_CommandTransactionInfo_t *info);
|
|
_Bool IEC104_Command_Get_Status(const IEC104_Command_t *self, IEC104_CommandStatus_t *status);
|
|
typedef uintptr_t IEC104_NetSocket_t;
|
|
typedef enum {
|
|
IEC104_NET_ERROR = -1,
|
|
IEC104_NET_OK = 0,
|
|
IEC104_NET_WOULD_BLOCK,
|
|
IEC104_NET_RETRY,
|
|
IEC104_NET_EOF,
|
|
IEC104_NET_RETRY_LATER
|
|
} IEC104_NetResult_t;
|
|
typedef struct {
|
|
IEC104_NetResult_t result;
|
|
size_t transferred;
|
|
int native_error;
|
|
} IEC104_NetIoResult_t;
|
|
typedef struct {
|
|
char address[16];
|
|
uint16_t port;
|
|
} IEC104_NetPeer_t;
|
|
extern IEC104_NetResult_t IEC104_Net_Init(int *native_error);
|
|
extern void IEC104_Net_Cleanup(void);
|
|
extern int IEC104_Net_Invalid_Argument_Error(void);
|
|
extern IEC104_NetResult_t IEC104_Net_Listen(
|
|
const char *bind_address, uint16_t port, IEC104_NetSocket_t *listener,
|
|
uint16_t *bound_port, int *native_error);
|
|
extern IEC104_NetResult_t IEC104_Net_Accept(
|
|
IEC104_NetSocket_t listener, IEC104_NetSocket_t *client, IEC104_NetPeer_t *peer, int *native_error);
|
|
extern IEC104_NetIoResult_t IEC104_Net_Recv(
|
|
IEC104_NetSocket_t socket_handle, void *data, size_t capacity);
|
|
extern IEC104_NetResult_t IEC104_Net_Pending_Input(
|
|
IEC104_NetSocket_t socket_handle, uint32_t *available, int *native_error);
|
|
extern IEC104_NetIoResult_t IEC104_Net_Send(
|
|
IEC104_NetSocket_t socket_handle, const void *data, size_t length);
|
|
extern IEC104_NetResult_t IEC104_Net_Wait(
|
|
IEC104_NetSocket_t listener, IEC104_NetSocket_t client, uint32_t interest,
|
|
uint32_t timeout_ms, uint32_t *ready_events, int *native_error);
|
|
extern IEC104_NetResult_t IEC104_Net_Close(
|
|
IEC104_NetSocket_t socket_handle, int *native_error);
|
|
extern uint64_t IEC104_Net_Now_Ms(void);
|
|
__attribute__ ((__dllimport__)) void *__attribute__((__cdecl__)) _memccpy(void *_Dst,const void *_Src,int _Val,size_t _MaxCount);
|
|
void *__attribute__((__cdecl__)) memchr(const void *_Buf ,int _Val,size_t _MaxCount);
|
|
__attribute__ ((__dllimport__)) int __attribute__((__cdecl__)) _memicmp(const void *_Buf1,const void *_Buf2,size_t _Size);
|
|
__attribute__ ((__dllimport__)) int __attribute__((__cdecl__)) _memicmp_l(const void *_Buf1,const void *_Buf2,size_t _Size,_locale_t _Locale);
|
|
int __attribute__((__cdecl__)) memcmp(const void *_Buf1,const void *_Buf2,size_t _Size);
|
|
void * __attribute__((__cdecl__)) memcpy(void * __restrict__ _Dst,const void * __restrict__ _Src,size_t _Size) ;
|
|
__attribute__((dllimport)) errno_t __attribute__((__cdecl__)) memcpy_s (void *_dest,size_t _numberOfElements,const void *_src,size_t _count);
|
|
void * __attribute__((__cdecl__)) mempcpy (void *_Dst, const void *_Src, size_t _Size);
|
|
void * __attribute__((__cdecl__)) memset(void *_Dst,int _Val,size_t _Size);
|
|
void * __attribute__((__cdecl__)) memccpy(void *_Dst,const void *_Src,int _Val,size_t _Size) ;
|
|
int __attribute__((__cdecl__)) memicmp(const void *_Buf1,const void *_Buf2,size_t _Size) ;
|
|
char * __attribute__((__cdecl__)) _strset(char *_Str,int _Val) ;
|
|
char * __attribute__((__cdecl__)) _strset_l(char *_Str,int _Val,_locale_t _Locale) ;
|
|
char * __attribute__((__cdecl__)) strcpy(char * __restrict__ _Dest,const char * __restrict__ _Source);
|
|
char * __attribute__((__cdecl__)) strcat(char * __restrict__ _Dest,const char * __restrict__ _Source);
|
|
int __attribute__((__cdecl__)) strcmp(const char *_Str1,const char *_Str2);
|
|
size_t __attribute__((__cdecl__)) strlen(const char *_Str);
|
|
size_t __attribute__((__cdecl__)) strnlen(const char *_Str,size_t _MaxCount);
|
|
void *__attribute__((__cdecl__)) memmove(void *_Dst,const void *_Src,size_t _Size) ;
|
|
__attribute__ ((__dllimport__)) char *__attribute__((__cdecl__)) _strdup(const char *_Src);
|
|
char *__attribute__((__cdecl__)) strchr(const char *_Str,int _Val);
|
|
__attribute__ ((__dllimport__)) int __attribute__((__cdecl__)) _stricmp(const char *_Str1,const char *_Str2);
|
|
__attribute__ ((__dllimport__)) int __attribute__((__cdecl__)) _strcmpi(const char *_Str1,const char *_Str2);
|
|
__attribute__ ((__dllimport__)) int __attribute__((__cdecl__)) _stricmp_l(const char *_Str1,const char *_Str2,_locale_t _Locale);
|
|
__attribute__ ((__dllimport__)) int __attribute__((__cdecl__)) strcoll(const char *_Str1,const char *_Str2);
|
|
__attribute__ ((__dllimport__)) int __attribute__((__cdecl__)) _strcoll_l(const char *_Str1,const char *_Str2,_locale_t _Locale);
|
|
__attribute__ ((__dllimport__)) int __attribute__((__cdecl__)) _stricoll(const char *_Str1,const char *_Str2);
|
|
__attribute__ ((__dllimport__)) int __attribute__((__cdecl__)) _stricoll_l(const char *_Str1,const char *_Str2,_locale_t _Locale);
|
|
__attribute__ ((__dllimport__)) int __attribute__((__cdecl__)) _strncoll (const char *_Str1,const char *_Str2,size_t _MaxCount);
|
|
__attribute__ ((__dllimport__)) int __attribute__((__cdecl__)) _strncoll_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale);
|
|
__attribute__ ((__dllimport__)) int __attribute__((__cdecl__)) _strnicoll (const char *_Str1,const char *_Str2,size_t _MaxCount);
|
|
__attribute__ ((__dllimport__)) int __attribute__((__cdecl__)) _strnicoll_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale);
|
|
size_t __attribute__((__cdecl__)) strcspn(const char *_Str,const char *_Control);
|
|
__attribute__ ((__dllimport__)) char *__attribute__((__cdecl__)) _strerror(const char *_ErrMsg) ;
|
|
__attribute__ ((__dllimport__)) char *__attribute__((__cdecl__)) strerror(int) ;
|
|
__attribute__ ((__dllimport__)) char *__attribute__((__cdecl__)) _strlwr(char *_String) ;
|
|
char *strlwr_l(char *_String,_locale_t _Locale) ;
|
|
char *__attribute__((__cdecl__)) strncat(char * __restrict__ _Dest,const char * __restrict__ _Source,size_t _Count) ;
|
|
int __attribute__((__cdecl__)) strncmp(const char *_Str1,const char *_Str2,size_t _MaxCount);
|
|
__attribute__ ((__dllimport__)) int __attribute__((__cdecl__)) _strnicmp(const char *_Str1,const char *_Str2,size_t _MaxCount);
|
|
__attribute__ ((__dllimport__)) int __attribute__((__cdecl__)) _strnicmp_l(const char *_Str1,const char *_Str2,size_t _MaxCount,_locale_t _Locale);
|
|
char *strncpy(char * __restrict__ _Dest,const char * __restrict__ _Source,size_t _Count) ;
|
|
__attribute__ ((__dllimport__)) char *__attribute__((__cdecl__)) _strnset(char *_Str,int _Val,size_t _MaxCount) ;
|
|
__attribute__ ((__dllimport__)) char *__attribute__((__cdecl__)) _strnset_l(char *str,int c,size_t count,_locale_t _Locale) ;
|
|
char *__attribute__((__cdecl__)) strpbrk(const char *_Str,const char *_Control);
|
|
char *__attribute__((__cdecl__)) strrchr(const char *_Str,int _Ch);
|
|
__attribute__ ((__dllimport__)) char *__attribute__((__cdecl__)) _strrev(char *_Str);
|
|
size_t __attribute__((__cdecl__)) strspn(const char *_Str,const char *_Control);
|
|
char *__attribute__((__cdecl__)) strstr(const char *_Str,const char *_SubStr);
|
|
__attribute__ ((__dllimport__)) char *__attribute__((__cdecl__)) strtok(char * __restrict__ _Str,const char * __restrict__ _Delim) ;
|
|
|
|
char *strtok_r(char * __restrict__ _Str, const char * __restrict__ _Delim, char ** __restrict__ __last);
|
|
|
|
__attribute__ ((__dllimport__)) char *__attribute__((__cdecl__)) _strupr(char *_String) ;
|
|
__attribute__ ((__dllimport__)) char *_strupr_l(char *_String,_locale_t _Locale) ;
|
|
__attribute__ ((__dllimport__)) size_t __attribute__((__cdecl__)) strxfrm(char * __restrict__ _Dst,const char * __restrict__ _Src,size_t _MaxCount);
|
|
__attribute__ ((__dllimport__)) size_t __attribute__((__cdecl__)) _strxfrm_l(char * __restrict__ _Dst,const char * __restrict__ _Src,size_t _MaxCount,_locale_t _Locale);
|
|
char *__attribute__((__cdecl__)) strdup(const char *_Src) ;
|
|
int __attribute__((__cdecl__)) strcmpi(const char *_Str1,const char *_Str2) ;
|
|
int __attribute__((__cdecl__)) stricmp(const char *_Str1,const char *_Str2) ;
|
|
char *__attribute__((__cdecl__)) strlwr(char *_Str) ;
|
|
int __attribute__((__cdecl__)) strnicmp(const char *_Str1,const char *_Str,size_t _MaxCount) ;
|
|
int __attribute__((__cdecl__)) strncasecmp (const char *, const char *, size_t);
|
|
int __attribute__((__cdecl__)) strcasecmp (const char *, const char *);
|
|
char *__attribute__((__cdecl__)) strnset(char *_Str,int _Val,size_t _MaxCount) ;
|
|
char *__attribute__((__cdecl__)) strrev(char *_Str) ;
|
|
char *__attribute__((__cdecl__)) strset(char *_Str,int _Val) ;
|
|
char *__attribute__((__cdecl__)) strupr(char *_Str) ;
|
|
__attribute__ ((__dllimport__)) wchar_t *__attribute__((__cdecl__)) _wcsdup(const wchar_t *_Str);
|
|
wchar_t *__attribute__((__cdecl__)) wcscat(wchar_t * __restrict__ _Dest,const wchar_t * __restrict__ _Source) ;
|
|
wchar_t *__attribute__((__cdecl__)) wcschr(const wchar_t *_Str,wchar_t _Ch);
|
|
int __attribute__((__cdecl__)) wcscmp(const wchar_t *_Str1,const wchar_t *_Str2);
|
|
wchar_t *__attribute__((__cdecl__)) wcscpy(wchar_t * __restrict__ _Dest,const wchar_t * __restrict__ _Source) ;
|
|
size_t __attribute__((__cdecl__)) wcscspn(const wchar_t *_Str,const wchar_t *_Control);
|
|
size_t __attribute__((__cdecl__)) wcslen(const wchar_t *_Str);
|
|
size_t __attribute__((__cdecl__)) wcsnlen(const wchar_t *_Src,size_t _MaxCount);
|
|
wchar_t *wcsncat(wchar_t * __restrict__ _Dest,const wchar_t * __restrict__ _Source,size_t _Count) ;
|
|
int __attribute__((__cdecl__)) wcsncmp(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount);
|
|
wchar_t *wcsncpy(wchar_t * __restrict__ _Dest,const wchar_t * __restrict__ _Source,size_t _Count) ;
|
|
wchar_t *__attribute__((__cdecl__)) _wcsncpy_l(wchar_t * __restrict__ _Dest,const wchar_t * __restrict__ _Source,size_t _Count,_locale_t _Locale) ;
|
|
wchar_t *__attribute__((__cdecl__)) wcspbrk(const wchar_t *_Str,const wchar_t *_Control);
|
|
wchar_t *__attribute__((__cdecl__)) wcsrchr(const wchar_t *_Str,wchar_t _Ch);
|
|
size_t __attribute__((__cdecl__)) wcsspn(const wchar_t *_Str,const wchar_t *_Control);
|
|
wchar_t *__attribute__((__cdecl__)) wcsstr(const wchar_t *_Str,const wchar_t *_SubStr);
|
|
__attribute__ ((__dllimport__)) wchar_t *__attribute__((__cdecl__)) wcstok(wchar_t * __restrict__ _Str,const wchar_t * __restrict__ _Delim,wchar_t ** __restrict__ _Ptr) ;
|
|
__attribute__ ((__dllimport__)) wchar_t *__attribute__((__cdecl__)) _wcstok(wchar_t * __restrict__ _Str,const wchar_t * __restrict__ _Delim) ;
|
|
__attribute__ ((__dllimport__)) wchar_t *__attribute__((__cdecl__)) _wcserror(int _ErrNum) ;
|
|
__attribute__ ((__dllimport__)) wchar_t *__attribute__((__cdecl__)) __wcserror(const wchar_t *_Str) ;
|
|
__attribute__ ((__dllimport__)) int __attribute__((__cdecl__)) _wcsicmp(const wchar_t *_Str1,const wchar_t *_Str2);
|
|
__attribute__ ((__dllimport__)) int __attribute__((__cdecl__)) _wcsicmp_l(const wchar_t *_Str1,const wchar_t *_Str2,_locale_t _Locale);
|
|
__attribute__ ((__dllimport__)) int __attribute__((__cdecl__)) _wcsnicmp(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount);
|
|
__attribute__ ((__dllimport__)) int __attribute__((__cdecl__)) _wcsnicmp_l(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount,_locale_t _Locale);
|
|
__attribute__ ((__dllimport__)) wchar_t *__attribute__((__cdecl__)) _wcsnset(wchar_t *_Str,wchar_t _Val,size_t _MaxCount) ;
|
|
__attribute__ ((__dllimport__)) wchar_t *__attribute__((__cdecl__)) _wcsrev(wchar_t *_Str);
|
|
__attribute__ ((__dllimport__)) wchar_t *__attribute__((__cdecl__)) _wcsset(wchar_t *_Str,wchar_t _Val) ;
|
|
__attribute__ ((__dllimport__)) wchar_t *__attribute__((__cdecl__)) _wcslwr(wchar_t *_String) ;
|
|
__attribute__ ((__dllimport__)) wchar_t *_wcslwr_l(wchar_t *_String,_locale_t _Locale) ;
|
|
__attribute__ ((__dllimport__)) wchar_t *__attribute__((__cdecl__)) _wcsupr(wchar_t *_String) ;
|
|
__attribute__ ((__dllimport__)) wchar_t *_wcsupr_l(wchar_t *_String,_locale_t _Locale) ;
|
|
__attribute__ ((__dllimport__)) size_t __attribute__((__cdecl__)) wcsxfrm(wchar_t * __restrict__ _Dst,const wchar_t * __restrict__ _Src,size_t _MaxCount);
|
|
__attribute__ ((__dllimport__)) size_t __attribute__((__cdecl__)) _wcsxfrm_l(wchar_t * __restrict__ _Dst,const wchar_t * __restrict__ _Src,size_t _MaxCount,_locale_t _Locale);
|
|
__attribute__ ((__dllimport__)) int __attribute__((__cdecl__)) wcscoll(const wchar_t *_Str1,const wchar_t *_Str2);
|
|
__attribute__ ((__dllimport__)) int __attribute__((__cdecl__)) _wcscoll_l(const wchar_t *_Str1,const wchar_t *_Str2,_locale_t _Locale);
|
|
__attribute__ ((__dllimport__)) int __attribute__((__cdecl__)) _wcsicoll(const wchar_t *_Str1,const wchar_t *_Str2);
|
|
__attribute__ ((__dllimport__)) int __attribute__((__cdecl__)) _wcsicoll_l(const wchar_t *_Str1,const wchar_t *_Str2,_locale_t _Locale);
|
|
__attribute__ ((__dllimport__)) int __attribute__((__cdecl__)) _wcsncoll(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount);
|
|
__attribute__ ((__dllimport__)) int __attribute__((__cdecl__)) _wcsncoll_l(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount,_locale_t _Locale);
|
|
__attribute__ ((__dllimport__)) int __attribute__((__cdecl__)) _wcsnicoll(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount);
|
|
__attribute__ ((__dllimport__)) int __attribute__((__cdecl__)) _wcsnicoll_l(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount,_locale_t _Locale);
|
|
wchar_t *__attribute__((__cdecl__)) wcsdup(const wchar_t *_Str) ;
|
|
int __attribute__((__cdecl__)) wcsicmp(const wchar_t *_Str1,const wchar_t *_Str2) ;
|
|
int __attribute__((__cdecl__)) wcsnicmp(const wchar_t *_Str1,const wchar_t *_Str2,size_t _MaxCount) ;
|
|
wchar_t *__attribute__((__cdecl__)) wcsnset(wchar_t *_Str,wchar_t _Val,size_t _MaxCount) ;
|
|
wchar_t *__attribute__((__cdecl__)) wcsrev(wchar_t *_Str) ;
|
|
wchar_t *__attribute__((__cdecl__)) wcsset(wchar_t *_Str,wchar_t _Val) ;
|
|
wchar_t *__attribute__((__cdecl__)) wcslwr(wchar_t *_Str) ;
|
|
wchar_t *__attribute__((__cdecl__)) wcsupr(wchar_t *_Str) ;
|
|
int __attribute__((__cdecl__)) wcsicoll(const wchar_t *_Str1,const wchar_t *_Str2) ;
|
|
__attribute__ ((__dllimport__)) errno_t __attribute__((__cdecl__)) _strset_s(char *_Dst,size_t _DstSize,int _Value);
|
|
|
|
__attribute__ ((__dllimport__)) errno_t __attribute__((__cdecl__)) _strerror_s(char *_Buf,size_t _SizeInBytes,const char *_ErrMsg);
|
|
|
|
__attribute__((dllimport)) errno_t __attribute__((__cdecl__)) strerror_s(char *_Buf,size_t _SizeInBytes,int _ErrNum);
|
|
|
|
__attribute__ ((__dllimport__)) errno_t __attribute__((__cdecl__)) _strlwr_s(char *_Str,size_t _Size);
|
|
|
|
__attribute__ ((__dllimport__)) errno_t __attribute__((__cdecl__)) _strlwr_s_l(char *_Str,size_t _Size,_locale_t _Locale);
|
|
|
|
__attribute__ ((__dllimport__)) errno_t __attribute__((__cdecl__)) _strnset_s(char *_Str,size_t _Size,int _Val,size_t _MaxCount);
|
|
|
|
__attribute__ ((__dllimport__)) errno_t __attribute__((__cdecl__)) _strupr_s(char *_Str,size_t _Size);
|
|
|
|
__attribute__ ((__dllimport__)) errno_t __attribute__((__cdecl__)) _strupr_s_l(char *_Str,size_t _Size,_locale_t _Locale);
|
|
|
|
__attribute__ ((__dllimport__)) errno_t __attribute__((__cdecl__)) strncat_s(char *_Dst,size_t _DstSizeInChars,const char *_Src,size_t _MaxCount);
|
|
|
|
__attribute__ ((__dllimport__)) errno_t __attribute__((__cdecl__)) _strncat_s_l(char *_Dst,size_t _DstSizeInChars,const char *_Src,size_t _MaxCount,_locale_t _Locale);
|
|
|
|
__attribute__ ((__dllimport__)) errno_t __attribute__((__cdecl__)) strcpy_s(char *_Dst, rsize_t _SizeInBytes, const char *_Src);
|
|
|
|
__attribute__ ((__dllimport__)) errno_t __attribute__((__cdecl__)) strncpy_s(char *_Dst, size_t _DstSizeInChars, const char *_Src, size_t _MaxCount);
|
|
|
|
__attribute__ ((__dllimport__)) errno_t __attribute__((__cdecl__)) _strncpy_s_l(char *_Dst, size_t _DstSizeInChars, const char *_Src, size_t _MaxCount, _locale_t _Locale);
|
|
|
|
__attribute__ ((__dllimport__)) char *__attribute__((__cdecl__)) strtok_s(char *_Str,const char *_Delim,char **_Context);
|
|
__attribute__ ((__dllimport__)) char *__attribute__((__cdecl__)) _strtok_s_l(char *_Str,const char *_Delim,char **_Context,_locale_t _Locale);
|
|
__attribute__ ((__dllimport__)) errno_t __attribute__((__cdecl__)) strcat_s(char *_Dst, rsize_t _SizeInBytes, const char * _Src);
|
|
|
|
extern __inline__ __attribute__((__always_inline__,__gnu_inline__)) size_t __attribute__((__cdecl__)) strnlen_s(const char * _src, size_t _count) {
|
|
return _src ? strnlen(_src, _count) : 0;
|
|
}
|
|
__attribute__((dllimport)) errno_t __attribute__((__cdecl__)) memmove_s(void *_dest,size_t _numberOfElements,const void *_src,size_t _count);
|
|
__attribute__ ((__dllimport__)) wchar_t *__attribute__((__cdecl__)) wcstok_s(wchar_t *_Str,const wchar_t *_Delim,wchar_t **_Context);
|
|
__attribute__ ((__dllimport__)) errno_t __attribute__((__cdecl__)) _wcserror_s(wchar_t *_Buf,size_t _SizeInWords,int _ErrNum);
|
|
|
|
__attribute__ ((__dllimport__)) errno_t __attribute__((__cdecl__)) __wcserror_s(wchar_t *_Buffer,size_t _SizeInWords,const wchar_t *_ErrMsg);
|
|
__attribute__ ((__dllimport__)) errno_t __attribute__((__cdecl__)) _wcsnset_s(wchar_t *_Dst,size_t _DstSizeInWords,wchar_t _Val,size_t _MaxCount);
|
|
__attribute__ ((__dllimport__)) errno_t __attribute__((__cdecl__)) _wcsset_s(wchar_t *_Str,size_t _SizeInWords,wchar_t _Val);
|
|
__attribute__ ((__dllimport__)) errno_t __attribute__((__cdecl__)) _wcslwr_s(wchar_t *_Str,size_t _SizeInWords);
|
|
|
|
__attribute__ ((__dllimport__)) errno_t __attribute__((__cdecl__)) _wcslwr_s_l(wchar_t *_Str,size_t _SizeInWords,_locale_t _Locale);
|
|
|
|
__attribute__ ((__dllimport__)) errno_t __attribute__((__cdecl__)) _wcsupr_s(wchar_t *_Str,size_t _Size);
|
|
|
|
__attribute__ ((__dllimport__)) errno_t __attribute__((__cdecl__)) _wcsupr_s_l(wchar_t *_Str,size_t _Size,_locale_t _Locale);
|
|
|
|
__attribute__ ((__dllimport__)) errno_t __attribute__((__cdecl__)) wcscpy_s(wchar_t *_Dst, rsize_t _SizeInWords, const wchar_t *_Src);
|
|
|
|
__attribute__ ((__dllimport__)) errno_t __attribute__((__cdecl__)) wcscat_s(wchar_t * _Dst, rsize_t _SizeInWords, const wchar_t *_Src);
|
|
|
|
__attribute__ ((__dllimport__)) errno_t __attribute__((__cdecl__)) wcsncat_s(wchar_t *_Dst,size_t _DstSizeInChars,const wchar_t *_Src,size_t _MaxCount);
|
|
|
|
__attribute__ ((__dllimport__)) errno_t __attribute__((__cdecl__)) _wcsncat_s_l(wchar_t *_Dst,size_t _DstSizeInChars,const wchar_t *_Src,size_t _MaxCount,_locale_t _Locale);
|
|
|
|
__attribute__ ((__dllimport__)) errno_t __attribute__((__cdecl__)) wcsncpy_s(wchar_t *_Dst, size_t _DstSizeInChars, const wchar_t *_Src, size_t _MaxCount);
|
|
|
|
__attribute__ ((__dllimport__)) errno_t __attribute__((__cdecl__)) _wcsncpy_s_l(wchar_t *_Dst, size_t _DstSizeInChars, const wchar_t *_Src, size_t _MaxCount, _locale_t _Locale);
|
|
|
|
__attribute__ ((__dllimport__)) wchar_t *__attribute__((__cdecl__)) _wcstok_s_l(wchar_t *_Str,const wchar_t *_Delim,wchar_t **_Context,_locale_t _Locale);
|
|
__attribute__ ((__dllimport__)) errno_t __attribute__((__cdecl__)) _wcsset_s_l(wchar_t *_Str,size_t _SizeInChars,wchar_t _Val,_locale_t _Locale);
|
|
|
|
__attribute__ ((__dllimport__)) errno_t __attribute__((__cdecl__)) _wcsnset_s_l(wchar_t *_Str,size_t _SizeInChars,wchar_t _Val, size_t _Count,_locale_t _Locale);
|
|
|
|
extern __inline__ __attribute__((__always_inline__,__gnu_inline__)) size_t __attribute__((__cdecl__)) wcsnlen_s(const wchar_t * _src, size_t _count) {
|
|
return _src ? wcsnlen(_src, _count) : 0;
|
|
}
|
|
_Static_assert(1U > 0U, "Command needs instance storage");
|
|
_Static_assert(4U > 0U &&
|
|
4U < 0xffffffffU / 2U, "Command needs bounded reply storage");
|
|
typedef struct {
|
|
IEC104_SlaveEventIdentity_t identity;
|
|
uint8_t request_bytes[10], reply_bytes[10];
|
|
IEC104_Station_t *station;
|
|
uint64_t transaction_id, receive_serial, accepted_ms, timer_start_ms;
|
|
uint64_t event_serial, accepted_event_serial, select_event_serial, execute_event_serial;
|
|
uint64_t confirm_serial, term_serial, reply_serial;
|
|
uint8_t phase, event_type, finish_reason, result, confirm_cot, reply_cot;
|
|
_Bool occupied, event_taken, ever_work_delivered, finish_pending;
|
|
_Bool select_delivered, execute_delivered, selected;
|
|
_Bool confirm_negative, confirm_try, send_waiting, return_waiting;
|
|
_Bool confirm_submitted, completed, term_submitted, select_effect, execute_effect;
|
|
} CommandTransaction;
|
|
typedef struct {
|
|
IEC104_SlaveEventIdentity_t identity;
|
|
uint8_t bytes[10];
|
|
uint64_t serial;
|
|
uint8_t cot;
|
|
_Bool occupied, send_waiting;
|
|
} CommandReply;
|
|
struct IEC104_Command {
|
|
IEC104_Slave_t *slave;
|
|
IEC104_SlaveEventIdentity_t session;
|
|
IEC104_CommandConfig_t config;
|
|
IEC104_CommandStatus_t status;
|
|
CommandTransaction transaction;
|
|
CommandReply replies[4U];
|
|
uint64_t serial, next_transaction, next_event, next_reply, last_generation;
|
|
_Bool in_use, in_action;
|
|
};
|
|
static IEC104_Command_t command_pool[1U];
|
|
static uint64_t next_instance;
|
|
static _Bool Owned(const IEC104_Command_t *self)
|
|
{
|
|
unsigned i;
|
|
for (i = 0U; i < 1U; ++i) {
|
|
if (self == &command_pool[i]) { return self->in_use; }
|
|
}
|
|
return 0;
|
|
}
|
|
static uint32_t Read_IOA(const uint8_t *bytes)
|
|
{
|
|
return (uint32_t)bytes[6] | ((uint32_t)bytes[7] << 8) | ((uint32_t)bytes[8] << 16);
|
|
}
|
|
static uint16_t Read_CA(const uint8_t *bytes)
|
|
{
|
|
return (uint16_t)((uint16_t)bytes[4] | ((uint16_t)bytes[5] << 8));
|
|
}
|
|
static void Copy_Request(const CommandTransaction *task, IEC104_CommandRequest_t *request)
|
|
{
|
|
memset(request, 0, sizeof(*request));
|
|
request->generation = task->identity.generation;
|
|
request->receive_serial = task->receive_serial;
|
|
request->station_id = IEC104_Station_Get_Id(task->station);
|
|
request->common_address = Read_CA(task->request_bytes);
|
|
request->originator_address = task->request_bytes[3];
|
|
request->type_id = task->request_bytes[0];
|
|
request->ioa = Read_IOA(task->request_bytes);
|
|
request->is_select = (task->request_bytes[9] & 0x80U) != 0U;
|
|
request->selected = task->selected;
|
|
request->state = task->request_bytes[9] & (request->type_id == 45U ? 1U : 3U);
|
|
request->qualifier = (task->request_bytes[9] >> 2) & 31U;
|
|
request->accepted_ms = task->accepted_ms;
|
|
}
|
|
static unsigned Pending_Replies(const IEC104_Command_t *self)
|
|
{
|
|
const CommandTransaction *task = &self->transaction;
|
|
unsigned i, count = (task->confirm_serial != 0U ? 1U : 0U) +
|
|
(task->term_serial != 0U ? 1U : 0U) + (task->reply_serial != 0U ? 1U : 0U);
|
|
for (i = 0U; i < 4U; ++i) {
|
|
if (self->replies[i].occupied) { ++count; }
|
|
}
|
|
return count;
|
|
}
|
|
static void Reap(IEC104_Command_t *self)
|
|
{
|
|
CommandTransaction *task = &self->transaction;
|
|
if (!task->occupied || task->phase != IEC104_COMMAND_PHASE_ENDED || task->finish_pending ||
|
|
task->confirm_serial != 0U || task->term_serial != 0U || task->reply_serial != 0U) { return; }
|
|
(void)IEC104_Slave_Release_Station(self->slave, task->station);
|
|
memset(task, 0, sizeof(*task));
|
|
}
|
|
static void Finish(IEC104_Command_t *self, IEC104_CommandFinishReason_t reason)
|
|
{
|
|
CommandTransaction *task = &self->transaction;
|
|
if (!task->occupied || task->phase == IEC104_COMMAND_PHASE_ENDED) { Reap(self); return; }
|
|
task->phase = IEC104_COMMAND_PHASE_ENDED;
|
|
task->finish_reason = (uint8_t)reason;
|
|
task->event_type = IEC104_COMMAND_FINISHED;
|
|
task->event_taken = 0;
|
|
task->finish_pending = task->ever_work_delivered;
|
|
task->return_waiting = 0;
|
|
if (task->finish_pending) { task->event_serial = ++self->next_event; }
|
|
switch (reason) {
|
|
case IEC104_COMMAND_FINISH_COMPLETED: ++self->status.completed; break;
|
|
case IEC104_COMMAND_FINISH_EXECUTION_FAILED: ++self->status.execution_failed; break;
|
|
case IEC104_COMMAND_FINISH_ACTION_FAILED: ++self->status.action_failed; break;
|
|
case IEC104_COMMAND_FINISH_MISMATCH: ++self->status.mismatches; break;
|
|
case IEC104_COMMAND_FINISH_DEACTIVATED: ++self->status.deactivated; break;
|
|
case IEC104_COMMAND_FINISH_SELECT_TIMEOUT: ++self->status.select_timeouts; break;
|
|
case IEC104_COMMAND_FINISH_DECISION_TIMEOUT: ++self->status.decision_timeouts; break;
|
|
case IEC104_COMMAND_FINISH_EXECUTE_TIMEOUT: ++self->status.execute_timeouts; break;
|
|
case IEC104_COMMAND_FINISH_CANCELLED:
|
|
case IEC104_COMMAND_FINISH_STOPPED:
|
|
case IEC104_COMMAND_FINISH_DISCONNECTED:
|
|
case IEC104_COMMAND_FINISH_CONNECTION_CHANGED:
|
|
case IEC104_COMMAND_FINISH_SEND_ERROR:
|
|
case IEC104_COMMAND_FINISH_SERVICE_ERROR: ++self->status.cancelled; break;
|
|
default: break;
|
|
}
|
|
Reap(self);
|
|
}
|
|
static void Cancel_All(IEC104_Command_t *self, IEC104_CommandFinishReason_t reason)
|
|
{
|
|
CommandTransaction *task = &self->transaction;
|
|
task->confirm_serial = task->term_serial = task->reply_serial = 0U;
|
|
task->send_waiting = 0;
|
|
memset(self->replies, 0, sizeof(self->replies));
|
|
Finish(self, reason);
|
|
}
|
|
static IEC104_SlaveRequestState_t Check_Session(IEC104_Command_t *self)
|
|
{
|
|
IEC104_SlaveRequestState_t state = IEC104_Slave_Check_Request(self->slave, &self->session);
|
|
self->status.events_pending = state == IEC104_SLAVE_REQUEST_WAIT_EVENTS;
|
|
if (state == IEC104_SLAVE_REQUEST_ERROR) {
|
|
Cancel_All(self, IEC104_COMMAND_FINISH_SERVICE_ERROR);
|
|
self->status.active = 0;
|
|
} else if (state != IEC104_SLAVE_REQUEST_WAIT_EVENTS &&
|
|
(!self->status.active || state != IEC104_SLAVE_REQUEST_READY)) {
|
|
Cancel_All(self, IEC104_COMMAND_FINISH_CONNECTION_CHANGED);
|
|
self->status.active = 0;
|
|
state = IEC104_SLAVE_REQUEST_STALE;
|
|
}
|
|
return state;
|
|
}
|
|
static uint32_t Timer_Limit(const IEC104_Command_t *self)
|
|
{
|
|
const CommandTransaction *task = &self->transaction;
|
|
if (!task->occupied || self->in_action) { return 0U; }
|
|
switch (task->phase) {
|
|
case IEC104_COMMAND_PHASE_SELECT_WAIT:
|
|
case IEC104_COMMAND_PHASE_EXECUTE_WAIT: return self->config.decision_timeout_ms;
|
|
case IEC104_COMMAND_PHASE_SELECTED: return self->config.select_timeout_ms;
|
|
case IEC104_COMMAND_PHASE_EXECUTING:
|
|
return task->result == 0U ? self->config.execute_timeout_ms : 0U;
|
|
default: return 0U;
|
|
}
|
|
}
|
|
static uint32_t Remaining(const CommandTransaction *task, uint32_t limit, uint64_t now)
|
|
{
|
|
if (now < task->timer_start_ms || now - task->timer_start_ms >= limit) { return 0U; }
|
|
return limit - (uint32_t)(now - task->timer_start_ms);
|
|
}
|
|
static _Bool Clock_Reversed(const IEC104_Command_t *self, uint64_t now)
|
|
{
|
|
const CommandTransaction *task = &self->transaction;
|
|
return !self->in_action && task->occupied && now < task->timer_start_ms &&
|
|
(task->phase == IEC104_COMMAND_PHASE_SELECT_WAIT || task->phase == IEC104_COMMAND_PHASE_SELECTED ||
|
|
task->phase == IEC104_COMMAND_PHASE_EXECUTE_WAIT ||
|
|
(task->phase == IEC104_COMMAND_PHASE_EXECUTING && task->result == 0U));
|
|
}
|
|
static uint64_t Reply_Serial(IEC104_Command_t *self)
|
|
{
|
|
if (self->next_reply == 0xffffffffffffffffULL) {
|
|
Cancel_All(self, IEC104_COMMAND_FINISH_SERVICE_ERROR);
|
|
self->status.active = 0;
|
|
return 0U;
|
|
}
|
|
return ++self->next_reply;
|
|
}
|
|
static _Bool Set_Confirm(IEC104_Command_t *self, uint8_t cause, _Bool negative, _Bool try_send)
|
|
{
|
|
CommandTransaction *task = &self->transaction;
|
|
uint64_t serial = Reply_Serial(self);
|
|
if (serial == 0U) { return 0; }
|
|
task->confirm_serial = serial;
|
|
task->confirm_cot = cause;
|
|
task->confirm_negative = negative;
|
|
task->confirm_try = try_send;
|
|
task->confirm_submitted = 0;
|
|
task->send_waiting = 0;
|
|
return 1;
|
|
}
|
|
static void Expire(IEC104_Command_t *self, uint64_t now)
|
|
{
|
|
CommandTransaction *task = &self->transaction;
|
|
uint32_t limit = Timer_Limit(self);
|
|
_Bool reversed = Clock_Reversed(self, now);
|
|
if (!reversed && (limit == 0U || Remaining(task, limit, now) != 0U)) { return; }
|
|
if (reversed) { ++self->status.clock_errors; }
|
|
switch (task->phase) {
|
|
case IEC104_COMMAND_PHASE_SELECT_WAIT:
|
|
case IEC104_COMMAND_PHASE_EXECUTE_WAIT:
|
|
if (Set_Confirm(self, IEC60870_ASDU_COT_ACTIVATION_CON, 1, 0)) {
|
|
Finish(self, IEC104_COMMAND_FINISH_DECISION_TIMEOUT);
|
|
}
|
|
break;
|
|
case IEC104_COMMAND_PHASE_SELECTED:
|
|
task->confirm_serial = 0U;
|
|
Finish(self, IEC104_COMMAND_FINISH_SELECT_TIMEOUT);
|
|
break;
|
|
case IEC104_COMMAND_PHASE_EXECUTING:
|
|
Finish(self, IEC104_COMMAND_FINISH_EXECUTE_TIMEOUT);
|
|
break;
|
|
default: break;
|
|
}
|
|
}
|
|
static _Bool Defer_For_Stop(IEC104_Command_t *self, const IEC104_SlaveEventIdentity_t *identity,
|
|
IEC104_TcpSubmitResult_t submitted)
|
|
{
|
|
IEC104_TcpServerStatus_t status;
|
|
if (submitted != IEC104_TCP_SUBMIT_ERROR || identity->slave != self->slave ||
|
|
identity->instance_id != self->session.instance_id || identity->generation != self->session.generation ||
|
|
IEC104_Slave_Get_Status(self->slave, &status, ((void *)0)) != IEC104_TCP_OK ||
|
|
status.generation != identity->generation || !status.connected || !status.connection_status_valid ||
|
|
!status.asdu_queue_status_valid || status.connection.phase != IEC104_TCP_SESSION_ACTIVE ||
|
|
status.connection.fault != IEC104_TCP_FAULT_NONE || status.connection.data_transfer_started ||
|
|
status.pending_event_count == 0U) { return 0; }
|
|
self->status.events_pending = 1;
|
|
return 1;
|
|
}
|
|
enum { COMMAND_HEAD_NONE, COMMAND_HEAD_CONFIRM, COMMAND_HEAD_TERM, COMMAND_HEAD_REPLY, COMMAND_HEAD_SHORT };
|
|
static unsigned Reply_Head(const IEC104_Command_t *self, unsigned *slot)
|
|
{
|
|
const CommandTransaction *task = &self->transaction;
|
|
uint64_t first = 0U;
|
|
unsigned head = COMMAND_HEAD_NONE, i;
|
|
if (task->confirm_serial != 0U) { first = task->confirm_serial; head = COMMAND_HEAD_CONFIRM; }
|
|
if (task->term_serial != 0U && (first == 0U || task->term_serial < first)) {
|
|
first = task->term_serial; head = COMMAND_HEAD_TERM;
|
|
}
|
|
if (task->reply_serial != 0U && (first == 0U || task->reply_serial < first)) {
|
|
first = task->reply_serial; head = COMMAND_HEAD_REPLY;
|
|
}
|
|
for (i = 0U; i < 4U; ++i) {
|
|
if (self->replies[i].occupied && (first == 0U || self->replies[i].serial < first)) {
|
|
first = self->replies[i].serial; head = COMMAND_HEAD_SHORT; *slot = i;
|
|
}
|
|
}
|
|
return head;
|
|
}
|
|
static void Complete_If_Sent(IEC104_Command_t *self)
|
|
{
|
|
CommandTransaction *task = &self->transaction;
|
|
if (task->occupied && task->phase == IEC104_COMMAND_PHASE_EXECUTING && task->completed &&
|
|
task->confirm_submitted && task->confirm_serial == 0U && task->term_serial == 0U) {
|
|
Finish(self, task->result == IEC104_COMMAND_RESULT_SUCCEEDED ?
|
|
IEC104_COMMAND_FINISH_COMPLETED : IEC104_COMMAND_FINISH_EXECUTION_FAILED);
|
|
}
|
|
Reap(self);
|
|
}
|
|
static int Submit_Head(IEC104_Command_t *self)
|
|
{
|
|
CommandTransaction *task = &self->transaction;
|
|
const IEC104_SlaveEventIdentity_t *identity;
|
|
const uint8_t *source;
|
|
uint8_t bytes[10], cause;
|
|
IEC60870_Asdu_t asdu;
|
|
IEC104_TcpSubmitResult_t submitted;
|
|
IEC104_SlaveRequestState_t state = Check_Session(self);
|
|
unsigned slot = 0U, head;
|
|
_Bool negative, try_send;
|
|
if (state == IEC104_SLAVE_REQUEST_ERROR) { return -1; }
|
|
if (state != IEC104_SLAVE_REQUEST_READY) { return 0; }
|
|
head = Reply_Head(self, &slot);
|
|
if (head == COMMAND_HEAD_NONE) { return 0; }
|
|
identity = &task->identity;
|
|
source = task->request_bytes;
|
|
cause = IEC60870_ASDU_COT_ACTIVATION_TERMINATION;
|
|
negative = 0;
|
|
try_send = 1;
|
|
if (head == COMMAND_HEAD_CONFIRM) {
|
|
cause = task->confirm_cot; negative = task->confirm_negative; try_send = task->confirm_try;
|
|
} else if (head == COMMAND_HEAD_REPLY) {
|
|
source = task->reply_bytes; cause = task->reply_cot;
|
|
negative = cause != IEC60870_ASDU_COT_DEACTIVATION_CON; try_send = 0;
|
|
} else if (head == COMMAND_HEAD_SHORT) {
|
|
identity = &self->replies[slot].identity;
|
|
source = self->replies[slot].bytes; cause = self->replies[slot].cot;
|
|
negative = 1; try_send = 0;
|
|
}
|
|
memcpy(bytes, source, sizeof(bytes));
|
|
if (IEC60870_Asdu_Create_From_Buffer(&asdu, IEC104_Slave_Get_Application_Layer_Parameters(self->slave),
|
|
bytes, sizeof(bytes)) != IEC60870_ASDU_OK ||
|
|
IEC60870_Asdu_Set_COT(&asdu, cause) != IEC60870_ASDU_OK ||
|
|
IEC60870_Asdu_Set_Negative(&asdu, negative) != IEC60870_ASDU_OK) {
|
|
Cancel_All(self, IEC104_COMMAND_FINISH_SERVICE_ERROR);
|
|
return -1;
|
|
}
|
|
submitted = try_send ? IEC104_Slave_Try_Send_Response(self->slave, identity, &asdu) :
|
|
IEC104_Slave_Send_Response(self->slave, identity, &asdu);
|
|
if (submitted == IEC104_TCP_SUBMIT_OK) {
|
|
++self->status.submitted;
|
|
if (negative) { ++self->status.negative_submitted; }
|
|
if (head == COMMAND_HEAD_SHORT) { memset(&self->replies[slot], 0, sizeof(self->replies[slot])); }
|
|
else {
|
|
task->send_waiting = 0;
|
|
if (head == COMMAND_HEAD_CONFIRM) { task->confirm_serial = 0U; task->confirm_submitted = 1; }
|
|
else if (head == COMMAND_HEAD_TERM) { task->term_serial = 0U; task->term_submitted = 1; }
|
|
else { task->reply_serial = 0U; }
|
|
}
|
|
Complete_If_Sent(self);
|
|
return 1;
|
|
}
|
|
if (submitted == IEC104_TCP_SUBMIT_WAIT) {
|
|
if (head == COMMAND_HEAD_SHORT) { self->replies[slot].send_waiting = 1; }
|
|
else { task->send_waiting = 1; }
|
|
++self->status.waits;
|
|
return 0;
|
|
}
|
|
if (Defer_For_Stop(self, identity, submitted)) { return 0; }
|
|
Cancel_All(self, IEC104_COMMAND_FINISH_SEND_ERROR);
|
|
self->status.active = 0;
|
|
return 0;
|
|
}
|
|
static _Bool Short_Reply(IEC104_Command_t *self, const IEC104_SlaveEventIdentity_t *identity,
|
|
const uint8_t *data, uint8_t cause)
|
|
{
|
|
unsigned slot;
|
|
_Bool empty = Pending_Replies(self) == 0U;
|
|
uint64_t serial;
|
|
for (slot = 0U; slot < 4U; ++slot) {
|
|
if (!self->replies[slot].occupied) { break; }
|
|
}
|
|
if (slot == 4U) {
|
|
++self->status.overloads;
|
|
++self->status.dropped_requests;
|
|
return 1;
|
|
}
|
|
serial = Reply_Serial(self);
|
|
if (serial == 0U) { return 0; }
|
|
self->replies[slot].identity = *identity;
|
|
memcpy(self->replies[slot].bytes, data, sizeof(self->replies[slot].bytes));
|
|
self->replies[slot].bytes[1] = 1U;
|
|
self->replies[slot].serial = serial;
|
|
self->replies[slot].cot = cause;
|
|
self->replies[slot].occupied = 1;
|
|
self->replies[slot].send_waiting = 0;
|
|
return !empty || Submit_Head(self) >= 0;
|
|
}
|
|
static void Work_Event(IEC104_Command_t *self, const uint8_t *data, uint64_t receive_serial,
|
|
uint64_t now, _Bool selected)
|
|
{
|
|
CommandTransaction *task = &self->transaction;
|
|
memcpy(task->request_bytes, data, sizeof(task->request_bytes));
|
|
task->request_bytes[1] = 1U;
|
|
task->receive_serial = receive_serial;
|
|
task->accepted_ms = task->timer_start_ms = now;
|
|
task->event_type = (data[9] & 0x80U) != 0U ? IEC104_COMMAND_SELECT : IEC104_COMMAND_EXECUTE;
|
|
task->phase = task->event_type == IEC104_COMMAND_SELECT ?
|
|
IEC104_COMMAND_PHASE_SELECT_WAIT : IEC104_COMMAND_PHASE_EXECUTE_WAIT;
|
|
task->event_serial = ++self->next_event;
|
|
task->accepted_event_serial = 0U;
|
|
if (task->event_type == IEC104_COMMAND_SELECT) { task->select_event_serial = task->event_serial; }
|
|
else { task->execute_event_serial = task->event_serial; }
|
|
task->event_taken = 0;
|
|
task->selected = selected;
|
|
task->confirm_submitted = 0;
|
|
task->send_waiting = 0;
|
|
++self->status.accepted;
|
|
}
|
|
static _Bool End_With_Reply(IEC104_Command_t *self, const uint8_t *data, uint8_t cause,
|
|
IEC104_CommandFinishReason_t reason)
|
|
{
|
|
CommandTransaction *task = &self->transaction;
|
|
uint64_t serial = Reply_Serial(self);
|
|
if (serial == 0U) { return 0; }
|
|
task->confirm_serial = task->term_serial = 0U;
|
|
memcpy(task->reply_bytes, data, sizeof(task->reply_bytes));
|
|
task->reply_bytes[1] = 1U;
|
|
task->reply_cot = cause;
|
|
task->reply_serial = serial;
|
|
task->send_waiting = 0;
|
|
Finish(self, reason);
|
|
return Submit_Head(self) >= 0;
|
|
}
|
|
static IEC104_CommandEventResult_t Request(IEC104_Command_t *self, const IEC104_SlaveEvent_t *event,
|
|
const IEC104_SlaveEventIdentity_t *identity)
|
|
{
|
|
CommandTransaction *task = &self->transaction;
|
|
IEC60870_AsduInfo_t info;
|
|
IEC104_Station_t *station;
|
|
const uint8_t *data;
|
|
uint16_t length;
|
|
uint8_t cause = 0U, state;
|
|
uint32_t ioa;
|
|
uint64_t now;
|
|
_Bool same_point, is_select;
|
|
if (!self->status.active || event->asdu_result != IEC60870_ASDU_OK ||
|
|
IEC60870_Asdu_Get_Data(&event->asdu, &data, &length) != IEC60870_ASDU_OK || length == 0U ||
|
|
(data[0] != 45U && data[0] != 46U) ||
|
|
(self->config.type_mask & ((uint16_t)( ((data[0]) >= 45U && (data[0]) <= 51U) ? (1U << ((data[0]) - 45U)) : (((data[0]) >= 58U && (data[0]) <= 64U) ? (1U << ((data[0]) - 51U)) : 0U)))) == 0U ||
|
|
!IEC60870_Parse_ASDU_Header(event->asdu.parameters, data, length, &info)) {
|
|
return IEC104_COMMAND_EVENT_IGNORED;
|
|
}
|
|
now = IEC104_Net_Now_Ms();
|
|
Expire(self, now);
|
|
if (info.object_count != 1U || info.information_objects_len < 4U) {
|
|
++self->status.rejected;
|
|
return IEC104_COMMAND_EVENT_HANDLED;
|
|
}
|
|
ioa = Read_IOA(data);
|
|
station = IEC104_Slave_Get_Station(self->slave, info.common_address);
|
|
state = data[9] & 3U;
|
|
is_select = (data[9] & 0x80U) != 0U;
|
|
if (info.cause_of_transmission != IEC60870_ASDU_COT_ACTIVATION &&
|
|
info.cause_of_transmission != IEC60870_ASDU_COT_DEACTIVATION) {
|
|
cause = IEC60870_ASDU_COT_UNKNOWN_CAUSE;
|
|
} else if (station == ((void *)0)) { cause = IEC60870_ASDU_COT_UNKNOWN_COMMON_ADDRESS; }
|
|
else if (ioa == 0U) { cause = IEC60870_ASDU_COT_UNKNOWN_IOA; }
|
|
else if (info.is_sequence || length != 10U || info.is_negative_confirm || info.is_test ||
|
|
(data[0] == 45U ? (data[9] & 2U) != 0U : (state == 0U || state == 3U))) {
|
|
cause = info.cause_of_transmission == IEC60870_ASDU_COT_DEACTIVATION ?
|
|
IEC60870_ASDU_COT_DEACTIVATION_CON : IEC60870_ASDU_COT_ACTIVATION_CON;
|
|
}
|
|
if (cause != 0U) {
|
|
++self->status.rejected;
|
|
return Short_Reply(self, identity, data, cause) ? IEC104_COMMAND_EVENT_HANDLED : IEC104_COMMAND_EVENT_ERROR;
|
|
}
|
|
same_point = task->occupied && task->identity.generation == identity->generation &&
|
|
IEC104_Station_Get_Id(task->station) == IEC104_Station_Get_Id(station) &&
|
|
Read_IOA(task->request_bytes) == ioa;
|
|
if (info.cause_of_transmission == IEC60870_ASDU_COT_DEACTIVATION) {
|
|
if (same_point && task->request_bytes[0] == data[0] && task->request_bytes[3] == data[3] &&
|
|
(task->phase == IEC104_COMMAND_PHASE_SELECT_WAIT || task->phase == IEC104_COMMAND_PHASE_SELECTED ||
|
|
task->phase == IEC104_COMMAND_PHASE_EXECUTE_WAIT)) {
|
|
return End_With_Reply(self, data, IEC60870_ASDU_COT_DEACTIVATION_CON,
|
|
IEC104_COMMAND_FINISH_DEACTIVATED) ? IEC104_COMMAND_EVENT_HANDLED : IEC104_COMMAND_EVENT_ERROR;
|
|
}
|
|
++self->status.rejected;
|
|
return Short_Reply(self, identity, data, IEC60870_ASDU_COT_DEACTIVATION_CON) ?
|
|
IEC104_COMMAND_EVENT_HANDLED : IEC104_COMMAND_EVENT_ERROR;
|
|
}
|
|
if (same_point && !is_select && task->phase == IEC104_COMMAND_PHASE_SELECTED && task->confirm_submitted) {
|
|
if (task->request_bytes[0] != data[0] || task->request_bytes[3] != data[3] ||
|
|
(task->request_bytes[9] & 0x7FU) != (data[9] & 0x7FU)) {
|
|
++self->status.rejected;
|
|
return End_With_Reply(self, data, IEC60870_ASDU_COT_ACTIVATION_CON,
|
|
IEC104_COMMAND_FINISH_MISMATCH) ? IEC104_COMMAND_EVENT_HANDLED : IEC104_COMMAND_EVENT_ERROR;
|
|
}
|
|
Work_Event(self, data, event->transport.data.i_frame.receive_serial, now, 1);
|
|
return IEC104_COMMAND_EVENT_HANDLED;
|
|
}
|
|
if (task->occupied || (!is_select && (self->config.select_required_mask & ((uint16_t)( ((data[0]) >= 45U && (data[0]) <= 51U) ? (1U << ((data[0]) - 45U)) : (((data[0]) >= 58U && (data[0]) <= 64U) ? (1U << ((data[0]) - 51U)) : 0U)))) != 0U)) {
|
|
++self->status.rejected;
|
|
if (task->occupied) { ++self->status.busy_rejected; }
|
|
return Short_Reply(self, identity, data, IEC60870_ASDU_COT_ACTIVATION_CON) ?
|
|
IEC104_COMMAND_EVENT_HANDLED : IEC104_COMMAND_EVENT_ERROR;
|
|
}
|
|
if (self->next_transaction == 0xffffffffffffffffULL || self->next_event > 0xffffffffffffffffULL - 3U) {
|
|
++self->status.overloads;
|
|
++self->status.dropped_requests;
|
|
return IEC104_COMMAND_EVENT_HANDLED;
|
|
}
|
|
if (IEC104_Slave_Acquire_Station(self->slave, station) != IEC104_STATION_OK) { return IEC104_COMMAND_EVENT_ERROR; }
|
|
memset(task, 0, sizeof(*task));
|
|
task->occupied = 1;
|
|
task->identity = *identity;
|
|
task->station = station;
|
|
task->transaction_id = ++self->next_transaction;
|
|
Work_Event(self, data, event->transport.data.i_frame.receive_serial, now, 0);
|
|
return IEC104_COMMAND_EVENT_HANDLED;
|
|
}
|
|
void IEC104_Command_Config_Default(IEC104_CommandConfig_t *config)
|
|
{
|
|
if (config == ((void *)0)) { return; }
|
|
memset(config, 0, sizeof(*config));
|
|
config->type_mask = ((uint16_t)( ((45U) >= 45U && (45U) <= 51U) ? (1U << ((45U) - 45U)) : (((45U) >= 58U && (45U) <= 64U) ? (1U << ((45U) - 51U)) : 0U))) | ((uint16_t)( ((46U) >= 45U && (46U) <= 51U) ? (1U << ((46U) - 45U)) : (((46U) >= 58U && (46U) <= 64U) ? (1U << ((46U) - 51U)) : 0U)));
|
|
config->select_required_mask = config->type_mask;
|
|
config->select_timeout_ms = 30000U;
|
|
config->decision_timeout_ms = 15000U;
|
|
config->execute_timeout_ms = 60000U;
|
|
config->send_act_term = 1;
|
|
}
|
|
IEC104_Command_t *IEC104_Command_Create(IEC104_Slave_t *slave, const IEC104_CommandConfig_t *config)
|
|
{
|
|
const uint16_t supported = ((uint16_t)( ((45U) >= 45U && (45U) <= 51U) ? (1U << ((45U) - 45U)) : (((45U) >= 58U && (45U) <= 64U) ? (1U << ((45U) - 51U)) : 0U))) | ((uint16_t)( ((46U) >= 45U && (46U) <= 51U) ? (1U << ((46U) - 45U)) : (((46U) >= 58U && (46U) <= 64U) ? (1U << ((46U) - 51U)) : 0U)));
|
|
IEC104_Command_t *free_slot = ((void *)0);
|
|
unsigned i;
|
|
if (config == ((void *)0) || config->type_mask == 0U || (config->type_mask & (uint16_t)~supported) != 0U ||
|
|
(config->select_required_mask & (uint16_t)~config->type_mask) != 0U || config->select_timeout_ms == 0U ||
|
|
next_instance == 0xffffffffffffffffULL || IEC104_Slave_Get_Application_Layer_Parameters(slave) == ((void *)0)) { return ((void *)0); }
|
|
for (i = 0U; i < 1U; ++i) {
|
|
if (command_pool[i].in_use && command_pool[i].slave == slave) { return ((void *)0); }
|
|
if (!command_pool[i].in_use && free_slot == ((void *)0)) { free_slot = &command_pool[i]; }
|
|
}
|
|
if (free_slot == ((void *)0)) { return ((void *)0); }
|
|
memset(free_slot, 0, sizeof(*free_slot));
|
|
free_slot->slave = slave;
|
|
free_slot->config = *config;
|
|
free_slot->serial = ++next_instance;
|
|
free_slot->in_use = 1;
|
|
return free_slot;
|
|
}
|
|
_Bool IEC104_Command_Destroy(IEC104_Command_t *self)
|
|
{
|
|
if (!Owned(self) || self->in_action || self->transaction.occupied || Pending_Replies(self) != 0U) { return 0; }
|
|
memset(self, 0, sizeof(*self));
|
|
return 1;
|
|
}
|
|
void IEC104_Command_Cancel(IEC104_Command_t *self)
|
|
{
|
|
if (Owned(self) && !self->in_action) { Cancel_All(self, IEC104_COMMAND_FINISH_CANCELLED); }
|
|
}
|
|
IEC104_CommandEventResult_t IEC104_Command_Handle_Event(IEC104_Command_t *self,
|
|
const IEC104_SlaveEvent_t *event)
|
|
{
|
|
IEC104_SlaveEventIdentity_t identity;
|
|
if (!Owned(self) || self->in_action ||
|
|
!IEC104_Slave_Get_Event_Identity(self->slave, event, &identity) ||
|
|
(self->session.instance_id != 0U && self->session.instance_id != identity.instance_id)) {
|
|
return IEC104_COMMAND_EVENT_ERROR;
|
|
}
|
|
self->session.slave = identity.slave;
|
|
self->session.instance_id = identity.instance_id;
|
|
if (event->transport.type == IEC104_TCP_EVENT_CONNECTED) {
|
|
if (identity.generation <= self->last_generation) { return IEC104_COMMAND_EVENT_IGNORED; }
|
|
Cancel_All(self, IEC104_COMMAND_FINISH_CONNECTION_CHANGED);
|
|
self->session.generation = self->last_generation = identity.generation;
|
|
self->status.active = 0;
|
|
return IEC104_COMMAND_EVENT_HANDLED;
|
|
}
|
|
if (identity.generation != self->session.generation || identity.generation == 0U) {
|
|
return IEC104_COMMAND_EVENT_IGNORED;
|
|
}
|
|
switch (event->transport.type) {
|
|
case IEC104_TCP_EVENT_ACTIVATED:
|
|
self->status.active = 1;
|
|
return IEC104_COMMAND_EVENT_HANDLED;
|
|
case IEC104_TCP_EVENT_DEACTIVATED:
|
|
Cancel_All(self, IEC104_COMMAND_FINISH_STOPPED);
|
|
self->status.active = 0;
|
|
return IEC104_COMMAND_EVENT_HANDLED;
|
|
case IEC104_TCP_EVENT_DISCONNECTED:
|
|
Cancel_All(self, IEC104_COMMAND_FINISH_DISCONNECTED);
|
|
self->session.generation = 0U;
|
|
self->status.active = 0;
|
|
return IEC104_COMMAND_EVENT_HANDLED;
|
|
case IEC104_TCP_EVENT_I_FRAME: return Request(self, event, &identity);
|
|
default: return IEC104_COMMAND_EVENT_IGNORED;
|
|
}
|
|
}
|
|
_Bool IEC104_Command_Process(IEC104_Command_t *self)
|
|
{
|
|
unsigned step;
|
|
if (!Owned(self) || self->in_action) { return 0; }
|
|
for (step = 0U; step < 2U * (1U + 4U); ++step) {
|
|
IEC104_SlaveRequestState_t state = Check_Session(self);
|
|
int submitted;
|
|
if (state == IEC104_SLAVE_REQUEST_ERROR) { return 0; }
|
|
if (state != IEC104_SLAVE_REQUEST_READY) { return 1; }
|
|
Expire(self, IEC104_Net_Now_Ms());
|
|
Complete_If_Sent(self);
|
|
submitted = Submit_Head(self);
|
|
if (submitted <= 0) { return submitted == 0; }
|
|
}
|
|
return 1;
|
|
}
|
|
IEC104_CommandNextResult_t IEC104_Command_NextEvent(IEC104_Command_t *self, IEC104_CommandEvent_t *event)
|
|
{
|
|
CommandTransaction *task;
|
|
IEC104_CommandEvent_t result;
|
|
IEC104_SlaveRequestState_t state = IEC104_SLAVE_REQUEST_READY;
|
|
if (!Owned(self) || self->in_action || event == ((void *)0)) { return IEC104_COMMAND_NEXT_ERROR; }
|
|
task = &self->transaction;
|
|
if (!task->finish_pending) {
|
|
state = Check_Session(self);
|
|
if (state == IEC104_SLAVE_REQUEST_READY) { Expire(self, IEC104_Net_Now_Ms()); }
|
|
}
|
|
if (!task->finish_pending && state == IEC104_SLAVE_REQUEST_ERROR) { return IEC104_COMMAND_NEXT_ERROR; }
|
|
if (!task->occupied || (!task->finish_pending &&
|
|
(state != IEC104_SLAVE_REQUEST_READY || task->event_taken ||
|
|
(task->phase != IEC104_COMMAND_PHASE_SELECT_WAIT && task->phase != IEC104_COMMAND_PHASE_EXECUTE_WAIT)))) {
|
|
return IEC104_COMMAND_NEXT_EMPTY;
|
|
}
|
|
memset(&result, 0, sizeof(result));
|
|
result.type = (IEC104_CommandEventType_t)task->event_type;
|
|
result.instance_id = self->serial;
|
|
result.transaction_id = task->transaction_id;
|
|
result.event_serial = task->event_serial;
|
|
Copy_Request(task, &result.request);
|
|
if (task->finish_pending) {
|
|
result.reason = (IEC104_CommandFinishReason_t)task->finish_reason;
|
|
result.select_effect = task->select_effect;
|
|
result.execute_effect = task->execute_effect;
|
|
task->finish_pending = 0;
|
|
} else {
|
|
task->ever_work_delivered = 1;
|
|
if (result.type == IEC104_COMMAND_SELECT) { task->select_delivered = 1; }
|
|
else { task->execute_delivered = 1; }
|
|
}
|
|
task->event_taken = 1;
|
|
*event = result;
|
|
Reap(self);
|
|
return IEC104_COMMAND_NEXT_READY;
|
|
}
|
|
static _Bool Current_Event(const IEC104_Command_t *self, const IEC104_CommandEvent_t *event)
|
|
{
|
|
const CommandTransaction *task = &self->transaction;
|
|
return event != ((void *)0) && task->occupied && event->instance_id == self->serial &&
|
|
event->transaction_id == task->transaction_id && event->event_serial == task->event_serial &&
|
|
event->type == task->event_type && task->event_taken;
|
|
}
|
|
static _Bool Reply_Stage(const IEC104_Command_t *self, const IEC104_CommandEvent_t *event, _Bool work)
|
|
{
|
|
const CommandTransaction *task = &self->transaction;
|
|
if (!Current_Event(self, event)) { return 0; }
|
|
if (work) {
|
|
return task->accepted_event_serial == 0U &&
|
|
((event->type == IEC104_COMMAND_SELECT && task->phase == IEC104_COMMAND_PHASE_SELECT_WAIT) ||
|
|
(event->type == IEC104_COMMAND_EXECUTE && task->phase == IEC104_COMMAND_PHASE_EXECUTE_WAIT));
|
|
}
|
|
return event->type == IEC104_COMMAND_EXECUTE && task->phase == IEC104_COMMAND_PHASE_EXECUTING &&
|
|
task->accepted_event_serial == event->event_serial && task->execute_effect;
|
|
}
|
|
static IEC104_CommandReplyResult_t Check_Reply(IEC104_Command_t *self,
|
|
const IEC104_CommandEvent_t *event, _Bool work)
|
|
{
|
|
IEC104_SlaveRequestState_t state;
|
|
if (!Owned(self) || self->in_action || event == ((void *)0)) { return IEC104_COMMAND_REPLY_ERROR; }
|
|
if (!Reply_Stage(self, event, work)) { return IEC104_COMMAND_REPLY_STALE; }
|
|
state = Check_Session(self);
|
|
if (state == IEC104_SLAVE_REQUEST_ERROR) { return IEC104_COMMAND_REPLY_ERROR; }
|
|
if (state == IEC104_SLAVE_REQUEST_WAIT_EVENTS) { return IEC104_COMMAND_REPLY_WAIT; }
|
|
if (state != IEC104_SLAVE_REQUEST_READY) { return IEC104_COMMAND_REPLY_STALE; }
|
|
Expire(self, IEC104_Net_Now_Ms());
|
|
return Reply_Stage(self, event, work) ? IEC104_COMMAND_REPLY_OK : IEC104_COMMAND_REPLY_STALE;
|
|
}
|
|
IEC104_CommandReplyResult_t IEC104_Command_Accept(IEC104_Command_t *self,
|
|
const IEC104_CommandEvent_t *event, IEC104_CommandAction_t action, void *context)
|
|
{
|
|
CommandTransaction *task;
|
|
IEC104_CommandRequest_t request;
|
|
IEC104_CommandActionResult_t action_result;
|
|
IEC104_CommandReplyResult_t checked;
|
|
_Bool selecting;
|
|
if (event != ((void *)0) && event->type == IEC104_COMMAND_EXECUTE && action == ((void *)0)) {
|
|
return IEC104_COMMAND_REPLY_ERROR;
|
|
}
|
|
checked = Check_Reply(self, event, 1);
|
|
if (checked != IEC104_COMMAND_REPLY_OK) { return checked; }
|
|
task = &self->transaction;
|
|
selecting = task->event_type == IEC104_COMMAND_SELECT;
|
|
if (!Set_Confirm(self, IEC60870_ASDU_COT_ACTIVATION_CON, 0, !selecting)) {
|
|
return IEC104_COMMAND_REPLY_ERROR;
|
|
}
|
|
Copy_Request(task, &request);
|
|
task->accepted_event_serial = task->event_serial;
|
|
self->in_action = 1;
|
|
action_result = action == ((void *)0) ? IEC104_COMMAND_ACTION_STARTED : action(context, &request);
|
|
self->in_action = 0;
|
|
if (action_result != IEC104_COMMAND_ACTION_STARTED && action_result != IEC104_COMMAND_ACTION_NOT_STARTED) {
|
|
action_result = IEC104_COMMAND_ACTION_FAILED;
|
|
}
|
|
if (selecting) { task->select_effect = action != ((void *)0) && action_result != IEC104_COMMAND_ACTION_NOT_STARTED; }
|
|
else { task->execute_effect = action_result != IEC104_COMMAND_ACTION_NOT_STARTED; }
|
|
if (action_result == IEC104_COMMAND_ACTION_STARTED) {
|
|
task->phase = selecting ? IEC104_COMMAND_PHASE_SELECTED : IEC104_COMMAND_PHASE_EXECUTING;
|
|
task->timer_start_ms = IEC104_Net_Now_Ms();
|
|
if (selecting) { ++self->status.selected; }
|
|
else { ++self->status.executed; }
|
|
} else {
|
|
task->confirm_negative = 1;
|
|
task->confirm_try = !selecting && action_result == IEC104_COMMAND_ACTION_FAILED;
|
|
if (action_result == IEC104_COMMAND_ACTION_NOT_STARTED) {
|
|
++self->status.app_rejected;
|
|
Finish(self, IEC104_COMMAND_FINISH_REJECTED);
|
|
} else { Finish(self, IEC104_COMMAND_FINISH_ACTION_FAILED); }
|
|
}
|
|
(void)Submit_Head(self);
|
|
return IEC104_COMMAND_REPLY_OK;
|
|
}
|
|
IEC104_CommandReplyResult_t IEC104_Command_Reject(IEC104_Command_t *self,
|
|
const IEC104_CommandEvent_t *event, IEC104_CommandRejectCause_t cause)
|
|
{
|
|
IEC104_CommandReplyResult_t checked;
|
|
if (cause != IEC104_COMMAND_REJECT_NEGATIVE && cause != IEC104_COMMAND_REJECT_UNKNOWN_IOA) {
|
|
return IEC104_COMMAND_REPLY_ERROR;
|
|
}
|
|
checked = Check_Reply(self, event, 1);
|
|
if (checked != IEC104_COMMAND_REPLY_OK) { return checked; }
|
|
if (!Set_Confirm(self, cause == IEC104_COMMAND_REJECT_UNKNOWN_IOA ?
|
|
IEC60870_ASDU_COT_UNKNOWN_IOA : IEC60870_ASDU_COT_ACTIVATION_CON, 1, 0)) {
|
|
return IEC104_COMMAND_REPLY_ERROR;
|
|
}
|
|
self->transaction.accepted_event_serial = self->transaction.event_serial;
|
|
++self->status.app_rejected;
|
|
Finish(self, IEC104_COMMAND_FINISH_REJECTED);
|
|
(void)Submit_Head(self);
|
|
return IEC104_COMMAND_REPLY_OK;
|
|
}
|
|
IEC104_CommandReplyResult_t IEC104_Command_Report_Result(IEC104_Command_t *self,
|
|
const IEC104_CommandEvent_t *event, IEC104_CommandResult_t result)
|
|
{
|
|
IEC104_CommandReplyResult_t checked;
|
|
if (result != IEC104_COMMAND_RESULT_SUCCEEDED && result != IEC104_COMMAND_RESULT_FAILED) {
|
|
return IEC104_COMMAND_REPLY_ERROR;
|
|
}
|
|
checked = Check_Reply(self, event, 0);
|
|
if (checked != IEC104_COMMAND_REPLY_OK) { return checked; }
|
|
if (self->transaction.result != 0U || self->transaction.completed) { return IEC104_COMMAND_REPLY_ERROR; }
|
|
self->transaction.result = (uint8_t)result;
|
|
return IEC104_COMMAND_REPLY_OK;
|
|
}
|
|
IEC104_CommandReplyResult_t IEC104_Command_Submit_Return_Info(IEC104_Command_t *self,
|
|
const IEC104_CommandEvent_t *event, const IEC60870_Asdu_t *asdu)
|
|
{
|
|
CommandTransaction *task;
|
|
IEC60870_AsduInfo_t info;
|
|
const uint8_t *data;
|
|
uint16_t length;
|
|
IEC104_TcpSubmitResult_t submitted;
|
|
IEC104_CommandReplyResult_t checked = Check_Reply(self, event, 0);
|
|
if (checked != IEC104_COMMAND_REPLY_OK) { return checked; }
|
|
task = &self->transaction;
|
|
if (task->completed || asdu == ((void *)0) || !IEC60870_AppLayerParameters_Valid(asdu->parameters) ||
|
|
asdu->parameters->sizeOfCOT != 2 || asdu->parameters->sizeOfCA != 2 || asdu->parameters->sizeOfIOA != 3 ||
|
|
asdu->parameters->maxSizeOfASDU > 249 ||
|
|
IEC60870_Asdu_Get_Data(asdu, &data, &length) != IEC60870_ASDU_OK || length > 249 ||
|
|
IEC60870_Asdu_Parse(IEC104_Slave_Get_Application_Layer_Parameters(self->slave), data, length, &info) !=
|
|
IEC60870_ASDU_OK ||
|
|
!((info.type_id >= 1U && info.type_id <= 21U) || (info.type_id >= 30U && info.type_id <= 40U)) ||
|
|
info.object_count == 0U ||
|
|
(info.cause_of_transmission != IEC60870_ASDU_COT_RETURN_INFO_REMOTE &&
|
|
info.cause_of_transmission != IEC60870_ASDU_COT_SPONTANEOUS) ||
|
|
info.is_negative_confirm || info.is_test != ((task->request_bytes[2] >> 7) & 1U) ||
|
|
info.common_address != Read_CA(task->request_bytes)) { return IEC104_COMMAND_REPLY_ERROR; }
|
|
if (!task->confirm_submitted || Pending_Replies(self) != 0U) { return IEC104_COMMAND_REPLY_WAIT; }
|
|
submitted = IEC104_Slave_Try_Send_Response(self->slave, &task->identity, asdu);
|
|
if (submitted == IEC104_TCP_SUBMIT_WAIT) {
|
|
task->return_waiting = 1;
|
|
++self->status.waits;
|
|
return IEC104_COMMAND_REPLY_WAIT;
|
|
}
|
|
if (submitted == IEC104_TCP_SUBMIT_OK) {
|
|
task->return_waiting = 0;
|
|
++self->status.submitted;
|
|
++self->status.return_info_submitted;
|
|
return IEC104_COMMAND_REPLY_OK;
|
|
}
|
|
if (Defer_For_Stop(self, &task->identity, submitted)) { return IEC104_COMMAND_REPLY_WAIT; }
|
|
Cancel_All(self, IEC104_COMMAND_FINISH_SEND_ERROR);
|
|
self->status.active = 0;
|
|
return IEC104_COMMAND_REPLY_STALE;
|
|
}
|
|
IEC104_CommandReplyResult_t IEC104_Command_Complete(IEC104_Command_t *self,
|
|
const IEC104_CommandEvent_t *event)
|
|
{
|
|
CommandTransaction *task;
|
|
IEC104_CommandReplyResult_t checked = Check_Reply(self, event, 0);
|
|
if (checked != IEC104_COMMAND_REPLY_OK) { return checked; }
|
|
task = &self->transaction;
|
|
if (task->result == 0U || task->completed) { return IEC104_COMMAND_REPLY_ERROR; }
|
|
if (self->config.send_act_term &&
|
|
(task->result == IEC104_COMMAND_RESULT_SUCCEEDED || self->config.act_term_on_failure)) {
|
|
uint64_t serial = Reply_Serial(self);
|
|
if (serial == 0U) { return IEC104_COMMAND_REPLY_ERROR; }
|
|
task->term_serial = serial;
|
|
}
|
|
task->completed = 1;
|
|
task->return_waiting = 0;
|
|
Complete_If_Sent(self);
|
|
return IEC104_COMMAND_REPLY_OK;
|
|
}
|
|
_Bool IEC104_Command_Get_Transaction(const IEC104_Command_t *self,
|
|
const IEC104_CommandEvent_t *event, IEC104_CommandTransactionInfo_t *info)
|
|
{
|
|
const CommandTransaction *task;
|
|
IEC104_CommandTransactionInfo_t result;
|
|
_Bool delivered;
|
|
if (!Owned(self) || event == ((void *)0) || info == ((void *)0)) { return 0; }
|
|
task = &self->transaction;
|
|
if (!task->occupied || event->instance_id != self->serial || event->transaction_id != task->transaction_id) {
|
|
return 0;
|
|
}
|
|
delivered = (event->type == IEC104_COMMAND_SELECT && task->select_delivered &&
|
|
event->event_serial == task->select_event_serial) ||
|
|
(event->type == IEC104_COMMAND_EXECUTE && task->execute_delivered &&
|
|
event->event_serial == task->execute_event_serial) ||
|
|
(event->type == IEC104_COMMAND_FINISHED && task->event_type == IEC104_COMMAND_FINISHED &&
|
|
task->event_taken && event->event_serial == task->event_serial);
|
|
if (!delivered) { return 0; }
|
|
memset(&result, 0, sizeof(result));
|
|
result.active = task->phase != IEC104_COMMAND_PHASE_ENDED;
|
|
result.phase = (IEC104_CommandPhase_t)task->phase;
|
|
result.confirm_submitted = task->confirm_submitted;
|
|
result.result_reported = task->result != 0U;
|
|
result.completed = task->completed;
|
|
result.term_submitted = task->term_submitted;
|
|
*info = result;
|
|
return 1;
|
|
}
|
|
_Bool IEC104_Command_Get_Status(const IEC104_Command_t *self, IEC104_CommandStatus_t *status)
|
|
{
|
|
const CommandTransaction *task;
|
|
IEC104_CommandStatus_t result;
|
|
IEC104_SlaveRequestState_t state;
|
|
uint32_t limit;
|
|
uint64_t now;
|
|
unsigned slot = 0U, head;
|
|
_Bool waiting;
|
|
if (!Owned(self) || status == ((void *)0)) { return 0; }
|
|
state = IEC104_Slave_Check_Request(self->slave, &self->session);
|
|
if (state == IEC104_SLAVE_REQUEST_ERROR) { return 0; }
|
|
task = &self->transaction;
|
|
result = self->status;
|
|
result.generation = self->session.generation;
|
|
result.events_pending = state == IEC104_SLAVE_REQUEST_WAIT_EVENTS;
|
|
result.busy = task->occupied;
|
|
result.pending_replies = Pending_Replies(self);
|
|
result.pending_events = task->occupied && (task->finish_pending ||
|
|
(!task->event_taken && (task->phase == IEC104_COMMAND_PHASE_SELECT_WAIT ||
|
|
task->phase == IEC104_COMMAND_PHASE_EXECUTE_WAIT))) ? 1U : 0U;
|
|
limit = Timer_Limit(self);
|
|
now = IEC104_Net_Now_Ms();
|
|
result.timer_active = limit != 0U;
|
|
result.timeout_remaining_ms = limit != 0U ? Remaining(task, limit, now) : 0U;
|
|
result.need_process = 0;
|
|
head = Reply_Head(self, &slot);
|
|
waiting = head == COMMAND_HEAD_SHORT ? self->replies[slot].send_waiting : task->send_waiting;
|
|
if (!self->in_action && !result.events_pending) {
|
|
if (state != IEC104_SLAVE_REQUEST_READY || !result.active) {
|
|
result.need_process = result.pending_replies != 0U ||
|
|
(task->occupied && task->phase != IEC104_COMMAND_PHASE_ENDED);
|
|
} else {
|
|
result.need_process = Clock_Reversed(self, now) ||
|
|
(result.timer_active && result.timeout_remaining_ms == 0U) ||
|
|
(head != COMMAND_HEAD_NONE && !waiting);
|
|
}
|
|
}
|
|
*status = result;
|
|
return 1;
|
|
}
|