diff --git a/DeviceAdapters/AlliedVisionCamera/AlliedVisionCamera.cpp b/DeviceAdapters/AlliedVisionCamera/AlliedVisionCamera.cpp new file mode 100644 index 000000000..fbc80e37c --- /dev/null +++ b/DeviceAdapters/AlliedVisionCamera/AlliedVisionCamera.cpp @@ -0,0 +1,1411 @@ +/*============================================================================= + Copyright (C) 2023 Allied Vision Technologies. All Rights Reserved. + + This file is distributed under the BSD license. + License text is included with the source distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF TITLE, + NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=============================================================================*/ +#define NOMINMAX // +#include +#include +#include +#include + +#include "AlliedVisionHub.h" +#include "ModuleInterface.h" +#include "VmbC/VmbC.h" + +/////////////////////////////////////////////////////////////////////////////// +// STATIC VALUES +/////////////////////////////////////////////////////////////////////////////// + +constexpr const char *ADJUST_PACKAGE_SIZE_COMMAND = "GVSPAdjustPacketSize"; + +const std::unordered_map AlliedVisionCamera::m_featureToProperty = { { g_PixelFormatFeature, + MM::g_Keyword_PixelType } }; +const std::unordered_set AlliedVisionCamera::m_ipAddressFeatures = { + "MulticastIPAddress", + "GevCurrentSubnetMask", + "GevCurrentIPAddress", + "GevCurrentDefaultGateway", + "GevPersistentIPAddress", + "GevPersistentDefaultGateway", + "GevPersistentSubnetMask", +}; + +const std::unordered_set AlliedVisionCamera::m_macAddressFeatures = { + "GevMACAddress" +}; + +/////////////////////////////////////////////////////////////////////////////// +// Exported MMDevice API +/////////////////////////////////////////////////////////////////////////////// +MODULE_API void InitializeModuleData() +{ + RegisterDevice(g_hubName, MM::HubDevice, "Allied Vision Hub"); +} + +MODULE_API MM::Device *CreateDevice(const char *deviceName) +{ + if (deviceName == nullptr) + { + return nullptr; + } + + if (std::string(deviceName) == std::string(g_hubName)) + { + return new AlliedVisionHub(); + } + else + { + return new AlliedVisionCamera(deviceName); + } +} + +MODULE_API void DeleteDevice(MM::Device *pDevice) +{ + delete pDevice; +} + +/////////////////////////////////////////////////////////////////////////////// +// AlliedVisionCamera +/////////////////////////////////////////////////////////////////////////////// +AlliedVisionCamera::~AlliedVisionCamera() +{ + m_handle = nullptr; + + for (size_t i = 0; i < MAX_FRAMES; i++) + { + delete[] m_buffer[i]; + } +} + +AlliedVisionCamera::AlliedVisionCamera(const char *deviceName) : + m_sdk(nullptr), + m_handle{ nullptr }, + m_cameraName{ deviceName }, + m_frames{}, + m_buffer{}, + m_bufferSize{ 0 }, + m_payloadSize{ 0 }, + m_isAcquisitionRunning{ false }, + m_currentPixelFormat{}, + m_propertyToFeature{}, + m_exposureFeatureName{} +{ + CreateHubIDProperty(); + // Binning property is a Core Property, we will have a dummy one + CreateProperty(MM::g_Keyword_Binning, "N/A", MM::String, true, nullptr); + AddAllowedValue(MM::g_Keyword_Binning, "N/A"); +} + +int AlliedVisionCamera::Initialize() +{ + auto parentHub = dynamic_cast(GetParentHub()); + if (parentHub == nullptr) + { + LOG_ERROR(VmbErrorBadParameter, "Parent HUB not found!"); + return VmbErrorBadParameter; + } + m_sdk = parentHub->getSDK(); + + LogMessage("Opening camera: " + m_cameraName); + VmbError_t err = m_sdk->VmbCameraOpen_t(m_cameraName.c_str(), VmbAccessModeType::VmbAccessModeFull, &m_handle); + if (err != VmbErrorSuccess || m_handle == nullptr) + { + LOG_ERROR(err, "Error while opening camera or handle is NULL!"); + return err; + } + + // Try to execute custom command available to Allied Vision GigE Cameras to ensure the packet size is chosen well + VmbCameraInfo_t info; + err = m_sdk->VmbCameraInfoQuery_t(m_cameraName.c_str(), &info, sizeof(info)); + if (err == VmbErrorSuccess && info.streamCount > 0) + { + VmbHandle_t stream = info.streamHandles[0]; + if (m_sdk->VmbFeatureCommandRun_t(stream, ADJUST_PACKAGE_SIZE_COMMAND) == VmbErrorSuccess) + { + VmbBool_t isCommandDone = VmbBoolFalse; + do + { + if (m_sdk->VmbFeatureCommandIsDone_t(stream, ADJUST_PACKAGE_SIZE_COMMAND, &isCommandDone) != VmbErrorSuccess) + { + break; + } + } while (isCommandDone == VmbBoolFalse); + } + } + + // Ignore errors from setting up properties + (void)setupProperties(); + return resizeImageBuffer(); +} + +int AlliedVisionCamera::Shutdown() +{ + LogMessage("Shutting down camera: " + m_cameraName); + VmbError_t err = VmbErrorSuccess; + if (m_sdk != nullptr && m_sdk->isInitialized()) + { + if (m_handle != nullptr) + { + err = m_sdk->VmbCameraClose_t(m_handle); + } + } + + return err; +} + +VmbError_t AlliedVisionCamera::setupProperties() +{ + VmbUint32_t featureCount = 0; + VmbError_t err = m_sdk->VmbFeaturesList_t(m_handle, NULL, 0, &featureCount, sizeof(VmbFeatureInfo_t)); + if (err != VmbErrorSuccess) + { + LOG_ERROR(err, "Error occurred when obtaining features count!"); + return err; + } + + std::vector features{ featureCount }; + + err = m_sdk->VmbFeaturesList_t(m_handle, features.data(), featureCount, &featureCount, sizeof(VmbFeatureInfo_t)); + if (err != VmbErrorSuccess) + { + LOG_ERROR(err, "Error occurred when obtaining features!"); + return err; + } + + const auto exposureTime = + std::find_if(features.begin(), features.end(), [](const auto &feat) { return std::string(feat.name) == g_ExposureFeature; }); + + if (exposureTime != features.end()) + { + m_exposureFeatureName = std::string{ exposureTime->name }; + } + else + { + const auto exposureTimeAbs = + std::find_if(features.begin(), features.end(), [](const auto &feat) { return std::string(feat.name) == g_ExposureAbsFeature; }); + + if (exposureTimeAbs != features.end()) + { + m_exposureFeatureName = std::string{ exposureTimeAbs->name }; + } + } + + for (const auto &feature : features) + { + if (feature.visibility != VmbFeatureVisibilityInvisible) + { + err = createPropertyFromFeature(&feature); + if (err != VmbErrorSuccess) + { + LOG_ERROR(err, "Error while creating property" + std::string(feature.name)); + } + } + } + + return VmbErrorSuccess; +} + +VmbError_t AlliedVisionCamera::resizeImageBuffer() +{ + VmbError_t err = m_sdk->VmbPayloadSizeGet_t(m_handle, &m_payloadSize); + if (err != VmbErrorSuccess) + { + LOG_ERROR(err, "Error while reading payload size"); + return err; + } + + m_bufferSize = std::max(GetImageWidth() * GetImageHeight() * m_currentPixelFormat.getBytesPerPixel(), m_payloadSize); + + for (size_t i = 0; i < MAX_FRAMES; i++) + { + delete[] m_buffer[i]; + m_buffer[i] = new VmbUint8_t[m_bufferSize]; + } + + return VmbErrorSuccess; +} + +VmbError_t AlliedVisionCamera::createPropertyFromFeature(const VmbFeatureInfo_t *feature) +{ + if (feature == nullptr) + { + LogMessage("Cannot create feature. It is NULL"); + return VmbErrorInvalidValue; + } + + VmbError_t err = VmbErrorSuccess; + // Skip Event, Chunk, RAW features + std::string featureCategory = feature->category; + if (featureCategory.find(g_EventCategory) != std::string::npos || featureCategory.find(g_ChunkCategory) != std::string::npos || + feature->featureDataType == VmbFeatureDataRaw) + { + // Skip + return err; + } + + // Map feature to property name + const auto propertyName = [&] + { + const auto tempName = mapFeatureNameToPropertyName(feature->name); + + if (tempName != feature->name) + { + if (!m_propertyToFeature.count(tempName)) + { + m_propertyToFeature.emplace(tempName, feature->name); + return tempName; + } + } + + return std::string(feature->name); + }(); + + // uManager callback + CPropertyAction *uManagerCallback = new CPropertyAction(this, &AlliedVisionCamera::onProperty); + + // Vimba callback + auto vmbCallback = [](VmbHandle_t handle, const char *name, void *userContext) + { + (void)handle; + AlliedVisionCamera *camera = reinterpret_cast(userContext); + const auto propertyName = camera->mapFeatureNameToPropertyName(name); + auto err = camera->UpdateProperty(propertyName.c_str()); + if (err != VmbErrorSuccess) + { + camera->LOG_ERROR(err, "Property: " + propertyName + " update failed"); + } + }; + + // Register VMB callback for given feature + err = m_sdk->VmbFeatureInvalidationRegister_t(m_handle, feature->name, vmbCallback, this); + if (err != VmbErrorSuccess) + { + LOG_ERROR(err, "Error while registering invalidation callback for " + std::string(feature->name)); + return err; + } + + if (m_ipAddressFeatures.count(feature->name) || m_macAddressFeatures.count(feature->name)) + { + err = CreateStringProperty(propertyName.c_str(), "", true, uManagerCallback); + return err; + } + + switch (feature->featureDataType) + { + case VmbFeatureDataInt: + { + err = CreateIntegerProperty(propertyName.c_str(), 0, false, uManagerCallback); + break; + } + case VmbFeatureDataBool: + { + err = CreateStringProperty(propertyName.c_str(), g_False, false, uManagerCallback); + AddAllowedValue(propertyName.c_str(), g_False); + AddAllowedValue(propertyName.c_str(), g_True); + break; + } + case VmbFeatureDataCommand: + { + err = CreateStringProperty(propertyName.c_str(), g_Command, false, uManagerCallback); + AddAllowedValue(propertyName.c_str(), g_Command); + AddAllowedValue(propertyName.c_str(), g_Execute); + break; + } + case VmbFeatureDataEnum: + case VmbFeatureDataString: + { + err = CreateStringProperty(propertyName.c_str(), "", false, uManagerCallback); + break; + } + case VmbFeatureDataFloat: + { + err = CreateFloatProperty(propertyName.c_str(), 0.0, false, uManagerCallback); + break; + } + case VmbFeatureDataUnknown: + case VmbFeatureDataRaw: + case VmbFeatureDataNone: + default: + // nothing + break; + } + + if (err != VmbErrorSuccess) + { + LOG_ERROR(err, "Error while creating property " + std::string(feature->name)); + } + + return err; +} + +const unsigned char *AlliedVisionCamera::GetImageBuffer() +{ + return reinterpret_cast(m_buffer[0]); +} + +unsigned AlliedVisionCamera::GetImageWidth() const +{ + std::string value{}; + auto ret = getFeatureValue(g_Width, value); + if (ret != VmbErrorSuccess) + { + LOG_ERROR(ret, "Error while getting image width!"); + return 0; + } + + return atoi(value.c_str()); +} + +unsigned AlliedVisionCamera::GetImageHeight() const +{ + std::string value{}; + auto ret = getFeatureValue(g_Height, value); + if (ret != VmbErrorSuccess) + { + LOG_ERROR(ret, "Error while getting image height!"); + return 0; + } + + return atoi(value.c_str()); +} + +unsigned AlliedVisionCamera::GetImageBytesPerPixel() const +{ + return m_currentPixelFormat.getBytesPerPixel(); +} + +long AlliedVisionCamera::GetImageBufferSize() const +{ + return m_bufferSize; +} + +unsigned AlliedVisionCamera::GetBitDepth() const +{ + return m_currentPixelFormat.getBitDepth(); +} + +unsigned AlliedVisionCamera::GetNumberOfComponents() const +{ + return m_currentPixelFormat.getNumberOfComponents(); +} + +int AlliedVisionCamera::GetBinning() const +{ + // Binning not supported. We support BinningVertical/Horizontal + return 1; +} + +int AlliedVisionCamera::SetBinning(int binSize) +{ + // Binning not supported. We support BinningVertical/Horizontal + return DEVICE_ERR; +} + +double AlliedVisionCamera::GetExposure() const +{ + std::string value{}; + auto ret = getFeatureValue(m_exposureFeatureName.c_str(), value); + if (ret != VmbErrorSuccess) + { + LOG_ERROR(ret, "Error while getting exposure!"); + return 0; + } + + return std::stod(value) / MS_TO_US; +} + +void AlliedVisionCamera::SetExposure(double exp_ms) +{ + SetProperty(m_exposureFeatureName.c_str(), CDeviceUtils::ConvertToString(exp_ms * MS_TO_US)); + GetCoreCallback()->OnExposureChanged(this, exp_ms); +} + +int AlliedVisionCamera::SetROI(unsigned x, unsigned y, unsigned xSize, unsigned ySize) +{ + auto width = GetImageWidth(); + auto height = GetImageHeight(); + VmbError_t err = VmbErrorSuccess; + + std::function setOffsetXProperty = [this](long x) + { + auto err = SetProperty(g_OffsetX, CDeviceUtils::ConvertToString(x)); + if (err) + { + LOG_ERROR(err, "Error while ROI Offset X!"); + } + return err; + }; + std::function setOffsetYProperty = [this](long y) + { + auto err = SetProperty(g_OffsetY, CDeviceUtils::ConvertToString(y)); + if (err) + { + LOG_ERROR(err, "Error while ROI Offset Y!"); + } + return err; + }; + std::function setWidthProperty = [this](long xSize) + { + auto err = SetProperty(g_Width, CDeviceUtils::ConvertToString(xSize)); + if (err) + { + LOG_ERROR(err, "Error while ROI X!"); + } + return err; + }; + std::function setHeightProperty = [this](long ySize) + { + auto err = SetProperty(g_Height, CDeviceUtils::ConvertToString(ySize)); + if (err) + { + LOG_ERROR(err, "Error while ROI Y!"); + } + return err; + }; + + if (xSize > width) + { + err = setOffsetXProperty(x) || setWidthProperty(xSize); + } + else + { + err = setWidthProperty(xSize) || setOffsetXProperty(x); + } + + if (ySize > height) + { + err = setOffsetYProperty(y) || setHeightProperty(ySize); + } + else + { + err = setHeightProperty(ySize) || setOffsetYProperty(y); + } + + if (err != VmbErrorSuccess) + { + return err; + } + + return resizeImageBuffer(); +} + +int AlliedVisionCamera::GetROI(unsigned &x, unsigned &y, unsigned &xSize, unsigned &ySize) +{ + std::map fields = { { g_OffsetX, x }, { g_OffsetY, y }, { g_Width, xSize }, { g_Height, ySize } }; + + VmbError_t err = VmbErrorSuccess; + for (auto &field : fields) + { + std::string value{}; + err = getFeatureValue(field.first, value); + if (err != VmbErrorSuccess) + { + LOG_ERROR(err, "Error while getting ROI!"); + break; + } + field.second = atoi(value.data()); + } + + return err; +} + +int AlliedVisionCamera::ClearROI() +{ + std::string maxWidth, maxHeight; + VmbError_t err = getFeatureValue(g_WidthMax, maxWidth) | getFeatureValue(g_HeightMax, maxHeight); + if (VmbErrorSuccess != err) + { + LOG_ERROR(err, "Error while clearing ROI!"); + return err; + } + + // Keep the order of the fields + std::vector> fields = { + { g_OffsetX, "0" }, { g_OffsetY, "0" }, { g_Width, maxWidth }, { g_Height, maxHeight } + }; + + for (auto &field : fields) + { + err = setFeatureValue(field.first, field.second); + if (err != VmbErrorSuccess) + { + LOG_ERROR(err, "Error while clearing ROI!"); + break; + } + } + + return resizeImageBuffer(); +} + +int AlliedVisionCamera::IsExposureSequenceable(bool &isSequenceable) const +{ + // TODO implement + return VmbErrorSuccess; +} + +void AlliedVisionCamera::GetName(char *name) const +{ + CDeviceUtils::CopyLimitedString(name, m_cameraName.c_str()); +} + +bool AlliedVisionCamera::IsCapturing() +{ + return m_isAcquisitionRunning; +} + +int AlliedVisionCamera::onProperty(MM::PropertyBase *pProp, MM::ActionType eAct) +{ + // Init + VmbError_t err = VmbErrorSuccess; + + auto pChildProperty = dynamic_cast(pProp); + if (pChildProperty == nullptr) + { + err = VmbErrorBadParameter; + LOG_ERROR(err, "Could not get Property from PropertyBase object"); + return err; + } + + const auto propertyName = pProp->GetName(); + + auto valueEqual = [pProp](const std::string& newValue) -> bool { + switch (pProp->GetType()) + { + case MM::PropertyType::Float: + { + double oldValue{}; + pProp->Get(oldValue); + return oldValue == std::stod(newValue); + } + default: + { + std::string oldValue{}; + pProp->Get(oldValue); + return oldValue == newValue; + } + } + }; + + // Check property mapping + auto const featureName = mapPropertyNameToFeatureName(propertyName.c_str()); + + // Get Feature Info and Access Mode + VmbFeatureInfo_t featureInfo; + bool rMode{}, wMode{}; + err = m_sdk->VmbFeatureInfoQuery_t(m_handle, featureName.c_str(), &featureInfo, sizeof(featureInfo)) | + m_sdk->VmbFeatureAccessQuery_t(m_handle, featureName.c_str(), &rMode, &wMode); + if (VmbErrorSuccess != err) + { + LOG_ERROR(err, "Error while getting info or access query!"); + return err; + } + + if (m_ipAddressFeatures.count(featureName)) + { + wMode = false; + } + + const bool readOnly = (rMode && !wMode); + const bool featureAvailable = (rMode || wMode); + + // Get values + std::string propertyValue{}, featureValue{}; + pProp->Get(propertyValue); + + // Handle property value change + switch (eAct) + { + case MM::ActionType::BeforeGet: //!< Update property from feature + + // Update feature range + if (featureAvailable) + { + err = setAllowedValues(&featureInfo, propertyName.c_str()); + } + // Feature not available -> clear value and range + else + { + switch (pProp->GetType()) + { + case MM::Float: + case MM::Integer: + SetPropertyLimits(propertyName.c_str(), 0.0, 0.0); + pProp->Set("0"); + break; + case MM::String: + ClearAllowedValues(propertyName.c_str()); + pProp->Set(""); + break; + default: + // feature type not supported + break; + } + } + + if (rMode) + { + err = getFeatureValue(&featureInfo, featureName.c_str(), featureValue); + if (VmbErrorSuccess != err) + { + LOG_ERROR(err, "Error while getting feature value " + featureName); + return err; + } + + // Update property + if (!valueEqual(featureValue)) + { + pProp->Set(featureValue.c_str()); + err = GetCoreCallback()->OnPropertyChanged(this, propertyName.c_str(), featureValue.c_str()); + if (propertyName == MM::g_Keyword_PixelType) + { + handlePixelFormatChange(featureValue); + } + + if (VmbErrorSuccess != err) + { + LOG_ERROR(err, "Error while calling OnPropertyChanged callback for " + featureName); + return err; + } + + if (m_exposureFeatureName == featureName) + { + GetCoreCallback()->OnExposureChanged(this, std::stod(featureValue) / MS_TO_US); + } + } + } + + // Set property to readonly (grey out in GUI) if it is readonly or unavailable + pChildProperty->SetReadOnly(readOnly || !featureAvailable); + + break; + case MM::ActionType::AfterSet: //!< Update feature from property + err = setFeatureValue(&featureInfo, featureName.c_str(), propertyValue); + if (err == VmbErrorInvalidValue) + { + // Update limits first to have latest min and max + err = setAllowedValues(&featureInfo, propertyName.c_str()); + if (VmbErrorSuccess != err) + { + LOG_ERROR(err, "Error while setting allowed values for feature " + featureName); + return err; + } + + // Adjust value + double min{}, max{}; + err = GetPropertyLowerLimit(propertyName.c_str(), min) | GetPropertyUpperLimit(propertyName.c_str(), max); + if (VmbErrorSuccess != err) + { + LOG_ERROR(err, "Error while getting limits for " + propertyName); + return err; + } + std::string adjustedValue = adjustValue(featureInfo, min, max, std::stod(propertyValue)); + err = setFeatureValue(&featureInfo, featureName.c_str(), adjustedValue); + if (err == VmbErrorSuccess) + { + err = GetCoreCallback()->OnPropertyChanged(this, propertyName.c_str(), adjustedValue.c_str()); + } + } + else if (err == VmbErrorSuccess) + { + err = GetCoreCallback()->OnPropertyChanged(this, propertyName.c_str(), propertyValue.c_str()); + } + + + if (propertyName == MM::g_Keyword_PixelType) + { + handlePixelFormatChange(propertyValue); + } + break; + default: + // nothing + break; + } + + if (VmbErrorSuccess != err) + { + LOG_ERROR(err, "Error while updating property " + propertyName); + } + + return err; + +} + +void AlliedVisionCamera::handlePixelFormatChange(const std::string &pixelType) +{ + m_currentPixelFormat.setPixelType(pixelType); +} + +VmbError_t AlliedVisionCamera::getFeatureValue(VmbFeatureInfo_t *featureInfo, const char *featureName, std::string &value) const +{ + VmbError_t err = VmbErrorSuccess; + switch (featureInfo->featureDataType) + { + case VmbFeatureDataBool: + { + VmbBool_t out; + err = m_sdk->VmbFeatureBoolGet_t(m_handle, featureName, &out); + if (err != VmbErrorSuccess) + { + break; + } + value = (out ? g_True : g_False); + break; + } + case VmbFeatureDataEnum: + { + const char *out = nullptr; + err = m_sdk->VmbFeatureEnumGet_t(m_handle, featureName, &out); + if (err != VmbErrorSuccess) + { + break; + } + value = std::string(out); + break; + } + case VmbFeatureDataFloat: + { + double out; + err = m_sdk->VmbFeatureFloatGet_t(m_handle, featureName, &out); + if (err != VmbErrorSuccess) + { + break; + } + value = std::to_string(out); + break; + } + case VmbFeatureDataInt: + { + VmbInt64_t out; + err = m_sdk->VmbFeatureIntGet_t(m_handle, featureName, &out); + if (err != VmbErrorSuccess) + { + break; + } + if (m_ipAddressFeatures.count(featureName)) + { + std::stringstream ipAddressStream; + ipAddressStream << (0xFF & (out >> 24)) << "." << (0xFF & (out >> 16)) << "." << (0xFF & (out >> 8)) << "." << (0xFF & out); + + value = ipAddressStream.str(); + } + else if (m_macAddressFeatures.count(featureName)) + { + std::stringstream macAddressStream; + macAddressStream << std::hex + << std::setw(2) << std::setfill('0') << static_cast(0xFF & (out >> 40)) << ":" + << std::setw(2) << std::setfill('0') << static_cast(0xFF & (out >> 32)) << ":" + << std::setw(2) << std::setfill('0') << static_cast(0xFF & (out >> 24)) << ":" + << std::setw(2) << std::setfill('0') << static_cast(0xFF & (out >> 16)) << ":" + << std::setw(2) << std::setfill('0') << static_cast(0xFF & (out >> 8)) << ":" + << std::setw(2) << std::setfill('0') << static_cast(0xFF & out); + value = macAddressStream.str(); + } + else + { + value = std::to_string(out); + } + break; + } + case VmbFeatureDataString: + { + VmbUint32_t size = 0; + err = m_sdk->VmbFeatureStringGet_t(m_handle, featureName, nullptr, 0, &size); + if (VmbErrorSuccess == err && size > 0) + { + std::shared_ptr buff = std::shared_ptr(new char[size]); + err = m_sdk->VmbFeatureStringGet_t(m_handle, featureName, buff.get(), size, &size); + if (err != VmbErrorSuccess) + { + break; + } + value = std::string(buff.get()); + } + break; + } + case VmbFeatureDataCommand: + value = std::string(g_Command); + break; + case VmbFeatureDataUnknown: + case VmbFeatureDataRaw: + case VmbFeatureDataNone: + default: + // nothing + break; + } + + if (VmbErrorSuccess != err) + { + LOG_ERROR(err, "Error while getting feature value " + std::string(featureName)); + } + + return err; +} + +VmbError_t AlliedVisionCamera::getFeatureValue(const char *featureName, std::string &value) const +{ + VmbFeatureInfo_t featureInfo; + VmbError_t err = m_sdk->VmbFeatureInfoQuery_t(m_handle, featureName, &featureInfo, sizeof(featureInfo)); + if (VmbErrorSuccess != err) + { + LOG_ERROR(err, "Error while getting feature value " + std::string(featureName)); + return err; + } + + return getFeatureValue(&featureInfo, featureName, value); +} + +VmbError_t AlliedVisionCamera::setFeatureValue(VmbFeatureInfo_t *featureInfo, const char *featureName, std::string &value) +{ + VmbError_t err = VmbErrorSuccess; + std::stringstream ss(value); + bool isDone = false; + VmbUint32_t maxLen = 0; + + switch (featureInfo->featureDataType) + { + case VmbFeatureDataBool: + { + VmbBool_t out = (value == g_True ? true : false); + err = m_sdk->VmbFeatureBoolSet_t(m_handle, featureName, out); + break; + } + case VmbFeatureDataEnum: + { + err = m_sdk->VmbFeatureEnumSet_t(m_handle, featureName, value.c_str()); + break; + } + case VmbFeatureDataFloat: + { + double out; + ss >> out; + err = m_sdk->VmbFeatureFloatSet_t(m_handle, featureName, out); + break; + } + case VmbFeatureDataInt: + { + VmbInt64_t out; + ss >> out; + err = m_sdk->VmbFeatureIntSet_t(m_handle, featureName, out); + break; + } + case VmbFeatureDataString: + { + err = m_sdk->VmbFeatureStringMaxlengthQuery_t(m_handle, featureName, &maxLen); + if (err != VmbErrorSuccess) + { + break; + } + if (value.size() > maxLen) + { + err = VmbErrorInvalidValue; + } + else + { + err = m_sdk->VmbFeatureStringSet_t(m_handle, featureName, value.c_str()); + } + break; + } + case VmbFeatureDataCommand: + if (value == g_Execute) + { + const auto propertyName = mapFeatureNameToPropertyName(featureName); + if (!propertyName.empty()) + { + err = m_sdk->VmbFeatureCommandRun_t(m_handle, featureName); + if (err != VmbErrorSuccess) + { + break; + } + while (!isDone) + { + err = m_sdk->VmbFeatureCommandIsDone_t(m_handle, featureName, &isDone); + if (err != VmbErrorSuccess) + { + break; + } + } + // Set back property to "Command" + err = SetProperty(propertyName.c_str(), g_Command); + GetCoreCallback()->OnPropertyChanged(this, propertyName.c_str(), g_Command); + if (err != VmbErrorSuccess) + { + break; + } + } + else + { + err = VmbErrorInvalidValue; + } + } + break; + case VmbFeatureDataUnknown: + case VmbFeatureDataRaw: + case VmbFeatureDataNone: + default: + // nothing + break; + } + + if (VmbErrorSuccess != err) + { + LOG_ERROR(err, "Error while setting feature value " + std::string(featureName)); + } + + return err; +} + +VmbError_t AlliedVisionCamera::setFeatureValue(const char *featureName, std::string &value) +{ + VmbFeatureInfo_t featureInfo; + VmbError_t err = m_sdk->VmbFeatureInfoQuery_t(m_handle, featureName, &featureInfo, sizeof(featureInfo)); + if (VmbErrorSuccess != err) + { + LOG_ERROR(err, "Error while setting feature value " + std::string(featureName)); + return err; + } + + return setFeatureValue(&featureInfo, featureName, value); +} + +std::string AlliedVisionCamera::mapFeatureNameToPropertyName(const char *feature) const +{ + + auto search = m_featureToProperty.find(feature); + if (search != m_featureToProperty.end()) + { + return search->second; + } + + return feature; +} +std::string AlliedVisionCamera::mapPropertyNameToFeatureName(const char *property) const +{ + auto search = m_propertyToFeature.find(property); + if (search != m_propertyToFeature.end()) + { + return search->second; + } + + return property; +} + +std::string AlliedVisionCamera::adjustValue(VmbFeatureInfo_t &featureInfo, double min, double max, double propertyValue) const +{ + VmbError_t err = VmbErrorSuccess; + double step = 1.0; + VmbInt64_t stepI = 1; + bool isIncremental = true; + switch (featureInfo.featureDataType) + { + case VmbFeatureDataFloat: + err = m_sdk->VmbFeatureFloatIncrementQuery_t(m_handle, featureInfo.name, &isIncremental, &step); + break; + case VmbFeatureDataInt: + err = m_sdk->VmbFeatureIntIncrementQuery_t(m_handle, featureInfo.name, &stepI); + step = static_cast(stepI); + break; + default: + // nothing + break; + } + if (VmbErrorSuccess != err) + { + LOG_ERROR(err, "Error while getting increment query for feature " + std::string(featureInfo.name)); + return std::to_string(propertyValue); + } + + if (!isIncremental) + { + return std::to_string(propertyValue); + } + + if (propertyValue > max) + { + return std::to_string(max); + } + if (propertyValue < min) + { + return std::to_string(min); + } + + VmbInt64_t factor = static_cast((propertyValue - min) / step); + double prev = min + factor * step; + double next = min + (factor + 1) * step; + + double prevDiff = abs(propertyValue - prev); + double nextDiff = abs(next - propertyValue); + + return (nextDiff < prevDiff) ? std::to_string(next) : std::to_string(prev); +} + +VmbError_t AlliedVisionCamera::setAllowedValues(const VmbFeatureInfo_t *feature, const char *propertyName) +{ + if (feature == nullptr || propertyName == nullptr) + { + return VmbErrorInvalidValue; + } + + VmbError_t err = VmbErrorSuccess; + + switch (feature->featureDataType) + { + case VmbFeatureDataBool: + { + // Already set in creation, but maybe reset when become unavailable + if (GetNumberOfPropertyValues(propertyName) == 0) + { + AddAllowedValue(propertyName, g_False); + AddAllowedValue(propertyName, g_True); + } + break; + } + case VmbFeatureDataCommand: + { + // Already set in creation, but maybe reset when become unavailable + if (GetNumberOfPropertyValues(propertyName) == 0) + { + AddAllowedValue(propertyName, g_Command); + AddAllowedValue(propertyName, g_Execute); + } + break; + } + case VmbFeatureDataFloat: + { + double min, max; + err = m_sdk->VmbFeatureFloatRangeQuery_t(m_handle, feature->name, &min, &max); + if (VmbErrorSuccess != err || min == max) + { + break; + } + + err = SetPropertyLimits(propertyName, min, max); + break; + } + case VmbFeatureDataEnum: + { + std::array values; + std::vector strValues; + VmbUint32_t valuesNum = 0; + err = m_sdk->VmbFeatureEnumRangeQuery_t(m_handle, feature->name, values.data(), MM::MaxStrLength, &valuesNum); + if (VmbErrorSuccess != err) + { + break; + } + + for (size_t i = 0; i < valuesNum; i++) + { + strValues.push_back(values[i]); + } + err = SetAllowedValues(propertyName, strValues); + + break; + } + case VmbFeatureDataInt: + { + VmbInt64_t min, max; + std::vector strValues; + + err = m_sdk->VmbFeatureIntRangeQuery_t(m_handle, feature->name, &min, &max); + if (VmbErrorSuccess != err || min == max) + { + break; + } + + err = SetPropertyLimits(propertyName, static_cast(min), static_cast(max)); + break; + } + case VmbFeatureDataString: + case VmbFeatureDataRaw: + case VmbFeatureDataNone: + default: + // nothing + break; + } + + if (VmbErrorSuccess != err) + { + LOG_ERROR(err, "Error while setting allowed values for feature " + std::string(feature->name)); + } + + return err; +} + +int AlliedVisionCamera::SnapImage() +{ + if (IsCapturing()) + { + return DEVICE_CAMERA_BUSY_ACQUIRING; + } + resizeImageBuffer(); + + VmbFrame_t frame; + frame.buffer = m_buffer[0]; + frame.bufferSize = m_payloadSize; + + VmbError_t err = VmbErrorSuccess; + err = m_sdk->VmbFrameAnnounce_t(m_handle, &frame, sizeof(VmbFrame_t)); + if (err != VmbErrorSuccess) + { + LOG_ERROR(err, "Error while snapping image!"); + (void)StopSequenceAcquisition(); + return err; + } + err = m_sdk->VmbCaptureStart_t(m_handle); + if (err != VmbErrorSuccess) + { + LOG_ERROR(err, "Error while snapping image!"); + (void)StopSequenceAcquisition(); + return err; + } + err = m_sdk->VmbCaptureFrameQueue_t(m_handle, &frame, nullptr); + if (err != VmbErrorSuccess) + { + LOG_ERROR(err, "Error while snapping image!"); + (void)StopSequenceAcquisition(); + return err; + } + err = m_sdk->VmbFeatureCommandRun_t(m_handle, g_AcquisitionStart); + if (err != VmbErrorSuccess) + { + LOG_ERROR(err, "Error while snapping image!"); + (void)StopSequenceAcquisition(); + return err; + } + m_isAcquisitionRunning = true; + err = m_sdk->VmbCaptureFrameWait_t(m_handle, &frame, 3000); + if (err != VmbErrorSuccess) + { + LOG_ERROR(err, "Error while snapping image!"); + (void)StopSequenceAcquisition(); + return err; + } + + err = transformImage(&frame); + if (err != VmbErrorSuccess) + { + LOG_ERROR(err, "Error while snapping image - cannot transform image!"); + (void)StopSequenceAcquisition(); + return err; + } + + (void)StopSequenceAcquisition(); + return err; +} + +int AlliedVisionCamera::StartSequenceAcquisition(long numImages, double interval_ms, bool stopOnOverflow) +{ + (void)stopOnOverflow; + (void)interval_ms; + (void)numImages; + + if (IsCapturing()) + { + return DEVICE_CAMERA_BUSY_ACQUIRING; + } + + int err = GetCoreCallback()->PrepareForAcq(this); + if (err != VmbErrorSuccess) + { + LOG_ERROR(err, "Error while preparing for acquisition!"); + return err; + } + + err = resizeImageBuffer(); + if (err != VmbErrorSuccess) + { + LOG_ERROR(err, "Error during frame praparation for continous acquisition!"); + return err; + } + + for (size_t i = 0; i < MAX_FRAMES; i++) + { + m_frames[i].buffer = m_buffer[i]; + m_frames[i].bufferSize = m_payloadSize; + m_frames[i].context[0] = this; //(i); //(frame->context[0])->insertFrame(frame); + }; + + err = m_sdk->VmbFrameAnnounce_t(m_handle, &(m_frames[i]), sizeof(VmbFrame_t)); + if (err != VmbErrorSuccess) + { + LOG_ERROR(err, "Error during frame praparation for continous acquisition!"); + return err; + } + + err = m_sdk->VmbCaptureFrameQueue_t(m_handle, &(m_frames[i]), frameCallback); + if (err != VmbErrorSuccess) + { + LOG_ERROR(err, "Error during frame praparation for continous acquisition!"); + return err; + } + } + + err = m_sdk->VmbCaptureStart_t(m_handle); + if (err != VmbErrorSuccess) + { + LOG_ERROR(err, "Error during frame praparation for continous acquisition!"); + return err; + } + + err = m_sdk->VmbFeatureCommandRun_t(m_handle, g_AcquisitionStart); + m_isAcquisitionRunning = true; + + if (err != VmbErrorSuccess) + { + LOG_ERROR(err, "Error during start acquisition!"); + return err; + } + + GetCoreCallback()->OnPropertiesChanged(this); + + return UpdateStatus(); +} + +int AlliedVisionCamera::StartSequenceAcquisition(double interval_ms) +{ + return StartSequenceAcquisition(LONG_MAX, interval_ms, true); +} +int AlliedVisionCamera::StopSequenceAcquisition() +{ + // This method shall never return any error + VmbError_t err = VmbErrorSuccess; + if (IsCapturing()) + { + err = m_sdk->VmbFeatureCommandRun_t(m_handle, g_AcquisitionStop); + m_isAcquisitionRunning = false; + if (err != VmbErrorSuccess) + { + LOG_ERROR(err, "Error during stopping acquisition command!"); + return err; + } + } + + err = m_sdk->VmbCaptureEnd_t(m_handle); + if (err != VmbErrorSuccess) + { + LOG_ERROR(err, "Error during stop acquisition!"); + return err; + } + + err = m_sdk->VmbCaptureQueueFlush_t(m_handle); + if (err != VmbErrorSuccess) + { + LOG_ERROR(err, "Error during stop acquisition!"); + return err; + } + + err = m_sdk->VmbFrameRevokeAll_t(m_handle); + if (err != VmbErrorSuccess) + { + LOG_ERROR(err, "Error during stop acquisition!"); + return err; + } + + GetCoreCallback()->OnPropertiesChanged(this); + + return UpdateStatus(); +} + +VmbError_t AlliedVisionCamera::transformImage(VmbFrame_t *frame) +{ + VmbError_t err = VmbErrorSuccess; + VmbImage src{}, dest{}; + VmbTransformInfo info{}; + std::shared_ptr tempBuff = std::shared_ptr(new VmbUint8_t[m_bufferSize]); + auto srcBuff = reinterpret_cast(frame->buffer); + + src.Data = srcBuff; + src.Size = sizeof(src); + + dest.Data = tempBuff.get(); + dest.Size = sizeof(dest); + + err = m_sdk->VmbSetImageInfoFromPixelFormat_t(frame->pixelFormat, frame->width, frame->height, &src); + if (err != VmbErrorSuccess) + { + LOG_ERROR(err, "Cannot set image info from pixel format!"); + return err; + } + + err = m_sdk->VmbSetImageInfoFromPixelFormat_t(m_currentPixelFormat.getVmbFormat(), frame->width, frame->height, &dest); + if (err != VmbErrorSuccess) + { + LOG_ERROR(err, "Cannot set image info from pixel format!"); + return err; + } + + err = m_sdk->VmbImageTransform_t(&src, &dest, &info, 0); + if (err != VmbErrorSuccess) + { + LOG_ERROR(err, "Cannot transform image!"); + return err; + } + + memcpy(srcBuff, tempBuff.get(), m_bufferSize); + return err; +} + +void AlliedVisionCamera::insertFrame(VmbFrame_t *frame) +{ + if (frame != nullptr && frame->receiveStatus == VmbFrameStatusComplete) + { + VmbError_t err = VmbErrorSuccess; + + err = transformImage(frame); + if (err != VmbErrorSuccess) + { + // Error logged in transformImage + return; + } + + // TODO implement metadata + Metadata md; + md.put("Camera", m_cameraName); + + VmbUint8_t *buffer = reinterpret_cast(frame->buffer); + err = GetCoreCallback()->InsertImage(this, buffer, GetImageWidth(), GetImageHeight(), m_currentPixelFormat.getBytesPerPixel(), + m_currentPixelFormat.getNumberOfComponents(), md.Serialize().c_str()); + + if (err == DEVICE_BUFFER_OVERFLOW) + { + GetCoreCallback()->ClearImageBuffer(this); + err = GetCoreCallback()->InsertImage(this, buffer, GetImageWidth(), GetImageHeight(), m_currentPixelFormat.getBytesPerPixel(), + m_currentPixelFormat.getNumberOfComponents(), md.Serialize().c_str(), false); + } + + if (IsCapturing()) + { + m_sdk->VmbCaptureFrameQueue_t(m_handle, frame, + [](const VmbHandle_t cameraHandle, const VmbHandle_t streamHandle, VmbFrame_t *frame) + { + (void)cameraHandle; + (void)streamHandle; + reinterpret_cast(frame->context[0])->insertFrame(frame); + }); + } + } +} \ No newline at end of file diff --git a/DeviceAdapters/AlliedVisionCamera/AlliedVisionCamera.h b/DeviceAdapters/AlliedVisionCamera/AlliedVisionCamera.h new file mode 100644 index 000000000..ec0e2660c --- /dev/null +++ b/DeviceAdapters/AlliedVisionCamera/AlliedVisionCamera.h @@ -0,0 +1,472 @@ +/*============================================================================= + Copyright (C) 2023 Allied Vision Technologies. All Rights Reserved. + + This file is distributed under the BSD license. + License text is included with the source distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF TITLE, + NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=============================================================================*/ +#ifndef ALLIEDVISIONCAMERA_H +#define ALLIEDVISIONCAMERA_H + +#include +#include +#include +#include +#include + +#include "AlliedVisionDeviceBase.h" +#include "DeviceBase.h" +#include "Loader/LibLoader.h" + +/////////////////////////////////////////////////////////////////////////////// +// STATIC FEATURE NAMES (FROM VIMBA) +/////////////////////////////////////////////////////////////////////////////// +static constexpr const char *g_PixelFormatFeature = "PixelFormat"; +static constexpr const char *g_ExposureFeature = "ExposureTime"; +static constexpr const char *g_ExposureAbsFeature = "ExposureTimeAbs"; +static constexpr const char *g_BinningHorizontalFeature = "BinningHorizontal"; +static constexpr const char *g_BinningVerticalFeature = "BinningVertical"; +static constexpr const char *g_Width = "Width"; +static constexpr const char *g_Height = "Height"; +static constexpr const char *g_OffsetX = "OffsetX"; +static constexpr const char *g_OffsetY = "OffsetY"; +static constexpr const char *g_WidthMax = "WidthMax"; +static constexpr const char *g_HeightMax = "HeightMax"; + +/////////////////////////////////////////////////////////////////////////////// +// STATIC VARIABLES +/////////////////////////////////////////////////////////////////////////////// +static constexpr const char *g_True = "True"; +static constexpr const char *g_False = "False"; +static constexpr const char *g_Execute = "Execute"; +static constexpr const char *g_Command = "Command"; +static constexpr const char *g_ChunkCategory = "ChunkDataControl"; +static constexpr const char *g_EventCategory = "EventControl"; +static constexpr const char *g_AcquisitionStart = "AcquisitionStart"; +static constexpr const char *g_AcquisitionStop = "AcquisitionStop"; +static constexpr const char *g_AcqusitionStatus = "AcqusitionStatus"; + +static constexpr const double MS_TO_US = 1000.0; + +/** + * @brief Pixel Format class that contains VMB Pixel Format info and contains + * helper methods to convert these information to the one that uManager + * supports. + * + * [IMPORTANT] uManager supports formats: + * 8bit GRAY [no. component = 1] + * 16bit GRAY [no. component = 1] + * 32bit RGB [no. component = 4] + */ +class PixelFormatConverter +{ + /////////////////////////////////////////////////////////////////////////////// + // PUBLIC + /////////////////////////////////////////////////////////////////////////////// +public: + /** + * @brief Constructor + */ + PixelFormatConverter() : + m_pixelType{ "Mono8" }, + m_components{ 1 }, + m_bitDepth{ 8 }, + m_bytesPerPixel{ 1 }, + m_isMono{ true }, + m_vmbFormat{ VmbPixelFormatMono8 } + { + } + + /** + * @brief Destructor + */ + virtual ~PixelFormatConverter() = default; + + /** + * @brief Setter for pixel type + * @param[in] type New pixel type (string value from VMB) + */ + void setPixelType(const std::string &type) + { + m_pixelType = type; + updateFields(); + } + + /** + * @brief Getter to check if given pixel type is Mono or Color + * @return True if Mono, otherwise false + */ + bool isMono() const + { + return m_isMono; + } + + /** + * @brief Getter for number of components for given pixel type + * uManager supports only 1 or 4 components + * @return Number of components + */ + unsigned getNumberOfComponents() const + { + return m_components; + } + + /** + * @brief Getter for bit depth for given pixel type + * @return Number of bits for one pixel + */ + unsigned getBitDepth() const + { + return m_bitDepth; + } + + /** + * @brief Getter for bytes per pixel + * @return Bytes per pixel + */ + unsigned getBytesPerPixel() const + { + return m_bytesPerPixel; + } + + /** + * @brief Getter of destination VmbPixelFormat that fits into the one, that + * uManager supports. In general uManager supports three pixelFormats: + * 1. Mono8 + * 2. Mono16 + * 3. RGB32 + * These types fits into following VmbPixelTypes: + * 1. VmbPixelFormatMono8 + * 2. VmbPixelFormatMono16 + * 3. VmbPixelFormatBgra8 + * @return Destination VmbPixelFormat + */ + VmbPixelFormatType getVmbFormat() const + { + return m_vmbFormat; + } + + /////////////////////////////////////////////////////////////////////////////// + // PRIVATE + /////////////////////////////////////////////////////////////////////////////// +private: + /** + * @brief Helper method to update info if given format is Mono or Color + */ + void updateMono() + { + std::regex re("Mono(\\d+)"); + std::smatch m; + m_isMono = std::regex_search(m_pixelType, m, re); + } + + /** + * @brief Helper method to update number of components for given pixel type + * uManager supports only 1 or 4 components + */ + void updateNumberOfComponents() + { + m_components = m_isMono ? 1 : 4; + } + + /** + * @brief Helper method to update bit depth for given pixel type + */ + void updateBitDepth() + { + m_bitDepth = 8; + if (isMono()) + { + std::regex re("Mono(\\d+)"); + std::smatch m; + std::regex_search(m_pixelType, m, re); + if (m.size() > 0) + { + if (std::atoi(m[1].str().c_str()) == 16) + { + // We do transformation to Mono16 only for Mono16, otherwise + // it will always be Mono8 + m_bitDepth = 16; + } + else + { + m_bitDepth = 8; + } + } + else + { + // ERROR + } + } + else + { + m_bitDepth = 32; + } + } + + /** + * @brief Helper method to update bytes per pixel + */ + void updateBytesPerPixel() + { + m_bytesPerPixel = m_bitDepth / 8; + } + + /** + * @brief Helper method to update destination VmbPixelFormatType + */ + void updateVmbFormat() + { + switch (m_bytesPerPixel) + { + case 1: + m_vmbFormat = VmbPixelFormatMono8; + break; + case 2: + m_vmbFormat = VmbPixelFormatMono16; + break; + case 4: + m_vmbFormat = VmbPixelFormatBgra8; // TODO check if this is a valid format + break; + default: + break; + } + } + + /** + * @brief Helper method to update all required fields + */ + void updateFields() + { + // [IMPORTANT] Keep order of the calls + updateMono(); + updateNumberOfComponents(); + updateBitDepth(); + updateBytesPerPixel(); + updateVmbFormat(); + } + + std::string m_pixelType; //!< Pixel type (in string) - value from VMB + unsigned m_components; //!< Number of components + unsigned m_bitDepth; //, AlliedVisionCamera> +{ + /////////////////////////////////////////////////////////////////////////////// + // PUBLIC + /////////////////////////////////////////////////////////////////////////////// +public: + /** + * @brief Contructor of Allied Vision Camera + * @param[in] deviceName Device name + */ + AlliedVisionCamera(const char *deviceName); + /** + * @brief Allied Vision Camera destructor + */ + virtual ~AlliedVisionCamera(); + + /////////////////////////////////////////////////////////////////////////////// + // uMANAGER API METHODS + /////////////////////////////////////////////////////////////////////////////// + int Initialize() override; + int Shutdown() override; + const unsigned char *GetImageBuffer() override; + unsigned GetImageWidth() const override; + unsigned GetImageHeight() const override; + unsigned GetImageBytesPerPixel() const override; + int SnapImage() override; + long GetImageBufferSize() const override; + unsigned GetBitDepth() const override; + int GetBinning() const override; + int SetBinning(int binSize) override; + void SetExposure(double exp_ms) override; + double GetExposure() const override; + int SetROI(unsigned x, unsigned y, unsigned xSize, unsigned ySize) override; + int GetROI(unsigned &x, unsigned &y, unsigned &xSize, unsigned &ySize) override; + int ClearROI() override; + int IsExposureSequenceable(bool &isSequenceable) const override; + void GetName(char *name) const override; + int StartSequenceAcquisition(double interval_ms) override; + int StartSequenceAcquisition(long numImages, double interval_ms, bool stopOnOverflow) override; + int StopSequenceAcquisition() override; + bool IsCapturing() override; + unsigned GetNumberOfComponents() const override; + + /////////////////////////////////////////////////////////////////////////////// + // uMANAGER CALLBACKS + /////////////////////////////////////////////////////////////////////////////// + int onProperty(MM::PropertyBase *pProp, + MM::ActionType eAct); //!<< General property callback + + /////////////////////////////////////////////////////////////////////////////// + // PRIVATE + /////////////////////////////////////////////////////////////////////////////// +private: + // Static variables + static constexpr const VmbUint8_t MAX_FRAMES = 7; //!<< Max frame number in the buffer + + /** + * @brief Helper method to handle change of pixel type + * @param[in] pixelType New pixel type (as string) + */ + void handlePixelFormatChange(const std::string &pixelType); + + /** + * @brief Resize all buffers for image frames + * @return VmbError_t + */ + VmbError_t resizeImageBuffer(); + + /** + * @brief Setup uManager properties from Vimba features + * @return VmbError_t + */ + VmbError_t setupProperties(); + + /** + * @brief Helper method to create single uManager property from Vimba feature + * @param[in] feature Pointer to the Vimba feature + * @return VmbError_t + */ + VmbError_t createPropertyFromFeature(const VmbFeatureInfo_t *feature); + + /** + * @brief Helper method to set allowed values for given property, based on + * its feature type + * @param[in] feature Vimba feature name + * @param[in] propertyName uManager propery name (if differs from + * feature name) + * @return + */ + VmbError_t setAllowedValues(const VmbFeatureInfo_t *feature, const char *propertyName); + + /** + * @brief Insert ready frame to the uManager + * @param[in] frame Pointer to the frame + */ + void insertFrame(VmbFrame_t *frame); + + /** + * @brief Method to get feature value, based on its type. Feature value is + * always a string type. + * @param[in] featureInfo Feature info object + * @param[in] featureName Feature name + * @param[out] value Value of feature, read from device + * @return VmbError_t + */ + VmbError_t getFeatureValue(VmbFeatureInfo_t *featureInfo, const char *featureName, std::string &value) const; + /** + * @brief Method to get feature value, based on its type. Feature value is + * always a string type. + * @param[in] featureName Feature name + * @param[out] value Value of feature, read from device + * @return VmbError_t + */ + VmbError_t getFeatureValue(const char *featureName, std::string &value) const; + + /** + * @brief Method to set a feature value, bases on its type. Feature value is + * always a string type. + * @param[in] featureInfo Feature info object + * @param[in] featureName Feature name + * @param[in] value Value of feature to be set + * @return VmbError_t + */ + VmbError_t setFeatureValue(VmbFeatureInfo_t *featureInfo, const char *featureName, std::string &value); + + /** + * @brief Method to set a feature value, bases on its type. Feature value is + * always a string type. + * @param[in] featureName Feature name + * @param[in] value Value of feature to be set + * @return VmbError_t + */ + VmbError_t setFeatureValue(const char *featureName, std::string &value); + + /** + * @brief Helper method to map feature name into property name of uManager + * @param[in] feature Vimba Feature name + * @return uManager property name + */ + std::string mapFeatureNameToPropertyName(const char *feature) const; + + /** + * @brief Helper method to map uManager property in Vimba feature or features + * name + * @param[in] property uManager property name + * @param featureNames Vimba feature or features name + */ + std::string mapPropertyNameToFeatureName(const char *property) const; + + /** + * @brief In case trying to set invalid value, adjust it to the closest with + * inceremntal step + + * @param[in] step Incremental step + + * @return Adjusted value resresented as a string + */ + + /** + * @brief In case trying to set invalid value, adjust it to the closest with + * inceremntal step + * @param[in] featureInfo Feature info object + * @param[in] min Minimum for given property + * @param[in] max Maximum for given property + * @param[in] propertyValue Value that was tried to be set + * @return Adjusted value resresented as a string + */ + std::string adjustValue(VmbFeatureInfo_t &featureInfo, double min, double max, double propertyValue) const; + + /** + * @brief Internal method to transform image to the destination format that + * uManager supports (see \ref PixelFormatConverter) and replaces input frame + * with output (transformed) frame + * @param[in] frame Frame with image to transform from and into + * @return Error in case of failure + */ + VmbError_t transformImage(VmbFrame_t *frame); + + /////////////////////////////////////////////////////////////////////////////// + // MEMBERS + /////////////////////////////////////////////////////////////////////////////// + std::shared_ptr m_sdk; // m_frames; // m_buffer; // m_featureToProperty; //!< Map of features name into uManager properties + std::unordered_map m_propertyToFeature; //!< Map of uManager properties into Vimba features + + static const std::unordered_set m_ipAddressFeatures; + static const std::unordered_set m_macAddressFeatures; +}; + +#endif diff --git a/DeviceAdapters/AlliedVisionCamera/AlliedVisionCamera.vcxproj b/DeviceAdapters/AlliedVisionCamera/AlliedVisionCamera.vcxproj new file mode 100644 index 000000000..1aa16787b --- /dev/null +++ b/DeviceAdapters/AlliedVisionCamera/AlliedVisionCamera.vcxproj @@ -0,0 +1,110 @@ + + + + + Debug + x64 + + + Release + x64 + + + + + + + + + + + + + + + + + + {b8c95f39-54bf-40a9-807b-598df2821d55} + + + + 16.0 + Win32Proj + {12e75cb0-4b48-4d7c-bb26-d928f18488c2} + AlliedVisionCamera + 10.0 + + + + DynamicLibrary + true + v142 + Unicode + + + DynamicLibrary + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + true + C:\Program Files\Micro-Manager-2.0\ + + + false + + + + true + _DEBUG;ALLIEDVISIONCAMERA_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + + $(MM_3RDPARTYPRIVATE)\AVT\VimbaX-2023-1-Win64\api\include;%(AdditionalIncludeDirectories) + + + Windows + true + false + + + + + true + true + true + NDEBUG;ALLIEDVISIONCAMERA_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + + $(MM_3RDPARTYPRIVATE)\AVT\VimbaX-2023-1-Win64\api\include;%(AdditionalIncludeDirectories) + + + Windows + true + true + true + false + + + + + + \ No newline at end of file diff --git a/DeviceAdapters/AlliedVisionCamera/AlliedVisionCamera.vcxproj.filters b/DeviceAdapters/AlliedVisionCamera/AlliedVisionCamera.vcxproj.filters new file mode 100644 index 000000000..cbb7c0517 --- /dev/null +++ b/DeviceAdapters/AlliedVisionCamera/AlliedVisionCamera.vcxproj.filters @@ -0,0 +1,48 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/DeviceAdapters/AlliedVisionCamera/AlliedVisionDeviceBase.cpp b/DeviceAdapters/AlliedVisionCamera/AlliedVisionDeviceBase.cpp new file mode 100644 index 000000000..6e1430cb5 --- /dev/null +++ b/DeviceAdapters/AlliedVisionCamera/AlliedVisionDeviceBase.cpp @@ -0,0 +1 @@ +#include "AlliedVisionDeviceBase.h" diff --git a/DeviceAdapters/AlliedVisionCamera/AlliedVisionDeviceBase.h b/DeviceAdapters/AlliedVisionCamera/AlliedVisionDeviceBase.h new file mode 100644 index 000000000..a719d772e --- /dev/null +++ b/DeviceAdapters/AlliedVisionCamera/AlliedVisionDeviceBase.h @@ -0,0 +1,85 @@ +/*============================================================================= + Copyright (C) 2023 Allied Vision Technologies. All Rights Reserved. + + This file is distributed under the BSD license. + License text is included with the source distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF TITLE, + NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=============================================================================*/ +#ifndef ALLIEDVISIONDEVICEBASE_H +#define ALLIEDVISIONDEVICEBASE_H + +#include "DeviceBase.h" +#include "Loader/LibLoader.h" + +#define LOG_ERROR(err, message) logError(err, message, __FUNCTION__, __LINE__) + +/** + * @brief Base class for Allied Vision devices + */ +template class AlliedVisionDeviceBase : public CDeviceBase +{ + /////////////////////////////////////////////////////////////////////////////// + // PUBLIC + /////////////////////////////////////////////////////////////////////////////// +public: + /** + * @brief Constructor + */ + AlliedVisionDeviceBase() + { + CDeviceBase::InitializeDefaultErrorMessages(); + setApiErrorMessages(); + }; + + /** + * @brief Destructor + */ + virtual ~AlliedVisionDeviceBase() = default; + + void logError(int error, std::string message, std::string function = "", int line = 0) const + { + std::string prefix = "[" + function + "():" + std::to_string(line) + "] "; + CDeviceBase::LogMessage(prefix + message); + CDeviceBase::LogMessageCode(error); + } + + /////////////////////////////////////////////////////////////////////////////// + // PRIVATE + /////////////////////////////////////////////////////////////////////////////// +private: + /** + * @brief Setup error messages for Vimba API + */ + void setApiErrorMessages() + { + CDeviceBase::SetErrorText(VmbErrorApiNotStarted, "Vimba X API not started"); + CDeviceBase::SetErrorText(VmbErrorNotFound, "Device cannot be found"); + CDeviceBase::SetErrorText(VmbErrorDeviceNotOpen, "Device cannot be opened"); + CDeviceBase::SetErrorText(VmbErrorBadParameter, "Invalid parameter passed to the function"); + CDeviceBase::SetErrorText(VmbErrorNotImplemented, "Feature not implemented"); + CDeviceBase::SetErrorText(VmbErrorNotSupported, "Feature not supported"); + CDeviceBase::SetErrorText(VmbErrorUnknown, "Unknown error"); + CDeviceBase::SetErrorText(VmbErrorInvalidValue, "The value is not valid: either out of bounds or not an " + "increment of the minimum"); + CDeviceBase::SetErrorText(VmbErrorBadHandle, "Given device handle is not valid"); + CDeviceBase::SetErrorText(VmbErrorInvalidAccess, "Operation is invalid with the current access mode"); + CDeviceBase::SetErrorText(VmbErrorTimeout, "Timeout occured"); + CDeviceBase::SetErrorText(VmbErrorNotAvailable, "Something is not available"); + CDeviceBase::SetErrorText(VmbErrorNotInitialized, "Something is not initialized"); + CDeviceBase::SetErrorText(VmbErrorAlready, "The operation has been already done"); + CDeviceBase::SetErrorText(VmbErrorFeaturesUnavailable, "Feature is currently unavailable"); + } +}; + +#endif diff --git a/DeviceAdapters/AlliedVisionCamera/AlliedVisionHub.cpp b/DeviceAdapters/AlliedVisionCamera/AlliedVisionHub.cpp new file mode 100644 index 000000000..aa3147fea --- /dev/null +++ b/DeviceAdapters/AlliedVisionCamera/AlliedVisionHub.cpp @@ -0,0 +1,96 @@ +/*============================================================================= + Copyright (C) 2023 Allied Vision Technologies. All Rights Reserved. + + This file is distributed under the BSD license. + License text is included with the source distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF TITLE, + NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=============================================================================*/ +#include "AlliedVisionHub.h" + +#include "AlliedVisionCamera.h" + +AlliedVisionHub::AlliedVisionHub() : + m_sdk(std::make_shared()) +{ +} + +int AlliedVisionHub::DetectInstalledDevices() +{ + LogMessage("Detecting installed cameras..."); + VmbUint32_t camNum; + // Get the number of connected cameras first + VmbError_t err = m_sdk->VmbCamerasList_t(nullptr, 0, &camNum, 0); + if (VmbErrorSuccess == err) + { + VmbCameraInfo_t *camInfo = new VmbCameraInfo_t[camNum]; + + // Get the cameras + err = m_sdk->VmbCamerasList_t(camInfo, camNum, &camNum, sizeof *camInfo); + + if (err == VmbErrorSuccess) + { + for (VmbUint32_t i = 0; i < camNum; ++i) + { + if (camInfo[i].permittedAccess & VmbAccessModeFull) + { + MM::Device *pDev = new AlliedVisionCamera(camInfo[i].cameraIdString); + AddInstalledDevice(pDev); + } + } + } + + delete[] camInfo; + } + else + { + LOG_ERROR(err, "Cannot get installed devices!"); + } + + return err; +} + +int AlliedVisionHub::Initialize() +{ + LogMessage("Init HUB"); + if (m_sdk->isInitialized()) + { + return DEVICE_OK; + } + else + { + LOG_ERROR(VmbErrorApiNotStarted, "SDK not initialized!"); + return VmbErrorApiNotStarted; + } +} + +int AlliedVisionHub::Shutdown() +{ + LogMessage("Shutting down HUB"); + return DEVICE_OK; +} + +void AlliedVisionHub::GetName(char *name) const +{ + CDeviceUtils::CopyLimitedString(name, g_hubName); +} + +bool AlliedVisionHub::Busy() +{ + return false; +} + +std::shared_ptr &AlliedVisionHub::getSDK() +{ + return m_sdk; +} diff --git a/DeviceAdapters/AlliedVisionCamera/AlliedVisionHub.h b/DeviceAdapters/AlliedVisionCamera/AlliedVisionHub.h new file mode 100644 index 000000000..7d47f4b96 --- /dev/null +++ b/DeviceAdapters/AlliedVisionCamera/AlliedVisionHub.h @@ -0,0 +1,73 @@ +/*============================================================================= + Copyright (C) 2023 Allied Vision Technologies. All Rights Reserved. + + This file is distributed under the BSD license. + License text is included with the source distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF TITLE, + NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=============================================================================*/ +#ifndef ALLIEDVISIONHUB_H +#define ALLIEDVISIONHUB_H + +#include "AlliedVisionDeviceBase.h" +#include "DeviceBase.h" +#include "Loader/LibLoader.h" + +#include +/////////////////////////////////////////////////////////////////////////////// +// STATIC VARIABLES +/////////////////////////////////////////////////////////////////////////////// +static constexpr const char *g_hubName = "AlliedVisionHub"; + +/** + * @brief Class that represents a HUB of supported devices + */ +class AlliedVisionHub : public AlliedVisionDeviceBase, AlliedVisionHub> +{ + /////////////////////////////////////////////////////////////////////////////// + // PUBLIC + /////////////////////////////////////////////////////////////////////////////// +public: + /** + * @brief Contructor of a HUB + */ + AlliedVisionHub(); + + /** + * @brief Destructor of a HUB + */ + virtual ~AlliedVisionHub() = default; + + /** + * @brief SDK getter + * @return Pointer to SDK + */ + std::shared_ptr &getSDK(); + + /////////////////////////////////////////////////////////////////////////////// + // uMANAGER API METHODS + /////////////////////////////////////////////////////////////////////////////// + int DetectInstalledDevices() override; + int Initialize() override; + int Shutdown() override; + void GetName(char *name) const override; + bool Busy() override; + + /////////////////////////////////////////////////////////////////////////////// + // PRIVATE + /////////////////////////////////////////////////////////////////////////////// +private: + std::shared_ptr m_sdk; // +#elif _WIN32 +#include +#else +// nothing +#endif + +#include "Constants.h" + +VimbaXApi::VimbaXApi() : + m_sdk(VIMBA_X_LIB_NAME, VIMBA_X_LIB_DIR.c_str()), + m_initialized(false), + m_imageTransform(VIMBA_X_IMAGE_TRANSFORM_NAME, VIMBA_X_LIB_DIR.c_str()) +{ + if (m_sdk.isLoaded() && m_imageTransform.isLoaded()) + { + bool allResolved = true; + VmbStartup_t = m_sdk.resolveFunction("VmbStartup", allResolved); + VmbVersionQuery_t = m_sdk.resolveFunction("VmbVersionQuery", allResolved); + VmbShutdown_t = m_sdk.resolveFunction("VmbShutdown", allResolved); + VmbCamerasList_t = m_sdk.resolveFunction("VmbCamerasList", allResolved); + VmbCameraOpen_t = m_sdk.resolveFunction("VmbCameraOpen", allResolved); + VmbCameraClose_t = m_sdk.resolveFunction("VmbCameraClose", allResolved); + VmbCameraInfoQuery_t = m_sdk.resolveFunction("VmbCameraInfoQuery", allResolved); + VmbPayloadSizeGet_t = m_sdk.resolveFunction("VmbPayloadSizeGet", allResolved); + VmbFrameAnnounce_t = m_sdk.resolveFunction("VmbFrameAnnounce", allResolved); + VmbCaptureStart_t = m_sdk.resolveFunction("VmbCaptureStart", allResolved); + VmbCaptureEnd_t = m_sdk.resolveFunction("VmbCaptureEnd", allResolved); + VmbCaptureFrameQueue_t = m_sdk.resolveFunction("VmbCaptureFrameQueue", allResolved); + VmbCaptureFrameWait_t = m_sdk.resolveFunction("VmbCaptureFrameWait", allResolved); + VmbCaptureQueueFlush_t = m_sdk.resolveFunction("VmbCaptureQueueFlush", allResolved); + VmbFrameRevokeAll_t = m_sdk.resolveFunction("VmbFrameRevokeAll", allResolved); + VmbFeatureCommandRun_t = m_sdk.resolveFunction("VmbFeatureCommandRun", allResolved); + VmbFeaturesList_t = m_sdk.resolveFunction("VmbFeaturesList", allResolved); + VmbFeatureBoolGet_t = m_sdk.resolveFunction("VmbFeatureBoolGet", allResolved); + VmbFeatureBoolSet_t = m_sdk.resolveFunction("VmbFeatureBoolSet", allResolved); + VmbFeatureEnumGet_t = m_sdk.resolveFunction("VmbFeatureEnumGet", allResolved); + VmbFeatureEnumSet_t = m_sdk.resolveFunction("VmbFeatureEnumSet", allResolved); + VmbFeatureFloatGet_t = m_sdk.resolveFunction("VmbFeatureFloatGet", allResolved); + VmbFeatureFloatSet_t = m_sdk.resolveFunction("VmbFeatureFloatSet", allResolved); + VmbFeatureIntGet_t = m_sdk.resolveFunction("VmbFeatureIntGet", allResolved); + VmbFeatureIntSet_t = m_sdk.resolveFunction("VmbFeatureIntSet", allResolved); + VmbFeatureStringGet_t = m_sdk.resolveFunction("VmbFeatureStringGet", allResolved); + VmbFeatureStringSet_t = m_sdk.resolveFunction("VmbFeatureStringSet", allResolved); + VmbChunkDataAccess_t = m_sdk.resolveFunction("VmbChunkDataAccess", allResolved); + VmbFeatureEnumRangeQuery_t = m_sdk.resolveFunction("VmbFeatureEnumRangeQuery", allResolved); + VmbFeatureIntRangeQuery_t = m_sdk.resolveFunction("VmbFeatureIntRangeQuery", allResolved); + VmbFeatureStringMaxlengthQuery_t = m_sdk.resolveFunction("VmbFeatureStringMaxlengthQuery", allResolved); + VmbFeatureInfoQuery_t = m_sdk.resolveFunction("VmbFeatureInfoQuery", allResolved); + VmbFeatureFloatRangeQuery_t = m_sdk.resolveFunction("VmbFeatureFloatRangeQuery", allResolved); + VmbFeatureInvalidationRegister_t = m_sdk.resolveFunction("VmbFeatureInvalidationRegister", allResolved); + VmbFeatureAccessQuery_t = m_sdk.resolveFunction("VmbFeatureAccessQuery", allResolved); + VmbFeatureIntIncrementQuery_t = m_sdk.resolveFunction("VmbFeatureIntIncrementQuery", allResolved); + VmbFeatureFloatIncrementQuery_t = m_sdk.resolveFunction("VmbFeatureFloatIncrementQuery", allResolved); + VmbFeatureCommandIsDone_t = m_sdk.resolveFunction("VmbFeatureCommandIsDone", allResolved); + VmbSetImageInfoFromPixelFormat_t = m_imageTransform.resolveFunction("VmbSetImageInfoFromPixelFormat", allResolved); + VmbImageTransform_t = m_imageTransform.resolveFunction("VmbImageTransform", allResolved); + if (allResolved) + { + auto err = VmbStartup_t(nullptr); + if (err == VmbErrorSuccess) + { + m_initialized = true; + } + } + } +} + +bool VimbaXApi::isInitialized() const +{ + return m_initialized; +} + +VimbaXApi::~VimbaXApi() +{ + if (m_initialized) + { + m_initialized = false; + VmbShutdown_t(); + } +} + +bool LibLoader::isLoaded() const +{ + return m_loaded; +} +#ifdef __linux__ +LibLoader::LibLoader(const char *lib, const char *libPath) : + m_libName(lib), + m_libPath(libPath), + m_module(nullptr), + m_loaded(false) +{ + std::string path = std::string(m_libName); + dlerror(); + m_module = dlopen(path.c_str(), RTLD_NOW); + if (m_module != nullptr) + { + m_loaded = true; + } +} + +LibLoader::~LibLoader() +{ + if (m_loaded) + { + dlclose(m_module); + m_module = nullptr; + m_loaded = false; + m_libName = nullptr; + } +} + +SymbolWrapper LibLoader::resolveFunction(const char *functionName, bool &allResolved) const +{ + dlerror(); + void *funPtr = nullptr; + if (allResolved) + { + funPtr = dlsym(m_module, functionName); + allResolved = allResolved && (funPtr != nullptr); + } + return SymbolWrapper(funPtr); +} +#elif _WIN32 +LibLoader::LibLoader(const char *lib, const char *libPath) : + m_libName(lib), + m_libPath(libPath), + m_module(nullptr), + m_loaded(false) +{ + SetDllDirectoryA(m_libPath); + m_module = LoadLibraryA(m_libName); + if (m_module != nullptr) + { + m_loaded = true; + } +} + +LibLoader::~LibLoader() +{ + if (m_loaded) + { + FreeModule(static_cast(m_module)); + m_module = nullptr; + m_loaded = false; + m_libName = nullptr; + } +} + +SymbolWrapper LibLoader::resolveFunction(const char *functionName, bool &allResolved) const +{ + void *funPtr = nullptr; + if (allResolved) + { + funPtr = GetProcAddress(static_cast(m_module), functionName); + allResolved = allResolved && (funPtr != nullptr); + } + return SymbolWrapper(funPtr); +} +#else +// nothing +#endif diff --git a/DeviceAdapters/AlliedVisionCamera/Loader/LibLoader.h b/DeviceAdapters/AlliedVisionCamera/Loader/LibLoader.h new file mode 100644 index 000000000..fc63ea663 --- /dev/null +++ b/DeviceAdapters/AlliedVisionCamera/Loader/LibLoader.h @@ -0,0 +1,187 @@ +/*============================================================================= + Copyright (C) 2023 Allied Vision Technologies. All Rights Reserved. + + This file is distributed under the BSD license. + License text is included with the source distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF TITLE, + NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=============================================================================*/ +#ifndef LIBLOADER_H +#define LIBLOADER_H + +#include +#include + +#include "VmbC/VmbC.h" +#include "VmbImageTransform/VmbTransform.h" + +/** + * @brief Wrapper for single Windows process + */ +class SymbolWrapper +{ + /////////////////////////////////////////////////////////////////////////////// + // PUBLIC + /////////////////////////////////////////////////////////////////////////////// +public: + /** + * @brief Constructor of wrapper + * @param[in] funPtr Pointer to the resolved symbol + */ + explicit SymbolWrapper(void *funPtr) : + m_funPtr(funPtr) + { + } + + /** + * @brief Operator () overload to call function + */ + template ::value>> operator T *() const + { + return reinterpret_cast(m_funPtr); + } + /////////////////////////////////////////////////////////////////////////////// + // PRIVATE + /////////////////////////////////////////////////////////////////////////////// +private: + void *m_funPtr; //