|
|
|
@ -1,7 +1,9 @@
|
|
|
|
package com.zhehekeji.web.service.IndustrialCamera;
|
|
|
|
package com.zhehekeji.web.service.IndustrialCamera;
|
|
|
|
|
|
|
|
|
|
|
|
import com.sun.jna.Native;
|
|
|
|
import com.sun.jna.Native;
|
|
|
|
|
|
|
|
import com.sun.jna.Pointer;
|
|
|
|
import com.sun.jna.ptr.PointerByReference;
|
|
|
|
import com.sun.jna.ptr.PointerByReference;
|
|
|
|
|
|
|
|
import io.swagger.models.auth.In;
|
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
|
|
|
|
|
|
|
|
|
import java.nio.file.Files;
|
|
|
|
import java.nio.file.Files;
|
|
|
|
@ -9,153 +11,539 @@ import java.nio.file.Path;
|
|
|
|
import java.nio.file.Paths;
|
|
|
|
import java.nio.file.Paths;
|
|
|
|
import java.util.Map;
|
|
|
|
import java.util.Map;
|
|
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
|
|
|
|
|
|
import java.util.concurrent.atomic.AtomicInteger;
|
|
|
|
|
|
|
|
|
|
|
|
@Slf4j
|
|
|
|
@Slf4j
|
|
|
|
public class LxPointCloudSaveImage {
|
|
|
|
public class LxPointCloudSaveImage {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static final int MAX_RETRY_COUNT = 3;
|
|
|
|
|
|
|
|
private static final int RETRY_INTERVAL_MS = 500;
|
|
|
|
|
|
|
|
|
|
|
|
public static DcLibrary INSTANCER = (DcLibrary) Native.loadLibrary((System.getProperty("user.dir"))+"\\libs\\lx\\LxCameraApi.dll", DcLibrary.class);
|
|
|
|
public static DcLibrary INSTANCER = (DcLibrary) Native.loadLibrary((System.getProperty("user.dir"))+"\\libs\\lx\\LxCameraApi.dll", DcLibrary.class);
|
|
|
|
|
|
|
|
|
|
|
|
static Map<String, PointerByReference> handleMap = new ConcurrentHashMap<>();
|
|
|
|
// 设备句柄映射
|
|
|
|
public static PointerByReference getHandle(String sn,int type ,DcLibrary INSTANCE){
|
|
|
|
static Map<String, DeviceInfo> handleMap = new ConcurrentHashMap<>();
|
|
|
|
if(handleMap.get(sn)!=null){
|
|
|
|
|
|
|
|
return handleMap.get(sn);
|
|
|
|
// 设备信息封装类
|
|
|
|
}else {
|
|
|
|
static class DeviceInfo {
|
|
|
|
// 创建 Pointer 的引用
|
|
|
|
PointerByReference handleRef;
|
|
|
|
PointerByReference handleRef = new PointerByReference();
|
|
|
|
DcLibrary.LxDeviceInfo deviceInfo;
|
|
|
|
|
|
|
|
int type;
|
|
|
|
|
|
|
|
long lastUseTime;
|
|
|
|
// 创建 PointerByReference 的实例用于接收设备列表
|
|
|
|
boolean streamStarted; // 流是否已启动
|
|
|
|
// PointerByReference devlistRef = new PointerByReference();
|
|
|
|
|
|
|
|
// 创建 LxDeviceInfo 实例
|
|
|
|
DeviceInfo(PointerByReference handleRef, DcLibrary.LxDeviceInfo deviceInfo, int type) {
|
|
|
|
DcLibrary.LxDeviceInfo info = new DcLibrary.LxDeviceInfo();
|
|
|
|
this.handleRef = handleRef;
|
|
|
|
|
|
|
|
this.deviceInfo = deviceInfo;
|
|
|
|
//library.DcGetDeviceList( devlistRef,0);
|
|
|
|
this.type = type;
|
|
|
|
|
|
|
|
this.lastUseTime = System.currentTimeMillis();
|
|
|
|
// 调用 DcOpenDevice 函数
|
|
|
|
this.streamStarted = false;
|
|
|
|
System.out.println(sn+" "+handleRef+" "+info);
|
|
|
|
}
|
|
|
|
int result = INSTANCE.DcOpenDevice(1, sn, handleRef, info);
|
|
|
|
|
|
|
|
int i = 0;
|
|
|
|
void updateTime() {
|
|
|
|
if(result ==0) {
|
|
|
|
this.lastUseTime = System.currentTimeMillis();
|
|
|
|
handleMap.put(sn, handleRef);
|
|
|
|
}
|
|
|
|
}else {
|
|
|
|
}
|
|
|
|
for (int ii=0;i<50;i++ ) {
|
|
|
|
|
|
|
|
result = INSTANCE.DcOpenDevice(1, sn, handleRef, info);
|
|
|
|
/**
|
|
|
|
System.out.println(i + "次尝试;"+"异常:"+result);
|
|
|
|
* 获取设备句柄,如果不存在则初始化
|
|
|
|
try {
|
|
|
|
* @param sn 设备序列号
|
|
|
|
Thread.sleep(500);
|
|
|
|
* @param type 设备类型
|
|
|
|
} catch (InterruptedException e) {
|
|
|
|
* @param INSTANCE DcLibrary实例
|
|
|
|
throw new RuntimeException(e);
|
|
|
|
* @return 设备句柄引用,失败返回null
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
public static PointerByReference getHandle(String sn, int type, DcLibrary INSTANCE) {
|
|
|
|
|
|
|
|
DeviceInfo deviceInfo = handleMap.get(sn);
|
|
|
|
|
|
|
|
if (deviceInfo != null) {
|
|
|
|
|
|
|
|
deviceInfo.updateTime();
|
|
|
|
|
|
|
|
return deviceInfo.handleRef;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 设备不存在,进行初始化
|
|
|
|
|
|
|
|
return initDevice(sn, type, INSTANCE);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 初始化设备连接(启动流并设置命令码)
|
|
|
|
|
|
|
|
* @param sn 设备序列号
|
|
|
|
|
|
|
|
* @param type 设备类型
|
|
|
|
|
|
|
|
* @param INSTANCE DcLibrary实例
|
|
|
|
|
|
|
|
* @return 设备句柄引用,失败返回null
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
public static PointerByReference initDevice(String sn, int type, DcLibrary INSTANCE) {
|
|
|
|
|
|
|
|
if (INSTANCE == null) {
|
|
|
|
|
|
|
|
INSTANCE = INSTANCER;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 检查是否已经存在连接
|
|
|
|
|
|
|
|
DeviceInfo existingInfo = handleMap.get(sn);
|
|
|
|
|
|
|
|
if (existingInfo != null && existingInfo.handleRef != null && existingInfo.handleRef.getValue() != null) {
|
|
|
|
|
|
|
|
log.info("设备 {} 已连接,复用现有连接", sn);
|
|
|
|
|
|
|
|
existingInfo.updateTime();
|
|
|
|
|
|
|
|
return existingInfo.handleRef;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 创建句柄引用
|
|
|
|
|
|
|
|
PointerByReference handleRef = new PointerByReference();
|
|
|
|
|
|
|
|
DcLibrary.LxDeviceInfo info = new DcLibrary.LxDeviceInfo();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
log.info("开始初始化设备: SN={}, Type={}", sn, type);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 尝试打开设备
|
|
|
|
|
|
|
|
int result = openDeviceWithRetry(INSTANCE, sn, handleRef, info, MAX_RETRY_COUNT);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (result == 0) {
|
|
|
|
|
|
|
|
// 成功打开设备
|
|
|
|
|
|
|
|
DeviceInfo deviceInfo = new DeviceInfo(handleRef, info, type);
|
|
|
|
|
|
|
|
handleMap.put(sn, deviceInfo);
|
|
|
|
|
|
|
|
log.info("设备 {} 初始化成功, Handle: {}", sn, handleRef.getValue());
|
|
|
|
|
|
|
|
logDeviceInfo(info);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 立即启动流
|
|
|
|
|
|
|
|
result = INSTANCE.DcStartStream(handleRef.getValue());
|
|
|
|
|
|
|
|
if (result == 0) {
|
|
|
|
|
|
|
|
deviceInfo.streamStarted = true;
|
|
|
|
|
|
|
|
log.info("设备 {} 流启动成功", sn);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
log.warn("设备 {} 流启动失败,错误码: {}", sn, result);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// 输出结果
|
|
|
|
|
|
|
|
System.out.println("Result: " + result);
|
|
|
|
|
|
|
|
System.out.println("Handle: " + handleRef.getValue()); // 获取 DcHandle 的值
|
|
|
|
|
|
|
|
System.out.println("Device Type: " + info.dev_type);
|
|
|
|
|
|
|
|
System.out.println("ID: " + new String(info.id).trim());
|
|
|
|
|
|
|
|
System.out.println("IP: " + new String(info.ip).trim());
|
|
|
|
|
|
|
|
System.out.println("SN: " + new String(info.sn).trim());
|
|
|
|
|
|
|
|
System.out.println("MAC: " + new String(info.mac).trim());
|
|
|
|
|
|
|
|
System.out.println("Firmware Version: " + new String(info.firmware_ver).trim());
|
|
|
|
|
|
|
|
System.out.println("Algorithm Version: " + new String(info.algor_ver).trim());
|
|
|
|
|
|
|
|
System.out.println("Name: " + new String(info.name).trim());
|
|
|
|
|
|
|
|
System.out.println("Reserve: " + new String(info.reserve).trim());
|
|
|
|
|
|
|
|
System.out.println("Reserve2: " + new String(info.reserve2).trim());
|
|
|
|
|
|
|
|
System.out.println("Reserve3: " + new String(info.reserve3).trim());
|
|
|
|
|
|
|
|
System.out.println("Reserve4: " + new String(info.reserve4).trim());//lxPointCloudApi.DcCloseDevice(handle);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 设置命令码
|
|
|
|
|
|
|
|
result = INSTANCE.DcSetCmd(handleRef.getValue(), 5001);
|
|
|
|
|
|
|
|
if (result == 0 || result == 25) {
|
|
|
|
|
|
|
|
log.info("设备 {} 命令码设置成功(5001)", sn);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
log.warn("设备 {} 命令码设置失败,错误码: {}", sn, result);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return handleRef;
|
|
|
|
return handleRef;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
log.error("设备 {} 初始化失败,错误码: {}", sn, result);
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 带重试的设备打开方法
|
|
|
|
|
|
|
|
* @param INSTANCE DcLibrary实例
|
|
|
|
|
|
|
|
* @param sn 设备序列号
|
|
|
|
|
|
|
|
* @param handleRef 句柄引用
|
|
|
|
|
|
|
|
* @param info 设备信息
|
|
|
|
|
|
|
|
* @param maxRetries 最大重试次数
|
|
|
|
|
|
|
|
* @return 错误码,0表示成功
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
private static int openDeviceWithRetry(DcLibrary INSTANCE, String sn,
|
|
|
|
|
|
|
|
PointerByReference handleRef, DcLibrary.LxDeviceInfo info, int maxRetries) {
|
|
|
|
|
|
|
|
int result = INSTANCE.DcOpenDevice(1, sn, handleRef, info);
|
|
|
|
|
|
|
|
log.debug("设备 {} 首次打开结果: {}", sn, result);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (result == 0) {
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 首次失败,进行重试
|
|
|
|
|
|
|
|
AtomicInteger retryCount = new AtomicInteger(1);
|
|
|
|
|
|
|
|
while (retryCount.get() <= maxRetries) {
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
log.info("设备 {} 打开失败,第 {} 次重试,错误码: {}", sn, retryCount.get(), result);
|
|
|
|
|
|
|
|
Thread.sleep(RETRY_INTERVAL_MS);
|
|
|
|
|
|
|
|
result = INSTANCE.DcOpenDevice(1, sn, handleRef, info);
|
|
|
|
|
|
|
|
if (result == 0) {
|
|
|
|
|
|
|
|
log.info("设备 {} 第 {} 次重试成功", sn, retryCount.get());
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
retryCount.incrementAndGet();
|
|
|
|
|
|
|
|
} catch (InterruptedException e) {
|
|
|
|
|
|
|
|
log.error("设备 {} 重试被中断", sn, e);
|
|
|
|
|
|
|
|
Thread.currentThread().interrupt();
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
log.error("设备 {} 重试 {} 次后仍然失败", sn, maxRetries);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
public static PointerByReference init(String sn){
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
if(handleMap.get(sn)!=null){
|
|
|
|
* 重新连接设备(重新设置句柄,并重新启动流和设置命令码)
|
|
|
|
return handleMap.get(sn);
|
|
|
|
* @param sn 设备序列号
|
|
|
|
}else {
|
|
|
|
* @param type 设备类型
|
|
|
|
// 创建 Pointer 的引用
|
|
|
|
* @return true表示重连成功,false表示失败
|
|
|
|
PointerByReference handleRef = new PointerByReference();
|
|
|
|
*/
|
|
|
|
|
|
|
|
public static boolean reconnect(String sn, int type) {
|
|
|
|
|
|
|
|
log.info("开始重连设备(重新设置句柄): SN={}", sn);
|
|
|
|
// 创建 PointerByReference 的实例用于接收设备列表
|
|
|
|
|
|
|
|
// PointerByReference devlistRef = new PointerByReference();
|
|
|
|
DeviceInfo existingInfo = handleMap.get(sn);
|
|
|
|
// 创建 LxDeviceInfo 实例
|
|
|
|
|
|
|
|
DcLibrary.LxDeviceInfo info = new DcLibrary.LxDeviceInfo();
|
|
|
|
// 获取现有的句柄引用
|
|
|
|
|
|
|
|
PointerByReference handleRef;
|
|
|
|
//library.DcGetDeviceList( devlistRef,0);
|
|
|
|
if (existingInfo != null && existingInfo.handleRef != null) {
|
|
|
|
|
|
|
|
// 先停止现有的流
|
|
|
|
// 调用 DcOpenDevice 函数
|
|
|
|
if (existingInfo.streamStarted) {
|
|
|
|
System.out.println(sn+" "+handleRef+" "+info);
|
|
|
|
Pointer oldHandle = existingInfo.handleRef.getValue();
|
|
|
|
int result = INSTANCER.DcOpenDevice(1, sn, handleRef, info);
|
|
|
|
if (oldHandle != null) {
|
|
|
|
int i = 0;
|
|
|
|
INSTANCER.DcStopStream(oldHandle);
|
|
|
|
if(result ==0) {
|
|
|
|
log.debug("设备 {} 停止旧流", sn);
|
|
|
|
handleMap.put(sn, handleRef);
|
|
|
|
|
|
|
|
}else {
|
|
|
|
|
|
|
|
for (int ii=0;i<50;i++ ) {
|
|
|
|
|
|
|
|
result = INSTANCER.DcOpenDevice(1, sn, handleRef, info);
|
|
|
|
|
|
|
|
System.out.println(i + "次尝试;"+"异常:"+result);
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
Thread.sleep(500);
|
|
|
|
|
|
|
|
} catch (InterruptedException e) {
|
|
|
|
|
|
|
|
throw new RuntimeException(e);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// 输出结果
|
|
|
|
handleRef = existingInfo.handleRef;
|
|
|
|
System.out.println("Result: " + result);
|
|
|
|
log.info("复用现有句柄引用: {}", handleRef);
|
|
|
|
System.out.println("Handle: " + handleRef.getValue()); // 获取 DcHandle 的值
|
|
|
|
} else {
|
|
|
|
System.out.println("Device Type: " + info.dev_type);
|
|
|
|
// 创建新的句柄引用
|
|
|
|
System.out.println("ID: " + new String(info.id).trim());
|
|
|
|
handleRef = new PointerByReference();
|
|
|
|
System.out.println("IP: " + new String(info.ip).trim());
|
|
|
|
log.info("创建新句柄引用: {}", handleRef);
|
|
|
|
System.out.println("SN: " + new String(info.sn).trim());
|
|
|
|
}
|
|
|
|
System.out.println("MAC: " + new String(info.mac).trim());
|
|
|
|
|
|
|
|
System.out.println("Firmware Version: " + new String(info.firmware_ver).trim());
|
|
|
|
|
|
|
|
System.out.println("Algorithm Version: " + new String(info.algor_ver).trim());
|
|
|
|
|
|
|
|
System.out.println("Name: " + new String(info.name).trim());
|
|
|
|
|
|
|
|
System.out.println("Reserve: " + new String(info.reserve).trim());
|
|
|
|
|
|
|
|
System.out.println("Reserve2: " + new String(info.reserve2).trim());
|
|
|
|
|
|
|
|
System.out.println("Reserve3: " + new String(info.reserve3).trim());
|
|
|
|
|
|
|
|
System.out.println("Reserve4: " + new String(info.reserve4).trim());//lxPointCloudApi.DcCloseDevice(handle);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DcLibrary.LxDeviceInfo info = new DcLibrary.LxDeviceInfo();
|
|
|
|
|
|
|
|
|
|
|
|
return handleRef;
|
|
|
|
// 尝试重新打开设备,设置新的句柄
|
|
|
|
|
|
|
|
int result = openDeviceWithRetry(INSTANCER, sn, handleRef, info, MAX_RETRY_COUNT);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (result == 0) {
|
|
|
|
|
|
|
|
// 更新设备信息
|
|
|
|
|
|
|
|
DeviceInfo deviceInfo = new DeviceInfo(handleRef, info, type);
|
|
|
|
|
|
|
|
handleMap.put(sn, deviceInfo);
|
|
|
|
|
|
|
|
log.info("设备 {} 重连成功,新句柄: {}", sn, handleRef.getValue());
|
|
|
|
|
|
|
|
logDeviceInfo(info);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 重新启动流
|
|
|
|
|
|
|
|
result = INSTANCER.DcStartStream(handleRef.getValue());
|
|
|
|
|
|
|
|
if (result == 0) {
|
|
|
|
|
|
|
|
deviceInfo.streamStarted = true;
|
|
|
|
|
|
|
|
log.info("设备 {} 重连后流启动成功", sn);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
log.warn("设备 {} 重连后流启动失败,错误码: {}", sn, result);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 重新设置命令码
|
|
|
|
|
|
|
|
result = INSTANCER.DcSetCmd(handleRef.getValue(), 5001);
|
|
|
|
|
|
|
|
if (result == 0 || result == 25) {
|
|
|
|
|
|
|
|
log.info("设备 {} 重连后命令码设置成功(5001)", sn);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
log.warn("设备 {} 重连后命令码设置失败,错误码: {}", sn, result);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
log.error("设备 {} 重连失败,错误码: {}", sn, result);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static boolean reDevice(String sn) {
|
|
|
|
|
|
|
|
closeDevice(sn);
|
|
|
|
|
|
|
|
return reconnect(sn, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static boolean saveImage(String sn, String path,int type) {
|
|
|
|
/**
|
|
|
|
DcLibrary INSTANCE;
|
|
|
|
* 关闭指定设备连接(停止流后关闭设备)
|
|
|
|
INSTANCE = INSTANCER;
|
|
|
|
* @param sn 设备序列号
|
|
|
|
int result = 0;
|
|
|
|
* @return true表示关闭成功,false表示失败
|
|
|
|
PointerByReference handleRef = getHandle(sn,type,INSTANCE);
|
|
|
|
*/
|
|
|
|
result = INSTANCE.DcStartStream(handleRef.getValue());
|
|
|
|
public static boolean closeDevice(String sn) {
|
|
|
|
System.out.println("Result: " + result);
|
|
|
|
DeviceInfo deviceInfo = handleMap.get(sn);
|
|
|
|
result = INSTANCE.DcSetCmd(handleRef.getValue(),5001);
|
|
|
|
if (deviceInfo == null || deviceInfo.handleRef == null) {
|
|
|
|
|
|
|
|
log.warn("设备 {} 未找到连接,无需关闭", sn);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
Pointer handle = deviceInfo.handleRef.getValue();
|
|
|
|
|
|
|
|
if (handle != null) {
|
|
|
|
|
|
|
|
// 先停止流
|
|
|
|
|
|
|
|
if (deviceInfo.streamStarted) {
|
|
|
|
|
|
|
|
int stopResult = INSTANCER.DcStopStream(handle);
|
|
|
|
|
|
|
|
log.info("设备 {} 停止流结果: {}", sn, stopResult);
|
|
|
|
|
|
|
|
deviceInfo.streamStarted = false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
System.out.println("Result: " + result);
|
|
|
|
// 关闭设备
|
|
|
|
Path path1 = Paths.get(path);
|
|
|
|
int closeResult = INSTANCER.DcCloseDevice(handle);
|
|
|
|
|
|
|
|
log.info("设备 {} 关闭结果: {}", sn, closeResult);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 从映射中移除
|
|
|
|
|
|
|
|
handleMap.remove(sn);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return closeResult == 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
|
|
log.error("设备 {} 关闭时发生异常", sn, e);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
handleMap.remove(sn);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 关闭所有设备连接
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
public static void closeAllDevices() {
|
|
|
|
|
|
|
|
log.info("开始关闭所有设备连接");
|
|
|
|
|
|
|
|
handleMap.keySet().forEach(sn -> {
|
|
|
|
|
|
|
|
closeDevice(sn);
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
Thread.sleep(100);
|
|
|
|
|
|
|
|
} catch (InterruptedException e) {
|
|
|
|
|
|
|
|
Thread.currentThread().interrupt();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
log.info("所有设备连接已关闭");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 检查设备连接是否有效
|
|
|
|
|
|
|
|
* @param sn 设备序列号
|
|
|
|
|
|
|
|
* @return true表示连接有效,false表示无效
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
public static boolean isDeviceConnected(String sn) {
|
|
|
|
|
|
|
|
DeviceInfo deviceInfo = handleMap.get(sn);
|
|
|
|
|
|
|
|
if (deviceInfo == null || deviceInfo.handleRef == null) {
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return deviceInfo.handleRef.getValue() != null;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 获取设备信息
|
|
|
|
|
|
|
|
* @param sn 设备序列号
|
|
|
|
|
|
|
|
* @return 设备信息,不存在返回null
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
public static DcLibrary.LxDeviceInfo getDeviceInfo(String sn) {
|
|
|
|
|
|
|
|
DeviceInfo deviceInfo = handleMap.get(sn);
|
|
|
|
|
|
|
|
return deviceInfo != null ? deviceInfo.deviceInfo : null;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 记录设备信息
|
|
|
|
|
|
|
|
* @param info 设备信息
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
private static void logDeviceInfo(DcLibrary.LxDeviceInfo info) {
|
|
|
|
|
|
|
|
log.info("设备详细信息:");
|
|
|
|
|
|
|
|
log.info(" 设备类型: {}", info.dev_type);
|
|
|
|
|
|
|
|
log.info(" ID: {}", new String(info.id).trim());
|
|
|
|
|
|
|
|
log.info(" IP: {}", new String(info.ip).trim());
|
|
|
|
|
|
|
|
log.info(" SN: {}", new String(info.sn).trim());
|
|
|
|
|
|
|
|
log.info(" MAC: {}", new String(info.mac).trim());
|
|
|
|
|
|
|
|
log.info(" 固件版本: {}", new String(info.firmware_ver).trim());
|
|
|
|
|
|
|
|
log.info(" 算法版本: {}", new String(info.algor_ver).trim());
|
|
|
|
|
|
|
|
log.info(" 设备名称: {}", new String(info.name).trim());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 保存点云图像(流已在初始化时启动)
|
|
|
|
|
|
|
|
* @param sn 设备序列号
|
|
|
|
|
|
|
|
* @param path 保存路径
|
|
|
|
|
|
|
|
* @param type 设备类型
|
|
|
|
|
|
|
|
* @return 0表示成功,负数表示失败
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
public static Integer saveImage(String sn, String path, int type) {
|
|
|
|
|
|
|
|
DcLibrary INSTANCE = INSTANCER;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 获取设备句柄
|
|
|
|
|
|
|
|
PointerByReference handleRef = getHandle(sn, type, INSTANCE);
|
|
|
|
|
|
|
|
if (handleRef == null) {
|
|
|
|
|
|
|
|
log.error("设备 {} 获取句柄失败", sn);
|
|
|
|
|
|
|
|
return -3;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 检查流是否已启动
|
|
|
|
|
|
|
|
DeviceInfo deviceInfo = handleMap.get(sn);
|
|
|
|
|
|
|
|
if (deviceInfo != null && !deviceInfo.streamStarted) {
|
|
|
|
|
|
|
|
log.warn("设备 {} 流未启动,尝试启动流", sn);
|
|
|
|
|
|
|
|
int result = INSTANCE.DcStartStream(handleRef.getValue());
|
|
|
|
|
|
|
|
if (result == 0) {
|
|
|
|
|
|
|
|
deviceInfo.streamStarted = true;
|
|
|
|
|
|
|
|
log.info("设备 {} 流启动成功", sn);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 设置命令码
|
|
|
|
|
|
|
|
result = INSTANCE.DcSetCmd(handleRef.getValue(), 5001);
|
|
|
|
|
|
|
|
if (result != 0 && result != 25) {
|
|
|
|
|
|
|
|
log.error("设备 {} 设置命令失败,错误码: {}", sn, result);
|
|
|
|
|
|
|
|
return -3;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
log.error("设备 {} 流启动失败,错误码: {}", sn, result);
|
|
|
|
|
|
|
|
return -3;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 创建保存目录
|
|
|
|
|
|
|
|
Path path1 = Paths.get(path);
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
// 如果路径不存在,则创建目录
|
|
|
|
|
|
|
|
Files.createDirectories(path1.getParent());
|
|
|
|
Files.createDirectories(path1.getParent());
|
|
|
|
}catch (Exception e){
|
|
|
|
} catch (Exception e) {
|
|
|
|
log.info("路径失败");
|
|
|
|
log.error("设备 {} 创建目录失败: {}", sn, e.getMessage());
|
|
|
|
|
|
|
|
return -2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
int i = INSTANCE.DcSaveXYZ(handleRef.getValue(), path);
|
|
|
|
|
|
|
|
log.info(sn+" 3dCamera get pcd :"+path +";rest:"+i);
|
|
|
|
|
|
|
|
System.out.println(sn+" 3dCamera get pcd :"+path +";rest:"+i);
|
|
|
|
|
|
|
|
result = INSTANCE.DcStopStream(handleRef.getValue());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
System.out.println("stop Stream Result: " + result);
|
|
|
|
// 保存点云数据
|
|
|
|
|
|
|
|
int saveResult = INSTANCE.DcSaveXYZ(handleRef.getValue(), path);
|
|
|
|
|
|
|
|
log.info("设备 {} 3dCamera save pcd: {}, result: {}", sn, path, saveResult);
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
if (saveResult != 0 && saveResult != 25) {
|
|
|
|
|
|
|
|
log.error("设备 {} 保存点云失败,错误码: {}", sn, saveResult);
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 不再每次都停止流,流保持运行状态
|
|
|
|
|
|
|
|
log.info("设备 {} 保存成功", sn);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 保存点云图像(带循环拍照功能,失败自动重连)
|
|
|
|
|
|
|
|
* @param sn 设备序列号
|
|
|
|
|
|
|
|
* @param path 保存路径
|
|
|
|
|
|
|
|
* @param type 设备类型
|
|
|
|
|
|
|
|
* @param maxCount 最大拍照次数,默认10次
|
|
|
|
|
|
|
|
* @return 0表示成功,-3表示获取句柄失败,-2表示创建目录失败,-1表示保存点云失败
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
public static Integer saveImageWithRetry(String sn, String path, int type, int maxCount) {
|
|
|
|
|
|
|
|
if (maxCount <= 0) {
|
|
|
|
|
|
|
|
maxCount = 5;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
log.info("设备 {} 开始循环拍照,最多 {} 次,保存路径: {}", sn, maxCount, path);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int retryCount = 0;
|
|
|
|
|
|
|
|
Integer lastError = -3;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while (retryCount < maxCount) {
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
retryCount++;
|
|
|
|
|
|
|
|
log.info("设备 {} 第 {} 次拍照尝试", sn, retryCount);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 获取设备句柄
|
|
|
|
|
|
|
|
PointerByReference handleRef = getHandle(sn, type, INSTANCER);
|
|
|
|
|
|
|
|
if (handleRef == null) {
|
|
|
|
|
|
|
|
log.warn("设备 {} 第 {} 次拍照获取句柄失败,尝试重新设置句柄", sn, retryCount);
|
|
|
|
|
|
|
|
lastError = -3;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 尝试重新设置句柄
|
|
|
|
|
|
|
|
boolean reconnectSuccess = reDevice(sn);
|
|
|
|
|
|
|
|
if (reconnectSuccess) {
|
|
|
|
|
|
|
|
log.info("设备 {} 重新设置句柄成功,继续拍照", sn);
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
log.error("设备 {} 重新设置句柄失败", sn);
|
|
|
|
|
|
|
|
if (retryCount < maxCount) {
|
|
|
|
|
|
|
|
Thread.sleep(RETRY_INTERVAL_MS);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 检查流状态
|
|
|
|
|
|
|
|
DeviceInfo deviceInfo = handleMap.get(sn);
|
|
|
|
|
|
|
|
if (deviceInfo == null || !deviceInfo.streamStarted) {
|
|
|
|
|
|
|
|
log.warn("设备 {} 流未启动,重新初始化", sn);
|
|
|
|
|
|
|
|
boolean reconnectSuccess = reDevice(sn);
|
|
|
|
|
|
|
|
if (reconnectSuccess) {
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 创建保存目录
|
|
|
|
|
|
|
|
Path path1 = Paths.get(path);
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
Files.createDirectories(path1.getParent());
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
|
|
log.error("设备 {} 创建目录失败: {}", sn, e.getMessage());
|
|
|
|
|
|
|
|
lastError = -2;
|
|
|
|
|
|
|
|
if (retryCount < maxCount) {
|
|
|
|
|
|
|
|
Thread.sleep(RETRY_INTERVAL_MS);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int result = INSTANCER.DcSetCmd(handleRef.getValue(), 5001);
|
|
|
|
|
|
|
|
log.info("设备 {} 3dCamera set cmd: {}, result: {}", sn, 5001, result);
|
|
|
|
|
|
|
|
// 保存点云数据
|
|
|
|
|
|
|
|
int saveResult = INSTANCER.DcSaveXYZ(handleRef.getValue(), path);
|
|
|
|
|
|
|
|
log.info("设备 {} 3dCamera save pcd: {}, result: {}", sn, path, saveResult);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (saveResult != 0 && saveResult != 25) {
|
|
|
|
|
|
|
|
log.warn("设备 {} 第 {} 次拍照保存点云失败,错误码: {},尝试重新设置句柄", sn, retryCount, saveResult);
|
|
|
|
|
|
|
|
lastError = -1;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 尝试重新设置句柄
|
|
|
|
|
|
|
|
boolean reconnectSuccess = reconnect(sn, type);
|
|
|
|
|
|
|
|
if (reconnectSuccess) {
|
|
|
|
|
|
|
|
log.info("设备 {} 重新设置句柄成功,继续拍照", sn);
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
log.error("设备 {} 重新设置句柄失败", sn);
|
|
|
|
|
|
|
|
if (retryCount < maxCount) {
|
|
|
|
|
|
|
|
Thread.sleep(RETRY_INTERVAL_MS);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 拍照成功
|
|
|
|
|
|
|
|
log.info("设备 {} 第 {} 次拍照成功", sn, retryCount);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} catch (InterruptedException e) {
|
|
|
|
|
|
|
|
log.error("设备 {} 拍照重试被中断", sn, e);
|
|
|
|
|
|
|
|
Thread.currentThread().interrupt();
|
|
|
|
|
|
|
|
return lastError;
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
|
|
log.error("设备 {} 第 {} 次拍照发生异常", sn, retryCount, e);
|
|
|
|
|
|
|
|
lastError = -3;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
boolean reconnectSuccess = reconnect(sn, type);
|
|
|
|
|
|
|
|
if (reconnectSuccess) {
|
|
|
|
|
|
|
|
log.info("设备 {} 异常后重新设置句柄成功,继续拍照", sn);
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} catch (Exception ex) {
|
|
|
|
|
|
|
|
log.error("设备 {} 异常后重连失败", sn, ex);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (retryCount < maxCount) {
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
Thread.sleep(RETRY_INTERVAL_MS);
|
|
|
|
|
|
|
|
} catch (InterruptedException ie) {
|
|
|
|
|
|
|
|
Thread.currentThread().interrupt();
|
|
|
|
|
|
|
|
return lastError;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
log.error("设备 {} 重试 {} 次后拍照失败,最后错误码: {}", sn, maxCount, lastError);
|
|
|
|
|
|
|
|
return lastError;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 保存点云图像(带循环拍照功能,默认最多10次)
|
|
|
|
|
|
|
|
* @param sn 设备序列号
|
|
|
|
|
|
|
|
* @param path 保存路径
|
|
|
|
|
|
|
|
* @param type 设备类型
|
|
|
|
|
|
|
|
* @return 0表示成功,-3表示获取句柄失败,-2表示创建目录失败,-1表示保存点云失败
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
public static Integer saveImageWithRetry(String sn, String path, int type) {
|
|
|
|
|
|
|
|
return saveImageWithRetry(sn, path, type, 5);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static void main(String[] args) {
|
|
|
|
public static void main(String[] args) {
|
|
|
|
saveImage("1","E:\\1-8-2-R.pcd",1);
|
|
|
|
// 测试原始单次保存
|
|
|
|
|
|
|
|
// saveImage("1", "E:\\1-8-2-R.pcd", 1);
|
|
|
|
|
|
|
|
// saveImage("2", "E:\\12-R.pcd", 2);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 测试带循环拍照的保存(默认最多10次)
|
|
|
|
|
|
|
|
Integer result = saveImageWithRetry("1", "E:\\test-retry.pcd", 1);
|
|
|
|
|
|
|
|
log.info("最终结果: {} (0=成功, -3=句柄失败, -2=目录失败, -1=保存失败)", result);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 测试带循环拍照的保存(自定义最大次数)
|
|
|
|
|
|
|
|
// Integer result = saveImageWithRetry("1", "E:\\test-retry.pcd", 1, 5);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 测试重连
|
|
|
|
|
|
|
|
// boolean reconnectResult = reconnect("1", 1);
|
|
|
|
|
|
|
|
// log.info("重连结果: {}", reconnectResult);
|
|
|
|
|
|
|
|
|
|
|
|
saveImage("2","E:\\12-R.pcd",2);
|
|
|
|
// 测试关闭所有设备
|
|
|
|
|
|
|
|
// closeAllDevices();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|