diff --git a/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/bd/RtcmGgaUtil.java b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/bd/RtcmGgaUtil.java index 134d297f..0aea37d9 100644 --- a/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/bd/RtcmGgaUtil.java +++ b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/bd/RtcmGgaUtil.java @@ -5,6 +5,9 @@ import com.imdroid.common.util.ByteUtil; import com.imdroid.common.util.StringUtil; import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; import static java.lang.Math.*; @@ -13,6 +16,110 @@ public class RtcmGgaUtil { //gga样本:*后面跟的是校验和,其中76代表校验和,对$和*之间的数据(不包括这两个字符)按字节进行异或运算(二进制)的结果 private static final String ggaExample = "$GNGGA,020850.50,2258.10508,N,11317.67958,E,4,12,0.74,3.9,M,-5.4,M,1.3,0000*76"; + + + /** + * 提取多条rtcm + * 因为存在d331...rtcm...d331...rtcm..这样的数据 + * 还存在d331...rtcm rtcm rtcm...这样的数据 + * @param hex + * @return + */ + public static List getRtcms(String hex){ + return splitStartWith(hex,"d300","d301","d302").stream() + .map(com.imdroid.sideslope.bd.RtcmGgaUtil::getRtcm) + .filter(s -> s != null && !s.isEmpty()) + .collect(Collectors.toList()); + } + + /** + * 提取一条rtcm + * @param hex + * @return + */ + public static String getRtcm(String hex){ + try { + int index = getIndex(hex,"d300","d301","d302"); + if (index != -1 && index < hex.length()-6) { + //d300数据长度 + int length = Integer.parseInt(hex.substring(index + 3, index + 6), 16); + if(index + (3+length +3)*2 <= hex.length()){ + return hex.substring(index, index + (3 + length + 3) * 2); + } + } + }catch (Exception e){ + e.printStackTrace(); + } + return null; + } + + private static int getIndex(String... regex){ + for (int i = 1; i < regex.length; i++) { + if(regex[0].contains(regex[i])){ + return regex[0].indexOf(regex[i]); + } + } + return -1; + } + + /** + * 按前缀切割分段 + * @param regex 第一个是要处理的数据,其他是要检测的前缀 + * @return + */ + public static List splitStartWith(String... regex){ + ArrayList list = new ArrayList<>(); + try{ + List indexs = getIndexs(regex); + int start = 0; + for (int i = 0; i < indexs.size(); i++) { + if(indexs.get(i) != 0){ + list.add(regex[0].substring(start,indexs.get(i))); + start = indexs.get(i); + } + if(i == indexs.size() -1){ + list.add(regex[0].substring(indexs.get(i))); + } + } + }catch (Exception e){ + e.printStackTrace(); + } + return list; + } + + /** + * 按多个规则搜索索引 + * @param regex + * @return + */ + public static List getIndexs(String... regex){ + List list =new ArrayList<>(); + for (int i = 1; i < regex.length; i++) { + list.addAll(findAllIndex(regex[0],0,regex[i])); + } + list.sort((o1, o2) -> o1-o2); + return list; + } + + /** + * 按规则搜索所有索引 + * @param string + * @param index + * @param findStr + * @return + */ + public static List findAllIndex(String string, int index, String findStr){ + List list =new ArrayList<>(); + int num = string.indexOf(findStr,index); + if(num != -1){ + list.add(num); + //递归进行查找 + List myList = findAllIndex(string,num+1,findStr); + list.addAll(myList); + } + return list; + } + /** * 获取rtcm数据类型 * @param bytes diff --git a/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/executor/D331RtcmMessageExecutor.java b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/executor/D331RtcmMessageExecutor.java index 7e30d7d1..9194ce2e 100644 --- a/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/executor/D331RtcmMessageExecutor.java +++ b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/executor/D331RtcmMessageExecutor.java @@ -4,13 +4,17 @@ import com.imdroid.common.util.DataTypeUtil; import com.imdroid.common.util.ThreadManager; import com.imdroid.secapi.client.BeidouClient; import com.imdroid.secapi.dto.GnssDevice; +import com.imdroid.common.util.ByteUtil; import com.imdroid.sideslope.bd.Gga; import com.imdroid.sideslope.message.D331RtcmMessage; +import com.imdroid.sideslope.ntrip.UdpNtripServer; import com.imdroid.sideslope.sal.Device; import com.imdroid.sideslope.sal.DeviceService; import com.imdroid.sideslope.server.DeviceChannel; import com.imdroid.sideslope.server.OnlineChannels; import com.imdroid.sideslope.service.DataPersistService; +import com.imdroid.sideslope.bd.RtcmGgaUtil; +//import com.imdroid.common.util.RtcmGgaUtil; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import org.slf4j.Logger; @@ -21,6 +25,8 @@ import org.springframework.stereotype.Component; import javax.annotation.Resource; import java.time.LocalDateTime; import java.util.List; +import java.util.Optional; + /** * @author Layton @@ -37,13 +43,19 @@ public class D331RtcmMessageExecutor implements Executor private BeidouClient beidouClient; @Autowired private DataPersistService dataPersistService; + @Override public Void execute(D331RtcmMessage message) { String id = message.getId(); + byte[] srcdata = message.getSrcData(); + String rtcm = ByteUtil.bytesToHexString(srcdata); // 补齐tenantId Device deviceBs = deviceService.findByDeviceId(id); if(deviceBs == null || deviceBs.getOpMode() == GnssDevice.OP_MODE_UNUSE) return null; + // 添加NTRIP处理 + ntrip(id, rtcm); + // 推送基站数据 if(deviceBs.getOpMode() == GnssDevice.OP_MODE_USE) { byte[] forwardBytes = message.getSrcData(); @@ -79,8 +91,8 @@ public class D331RtcmMessageExecutor implements Executor if(deviceBs.getD3xxbytes()>0){ LocalDateTime now = LocalDateTime.now(); if(deviceBs.getLastRxTime().isBefore(now.minusMinutes(1)) && - (deviceBs.getLastD3f2Time() == null || - deviceBs.getLastD3f2Time().isBefore(now.minusMinutes(30)))) { + (deviceBs.getLastD3f2Time() == null || + deviceBs.getLastD3f2Time().isBefore(now.minusMinutes(30)))) { // new cycle logger.info("device {} rx {} d331 in a cycle while not d3f0f2",deviceBs.getDeviceId(),deviceBs.getD3xxCount()); @@ -115,11 +127,9 @@ public class D331RtcmMessageExecutor implements Executor Gga gga = message.getGga(); if(gga != null) { deviceBs.updateSatelitesNum(gga.getSatellitesInUsed()); - //if(gga.isFixed()) { //基站的quality不会是4 - deviceBs.setLatitude(gga.getLatitude()); - deviceBs.setLongitude(gga.getLongitude()); - deviceBs.setAltitude(gga.getAltitude()); - //} + deviceBs.setLatitude(gga.getLatitude()); + deviceBs.setLongitude(gga.getLongitude()); + deviceBs.setAltitude(gga.getAltitude()); } ThreadManager.getFixedThreadPool().submit(() -> { @@ -133,8 +143,29 @@ public class D331RtcmMessageExecutor implements Executor return null; } + private void ntrip(String mountpoint, String hexData) { + try { + + // 将原始字节转换为16进制字符串用于RTCM提取 + //String hexData = ByteUtil.bytesToHexString(rawData); + System.out.println(hexData); + + // 提取RTCM数据并发送到NtripServer,使用设备ID作为挂载点 + Optional.ofNullable(RtcmGgaUtil.getRtcms(hexData)) + .ifPresent(rtcm -> { + System.out.println("挂载点: " + mountpoint); + System.out.println("RTCM数据: " + rtcm); + UdpNtripServer.send(mountpoint, rtcm); + }); + } catch (Exception e) { + logger.error("处理NTRIP数据失败, 挂载点: {}, 错误: {}", mountpoint, e.getMessage()); + } + } + @Override public Class getMessageType() { return D331RtcmMessage.class; } -} + + +} \ No newline at end of file diff --git a/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/ntrip/HttpNtripServer.java b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/ntrip/HttpNtripServer.java new file mode 100644 index 00000000..68357d71 --- /dev/null +++ b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/ntrip/HttpNtripServer.java @@ -0,0 +1,31 @@ +package com.imdroid.sideslope.ntrip; + +import com.imdroid.common.util.HttpUtils; +import com.imdroid.common.util.ThreadManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +/** + * @author likongyong + * @date 2023/10/19 11:49 + */ +public class HttpNtripServer { + + private static final Logger logger = LoggerFactory.getLogger(HttpNtripServer.class); + + /** + * 修改挂载点获取xingyu差分的gga + * @param mount + * @param gga + */ + public static void sendGGA(String mount, String gga){ + ThreadManager.getSingleThreadPool(HttpNtripServer.class.getName()).execute(()->{ + try{ + String url = "http://localhost:11001/ntrip/sendGGA/" + mount + "/" + gga; + String result = HttpUtils.getUrl(url); + logger.debug("{} send gga {} {}",mount, gga, result); + }catch (Exception e){ + logger.error(e.toString()); + } + }); + } +} diff --git a/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/ntrip/UdpNtripServer.java b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/ntrip/UdpNtripServer.java new file mode 100644 index 00000000..d8e656fa --- /dev/null +++ b/sec-beidou-rtcm/src/main/java/com/imdroid/sideslope/ntrip/UdpNtripServer.java @@ -0,0 +1,69 @@ +package com.imdroid.sideslope.ntrip; + +import com.imdroid.common.util.ByteUtil; +import com.imdroid.common.util.ThreadManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.util.List; + +/** + * 本地udp发送差分数据到ntrip-forward-server项目 + */ +public class UdpNtripServer { + + private static final Logger logger = LoggerFactory.getLogger(UdpNtripServer.class); + + private static DatagramSocket socket; + private static DatagramPacket outPacket; + + /** + * 向某挂载点提供差分信息 + * @param mount 挂载点名称 + * @param hexRtcm 差分信息16进制字符串 + */ + public static void send(String mount, String hexRtcm){ + ThreadManager.getSingleThreadPool(UdpNtripServer.class.getName()).execute(()->{ + try{ + //随机端口 + if(socket == null) socket = new DatagramSocket(); + if(outPacket == null) outPacket = new DatagramPacket(new byte[0],0, InetAddress.getByName("localhost"),11100); + outPacket.setData(encode(ByteUtil.addBytes(mount.getBytes(), ByteUtil.hexStringTobyte(hexRtcm)))); + socket.send(outPacket); + }catch (Exception e){ + socket = null; + outPacket = null; + e.printStackTrace(); + } + }); + } + + /** + * 向某挂载点提供差分信息 + * @param mount 挂载点名称 + * @param hexRtcm 差分信息16进制字符串 + */ + public static void send(String mount, List hexRtcm){ + logger.debug(mount + ":" + hexRtcm.size()); + for (String s : hexRtcm) { + send(mount,s); + } + } + + //加入校验位,用于校验数据是否完整 + private static byte[] encode(byte[] bytes) { + byte[] bytes1 = new byte[bytes.length + 1]; + //校验位 + byte b = bytes[0]; + bytes1[0] = bytes[0]; + for (int i = 1; i < bytes.length; i++) { + b ^= bytes[i]; + bytes1[i] = bytes[i]; + } + bytes1[bytes1.length - 1] = b; + return bytes1; + } +}