Creating and handling TcCOM modules

This chapter describes how to add existing TcCOM modules to an existing TwinCAT configuration and how to configure them. This chapter briefly covers the following topics:

Obtaining a reference to a “TcCOM Objects” node

In a TwinCAT configuration, the “TcCOM Objects” node is located under “SYSTEM^TcCOM Objects”. Therefore, you can retrieve a reference to this node by using the ITcSysManager::LookupTreeItem() method as follows:

Code snippet (C#):

ITcSmTreeItem tcComObjects = systemManager.LookupTreeItem("TIRC^TcCOM Objects");

Code snippet (PowerShell):

$tcComObjects = $systemManager.LookupTreeItem("TIRC^TcCOM Objects")

Adding existing TcCOM modules

The code above assumes that a SystemManager object already exists in your AI code.

Adding TcCOM modules

To add existing TcCOM modules to your TwinCAT configuration, these modules must be recognizable by TwinCAT. This can be achieved using one of the following methods:

Either of these methods is sufficient to make the TcCOM modules recognizable to TwinCAT.

A TcCOM module is identified by its GUID or its name:

Creating and handling TcCOM modules 1:

Alternatively, you can determine the GUID using the TMC file of the TcCOM module.

<TcModuleClass>
  <Modules>
    <Module GUID="{8f5fdcff-ee4b-4ee5-80b1-25eb23bd1b45}">
    ...
    </Module>
  </Modules>
</TcModuleClass>

Let's assume we already have a TcCOM module that is registered in TwinCAT and is recognized by TwinCAT. We would now like to add this TcCOM module, which has the GUID {8F5FDCFF-EE4B-4EE5-80B1-25EB23BD1B45}, to the TwinCAT configuration. This can be done as follows:

Code snippet (C#):

Dictionary<string,Guid> tcomModuleTable = new Dictionary<string,Guid>();
tcomModuleTable.Add("TempContr",Guid.Parse("{8f5fdcff-ee4b-4ee5-80b1-25eb23bd1b45}"));
ITcSmTreeItem tempController = tcComObjects.CreateChild("Test", 0, "", tcomModuleTable["TempContr"]);

Code snippet (PowerShell):

$tcomModuleTable = @{}
$tcomModuleTable.Add("TempContr", "{8f5fdcff-ee4b-4ee5-80b1-25eb23bd1b45}")
$tempController = $tcComObjects.CreateChild("Test", 0, "", $tcomModuleTable["TempContr"])

Please note that the “vInfo” parameter of the “ITcSmTreeItem::CreateChild()” method contains the GUID of the TcCOM module, which is used to identify the module in the list of all registered TcCOM modules on this system.

Code snippet (C#):

ITcSmTreeItem tempController = tcComObjects.CreateChild("Test", 1, "", "NewModule");

Code snippet (Powershell):

$tempController = $tcComObjects.CreateChild("Test", 0, "", "NewModule")

Iterating through added TcCOM modules

To iterate through all added TcCOM module instances, you can use the ITcModuleManager2 interface. The following code snippet shows how to use this interface.

Code snippet (C#):

ITcSysManager15 sysManager15 = sysManager as ITcSysManager15;

ITcModuleManager3 moduleManager = sysManager15.GetModuleManager() as ITcModuleManager3;
foreach (ITcModuleInstance2 moduleInstance in moduleManager)
{
  string moduleType = moduleInstance.ModuleTypeName;
  string instanceName = moduleInstance.ModuleInstanceName;
  Guid classId = moduleInstance.ClassID;
  uint objId = moduleInstance.oid;
  uint parentObjId = moduleInstance.ParentOID;
}

Code snippet (PowerShell):

$moduleManager = $systemManager.GetModuleManager()
ForEach( $moduleInstance in $moduleManager )
{
  $moduleType = $moduleInstance.ModuleTypeName
  $instanceName = $moduleInstance.ModuleInstanceName
  $classId = $moduleInstance.ClassID
  $objId = $moduleInstance.oid
  $parentObjId = $moduleInstance.ParentOID
}

Keep in mind that every module object can also be interpreted as an ITcSmTreeItem, so the following type conversion would be valid:

Code snippet (C#):

ITcSmTreeItem treeItem = moduleInstance As ITcSmTreeItem;
Creating and handling TcCOM modules 3:

PowerShell uses dynamic data types by default.

Setting the CreateSymbol flag for parameters

The CreateSymbol (CS) flag for parameters of a TcCOM module can be set via its XML description. The following code snippet shows how to enable the CS flag for the “CallBy” parameter.

Code snippet (C#):

bool activateCS = true;
// First step: Read all Parameters of TcCOM module instance
string tempControllerXml = tempController.ProduceXml();
XmlDocument tempControllerDoc = new XmlDocument();
tempControllerDoc.LoadXml(tempControllerXml);
XmlNode sourceParameters = tempControllerDoc.SelectSingleNode("TreeItem/TcModuleInstance/Module/Parameters");

// Second step: Build target XML (for later ConsumeXml())
XmlDocument targetDoc = new XmlDocument();
XmlElement treeItemElement = targetDoc.CreateElement("TreeItem");
XmlElement moduleInstanceElement = targetDoc.CreateElement("TcModuleInstance");
XmlElement moduleElement = targetDoc.CreateElement("Module");
XmlElement parametersElement = (XmlElement) targetDoc.ImportNode(sourceParameters, true);
moduleElement.AppendChild(parametersElement);
moduleInstanceElement.AppendChild(moduleElement);
treeItemElement.AppendChild(moduleInstanceElement);
targetDoc.AppendChild(treeItemElement);

// Third step: Look for specific parameter (in this case "CallBy") and read its CreateSymbol attribute
XmlNode destModule = targetDoc.SelectSingleNode("TreeItem/TcModuleInstance/Module");
XmlNode callByParameter = destParameters.SelectSingleNode("Parameters/Parameter[Name='CallBy']");
XmlAttribute createSymbol = callByParameter.Attributes["CreateSymbol"];

createSymbol.Value = "true";

// Fifth step: Write prepared XML to configuration via ConsumeXml()
string targetXml = targetDoc.OuterXml;
tempController.ConsumeXml(targetXml);

Code snippet (PowerShell):

$tempControllerXml = [Xml]$tempController.ProduceXml()
$sourceParameters = $tempControllerXml.TreeItem.TcModuleInstance.Module.Parameters

[System.XML.XmlDocument] $targetDoc = New-Object System.XML.XmlDocument
[System.XML.XmlElement] $treeItemElement = $targetDoc.CreateElement("TreeItem")
[System.XML.XmlElement] $moduleInstanceElement = $targetDoc.CreateElement("TcModuleInstance")
[System.XML.XmlElement] $moduleElement = $targetDoc.CreateElement("Module")
[System.XML.XmlElement] $parametersElement = $targetDoc.ImportNode($sourceParameters, $true)
$moduleElement.AppendChild($parametersElement)
$moduleInstanceElement.AppendChild($moduleElement)
$treeItemElement.AppendChild($moduleInstanceElement)
$targetDoc.AppendChild($treeItemElement)

$destModule = $targetDoc.TreeItem.TcModuleInstance.Module
$callByParameter = $destmodule.SelectSingleNode("Parameters/Parameter[Name='CallBy']")

$callByParameter.CreateSymbol = "true"

$targetXml = $targetDoc.OuterXml
$tempController.ConsumeXml($targetXml)

Setting the CreateSymbol flag for data areas

The CreateSymbol (CS) flag for data areas of a TcCOM module can be set via its XML description. The following code snippet shows how to enable the CS flag for the “Input” data area. It should be noted that this procedure is very similar to the one used for parameters.

Code snippet (C#):

bool activateCS = true;
// First step: Read all Data Areas of a TcCOM module instance
string tempControllerXml = tempController.ProduceXml();
XmlDocument tempControllerDoc = new XmlDocument();
tempControllerDoc.LoadXml(tempControllerXml);
XmlNode sourceDataAreas = tempControllerDoc.SelectSingleNode("TreeItem/TcModuleInstance/Module/DataAreas");

// Second step: Build target XML (for later ConsumeXml())
XmlDocument targetDoc = new XmlDocument();
XmlElement treeItem = targetDoc.CreateElement("TreeItem");
XmlElement moduleInstance = targetDoc.CreateElement("TcModuleInstance");
XmlElement module = targetDoc.CreateElement("Module");
XmlElement dataAreas = (XmlElement)
targetDoc.ImportNode(sourceDataAreas, true);
module.AppendChild(dataAreas);
moduleInstance.AppendChild(module);
treeItem.AppendChild(moduleInstance);
targetDoc.AppendChild(treeItem);

// Third step: Look for specific Data Area (in this case "Input") and read its CreateSymbol attribute
XmlElement dataArea = (XmlElement)targetDoc.SelectSingleNode("TreeItem/TcModuleInstance/Module/DataAreas/DataArea[ContextId='0' and Name='Input']");
XmlNode dataAreaNo = dataArea.SelectSingleNode("AreaNo");
XmlAttribute createSymbol = dataAreaNoNode.Attributes["CreateSymbols"];

// Fourth step: Set CreateSymbol attribute to true if it exists. If not, create attribute and set its value
if (createSymbol != null)
string oldValue = createSymbol.Value;
else
{
createSymbol = targetDoc.CreateAttribute("CreateSymbols");
dataAreaNo.Attributes.Append(createSymbol);
}
createSymbol.Value = XmlConvert.ToString(activateCS);

// Fifth step: Write prepared XML to configuration via ConsumeXml()
string targetXml = targetDoc.OuterXml;
tempController.ConsumeXml(targetXml);

Code snippet (PowerShell):

$tempControllerXml = [Xml]$tempController.ProduceXml()
$sourceDataAreas = $tempControllerXml.TreeItem.TcModuleInstance.Module.DataAreas

[System.XML.XmlDocument] $targetDoc = New-Object System.XML.XmlDocument
[System.XML.XmlElement] $treeItem = $targetDoc.CreateElement("TreeItem")
[System.XML.XmlElement] $moduleInstance = $targetDoc.CreateElement("TcModuleInstance")
[System.XML.XmlElement] $module = $targetDoc.CreateElement("Module")
[System.XML.XmlElement] $dataAreas = $targetDoc.ImportNode($sourceDataAreas, $true)
$module.AppendChild($dataAreas)
$moduleInstance.AppendChild($module)
$treeItem.AppendChild($moduleInstance)
$targetDoc.AppendChild($treeItem)

$destModule = $targetDoc.TreeItem.TcModuleInstance.Module
[System.XML.XmlElement] $dataArea = $destModule.SelectSingleNode("DataAreas/DataArea[ContextId='0' and Name='Input']")
$dataAreaNo = $dataArea.SelectSingleNode("AreaNo")
$dataAreaNo.CreateSymbols = "true"

// Fifth step: Write prepared XML to configuration via ConsumeXml()
$targetXml = $targetDoc.OuterXml
$tempController.ConsumeXml($targetXml)

Setting the context (tasks)

Each TcCOM module instance must run in a specific context (task). This can be done using the ITcModuleInstance2::SetModuleContext() method. This method takes two parameters: ContextId and TaskObjectId. Both are equivalent to the corresponding parameters in TwinCAT XAE:

Creating and handling TcCOM modules 4:

Keep in mind that the TaskObjectId is displayed in hexadecimal format in TwinCAT XAE.

Code snippet (C#):

ITcModuleInstance2 tempControllerMi = (ITcModuleInstance2) tempController;
tempControllerMi.SetModuleContext(0, 33619984);

You can determine the TaskObjectId from the XML description of the corresponding task, for example:

Code snippet (C#):

ITcSmTreeItem someTask = systemManager.LookupTreeItem("TIRT^SomeTask");
string someTaskXml = someTask.ProduceXml();
XmlDocument someTaskDoc = new XmlDocument();
someTaskDoc.LoadXml(someTaskXml);
XmlNode taskObjectIdNode = someTaskDoc.SelectSingleNode("TreeItem/ObjectId");
string taskObjectIdStr = taskObjectId.InnerText;
uint taskObjectId = uint.Parse(taskObjectIdStr, NumberStyles.HexNumber);

Linking variables

Variables from a TcCOM module instance can be linked to PLC/IO or other TcCOM modules using the standard mechanisms of the Automation Interface, such as ITcSysManager::LinkVariables().