- added maximum log entry size for LogStorage
- implemented maximum log entries for sqlite log storage - added log to C# API
This commit is contained in:
parent
fca675e2a1
commit
dc281a7ee9
7 changed files with 449 additions and 255 deletions
|
@ -431,6 +431,10 @@ namespace IEC61850
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the connection parameters
|
||||
/// </summary>
|
||||
/// <returns>The connection parameters</returns>
|
||||
public IsoConnectionParameters GetConnectionParameters ()
|
||||
{
|
||||
IntPtr mmsConnection = IedConnection_getMmsConnection(connection);
|
||||
|
@ -448,6 +452,10 @@ namespace IEC61850
|
|||
|
||||
private UInt32 connectTimeout = 10000;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the timeout used for connection attempts.
|
||||
/// </summary>
|
||||
/// <value>The connect timeout in milliseconds</value>
|
||||
public UInt32 ConnectTimeout {
|
||||
get {
|
||||
return connectTimeout;
|
||||
|
@ -493,7 +501,15 @@ namespace IEC61850
|
|||
|
||||
return controlObject;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Updates the device model by quering the server.
|
||||
/// </summary>
|
||||
public void UpdateDeviceModel()
|
||||
{
|
||||
int error;
|
||||
|
@ -504,6 +520,12 @@ namespace IEC61850
|
|||
throw new IedConnectionException("UpdateDeviceModel failed", error);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the server directory (Logical devices or file objects)
|
||||
/// </summary>
|
||||
/// <returns>List of logical devices or files</returns>
|
||||
/// <param name="fileDirectory">If set to <c>true</c> the file directory is returned, otherwise the LD names</param>
|
||||
/// <exception cref="IedConnectionException">This exception is thrown if there is a connection or service error</exception>
|
||||
public List<string> GetServerDirectory (bool fileDirectory = false)
|
||||
{
|
||||
|
@ -731,6 +753,7 @@ namespace IEC61850
|
|||
/// <param name="entryID">EntryID of the last received MmsJournalEntry</param>
|
||||
/// <param name="timestamp">Timestamp of the last received MmsJournalEntry</param>
|
||||
/// <param name="moreFollows">Indicates that more log entries are available</param>
|
||||
/// <exception cref="IedConnectionException">This exception is thrown if there is a connection or service error</exception>
|
||||
public List<MmsJournalEntry> QueryLogAfter(string logRef, byte[] entryID, ulong timestamp, out bool moreFollows)
|
||||
{
|
||||
int error;
|
||||
|
@ -756,6 +779,7 @@ namespace IEC61850
|
|||
/// <param name="startTime">Start time of the time range</param>
|
||||
/// <param name="stopTime">End time of the time range</param>
|
||||
/// <param name="moreFollows">Indicates that more log entries are available</param>
|
||||
/// <exception cref="IedConnectionException">This exception is thrown if there is a connection or service error</exception>
|
||||
public List<MmsJournalEntry> QueryLogByTime(string logRef, ulong startTime, ulong stopTime, out bool moreFollows)
|
||||
{
|
||||
int error;
|
||||
|
@ -772,24 +796,6 @@ namespace IEC61850
|
|||
|
||||
}
|
||||
|
||||
private static DateTime DateTimeFromMsTimestamp(ulong msTime)
|
||||
{
|
||||
DateTime dateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
|
||||
|
||||
ulong seconds = msTime / 1000;
|
||||
ulong millies = msTime % 1000;
|
||||
|
||||
dateTime.AddSeconds ((double) seconds);
|
||||
dateTime.AddMilliseconds((double) millies);
|
||||
|
||||
return dateTime;
|
||||
}
|
||||
|
||||
private static ulong DateTimeToMsTimestamp(DateTime dateTime)
|
||||
{
|
||||
return (ulong) (dateTime.ToUniversalTime ().Subtract (new DateTime (1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queries all log entries of the given time range
|
||||
/// </summary>
|
||||
|
@ -798,10 +804,11 @@ namespace IEC61850
|
|||
/// <param name="startTime">Start time of the time range</param>
|
||||
/// <param name="stopTime">End time of the time range</param>
|
||||
/// <param name="moreFollows">Indicates that more log entries are available</param>
|
||||
/// <exception cref="IedConnectionException">This exception is thrown if there is a connection or service error</exception>
|
||||
public List<MmsJournalEntry> QueryLogByTime(string logRef, DateTime startTime, DateTime stopTime, out bool moreFollows)
|
||||
{
|
||||
ulong startTimeMs = DateTimeToMsTimestamp (startTime);
|
||||
ulong stopTimeMs = DateTimeToMsTimestamp (stopTime);
|
||||
ulong startTimeMs = LibIEC61850.DateTimeToMsTimestamp (startTime);
|
||||
ulong stopTimeMs = LibIEC61850.DateTimeToMsTimestamp (stopTime);
|
||||
|
||||
return QueryLogByTime (logRef, startTimeMs, stopTimeMs, out moreFollows);
|
||||
}
|
||||
|
@ -1445,233 +1452,4 @@ namespace IEC61850
|
|||
IED_ERROR_UNKNOWN = 99
|
||||
}
|
||||
}
|
||||
|
||||
namespace Common
|
||||
{
|
||||
|
||||
[Flags]
|
||||
public enum TriggerOptions {
|
||||
NONE = 0,
|
||||
/** send report when value of data changed */
|
||||
DATA_CHANGED = 1,
|
||||
/** send report when quality of data changed */
|
||||
QUALITY_CHANGED = 2,
|
||||
/** send report when data or quality is updated */
|
||||
DATA_UPDATE = 4,
|
||||
/** periodic transmission of all data set values */
|
||||
INTEGRITY = 8,
|
||||
/** general interrogation (on client request) */
|
||||
GI = 16
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum ReportOptions {
|
||||
NONE = 0,
|
||||
SEQ_NUM = 1,
|
||||
TIME_STAMP = 2,
|
||||
REASON_FOR_INCLUSION = 4,
|
||||
DATA_SET = 8,
|
||||
DATA_REFERENCE = 16,
|
||||
BUFFER_OVERFLOW = 32,
|
||||
ENTRY_ID = 64,
|
||||
CONF_REV = 128,
|
||||
ALL = 255
|
||||
}
|
||||
|
||||
public enum Validity
|
||||
{
|
||||
GOOD = 0,
|
||||
RESERVED = 1,
|
||||
INVALID = 2,
|
||||
QUESTIONABLE = 3
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The quality of a data object.
|
||||
/// </summary>
|
||||
public class Quality
|
||||
{
|
||||
|
||||
private UInt16 value;
|
||||
|
||||
public Quality (int bitStringValue)
|
||||
{
|
||||
value = (UInt16)bitStringValue;
|
||||
}
|
||||
|
||||
public Quality ()
|
||||
{
|
||||
value = 0;
|
||||
}
|
||||
|
||||
public Validity GetValidity ()
|
||||
{
|
||||
int qualityVal = value & 0x3;
|
||||
|
||||
return (Validity)qualityVal;
|
||||
}
|
||||
|
||||
public void SetValidity (Validity validity)
|
||||
{
|
||||
value = (UInt16)(value & 0xfffc);
|
||||
|
||||
value += (ushort)validity;
|
||||
}
|
||||
}
|
||||
|
||||
public enum ACSIClass
|
||||
{
|
||||
/** data objects */
|
||||
ACSI_CLASS_DATA_OBJECT,
|
||||
/** data sets (container for multiple data objects) */
|
||||
ACSI_CLASS_DATA_SET,
|
||||
/** buffered report control blocks */
|
||||
ACSI_CLASS_BRCB,
|
||||
/** unbuffered report control blocks */
|
||||
ACSI_CLASS_URCB,
|
||||
/** log control blocks */
|
||||
ACSI_CLASS_LCB,
|
||||
/** logs (journals) */
|
||||
ACSI_CLASS_LOG,
|
||||
/** setting group control blocks */
|
||||
ACSI_CLASS_SGCB,
|
||||
/** GOOSE control blocks */
|
||||
ACSI_CLASS_GoCB,
|
||||
/** GSE control blocks */
|
||||
ACSI_CLASS_GsCB,
|
||||
/** multicast sampled values control blocks */
|
||||
ACSI_CLASS_MSVCB,
|
||||
/** unicast sampled values control blocks */
|
||||
ACSI_CLASS_USVCB
|
||||
}
|
||||
|
||||
public enum FunctionalConstraint
|
||||
{
|
||||
/** Status information */
|
||||
ST = 0,
|
||||
/** Measurands - analog values */
|
||||
MX = 1,
|
||||
/** Setpoint */
|
||||
SP = 2,
|
||||
/** Substitution */
|
||||
SV = 3,
|
||||
/** Configuration */
|
||||
CF = 4,
|
||||
/** Description */
|
||||
DC = 5,
|
||||
/** Setting group */
|
||||
SG = 6,
|
||||
/** Setting group editable */
|
||||
SE = 7,
|
||||
/** Service response / Service tracking */
|
||||
SR = 8,
|
||||
/** Operate received */
|
||||
OR = 9,
|
||||
/** Blocking */
|
||||
BL = 10,
|
||||
/** Extended definition */
|
||||
EX = 11,
|
||||
/** Control */
|
||||
CO = 12,
|
||||
/** Unicast SV */
|
||||
US = 13,
|
||||
/** Multicast SV */
|
||||
MS = 14,
|
||||
/** Unbuffered report */
|
||||
RP = 15,
|
||||
/** Buffered report */
|
||||
BR = 16,
|
||||
/** Log control blocks */
|
||||
LG = 17,
|
||||
|
||||
/** All FCs - wildcard value */
|
||||
ALL = 99,
|
||||
NONE = -1
|
||||
}
|
||||
|
||||
public enum ControlAddCause {
|
||||
ADD_CAUSE_UNKNOWN = 0,
|
||||
ADD_CAUSE_NOT_SUPPORTED = 1,
|
||||
ADD_CAUSE_BLOCKED_BY_SWITCHING_HIERARCHY = 2,
|
||||
ADD_CAUSE_SELECT_FAILED = 3,
|
||||
ADD_CAUSE_INVALID_POSITION = 4,
|
||||
ADD_CAUSE_POSITION_REACHED = 5,
|
||||
ADD_CAUSE_PARAMETER_CHANGE_IN_EXECUTION = 6,
|
||||
ADD_CAUSE_STEP_LIMIT = 7,
|
||||
ADD_CAUSE_BLOCKED_BY_MODE = 8,
|
||||
ADD_CAUSE_BLOCKED_BY_PROCESS = 9,
|
||||
ADD_CAUSE_BLOCKED_BY_INTERLOCKING = 10,
|
||||
ADD_CAUSE_BLOCKED_BY_SYNCHROCHECK = 11,
|
||||
ADD_CAUSE_COMMAND_ALREADY_IN_EXECUTION = 12,
|
||||
ADD_CAUSE_BLOCKED_BY_HEALTH = 13,
|
||||
ADD_CAUSE_1_OF_N_CONTROL = 14,
|
||||
ADD_CAUSE_ABORTION_BY_CANCEL = 15,
|
||||
ADD_CAUSE_TIME_LIMIT_OVER = 16,
|
||||
ADD_CAUSE_ABORTION_BY_TRIP = 17,
|
||||
ADD_CAUSE_OBJECT_NOT_SELECTED = 18,
|
||||
ADD_CAUSE_OBJECT_ALREADY_SELECTED = 19,
|
||||
ADD_CAUSE_NO_ACCESS_AUTHORITY = 20,
|
||||
ADD_CAUSE_ENDED_WITH_OVERSHOOT = 21,
|
||||
ADD_CAUSE_ABORTION_DUE_TO_DEVIATION = 22,
|
||||
ADD_CAUSE_ABORTION_BY_COMMUNICATION_LOSS = 23,
|
||||
ADD_CAUSE_ABORTION_BY_COMMAND = 24,
|
||||
ADD_CAUSE_NONE = 25,
|
||||
ADD_CAUSE_INCONSISTENT_PARAMETERS = 26,
|
||||
ADD_CAUSE_LOCKED_BY_OTHER_CLIENT = 27
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Object reference. Helper function to handle object reference strings.
|
||||
/// </summary>
|
||||
public static class ObjectReference {
|
||||
|
||||
/// <summary>
|
||||
/// Get the name part of an object reference with appended FC
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The element name.
|
||||
/// </returns>
|
||||
/// <param name='objectReferenceWithFc'>
|
||||
/// Object reference with appended fc.
|
||||
/// </param>
|
||||
public static string getElementName (string objectReferenceWithFc)
|
||||
{
|
||||
int fcPartStartIndex = objectReferenceWithFc.IndexOf('[');
|
||||
|
||||
if (fcPartStartIndex == -1)
|
||||
return objectReferenceWithFc;
|
||||
|
||||
return objectReferenceWithFc.Substring(0, fcPartStartIndex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the FC of an object reference with appended FC.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The FC
|
||||
/// </returns>
|
||||
/// <param name='objectReferenceWithFc'>
|
||||
/// Object reference with FC.
|
||||
/// </param>
|
||||
public static FunctionalConstraint getFC (string objectReferenceWithFc)
|
||||
{
|
||||
int fcPartStartIndex = objectReferenceWithFc.IndexOf('[');
|
||||
|
||||
if (fcPartStartIndex == -1)
|
||||
return FunctionalConstraint.NONE;
|
||||
|
||||
string fcString = objectReferenceWithFc.Substring(fcPartStartIndex + 1 , 2);
|
||||
|
||||
try
|
||||
{
|
||||
return (FunctionalConstraint) Enum.Parse(typeof(FunctionalConstraint), fcString);
|
||||
}
|
||||
catch(ArgumentException)
|
||||
{
|
||||
return FunctionalConstraint.NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
278
dotnet/IEC61850forCSharp/IEC61850CommonAPI.cs
Normal file
278
dotnet/IEC61850forCSharp/IEC61850CommonAPI.cs
Normal file
|
@ -0,0 +1,278 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace IEC61850
|
||||
{
|
||||
namespace Common
|
||||
{
|
||||
|
||||
public class LibIEC61850
|
||||
{
|
||||
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
|
||||
static extern IntPtr LibIEC61850_getVersionString();
|
||||
|
||||
/// <summary>
|
||||
/// Get the version string of the native libiec61850 library
|
||||
/// </summary>
|
||||
/// <returns>The version string in format MAJOR.MINOR.PATCH</returns>
|
||||
public static string GetVersionString()
|
||||
{
|
||||
return Marshal.PtrToStringAnsi (LibIEC61850_getVersionString ());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts millisecond timestamp to a DateTime object
|
||||
/// </summary>
|
||||
/// <returns>The DateTime object representing the value of the timestamp</returns>
|
||||
/// <param name="msTime">The timestamp in milliseconds since epoch (UTC)</param>
|
||||
public static DateTime MsTimestampToDateTime(ulong msTime)
|
||||
{
|
||||
DateTime dateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
|
||||
|
||||
ulong seconds = msTime / 1000;
|
||||
ulong millies = msTime % 1000;
|
||||
|
||||
dateTime.AddSeconds ((double) seconds);
|
||||
dateTime.AddMilliseconds((double) millies);
|
||||
|
||||
return dateTime;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a DateTime object in milliseconds since epoch timestamp (UTC)
|
||||
/// </summary>
|
||||
/// <returns>The timestamp in ms</returns>
|
||||
/// <param name="msTime">The DateTime object to convert</param>
|
||||
public static ulong DateTimeToMsTimestamp(DateTime dateTime)
|
||||
{
|
||||
return (ulong) (dateTime.ToUniversalTime ().Subtract (new DateTime (1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds);
|
||||
}
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum TriggerOptions {
|
||||
NONE = 0,
|
||||
/** send report when value of data changed */
|
||||
DATA_CHANGED = 1,
|
||||
/** send report when quality of data changed */
|
||||
QUALITY_CHANGED = 2,
|
||||
/** send report when data or quality is updated */
|
||||
DATA_UPDATE = 4,
|
||||
/** periodic transmission of all data set values */
|
||||
INTEGRITY = 8,
|
||||
/** general interrogation (on client request) */
|
||||
GI = 16
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum ReportOptions {
|
||||
NONE = 0,
|
||||
SEQ_NUM = 1,
|
||||
TIME_STAMP = 2,
|
||||
REASON_FOR_INCLUSION = 4,
|
||||
DATA_SET = 8,
|
||||
DATA_REFERENCE = 16,
|
||||
BUFFER_OVERFLOW = 32,
|
||||
ENTRY_ID = 64,
|
||||
CONF_REV = 128,
|
||||
ALL = 255
|
||||
}
|
||||
|
||||
public enum Validity
|
||||
{
|
||||
GOOD = 0,
|
||||
RESERVED = 1,
|
||||
INVALID = 2,
|
||||
QUESTIONABLE = 3
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The quality of a data object.
|
||||
/// </summary>
|
||||
public class Quality
|
||||
{
|
||||
|
||||
private UInt16 value;
|
||||
|
||||
public Quality (int bitStringValue)
|
||||
{
|
||||
value = (UInt16)bitStringValue;
|
||||
}
|
||||
|
||||
public Quality ()
|
||||
{
|
||||
value = 0;
|
||||
}
|
||||
|
||||
public Validity GetValidity ()
|
||||
{
|
||||
int qualityVal = value & 0x3;
|
||||
|
||||
return (Validity)qualityVal;
|
||||
}
|
||||
|
||||
public void SetValidity (Validity validity)
|
||||
{
|
||||
value = (UInt16)(value & 0xfffc);
|
||||
|
||||
value += (ushort)validity;
|
||||
}
|
||||
}
|
||||
|
||||
public enum ACSIClass
|
||||
{
|
||||
/** data objects */
|
||||
ACSI_CLASS_DATA_OBJECT,
|
||||
/** data sets (container for multiple data objects) */
|
||||
ACSI_CLASS_DATA_SET,
|
||||
/** buffered report control blocks */
|
||||
ACSI_CLASS_BRCB,
|
||||
/** unbuffered report control blocks */
|
||||
ACSI_CLASS_URCB,
|
||||
/** log control blocks */
|
||||
ACSI_CLASS_LCB,
|
||||
/** logs (journals) */
|
||||
ACSI_CLASS_LOG,
|
||||
/** setting group control blocks */
|
||||
ACSI_CLASS_SGCB,
|
||||
/** GOOSE control blocks */
|
||||
ACSI_CLASS_GoCB,
|
||||
/** GSE control blocks */
|
||||
ACSI_CLASS_GsCB,
|
||||
/** multicast sampled values control blocks */
|
||||
ACSI_CLASS_MSVCB,
|
||||
/** unicast sampled values control blocks */
|
||||
ACSI_CLASS_USVCB
|
||||
}
|
||||
|
||||
public enum FunctionalConstraint
|
||||
{
|
||||
/** Status information */
|
||||
ST = 0,
|
||||
/** Measurands - analog values */
|
||||
MX = 1,
|
||||
/** Setpoint */
|
||||
SP = 2,
|
||||
/** Substitution */
|
||||
SV = 3,
|
||||
/** Configuration */
|
||||
CF = 4,
|
||||
/** Description */
|
||||
DC = 5,
|
||||
/** Setting group */
|
||||
SG = 6,
|
||||
/** Setting group editable */
|
||||
SE = 7,
|
||||
/** Service response / Service tracking */
|
||||
SR = 8,
|
||||
/** Operate received */
|
||||
OR = 9,
|
||||
/** Blocking */
|
||||
BL = 10,
|
||||
/** Extended definition */
|
||||
EX = 11,
|
||||
/** Control */
|
||||
CO = 12,
|
||||
/** Unicast SV */
|
||||
US = 13,
|
||||
/** Multicast SV */
|
||||
MS = 14,
|
||||
/** Unbuffered report */
|
||||
RP = 15,
|
||||
/** Buffered report */
|
||||
BR = 16,
|
||||
/** Log control blocks */
|
||||
LG = 17,
|
||||
|
||||
/** All FCs - wildcard value */
|
||||
ALL = 99,
|
||||
NONE = -1
|
||||
}
|
||||
|
||||
public enum ControlAddCause {
|
||||
ADD_CAUSE_UNKNOWN = 0,
|
||||
ADD_CAUSE_NOT_SUPPORTED = 1,
|
||||
ADD_CAUSE_BLOCKED_BY_SWITCHING_HIERARCHY = 2,
|
||||
ADD_CAUSE_SELECT_FAILED = 3,
|
||||
ADD_CAUSE_INVALID_POSITION = 4,
|
||||
ADD_CAUSE_POSITION_REACHED = 5,
|
||||
ADD_CAUSE_PARAMETER_CHANGE_IN_EXECUTION = 6,
|
||||
ADD_CAUSE_STEP_LIMIT = 7,
|
||||
ADD_CAUSE_BLOCKED_BY_MODE = 8,
|
||||
ADD_CAUSE_BLOCKED_BY_PROCESS = 9,
|
||||
ADD_CAUSE_BLOCKED_BY_INTERLOCKING = 10,
|
||||
ADD_CAUSE_BLOCKED_BY_SYNCHROCHECK = 11,
|
||||
ADD_CAUSE_COMMAND_ALREADY_IN_EXECUTION = 12,
|
||||
ADD_CAUSE_BLOCKED_BY_HEALTH = 13,
|
||||
ADD_CAUSE_1_OF_N_CONTROL = 14,
|
||||
ADD_CAUSE_ABORTION_BY_CANCEL = 15,
|
||||
ADD_CAUSE_TIME_LIMIT_OVER = 16,
|
||||
ADD_CAUSE_ABORTION_BY_TRIP = 17,
|
||||
ADD_CAUSE_OBJECT_NOT_SELECTED = 18,
|
||||
ADD_CAUSE_OBJECT_ALREADY_SELECTED = 19,
|
||||
ADD_CAUSE_NO_ACCESS_AUTHORITY = 20,
|
||||
ADD_CAUSE_ENDED_WITH_OVERSHOOT = 21,
|
||||
ADD_CAUSE_ABORTION_DUE_TO_DEVIATION = 22,
|
||||
ADD_CAUSE_ABORTION_BY_COMMUNICATION_LOSS = 23,
|
||||
ADD_CAUSE_ABORTION_BY_COMMAND = 24,
|
||||
ADD_CAUSE_NONE = 25,
|
||||
ADD_CAUSE_INCONSISTENT_PARAMETERS = 26,
|
||||
ADD_CAUSE_LOCKED_BY_OTHER_CLIENT = 27
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Object reference. Helper function to handle object reference strings.
|
||||
/// </summary>
|
||||
public static class ObjectReference {
|
||||
|
||||
/// <summary>
|
||||
/// Get the name part of an object reference with appended FC
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The element name.
|
||||
/// </returns>
|
||||
/// <param name='objectReferenceWithFc'>
|
||||
/// Object reference with appended fc.
|
||||
/// </param>
|
||||
public static string getElementName (string objectReferenceWithFc)
|
||||
{
|
||||
int fcPartStartIndex = objectReferenceWithFc.IndexOf('[');
|
||||
|
||||
if (fcPartStartIndex == -1)
|
||||
return objectReferenceWithFc;
|
||||
|
||||
return objectReferenceWithFc.Substring(0, fcPartStartIndex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the FC of an object reference with appended FC.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The FC
|
||||
/// </returns>
|
||||
/// <param name='objectReferenceWithFc'>
|
||||
/// Object reference with FC.
|
||||
/// </param>
|
||||
public static FunctionalConstraint getFC (string objectReferenceWithFc)
|
||||
{
|
||||
int fcPartStartIndex = objectReferenceWithFc.IndexOf('[');
|
||||
|
||||
if (fcPartStartIndex == -1)
|
||||
return FunctionalConstraint.NONE;
|
||||
|
||||
string fcString = objectReferenceWithFc.Substring(fcPartStartIndex + 1 , 2);
|
||||
|
||||
try
|
||||
{
|
||||
return (FunctionalConstraint) Enum.Parse(typeof(FunctionalConstraint), fcString);
|
||||
}
|
||||
catch(ArgumentException)
|
||||
{
|
||||
return FunctionalConstraint.NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -46,6 +46,7 @@
|
|||
<Compile Include="IsoConnectionParameters.cs" />
|
||||
<Compile Include="MmsVariableSpecification.cs" />
|
||||
<Compile Include="IEC61850ServerAPI.cs" />
|
||||
<Compile Include="IEC61850CommonAPI.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
|
@ -17,7 +17,8 @@
|
|||
|
||||
#include "logging_api.h"
|
||||
|
||||
LogStorage SqliteLogStorage_createInstance(const char*);
|
||||
LogStorage
|
||||
SqliteLogStorage_createInstance(const char* filename);
|
||||
|
||||
/* import IEC 61850 device model created from SCL-File */
|
||||
extern IedModel iedModel;
|
||||
|
@ -143,6 +144,8 @@ main(int argc, char** argv)
|
|||
|
||||
LogStorage statusLog = SqliteLogStorage_createInstance("log_status.db");
|
||||
|
||||
LogStorage_setMaxLogEntries(statusLog, 10);
|
||||
|
||||
IedServer_setLogStorage(iedServer, "GenericIO/LLN0$EventLog", statusLog);
|
||||
|
||||
#if 0
|
||||
|
|
|
@ -63,6 +63,9 @@ typedef struct sSqliteLogStorage {
|
|||
sqlite3_stmt* getEntryData;
|
||||
sqlite3_stmt* getOldEntry;
|
||||
sqlite3_stmt* getNewEntry;
|
||||
sqlite3_stmt* getEntriesCount;
|
||||
sqlite3_stmt* deleteEntryData;
|
||||
sqlite3_stmt* deleteEntry;
|
||||
} SqliteLogStorage;
|
||||
|
||||
static const char* CREATE_TABLE_ENTRYS = "create table if not exists Entries (entryID integer primary key, timeOfEntry integer)";
|
||||
|
@ -76,6 +79,11 @@ static const char* GET_ENTRY_DATA = "select dataRef, value, reasonCode from Entr
|
|||
static const char* GET_OLD_ENTRY = "select * from Entries where entryID = (select min(entryID) from Entries where timeOfEntry = (select min(timeOfEntry) from Entries))";
|
||||
static const char* GET_NEW_ENTRY = "select * from Entries where entryID = (select max(entryID) from Entries where timeOfEntry = (select max(timeOfEntry) from Entries))";
|
||||
|
||||
static const char* GET_ENTRIES_COUNT = "select Count(*) from Entries";
|
||||
|
||||
static const char* DELETE_ENTRY_DATA = "delete from EntryData where entryID=?";
|
||||
static const char* DELETE_ENTRY = "delete from Entries where entryID=?";
|
||||
|
||||
static char*
|
||||
copyStringInternal(const char* string)
|
||||
{
|
||||
|
@ -100,6 +108,10 @@ SqliteLogStorage_createInstance(const char* filename)
|
|||
sqlite3_stmt* getEntryData = NULL;
|
||||
sqlite3_stmt* getOldEntry = NULL;
|
||||
sqlite3_stmt* getNewEntry = NULL;
|
||||
sqlite3_stmt* getEntriesCount = NULL;
|
||||
sqlite3_stmt* deleteEntryData = NULL;
|
||||
sqlite3_stmt* deleteEntry = NULL;
|
||||
|
||||
char *zErrMsg = 0;
|
||||
|
||||
int rc = sqlite3_open(filename, &db);
|
||||
|
@ -143,6 +155,18 @@ SqliteLogStorage_createInstance(const char* filename)
|
|||
if (rc != SQLITE_OK)
|
||||
goto exit_with_error;
|
||||
|
||||
rc = sqlite3_prepare_v2(db, GET_ENTRIES_COUNT, -1, &getEntriesCount, NULL);
|
||||
if (rc != SQLITE_OK)
|
||||
goto exit_with_error;
|
||||
|
||||
rc = sqlite3_prepare_v2(db, DELETE_ENTRY_DATA, -1, &deleteEntryData, NULL);
|
||||
if (rc != SQLITE_OK)
|
||||
goto exit_with_error;
|
||||
|
||||
rc = sqlite3_prepare_v2(db, DELETE_ENTRY, -1, &deleteEntry, NULL);
|
||||
if (rc != SQLITE_OK)
|
||||
goto exit_with_error;
|
||||
|
||||
LogStorage self = (LogStorage) calloc(1, sizeof(struct sLogStorage));
|
||||
|
||||
SqliteLogStorage* instanceData = (SqliteLogStorage*) calloc(1, sizeof(struct sSqliteLogStorage));
|
||||
|
@ -156,6 +180,9 @@ SqliteLogStorage_createInstance(const char* filename)
|
|||
instanceData->getEntryData = getEntryData;
|
||||
instanceData->getOldEntry = getOldEntry;
|
||||
instanceData->getNewEntry = getNewEntry;
|
||||
instanceData->getEntriesCount = getEntriesCount;
|
||||
instanceData->deleteEntryData = deleteEntryData;
|
||||
instanceData->deleteEntry = deleteEntry;
|
||||
|
||||
self->instanceData = (void*) instanceData;
|
||||
|
||||
|
@ -165,6 +192,7 @@ SqliteLogStorage_createInstance(const char* filename)
|
|||
self->getEntriesAfter = SqliteLogStorage_getEntriesAfter;
|
||||
self->getOldestAndNewestEntries = SqliteLogStorage_getOldestAndNewestEntries;
|
||||
self->destroy = SqliteLogStorage_destroy;
|
||||
self->maxLogEntries = -1;
|
||||
|
||||
return self;
|
||||
|
||||
|
@ -175,6 +203,87 @@ exit_with_error:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
deleteOldestEntry(SqliteLogStorage* self)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* Get oldest entry */
|
||||
rc = sqlite3_reset(self->getOldEntry);
|
||||
|
||||
if (rc != SQLITE_OK)
|
||||
goto exit_with_error;
|
||||
|
||||
rc = sqlite3_step(self->getOldEntry);
|
||||
|
||||
int64_t entryId;
|
||||
|
||||
if (rc == SQLITE_ROW) {
|
||||
entryId = sqlite3_column_int64(self->getOldEntry, 0);
|
||||
|
||||
sqlite3_reset(self->deleteEntryData);
|
||||
|
||||
rc = sqlite3_bind_int64(self->deleteEntryData, 1, (sqlite_int64) entryId);
|
||||
|
||||
rc = sqlite3_step(self->deleteEntryData);
|
||||
|
||||
if (rc != SQLITE_DONE)
|
||||
goto exit_with_error;
|
||||
|
||||
sqlite3_reset(self->deleteEntry);
|
||||
|
||||
rc = sqlite3_bind_int64(self->deleteEntry, 1, (sqlite_int64) entryId);
|
||||
|
||||
rc = sqlite3_step(self->deleteEntry);
|
||||
|
||||
if (rc != SQLITE_DONE)
|
||||
goto exit_with_error;
|
||||
|
||||
}
|
||||
else
|
||||
goto exit_with_error;
|
||||
|
||||
return;
|
||||
|
||||
exit_with_error:
|
||||
if (DEBUG_LOG_STORAGE_DRIVER)
|
||||
printf("LOG_STORAGE_DRIVER: sqlite - failed to delete oldest entry (rc=%i)!\n", rc);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int
|
||||
getEntriesCount(SqliteLogStorage* self)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = sqlite3_reset(self->getEntriesCount);
|
||||
|
||||
if (rc != SQLITE_OK)
|
||||
goto exit_with_error;
|
||||
|
||||
rc = sqlite3_step(self->getEntriesCount);
|
||||
|
||||
int entryCount = sqlite3_column_int(self->getEntriesCount, 0);
|
||||
|
||||
return entryCount;
|
||||
|
||||
exit_with_error:
|
||||
if (DEBUG_LOG_STORAGE_DRIVER)
|
||||
printf("LOG_STORAGE_DRIVER: sqlite - failed to get entry count! (rc=%i)\n", rc);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void
|
||||
trimToMaxEntries(SqliteLogStorage* self, int maxEntries)
|
||||
{
|
||||
int deleteEntries = getEntriesCount(self) - maxEntries;
|
||||
|
||||
int i;
|
||||
for (i = 0; i < deleteEntries; i++)
|
||||
deleteOldestEntry(self);
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
SqliteLogStorage_addEntry(LogStorage self, uint64_t timestamp)
|
||||
|
@ -208,6 +317,11 @@ SqliteLogStorage_addEntry(LogStorage self, uint64_t timestamp)
|
|||
if (rc != SQLITE_OK)
|
||||
goto exit_with_error;
|
||||
|
||||
if (self->maxLogEntries > 0) {
|
||||
if (getEntriesCount(instanceData) > self->maxLogEntries)
|
||||
trimToMaxEntries(instanceData, self->maxLogEntries);
|
||||
}
|
||||
|
||||
return id;
|
||||
|
||||
exit_with_error:
|
||||
|
@ -379,6 +493,7 @@ SqliteLogStorage_getOldestAndNewestEntries(LogStorage self, uint64_t* newEntry,
|
|||
int rc;
|
||||
|
||||
/* Get oldest entry */
|
||||
sqlite3_reset(instanceData->getOldEntry);
|
||||
|
||||
rc = sqlite3_step(instanceData->getOldEntry);
|
||||
|
||||
|
@ -392,9 +507,9 @@ SqliteLogStorage_getOldestAndNewestEntries(LogStorage self, uint64_t* newEntry,
|
|||
*oldEntryTime = 0;
|
||||
}
|
||||
|
||||
sqlite3_reset(instanceData->getOldEntry);
|
||||
|
||||
/* Get newest entry */
|
||||
sqlite3_reset(instanceData->getNewEntry);
|
||||
|
||||
rc = sqlite3_step(instanceData->getNewEntry);
|
||||
|
||||
|
@ -408,8 +523,6 @@ SqliteLogStorage_getOldestAndNewestEntries(LogStorage self, uint64_t* newEntry,
|
|||
*newEntryTime = 0;
|
||||
}
|
||||
|
||||
sqlite3_reset(instanceData->getNewEntry);
|
||||
|
||||
return (validOldEntry && validNewEntry);
|
||||
}
|
||||
|
||||
|
@ -471,6 +584,9 @@ SqliteLogStorage_destroy(LogStorage self)
|
|||
sqlite3_finalize(instanceData->getEntryData);
|
||||
sqlite3_finalize(instanceData->getOldEntry);
|
||||
sqlite3_finalize(instanceData->getNewEntry);
|
||||
sqlite3_finalize(instanceData->getEntriesCount);
|
||||
sqlite3_finalize(instanceData->deleteEntryData);
|
||||
sqlite3_finalize(instanceData->deleteEntry);
|
||||
|
||||
if (sqlite3_close(instanceData->db) != SQLITE_OK)
|
||||
if (DEBUG_LOG_STORAGE_DRIVER)
|
||||
|
|
|
@ -23,6 +23,13 @@
|
|||
|
||||
#include "logging_api.h"
|
||||
|
||||
|
||||
void
|
||||
LogStorage_setMaxLogEntries(LogStorage self, int maxEntries)
|
||||
{
|
||||
self->maxLogEntries = maxEntries;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
LogStorage_addEntry(LogStorage self, uint64_t timestamp)
|
||||
{
|
||||
|
|
|
@ -41,7 +41,7 @@ extern "C" {
|
|||
*
|
||||
* This interface has to be implemented by the log storage provider. The Log storage provider
|
||||
* has to provide a specific constructor that creates an instance of LogStorage by allocating
|
||||
* the required memory fot the struct sLogStorage data structure and populate the function
|
||||
* the required memory for the struct sLogStorage data structure and populate the function
|
||||
* pointers with provider specific implementation functions.
|
||||
*
|
||||
* @{
|
||||
|
@ -80,6 +80,8 @@ struct sLogStorage {
|
|||
|
||||
void* instanceData;
|
||||
|
||||
int maxLogEntries;
|
||||
|
||||
uint64_t (*addEntry) (LogStorage self, uint64_t timestamp);
|
||||
|
||||
bool (*addEntryData) (LogStorage self, uint64_t entryID, const char* dataRef, uint8_t* data, int dataSize, uint8_t reasonCode);
|
||||
|
@ -97,6 +99,15 @@ struct sLogStorage {
|
|||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Set the maximum number of log entries for this log
|
||||
*
|
||||
* \param self the pointer of the LogStorage instance
|
||||
* \param maxEntries the maximum number of log entries
|
||||
*/
|
||||
void
|
||||
LogStorage_setMaxLogEntries(LogStorage self, int maxEntries);
|
||||
|
||||
/**
|
||||
* \brief Add an entry to the log
|
||||
*
|
||||
|
|
Loading…
Add table
Reference in a new issue