- added function ControlObjectClient_useConstantT to enable constant T parameter value during a control sequence

This commit is contained in:
Michael Zillgith 2015-07-20 17:09:05 +02:00
parent 16fe7c2a7c
commit 5ef1da7ac2
20 changed files with 245 additions and 88 deletions

View file

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

View file

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

View file

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

View file

@ -33,7 +33,7 @@ namespace IEC61850
{ {
public ReportControlBlock GetReportControlBlock (string rcbObjectReference) 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 rcb1 = con.GetReportControlBlock(rcbReference1);
ReportControlBlock rcb2 = con.GetReportControlBlock(rcbReference2); ReportControlBlock rcb2 = con.GetReportControlBlock(rcbReference2);
ReportControlBlock rcb3 = con.GetReportControlBlock(rcbReference3); ReportControlBlock rcb3 = con.GetReportControlBlock(rcbReference3);
rcb1.GetRCBValues(); rcb1.GetRCBValues();
// note: the second parameter is not required! // note: the second parameter is not required!
rcb1.InstallReportHandler(reportHandler, rcb1); rcb1.InstallReportHandler(reportHandler, rcb1);
if (rcb1.IsBuffered()) if (rcb1.IsBuffered())
Console.WriteLine ("RCB: " + rcbReference1 + " is buffered"); Console.WriteLine("RCB: " + rcbReference1 + " is buffered");
rcb1.SetTrgOps(TriggerOptions.DATA_CHANGED | TriggerOptions.INTEGRITY); rcb1.SetTrgOps(TriggerOptions.DATA_CHANGED | TriggerOptions.INTEGRITY);
rcb1.SetIntgPd(5000); rcb1.SetIntgPd(5000);
rcb1.SetRptEna(true); rcb1.SetRptEna(true);
rcb1.SetRCBValues(); rcb1.SetRCBValues();
rcb2.GetRCBValues(); rcb2.GetRCBValues();
if (rcb2.IsBuffered()) if (rcb2.IsBuffered())
Console.WriteLine ("RCB: " + rcbReference2 + " is buffered"); Console.WriteLine("RCB: " + rcbReference2 + " is buffered");
rcb2.InstallReportHandler(reportHandler, rcb2); rcb2.InstallReportHandler(reportHandler, rcb2);
rcb2.SetOptFlds(ReportOptions.REASON_FOR_INCLUSION | ReportOptions.SEQ_NUM | ReportOptions.TIME_STAMP | rcb2.SetOptFlds(ReportOptions.REASON_FOR_INCLUSION | ReportOptions.SEQ_NUM | ReportOptions.TIME_STAMP |
ReportOptions.CONF_REV | ReportOptions.ENTRY_ID | ReportOptions.DATA_REFERENCE | ReportOptions.DATA_SET); ReportOptions.CONF_REV | ReportOptions.ENTRY_ID | ReportOptions.DATA_REFERENCE | ReportOptions.DATA_SET);
rcb2.SetTrgOps(TriggerOptions.DATA_CHANGED | TriggerOptions.INTEGRITY); rcb2.SetTrgOps(TriggerOptions.DATA_CHANGED | TriggerOptions.INTEGRITY);
rcb2.SetIntgPd(2000); rcb2.SetIntgPd(2000);
rcb2.SetRptEna(true); rcb2.SetRptEna(true);
rcb2.SetRCBValues(); rcb2.SetRCBValues();
rcb3.GetRCBValues(); rcb3.GetRCBValues();
@ -128,14 +128,20 @@ namespace reporting
ReportingExample.running = false; ReportingExample.running = false;
}; };
/* stop main loop when connection is lost */
con.InstallConnectionClosedHandler(delegate(IedConnection connection) {
Console.WriteLine("Connection closed");
ReportingExample.running = false;
});
while (running) { while (running) {
Thread.Sleep(10); Thread.Sleep(10);
} }
con.Abort (); con.Abort ();
} catch (IedConnectionException e) { } 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"?> <?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup> <PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion> <ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion> <SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{9E29B4CE-EE5F-4CA6-85F6-5D1FF8B27BF8}</ProjectGuid> <ProjectGuid>{9E29B4CE-EE5F-4CA6-85F6-5D1FF8B27BF8}</ProjectGuid>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<RootNamespace>reporting</RootNamespace> <RootNamespace>reporting</RootNamespace>
<AssemblyName>reporting</AssemblyName> <AssemblyName>reporting</AssemblyName>
</PropertyGroup> <PublishUrl>publish\</PublishUrl>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <Install>true</Install>
<DebugSymbols>true</DebugSymbols> <InstallFrom>Disk</InstallFrom>
<DebugType>full</DebugType> <UpdateEnabled>false</UpdateEnabled>
<Optimize>false</Optimize> <UpdateMode>Foreground</UpdateMode>
<OutputPath>bin\Debug</OutputPath> <UpdateInterval>7</UpdateInterval>
<DefineConstants>DEBUG;</DefineConstants> <UpdateIntervalUnits>Days</UpdateIntervalUnits>
<ErrorReport>prompt</ErrorReport> <UpdatePeriodically>false</UpdatePeriodically>
<WarningLevel>4</WarningLevel> <UpdateRequired>false</UpdateRequired>
<Externalconsole>true</Externalconsole> <MapFileExtensions>true</MapFileExtensions>
</PropertyGroup> <ApplicationRevision>0</ApplicationRevision>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<DebugType>none</DebugType> <IsWebBootstrapper>false</IsWebBootstrapper>
<Optimize>true</Optimize> <UseApplicationTrust>false</UseApplicationTrust>
<OutputPath>bin\Release</OutputPath> <BootstrapperEnabled>true</BootstrapperEnabled>
<ErrorReport>prompt</ErrorReport> </PropertyGroup>
<WarningLevel>4</WarningLevel> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<Externalconsole>true</Externalconsole> <DebugSymbols>true</DebugSymbols>
</PropertyGroup> <DebugType>full</DebugType>
<ItemGroup> <Optimize>false</Optimize>
<Reference Include="System" /> <OutputPath>bin\Debug</OutputPath>
</ItemGroup> <DefineConstants>DEBUG;</DefineConstants>
<ItemGroup> <ErrorReport>prompt</ErrorReport>
<Compile Include="AssemblyInfo.cs" /> <WarningLevel>4</WarningLevel>
<Compile Include="ReportingExample.cs" /> <Externalconsole>true</Externalconsole>
</ItemGroup> <UseVSHostingProcess>true</UseVSHostingProcess>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> </PropertyGroup>
<ItemGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<ProjectReference Include="..\IEC61850forCSharp\IEC61850forCSharp.csproj"> <DebugType>none</DebugType>
<Project>{C35D624E-5506-4560-8074-1728F1FA1A4D}</Project> <Optimize>true</Optimize>
<Name>IEC61850forCSharp</Name> <OutputPath>bin\Release</OutputPath>
</ProjectReference> <ErrorReport>prompt</ErrorReport>
</ItemGroup> <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> </Project>

View file

@ -46,8 +46,12 @@ struct sControlObjectClient
bool interlockCheck; bool interlockCheck;
bool synchroCheck; bool synchroCheck;
bool hasTimeActivatedMode; bool hasTimeActivatedMode;
int edition; /* 1 = Ed. 1 - 2 = Ed. 2 */ 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; LastApplError lastApplError;
CommandTerminationHandler commandTerminationHandler; CommandTerminationHandler commandTerminationHandler;
@ -380,7 +384,16 @@ ControlObjectClient_operate(ControlObjectClient self, MmsValue* ctlVal, uint64_t
MmsValue* ctlNum = MmsValue_newUnsignedFromUint32(self->ctlNum); MmsValue* ctlNum = MmsValue_newUnsignedFromUint32(self->ctlNum);
MmsValue_setElement(operParameters, index++, 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; MmsValue* ctlTime;
if (self->edition == 2) if (self->edition == 2)
@ -485,6 +498,9 @@ ControlObjectClient_selectWithValue(ControlObjectClient self, MmsValue* ctlVal)
uint64_t timestamp = Hal_getTimeInMs(); uint64_t timestamp = Hal_getTimeInMs();
MmsValue* ctlTime; MmsValue* ctlTime;
if (self->useConstantT)
self->constantT = timestamp;
if (self->edition == 2) if (self->edition == 2)
ctlTime = MmsValue_newUtcTimeByMsTime(timestamp); ctlTime = MmsValue_newUtcTimeByMsTime(timestamp);
else { else {
@ -609,7 +625,13 @@ ControlObjectClient_cancel(ControlObjectClient self)
MmsValue* ctlNum = MmsValue_newUnsignedFromUint32(self->ctlNum); MmsValue* ctlNum = MmsValue_newUnsignedFromUint32(self->ctlNum);
MmsValue_setElement(cancelParameters, index++, 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; MmsValue* ctlTime;
if (self->edition == 2) if (self->edition == 2)
@ -652,6 +674,12 @@ ControlObjectClient_cancel(ControlObjectClient self)
return true; return true;
} }
void
ControlObjectClient_useConstantT(ControlObjectClient self, bool useConstantT)
{
self->useConstantT = useConstantT;
}
void void
ControlObjectClient_enableInterlockCheck(ControlObjectClient self) ControlObjectClient_enableInterlockCheck(ControlObjectClient self)
{ {

View file

@ -267,7 +267,9 @@ IedConnection_installReportHandler(IedConnection self, const char* rcbReference,
else else
report->rptId = NULL; report->rptId = NULL;
Semaphore_wait(self->reportHandlerMutex);
LinkedList_add(self->enabledReports, report); LinkedList_add(self->enabledReports, report);
Semaphore_post(self->reportHandlerMutex);
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("DEBUG_IED_CLIENT: Installed new report callback handler for %s\n", rcbReference); 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 void
IedConnection_uninstallReportHandler(IedConnection self, const char* rcbReference) IedConnection_uninstallReportHandler(IedConnection self, const char* rcbReference)
{ {
Semaphore_wait(self->reportHandlerMutex);
ClientReport report = lookupReportHandler(self, rcbReference); ClientReport report = lookupReportHandler(self, rcbReference);
if (report != NULL) { if (report != NULL) {
LinkedList_remove(self->enabledReports, report); LinkedList_remove(self->enabledReports, report);
ClientReport_destroy(report); ClientReport_destroy(report);
} }
Semaphore_post(self->reportHandlerMutex);
} }
void 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) if (matchingReport->callback != NULL)
matchingReport->callback(matchingReport->callbackParameter, matchingReport); matchingReport->callback(matchingReport->callbackParameter, matchingReport);
Semaphore_post(self->reportHandlerMutex);
printf("U2\n");
exit_function: exit_function:
return; return;
} }

View file

@ -485,6 +485,7 @@ IedConnection_create()
self->state = IED_STATE_IDLE; self->state = IED_STATE_IDLE;
self->stateMutex = Semaphore_create(1); self->stateMutex = Semaphore_create(1);
self->reportHandlerMutex = Semaphore_create(1);
self->connectionTimeout = DEFAULT_CONNECTION_TIMEOUT; self->connectionTimeout = DEFAULT_CONNECTION_TIMEOUT;
@ -617,10 +618,12 @@ IedConnection_destroy(IedConnection self)
LinkedList_destroyStatic(self->clientControls); LinkedList_destroyStatic(self->clientControls);
Semaphore_destroy(self->stateMutex); Semaphore_destroy(self->stateMutex);
Semaphore_destroy(self->reportHandlerMutex);
GLOBAL_FREEMEM(self); GLOBAL_FREEMEM(self);
} }
MmsVariableSpecification* MmsVariableSpecification*
IedConnection_getVariableSpecification(IedConnection self, IedClientError* error, const char* objectReference, IedConnection_getVariableSpecification(IedConnection self, IedClientError* error, const char* objectReference,
FunctionalConstraint fc) FunctionalConstraint fc)
@ -1129,7 +1132,6 @@ mmsFileReadHandler(void* parameter, int32_t frsmId, uint8_t* buffer, uint32_t by
{ {
struct sClientProvidedFileReadHandler* handler = (struct sClientProvidedFileReadHandler*) parameter; struct sClientProvidedFileReadHandler* handler = (struct sClientProvidedFileReadHandler*) parameter;
handler->retVal = handler->handler(handler->handlerParameter, buffer, bytesReceived); handler->retVal = handler->handler(handler->handlerParameter, buffer, bytesReceived);
handler->byteReceived += bytesReceived; handler->byteReceived += bytesReceived;

View file

@ -1335,6 +1335,17 @@ ControlObjectClient_setTestMode(ControlObjectClient self);
void void
ControlObjectClient_setOrigin(ControlObjectClient self, const char* orIdent, int orCat); 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 void
ControlObjectClient_enableInterlockCheck(ControlObjectClient self); ControlObjectClient_enableInterlockCheck(ControlObjectClient self);

View file

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

View file

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

View file

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

View file

@ -490,3 +490,4 @@ EXPORTS
ClientReport_getBufOvfl ClientReport_getBufOvfl
MmsValue_getUtcTimeInMsWithUs MmsValue_getUtcTimeInMsWithUs
IedModel_setIedNameForDynamicModel IedModel_setIedNameForDynamicModel
ControlObjectClient_useConstantT

View file

@ -514,3 +514,4 @@ EXPORTS
ClientReport_getBufOvfl ClientReport_getBufOvfl
MmsValue_getUtcTimeInMsWithUs MmsValue_getUtcTimeInMsWithUs
IedModel_setIedNameForDynamicModel IedModel_setIedNameForDynamicModel
ControlObjectClient_useConstantT

Binary file not shown.

Binary file not shown.

View file

@ -76,8 +76,11 @@ public class LogControl {
reasonCode = reasonCodeBoolean; reasonCode = reasonCodeBoolean;
Node trgOpsNode = ParserUtils.getChildNodeWithTag(logControlNode, "TrgOps"); 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"); 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"); Node optFieldsNode = ParserUtils.getChildNodeWithTag(reportControlNode, "OptFields");

View file

@ -32,7 +32,7 @@ public class TriggerOptions {
private boolean qchg = false; /* 2 */ private boolean qchg = false; /* 2 */
private boolean dupd = false; /* 4 */ private boolean dupd = false; /* 4 */
private boolean period = false; /* 8 */ private boolean period = false; /* 8 */
private boolean gi = false; /* 16 */ private boolean gi = true; /* 16 */
public TriggerOptions(Node trgOpsNode) throws SclParserException { public TriggerOptions(Node trgOpsNode) throws SclParserException {
@ -56,6 +56,11 @@ public class TriggerOptions {
if (giVal != null) if (giVal != null)
this.gi = giVal; 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) { public TriggerOptions(boolean dchg, boolean qchg, boolean dupd, boolean period, boolean gi) {
this.dchg = dchg; this.dchg = dchg;