Files
STM32F4-Base/IEC60870-Slave/.build/command-comments/command-before.i
T
STF cd42b4d61d
CI / L0 静态门禁 (pre-commit) (push) Failing after 2m51s
CI / L0.5 主机侧单测 (MSVC) (push) Successful in 18s
添加遥控业务代码
2026-10-30 20:03:19 -07:00

2426 lines
120 KiB
OpenEdge ABL

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