public void LoadAmlOrMtp( MtpVisualObjectLib objectLib, IMtpDataSourceFactoryOpcUa dataSourceFactory, MtpDataSourceOpcUaPreLoadInfo preLoadInfo, MtpDataSourceSubscriber subscriber, string fn, MtpSymbolMapRecordList makeUpConfigRecs = null) { // check if (fn == null) { return; } // check if we have a mtp-file, which needs to be unzipped bool unzip = fn.ToLower().EndsWith(".mtp") || fn.ToLower().EndsWith(".zip"); // easy? if (!unzip) { using (var stream = File.OpenRead(fn)) { LoadStream(objectLib, dataSourceFactory, preLoadInfo, subscriber, stream, makeUpConfigRecs); } return; } // not easy .. using (var file = File.OpenRead(fn)) using (var zip = new ZipArchive(file, ZipArchiveMode.Read)) { // simply take the first .aml file foreach (var entry in zip.Entries) { // take the 1st *.anl file; should be only one on the root level, even for MultiFileMTP if (entry.FullName.ToLower().EndsWith(".aml")) { using (var stream = entry.Open()) { LoadStream(objectLib, dataSourceFactory, preLoadInfo, subscriber, stream, makeUpConfigRecs); } break; } } } }
public void LoadStream( MtpVisualObjectLib objectLib, IMtpDataSourceFactoryOpcUa dataSourceFactory, MtpDataSourceOpcUaPreLoadInfo preLoadInfo, MtpDataSourceSubscriber subscriber, Stream stream, MtpSymbolMapRecordList makeUpConfigRecs = null) { // check if (stream == null) { return; } // try open file var doc = CAEXDocument.LoadFromStream(stream); if (doc == null) { return; } // load dynamic Instances var refIdToDynamicInstance = MtpAmlHelper.FindAllDynamicInstances(doc.CAEXFile); // load data sources if (dataSourceFactory != null) { MtpAmlHelper.CreateDataSources(dataSourceFactory, preLoadInfo, doc.CAEXFile); } // index pictures var pl = MtpAmlHelper.FindAllMtpPictures(doc.CAEXFile); foreach (var pi in pl) { var p = MtpPicture.ParsePicture(objectLib, subscriber, refIdToDynamicInstance, pi.Item2, makeUpConfigRecs); if (p != null) { this.PictureCollection.Add(pi.Item1, p); } } }
public static void CreateDataSources( IMtpDataSourceFactoryOpcUa dataSourceFactory, MtpDataSourceOpcUaPreLoadInfo preLoadInfo, CAEXFileType aml) { // access if (dataSourceFactory == null || aml == null) { return; } // assumption: all instances are on a fixed level of a instance hierarchy .. foreach (var ih in aml.InstanceHierarchy) // e.g.: ModuleTypePackage { foreach (var ie in ih.InternalElement) // e.g. Class = ModuleTypePackage { foreach (var ie2 in ie.InternalElement) // e.g. CommunicationSet { foreach (var ie3 in ie2.InternalElement) // e.g. InstanceList { if (ie3.RefBaseSystemUnitPath.Trim() == "MTPSUCLib/CommunicationSet/SourceList") { foreach (var server in ie3.InternalElement) // now on server { // check if server valid if (server.RefBaseSystemUnitPath.Trim() != "MTPCommunicationSUCLib/ServerAssembly/OPCUAServer") { continue; } if (!server.Name.HasContent()) { continue; } // get attributes var ep = FindAttributeValueByName(server.Attribute, "Endpoint"); // mapping?? if (preLoadInfo?.EndpointMapping != null) { foreach (var epm in preLoadInfo.EndpointMapping) { if (epm?.IsValid == true && (server.Name.Trim() == epm.ForName?.Trim() || server.ID.Trim() == epm.ForId?.Trim())) { ep = epm.NewEndpoint?.Trim(); } } } // check endpoint if (!ep.HasContent()) { continue; } // make server var serv = dataSourceFactory.CreateOrUseUaServer(ep); if (serv == null) { continue; } // go into items foreach (var item in server.ExternalInterface) { // check to item // TODO (MIHO, 2020-08-06): spec/example files seem not to be in a final state // check for the final role/class names to be used if (!item.RefBaseClassPath.Trim().Contains("OPCUAItem")) { continue; } // get attributes var id = FindAttributeValueByName(item.Attribute, "Identifier"); var ns = FindAttributeValueByName(item.Attribute, "Namespace"); var ac = FindAttributeValueByName(item.Attribute, "Access"); // potential renaming? if (preLoadInfo?.IdentifierRenaming != null) { foreach (var ren in preLoadInfo.IdentifierRenaming) { id = ren.DoReplacement(id); } } if (preLoadInfo?.NamespaceRenaming != null) { foreach (var ren in preLoadInfo.NamespaceRenaming) { ns = ren.DoReplacement(ns); } } // create // ReSharper disable once UnusedVariable var it = dataSourceFactory.CreateOrUseItem(serv, id, ns, ac, item.ID); } } } } } } } }
// handle Submodel data private bool GatherMtpInfos(MtpDataSourceOpcUaPreLoadInfo preLoadInfo) { // access var env = this.thePackage?.AasEnv; if (this.theSubmodel?.semanticId == null || this.theSubmodel.submodelElements == null || this.defsMtp == null || env?.AdministrationShells == null || this.thePackage.AasEnv.Submodels == null) { return(false); } // need to find the type Submodel AdminShell.Submodel mtpTypeSm = null; // check, if the user pointed to the instance submodel if (this.theSubmodel.semanticId.Matches(this.defsMtp.SEM_MtpInstanceSubmodel)) { // Source list foreach (var srcLst in this.theSubmodel.submodelElements .FindAllSemanticIdAs <AdminShell.SubmodelElementCollection>( this.defsMtp.CD_SourceList?.GetReference(), AdminShell.Key.MatchMode.Relaxed)) { // found a source list, might contain sources if (srcLst?.value == null) { continue; } // UA Server? foreach (var src in srcLst.value.FindAllSemanticIdAs <AdminShell.SubmodelElementCollection>( this.defsMtp.CD_SourceOpcUaServer?.GetReference(), AdminShell.Key.MatchMode.Relaxed)) { if (src?.value != null) { // UA server var ep = src.value.FindFirstSemanticIdAs <AdminShell.Property>( this.defsMtp.CD_Endpoint.GetReference(), AdminShell.Key.MatchMode.Relaxed)?.value; // add if (preLoadInfo?.EndpointMapping != null) { preLoadInfo.EndpointMapping.Add( new MtpDataSourceOpcUaEndpointMapping( "" + ep, ForName: ("" + src.idShort).Trim())); } } } } // Identifier renaming? foreach (var ren in theSubmodel.submodelElements .FindAllSemanticIdAs <AdminShell.SubmodelElementCollection>( this.defsMtp.CD_IdentifierRenaming?.GetReference(), AdminShell.Key.MatchMode.Relaxed)) { if (ren?.value != null) { var oldtxt = ren.value.FindFirstSemanticIdAs <AdminShell.Property>( this.defsMtp.CD_RenamingOldText?.GetReference(), AdminShell.Key.MatchMode.Relaxed)?.value; var newtxt = ren.value.FindFirstSemanticIdAs <AdminShell.Property>( this.defsMtp.CD_RenamingNewText?.GetReference(), AdminShell.Key.MatchMode.Relaxed)?.value; if (oldtxt.HasContent() && newtxt.HasContent() && preLoadInfo?.IdentifierRenaming != null) { preLoadInfo.IdentifierRenaming.Add(new MtpDataSourceStringReplacement(oldtxt, newtxt)); } } } // Namespace renaming? foreach (var ren in theSubmodel.submodelElements .FindAllSemanticIdAs <AdminShell.SubmodelElementCollection>( this.defsMtp.CD_NamespaceRenaming?.GetReference(), AdminShell.Key.MatchMode.Relaxed)) { if (ren?.value != null) { var oldtxt = ren?.value.FindFirstSemanticIdAs <AdminShell.Property>( this.defsMtp.CD_RenamingOldText?.GetReference(), AdminShell.Key.MatchMode.Relaxed)?.value; var newtxt = ren?.value.FindFirstSemanticIdAs <AdminShell.Property>( this.defsMtp.CD_RenamingNewText?.GetReference(), AdminShell.Key.MatchMode.Relaxed)?.value; if (oldtxt.HasContent() && newtxt.HasContent() && preLoadInfo?.NamespaceRenaming != null) { preLoadInfo.NamespaceRenaming.Add(new MtpDataSourceStringReplacement(oldtxt, newtxt)); } } } // according spec from Sten Gruener, the AAS.derivedFrom relationship shall be exploited. // How to get from subModel to AAS? var instanceAas = env.FindAASwithSubmodel(this.theSubmodel.identification); var typeAas = env.FindReferableByReference(instanceAas?.derivedFrom) as AdminShell.AdministrationShell; if (instanceAas?.derivedFrom != null && typeAas != null) { foreach (var msm in env.FindAllSubmodelGroupedByAAS((aas, sm) => { return(aas == typeAas && true == sm?.semanticId?.Matches(this.defsMtp.SEM_MtpSubmodel)); })) { mtpTypeSm = msm; break; } } // another possibility: direct reference var dirLink = this.theSubmodel.submodelElements .FindFirstSemanticIdAs <AdminShell.ReferenceElement>( this.defsMtp.CD_MtpTypeSubmodel?.GetReference(), AdminShell.Key.MatchMode.Relaxed); var dirLinkSm = env.FindReferableByReference(dirLink?.value) as AdminShell.Submodel; if (mtpTypeSm == null) { mtpTypeSm = dirLinkSm; } } // other (not intended) case: user points to type submodel directly if (mtpTypeSm == null && this.theSubmodel.semanticId.Matches(this.defsMtp.SEM_MtpSubmodel)) { mtpTypeSm = this.theSubmodel; } // ok, is there a type submodel? if (mtpTypeSm == null) { return(false); } // find file, remember Submodel element for it, find filename // (ConceptDescription)(no-local)[IRI]http://www.admin-shell.io/mtp/v1/MTPSUCLib/ModuleTypePackage this.activeMtpFileElem = mtpTypeSm.submodelElements? .FindFirstSemanticIdAs <AdminShell.File>(this.defsMtp.CD_MtpFile.GetReference(), AdminShell.Key.MatchMode.Relaxed); var inputFn = this.activeMtpFileElem?.value; if (inputFn == null) { return(false); } this.activeMtpFileFn = inputFn; return(true); }