Files
STM32F4-Base/IEC60870-Slave/test/iec104_interrogation_rules_test.c
T
STF 7596f3371a
CI / L0 静态门禁 (pre-commit) (push) Failing after 44s
CI / L0.5 主机侧单测 (MSVC) (push) Failing after 42s
补充总召唤的广播地址,电度召唤+时钟同步业务的实现
2026-10-29 03:20:19 -07:00

88 lines
4.2 KiB
C

/* 召唤种类规则单测:直接调用无状态规则,验证限定词解析、数据COT和允许的数据类型。
* 使用独立请求字节,不经过网络,也不执行应用的冻结或复位动作。 */
#include "../104/business/IEC104_Interrogation_Internal.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define CHECK(x) do { if (!(x)) { fprintf(stderr, "%s:%d: %s\n", __FILE__, __LINE__, #x); exit(1); } } while (0)
/* QCC同时包含RQT和FRZ;用非零IOA确认解析保留原值,业务合法性由后续校验决定。 */
static void test_decode(void)
{
static const uint8_t qcc[] = {0x05, 0x45, 0x85, 0xc5, 0x01, 0x3f};
IEC60870_AppLayerParameters_t parameters = {1, 1, 2, 0, 2, 3, 249};
unsigned i;
for (i = 0; i < sizeof(qcc); ++i) {
uint8_t bytes[] = {101, 1, 6, 0x5a, 1, 0, 0x34, 0x12, 0, 0};
IEC60870_AsduInfo_t info;
uint32_t ioa = 0;
uint8_t qualifier = 0, freeze = 0;
bytes[9] = qcc[i];
CHECK(IEC60870_Asdu_Parse(&parameters, bytes, sizeof(bytes), &info) == IEC60870_ASDU_OK);
CHECK(IEC104_COUNTER_INTERROGATION_RULES.decode(&info, &ioa, &qualifier, &freeze));
CHECK(ioa == 0x1234 && qualifier == (qcc[i] & 0x3f) && freeze == (qcc[i] >> 6));
}
{
uint8_t bytes[] = {100, 1, 6, 0, 1, 0, 0, 0, 0, 36};
IEC60870_AsduInfo_t info;
uint32_t ioa = 1;
uint8_t qualifier = 0, freeze = 3;
CHECK(IEC60870_Asdu_Parse(&parameters, bytes, sizeof(bytes), &info) == IEC60870_ASDU_OK);
CHECK(IEC104_GENERAL_INTERROGATION_RULES.decode(&info, &ioa, &qualifier, &freeze));
CHECK(ioa == 0 && qualifier == 36 && freeze == 0);
}
}
/* 遍历完整字节范围验证限定词边界,并检查总请求及四个分组的数据COT映射。 */
static void test_qualifiers(void)
{
unsigned q;
CHECK(IEC104_GENERAL_INTERROGATION_RULES.type_id == 100);
CHECK(IEC104_GENERAL_INTERROGATION_RULES.has_deactivation);
CHECK(IEC104_COUNTER_INTERROGATION_RULES.type_id == 101);
CHECK(!IEC104_COUNTER_INTERROGATION_RULES.has_deactivation);
for (q = 0; q < 256; ++q) {
CHECK(IEC104_GENERAL_INTERROGATION_RULES.qualifier_valid((uint8_t)q) == (q >= 20 && q <= 36));
CHECK(IEC104_COUNTER_INTERROGATION_RULES.qualifier_valid((uint8_t)q) == (q >= 1 && q <= 5));
}
for (q = 20; q <= 36; ++q) { CHECK(IEC104_GENERAL_INTERROGATION_RULES.data_cause((uint8_t)q) == q); }
CHECK(IEC104_COUNTER_INTERROGATION_RULES.data_cause(1) == 38);
CHECK(IEC104_COUNTER_INTERROGATION_RULES.data_cause(2) == 39);
CHECK(IEC104_COUNTER_INTERROGATION_RULES.data_cause(3) == 40);
CHECK(IEC104_COUNTER_INTERROGATION_RULES.data_cause(4) == 41);
CHECK(IEC104_COUNTER_INTERROGATION_RULES.data_cause(5) == 37);
}
/* 交叉验证Type/SQ/FRZ:计数量只在读取时允许Type15或非连续寻址的Type37。
* 总召保持原九种监视类型,不能因共用引擎而接受累计量或命令类型。 */
static void test_types(void)
{
static const uint8_t types[] = {1, 3, 5, 7, 9, 11, 13, 15, 16, 20, 21, 37, 100, 101};
unsigned i, sq, freeze;
for (i = 0; i < sizeof(types); ++i) {
for (sq = 0; sq < 2; ++sq) {
for (freeze = 0; freeze < 4; ++freeze) {
IEC60870_AsduInfo_t info;
bool expected = freeze == 0 && (types[i] == 15 || (types[i] == 37 && sq == 0));
memset(&info, 0, sizeof(info)); info.type_id = types[i]; info.is_sequence = (uint8_t)sq;
CHECK(IEC104_COUNTER_INTERROGATION_RULES.data_allowed(&info, (uint8_t)freeze) == expected);
if (freeze == 0) {
bool general = types[i] == 1 || types[i] == 3 || types[i] == 5 || types[i] == 7 ||
types[i] == 9 || types[i] == 11 || types[i] == 13 || types[i] == 20 || types[i] == 21;
CHECK(IEC104_GENERAL_INTERROGATION_RULES.data_allowed(&info, 0) == general);
}
}
}
}
}
int main(void)
{
test_decode(); test_qualifiers(); test_types();
printf("interrogation rules: 3 groups passed; request=%zu event=%zu station=%zu\n",
sizeof(IEC104_InterrogationRequest_t), sizeof(IEC104_InterrogationEvent_t),
sizeof(IEC104_InterrogationStationState_t));
return 0;
}