59 lines
3.1 KiB
C
59 lines
3.1 KiB
C
/*
|
||
* 104计数量种类规则:解析C_CI_NA_1的QCC,限定RQT和读取数据类型,选择完成方式。
|
||
* 规则函数不保存状态、不访问网络;计数器存储及冻结/复位由应用提供。
|
||
* 创建和动作入口只委托共用引擎,避免另建一套任务、广播、期限及取消流程。
|
||
*/
|
||
#include "IEC104_CounterInterrogation.h"
|
||
#include "IEC104_Interrogation_Internal.h"
|
||
|
||
/* 从首对象取IOA和QCC;对象层已将低6位RQT与高2位FRZ拆开。
|
||
* 这里只解析,不校验是否支持该分组;失败时不写调用方的输出。 */
|
||
static bool Counter_Decode(const IEC60870_AsduInfo_t *info, uint32_t *ioa, uint8_t *qualifier, uint8_t *freeze)
|
||
{
|
||
IEC60870_CounterInterrogationCommand_t command;
|
||
if (IEC60870_Asdu_Get_Element(info, 0U, &command, sizeof(command)) != IEC60870_ASDU_OK) { return false; }
|
||
*ioa = command.object.ioa;
|
||
*qualifier = command.qualifier;
|
||
*freeze = command.freeze;
|
||
return true;
|
||
}
|
||
|
||
/* RQT=1..4为分组,5为总请求;0未用、6..63保留。具体分组是否配置由应用在BEGIN决定。 */
|
||
static bool Counter_Qualifier_Valid(uint8_t qualifier) { return qualifier >= 1U && qualifier <= 5U; }
|
||
/* 引擎准入后使用:总请求的数据COT为37,第1..4组依次为38..41。 */
|
||
static uint8_t Counter_Data_Cause(uint8_t qualifier)
|
||
{
|
||
return (uint8_t)(qualifier == 5U ? IEC60870_ASDU_COT_COUNTER_INTERROGATION :
|
||
IEC60870_ASDU_COT_COUNTER_INTERROGATION + qualifier);
|
||
}
|
||
/* 只有读取存在数据阶段;冻结/复位在肯定确认提交后直接完成。 */
|
||
static bool Counter_Has_Data(uint8_t freeze) { return freeze == 0U; }
|
||
/* 读取接受无时标Type15和CP56时标Type37;Type37仅SQ=0,Type16不用于104。
|
||
* 报文完整布局、对象数和头部一致性仍由共用引擎及ASDU层检查。 */
|
||
static bool Counter_Data_Allowed(const IEC60870_AsduInfo_t *info, uint8_t freeze)
|
||
{
|
||
return freeze == 0U && (info->type_id == IEC60870_ASDU_M_IT_NA_1 ||
|
||
(info->type_id == IEC60870_ASDU_M_IT_TB_1 && info->is_sequence == 0U));
|
||
}
|
||
|
||
/* 只读规则存活至进程结束;has_deactivation=false使COT=8按未知传送原因处理。 */
|
||
const IEC104_InterrogationRules_t IEC104_COUNTER_INTERROGATION_RULES = {
|
||
IEC60870_ASDU_C_CI_NA_1, false, Counter_Decode, Counter_Qualifier_Valid,
|
||
Counter_Data_Cause, Counter_Data_Allowed, Counter_Has_Data
|
||
};
|
||
|
||
/* 用计数量规则创建独立实例;配置、站点引用、重复实例和状态区重叠统一由引擎校验。 */
|
||
IEC104_Interrogation_t *IEC104_CounterInterrogation_Create(IEC104_Slave_t *slave,
|
||
const IEC104_InterrogationConfig_t *config)
|
||
{
|
||
return IEC104_Interrogation_Create_With_Rules(slave, config, &IEC104_COUNTER_INTERROGATION_RULES);
|
||
}
|
||
|
||
/* 传入本种类规则作为身份约束,防止误把总召句柄交给动作入口。 */
|
||
IEC104_InterrogationReplyResult_t IEC104_CounterInterrogation_Execute_Begin(
|
||
IEC104_Interrogation_t *self, const IEC104_InterrogationEvent_t *event,
|
||
IEC104_CounterInterrogationAction_t action, void *context)
|
||
{
|
||
return IEC104_Interrogation_Execute_Action(self, event, &IEC104_COUNTER_INTERROGATION_RULES, action, context);
|
||
}
|