diff --git a/api/icsneoc/icsneoc.cpp b/api/icsneoc/icsneoc.cpp index 12baf19..0df047b 100644 --- a/api/icsneoc/icsneoc.cpp +++ b/api/icsneoc/icsneoc.cpp @@ -376,4 +376,83 @@ bool icsneo_describeDevice(const neodevice_t* device, char* str, size_t* maxLeng neoversion_t icsneo_getVersion(void) { return icsneo::GetVersion(); +} + +bool icsneo_getErrors(neoerror_t* errors, size_t* size) { + if(size == nullptr) { + ErrorManager::GetInstance().add(APIError::RequiredParameterNull); + return false; + } + + if(errors == nullptr) { + *size = icsneo::ErrorCount(); + return false; + } + + auto cppErrors = icsneo::GetErrors(*size); + for(size_t i = 0; i < cppErrors.size(); i++) + memcpy(&errors[i], cppErrors[i].getNeoError(), sizeof(neoerror_t)); + *size = cppErrors.size(); + + return true; +} + +bool icsneo_getDeviceErrors(const neodevice_t* device, neoerror_t* errors, size_t* size) { + if(!icsneo_isValidNeoDevice(device)) { + ErrorManager::GetInstance().add(APIError::InvalidNeoDevice); + return false; + } + + if(size == nullptr) { + ErrorManager::GetInstance().add(APIError::RequiredParameterNull); + return false; + } + + ErrorFilter filter = (icsneo::Device*)device->device; + + if(errors == nullptr) { + *size = icsneo::ErrorCount(filter); + return false; + } + + auto cppErrors = icsneo::GetErrors(*size, filter); + for(size_t i = 0; i < cppErrors.size(); i++) + memcpy(&errors[i], cppErrors[i].getNeoError(), sizeof(neoerror_t)); + *size = cppErrors.size(); + + return true; +} + +bool icsneo_getLastError(neoerror_t* error) { + if(error == nullptr) { + ErrorManager::GetInstance().add(APIError::RequiredParameterNull); + return false; + } + + APIError cppErr; + if(!icsneo::GetLastError(cppErr)) + return false; + memcpy(error, cppErr.getNeoError(), sizeof(neoerror_t)); + return true; +} + +void icsneo_discardAllErrors(void) { + icsneo::DiscardErrors(); +} + +void icsneo_discardDeviceErrors(const neodevice_t* device) { + if(!icsneo_isValidNeoDevice(device)) { + ErrorManager::GetInstance().add(APIError::InvalidNeoDevice); + return; + } + + icsneo::DiscardErrors(icsneo::ErrorFilter((icsneo::Device*)device->device)); +} + +void icsneo_setErrorLimit(size_t newLimit) { + icsneo::SetErrorLimit(newLimit); +} + +size_t icsneo_getErrorLimit(void) { + return icsneo::GetErrorLimit(); } \ No newline at end of file diff --git a/api/icsneocpp/errormanager.cpp b/api/icsneocpp/errormanager.cpp index 08f1f6a..5f13a17 100644 --- a/api/icsneocpp/errormanager.cpp +++ b/api/icsneocpp/errormanager.cpp @@ -27,20 +27,25 @@ void ErrorManager::get(std::vector& errorOutput, size_t max, ErrorFilt if(count++ >= max) break; // We now have as many written to output as we can } else { - it++; + std::advance(it, 1); } } } -bool ErrorManager::getOne(APIError& errorOutput, ErrorFilter filter) { - std::vector output; - get(output, filter, 1); +bool ErrorManager::getLastError(APIError& errorOutput, ErrorFilter filter) { + std::lock_guard lk(mutex); - if(output.size() == 0) - return false; - - errorOutput = output[0]; - return true; + auto it = errors.rbegin(); + while(it != errors.rend()) { + if(filter.match(*it)) { + errorOutput = *it; + errors.erase(std::next(it).base()); + return true; + } + std::advance(it, 1); + } + + return false; } void ErrorManager::discard(ErrorFilter filter) { diff --git a/api/icsneocpp/icsneocpp.cpp b/api/icsneocpp/icsneocpp.cpp index aa24b7d..dfa2d00 100644 --- a/api/icsneocpp/icsneocpp.cpp +++ b/api/icsneocpp/icsneocpp.cpp @@ -5,4 +5,40 @@ using namespace icsneo; std::vector> icsneo::FindAllDevices() { return DeviceFinder::FindAll(); +} + +size_t icsneo::ErrorCount(ErrorFilter filter) { + return ErrorManager::GetInstance().count(filter); +} + +std::vector icsneo::GetErrors(ErrorFilter filter, size_t max) { + return ErrorManager::GetInstance().get(filter, max); +} + +std::vector icsneo::GetErrors(size_t max, ErrorFilter filter) { + return ErrorManager::GetInstance().get(max, filter); +} + +void icsneo::GetErrors(std::vector& errors, ErrorFilter filter, size_t max) { + ErrorManager::GetInstance().get(errors, filter, max); +} + +void icsneo::GetErrors(std::vector& errors, size_t max, ErrorFilter filter) { + ErrorManager::GetInstance().get(errors, max, filter); +} + +bool icsneo::GetLastError(APIError& error, ErrorFilter filter) { + return ErrorManager::GetInstance().getLastError(error, filter); +} + +void icsneo::DiscardErrors(ErrorFilter filter) { + ErrorManager::GetInstance().discard(filter); +} + +void icsneo::SetErrorLimit(size_t newLimit) { + ErrorManager::GetInstance().setErrorLimit(newLimit); +} + +size_t icsneo::GetErrorLimit() { + return ErrorManager::GetInstance().getErrorLimit(); } \ No newline at end of file diff --git a/include/icsneo/api/error.h b/include/icsneo/api/error.h index b103e2b..e915a12 100644 --- a/include/icsneo/api/error.h +++ b/include/icsneo/api/error.h @@ -19,6 +19,8 @@ typedef struct { uint8_t reserved[16]; } neoerror_t; +#ifdef __cplusplus + #include #include #include @@ -68,16 +70,18 @@ public: Error = 0x30 }; + APIError() : errorStruct({}), device(nullptr) {} APIError(ErrorType error); APIError(ErrorType error, const Device* device); + const neoerror_t* getNeoError() const noexcept { return &errorStruct; } 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 getTimestamp() const noexcept { return timepoint; } - bool isForDevice(Device* forDevice) const noexcept { return forDevice == device; } + bool isForDevice(const 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 @@ -104,20 +108,22 @@ 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(const Device* device, APIError::ErrorType error = APIError::Any) : type(error), matchOnDevicePtr(true), device(device) {} + ErrorFilter(const Device* device, APIError::Severity severity) : 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) {} + ErrorFilter(std::string serial, APIError::Severity severity) : 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" + const 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 // __cplusplus + #endif \ No newline at end of file diff --git a/include/icsneo/api/errormanager.h b/include/icsneo/api/errormanager.h index 896557b..eb4b43e 100644 --- a/include/icsneo/api/errormanager.h +++ b/include/icsneo/api/errormanager.h @@ -28,7 +28,7 @@ public: } void get(std::vector& errors, ErrorFilter filter, size_t max = 0) { get(errors, max, filter); } void get(std::vector& errors, size_t max = 0, ErrorFilter filter = ErrorFilter()); - bool getOne(APIError& error, ErrorFilter filter = ErrorFilter()); + bool getLastError(APIError& error, ErrorFilter filter = ErrorFilter()); void add(APIError error) { std::lock_guard lk(mutex); diff --git a/include/icsneo/icsneoc.h b/include/icsneo/icsneoc.h index ea629b4..04a9172 100644 --- a/include/icsneo/icsneoc.h +++ b/include/icsneo/icsneoc.h @@ -7,6 +7,7 @@ #include "icsneo/platform/dynamiclib.h" // Dynamic library loading and exporting #include "icsneo/communication/network.h" // Network type and netID defines #include "icsneo/api/version.h" // For version info +#include "icsneo/api/error.h" // For error info #ifndef ICSNEOC_DYNAMICLOAD @@ -68,6 +69,20 @@ extern bool DLLExport icsneo_describeDevice(const neodevice_t* device, char* str extern neoversion_t DLLExport icsneo_getVersion(void); +extern bool DLLExport icsneo_getErrors(neoerror_t* errors, size_t* size); + +extern bool DLLExport icsneo_getDeviceErrors(const neodevice_t* device, neoerror_t* errors, size_t* size); + +extern bool DLLExport icsneo_getLastError(neoerror_t* error); + +extern void DLLExport icsneo_discardAllErrors(void); + +extern void DLLExport icsneo_discardDeviceErrors(const neodevice_t* device); + +extern void DLLExport icsneo_setErrorLimit(size_t newLimit); + +extern size_t DLLExport icsneo_getErrorLimit(void); + #ifdef __cplusplus } // extern "C" #endif @@ -155,6 +170,27 @@ fn_icsneo_describeDevice icsneo_describeDevice; typedef neoversion_t(*fn_icsneo_getVersion)(void); fn_icsneo_getVersion icsneo_getVersion; +typedef bool(*fn_icsneo_getErrors)(neoerror_t* errors, size_t* size); +fn_icsneo_getErrors icsneo_getErrors; + +typedef bool(*fn_icsneo_getDeviceErrors)(const neodevice_t* device, neoerror_t* errors, size_t* size); +fn_icsneo_getDeviceErrors icsneo_getDeviceErrors; + +typedef bool(*fn_icsneo_getLastError)(neoerror_t* error); +fn_icsneo_getLastError icsneo_getLastError; + +typedef void(*fn_icsneo_discardAllErrors)(void); +fn_icsneo_discardAllErrors icsneo_discardAllErrors; + +typedef void(*fn_icsneo_discardDeviceErrors)(const neodevice_t* device); +fn_icsneo_discardDeviceErrors icsneo_discardDeviceErrors; + +typedef void(*fn_icsneo_setErrorLimit)(size_t newLimit); +fn_icsneo_setErrorLimit icsneo_setErrorLimit; + +typedef size_t(*fn_icsneo_getErrorLimit)(void); +fn_icsneo_getErrorLimit icsneo_getErrorLimit; + #define ICSNEO_IMPORT(func) func = (fn_##func)icsneo_dynamicLibraryGetFunction(icsneo_libraryHandle, #func) #define ICSNEO_IMPORTASSERT(func) if((ICSNEO_IMPORT(func)) == NULL) return 3 void* icsneo_libraryHandle = NULL; @@ -196,6 +232,13 @@ int icsneo_init() { ICSNEO_IMPORTASSERT(icsneo_transmitMessages); ICSNEO_IMPORTASSERT(icsneo_describeDevice); ICSNEO_IMPORTASSERT(icsneo_getVersion); + ICSNEO_IMPORTASSERT(icsneo_getErrors); + ICSNEO_IMPORTASSERT(icsneo_getDeviceErrors); + ICSNEO_IMPORTASSERT(icsneo_getLastError); + ICSNEO_IMPORTASSERT(icsneo_discardAllErrors); + ICSNEO_IMPORTASSERT(icsneo_discardDeviceErrors); + ICSNEO_IMPORTASSERT(icsneo_setErrorLimit); + ICSNEO_IMPORTASSERT(icsneo_getErrorLimit); icsneo_initialized = true; return 0; diff --git a/include/icsneo/icsneocpp.h b/include/icsneo/icsneocpp.h index a379a4e..0003a39 100644 --- a/include/icsneo/icsneocpp.h +++ b/include/icsneo/icsneocpp.h @@ -6,11 +6,22 @@ #include "icsneo/device/device.h" #include "icsneo/api/version.h" +#include "icsneo/api/errormanager.h" namespace icsneo { std::vector> FindAllDevices(); +size_t ErrorCount(ErrorFilter filter = ErrorFilter()); +std::vector GetErrors(ErrorFilter filter, size_t max = 0); +std::vector GetErrors(size_t max = 0, ErrorFilter filter = ErrorFilter()); +void GetErrors(std::vector& errors, ErrorFilter filter, size_t max = 0); +void GetErrors(std::vector& errors, size_t max = 0, ErrorFilter filter = ErrorFilter()); +bool GetLastError(APIError& error, ErrorFilter filter = ErrorFilter()); +void DiscardErrors(ErrorFilter filter = ErrorFilter()); +void SetErrorLimit(size_t newLimit); +size_t GetErrorLimit(); + } #endif \ No newline at end of file