2026-01-27 20:43:12 +08:00
|
|
|
|
#include "GlLineLaserDevice.h"
|
|
|
|
|
|
#include "VrError.h"
|
|
|
|
|
|
#include "VrLog.h"
|
|
|
|
|
|
|
|
|
|
|
|
#include <cstring>
|
|
|
|
|
|
#include <chrono>
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
|
2026-02-07 23:46:44 +08:00
|
|
|
|
// 静态实例指针,供SDK回调访问
|
|
|
|
|
|
CGlLineLaserDevice* CGlLineLaserDevice::s_pInstance = nullptr;
|
|
|
|
|
|
|
2026-01-27 20:43:12 +08:00
|
|
|
|
CGlLineLaserDevice::CGlLineLaserDevice()
|
|
|
|
|
|
: m_nDeviceId(0)
|
|
|
|
|
|
, m_bDeviceOpen(false)
|
|
|
|
|
|
, m_nProfileWidth(4096)
|
|
|
|
|
|
, m_dXPitch(0.01)
|
|
|
|
|
|
, m_dYPitch(1.0)
|
|
|
|
|
|
, m_nBatchLines(200)
|
|
|
|
|
|
{
|
|
|
|
|
|
memset(&m_modelInfo, 0, sizeof(GLX8_2_ModelInfo));
|
2026-02-07 23:46:44 +08:00
|
|
|
|
s_pInstance = this;
|
2026-01-27 20:43:12 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CGlLineLaserDevice::~CGlLineLaserDevice()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (m_bDeviceOpen) {
|
|
|
|
|
|
CloseDevice();
|
|
|
|
|
|
}
|
2026-02-07 23:46:44 +08:00
|
|
|
|
if (s_pInstance == this) {
|
|
|
|
|
|
s_pInstance = nullptr;
|
|
|
|
|
|
}
|
2026-01-27 20:43:12 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int CGlLineLaserDevice::InitDevice()
|
|
|
|
|
|
{
|
|
|
|
|
|
int ret = GLX8_2_Initialize();
|
|
|
|
|
|
if (ret != 0) {
|
|
|
|
|
|
LOG_ERROR("GLX8_2_Initialize failed: %d\n", ret);
|
|
|
|
|
|
return ERR_CODE(DEV_OPEN_ERR);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LOG_DEBUG("GLX8_2_Initialize success, SDK version: %s\n", GLX8_2_GetVersion());
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int CGlLineLaserDevice::SetStatusCallback(VzNL_OnNotifyStatusCBEx fNotify, void *param)
|
|
|
|
|
|
{
|
|
|
|
|
|
m_pStatusCallback = fNotify;
|
|
|
|
|
|
m_pStatusCallbackParam = param;
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int CGlLineLaserDevice::OpenDevice(const char* sIP, bool bRGBD, bool bSwing, bool bFillLaser)
|
|
|
|
|
|
{
|
|
|
|
|
|
(void)bRGBD;
|
|
|
|
|
|
(void)bSwing;
|
|
|
|
|
|
(void)bFillLaser;
|
|
|
|
|
|
|
|
|
|
|
|
if (m_bDeviceOpen) {
|
|
|
|
|
|
LOG_WARNING("Device already open\n");
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 解析IP地址
|
|
|
|
|
|
GLX8_2_ETHERNET_CONFIG ethConfig;
|
|
|
|
|
|
memset(ðConfig, 0, sizeof(ethConfig));
|
2026-02-07 23:46:44 +08:00
|
|
|
|
|
2026-01-27 20:43:12 +08:00
|
|
|
|
if (sIP && strlen(sIP) > 0) {
|
2026-02-06 01:14:27 +08:00
|
|
|
|
LOG_DEBUG("open IP address format: %s\n", sIP);
|
2026-01-27 20:43:12 +08:00
|
|
|
|
int ip[4];
|
|
|
|
|
|
if (sscanf(sIP, "%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3]) == 4) {
|
|
|
|
|
|
ethConfig.abyIpAddress[0] = (unsigned char)ip[0];
|
|
|
|
|
|
ethConfig.abyIpAddress[1] = (unsigned char)ip[1];
|
|
|
|
|
|
ethConfig.abyIpAddress[2] = (unsigned char)ip[2];
|
|
|
|
|
|
ethConfig.abyIpAddress[3] = (unsigned char)ip[3];
|
|
|
|
|
|
m_strDeviceIP = sIP;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
LOG_ERROR("Invalid IP address format: %s\n", sIP);
|
|
|
|
|
|
return ERR_CODE(DEV_ARG_INVAILD);
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 搜索在线设备
|
|
|
|
|
|
int count = 0;
|
|
|
|
|
|
GLX8_2_ETHERNET_CONFIG* pDevices = GLX8_2_SearchOnline(&count, 3000);
|
|
|
|
|
|
if (count == 0 || pDevices == nullptr) {
|
|
|
|
|
|
LOG_ERROR("No device found\n");
|
|
|
|
|
|
return ERR_CODE(DEV_NOT_FIND);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
memcpy(ðConfig, &pDevices[0], sizeof(GLX8_2_ETHERNET_CONFIG));
|
|
|
|
|
|
char ipStr[32];
|
|
|
|
|
|
sprintf(ipStr, "%d.%d.%d.%d", ethConfig.abyIpAddress[0], ethConfig.abyIpAddress[1], ethConfig.abyIpAddress[2], ethConfig.abyIpAddress[3]);
|
|
|
|
|
|
m_strDeviceIP = ipStr;
|
|
|
|
|
|
LOG_DEBUG("Found device: %s\n", m_strDeviceIP.c_str());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 打开设备
|
|
|
|
|
|
int ret = GLX8_2_EthernetOpen(m_nDeviceId, ðConfig);
|
|
|
|
|
|
if (ret != 0) {
|
2026-02-07 23:46:44 +08:00
|
|
|
|
LOG_ERROR("GLX8_2_EthernetOpen failed: %d\n", ret);
|
2026-01-27 20:43:12 +08:00
|
|
|
|
return ERR_CODE(DEV_OPEN_ERR);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
m_bDeviceOpen = true;
|
|
|
|
|
|
LOG_DEBUG("Device opened: %s\n", m_strDeviceIP.c_str());
|
|
|
|
|
|
|
|
|
|
|
|
// 获取设备信息
|
|
|
|
|
|
ret = GLX8_2_GetModelInfos(m_nDeviceId, &m_modelInfo);
|
|
|
|
|
|
if (ret == 0) {
|
|
|
|
|
|
m_nProfileWidth = m_modelInfo.ProfileDataWidth;
|
|
|
|
|
|
m_dXPitch = m_modelInfo.xPixth;
|
|
|
|
|
|
if (m_modelInfo.yPixth > 0) {
|
|
|
|
|
|
m_dYPitch = m_modelInfo.yPixth;
|
|
|
|
|
|
}
|
|
|
|
|
|
LOG_DEBUG("Device model: %s, width: %d, xPitch: %.4f, yPitch: %.4f\n",
|
|
|
|
|
|
m_modelInfo.Model, m_nProfileWidth, m_dXPitch, m_dYPitch);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-07 23:46:44 +08:00
|
|
|
|
// 注册SDK批处理回调(批处理参数在设备端软件预先配置)
|
|
|
|
|
|
ret = RegisterBatchCallback();
|
|
|
|
|
|
if (ret != SUCCESS) {
|
|
|
|
|
|
LOG_ERROR("RegisterBatchCallback failed: %d\n", ret);
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
}
|
2026-01-27 20:43:12 +08:00
|
|
|
|
|
2026-02-07 23:46:44 +08:00
|
|
|
|
LOG_DEBUG("Device initialized successfully (callback mode)\n");
|
2026-01-27 20:43:12 +08:00
|
|
|
|
return SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-07 23:46:44 +08:00
|
|
|
|
// 配置批处理模式
|
|
|
|
|
|
int CGlLineLaserDevice::ConfigureBatchMode()
|
|
|
|
|
|
{
|
|
|
|
|
|
LOG_DEBUG("Configuring batch mode...\n");
|
|
|
|
|
|
|
|
|
|
|
|
char inval[4];
|
|
|
|
|
|
uint32_t ival;
|
|
|
|
|
|
|
|
|
|
|
|
// 1. 开启批处理测量
|
|
|
|
|
|
ival = 1;
|
|
|
|
|
|
memcpy(inval, &ival, 4);
|
|
|
|
|
|
int ret = GLX8_2_SetSetting(m_nDeviceId, 1, 0, 0, 3, nullptr, inval, 4);
|
|
|
|
|
|
if (ret != 0) {
|
|
|
|
|
|
LOG_ERROR("Failed to enable batch mode: %d\n", ret);
|
|
|
|
|
|
return ERR_CODE(DEV_CTRL_ERR);
|
|
|
|
|
|
}
|
|
|
|
|
|
LOG_DEBUG("Batch mode enabled\n");
|
|
|
|
|
|
|
|
|
|
|
|
// 2. 设置批处理数量
|
|
|
|
|
|
ival = m_nBatchLines;
|
|
|
|
|
|
memcpy(inval, &ival, 4);
|
|
|
|
|
|
ret = GLX8_2_SetSetting(m_nDeviceId, 1, 0, 0, 0x0a, nullptr, inval, 4);
|
|
|
|
|
|
if (ret != 0) {
|
|
|
|
|
|
LOG_ERROR("Failed to set batch lines: %d\n", ret);
|
|
|
|
|
|
return ERR_CODE(DEV_CTRL_ERR);
|
|
|
|
|
|
}
|
|
|
|
|
|
LOG_DEBUG("Batch lines set to %d\n", m_nBatchLines);
|
|
|
|
|
|
|
|
|
|
|
|
// 3. 设置带亮度输出
|
|
|
|
|
|
ival = 1;
|
|
|
|
|
|
memcpy(inval, &ival, 4);
|
|
|
|
|
|
ret = GLX8_2_SetSetting(m_nDeviceId, 1, 2, 0, 0x0b, nullptr, inval, 4);
|
|
|
|
|
|
if (ret != 0) {
|
|
|
|
|
|
LOG_ERROR("Failed to enable intensity output: %d\n", ret);
|
|
|
|
|
|
return ERR_CODE(DEV_CTRL_ERR);
|
|
|
|
|
|
}
|
|
|
|
|
|
LOG_DEBUG("Intensity output enabled\n");
|
|
|
|
|
|
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 注册SDK批处理回调
|
|
|
|
|
|
int CGlLineLaserDevice::RegisterBatchCallback()
|
|
|
|
|
|
{
|
|
|
|
|
|
s_pInstance = this;
|
|
|
|
|
|
|
|
|
|
|
|
int ret = GLX8_2_SetBatchOneTimeDataHandler(m_nDeviceId, BatchOneTimeCallback);
|
|
|
|
|
|
if (ret != 0) {
|
|
|
|
|
|
LOG_ERROR("GLX8_2_SetBatchOneTimeDataHandler failed: %d\n", ret);
|
|
|
|
|
|
return ERR_CODE(DEV_CTRL_ERR);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LOG_DEBUG("Batch callback registered\n");
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// SDK批处理回调(静态函数,由SDK线程调用)
|
|
|
|
|
|
void CGlLineLaserDevice::BatchOneTimeCallback(const GLX8_2_STR_CALLBACK_INFO* info, const GLX8_2_Data DataObj)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (s_pInstance == nullptr) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!s_pInstance->m_bDetecting) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
s_pInstance->ProcessBatchData(info, DataObj);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 处理一次批处理回调数据
|
|
|
|
|
|
void CGlLineLaserDevice::ProcessBatchData(const GLX8_2_STR_CALLBACK_INFO* info, const GLX8_2_Data DataObj)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (info == nullptr || DataObj == nullptr) {
|
|
|
|
|
|
LOG_ERROR("ProcessBatchData: null parameter\n");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 检查批处理状态
|
|
|
|
|
|
if (info->returnStatus != 0) {
|
|
|
|
|
|
LOG_WARNING("Batch returnStatus: %d\n", info->returnStatus);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int batchCount = info->BatchPoints;
|
|
|
|
|
|
int width = info->xPoints;
|
|
|
|
|
|
|
|
|
|
|
|
if (batchCount <= 0 || width <= 0) {
|
|
|
|
|
|
LOG_WARNING("Invalid batch data: batchCount=%d, width=%d\n", batchCount, width);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LOG_DEBUG("Received batch: %d lines, width: %d, startEncoder: %d, batchTimes: %d\n", batchCount, width, info->startEncoder, info->BatchTimes);
|
|
|
|
|
|
|
|
|
|
|
|
// 使用回调info中的实时参数
|
|
|
|
|
|
double xPitch = info->xPixth;
|
|
|
|
|
|
if (xPitch <= 0) {
|
|
|
|
|
|
xPitch = m_dXPitch; // 回退到设备初始化时获取的值
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 从SDK获取数据指针(SDK内部管理内存,无需自己分配)
|
|
|
|
|
|
int32_t* profileData = GLX8_2_GetBatchProfilePoint(DataObj, 0);
|
|
|
|
|
|
uint32_t* encoderData = GLX8_2_GetBatchEncoderPoint(DataObj, 0);
|
|
|
|
|
|
|
|
|
|
|
|
if (profileData == nullptr) {
|
|
|
|
|
|
LOG_ERROR("GLX8_2_GetBatchProfilePoint returned null\n");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 局部位置缓存
|
|
|
|
|
|
std::vector<SVzNL3DPosition> positionBuffer(width);
|
|
|
|
|
|
|
|
|
|
|
|
// 逐行处理数据并回调给上层
|
|
|
|
|
|
for (int lineIdx = 0; lineIdx < batchCount; lineIdx++) {
|
|
|
|
|
|
if (!m_bDetecting) {
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 计算当前行在批处理数据中的偏移
|
|
|
|
|
|
const int32_t* lineProfile = profileData + static_cast<size_t>(lineIdx) * width;
|
|
|
|
|
|
|
|
|
|
|
|
// 转换为xyz坐标
|
|
|
|
|
|
double yOffset = static_cast<double>(m_ullFrameIndex) * m_dYPitch;
|
|
|
|
|
|
for (int i = 0; i < width; i++) {
|
|
|
|
|
|
SVzNL3DPosition& pos = positionBuffer[i];
|
|
|
|
|
|
pos.nPointIdx = i;
|
|
|
|
|
|
pos.pt3D.x = (static_cast<double>(i) - static_cast<double>(width) / 2.0) * xPitch;
|
|
|
|
|
|
pos.pt3D.y = yOffset;
|
|
|
|
|
|
|
|
|
|
|
|
int32_t rawZ = lineProfile[i];
|
|
|
|
|
|
if (rawZ == 0x7FFFFFFF || rawZ < -100000000) {
|
|
|
|
|
|
pos.pt3D.z = 0.0;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
pos.pt3D.z = static_cast<double>(rawZ) * 0.00001; // 0.01um -> mm
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 填充 SVzLaserLineData 结构
|
|
|
|
|
|
SVzLaserLineData laserLineData;
|
|
|
|
|
|
memset(&laserLineData, 0, sizeof(SVzLaserLineData));
|
|
|
|
|
|
|
|
|
|
|
|
laserLineData.p3DPoint = positionBuffer.data();
|
|
|
|
|
|
laserLineData.p2DPoint = nullptr;
|
|
|
|
|
|
laserLineData.nPointCount = width;
|
|
|
|
|
|
laserLineData.dTotleOffset = yOffset;
|
|
|
|
|
|
laserLineData.dStep = m_dYPitch;
|
|
|
|
|
|
laserLineData.llFrameIdx = m_ullFrameIndex;
|
|
|
|
|
|
laserLineData.llTimeStamp = std::chrono::duration_cast<std::chrono::microseconds>(
|
|
|
|
|
|
std::chrono::steady_clock::now().time_since_epoch()).count();
|
|
|
|
|
|
laserLineData.nEncodeNo = encoderData ? encoderData[lineIdx] : 0;
|
|
|
|
|
|
laserLineData.fSwingAngle = 0.0f;
|
|
|
|
|
|
laserLineData.bEndOnceScan = (lineIdx == batchCount - 1) ? VzTrue : VzFalse;
|
|
|
|
|
|
|
|
|
|
|
|
// 回调给上层应用
|
|
|
|
|
|
if (m_pDetectCallback) {
|
|
|
|
|
|
m_pDetectCallback(m_eDataType, &laserLineData, m_pDetectCallbackParam);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
m_ullFrameIndex++;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LOG_DEBUG("Processed %d lines, total frames: %llu\n", batchCount, m_ullFrameIndex);
|
|
|
|
|
|
|
|
|
|
|
|
// 通知上层本次批处理数据处理完成
|
|
|
|
|
|
if (m_pStatusCallback) {
|
|
|
|
|
|
m_pStatusCallback(keDeviceWorkStatus_Device_Swing_Finish, nullptr, 0, m_pStatusCallbackParam);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-27 20:43:12 +08:00
|
|
|
|
int CGlLineLaserDevice::GetVersion(SVzNLVersionInfo& sVersionInfo)
|
|
|
|
|
|
{
|
|
|
|
|
|
memset(&sVersionInfo, 0, sizeof(SVzNLVersionInfo));
|
|
|
|
|
|
|
|
|
|
|
|
const char* sdkVersion = GLX8_2_GetVersion();
|
|
|
|
|
|
if (sdkVersion) {
|
|
|
|
|
|
strncpy(sVersionInfo.szSDKVersion, sdkVersion, VZNL_VERSION_LENGTH - 1);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
strncpy(sVersionInfo.szAppVersion, "GlLineLaser", VZNL_VERSION_LENGTH - 1);
|
|
|
|
|
|
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int CGlLineLaserDevice::GetDevInfo(SVzNLEyeDeviceInfoEx& sDeviceInfo)
|
|
|
|
|
|
{
|
|
|
|
|
|
memset(&sDeviceInfo, 0, sizeof(SVzNLEyeDeviceInfoEx));
|
|
|
|
|
|
|
|
|
|
|
|
strncpy(sDeviceInfo.sEyeCBInfo.byServerIP, m_strDeviceIP.c_str(), VZNL_SDK_NETWORK_IPv4_LENGTH - 1);
|
|
|
|
|
|
strncpy(sDeviceInfo.sEyeCBInfo.szDeviceName, m_modelInfo.Model, VZNL_DEVICE_NAME_LENGTH - 1);
|
|
|
|
|
|
strncpy(sDeviceInfo.sEyeCBInfo.szDeviceID, m_modelInfo.HeaderSerial, VZNL_GUID_LENGTH - 1);
|
|
|
|
|
|
|
|
|
|
|
|
sDeviceInfo.sVideoRes.nFrameWidth = m_nProfileWidth;
|
|
|
|
|
|
sDeviceInfo.sVideoRes.nFrameHeight = m_nBatchLines;
|
|
|
|
|
|
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int CGlLineLaserDevice::CloseDevice()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!m_bDeviceOpen) {
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 先停止检测
|
|
|
|
|
|
if (m_bDetecting) {
|
|
|
|
|
|
StopDetect();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 关闭设备
|
|
|
|
|
|
int ret = GLX8_2_CommClose(m_nDeviceId);
|
|
|
|
|
|
if (ret != 0) {
|
|
|
|
|
|
LOG_ERROR("GLX8_2_CommClose failed: %d\n", ret);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
m_bDeviceOpen = false;
|
|
|
|
|
|
LOG_DEBUG("Device closed\n");
|
|
|
|
|
|
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int CGlLineLaserDevice::StartDetect(VzNL_AutoOutputLaserLineExCB fCallFunc, EVzResultDataType eDataType, void *param)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!m_bDeviceOpen) {
|
|
|
|
|
|
LOG_ERROR("Device not open\n");
|
|
|
|
|
|
return ERR_CODE(DEV_NO_OPEN);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (m_bDetecting) {
|
|
|
|
|
|
LOG_WARNING("Already detecting\n");
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
m_pDetectCallback = fCallFunc;
|
|
|
|
|
|
m_pDetectCallbackParam = param;
|
|
|
|
|
|
m_eDataType = eDataType;
|
|
|
|
|
|
m_ullFrameIndex = 0;
|
|
|
|
|
|
|
|
|
|
|
|
m_bDetecting = true;
|
2026-02-06 01:14:27 +08:00
|
|
|
|
|
2026-02-07 23:46:44 +08:00
|
|
|
|
// 启动回调模式批处理(0=立即开始)
|
|
|
|
|
|
int ret = GLX8_2_StartMeasureWithCallback(m_nDeviceId, 0);
|
|
|
|
|
|
if (ret != 0) {
|
|
|
|
|
|
LOG_ERROR("GLX8_2_StartMeasureWithCallback failed: %d\n", ret);
|
|
|
|
|
|
m_bDetecting = false;
|
|
|
|
|
|
return ERR_CODE(DEV_CTRL_ERR);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LOG_DEBUG("Detection started (callback mode)\n");
|
2026-01-27 20:43:12 +08:00
|
|
|
|
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool CGlLineLaserDevice::IsDetectIng()
|
|
|
|
|
|
{
|
|
|
|
|
|
return m_bDetecting;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int CGlLineLaserDevice::StopDetect()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!m_bDetecting) {
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-07 23:46:44 +08:00
|
|
|
|
m_bDetecting = false;
|
2026-01-27 20:43:12 +08:00
|
|
|
|
|
|
|
|
|
|
// 停止批处理
|
|
|
|
|
|
int ret = GLX8_2_StopMeasure(m_nDeviceId);
|
|
|
|
|
|
if (ret != 0) {
|
|
|
|
|
|
LOG_ERROR("GLX8_2_StopMeasure failed: %d\n", ret);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 通知状态变化
|
|
|
|
|
|
if (m_pStatusCallback) {
|
|
|
|
|
|
m_pStatusCallback(keDeviceWorkStatus_Device_Swing_Finish, nullptr, 0, m_pStatusCallbackParam);
|
|
|
|
|
|
m_pStatusCallback(keDeviceWorkStatus_Device_Auto_Stop, nullptr, 0, m_pStatusCallbackParam);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LOG_DEBUG("Detection stopped\n");
|
|
|
|
|
|
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ============ ROI相关(线激光不支持)============
|
|
|
|
|
|
|
|
|
|
|
|
int CGlLineLaserDevice::SetDetectROI(SVzNLRect& leftROI, SVzNLRect& rightROI)
|
|
|
|
|
|
{
|
|
|
|
|
|
(void)leftROI;
|
|
|
|
|
|
(void)rightROI;
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int CGlLineLaserDevice::GetDetectROI(SVzNLRect& leftROI, SVzNLRect& rightROI)
|
|
|
|
|
|
{
|
|
|
|
|
|
memset(&leftROI, 0, sizeof(SVzNLRect));
|
|
|
|
|
|
memset(&rightROI, 0, sizeof(SVzNLRect));
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-07 23:46:44 +08:00
|
|
|
|
// ============ 曝光/增益相关 ============
|
2026-01-27 20:43:12 +08:00
|
|
|
|
|
|
|
|
|
|
int CGlLineLaserDevice::SetEyeExpose(unsigned int& exposeTime)
|
|
|
|
|
|
{
|
|
|
|
|
|
(void)exposeTime;
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int CGlLineLaserDevice::GetEyeExpose(unsigned int& exposeTime)
|
|
|
|
|
|
{
|
2026-02-07 23:46:44 +08:00
|
|
|
|
exposeTime = 1000;
|
2026-01-27 20:43:12 +08:00
|
|
|
|
return SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int CGlLineLaserDevice::SetEyeGain(unsigned int& gain)
|
|
|
|
|
|
{
|
|
|
|
|
|
(void)gain;
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int CGlLineLaserDevice::GetEyeGain(unsigned int& gain)
|
|
|
|
|
|
{
|
2026-02-07 23:46:44 +08:00
|
|
|
|
gain = 100;
|
2026-01-27 20:43:12 +08:00
|
|
|
|
return SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ============ 帧率相关 ============
|
|
|
|
|
|
|
|
|
|
|
|
int CGlLineLaserDevice::SetFrame(int& frame)
|
|
|
|
|
|
{
|
|
|
|
|
|
(void)frame;
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int CGlLineLaserDevice::GetFrame(int& frame)
|
|
|
|
|
|
{
|
2026-02-07 23:46:44 +08:00
|
|
|
|
frame = 100;
|
2026-01-27 20:43:12 +08:00
|
|
|
|
return SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ============ RGBD相关(线激光不支持)============
|
|
|
|
|
|
|
|
|
|
|
|
bool CGlLineLaserDevice::IsSupport()
|
|
|
|
|
|
{
|
2026-02-07 23:46:44 +08:00
|
|
|
|
return false;
|
2026-01-27 20:43:12 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int CGlLineLaserDevice::SetRGBDExposeThres(float& value)
|
|
|
|
|
|
{
|
|
|
|
|
|
(void)value;
|
|
|
|
|
|
return ERR_CODE(DEV_UNSUPPORT);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int CGlLineLaserDevice::GetRGBDExposeThres(float& value)
|
|
|
|
|
|
{
|
|
|
|
|
|
value = 0.0f;
|
|
|
|
|
|
return ERR_CODE(DEV_UNSUPPORT);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ============ 过滤高度 ============
|
|
|
|
|
|
|
|
|
|
|
|
int CGlLineLaserDevice::SetFilterHeight(double& dHeight)
|
|
|
|
|
|
{
|
|
|
|
|
|
(void)dHeight;
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int CGlLineLaserDevice::GetFilterHeight(double& dHeight)
|
|
|
|
|
|
{
|
|
|
|
|
|
dHeight = 0.0;
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ============ 摆动机构相关(线激光不支持)============
|
|
|
|
|
|
|
|
|
|
|
|
int CGlLineLaserDevice::GetSwingSpeed(float& fSpeed)
|
|
|
|
|
|
{
|
|
|
|
|
|
fSpeed = 0.0f;
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int CGlLineLaserDevice::SetSwingSpeed(float& fSpeed)
|
|
|
|
|
|
{
|
|
|
|
|
|
(void)fSpeed;
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int CGlLineLaserDevice::SetSwingAngle(float& fMin, float& fMax)
|
|
|
|
|
|
{
|
|
|
|
|
|
(void)fMin;
|
|
|
|
|
|
(void)fMax;
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int CGlLineLaserDevice::GetSwingAngle(float& fMin, float& fMax)
|
|
|
|
|
|
{
|
|
|
|
|
|
fMin = 0.0f;
|
|
|
|
|
|
fMax = 0.0f;
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int CGlLineLaserDevice::SetWorkRange(double& dMin, double& dMax)
|
|
|
|
|
|
{
|
|
|
|
|
|
(void)dMin;
|
|
|
|
|
|
(void)dMax;
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int CGlLineLaserDevice::GetWorkRange(double& dMin, double& dMax)
|
|
|
|
|
|
{
|
|
|
|
|
|
dMin = m_modelInfo.zRangmin;
|
|
|
|
|
|
dMax = m_modelInfo.zRangmax;
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ============ GL线激光专用接口实现 ============
|
|
|
|
|
|
|
|
|
|
|
|
int CGlLineLaserDevice::GetProfileDataWidth()
|
|
|
|
|
|
{
|
|
|
|
|
|
return m_nProfileWidth;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
double CGlLineLaserDevice::GetXPitch()
|
|
|
|
|
|
{
|
|
|
|
|
|
return m_dXPitch;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
double CGlLineLaserDevice::GetYPitch()
|
|
|
|
|
|
{
|
|
|
|
|
|
return m_dYPitch;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int CGlLineLaserDevice::SetYPitch(double pitch)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (pitch <= 0) {
|
|
|
|
|
|
return ERR_CODE(DEV_ARG_INVAILD);
|
|
|
|
|
|
}
|
|
|
|
|
|
m_dYPitch = pitch;
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int CGlLineLaserDevice::SetBatchLines(unsigned int batchLines)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (batchLines == 0) {
|
|
|
|
|
|
return ERR_CODE(DEV_ARG_INVAILD);
|
|
|
|
|
|
}
|
|
|
|
|
|
m_nBatchLines = batchLines;
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
unsigned int CGlLineLaserDevice::GetBatchLines()
|
|
|
|
|
|
{
|
|
|
|
|
|
return m_nBatchLines;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int CGlLineLaserDevice::SwitchProgram(int programNo)
|
|
|
|
|
|
{
|
|
|
|
|
|
int ret = GLX8_2_SwitchProgram(m_nDeviceId, programNo);
|
|
|
|
|
|
if (ret != 0) {
|
|
|
|
|
|
LOG_ERROR("GLX8_2_SwitchProgram failed: %d\n", ret);
|
|
|
|
|
|
return ERR_CODE(DEV_CTRL_ERR);
|
|
|
|
|
|
}
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int CGlLineLaserDevice::GetModelInfo(char* model, char* serialNumber)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (model) {
|
|
|
|
|
|
strcpy(model, m_modelInfo.Model);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (serialNumber) {
|
|
|
|
|
|
strcpy(serialNumber, m_modelInfo.HeaderSerial);
|
|
|
|
|
|
}
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int CGlLineLaserDevice::GetMeasureRange(double& xMin, double& xMax, double& zMin, double& zMax)
|
|
|
|
|
|
{
|
|
|
|
|
|
xMin = m_modelInfo.xRangmin;
|
|
|
|
|
|
xMax = m_modelInfo.xRangmax;
|
|
|
|
|
|
zMin = m_modelInfo.zRangmin;
|
|
|
|
|
|
zMax = m_modelInfo.zRangmax;
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ============ 工厂方法实现 ============
|
|
|
|
|
|
|
|
|
|
|
|
int IGlLineLaserDevice::CreateGlLineLaserObject(IGlLineLaserDevice** ppDevice)
|
|
|
|
|
|
{
|
|
|
|
|
|
CGlLineLaserDevice* p = new CGlLineLaserDevice();
|
|
|
|
|
|
*ppDevice = p;
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
|
|
}
|