126 lines
6.0 KiB
C
126 lines
6.0 KiB
C
/* 公共ASDU与104传输的集成回归:独立测试中的字节向量仍用于期望值。
|
|
* 公共套件单独构建时不链接104实现;本文件专门检查I帧接入边界。 */
|
|
#define main common_asdu_suite_main
|
|
#include "iec60870_asdu_test.c"
|
|
#undef main
|
|
#include "IEC104_Codec.h"
|
|
|
|
/**
|
|
* 功能:验证公共对象构造的ASDU可按标准104布局封装并交付给公共解析器。
|
|
* 输入参数:无。
|
|
* 输出参数:无。
|
|
* 返回值:全部检查成功返回1,断言失败返回0。
|
|
* 说明:复用30种类型的独立载荷向量,覆盖42种类型/SQ组合及真实I帧序号。
|
|
*/
|
|
static int test_common_asdu_in_iframe(void)
|
|
{
|
|
const IEC60870_AppLayerParameters_t parameters = IEC104_APP_LAYER_PARAMETERS_DEFAULT;
|
|
static const uint8_t addresses[2][3] = {{0x56, 0x34, 0x12}, {0x57, 0x34, 0x12}};
|
|
size_t v;
|
|
unsigned int layouts = 0;
|
|
CHECK(parameters.sizeOfTypeId == 1 && parameters.sizeOfVSQ == 1);
|
|
CHECK(parameters.sizeOfCOT == 2 && parameters.sizeOfCA == 2 && parameters.sizeOfIOA == 3);
|
|
CHECK(parameters.originatorAddress == 0 && parameters.maxSizeOfASDU == 249);
|
|
for (v = 0; v < COUNT(vectors); ++v) {
|
|
const Vector *vector = &vectors[v];
|
|
int sq;
|
|
for (sq = 0; sq <= (vector->command ? 0 : 1); ++sq) {
|
|
uint8_t frame[64], expected[64], apdu[IEC104_MAX_APDU_LEN];
|
|
IEC60870_AsduHeader_t header = Header();
|
|
IEC60870_Asdu_t asdu;
|
|
IEC60870_AsduInfo_t info;
|
|
IEC104_ApciInfo_t apci;
|
|
TestObject input, output;
|
|
const uint8_t *data = NULL;
|
|
uint16_t length = 0, n;
|
|
int i, count = vector->command ? 1 : 2;
|
|
header.cause_of_transmission = vector->command ? 6 : 3;
|
|
header.is_negative_confirm = vector->command;
|
|
n = Wire_Header(¶meters, vector->type, (uint8_t)(count | (sq << 7)),
|
|
vector->command ? 0xC6 : 0x83, expected);
|
|
CHECK(IEC60870_Asdu_Create(&asdu, ¶meters, frame, sizeof(frame), &header, sq) == IEC60870_ASDU_OK);
|
|
for (i = 0; i < count; ++i) {
|
|
CHECK(Sample_Object(vector->type, 0x123456U + (uint32_t)i, &input) == IEC60870_ASDU_OK);
|
|
CHECK(IEC60870_Asdu_Add_InformationObject(&asdu, Object_Base(&input, vector->type)) == IEC60870_ASDU_OK);
|
|
if (!sq || i == 0) {
|
|
memcpy(expected + n, addresses[i], 3);
|
|
n += 3;
|
|
}
|
|
memcpy(expected + n, vector->payload, vector->size);
|
|
n += vector->size;
|
|
}
|
|
CHECK(IEC60870_Asdu_Get_Data(&asdu, &data, &length) == IEC60870_ASDU_OK);
|
|
CHECK(length == n && memcmp(data, expected, n) == 0);
|
|
CHECK(IEC104_Build_Iframe(apdu, 0x1234, 0x2345, data, length) == length + IEC104_APCI_LEN);
|
|
CHECK(apdu[0] == 0x68 && apdu[1] == length + 4);
|
|
CHECK(apdu[2] == 0x68 && apdu[3] == 0x24 && apdu[4] == 0x8A && apdu[5] == 0x46);
|
|
CHECK(IEC104_Parse_APCI(apdu, (uint16_t)(length + IEC104_APCI_LEN), &apci));
|
|
CHECK(apci.frame_type == IEC104_FRAME_TYPE_I && apci.send_number == 0x1234 && apci.receive_number == 0x2345);
|
|
CHECK(apci.asdu_len == length && memcmp(apci.asdu, expected, n) == 0);
|
|
CHECK(IEC60870_Asdu_Parse(¶meters, apci.asdu, apci.asdu_len, &info) == IEC60870_ASDU_OK);
|
|
for (i = 0; i < count; ++i) {
|
|
CHECK(IEC60870_Asdu_Get_Element(&info, (uint8_t)i, &output, Object_Size(vector->type)) == IEC60870_ASDU_OK);
|
|
CHECK(Object_Base(&output, vector->type)->ioa == 0x123456U + (uint32_t)i);
|
|
CHECK(Check_Object(vector, &output));
|
|
}
|
|
++layouts;
|
|
}
|
|
}
|
|
CHECK(layouts == 42);
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
* 功能:验证公共ASDU容量与104帧容量分别生效。
|
|
* 输入参数:无。
|
|
* 输出参数:无。
|
|
* 返回值:全部检查成功返回1,断言失败返回0。
|
|
* 说明:公共层可构造254字节,104仍只接受至249字节;拒绝时输出保持不变。
|
|
*/
|
|
static int test_transport_length_boundary(void)
|
|
{
|
|
IEC60870_AppLayerParameters_t parameters = IEC104_APP_LAYER_PARAMETERS_DEFAULT;
|
|
IEC60870_AsduHeader_t header = Header();
|
|
IEC60870_Asdu_t asdu;
|
|
IEC60870_AsduInfo_t info;
|
|
IEC60870_MeasuredValueNormalized_t value;
|
|
IEC104_ApciInfo_t apci;
|
|
uint8_t frame[IEC60870_MAX_ASDU_LEN], apdu[260], before[260];
|
|
unsigned int i;
|
|
CHECK(IEC60870_MeasuredValueNormalized_Create(&value, 0, -1, 0) == IEC60870_ASDU_OK);
|
|
CHECK(IEC60870_Asdu_Create(&asdu, ¶meters, frame, sizeof(frame), &header, 1) == IEC60870_ASDU_OK);
|
|
for (i = 0; i < 80; ++i) {
|
|
value.object.ioa = i;
|
|
CHECK(IEC60870_Asdu_Add_InformationObject(&asdu, &value.object) == IEC60870_ASDU_OK);
|
|
}
|
|
CHECK(asdu.length == 249);
|
|
CHECK(IEC104_Build_Iframe(apdu, 0, 0, frame, asdu.length) == 255);
|
|
CHECK(IEC104_Parse_APCI(apdu, 255, &apci));
|
|
CHECK(apci.asdu_len == 249 && memcmp(apci.asdu, frame, 249) == 0);
|
|
|
|
parameters.sizeOfCOT = 1; parameters.sizeOfCA = 1;
|
|
parameters.sizeOfIOA = 2; parameters.maxSizeOfASDU = 254;
|
|
header.common_address = 0x67;
|
|
CHECK(IEC60870_Asdu_Create(&asdu, ¶meters, frame, sizeof(frame), &header, 0) == IEC60870_ASDU_OK);
|
|
for (i = 0; i < 50; ++i) {
|
|
value.object.ioa = i;
|
|
CHECK(IEC60870_Asdu_Add_InformationObject(&asdu, &value.object) == IEC60870_ASDU_OK);
|
|
}
|
|
CHECK(asdu.length == 254);
|
|
CHECK(IEC60870_Asdu_Parse(¶meters, frame, asdu.length, &info) == IEC60870_ASDU_OK);
|
|
memset(apdu, 0xA5, sizeof(apdu));
|
|
memcpy(before, apdu, sizeof(before));
|
|
CHECK(IEC104_Build_Iframe(apdu, 0, 0, frame, 250) == -1);
|
|
CHECK(memcmp(before, apdu, sizeof(apdu)) == 0);
|
|
CHECK(IEC104_Build_Iframe(apdu, 0, 0, frame, 254) == -1);
|
|
CHECK(memcmp(before, apdu, sizeof(apdu)) == 0);
|
|
return 1;
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
if (!test_common_asdu_in_iframe() || !test_transport_length_boundary()) { return 1; }
|
|
puts("104 ASDU transport: 2 groups passed (42 layouts, 249/254-byte boundary)");
|
|
return 0;
|
|
}
|