예제 #1
0
static MmsValue*
createOptFlds(ReportControlBlock* reportControlBlock)
{
    MmsValue* optFlds = MmsValue_newBitString(10);
    uint8_t options = reportControlBlock->options;

    if (options & 0x01)
        MmsValue_setBitStringBit(optFlds, 1, true);
    if (options & 0x02)
        MmsValue_setBitStringBit(optFlds, 2, true);
    if (options & 0x04)
        MmsValue_setBitStringBit(optFlds, 3, true);
    if (options & 0x08)
        MmsValue_setBitStringBit(optFlds, 4, true);
    if (options & 0x10)
        MmsValue_setBitStringBit(optFlds, 5, true);
    if (options & 0x20)
        MmsValue_setBitStringBit(optFlds, 6, true);
    if (options & 0x40)
        MmsValue_setBitStringBit(optFlds, 7, true);
    if (options & 0x80)
        MmsValue_setBitStringBit(optFlds, 8, true);

    return optFlds;
}
예제 #2
0
void
ClientReportControlBlock_setTrgOps(ClientReportControlBlock self, int trgOps)
{
    if (self->trgOps == NULL)
        self->trgOps = MmsValue_newBitString(6);

    MmsValue_setBitStringFromInteger(self->trgOps, trgOps << 1);
}
예제 #3
0
static MmsValue*
createTrgOps(ReportControlBlock* reportControlBlock) {
    MmsValue* trgOps = MmsValue_newBitString(6);

    uint8_t triggerOps = reportControlBlock->trgOps;

    if (triggerOps & 0x02)
        MmsValue_setBitStringBit(trgOps, 1, true);
    if (triggerOps & 0x04)
        MmsValue_setBitStringBit(trgOps, 2, true);
    if (triggerOps & 0x08)
        MmsValue_setBitStringBit(trgOps, 3, true);
    if (triggerOps & 0x10)
        MmsValue_setBitStringBit(trgOps, 4, true);
    if (triggerOps & 0x20)
        MmsValue_setBitStringBit(trgOps, 5, true);

    return trgOps;
}
예제 #4
0
bool
ControlObjectClient_selectWithValue(ControlObjectClient self, MmsValue* ctlVal)
{
    resetLastApplError(self);

    char domainId[65];
    char itemId[65];

    MmsMapping_getMmsDomainFromObjectReference(self->objectReference, domainId);

    convertToMmsAndInsertFC(itemId, self->objectReference + strlen(domainId) + 1, "CO");

    strncat(itemId, "$SBOw", 64);

    if (DEBUG_IED_CLIENT)
        printf("IED_CLIENT: select with value: %s/%s\n", domainId, itemId);

    MmsError mmsError;

    MmsValue* selValParameters;

    if (self->hasTimeActivatedMode)
        selValParameters = MmsValue_createEmptyStructure(7);
    else
        selValParameters = MmsValue_createEmptyStructure(6);

    MmsValue_setElement(selValParameters, 0, ctlVal);

    int index = 1;

    if (self->hasTimeActivatedMode) {
        MmsValue* operTm = MmsValue_newUtcTimeByMsTime(0);
        MmsValue_setElement(selValParameters, index++, operTm);
    }

    MmsValue* origin = createOriginValue(self);
    MmsValue_setElement(selValParameters, index++, origin);

    self->ctlNum++;

    MmsValue* ctlNum = MmsValue_newUnsignedFromUint32(self->ctlNum);
    MmsValue_setElement(selValParameters, index++, ctlNum);


    uint64_t timestamp = Hal_getTimeInMs();
    MmsValue* ctlTime;

    if (self->edition == 2)
        ctlTime = MmsValue_newUtcTimeByMsTime(timestamp);
    else {
        ctlTime = MmsValue_newBinaryTime(false);
        MmsValue_setBinaryTime(ctlTime, timestamp);
    }

    MmsValue_setElement(selValParameters, index++, ctlTime);

    MmsValue* ctlTest = MmsValue_newBoolean(self->test);
    MmsValue_setElement(selValParameters, index++, ctlTest);

    MmsValue* check = MmsValue_newBitString(2);
    MmsValue_setBitStringBit(check, 1, self->interlockCheck);
    MmsValue_setBitStringBit(check, 0, self->synchroCheck);
    MmsValue_setElement(selValParameters, index++, check);

    MmsConnection_writeVariable(IedConnection_getMmsConnection(self->connection),
            &mmsError, domainId, itemId, selValParameters);

    MmsValue_setElement(selValParameters, 0, NULL);
    MmsValue_delete(selValParameters);

    if (mmsError != MMS_ERROR_NONE) {
        if (DEBUG_IED_CLIENT)
            printf("IED_CLIENT: select-with-value failed!\n");
        return false;
    }

    MmsValue_update(self->ctlVal, ctlVal);

    return true;
}
예제 #5
0
bool
ControlObjectClient_operate(ControlObjectClient self, MmsValue* ctlVal, uint64_t operTime)
{
    bool success = false;

    if (ctlVal == NULL) {
        if (DEBUG_IED_CLIENT)
            printf("IED_CLIENT: operate - (ctlVal == NULL)!\n");

        goto exit_function;
    }

    resetLastApplError(self);

    MmsValue* operParameters;

    if (self->hasTimeActivatedMode)
        operParameters = MmsValue_createEmptyStructure(7);
    else
        operParameters = MmsValue_createEmptyStructure(6);

    MmsValue_setElement(operParameters, 0, ctlVal);

    int index = 1;

    if (self->hasTimeActivatedMode) {
        MmsValue* operTm = MmsValue_newUtcTimeByMsTime(operTime);
        MmsValue_setElement(operParameters, index++, operTm);
    }

    MmsValue* origin = createOriginValue(self);
    MmsValue_setElement(operParameters, index++, origin);

    if (!((self->ctlModel == CONTROL_MODEL_SBO_NORMAL) ||
            (self->ctlModel == CONTROL_MODEL_SBO_ENHANCED)))
    {
        self->ctlNum++;
    }

    MmsValue* ctlNum = MmsValue_newUnsignedFromUint32(self->ctlNum);
    MmsValue_setElement(operParameters, index++, ctlNum);

    uint64_t timestamp = Hal_getTimeInMs();
    MmsValue* ctlTime;

    if (self->edition == 2)
        ctlTime = MmsValue_newUtcTimeByMsTime(timestamp);
    else {
        ctlTime = MmsValue_newBinaryTime(false);
        MmsValue_setBinaryTime(ctlTime, timestamp);
    }

    MmsValue_setElement(operParameters, index++, ctlTime);

    MmsValue* ctlTest = MmsValue_newBoolean(self->test);
    MmsValue_setElement(operParameters, index++, ctlTest);

    MmsValue* check = MmsValue_newBitString(2);
    MmsValue_setBitStringBit(check, 1, self->interlockCheck);
    MmsValue_setBitStringBit(check, 0, self->synchroCheck);
    MmsValue_setElement(operParameters, index++, check);

    char domainId[65];
    char itemId[65];

    MmsMapping_getMmsDomainFromObjectReference(self->objectReference, domainId);

    convertToMmsAndInsertFC(itemId, self->objectReference + strlen(domainId) + 1, "CO");

    int controlObjectItemIdLen = strlen(itemId);

    strncat(itemId, "$Oper", 64 - controlObjectItemIdLen);

    if (DEBUG_IED_CLIENT)
        printf("IED_CLIENT: operate: %s/%s\n", domainId, itemId);

    MmsError mmsError;

    MmsConnection_writeVariable(IedConnection_getMmsConnection(self->connection),
            &mmsError, domainId, itemId, operParameters);

    MmsValue_setElement(operParameters, 0, NULL);
    MmsValue_delete(operParameters);

    if (mmsError != MMS_ERROR_NONE) {
        if (DEBUG_IED_CLIENT)
            printf("IED_CLIENT: operate failed!\n");

        goto exit_function;
    }

    MmsValue_update(self->ctlVal, ctlVal);
    self->opertime = operTime;

    success = true;

exit_function:
    return success;
}
예제 #6
0
MmsDataAccessError
Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* elementName, MmsValue* value,
        MmsServerConnection* connection)
{
    if (strcmp(elementName, "RptEna") == 0) {

        if (value->value.boolean == true) {

            if (rc->enabled == true)
                return DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE;

            if (DEBUG)
                printf("Activate report for client %s\n",
                        MmsServerConnection_getClientAddress(connection));

            MmsValue* dataSetValue;

            dataSetValue = ReportControl_getRCBValue(rc, "DatSet");

            char* dataSetName = MmsValue_toString(dataSetValue);

            if (rc->isDynamicDataSet) {
                if (rc->dataSet != NULL)
                    MmsMapping_freeDynamicallyCreatedDataSet(rc->dataSet);
            }

            if (dataSetValue != NULL) {
                DataSet* dataSet = IedModel_lookupDataSet(self->model, dataSetName);

                if (dataSet == NULL) {
                    dataSet = MmsMapping_getDomainSpecificDataSet(self, dataSetName);

                    if (dataSet == NULL)
                        return DATA_ACCESS_ERROR_OBJECT_ATTRIBUTE_INCONSISTENT;

                    rc->isDynamicDataSet = true;

                }
                else
                    rc->isDynamicDataSet = false;

                rc->dataSet = dataSet;

                rc->inclusionField = MmsValue_newBitString(
                        dataSet->elementCount);

                rc->clientConnection = connection;

                // TODO check integrity bit in trigger options

                MmsValue* intgPd = ReportControl_getRCBValue(rc, "IntgPd");

                rc->intgPd = MmsValue_toUint32(intgPd);

                MmsValue* rptEna = ReportControl_getRCBValue(rc, "RptEna");

                MmsValue_update(rptEna, value);

                MmsValue* bufTm = ReportControl_getRCBValue(rc, "BufTm");

                rc->bufTm = MmsValue_toUint32(bufTm);

                rc->triggerOps = 0;

                MmsValue* trgOps = ReportControl_getRCBValue(rc, "TrgOps");

                if (MmsValue_getBitStringBit(trgOps, 1))
                    rc->triggerOps += TRG_OPT_DATA_CHANGED;
                if (MmsValue_getBitStringBit(trgOps, 2))
                    rc->triggerOps += TRG_OPT_QUALITY_CHANGED;
                if (MmsValue_getBitStringBit(trgOps, 3))
                    rc->triggerOps += TRG_OPT_DATA_UPDATE;
                if (MmsValue_getBitStringBit(trgOps, 4))
                    rc->triggerOps += TRG_OPT_INTEGRITY;
                if (MmsValue_getBitStringBit(trgOps, 5))
                    rc->triggerOps += TRG_OPT_GI;

                rc->sqNum = 0;

                rc->inclusionFlags = (ReportInclusionFlag*) calloc(dataSet->elementCount, sizeof(ReportInclusionFlag));

                rc->enabled = true;

                return DATA_ACCESS_ERROR_SUCCESS;
            }

            return DATA_ACCESS_ERROR_OBJECT_ATTRIBUTE_INCONSISTENT;
        }
        else {
            if (((rc->enabled) || (rc->reserved)) && (rc->clientConnection != connection))
                return DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE;

            if (DEBUG)
                printf("Deactivate report for client %s\n",
                        MmsServerConnection_getClientAddress(connection));

            free(rc->inclusionFlags);
            rc->inclusionFlags = NULL;

            rc->enabled = false;
        }

    }

    if (strcmp(elementName, "GI") == 0) {
        if ((rc->enabled) && (rc->clientConnection == connection)) {
            rc->gi = true;
            return DATA_ACCESS_ERROR_SUCCESS;;
        }
        else
            return DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE;
    }

    if (rc->enabled == false) {

        if ((rc->reserved) && (rc->clientConnection != connection))
            return DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE;

        if (rc->bufferd == false) {
            if (strcmp(elementName, "Resv") == 0) {
                rc->reserved = value->value.boolean;

                if (rc->reserved == true)
                    rc->clientConnection = connection;
            }
        }

        MmsValue* rcbValue = ReportControl_getRCBValue(rc, elementName);

        if (rcbValue != NULL)
            MmsValue_update(rcbValue, value);
        else
            return DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID;
    }
    else
        return DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE;

    return DATA_ACCESS_ERROR_SUCCESS;;
}
예제 #7
0
static void
sendReport(ReportControl* self, bool isIntegrity, bool isGI)
{
    LinkedList reportElements = LinkedList_create();

    LinkedList deletableElements = LinkedList_create();

    MmsValue* rptId = ReportControl_getRCBValue(self, "RptID");
    MmsValue* optFlds = ReportControl_getRCBValue(self, "OptFlds");
    MmsValue* datSet = ReportControl_getRCBValue(self, "DatSet");

    LinkedList_add(reportElements, rptId);
    LinkedList_add(reportElements, optFlds);

    /* delete option fields for unsupported options */
    MmsValue_setBitStringBit(optFlds, 5, false); /* data-reference */
    MmsValue_setBitStringBit(optFlds, 7, false); /* entryID */
    MmsValue_setBitStringBit(optFlds, 9, false); /* segmentation */

    MmsValue* sqNum = ReportControl_getRCBValue(self, "SqNum");

    if (MmsValue_getBitStringBit(optFlds, 1)) /* sequence number */
        LinkedList_add(reportElements, sqNum);

    if (MmsValue_getBitStringBit(optFlds, 2)) { /* report time stamp */
        LinkedList_add(reportElements, self->timeOfEntry);
    }

    if (MmsValue_getBitStringBit(optFlds, 4)) /* data set reference */
        LinkedList_add(reportElements, datSet);

    if (MmsValue_getBitStringBit(optFlds, 6)) { /* bufOvfl */
        MmsValue* bufOvfl = MmsValue_newBoolean(false);

        LinkedList_add(reportElements, bufOvfl);
        LinkedList_add(deletableElements, bufOvfl);
    }

    if (MmsValue_getBitStringBit(optFlds, 8))
        LinkedList_add(reportElements, self->confRev);

    if (isGI || isIntegrity)
        MmsValue_setAllBitStringBits(self->inclusionField);
    else
        MmsValue_deleteAllBitStringBits(self->inclusionField);

    LinkedList_add(reportElements, self->inclusionField);


    /* add data set value elements */
    int i = 0;
    for (i = 0; i < self->dataSet->elementCount; i++) {

        if (isGI || isIntegrity)
            LinkedList_add(reportElements, self->dataSet->fcda[i]->value);
        else {
            if (self->inclusionFlags[i] != REPORT_CONTROL_NONE) {
                LinkedList_add(reportElements, self->dataSet->fcda[i]->value);
                MmsValue_setBitStringBit(self->inclusionField, i, true);
            }
        }
    }

    /* add reason code to report if requested */
    if (MmsValue_getBitStringBit(optFlds, 3)) {
        for (i = 0; i < self->dataSet->elementCount; i++) {

            if (isGI || isIntegrity) {
                MmsValue* reason = MmsValue_newBitString(6);

                if (isGI)
                    MmsValue_setBitStringBit(reason, 5, true);

                if (isIntegrity)
                    MmsValue_setBitStringBit(reason, 4, true);

                LinkedList_add(reportElements, reason);
                LinkedList_add(deletableElements, reason);
            }
            else if (self->inclusionFlags[i] != REPORT_CONTROL_NONE) {
                MmsValue* reason = MmsValue_newBitString(6);

                switch(self->inclusionFlags[i]) {
                case REPORT_CONTROL_QUALITY_CHANGED:
                    MmsValue_setBitStringBit(reason, 2, true);
                    break;
                case REPORT_CONTROL_VALUE_CHANGED:
                    MmsValue_setBitStringBit(reason, 1, true);
                    break;
                case REPORT_CONTROL_VALUE_UPDATE:
                    MmsValue_setBitStringBit(reason, 3, true);
                    break;
                }

                LinkedList_add(reportElements, reason);
                LinkedList_add(deletableElements, reason);
            }
        }
    }

    /* clear inclusion flags */
    for (i = 0; i < self->dataSet->elementCount; i++) {
        self->inclusionFlags[i] = REPORT_CONTROL_NONE;
    }

    MmsServerConnection_sendInformationReportVMDSpecific(self->clientConnection, "RPT", reportElements);

    /* Increase sequence number */
    self->sqNum++;
    MmsValue_setUint16(sqNum, self->sqNum);

    LinkedList_destroyDeep(deletableElements, (LinkedListValueDeleteFunction) MmsValue_delete);
    LinkedList_destroyStatic(reportElements);

    /* clear GI flag */
    if (isGI) {
        MmsValue* gi = ReportControl_getRCBValue(self, "GI");
        self->gi = false;
        MmsValue_setBoolean(gi, false);
    }
}
예제 #8
0
static MmsValue*
parseAllDataUnknownValue(GooseSubscriber self, uint8_t* buffer, int allDataLength, bool isStructure)
{
    int bufPos = 0;
    int elementLength = 0;

    int elementIndex = 0;

    MmsValue* dataSetValues = NULL;

    while (bufPos < allDataLength) {
        uint8_t tag = buffer[bufPos++];

        bufPos = BerDecoder_decodeLength(buffer, &elementLength, bufPos, allDataLength);

        if (bufPos + elementLength > allDataLength) {
            if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Malformed message: sub element is too large!\n");
            goto exit_with_error;
        }

        switch (tag) {
        case 0x80: /* reserved for access result */
            break;
        case 0xa1: /* array */
            break;
        case 0xa2: /* structure */
            break;
        case 0x83: /* boolean */
            break;
        case 0x84: /* BIT STRING */
            break;
        case 0x85: /* integer */
            break;
        case 0x86: /* unsigned integer */
            break;
        case 0x87: /* Float */
            break;
        case 0x89: /* octet string */
            break;
        case 0x8a: /* visible string */
            break;
        case 0x8c: /* binary time */
            break;
        case 0x91: /* Utctime */
            break;
        default:
            if (DEBUG_GOOSE_SUBSCRIBER)
                printf("GOOSE_SUBSCRIBER:    found unknown tag %02x\n", tag);
            goto exit_with_error;
        }

        bufPos += elementLength;

        elementIndex++;
    }

    if (isStructure)
        dataSetValues = MmsValue_createEmptyStructure(elementIndex);
    else
        dataSetValues = MmsValue_createEmptyArray(elementIndex);

    elementIndex = 0;
    bufPos = 0;

    while (bufPos < allDataLength) {
        uint8_t tag = buffer[bufPos++];

        bufPos = BerDecoder_decodeLength(buffer, &elementLength, bufPos, allDataLength);

        if (bufPos + elementLength > allDataLength) {
            if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Malformed message: sub element is too large!\n");
            goto exit_with_error;
        }

        MmsValue* value = NULL;

        switch (tag) {
        case 0xa1: /* array */
            if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER:    found array\n");

            value = parseAllDataUnknownValue(self, buffer + bufPos, elementLength, false);

            if (value == NULL)
                goto exit_with_error;

            break;
        case 0xa2: /* structure */
            if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER:    found structure\n");

            value = parseAllDataUnknownValue(self, buffer + bufPos, elementLength, true);

            if (value == NULL)
                goto exit_with_error;

            break;
        case 0x83: /* boolean */
            if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER:    found boolean\n");
            value = MmsValue_newBoolean(BerDecoder_decodeBoolean(buffer, bufPos));

            break;

        case 0x84: /* BIT STRING */
            {
                int padding = buffer[bufPos];
                int bitStringLength = (8 * (elementLength - 1)) - padding;
                value = MmsValue_newBitString(bitStringLength);
                memcpy(value->value.bitString.buf, buffer + bufPos + 1, elementLength - 1);

            }
            break;
        case 0x85: /* integer */
            value = MmsValue_newInteger(elementLength * 8);
            memcpy(value->value.integer->octets, buffer + bufPos, elementLength);
            value->value.integer->size = elementLength;
            break;
        case 0x86: /* unsigned integer */
            value = MmsValue_newUnsigned(elementLength * 8);
            memcpy(value->value.integer->octets, buffer + bufPos, elementLength);
            value->value.integer->size = elementLength;
            break;
        case 0x87: /* Float */
                if (elementLength == 9)
                    value = MmsValue_newDouble(BerDecoder_decodeDouble(buffer, bufPos));
                else if (elementLength == 5)
                    value = MmsValue_newFloat(BerDecoder_decodeFloat(buffer, bufPos));
            break;

        case 0x89: /* octet string */
            value = MmsValue_newOctetString(elementLength, elementLength);
            memcpy(value->value.octetString.buf, buffer + bufPos, elementLength);
            break;
        case 0x8a: /* visible string */
            value = MmsValue_newVisibleStringFromByteArray(buffer + bufPos, elementLength);
            break;
        case 0x8c: /* binary time */
            if (elementLength == 4)
                value = MmsValue_newBinaryTime(true);
            else if (elementLength == 6)
                value = MmsValue_newBinaryTime(false);

            if ((elementLength == 4) || (elementLength == 6))
                memcpy(value->value.binaryTime.buf, buffer + bufPos, elementLength);

            break;
        case 0x91: /* Utctime */
            if (elementLength == 8) {
                value = MmsValue_newUtcTime(0);
                MmsValue_setUtcTimeByBuffer(value, buffer + bufPos);
            }
            else
                if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER:      UTCTime element is of wrong size!\n");
            break;
        default:
            if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER:    found unkown tag %02x\n", tag);
            goto exit_with_error;
        }

        bufPos += elementLength;

        if (value != NULL) {
            MmsValue_setElement(dataSetValues, elementIndex, value);
            elementIndex++;
        }
    }

    self->dataSetValuesSelfAllocated = true;

    return dataSetValues;

exit_with_error:

    if (dataSetValues != NULL)
        MmsValue_delete(dataSetValues);

    return NULL;
}