diff --git a/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs b/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs
index ef82f76..a6a0adc 100644
--- a/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs
+++ b/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs
@@ -431,6 +431,10 @@ namespace IEC61850
}
}
+ ///
+ /// Gets the connection parameters
+ ///
+ /// The connection parameters
public IsoConnectionParameters GetConnectionParameters ()
{
IntPtr mmsConnection = IedConnection_getMmsConnection(connection);
@@ -448,6 +452,10 @@ namespace IEC61850
private UInt32 connectTimeout = 10000;
+ ///
+ /// Gets or sets the timeout used for connection attempts.
+ ///
+ /// The connect timeout in milliseconds
public UInt32 ConnectTimeout {
get {
return connectTimeout;
@@ -493,7 +501,15 @@ namespace IEC61850
return controlObject;
}
-
+
+
+
+
+
+
+ ///
+ /// Updates the device model by quering the server.
+ ///
public void UpdateDeviceModel()
{
int error;
@@ -504,6 +520,12 @@ namespace IEC61850
throw new IedConnectionException("UpdateDeviceModel failed", error);
}
+
+ ///
+ /// Gets the server directory (Logical devices or file objects)
+ ///
+ /// List of logical devices or files
+ /// If set to true the file directory is returned, otherwise the LD names
/// This exception is thrown if there is a connection or service error
public List GetServerDirectory (bool fileDirectory = false)
{
@@ -731,6 +753,7 @@ namespace IEC61850
/// EntryID of the last received MmsJournalEntry
/// Timestamp of the last received MmsJournalEntry
/// Indicates that more log entries are available
+ /// This exception is thrown if there is a connection or service error
public List QueryLogAfter(string logRef, byte[] entryID, ulong timestamp, out bool moreFollows)
{
int error;
@@ -756,6 +779,7 @@ namespace IEC61850
/// Start time of the time range
/// End time of the time range
/// Indicates that more log entries are available
+ /// This exception is thrown if there is a connection or service error
public List 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);
- }
-
///
/// Queries all log entries of the given time range
///
@@ -798,10 +804,11 @@ namespace IEC61850
/// Start time of the time range
/// End time of the time range
/// Indicates that more log entries are available
+ /// This exception is thrown if there is a connection or service error
public List 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
- }
-
- ///
- /// The quality of a data object.
- ///
- 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
- }
-
- ///
- /// Object reference. Helper function to handle object reference strings.
- ///
- public static class ObjectReference {
-
- ///
- /// Get the name part of an object reference with appended FC
- ///
- ///
- /// The element name.
- ///
- ///
- /// Object reference with appended fc.
- ///
- public static string getElementName (string objectReferenceWithFc)
- {
- int fcPartStartIndex = objectReferenceWithFc.IndexOf('[');
-
- if (fcPartStartIndex == -1)
- return objectReferenceWithFc;
-
- return objectReferenceWithFc.Substring(0, fcPartStartIndex);
- }
-
- ///
- /// Get the FC of an object reference with appended FC.
- ///
- ///
- /// The FC
- ///
- ///
- /// Object reference with FC.
- ///
- 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;
- }
- }
- }
-
- }
}
diff --git a/dotnet/IEC61850forCSharp/IEC61850CommonAPI.cs b/dotnet/IEC61850forCSharp/IEC61850CommonAPI.cs
new file mode 100644
index 0000000..ac08ca4
--- /dev/null
+++ b/dotnet/IEC61850forCSharp/IEC61850CommonAPI.cs
@@ -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();
+
+ ///
+ /// Get the version string of the native libiec61850 library
+ ///
+ /// The version string in format MAJOR.MINOR.PATCH
+ public static string GetVersionString()
+ {
+ return Marshal.PtrToStringAnsi (LibIEC61850_getVersionString ());
+ }
+
+ ///
+ /// Converts millisecond timestamp to a DateTime object
+ ///
+ /// The DateTime object representing the value of the timestamp
+ /// The timestamp in milliseconds since epoch (UTC)
+ 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;
+ }
+
+ ///
+ /// Converts a DateTime object in milliseconds since epoch timestamp (UTC)
+ ///
+ /// The timestamp in ms
+ /// The DateTime object to convert
+ 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
+ }
+
+ ///
+ /// The quality of a data object.
+ ///
+ 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
+ }
+
+ ///
+ /// Object reference. Helper function to handle object reference strings.
+ ///
+ public static class ObjectReference {
+
+ ///
+ /// Get the name part of an object reference with appended FC
+ ///
+ ///
+ /// The element name.
+ ///
+ ///
+ /// Object reference with appended fc.
+ ///
+ public static string getElementName (string objectReferenceWithFc)
+ {
+ int fcPartStartIndex = objectReferenceWithFc.IndexOf('[');
+
+ if (fcPartStartIndex == -1)
+ return objectReferenceWithFc;
+
+ return objectReferenceWithFc.Substring(0, fcPartStartIndex);
+ }
+
+ ///
+ /// Get the FC of an object reference with appended FC.
+ ///
+ ///
+ /// The FC
+ ///
+ ///
+ /// Object reference with FC.
+ ///
+ 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;
+ }
+ }
+ }
+
+ }
+}
+
diff --git a/dotnet/IEC61850forCSharp/IEC61850forCSharp.csproj b/dotnet/IEC61850forCSharp/IEC61850forCSharp.csproj
index e0019db..e64649d 100644
--- a/dotnet/IEC61850forCSharp/IEC61850forCSharp.csproj
+++ b/dotnet/IEC61850forCSharp/IEC61850forCSharp.csproj
@@ -46,6 +46,7 @@
+
\ No newline at end of file
diff --git a/examples/server_example_logging/server_example_logging.c b/examples/server_example_logging/server_example_logging.c
index f0c80ae..938b6aa 100644
--- a/examples/server_example_logging/server_example_logging.c
+++ b/examples/server_example_logging/server_example_logging.c
@@ -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
diff --git a/src/logging/drivers/sqlite/log_storage_sqlite.c b/src/logging/drivers/sqlite/log_storage_sqlite.c
index 07b0409..426e0a6 100644
--- a/src/logging/drivers/sqlite/log_storage_sqlite.c
+++ b/src/logging/drivers/sqlite/log_storage_sqlite.c
@@ -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)
diff --git a/src/logging/log_storage.c b/src/logging/log_storage.c
index e7847e4..4033551 100644
--- a/src/logging/log_storage.c
+++ b/src/logging/log_storage.c
@@ -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)
{
diff --git a/src/logging/logging_api.h b/src/logging/logging_api.h
index 403c3fb..880b298 100644
--- a/src/logging/logging_api.h
+++ b/src/logging/logging_api.h
@@ -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
*