#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; }