IC_104/lib60870-C/examples/cs104_client/simple_client.c
George 1ddf693260 feat:
--READ smash_read_this.txt
2026-06-22 16:04:13 +05:30

173 lines
6.0 KiB
C

/* scada.c — simulates a SCADA control center */
#include <stdlib.h>
#include <stdbool.h>
#include <stdio.h>
#include <signal.h>
#include <string.h>
#include "cs104_connection.h"
#include "hal_thread.h"
#include "hal_time.h"
static bool running = true;
void sigint_handler(int s) { running = false; }
/* ── called for every ASDU received from RTU ───────────────── */
static bool asduReceivedHandler(void* p, int address, CS101_ASDU asdu) {
int typeId = CS101_ASDU_getTypeID(asdu);
int cot = CS101_ASDU_getCOT(asdu);
/* measured float value M_ME_NC_1 */
if (typeId == M_ME_NC_1) {
int i;
for (i = 0; i < CS101_ASDU_getNumberOfElements(asdu); i++) {
MeasuredValueShort mv = (MeasuredValueShort)
CS101_ASDU_getElement(asdu, i);
int ioa = InformationObject_getObjectAddress((InformationObject)mv);
float value = MeasuredValueShort_getValue(mv);
InformationObject_destroy((InformationObject)mv);
if (ioa == 100)
printf("[SCADA ←] Voltage IOA=100 %.2f kV\n", value);
else if (ioa == 101)
printf("[SCADA ←] Current IOA=101 %.1f A\n", value);
else
printf("[SCADA ←] Float IOA=%d %.2f\n", ioa, value);
}
}
/* single point M_SP_NA_1 */
else if (typeId == M_SP_NA_1) {
int i;
for (i = 0; i < CS101_ASDU_getNumberOfElements(asdu); i++) {
SinglePointInformation sp = (SinglePointInformation)
CS101_ASDU_getElement(asdu, i);
int ioa = InformationObject_getObjectAddress((InformationObject)sp);
bool state = SinglePointInformation_getValue(sp);
InformationObject_destroy((InformationObject)sp);
if (ioa == 200)
printf("[SCADA ←] Breaker1 IOA=200 %s\n", state ? "ON" : "OFF");
else if (ioa == 201)
printf("[SCADA ←] Breaker2 IOA=201 %s\n", state ? "ON" : "OFF");
else
printf("[SCADA ←] Point IOA=%d %s\n", ioa, state ? "ON" : "OFF");
}
}
/* command confirmation */
else if (typeId == C_SC_NA_1) {
if (cot == CS101_COT_ACTIVATION_CON)
printf("[SCADA ←] Command confirmed by RTU\n");
else if (cot == CS101_COT_UNKNOWN_IOA)
printf("[SCADA ←] Command rejected — unknown IOA\n");
}
else {
printf("[SCADA ←] TypeID=%d COT=%d\n", typeId, cot);
}
return true;
}
/* ── connection state ───────────────────────────────────────── */
static void connectionHandler(void* p, CS104_Connection con, CS104_ConnectionEvent event) {
if (event == CS104_CONNECTION_OPENED)
printf("[SCADA] Connected to RTU\n");
else if (event == CS104_CONNECTION_CLOSED)
printf("[SCADA] Disconnected from RTU\n");
else if (event == CS104_CONNECTION_STARTDT_CON_RECEIVED)
printf("[SCADA] STARTDT confirmed — data transfer active\n");
else if (event == CS104_CONNECTION_STOPDT_CON_RECEIVED)
printf("[SCADA] STOPDT confirmed\n");
}
/* ── send a single command to RTU ───────────────────────────── */
void send_command(CS104_Connection con, int ioa, bool state) {
CS101_AppLayerParameters alParams =
CS104_Connection_getAppLayerParameters(con);
CS101_ASDU asdu = CS101_ASDU_create(alParams, false,
CS101_COT_ACTIVATION, 0, 1, false, false);
InformationObject io = (InformationObject)
SingleCommand_create(NULL, ioa, state, false, 0);
CS101_ASDU_addInformationObject(asdu, io);
InformationObject_destroy(io);
CS104_Connection_sendASDU(con, asdu);
CS101_ASDU_destroy(asdu);
printf("[SCADA →] Command sent — IOA=%d state=%s\n",
ioa, state ? "ON" : "OFF");
}
/* ── send general interrogation ─────────────────────────────── */
void send_gi(CS104_Connection con) {
CS104_Connection_sendInterrogationCommand(con,
CS101_COT_ACTIVATION, 1, IEC60870_QOI_STATION);
printf("[SCADA →] General Interrogation sent\n");
}
/* ── main ───────────────────────────────────────────────────── */
int main(int argc, char** argv) {
signal(SIGINT, sigint_handler);
const char* ip = (argc > 1) ? argv[1] : "127.0.0.1";
printf("[SCADA] Connecting to RTU at %s:2404\n\n", ip);
CS104_Connection con = CS104_Connection_create(ip, 2404);
CS104_Connection_setConnectionHandler(con, connectionHandler, NULL);
CS104_Connection_setASDUReceivedHandler(con, asduReceivedHandler, NULL);
CS104_Connection_connect(con);
Thread_sleep(1000);
/* start data transfer */
CS104_Connection_sendStartDT(con);
Thread_sleep(500);
/* request all current values */
send_gi(con);
Thread_sleep(2000);
/* main loop — send commands periodically */
uint64_t lastCmd = 0;
bool b1_state = false;
bool b2_state = false;
printf("\n[SCADA] Running — commands every 5s, Ctrl+C to stop\n\n");
while (running) {
uint64_t now = Hal_getMonotonicTimeInMs();
/* every 5s — toggle breaker1 then breaker2 alternately */
if (now >= lastCmd + 5000) {
lastCmd = now;
static int cmd_count = 0;
cmd_count++;
if (cmd_count % 2 == 0) {
b1_state = !b1_state;
send_command(con, 200, b1_state); /* toggle breaker1 */
} else {
b2_state = !b2_state;
send_command(con, 201, b2_state); /* toggle breaker2 */
}
}
Thread_sleep(10);
}
printf("\n[SCADA] Shutting down\n");
CS104_Connection_sendStopDT(con);
Thread_sleep(500);
CS104_Connection_destroy(con);
return 0;
}