添加遥控业务代码
This commit is contained in:
@@ -176,34 +176,36 @@ static void check_gi(unsigned extra_reply, uint8_t oa)
|
||||
static const int16_t measures[] = {2300, 2310, 2290, 5000, -125, 0, 1234, 42};
|
||||
const uint8_t *frames[32];
|
||||
size_t lengths[32];
|
||||
unsigned f, p, indexes[6], gi_count = 0U;
|
||||
unsigned f, p, indexes[8], gi_count = 0U;
|
||||
unsigned total = collect_asdus(frames, lengths);
|
||||
CHECK(total == 6 + extra_reply);
|
||||
CHECK(total == 8 + extra_reply);
|
||||
for (f = 0U; f < total; ++f) {
|
||||
if (frames[f][3] == oa && (frames[f][2] & 0x40U) == 0U) {
|
||||
CHECK(gi_count < 6U);
|
||||
CHECK(gi_count < 8U);
|
||||
indexes[gi_count++] = f;
|
||||
}
|
||||
}
|
||||
CHECK(gi_count == 6U); /* 其他请求的否定应答可穿插,但本次总召内容及自身顺序不变。 */
|
||||
for (f = 0; f < 6; ++f) {
|
||||
CHECK(gi_count == 8U); /* 其他请求的否定应答可穿插,但本次总召内容及自身顺序不变。 */
|
||||
for (f = 0; f < 8; ++f) {
|
||||
const uint8_t *a = frames[indexes[f]];
|
||||
CHECK(a[3] == oa && a[4] == 1 && a[5] == 0);
|
||||
if (f == 0 || f == 5) {
|
||||
if (f == 0 || f == 7) {
|
||||
CHECK(lengths[indexes[f]] == 10 && a[0] == 100 && a[1] == 1);
|
||||
CHECK(a[2] == (f == 0 ? 0x87 : 0x8a));
|
||||
CHECK(a[6] == 0 && a[7] == 0 && a[8] == 0 && a[9] == 20);
|
||||
} else {
|
||||
unsigned is_signal = f < 3;
|
||||
unsigned is_signal = f < 5;
|
||||
unsigned is_single = f < 3;
|
||||
size_t width = is_signal ? 4U : 6U;
|
||||
unsigned first = (is_signal ? f - 1U : f - 3U) * 4U;
|
||||
CHECK(a[0] == (is_signal ? 1 : 11) && a[1] == 4 && a[2] == 0x94);
|
||||
unsigned first = (is_single ? f - 1U : is_signal ? f - 3U : f - 5U) * 4U;
|
||||
CHECK(a[0] == (is_single ? 1 : is_signal ? 3 : 11) && a[1] == 4 && a[2] == 0x94);
|
||||
CHECK(lengths[indexes[f]] == 6 + width * 4);
|
||||
for (p = 0; p < 4; ++p) {
|
||||
const uint8_t *object = a + 6 + width * p;
|
||||
unsigned ioa = object[0] | (unsigned)object[1] << 8 | (unsigned)object[2] << 16;
|
||||
CHECK(ioa == (is_signal ? 1001U : 2001U) + first + p);
|
||||
if (is_signal) { CHECK(object[3] == values[first + p]); }
|
||||
CHECK(ioa == (is_single ? 1001U : is_signal ? 1101U : 2001U) + first + p);
|
||||
if (is_single) { CHECK(object[3] == values[first + p]); }
|
||||
else if (is_signal) { CHECK(object[3] == 1U); }
|
||||
else {
|
||||
CHECK((int16_t)(object[3] | (uint16_t)object[4] << 8) == measures[first + p]);
|
||||
CHECK(object[5] == 0);
|
||||
@@ -262,7 +264,7 @@ static void test_wait_each_phase(void)
|
||||
{
|
||||
static const struct { IEC104_InterrogationPhase_t phase; size_t batch; } phases[] = {
|
||||
{IEC104_INTERROGATION_CONFIRM, 0}, {IEC104_INTERROGATION_DATA, 0},
|
||||
{IEC104_INTERROGATION_DATA, 2}, {IEC104_INTERROGATION_TERMINATE, 4}
|
||||
{IEC104_INTERROGATION_DATA, 2}, {IEC104_INTERROGATION_DATA, 4}, {IEC104_INTERROGATION_TERMINATE, 6}
|
||||
};
|
||||
unsigned i;
|
||||
for (i = 0; i < sizeof(phases) / sizeof(phases[0]); ++i) {
|
||||
@@ -337,7 +339,7 @@ static void test_busy(void)
|
||||
CHECK(app.gi.pending_requests == 1 && app.gi.negative_submitted == 1);
|
||||
app_finish();
|
||||
check_gi(1, 0x5a);
|
||||
CHECK(collect_asdus(out, lengths) == 7);
|
||||
CHECK(collect_asdus(out, lengths) == 9);
|
||||
CHECK(lengths[0] == 10 && out[0][2] == 0xc7 && out[0][3] == 0x6b);
|
||||
app_close();
|
||||
}
|
||||
@@ -2083,15 +2085,22 @@ static void test_example_groups(void)
|
||||
memcpy(request, gi_request, sizeof(request)); request[9] = groups[i];
|
||||
app_request(request, sizeof(request)); app_finish();
|
||||
count = collect_asdus(frames, lengths);
|
||||
CHECK(count == (groups[i] <= 22 ? 4U : 1U));
|
||||
CHECK(count == (groups[i] == 21 ? 6U : groups[i] == 22 ? 4U : 1U));
|
||||
if (count == 1) { CHECK(frames[0][2] == 0xc7 && app.gi.gi_submitted == 0); }
|
||||
else {
|
||||
CHECK(frames[0][2] == 0x87 && frames[3][2] == 0x8a);
|
||||
for (f = 1; f <= 2; ++f) {
|
||||
CHECK(frames[0][2] == 0x87 && frames[count - 1U][2] == 0x8a);
|
||||
for (f = 1; f < count - 1U; ++f) {
|
||||
const uint8_t *a = frames[f];
|
||||
unsigned first = groups[i] == 21 ? 1001 : 2001;
|
||||
CHECK(a[0] == (groups[i] == 21 ? 1 : 11) && a[1] == 4 && a[2] == (0x80 | groups[i]));
|
||||
CHECK((unsigned)(a[6] | (unsigned)a[7] << 8 | (unsigned)a[8] << 16) == first + (f - 1) * 4);
|
||||
unsigned is_double = groups[i] == 21 && f >= 3U;
|
||||
unsigned first = groups[i] == 22 ? 2001U : is_double ? 1101U : 1001U;
|
||||
unsigned batch = is_double ? f - 3U : f - 1U;
|
||||
CHECK(a[0] == (groups[i] == 22 ? 11 : is_double ? 3 : 1) && a[1] == 4 && a[2] == (0x80 | groups[i]));
|
||||
CHECK((unsigned)(a[6] | (unsigned)a[7] << 8 | (unsigned)a[8] << 16) == first + batch * 4U);
|
||||
if (is_double) {
|
||||
unsigned point;
|
||||
CHECK(lengths[f] == 22U);
|
||||
for (point = 0U; point < 4U; ++point) { CHECK(a[9U + point * 4U] == 1U); }
|
||||
}
|
||||
}
|
||||
}
|
||||
CHECK(frames[0][9] == groups[i] && app.session_request == 0);
|
||||
@@ -2099,6 +2108,48 @@ static void test_example_groups(void)
|
||||
}
|
||||
}
|
||||
|
||||
/* 站总召和遥信分组均包含双点实时值:首批双点遭发送WAIT时保持游标,
|
||||
* 下一次尝试重新读取变化后的double_values;最终每个双点恰好交接一次。 */
|
||||
static void test_example_double_wait_values(void)
|
||||
{
|
||||
unsigned qualifier;
|
||||
for (qualifier = 20U; qualifier <= 21U; ++qualifier) {
|
||||
uint8_t request[sizeof(gi_request)];
|
||||
const uint8_t *frames[32];
|
||||
size_t lengths[32];
|
||||
unsigned step, point;
|
||||
app_open();
|
||||
memcpy(request, gi_request, sizeof(request)); request[9] = (uint8_t)qualifier;
|
||||
app_request(request, sizeof(request));
|
||||
for (step = 0U; step < 32U; ++step) {
|
||||
CHECK(IEC104_Interrogation_Process(app.interrogation));
|
||||
CHECK(IEC104_Interrogation_Get_Status(app.interrogation, &app.gi));
|
||||
if (app.gi.phase == IEC104_INTERROGATION_DATA && app.gi.batch_index == 2U) { break; }
|
||||
CHECK(Example_Drain_Business(&app));
|
||||
}
|
||||
CHECK(step < 32U && app.gi_data.single_index == 8U && app.gi_data.double_index == 0U);
|
||||
congest(&last_request.connection);
|
||||
CHECK(Example_Step(&app) && app.business_pending && app.gi.waiting);
|
||||
CHECK(app.gi_data.double_index == 0U && app.gi.batch_index == 2U && app.batch_bytes[9] == 1U);
|
||||
app.double_values[0] = app.double_values[3] = app.double_values[7] = 2U;
|
||||
CHECK(Example_Step(&app) && app.business_pending && app.gi.waiting);
|
||||
CHECK(app.gi_data.double_index == 0U && app.gi.batch_index == 2U && app.batch_bytes[9] == 2U);
|
||||
fake.send_blocked = 0;
|
||||
app_finish();
|
||||
CHECK(collect_asdus(frames, lengths) == (qualifier == 20U ? 8U : 6U));
|
||||
for (point = 0U; point < 8U; ++point) {
|
||||
unsigned batch = 3U + point / 4U;
|
||||
const uint8_t *a = frames[batch];
|
||||
const uint8_t *object = a + 6U + (point % 4U) * 4U;
|
||||
CHECK(lengths[batch] == 22U && a[0] == 3U && a[1] == 4U && a[2] == (0x80U | qualifier));
|
||||
CHECK((unsigned)(object[0] | (unsigned)object[1] << 8 | (unsigned)object[2] << 16) == 1101U + point);
|
||||
CHECK(object[3] == (point == 0U || point == 3U || point == 7U ? 2U : 1U));
|
||||
}
|
||||
CHECK(app.gi.gi_submitted == 1U && app.session_request == 0U && app.gi_station == NULL);
|
||||
app_close();
|
||||
}
|
||||
}
|
||||
|
||||
/* 撤销覆盖所有阶段,包含未读事件、已取事件、HIGH满、已提交部分数据和待发终止。
|
||||
* 已提交帧保留顺序;尚未提交批次及ACT_TERM不能越过肯定撤销确认。 */
|
||||
static void test_remote_deactivation_phases(void)
|
||||
@@ -2159,7 +2210,7 @@ static void test_remote_deactivation_phases(void)
|
||||
request[2] = 0x89;
|
||||
CHECK(lengths[prior] == 10 && memcmp(frames[prior], request, 10) == 0);
|
||||
app_request(gi_request, sizeof(gi_request)); app_finish();
|
||||
CHECK(app.gi.gi_submitted == 1 && collect_asdus(frames, lengths) == prior + 7);
|
||||
CHECK(app.gi.gi_submitted == 1 && collect_asdus(frames, lengths) == prior + 9);
|
||||
app_close();
|
||||
}
|
||||
}
|
||||
@@ -2945,15 +2996,15 @@ static void test_station_binding_wire(void)
|
||||
request[5] = broadcast ? 0xffU : 0x12U;
|
||||
app_request(request, sizeof(request));
|
||||
app_finish();
|
||||
CHECK(collect_asdus(frames, lengths) == 6U);
|
||||
CHECK(frames[0][2] == 0x87U && frames[5][2] == 0x8aU);
|
||||
for (i = 0U; i < 6U; ++i) { CHECK(frames[i][4] == 0x34U && frames[i][5] == 0x12U); }
|
||||
CHECK(collect_asdus(frames, lengths) == 8U);
|
||||
CHECK(frames[0][2] == 0x87U && frames[7][2] == 0x8aU);
|
||||
for (i = 0U; i < 8U; ++i) { CHECK(frames[i][4] == 0x34U && frames[i][5] == 0x12U); }
|
||||
request[4] = 7U;
|
||||
request[5] = 0U;
|
||||
app_request(request, sizeof(request));
|
||||
app_finish();
|
||||
CHECK(collect_asdus(frames, lengths) == 7U);
|
||||
CHECK(frames[6][2] == 0xeeU && frames[6][4] == 7U && frames[6][5] == 0U);
|
||||
CHECK(collect_asdus(frames, lengths) == 9U);
|
||||
CHECK(frames[8][2] == 0xeeU && frames[8][4] == 7U && frames[8][5] == 0U);
|
||||
CHECK(IEC104_Slave_Remove_Station(app.slave, &other) == IEC104_STATION_OK);
|
||||
app_close();
|
||||
}
|
||||
@@ -3337,12 +3388,16 @@ static void test_registry_example_order(void)
|
||||
CHECK(IEC104_Slave_Add_Station(app.slave, &second, 2U, &app) == IEC104_STATION_OK);
|
||||
CHECK(IEC104_Slave_Add_Station(app.slave, &third, 3U, &app) == IEC104_STATION_OK);
|
||||
registry_request(IEC104_CA_BROADCAST, 6U); app_finish();
|
||||
CHECK(collect_asdus(frames, lengths) == 18U && app.gi.gi_submitted == 3U);
|
||||
for (i = 0U; i < 18U; ++i) {
|
||||
unsigned ca = i < 3U ? i + 1U : i < 15U ? (i - 3U) / 4U + 1U : i - 14U;
|
||||
CHECK(collect_asdus(frames, lengths) == 24U && app.gi.gi_submitted == 3U);
|
||||
for (i = 0U; i < 24U; ++i) {
|
||||
unsigned ca = i < 3U ? i + 1U : i < 21U ? (i - 3U) / 6U + 1U : i - 20U;
|
||||
CHECK(frames[i][4] == ca && frames[i][5] == 0U);
|
||||
CHECK(frames[i][2] == (i < 3U ? 0x87U : i < 15U ? 0x94U : 0x8aU));
|
||||
if (i >= 3U && i < 15U) { CHECK((frames[i][1] & 0x7fU) == 4U); }
|
||||
CHECK(frames[i][2] == (i < 3U ? 0x87U : i < 21U ? 0x94U : 0x8aU));
|
||||
if (i >= 3U && i < 21U) {
|
||||
unsigned batch = (i - 3U) % 6U;
|
||||
CHECK((frames[i][1] & 0x7fU) == 4U);
|
||||
CHECK(frames[i][0] == (batch < 2U ? 1U : batch < 4U ? 3U : 11U));
|
||||
}
|
||||
}
|
||||
CHECK(app.gi_station == NULL && app.session_request == 0U);
|
||||
CHECK(IEC104_Slave_Remove_Station(app.slave, &second) == IEC104_STATION_OK);
|
||||
@@ -3576,7 +3631,7 @@ static void test_registry_reject_during_deactivation(void)
|
||||
if (mode == 1U) { registry_request(IEC104_CA_BROADCAST, 8U); }
|
||||
(void)gi_take(IEC104_INTERROGATION_FINISHED); (void)gi_take(IEC104_INTERROGATION_FINISHED);
|
||||
app_finish();
|
||||
CHECK(collect_asdus(frames, lengths) == (mode == 0U ? 9U : 3U));
|
||||
CHECK(collect_asdus(frames, lengths) == (mode == 0U ? 11U : 3U));
|
||||
CHECK(frames[0][2] == 0x87U && frames[0][4] == 1U);
|
||||
CHECK(frames[1][2] == 0xc7U && frames[1][4] == 2U);
|
||||
CHECK(frames[2][2] == 0x89U && frames[2][4] == 1U);
|
||||
@@ -3853,7 +3908,7 @@ static void test_counter_busy_independent(void)
|
||||
CHECK(app.gi.gi_submitted == 1);
|
||||
CHECK(IEC104_Interrogation_Reply_Begin(app.counter, &event, true) == IEC104_INTERROGATION_REPLY_OK);
|
||||
ci_process(); event = ci_take(IEC104_INTERROGATION_NEED_DATA); ci_done(&event);
|
||||
CHECK(collect_asdus(frames, lengths) == 9); ci_close();
|
||||
CHECK(collect_asdus(frames, lengths) == 11); ci_close();
|
||||
{
|
||||
IEC104_InterrogationConfig_t config; unsigned step, acked = 0, first_counter = 32, last_general = 0, i;
|
||||
IEC104_Interrogation_Config_Default(&config); config.max_objects_per_asdu = 1;
|
||||
@@ -3865,10 +3920,10 @@ static void test_counter_busy_independent(void)
|
||||
if (sent != acked) { push_ack(sent); acked = sent; app_poll(); }
|
||||
if (app.gi.pending_requests == 0 && app.ci.pending_requests == 0) { break; }
|
||||
}
|
||||
CHECK(step < 128 && acked == 22 && app.counter_completed == 1 && app.gi.gi_submitted == 1);
|
||||
CHECK(step < 128 && acked == 30 && app.counter_completed == 1 && app.gi.gi_submitted == 1);
|
||||
for (i = 0; i < acked; ++i) {
|
||||
if (frames[i][0] == 15 && first_counter == 32) { first_counter = i; }
|
||||
if (frames[i][0] == 1 || frames[i][0] == 11) { last_general = i; }
|
||||
if (frames[i][0] == 1 || frames[i][0] == 3 || frames[i][0] == 11) { last_general = i; }
|
||||
}
|
||||
CHECK(first_counter < last_general); ci_close(); custom_config = NULL; custom_window = 32;
|
||||
}
|
||||
@@ -4846,6 +4901,7 @@ int main(void)
|
||||
test_cancel_before_begin();
|
||||
test_group_interrogation();
|
||||
test_example_groups();
|
||||
test_example_double_wait_values();
|
||||
test_remote_deactivation_phases();
|
||||
test_remote_deactivation_validation();
|
||||
test_remote_deactivation_full_queue();
|
||||
@@ -4915,6 +4971,6 @@ int main(void)
|
||||
test_clock_broadcast();
|
||||
test_clock_broadcast_mutation();
|
||||
test_clock_example_integration();
|
||||
puts("slave example + event interrogation tests: 130 groups passed (98 general + 12 counter + 4 fallback + 16 clock)");
|
||||
puts("slave example + event interrogation tests: 131 groups passed (99 general + 12 counter + 4 fallback + 16 clock)");
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user