diff --git a/src/components/comp_fmu.c b/src/components/comp_fmu.c index 2024c88..8b8cfff 100644 --- a/src/components/comp_fmu.c +++ b/src/components/comp_fmu.c @@ -871,19 +871,19 @@ static McxStatus Fmu2Initialize(Component * comp, size_t group, double startTime McxStatus retVal = RETURN_OK; // Set variables - retVal = Fmu2SetVariableArray(fmu2, fmu2->params); + retVal = Fmu2SetVariableArrayInitialize(fmu2, fmu2->params); if (RETURN_OK != retVal) { ComponentLog(comp, LOG_ERROR, "Setting params failed"); return RETURN_ERROR; } - retVal = Fmu2SetVariableArray(fmu2, fmu2->initialValues); + retVal = Fmu2SetVariableArrayInitialize(fmu2, fmu2->initialValues); if (RETURN_OK != retVal) { ComponentLog(comp, LOG_ERROR, "Setting initialValues failed"); return RETURN_ERROR; } - retVal = Fmu2SetVariableArray(fmu2, fmu2->in); + retVal = Fmu2SetVariableArrayInitialize(fmu2, fmu2->in); if (RETURN_OK != retVal) { ComponentLog(comp, LOG_ERROR, "Setting inChannels failed"); return RETURN_ERROR; @@ -916,13 +916,13 @@ static McxStatus Fmu2Initialize(Component * comp, size_t group, double startTime } // Set variables - retVal = Fmu2SetVariableArray(fmu2, fmu2->initialValues); + retVal = Fmu2SetVariableArrayInitialize(fmu2, fmu2->initialValues); if (RETURN_OK != retVal) { ComponentLog(comp, LOG_ERROR, "Setting initialValues failed"); return RETURN_ERROR; } - retVal = Fmu2SetVariableArray(fmu2, fmu2->in); + retVal = Fmu2SetVariableArrayInitialize(fmu2, fmu2->in); if (RETURN_OK != retVal) { ComponentLog(comp, LOG_ERROR, "Setting inChannels failed"); return RETURN_ERROR; diff --git a/src/core/Component.c b/src/core/Component.c index b8070aa..305fee5 100644 --- a/src/core/Component.c +++ b/src/core/Component.c @@ -851,7 +851,7 @@ Vector * GetInConnectionInfos(const Component * comp, size_t channelID) { return NULL; } -ObjectContainer * GetInConnections(const Component * comp, size_t channelID) { +ConnectionList * GetInConnections(const Component * comp, size_t channelID) { size_t channelNum = DatabusInfoGetChannelNum(DatabusGetInInfo(comp->data->databus)); if (channelID < channelNum) { ChannelIn * in = DatabusGetInChannel(comp->data->databus, channelID); @@ -972,11 +972,10 @@ static ObjectList * ComponentGetConnections(Component * fromComp, Component * to for (i = 0; i < DatabusGetOutChannelsNum(db); i++) { ChannelOut * out = DatabusGetOutChannel(db, i); - ObjectList * conns = out->GetConnections(out); - size_t connSize = conns->Size(conns); + ConnectionList * conns = out->GetConnections(out); - for (j = 0; j < connSize; j++) { - Connection * conn = (Connection *) conns->At(conns, j); + for (j = 0; j < conns->numConnections; j++) { + Connection * conn = conns->connections[j]; ConnectionInfo * info = conn->GetInfo(conn); if (info->targetComponent == toComp) { @@ -1014,11 +1013,10 @@ McxStatus ComponentOutConnectionsEnterInitMode(Component * comp) { for (i = 0; i < numOutChannels; i++) { ChannelOut * out = DatabusGetOutChannel(db, i); - ObjectList * conns = out->GetConnections(out); - size_t connSize = conns->Size(conns); + ConnectionList * conns = out->GetConnections(out); - for (j = 0; j < connSize; j++) { - Connection * connection = (Connection *) conns->At(conns, j); + for (j = 0; j < conns->numConnections; j++) { + Connection * connection = conns->connections[j]; retVal = connection->EnterInitializationMode(connection); if (RETURN_OK != retVal) { // error message in calling function return RETURN_ERROR; @@ -1035,11 +1033,10 @@ McxStatus ComponentDoOutConnectionsInitialization(Component * comp, int onlyIfDe for (i = 0; i < numOutChannels; i++) { ChannelOut * out = DatabusGetOutChannel(db, i); - ObjectList * conns = out->GetConnections(out); - size_t connSize = conns->Size(conns); + ConnectionList * conns = out->GetConnections(out); - for (j = 0; j < connSize; j++) { - Connection * connection = (Connection *) conns->At(conns, j); + for (j = 0; j < conns->numConnections; j++) { + Connection * connection = conns->connections[j]; if (!onlyIfDecoupled || connection->IsDecoupled(connection)) { McxStatus retVal = connection->UpdateInitialValue(connection); @@ -1063,11 +1060,10 @@ McxStatus ComponentOutConnectionsExitInitMode(Component * comp, double time) { for (i = 0; i < numOutChannels; i++) { ChannelOut * out = DatabusGetOutChannel(db, i); - ObjectList * conns = out->GetConnections(out); - size_t connSize = conns->Size(conns); + ConnectionList * conns = out->GetConnections(out); - for (j = 0; j < connSize; j++) { - Connection * connection = (Connection *) conns->At(conns, j); + for (j = 0; j < conns->numConnections; j++) { + Connection * connection = conns->connections[j]; retVal = connection->ExitInitializationMode(connection, time); if (RETURN_OK != retVal) { // error message in calling function return RETURN_ERROR; diff --git a/src/core/Component.h b/src/core/Component.h index 4893dae..997d330 100644 --- a/src/core/Component.h +++ b/src/core/Component.h @@ -255,7 +255,7 @@ McxStatus ComponentEnterCommunicationPoint(Component * comp, TimeInterval * time McxStatus ComponentEnterCommunicationPointForConnections(Component * comp, ObjectList * connections, TimeInterval * time); Vector * GetInConnectionInfos(const Component * comp, size_t channelID); -struct ObjectContainer * GetInConnections(const Component * comp, size_t channelID); +struct ConnectionList * GetInConnections(const Component * comp, size_t channelID); size_t ComponentGetNumOutGroups(const Component * comp); size_t ComponentGetNumInitialOutGroups(const Component * comp); diff --git a/src/core/Conversion.c b/src/core/Conversion.c index 6ccec92..cb1677d 100644 --- a/src/core/Conversion.c +++ b/src/core/Conversion.c @@ -99,23 +99,22 @@ McxStatus RangeConversionMinValueRefConversion(void * element, size_t idx, Chann ChannelValue * min = (ChannelValue *) ctx; void * minElem = mcx_array_get_elem_reference(&min->value.a, idx); if (RangeConversionElemwiseLeq(element, minElem, type)) { - switch (type->con) - { + switch (type->con) { case CHANNEL_DOUBLE: { double * elem = (double *) element; - *elem = *((double *)minElem); + *elem = *((double *) minElem); break; } - case CHANNEL_INTEGER: + case CHANNEL_INTEGER: { int * elem = (int *) element; - *elem = *((int *)minElem); + *elem = *((int *) minElem); break; } - default: - mcx_log(LOG_ERROR, "RangeConversion: Unsupported type"); - return RETURN_ERROR; + default: + mcx_log(LOG_ERROR, "RangeConversion: Unsupported type"); + return RETURN_ERROR; } } diff --git a/src/core/Databus.c b/src/core/Databus.c index 4385837..7e920e7 100644 --- a/src/core/Databus.c +++ b/src/core/Databus.c @@ -1303,8 +1303,8 @@ McxStatus DatabusCollectModeSwitchData(Databus * db) { // determine cache size for (i = 0; i < size; i++) { ChannelOut * out = db->data->out[i]; - ObjectList * conns = out->GetConnections(out); - db->modeSwitchDataSize += conns->Size(conns); + ConnectionList * conns = out->GetConnections(out); + db->modeSwitchDataSize += conns->numConnections; } // allocate cache @@ -1316,11 +1316,11 @@ McxStatus DatabusCollectModeSwitchData(Databus * db) { // fill up the cache for (i = 0, idx = 0; i < size; i++) { ChannelOut * out = db->data->out[i]; - ObjectList * conns = out->GetConnections(out); - size_t connSize = conns->Size(conns); + ConnectionList * conns = out->GetConnections(out); + size_t connSize = conns->numConnections; for (j = 0; j < connSize; j++, idx++) { - Connection * connection = (Connection*)conns->At(conns, j); + Connection * connection = conns->connections[j]; ConnectionInfo * info = connection->GetInfo(connection); Component * target = info->targetComponent; Component * source = info->sourceComponent; diff --git a/src/core/Model.c b/src/core/Model.c index 12321cb..e89be67 100644 --- a/src/core/Model.c +++ b/src/core/Model.c @@ -447,10 +447,10 @@ static McxStatus ModelInsertAllFilters(Model * model) { for (j = 0; j < numOutChannels; j++) { ChannelOut * out = DatabusGetOutChannel(db, j); - ObjectList * conns = out->GetConnections(out); + ConnectionList * conns = out->GetConnections(out); - for (k = 0; k < conns->Size(conns); k++) { - Connection * connection = (Connection *) conns->At(conns, k); + for (k = 0; k < conns->numConnections; k++) { + Connection * connection = conns->connections[k]; ConnectionInfo * info = connection->GetInfo(connection); if (connection->AddFilter) { char * connStr = ConnectionInfoConnectionString(info); @@ -700,10 +700,10 @@ static Connection * ModelGetConnectionFromInfo(Model * model, ConnectionInfo * i for (j = 0; j < numOutChannels; j++) { ChannelOut * out = DatabusGetOutChannel(db, j); - ObjectList * conns = out->GetConnections(out); + ConnectionList * conns = out->GetConnections(out); - for (k = 0; k < conns->Size(conns); k++) { - Connection * connection = (Connection *) conns->At(conns, k); + for (k = 0; k < conns->numConnections; k++) { + Connection * connection = conns->connections[k]; if (connection->GetInfo(connection) == info) { return connection; } @@ -1263,6 +1263,38 @@ static McxStatus ModelSetup(void * self) { } mcx_log(LOG_DEBUG, " "); + // Set isFullyConnected status on all channels + size_t i = 0; + size_t j = 0; + Component * comp = NULL; + Databus * db = NULL; + size_t inNum = 0; + size_t outNum = 0; + Channel * channel = NULL; + ObjectContainer * comps = model->components; + for (i = 0; i < comps->Size(comps); i++) { + comp = (Component *)comps->At(comps, i); + db = comp->GetDatabus(comp); + inNum = DatabusGetInChannelsNum(db); + for (j = 0; j < inNum; j++) { + channel = (Channel *) DatabusGetInChannel(db, j); + retVal = channel->SetIsFullyConnected(channel); + if (RETURN_OK != retVal) { + mcx_log(LOG_ERROR, "Model: Setting IsFullyConnected state for input %s failed", channel->info.name); + return RETURN_ERROR; + } + } + outNum = DatabusGetOutChannelsNum(db); + for (j = 0; j < outNum; j++) { + channel = (Channel *) DatabusGetOutChannel(db, j); + retVal = channel->SetIsFullyConnected(channel); + if (RETURN_OK != retVal) { + mcx_log(LOG_ERROR, "Model: Setting IsFullyConnected state for output %s failed", channel->info.name); + return RETURN_ERROR; + } + } + } + if (model->config->outputModel) { retVal = ModelPrint(model); if (RETURN_OK != retVal) { diff --git a/src/core/SubModel.c b/src/core/SubModel.c index f55ee35..e2e64d8 100644 --- a/src/core/SubModel.c +++ b/src/core/SubModel.c @@ -716,12 +716,12 @@ static struct Dependencies * SubModelGeneratorCreateDependencyMatrix(SubModelGen if (DEP_INDEPENDENT != dependency) { Vector * infos = GetInConnectionInfos(targetComp, targetInChannelID); - ObjectContainer * conns = GetInConnections(targetComp, targetInChannelID); + ConnectionList * conns = GetInConnections(targetComp, targetInChannelID); size_t i = 0; for (i = 0; i < infos->Size(infos); i++) { ConnectionInfo * info = *(ConnectionInfo**) infos->At(infos, i); - Connection * conn = conns->At(conns, i); + Connection * conn = conns->connections[i]; if (info && (info->decoupleType & (DECOUPLE_NEVER | DECOUPLE_IFNEEDED)) && (!ConnectionInfoIsDecoupled(info)) && conn && conn->IsActiveDependency(conn)) diff --git a/src/core/channels/Channel.c b/src/core/channels/Channel.c index 73f945a..53a0ad4 100644 --- a/src/core/channels/Channel.c +++ b/src/core/channels/Channel.c @@ -96,6 +96,12 @@ static McxStatus ReportConnStringError(ChannelInfo * chInfo, const char * prefix // ---------------------------------------------------------------------- // Channel +static int ChannelIsFullyConnected(Channel * channel) { + if (channel->isFullyConnected_ == INVALID_CONNECTION_STATUS) { + channel->SetIsFullyConnected(channel); + } + return channel->isFullyConnected_ == CHANNEL_FULLY_CONNECTED; +} static int ChannelIsDefinedDuringInit(Channel * channel) { return channel->isDefinedDuringInit; @@ -142,7 +148,8 @@ static Channel * ChannelCreate(Channel * channel) { channel->ProvidesValue = NULL; channel->IsConnected = NULL; - channel->IsFullyConnected = NULL; + channel->isFullyConnected_ = INVALID_CONNECTION_STATUS; + channel->IsFullyConnected = ChannelIsFullyConnected; return channel; } @@ -158,45 +165,49 @@ static void DestroyChannelValueReferencePtr(ChannelValueReference ** ptr) { DestroyChannelValueReference(*ptr); } -static ChannelInData * ChannelInDataCreate(ChannelInData * data) { - data->connections = (ObjectContainer *) object_create(ObjectContainer); - if (!data->connections) { - return NULL; +static McxStatus ChannelInDataInit(ChannelInData * data) { + data->increment = 2; + + data->connList.connections = (Connection * *) mcx_malloc(sizeof(Connection *)); + if (!data->connList.connections) { + mcx_log(LOG_ERROR, "ChannelInDataInit: Allocating space for connections failed"); + return RETURN_ERROR; } + data->connList.capacity = 1; + data->connList.numConnections = 0; - data->valueReferences = (Vector *) object_create(Vector); + data->valueReferences = (ChannelValueReference * *) mcx_malloc(sizeof(ChannelValueReference *)); if (!data->valueReferences) { - return NULL; + mcx_log(LOG_ERROR, "ChannelInDataInit: Allocating space for value references failed"); + return RETURN_ERROR; } - data->valueReferences->Setup(data->valueReferences, sizeof(ChannelValueReference *), NULL, NULL, DestroyChannelValueReferencePtr); - data->reference = NULL; data->type = ChannelTypeClone(&ChannelTypeUnknown); + if (!data->type) { + mcx_log(LOG_ERROR, "ChannelInDataInit: Cloning ChannelType failed"); + return RETURN_ERROR; + } - data->typeConversions = (ObjectContainer *) object_create(ObjectContainer); + data->typeConversions = (TypeConversion * *) mcx_malloc(sizeof(TypeConversion *)); if (!data->typeConversions) { - return NULL; + mcx_log(LOG_ERROR, "ChannelInDataInit: Allocating space for type conversion objects failed"); + return RETURN_ERROR; } - data->unitConversions = (ObjectContainer *) object_create(ObjectContainer); + data->unitConversions = (UnitConversion * *) mcx_malloc(sizeof(UnitConversion *)); if (!data->unitConversions) { - return NULL; + mcx_log(LOG_ERROR, "ChannelInDataInit: Allocating space for unit conversion objects failed"); + return RETURN_ERROR; } data->linearConversion = NULL; data->rangeConversion = NULL; data->isDiscrete = FALSE; - return data; + return RETURN_OK; } static void ChannelInDataDestructor(ChannelInData * data) { - // clean up conversion objects - data->typeConversions->DestroyObjects(data->typeConversions); - object_destroy(data->typeConversions); - - data->unitConversions->DestroyObjects(data->unitConversions); - object_destroy(data->unitConversions); if (data->linearConversion) { object_destroy(data->linearConversion); @@ -208,19 +219,27 @@ static void ChannelInDataDestructor(ChannelInData * data) { ChannelTypeDestructor(data->type); } - if (data->connections) { - object_destroy(data->connections); + if (data->valueReferences) { + mcx_free((void *) data->valueReferences); } - if (data->valueReferences) { - object_destroy(data->valueReferences); + if (data->connList.connections) { + mcx_free((void *) data->connList.connections); + } + if (data->typeConversions) { + for (int j = 0; j < data->connList.numConnections; j++) { + object_destroy(data->typeConversions[j]); + } + mcx_free((void *) data->typeConversions); + } + if (data->unitConversions) { + for (int j = 0; j < data->connList.numConnections; j++) { + object_destroy(data->unitConversions[j]); + } + mcx_free((void *) data->unitConversions); } } -OBJECT_CLASS(ChannelInData, Object); - - - static McxStatus ChannelInSetReference(ChannelIn * in, void * reference, ChannelType * type) { Channel * ch = (Channel *) in; ChannelInfo * info = &ch->info; @@ -229,7 +248,7 @@ static McxStatus ChannelInSetReference(ChannelIn * in, void * reference, Channel mcx_log(LOG_ERROR, "Port: Set inport reference: Invalid port"); return RETURN_ERROR; } - if (in->data->reference) { + if (in->data.reference) { mcx_log(LOG_ERROR, "Port %s: Set inport reference: Reference already set", ChannelInfoGetLogName(info)); return RETURN_ERROR; } @@ -249,8 +268,8 @@ static McxStatus ChannelInSetReference(ChannelIn * in, void * reference, Channel } } - in->data->reference = reference; - in->data->type = ChannelTypeClone(type); + in->data.reference = reference; + in->data.type = ChannelTypeClone(type); return RETURN_OK; } @@ -282,13 +301,13 @@ static McxStatus ChannelInUpdate(Channel * channel, TimeInterval * time) { /* if no connection is present we have nothing to update*/ size_t i = 0; - size_t numConns = in->data->connections->Size(in->data->connections); + size_t numConns = in->data.connList.numConnections; for (i = 0; i < numConns; i++) { - Connection * conn = (Connection *) in->data->connections->At(in->data->connections, i); + Connection * conn = (Connection *) in->data.connList.connections[i]; ConnectionInfo * connInfo = &conn->info; - TypeConversion * typeConv = (TypeConversion *) in->data->typeConversions->At(in->data->typeConversions, i); - UnitConversion * unitConv = (UnitConversion *) in->data->unitConversions->At(in->data->unitConversions, i); - ChannelValueReference * valueRef = *(ChannelValueReference **) in->data->valueReferences->At(in->data->valueReferences, i); + TypeConversion * typeConv = in->data.typeConversions[i]; + UnitConversion * unitConv = in->data.unitConversions[i]; + ChannelValueReference * valueRef = in->data.valueReferences[i]; /* Update the connection for the current time */ if (RETURN_OK != conn->UpdateToOutput(conn, time)) { @@ -315,8 +334,8 @@ static McxStatus ChannelInUpdate(Channel * channel, TimeInterval * time) { ChannelValue * val = &channel->value; // linear - if (in->data->linearConversion) { - Conversion * conversion = (Conversion *) in->data->linearConversion; + if (in->data.linearConversion) { + Conversion * conversion = (Conversion *) in->data.linearConversion; retVal = conversion->convert(conversion, val); if (RETURN_OK != retVal) { mcx_log(LOG_ERROR, "Port %s: Update inport: Could not execute linear conversion", ChannelInfoGetLogName(info)); @@ -325,8 +344,8 @@ static McxStatus ChannelInUpdate(Channel * channel, TimeInterval * time) { } // range - if (in->data->rangeConversion) { - Conversion * conversion = (Conversion *) in->data->rangeConversion; + if (in->data.rangeConversion) { + Conversion * conversion = (Conversion *) in->data.rangeConversion; retVal = conversion->convert(conversion, val); if (RETURN_OK != retVal) { mcx_log(LOG_ERROR, "Port %s: Update inport: Could not execute range conversion", ChannelInfoGetLogName(info)); @@ -336,43 +355,43 @@ static McxStatus ChannelInUpdate(Channel * channel, TimeInterval * time) { } /* no reference from the component was set, skip updating*/ - if (!in->data->reference || !channel->GetValueReference(channel)) { + if (!in->data.reference || !channel->GetValueReference(channel)) { return RETURN_OK; } +#ifdef MCX_DEBUG if (time->startTime < MCX_DEBUG_LOG_TIME && ChannelTypeEq(info->type, &ChannelTypeDouble)) { MCX_DEBUG_LOG("[%f] CH IN (%s) (%f, %f)", time->startTime, ChannelInfoGetLogName(info), time->startTime, * (double *) channel->GetValueReference(channel)); } +#endif // MCX_DEBUG - if (RETURN_OK != ChannelValueDataSetFromReference(in->data->reference, in->data->type, channel->GetValueReference(channel))) { + if (RETURN_OK != ChannelValueDataSetFromReference(in->data.reference, in->data.type, channel->GetValueReference(channel))) { return RETURN_ERROR; } return RETURN_OK; } -static int ChannelInIsFullyConnected(Channel * channel) { +static McxStatus ChannelInSetIsFullyConnected(Channel * channel) { ChannelIn * in = (ChannelIn *) channel; size_t i = 0; size_t connectedElems = 0; size_t channelNumElems = channel->info.dimension ? ChannelDimensionNumElements(channel->info.dimension) : 1; - for (i = 0; i < in->data->connections->Size(in->data->connections); i++) { - Connection * conn = (Connection *) in->data->connections->At(in->data->connections, i); + for (i = 0; i < in->data.connList.numConnections; i++) { + Connection * conn = (Connection *) in->data.connList.connections[i]; ConnectionInfo * info = &conn->info; connectedElems += info->targetDimension ? ChannelDimensionNumElements(info->targetDimension) : 1; } - if (connectedElems == channelNumElems) { - return TRUE; - } + channel->isFullyConnected_ = connectedElems == channelNumElems; - return FALSE; + return RETURN_OK; } static int ChannelInProvidesValue(Channel * channel) { - if (ChannelInIsFullyConnected(channel)) { + if (channel->IsFullyConnected(channel)) { return TRUE; } else { ChannelInfo * info = &channel->info; @@ -384,11 +403,11 @@ static int ChannelInProvidesValue(Channel * channel) { } static void ChannelInSetDiscrete(ChannelIn * in) { - in->data->isDiscrete = TRUE; + in->data.isDiscrete = TRUE; } static int ChannelInIsDiscrete(ChannelIn * in) { - return in->data->isDiscrete; + return in->data.isDiscrete; } static int ChannelInIsConnected(Channel * channel) { @@ -396,7 +415,7 @@ static int ChannelInIsConnected(Channel * channel) { return TRUE; } else { ChannelIn * in = (ChannelIn *) channel; - if (in->data->connections->Size(in->data->connections) > 0) { + if (in->data.connList.numConnections > 0) { return TRUE; } } @@ -406,7 +425,7 @@ static int ChannelInIsConnected(Channel * channel) { static Vector * ChannelInGetConnectionInfos(ChannelIn * in) { Vector * infos = (Vector*) object_create(Vector); - size_t numConns = in->data->connections->Size(in->data->connections); + size_t numConns = in->data.connList.numConnections; size_t i = 0; if (!infos) { @@ -416,7 +435,7 @@ static Vector * ChannelInGetConnectionInfos(ChannelIn * in) { infos->Setup(infos, sizeof(ConnectionInfo*), NULL, NULL, NULL); for (i = 0; i < numConns; i++) { - Connection * conn = in->data->connections->At(in->data->connections, i); + Connection * conn = in->data.connList.connections[i]; ConnectionInfo * connInfo = &conn->info; if (RETURN_ERROR == infos->PushBack(infos, &connInfo)) { object_destroy(infos); @@ -427,8 +446,8 @@ static Vector * ChannelInGetConnectionInfos(ChannelIn * in) { return infos; } -static ObjectContainer * ChannelInGetConnections(ChannelIn * in) { - return in->data->connections; +static ConnectionList * ChannelInGetConnections(ChannelIn * in) { + return &in->data.connList; } static McxStatus ChannelInRegisterConnection(ChannelIn * in, Connection * connection, const char * unit, ChannelType * type) { @@ -436,13 +455,23 @@ static McxStatus ChannelInRegisterConnection(ChannelIn * in, Connection * connec Channel * channel = (Channel *) in; ChannelInfo * inInfo = &channel->info; ChannelValueReference * valRef = NULL; + ConnectionList * connList = &in->data.connList; McxStatus retVal = RETURN_OK; - retVal = in->data->connections->PushBack(in->data->connections, (Object *) connection); - if (RETURN_OK != retVal) { - return ReportConnStringError(inInfo, "Register inport connection %s: ", connInfo, "Could not register connection"); + while (connList->capacity <= connList->numConnections) { + connList->capacity *= in->data.increment; + connList->connections = mcx_realloc(connList->connections, sizeof(Connection *) * connList->capacity); + in->data.typeConversions = mcx_realloc(in->data.typeConversions, sizeof(TypeConversion *) * connList->capacity); + in->data.unitConversions = mcx_realloc(in->data.unitConversions, sizeof(UnitConversion *) * connList->capacity); + in->data.valueReferences = mcx_realloc(in->data.valueReferences, sizeof(ChannelValueReference *) * connList->capacity); + if (!connList->connections || !in->data.typeConversions || !in->data.unitConversions || !in->data.valueReferences) { + mcx_log(LOG_ERROR, "ChannelInRegisterConnection: (Re-)Allocation of connection related data failed"); + return RETURN_ERROR; + } } + connList->connections[connList->numConnections] = connection; + connList->numConnections++; ChannelDimension * dimension = connInfo->targetDimension; if (dimension && !ChannelDimensionEq(dimension, inInfo->dimension)) { @@ -459,11 +488,7 @@ static McxStatus ChannelInRegisterConnection(ChannelIn * in, Connection * connec valRef = MakeChannelValueReference(&channel->value, NULL); } - retVal = in->data->valueReferences->PushBack(in->data->valueReferences, &valRef); - if (RETURN_ERROR == retVal) { - ReportConnStringError(inInfo, "Register inport connection %s: ", connInfo, "Storing value reference failed"); - return RETURN_ERROR; - } + in->data.valueReferences[connList->numConnections - 1] = valRef; if (ChannelTypeEq(ChannelTypeBaseType(inInfo->type), &ChannelTypeDouble)) { UnitConversion * conversion = (UnitConversion *) object_create(UnitConversion); @@ -477,15 +502,9 @@ static McxStatus ChannelInRegisterConnection(ChannelIn * in, Connection * connec object_destroy(conversion); } - retVal = in->data->unitConversions->PushBack(in->data->unitConversions, (Object *) conversion); - if (RETURN_ERROR == retVal) { - return ReportConnStringError(inInfo, "Register inport connection %s: ", connInfo, "Could not add unit conversion"); - } + in->data.unitConversions[connList->numConnections - 1] = conversion; } else { - retVal = in->data->unitConversions->PushBack(in->data->unitConversions, NULL); - if (RETURN_ERROR == retVal) { - return ReportConnStringError(inInfo, "Register inport connection %s: ", connInfo, "Could not add empty unit conversion"); - } + in->data.unitConversions[connList->numConnections - 1] = NULL; } // setup type conversion @@ -500,15 +519,9 @@ static McxStatus ChannelInRegisterConnection(ChannelIn * in, Connection * connec return ReportConnStringError(inInfo, "Register inport connection %s: ", connInfo, "Could not set up type conversion"); } - retVal = in->data->typeConversions->PushBack(in->data->typeConversions, (Object *) typeConv); - if (RETURN_ERROR == retVal) { - return ReportConnStringError(inInfo, "Register inport connection %s: ", connInfo, "Could not add type conversion"); - } + in->data.typeConversions[connList->numConnections - 1] = typeConv; } else { - retVal = in->data->typeConversions->PushBack(in->data->typeConversions, NULL); - if (RETURN_ERROR == retVal) { - return ReportConnStringError(inInfo, "Register inport connection %s: ", connInfo, "Could not add empty type conversion"); - } + in->data.typeConversions[connList->numConnections - 1] = NULL; } return retVal; @@ -557,27 +570,27 @@ static McxStatus ChannelInSetup(ChannelIn * in, ChannelInfo * info) { ChannelValue * scale = info->scale; ChannelValue * offset = info->offset; - in->data->rangeConversion = (RangeConversion *) object_create(RangeConversion); - retVal = in->data->rangeConversion->Setup(in->data->rangeConversion, min, max); + in->data.rangeConversion = (RangeConversion *) object_create(RangeConversion); + retVal = in->data.rangeConversion->Setup(in->data.rangeConversion, min, max); if (RETURN_ERROR == retVal) { mcx_log(LOG_ERROR, "Port %s: Setup inport: Could not setup range conversion", ChannelInfoGetLogName(info)); - object_destroy(in->data->rangeConversion); + object_destroy(in->data.rangeConversion); return RETURN_ERROR; } else { - if (in->data->rangeConversion->IsEmpty(in->data->rangeConversion)) { - object_destroy(in->data->rangeConversion); + if (in->data.rangeConversion->IsEmpty(in->data.rangeConversion)) { + object_destroy(in->data.rangeConversion); } } - in->data->linearConversion = (LinearConversion *) object_create(LinearConversion); - retVal = in->data->linearConversion->Setup(in->data->linearConversion, scale, offset); + in->data.linearConversion = (LinearConversion *) object_create(LinearConversion); + retVal = in->data.linearConversion->Setup(in->data.linearConversion, scale, offset); if (RETURN_ERROR == retVal) { mcx_log(LOG_ERROR, "Port %s: Setup inport: Could not setup linear conversion", ChannelInfoGetLogName(info)); - object_destroy(in->data->linearConversion); + object_destroy(in->data.linearConversion); return RETURN_ERROR; } else { - if (in->data->linearConversion->IsEmpty(in->data->linearConversion)) { - object_destroy(in->data->linearConversion); + if (in->data.linearConversion->IsEmpty(in->data.linearConversion)) { + object_destroy(in->data.linearConversion); } } } @@ -586,14 +599,16 @@ static McxStatus ChannelInSetup(ChannelIn * in, ChannelInfo * info) { } static void ChannelInDestructor(ChannelIn * in) { - object_destroy(in->data); + ChannelInDataDestructor(&in->data); } static ChannelIn * ChannelInCreate(ChannelIn * in) { Channel * channel = (Channel *) in; + McxStatus retVal = RETURN_OK; - in->data = (ChannelInData *) object_create(ChannelInData); - if (!in->data) { + retVal = ChannelInDataInit(&in->data); + if (RETURN_OK != retVal) { + mcx_log(LOG_ERROR, "ChannelInCreate: ChannelInDataInit failed"); return NULL; } @@ -602,7 +617,7 @@ static ChannelIn * ChannelInCreate(ChannelIn * in) { channel->ProvidesValue = ChannelInProvidesValue; channel->Update = ChannelInUpdate; channel->IsConnected = ChannelInIsConnected; - channel->IsFullyConnected = ChannelInIsFullyConnected; + channel->SetIsFullyConnected = ChannelInSetIsFullyConnected; in->Setup = ChannelInSetup; in->SetReference = ChannelInSetReference; @@ -622,7 +637,7 @@ static ChannelIn * ChannelInCreate(ChannelIn * in) { // ---------------------------------------------------------------------- // ChannelOut -static ChannelOutData * ChannelOutDataCreate(ChannelOutData * data) { +static McxStatus ChannelOutDataInit(ChannelOutData * data) { data->valueFunction = NULL; ChannelValueInit(&data->valueFunctionRes, ChannelTypeClone(&ChannelTypeUnknown)); data->rangeConversion = NULL; @@ -630,7 +645,15 @@ static ChannelOutData * ChannelOutDataCreate(ChannelOutData * data) { data->rangeConversionIsActive = TRUE; - data->connections = (ObjectList *) object_create(ObjectList); + data->increment = 2; + + data->connList.numConnections = 0; + data->connList.capacity = 1; + data->connList.connections = (Connection * *) mcx_malloc(sizeof(Connection *)); + if (!data->connList.connections) { + mcx_log(LOG_ERROR, "ChannelOutDataInit: Allocation of connections failed"); + return RETURN_ERROR; + } data->nanCheck = NAN_CHECK_ALWAYS; @@ -638,11 +661,10 @@ static ChannelOutData * ChannelOutDataCreate(ChannelOutData * data) { data->maxNumNaNCheckWarning = 0; - return data; + return RETURN_OK; } static void ChannelOutDataDestructor(ChannelOutData * data) { - ObjectList * conns = data->connections; size_t i = 0; if (data->rangeConversion) { @@ -652,18 +674,18 @@ static void ChannelOutDataDestructor(ChannelOutData * data) { object_destroy(data->linearConversion); } - for (i = 0; i < conns->Size(conns); i++) { - object_destroy(conns->elements[i]); + if (data->connList.connections) { + for (i = 0; i < data->connList.numConnections; i++) { + if (data->connList.connections[i]) { + object_destroy(data->connList.connections[i]); + } + } + mcx_free(data->connList.connections); } - object_destroy(data->connections); ChannelValueDestructor(&data->valueFunctionRes); } -OBJECT_CLASS(ChannelOutData, Object); - - - static McxStatus ChannelOutSetup(ChannelOut * out, ChannelInfo * info, Config * config) { Channel * channel = (Channel *) out; @@ -694,27 +716,27 @@ static McxStatus ChannelOutSetup(ChannelOut * out, ChannelInfo * info, Config * if (ChannelTypeEq(ChannelTypeBaseType(info->type), &ChannelTypeDouble) || ChannelTypeEq(ChannelTypeBaseType(info->type), &ChannelTypeInteger)) { - out->data->rangeConversion = (RangeConversion *) object_create(RangeConversion); - retVal = out->data->rangeConversion->Setup(out->data->rangeConversion, min, max); + out->data.rangeConversion = (RangeConversion *) object_create(RangeConversion); + retVal = out->data.rangeConversion->Setup(out->data.rangeConversion, min, max); if (RETURN_ERROR == retVal) { mcx_log(LOG_ERROR, "Port %s: Setup outport: Could not setup range conversion", ChannelInfoGetLogName(info)); - object_destroy(out->data->rangeConversion); + object_destroy(out->data.rangeConversion); return RETURN_ERROR; } else { - if (out->data->rangeConversion->IsEmpty(out->data->rangeConversion)) { - object_destroy(out->data->rangeConversion); + if (out->data.rangeConversion->IsEmpty(out->data.rangeConversion)) { + object_destroy(out->data.rangeConversion); } } - out->data->linearConversion = (LinearConversion *) object_create(LinearConversion); - retVal = out->data->linearConversion->Setup(out->data->linearConversion, scale, offset); + out->data.linearConversion = (LinearConversion *) object_create(LinearConversion); + retVal = out->data.linearConversion->Setup(out->data.linearConversion, scale, offset); if (RETURN_ERROR == retVal) { mcx_log(LOG_ERROR, "Port %s: Setup outport: Could not setup linear conversion", ChannelInfoGetLogName(info)); - object_destroy(out->data->linearConversion); + object_destroy(out->data.linearConversion); return RETURN_ERROR; } else { - if (out->data->linearConversion->IsEmpty(out->data->linearConversion)) { - object_destroy(out->data->linearConversion); + if (out->data.linearConversion->IsEmpty(out->data.linearConversion)) { + object_destroy(out->data.linearConversion); } } } @@ -724,21 +746,31 @@ static McxStatus ChannelOutSetup(ChannelOut * out, ChannelInfo * info, Config * return RETURN_ERROR; } - out->data->nanCheck = config->nanCheck; - out->data->maxNumNaNCheckWarning = config->nanCheckNumMessages; + out->data.nanCheck = config->nanCheck; + out->data.maxNumNaNCheckWarning = config->nanCheckNumMessages; return RETURN_OK; } static McxStatus ChannelOutRegisterConnection(ChannelOut * out, Connection * connection) { - ObjectList * conns = out->data->connections; - ChannelDimension * outDim = ((Channel*)out)->info.dimension; - ChannelDimension * connDim = connection->info.sourceDimension; + ChannelInfo * outInfo = &((Channel *) out)->info; + ConnectionInfo * connInfo = &connection->info; + ConnectionList * connList = &out->data.connList; // TODO: do we have to check that channelout and connection match // in type/dimension? - return conns->PushBack(conns, (Object *) connection); + while (connList->capacity <= connList->numConnections) { + connList->capacity *= out->data.increment; + connList->connections = mcx_realloc(connList->connections, connList->capacity * sizeof(Connection *)); + if (!connList->connections) { + return ReportConnStringError(outInfo, "Register outport connection %s: ", connInfo, "Could not set up connections (realloc failed)"); + } + } + connList->connections[connList->numConnections] = connection; + connList->numConnections++; + + return RETURN_OK; } static const void * ChannelOutGetValueReference(Channel * channel) { @@ -755,11 +787,11 @@ static const void * ChannelOutGetValueReference(Channel * channel) { } static const proc * ChannelOutGetFunction(ChannelOut * out) { - return out->data->valueFunction; + return out->data.valueFunction; } -static ObjectList * ChannelOutGetConnections(ChannelOut * out) { - return out->data->connections; +static ConnectionList * ChannelOutGetConnections(ChannelOut * out) { + return &out->data.connList; } static int ChannelOutProvidesValue(Channel * channel) { @@ -771,51 +803,50 @@ static int ChannelOutIsConnected(Channel * channel) { return TRUE; } else { ChannelOut * out = (ChannelOut *) channel; - if (NULL != out->data->connections) { - if (out->data->connections->Size(out->data->connections)) { - return TRUE; - } + if (out->data.connList.numConnections) { + return TRUE; } } return FALSE; } -static int ChannelOutIsFullyConnected(Channel * channel) { +static McxStatus ChannelOutSetIsFullyConnected(Channel * channel) { ChannelOut * out = (ChannelOut *) channel; - if (ChannelTypeIsArray(&channel->info.type)) { - ObjectList* conns = out->data->connections; + if (ChannelTypeIsArray(channel->info.type)) { + ConnectionList * conns = &out->data.connList; size_t i = 0; size_t num_elems = ChannelDimensionNumElements(channel->info.dimension); int * connected = (int *) mcx_calloc(num_elems, sizeof(int)); if (!connected) { mcx_log(LOG_ERROR, "ChannelOutIsFullyConnected: Not enough memory"); - return -1; + return RETURN_ERROR; } - for (i = 0; i < conns->Size(conns); i++) { - Connection * conn = (Connection *) out->data->connections->At(out->data->connections, i); + for (i = 0; i < conns->numConnections; i++) { + Connection * conn = out->data.connList.connections[i]; ConnectionInfo * info = &conn->info; size_t j = 0; - for (j = 0; j < ChannelDimensionNumElements(info->sourceDimension); i++) { + for (j = 0; j < ChannelDimensionNumElements(info->sourceDimension); j++) { size_t idx = ChannelDimensionGetIndex(info->sourceDimension, j, channel->info.type->ty.a.dims); - connected[idx] = 1; + connected[idx - info->sourceDimension->startIdxs[0]] = 1; } } + channel->isFullyConnected_ = CHANNEL_FULLY_CONNECTED; for (i = 0; i < num_elems; i++) { if (!connected[i]) { - return FALSE; + channel->isFullyConnected_ = CHANNEL_ONLY_PARTIALLY_CONNETED; } } - - return TRUE; } else { - return ChannelOutIsConnected(channel); + channel->isFullyConnected_ = ChannelOutIsConnected(channel); } + + return RETURN_OK; } static McxStatus ChannelOutSetReference(ChannelOut * out, const void * reference, ChannelType * type) { @@ -868,16 +899,16 @@ static McxStatus ChannelOutSetReferenceFunction(ChannelOut * out, const proc * r } } - if (out->data->valueFunction) { + if (out->data.valueFunction) { mcx_log(LOG_ERROR, "Port %s: Set outport function: Reference already set", ChannelInfoGetLogName(info)); return RETURN_ERROR; } // Save channel procedure - out->data->valueFunction = (const proc *) reference; + out->data.valueFunction = (const proc *) reference; // Initialize (and allocate necessary memory) - ChannelValueInit(&out->data->valueFunctionRes, ChannelTypeClone(type)); + ChannelValueInit(&out->data.valueFunctionRes, ChannelTypeClone(type)); // Setup value reference to point to internal value channel->internalValue = ChannelValueDataPointer(&channel->value); @@ -905,7 +936,9 @@ static McxStatus ChannelOutUpdate(Channel * channel, TimeInterval * time) { ChannelOut * out = (ChannelOut *)channel; ChannelInfo * info = &channel->info; - ObjectList * conns = out->data->connections; + ConnectionList * conns = &out->data.connList; + + ChannelValue * val = NULL; McxStatus retVal = RETURN_OK; @@ -917,7 +950,7 @@ static McxStatus ChannelOutUpdate(Channel * channel, TimeInterval * time) { if (out->GetFunction(out)) { // function value proc * p = (proc *) out->GetFunction(out); - if (p->fn(time, p->env, &out->data->valueFunctionRes) != 0) { + if (RETURN_ERROR == p->fn(time, p->env, &out->data.valueFunctionRes)) { mcx_log(LOG_ERROR, "Port %s: Update outport: Function failed", ChannelInfoGetLogName(info)); return RETURN_ERROR; } @@ -927,10 +960,10 @@ static McxStatus ChannelOutUpdate(Channel * channel, TimeInterval * time) { time->startTime, ChannelInfoGetLogName(info), time->startTime, - out->data->valueFunctionRes.value.d); + out->data.valueFunctionRes.value.d); } #endif // MCX_DEBUG - if (RETURN_OK != ChannelValueSetFromReference(&channel->value, ChannelValueDataPointer(&out->data->valueFunctionRes))) { + if (RETURN_OK != ChannelValueSetFromReference(&channel->value, ChannelValueDataPointer(&out->data.valueFunctionRes))) { return RETURN_ERROR; } } else { @@ -953,39 +986,34 @@ static McxStatus ChannelOutUpdate(Channel * channel, TimeInterval * time) { } } - // Apply conversion - if (ChannelTypeEq(ChannelTypeBaseType(info->type), &ChannelTypeDouble) || - ChannelTypeEq(ChannelTypeBaseType(info->type), &ChannelTypeInteger)) { - ChannelValue * val = &channel->value; - - // range - if (out->data->rangeConversion) { - if (out->data->rangeConversionIsActive) { - Conversion * conversion = (Conversion *) out->data->rangeConversion; - retVal = conversion->convert(conversion, val); - if (RETURN_OK != retVal) { - mcx_log(LOG_ERROR, "Port %s: Update outport: Could not execute range conversion", ChannelInfoGetLogName(info)); - return RETURN_ERROR; - } - } - } + val = &channel->value; - // linear - if (out->data->linearConversion) { - Conversion * conversion = (Conversion *) out->data->linearConversion; + // range conversion + if (out->data.rangeConversion) { + if (out->data.rangeConversionIsActive) { + Conversion * conversion = (Conversion *) out->data.rangeConversion; retVal = conversion->convert(conversion, val); if (RETURN_OK != retVal) { - mcx_log(LOG_ERROR, "Port %s: Update outport: Could not execute linear conversion", ChannelInfoGetLogName(info)); + mcx_log(LOG_ERROR, "Port %s: Update outport: Could not execute range conversion", ChannelInfoGetLogName(info)); return RETURN_ERROR; } } } + // linear conversion + if (out->data.linearConversion) { + Conversion * conversion = (Conversion *) out->data.linearConversion; + retVal = conversion->convert(conversion, val); + if (RETURN_OK != retVal) { + mcx_log(LOG_ERROR, "Port %s: Update outport: Could not execute linear conversion", ChannelInfoGetLogName(info)); + return RETURN_ERROR; + } + } + // Notify connections of new values - size_t connSize = conns->Size(conns); - for (j = 0; j < connSize; j++) { - Connection * connection = (Connection *) conns->At(conns, j); - channel->SetDefinedDuringInit(channel); + channel->SetDefinedDuringInit(channel); + for (j = 0; j < conns->numConnections; j++) { + Connection * connection = conns->connections[j]; connection->UpdateFromInput(connection, time); } } @@ -1000,7 +1028,7 @@ static McxStatus ChannelOutUpdate(Channel * channel, TimeInterval * time) { if (isnan(*val)) { - switch (out->data->nanCheck) { + switch (out->data.nanCheck) { case NAN_CHECK_ALWAYS: mcx_log(LOG_ERROR, "Outport %s at time %f is not a number (NaN)", @@ -1008,18 +1036,18 @@ static McxStatus ChannelOutUpdate(Channel * channel, TimeInterval * time) { return RETURN_ERROR; case NAN_CHECK_CONNECTED: - if (conns->Size(conns) > 0) { + if (conns->numConnections > 0) { mcx_log(LOG_ERROR, "Outport %s at time %f is not a number (NaN)", ChannelInfoGetName(info), time->startTime); return RETURN_ERROR; } else { - WarnAboutNaN(LOG_WARNING, info, time, &out->data->countNaNCheckWarning, &out->data->maxNumNaNCheckWarning); + WarnAboutNaN(LOG_WARNING, info, time, &out->data.countNaNCheckWarning, &out->data.maxNumNaNCheckWarning); break; } case NAN_CHECK_NEVER: - WarnAboutNaN((conns->Size(conns) > 0) ? LOG_ERROR : LOG_WARNING, - info, time, &out->data->countNaNCheckWarning, &out->data->maxNumNaNCheckWarning); + WarnAboutNaN((conns->numConnections > 0) ? LOG_ERROR : LOG_WARNING, + info, time, &out->data.countNaNCheckWarning, &out->data.maxNumNaNCheckWarning); break; } } @@ -1030,14 +1058,16 @@ static McxStatus ChannelOutUpdate(Channel * channel, TimeInterval * time) { } static void ChannelOutDestructor(ChannelOut * out) { - object_destroy(out->data); + ChannelOutDataDestructor(&out->data); } static ChannelOut * ChannelOutCreate(ChannelOut * out) { Channel * channel = (Channel *) out; + McxStatus retVal = RETURN_OK; - out->data = (ChannelOutData *) object_create(ChannelOutData); - if (!out->data) { + retVal = ChannelOutDataInit(&out->data); + if (RETURN_OK != retVal) { + mcx_log(LOG_ERROR, "ChannelOutCreate: ChannelOutDataInit failed"); return NULL; } @@ -1046,7 +1076,7 @@ static ChannelOut * ChannelOutCreate(ChannelOut * out) { channel->ProvidesValue = ChannelOutProvidesValue; channel->Update = ChannelOutUpdate; channel->IsConnected = ChannelOutIsConnected; - channel->IsFullyConnected = ChannelOutIsFullyConnected; + channel->SetIsFullyConnected = ChannelOutSetIsFullyConnected; out->Setup = ChannelOutSetup; out->RegisterConnection = ChannelOutRegisterConnection; diff --git a/src/core/channels/Channel.h b/src/core/channels/Channel.h index 52d45d3..7b53d95 100644 --- a/src/core/channels/Channel.h +++ b/src/core/channels/Channel.h @@ -13,6 +13,11 @@ #include "CentralParts.h" #include "core/channels/ChannelInfo.h" +#include "core/channels/ChannelValueReference.h" +#include "objects/ObjectContainer.h" +#include "objects/Vector.h" +#include "core/connections/Connection.h" +#include "core/Conversion.h" #ifdef __cplusplus extern "C" { @@ -21,8 +26,6 @@ extern "C" { struct Config; struct Component; -struct ChannelInData; -struct ChannelOutData; struct Connection; @@ -39,6 +42,8 @@ typedef int (* fChannelIsConnected)(Channel * channel); typedef int (* fChannelIsFullyConnected)(Channel * channel); +typedef McxStatus (* fChannelSetIsFullyConnected)(Channel * channel); + typedef int (* fChannelIsDefinedDuringInit)(Channel * channel); typedef void (* fChannelSetDefinedDuringInit)(Channel * channel); @@ -96,6 +101,11 @@ struct Channel { */ fChannelIsFullyConnected IsFullyConnected; + /** + * Set the isFullyConnected member to reflect whether all elements of the channel are connected + */ + fChannelSetIsFullyConnected SetIsFullyConnected; + /** * Getter for the flag data->isDefinedDuringInit */ @@ -109,6 +119,16 @@ struct Channel { * Initialize channel with info struct. */ fChannelSetup Setup; + + /** + * Flag storing whether channel is fully connected + * Do not use this directly, but via the member function `IsFullyConnected` + */ + enum { + INVALID_CONNECTION_STATUS = -1, + CHANNEL_ONLY_PARTIALLY_CONNETED = 0, + CHANNEL_FULLY_CONNECTED = 1 + } isFullyConnected_; }; // ---------------------------------------------------------------------- @@ -116,6 +136,38 @@ struct Channel { typedef struct ChannelIn ChannelIn; +typedef struct ConnectionList { + Connection * * connections; // connections (non-overlapping) going into the channel + size_t numConnections; + size_t capacity; +} ConnectionList; + +// object that is stored in target component that stores the channel connection +typedef struct ChannelInData { + + ConnectionList connList; + size_t increment; + + // references to non-overlapping parts of ChannelData::value, where + // values gotten from connections are going to be stored + ChannelValueReference * * valueReferences; + + // ---------------------------------------------------------------------- + // Conversions + struct LinearConversion * linearConversion; + struct RangeConversion * rangeConversion; + TypeConversion * * typeConversions; // conversion objects (or NULL) for each connection in `connections` + UnitConversion * * unitConversions; // conversion objects (or NULL) for each connection in `connections` + + // ---------------------------------------------------------------------- + // Storage in Component + + int isDiscrete; + + void * reference; + ChannelType * type; +} ChannelInData; + typedef McxStatus (* fChannelInSetup)(ChannelIn * in, struct ChannelInfo * info); typedef McxStatus (* fChannelInSetReference) (ChannelIn * in, @@ -124,7 +176,7 @@ typedef McxStatus (* fChannelInSetReference) (ChannelIn * in, typedef struct Vector * (* fChannelInGetConnectionInfos)(ChannelIn * in); -typedef struct ObjectContainer * (* fChannelInGetConnections)(ChannelIn * in); +typedef ConnectionList * (* fChannelInGetConnections)(ChannelIn * in); typedef McxStatus (*fChannelInRegisterConnection)(ChannelIn * in, struct Connection * connection, const char * unit, ChannelType * type); @@ -174,7 +226,7 @@ struct ChannelIn { */ fChannelInSetDiscrete SetDiscrete; - struct ChannelInData * data; + ChannelInData data; }; @@ -182,6 +234,40 @@ struct ChannelIn { // ChannelOut typedef struct ChannelOut ChannelOut; +// object that is provided to consumer of output channel +typedef struct ChannelOutData { + + // Function pointer that provides the value of the channel when called + const proc * valueFunction; + + // Used to store results of channel-internal valueFunction calls + ChannelValue valueFunctionRes; + + // ---------------------------------------------------------------------- + // Conversion + + struct RangeConversion * rangeConversion; + struct LinearConversion * linearConversion; + + int rangeConversionIsActive; + + // ---------------------------------------------------------------------- + // NaN Handling + + NaNCheckLevel nanCheck; + + size_t countNaNCheckWarning; + size_t maxNumNaNCheckWarning; + + // ---------------------------------------------------------------------- + // Connections to Consumers + + // A list of all input channels that are connected to this output channel + ConnectionList connList; + size_t increment; + +} ChannelOutData; + typedef McxStatus (* fChannelOutSetup)(ChannelOut * out, struct ChannelInfo * info, struct Config * config); @@ -198,7 +284,7 @@ typedef McxStatus (* fChannelOutRegisterConnection)(struct ChannelOut * out, typedef const proc * (* fChannelOutGetFunction)(ChannelOut * out); -typedef ObjectList * (* fChannelOutGetConnections)(ChannelOut * out); +typedef ConnectionList * (* fChannelOutGetConnections)(ChannelOut * out); extern const struct ObjectClass _ChannelOut; @@ -245,7 +331,7 @@ struct ChannelOut { */ fChannelOutGetConnections GetConnections; - struct ChannelOutData * data; + ChannelOutData data; }; // ---------------------------------------------------------------------- diff --git a/src/core/channels/ChannelDimension.c b/src/core/channels/ChannelDimension.c index 03ef23e..9596e61 100644 --- a/src/core/channels/ChannelDimension.c +++ b/src/core/channels/ChannelDimension.c @@ -243,7 +243,7 @@ size_t ChannelDimensionGetSliceIndex(const ChannelDimension * dimension, size_t size_t dim_1_slice_size = dimension->endIdxs[1] - dimension->startIdxs[1] + 1; - return slice_idx_0 * dim_1_slice_size * slice_idx_1; + return slice_idx_0 * dim_1_slice_size + slice_idx_1; } default: mcx_log(LOG_ERROR, "ChannelDimensionGetSliceIndex: Number of dimensions not supported (%zu)", dimension->num); diff --git a/src/core/channels/ChannelValue.c b/src/core/channels/ChannelValue.c index 1e33f03..9386b73 100644 --- a/src/core/channels/ChannelValue.c +++ b/src/core/channels/ChannelValue.c @@ -117,7 +117,7 @@ ChannelType * ChannelTypeArray(ChannelType * inner, size_t numDims, size_t * dim return array; } -ChannelType * ChannelTypeArrayLongDims(ChannelType * inner, size_t numDims, unsigned long * dims) { +ChannelType * ChannelTypeArrayUInt64Dims(ChannelType * inner, size_t numDims, uint64_t * dims) { ChannelType * array = NULL; size_t i = 0; @@ -205,6 +205,7 @@ int ChannelTypeConformable(ChannelType * a, ChannelDimension * sliceA, ChannelTy } } else { if (sliceA || sliceB) { + mcx_log(LOG_ERROR, "ChannelTypeConformable: Slice dimensions defined for non-array channels"); return 0; } @@ -224,7 +225,6 @@ int ChannelTypeEq(const ChannelType * a, const ChannelType * b) { } } return a->ty.a.inner == b->ty.a.inner; - return 1; } else { return a->con == b->con; } @@ -256,8 +256,9 @@ void mcx_array_destroy(mcx_array * a) { int mcx_array_all(mcx_array * a, mcx_array_predicate_f_ptr predicate) { size_t i = 0; ChannelValueData element = {0}; + size_t numElems = mcx_array_num_elements(a); - for (i = 0; i < mcx_array_num_elements(a); i++) { + for (i = 0; i < numElems; i++) { if (RETURN_OK != mcx_array_get_elem(a, i, &element)) { mcx_log(LOG_WARNING, "mcx_array_all: Getting element %zu failed", i); return 0; @@ -936,6 +937,11 @@ McxStatus ChannelValueSet(ChannelValue * value, const ChannelValue * source) { } McxStatus ChannelValueDataSetToReference(ChannelValueData * value, ChannelType * type, void * reference) { + if (!reference) { + mcx_log(LOG_ERROR, "ChannelValueDataSetToReference: Reference not defined"); + return RETURN_ERROR; + } + switch (type->con) { case CHANNEL_DOUBLE: *(double *) reference = value->d; @@ -961,10 +967,11 @@ McxStatus ChannelValueDataSetToReference(ChannelValueData * value, ChannelType * } break; case CHANNEL_BINARY: - if (NULL != reference && NULL != ((binary_string *) reference)->data) { + if (NULL != ((binary_string *) reference)->data) { mcx_free(((binary_string *) reference)->data); ((binary_string *) reference)->data = NULL; } + if (value->b.data) { ((binary_string *) reference)->len = value->b.len; ((binary_string *) reference)->data = (char *) mcx_calloc(value->b.len, 1); @@ -974,34 +981,35 @@ McxStatus ChannelValueDataSetToReference(ChannelValueData * value, ChannelType * } break; case CHANNEL_BINARY_REFERENCE: - if (NULL != reference) { - ((binary_string *) reference)->len = value->b.len; - ((binary_string *) reference)->data = value->b.data; - } + ((binary_string *) reference)->len = value->b.len; + ((binary_string *) reference)->data = value->b.data; break; case CHANNEL_ARRAY: - if (NULL != reference) { + { mcx_array * a = (mcx_array *) reference; // First Set fixes the dimensions if (value->a.numDims && !a->numDims) { if (RETURN_OK != mcx_array_init(a, value->a.numDims, value->a.dims, value->a.type)) { + mcx_log(LOG_ERROR, "ChannelValueDataSetToReference: Array initialization failed"); return RETURN_ERROR; } } // Arrays do not support multiplexing (yet) if (!mcx_array_dims_match(a, &value->a)) { + mcx_log(LOG_ERROR, "ChannelValueDataSetToReference: Array dimensions do not match"); return RETURN_ERROR; } if (value->a.data == NULL || a->data == NULL) { + mcx_log(LOG_ERROR, "ChannelValueDataSetToReference: No array data available"); return RETURN_ERROR; } memcpy(a->data, value->a.data, ChannelValueTypeSize(a->type) * mcx_array_num_elements(a)); + break; } - break; case CHANNEL_UNKNOWN: default: break; diff --git a/src/core/channels/ChannelValue.h b/src/core/channels/ChannelValue.h index a2936bd..9647c62 100644 --- a/src/core/channels/ChannelValue.h +++ b/src/core/channels/ChannelValue.h @@ -13,6 +13,7 @@ #include "CentralParts.h" #include +#include #ifdef __cplusplus extern "C" { @@ -57,7 +58,7 @@ extern ChannelType ChannelTypeString; extern ChannelType ChannelTypeBinary; extern ChannelType ChannelTypeBinaryReference; ChannelType * ChannelTypeArray(ChannelType * inner, size_t numDims, size_t * dims); -ChannelType * ChannelTypeArrayLongDims(ChannelType * inner, size_t numDims, unsigned long * dims); +ChannelType * ChannelTypeArrayUInt64Dims(ChannelType * inner, size_t numDims, uint64_t * dims); ChannelType * ChannelTypeClone(ChannelType * type); void ChannelTypeDestructor(ChannelType * type); @@ -93,7 +94,7 @@ typedef union ChannelValueData ChannelValueData; typedef struct ChannelValue ChannelValue; typedef struct { - int (* fn)(TimeInterval * arg, void * env, ChannelValue * res); + McxStatus (* fn)(TimeInterval * arg, void * env, ChannelValue * res); void * env; } proc; diff --git a/src/core/channels/Channel_impl.h b/src/core/channels/Channel_impl.h index 2b330e6..9588c99 100644 --- a/src/core/channels/Channel_impl.h +++ b/src/core/channels/Channel_impl.h @@ -19,73 +19,6 @@ extern "C" { #endif /* __cplusplus */ - - -// ---------------------------------------------------------------------- -// ChannelIn - -// object that is stored in target component that stores the channel connection -typedef struct ChannelInData { - Object _; // base class - - ObjectContainer * connections; // connections (non-overlapping) going into the channel - Vector * valueReferences; // references to non-overlapping parts of ChannelData::value, where - // values gotten from connections are going to be stored - - // ---------------------------------------------------------------------- - // Conversions - - ObjectContainer * typeConversions; // conversion objects (or NULL) for each connection in `connections` - ObjectContainer * unitConversions; // conversion objects (or NULL) for each connection in `connections` - struct LinearConversion * linearConversion; - struct RangeConversion * rangeConversion; - - // ---------------------------------------------------------------------- - // Storage in Component - - int isDiscrete; - - void * reference; - ChannelType * type; -} ChannelInData; - -// ---------------------------------------------------------------------- -// ChannelOut - -// object that is provided to consumer of output channel -typedef struct ChannelOutData { - Object _; // base class - - // Function pointer that provides the value of the channel when called - const proc * valueFunction; - - // Used to store results of channel-internal valueFunction calls - ChannelValue valueFunctionRes; - - // ---------------------------------------------------------------------- - // Conversion - - struct RangeConversion * rangeConversion; - struct LinearConversion * linearConversion; - - int rangeConversionIsActive; - - // ---------------------------------------------------------------------- - // NaN Handling - - NaNCheckLevel nanCheck; - - size_t countNaNCheckWarning; - size_t maxNumNaNCheckWarning; - - // ---------------------------------------------------------------------- - // Connections to Consumers - - // A list of all input channels that are connected to this output channel - ObjectList * connections; - -} ChannelOutData; - // ---------------------------------------------------------------------- // ChannelLocal diff --git a/src/core/connections/FilteredConnection.c b/src/core/connections/FilteredConnection.c index 9815911..dfa516a 100644 --- a/src/core/connections/FilteredConnection.c +++ b/src/core/connections/FilteredConnection.c @@ -9,7 +9,6 @@ ********************************************************************************/ #include "core/connections/FilteredConnection.h" -#include "core/connections/FilteredConnection_impl.h" #include "core/connections/Connection.h" #include "core/connections/ConnectionInfo.h" #include "core/channels/Channel.h" @@ -20,14 +19,15 @@ extern "C" { #endif /* __cplusplus */ -static FilteredConnectionData * FilteredConnectionDataCreate(FilteredConnectionData * data) { +static McxStatus FilteredConnectionDataInit(FilteredConnectionData * data) { data->filters = NULL; + data->_filter = NULL; data->numFilters = 0; ChannelValueInit(&data->updateBuffer, ChannelTypeClone(&ChannelTypeUnknown)); ChannelValueInit(&data->store, ChannelTypeClone(&ChannelTypeUnknown)); - return data; + return RETURN_OK; } static void FilteredConnectionDataDestructor(FilteredConnectionData * data) { @@ -39,13 +39,12 @@ static void FilteredConnectionDataDestructor(FilteredConnectionData * data) { for (i = 0; i < data->numFilters; i++) { object_destroy(data->filters[i]); } - mcx_free(data->filters); + if (data->numFilters != 1) { + mcx_free(data->filters); + } } } -OBJECT_CLASS(FilteredConnectionData, Object); - - static McxStatus FilteredConnectionSetup(Connection * connection, ChannelOut * out, ChannelIn * in, ConnectionInfo * info) { FilteredConnection * filteredConnection = (FilteredConnection *) connection; @@ -63,8 +62,8 @@ static McxStatus FilteredConnectionSetup(Connection * connection, ChannelOut * o } // filter will be added after model is connected - filteredConnection->data->filters = NULL; - filteredConnection->data->numFilters = 0; + filteredConnection->data.filters = NULL; + filteredConnection->data.numFilters = 0; storeType = ChannelTypeFromDimension(sourceInfo->type, info->sourceDimension); if (!storeType) { @@ -72,13 +71,13 @@ static McxStatus FilteredConnectionSetup(Connection * connection, ChannelOut * o } // value store - ChannelValueInit(&filteredConnection->data->store, storeType); // steals ownership of storeType -> no clone needed + ChannelValueInit(&filteredConnection->data.store, storeType); // steals ownership of storeType -> no clone needed // value reference - connection->value_ = ChannelValueDataPointer(&filteredConnection->data->store); + connection->value_ = ChannelValueDataPointer(&filteredConnection->data.store); // initialize the buffer for channel function calls - ChannelValueInit(&filteredConnection->data->updateBuffer, ChannelTypeClone(storeType)); + ChannelValueInit(&filteredConnection->data.updateBuffer, ChannelTypeClone(storeType)); // Connection::Setup() // this has to be done last as it connects the channels @@ -96,7 +95,7 @@ static McxStatus FilteredConnectionEnterCommunicationMode(Connection * connectio McxStatus retVal = RETURN_OK; size_t i = 0; - for (i = 0; i < filteredConnection->data->numFilters; i++) { + for (i = 0; i < filteredConnection->data.numFilters; i++) { ChannelFilter * filter = filteredConnection->GetWriteFilter(filteredConnection, i); if (filter) { if (filter->EnterCommunicationMode) { @@ -120,7 +119,7 @@ static McxStatus FilteredConnectionEnterCouplingStepMode(Connection * connection McxStatus retVal = RETURN_OK; size_t i = 0; - for (i = 0; i < filteredConnection->data->numFilters; i++) { + for (i = 0; i < filteredConnection->data.numFilters; i++) { ChannelFilter * filter = filteredConnection->GetWriteFilter(filteredConnection, i); if (filter) { if (filter->EnterCouplingStepMode) { @@ -137,18 +136,18 @@ static McxStatus FilteredConnectionEnterCouplingStepMode(Connection * connection } static ChannelFilter * FilteredConnectionGetFilter(FilteredConnection * connection, size_t idx) { - if (connection->data->filters && idx < connection->data->numFilters) { - return connection->data->filters[idx]; + if (connection->data.filters && idx < connection->data.numFilters) { + return connection->data.filters[idx]; } return NULL; } static size_t FilteredConnectionGetNumFilters(FilteredConnection *connection) { - return connection->data->numFilters; + return connection->data.numFilters; } static McxStatus FilteredConnectionSetResult(FilteredConnection * connection, const void * value) { - return ChannelValueSetFromReference(&connection->data->store, value); + return ChannelValueSetFromReference(&connection->data.store, value); } static size_t GetSliceShift(Connection * connection) { @@ -217,12 +216,12 @@ static McxStatus FilteredConnectionUpdateToOutput(Connection * connection, TimeI proc * p = (proc *) out->GetFunction(out); // TODO: Update functions to only update the slices ? - if (p->fn(time, p->env, &filteredConnection->data->updateBuffer) != 0) { + if (RETURN_ERROR == p->fn(time, p->env, &filteredConnection->data.updateBuffer)) { mcx_log(LOG_ERROR, "FilteredConnection: Function failed"); return RETURN_ERROR; } - if (RETURN_OK != filteredConnection->SetResult(filteredConnection, ChannelValueDataPointer(&filteredConnection->data->updateBuffer))) { + if (RETURN_OK != filteredConnection->SetResult(filteredConnection, ChannelValueDataPointer(&filteredConnection->data.updateBuffer))) { mcx_log(LOG_ERROR, "FilteredConnection: SetResult failed"); return RETURN_ERROR; } @@ -244,7 +243,7 @@ static McxStatus FilteredConnectionUpdateToOutput(Connection * connection, TimeI size_t numFilters = FilteredConnectionGetNumFilters(filteredConnection); ChannelType * type = info->type; - mcx_array * elements = (mcx_array *) ChannelValueDataPointer(&filteredConnection->data->updateBuffer); + mcx_array * elements = (mcx_array *) ChannelValueDataPointer(&filteredConnection->data.updateBuffer); char * dest = (char *) elements->data; for (i = 0; i < numFilters; i++) { filter = filteredConnection->GetReadFilter(filteredConnection, i); @@ -271,7 +270,7 @@ static McxStatus AddFilter(Connection * connection) { McxStatus retVal = RETURN_OK; - if (filteredConnection->data->filters) { + if (filteredConnection->data.filters) { mcx_log(LOG_DEBUG, "Connection: Not inserting filter"); } else { ConnectionInfo * info = connection->GetInfo(connection); @@ -287,16 +286,16 @@ static McxStatus AddFilter(Connection * connection) { goto cleanup; } - filteredConnection->data->numFilters = dimension->endIdxs[0] - dimension->startIdxs[0] + 1; - filteredConnection->data->filters = (ChannelFilter **) mcx_calloc(filteredConnection->data->numFilters, sizeof(ChannelFilter*)); - if (!filteredConnection->data->filters) { + filteredConnection->data.numFilters = dimension->endIdxs[0] - dimension->startIdxs[0] + 1; + filteredConnection->data.filters = (ChannelFilter **) mcx_calloc(filteredConnection->data.numFilters, sizeof(ChannelFilter*)); + if (!filteredConnection->data.filters) { mcx_log(LOG_ERROR, "Creating array filters failed: no memory"); retVal = RETURN_ERROR; goto cleanup; } - for (i = 0; i < filteredConnection->data->numFilters; i++) { - filteredConnection->data->filters[i] = FilterFactory(&connection->state_, + for (i = 0; i < filteredConnection->data.numFilters; i++) { + filteredConnection->data.filters[i] = FilterFactory(&connection->state_, info->interExtrapolationType, &info->interExtrapolationParams, ChannelTypeBaseType(ConnectionInfoGetType(info)), @@ -305,35 +304,29 @@ static McxStatus AddFilter(Connection * connection) { info->sourceComponent, info->targetComponent, connString); - if (NULL == filteredConnection->data->filters[i]) { + if (NULL == filteredConnection->data.filters[i]) { mcx_log(LOG_DEBUG, "Connection: Array filter creation failed for index %zu", i); retVal = RETURN_ERROR; goto cleanup; } } } else { - filteredConnection->data->filters = (ChannelFilter **) mcx_calloc(1, sizeof(ChannelFilter *)); - if (!filteredConnection->data->filters) { - mcx_log(LOG_ERROR, "Creating filter failed: no memory"); - retVal = RETURN_ERROR; - goto cleanup; - } - - filteredConnection->data->numFilters = 1; - filteredConnection->data->filters[0] = FilterFactory(&connection->state_, - info->interExtrapolationType, - &info->interExtrapolationParams, - ConnectionInfoGetType(info), - info->isInterExtrapolating, - ConnectionInfoIsDecoupled(info), - info->sourceComponent, - info->targetComponent, - connString); - if (NULL == filteredConnection->data->filters[0]) { + filteredConnection->data.numFilters = 1; + filteredConnection->data._filter = FilterFactory(&connection->state_, + info->interExtrapolationType, + &info->interExtrapolationParams, + ConnectionInfoGetType(info), + info->isInterExtrapolating, + ConnectionInfoIsDecoupled(info), + info->sourceComponent, + info->targetComponent, + connString); + if (NULL == filteredConnection->data._filter) { mcx_log(LOG_DEBUG, "Connection: No Filter created"); retVal = RETURN_ERROR; goto cleanup; } + filteredConnection->data.filters = &filteredConnection->data._filter; } cleanup: @@ -348,15 +341,16 @@ static McxStatus AddFilter(Connection * connection) { static ChannelType * FilteredConnectionGetValueType(Connection * connection) { FilteredConnection * filteredConnection = (FilteredConnection *) connection; - return filteredConnection->data->store.type; + return filteredConnection->data.store.type; } static void FilteredConnectionDestructor(FilteredConnection * filteredConnection) { - object_destroy(filteredConnection->data); + FilteredConnectionDataDestructor(&filteredConnection->data); } static FilteredConnection * FilteredConnectionCreate(FilteredConnection * filteredConnection) { Connection * connection = (Connection *) filteredConnection; + McxStatus retVal = RETURN_OK; connection->Setup = FilteredConnectionSetup; connection->UpdateFromInput = FilteredConnectionUpdateFromInput; @@ -373,7 +367,11 @@ static FilteredConnection * FilteredConnectionCreate(FilteredConnection * filter filteredConnection->SetResult = FilteredConnectionSetResult; - filteredConnection->data = (FilteredConnectionData *) object_create(FilteredConnectionData); + retVal = FilteredConnectionDataInit(&filteredConnection->data); + if (RETURN_OK != retVal) { + mcx_log(LOG_ERROR, "FilteredConnectionCreate: FilteredConnectionDataInit failed"); + return NULL; + } return filteredConnection; } diff --git a/src/core/connections/FilteredConnection.h b/src/core/connections/FilteredConnection.h index 01f0f4e..8a6f546 100644 --- a/src/core/connections/FilteredConnection.h +++ b/src/core/connections/FilteredConnection.h @@ -13,11 +13,27 @@ #include "core/connections/Connection.h" #include "core/Conversion.h" +#include "core/channels/ChannelValue.h" +#include "core/connections/filters/Filter.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ +typedef struct FilteredConnectionData { + + // storage of the filtered value provided by the output channel + ChannelValue store; + + // storage for temporary results during out channel updates + ChannelValue updateBuffer; + + ChannelFilter ** filters; + ChannelFilter * _filter; + size_t numFilters; + +} FilteredConnectionData; + typedef struct FilteredConnection FilteredConnection; typedef struct ChannelFilter * (* fConnectionGetFilter)(FilteredConnection * connection, size_t idx); @@ -34,7 +50,7 @@ struct FilteredConnection { fFilteredConnectionSetResult SetResult; - struct FilteredConnectionData * data; + FilteredConnectionData data; } ; #ifdef __cplusplus diff --git a/src/core/connections/FilteredConnection_impl.h b/src/core/connections/FilteredConnection_impl.h deleted file mode 100644 index 8071a00..0000000 --- a/src/core/connections/FilteredConnection_impl.h +++ /dev/null @@ -1,43 +0,0 @@ -/******************************************************************************** - * Copyright (c) 2020 AVL List GmbH and others - * - * This program and the accompanying materials are made available under the - * terms of the Apache Software License 2.0 which is available at - * https://www.apache.org/licenses/LICENSE-2.0. - * - * SPDX-License-Identifier: Apache-2.0 - ********************************************************************************/ - -#ifndef MCX_CORE_CONNECTIONS_FILTEREDCONNECTIONDATA_H -#define MCX_CORE_CONNECTIONS_FILTEREDCONNECTIONDATA_H - -#include "core/Conversion.h" - -// for ExtrapolType -#include "core/connections/filters/Filter.h" - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -extern const struct ObjectClass _FilteredConnectionData; - -typedef struct FilteredConnectionData { - Object _; /* super class */ - - // storage of the filtered value provided by the output channel - ChannelValue store; - - // storage for temporary results during out channel updates - ChannelValue updateBuffer; - - ChannelFilter ** filters; - size_t numFilters; - -} FilteredConnectionData; - -#ifdef __cplusplus -} /* closing brace for extern "C" */ -#endif /* __cplusplus */ - -#endif /* MCX_CORE_CONNECTIONS_FILTEREDCONNECTIONDATA_H */ \ No newline at end of file diff --git a/src/fmu/common_fmu2.c b/src/fmu/common_fmu2.c index cb8fd8c..d801886 100644 --- a/src/fmu/common_fmu2.c +++ b/src/fmu/common_fmu2.c @@ -1010,11 +1010,8 @@ McxStatus Fmu2SetDependencies(Fmu2CommonStruct * fmu2, Databus * db, Dependencie } -// TODO: move into fmu2value? -McxStatus Fmu2SetVariable(Fmu2CommonStruct * fmu, Fmu2Value * fmuVal) { - fmi2_status_t status = fmi2_status_ok; - - char * const name = fmuVal->name; +McxStatus Fmu2SetVariableInitialize(Fmu2CommonStruct * fmu, Fmu2Value * fmuVal) { + McxStatus status = RETURN_OK; Channel * channel = fmuVal->channel; if (channel && FALSE == channel->IsDefinedDuringInit(channel)) { @@ -1022,6 +1019,13 @@ McxStatus Fmu2SetVariable(Fmu2CommonStruct * fmu, Fmu2Value * fmuVal) { return RETURN_OK; } + return Fmu2SetVariable(fmu, fmuVal); +} + +// TODO: move into fmu2value? +McxStatus Fmu2SetVariable(Fmu2CommonStruct * fmu, Fmu2Value * fmuVal) { + fmi2_status_t status = fmi2_status_ok; + ChannelValue * const chVal = &fmuVal->val; ChannelType * type = ChannelValueType(chVal); @@ -1108,13 +1112,13 @@ McxStatus Fmu2SetVariable(Fmu2CommonStruct * fmu, Fmu2Value * fmuVal) { if (fmi2_status_ok != status) { if (fmi2_status_error == status || fmi2_status_fatal == status) { fmu->runOk = fmi2_false; - mcx_log(LOG_ERROR, "FMU: Setting of variable %s failed", name); + mcx_log(LOG_ERROR, "FMU: Setting of variable %s failed", fmuVal->name); return RETURN_ERROR; } else { if (fmi2_status_warning == status) { - mcx_log(LOG_WARNING, "FMU: Setting of variable %s return with a warning", name); + mcx_log(LOG_WARNING, "FMU: Setting of variable %s return with a warning", fmuVal->name); } else if (fmi2_status_discard == status) { - mcx_log(LOG_WARNING, "FMU: Setting of variable %s discarded", name); + mcx_log(LOG_WARNING, "FMU: Setting of variable %s discarded", fmuVal->name); } } } @@ -1145,6 +1149,29 @@ McxStatus Fmu2SetVariableArray(Fmu2CommonStruct * fmu, ObjectContainer * vals) { return RETURN_OK; } +McxStatus Fmu2SetVariableArrayInitialize(Fmu2CommonStruct * fmu, ObjectContainer * vals) { + size_t i = 0; + size_t numVars = vals->Size(vals); + + McxStatus retVal = RETURN_OK; + + mcx_signal_handler_set_this_function(); + + for (i = 0; i < numVars; i++) { + Fmu2Value * const fmuVal = (Fmu2Value *) vals->At(vals, i); + + retVal = Fmu2SetVariableInitialize(fmu, fmuVal); + if (RETURN_ERROR == retVal) { + mcx_signal_handler_unset_function(); + return RETURN_ERROR; + } + } + + mcx_signal_handler_unset_function(); + + return RETURN_OK; +} + McxStatus Fmu2GetVariable(Fmu2CommonStruct * fmu, Fmu2Value * fmuVal) { fmi2_status_t status = fmi2_status_ok; @@ -1355,8 +1382,17 @@ ObjectContainer * Fmu2ValueScalarListFromVarList(fmi2_import_variable_list_t * v fmi2_import_variable_t * var = fmi2_import_get_variable(vars, i); char * name = (char *)fmi2_import_get_variable_name(var); ChannelType * type = Fmi2TypeToChannelType(fmi2_import_get_variable_base_type(var)); + fmi2_import_unit_t * unit = NULL; + const char * unitName = NULL; + + if (ChannelTypeEq(&ChannelTypeDouble, type)) { + unit = fmi2_import_get_real_variable_unit(fmi2_import_get_variable_as_real(var)); + if (unit) { + unitName = fmi2_import_get_unit_name(unit); + } + } - Fmu2Value * value = Fmu2ValueScalarMake(name, var, NULL, NULL); + Fmu2Value * value = Fmu2ValueScalarMake(name, var, unitName, NULL); if (value) { list->PushBackNamed(list, (Object *) value, name); } else { diff --git a/src/fmu/common_fmu2.h b/src/fmu/common_fmu2.h index 5b19e8a..9624941 100644 --- a/src/fmu/common_fmu2.h +++ b/src/fmu/common_fmu2.h @@ -37,9 +37,11 @@ McxStatus Fmu2ReadParams(ObjectContainer * params, ObjectContainer * arrayParams McxStatus Fmu2SetDependencies(Fmu2CommonStruct * fmu2, Databus * db, Dependencies * deps, int init); // TODO: rename all variablearrays to something better +McxStatus Fmu2SetVariableArrayInitialize(Fmu2CommonStruct * fmu, ObjectContainer * vals); McxStatus Fmu2SetVariableArray(Fmu2CommonStruct * fmu, ObjectContainer * vals); McxStatus Fmu2GetVariableArray(Fmu2CommonStruct * fmu, ObjectContainer * vals); +McxStatus Fmu2SetVariableInitialize(Fmu2CommonStruct * fmu, Fmu2Value * fmuVal); McxStatus Fmu2SetVariable(Fmu2CommonStruct * fmu, Fmu2Value * fmuVal); McxStatus Fmu2GetVariable(Fmu2CommonStruct * fmu, Fmu2Value * fmuVal); diff --git a/src/objects/ObjectContainer.c b/src/objects/ObjectContainer.c index c7c9cdc..48304d1 100644 --- a/src/objects/ObjectContainer.c +++ b/src/objects/ObjectContainer.c @@ -476,7 +476,7 @@ static McxStatus ObjectContainerSetElementName(ObjectContainer * container, size_t pos, const char * name) { if (pos >= container->size) { - mcx_log(LOG_ERROR, "ObjectContainer: SetElementName: Position %u out of bounds, max is %u", pos, container->size); + mcx_log(LOG_ERROR, "ObjectContainer: SetElementName: Position %zu out of bounds, max is %zu", pos, container->size); return RETURN_ERROR; }