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 *