作者 钟来

模块整理

正在显示 26 个修改的文件 包含 447 行增加755 行删除
... ... @@ -65,20 +65,6 @@
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<!-- 串口开发 -->
<dependency>
<groupId>com.github.purejavacomm</groupId>
<artifactId>purejavacomm</artifactId>
<version>1.0.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>3.10.8</version>
</dependency>
<!-- sqlite -->
<dependency>
<groupId>com.zhonglai.luhui</groupId>
... ... @@ -98,11 +84,6 @@
<version>3.21.0.1</version>
</dependency>
<!-- <dependency>-->
<!-- <groupId>mysql</groupId>-->
<!-- <artifactId>mysql-connector-java</artifactId>-->
<!-- </dependency>-->
<!-- mqtt -->
<dependency>
<groupId>org.eclipse.paho</groupId>
... ... @@ -112,6 +93,14 @@
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</dependency>
<!-- 串口开发 -->
<!-- https://mvnrepository.com/artifact/com.fazecast/jSerialComm -->
<dependency>
<groupId>com.fazecast</groupId>
<artifactId>jSerialComm</artifactId>
<version>2.10.3</version>
</dependency>
</dependencies>
<build>
... ...
... ... @@ -2,7 +2,6 @@ package com.zhonglai.luhui.smart.feeder;
import com.ruoyi.framework.config.ResourcesConfig;
import com.zhonglai.luhui.smart.feeder.config.OpenCVConfig;
import com.zhonglai.luhui.smart.feeder.config.v2apibug.ResponseFilter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
... ...
... ... @@ -2,6 +2,7 @@ package com.zhonglai.luhui.smart.feeder.config.manager;
import com.zhonglai.luhui.smart.feeder.service.DeviceService;
import com.zhonglai.luhui.smart.feeder.service.EhCacheService;
import com.zhonglai.luhui.smart.feeder.service.SerialPortService;
import com.zhonglai.luhui.smart.feeder.service.TerminalService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
... ... @@ -24,7 +25,7 @@ public class ShutdownManager
private EhCacheService ehCacheService;
@Autowired
private DeviceService deviceService;
private SerialPortService serialPortService;
@Autowired
private TerminalService terminalService;
... ... @@ -33,7 +34,7 @@ public class ShutdownManager
public void destroy()
{
terminalService.close();
deviceService.close();
serialPortService.close();
ehCacheService.shutdown();
shutdownAsyncManager();
}
... ...
... ... @@ -26,22 +26,6 @@ public class CameraController {
@Autowired
private DeviceService deviceService;
@ApiOperation("打开鱼群识别")
@GetMapping("/open")
public AjaxResult open()
{
// fishGroupImageRecognitionService.start(VeiwType.html);
return AjaxResult.success();
}
@ApiOperation("关闭鱼群识别")
@GetMapping("/close")
public AjaxResult close()
{
// fishGroupImageRecognitionService.stop();
return AjaxResult.success();
}
@ApiOperation("关闭连接")
@GetMapping("/discon/{userId}")
public AjaxResult discon( @PathVariable(value = "userId") Integer userId)
... ... @@ -50,54 +34,4 @@ public class CameraController {
return AjaxResult.success();
}
@ApiOperation("打开串口")
@ApiImplicitParams({
@ApiImplicitParam(value = "串口名称",name = "portName"),
@ApiImplicitParam(value = "波特率",name = "baudrate"),
@ApiImplicitParam(value = "数据位",name = "dataBits"),
@ApiImplicitParam(value = "停止位",name = "stopBits"),
@ApiImplicitParam(value = "校验位",name = "parity"),
})
@GetMapping("/openSerial")
public AjaxResult openSerial(String portName, Integer baudrate, Integer dataBits, Integer stopBits,Integer parity) throws Exception {
deviceService.openSerialPort(portName,baudrate,dataBits,stopBits,parity);
return AjaxResult.success();
}
@ApiOperation("强行打开串口")
@ApiImplicitParams({
@ApiImplicitParam(value = "串口名称",name = "portName"),
@ApiImplicitParam(value = "波特率",name = "baudrate"),
@ApiImplicitParam(value = "数据位",name = "dataBits"),
@ApiImplicitParam(value = "停止位",name = "stopBits"),
@ApiImplicitParam(value = "校验位",name = "parity"),
})
@GetMapping("/nowOpenSerial")
public AjaxResult nowOpenSerial(String portName, Integer baudrate, Integer dataBits, Integer stopBits,Integer parity) throws Exception {
deviceService.nowOpenSerial(portName,baudrate,dataBits,stopBits,parity);
return AjaxResult.success();
}
@ApiOperation("串口发送指令")
@GetMapping("/sendSerialData")
public AjaxResult sendSerialData(String hexStr) throws IOException {
hexStr = hexStr.replace(" ","").trim();
ModbusDto commdDto = deviceService.sendData(hexStr);
return AjaxResult.success(commdDto);
}
@ApiOperation("地址发送指令")
@GetMapping("/controlData")
public AjaxResult controlData(FeederCommd06ResponseType feederCommd06ResponseType,int value) throws IOException {
ModbusDto commdDto = deviceService.sendData(FeederCommdUtil.controlData( feederCommd06ResponseType, value));
return AjaxResult.success(commdDto);
}
@ApiOperation("获取所有串口")
@GetMapping("/getAllSerial")
public AjaxResult getAllSerial() {
return AjaxResult.success().put("data",deviceService.getAllSerial());
}
}
... ...
... ... @@ -3,17 +3,12 @@ package com.zhonglai.luhui.smart.feeder.controller;
import com.ruoyi.common.core.domain.AjaxResult;
import com.zhonglai.luhui.dao.service.PublicService;
import com.zhonglai.luhui.smart.feeder.dto.ConfigDto;
import com.zhonglai.luhui.smart.feeder.dto.ConfigurationParameter;
import com.zhonglai.luhui.smart.feeder.dto.VeiwType;
import com.zhonglai.luhui.smart.feeder.service.ConfigurationParameterService;
import com.zhonglai.luhui.smart.feeder.service.FishGroupImageRecognitionService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.ehcache.Cache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
... ... @@ -30,14 +25,10 @@ public class ConfigController {
public AjaxResult all()
{
AjaxResult ajaxResult = AjaxResult.success();
Cache<String, Object> cache = configurationParameterService.getAll();
Iterator<Cache.Entry<String, Object>> iterator = cache.iterator();
while (iterator.hasNext()) {
Cache.Entry<String, Object> entry = iterator.next();
String key = entry.getKey();
Object value = entry.getValue();
Map<String, Object> cache = configurationParameterService.getAll();
for (String key:cache.keySet()) {
// Process the key and value as needed.
ajaxResult.put(key,value);
ajaxResult.put(key,cache.get(key));
}
return ajaxResult;
}
... ...
package com.zhonglai.luhui.smart.feeder.controller;
import com.fazecast.jSerialComm.SerialPort;
import com.ruoyi.common.core.domain.AjaxResult;
import com.zhonglai.luhui.smart.feeder.dto.ConfigDto;
import com.zhonglai.luhui.smart.feeder.dto.commd.*;
import com.zhonglai.luhui.smart.feeder.service.DeviceService;
import com.zhonglai.luhui.smart.feeder.service.SerialPortService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@Api(tags = "串口管理")
@RestController
@RequestMapping("/serialPort")
public class SerialPortController {
@Autowired
private SerialPortService serialPortService;
@ApiOperation("打开")
@PostMapping("/open")
public AjaxResult open(Integer baudrate)
{
return AjaxResult.success(serialPortService.open());
}
@ApiOperation("发送16进制")
@GetMapping("/sendHexData")
public AjaxResult sendHexData(String hexStr)
{
return AjaxResult.success(serialPortService.sendHexData(hexStr));
}
@ApiOperation("发送字符串")
@GetMapping("/sendStrData")
public AjaxResult sendStrData(String str)
{
return AjaxResult.success(serialPortService.sendStrData(str));
}
@ApiOperation("读取")
@GetMapping("/read")
public AjaxResult read(Integer start_char,Integer char_lenth)
{
return AjaxResult.success(serialPortService.sendHexData(new FeederCommdDto(new FeederCommd03Response(start_char,char_lenth)).getHstr()));
}
@ApiOperation("单独写入")
@GetMapping("/write")
public AjaxResult write(Integer register_address,Integer value)
{
return AjaxResult.success(serialPortService.sendHexData(new FeederCommdDto(new FeederCommd06Response(register_address,value)).getHstr()));
}
}
... ...
... ... @@ -20,6 +20,7 @@ public enum ConfigurationParameter {
VeiwDto_isSize(false, Boolean.class,"sys_config","是否显示面积",true), //是否显示面积
VeiwDto_isAbsValue(false, Boolean.class,"sys_config","是否显示斜率",true), //是否显示斜率
absValue(0.0, Double.class,"sys_config","显示斜率",false), //斜率
IdentificationFrequency(1000l, Long.class,"sys_config","鱼群图像识别的频率(单位秒)",true), //鱼群图像识别的频率
FishGroupImageRecognition(true, Boolean.class,"sys_config","鱼群图像识别是否开启",true), //鱼群图像识别是否开启
FeedingControl(true, Boolean.class,"sys_config","鱼群图像识别控制投料控制是否开启",true), //鱼群图像识别投料控制是否开启
SerialPortConfig(new SerialPortConfig().defaultSerialPortConfig(),com.zhonglai.luhui.smart.feeder.dto.SerialPortConfig.class,"sys_config","串口配置",true),//串口配置
... ...
package com.zhonglai.luhui.smart.feeder.dto;
import org.ehcache.spi.serialization.Serializer;
import org.ehcache.spi.serialization.SerializerException;
import java.io.*;
import java.nio.ByteBuffer;
public class MyCustomSerializer implements Serializer<Object>{
private final ClassLoader classLoader;
public MyCustomSerializer(ClassLoader classLoader) {
this.classLoader = classLoader;
}
@Override
public ByteBuffer serialize(Object object) throws SerializerException {
try {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(object);
objectOutputStream.flush();
return ByteBuffer.wrap(byteArrayOutputStream.toByteArray());
} catch (IOException e) {
throw new SerializerException(e);
}
}
@Override
public Object read(ByteBuffer byteBuffer) throws ClassNotFoundException, SerializerException {
try {
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteBuffer.array());
ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
return objectInputStream.readObject();
} catch (IOException e) {
throw new SerializerException(e);
}
}
@Override
public boolean equals(Object o, ByteBuffer byteBuffer) throws ClassNotFoundException, SerializerException {
return o.equals(read(byteBuffer));
}
}
... ... @@ -9,14 +9,15 @@ import java.util.Map;
public class FeederCommd03Request implements FeederCommd {
private static final long serialVersionUID = 200980498094314547L;
private Integer lenth;
private Map<Integer,byte[]> addressValue = new HashMap<>();
private Map<Integer,Long> addressValue = new HashMap<>();
public FeederCommd03Request(byte[] data)
{
lenth = new Long(ByteUtil.bytesToLongDESC(data,0,1)).intValue()/2;
for (int i=0;i<lenth;i++)
{
byte[] bytes = ArrayUtils.subarray(data,1+2*i,1+2*i+2);
addressValue.put(i, bytes);
addressValue.put(i,ByteUtil.bytesToLongDESC(bytes,0,2));
}
}
... ... @@ -28,11 +29,11 @@ public class FeederCommd03Request implements FeederCommd {
this.lenth = lenth;
}
public Map<Integer, byte[]> getAddressValue() {
public Map<Integer, Long> getAddressValue() {
return addressValue;
}
public void setAddressValue(Map<Integer, byte[]> addressValue) {
public void setAddressValue(Map<Integer, Long> addressValue) {
this.addressValue = addressValue;
}
}
... ...
... ... @@ -72,6 +72,28 @@ public class OpenCVUtil {
return null;
}
public static VideoCapture openCapture()
{
for(int i=0;i<10;i++)
{
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
VideoCapture videoCapture = new VideoCapture();
boolean isopen = videoCapture.open(i);
if(isopen)
{
logger.info("打开化摄像头"+i+"成功");
return videoCapture;
}else {
logger.info("打开化摄像头"+i+"失败");
}
}
return null;
}
public static VideoCapture readVideoCaptureForVideo(String videoPath )
{
// 创建VideoCapture对象
... ...
... ... @@ -43,10 +43,10 @@ public class AnalysisDataService {
Map<String,Object> valueMap = new HashMap<>();
FeederCommd03Request feederCommd03Request = (FeederCommd03Request) feederCommd;
Map<Integer, byte[]> map = feederCommd03Request.getAddressValue();
Map<Integer,Long> map = feederCommd03Request.getAddressValue();
for (Integer adrress:map.keySet())
{
byte[] bytes = map.get(adrress);
Long bytes = map.get(adrress);
List<Register> registers = configMap.get(adrress);
if(null != registers)
{
... ... @@ -61,7 +61,7 @@ public class AnalysisDataService {
}
}else{
logger.error("未读取到"+adrress+"的地址读取配置");
logger.debug("未读取到"+adrress+"的地址读取配置");
}
}
... ... @@ -74,11 +74,11 @@ public class AnalysisDataService {
}
private void registerTo(Map<String,Object> valueMap,byte[] bytes,Register register)
private void registerTo(Map<String,Object> valueMap,Long bytes,Register register)
{
String field = register.getField_name();
long value = ByteUtil.readBits(ByteUtil.bytesToLongDESC(bytes,0,2),register.getStart_char(),register.getChar_lenth());
long value = ByteUtil.readBits(bytes,register.getStart_char(),register.getChar_lenth());
switch (register.getClas())
{
... ...
... ... @@ -37,7 +37,12 @@ public class CameraService {
*/
private void openCapture()
{
videoCapture = OpenCVUtil.readVideoCaptureForVideo((Integer) configurationParameterService.getConfig(ConfigurationParameter.captureNumber));
// videoCapture = OpenCVUtil.readVideoCaptureForVideo((Integer) configurationParameterService.getConfig(ConfigurationParameter.captureNumber));
videoCapture = OpenCVUtil.openCapture();
if(null == videoCapture)
{
return;
}
monitorCapture();
// if (!videoIsOpen)
... ...
... ... @@ -5,7 +5,6 @@ import com.zhonglai.luhui.smart.feeder.domain.Register;
import com.zhonglai.luhui.smart.feeder.dto.ConfigurationParameter;
import com.zhonglai.luhui.smart.feeder.dto.FishCurveControlCondition;
import com.zhonglai.luhui.smart.feeder.dto.StateData;
import org.ehcache.Cache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
... ... @@ -21,7 +20,9 @@ import java.util.Map;
@Service
public class ConfigurationParameterService {
private Map<Integer,List<Register>> registerMap = new HashMap<>();
private Map<Integer,List<Register>> registerMap = new HashMap<>(); //解析的数据字典
private Map<String,Register> controlMap = new HashMap<>(); //控制的数据字典
@Autowired
private EhCacheService ehCacheService;
... ... @@ -67,10 +68,17 @@ public class ConfigurationParameterService {
}
list.add(register);
}
for (Map<String,Object> map:registerList)
{
Register register = BeanUtil.mapToBean(map,Register.class,false,null);
controlMap.put(register.getField_name(),register);
}
}
public Cache<String, Object> getAll()
}
public Map<String, Object> getAll()
{
return ehCacheService.getMyCache();
}
... ... @@ -167,6 +175,10 @@ public class ConfigurationParameterService {
return registerMap;
}
public Map<String, Register> getControlMap() {
return controlMap;
}
public StateData getStateData() {
return stateData;
}
... ...
... ... @@ -32,7 +32,7 @@ public class DateListenService {
private ScheduledExecutorService scheduledExecutorService;
@Autowired
private DeviceService deviceService;
private SerialPortService serialPortService;
@Autowired
private AnalysisDataService analysisDataService;
... ... @@ -47,18 +47,12 @@ public class DateListenService {
{
scheduledExecutorService.scheduleAtFixedRate(() -> {
if(!(Boolean) configurationParameterService.getConfig(ConfigurationParameter.ifUpLoadData))
if(null == configurationParameterService.getConfig(ConfigurationParameter.ifUpLoadData) || !(Boolean) configurationParameterService.getConfig(ConfigurationParameter.ifUpLoadData))
{
return;
}
try {
deviceService.openDefaultSerialPort();
} catch (Exception e) {
logger.error("串口打开失败",e);
return;
}
try {
ModbusDto modbusDto = deviceService.sendData(FeederCommdUtil.readAll());
ModbusDto modbusDto = serialPortService.sendHexData(FeederCommdUtil.readAll());
Map<String,Object> data = analysisDataService.analysis(modbusDto);
if(null != data && data.size() != 0)
{
... ...
package com.zhonglai.luhui.smart.feeder.service;
import com.ruoyi.common.utils.GsonConstructor;
import com.ruoyi.common.utils.StringUtils;
import com.zhonglai.luhui.smart.feeder.dto.*;
import com.zhonglai.luhui.smart.feeder.dto.commd.FeederCommdDto;
import com.zhonglai.luhui.smart.feeder.util.FeederCommd06ResponseType;
import com.zhonglai.luhui.smart.feeder.util.FeederCommdUtil;
import com.zhonglai.luhui.smart.feeder.util.serial.SerialTool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import purejavacomm.SerialPort;
import javax.annotation.PostConstruct;
import java.io.IOException;
import java.io.OutputStream;
import java.util.*;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
... ... @@ -29,11 +20,6 @@ import java.util.concurrent.TimeUnit;
public class DeviceService {
private static Logger logger = LoggerFactory.getLogger(DeviceService.class);
// 锁对象
private final Object lock = new Object();
// 用于存储串口返回的数据,使用线程安全的队列
private BlockingQueue<ModbusDto> dataQueue = new LinkedBlockingQueue<>();
private Double backArea; //上一个大小
private Double slope; //斜率
... ... @@ -57,7 +43,8 @@ public class DeviceService {
@Autowired
private EhCacheService ehCacheService;
private SerialPort serialPort;
@Autowired
private SerialPortService serialPortService;
public void run()
{
... ... @@ -72,22 +59,22 @@ public class DeviceService {
{
if(null !=configurationParameterService.getStateData() && 1==configurationParameterService.getStateData().getRunmode())
{
send485SerialData(FeederCommdUtil.controlData(FeederCommd06ResponseType.runmode,0)); //,运行模式改成手动
serialPortService.sendHexData(FeederCommdUtil.controlData(FeederCommd06ResponseType.runmode,0)); //,运行模式改成手动
}
if(null !=configurationParameterService.getStateData() && 0==configurationParameterService.getStateData().getSwitch_status())
{
send485SerialData(FeederCommdUtil.controlData(FeederCommd06ResponseType.OnOroff,1)); //,开关是关的就先打开开关
serialPortService.sendHexData(FeederCommdUtil.controlData(FeederCommd06ResponseType.OnOroff,1)); //,开关是关的就先打开开关
}
send485SerialData(FeederCommdUtil.controlData(FeederCommd06ResponseType.runspeed,nowGear));
serialPortService.sendHexData(FeederCommdUtil.controlData(FeederCommd06ResponseType.runspeed,nowGear));
oldGear = nowGear;
}else{
if(null !=configurationParameterService.getStateData() && 0==configurationParameterService.getStateData().getRunmode())
{
send485SerialData(FeederCommdUtil.controlData(FeederCommd06ResponseType.runmode,1)); //,运行模式改成自动
serialPortService.sendHexData(FeederCommdUtil.controlData(FeederCommd06ResponseType.runmode,1)); //,运行模式改成自动
}
if(null !=configurationParameterService.getStateData() && 1==configurationParameterService.getStateData().getSwitch_status())
{
send485SerialData(FeederCommdUtil.controlData(FeederCommd06ResponseType.OnOroff,0)); //,开关是关的就先打开开关
serialPortService.sendHexData(FeederCommdUtil.controlData(FeederCommd06ResponseType.OnOroff,0)); //,开关是关的就先打开开关
}
}
... ... @@ -137,20 +124,6 @@ public class DeviceService {
return absValue;
}
private void send485SerialData(String commd)
{
if(null == serialPort)
{
openSerialPort();
}
try {
sendData(commd);
} catch (IOException e) {
logger.error("串口指令发送错误",e);
}
}
/**
* 根据斜率计算档位
* @return
... ... @@ -174,107 +147,4 @@ public class DeviceService {
return gear;
}
public void openSerialPort()
{
SerialPortConfig serialPortConfig = (SerialPortConfig) configurationParameterService.getConfig(ConfigurationParameter.SerialPortConfig);
try {
openSerialPort(serialPortConfig.getPortName(),serialPortConfig.getBaudrate(),serialPortConfig.getDataBits(),serialPortConfig.getStopBits(),serialPortConfig.getParity());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 获取所有串口
* @return
*/
public ArrayList<String> getAllSerial()
{
return SerialTool.findPorts();
}
/**
* 打开串口
* @param portName 串口名称
* @param baudrate 波特率,用于指定每秒传输的位数。
* @param dataBits 数据位,表示每个字节的位数。常见的值为 5、6、7、8。
* @param stopBits 停止位,用于指定每个字节的停止位数。
* @param parity 校验位,用于验证数据的正确性。常见的值有 NONE(无校验)、ODD(奇校验)、EVEN(偶校验)等。
* @throws Exception
*/
public void openSerialPort(String portName, Integer baudrate, Integer dataBits, Integer stopBits,
Integer parity) throws Exception {
if(null != serialPort)
{
return;
}
serialPort = SerialTool.openPort(portName,baudrate,dataBits,stopBits,parity);
SerialTool.addListener(serialPortEvent -> {
try {
Thread.sleep(500);
FeederCommdDto commdDto = new FeederCommdDto (SerialTool.readFromPort(serialPort));
dataQueue.offer(commdDto); // 将数据添加到队列中// 处理串口返回的数据
} catch (Exception e) {
logger.error("返回数据处理异常",e);
}
}, serialPort);
logger.info("打开串口成功");
}
public void nowOpenSerial(String portName, Integer baudrate, Integer dataBits, Integer stopBits,
Integer parity) throws Exception {
if(null != serialPort)
{
serialPort.removeEventListener();
serialPort.close();
}
serialPort = SerialTool.openPort(portName,baudrate,dataBits,stopBits,parity);
SerialTool.addListener(serialPortEvent -> {
try {
Thread.sleep(500);
FeederCommdDto commdDto = new FeederCommdDto (SerialTool.readFromPort(serialPort));
dataQueue.offer(commdDto); // 将数据添加到队列中// 处理串口返回的数据
} catch (Exception e) {
logger.error("返回数据处理异常",e);
}
}, serialPort);
}
public void openDefaultSerialPort() throws Exception {
SerialPortConfig serialPortConfig = (SerialPortConfig) configurationParameterService.getConfig(ConfigurationParameter.SerialPortConfig);
openSerialPort(serialPortConfig.getPortName(),serialPortConfig.getBaudrate(),serialPortConfig.getDataBits(),serialPortConfig.getStopBits(),serialPortConfig.getParity());
}
/**
* 发送数据
* @param hexStr
* @throws IOException
*/
public ModbusDto sendData(String hexStr) throws IOException {
synchronized (lock)
{
SerialTool.sendToPort(SerialTool.HexString2Bytes(hexStr),serialPort);
try {
ModbusDto reStr = dataQueue.poll(15,TimeUnit.SECONDS);
return reStr;
} catch (InterruptedException e) {
logger.error("等待串口返回数据异常!" + e);
}
}
return null;
}
public void close()
{
dataQueue.clear();
if(null != serialPort)
{
serialPort.removeEventListener();
serialPort.close();
}
}
}
... ...
... ... @@ -3,86 +3,43 @@ package com.zhonglai.luhui.smart.feeder.service;
import com.ruoyi.common.utils.GsonConstructor;
import com.zhonglai.luhui.smart.feeder.dto.ConfigurationParameter;
import com.zhonglai.luhui.smart.feeder.dto.SerialPortConfig;
import org.ehcache.Cache;
import org.ehcache.CacheManager;
import org.ehcache.config.CacheConfiguration;
import org.ehcache.config.ResourcePools;
import org.ehcache.config.builders.CacheConfigurationBuilder;
import org.ehcache.config.builders.CacheManagerBuilder;
import org.ehcache.config.builders.ResourcePoolsBuilder;
import org.ehcache.config.units.MemoryUnit;
import org.ehcache.impl.serialization.PlainJavaSerializer;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.io.File;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
/**
* 缓存
*/
@Service
public class EhCacheService {
private static Cache<String, Object> myCache;
private static Map<String,Object> cacheMap = new HashMap<>();
private static CacheManager cacheManager;
public static final String MY_CACHE = "myCache";
@Value("${sys.cacheFilePath}")
private String cacheFilePath;
public void instance()
{
cacheManager = CacheManagerBuilder.newCacheManagerBuilder()
.with(CacheManagerBuilder.persistence(new File(cacheFilePath)))
.build(true);
if (cacheManager.getRuntimeConfiguration().getCacheConfigurations().containsKey(MY_CACHE))
{
// 缓存对象存在,直接读取
myCache = cacheManager.getCache(MY_CACHE, String.class, Object.class);
}else {
// 指定缓存的存储形式,采用多级缓存,并开启缓存持久化操作
ResourcePools resourcePools = ResourcePoolsBuilder.newResourcePoolsBuilder()
.heap(1, MemoryUnit.MB)
.disk(2, MemoryUnit.MB, true)
.build();
// 封装缓存配置对象,指定了键值类型、指定了使用TTL与TTI联合的过期淘汰策略
CacheConfiguration<String, Object> cacheConfiguration =
CacheConfigurationBuilder.newCacheConfigurationBuilder(String.class, Object.class, resourcePools)
.withValueSerializer(new PlainJavaSerializer<>(this.getClass().getClassLoader()))
.build();
// 使用给定的配置参数,创建指定名称的缓存对象
myCache = cacheManager.createCache(MY_CACHE, cacheConfiguration);
}
}
public void writeToCache(ConfigurationParameter key, Object value) {
Class cls = key.getValuType();
if(cls.isInstance(value))
{
myCache.put(key.name(), cls.cast(value));
cacheMap.put(key.name(), cls.cast(value));
}else if(value instanceof String)
{
switch (cls.getName())
{
case "java.lang.Boolean":
myCache.put(key.name(), Boolean.valueOf((String) value));
cacheMap.put(key.name(), Boolean.valueOf((String) value));
return;
case "java.lang.Integer":
myCache.put(key.name(), Integer.valueOf((String) value));
cacheMap.put(key.name(), Integer.valueOf((String) value));
return;
case "java.lang.Double":
myCache.put(key.name(), Double.valueOf((String) value));
cacheMap.put(key.name(), Double.valueOf((String) value));
return;
case "java.lang.Long":
cacheMap.put(key.name(), Long.valueOf((String) value));
return;
case "com.zhonglai.luhui.smart.feeder.dto.SerialPortConfig":
SerialPortConfig serialPortConfig = GsonConstructor.get().fromJson((String) value,SerialPortConfig.class);
myCache.put(key.name(), serialPortConfig);
cacheMap.put(key.name(), serialPortConfig);
return;
default:
throw new RuntimeException("配置参数类型不正确"+key+value);
... ... @@ -94,16 +51,16 @@ public class EhCacheService {
}
public Object readFromCache(ConfigurationParameter key) {
return myCache.get(key.name());
return cacheMap.get(key.name());
}
public Cache<String, Object> getMyCache() {
return myCache;
public Map<String, Object> getMyCache() {
return cacheMap;
}
public void shutdown() {
if (cacheManager != null) {
cacheManager.close();
if (cacheMap != null) {
cacheMap.clear();
}
}
}
... ...
package com.zhonglai.luhui.smart.feeder.service;
import org.springframework.stereotype.Service;
@Service
public class FeederDeviceService {
}
package com.zhonglai.luhui.smart.feeder.service;
import com.zhonglai.luhui.smart.feeder.config.WebSocketClien;
import com.zhonglai.luhui.smart.feeder.dto.ConfigurationParameter;
import com.zhonglai.luhui.smart.feeder.dto.VeiwDto;
import com.zhonglai.luhui.smart.feeder.dto.VeiwType;
... ... @@ -137,23 +138,27 @@ public class FishGroupImageRecognitionService {
logger.info("鱼群识别时检测摄像头");
// 获取水域轮廓
MatOfPoint largestContour = getDefaultMatOfPoint(previousFrame);
Long time =1000l;
if(null != configurationParameterService.getConfig(ConfigurationParameter.IdentificationFrequency))
{
time = (Long) configurationParameterService.getConfig(ConfigurationParameter.IdentificationFrequency);
}
// 逐帧处理视频
Mat frame = new Mat();
scheduledExecutorService.scheduleWithFixedDelay(() -> {
try {
logger.info("逐帧处理视频");
if (((Boolean)configurationParameterService.getConfig(ConfigurationParameter.FishGroupImageRecognition)) && videoCapture.read(frame)) {
logger.info("开始逐帧处理视频");
identify(frame,largestContour);
logger.info("结束逐帧处理视频");
}
}catch (Exception e)
{
logger.error("检测摄像头异常",e);
}
},0,1, TimeUnit.SECONDS);
},0,time, TimeUnit.MILLISECONDS);
}
/**
* 识别
* @param frame
... ... @@ -190,12 +195,13 @@ public class FishGroupImageRecognitionService {
configurationParameterService.setConfig(ConfigurationParameter.absValue,absValue);
// 显示图像
logger.info("是否显示{},客户端数量{}",configurationParameterService.getConfig(ConfigurationParameter.ifVeiw),WebSocketClien.webSocketSet.size());
// 在图像上显示结果
if((Boolean)configurationParameterService.getConfig(ConfigurationParameter.ifVeiw))
if((Boolean)configurationParameterService.getConfig(ConfigurationParameter.ifVeiw) && WebSocketClien.webSocketSet.size()>0)
{
logger.info("socket数量{}",WebSocketClien.webSocketSet.size());
dsplayVeiwService.veiw(new VeiwDto(frame,binaryImage,new Double(area).intValue(),absValue));
}
}
/**
... ... @@ -220,8 +226,6 @@ public class FishGroupImageRecognitionService {
//删除最大
if(-1 != maxAreaIndex)
{
double area = Imgproc.contourArea(contours.get(maxAreaIndex));
contours.remove(maxAreaIndex);
}
... ...
... ... @@ -38,8 +38,6 @@ public class InitService {
*/
@PostConstruct
private void run() throws MqttException {
//加载缓存
ehCacheService.instance();
//持久化初始
sqliteService.init();
//配置参数
... ... @@ -51,7 +49,7 @@ public class InitService {
//鱼群图像识别控制投料控制
deviceService.run();
//连接上报终端
terminalService.init();
terminalService.startMqttListenerService();
//串口数据上报
dateListenService.run();
}
... ...
package com.zhonglai.luhui.smart.feeder.service;
import com.google.gson.JsonObject;
import com.ruoyi.common.utils.GsonConstructor;
import com.zhonglai.luhui.smart.feeder.domain.Register;
import com.zhonglai.luhui.smart.feeder.dto.commd.FeederCommd06Response;
import com.zhonglai.luhui.smart.feeder.dto.commd.FeederCommdDto;
import com.zhonglai.luhui.smart.feeder.dto.commd.FeederTimer;
import com.zhonglai.luhui.smart.feeder.util.FeederCommdUtil;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallbackExtended;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Component
public class MqttCallback implements MqttCallbackExtended {
@Autowired
private ConfigurationParameterService configurationParameterService;
@Autowired
private SerialPortService serialPortService;
private static final Logger log = LoggerFactory.getLogger(MqttCallback.class);
@Override
... ... @@ -26,15 +44,53 @@ public class MqttCallback implements MqttCallbackExtended {
@Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
log.info("收到消息 {}",message);
if(topic.indexOf("PUT")>=0)
{
Map<String, Register> map = configurationParameterService.getControlMap();
byte[] bs = message.getPayload();
if(null != bs && bs.length!=0)
{
String str = new String(bs);
JsonObject jsonObject = GsonConstructor.get().fromJson(str, JsonObject.class);
if(jsonObject.has("1"))
{
JsonObject controlData = jsonObject.get("1").getAsJsonObject();
Map<Integer, FeederTimer> timerMap = new HashMap<>();
for (String key:controlData.keySet())
{
if(key.startsWith("timer"))
{
Integer timerNumber = Integer.parseInt(key.split("_")[0].replace("timer",""));
FeederTimer feederTimer = timerMap.get(timerNumber);
if(null == feederTimer)
{
feederTimer = new FeederTimer();
timerMap.put(timerNumber,feederTimer);
}
feederTimer.setObjectValue(key.replace(""+timerNumber+"",""),Long.valueOf(controlData.get(key).getAsString()));
}else {
Register register = map.get(key);
serialPortService.sendHexData(new FeederCommdDto(new FeederCommd06Response(register.getAddress(),controlData.get(key).getAsInt())).getHstr());
}
}
if(null != timerMap && timerMap.size() != 0)
{
for (Integer timerNumber:timerMap.keySet())
{
serialPortService.sendHexData(FeederCommdUtil.controlTimer(timerNumber,timerMap.get(timerNumber)));
}
}
}
}
}
}
@Override
public void deliveryComplete(IMqttDeliveryToken token) {
// 成功发出消息
try {
log.info("成功发出消息 messageid{}",token.getMessage());
} catch (MqttException e) {
e.printStackTrace();
}
log.info("成功发出消息 messageid{}",token);
}
}
... ...
package com.zhonglai.luhui.smart.feeder.service;
import com.fazecast.jSerialComm.SerialPort;
import com.fazecast.jSerialComm.SerialPortDataListener;
import com.fazecast.jSerialComm.SerialPortEvent;
import com.ruoyi.common.utils.ByteUtil;
import com.zhonglai.luhui.smart.feeder.dto.ConfigurationParameter;
import com.zhonglai.luhui.smart.feeder.dto.ModbusDto;
import com.zhonglai.luhui.smart.feeder.dto.SerialPortConfig;
import com.zhonglai.luhui.smart.feeder.dto.commd.FeederCommdDto;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
@Service
public class SerialPortService {
private static final Logger logger = LoggerFactory.getLogger(SerialPortService.class);
private SerialPort serialPort;
// 锁对象
private final Object lock = new Object();
// 用于存储串口返回的数据,使用线程安全的队列
private BlockingQueue<ModbusDto> dataQueue = new LinkedBlockingQueue<>();
@Autowired
private ConfigurationParameterService configurationParameterService;
public void init()
{
open();
}
private SerialPort findSerialPort()
{
SerialPort serialPort = null;
SerialPort[] serialPorts = SerialPort.getCommPorts();//查找所有串口
for(SerialPort port:serialPorts){
System.out.println("Port:"+port.getSystemPortName());//打印串口名称,如COM4
System.out.println("PortDesc:"+port.getPortDescription());//打印串口类型,如USB Serial
System.out.println("PortDesc:"+port.getDescriptivePortName());//打印串口的完整类型,如USB-SERIAL CH340(COM4)
if(port.getPortDescription().indexOf("USB")>=0)
{
serialPort = port;
break;
}
}
return serialPort;
}
private void setComPortParameters()
{
SerialPortConfig serialPortConfig = (SerialPortConfig)configurationParameterService.getConfig(ConfigurationParameter.SerialPortConfig);
serialPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_BLOCKING | SerialPort.TIMEOUT_WRITE_BLOCKING, 1000, 1000);//设置超时
serialPort.setFlowControl(SerialPort.FLOW_CONTROL_DISABLED);//设置串口的控制流,可以设置为disabled,或者CTS, RTS/CTS, DSR, DTR/DSR, Xon, Xoff, Xon/Xoff等
serialPort.setComPortParameters(serialPortConfig.getBaudrate(), serialPortConfig.getDataBits(), serialPortConfig.getStopBits(), serialPortConfig.getParity());//一次性设置所有的串口参数,第一个参数为波特率,默认9600;第二个参数为每一位的大小,默认8,可以输入5到8之间的值;第三个参数为停止位大小,只接受内置常量,可以选择(ONE_STOP_BIT, ONE_POINT_FIVE_STOP_BITS, TWO_STOP_BITS);第四位为校验位,同样只接受内置常量,可以选择 NO_PARITY, EVEN_PARITY, ODD_PARITY, MARK_PARITY,SPACE_PARITY。
}
public boolean open()
{
if(null == serialPort || !serialPort.isOpen())
{
serialPort = findSerialPort();
setComPortParameters();
}
if(null == serialPort)
{
logger.error("没有找到串口");
return false;
}
if(!serialPort.isOpen()){
boolean isCommOpeded = serialPort.openPort();//判断串口是否打开,如果没打开,就打开串口。打开串口的函数会返回一个boolean值,用于表明串口是否成功打开了
addLister();
return isCommOpeded;
}
return true;
}
private void addLister()
{
if(serialPort.isOpen()){
serialPort.addDataListener(new SerialPortDataListener() {//添加监听器。由于该监听器有两个函数,无法使用Lambda表达式
@Override
public int getListeningEvents() {
// TODO Auto-generated method stub
return SerialPort.LISTENING_EVENT_DATA_AVAILABLE;//返回要监听的事件类型,以供回调函数使用。可发回的事件包括:SerialPort.LISTENING_EVENT_DATA_AVAILABLE,SerialPort.LISTENING_EVENT_DATA_WRITTEN,SerialPort.LISTENING_EVENT_DATA_RECEIVED。分别对应有数据在串口(不论是读的还是写的),有数据写入串口,从串口读取数据。如果AVAILABLE和RECEIVED同时被监听,优先触发RECEIVED
}
@Override
public void serialEvent(SerialPortEvent event) {//事件处理函数
// TODO Auto-generated method stub
String data = "";
if (event.getEventType() != SerialPort.LISTENING_EVENT_DATA_AVAILABLE){
return;//判断事件的类型
}
SerialPort port = event.getSerialPort();
try {
Thread.sleep(500);
FeederCommdDto commdDto = new FeederCommdDto(readFromPort(port));
dataQueue.offer(commdDto); // 将数据添加到队列中// 处理串口返回的数据
} catch (Exception e) {
logger.error("返回数据处理异常",e);
}
}
});
}
}
public boolean close()
{
dataQueue.clear();
if(null != serialPort)
{
return serialPort.closePort();//关闭串口。该函数同样会返回一个boolean值,表明串口是否成功关闭
}
return true;
}
/**
* 发送16进制数据
* @param hexStr
* @throws IOException
*/
public ModbusDto sendHexData(String hexStr) {
byte[] bytes = ByteUtil.hexStringToByte(hexStr.replace(" ","").trim().toUpperCase());
return sendByte(bytes);
}
/**
* 发送支持中文的字符串
* @param str
* @throws IOException
*/
public ModbusDto sendStrData(String str) {
return sendByte(str.getBytes(StandardCharsets.UTF_8));
}
/**
* 发送byte数组
* @param bytes
* @return
*/
public ModbusDto sendByte(byte[] bytes)
{
synchronized (lock)
{
if(open())
{
serialPort.writeBytes(bytes,bytes.length);
try {
ModbusDto reStr = dataQueue.poll(15, TimeUnit.SECONDS);
return reStr;
} catch (InterruptedException e) {
logger.error("等待串口返回数据异常!" + e);
}
}else{
logger.error("串口未打开!" );
return null;
}
}
return null;
}
private static byte[] readFromPort(SerialPort serialPort) throws Exception {
InputStream in = null;
byte[] bytes = null;
try {
if (serialPort != null) {
in = serialPort.getInputStream();
} else {
return null;
}
int bufflenth = in.available(); // 获取buffer里的数据长度
while (bufflenth > 0) {
bytes = new byte[bufflenth]; // 初始化byte数组为buffer中数据的长度
in.read(bytes);
bufflenth = in.available();
}
} catch (Exception e) {
throw e;
} finally {
try {
if (in != null) {
in.close();
}
} catch (IOException e) {
throw e;
}
}
return bytes;
}
}
... ...
... ... @@ -49,7 +49,6 @@ public class TerminalService {
@Value("${mqtt.password}")
private String password;
@PostConstruct
public void startMqttListenerService() throws MqttException{
log.info("-----------开始启动mqtt监听服务--------------------");
init();
... ... @@ -108,7 +107,13 @@ public class TerminalService {
public void close()
{
try {
options.setAutomaticReconnect(false);
if(null != mqttclient && mqttclient.isConnected())
{
mqttclient.disconnect();
mqttclient.close();
}
} catch (MqttException e) {
log.error("关闭失败",e);
}
... ...
package com.zhonglai.luhui.smart.feeder.util.serial;
import purejavacomm.SerialPort;
import java.util.HashMap;
import java.util.Map;
public class GlobalCache {
public static Map<String,Boolean> bmap = new HashMap<>();
public static Map<String, byte[]> dmap = new HashMap<>();
public static Map<String, SerialPort> smap = new HashMap<>();
}
package com.zhonglai.luhui.smart.feeder.util.serial;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import purejavacomm.SerialPort;
import purejavacomm.SerialPortEvent;
import purejavacomm.SerialPortEventListener;
import java.io.IOException;
public class SerialResquest {
private static Logger logger = LoggerFactory.getLogger(SerialResquest.class);
public static void resquest(String portName, Integer baudrate, Integer dataBits, Integer stopBits,
Integer parity,byte[] data) throws Exception {
SerialPort serialPort;
if (!GlobalCache.smap.containsKey(portName)) {
GlobalCache.bmap.put(portName, false);
serialPort = SerialTool.openPort(portName, baudrate, dataBits, stopBits, parity);
GlobalCache.smap.put(portName, serialPort);
SerialTool.addListener(new SerialPortEventListener() {
@Override
public void serialEvent(SerialPortEvent event) {
try {
Thread.sleep(50);
} catch (InterruptedException e1) {
logger.error("SerialResquest 监听异常!"+e1);
}
switch (event.getEventType()) {
case SerialPortEvent.DATA_AVAILABLE:
byte[] readBuffer = null;
int availableBytes = 0;
try {
availableBytes = serialPort.getInputStream().available();
if (availableBytes > 0) {
try {
readBuffer = SerialTool.readFromPort(serialPort);
GlobalCache.bmap.put(portName, true);
GlobalCache.dmap.put(portName, readBuffer);
} catch (Exception e) {
logger.error("读取推送信息异常!"+e);
}
}
} catch (IOException e) {
logger.error("读取流信息异常!"+e);
}
}
}
}, serialPort);
}else {
serialPort = GlobalCache.smap.get(portName);
}
SerialTool.sendToPort(data, serialPort);
}
public static byte[] response(String portName) throws InterruptedException {
/*if (!GlobalCache.dmap.containsKey(portName)) {
return null;
}*/
Thread.sleep(100);
int i =0;
while (!GlobalCache.bmap.get(portName)) {
Thread.sleep(100);
if (i++>30) {
return new byte[0];
}
}
GlobalCache.bmap.put(portName, false);
return GlobalCache.dmap.get(portName);
}
public static void close(String portName) throws IOException {
SerialTool.closePort(GlobalCache.smap.get(portName));
GlobalCache.smap.remove(portName);
}
}
package com.zhonglai.luhui.smart.feeder.util.serial;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.TooManyListenersException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import purejavacomm.CommPort;
import purejavacomm.CommPortIdentifier;
import purejavacomm.NoSuchPortException;
import purejavacomm.PortInUseException;
import purejavacomm.SerialPort;
import purejavacomm.SerialPortEventListener;
import purejavacomm.UnsupportedCommOperationException;
public class SerialTool {
private static Logger logger = LoggerFactory.getLogger(SerialTool.class);
public static final ArrayList<String> findPorts() {
// 获得当前所有可用串口
Enumeration<CommPortIdentifier> portList = CommPortIdentifier.getPortIdentifiers();
ArrayList<String> portNameList = new ArrayList<String>();
// 将可用串口名添加到List并返回该List
while (portList.hasMoreElements()) {
String portName = portList.nextElement().getName();
portNameList.add(portName);
}
return portNameList;
}
/**
* 打开串口
*
* @param portName
* 端口名称
* @param baudrate
* 波特率
* @return 串口对象
* @throws Exception
// * @throws SerialPortParameterFailure
// * 设置串口参数失败
// * @throws NotASerialPort
// * 端口指向设备不是串口类型
// * @throws NoSuchPort
// * 没有该端口对应的串口设备
// * @throws PortInUse
// * 端口已被占用
*/
public static SerialPort openPort(String portName, Integer baudrate, Integer dataBits, Integer stopBits,
Integer parity) throws Exception {
try {
// 通过端口名识别端口
CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName);
if(portIdentifier.isCurrentlyOwned())
{
throw new RuntimeException("串口已被占用");
}
// 打开端口,并给端口名字和一个timeout(打开操作的超时时间)
CommPort commPort = portIdentifier.open(portName, 2000);
// 判断是不是串口
if (commPort instanceof SerialPort) {
SerialPort serialPort = (SerialPort) commPort;
try {
// 设置一下串口的波特率等参数
serialPort.setSerialPortParams(baudrate, dataBits, stopBits, parity);
} catch (UnsupportedCommOperationException e) {
logger.error("设置串口" + portName + "参数失败:" + e.getMessage());
throw e;
}
return serialPort;
} else {
logger.error("不是串口" + portName);
// 不是串口
throw new Exception();
}
} catch (NoSuchPortException e1) {
logger.error("无此串口" + portName);
throw e1;
} catch (PortInUseException e2) {
logger.error("串口使用中" + portName);
throw e2;
} catch (Exception e) {
throw e;
}
}
/**
* 将字节数组转换为16进制字符串,并在每个字符之间用空格分隔
* @param byteArray
* @return
*/
public static String bytesToHexString(byte[] byteArray) {
StringBuilder sb = new StringBuilder();
for (byte b : byteArray) {
// 将每个字节转换为两位的16进制字符串
String hex = String.format("%02X", b);
sb.append(hex);
// 在每个字符之间添加空格
sb.append(" ");
}
// 删除最后一个空格
sb.deleteCharAt(sb.length() - 1);
return sb.toString();
}
public static byte[] HexString2Bytes(String src) {
if (null == src || 0 == src.length()) {
return null;
}
byte[] ret = new byte[src.length() / 2];
byte[] tmp = src.getBytes();
for (int i = 0; i < (tmp.length / 2); i++) {
ret[i] = uniteBytes(tmp[i * 2], tmp[i * 2 + 1]);
}
return ret;
}
// byte类型数据,转成十六进制形式;
public static byte uniteBytes(byte src0, byte src1) {
byte _b0 = Byte.decode("0x" + new String(new byte[] { src0 })).byteValue();
_b0 = (byte) (_b0 << 4);
byte _b1 = Byte.decode("0x" + new String(new byte[] { src1 })).byteValue();
byte ret = (byte) (_b0 ^ _b1);
return ret;
}
/**
* 关闭串口
*
* @throws IOException
*/
public static synchronized void closePort(SerialPort serialPort) throws IOException {
if (serialPort != null) {
serialPort.close();
logger.info("串口" + serialPort.getName() + "已关闭");
}
}
public static OutputStream getSerialPortStream( SerialPort serialPort) throws IOException {
return serialPort.getOutputStream();
}
public static void sendToPort(byte[] order, OutputStream out) throws IOException {
out.write(order);
out.flush();
}
/**
* 往串口发送数据
*
* @param order
* 待发送数据
// * @throws SendDataToSerialPortFailure
// * 向串口发送数据失败
// * @throws SerialPortOutputStreamCloseFailure
// * 关闭串口对象的输出流出错
*/
public static void sendToPort(byte[] order, SerialPort serialPort) throws IOException {
OutputStream out = null;
try {
out = serialPort.getOutputStream();
if(null == out)
{
logger.error("窗口未打开" );
}
out.write(order);
out.flush();
logger.info("发送数据成功" + serialPort.getName());
} catch (IOException e) {
logger.error("发送数据失败" + serialPort.getName());
throw e;
} finally {
try {
if (out != null) {
out.close();
}
} catch (IOException e) {
logger.error("关闭串口对象的输出流出错");
throw e;
}
}
}
/**
* 从串口读取数据
*
* @param serialPort
* 当前已建立连接的SerialPort对象
* @return 读取到的数据
// * @throws ReadDataFromSerialPortFailure
// * 从串口读取数据时出错
// * @throws SerialPortInputStreamCloseFailure
// * 关闭串口对象输入流出错
*/
public static byte[] readFromPort(SerialPort serialPort) throws Exception {
InputStream in = null;
byte[] bytes = null;
try {
if (serialPort != null) {
in = serialPort.getInputStream();
} else {
return null;
}
int bufflenth = in.available(); // 获取buffer里的数据长度
while (bufflenth != 0) {
bytes = new byte[bufflenth]; // 初始化byte数组为buffer中数据的长度
in.read(bytes);
bufflenth = in.available();
}
} catch (Exception e) {
throw e;
} finally {
try {
if (in != null) {
in.close();
in = null;
}
} catch (IOException e) {
throw e;
}
}
return bytes;
}
/**
* 添加监听器
*
// * @param port
// * 串口对象
* @param listener
* 串口监听器
// * @throws TooManyListeners
// * 监听类对象过多
*/
public static void addListener(SerialPortEventListener listener, SerialPort serialPort) throws TooManyListenersException {
try {
if(null == serialPort)
{
throw new RuntimeException("端口未初始化");
}
// 给串口添加监听器
serialPort.addEventListener(listener);
// 设置当有数据到达时唤醒监听接收线程
serialPort.notifyOnDataAvailable(true);
// 设置当通信中断时唤醒中断线程
serialPort.notifyOnBreakInterrupt(true);
} catch (TooManyListenersException e) {
throw e;
}
}
}
# 开发环境配置 server: # 服务器的HTTP端口,默认为8080 port: 8064 servlet: # 应用的访问路径 context-path: / tomcat: # tomcat的URI编码 uri-encoding: UTF-8 # 连接数满后的排队数,默认为100 accept-count: 1000 threads: # tomcat最大线程数,默认为200 max: 800 # Tomcat启动初始化的线程数,默认值10 min-spare: 100 # 日志配置 logging: level: com.ruoyi: debug org.springframework: warn # Swagger配置 swagger: # 是否开启swagger enabled: true # 请求前缀 pathMapping: /dev-api # 防止XSS攻击 xss: # 过滤开关 enabled: true # 排除链接(多个用逗号分隔) excludes: /system/notice # 匹配链接 urlPatterns: /system/*,/monitor/*,/tool/* sys: staticPath: "file:/opt/lh-smart-feeder/lh-smart-feeder/html/" cacheFilePath: "E:/opt/lh-smart-feeder/lh-smart-feeder/cache/" # MyBatis配置 mybatis: # 搜索指定包别名 typeAliasesPackage: com.ruoyi.**.domain,com.zhonglai.**.domain # 配置mapper的扫描,找到所有的mapper.xml映射文件 mapperLocations: classpath*:mapper/**/*Mapper.xml # 加载全局的配置文件 configLocation: classpath:mybatis/mybatis-config.xml # 数据源配置 spring: # autoconfigure: # exclude: org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration datasource: type: com.alibaba.druid.pool.DruidDataSource driverClassName: org.sqlite.JDBC druid: # 主库数据源 master: url: jdbc:sqlite:db/my.db username: password: # 从库数据源 slave: # 从数据源开关/默认关闭 enabled: false url: username: password: # 初始连接数 initialSize: 5 # 最小连接池数量 minIdle: 10 # 最大连接池数量 maxActive: 20 # 配置获取连接等待超时的时间 maxWait: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 timeBetweenEvictionRunsMillis: 60000 # 配置一个连接在池中最小生存的时间,单位是毫秒 minEvictableIdleTimeMillis: 300000 # 配置一个连接在池中最大生存的时间,单位是毫秒 maxEvictableIdleTimeMillis: 900000 # 配置检测连接是否有效 validationQuery: SELECT 1 testWhileIdle: true testOnBorrow: false testOnReturn: false webStatFilter: enabled: true statViewServlet: enabled: true # 设置白名单,不填则允许所有访问 allow: url-pattern: /druid/* # 控制台管理用户名和密码 login-username: ruoyi login-password: 123456 filter: stat: enabled: true # 慢SQL记录 log-slow-sql: true slow-sql-millis: 1000 merge-sql: true wall: config: multi-statement-allow: true ## 数据源配置 #spring: # datasource: # type: com.alibaba.druid.pool.DruidDataSource # driverClassName: com.mysql.cj.jdbc.Driver # druid: # # 主库数据源 # master: # url: jdbc:mysql://rm-wz9740un21f09iokuao.mysql.rds.aliyuncs.com:3306/mqtt_broker?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 # username: luhui # password: Luhui586 # # 从库数据源 # slave: # # 从数据源开关/默认关闭 # enabled: true # url: jdbc:mysql://119.23.218.181:3306/lh-server-ops?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 # username: luhui # password: Luhui586 # # 初始连接数 # initialSize: 5 # # 最小连接池数量 # minIdle: 10 # # 最大连接池数量 # maxActive: 20 # # 配置获取连接等待超时的时间 # maxWait: 60000 # # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 # timeBetweenEvictionRunsMillis: 60000 # # 配置一个连接在池中最小生存的时间,单位是毫秒 # minEvictableIdleTimeMillis: 300000 # # 配置一个连接在池中最大生存的时间,单位是毫秒 # maxEvictableIdleTimeMillis: 900000 # # 配置检测连接是否有效 # validationQuery: SELECT 1 FROM DUAL # testWhileIdle: true # testOnBorrow: false # testOnReturn: false # webStatFilter: # enabled: true # statViewServlet: # enabled: true # # 设置白名单,不填则允许所有访问 # allow: # url-pattern: /druid/* # # 控制台管理用户名和密码 # login-username: ruoyi # login-password: 123456 # filter: # stat: # enabled: true # # 慢SQL记录 # log-slow-sql: true # slow-sql-millis: 1000 # merge-sql: true # wall: # config: # multi-statement-allow: true mqtt: #链接地址 broker: tcp://175.24.61.68:1883 #唯一标识 clientId: 70094a59d1d991d #公司id roleid: 2 mqtt_usernames: 12_ZNZY #订阅的topic topics: PUT/+,GET_REQ/+, READ/+,POST_REQ/+ sub_clientid: '70094a59d1d991d' username: 12_ZNZY password: Luhui586 client: #客户端操作时间 operationTime: 10
\ No newline at end of file
# 开发环境配置 server: # 服务器的HTTP端口,默认为8080 port: 8064 servlet: # 应用的访问路径 context-path: / tomcat: # tomcat的URI编码 uri-encoding: UTF-8 # 连接数满后的排队数,默认为100 accept-count: 1000 threads: # tomcat最大线程数,默认为200 max: 800 # Tomcat启动初始化的线程数,默认值10 min-spare: 100 # 日志配置 logging: level: com.ruoyi: debug org.springframework: warn # Swagger配置 swagger: # 是否开启swagger enabled: true # 请求前缀 pathMapping: /dev-api # 防止XSS攻击 xss: # 过滤开关 enabled: true # 排除链接(多个用逗号分隔) excludes: /system/notice # 匹配链接 urlPatterns: /system/*,/monitor/*,/tool/* sys: staticPath: "file:/opt/lh-smart-feeder/lh-smart-feeder/html/" cacheFilePath: "E:/opt/lh-smart-feeder/lh-smart-feeder/cache/" # MyBatis配置 mybatis: # 搜索指定包别名 typeAliasesPackage: com.ruoyi.**.domain,com.zhonglai.**.domain # 配置mapper的扫描,找到所有的mapper.xml映射文件 mapperLocations: classpath*:mapper/**/*Mapper.xml # 加载全局的配置文件 configLocation: classpath:mybatis/mybatis-config.xml # 数据源配置 spring: # autoconfigure: # exclude: org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration datasource: type: com.alibaba.druid.pool.DruidDataSource driverClassName: org.sqlite.JDBC druid: # 主库数据源 master: url: jdbc:sqlite:db/my.db username: password: # 从库数据源 slave: # 从数据源开关/默认关闭 enabled: false url: username: password: # 初始连接数 initialSize: 5 # 最小连接池数量 minIdle: 10 # 最大连接池数量 maxActive: 20 # 配置获取连接等待超时的时间 maxWait: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 timeBetweenEvictionRunsMillis: 60000 # 配置一个连接在池中最小生存的时间,单位是毫秒 minEvictableIdleTimeMillis: 300000 # 配置一个连接在池中最大生存的时间,单位是毫秒 maxEvictableIdleTimeMillis: 900000 # 配置检测连接是否有效 validationQuery: SELECT 1 testWhileIdle: true testOnBorrow: false testOnReturn: false webStatFilter: enabled: true statViewServlet: enabled: true # 设置白名单,不填则允许所有访问 allow: url-pattern: /druid/* # 控制台管理用户名和密码 login-username: ruoyi login-password: 123456 filter: stat: enabled: true # 慢SQL记录 log-slow-sql: true slow-sql-millis: 1000 merge-sql: true wall: config: multi-statement-allow: true ## 数据源配置 #spring: # datasource: # type: com.alibaba.druid.pool.DruidDataSource # driverClassName: com.mysql.cj.jdbc.Driver # druid: # # 主库数据源 # master: # url: jdbc:mysql://rm-wz9740un21f09iokuao.mysql.rds.aliyuncs.com:3306/mqtt_broker?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 # username: luhui # password: Luhui586 # # 从库数据源 # slave: # # 从数据源开关/默认关闭 # enabled: true # url: jdbc:mysql://119.23.218.181:3306/lh-server-ops?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 # username: luhui # password: Luhui586 # # 初始连接数 # initialSize: 5 # # 最小连接池数量 # minIdle: 10 # # 最大连接池数量 # maxActive: 20 # # 配置获取连接等待超时的时间 # maxWait: 60000 # # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 # timeBetweenEvictionRunsMillis: 60000 # # 配置一个连接在池中最小生存的时间,单位是毫秒 # minEvictableIdleTimeMillis: 300000 # # 配置一个连接在池中最大生存的时间,单位是毫秒 # maxEvictableIdleTimeMillis: 900000 # # 配置检测连接是否有效 # validationQuery: SELECT 1 FROM DUAL # testWhileIdle: true # testOnBorrow: false # testOnReturn: false # webStatFilter: # enabled: true # statViewServlet: # enabled: true # # 设置白名单,不填则允许所有访问 # allow: # url-pattern: /druid/* # # 控制台管理用户名和密码 # login-username: ruoyi # login-password: 123456 # filter: # stat: # enabled: true # # 慢SQL记录 # log-slow-sql: true # slow-sql-millis: 1000 # merge-sql: true # wall: # config: # multi-statement-allow: true mqtt: #链接地址 broker: tcp://175.24.61.68:1883 #唯一标识 clientId: 70094a59d1d991d #公司id roleid: 2 mqtt_usernames: 12_ZNZY #订阅的topic topics: PUT/+,GET_REQ/+, READ/+,POST_REQ/+ username: 12_ZNZY password: Luhui586 client: #客户端操作时间 operationTime: 10
\ No newline at end of file
... ...