fledge-power / fledge-south-iec104

A south plugin to gather data using the IEC 104 protocol.
Apache License 2.0
1 stars 3 forks source link

The south service transforms the type C_RC_NA_1 into C_RC_TA_1 #58

Closed YmaIneo closed 1 year ago

YmaIneo commented 1 year ago

Describe the bug A clear and concise description of what the bug is.

To Reproduce Steps to reproduce the behavior:

  1. Initial state I have: [RTU] running <=> [FLEDGEPOWER] running <=> [CENTER] running
  2. A command of type C_RC_NA_1 must be configured on the RTU, on fledge and on the center.
  3. Sending the command from the center.
  4. The command is transformed in C_RC_TA by the south service.
  5. The center never receives an acknowledgement of the command (error of timeout).

Expected behavior A command of type C_RC_NA is not transformed into C_RC_TA by the south service

Screenshots

  1. Wireshark on the center, sending the commande C_RC_NA : image

  2. Wireshark on RTU, received the command C_RC_TA : image

  3. Logs of Fledge :

Apr 6 09:32:31 be3fa5838c90 Fledge iec104north_c1[1930]: WARNING: command 37873:3268708 (type: 47) timeout Apr 6 09:32:24 be3fa5838c90 Fledge[144] INFO: scheduler: fledge.services.core.scheduler.scheduler: Scheduled task for schedule 'stats collection' to start at 2023-04-06 09:32:38.682216 Apr 6 09:32:24 be3fa5838c90 Fledge[144] INFO: scheduler: fledge.services.core.scheduler.scheduler: Process terminated: Schedule 'stats collection' process 'stats collector' task c36af4c3-d0ef-4394-8dd4-5ad3659f7db7 pid 18032 exit 0, 3 running tasks#012['tasks/statistics'] Apr 6 09:32:23 be3fa5838c90 Fledge[144] INFO: scheduler: fledge.services.core.scheduler.scheduler: Process started: Schedule 'stats collection' process 'stats collector' task c36af4c3-d0ef-4394-8dd4-5ad3659f7db7 pid 18032, 4 running tasks#012['tasks/statistics', '--port=40963', '--address=127.0.0.1', '--name=stats collection'] Apr 6 09:32:12 be3fa5838c90 Fledge iec104south_s1[1937]: WARNING: ACT-CON timeout for outstanding command - type: 58 ca: 37873 ioa: 3268708 Apr 6 09:32:11 be3fa5838c90 Fledge iec104north_c1[1930]: INFO: Parameter 3: 0 Apr 6 09:32:11 be3fa5838c90 Fledge iec104north_c1[1930]: INFO: Parameter 2: 2 Apr 6 09:32:11 be3fa5838c90 Fledge iec104north_c1[1930]: INFO: Parameter 1: 3268708 Apr 6 09:32:11 be3fa5838c90 Fledge iec104north_c1[1930]: INFO: Parameter 0: 37873 Apr 6 09:32:11 be3fa5838c90 Fledge iec104north_c1[1930]: INFO: Control operation StepCommand with 4 parameters Apr 6 09:32:11 be3fa5838c90 Fledge iec104north_c1[1930]: INFO: received command

Additional context

I found two problems in the south service concerning the handling of command of type C_RC_NA_1 and C_RC_TA_1:

File iec104.cpp :

bool
IEC104::operation(const std::string& operation, int count,
                       PLUGIN_PARAMETER** params)
{
    printf("IEC104::operation(%s)\n", operation.c_str());

    if (operation.compare("CS104_Connection_sendInterrogationCommand") == 0)
    {
        int ca = atoi(params[0]->value.c_str());

        return m_client->sendInterrogationCommand(ca);
    }
    else if (operation.compare(
                    "CS104_Connection_sendTestCommandWithTimestamp") == 0)
    {
        int casdu = atoi(params[0]->value.c_str());

        //TODO implement?

        return false;
    }
    else if (operation.compare("SingleCommandWithCP56Time2a") == 0)
    {
        return m_singleCommandOperation(count, params, true);
    }
    else if (operation.compare("SingleCommand") == 0)
    {
        return m_singleCommandOperation(count, params, false);
    }
    else if (operation.compare("DoubleCommandWithCP56Time2a") == 0)
    {
        return m_doubleCommandOperation(count, params, true);
    }
    else if (operation.compare("DoubleCommand") == 0)
    {
        return m_doubleCommandOperation(count, params, false);
    }
    else if (operation.compare("StepCommandWithCP56Time2a") == 0)
    {
        return m_stepCommandOperation(count, params, true);
    }
    else if (operation.compare("StepCommand") == 0)
    {
-        return m_stepCommandOperation(count, params, true);
+        return m_stepCommandOperation(count, params, false);
    }
    else if (operation.compare("SetpointNormalizedWithCP56Time2a") == 0)
    {
        return m_setpointNormalized(count, params, true);
    }
    else if (operation.compare("SetpointNormalized") == 0)
    {
        return m_setpointNormalized(count, params, false);
    }
    else if (operation.compare("SetpointScaledWithCP56Time2a") == 0)
    {
        return m_setpointScaled(count, params, true);
    }
    else if (operation.compare("SetpointScaled") == 0)
    {
        return m_setpointScaled(count, params, false);
    }
    else if (operation.compare("SetpointShortWithCP56Time2a") == 0)
    {
        return m_setpointShort(count, params, true);
    }
    else if (operation.compare("SetpointShort") == 0)
    {
        return m_setpointShort(count, params, false);
    }
    else if (operation.compare("request_connection_status") == 0) {
        return m_client->sendConnectionStatus();
    }

    Logger::getLogger()->error("Unrecognised operation %s", operation.c_str());

    return false;
}

StepCommand operations are not dated types. Is this correct?

File iec104_client.cpp :

void IEC104Client::handle_C_RC_NA_1(vector<Datapoint*>& datapoints, string& label,
                             unsigned int ca,
                             CS101_ASDU asdu, InformationObject io,
                             uint64_t ioa,
                             OutstandingCommand* outstandingCommand)
{
    auto io_casted = (StepCommandWithCP56Time2a)io;
    int64_t state = StepCommand_getState((StepCommand)io_casted);

    QualifierOfCommand qu = StepCommand_getQU((StepCommand)io_casted);

    if (outstandingCommand) {
        if (CS101_ASDU_getCOT(asdu) == CS101_COT_ACTIVATION_CON) {
            outstandingCommand->actConReceived = true;
            outstandingCommand->timeout = getMonotonicTimeInMs();
        }
        else if (CS101_ASDU_getCOT(asdu) == CS101_COT_ACTIVATION_TERMINATION) {
            removeOutstandingCommand(outstandingCommand);
        }
    }

-    if (CS101_ASDU_getTypeID(asdu) == C_DC_TA_1)
+    if (CS101_ASDU_getTypeID(asdu) == C_RC_TA_1)
    {
        CP56Time2a ts = StepCommandWithCP56Time2a_getTimestamp(io_casted);

        datapoints.push_back(m_createDataObject(asdu, ioa, label, state, nullptr, ts));
    }
    else
        datapoints.push_back(m_createDataObject(asdu, ioa, label, state, nullptr));
}

This method should handle the dated type C_RC_TA_1 and not C_DC_TA_1. Is this correct?