Merge branch 'pavo_changes' of mz-automation.de:libiec61850 into pavo_changes

Conflicts:
	src/vs/libiec61850-wo-goose.def
	src/vs/libiec61850.def
This commit is contained in:
Michael Zillgith 2015-10-09 15:04:26 +02:00
commit e8f7f17a8f
21 changed files with 248 additions and 90 deletions

View file

@ -18,8 +18,8 @@
#define DEBUG_ISO_SERVER 0
#define DEBUG_ISO_CLIENT 0
#define DEBUG_IED_SERVER 0
#define DEBUG_IED_CLIENT 0
#define DEBUG_MMS_CLIENT 0
#define DEBUG_IED_CLIENT 1
#define DEBUG_MMS_CLIENT 1
#define DEBUG_MMS_SERVER 0
#define DEBUG_GOOSE_SUBSCRIBER 0
#define DEBUG_GOOSE_PUBLISHER 0

View file

@ -164,6 +164,7 @@ namespace IEC61850
commandTerminationHandler(commandTerminationHandlerParameter, this);
}
private InternalCommandTerminationHandler intCommandTerminationHandler;
internal ControlObject (string objectReference, IntPtr connection, IedConnection iedConnection)
{
@ -174,7 +175,7 @@ namespace IEC61850
if (this.controlObject == System.IntPtr.Zero)
throw new IedConnectionException("Control object not found", 0);
InternalCommandTerminationHandler intCommandTerminationHandler = new InternalCommandTerminationHandler (MyCommandTerminationHandler);
intCommandTerminationHandler = new InternalCommandTerminationHandler (MyCommandTerminationHandler);
ControlObjectClient_setCommandTerminationHandler(controlObject, intCommandTerminationHandler, controlObject);
}

View file

@ -261,8 +261,10 @@ namespace IEC61850
~IedConnection ()
{
Console.WriteLine ("IedConnection destructor invoked");
if (connection != IntPtr.Zero)
IedConnection_destroy(connection);
Console.WriteLine ("IedConnection destructor finished");
}
public IsoConnectionParameters GetConnectionParameters ()

View file

@ -159,6 +159,7 @@ namespace IEC61850
private IntPtr self;
private IntPtr connection;
private IedConnection iedConnection = null;
private string objectReference;
private bool flagRptId = false;
private bool flagRptEna = false;
@ -202,6 +203,7 @@ namespace IEC61850
private void internalReportHandler (IntPtr parameter, IntPtr report)
{
Console.WriteLine ("called internalReportHandler");
try {
if (this.report == null)
@ -217,16 +219,20 @@ namespace IEC61850
}
}
internal ReportControlBlock (string objectReference, IntPtr connection)
internal ReportControlBlock (string objectReference, IedConnection iedConnection, IntPtr connection)
{
self = ClientReportControlBlock_create (objectReference);
this.iedConnection = iedConnection;
this.connection = connection;
this.objectReference = objectReference;
}
~ReportControlBlock()
{
IedConnection_uninstallReportHandler(connection, objectReference);
Console.WriteLine ("Destructor invoked");
//IedConnection_uninstallReportHandler(connection, objectReference);
//this.iedConnection = null;
Console.WriteLine ("Destructor finished");
}
public string GetObjectReference ()

View file

@ -33,7 +33,7 @@ namespace IEC61850
{
public ReportControlBlock GetReportControlBlock (string rcbObjectReference)
{
return new ReportControlBlock (rcbObjectReference, connection);
return new ReportControlBlock (rcbObjectReference, this, connection);
}
}

View file

@ -75,36 +75,36 @@ namespace reporting
ReportControlBlock rcb1 = con.GetReportControlBlock(rcbReference1);
ReportControlBlock rcb2 = con.GetReportControlBlock(rcbReference2);
ReportControlBlock rcb3 = con.GetReportControlBlock(rcbReference3);
rcb1.GetRCBValues();
// note: the second parameter is not required!
rcb1.InstallReportHandler(reportHandler, rcb1);
if (rcb1.IsBuffered())
Console.WriteLine ("RCB: " + rcbReference1 + " is buffered");
rcb1.SetTrgOps(TriggerOptions.DATA_CHANGED | TriggerOptions.INTEGRITY);
rcb1.SetIntgPd(5000);
rcb1.SetRptEna(true);
rcb1.SetRCBValues();
rcb2.GetRCBValues();
if (rcb2.IsBuffered())
Console.WriteLine ("RCB: " + rcbReference2 + " is buffered");
rcb2.InstallReportHandler(reportHandler, rcb2);
ReportControlBlock rcb3 = con.GetReportControlBlock(rcbReference3);
rcb1.GetRCBValues();
// note: the second parameter is not required!
rcb1.InstallReportHandler(reportHandler, rcb1);
if (rcb1.IsBuffered())
Console.WriteLine("RCB: " + rcbReference1 + " is buffered");
rcb1.SetTrgOps(TriggerOptions.DATA_CHANGED | TriggerOptions.INTEGRITY);
rcb1.SetIntgPd(5000);
rcb1.SetRptEna(true);
rcb1.SetRCBValues();
rcb2.GetRCBValues();
if (rcb2.IsBuffered())
Console.WriteLine("RCB: " + rcbReference2 + " is buffered");
rcb2.InstallReportHandler(reportHandler, rcb2);
rcb2.SetOptFlds(ReportOptions.REASON_FOR_INCLUSION | ReportOptions.SEQ_NUM | ReportOptions.TIME_STAMP |
ReportOptions.CONF_REV | ReportOptions.ENTRY_ID | ReportOptions.DATA_REFERENCE | ReportOptions.DATA_SET);
rcb2.SetTrgOps(TriggerOptions.DATA_CHANGED | TriggerOptions.INTEGRITY);
rcb2.SetIntgPd(2000);
rcb2.SetRptEna(true);
rcb2.SetRCBValues();
ReportOptions.CONF_REV | ReportOptions.ENTRY_ID | ReportOptions.DATA_REFERENCE | ReportOptions.DATA_SET);
rcb2.SetTrgOps(TriggerOptions.DATA_CHANGED | TriggerOptions.INTEGRITY);
rcb2.SetIntgPd(2000);
rcb2.SetRptEna(true);
rcb2.SetRCBValues();
rcb3.GetRCBValues();
@ -128,14 +128,20 @@ namespace reporting
ReportingExample.running = false;
};
/* stop main loop when connection is lost */
con.InstallConnectionClosedHandler(delegate(IedConnection connection) {
Console.WriteLine("Connection closed");
ReportingExample.running = false;
});
while (running) {
Thread.Sleep(10);
}
con.Abort ();
} catch (IedConnectionException e) {
Console.WriteLine (e.Message);
}
Console.WriteLine ("Error: " + e.Message);
}
}
}

View file

@ -1,45 +1,95 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{9E29B4CE-EE5F-4CA6-85F6-5D1FF8B27BF8}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>reporting</RootNamespace>
<AssemblyName>reporting</AssemblyName>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
</ItemGroup>
<ItemGroup>
<Compile Include="AssemblyInfo.cs" />
<Compile Include="ReportingExample.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
<ProjectReference Include="..\IEC61850forCSharp\IEC61850forCSharp.csproj">
<Project>{C35D624E-5506-4560-8074-1728F1FA1A4D}</Project>
<Name>IEC61850forCSharp</Name>
</ProjectReference>
</ItemGroup>
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{9E29B4CE-EE5F-4CA6-85F6-5D1FF8B27BF8}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>reporting</RootNamespace>
<AssemblyName>reporting</AssemblyName>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<UpdateEnabled>false</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<IsWebBootstrapper>false</IsWebBootstrapper>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
<UseVSHostingProcess>true</UseVSHostingProcess>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
</ItemGroup>
<ItemGroup>
<Compile Include="AssemblyInfo.cs" />
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
<DependentUpon>Settings.settings</DependentUpon>
</Compile>
<Compile Include="ReportingExample.cs" />
<Compile Include="Settings.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
<ProjectReference Include="..\IEC61850forCSharp\IEC61850forCSharp.csproj">
<Project>{C35D624E-5506-4560-8074-1728F1FA1A4D}</Project>
<Name>IEC61850forCSharp</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include=".NETFramework,Version=v4.0">
<Visible>False</Visible>
<ProductName>Microsoft .NET Framework 4 %28x86 and x64%29</ProductName>
<Install>true</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
<Install>false</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>false</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Windows.Installer.4.5">
<Visible>False</Visible>
<ProductName>Windows Installer 4.5</ProductName>
<Install>true</Install>
</BootstrapperPackage>
</ItemGroup>
</Project>

View file

@ -46,8 +46,12 @@ struct sControlObjectClient
bool interlockCheck;
bool synchroCheck;
bool hasTimeActivatedMode;
int edition; /* 1 = Ed. 1 - 2 = Ed. 2 */
bool useConstantT; /* some servers require a constant T parameter for select and operate */
uint64_t constantT; /* timestamp of select/operate to be used when constant T option is selected */
LastApplError lastApplError;
CommandTerminationHandler commandTerminationHandler;
@ -380,7 +384,16 @@ ControlObjectClient_operate(ControlObjectClient self, MmsValue* ctlVal, uint64_t
MmsValue* ctlNum = MmsValue_newUnsignedFromUint32(self->ctlNum);
MmsValue_setElement(operParameters, index++, ctlNum);
uint64_t timestamp = Hal_getTimeInMs();
uint64_t timestamp;
if ((self->ctlModel == CONTROL_MODEL_SBO_ENHANCED) && (self->useConstantT))
timestamp = self->constantT;
else
timestamp = Hal_getTimeInMs();
if (self->useConstantT)
self->constantT = timestamp;
MmsValue* ctlTime;
if (self->edition == 2)
@ -485,6 +498,9 @@ ControlObjectClient_selectWithValue(ControlObjectClient self, MmsValue* ctlVal)
uint64_t timestamp = Hal_getTimeInMs();
MmsValue* ctlTime;
if (self->useConstantT)
self->constantT = timestamp;
if (self->edition == 2)
ctlTime = MmsValue_newUtcTimeByMsTime(timestamp);
else {
@ -609,7 +625,13 @@ ControlObjectClient_cancel(ControlObjectClient self)
MmsValue* ctlNum = MmsValue_newUnsignedFromUint32(self->ctlNum);
MmsValue_setElement(cancelParameters, index++, ctlNum);
uint64_t timestamp = Hal_getTimeInMs();
uint64_t timestamp;
if (self->useConstantT)
timestamp = self->constantT;
else
timestamp = Hal_getTimeInMs();
MmsValue* ctlTime;
if (self->edition == 2)
@ -652,6 +674,12 @@ ControlObjectClient_cancel(ControlObjectClient self)
return true;
}
void
ControlObjectClient_useConstantT(ControlObjectClient self, bool useConstantT)
{
self->useConstantT = useConstantT;
}
void
ControlObjectClient_enableInterlockCheck(ControlObjectClient self)
{

View file

@ -267,7 +267,9 @@ IedConnection_installReportHandler(IedConnection self, const char* rcbReference,
else
report->rptId = NULL;
Semaphore_wait(self->reportHandlerMutex);
LinkedList_add(self->enabledReports, report);
Semaphore_post(self->reportHandlerMutex);
if (DEBUG_IED_CLIENT)
printf("DEBUG_IED_CLIENT: Installed new report callback handler for %s\n", rcbReference);
@ -276,12 +278,16 @@ IedConnection_installReportHandler(IedConnection self, const char* rcbReference,
void
IedConnection_uninstallReportHandler(IedConnection self, const char* rcbReference)
{
Semaphore_wait(self->reportHandlerMutex);
ClientReport report = lookupReportHandler(self, rcbReference);
if (report != NULL) {
LinkedList_remove(self->enabledReports, report);
ClientReport_destroy(report);
}
Semaphore_post(self->reportHandlerMutex);
}
void
@ -544,9 +550,13 @@ private_IedConnection_handleReport(IedConnection self, MmsValue* value)
}
}
printf("U0 sem wait\n");
Semaphore_wait(self->reportHandlerMutex);
printf("U1 call user\n");
if (matchingReport->callback != NULL)
matchingReport->callback(matchingReport->callbackParameter, matchingReport);
Semaphore_post(self->reportHandlerMutex);
printf("U2\n");
exit_function:
return;
}

View file

@ -485,6 +485,7 @@ IedConnection_create()
self->state = IED_STATE_IDLE;
self->stateMutex = Semaphore_create(1);
self->reportHandlerMutex = Semaphore_create(1);
self->connectionTimeout = DEFAULT_CONNECTION_TIMEOUT;
@ -629,6 +630,7 @@ IedConnection_destroy(IedConnection self)
printf("D6\n");
Semaphore_destroy(self->stateMutex);
Semaphore_destroy(self->reportHandlerMutex);
printf("D7\n");
@ -637,6 +639,7 @@ IedConnection_destroy(IedConnection self)
printf("D8\n");
}
MmsVariableSpecification*
IedConnection_getVariableSpecification(IedConnection self, IedClientError* error, const char* objectReference,
FunctionalConstraint fc)
@ -1145,7 +1148,6 @@ mmsFileReadHandler(void* parameter, int32_t frsmId, uint8_t* buffer, uint32_t by
{
struct sClientProvidedFileReadHandler* handler = (struct sClientProvidedFileReadHandler*) parameter;
handler->retVal = handler->handler(handler->handlerParameter, buffer, bytesReceived);
handler->byteReceived += bytesReceived;

View file

@ -1335,6 +1335,17 @@ ControlObjectClient_setTestMode(ControlObjectClient self);
void
ControlObjectClient_setOrigin(ControlObjectClient self, const char* orIdent, int orCat);
/**
* \brief Use a constant T parameter for all command (select, operate, cancel) of a single control sequence
*
* NOTE: Some non-standard compliant servers may require this to accept oper/cancel requests
*
* \param self the ControlObjectClient instance
* \param useContantT enable this behaviour with true, disable with false
*/
void
ControlObjectClient_useConstantT(ControlObjectClient self, bool useConstantT);
void
ControlObjectClient_enableInterlockCheck(ControlObjectClient self);

View file

@ -40,6 +40,7 @@ struct sIedConnection
LastApplError lastApplError;
Semaphore stateMutex;
Semaphore reportHandlerMutex;
IedConnectionClosedHandler connectionCloseHandler;
void* connectionClosedParameter;

View file

@ -1414,6 +1414,8 @@ writeAccessGooseControlBlock(MmsMapping* self, MmsDomain* domain, char* variable
#if (CONFIG_GOOSE_DATSET_WRITABLE == 1)
if (strcmp(varName, "DatSet") == 0) {
// allow to set non-existing data set?
MmsValue_update(MmsValue_getElement(MmsGooseControlBlock_getMmsValues(mmsGCB), 2), value);
allowAccess = true;
}

View file

@ -106,6 +106,8 @@ connectionHandlingThread(IsoClientConnection self)
TpktState packetState;
printf("P1\n");
while ((packetState = CotpConnection_readToTpktBuffer(self->cotpConnection)) == TPKT_WAITING)
{
Thread_sleep(1);
@ -116,6 +118,9 @@ connectionHandlingThread(IsoClientConnection self)
}
}
printf("P2\n");
if (packetState == TPKT_ERROR)
break;
@ -146,27 +151,44 @@ connectionHandlingThread(IsoClientConnection self)
break;
}
printf("P3\n");
self->callback(ISO_IND_DATA, self->callbackParameter,
&(self->presentation->nextPayload));
printf("P4\n");
/* wait for user to release the buffer */
Semaphore_wait(self->receiveBufferMutex);
printf("P5\n");
CotpConnection_resetPayload(self->cotpConnection);
}
printf("I1\n");
self->callback(ISO_IND_CLOSED, self->callbackParameter, NULL);
printf("I2\n");
self->state = STATE_IDLE;
Socket_destroy(self->socket);
printf("I3\n");
if (DEBUG_ISO_CLIENT)
printf("ISO_CLIENT_CONNECTION: exit connection %p\n", self);
/* release buffer to enable resuse of client connection */
/* release buffer to enable reuse of client connection */
Semaphore_post(self->receiveBufferMutex);
printf("I4\n");
self->handlingThreadRunning = false;
}
@ -427,12 +449,16 @@ IsoClientConnection_close(IsoClientConnection self)
if (DEBUG_ISO_CLIENT)
printf("ISO_CLIENT: IsoClientConnection_close\n");
printf("B1\n");
if (self->handlingThreadRunning) {
self->stopHandlingThread = true;
while (self->handlingThreadRunning)
Thread_sleep(1);
}
printf("B2\n");
self->state = STATE_IDLE;
}

View file

@ -490,4 +490,5 @@ EXPORTS
ClientReport_getBufOvfl
MmsValue_getUtcTimeInMsWithUs
IedModel_setIedNameForDynamicModel
ControlObjectClient_useConstantT
ControlObjectClient_setOrigin

View file

@ -91,7 +91,7 @@ EXPORTS
ControlObjectClient_getObjectReference @218
ControlObjectClient_operate @219
ControlObjectClient_select @220
ControlObjectClient_selectWithValue @221MmsConnection_setConnectTimeout
ControlObjectClient_selectWithValue @221
ControlObjectClient_setLastApplError @222
ControlObjectClient_setCommandTerminationHandler
DataAttribute_create @273
@ -514,4 +514,5 @@ EXPORTS
ClientReport_getBufOvfl
MmsValue_getUtcTimeInMsWithUs
IedModel_setIedNameForDynamicModel
ControlObjectClient_useConstantT
ControlObjectClient_setOrigin

Binary file not shown.

Binary file not shown.

View file

@ -76,8 +76,11 @@ public class LogControl {
reasonCode = reasonCodeBoolean;
Node trgOpsNode = ParserUtils.getChildNodeWithTag(logControlNode, "TrgOps");
this.triggerOptions = new TriggerOptions(trgOpsNode);
if (trgOpsNode != null)
this.triggerOptions = new TriggerOptions(trgOpsNode);
else
this.triggerOptions = new TriggerOptions(); // use default values if no node present
}

View file

@ -77,7 +77,10 @@ public class ReportControlBlock {
Node trgOpsNode = ParserUtils.getChildNodeWithTag(reportControlNode, "TrgOps");
this.triggerOptions = new TriggerOptions(trgOpsNode);
if (trgOpsNode != null)
this.triggerOptions = new TriggerOptions(trgOpsNode);
else
this.triggerOptions = new TriggerOptions(); // use default values if no node present
Node optFieldsNode = ParserUtils.getChildNodeWithTag(reportControlNode, "OptFields");

View file

@ -32,7 +32,7 @@ public class TriggerOptions {
private boolean qchg = false; /* 2 */
private boolean dupd = false; /* 4 */
private boolean period = false; /* 8 */
private boolean gi = false; /* 16 */
private boolean gi = true; /* 16 */
public TriggerOptions(Node trgOpsNode) throws SclParserException {
@ -56,6 +56,11 @@ public class TriggerOptions {
if (giVal != null)
this.gi = giVal;
}
/** Constructor for default values when trigger options are not present */
public TriggerOptions() {
// nothing to do
}
public TriggerOptions(boolean dchg, boolean qchg, boolean dupd, boolean period, boolean gi) {
this.dchg = dchg;