Compare commits
10 Commits
4fc3fb9617
...
3aa4e2a0fb
| Author | SHA1 | Date | |
|---|---|---|---|
| 3aa4e2a0fb | |||
|
|
8ca33f908a | ||
|
|
b7453a9331 | ||
|
|
387364029a | ||
|
|
d0ae7671d7 | ||
|
|
77cc7707ee | ||
|
|
3cd8277586 | ||
|
|
f2ef68a9ae | ||
|
|
ab0bd9943c | ||
|
|
b04ec862b2 |
@ -47,4 +47,15 @@ public interface BeidouClient {
|
||||
|
||||
@PostMapping("/upgrade_complete")
|
||||
String onUpgradeComplete();
|
||||
|
||||
@PostMapping("/rtkrcv_ack")
|
||||
String onRtkrcvAck(@RequestParam(name = "deviceId") String deviceId,
|
||||
@RequestParam(name = "data") String data);
|
||||
|
||||
@PostMapping("/rtk_gngga")
|
||||
String onRtkGngga(@RequestParam(name = "deviceId") String deviceId,
|
||||
@RequestParam(name = "lat") Double lat,
|
||||
@RequestParam(name = "lon") Double lon,
|
||||
@RequestParam(name = "alt") Double alt,
|
||||
@RequestParam(name = "geo") Double geoidSeparation);
|
||||
}
|
||||
|
||||
@ -0,0 +1,19 @@
|
||||
package com.imdroid.secapi.client;
|
||||
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
@FeignClient(name="RtkrcvClient", url = "http://localhost:9904/gnss")
|
||||
public interface RtkrcvClient {
|
||||
@PostMapping("/rtk/start")
|
||||
String start(@RequestParam("device_id") String deviceId,
|
||||
@RequestParam(value = "clear_log", required = false) boolean clearLog);
|
||||
|
||||
@PostMapping("/rtk/stop")
|
||||
String stop(@RequestParam("device_id") String deviceId);
|
||||
|
||||
@GetMapping("/rtk/log_exists")
|
||||
Boolean logExists(@RequestParam("device_id") String deviceId);
|
||||
}
|
||||
@ -3,7 +3,6 @@ package com.imdroid.secapi.dto;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.imdroid.common.util.ByteUtil;
|
||||
import com.imdroid.common.util.HexUtil;
|
||||
import lombok.Data;
|
||||
|
||||
@ -103,10 +102,9 @@ public class GnssDevice {
|
||||
return cmdList;
|
||||
}
|
||||
|
||||
public boolean clearChangeFlag(String ack){
|
||||
public boolean clearChangeFlag(byte[] ackBytes){
|
||||
boolean result = false;
|
||||
if(change_flag!=0) {
|
||||
byte[] ackBytes = ByteUtil.hexStringTobyte(ack);
|
||||
if(ackBytes[ackBytes.length-1] == 1) {
|
||||
if (ackBytes[8] == 0x55) {
|
||||
change_flag &= ~PARA_MASK_HAS_BATTERY;
|
||||
|
||||
@ -16,6 +16,9 @@ public class GnssStatusJoin {
|
||||
@ExcelProperty("租户id")
|
||||
Integer tenantid;
|
||||
|
||||
@ExcelProperty("租户名")
|
||||
String tenantname;
|
||||
|
||||
@ExcelProperty("更新日期时间")
|
||||
LocalDateTime updatetime;
|
||||
|
||||
|
||||
@ -22,23 +22,23 @@ public interface GnssStatusMapper extends MPJBaseMapper<GnssStatus> {
|
||||
@Select({"select s.*, d.devicetype, d.model, d.group_id, d.name, d.project_id,d.iccid from gnssstatus s ,gnssdevices d where s.deviceid=d.deviceid and s.state <> 0"})
|
||||
List<GnssStatusJoin> queryOnline();
|
||||
|
||||
@Select({"select s.*, d.devicetype, d.model, d.group_id, d.name, d.project_id,d.iccid from gnssstatus s ,gnssdevices d where " +
|
||||
@Select({"select s.*, d.devicetype, d.model, d.group_id, d.name, d.project_id,d.iccid,d.tenantname from gnssstatus s ,gnssdevices d where " +
|
||||
"s.deviceid=d.deviceid and d.tenantid<>0 and d.opmode=0"})
|
||||
List<GnssStatusJoin> queryDeployed();
|
||||
|
||||
@Select({"select s.*, d.devicetype, d.model, d.group_id, d.name, d.project_id,d.iccid from gnssstatus s ,gnssdevices d where " +
|
||||
@Select({"select s.*, d.devicetype, d.model, d.group_id, d.name, d.project_id,d.iccid,d.tenantname from gnssstatus s ,gnssdevices d where " +
|
||||
"s.deviceid=d.deviceid and d.tenantid = #{tenantid} and d.opmode=0"})
|
||||
List<GnssStatusJoin> queryDeployedByTenant(int tenantid);
|
||||
|
||||
//多个入参要用Param注解
|
||||
@Select({"select s.*, d.devicetype, d.model, d.group_id, d.name, d.project_id,d.iccid from gnssstatus s ,gnssdevices d where " +
|
||||
@Select({"select s.*, d.devicetype, d.model, d.group_id, d.name, d.project_id,d.iccid,d.tenantname from gnssstatus s ,gnssdevices d where " +
|
||||
"s.deviceid=d.deviceid and d.tenantid = #{tenantid} and d.opmode=0 and d.project_id = #{projectName}"})
|
||||
List<GnssStatusJoin> queryDeployedByProject(@Param("tenantid") int tenantid, @Param("projectName") String projectName);
|
||||
|
||||
// 需要关联设备类型
|
||||
@Select({"select s.*, d.devicetype, d.model, d.group_id, d.name, d.project_id,d.iccid from gnssstatus s ,gnssdevices d where s.deviceid=d.deviceid and s.deviceid = #{deviceId}"})
|
||||
@Select({"select s.*, d.devicetype, d.model, d.group_id, d.name, d.project_id,d.iccid,d.tenantname from gnssstatus s ,gnssdevices d where s.deviceid=d.deviceid and s.deviceid = #{deviceId}"})
|
||||
GnssStatusJoin queryByDeviceId(String deviceId);
|
||||
|
||||
@Select({"select s.*, d.devicetype, d.model, d.group_id, d.name, d.project_id,d.iccid from gnssstatus s ,gnssdevices d where s.deviceid=d.deviceid"})
|
||||
@Select({"select s.*, d.devicetype, d.model, d.group_id, d.name, d.project_id,d.iccid,d.tenantname from gnssstatus s ,gnssdevices d where s.deviceid=d.deviceid"})
|
||||
GnssStatusJoin queryAll();
|
||||
}
|
||||
|
||||
16
sec-api/src/main/java/com/imdroid/secapi/dto/RtkGroup.java
Normal file
16
sec-api/src/main/java/com/imdroid/secapi/dto/RtkGroup.java
Normal file
@ -0,0 +1,16 @@
|
||||
package com.imdroid.secapi.dto;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@TableName(value = "rtkgroup")
|
||||
public class RtkGroup {
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
Integer id;
|
||||
String name;
|
||||
String inpstr2_path;
|
||||
String inpstr3_path;
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
package com.imdroid.secapi.dto;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
public interface RtkGroupMapper extends BaseMapper<RtkGroup> {
|
||||
}
|
||||
|
||||
21
sec-api/src/main/java/com/imdroid/secapi/dto/RtkProfile.java
Normal file
21
sec-api/src/main/java/com/imdroid/secapi/dto/RtkProfile.java
Normal file
@ -0,0 +1,21 @@
|
||||
package com.imdroid.secapi.dto;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@TableName(value = "rtkprofile")
|
||||
public class RtkProfile {
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
Integer id;
|
||||
Integer rtkgroup_id;
|
||||
String device_id;
|
||||
String pos1_posmode;
|
||||
String inpstr1_type;
|
||||
String inpstr1_path;
|
||||
String outstr2_path;
|
||||
String out_height;
|
||||
}
|
||||
|
||||
@ -0,0 +1,7 @@
|
||||
package com.imdroid.secapi.dto;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
public interface RtkProfileMapper extends BaseMapper<RtkProfile> {
|
||||
}
|
||||
|
||||
@ -0,0 +1,19 @@
|
||||
package com.imdroid.secapi.dto;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@TableName(value = "rtksolution")
|
||||
public class RtkSolution {
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
Integer id;
|
||||
String device_id;
|
||||
Double latitude;
|
||||
Double longitude;
|
||||
Double altitude;
|
||||
Short status;
|
||||
}
|
||||
|
||||
@ -0,0 +1,7 @@
|
||||
package com.imdroid.secapi.dto;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
public interface RtkSolutionMapper extends BaseMapper<RtkSolution> {
|
||||
}
|
||||
|
||||
@ -15,10 +15,7 @@ import org.springframework.util.StringUtils;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class Forwarder {
|
||||
@ -96,15 +93,10 @@ public class Forwarder {
|
||||
|
||||
/***
|
||||
* 推送指定企业、设备ID、时间的GNSS记录,查找指定时间前cycle分钟的有效数据推送
|
||||
* @param sendTime:要推送的记录的时间
|
||||
* @param resendRecord:重推送信息
|
||||
*/
|
||||
|
||||
private boolean forwardGnssRecords(LocalDateTime sendTime, ResendRecord resendRecord) {
|
||||
String endTime = sendTime.format(formatter);
|
||||
String beginTime = sendTime.minusMinutes(fwdCycleMinutes).format(formatter);
|
||||
|
||||
// 查找属于指定推送组的设备列表
|
||||
List<GnssDeviceJoin> gnssDeviceList;
|
||||
private List<GnssDeviceJoin> getFwdDeviceList(ResendRecord resendRecord){
|
||||
MPJQueryWrapper jquery = null;
|
||||
|
||||
if(resendRecord!=null && StringUtils.hasText(resendRecord.getDeviceid())){
|
||||
@ -118,8 +110,9 @@ public class Forwarder {
|
||||
.leftJoin("gnssstatus d on t.deviceid = d.deviceid")
|
||||
.and(warpper->warpper.eq("fwd_group_id", fwdGroupId)
|
||||
.or()
|
||||
.eq("fwd_group_id2", fwdGroupId)).
|
||||
eq("t.deviceid", resendRecord.getDeviceid());
|
||||
.eq("fwd_group_id2", fwdGroupId))
|
||||
.eq("t.deviceid", resendRecord.getDeviceid())
|
||||
.eq("opmode",GnssDevice.OP_MODE_USE);
|
||||
}
|
||||
else if(resendRecord!=null && resendRecord.getProjectid()!=null){
|
||||
jquery = new MPJQueryWrapper<GnssDevice> ()
|
||||
@ -135,7 +128,8 @@ public class Forwarder {
|
||||
.eq("fwd_group_id2", fwdGroupId))
|
||||
.and(warpper->warpper.eq("project_id",resendRecord.getProjectid())
|
||||
.or()
|
||||
.eq("project2_id",resendRecord.getProjectid()));
|
||||
.eq("project2_id",resendRecord.getProjectid()))
|
||||
.eq("opmode",GnssDevice.OP_MODE_USE);
|
||||
}
|
||||
else{
|
||||
jquery = new MPJQueryWrapper<GnssDevice> ()
|
||||
@ -148,29 +142,58 @@ public class Forwarder {
|
||||
.leftJoin("gnssstatus d on t.deviceid = d.deviceid")
|
||||
.and(warpper->warpper.eq("fwd_group_id", fwdGroupId)
|
||||
.or()
|
||||
.eq("fwd_group_id2", fwdGroupId));
|
||||
.eq("fwd_group_id2", fwdGroupId))
|
||||
.eq("opmode",GnssDevice.OP_MODE_USE);
|
||||
}
|
||||
gnssDeviceList = deviceMapper.selectJoinList(GnssDeviceJoin.class, jquery);
|
||||
logger.debug("candidate fwd devices {}", gnssDeviceList.size());
|
||||
return deviceMapper.selectJoinList(GnssDeviceJoin.class, jquery);
|
||||
}
|
||||
|
||||
// 查询最近半小时的GNSS记录
|
||||
HashMap<String, GnssCalcData> getFwdGnssData(LocalDateTime sendTime,List<GnssDeviceJoin> gnssDeviceList, ResendRecord resendRecord){
|
||||
String endTime = sendTime.format(formatter);
|
||||
String beginTime = sendTime.minusMinutes(fwdCycleMinutes).format(formatter);
|
||||
|
||||
// 直接以设备列表作为查询条件,查询语句很大(一个单位可能有几千台设备)。
|
||||
// 用设备列表关联的所有的tenantId来查询,然后再筛选,效率更高,但可能包含了非推送的设备列表
|
||||
HashSet<Integer> tenantIdSet = new HashSet<>();
|
||||
for(GnssDeviceJoin d:gnssDeviceList){
|
||||
tenantIdSet.add(d.getTenantid());
|
||||
}
|
||||
logger.debug("candidate fwd tenants {}", tenantIdSet.size());
|
||||
|
||||
// 查询最近一个推送周期的GNSS记录
|
||||
QueryWrapper<GnssCalcData> gnssQueryWrapper = new QueryWrapper<>();
|
||||
gnssQueryWrapper.ge("createtime",beginTime);
|
||||
gnssQueryWrapper.le("createtime",endTime);
|
||||
gnssQueryWrapper.orderByDesc("createtime");
|
||||
gnssQueryWrapper.eq("enabled",true);
|
||||
gnssQueryWrapper.eq("stabled",true);
|
||||
gnssQueryWrapper.isNotNull("rpose");
|
||||
if(resendRecord != null && StringUtils.hasText(resendRecord.getDeviceid())){
|
||||
gnssQueryWrapper.eq("deviceid", resendRecord.getDeviceid());
|
||||
}
|
||||
else {
|
||||
gnssQueryWrapper.and(wrapper -> {
|
||||
int i=0;
|
||||
for (Integer tenantId : tenantIdSet) {
|
||||
if(i==0) wrapper.eq("tenantid", tenantId);
|
||||
else wrapper.or().eq("tenantid", tenantId);
|
||||
i++;
|
||||
}
|
||||
});
|
||||
}
|
||||
gnssQueryWrapper.orderByDesc("createtime");
|
||||
|
||||
List<GnssCalcData> locationRecords = gnssDataMapper.selectList(gnssQueryWrapper);
|
||||
logger.debug("candidate fwd records {}", locationRecords.size());
|
||||
if(locationRecords.size() == 0) return false;
|
||||
List<GnssCalcData> gnssDataList = gnssDataMapper.selectList(gnssQueryWrapper);
|
||||
// 同一台设备只保留最近的记录
|
||||
HashMap<String, GnssCalcData> gnssDataMap = new HashMap<>();
|
||||
for(GnssCalcData data:gnssDataList){
|
||||
gnssDataMap.put(data.getDeviceid(),data);
|
||||
}
|
||||
return gnssDataMap;
|
||||
}
|
||||
|
||||
// 构造按项目id分类的GNSS记录
|
||||
ConcurrentHashMap<String, List<GnssCalcData>> projects = new ConcurrentHashMap<>();
|
||||
HashMap<String, List<GnssCalcData>> createFwdDataByProject(
|
||||
List<GnssDeviceJoin> gnssDeviceList,HashMap<String, GnssCalcData> gnssDataMap,ResendRecord resendRecord){
|
||||
HashMap<String, List<GnssCalcData>> projects = new HashMap<>();
|
||||
for(GnssDeviceJoin device:gnssDeviceList){
|
||||
if(device.getOpmode() != GnssDevice.OP_MODE_USE) continue;
|
||||
String projectId = device.getProject_id();
|
||||
@ -191,43 +214,57 @@ public class Forwarder {
|
||||
recordsToSend = new ArrayList<>();
|
||||
projects.put(projectId,recordsToSend);
|
||||
}
|
||||
for(GnssCalcData record:locationRecords){
|
||||
if(record.getDeviceid().equals(device.getDeviceid())) {
|
||||
// 替换成推送用的名字和数值
|
||||
if (device.getIpose() != null &&
|
||||
device.getIposn() != null &&
|
||||
device.getIposd() != null) {
|
||||
record.setRpose(record.getRpose() - device.getIpose());
|
||||
record.setRposn(record.getRposn() - device.getIposn());
|
||||
record.setRposd(record.getRposd() - device.getIposd());
|
||||
}
|
||||
if (fwdNameType == FWD_DEVICE_ALIAS_NAME || (device.getName()!=null&&device.getName().contains("替换"))) {
|
||||
if (StringUtils.hasText(device.getFwddeviceid())) {
|
||||
record.setDeviceid(device.getFwddeviceid());
|
||||
}
|
||||
}
|
||||
else if(fwdNameType == FWD_DEVICE_NAME){
|
||||
String devName = "";
|
||||
if(StringUtils.hasText(device.getProject_id())) devName = devName+device.getProject_id()+"-";
|
||||
if(StringUtils.hasText(device.getSector())) devName = devName+device.getSector()+"-";
|
||||
if(StringUtils.hasText(device.getName())) devName = devName+device.getName();
|
||||
if(StringUtils.hasText(devName)) {
|
||||
record.setDeviceid(devName);
|
||||
}
|
||||
}
|
||||
// 用r9250来传设备经纬度
|
||||
record.setR9250e(device.getLongitude());
|
||||
record.setR9250n(device.getLatitude());
|
||||
// 用aux来传xyz
|
||||
record.setAuxe(device.getRoll());
|
||||
record.setAuxn(device.getPitch());
|
||||
record.setAuxd(device.getYaw());
|
||||
|
||||
recordsToSend.add(record);
|
||||
break;
|
||||
GnssCalcData record=gnssDataMap.get(device.getDeviceid());
|
||||
if(record!=null) {
|
||||
// 替换成推送用的名字和数值
|
||||
if (device.getIpose() != null &&
|
||||
device.getIposn() != null &&
|
||||
device.getIposd() != null) {
|
||||
record.setRpose(record.getRpose() - device.getIpose());
|
||||
record.setRposn(record.getRposn() - device.getIposn());
|
||||
record.setRposd(record.getRposd() - device.getIposd());
|
||||
}
|
||||
if (fwdNameType == FWD_DEVICE_ALIAS_NAME || (device.getName()!=null&&device.getName().contains("替换"))) {
|
||||
if (StringUtils.hasText(device.getFwddeviceid())) {
|
||||
record.setDeviceid(device.getFwddeviceid());
|
||||
}
|
||||
}
|
||||
else if(fwdNameType == FWD_DEVICE_NAME){
|
||||
String devName = "";
|
||||
if(StringUtils.hasText(device.getProject_id())) devName = devName+device.getProject_id()+"-";
|
||||
if(StringUtils.hasText(device.getSector())) devName = devName+device.getSector()+"-";
|
||||
if(StringUtils.hasText(device.getName())) devName = devName+device.getName();
|
||||
if(StringUtils.hasText(devName)) {
|
||||
record.setDeviceid(devName);
|
||||
}
|
||||
}
|
||||
// 用r9250来传设备经纬度
|
||||
record.setR9250e(device.getLongitude());
|
||||
record.setR9250n(device.getLatitude());
|
||||
// 用aux来传xyz
|
||||
record.setAuxe(device.getRoll());
|
||||
record.setAuxn(device.getPitch());
|
||||
record.setAuxd(device.getYaw());
|
||||
|
||||
recordsToSend.add(record);
|
||||
}
|
||||
}
|
||||
return projects;
|
||||
}
|
||||
private boolean forwardGnssRecords(LocalDateTime sendTime, ResendRecord resendRecord) {
|
||||
// 查找属于指定推送组fwdGroupId的设备列表,补推条件可能包含项目号或设备号
|
||||
List<GnssDeviceJoin> gnssDeviceList = getFwdDeviceList(resendRecord);
|
||||
logger.debug("candidate fwd devices {}", gnssDeviceList.size());
|
||||
if(gnssDeviceList.size() == 0) return false;
|
||||
|
||||
//查找要推送的数据
|
||||
HashMap<String, GnssCalcData> gnssDataMap = getFwdGnssData(sendTime, gnssDeviceList, resendRecord);
|
||||
logger.debug("candidate fwd records {}", gnssDataMap.size());
|
||||
if(gnssDataMap.size() == 0) return false;
|
||||
|
||||
// 构造按项目id分类的GNSS记录
|
||||
HashMap<String, List<GnssCalcData>> projects =
|
||||
createFwdDataByProject(gnssDeviceList,gnssDataMap,resendRecord);
|
||||
|
||||
// 按项目打包推送
|
||||
totalSendNum = 0;
|
||||
|
||||
@ -31,6 +31,11 @@ public class Gga {
|
||||
*/
|
||||
private double altitude=0;
|
||||
|
||||
/**
|
||||
* 大地水准面相对椭球面的高度
|
||||
*/
|
||||
private double geoidSeparation = 0;
|
||||
|
||||
/**
|
||||
* GPS状态,0初始化,1单点定位,2码差分,3无效PPS,4固定解,5浮点解,6正在估算7,人工输入固定值,8模拟模式,9WAAS差分
|
||||
*/
|
||||
@ -94,8 +99,8 @@ public class Gga {
|
||||
}
|
||||
}
|
||||
if(ggaStr != null){
|
||||
String[] params = ggaStr.split(",",11);
|
||||
if(params.length == 11){
|
||||
String[] params = ggaStr.split(",",14);
|
||||
if(params.length >= 12){
|
||||
Gga gga = new Gga();
|
||||
try {
|
||||
gga.setLatitude(transGGAPos(Double.parseDouble(params[2])));
|
||||
@ -103,6 +108,7 @@ public class Gga {
|
||||
gga.setAltitude(Double.parseDouble(params[9]));
|
||||
gga.setQuality(Integer.parseInt(params[6]));
|
||||
gga.setSatellitesInUsed(Integer.parseInt(params[7]));
|
||||
gga.setGeoidSeparation(Double.parseDouble(params[11]));
|
||||
return gga;
|
||||
}
|
||||
catch (Exception e){
|
||||
|
||||
@ -169,7 +169,9 @@ public class GNSSCalcFilterService {
|
||||
newRecord.setAuxn(NumberUtils.scaleTwo(msumN / minCount));
|
||||
newRecord.setAuxd(NumberUtils.scaleTwo(msumD / minCount));
|
||||
//滤波窗口里的时间跨度超过滤波时间的2/3才认为稳定
|
||||
newRecord.setStabled(lastRecordTime.isBefore(newRecordTime.minusHours(filterCycleHour * 1 / 2)));
|
||||
int stabledHours=filterCycleHour/2;
|
||||
if(stabledHours>12) stabledHours=12;
|
||||
newRecord.setStabled(lastRecordTime.isBefore(newRecordTime.minusHours(stabledHours)));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -249,7 +251,9 @@ public class GNSSCalcFilterService {
|
||||
newRecord.setAuxn(NumberUtils.scaleTwo(msumN / minCount));
|
||||
newRecord.setAuxd(NumberUtils.scaleTwo(msumD / minCount));
|
||||
//滤波窗口里的时间跨度超过滤波时间的2/3才认为稳定
|
||||
newRecord.setStabled(lastRecordTime.isBefore(newRecordTime.minusHours(filterCycleHour * 1 / 2)));
|
||||
int stabledHours=filterCycleHour/2;
|
||||
if(stabledHours>12) stabledHours=12;
|
||||
newRecord.setStabled(lastRecordTime.isBefore(newRecordTime.minusHours(stabledHours)));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@ import com.imdroid.secapi.dto.GnssDevice;
|
||||
import com.imdroid.common.util.ByteUtil;
|
||||
import com.imdroid.sideslope.bd.Gga;
|
||||
import com.imdroid.sideslope.bd.Rtcm1005;
|
||||
import com.imdroid.sideslope.bd.Tilt;
|
||||
import com.imdroid.sideslope.calc.GNSSDataCalcService;
|
||||
import com.imdroid.sideslope.message.D331RtcmMessage;
|
||||
import com.imdroid.sideslope.ntrip.UdpNtripServer;
|
||||
@ -117,6 +118,11 @@ public class D331RtcmMessageExecutor implements Executor<D331RtcmMessage, Void>
|
||||
deviceBs.setLongitude(gga.getLongitude());
|
||||
deviceBs.setAltitude(gga.getAltitude());
|
||||
}
|
||||
// update angles
|
||||
Tilt tilt = message.getTilt();
|
||||
if(tilt!=null){
|
||||
deviceBs.updateMinMaxAngle(tilt.getRoll(),tilt.getPitch());
|
||||
}
|
||||
|
||||
// 添加NTRIP处理
|
||||
|
||||
|
||||
@ -5,6 +5,7 @@ import com.imdroid.common.util.ThreadManager;
|
||||
import com.imdroid.secapi.client.BeidouClient;
|
||||
import com.imdroid.secapi.dto.GnssDevice;
|
||||
import com.imdroid.sideslope.bd.Gga;
|
||||
import com.imdroid.sideslope.bd.Tilt;
|
||||
import com.imdroid.sideslope.calc.GNSSDataCalcService;
|
||||
import com.imdroid.sideslope.message.D341LocationMessage;
|
||||
import com.imdroid.sideslope.service.Device;
|
||||
@ -78,6 +79,10 @@ public class D341LocationMessageExecutor implements Executor<D341LocationMessage
|
||||
double[] pos = message.getB562_loc();
|
||||
device.updateCalcQuality((int) pos[3]);
|
||||
}
|
||||
Tilt tilt = message.getTilt();
|
||||
if(tilt!=null){
|
||||
device.updateMinMaxAngle(tilt.getRoll(),tilt.getPitch());
|
||||
}
|
||||
|
||||
Gga gga = message.getGga();
|
||||
if(gga != null) {
|
||||
|
||||
@ -60,6 +60,14 @@ public class D3F2StopIndicationMessageExecutor implements Executor<D3F2StopIndic
|
||||
message.setOtherInfo(message.getOtherInfo() + ",valid calc:" + device.getLastValidCalcDataTime());
|
||||
}
|
||||
}
|
||||
if(device.getMinAngleX()!=null){
|
||||
message.setOtherInfo(String.format("%s,303(%.2f,%.2f,%.2f,%.2f)",
|
||||
message.getOtherInfo(),
|
||||
device.getMinAngleX(),
|
||||
device.getMaxAngleX(),
|
||||
device.getMinAngleY(),
|
||||
device.getMaxAngleY()));
|
||||
}
|
||||
//更新统计
|
||||
device.updateRx(message.getHeader(), message.getLen(),1);
|
||||
GnssTrxMsg gnssTrxMsg = message.getTrxMsg();
|
||||
|
||||
@ -20,21 +20,22 @@ public class D331RtcmMessage extends BaseMessage {
|
||||
@Override
|
||||
public void decodeBody(ByteBuf src) {
|
||||
// get操作不会移动指针,这样可以确保整个全转发出去
|
||||
int pos = 0;
|
||||
this.packetNum = 1;
|
||||
this.len = src.readableBytes();//this.len & 0x7FF;//有可能两个d331粘包
|
||||
this.header = src.getUnsignedShort(0); // flag
|
||||
int onePacketLen = src.getUnsignedShort(2); // length:11 bits
|
||||
this.header = src.getUnsignedShort(pos); pos+=2;// flag
|
||||
int onePacketLen = src.getUnsignedShort(pos); pos+=2;// length:11 bits
|
||||
this.seq = onePacketLen >> 11;
|
||||
onePacketLen = onePacketLen&0x7FF;
|
||||
this.id = String.valueOf(src.getUnsignedInt(4)); //id
|
||||
int pos = onePacketLen + 4;
|
||||
while(pos < this.len){
|
||||
if(src.getUnsignedShort(pos) == 0xd331){
|
||||
onePacketLen = src.getUnsignedShort(pos+2)&0x7FF;
|
||||
pos = pos+4+onePacketLen;
|
||||
packetNum ++;
|
||||
this.id = String.valueOf(src.getUnsignedInt(pos)); pos+=4;//id
|
||||
if(onePacketLen + 4<this.len) {
|
||||
while (pos < this.len) {
|
||||
if (src.getUnsignedShort(pos) == 0xd331) {
|
||||
onePacketLen = src.getUnsignedShort(pos + 2) & 0x7FF;
|
||||
pos = pos + 4 + onePacketLen;
|
||||
packetNum++;
|
||||
} else pos++;
|
||||
}
|
||||
else pos++;
|
||||
}
|
||||
/*if (src.readableBytes() - 4 < this.len) {
|
||||
String msg = String.format("id[%s],长度字段值[%s]效益包的消息体长度[%s]", id, this.len, src.readableBytes() - 4);
|
||||
|
||||
@ -0,0 +1,78 @@
|
||||
package com.imdroid.sideslope.rtkrcv;
|
||||
|
||||
import com.imdroid.secapi.client.BeidouClient;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public class RtkOutServer {
|
||||
private final String deviceId;
|
||||
private final int port;
|
||||
private final BeidouClient beidouClient;
|
||||
private volatile boolean running = false;
|
||||
private ServerSocket serverSocket;
|
||||
|
||||
private java.io.BufferedWriter logWriter;
|
||||
|
||||
public RtkOutServer(String deviceId, int port, BeidouClient beidouClient){
|
||||
this.deviceId = deviceId;
|
||||
this.port = port;
|
||||
this.beidouClient = beidouClient;
|
||||
}
|
||||
|
||||
public void start() throws IOException {
|
||||
if(running) return;
|
||||
running = true;
|
||||
serverSocket = new ServerSocket(port);
|
||||
try {
|
||||
java.nio.file.Path dir = java.nio.file.Paths.get("/opt/rtk/"+deviceId);
|
||||
java.nio.file.Files.createDirectories(dir);
|
||||
java.nio.file.Path log = dir.resolve("rtkrcv.log");
|
||||
logWriter = java.nio.file.Files.newBufferedWriter(log, java.nio.charset.StandardCharsets.UTF_8,
|
||||
java.nio.file.StandardOpenOption.CREATE, java.nio.file.StandardOpenOption.APPEND);
|
||||
} catch (Exception ignore) {}
|
||||
Thread t = new Thread(this::acceptLoop, "rtk-out-server-"+deviceId+":"+port);
|
||||
t.setDaemon(true);
|
||||
t.start();
|
||||
}
|
||||
|
||||
private void acceptLoop(){
|
||||
while(running){
|
||||
try {
|
||||
Socket sock = serverSocket.accept();
|
||||
handleClient(sock);
|
||||
} catch (IOException e) {
|
||||
if(running) { /* ignore transient errors */ }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleClient(Socket sock){
|
||||
Thread t = new Thread(() -> {
|
||||
try (BufferedReader br = new BufferedReader(new InputStreamReader(sock.getInputStream(), StandardCharsets.UTF_8))){
|
||||
String line;
|
||||
while((line = br.readLine()) != null){
|
||||
try{ beidouClient.onRtkrcvAck(deviceId, line); } catch (Exception ignore) {}
|
||||
try{
|
||||
if(logWriter!=null){ synchronized (this){ logWriter.write(line); logWriter.write("\n"); logWriter.flush(); } }
|
||||
}catch(Exception ignore){}
|
||||
}
|
||||
} catch (IOException ignored) {
|
||||
} finally {
|
||||
try { sock.close(); } catch (Exception ignore) {}
|
||||
}
|
||||
}, "rtk-out-client-"+deviceId);
|
||||
t.setDaemon(true);
|
||||
t.start();
|
||||
}
|
||||
|
||||
public void close(){
|
||||
running = false;
|
||||
try { if(serverSocket!=null) serverSocket.close(); } catch (Exception ignore) {}
|
||||
try { if(logWriter!=null) logWriter.close(); } catch (Exception ignore) {}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
package com.imdroid.sideslope.rtkrcv;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/rtk")
|
||||
public class RtkrcvController {
|
||||
@Autowired
|
||||
RtkrcvManager manager;
|
||||
|
||||
@PostMapping("/start")
|
||||
public String start(@RequestParam("device_id") String deviceId,
|
||||
@RequestParam(value = "clear_log", required = false) Boolean clearLog){
|
||||
return manager.start(deviceId, clearLog!=null && clearLog);
|
||||
}
|
||||
|
||||
@PostMapping("/stop")
|
||||
public String stop(@RequestParam("device_id") String deviceId){
|
||||
manager.stop(deviceId);
|
||||
return "ok";
|
||||
}
|
||||
|
||||
@GetMapping("/log_exists")
|
||||
public boolean logExists(@RequestParam("device_id") String deviceId){
|
||||
java.nio.file.Path p = java.nio.file.Paths.get("/opt/rtk/"+deviceId+"/rtkrcv.log");
|
||||
return java.nio.file.Files.exists(p);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,206 @@
|
||||
package com.imdroid.sideslope.rtkrcv;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.imdroid.secapi.client.BeidouClient;
|
||||
import com.imdroid.secapi.dto.RtkGroup;
|
||||
import com.imdroid.secapi.dto.RtkGroupMapper;
|
||||
import com.imdroid.secapi.dto.RtkProfile;
|
||||
import com.imdroid.secapi.dto.RtkProfileMapper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.ServerSocket;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Service
|
||||
public class RtkrcvManager {
|
||||
@Autowired
|
||||
RtkProfileMapper profileMapper;
|
||||
@Autowired
|
||||
RtkGroupMapper groupMapper;
|
||||
@Autowired
|
||||
BeidouClient beidouClient;
|
||||
@Autowired
|
||||
com.imdroid.sideslope.service.DeviceService deviceService;
|
||||
|
||||
private final Map<String, Process> procMap = new HashMap<>();
|
||||
private final Map<String, RtkOutServer> outServerMap = new HashMap<>();
|
||||
|
||||
public synchronized String start(String deviceId, boolean clearLog){
|
||||
RtkProfile profile = getOrCreateProfile(deviceId);
|
||||
if(profile.getRtkgroup_id()==null){
|
||||
return "profile group id is null";
|
||||
}
|
||||
RtkGroup group = groupMapper.selectById(profile.getRtkgroup_id());
|
||||
if(group == null){
|
||||
return "group not found";
|
||||
}
|
||||
ensureDefaults(profile, deviceId);
|
||||
String retHint = "ok";
|
||||
try{
|
||||
com.imdroid.sideslope.service.Device dev = deviceService.findByDeviceId(deviceId);
|
||||
if(dev!=null){
|
||||
Double lat = dev.getLatitude()==null?0.0:dev.getLatitude();
|
||||
Double lon = dev.getLongitude()==null?0.0:dev.getLongitude();
|
||||
Double alt = dev.getAltitude()==null?0.0:dev.getAltitude();
|
||||
Double geo = dev.getGeoidSeparation()==null?0.0:dev.getGeoidSeparation();
|
||||
try{ beidouClient.onRtkGngga(deviceId, lat, lon, alt, geo); }catch(Exception ignore){}
|
||||
if(!(lat==0.0 && lon==0.0 && alt==0.0)){
|
||||
profile.setOut_height(geo==0.0?"ellipsoidal":"geodetic");
|
||||
} else {
|
||||
retHint = "all_zero";
|
||||
}
|
||||
}
|
||||
}catch(Exception ignore){}
|
||||
profileMapper.updateById(profile);
|
||||
try {
|
||||
startOutServerIfNeeded(deviceId, profile.getOutstr2_path());
|
||||
if(clearLog) clearLogFile(deviceId);
|
||||
String confPath = generateConfig(deviceId, profile, group);
|
||||
Process old = procMap.get(deviceId);
|
||||
if(old!=null && old.isAlive()){
|
||||
old.destroy();
|
||||
}
|
||||
ProcessBuilder pb = new ProcessBuilder("/opt/rtk/bin/rtkrcv","-nc","-o",confPath);
|
||||
pb.redirectErrorStream(true);
|
||||
Process p = pb.start();
|
||||
procMap.put(deviceId, p);
|
||||
new Thread(() -> pumpProcessOutput(deviceId, p)).start();
|
||||
return retHint;
|
||||
} catch (Exception e){
|
||||
return "start failed: "+ e.getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void stop(String deviceId){
|
||||
Process p = procMap.get(deviceId);
|
||||
if(p!=null){
|
||||
p.destroy();
|
||||
procMap.remove(deviceId);
|
||||
}
|
||||
RtkOutServer s = outServerMap.get(deviceId);
|
||||
if(s!=null){
|
||||
s.close();
|
||||
outServerMap.remove(deviceId);
|
||||
}
|
||||
}
|
||||
|
||||
private void pumpProcessOutput(String deviceId, Process p){
|
||||
try (BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream(), StandardCharsets.UTF_8))){
|
||||
String line;
|
||||
while((line = br.readLine()) != null){
|
||||
try{ beidouClient.onRtkrcvAck(deviceId, line); } catch (Exception ignore) {}
|
||||
}
|
||||
} catch (IOException ignored) {}
|
||||
}
|
||||
|
||||
private RtkProfile getOrCreateProfile(String deviceId){
|
||||
QueryWrapper<RtkProfile> q = new QueryWrapper<>();
|
||||
q.eq("device_id", deviceId);
|
||||
RtkProfile p = profileMapper.selectOne(q);
|
||||
if(p==null){
|
||||
p = new RtkProfile();
|
||||
p.setDevice_id(deviceId);
|
||||
p.setPos1_posmode("static");
|
||||
p.setInpstr1_type("ntripcli");
|
||||
p.setOut_height("geodetic");
|
||||
profileMapper.insert(p);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
private void ensureDefaults(RtkProfile p, String deviceId){
|
||||
if(p.getInpstr1_type()==null || p.getInpstr1_type().isEmpty()) p.setInpstr1_type("ntripcli");
|
||||
if(p.getPos1_posmode()==null || p.getPos1_posmode().isEmpty()) p.setPos1_posmode("static");
|
||||
if(p.getOut_height()==null || p.getOut_height().isEmpty()) p.setOut_height("geodetic");
|
||||
if((p.getInpstr1_path()==null || p.getInpstr1_path().isEmpty()) && "ntripcli".equalsIgnoreCase(p.getInpstr1_type())){
|
||||
p.setInpstr1_path("beidou:29832611@8.134.185.53:8001/"+deviceId);
|
||||
}
|
||||
if(p.getOutstr2_path()==null || p.getOutstr2_path().isEmpty()){
|
||||
int port = pickFreePort();
|
||||
p.setOutstr2_path("127.0.0.1:"+port);
|
||||
}
|
||||
}
|
||||
|
||||
private int pickFreePort(){
|
||||
try (ServerSocket socket = new ServerSocket(0)){
|
||||
return socket.getLocalPort();
|
||||
} catch (IOException e){
|
||||
return 24001;
|
||||
}
|
||||
}
|
||||
|
||||
private String generateConfig(String deviceId, RtkProfile profile, RtkGroup group) throws IOException {
|
||||
ClassPathResource res = new ClassPathResource("rtkrcv_default.conf");
|
||||
String template;
|
||||
try (InputStream is = res.getInputStream(); ByteArrayOutputStream bos = new ByteArrayOutputStream()){
|
||||
byte[] buf = new byte[4096];
|
||||
int n;
|
||||
while((n = is.read(buf)) != -1){ bos.write(buf, 0, n); }
|
||||
template = bos.toString(StandardCharsets.UTF_8.name());
|
||||
}
|
||||
|
||||
template = replaceLine(template, "pos1-posmode", profile.getPos1_posmode());
|
||||
template = replaceLine(template, "out-height", profile.getOut_height());
|
||||
template = replaceLine(template, "inpstr1-type", profile.getInpstr1_type());
|
||||
if(profile.getInpstr1_path()!=null) template = replaceLine(template, "inpstr1-path", profile.getInpstr1_path());
|
||||
if(group.getInpstr2_path()!=null) template = replaceLine(template, "inpstr2-path", group.getInpstr2_path());
|
||||
if(group.getInpstr3_path()!=null) template = replaceLine(template, "inpstr3-path", group.getInpstr3_path());
|
||||
if(profile.getOutstr2_path()!=null) template = replaceLine(template, "outstr2-path", profile.getOutstr2_path());
|
||||
|
||||
Path dir = Paths.get("/opt/rtk/"+deviceId);
|
||||
Files.createDirectories(dir);
|
||||
Path conf = dir.resolve("rtkrcv.conf");
|
||||
Files.write(conf, template.getBytes(StandardCharsets.UTF_8));
|
||||
return conf.toAbsolutePath().toString();
|
||||
}
|
||||
|
||||
private String replaceLine(String content, String key, String value){
|
||||
String[] lines = content.split("\n");
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String prefix = key + " =";
|
||||
for(String line : lines){
|
||||
if(line.trim().startsWith(key+" =") || line.trim().startsWith(key+" =") || line.trim().startsWith(key+" =")){
|
||||
sb.append(key).append(" =").append(value).append("\n");
|
||||
}else{
|
||||
sb.append(line).append("\n");
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private void startOutServerIfNeeded(String deviceId, String outstr2Path){
|
||||
if(outstr2Path == null || outstr2Path.isEmpty()) return;
|
||||
if(outServerMap.containsKey(deviceId)) return;
|
||||
try{
|
||||
int port = parsePort(outstr2Path);
|
||||
RtkOutServer server = new RtkOutServer(deviceId, port, beidouClient);
|
||||
server.start();
|
||||
outServerMap.put(deviceId, server);
|
||||
}catch(Exception ignored){ }
|
||||
}
|
||||
|
||||
private int parsePort(String hostPort){
|
||||
int idx = hostPort.lastIndexOf(':');
|
||||
if(idx>0){
|
||||
return Integer.parseInt(hostPort.substring(idx+1));
|
||||
}
|
||||
return Integer.parseInt(hostPort);
|
||||
}
|
||||
|
||||
private void clearLogFile(String deviceId){
|
||||
Path dir = Paths.get("/opt/rtk/"+deviceId);
|
||||
Path log = dir.resolve("rtkrcv.log");
|
||||
try {
|
||||
Files.createDirectories(dir);
|
||||
Files.write(log, new byte[0]);
|
||||
} catch (IOException ignored) {}
|
||||
}
|
||||
}
|
||||
@ -62,6 +62,10 @@ public class Device {
|
||||
Double latitude;
|
||||
Double longitude;
|
||||
Double altitude;
|
||||
// 大地水准面相对椭球面的高度差
|
||||
// 博通 GGA 此处可能非零,影响 RTK 运算,故需通过此属性判断。
|
||||
Double geoidSeparation = 0.0;
|
||||
|
||||
Double ecefx;
|
||||
Double ecefy;
|
||||
Double ecefz;
|
||||
@ -93,6 +97,11 @@ public class Device {
|
||||
byte dataChannelType = CHANNEL_TYPE_UDP; // 0:TCP;1:DUP
|
||||
int lasQuality = 0;
|
||||
|
||||
Double minAngleX;
|
||||
Double maxAngleX;
|
||||
Double minAngleY;
|
||||
Double maxAngleY;
|
||||
|
||||
public void updateRx(int head, int bytes,int count){
|
||||
lastRxHead = head;
|
||||
|
||||
@ -155,6 +164,11 @@ public class Device {
|
||||
fixedNum = 0;
|
||||
floatNum = 0;
|
||||
jumpCount = 0;
|
||||
|
||||
minAngleX=null;
|
||||
minAngleY=null;
|
||||
maxAngleX=null;
|
||||
maxAngleY=null;
|
||||
}
|
||||
|
||||
public void clearD342Stat(){
|
||||
@ -169,4 +183,24 @@ public class Device {
|
||||
abnormalD341Num = 0;
|
||||
}
|
||||
|
||||
public void updateMinMaxAngle(double x, double y){
|
||||
if(minAngleX == null || maxAngleX == null){
|
||||
minAngleX = x;
|
||||
maxAngleX = x;
|
||||
}
|
||||
else{
|
||||
if(x<minAngleX) minAngleX = x;
|
||||
if(x>maxAngleX) maxAngleX = x;
|
||||
}
|
||||
|
||||
if(minAngleY == null || maxAngleY == null){
|
||||
minAngleY = y;
|
||||
maxAngleY = y;
|
||||
}
|
||||
else{
|
||||
if(y<minAngleY) minAngleY = y;
|
||||
if(y>maxAngleY) maxAngleY = y;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -7,9 +7,9 @@ spring.application.build=20230924
|
||||
spring.jpa.show-sql = true
|
||||
spring.jpa.hibernate.ddl-auto = none
|
||||
spring.jpa.database-platform = org.hibernate.dialect.MySQLDialect
|
||||
spring.datasource.url = jdbc:mysql://localhost:3306/beidou?characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
|
||||
spring.datasource.username = admin
|
||||
spring.datasource.password = DBMgr_2022
|
||||
spring.datasource.url = jdbc:mysql://8.134.185.53:3306/beidou?characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai&useSSL=false
|
||||
spring.datasource.username=remote
|
||||
spring.datasource.password=root
|
||||
spring.datasource.driverClassName = com.mysql.cj.jdbc.Driver
|
||||
|
||||
spring.jackson.dateFormat = yyyy-MM-dd HH:mm:ss
|
||||
|
||||
161
sec-beidou-rtcm/src/main/resources/rtkrcv_default.conf
Normal file
161
sec-beidou-rtcm/src/main/resources/rtkrcv_default.conf
Normal file
@ -0,0 +1,161 @@
|
||||
# RTKNAVI options (template)
|
||||
|
||||
pos1-posmode =static
|
||||
pos1-frequency =l1+l2+l5
|
||||
pos1-soltype =forward
|
||||
pos1-elmask =10
|
||||
pos1-snrmask_r =on
|
||||
pos1-snrmask_b =on
|
||||
pos1-snrmask_L1 =0,0,0,0,0,0,0,0,0
|
||||
pos1-snrmask_L2 =0,0,0,0,0,0,0,0,0
|
||||
pos1-snrmask_L5 =0,0,0,0,0,0,0,0,0
|
||||
pos1-dynamics =off
|
||||
pos1-tidecorr =off
|
||||
pos1-ionoopt =brdc
|
||||
pos1-tropopt =saas
|
||||
pos1-sateph =brdc+sbas
|
||||
pos1-posopt1 =off
|
||||
pos1-posopt2 =off
|
||||
pos1-posopt3 =off
|
||||
pos1-posopt4 =off
|
||||
pos1-posopt5 =off
|
||||
pos1-posopt6 =off
|
||||
pos1-exclsats =
|
||||
pos1-navsys =45
|
||||
pos2-armode =continuous
|
||||
pos2-gloarmode =fix-and-hold
|
||||
pos2-bdsarmode =on
|
||||
pos2-arfilter =on
|
||||
pos2-arthres =3
|
||||
pos2-arthresmin =2
|
||||
pos2-arthresmax =2
|
||||
pos2-arthres1 =0.1
|
||||
pos2-arthres2 =0
|
||||
pos2-arthres3 =1e-09
|
||||
pos2-arthres4 =1e-05
|
||||
pos2-varholdamb =0.1
|
||||
pos2-gainholdamb =0.01
|
||||
pos2-arlockcnt =5
|
||||
pos2-minfixsats =4
|
||||
pos2-minholdsats =5
|
||||
pos2-mindropsats =10
|
||||
pos2-arelmask =10
|
||||
pos2-arminfix =20
|
||||
pos2-armaxiter =1
|
||||
pos2-elmaskhold =10
|
||||
pos2-aroutcnt =20
|
||||
pos2-maxage =30
|
||||
pos2-syncsol =off
|
||||
pos2-slipthres =0.05
|
||||
pos2-dopthres =0
|
||||
pos2-rejionno =5
|
||||
pos2-rejcode =30
|
||||
pos2-niter =1
|
||||
pos2-baselen =0
|
||||
pos2-basesig =0
|
||||
out-solformat =llh
|
||||
out-outhead =on
|
||||
out-outopt =on
|
||||
out-outvel =off
|
||||
out-timesys =gpst
|
||||
out-timeform =hms
|
||||
out-timendec =3
|
||||
out-degform =deg
|
||||
out-fieldsep =
|
||||
out-outsingle =off
|
||||
out-maxsolstd =0
|
||||
out-height =geodetic
|
||||
out-geoid =internal
|
||||
out-solstatic =all
|
||||
out-nmeaintv1 =0
|
||||
out-nmeaintv2 =0
|
||||
out-outstat =residual
|
||||
stats-eratio1 =300
|
||||
stats-eratio2 =300
|
||||
stats-eratio5 =300
|
||||
stats-errphase =0.003
|
||||
stats-errphaseel =0.003
|
||||
stats-errphasebl =0
|
||||
stats-errdoppler =1
|
||||
stats-snrmax =52
|
||||
stats-errsnr =0
|
||||
stats-errrcv =0
|
||||
stats-stdbias =30
|
||||
stats-stdiono =0.03
|
||||
stats-stdtrop =0.3
|
||||
stats-prnaccelh =3
|
||||
stats-prnaccelv =1
|
||||
stats-prnbias =0.0001
|
||||
stats-prniono =0.001
|
||||
stats-prntrop =0.0001
|
||||
stats-prnpos =0
|
||||
stats-clkstab =5e-12
|
||||
ant1-postype =llh
|
||||
ant1-pos1 =90
|
||||
ant1-pos2 =0
|
||||
ant1-pos3 =-6335367.6285
|
||||
ant1-anttype =
|
||||
ant1-antdele =0
|
||||
ant1-antdeln =0
|
||||
ant1-antdelu =0
|
||||
ant2-postype =rtcm
|
||||
ant2-pos1 =0
|
||||
ant2-pos2 =0
|
||||
ant2-pos3 =0
|
||||
ant2-anttype =
|
||||
ant2-antdele =0
|
||||
ant2-antdeln =0
|
||||
ant2-antdelu =0
|
||||
ant2-maxaveep =1
|
||||
ant2-initrst =on
|
||||
misc-timeinterp =off
|
||||
misc-sbasatsel =0
|
||||
misc-rnxopt1 =
|
||||
misc-rnxopt2 =
|
||||
misc-pppopt =
|
||||
file-satantfile =
|
||||
file-rcvantfile =
|
||||
file-staposfile =
|
||||
file-geoidfile =
|
||||
file-ionofile =
|
||||
file-dcbfile =
|
||||
file-eopfile =
|
||||
file-blqfile =
|
||||
file-tempdir =./RTKNAVI
|
||||
file-geexefile =
|
||||
file-solstatfile =
|
||||
file-tracefile =
|
||||
|
||||
inpstr1-type =ntripcli
|
||||
inpstr2-type =ntripcli
|
||||
inpstr3-type =ntripcli
|
||||
inpstr1-path =beidou:29832611@8.134.185.53:8001/6539837
|
||||
inpstr2-path =ytcors14847:fyx25943@gnss.ytcors.cn:8003/RTCM33GRCEJpro
|
||||
inpstr3-path =Ming:@Zhang12345@ntrip.data.gnss.ga.gov.au:2101/BCEP00BKG0
|
||||
inpstr1-format =rtcm3
|
||||
inpstr2-format =rtcm3
|
||||
inpstr3-format =rtcm3
|
||||
inpstr2-nmeareq =single
|
||||
inpstr2-nmealat =
|
||||
inpstr2-nmealon =
|
||||
outstr1-type =off
|
||||
outstr2-type =tcpcli
|
||||
outstr1-path =127.0.0.1:60000
|
||||
outstr2-path =127.0.0.1:24001
|
||||
outstr1-format =xyz
|
||||
outstr2-format =llh
|
||||
logstr1-type =off
|
||||
logstr2-type =off
|
||||
logstr3-type =off
|
||||
logstr1-path =
|
||||
logstr2-path =
|
||||
logstr3-path =
|
||||
misc-svrcycle =10
|
||||
misc-timeout =10000
|
||||
misc-reconnect =10000
|
||||
misc-nmeacycle =5000
|
||||
misc-buffsize =32768
|
||||
misc-navmsgsel =all
|
||||
misc-proxyaddr =
|
||||
misc-fswapmargin =30
|
||||
console-passwd =
|
||||
@ -36,6 +36,10 @@ public class APIController extends BasicController {
|
||||
WarningMsgMapper warningMsgMapper;
|
||||
@Autowired
|
||||
GnssStatusMapper gnssStatusMapper;
|
||||
@Autowired
|
||||
com.imdroid.secapi.dto.RtkSolutionMapper rtkSolutionMapper;
|
||||
@Autowired
|
||||
com.imdroid.beidou.service.RtkMonitorService rtkMonitorService;
|
||||
|
||||
/****** config ack *******/
|
||||
@PostMapping(value = "/api/config_ack")
|
||||
@ -44,20 +48,24 @@ public class APIController extends BasicController {
|
||||
GnssDevice device = deviceMapper.queryByDeviceId(deviceId);
|
||||
if (device == null) return null;
|
||||
|
||||
int msgType = Integer.parseInt(configAck.substring(0, 4), 16);
|
||||
byte[] hexValues = ByteUtil.hexStringTobyte(configAck);
|
||||
// d3 12 00 12 00 81 e7 6f
|
||||
if(hexValues.length < 9) return null;
|
||||
|
||||
int msgType = ByteUtil.getUnsignedShort(hexValues[0],hexValues[1]);
|
||||
byte code = hexValues[8];
|
||||
// 配置是否成功
|
||||
if (msgType == 0xd311) {
|
||||
//最后一个字节为1表示配置成功,0表示配置失败
|
||||
if (configAck.endsWith("01")) {
|
||||
if (hexValues[hexValues.length-1] == 1) {
|
||||
device.setSyn(true);
|
||||
deviceMapper.updateById(device);
|
||||
}
|
||||
} else if (msgType == 0xd312) {
|
||||
} else if (msgType == 0xd312 || msgType == 0xd313) {
|
||||
// 工作周期一致性检查
|
||||
checkWorkCycle(device, configAck);
|
||||
} else if (msgType == 0xd313) {
|
||||
if(device.getChange_flag()!=0) {
|
||||
if(device.clearChangeFlag(configAck)){
|
||||
if(msgType == 0xd312 && code == 1) checkWorkCycle(device, hexValues);
|
||||
else if((code&0xF0) == 0x50 && device.getChange_flag()!=0){
|
||||
if(device.clearChangeFlag(hexValues)){
|
||||
deviceMapper.updateById(device);
|
||||
}
|
||||
}
|
||||
@ -90,10 +98,9 @@ public class APIController extends BasicController {
|
||||
return null;
|
||||
}
|
||||
|
||||
void checkWorkCycle(GnssDevice device, String cfgData) {
|
||||
void checkWorkCycle(GnssDevice device, byte[] hexValues) {
|
||||
// d3 12 00 12 00 81 e7 6f 01 0a09000001c2dd7ae1419ee148
|
||||
int pos = 9;
|
||||
byte[] hexValues = ByteUtil.hexStringTobyte(cfgData);
|
||||
byte workCycle = hexValues[pos++];
|
||||
byte workDur = hexValues[pos++];
|
||||
byte workOffset = hexValues[pos++];
|
||||
@ -356,4 +363,74 @@ public class APIController extends BasicController {
|
||||
// 保存升级记录
|
||||
return null;
|
||||
}
|
||||
@PostMapping(value = "/api/rtkrcv_ack")
|
||||
@ResponseBody
|
||||
public String onRtkRcvAck(String deviceId, String data) {
|
||||
if(data == null) data = "";
|
||||
String line = data.trim();
|
||||
try {
|
||||
String time = "";
|
||||
double lat = 0, lon = 0, h = 0;
|
||||
int q = -1, ns = -1;
|
||||
String s = line;
|
||||
if(s.startsWith("RTK ")){
|
||||
String[] ps = s.split("\\s+");
|
||||
// RTK dev yyyy/mm/dd hh:mm:ss ...
|
||||
if(ps.length > 4) {
|
||||
s = s.substring(s.indexOf(ps[3]));
|
||||
}
|
||||
}
|
||||
String[] tok = s.split("\\s+");
|
||||
if(tok.length >= 7){
|
||||
time = tok[0] + (tok[1].contains(":")? (" " + tok[1]) : "");
|
||||
int base = tok[1].contains(":")? 2 : 1;
|
||||
lat = Double.parseDouble(tok[base]);
|
||||
lon = Double.parseDouble(tok[base+1]);
|
||||
h = Double.parseDouble(tok[base+2]);
|
||||
q = Integer.parseInt(tok[base+3]);
|
||||
ns = Integer.parseInt(tok[base+4]);
|
||||
}
|
||||
com.alibaba.fastjson.JSONObject obj = new com.alibaba.fastjson.JSONObject();
|
||||
obj.put("type","rtk");
|
||||
obj.put("deviceId", deviceId);
|
||||
obj.put("time", time);
|
||||
obj.put("lat", lat);
|
||||
obj.put("lon", lon);
|
||||
obj.put("h", h);
|
||||
obj.put("q", q);
|
||||
obj.put("ns", ns);
|
||||
obj.put("raw", line);
|
||||
RtkrcvWebSocketServer.sendMessageToAll(obj.toJSONString());
|
||||
if(q == 1){
|
||||
com.imdroid.secapi.dto.RtkSolution sol = new com.imdroid.secapi.dto.RtkSolution();
|
||||
sol.setDevice_id(deviceId);
|
||||
sol.setLatitude(lat);
|
||||
sol.setLongitude(lon);
|
||||
sol.setAltitude(h);
|
||||
sol.setStatus((short)1);
|
||||
try{ rtkSolutionMapper.insert(sol);}catch(Exception ignore){}
|
||||
}
|
||||
if(q >= 0){
|
||||
rtkMonitorService.onSolution(deviceId, q);
|
||||
}
|
||||
} catch (Exception e){
|
||||
String msg = "RTK " + deviceId + " " + line;
|
||||
RtkrcvWebSocketServer.sendMessageToAll(msg);
|
||||
}
|
||||
return "ok";
|
||||
}
|
||||
|
||||
@PostMapping(value = "/api/rtk_gngga")
|
||||
@ResponseBody
|
||||
public String onRtkGngga(String deviceId, Double lat, Double lon, Double alt, Double geo) {
|
||||
com.alibaba.fastjson.JSONObject obj = new com.alibaba.fastjson.JSONObject();
|
||||
obj.put("type","rtk_gngga");
|
||||
obj.put("deviceId", deviceId);
|
||||
obj.put("lat", lat);
|
||||
obj.put("lon", lon);
|
||||
obj.put("alt", alt);
|
||||
obj.put("geo", geo);
|
||||
RtkrcvWebSocketServer.sendMessageToAll(obj.toJSONString());
|
||||
return "ok";
|
||||
}
|
||||
}
|
||||
@ -48,6 +48,8 @@ public class DeviceSummaryController extends BasicController{
|
||||
jsonObject.put("satNum",gnssStatus.getSatelliteinuse()>=12?"多于12":gnssStatus.getSatelliteinuse());
|
||||
jsonObject.put("rxBytes",gnssStatus.getB562bytes()+gnssStatus.getD3xxbytes());
|
||||
jsonObject.put("rssi",gnssStatus.getRssi());
|
||||
jsonObject.put("loc",NumberUtils.scale(gnssStatus.getLongitude(), 8)
|
||||
+","+NumberUtils.scale(gnssStatus.getLatitude(), 8));
|
||||
}
|
||||
return jsonObject;
|
||||
}
|
||||
|
||||
@ -145,6 +145,11 @@ public class GnssDeviceController extends BasicController{
|
||||
if (StringUtils.hasText(deviceid)) {
|
||||
queryWrapper.like("deviceid", deviceid);
|
||||
}
|
||||
//型号
|
||||
Integer model = search.getInteger("model");
|
||||
if (model!=null) {
|
||||
queryWrapper.eq("model", model);
|
||||
}
|
||||
//父设备号
|
||||
String parentid = search.getString("parentid");
|
||||
if (StringUtils.hasText(parentid)) {
|
||||
@ -155,6 +160,11 @@ public class GnssDeviceController extends BasicController{
|
||||
if (StringUtils.hasText(project_id)) {
|
||||
queryWrapper.like("project_id", project_id);
|
||||
}
|
||||
//桩号
|
||||
String sector = search.getString("sector");
|
||||
if (StringUtils.hasText(sector)) {
|
||||
queryWrapper.like("sector", sector);
|
||||
}
|
||||
//所属组织
|
||||
String tenantname = search.getString("tenantname");
|
||||
if (StringUtils.hasText(tenantname)) {
|
||||
|
||||
@ -99,7 +99,7 @@ public class GnssStatusController extends BasicController implements CommonExcel
|
||||
public MPJQueryWrapper<GnssStatus> prepareQueryWrapper() {
|
||||
return new MPJQueryWrapper<GnssStatus>()
|
||||
.selectAll(GnssStatus.class)
|
||||
.select("d.devicetype as devicetype,d.remark as remark,d.iccid as iccid")
|
||||
.select("d.devicetype as devicetype,d.remark as remark,d.iccid as iccid,d.tenantname as tenantname")
|
||||
.leftJoin("gnssdevices d on t.deviceid = d.deviceid")
|
||||
.orderByDesc("t.updatetime");
|
||||
}
|
||||
|
||||
@ -0,0 +1,41 @@
|
||||
package com.imdroid.beidou.controller;
|
||||
|
||||
import com.imdroid.beidou.common.HttpResult;
|
||||
import com.imdroid.beidou.service.GroupRtkScheduler;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
public class GroupRtkController {
|
||||
@Autowired
|
||||
GroupRtkScheduler scheduler;
|
||||
|
||||
@PostMapping("/rtk/group/start")
|
||||
public HttpResult start(@RequestParam("group_id") Integer groupId,
|
||||
@RequestParam(value = "clear_log", required = false) Boolean clearLog){
|
||||
scheduler.startGroup(groupId, clearLog!=null && clearLog);
|
||||
return HttpResult.success("ok");
|
||||
}
|
||||
|
||||
@PostMapping("/rtk/group/stop")
|
||||
public HttpResult stop(@RequestParam("group_id") Integer groupId){
|
||||
scheduler.stopGroup(groupId);
|
||||
return HttpResult.success("ok");
|
||||
}
|
||||
|
||||
@GetMapping("/rtk/group/status")
|
||||
public Map<String,Object> status(@RequestParam("group_id") Integer groupId){
|
||||
List<Map<String,Object>> data = scheduler.getStatus(groupId);
|
||||
Map<String,Object> r = new HashMap<>();
|
||||
r.put("code",0);
|
||||
r.put("data", data);
|
||||
r.put("count", data.size());
|
||||
r.put("msg","");
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,6 +14,7 @@ import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import javax.servlet.http.HttpSession;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
@ -39,15 +40,16 @@ public class IndexController extends BasicController{
|
||||
@RequestMapping("/page/device_overview")
|
||||
public String deviceOverview(Model m, HttpSession session) {
|
||||
initModel(m, session);
|
||||
int deviceDeployedNum;
|
||||
int deviceOfflineNum=0;
|
||||
int deviceDeployedNum = 0;
|
||||
int deviceOfflineNum = 0;
|
||||
int deviceOfflineNumIn24h = 0;
|
||||
int warning1Num=0;//一般告警
|
||||
int warning2Num=0;//严重告警
|
||||
int noGGA = 0;
|
||||
int noFix = 0;
|
||||
long deviceNoFwdNum=0;
|
||||
|
||||
//未推送设备数(同时满足:非SAAS服务商、使用状态正常、fwd_group_id和fwd_group_id2都为"不推送"的设备)
|
||||
Long deviceNoFwdNum;
|
||||
QueryWrapper<GnssDevice> noFwdQueryWrapper = new QueryWrapper<>();
|
||||
if (tenantId != Tenant.SAAS_PROVIDER_ID) {
|
||||
// 非SAAS服务商查询当前租户
|
||||
@ -63,7 +65,7 @@ public class IndexController extends BasicController{
|
||||
// fwd_group_id为"不推送"
|
||||
noFwdQueryWrapper.eq("fwd_group_id", GnssGroupFwd.FWD_TYPE_NONE);
|
||||
// fwd_group_id2为"不推送"或为null
|
||||
noFwdQueryWrapper.and(wrapper -> wrapper.eq("fwd_group_id2", GnssGroupFwd.FWD_TYPE_NONE).or().isNull("fwd_group_id2"));
|
||||
//noFwdQueryWrapper.and(wrapper -> wrapper.eq("fwd_group_id2", GnssGroupFwd.FWD_TYPE_NONE).or().isNull("fwd_group_id2"));
|
||||
deviceNoFwdNum = gnssDeviceMapper.selectCount(noFwdQueryWrapper);
|
||||
|
||||
List<GnssStatusJoin> deviceList;
|
||||
@ -76,19 +78,26 @@ public class IndexController extends BasicController{
|
||||
deviceDeployedNum = deviceList.size();
|
||||
|
||||
//for(GnssStatusJoin status:deviceList){遍历删除异常
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
Iterator<GnssStatusJoin> iterator = deviceList.iterator();
|
||||
while(iterator.hasNext()){
|
||||
GnssStatusJoin status=iterator.next();
|
||||
if(status.getState() == GnssStatus.STATE_OFFLINE) {
|
||||
deviceOfflineNum++;
|
||||
if(status.getUpdatetime()!=null &&
|
||||
status.getUpdatetime().isAfter(now.minusHours(24))){
|
||||
deviceOfflineNumIn24h++;
|
||||
status.setWarning((short) 3);
|
||||
}
|
||||
else {
|
||||
status.setWarning((short) 2);
|
||||
}
|
||||
}
|
||||
else if((status.getWarningcode()&WarningCfg.TYPE_CONT_INVALID_RESULT) != 0) {
|
||||
noFix++;
|
||||
status.setWarning((short) 4);
|
||||
}
|
||||
|
||||
if(status.getWarning() == WarningCfg.LEVEL_1) warning1Num++;
|
||||
else if(status.getWarning() == WarningCfg.LEVEL_2) warning2Num++;
|
||||
|
||||
// 剔除无经纬度的对象,不在地图上显示
|
||||
if(status.getLatitude()==null || status.getLongitude()==null){
|
||||
noGGA++;
|
||||
@ -115,6 +124,7 @@ public class IndexController extends BasicController{
|
||||
m.addAttribute("deviceDeployedNum", deviceDeployedNum);
|
||||
m.addAttribute("deviceOnlineNum", deviceDeployedNum-deviceOfflineNum);
|
||||
m.addAttribute("deviceOfflineNum", deviceOfflineNum);
|
||||
m.addAttribute("deviceOfflineNumIn24h", deviceOfflineNumIn24h);
|
||||
m.addAttribute("warning1Num", warning1Num);
|
||||
m.addAttribute("warning2Num", warning2Num);
|
||||
m.addAttribute("warningTotalNum", warning1Num+warning2Num);
|
||||
@ -144,7 +154,7 @@ public class IndexController extends BasicController{
|
||||
Integer tenantId = getTenantId(session);
|
||||
if(tenantId == Tenant.SAAS_PROVIDER_ID) {
|
||||
queryWrapper.selectAll(GnssStatus.class)
|
||||
.select("d.name as name", "d.devicetype as devicetype", "d.project_id as project_id")
|
||||
.select("d.name as name", "d.devicetype as devicetype", "d.tenantname as tenantname","d.project_id as project_id")
|
||||
.leftJoin("gnssdevices d on t.deviceid = d.deviceid")
|
||||
.ne("d.tenantid", Tenant.SAAS_PROVIDER_ID)
|
||||
.eq("opmode", GnssDevice.OP_MODE_USE)
|
||||
@ -152,7 +162,7 @@ public class IndexController extends BasicController{
|
||||
}
|
||||
else{
|
||||
queryWrapper.selectAll(GnssStatus.class)
|
||||
.select("d.name as name", "d.devicetype as devicetype", "d.project_id as project_id")
|
||||
.select("d.name as name", "d.devicetype as devicetype", "d.tenantname as tenantname", "d.project_id as project_id")
|
||||
.leftJoin("gnssdevices d on t.deviceid = d.deviceid")
|
||||
.eq("d.tenantid", tenantId)
|
||||
.eq("opmode", GnssDevice.OP_MODE_USE)
|
||||
@ -164,6 +174,10 @@ public class IndexController extends BasicController{
|
||||
if(query.equals("offline")){
|
||||
queryWrapper.eq("state",GnssStatus.STATE_OFFLINE);
|
||||
}
|
||||
else if(query.equals("offline_in24h")){
|
||||
queryWrapper.eq("state",GnssStatus.STATE_OFFLINE);
|
||||
queryWrapper.ge("t.updatetime",LocalDateTime.now().minusHours(24));
|
||||
}
|
||||
else if(query.equals("nofixed")){
|
||||
queryWrapper.eq("warningcode&"+WarningCfg.TYPE_CONT_INVALID_RESULT,WarningCfg.TYPE_CONT_INVALID_RESULT);
|
||||
}
|
||||
|
||||
@ -0,0 +1,209 @@
|
||||
package com.imdroid.beidou.controller;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.imdroid.beidou.common.HttpResult;
|
||||
import com.imdroid.secapi.dto.OpLogManager;
|
||||
import com.imdroid.secapi.dto.*;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
@Controller
|
||||
public class RtkGroupController extends BasicController {
|
||||
@Autowired
|
||||
RtkGroupMapper rtkGroupMapper;
|
||||
@Autowired
|
||||
RtkProfileMapper rtkProfileMapper;
|
||||
@Autowired
|
||||
GnssDeviceMapper gnssDeviceMapper;
|
||||
@Autowired
|
||||
OpLogManager opLogManager;
|
||||
|
||||
@RequestMapping("/page/table/rtk_group_edit")
|
||||
public String rtkGroupEdit(Model m, HttpSession session) {
|
||||
initModel(m, session);
|
||||
return "/page/table/rtk_group_edit";
|
||||
}
|
||||
|
||||
@RequestMapping("/page/table/rtk_profile_edit")
|
||||
public String rtkProfileEdit(Model m, HttpSession session) {
|
||||
initModel(m, session);
|
||||
return "/page/table/rtk_profile_edit";
|
||||
}
|
||||
|
||||
@RequestMapping("/rtk/group/list")
|
||||
@ResponseBody
|
||||
public JSONObject list(int page, int limit) {
|
||||
Page<RtkGroup> pageable = new Page<>(page, limit);
|
||||
IPage<RtkGroup> cs = rtkGroupMapper.selectPage(pageable, null);
|
||||
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put("code", 0);
|
||||
jsonObject.put("msg", "");
|
||||
jsonObject.put("count", cs.getTotal());
|
||||
jsonObject.put("data", cs.getRecords());
|
||||
return jsonObject;
|
||||
}
|
||||
|
||||
@RequestMapping("/rtk/profile/list")
|
||||
@ResponseBody
|
||||
public com.alibaba.fastjson.JSONObject listProfiles(@RequestParam int page,
|
||||
@RequestParam int limit,
|
||||
@RequestParam(value = "group_id", required = false) Integer groupId,
|
||||
@RequestParam(value = "device_id", required = false) String deviceId) {
|
||||
com.baomidou.mybatisplus.extension.plugins.pagination.Page<RtkProfile> pageable = new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(page, limit);
|
||||
QueryWrapper<RtkProfile> wrapper = new QueryWrapper<>();
|
||||
if (groupId != null) wrapper.eq("rtkgroup_id", groupId);
|
||||
if (deviceId != null && !deviceId.isEmpty()) wrapper.like("device_id", deviceId);
|
||||
com.baomidou.mybatisplus.core.metadata.IPage<RtkProfile> cs = rtkProfileMapper.selectPage(pageable, wrapper);
|
||||
|
||||
com.alibaba.fastjson.JSONObject jsonObject = new com.alibaba.fastjson.JSONObject();
|
||||
jsonObject.put("code", 0);
|
||||
jsonObject.put("msg", "");
|
||||
jsonObject.put("count", cs.getTotal());
|
||||
jsonObject.put("data", cs.getRecords());
|
||||
return jsonObject;
|
||||
}
|
||||
|
||||
@PostMapping("/rtk/profile/update")
|
||||
@ResponseBody
|
||||
public HttpResult updateProfile(@RequestBody com.alibaba.fastjson.JSONObject object) {
|
||||
RtkProfile profile = com.alibaba.fastjson.JSONObject.toJavaObject(object, RtkProfile.class);
|
||||
if ((profile.getId() == null) && (profile.getDevice_id() == null || profile.getDevice_id().isEmpty())) {
|
||||
return HttpResult.fail("device_id不能为空");
|
||||
}
|
||||
if (profile.getInpstr1_type() == null || profile.getInpstr1_type().isEmpty()) profile.setInpstr1_type("ntripcli");
|
||||
if (profile.getPos1_posmode() == null || profile.getPos1_posmode().isEmpty()) profile.setPos1_posmode("static");
|
||||
if (profile.getOut_height() == null || profile.getOut_height().isEmpty()) profile.setOut_height("geodetic");
|
||||
|
||||
RtkProfile exist = null;
|
||||
if (profile.getId() != null) exist = rtkProfileMapper.selectById(profile.getId());
|
||||
if (exist == null && profile.getDevice_id() != null) {
|
||||
QueryWrapper<RtkProfile> q = new QueryWrapper<>();
|
||||
q.eq("device_id", profile.getDevice_id());
|
||||
exist = rtkProfileMapper.selectOne(q);
|
||||
}
|
||||
int num;
|
||||
if (exist == null) {
|
||||
num = rtkProfileMapper.insert(profile);
|
||||
} else {
|
||||
profile.setId(exist.getId());
|
||||
num = rtkProfileMapper.updateById(profile);
|
||||
}
|
||||
if (num == 0) return HttpResult.fail("保存失败");
|
||||
return HttpResult.success("ok");
|
||||
}
|
||||
|
||||
@GetMapping("/rtk/transfer/options")
|
||||
@ResponseBody
|
||||
public HttpResult transferOptions(@RequestParam("group_id") Integer groupId) {
|
||||
java.util.List<GnssDevice> all = gnssDeviceMapper.selectList(null);
|
||||
java.util.List<java.util.Map<String, Object>> data = new java.util.ArrayList<>();
|
||||
for (GnssDevice d : all) {
|
||||
java.util.HashMap<String, Object> m = new java.util.HashMap<>();
|
||||
m.put("value", d.getDeviceid());
|
||||
String title = d.getDeviceid();
|
||||
if (d.getName() != null && !d.getName().isEmpty()) title += " " + d.getName();
|
||||
m.put("title", title);
|
||||
data.add(m);
|
||||
}
|
||||
QueryWrapper<RtkProfile> qw = new QueryWrapper<>();
|
||||
qw.eq("rtkgroup_id", groupId);
|
||||
java.util.List<RtkProfile> profiles = rtkProfileMapper.selectList(qw);
|
||||
java.util.List<String> selected = new java.util.ArrayList<>();
|
||||
for (RtkProfile p : profiles) selected.add(p.getDevice_id());
|
||||
java.util.HashMap<String, Object> resp = new java.util.HashMap<>();
|
||||
resp.put("data", data);
|
||||
resp.put("value", selected);
|
||||
return HttpResult.success(resp);
|
||||
}
|
||||
|
||||
@PostMapping("/rtk/profile/save_group_devices")
|
||||
@ResponseBody
|
||||
public HttpResult saveGroupDevices(@RequestBody JSONObject body) {
|
||||
Integer groupId = body.getInteger("group_id");
|
||||
java.util.List<String> deviceIds = body.getJSONArray("device_ids").toJavaList(String.class);
|
||||
QueryWrapper<RtkProfile> qw = new QueryWrapper<>();
|
||||
qw.eq("rtkgroup_id", groupId);
|
||||
java.util.List<RtkProfile> current = rtkProfileMapper.selectList(qw);
|
||||
java.util.HashSet<String> want = new java.util.HashSet<>(deviceIds);
|
||||
java.util.HashSet<String> exists = new java.util.HashSet<>();
|
||||
for (RtkProfile p : current) exists.add(p.getDevice_id());
|
||||
|
||||
for (String did : deviceIds) {
|
||||
QueryWrapper<RtkProfile> q1 = new QueryWrapper<>();
|
||||
q1.eq("device_id", did);
|
||||
RtkProfile prof = rtkProfileMapper.selectOne(q1);
|
||||
if (prof == null) {
|
||||
RtkProfile np = new RtkProfile();
|
||||
np.setDevice_id(did);
|
||||
np.setRtkgroup_id(groupId);
|
||||
np.setPos1_posmode("static");
|
||||
np.setInpstr1_type("ntripcli");
|
||||
np.setOut_height("geodetic");
|
||||
np.setInpstr1_path("");
|
||||
np.setOutstr2_path("");
|
||||
rtkProfileMapper.insert(np);
|
||||
} else if (prof.getRtkgroup_id() == null || !prof.getRtkgroup_id().equals(groupId)) {
|
||||
prof.setRtkgroup_id(groupId);
|
||||
rtkProfileMapper.updateById(prof);
|
||||
}
|
||||
}
|
||||
|
||||
for (RtkProfile p : current) {
|
||||
if (!want.contains(p.getDevice_id())) {
|
||||
p.setRtkgroup_id(0);
|
||||
rtkProfileMapper.updateById(p);
|
||||
}
|
||||
}
|
||||
return HttpResult.success("ok");
|
||||
}
|
||||
|
||||
@PostMapping("/rtk/group/update")
|
||||
@ResponseBody
|
||||
public HttpResult update(HttpSession session, @RequestBody JSONObject object) {
|
||||
int num;
|
||||
RtkGroup group = JSONObject.toJavaObject(object, RtkGroup.class);
|
||||
if (group.getName() == null || group.getName().trim().isEmpty()) {
|
||||
return HttpResult.fail("名称不能为空");
|
||||
}
|
||||
if (group.getInpstr2_path() == null || group.getInpstr2_path().isEmpty()) {
|
||||
group.setInpstr2_path("ytcors14847:fyx25943@gnss.ytcors.cn:8003/RTCM33GRCEJpro");
|
||||
}
|
||||
if (group.getInpstr3_path() == null || group.getInpstr3_path().isEmpty()) {
|
||||
group.setInpstr3_path("Ming:@Zhang12345@ntrip.data.gnss.ga.gov.au:2101/BCEP00BKG0");
|
||||
}
|
||||
|
||||
if (group.getId() != null) {
|
||||
num = rtkGroupMapper.updateById(group);
|
||||
opLogManager.addLog(getLoginUser(session), getTenantId(session),
|
||||
OpLogManager.OP_TYPE_UPDATE, OpLogManager.OP_OBJ_GROUP, group.getName());
|
||||
} else {
|
||||
num = rtkGroupMapper.insert(group);
|
||||
opLogManager.addLog(getLoginUser(session), getTenantId(session),
|
||||
OpLogManager.OP_TYPE_ADD, OpLogManager.OP_OBJ_GROUP, group.getName());
|
||||
}
|
||||
if (num == 0) {
|
||||
return HttpResult.fail("保存失败");
|
||||
} else return HttpResult.success("ok");
|
||||
}
|
||||
|
||||
@PostMapping("/rtk/group/delete")
|
||||
@ResponseBody
|
||||
public HttpResult delete(HttpSession session, @RequestParam int del_id) {
|
||||
RtkGroup group = rtkGroupMapper.selectById(del_id);
|
||||
if (group == null) return HttpResult.fail("记录不存在");
|
||||
int num = rtkGroupMapper.deleteById(del_id);
|
||||
opLogManager.addLog(getLoginUser(session), getTenantId(session),
|
||||
OpLogManager.OP_TYPE_DEL, OpLogManager.OP_OBJ_GROUP, group.getName());
|
||||
if (num == 0) {
|
||||
return HttpResult.fail("删除失败");
|
||||
} else return HttpResult.success("ok");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
package com.imdroid.beidou.controller;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
@Controller
|
||||
public class RtkrcvController extends BasicController {
|
||||
@RequestMapping("/page/rtkrcv")
|
||||
public String rtkrcv(Model m, HttpSession session) {
|
||||
initModel(m, session);
|
||||
return "/page/rtkrcv";
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,44 @@
|
||||
package com.imdroid.beidou.controller;
|
||||
|
||||
import com.imdroid.beidou.common.HttpResult;
|
||||
import com.imdroid.secapi.client.RtkrcvClient;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
@Controller
|
||||
public class RtkrcvProxyController {
|
||||
@Autowired
|
||||
RtkrcvClient rtkrcvClient;
|
||||
@Autowired
|
||||
com.imdroid.beidou.service.RtkMonitorService rtkMonitorService;
|
||||
|
||||
@PostMapping("/rtk/start")
|
||||
@ResponseBody
|
||||
public HttpResult start(@RequestParam("device_id") String deviceId,
|
||||
@RequestParam(value = "clear_log", required = false) Boolean clearLog){
|
||||
String res = rtkrcvClient.start(deviceId, clearLog!=null && clearLog);
|
||||
rtkMonitorService.onStart(deviceId);
|
||||
if(res==null) return HttpResult.fail("start failed");
|
||||
return HttpResult.success(res);
|
||||
}
|
||||
|
||||
@PostMapping("/rtk/stop")
|
||||
@ResponseBody
|
||||
public HttpResult stop(@RequestParam("device_id") String deviceId){
|
||||
String res = rtkrcvClient.stop(deviceId);
|
||||
rtkMonitorService.onStop(deviceId);
|
||||
if(res==null) return HttpResult.fail("stop failed");
|
||||
return HttpResult.success(res);
|
||||
}
|
||||
|
||||
@GetMapping("/rtk/log_exists")
|
||||
@ResponseBody
|
||||
public Boolean logExists(@RequestParam("device_id") String deviceId){
|
||||
Boolean exists = rtkrcvClient.logExists(deviceId);
|
||||
return exists != null && exists;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,69 @@
|
||||
package com.imdroid.beidou.controller;
|
||||
|
||||
import com.imdroid.beidou.config.WebSocketConfig;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.servlet.http.HttpSession;
|
||||
import javax.websocket.*;
|
||||
import javax.websocket.server.ServerEndpoint;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@ServerEndpoint(value = "/websocket/rtkrcv", configurator = WebSocketConfig.class)
|
||||
@Component
|
||||
@Slf4j
|
||||
public class RtkrcvWebSocketServer {
|
||||
private static final Map<String, Session> webSocketSet = new ConcurrentHashMap<>();
|
||||
|
||||
@OnOpen
|
||||
public void onOpen(Session session){
|
||||
HttpSession httpSession= (HttpSession) session.getUserProperties().get(HttpSession.class.getName());
|
||||
if(httpSession!=null){
|
||||
webSocketSet.put(httpSession.getId(), session);
|
||||
}
|
||||
log.info("rtkrcv websocket opened, total: {}", webSocketSet.size());
|
||||
}
|
||||
|
||||
@OnClose
|
||||
public void onClose(Session session){
|
||||
HttpSession httpSession= (HttpSession) session.getUserProperties().get(HttpSession.class.getName());
|
||||
if(httpSession!=null){
|
||||
webSocketSet.remove(httpSession.getId());
|
||||
}
|
||||
log.info("rtkrcv websocket closed, total: {}", webSocketSet.size());
|
||||
}
|
||||
|
||||
@OnMessage
|
||||
public void onMessage(String msg, Session session){
|
||||
}
|
||||
|
||||
@OnError
|
||||
public void onError(Session session, Throwable error){
|
||||
log.error("rtkrcv websocket error", error);
|
||||
}
|
||||
|
||||
public static void sendMessageToAll(String msg){
|
||||
try {
|
||||
for (Session item : webSocketSet.values()) {
|
||||
item.getBasicRemote().sendText(msg);
|
||||
}
|
||||
}
|
||||
catch (Exception e){
|
||||
log.error("rtkrcv websocket send msg error:", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void sendMessage(HttpSession httpSession, String msg) {
|
||||
Session session = webSocketSet.get(httpSession.getId());
|
||||
if(session != null){
|
||||
try {
|
||||
session.getBasicRemote().sendText(msg);
|
||||
}
|
||||
catch (Exception e){
|
||||
log.error("rtkrcv websocket send msg error:", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,124 @@
|
||||
package com.imdroid.beidou.service;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.imdroid.beidou.controller.RtkrcvWebSocketServer;
|
||||
import com.imdroid.secapi.client.RtkrcvClient;
|
||||
import com.imdroid.secapi.dto.RtkProfile;
|
||||
import com.imdroid.secapi.dto.RtkProfileMapper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@Component
|
||||
public class GroupRtkScheduler {
|
||||
static final int MAX_RUN = 6;
|
||||
@Autowired
|
||||
RtkrcvClient rtkrcvClient;
|
||||
@Autowired
|
||||
RtkProfileMapper rtkProfileMapper;
|
||||
|
||||
static class GroupState {
|
||||
Deque<String> queue = new ArrayDeque<>();
|
||||
Set<String> running = new HashSet<>();
|
||||
Set<String> done = new HashSet<>();
|
||||
boolean active = false;
|
||||
boolean clearLog = false;
|
||||
}
|
||||
|
||||
private final Map<Integer, GroupState> groups = new ConcurrentHashMap<>();
|
||||
|
||||
public synchronized void startGroup(Integer groupId, boolean clearLog){
|
||||
GroupState st = groups.computeIfAbsent(groupId, k -> new GroupState());
|
||||
st.queue.clear();
|
||||
st.running.clear();
|
||||
st.done.clear();
|
||||
st.active = true;
|
||||
st.clearLog = clearLog;
|
||||
QueryWrapper<RtkProfile> qw = new QueryWrapper<>();
|
||||
qw.eq("rtkgroup_id", groupId);
|
||||
List<RtkProfile> list = rtkProfileMapper.selectList(qw);
|
||||
for(RtkProfile p:list){
|
||||
st.queue.addLast(p.getDevice_id());
|
||||
pushStatus(groupId, p.getDevice_id(), "QUEUED");
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void stopGroup(Integer groupId){
|
||||
GroupState st = groups.get(groupId);
|
||||
if(st==null) return;
|
||||
for(String dev: new ArrayList<>(st.running)){
|
||||
try{ rtkrcvClient.stop(dev);}catch(Exception ignored){}
|
||||
pushStatus(groupId, dev, "DONE");
|
||||
}
|
||||
st.running.clear();
|
||||
st.queue.clear();
|
||||
st.active = false;
|
||||
}
|
||||
|
||||
public synchronized List<Map<String,Object>> getStatus(Integer groupId){
|
||||
GroupState st = groups.get(groupId);
|
||||
List<Map<String,Object>> list = new ArrayList<>();
|
||||
if(st==null) return list;
|
||||
for(String d: st.running){ list.add(row(d, "RUNNING")); }
|
||||
for(String d: st.queue){ list.add(row(d, "QUEUED")); }
|
||||
for(String d: st.done){ list.add(row(d, "DONE")); }
|
||||
return list;
|
||||
}
|
||||
|
||||
private Map<String,Object> row(String dev, String status){
|
||||
Map<String,Object> m = new HashMap<>();
|
||||
m.put("device_id", dev);
|
||||
m.put("status", status);
|
||||
return m;
|
||||
}
|
||||
|
||||
public synchronized void onDeviceAutoStop(String deviceId){
|
||||
Integer gid = getGroupId(deviceId);
|
||||
if(gid==null) return;
|
||||
GroupState st = groups.get(gid);
|
||||
if(st==null) return;
|
||||
st.running.remove(deviceId);
|
||||
st.done.add(deviceId);
|
||||
pushStatus(gid, deviceId, "DONE");
|
||||
}
|
||||
|
||||
private Integer getGroupId(String deviceId){
|
||||
QueryWrapper<RtkProfile> qw = new QueryWrapper<>();
|
||||
qw.eq("device_id", deviceId);
|
||||
RtkProfile p = rtkProfileMapper.selectOne(qw);
|
||||
return p!=null? p.getRtkgroup_id(): null;
|
||||
}
|
||||
|
||||
@Scheduled(fixedRate = 1000)
|
||||
public void tick(){
|
||||
for(Map.Entry<Integer, GroupState> e: groups.entrySet()){
|
||||
Integer gid = e.getKey();
|
||||
GroupState st = e.getValue();
|
||||
if(!st.active) continue;
|
||||
while(st.running.size() < MAX_RUN && !st.queue.isEmpty()){
|
||||
String dev = st.queue.pollFirst();
|
||||
boolean started = false;
|
||||
try{ rtkrcvClient.start(dev, st.clearLog); started = true; }catch(Exception ignored){}
|
||||
if(started){
|
||||
st.running.add(dev);
|
||||
pushStatus(gid, dev, "RUNNING");
|
||||
} else {
|
||||
pushStatus(gid, dev, "FAILED");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void pushStatus(Integer gid, String dev, String status){
|
||||
com.alibaba.fastjson.JSONObject obj = new com.alibaba.fastjson.JSONObject();
|
||||
obj.put("type","rtk_group");
|
||||
obj.put("groupId", gid);
|
||||
obj.put("deviceId", dev);
|
||||
obj.put("status", status);
|
||||
RtkrcvWebSocketServer.sendMessageToAll(obj.toJSONString());
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,58 @@
|
||||
package com.imdroid.beidou.service;
|
||||
|
||||
import com.imdroid.secapi.client.RtkrcvClient;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@Component
|
||||
public class RtkMonitorService {
|
||||
private final Map<String, Integer> consecFix = new ConcurrentHashMap<>();
|
||||
private final Map<String, Boolean> running = new ConcurrentHashMap<>();
|
||||
|
||||
@Autowired
|
||||
RtkrcvClient rtkrcvClient;
|
||||
@Autowired
|
||||
GroupRtkScheduler groupRtkScheduler;
|
||||
|
||||
public void onStart(String deviceId){
|
||||
running.put(deviceId, true);
|
||||
consecFix.put(deviceId, 0);
|
||||
}
|
||||
public void onStop(String deviceId){
|
||||
running.remove(deviceId);
|
||||
consecFix.remove(deviceId);
|
||||
}
|
||||
public void onSolution(String deviceId, int q){
|
||||
if(Boolean.TRUE.equals(running.get(deviceId))){
|
||||
if(q == 1){
|
||||
consecFix.merge(deviceId, 1, Integer::sum);
|
||||
} else {
|
||||
consecFix.put(deviceId, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Scheduled(fixedRate = 30000)
|
||||
public void check(){
|
||||
for(Map.Entry<String, Integer> e : consecFix.entrySet()){
|
||||
String dev = e.getKey();
|
||||
Integer cnt = e.getValue();
|
||||
if(Boolean.TRUE.equals(running.get(dev)) && cnt != null && cnt >= 40){
|
||||
try { rtkrcvClient.stop(dev); } catch (Exception ignore) {}
|
||||
running.remove(dev);
|
||||
try {
|
||||
com.alibaba.fastjson.JSONObject ctrl = new com.alibaba.fastjson.JSONObject();
|
||||
ctrl.put("type","rtk_ctrl");
|
||||
ctrl.put("action","auto_stop");
|
||||
ctrl.put("deviceId", dev);
|
||||
com.imdroid.beidou.controller.RtkrcvWebSocketServer.sendMessageToAll(ctrl.toJSONString());
|
||||
} catch (Exception ignore) {}
|
||||
try { groupRtkScheduler.onDeviceAutoStop(dev);} catch (Exception ignore) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2,10 +2,10 @@
|
||||
#spring.datasource.url=jdbc:mysql://192.168.101.54:3306/beidou?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&useSSL=true
|
||||
#spring.datasource.username=beidou
|
||||
#spring.datasource.password=Passw0rd#123!
|
||||
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/beidou?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&useSSL=true
|
||||
#spring.datasource.url=jdbc:mysql://139.9.51.237:3306/beidou?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&useSSL=true
|
||||
spring.datasource.username=admin
|
||||
spring.datasource.password=DBMgr_2022
|
||||
spring.datasource.url=jdbc:mysql://8.134.185.53:3306/beidou?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&useSSL=true
|
||||
#spring.datasource.url=jdbc:mysql://139.9.51.237:3306/beidou?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&useSSL=false
|
||||
spring.datasource.username=remote
|
||||
spring.datasource.password=root
|
||||
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
|
||||
spring.jpa.properties.hibernate.hbm2ddl.auto=update
|
||||
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MYSQL5InnoDBDialect
|
||||
@ -52,3 +52,6 @@ warning.log.directory=./log
|
||||
sim.url = http://120.78.169.220:8089
|
||||
sim.username = gzyzdz
|
||||
sim.key = 632629d1269a202c9d49a574623e4e4c
|
||||
|
||||
version.path = "./"
|
||||
ver_server.connect.cmd = ""
|
||||
162
sec-beidou/src/main/resources/rtkrcv_default.conf
Normal file
162
sec-beidou/src/main/resources/rtkrcv_default.conf
Normal file
@ -0,0 +1,162 @@
|
||||
# RTKNAVI options (2024/12/09 02:35:36, v.demo5 b34k)
|
||||
|
||||
pos1-posmode =static # (0:single,1:dgps,2:kinematic,3:static,4:static-start,5:movingbase,6:fixed,7:ppp-kine,8:ppp-static,9:ppp-fixed)
|
||||
pos1-frequency =l1+l2+l5 # (1:l1,2:l1+l2,3:l1+l2+l5,4:l1+l2+l5+l6)
|
||||
pos1-soltype =forward # (0:forward,1:backward,2:combined,3:combined-nophasereset)
|
||||
pos1-elmask =10 # (deg)
|
||||
pos1-snrmask_r =on # (0:off,1:on)
|
||||
pos1-snrmask_b =on # (0:off,1:on)
|
||||
pos1-snrmask_L1 =0,0,0,0,0,0,0,0,0
|
||||
pos1-snrmask_L2 =0,0,0,0,0,0,0,0,0
|
||||
pos1-snrmask_L5 =0,0,0,0,0,0,0,0,0
|
||||
pos1-dynamics =off # (0:off,1:on)
|
||||
pos1-tidecorr =off # (0:off,1:on,2:otl)
|
||||
pos1-ionoopt =brdc # (0:off,1:brdc,2:sbas,3:dual-freq,4:est-stec,5:ionex-tec,6:qzs-brdc)
|
||||
pos1-tropopt =saas # (0:off,1:saas,2:sbas,3:est-ztd,4:est-ztdgrad)
|
||||
pos1-sateph =brdc+sbas # (0:brdc,1:precise,2:brdc+sbas,3:brdc+ssrapc,4:brdc+ssrcom)
|
||||
pos1-posopt1 =off # (0:off,1:on)
|
||||
pos1-posopt2 =off # (0:off,1:on)
|
||||
pos1-posopt3 =off # (0:off,1:on,2:precise)
|
||||
pos1-posopt4 =off # (0:off,1:on)
|
||||
pos1-posopt5 =off # (0:off,1:on)
|
||||
pos1-posopt6 =off # (0:off,1:on)
|
||||
pos1-exclsats = # (prn ...)
|
||||
pos1-navsys =45 # (1:gps+2:sbas+4:glo+8:gal+16:qzs+32:bds+64:navic)
|
||||
pos2-armode =continuous # (0:off,1:continuous,2:instantaneous,3:fix-and-hold)
|
||||
pos2-gloarmode =fix-and-hold # (0:off,1:on,2:autocal,3:fix-and-hold)
|
||||
pos2-bdsarmode =on # (0:off,1:on)
|
||||
pos2-arfilter =on # (0:off,1:on)
|
||||
pos2-arthres =3
|
||||
pos2-arthresmin =2
|
||||
pos2-arthresmax =2
|
||||
pos2-arthres1 =0.1
|
||||
pos2-arthres2 =0
|
||||
pos2-arthres3 =1e-09
|
||||
pos2-arthres4 =1e-05
|
||||
pos2-varholdamb =0.1 # (cyc^2)
|
||||
pos2-gainholdamb =0.01
|
||||
pos2-arlockcnt =5
|
||||
pos2-minfixsats =4
|
||||
pos2-minholdsats =5
|
||||
pos2-mindropsats =10
|
||||
pos2-arelmask =10 # (deg)
|
||||
pos2-arminfix =20
|
||||
pos2-armaxiter =1
|
||||
pos2-elmaskhold =10 # (deg)
|
||||
pos2-aroutcnt =20
|
||||
pos2-maxage =30 # (s)
|
||||
pos2-syncsol =off # (0:off,1:on)
|
||||
pos2-slipthres =0.05 # (m)
|
||||
pos2-dopthres =0 # (m)
|
||||
pos2-rejionno =5 # (m)
|
||||
pos2-rejcode =30 # (m)
|
||||
pos2-niter =1
|
||||
pos2-baselen =0 # (m)
|
||||
pos2-basesig =0 # (m)
|
||||
out-solformat =llh # (0:llh,1:xyz,2:enu,3:nmea)
|
||||
out-outhead =on # (0:off,1:on)
|
||||
out-outopt =on # (0:off,1:on)
|
||||
out-outvel =off # (0:off,1:on)
|
||||
out-timesys =gpst # (0:gpst,1:utc,2:jst)
|
||||
out-timeform =hms # (0:tow,1:hms)
|
||||
out-timendec =3
|
||||
out-degform =deg # (0:deg,1:dms)
|
||||
out-fieldsep =
|
||||
out-outsingle =off # (0:off,1:on)
|
||||
out-maxsolstd =0 # (m)
|
||||
out-height =1 # (0:ellipsoidal,1:geodetic)
|
||||
out-geoid =internal # (0:internal,1:egm96,2:egm08_2.5,3:egm08_1,4:gsi2000)
|
||||
out-solstatic =all # (0:all,1:single)
|
||||
out-nmeaintv1 =0 # (s)
|
||||
out-nmeaintv2 =0 # (s)
|
||||
out-outstat =residual # (0:off,1:state,2:residual)
|
||||
stats-eratio1 =300
|
||||
stats-eratio2 =300
|
||||
stats-eratio5 =300
|
||||
stats-errphase =0.003 # (m)
|
||||
stats-errphaseel =0.003 # (m)
|
||||
stats-errphasebl =0 # (m/10km)
|
||||
stats-errdoppler =1 # (Hz)
|
||||
stats-snrmax =52 # (dB.Hz)
|
||||
stats-errsnr =0 # (m)
|
||||
stats-errrcv =0 # ( )
|
||||
stats-stdbias =30 # (m)
|
||||
stats-stdiono =0.03 # (m)
|
||||
stats-stdtrop =0.3 # (m)
|
||||
stats-prnaccelh =3 # (m/s^2)
|
||||
stats-prnaccelv =1 # (m/s^2)
|
||||
stats-prnbias =0.0001 # (m)
|
||||
stats-prniono =0.001 # (m)
|
||||
stats-prntrop =0.0001 # (m)
|
||||
stats-prnpos =0 # (m)
|
||||
stats-clkstab =5e-12 # (s/s)
|
||||
ant1-postype =llh # (0:llh,1:xyz,2:single,3:posfile,4:rinexhead,5:rtcm,6:raw)
|
||||
ant1-pos1 =90 # (deg|m)
|
||||
ant1-pos2 =0 # (deg|m)
|
||||
ant1-pos3 =-6335367.6285 # (m|m)
|
||||
ant1-anttype =
|
||||
ant1-antdele =0 # (m)
|
||||
ant1-antdeln =0 # (m)
|
||||
ant1-antdelu =0 # (m)
|
||||
ant2-postype =rtcm # (0:llh,1:xyz,2:single,3:posfile,4:rinexhead,5:rtcm,6:raw)
|
||||
ant2-pos1 =0 # (deg|m)
|
||||
ant2-pos2 =0 # (deg|m)
|
||||
ant2-pos3 =0 # (m|m)
|
||||
ant2-anttype =
|
||||
ant2-antdele =0 # (m)
|
||||
ant2-antdeln =0 # (m)
|
||||
ant2-antdelu =0 # (m)
|
||||
ant2-maxaveep =1
|
||||
ant2-initrst =on # (0:off,1:on)
|
||||
misc-timeinterp =off # (0:off,1:on)
|
||||
misc-sbasatsel =0 # (0:all)
|
||||
misc-rnxopt1 =
|
||||
misc-rnxopt2 =
|
||||
misc-pppopt =
|
||||
file-satantfile =
|
||||
file-rcvantfile =
|
||||
file-staposfile =
|
||||
file-geoidfile =
|
||||
file-ionofile =
|
||||
file-dcbfile =
|
||||
file-eopfile =
|
||||
file-blqfile =
|
||||
file-tempdir =./RTKNAVI
|
||||
file-geexefile =
|
||||
file-solstatfile =
|
||||
file-tracefile =
|
||||
#
|
||||
|
||||
inpstr1-type =ntripcli # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripcli,7:ftp,8:http)
|
||||
inpstr2-type =ntripcli # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripcli,7:ftp,8:http)
|
||||
inpstr3-type =ntripcli # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripcli,7:ftp,8:http)
|
||||
inpstr1-path =beidou:29832611@8.134.185.53:8001/6539837
|
||||
inpstr2-path =ytcors14847:fyx25943@gnss.ytcors.cn:8003/RTCM33GRCEJpro
|
||||
inpstr3-path =Ming:@Zhang12345@ntrip.data.gnss.ga.gov.au:2101/BCEP00BKG0
|
||||
inpstr1-format =rtcm3 # (0:rtcm2,1:rtcm3,2:oem4,4:ubx,5:swift,6:hemis,7:skytraq,8:javad,9:nvs,10:binex,11:rt17,12:sbf,15:sp3)
|
||||
inpstr2-format =rtcm3 # (0:rtcm2,1:rtcm3,2:oem4,4:ubx,5:swift,6:hemis,7:skytraq,8:javad,9:nvs,10:binex,11:rt17,12:sbf,15:sp3)
|
||||
inpstr3-format =rtcm3 # (0:rtcm2,1:rtcm3,2:oem4,4:ubx,5:swift,6:hemis,7:skytraq,8:javad,9:nvs,10:binex,11:rt17,12:sbf,15:sp3)
|
||||
inpstr2-nmeareq =single # (0:off,1:latlon,2:single)
|
||||
inpstr2-nmealat = # (deg)
|
||||
inpstr2-nmealon = # (deg)
|
||||
outstr1-type =off # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,5:ntripsvr,9:ntripcas)
|
||||
outstr2-type =tcpcli # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,5:ntripsvr,9:ntripcas)
|
||||
outstr1-path =127.0.0.1:60000
|
||||
outstr2-path =127.0.0.1:24001
|
||||
outstr1-format =xyz # (0:llh,1:xyz,2:enu,3:nmea:4:stat)
|
||||
outstr2-format =llh # (0:llh,1:xyz,2:enu,3:nmea:4:stat)
|
||||
logstr1-type =off # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,5:ntripsvr,9:ntripcas)
|
||||
logstr2-type =off # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,5:ntripsvr,9:ntripcas)
|
||||
logstr3-type =off # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,5:ntripsvr,9:ntripcas)
|
||||
logstr1-path =
|
||||
logstr2-path =
|
||||
logstr3-path =
|
||||
misc-svrcycle =10 # (ms)
|
||||
misc-timeout =10000 # (ms)
|
||||
misc-reconnect =10000 # (ms)
|
||||
misc-nmeacycle =5000 # (ms)
|
||||
misc-buffsize =32768 # (bytes)
|
||||
misc-navmsgsel =all # (0:all,1:rover,2:base,3:corr)
|
||||
misc-proxyaddr =
|
||||
misc-fswapmargin =30 # (s)
|
||||
console-passwd =
|
||||
@ -82,6 +82,12 @@
|
||||
"href": "page/cmd_line",
|
||||
"icon": "fa fa-minus",
|
||||
"target": "_self"
|
||||
},
|
||||
{
|
||||
"title": "定位管理",
|
||||
"href": "page/rtkrcv",
|
||||
"icon": "fa fa-minus",
|
||||
"target": "_self"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
var DeviceMarkers = (function() {
|
||||
'use strict';
|
||||
|
||||
var greenFeatures = [];
|
||||
var orangeFeatures = [];
|
||||
var redFeatures = [];
|
||||
var invalidDataFeatures = [];
|
||||
var offlineIn24hFeatures = [];
|
||||
var offlineFeatures = [];
|
||||
var allFeatures = [];
|
||||
var myLocationFeature = null;
|
||||
var myLocationInterval = null;
|
||||
@ -43,9 +43,9 @@ var DeviceMarkers = (function() {
|
||||
var scale = isHovered ? 0.85 : 0.7;
|
||||
|
||||
// 根据告警级别选择图标
|
||||
if (deviceInfo.warning == 2) {
|
||||
if (deviceInfo.warning == 2||deviceInfo.warning == 3) {
|
||||
iconSrc = '../images/loc1_red.png';
|
||||
} else if (deviceInfo.warning == 1) {
|
||||
} else if (deviceInfo.warning == 4) {
|
||||
iconSrc = '../images/loc1_orange.png';
|
||||
} else {
|
||||
iconSrc = '../images/loc1_green.png';
|
||||
@ -85,9 +85,9 @@ var DeviceMarkers = (function() {
|
||||
var savedMyLocationFeature = myLocationFeature;
|
||||
|
||||
vectorSource.clear();
|
||||
greenFeatures = [];
|
||||
orangeFeatures = [];
|
||||
redFeatures = [];
|
||||
invalidDataFeatures = [];
|
||||
offlineIn24hFeatures = [];
|
||||
offlineFeatures = [];
|
||||
allFeatures = [];
|
||||
|
||||
for (var i = 0; i < deviceList.length; i++) {
|
||||
@ -106,11 +106,12 @@ var DeviceMarkers = (function() {
|
||||
|
||||
// 按告警级别分类
|
||||
if (device.warning == 2) {
|
||||
redFeatures.push(feature);
|
||||
} else if (device.warning == 1) {
|
||||
orangeFeatures.push(feature);
|
||||
} else {
|
||||
greenFeatures.push(feature);
|
||||
offlineFeatures.push(feature);
|
||||
} else if (device.warning == 3) {
|
||||
offlineFeatures.push(feature);
|
||||
offlineIn24hFeatures.push(feature);
|
||||
} else if (device.warning == 4) {
|
||||
invalidDataFeatures.push(feature);
|
||||
}
|
||||
|
||||
allFeatures.push(feature);
|
||||
@ -149,9 +150,10 @@ var DeviceMarkers = (function() {
|
||||
}
|
||||
}
|
||||
|
||||
function showWarning1Devices() {
|
||||
function showWarning4Devices() {
|
||||
console.log("showWarning4Devices");
|
||||
if (!vectorSource) return;
|
||||
|
||||
console.log("showWarning4Devices:",invalidDataFeatures.length);
|
||||
var savedMyLocationFeature = myLocationFeature;
|
||||
vectorSource.clear();
|
||||
|
||||
@ -159,18 +161,18 @@ var DeviceMarkers = (function() {
|
||||
vectorSource.addFeature(savedMyLocationFeature);
|
||||
}
|
||||
|
||||
for (var i = 0; i < allFeatures.length; i++) {
|
||||
vectorSource.addFeature(allFeatures[i]);
|
||||
for (var i = 0; i < invalidDataFeatures.length; i++) {
|
||||
vectorSource.addFeature(invalidDataFeatures[i]);
|
||||
}
|
||||
|
||||
hideGreenFeatures();
|
||||
hideRedFeatures();
|
||||
//hideofflineIn24hFeatures();
|
||||
//hideofflineFeatures();
|
||||
}
|
||||
|
||||
|
||||
function showWarning2Devices() {
|
||||
if (!vectorSource) return;
|
||||
|
||||
console.log("showWarning2Devices:",offlineFeatures.length);
|
||||
var savedMyLocationFeature = myLocationFeature;
|
||||
vectorSource.clear();
|
||||
|
||||
@ -178,30 +180,31 @@ var DeviceMarkers = (function() {
|
||||
vectorSource.addFeature(savedMyLocationFeature);
|
||||
}
|
||||
|
||||
for (var i = 0; i < allFeatures.length; i++) {
|
||||
vectorSource.addFeature(allFeatures[i]);
|
||||
for (var i = 0; i < offlineFeatures.length; i++) {
|
||||
vectorSource.addFeature(offlineFeatures[i]);
|
||||
}
|
||||
|
||||
hideGreenFeatures();
|
||||
hideOrangeFeatures();
|
||||
//hideinvalidDataFeatures();
|
||||
//hideofflineIn24hFeatures();
|
||||
}
|
||||
|
||||
function hideGreenFeatures() {
|
||||
for (var i = 0; i < greenFeatures.length; i++) {
|
||||
vectorSource.removeFeature(greenFeatures[i]);
|
||||
}
|
||||
}
|
||||
function showWarning3Devices() {
|
||||
console.log("showWarning3Devices");
|
||||
if (!vectorSource) return;
|
||||
console.log("showWarning3Devices:",offlineIn24hFeatures.length);
|
||||
var savedMyLocationFeature = myLocationFeature;
|
||||
vectorSource.clear();
|
||||
|
||||
function hideOrangeFeatures() {
|
||||
for (var i = 0; i < orangeFeatures.length; i++) {
|
||||
vectorSource.removeFeature(orangeFeatures[i]);
|
||||
if (savedMyLocationFeature) {
|
||||
vectorSource.addFeature(savedMyLocationFeature);
|
||||
}
|
||||
}
|
||||
|
||||
function hideRedFeatures() {
|
||||
for (var i = 0; i < redFeatures.length; i++) {
|
||||
vectorSource.removeFeature(redFeatures[i]);
|
||||
for (var i = 0; i < offlineIn24hFeatures.length; i++) {
|
||||
vectorSource.addFeature(offlineIn24hFeatures[i]);
|
||||
}
|
||||
|
||||
//hideinvalidDataFeatures();
|
||||
//hideofflineFeatures();
|
||||
}
|
||||
|
||||
function findDeviceById(deviceId) {
|
||||
@ -375,9 +378,9 @@ var DeviceMarkers = (function() {
|
||||
function getDeviceStats() {
|
||||
return {
|
||||
total: allFeatures.length,
|
||||
green: greenFeatures.length,
|
||||
orange: orangeFeatures.length,
|
||||
red: redFeatures.length
|
||||
green: invalidDataFeatures.length,
|
||||
orange: offlineIn24hFeatures.length,
|
||||
red: offlineFeatures.length
|
||||
};
|
||||
}
|
||||
|
||||
@ -386,11 +389,9 @@ var DeviceMarkers = (function() {
|
||||
createDeviceStyle: createDeviceStyle,
|
||||
addDeviceMarkers: addDeviceMarkers,
|
||||
showAllDevices: showAllDevices,
|
||||
showWarning1Devices: showWarning1Devices,
|
||||
showWarning2Devices: showWarning2Devices,
|
||||
hideGreenFeatures: hideGreenFeatures,
|
||||
hideOrangeFeatures: hideOrangeFeatures,
|
||||
hideRedFeatures: hideRedFeatures,
|
||||
showWarning3Devices: showWarning3Devices,
|
||||
showWarning4Devices: showWarning4Devices,
|
||||
findDeviceById: findDeviceById,
|
||||
locateDevice: locateDevice,
|
||||
getMyLocation: getMyLocation,
|
||||
@ -402,9 +403,9 @@ var DeviceMarkers = (function() {
|
||||
getDeviceStats: getDeviceStats,
|
||||
|
||||
getAllFeatures: function() { return allFeatures; },
|
||||
getGreenFeatures: function() { return greenFeatures; },
|
||||
getOrangeFeatures: function() { return orangeFeatures; },
|
||||
getRedFeatures: function() { return redFeatures; },
|
||||
getinvalidDataFeatures: function() { return invalidDataFeatures; },
|
||||
getofflineIn24hFeatures: function() { return offlineIn24hFeatures; },
|
||||
getofflineFeatures: function() { return offlineFeatures; },
|
||||
getMyLocationFeature: function() { return myLocationFeature; }
|
||||
};
|
||||
})();
|
||||
@ -292,12 +292,16 @@ var MapCore = (function() {
|
||||
|
||||
function onWarningFilterChange() {
|
||||
var filterValue = document.getElementById('warningFilter').value;
|
||||
console.log("onWarningFilterChange: ",filterValue);
|
||||
switch(filterValue) {
|
||||
case 'all':
|
||||
SearchFilter.showAllDevices();
|
||||
break;
|
||||
case 'warning1':
|
||||
SearchFilter.showWarning1Devices();
|
||||
case 'warning4':
|
||||
SearchFilter.showWarning4Devices();
|
||||
break;
|
||||
case 'warning3':
|
||||
SearchFilter.showWarning3Devices();
|
||||
break;
|
||||
case 'warning2':
|
||||
SearchFilter.showWarning2Devices();
|
||||
|
||||
@ -187,10 +187,13 @@ var SearchFilter = (function() {
|
||||
showAllDevices();
|
||||
break;
|
||||
case 2:
|
||||
showWarning1Devices();
|
||||
showWarning2Devices();
|
||||
break;
|
||||
case 3:
|
||||
showWarning2Devices();
|
||||
showWarning3Devices();
|
||||
break;
|
||||
case 4:
|
||||
showWarning4Devices();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -203,20 +206,30 @@ var SearchFilter = (function() {
|
||||
updateFilterSelect('all');
|
||||
}
|
||||
|
||||
function showWarning1Devices() {
|
||||
currentSearchedDevice = null;
|
||||
clearSearchInput();
|
||||
DeviceMarkers.showWarning1Devices();
|
||||
markerState = 2;
|
||||
updateFilterSelect('warning1');
|
||||
}
|
||||
function showWarning2Devices() {
|
||||
console.log("SearchFilter.showWarning2Devices");
|
||||
currentSearchedDevice = null;
|
||||
clearSearchInput();
|
||||
DeviceMarkers.showWarning2Devices();
|
||||
markerState = 3;
|
||||
markerState = 2;
|
||||
updateFilterSelect('warning2');
|
||||
}
|
||||
function showWarning3Devices() {
|
||||
console.log("SearchFilter.showWarning3Devices");
|
||||
currentSearchedDevice = null;
|
||||
clearSearchInput();
|
||||
DeviceMarkers.showWarning3Devices();
|
||||
markerState = 3;
|
||||
updateFilterSelect('warning3');
|
||||
}
|
||||
function showWarning4Devices() {
|
||||
console.log("SearchFilter.showWarning4Devices");
|
||||
currentSearchedDevice = null;
|
||||
clearSearchInput();
|
||||
DeviceMarkers.showWarning4Devices();
|
||||
markerState = 4;
|
||||
updateFilterSelect('warning4');
|
||||
}
|
||||
function clearSearchInput() {
|
||||
var searchInput = document.getElementById('deviceSearchNew');
|
||||
if (searchInput) {
|
||||
@ -233,13 +246,15 @@ var SearchFilter = (function() {
|
||||
|
||||
function filterDevicesByStatus(statusType) {
|
||||
switch(statusType) {
|
||||
case 'warning1':
|
||||
showWarning1Devices();
|
||||
break;
|
||||
case 'warning2':
|
||||
showWarning2Devices();
|
||||
break;
|
||||
case 'offline':
|
||||
case 'warning3':
|
||||
showWarning3Devices();
|
||||
break;
|
||||
case 'warning4':
|
||||
showWarning4Devices();
|
||||
break;
|
||||
case 'no_fwd':
|
||||
case 'nofixed':
|
||||
case 'nogga':
|
||||
@ -311,8 +326,9 @@ var SearchFilter = (function() {
|
||||
searchDevice: searchDevice,
|
||||
clearSearch: clearSearch,
|
||||
showAllDevices: showAllDevices,
|
||||
showWarning1Devices: showWarning1Devices,
|
||||
showWarning2Devices: showWarning2Devices,
|
||||
showWarning3Devices: showWarning3Devices,
|
||||
showWarning4Devices: showWarning4Devices,
|
||||
filterDevicesByStatus: filterDevicesByStatus,
|
||||
queryDevices: queryDevices,
|
||||
locateDeviceOnMap: locateDeviceOnMap,
|
||||
|
||||
@ -836,6 +836,11 @@
|
||||
<span>掉线数</span>
|
||||
<span class="stat-number" th:text="${deviceOfflineNum}">22</span>
|
||||
</div>
|
||||
<div class="stat-item" onclick="queryDevices('offline_in24h')" th:if="${deviceOfflineNumIn24h > 0}">
|
||||
<span class="stat-dot dot-gray"></span>
|
||||
<span>24小时掉线数</span>
|
||||
<span class="stat-number" th:text="${deviceOfflineNumIn24h}">22</span>
|
||||
</div>
|
||||
<div class="stat-item" onclick="queryDevices('no_fwd')" th:if="${deviceNoFwdNum > 0}">
|
||||
<span class="stat-dot dot-orange"></span>
|
||||
<span>未推送数</span>
|
||||
@ -846,16 +851,6 @@
|
||||
<span>长期无效解</span>
|
||||
<span class="stat-number" th:text="${noFix}">10</span>
|
||||
</div>
|
||||
<div class="stat-item" onclick="queryDevices('warning2')" th:if="${warning2Num > 0}">
|
||||
<span class="stat-dot dot-red"></span>
|
||||
<span>严重告警</span>
|
||||
<span class="stat-number" th:text="${warning2Num}">40</span>
|
||||
</div>
|
||||
<div class="stat-item" onclick="queryDevices('warning1')" th:if="${warning1Num > 0}">
|
||||
<span class="stat-dot dot-orange"></span>
|
||||
<span>一般告警</span>
|
||||
<span class="stat-number" th:text="${warning1Num}">79</span>
|
||||
</div>
|
||||
<div class="stat-item" onclick="queryDevices('nogga')" th:if="${noGGA > 0}">
|
||||
<span class="stat-dot dot-gray"></span>
|
||||
<span>无GGA告警</span>
|
||||
@ -925,8 +920,9 @@
|
||||
<div class="toolbar-item">
|
||||
<select id="warningFilter" class="toolbar-select" onchange="onWarningFilterChange()">
|
||||
<option value="all">全部设备</option>
|
||||
<option value="warning1">一般告警</option>
|
||||
<option value="warning2" selected>严重告警</option>
|
||||
<option value="warning2">离线</option>
|
||||
<option value="warning3">24小时内离线</option>
|
||||
<option value="warning4">长期无效解</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
|
||||
@ -24,6 +24,15 @@
|
||||
<input type="text" name="deviceid" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label required">产品型号</label>
|
||||
<div class="layui-input-inline">
|
||||
<select name="model" id="model" lay-search="">
|
||||
<option value="0">G505</option>
|
||||
<option value="1">G510</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">关联基站号</label>
|
||||
<div class="layui-input-inline">
|
||||
@ -36,6 +45,12 @@
|
||||
<input type="text" name="project_id" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">桩号</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="sector" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline" th:if="${tenant_id==0}">
|
||||
<label class="layui-form-label">所属部门</label>
|
||||
<div class="layui-input-inline">
|
||||
|
||||
@ -65,6 +65,12 @@
|
||||
<input type="text" name="rssi" id="rssi" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">经纬度</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="loc" id="loc" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">卫星</label>
|
||||
<div class="layui-input-inline">
|
||||
@ -100,7 +106,6 @@
|
||||
url:"/device_summary/query",
|
||||
data: data.field,
|
||||
success: function (result) {
|
||||
console.log(result);
|
||||
if(result.code == 0){
|
||||
layer.alert(result.msg);
|
||||
}
|
||||
@ -119,6 +124,7 @@
|
||||
$('#rxBytes').val(result.rxBytes)
|
||||
$('#deviceType').val(result.deviceType)
|
||||
$('#rssi').val(result.rssi)
|
||||
$('#loc').val(result.loc)
|
||||
form.render();
|
||||
}
|
||||
},
|
||||
|
||||
@ -92,6 +92,7 @@
|
||||
table = layui.table;
|
||||
var cfg_cols = [
|
||||
{field: 'deviceid', title: '设备号', sort: true},
|
||||
{field: 'tenantname', title: '部门', sort: true},
|
||||
{field: 'devicetype', title: '设备类型',templet: '#typeTrans'},
|
||||
{field: 'updatetime', title: '更新时间', templet: "<div>{{layui.util.toDateString(d.updatetime, 'yyyy-MM-dd HH:mm:ss')}}</div>"},
|
||||
{field: 'state', title: '状态',templet: '#stateTrans'},
|
||||
|
||||
523
sec-beidou/src/main/resources/templates/page/rtkrcv.html
Normal file
523
sec-beidou/src/main/resources/templates/page/rtkrcv.html
Normal file
@ -0,0 +1,523 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>定位管理</title>
|
||||
<meta name="renderer" content="webkit">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<link rel="stylesheet" href="../lib/layui-v2.6.3/css/layui.css" media="all">
|
||||
<link rel="stylesheet" href="../css/public.css" media="all">
|
||||
<style>
|
||||
.layui-tab-content{padding: 1.2em;}
|
||||
.transfer-wrap{display:flex;justify-content:center;align-items:flex-start;padding:1em 0}
|
||||
.transfer-inner{min-width:720px}
|
||||
#rtk-transfer .layui-transfer{display:flex;justify-content:center}
|
||||
#rtk-transfer .layui-transfer .layui-transfer-box{width:50% !important;height:360px !important}
|
||||
/* RTK panel ~80vh */
|
||||
#rtk-panel{height:80vh;}
|
||||
#rtk-info{max-height:calc(80vh - 120px);} /* leave room for header/badges */
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="layuimini-container">
|
||||
<div class="layuimini-main">
|
||||
<div class="layui-tab layui-tab-card" lay-filter="rtk-tab">
|
||||
<ul class="layui-tab-title">
|
||||
<li class="layui-this">分组管理</li>
|
||||
<li>设备管理</li>
|
||||
<li>单设备定位</li>
|
||||
<li>组设备定位</li>
|
||||
</ul>
|
||||
<div class="layui-tab-content">
|
||||
<div class="layui-tab-item layui-show">
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-md12">
|
||||
<div class="btn-bar">
|
||||
<button class="layui-btn" id="btn-group-add">新增分组</button>
|
||||
<button class="layui-btn layui-btn-normal" id="btn-group-edit">编辑分组</button>
|
||||
<button class="layui-btn layui-btn-danger" id="btn-group-del">删除分组</button>
|
||||
<button class="layui-btn layui-btn-warm" id="btn-transfer-save">保存设备分配</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="margin-top:10px;">
|
||||
<table class="layui-hide" id="table-group" lay-filter="table-group-filter"></table>
|
||||
</div>
|
||||
<div class="transfer-wrap">
|
||||
<div class="transfer-inner">
|
||||
<div id="rtk-transfer"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-tab-item">
|
||||
<div class="layui-row" style="margin:10px 0;">
|
||||
<div class="layui-col-md12">
|
||||
<div class="layui-form layui-form-pane">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">分组</label>
|
||||
<div class="layui-input-inline">
|
||||
<select id="sel-group" lay-search=""><option value="">全部</option></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">设备号</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" id="q-deviceid" placeholder="设备号" autocomplete="off" class="layui-input" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn" id="btn-device-search">搜索</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="margin-top:10px;">
|
||||
<table class="layui-hide" id="table-device" lay-filter="table-device-filter"></table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-tab-item">
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-md12">
|
||||
<form class="layui-form layui-form-pane" action="" id="rtk-form">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">分组</label>
|
||||
<div class="layui-input-block">
|
||||
<select id="rtk-group" lay-search="" lay-filter="rtk-group"></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">设备</label>
|
||||
<div class="layui-input-block">
|
||||
<select id="rtk-device" lay-search="" lay-filter="rtk-device"></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<button class="layui-btn" id="btn-rtk-start" type="button">开始定位</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-row" style="margin-top: 1em;">
|
||||
<div class="layui-col-md12">
|
||||
<div id="rtk-panel" style="border: 1px solid #e6e6e6;border-radius: 2px;padding: 1em;">
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;gap:12px;">
|
||||
<div class="layui-text">RTKRCV</div>
|
||||
<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap;">
|
||||
<span id="rtk-sol-badge" class="layui-badge layui-bg-gray">--</span>
|
||||
<span id="rtk-sat-badge" class="layui-badge layui-bg-gray">--</span>
|
||||
<span id="rtk-llh" class="layui-badge-rim">LLH: --</span>
|
||||
<span id="rtk-gngga" class="layui-badge-rim">GNGGA: --</span>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<pre id="rtk-info" style="white-space: pre-wrap;word-break: break-all;overflow-y:auto;"></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-md12">
|
||||
<form class="layui-form layui-form-pane" action="" id="rtk-group-form">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">分组</label>
|
||||
<div class="layui-input-block">
|
||||
<select id="gr-group" lay-search="" lay-filter="gr-group"></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<button class="layui-btn" id="btn-gr-start" type="button">开始组定位</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-row" style="margin-top: 1em;">
|
||||
<div class="layui-col-md12">
|
||||
<table class="layui-hide" id="group-table" lay-filter="group-table-filter"></table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-row" style="margin-top: 1em;">
|
||||
<div class="layui-col-md12">
|
||||
<div id="group-panel" style="border:1px solid #e6e6e6;border-radius:2px;padding:1em;height:60vh;">
|
||||
<div class="layui-text">组定位消息</div>
|
||||
<hr>
|
||||
<pre id="group-info" style="white-space: pre-wrap;word-break: break-all;overflow-y:auto;height:calc(60vh - 80px);"></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="../lib/layui-v2.6.3/layui.js" charset="utf-8"></script>
|
||||
<script>
|
||||
layui.use(['form','table','element','layer','transfer'], function(){
|
||||
var $ = layui.$,
|
||||
form = layui.form,
|
||||
table = layui.table,
|
||||
element = layui.element,
|
||||
layer = layui.layer,
|
||||
transfer = layui.transfer;
|
||||
|
||||
form.render();
|
||||
|
||||
var selectedGroup = null;
|
||||
var transferIns = null;
|
||||
var groupTableIns = table.render({
|
||||
elem: '#table-group',
|
||||
url: '/rtk/group/list',
|
||||
cols: [ [
|
||||
{type:'radio', width:50},
|
||||
{field:'id', title:'ID', width:90},
|
||||
{field:'name', title:'分组名称', width:180},
|
||||
{field:'inpstr2_path', title:'inpstr2-path'},
|
||||
{field:'inpstr3_path', title:'inpstr3-path'}
|
||||
] ],
|
||||
limits: [10,20,50,100],
|
||||
limit: 10,
|
||||
page: true
|
||||
});
|
||||
|
||||
table.on('radio(table-group-filter)', function(obj){
|
||||
selectedGroup = obj.data;
|
||||
loadTransfer();
|
||||
});
|
||||
|
||||
$('#btn-group-add').on('click', function(){
|
||||
var index = layer.open({
|
||||
title: '新增分组',
|
||||
type: 2,
|
||||
shade: 0.2,
|
||||
maxmin:true,
|
||||
shadeClose: true,
|
||||
area: ['600px', '420px'],
|
||||
content: '../page/table/rtk_group_edit'
|
||||
});
|
||||
});
|
||||
|
||||
$('#btn-group-edit').on('click', function(){
|
||||
if(!selectedGroup){ layer.msg('请先选择一行'); return; }
|
||||
var index = layer.open({
|
||||
title: '编辑分组',
|
||||
type: 2,
|
||||
shade: 0.2,
|
||||
maxmin:true,
|
||||
shadeClose: true,
|
||||
area: ['600px', '420px'],
|
||||
content: '../page/table/rtk_group_edit',
|
||||
success: function(layero, idx){
|
||||
var iframeWin = window[layero.find('iframe')[0]['name']];
|
||||
if(iframeWin && iframeWin.setParams){
|
||||
iframeWin.setParams(selectedGroup);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('#btn-group-del').on('click', function(){
|
||||
if(!selectedGroup){ layer.msg('请先选择一行'); return; }
|
||||
layer.confirm('确认删除该分组?', function(i){
|
||||
$.post('/rtk/group/delete', {del_id: selectedGroup.id}, function(res){
|
||||
if(res === 'ok' || res.code === 0){
|
||||
onRtkGroupUpdated();
|
||||
layer.close(i);
|
||||
} else {
|
||||
layer.alert(res.msg || '删除失败');
|
||||
}
|
||||
}).fail(function(){ layer.alert('请求失败'); });
|
||||
});
|
||||
});
|
||||
|
||||
window.onRtkGroupUpdated = function(){
|
||||
selectedGroup = null;
|
||||
groupTableIns.reload({page:{curr:1}});
|
||||
}
|
||||
|
||||
function loadTransfer(){
|
||||
if(!selectedGroup) return;
|
||||
$.get('/rtk/transfer/options', {group_id: selectedGroup.id}, function(res){
|
||||
if(res.code !== 0){ layer.alert(res.msg || '加载失败'); return; }
|
||||
var opt = res.data;
|
||||
if(transferIns){ $("#rtk-transfer").html(''); }
|
||||
transferIns = transfer.render({
|
||||
elem: '#rtk-transfer',
|
||||
title: ['待加入设备','组内设备'],
|
||||
data: opt.data,
|
||||
value: opt.value,
|
||||
id: 'rtk-transfer-id',
|
||||
showSearch: true,
|
||||
parseData: function(item){ return {value: item.value, title: item.title}; }
|
||||
});
|
||||
// 覆盖渲染后的内联尺寸
|
||||
var boxes = $('#rtk-transfer .layui-transfer .layui-transfer-box');
|
||||
if(boxes && boxes.length){ boxes.css({width:'50%', height:'360px'}); }
|
||||
}).fail(function(){ layer.alert('请求失败'); });
|
||||
}
|
||||
|
||||
$('#btn-transfer-save').on('click', function(){
|
||||
if(!selectedGroup){ layer.msg('请先选择分组'); return; }
|
||||
var vals = transfer.getData('rtk-transfer-id').map(function(it){ return it.value; });
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: '/rtk/profile/save_group_devices',
|
||||
contentType: 'application/json;charset=UTF-8',
|
||||
data: JSON.stringify({group_id: selectedGroup.id, device_ids: vals}),
|
||||
success: function(result){
|
||||
if(result.code === 0){ layer.msg('已保存'); }
|
||||
else { layer.alert(result.msg || '保存失败'); }
|
||||
},
|
||||
error: function(){ layer.alert('请求失败'); }
|
||||
});
|
||||
});
|
||||
|
||||
function loadGroupSelect(){
|
||||
$.get('/rtk/group/list', {page:1, limit:1000}, function(res){
|
||||
if(res.code===0){
|
||||
var sel = $('#sel-group');
|
||||
sel.empty(); sel.append('<option value="">全部</option>');
|
||||
res.data.forEach(function(g){ sel.append('<option value="'+g.id+'">'+g.name+'</option>'); });
|
||||
form.render('select');
|
||||
var gr = $('#gr-group');
|
||||
gr.empty(); gr.append('<option value="">请选择</option>');
|
||||
res.data.forEach(function(g){ gr.append('<option value="'+g.id+'">'+g.name+'</option>'); });
|
||||
form.render('select');
|
||||
}
|
||||
});
|
||||
}
|
||||
loadGroupSelect();
|
||||
|
||||
var deviceTableIns = table.render({
|
||||
elem: '#table-device',
|
||||
url: '/rtk/profile/list',
|
||||
id: 'rtk-profile-table',
|
||||
cols: [ [
|
||||
{type:'numbers', title:'序号', width:70},
|
||||
{field:'id', title:'ID', width:80},
|
||||
{field:'device_id', title:'设备号', width:140},
|
||||
{field:'rtkgroup_id', title:'分组ID', width:100},
|
||||
{field:'pos1_posmode', title:'pos1-posmode', width:130},
|
||||
{field:'inpstr1_type', title:'inpstr1-type', width:120},
|
||||
{field:'inpstr1_path', title:'inpstr1-path'},
|
||||
{field:'outstr2_path', title:'outstr2-path'},
|
||||
{field:'out_height', title:'out-height', width:120},
|
||||
{title: '操作', toolbar: '#rtkProfileBar', fixed: 'right', width: 100}
|
||||
] ],
|
||||
limits: [10,20,50,100],
|
||||
limit: 10,
|
||||
page: true
|
||||
});
|
||||
|
||||
$('#btn-device-search').on('click', function(){
|
||||
var gid = $('#sel-group').val();
|
||||
var did = $('#q-deviceid').val();
|
||||
deviceTableIns.reload({where:{group_id: gid, device_id: did}, page:{curr:1}});
|
||||
});
|
||||
|
||||
table.on('tool(table-device-filter)', function(obj){
|
||||
var data = obj.data;
|
||||
if(obj.event === 'edit'){
|
||||
var index = layer.open({
|
||||
title: '编辑设备配置',
|
||||
type: 2,
|
||||
shade: 0.2,
|
||||
maxmin:true,
|
||||
shadeClose: true,
|
||||
area: ['700px', '520px'],
|
||||
content: '../page/table/rtk_profile_edit',
|
||||
success: function(layero){
|
||||
var iframeWin = window[layero.find('iframe')[0]['name']];
|
||||
if(iframeWin && iframeWin.setParams){ iframeWin.setParams(data); }
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// toolbar template for device table
|
||||
|
||||
|
||||
var rtkWs = null;
|
||||
var rtkSelectedDevice = '';
|
||||
var rtkRunning = false;
|
||||
function connectRtkWs(){
|
||||
if(rtkWs && rtkWs.readyState === WebSocket.OPEN) return;
|
||||
var curPath = window.document.location.href;
|
||||
var pathName = window.document.location.pathname;
|
||||
var pos = curPath.indexOf(pathName);
|
||||
var basePath = curPath.substring(0, pos);
|
||||
var wsUrl = (basePath+"/websocket/rtkrcv").replace("http","ws");
|
||||
rtkWs = new WebSocket(wsUrl);
|
||||
rtkWs.onopen = function(){ };
|
||||
rtkWs.onerror = function(){ layer.msg('RTK WebSocket 连接失败'); };
|
||||
rtkWs.onclose = function(){ };
|
||||
rtkWs.onmessage = function (event) {
|
||||
var msg = event.data || '';
|
||||
var info = $('#rtk-info');
|
||||
try {
|
||||
var obj = JSON.parse(msg);
|
||||
if(obj && obj.type==='rtk'){
|
||||
if(rtkSelectedDevice && obj.deviceId !== rtkSelectedDevice) return;
|
||||
var sol = (obj.q===1)?'固定解':((obj.q===2)?'浮点解':'--');
|
||||
var solCls = (obj.q===1)?'layui-bg-green':((obj.q===2)?'layui-bg-orange':'layui-bg-gray');
|
||||
$('#rtk-sol-badge').attr('class','layui-badge ' + solCls).text(sol);
|
||||
var ns = (obj.ns!=null? obj.ns : '--');
|
||||
$('#rtk-sat-badge').attr('class','layui-badge layui-bg-blue').text('卫星数: '+ns);
|
||||
var llh = (obj.lat && obj.lon && obj.h!=null)? (obj.lat.toFixed(9)+' '+obj.lon.toFixed(9)+' '+obj.h) : '--';
|
||||
$('#rtk-llh').text('LLH: ' + llh);
|
||||
info.text(info.text() + (obj.raw || msg) + "\n");
|
||||
} else if(obj && obj.type==='rtk_gngga'){
|
||||
if(rtkSelectedDevice && obj.deviceId !== rtkSelectedDevice) return;
|
||||
var gtxt = 'lat='+ (obj.lat!=null?obj.lat:0) + ', lon='+(obj.lon!=null?obj.lon:0)+', alt='+(obj.alt!=null?obj.alt:0)+', geo='+(obj.geo!=null?obj.geo:0);
|
||||
$('#rtk-gngga').text('GNGGA: ' + gtxt);
|
||||
} else if(obj && obj.type==='rtk_ctrl'){
|
||||
if(obj.action==='auto_stop' && (!rtkSelectedDevice || obj.deviceId === rtkSelectedDevice)){
|
||||
rtkRunning = false; updateToggleBtn();
|
||||
layer.msg('已自动停止: 连续固定解达阈值');
|
||||
}
|
||||
if(groupSelectedId){
|
||||
if(obj.deviceId){ groupStatus[obj.deviceId]='DONE'; renderGroupTable(); }
|
||||
}
|
||||
} else if(obj && obj.type==='rtk_group'){
|
||||
if(groupSelectedId && obj.groupId==groupSelectedId){
|
||||
groupStatus[obj.deviceId]=obj.status; renderGroupTable();
|
||||
}
|
||||
} else {
|
||||
info.text(info.text() + msg + "\n");
|
||||
}
|
||||
} catch(e){
|
||||
var parts = msg.trim().split(/\s+/);
|
||||
var ok = parts.length >= 3 && parts[0] === 'RTK';
|
||||
if(ok){
|
||||
var did = parts[1];
|
||||
if(rtkSelectedDevice && did !== rtkSelectedDevice) return;
|
||||
}
|
||||
info.text(info.text() + msg + "\n");
|
||||
}
|
||||
var el = document.getElementById('rtk-info');
|
||||
el.scrollTop = el.scrollHeight;
|
||||
if(groupSelectedId){
|
||||
try{ var o=JSON.parse(msg); if(o && o.type==='rtk' && groupDevices.has(o.deviceId)){ appendGroupLog(o.raw || msg); } }catch(ex){ var pp=msg.trim().split(/\s+/); if(pp[0]==='RTK' && groupDevices.has(pp[1])) appendGroupLog(msg); }
|
||||
}
|
||||
};
|
||||
}
|
||||
function closeRtkWs(){ if(rtkWs){ try{ rtkWs.close(); }catch(e){} rtkWs=null; } }
|
||||
|
||||
function loadRtkGroups(){
|
||||
$.get('/rtk/group/list', {page:1,limit:1000}, function(res){
|
||||
if(res.code===0){
|
||||
var sel = $('#rtk-group'); sel.empty();
|
||||
sel.append('<option value="">请选择</option>');
|
||||
(res.data||[]).forEach(function(g){ sel.append('<option value="'+g.id+'">'+g.name+'</option>'); });
|
||||
form.render('select');
|
||||
}
|
||||
});
|
||||
}
|
||||
function loadRtkDevices(gid){
|
||||
var devSel = $('#rtk-device'); devSel.empty();
|
||||
devSel.append('<option value="">请选择</option>');
|
||||
if(!gid){ form.render('select'); return; }
|
||||
$.get('/rtk/profile/list', {page:1,limit:1000, group_id: gid}, function(res){
|
||||
if(res.code===0){
|
||||
(res.data||[]).forEach(function(p){ devSel.append('<option value="'+p.device_id+'">'+p.device_id+'</option>'); });
|
||||
form.render('select');
|
||||
}
|
||||
});
|
||||
}
|
||||
loadRtkGroups();
|
||||
|
||||
form.on('select(rtk-group)', function(data){
|
||||
loadRtkDevices(data.value);
|
||||
});
|
||||
form.on('select(rtk-device)', function(data){ rtkSelectedDevice = data.value; });
|
||||
|
||||
function updateToggleBtn(){
|
||||
var btn = $('#btn-rtk-start');
|
||||
if(rtkRunning){
|
||||
btn.text('停止定位');
|
||||
btn.addClass('layui-btn-danger');
|
||||
} else {
|
||||
btn.text('开始定位');
|
||||
btn.removeClass('layui-btn-danger');
|
||||
}
|
||||
}
|
||||
updateToggleBtn();
|
||||
|
||||
$('#btn-rtk-start').on('click', function(){
|
||||
rtkSelectedDevice = $('#rtk-device').val();
|
||||
if(!rtkSelectedDevice){ layer.msg('请选择设备'); return; }
|
||||
if(!rtkRunning){
|
||||
$.get('/rtk/log_exists', {device_id: rtkSelectedDevice}, function(exists){
|
||||
function doStart(clear){
|
||||
$.post('/rtk/start', {device_id: rtkSelectedDevice, clear_log: clear}, function(res){
|
||||
if(res && res.code === 0){
|
||||
if(res.data === 'ok' || res.data === 'all_zero'){
|
||||
connectRtkWs(); rtkRunning = true; updateToggleBtn();
|
||||
if(res.data === 'all_zero'){ layer.msg('GNGGA全零,使用默认配置启动'); }
|
||||
} else {
|
||||
layer.msg(res.data||'已处理');
|
||||
}
|
||||
} else { layer.alert((res&&res.msg)||'启动失败'); }
|
||||
}).fail(function(){ layer.alert('启动请求失败'); });
|
||||
}
|
||||
if(exists){
|
||||
layer.confirm('检测到已有日志,是否清空后再开始?', {btn:['清空','追加','取消']}, function(idx){
|
||||
layer.close(idx); doStart(true);
|
||||
}, function(idx){
|
||||
layer.close(idx); doStart(false);
|
||||
});
|
||||
} else {
|
||||
doStart(false);
|
||||
}
|
||||
}).fail(function(){ layer.alert('检查日志失败'); });
|
||||
} else {
|
||||
$.post('/rtk/stop', {device_id: rtkSelectedDevice}, function(){
|
||||
rtkRunning = false; updateToggleBtn();
|
||||
closeRtkWs();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
var grRunning = false; function updateGrBtn(){ var b=$('#btn-gr-start'); if(grRunning){b.text('停止组定位').addClass('layui-btn-danger');} else {b.text('开始组定位').removeClass('layui-btn-danger');} }
|
||||
updateGrBtn();
|
||||
var groupSelectedId = null; var groupDevices = new Set(); var groupStatus = {};
|
||||
form.on('select(gr-group)', function(data){ groupSelectedId = data.value; reloadGroupStatus(); loadGroupDevices(); });
|
||||
function loadGroupDevices(){ groupDevices.clear(); if(!groupSelectedId)return; $.get('/rtk/profile/list',{page:1,limit:1000, group_id: groupSelectedId}, function(res){ if(res.code===0){ (res.data||[]).forEach(function(p){ groupDevices.add(p.device_id);}); renderGroupTable(); } }); }
|
||||
function renderGroupTable(){
|
||||
table.render({
|
||||
elem: '#group-table',
|
||||
data: Array.from(groupDevices).map(function(d){ return {device_id:d, status: (groupStatus[d]||'--')}; }),
|
||||
cols: [ [
|
||||
{field:'device_id', title:'设备号'},
|
||||
{field:'status', title:'状态', templet: function(d){
|
||||
var s=d.status;
|
||||
var m={'RUNNING':'layui-bg-green','QUEUED':'','DONE':'layui-bg-blue','FAILED':'layui-bg-red'};
|
||||
var cls=m[s]||'';
|
||||
return '<span class="layui-badge '+cls+'">'+(s||'--')+'</span>';
|
||||
}}
|
||||
] ],
|
||||
page: true,
|
||||
limit: 10,
|
||||
limits: [10,20,50,100]
|
||||
});
|
||||
}
|
||||
function reloadGroupStatus(){ if(!groupSelectedId) return; $.get('/rtk/group/status',{group_id: groupSelectedId}, function(res){ if(res.code===0){ (res.data||[]).forEach(function(r){ groupStatus[r.device_id]=r.status; }); renderGroupTable(); } }); }
|
||||
$('#btn-gr-start').on('click', function(){ if(!groupSelectedId){ layer.msg('请选择分组'); return; } if(!grRunning){ layer.confirm('是否清空日志后开始?',{btn:['清空','追加','取消']}, function(idx){ layer.close(idx); $.post('/rtk/group/start',{group_id: groupSelectedId, clear_log:true}, function(){ grRunning=true; updateGrBtn(); connectRtkWs(); }); }, function(idx){ layer.close(idx); $.post('/rtk/group/start',{group_id: groupSelectedId, clear_log:false}, function(){ grRunning=true; updateGrBtn(); connectRtkWs(); }); }); } else { $.post('/rtk/group/stop',{group_id: groupSelectedId}, function(){ grRunning=false; updateGrBtn(); }); } });
|
||||
|
||||
function appendGroupLog(msg){ var gi=$('#group-info'); gi.text(gi.text()+msg+'\n'); var el=document.getElementById('group-info'); el.scrollTop=el.scrollHeight; }
|
||||
});
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="rtkProfileBar">
|
||||
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="edit">编辑</a>
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@ -94,9 +94,10 @@
|
||||
url: '/gnss/q_status/list',
|
||||
cols: [[
|
||||
{field: 'deviceid', title: '设备号', width: 120, templet: '#deviceIdTpl', align: 'center',sort: true},
|
||||
{field: 'devicetype', title: '设备类型', templet: '#typeTrans', width: 100},
|
||||
{field: 'devicetype', title: '设备类型', templet: '#typeTrans', width: 80},
|
||||
{field: 'tenantname', title: '部门', width: 100},
|
||||
{field: 'project_id', title: '项目号', width: 100},
|
||||
{field: 'name', title: '工点', width: 150},
|
||||
{field: 'name', title: '工点', width: 100},
|
||||
{field: 'updatetime', title: '更新时间', templet: "<div>{{layui.util.toDateString(d.updatetime, 'yyyy-MM-dd HH:mm:ss')}}</div>", width: 170},
|
||||
{field: 'state', title: '状态', templet: '#stateTrans', width: 80, align: 'center'},
|
||||
{field: 'warning', title: '告警', templet: '#warningTrans', width: 80, align: 'center'},
|
||||
|
||||
@ -0,0 +1,101 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>定位管理-分组</title>
|
||||
<meta name="renderer" content="webkit">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<link rel="stylesheet" href="../../lib/layui-v2.6.3/css/layui.css" media="all">
|
||||
<link rel="stylesheet" href="../../css/public.css" media="all">
|
||||
<style>
|
||||
body { background-color: #ffffff; }
|
||||
</style>
|
||||
<script>
|
||||
var default_inpstr2 = 'ytcors14847:fyx25943@gnss.ytcors.cn:8003/RTCM33GRCEJpro';
|
||||
var default_inpstr3 = 'Ming:@Zhang12345@ntrip.data.gnss.ga.gov.au:2101/BCEP00BKG0';
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div class="layui-form layuimini-form">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">ID</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="id" id="id" placeholder="留空自动生成" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label required">名称</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="name" id="name" lay-verify="required" lay-reqtext="不能为空" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label required">inpstr2-path</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="inpstr2_path" id="inpstr2_path" lay-verify="required" lay-reqtext="不能为空" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label required">inpstr3-path</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="inpstr3_path" id="inpstr3_path" lay-verify="required" lay-reqtext="不能为空" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn layui-btn-normal" lay-submit lay-filter="saveBtn">确认保存</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="../../lib/layui-v2.6.3/layui.js" charset="utf-8"></script>
|
||||
<script>
|
||||
layui.use(['form'], function () {
|
||||
var form = layui.form,
|
||||
$ = layui.$;
|
||||
var iframeIndex = parent.layer.getFrameIndex(window.name);
|
||||
|
||||
$(function(){
|
||||
if(!$('#inpstr2_path').val()) $('#inpstr2_path').val(default_inpstr2);
|
||||
if(!$('#inpstr3_path').val()) $('#inpstr3_path').val(default_inpstr3);
|
||||
});
|
||||
|
||||
form.on('submit(saveBtn)', function (data) {
|
||||
if(!data.field.id){ delete data.field.id; }
|
||||
$.ajax({
|
||||
type:"POST",
|
||||
url:"/rtk/group/update",
|
||||
contentType: "application/json;charset=UTF-8",
|
||||
data: JSON.stringify(data.field),
|
||||
success: function (result) {
|
||||
if(result === 'ok' || result.code === 0){
|
||||
if(parent.onRtkGroupUpdated) parent.onRtkGroupUpdated();
|
||||
parent.layer.close(iframeIndex);
|
||||
} else {
|
||||
layer.alert(result.msg || '保存失败');
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
parent.layer.close(iframeIndex);
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
});
|
||||
|
||||
function setParams(data){
|
||||
var form = layui.form,
|
||||
$ = layui.$;
|
||||
$('#id').val(data.id).attr('readonly', true);
|
||||
$('#name').val(data.name);
|
||||
$('#inpstr2_path').val(data.inpstr2_path);
|
||||
$('#inpstr3_path').val(data.inpstr3_path);
|
||||
form.render();
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@ -0,0 +1,118 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>编辑设备配置</title>
|
||||
<meta name="renderer" content="webkit">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<link rel="stylesheet" href="../../lib/layui-v2.6.3/css/layui.css" media="all">
|
||||
<link rel="stylesheet" href="../../css/public.css" media="all">
|
||||
<style>body{background-color:#fff;}</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="layui-form layuimini-form">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">ID</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="id" id="id" readonly class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label required">设备号</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="device_id" id="device_id" lay-verify="required" lay-reqtext="不能为空" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">分组ID</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="rtkgroup_id" id="rtkgroup_id" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">pos1-posmode</label>
|
||||
<div class="layui-input-inline">
|
||||
<select name="pos1_posmode" id="pos1_posmode">
|
||||
<option value="static">static</option>
|
||||
<option value="kinematic">kinematic</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">inpstr1-type</label>
|
||||
<div class="layui-input-inline">
|
||||
<select name="inpstr1_type" id="inpstr1_type">
|
||||
<option value="ntripcli">ntripcli</option>
|
||||
<option value="tcpcli">tcpcli</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">inpstr1-path</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="inpstr1_path" id="inpstr1_path" placeholder="可留空" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">outstr2-path</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="outstr2_path" id="outstr2_path" placeholder="可留空" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">out-height</label>
|
||||
<div class="layui-input-inline">
|
||||
<select name="out_height" id="out_height">
|
||||
<option value="ellipsoidal">ellipsoidal</option>
|
||||
<option value="geodetic" selected>geodetic</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn layui-btn-normal" lay-submit lay-filter="saveBtn">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="../../lib/layui-v2.6.3/layui.js" charset="utf-8"></script>
|
||||
<script>
|
||||
layui.use(['form'], function(){
|
||||
var form = layui.form, $ = layui.$;
|
||||
var iframeIndex = parent.layer.getFrameIndex(window.name);
|
||||
|
||||
form.on('submit(saveBtn)', function(data){
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: '/rtk/profile/update',
|
||||
contentType: 'application/json;charset=UTF-8',
|
||||
data: JSON.stringify(data.field),
|
||||
success: function(res){
|
||||
if(res.code === 0){
|
||||
parent.layui.table.reload('rtk-profile-table');
|
||||
parent.layer.close(iframeIndex);
|
||||
} else { layer.alert(res.msg || '保存失败'); }
|
||||
},
|
||||
error: function(){ layer.alert('请求失败'); }
|
||||
});
|
||||
return false;
|
||||
});
|
||||
});
|
||||
|
||||
function setParams(d){
|
||||
var form = layui.form, $ = layui.$;
|
||||
if(d.id) $('#id').val(d.id);
|
||||
if(d.device_id) $('#device_id').val(d.device_id);
|
||||
if(d.rtkgroup_id!=null) $('#rtkgroup_id').val(d.rtkgroup_id);
|
||||
$('#pos1_posmode').val(d.pos1_posmode||'static');
|
||||
$('#inpstr1_type').val(d.inpstr1_type||'ntripcli');
|
||||
$('#inpstr1_path').val(d.inpstr1_path||'');
|
||||
$('#outstr2_path').val(d.outstr2_path||'');
|
||||
$('#out_height').val(d.out_height||'geodetic');
|
||||
form.render();
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@ -54,13 +54,12 @@ public class D350SurfaceInclineMessageExecutor implements Executor<D350SurfaceIn
|
||||
logger.debug("{} not existed", deviceId);
|
||||
return null;
|
||||
}
|
||||
SurfaceInclineData data = message.getInclineData();
|
||||
data.setTenantid(device.device.getTenantid());
|
||||
forwardData(device, data);
|
||||
|
||||
ThreadManager.getFixedThreadPool().submit(() -> {
|
||||
SurfaceInclineData data = message.getInclineData();
|
||||
data.setTenantid(device.device.getTenantid());
|
||||
dataMapper.insert(data);
|
||||
|
||||
forwardData(device, data);
|
||||
});
|
||||
return null;
|
||||
}
|
||||
@ -122,9 +121,11 @@ public class D350SurfaceInclineMessageExecutor implements Executor<D350SurfaceIn
|
||||
if (device.sensorNum == 2) {
|
||||
if (data.getSensorid()==1) device.data1 = data;
|
||||
else {
|
||||
data1.setAngley(data.getAnglex());
|
||||
data1.setAccy(data.getAccx());
|
||||
dataForwarder.send(device.device, data1);
|
||||
data.setAngley(data.getAnglex());
|
||||
data.setAnglex(data1.getAnglex());
|
||||
//data1.setAngley(data.getAnglex());
|
||||
//data1.setAccy(data.getAccx());
|
||||
dataForwarder.send(device.device, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user