mirror of
https://github.com/intrepidcs/libicsneo.git
synced 2026-08-05 01:18:36 +02:00
Add error system
This commit is contained in:
@@ -0,0 +1,115 @@
|
||||
#ifndef __ICSNEO_API_ERROR_H_
|
||||
#define __ICSNEO_API_ERROR_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define CONSTEXPR constexpr
|
||||
#else
|
||||
#define CONSTEXPR const
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
const char* description;
|
||||
time_t timestamp;
|
||||
uint32_t errorNumber;
|
||||
uint8_t severity;
|
||||
char serial[7];
|
||||
uint8_t reserved[16];
|
||||
} neoerror_t;
|
||||
|
||||
#include <vector>
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
#include <ostream>
|
||||
|
||||
namespace icsneo {
|
||||
|
||||
class Device;
|
||||
|
||||
class APIError {
|
||||
public:
|
||||
enum ErrorType : uint32_t {
|
||||
Any = 0, // Used for filtering, should not appear in data
|
||||
|
||||
// API Errors
|
||||
InvalidNeoDevice = 0x1000,
|
||||
RequiredParameterNull = 0x1001,
|
||||
BufferInsufficient = 0x1002,
|
||||
OutputTruncated = 0x1003,
|
||||
ParameterOutOfRange = 0x1004,
|
||||
|
||||
// Device Errors
|
||||
PollingMessageOverflow = 0x2000,
|
||||
NoSerialNumber = 0x2001,
|
||||
IncorrectSerialNumber = 0x2002,
|
||||
SettingsReadError = 0x2003,
|
||||
SettingsVersionError = 0x2004,
|
||||
SettingsLengthError = 0x2005,
|
||||
SettingsChecksumError = 0x2006,
|
||||
SettingsNotAvailable = 0x2007,
|
||||
|
||||
TooManyErrors = 0xFFFFFFFE,
|
||||
Unknown = 0xFFFFFFFF
|
||||
};
|
||||
enum class Severity : uint8_t {
|
||||
Any = 0, // Used for filtering, should not appear in data
|
||||
Info = 0x10,
|
||||
Warning = 0x20,
|
||||
Error = 0x30
|
||||
};
|
||||
|
||||
APIError(ErrorType error);
|
||||
APIError(ErrorType error, const Device* device);
|
||||
|
||||
ErrorType getType() const noexcept { return ErrorType(errorStruct.errorNumber); }
|
||||
Severity getSeverity() const noexcept { return Severity(errorStruct.severity); }
|
||||
std::string getDescription() const noexcept { return std::string(errorStruct.description); }
|
||||
const Device* getDevice() const noexcept { return device; } // Will return nullptr if this is an API-wide error
|
||||
std::chrono::time_point<std::chrono::high_resolution_clock> getTimestamp() const noexcept { return timepoint; }
|
||||
|
||||
bool isForDevice(Device* forDevice) const noexcept { return forDevice == device; }
|
||||
bool isForDevice(std::string serial) const noexcept;
|
||||
|
||||
// As opposed to getDescription, this will also add text such as "neoVI FIRE 2 CY2468 Error: " to fully describe the problem
|
||||
std::string describe() const noexcept;
|
||||
friend std::ostream& operator<<(std::ostream& os, const APIError& error) {
|
||||
os << error.describe();
|
||||
return os;
|
||||
}
|
||||
|
||||
static const char* DescriptionForType(ErrorType type);
|
||||
static Severity SeverityForType(ErrorType type);
|
||||
|
||||
private:
|
||||
neoerror_t errorStruct;
|
||||
std::string serial;
|
||||
std::chrono::time_point<std::chrono::high_resolution_clock> timepoint;
|
||||
const Device* device;
|
||||
|
||||
void init(ErrorType error);
|
||||
};
|
||||
|
||||
class ErrorFilter {
|
||||
public:
|
||||
ErrorFilter() {} // Empty filter matches anything
|
||||
ErrorFilter(APIError::ErrorType error) : type(error) {}
|
||||
ErrorFilter(APIError::Severity severity) : severity(severity) {}
|
||||
ErrorFilter(Device* device, APIError::ErrorType error = APIError::Any) : type(error), matchOnDevicePtr(true), device(device) {}
|
||||
ErrorFilter(Device* device, APIError::Severity severity = APIError::Severity::Any) : severity(severity), matchOnDevicePtr(true), device(device) {}
|
||||
ErrorFilter(std::string serial, APIError::ErrorType error = APIError::Any) : type(error), serial(serial) {}
|
||||
ErrorFilter(std::string serial, APIError::Severity severity = APIError::Severity::Any) : severity(severity), serial(serial) {}
|
||||
|
||||
bool match(const APIError& error) const noexcept;
|
||||
|
||||
APIError::Severity severity = APIError::Severity::Any;
|
||||
APIError::ErrorType type = APIError::Any;
|
||||
bool matchOnDevicePtr = false;
|
||||
Device* device = nullptr; // nullptr will match on "no device, generic API error"
|
||||
std::string serial; // Empty serial will match any, including no device. Not affected by matchOnDevicePtr
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,98 @@
|
||||
#ifndef __ICSNEO_API_ERRORMANAGER_H_
|
||||
#define __ICSNEO_API_ERRORMANAGER_H_
|
||||
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <mutex>
|
||||
#include <functional>
|
||||
#include "icsneo/api/error.h"
|
||||
|
||||
namespace icsneo {
|
||||
|
||||
typedef std::function<void (APIError::ErrorType)> device_errorhandler_t;
|
||||
|
||||
class ErrorManager {
|
||||
public:
|
||||
static ErrorManager& GetInstance();
|
||||
|
||||
size_t count(ErrorFilter filter = ErrorFilter()) const {
|
||||
std::lock_guard<std::mutex> lk(mutex);
|
||||
return count_internal(filter);
|
||||
};
|
||||
|
||||
std::vector<APIError> get(ErrorFilter filter, size_t max = 0) { return get(max, filter); }
|
||||
std::vector<APIError> get(size_t max = 0, ErrorFilter filter = ErrorFilter()) {
|
||||
std::vector<APIError> ret;
|
||||
get(ret, filter, max);
|
||||
return ret;
|
||||
}
|
||||
void get(std::vector<APIError>& errors, ErrorFilter filter, size_t max = 0) { get(errors, max, filter); }
|
||||
void get(std::vector<APIError>& errors, size_t max = 0, ErrorFilter filter = ErrorFilter());
|
||||
bool getOne(APIError& error, ErrorFilter filter = ErrorFilter());
|
||||
|
||||
void add(APIError error) {
|
||||
std::lock_guard<std::mutex> lk(mutex);
|
||||
add_internal(error);
|
||||
}
|
||||
void add(APIError::ErrorType type) {
|
||||
std::lock_guard<std::mutex> lk(mutex);
|
||||
add_internal(type);
|
||||
}
|
||||
void add(APIError::ErrorType type, const Device* forDevice) {
|
||||
std::lock_guard<std::mutex> lk(mutex);
|
||||
add_internal(type, forDevice);
|
||||
}
|
||||
|
||||
void discard(ErrorFilter filter = ErrorFilter());
|
||||
|
||||
void setErrorLimit(size_t newLimit) {
|
||||
if(newLimit < 10) {
|
||||
add(APIError::ParameterOutOfRange);
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lk(mutex);
|
||||
errorLimit = newLimit;
|
||||
enforceLimit();
|
||||
}
|
||||
|
||||
size_t getErrorLimit() const { return errorLimit; }
|
||||
|
||||
private:
|
||||
ErrorManager() {}
|
||||
mutable std::mutex mutex;
|
||||
std::list<APIError> errors;
|
||||
size_t errorLimit = 10000;
|
||||
|
||||
size_t count_internal(ErrorFilter filter = ErrorFilter()) const;
|
||||
|
||||
void add_internal(APIError error) {
|
||||
if(!beforeAddCheck(error.getType()))
|
||||
return;
|
||||
errors.push_back(error);
|
||||
enforceLimit();
|
||||
}
|
||||
void add_internal(APIError::ErrorType type) {
|
||||
if(!beforeAddCheck(type))
|
||||
return;
|
||||
errors.emplace_back(type);
|
||||
enforceLimit();
|
||||
}
|
||||
void add_internal(APIError::ErrorType type, const Device* forDevice) {
|
||||
if(!beforeAddCheck(type))
|
||||
return;
|
||||
errors.emplace_back(type, forDevice);
|
||||
enforceLimit();
|
||||
}
|
||||
|
||||
bool beforeAddCheck(APIError::ErrorType type); // Returns whether the error should be added
|
||||
|
||||
bool enforceLimit(); // Returns whether the limit enforcement resulted in an overflow
|
||||
|
||||
APIError::Severity lowestCurrentSeverity();
|
||||
void discardLeastSevere(size_t count = 1);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user