Merge branch '泸州-视觉+扫码-昆船' of https://gitlab.hzleaper.com:81/duoji/backend-duoji-monitor into 泸州-视觉+扫码-昆船

泸州-视觉+扫码-昆船
LAPTOP-S9HJSOEB\昊天 1 month ago
commit 3cf128adad

@ -20,8 +20,8 @@ public class FusionDesignApplication {
// 使用RestTemplateBuilder来实例化RestTemplate对象spring默认已经注入了RestTemplateBuilder实例 // 使用RestTemplateBuilder来实例化RestTemplate对象spring默认已经注入了RestTemplateBuilder实例
@Bean @Bean
public RestTemplate restTemplate() { public RestTemplate restTemplate() {
return builder.setConnectTimeout(Duration.ofMinutes(10)) // 设置连接超时时间,单位毫秒 return builder.setConnectTimeout(Duration.ofMinutes(10)) // 设置连接超时时间,单位分钟
.setReadTimeout(Duration.ofMinutes(20)) // 设置读取超时时间,单位 .setReadTimeout(Duration.ofMinutes(20)) // 设置读取超时时间,单位分钟
.build(); .build();
} }
} }

@ -65,8 +65,8 @@ public class IndustrialCameraController {
@ApiOperation("拍照") @ApiOperation("拍照")
@PostMapping("pic") @PostMapping("pic")
public Result<List<String>> pic(){ public Result<List<ReadOCR>> pic(){
List<String> list = new ArrayList<>(); List<ReadOCR> list = new ArrayList<>();
LocalDate currentDate = LocalDate.now(); LocalDate currentDate = LocalDate.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
@ -80,9 +80,12 @@ public class IndustrialCameraController {
// 提交异步任务 // 提交异步任务
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> { CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
hikSaveImage.saveImage(camera, fullPath, "sn"); boolean flag = hikSaveImage.saveImage(camera, fullPath, "sn");
synchronized (list) { synchronized (list) {
list.add(path); ReadOCR readOCR = new ReadOCR();
readOCR.setCode(path);
readOCR.setStatus(flag ? 1 : 0);
list.add(readOCR);
} }
}); });
@ -166,31 +169,46 @@ public class IndustrialCameraController {
public Result<KuKou> siteInventory(@RequestBody IndustrialCameraVO industrialCameraVo) { public Result<KuKou> siteInventory(@RequestBody IndustrialCameraVO industrialCameraVo) {
serialPortExample.openLight(1); serialPortExample.openLight(1);
//2d图片保存 //2d图片保存
Result<List<String>> listResult = pic(); Result<List<ReadOCR>> listResult = pic();
boolean re = false; boolean re = false;
//sick识别 //sick识别
Integer count = 0; Integer count = 0;
String code = ""; String code = "";
String pa = ""; String pa = "";
int hikFlag = 0;
ReadOCR readOCR = new ReadOCR();
try { try {
Thread.sleep(400); Thread.sleep(400);
ReadOCR readOCR = new ReadOCR();
readOCR = SickSocket.readOCR(configProperties.getCameraConfig().getSickIp(), configProperties.getCameraConfig().getSickPort()); readOCR = SickSocket.readOCR(configProperties.getCameraConfig().getSickIp(), configProperties.getCameraConfig().getSickPort());
code = readOCR.getCode(); log.info("sick识别结果"+readOCR);
if(readOCR.getStatus()!=1){
code = "0";
}else {
code = readOCR.getCode();
}
//2d识别 //2d识别
for (String path : listResult.getData()) { for (ReadOCR readOCR1 : listResult.getData()) {
if (readOCR1.getStatus()!=1){
continue;
}
String path = readOCR1.getCode();
re = FeatureMatchingExample.matchTemplate( re = FeatureMatchingExample.matchTemplate(
InventoryService.readImagesInFolder(configProperties.getSavePath().getMediaPath() + "template/" + industrialCameraVo.getTypeMacth()), InventoryService.readImagesInFolder(configProperties.getSavePath().getMediaPath() + "template/" + industrialCameraVo.getTypeMacth()),
configProperties.getSavePath().getMediaPath() + path); configProperties.getSavePath().getMediaPath() + path);
log.info("2d识别结果"+re);
if (re) { if (re) {
pa = path; pa = path;
hikFlag= 1;
break; break;
} }
} }
if (pa.equals("")) { if (pa.equals("")) {
pa = listResult.getData().get(0); pa = listResult.getData().get(0).getCode();
} }
//3d pcd保存 //3d pcd保存
LocalDate currentDate = LocalDate.now(); LocalDate currentDate = LocalDate.now();
@ -214,9 +232,27 @@ public class IndustrialCameraController {
kuKou.setWmsCode(industrialCameraVo.getCode()); kuKou.setWmsCode(industrialCameraVo.getCode());
kuKou.setPath(configProperties.getSavePath().getNetPicPath() + pa + ".jpg"); kuKou.setPath(configProperties.getSavePath().getNetPicPath() + pa + ".jpg");
kuKou.setCategoryName(industrialCameraVo.getTypeMacth()); kuKou.setCategoryName(industrialCameraVo.getTypeMacth());
if (re && count == industrialCameraVo.getCount() && code.endsWith(industrialCameraVo.getCode())) { // 现场盘点不再进行识别flag代表是否出现问题
// if (re && count.equals(industrialCameraVo.getCount()) && code.endsWith(industrialCameraVo.getCode())) {
// kuKou.setFlag(1);
// } else
if (count.equals(-2)||readOCR.getStatus() ==0 || listResult.getData().get(0).getStatus() ==0){
kuKou.setCount(0);
kuKou.setFlag(11);
}else if (count.equals(-1)){
kuKou.setCount(0);
kuKou.setFlag(12);
}else {
//
// kuKou.setCount(0);
kuKou.setFlag(1); kuKou.setFlag(1);
} else kuKou.setFlag(0);
}
kuKouService.save(kuKou); kuKouService.save(kuKou);
// serialPortExample.openLight(0); // serialPortExample.openLight(0);

@ -12,6 +12,10 @@ import com.zhehekeji.web.lib.joyware.NetSDKLib.NET_IN_LOGIN_WITH_HIGHLEVEL_SECUR
import com.zhehekeji.web.lib.joyware.NetSDKLib.NET_OUT_LOGIN_WITH_HIGHLEVEL_SECURITY; import com.zhehekeji.web.lib.joyware.NetSDKLib.NET_OUT_LOGIN_WITH_HIGHLEVEL_SECURITY;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Scanner;
/** /**
* *
* *
@ -19,8 +23,8 @@ import lombok.extern.slf4j.Slf4j;
@Slf4j @Slf4j
public class JoywareLoginModuleImpl implements CameraControlLoginModule { public class JoywareLoginModuleImpl implements CameraControlLoginModule {
public static NetSDKLib netsdk = NetSDKLib.NETSDK_INSTANCE; public static NetSDKLib netsdk = NetSDKLib.NETSDK_INSTANCE;
public static NetSDKLib configsdk = NetSDKLib.CONFIG_INSTANCE; public static NetSDKLib configsdk = NetSDKLib.CONFIG_INSTANCE;
private static int MAX_RECONNET_TIME = 100000; private static int MAX_RECONNET_TIME = 100000;
@ -31,14 +35,14 @@ public class JoywareLoginModuleImpl implements CameraControlLoginModule {
private static CallBack.HaveReConnect haveReConnect = new CallBack.HaveReConnect(); private static CallBack.HaveReConnect haveReConnect = new CallBack.HaveReConnect();
private static boolean bInit = false; private static boolean bInit = false;
private static boolean bLogopen = false; private static boolean bLogopen = false;
private static CaptureReceiveCB captureReceiveCB = new CaptureReceiveCB(); private static CaptureReceiveCB captureReceiveCB = new CaptureReceiveCB();
public static CallBack.Mp4ReceiveCB mp4ReceiveCB= new CallBack.Mp4ReceiveCB(); public static CallBack.Mp4ReceiveCB mp4ReceiveCB = new CallBack.Mp4ReceiveCB();
public static Boolean connectStatus(LLong userId){ public static Boolean connectStatus(LLong userId) {
IntByReference retLen = new IntByReference(0); IntByReference retLen = new IntByReference(0);
Pointer p = new Memory(Integer.SIZE); Pointer p = new Memory(Integer.SIZE);
p.clear(Integer.SIZE); p.clear(Integer.SIZE);
@ -48,10 +52,10 @@ public class JoywareLoginModuleImpl implements CameraControlLoginModule {
Integer.SIZE, Integer.SIZE,
retLen, retLen,
500)) { 500)) {
log.error("joyware connectStatus error,errorCode:{}",netsdk.CLIENT_GetLastError()); log.error("joyware connectStatus error,errorCode:{}", netsdk.CLIENT_GetLastError());
return false; return false;
} }
int []a = new int[1]; int[] a = new int[1];
p.read(0, a, 0, 1); p.read(0, a, 0, 1);
return a[0] == 1; return a[0] == 1;
} }
@ -65,7 +69,7 @@ public class JoywareLoginModuleImpl implements CameraControlLoginModule {
*/ */
public boolean init(NetSDKLib.fDisConnect disConnect, NetSDKLib.fHaveReConnect haveReConnect) { public boolean init(NetSDKLib.fDisConnect disConnect, NetSDKLib.fHaveReConnect haveReConnect) {
bInit = netsdk.CLIENT_Init(disConnect, null); bInit = netsdk.CLIENT_Init(disConnect, null);
if(!bInit) { if (!bInit) {
System.out.println("Initialize SDK failed"); System.out.println("Initialize SDK failed");
return false; return false;
} }
@ -86,7 +90,7 @@ public class JoywareLoginModuleImpl implements CameraControlLoginModule {
netParam.nGetConnInfoTime = 3000; // 设置子连接的超时时间 netParam.nGetConnInfoTime = 3000; // 设置子连接的超时时间
netsdk.CLIENT_SetNetworkParam(netParam); netsdk.CLIENT_SetNetworkParam(netParam);
//todo //todo
netsdk.CLIENT_SetSnapRevCallBack(captureReceiveCB,null); netsdk.CLIENT_SetSnapRevCallBack(captureReceiveCB, null);
Native.setCallbackThreadInitializer(mp4ReceiveCB, Native.setCallbackThreadInitializer(mp4ReceiveCB,
new CallbackThreadInitializer(false, false, "downloadbytime callback thread")); new CallbackThreadInitializer(false, false, "downloadbytime callback thread"));
@ -101,11 +105,11 @@ public class JoywareLoginModuleImpl implements CameraControlLoginModule {
* \endif * \endif
*/ */
public static void cleanup() { public static void cleanup() {
if(bLogopen) { if (bLogopen) {
netsdk.CLIENT_LogClose(); netsdk.CLIENT_LogClose();
} }
if(bInit) { if (bInit) {
netsdk.CLIENT_Cleanup(); netsdk.CLIENT_Cleanup();
} }
} }
@ -120,30 +124,28 @@ public class JoywareLoginModuleImpl implements CameraControlLoginModule {
public LLong login(String m_strIp, int m_nPort, String m_strUser, String m_strPassword) { public LLong login(String m_strIp, int m_nPort, String m_strUser, String m_strPassword) {
//IntByReference nError = new IntByReference(0); //IntByReference nError = new IntByReference(0);
//入参 //入参
init(disConnectCallBack,haveReConnect); init(disConnectCallBack, haveReConnect);
NET_IN_LOGIN_WITH_HIGHLEVEL_SECURITY pstInParam=new NET_IN_LOGIN_WITH_HIGHLEVEL_SECURITY(); NET_IN_LOGIN_WITH_HIGHLEVEL_SECURITY pstInParam = new NET_IN_LOGIN_WITH_HIGHLEVEL_SECURITY();
pstInParam.nPort=m_nPort; pstInParam.nPort = m_nPort;
pstInParam.szIP=m_strIp.getBytes(); pstInParam.szIP = m_strIp.getBytes();
pstInParam.szPassword=m_strPassword.getBytes(); pstInParam.szPassword = m_strPassword.getBytes();
pstInParam.szUserName=m_strUser.getBytes(); pstInParam.szUserName = m_strUser.getBytes();
//出参 //出参
NET_OUT_LOGIN_WITH_HIGHLEVEL_SECURITY pstOutParam=new NET_OUT_LOGIN_WITH_HIGHLEVEL_SECURITY(); NET_OUT_LOGIN_WITH_HIGHLEVEL_SECURITY pstOutParam = new NET_OUT_LOGIN_WITH_HIGHLEVEL_SECURITY();
pstOutParam.stuDeviceInfo=m_stDeviceInfo; pstOutParam.stuDeviceInfo = m_stDeviceInfo;
//m_hLoginHandle = netsdk.CLIENT_LoginEx2(m_strIp, m_nPort, m_strUser, m_strPassword, 0, null, m_stDeviceInfo, nError); //m_hLoginHandle = netsdk.CLIENT_LoginEx2(m_strIp, m_nPort, m_strUser, m_strPassword, 0, null, m_stDeviceInfo, nError);
LLong m_hLoginHandle=netsdk.CLIENT_LoginWithHighLevelSecurity(pstInParam, pstOutParam); LLong m_hLoginHandle = netsdk.CLIENT_LoginWithHighLevelSecurity(pstInParam, pstOutParam);
int tryTimes = 0; int tryTimes = 0;
while (m_hLoginHandle.longValue()==0 && tryTimes <= MAX_RECONNET_TIME){ while (m_hLoginHandle.longValue() == 0 && tryTimes <= MAX_RECONNET_TIME) {
log.error("joyware login error,ip:{},port:{},errorCode:{}",m_strIp,m_nPort,netsdk.CLIENT_GetLastError()); log.error("joyware login error,ip:{},port:{},errorCode:{}", m_strIp, m_nPort, netsdk.CLIENT_GetLastError());
m_hLoginHandle=netsdk.CLIENT_LoginWithHighLevelSecurity(pstInParam, pstOutParam); m_hLoginHandle = netsdk.CLIENT_LoginWithHighLevelSecurity(pstInParam, pstOutParam);
tryTimes ++; tryTimes++;
} }
if(m_hLoginHandle.longValue()==0){ if (m_hLoginHandle.longValue() == 0) {
return null; return null;
} }
log.info("joyware login success,loginId:{}",m_hLoginHandle.longValue()); log.info("joyware login success,loginId:{}", m_hLoginHandle.longValue());
return m_hLoginHandle; return m_hLoginHandle;
} }
} }

@ -0,0 +1,455 @@
package com.zhehekeji.web.lib.joyware.callBackTest;
import com.sun.jna.Pointer;
import com.zhehekeji.web.lib.joyware.CallBack;
import com.zhehekeji.web.lib.joyware.JoywareLoginModuleImpl;
import com.zhehekeji.web.lib.joyware.NetSDKLib;
import com.zhehekeji.web.lib.joyware.NetSDKLib.LLong;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Scanner;
import java.util.concurrent.ConcurrentHashMap;
/**
*
* /FFmpeg
*/
public class JoywarePlaybackTest {
// 存储登录句柄ip -> loginId
private static final ConcurrentHashMap<String, LLong> loginIdMap = new ConcurrentHashMap<>();
// 存储回放会话sessionId -> PlaybackSession
private static final ConcurrentHashMap<String, PlaybackSession> playbackSessions = new ConcurrentHashMap<>();
/**
*
*/
public static class PlaybackSession {
public String sessionId;
public String ip;
public int channel;
public LocalDateTime startTime;
public LocalDateTime endTime;
public LLong loginId;
public LLong playbackId;
public boolean isPaused;
public LocalDateTime createTime;
public enum PlaybackStatus {
PLAYING, PAUSED, STOPPED
}
public PlaybackStatus getStatus() {
if (isPaused) return PlaybackStatus.PAUSED;
return PlaybackStatus.PLAYING;
}
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("========================================");
System.out.println(" 大华回放测试工具(精简版)");
System.out.println("========================================");
System.out.println();
// 初始化SDK
System.out.println("正在初始化大华SDK...");
JoywareLoginModuleImpl joywareLogin = new JoywareLoginModuleImpl();
joywareLogin.init(
new CallBack.DisConnectCallBack(),
new CallBack.HaveReConnect()
);
System.out.println("SDK初始化完成");
System.out.println();
while (true) {
printMenu();
System.out.print("请输入操作编号: ");
String choice = scanner.nextLine().trim();
switch (choice) {
case "1":
loginDevice(scanner, joywareLogin);
break;
case "2":
startPlayback(scanner);
break;
case "3":
pauseOrResume(scanner);
break;
case "4":
stopPlayback(scanner);
break;
case "5":
listAllSessions();
break;
case "0":
cleanup(joywareLogin);
System.out.println("退出程序!");
return;
default:
System.out.println("无效的编号,请重新输入!");
break;
}
System.out.println();
}
}
/**
*
*/
private static void printMenu() {
System.out.println("----------------------------------------");
System.out.println("1. 登录设备");
System.out.println("2. 开始回放");
System.out.println("3. 暂停/恢复回放");
System.out.println("4. 停止回放");
System.out.println("5. 查看所有会话");
System.out.println("0. 退出");
System.out.println("----------------------------------------");
}
/**
*
*/
private static void loginDevice(Scanner scanner, JoywareLoginModuleImpl joywareLogin) {
System.out.println();
System.out.println(">>> 登录设备");
System.out.print("设备IP: ");
String ip = scanner.nextLine().trim();
System.out.print("设备端口默认37777: ");
String portStr = scanner.nextLine().trim();
int port = portStr.isEmpty() ? 37777 : Integer.parseInt(portStr);
System.out.print("用户名默认admin: ");
String username = scanner.nextLine().trim();
if (username.isEmpty()) username = "admin";
System.out.print("密码默认admin123: ");
String password = scanner.nextLine().trim();
if (password.isEmpty()) password = "admin123";
try {
LLong loginId = joywareLogin.login(ip, port, username, password);
if (loginId != null && loginId.longValue() != 0) {
loginIdMap.put(ip, loginId);
System.out.println("登录成功!");
System.out.println(" 设备IP: " + ip);
System.out.println(" 登录句柄: " + loginId.longValue());
} else {
System.out.println("登录失败请检查IP、端口、用户名密码");
}
} catch (Exception e) {
System.out.println("登录异常: " + e.getMessage());
e.printStackTrace();
}
}
/**
*
*/
private static void startPlayback(Scanner scanner) {
System.out.println();
System.out.println(">>> 开始回放");
System.out.print("设备IP: ");
String ip = scanner.nextLine().trim();
if (!loginIdMap.containsKey(ip)) {
System.out.println("设备未登录,请先登录!");
return;
}
LLong loginId = loginIdMap.get(ip);
System.out.print("通道号默认0: ");
String channelStr = scanner.nextLine().trim();
int channel = channelStr.isEmpty() ? 0 : Integer.parseInt(channelStr);
System.out.print("开始时间格式2024-01-01 00:00:00: ");
String startTimeStr = scanner.nextLine().trim();
System.out.print("结束时间格式2024-01-01 23:59:59: ");
String endTimeStr = scanner.nextLine().trim();
// 检查输入是否为空
if (startTimeStr.isEmpty()) {
System.out.println("开始时间不能为空!");
return;
}
if (endTimeStr.isEmpty()) {
System.out.println("结束时间不能为空!");
return;
}
try {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime startTime = LocalDateTime.parse(startTimeStr, formatter);
LocalDateTime endTime = LocalDateTime.parse(endTimeStr, formatter);
PlaybackSession session = performStartPlayback(
loginId,
ip,
channel,
startTime,
endTime
);
playbackSessions.put(session.sessionId, session);
System.out.println("回放启动成功!");
System.out.println(" 会话ID: " + session.sessionId);
System.out.println(" 播放句柄: " + session.playbackId.longValue());
System.out.println(" 回放时间: " + startTime + " ~ " + endTime);
System.out.println(" 播放状态: " + session.getStatus());
System.out.println();
System.out.println("H.264数据将通过回调推送到FFmpeg请检查RTSP推流是否正常");
} catch (Exception e) {
System.out.println("启动回放失败: " + e.getMessage());
e.printStackTrace();
}
}
/**
*
*/
private static PlaybackSession performStartPlayback(LLong loginId, String ip, int channel,
LocalDateTime startTime, LocalDateTime endTime) {
// 准备时间结构
NetSDKLib.NET_TIME stStartTime = new NetSDKLib.NET_TIME();
stStartTime.setTime(
startTime.getYear(),
startTime.getMonthValue(),
startTime.getDayOfMonth(),
startTime.getHour(),
startTime.getMinute(),
startTime.getSecond()
);
NetSDKLib.NET_TIME stStopTime = new NetSDKLib.NET_TIME();
stStopTime.setTime(
endTime.getYear(),
endTime.getMonthValue(),
endTime.getDayOfMonth(),
endTime.getHour(),
endTime.getMinute(),
endTime.getSecond()
);
// 调用大华SDK开始回放
// hWnd = null 表示无窗口
// mp4ReceiveCB 是数据回调接收H.264数据
LLong playbackId = JoywareLoginModuleImpl.netsdk.CLIENT_PlayBackByTimeEx(
loginId, // 登录句柄
channel, // 通道号
stStartTime, // 开始时间
stStopTime, // 结束时间
null, // hWnd = null无窗口
null, // 下载进度回调
null, // 用户数据
JoywareLoginModuleImpl.mp4ReceiveCB, // 数据回调(关键!)
null // 用户数据
);
if (playbackId == null || playbackId.longValue() == 0) {
throw new RuntimeException("开始回放失败,错误码: " +
JoywareLoginModuleImpl.netsdk.CLIENT_GetLastError());
}
// 创建会话
PlaybackSession session = new PlaybackSession();
session.sessionId = java.util.UUID.randomUUID().toString();
session.loginId = loginId;
session.playbackId = playbackId;
session.ip = ip;
session.channel = channel;
session.startTime = startTime;
session.endTime = endTime;
session.isPaused = false;
session.createTime = LocalDateTime.now();
return session;
}
/**
*
*/
private static void pauseOrResume(Scanner scanner) {
System.out.println();
System.out.println(">>> 暂停/恢复回放");
System.out.print("会话ID: ");
String sessionId = scanner.nextLine().trim();
PlaybackSession session = playbackSessions.get(sessionId);
if (session == null) {
System.out.println("会话不存在!");
return;
}
try {
if (session.isPaused) {
// 当前是暂停状态,执行恢复
performResume(session);
System.out.println("回放已恢复");
System.out.println(" 会话ID: " + sessionId);
System.out.println(" 播放状态: " + session.getStatus());
} else {
// 当前是播放状态,执行暂停
performPause(session);
System.out.println("回放已暂停");
System.out.println(" 会话ID: " + sessionId);
System.out.println(" 播放状态: " + session.getStatus());
}
} catch (Exception e) {
System.out.println("操作失败: " + e.getMessage());
}
}
/**
*
*/
private static void performPause(PlaybackSession session) {
// 调用大华SDK暂停回放
boolean result = JoywareLoginModuleImpl.netsdk.CLIENT_PausePlayBack(
session.playbackId,
1 // 1表示暂停
);
if (!result) {
throw new RuntimeException("暂停失败,错误码: " +
JoywareLoginModuleImpl.netsdk.CLIENT_GetLastError());
}
session.isPaused = true;
}
/**
*
*/
private static void performResume(PlaybackSession session) {
// 调用大华SDK恢复回放
boolean result = JoywareLoginModuleImpl.netsdk.CLIENT_PausePlayBack(
session.playbackId,
0 // 0表示恢复
);
if (!result) {
throw new RuntimeException("恢复失败,错误码: " +
JoywareLoginModuleImpl.netsdk.CLIENT_GetLastError());
}
session.isPaused = false;
}
/**
*
*/
private static void stopPlayback(Scanner scanner) {
System.out.println();
System.out.println(">>> 停止回放");
System.out.print("会话ID: ");
String sessionId = scanner.nextLine().trim();
PlaybackSession session = playbackSessions.remove(sessionId);
if (session == null) {
System.out.println("会话不存在!");
return;
}
try {
performStop(session);
System.out.println("回放已停止");
System.out.println(" 会话ID: " + sessionId);
} catch (Exception e) {
System.out.println("停止失败: " + e.getMessage());
}
}
/**
*
*/
private static void performStop(PlaybackSession session) {
// 调用大华SDK停止回放
boolean result = JoywareLoginModuleImpl.netsdk.CLIENT_StopPlayBack(session.playbackId);
if (!result) {
throw new RuntimeException("停止失败,错误码: " +
JoywareLoginModuleImpl.netsdk.CLIENT_GetLastError());
}
session.isPaused = false;
}
/**
*
*/
private static void listAllSessions() {
System.out.println();
System.out.println(">>> 所有回放会话");
if (playbackSessions.isEmpty()) {
System.out.println("当前没有活动的回放会话");
return;
}
System.out.println("----------------------------------------");
System.out.printf("%-15s %-15s %-10s %-10s%n", "会话ID", "设备IP", "通道", "状态");
System.out.println("----------------------------------------");
for (PlaybackSession session : playbackSessions.values()) {
System.out.printf("%-15s %-15s %-10d %-10s%n",
session.sessionId.substring(0, Math.min(15, session.sessionId.length())),
session.ip,
session.channel,
session.getStatus());
}
System.out.println("----------------------------------------");
System.out.println("总计: " + playbackSessions.size() + " 个会话");
}
/**
*
*/
private static void cleanup(JoywareLoginModuleImpl joywareLogin) {
System.out.println();
System.out.println("正在清理资源...");
// 停止所有回放
for (PlaybackSession session : playbackSessions.values()) {
performStop(session);
}
playbackSessions.clear();
// 登出所有设备
for (String ip : loginIdMap.keySet()) {
LLong loginId = loginIdMap.get(ip);
// boolean result = joywareLogin.logout(loginId);
// if (result) {
// System.out.println("登出设备: " + ip);
// } else {
// System.out.println("登出失败: " + ip);
// }
}
loginIdMap.clear();
// 清理SDK
JoywareLoginModuleImpl.cleanup();
System.out.println("资源清理完成!");
}
}

@ -0,0 +1,69 @@
package com.zhehekeji.web.lib.joyware.callBackTest;
import com.sun.jna.Pointer;
import com.zhehekeji.web.lib.joyware.NetSDKLib;
import javax.security.auth.callback.Callback;
import java.io.IOException;
import java.io.OutputStream;
// 在 Mp4ReceiveCB.java 中添加FFmpeg推流逻辑
public class Mp4ReceivePlayCB implements NetSDKLib.fTimeDownLoadPosCallBack {
private Process ffmpegProcess;
private OutputStream ffmpegStdin;
public void startFFmpegPush(String streamId) {
try {
// 启动FFmpeg推流到RTSP服务器
ProcessBuilder pb = new ProcessBuilder(
"D:\\git\\duoji_old\\libs\\ffmpeg\\ffmpeg.exe",
"-re", // 实时读取
"-i", "pipe:0", // 从stdin读取H.264数据
"-c:v", "copy", // 不重新编码
"-f", "rtsp", // 输出RTSP格式
"rtsp://127.0.0.1:8554/playback/" + streamId
);
ffmpegProcess = pb.start();
ffmpegStdin = ffmpegProcess.getOutputStream();
System.out.println("FFmpeg推流已启动: " + streamId);
} catch (IOException e) {
e.printStackTrace();
}
}
public void invoke(Pointer buffer, int bufferSize, Pointer user) {
// 接收H.264数据
byte[] h264Data = buffer.getByteArray(0, bufferSize);
// 写入FFmpeg的stdin
try {
if (ffmpegStdin != null) {
ffmpegStdin.write(h264Data);
ffmpegStdin.flush();
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void stopFFmpegPush() {
if (ffmpegProcess != null) {
ffmpegProcess.destroy();
}
if (ffmpegStdin != null) {
try {
ffmpegStdin.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public void invoke(NetSDKLib.LLong lPlayHandle, int dwTotalSize, int dwDownLoadSize, int index, NetSDKLib.NET_RECORDFILE_INFO.ByValue recordfileinfo, Pointer dwUser) {
}
}

@ -168,8 +168,6 @@ public class HikSaveImage implements CameraSaveUtil{
public boolean saveImage(String sn, String path,String type) { public boolean saveImage(String sn, String path,String type) {
int nRet = MV_OK; int nRet = MV_OK;
do
{
System.out.println("SDK Version " + MvCameraControl.MV_CC_GetSDKVersion()); System.out.println("SDK Version " + MvCameraControl.MV_CC_GetSDKVersion());
// Enuerate GigE and USB devices // Enuerate GigE and USB devices
@ -194,7 +192,7 @@ public class HikSaveImage implements CameraSaveUtil{
if (MV_OK != nRet) if (MV_OK != nRet)
{ {
System.err.printf("Get PayloadSize fail, errcode: [%#x]\n", nRet); System.err.printf("Get PayloadSize fail, errcode: [%#x]\n", nRet);
break; return false;
} }
@ -211,7 +209,7 @@ public class HikSaveImage implements CameraSaveUtil{
if (MV_OK != nRet) if (MV_OK != nRet)
{ {
System.err.printf("GetOneFrameTimeout fail, errcode:[%#x]\n", nRet); System.err.printf("GetOneFrameTimeout fail, errcode:[%#x]\n", nRet);
break; return false;
} }
System.out.println("GetOneFrame: "); System.out.println("GetOneFrame: ");
@ -235,16 +233,14 @@ public class HikSaveImage implements CameraSaveUtil{
if (MV_OK != nRet) if (MV_OK != nRet)
{ {
System.err.printf("SaveImage fail, errcode: [%#x]\n", nRet); System.err.printf("SaveImage fail, errcode: [%#x]\n", nRet);
break; return false;
} }
// Save buffer content to file // Save buffer content to file
saveDataToFile(imageBuffer, imageLen, path); saveDataToFile(imageBuffer, imageLen, path);
} while (false);
return false; return true;
} }
public void init(List<String> sns,String type){ public void init(List<String> sns,String type){
ArrayList<MV_CC_DEVICE_INFO> stDeviceList = new ArrayList<>(); ArrayList<MV_CC_DEVICE_INFO> stDeviceList = new ArrayList<>();

@ -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 truefalse
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 truefalse
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 truefalse
*/
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();
} }
} }

@ -480,12 +480,13 @@ public class PlcService {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
headers.set("Content-Type", "application/json"); headers.set("Content-Type", "application/json");
headers.set("User-Agent", "Mozilla/5.0"); headers.set("User-Agent", "Mozilla/5.0");
log.info("scTransmission:{}",scTransmission);
// 创建 HttpEntity 对象 // 创建 HttpEntity 对象
HttpEntity<IndustrialCameraVO> entity = new HttpEntity<>(scTransmission, headers); HttpEntity<IndustrialCameraVO> entity = new HttpEntity<>(scTransmission, headers);
// Map<String, ConfigProperties.Template> map = configProperties.getTemplate().stream().collect(Collectors.toMap(k->k.getCode(), v->v)); // Map<String, ConfigProperties.Template> map = configProperties.getTemplate().stream().collect(Collectors.toMap(k->k.getCode(), v->v));
log.info("发送站台盘点:"+scTransmission.toString());
// 发送 POST 请求 // 发送 POST 请求
ResponseEntity<Result<KuKou>> response = restTemplate.exchange( ResponseEntity<Result<KuKou>> response = restTemplate.exchange(
"http://" + configProperties.getSiteInventoryIp() + ":8099" + "/api/industrialCamera/siteInventory", "http://" + configProperties.getSiteInventoryIp() + ":8099" + "/api/industrialCamera/siteInventory",
@ -493,6 +494,7 @@ public class PlcService {
entity, entity,
new ParameterizedTypeReference<Result<KuKou>>() {} new ParameterizedTypeReference<Result<KuKou>>() {}
); );
log.info("请求成功,响应:{}", response.getBody());
if (response.getBody()!=null && Objects.requireNonNull(response.getBody()).getData().getFlag()==1){ if (response.getBody()!=null && Objects.requireNonNull(response.getBody()).getData().getFlag()==1){
scTransmission.setWmsTrayCode(dataInfo.getTrayCode()); scTransmission.setWmsTrayCode(dataInfo.getTrayCode());
@ -511,6 +513,7 @@ public class PlcService {
}else }else
scTransmission.setTrayCode(""); scTransmission.setTrayCode("");
scTransmission.setCount(0); scTransmission.setCount(0);
scTransmission.setFlag(response.getBody().getData().getFlag());
kuKouService.setHttp(scTransmission,flag); kuKouService.setHttp(scTransmission,flag);
return i; return i;
} }

@ -26,6 +26,8 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static com.zhehekeji.web.service.IndustrialCamera.LxPointCloudSaveImage.INSTANCER;
@Service @Service
@Slf4j @Slf4j
public class InventoryService { public class InventoryService {
@ -69,7 +71,8 @@ public class InventoryService {
public void init(){ public void init(){
if (configProperties.getCameraConfig()!=null && configProperties.getCameraConfig().getCamera3D()!=null && !configProperties.getCameraConfig().getCamera3D().equals("")) { if (configProperties.getCameraConfig()!=null && configProperties.getCameraConfig().getCamera3D()!=null && !configProperties.getCameraConfig().getCamera3D().equals("")) {
PointerByReference handleRef = LxPointCloudSaveImage.init(configProperties.getCameraConfig().getCamera3D()); DcLibrary INSTANCE = INSTANCER;
PointerByReference handleRef = LxPointCloudSaveImage.initDevice(configProperties.getCameraConfig().getCamera3D(), 1, INSTANCE);
} }
} }
public int match3D(String category,String path){ public int match3D(String category,String path){
@ -84,10 +87,20 @@ public class InventoryService {
public int match3D(String category,String path,String configPath){ public int match3D(String category,String path,String configPath){
//拍照 //拍照
List<Integer> results = new ArrayList<>(); List<Integer> results = new ArrayList<>();
if(!pingDevice(configProperties.getCameraConfig().getCamera3D())){
return -1;
}
log.info("3D拍照pcd "+path);
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
String currentPath = path.replace(".pcd", "_" + i + ".pcd"); // 添加索引以区分不同次拍照的文件路径 String currentPath = path.replace(".pcd", "_" + i + ".pcd"); // 添加索引以区分不同次拍照的文件路径
LxPointCloudSaveImage.saveImage(configProperties.getCameraConfig().getCamera3D(), currentPath, 1); int picResult = LxPointCloudSaveImage.saveImageWithRetry(configProperties.getCameraConfig().getCamera3D(), currentPath, 1);
if(picResult != 0 && picResult!=25){
// 没有成功拍照
log.error("3D拍照失败相机取流未成功拍照"+picResult);
return -2;
}
log.info("3D拍照成功 "+picResult);
Integer result = PointCloudProcessor.getBaijiuBox( Integer result = PointCloudProcessor.getBaijiuBox(
currentPath, currentPath,
@ -107,14 +120,11 @@ public class InventoryService {
return results.get(2); return results.get(2);
} }
try {
try {
Thread.sleep(300*(i+1)); // 间隔300ms Thread.sleep(300*(i+1)); // 间隔300ms
} catch (InterruptedException e) { } catch (InterruptedException e) {
log.error("线程休眠异常", e); log.error("线程休眠异常", e);
} }
} }
return results.get(results.size() - 1); return results.get(results.size() - 1);
@ -150,8 +160,84 @@ public class InventoryService {
return list; return list;
} }
public static void main(String[] args) {
/**
* PingIPTTL
* @param ip IP
* @return truefalse
*/
private boolean pingDevice(String ip) {
try {
log.info("开始Ping设备IP: {}", ip);
// 根据操作系统选择Ping命令
boolean isWindows = System.getProperty("os.name").toLowerCase().contains("win");
String command;
int timeout = 2000; // 超时时间2秒
if (isWindows) {
command = String.format("ping -n 2 -w %d %s", timeout, ip);
} else {
command = String.format("ping -c 2 -W %d %s", timeout / 1000, ip);
}
Process process = Runtime.getRuntime().exec(command);
// 读取输出以检查是否有TTL过期等异常
java.io.BufferedReader reader = new java.io.BufferedReader(
new java.io.InputStreamReader(process.getInputStream(), "GBK")
);
java.io.BufferedReader errorReader = new java.io.BufferedReader(
new java.io.InputStreamReader(process.getErrorStream(), "GBK")
);
StringBuilder output = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
output.append(line).append("\n");
}
while ((line = errorReader.readLine()) != null) {
output.append(line).append("\n");
}
int exitCode = process.waitFor();
// 检查输出中的关键字
String outputStr = output.toString().toLowerCase();
log.debug("Ping输出: {}", outputStr);
// 检查是否包含TTL过期、超时等异常信息
boolean hasError = outputStr.contains("timed out") ||
outputStr.contains("传输失败") ||
outputStr.contains("请求超时") ||
outputStr.contains("无法访问目标主机") ||
outputStr.contains("destination host unreachable") ||
outputStr.contains("100% loss");
// 检查是否有成功的回复Windows: 字节数=32 时间<xxxms TTL=xxx
boolean hasSuccess = isWindows ?
(outputStr.contains("来自") && outputStr.contains("字节") && outputStr.contains("时间") && outputStr.contains("ttl")) :
(outputStr.contains("bytes from") && outputStr.contains("icmp_seq") && outputStr.contains("ttl"));
// 综合判断退出码为0且没有错误信息且至少有一次成功回复
boolean isConnected = (exitCode == 0) && !hasError && hasSuccess;
log.info("设备IP {} Ping结果: {} (exitCode={}, hasError={}, hasSuccess={})",
ip, isConnected ? "可连通" : "不可连通", exitCode, hasError, hasSuccess);
return isConnected;
} catch (Exception e) {
log.error("Ping设备IP {} 时发生异常", ip, e);
return false;
}
}
public static void main(String[] args) {
// 测试连接检查
InventoryService service = new InventoryService();
boolean connected = service.pingDevice("192.168.1.21");
System.out.println("设备连接状态: " + connected);
} }
} }

@ -1,48 +0,0 @@
package com.zhehekeji.web.service.visualQuantity;
import com.sun.jna.Native;
import com.zhehekeji.web.service.IndustrialCamera.DcLibrary;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.HashMap;
import java.util.Map;
import static com.zhehekeji.web.service.algorithm.PointCloudProcessor.findPcdFiles;
public class test {
static VisualQuantityCameraApi INSTANCER = (VisualQuantityCameraApi) Native.loadLibrary((System.getProperty("user.dir"))+"\\libs\\3d\\3ddll.dll", VisualQuantityCameraApi.class);
public static void main(String[] args) {
String directoryPath = "E:\\泸州\\task国窖\\task"; // 替换为实际路径
File directory = new File(directoryPath);
if (!directory.exists() || !directory.isDirectory()) {
System.out.println("指定路径不是一个有效的目录!");
return;
}
Map<Integer,String> map = new HashMap<>();
findPcdFiles(directory,map);
for (Integer count : map.keySet()) {
System.out.print(count +" ");
try {
Files.copy(Paths.get(map.get(count)), Paths.get("E:\\192.168.40.11.pcd"), StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
throw new RuntimeException(e);
}
System.out.println(1111);
int i = INSTANCER.cameraapi("E:\\192.168.40.11.pcd","E:\\2.json",3);
System.out.println(i);
// System.out.println(similarity);
}
}
}

@ -73,7 +73,7 @@ savePath:
# ------------服务端类型 0TCP(罗伯泰克) 1:KSEC(JSON)(昆船) # ------------服务端类型 0TCP(罗伯泰克) 1:KSEC(JSON)(昆船)
serverMode: 1 serverMode: 1
ksec: ksec:
port: 3000 port: 3010
ip: 127.0.0.1 ip: 127.0.0.1
platformIp: 127.0.0.1 platformIp: 127.0.0.1
platformPort: 3000 platformPort: 3000

Loading…
Cancel
Save