GrabBag/Device/IKapDevice/Src/IKapDevice.cpp
2025-12-10 00:01:32 +08:00

682 lines
17 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "IKapDevice.h"
#include <cstring>
#include <iostream>
// 静态工厂方法实现
int IIKapDevice::CreateObject(IIKapDevice** ppDevice)
{
if (ppDevice == nullptr)
return -1;
*ppDevice = new CIKapDevice();
return (*ppDevice) ? 0 : -1;
}
CIKapDevice::CIKapDevice()
: m_hDevice(nullptr)
, m_hStream(nullptr)
, m_bIsGrabbing(false)
, m_bLibInitialized(false)
, m_imageCallback(nullptr)
, m_pUserData(nullptr)
, m_nDeviceIndex(0)
, m_bDeviceOpened(false)
{
}
CIKapDevice::~CIKapDevice()
{
// 确保资源被释放
if (m_bIsGrabbing.load())
{
StopGrabbing();
}
if (m_bDeviceOpened)
{
CloseDevice();
}
if (m_bLibInitialized.load())
{
TerminateLibrary();
}
}
int CIKapDevice::InitLibrary()
{
if (m_bLibInitialized.load())
return 0;
ITKSTATUS status = ItkManInitialize();
if (status != ITKSTATUS_OK)
{
std::cerr << "ItkManInitialize failed, status: " << status << std::endl;
return -1;
}
m_bLibInitialized.store(true);
return 0;
}
int CIKapDevice::TerminateLibrary()
{
if (!m_bLibInitialized.load())
return 0;
ITKSTATUS status = ItkManTerminate();
if (status != ITKSTATUS_OK)
{
std::cerr << "ItkManTerminate failed, status: " << status << std::endl;
return -1;
}
m_bLibInitialized.store(false);
return 0;
}
int CIKapDevice::EnumerateDevices(unsigned int& nCount)
{
if (!m_bLibInitialized.load())
{
std::cerr << "Library not initialized" << std::endl;
return -1;
}
ITKSTATUS status = ItkManGetDeviceCount(&nCount);
if (status != ITKSTATUS_OK)
{
std::cerr << "ItkManGetDeviceCount failed, status: " << status << std::endl;
return -1;
}
return 0;
}
int CIKapDevice::GetDeviceInfo(unsigned int nIndex, IKapDeviceInfo& deviceInfo)
{
if (!m_bLibInitialized.load())
{
std::cerr << "Library not initialized" << std::endl;
return -1;
}
ITKDEV_INFO devInfo;
memset(&devInfo, 0, sizeof(devInfo));
ITKSTATUS status = ItkManGetDeviceInfo(nIndex, &devInfo);
if (status != ITKSTATUS_OK)
{
std::cerr << "ItkManGetDeviceInfo failed, status: " << status << std::endl;
return -1;
}
// 复制设备信息
strncpy(deviceInfo.vendorName, devInfo.VendorName, sizeof(deviceInfo.vendorName) - 1);
deviceInfo.vendorName[sizeof(deviceInfo.vendorName) - 1] = '\0';
strncpy(deviceInfo.modelName, devInfo.ModelName, sizeof(deviceInfo.modelName) - 1);
deviceInfo.modelName[sizeof(deviceInfo.modelName) - 1] = '\0';
strncpy(deviceInfo.serialNumber, devInfo.SerialNumber, sizeof(deviceInfo.serialNumber) - 1);
deviceInfo.serialNumber[sizeof(deviceInfo.serialNumber) - 1] = '\0';
strncpy(deviceInfo.userDefinedName, devInfo.UserDefinedName, sizeof(deviceInfo.userDefinedName) - 1);
deviceInfo.userDefinedName[sizeof(deviceInfo.userDefinedName) - 1] = '\0';
return 0;
}
int CIKapDevice::OpenDevice(unsigned int nIndex, int accessMode)
{
std::lock_guard<std::mutex> lock(m_mutex);
if (m_bDeviceOpened)
{
std::cerr << "Device already opened" << std::endl;
return -1;
}
if (!m_bLibInitialized.load())
{
std::cerr << "Library not initialized" << std::endl;
return -1;
}
// 打开设备
ITKSTATUS status = ItkDevOpen(nIndex, accessMode, &m_hDevice);
if (status != ITKSTATUS_OK || m_hDevice == nullptr)
{
std::cerr << "ItkDevOpen failed, status: " << status << std::endl;
return -1;
}
m_nDeviceIndex = nIndex;
m_bDeviceOpened = true;
// 创建数据流和Buffer
if (CreateStreamAndBuffer() != 0)
{
CloseDevice();
return -1;
}
return 0;
}
int CIKapDevice::CloseDevice()
{
std::lock_guard<std::mutex> lock(m_mutex);
if (!m_bDeviceOpened)
return 0;
// 释放数据流和Buffer
ReleaseStreamAndBuffer();
// 关闭设备
if (m_hDevice != nullptr)
{
ITKSTATUS status = ItkDevClose(m_hDevice);
if (status != ITKSTATUS_OK)
{
std::cerr << "ItkDevClose failed, status: " << status << std::endl;
}
m_hDevice = nullptr;
}
m_bDeviceOpened = false;
return 0;
}
int CIKapDevice::IsConnected(bool& bConnected)
{
if (!m_bDeviceOpened || m_hDevice == nullptr)
{
bConnected = false;
return 0;
}
#ifdef _WIN32
// Windows 平台:使用新版 API
bool connected = false;
ITKSTATUS status = ItkDevIsConnected(m_hDevice, &connected);
if (status != ITKSTATUS_OK)
{
std::cerr << "ItkDevIsConnected failed, status: " << status << std::endl;
return -1;
}
bConnected = connected;
#else
// Linux/ARM 平台:旧版 SDK 没有 IsConnected 接口,简化实现
// 假设设备打开后就是连接状态
bConnected = (m_hDevice != nullptr);
#endif
return 0;
}
int CIKapDevice::CreateStreamAndBuffer()
{
if (m_hDevice == nullptr)
return -1;
// 获取数据流数量
uint32_t streamCount = 0;
ITKSTATUS status = ItkDevGetStreamCount(m_hDevice, &streamCount);
if (status != ITKSTATUS_OK || streamCount == 0)
{
std::cerr << "ItkDevGetStreamCount failed or no stream available" << std::endl;
return -1;
}
#ifdef _WIN32
// Windows 平台:使用新版 API ItkDevAllocStreamEx自动分配buffer
status = ItkDevAllocStreamEx(m_hDevice, 0, m_nBufferCount, &m_hStream);
if (status != ITKSTATUS_OK || m_hStream == nullptr)
{
std::cerr << "ItkDevAllocStreamEx failed, status: " << status << std::endl;
return -1;
}
// 获取所有 Buffer
m_vecBuffers.resize(m_nBufferCount);
for (unsigned int i = 0; i < m_nBufferCount; ++i)
{
status = ItkStreamGetBuffer(m_hStream, i, &m_vecBuffers[i]);
if (status != ITKSTATUS_OK)
{
std::cerr << "ItkStreamGetBuffer failed for index " << i << std::endl;
ReleaseStreamAndBuffer();
return -1;
}
}
#else
// Linux/ARM 平台:使用旧版 API ItkDevAllocStream需要手动创建buffer
// 旧版 API 需要传入单个 buffer简化实现使用 nullptr 让SDK自动分配
status = ItkDevAllocStream(m_hDevice, 0, nullptr, &m_hStream);
if (status != ITKSTATUS_OK || m_hStream == nullptr)
{
std::cerr << "ItkDevAllocStream failed, status: " << status << std::endl;
return -1;
}
// ARM 版本不支持 GetBufferbuffer 由 SDK 内部管理
m_vecBuffers.clear();
#endif
return 0;
}
int CIKapDevice::ReleaseStreamAndBuffer()
{
// 清空 Buffer 列表
m_vecBuffers.clear();
// 释放数据流
if (m_hStream != nullptr)
{
ItkDevFreeStream(m_hStream);
m_hStream = nullptr;
}
return 0;
}
int CIKapDevice::GrabSingleFrame(ImageData& imageData, unsigned int nTimeout)
{
if (!m_bDeviceOpened || m_hDevice == nullptr || m_hStream == nullptr)
{
std::cerr << "Device not opened" << std::endl;
return -1;
}
#ifdef _WIN32
// Windows 平台:使用主动取图 API
// 开始采集单帧
ITKSTATUS status = ItkStreamStart(m_hStream, 1);
if (status != ITKSTATUS_OK)
{
std::cerr << "ItkStreamStart failed, status: " << status << std::endl;
return -1;
}
// 等待单帧图像
ITKBUFFER hReadyBuffer = nullptr;
status = ItkStreamWaitOneFrameReady(m_hStream, &hReadyBuffer, (long long)nTimeout);
if (status != ITKSTATUS_OK || hReadyBuffer == nullptr)
{
std::cerr << "ItkStreamWaitOneFrameReady failed or timeout, status: " << status << std::endl;
ItkStreamStop(m_hStream);
return -1;
}
// 复制图像数据
int ret = CopyImageData(hReadyBuffer, imageData);
// 清除buffer返还给stream
ItkStreamClearBuffer(m_hStream, hReadyBuffer);
// 停止采集
ItkStreamStop(m_hStream);
return ret;
#else
// Linux/ARM 平台:旧版 SDK 不支持 WaitOneFrameReady
// 简化实现:返回不支持错误
std::cerr << "GrabSingleFrame not supported on ARM platform (old SDK)" << std::endl;
return -1;
#endif
}
int CIKapDevice::CopyImageData(ITKBUFFER hBuffer, ImageData& imageData)
{
if (hBuffer == nullptr)
return -1;
// 获取 Buffer 信息
ITK_BUFFER_INFO bufferInfo;
memset(&bufferInfo, 0, sizeof(bufferInfo));
ITKSTATUS status = ItkBufferGetInfo(hBuffer, &bufferInfo);
if (status != ITKSTATUS_OK)
{
std::cerr << "ItkBufferGetInfo failed, status: " << status << std::endl;
return -1;
}
// 填充图像数据结构
imageData.width = static_cast<unsigned int>(bufferInfo.ImageWidth);
imageData.height = static_cast<unsigned int>(bufferInfo.ImageHeight);
imageData.pixelFormat = static_cast<unsigned int>(bufferInfo.PixelFormat);
imageData.imageSize = static_cast<unsigned int>(bufferInfo.ImageSize);
imageData.timestamp = bufferInfo.TimestampNs;
imageData.frameID = bufferInfo.BlockID;
// 分配内存并复制图像数据
if (imageData.pData != nullptr)
{
delete[] imageData.pData;
}
imageData.pData = new unsigned char[imageData.imageSize];
// 使用ItkBufferRead读取数据
status = ItkBufferRead(hBuffer, 0, imageData.pData, (uint32_t)imageData.imageSize);
if (status != ITKSTATUS_OK)
{
std::cerr << "ItkBufferRead failed, status: " << status << std::endl;
delete[] imageData.pData;
imageData.pData = nullptr;
return -1;
}
return 0;
}
int CIKapDevice::StartGrabbing(ImageCallback callback, void* pUser)
{
if (m_bIsGrabbing.load())
{
std::cerr << "Already grabbing" << std::endl;
return -1;
}
if (!m_bDeviceOpened || m_hDevice == nullptr || m_hStream == nullptr)
{
std::cerr << "Device not opened" << std::endl;
return -1;
}
if (callback == nullptr)
{
std::cerr << "Callback is null" << std::endl;
return -1;
}
m_imageCallback = callback;
m_pUserData = pUser;
m_bIsGrabbing.store(true);
// 启动采集线程
m_grabbingThread = std::thread(&CIKapDevice::GrabbingThread, this);
return 0;
}
int CIKapDevice::StopGrabbing()
{
if (!m_bIsGrabbing.load())
return 0;
// 设置停止标志
m_bIsGrabbing.store(false);
// 等待线程结束
if (m_grabbingThread.joinable())
{
m_grabbingThread.join();
}
m_imageCallback = nullptr;
m_pUserData = nullptr;
return 0;
}
bool CIKapDevice::IsGrabbing()
{
return m_bIsGrabbing.load();
}
void CIKapDevice::GrabbingThread()
{
// 开始连续采集
ITKSTATUS status = ItkStreamStart(m_hStream, 0); // 0表示连续采集
if (status != ITKSTATUS_OK)
{
std::cerr << "ItkStreamStart failed in thread" << std::endl;
m_bIsGrabbing.store(false);
return;
}
while (m_bIsGrabbing.load())
{
// 等待图像
ITKBUFFER hReadyBuffer = nullptr;
status = ItkStreamWaitOneFrameReady(m_hStream, &hReadyBuffer, 1000);
if (status == ITKSTATUS_OK && hReadyBuffer != nullptr)
{
// 复制图像数据
ImageData imageData;
imageData.pData = nullptr;
if (CopyImageData(hReadyBuffer, imageData) == 0)
{
// 调用回调函数
if (m_imageCallback)
{
m_imageCallback(imageData, m_pUserData);
}
// 释放图像数据内存
if (imageData.pData != nullptr)
{
delete[] imageData.pData;
imageData.pData = nullptr;
}
}
// 清除buffer返还给stream继续使用
ItkStreamClearBuffer(m_hStream, hReadyBuffer);
}
}
// 停止采集
ItkStreamStop(m_hStream);
}
int CIKapDevice::SetExposureTime(double exposureTime)
{
if (!m_bDeviceOpened || m_hDevice == nullptr)
{
std::cerr << "Device not opened" << std::endl;
return -1;
}
ITKSTATUS status = ItkDevSetDouble(m_hDevice, "ExposureTime", exposureTime);
if (status != ITKSTATUS_OK)
{
std::cerr << "SetExposureTime failed, status: " << status << std::endl;
return -1;
}
return 0;
}
int CIKapDevice::GetExposureTime(double& exposureTime)
{
if (!m_bDeviceOpened || m_hDevice == nullptr)
{
std::cerr << "Device not opened" << std::endl;
return -1;
}
ITKSTATUS status = ItkDevGetDouble(m_hDevice, "ExposureTime", &exposureTime);
if (status != ITKSTATUS_OK)
{
std::cerr << "GetExposureTime failed, status: " << status << std::endl;
return -1;
}
return 0;
}
int CIKapDevice::SetGain(double gain)
{
if (!m_bDeviceOpened || m_hDevice == nullptr)
{
std::cerr << "Device not opened" << std::endl;
return -1;
}
ITKSTATUS status = ItkDevSetDouble(m_hDevice, "Gain", gain);
if (status != ITKSTATUS_OK)
{
std::cerr << "SetGain failed, status: " << status << std::endl;
return -1;
}
return 0;
}
int CIKapDevice::GetGain(double& gain)
{
if (!m_bDeviceOpened || m_hDevice == nullptr)
{
std::cerr << "Device not opened" << std::endl;
return -1;
}
ITKSTATUS status = ItkDevGetDouble(m_hDevice, "Gain", &gain);
if (status != ITKSTATUS_OK)
{
std::cerr << "GetGain failed, status: " << status << std::endl;
return -1;
}
return 0;
}
int CIKapDevice::SetTriggerMode(bool bEnable)
{
if (!m_bDeviceOpened || m_hDevice == nullptr)
{
std::cerr << "Device not opened" << std::endl;
return -1;
}
const char* triggerMode = bEnable ? "On" : "Off";
ITKSTATUS status = ItkDevFromString(m_hDevice, "TriggerMode", triggerMode);
if (status != ITKSTATUS_OK)
{
std::cerr << "SetTriggerMode failed, status: " << status << std::endl;
return -1;
}
return 0;
}
int CIKapDevice::ExecuteSoftwareTrigger()
{
if (!m_bDeviceOpened || m_hDevice == nullptr)
{
std::cerr << "Device not opened" << std::endl;
return -1;
}
ITKSTATUS status = ItkDevExecuteCommand(m_hDevice, "TriggerSoftware");
if (status != ITKSTATUS_OK)
{
std::cerr << "ExecuteSoftwareTrigger failed, status: " << status << std::endl;
return -1;
}
return 0;
}
int CIKapDevice::GetWidth(unsigned int& width)
{
if (!m_bDeviceOpened || m_hDevice == nullptr)
{
std::cerr << "Device not opened" << std::endl;
return -1;
}
int64_t value = 0;
ITKSTATUS status = ItkDevGetInt64(m_hDevice, "Width", &value);
if (status != ITKSTATUS_OK)
{
std::cerr << "GetWidth failed, status: " << status << std::endl;
return -1;
}
width = static_cast<unsigned int>(value);
return 0;
}
int CIKapDevice::GetHeight(unsigned int& height)
{
if (!m_bDeviceOpened || m_hDevice == nullptr)
{
std::cerr << "Device not opened" << std::endl;
return -1;
}
int64_t value = 0;
ITKSTATUS status = ItkDevGetInt64(m_hDevice, "Height", &value);
if (status != ITKSTATUS_OK)
{
std::cerr << "GetHeight failed, status: " << status << std::endl;
return -1;
}
height = static_cast<unsigned int>(value);
return 0;
}
int CIKapDevice::SetROI(unsigned int offsetX, unsigned int offsetY,
unsigned int width, unsigned int height)
{
if (!m_bDeviceOpened || m_hDevice == nullptr)
{
std::cerr << "Device not opened" << std::endl;
return -1;
}
ITKSTATUS status;
// 设置 OffsetX
status = ItkDevSetInt64(m_hDevice, "OffsetX", offsetX);
if (status != ITKSTATUS_OK)
{
std::cerr << "Set OffsetX failed" << std::endl;
return -1;
}
// 设置 OffsetY
status = ItkDevSetInt64(m_hDevice, "OffsetY", offsetY);
if (status != ITKSTATUS_OK)
{
std::cerr << "Set OffsetY failed" << std::endl;
return -1;
}
// 设置 Width
status = ItkDevSetInt64(m_hDevice, "Width", width);
if (status != ITKSTATUS_OK)
{
std::cerr << "Set Width failed" << std::endl;
return -1;
}
// 设置 Height
status = ItkDevSetInt64(m_hDevice, "Height", height);
if (status != ITKSTATUS_OK)
{
std::cerr << "Set Height failed" << std::endl;
return -1;
}
return 0;
}
int CIKapDevice::GetLibraryVersion(unsigned int& version)
{
ITKSTATUS status = ItkManGetVersion(&version);
if (status != ITKSTATUS_OK)
{
std::cerr << "ItkManGetVersion failed, status: " << status << std::endl;
return -1;
}
return 0;
}