GrabBag/Device/IKapDevice/Src/IKapDevice.cpp

682 lines
17 KiB
C++
Raw Normal View History

2025-12-10 00:01:32 +08:00
#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;
}